import { parseBridgeKey, parseDeploymentRelease, type BridgeKey, type DeploymentRelease, } from "./bridge.ts"; import { requiredSecret } from "./secrets.ts"; import { ConfigurationError, json, origin, record, serverSettings, text, type Bindings, type Environment, } from "./validation.ts"; const installationKeys = [ "schemaVersion", "installationId", "ownerSubject", "runtimeOrigin", "controlPlaneOrigin", "bridge", "release", ] as const; const bindingKeys = [ "FLAREBOT_MODE", "FLAREBOT_ENV", "FLAREBOT_INSTALLATION", "FLAREBOT_DEV_OVERRIDES", "FLAREBOT_SESSION_SECRET", ] as const; export interface CustomerConfigBindings { FLAREBOT_MODE?: unknown; FLAREBOT_ENV?: unknown; FLAREBOT_INSTALLATION?: unknown; FLAREBOT_DEV_OVERRIDES?: unknown; FLAREBOT_SESSION_SECRET?: unknown; } export interface InstallationConfig { readonly schemaVersion: 1; readonly installationId: string; readonly ownerSubject: string; readonly runtimeOrigin: string; readonly controlPlaneOrigin: string; readonly bridge?: BridgeKey; readonly release?: DeploymentRelease; } export function parseInstallationConfig( value: unknown, environment: Environment = "production", ): InstallationConfig { const config = record(value, installationKeys, "FLAREBOT_INSTALLATION"); if (config.schemaVersion !== 1) throw new ConfigurationError( "FLAREBOT_INSTALLATION.schemaVersion", "expected version 1; migrate unsupported configuration explicitly", ); const installationId = text( config.installationId, "FLAREBOT_INSTALLATION.installationId", ); if (!/^[a-f0-9]{32}$/.test(installationId)) throw new ConfigurationError( "FLAREBOT_INSTALLATION.installationId", "set the stable 32-character lowercase hexadecimal installation ID; preserve it across upgrades", ); return Object.freeze({ schemaVersion: 1, ...(config.bridge === undefined ? {} : { bridge: parseBridgeKey(config.bridge) }), ...(config.release === undefined ? {} : { release: parseDeploymentRelease(config.release) }), installationId, ownerSubject: text( config.ownerSubject, "FLAREBOT_INSTALLATION.ownerSubject", ), runtimeOrigin: origin( config.runtimeOrigin, "FLAREBOT_INSTALLATION.runtimeOrigin", environment, ), controlPlaneOrigin: origin( config.controlPlaneOrigin, "FLAREBOT_INSTALLATION.controlPlaneOrigin", environment, ), }); } // Use at nonsecret persistence/export boundaries, even for an already typed value. // Revalidation rejects secrets and other extra fields added by JS/object spreads. export function serializeInstallationConfig( value: unknown, environment: Environment = "production", ): string { return JSON.stringify(parseInstallationConfig(value, environment)); } export function loadCustomerConfig(env: CustomerConfigBindings) { const bindings = env as Bindings; const settings = serverSettings(bindings, "customer-runtime", bindingKeys); const installation = parseInstallationConfig( json(env.FLAREBOT_INSTALLATION, "FLAREBOT_INSTALLATION"), settings.environment, ); let effectiveInstallation = installation; if (env.FLAREBOT_DEV_OVERRIDES !== undefined) { const overrides = record( json(env.FLAREBOT_DEV_OVERRIDES, "FLAREBOT_DEV_OVERRIDES"), ["runtimeOrigin", "controlPlaneOrigin"], "FLAREBOT_DEV_OVERRIDES", ); effectiveInstallation = parseInstallationConfig( { ...installation, ...overrides }, settings.environment, ); } return Object.freeze({ ...settings, mode: "customer-runtime" as const, installation, effectiveInstallation, }); } export function loadCustomerSecrets(env: CustomerConfigBindings) { serverSettings(env as Bindings, "customer-runtime", bindingKeys); return Object.freeze({ sessionSecret: requiredSecret(env as Bindings, "FLAREBOT_SESSION_SECRET"), }); }