import * as Effect from "effect/Effect"; import { loadControlPlaneConfig, loadControlPlaneSecrets, type ControlPlaneConfigBindings, } from "../configuration/control-plane.ts"; import release from "../package.json"; import { OAuthError } from "./errors.ts"; import type { InstallationRegistry } from "./installation-registry.ts"; import type { AuthVault } from "./vault.ts"; export interface Env extends ControlPlaneConfigBindings { INSTALLATION_WORKFLOW: Workflow< import("./installation-workflow.ts").InstallationParams >; INSTALLATIONS: DurableObjectNamespace; AUTH_VAULT: DurableObjectNamespace; ASSETS: Fetcher; } export function configuration(env: Env) { return Effect.try({ try: () => { let settings; let secrets; try { settings = loadControlPlaneConfig(env); secrets = loadControlPlaneSecrets(env); } catch { throw new OAuthError("oauth_setup_required"); } const config = settings.config; const manifest = config.oauthCapabilities; const method = config.oauthTokenAuthMethod; if (!manifest || !method) throw new OAuthError("oauth_capability_unavailable"); const same = (a: readonly string[], b: readonly string[]) => a.length === b.length && a.every((s) => b.includes(s)); if ( manifest.artifactVersion !== release.version || manifest.registeredClient.clientId !== config.oauthClientId || manifest.registeredClient.redirectUri !== config.oauthRedirectUri || manifest.registeredClient.tokenAuthMethod !== method || !config.oauthScopes.every((scope) => manifest.registeredClient.scopeIds.includes(scope), ) || !same( manifest.scopes.map((s) => s.id), config.oauthScopes, ) ) throw new OAuthError("oauth_capability_unavailable"); if ( new URL(config.oauthRedirectUri).pathname !== "/auth/callback" || (method !== "none" && !secrets.oauthClientSecret) || (method === "none" && secrets.oauthClientSecret) ) throw new OAuthError("oauth_setup_required"); return { ...config, oauthTokenAuthMethod: method, secrets }; }, catch: (error) => error instanceof OAuthError ? error : new OAuthError("oauth_setup_required"), }); } export type OAuthConfiguration = Effect.Success< ReturnType >;