1import { Credentials } from "@distilled.cloud/axiom/Credentials";
2import { ConfigError } from "@distilled.cloud/core/errors";
3import * as Effect from "effect/Effect";
4import * as Layer from "effect/Layer";
5import * as Match from "effect/Match";
6import {
7 deferUntilFirstUse,
8 orDieCredentialsUnavailable,
9 resolveProviderConfig,
10} from "../Auth/Resolve.ts";
11import {
12 AXIOM_AUTH_PROVIDER_NAME,
13 type AxiomAuthConfig,
14 type AxiomResolvedCredentials,
15} from "./AuthProvider.ts";
16
17export {
18 Credentials,
19 CredentialsFromEnv,
20 DEFAULT_API_BASE_URL,
21} from "@distilled.cloud/axiom/Credentials";
22
23/**
24 * Build a `Credentials` layer that resolves Axiom credentials via the Alchemy
25 * AuthProvider using the configured profile (defaults to "default", overridable
26 * with the current Alchemy profile).
27 */
28export const fromAuthProvider = () =>
29 Layer.effect(
30 Credentials,
31 Effect.gen(function* () {
32 // Defer profile lookup and credential resolution until first use, so
33 // building the provider layers never requires a configured profile.
34 const resolve = yield* resolveProviderConfig<
35 AxiomAuthConfig,
36 AxiomResolvedCredentials
37 >(AXIOM_AUTH_PROVIDER_NAME).pipe(
38 Effect.flatMap(({ profileName, resolve }) =>
39 resolve.pipe(
40 Effect.map((creds) =>
41 Match.value(creds).pipe(
42 Match.when({ type: "apiToken" }, (c) => ({
43 apiKey: c.apiToken,
44 apiBaseUrl: c.apiBaseUrl,
45 orgId: c.orgId,
46 })),
47 Match.when({ type: "pat" }, (c) => ({
48 apiKey: c.apiToken,
49 apiBaseUrl: c.apiBaseUrl,
50 orgId: c.orgId,
51 })),
52 Match.exhaustive,
53 ),
54 ),
55 Effect.mapError(
56 (e) =>
57 new ConfigError({
58 message: `Failed to resolve Axiom credentials from ${profileName === undefined ? "the CI environment" : `profile '${profileName}'`}: ${(e as { message?: string }).message ?? String(e)}`,
59 }),
60 ),
61 ),
62 ),
63 deferUntilFirstUse,
64 );
65 return yield* resolve.pipe(
66 orDieCredentialsUnavailable(AXIOM_AUTH_PROVIDER_NAME),
67 Effect.cached,
68 );
69 }),
70 );