import { ConfigError } from "@distilled.cloud/core/errors"; import { Credentials } from "@distilled.cloud/hetzner"; import * as Config from "effect/Config"; import * as Effect from "effect/Effect"; import * as Layer from "effect/Layer"; import { getAuthProvider } from "../Auth/AuthProvider.ts"; import { ALCHEMY_PROFILE, AlchemyProfile } from "../Auth/Profile.ts"; import { HETZNER_AUTH_PROVIDER_NAME, type HetznerAuthConfig, type HetznerResolvedCredentials, } from "./AuthProvider.ts"; export { Credentials, CredentialsFromEnv, credentials, DEFAULT_API_BASE_URL, type Config as CredentialsConfig, } from "@distilled.cloud/hetzner"; /** * Build a `Credentials` layer that resolves Hetzner credentials via the * Alchemy AuthProvider using the configured profile (defaults to "default", * overridable with the `ALCHEMY_PROFILE` env/config value). * * Maps onto `@distilled.cloud/hetzner`'s `{ token, apiBaseUrl }` shape. */ export const fromAuthProvider = () => Layer.effect( Credentials, Effect.gen(function* () { const profile = yield* AlchemyProfile; const auth = yield* getAuthProvider< HetznerAuthConfig, HetznerResolvedCredentials >(HETZNER_AUTH_PROVIDER_NAME); const profileName = yield* ALCHEMY_PROFILE; const ci = yield* Config.boolean("CI").pipe(Config.withDefault(false)); return yield* profile.loadOrConfigure(auth, profileName, { ci }).pipe( Effect.flatMap((config) => auth.read(profileName, config as HetznerAuthConfig), ), Effect.map((creds) => ({ token: creds.token, apiBaseUrl: creds.apiBaseUrl, })), Effect.mapError( (e) => new ConfigError({ message: `Failed to resolve Hetzner credentials for profile '${profileName}': ${(e as { message?: string }).message ?? String(e)}`, }), ), Effect.orDie, Effect.cached, ); }), );