import { BUILD_GIT_SHA } from "./build-info.js"; export const USER_ROLES = ["admin", "ap_processor", "approver", "viewer"] as const; export type UserRole = (typeof USER_ROLES)[number]; export function isUserRole(value: string): value is UserRole { return (USER_ROLES as readonly string[]).includes(value); } const LOCAL_NODE_ENVS = new Set(["development", "test"]); export type ApiEnv = { nodeEnv: string; stage: string; sha: string; port: number; databaseDriver: "postgres" | "data-api"; databaseUrl: string; awsRegion: string; rdsClusterArn: string; rdsSecretArn: string; rdsDatabase: string; cognitoIssuer: string; cognitoAudience: string; cognitoDomain: string; appOrigin: string; originVerifySecret: string; devAuthBypass: boolean; devAuthSub: string; devAuthEmail: string; devAuthName: string; devAuthRole: UserRole; }; function required(name: string, value: string | undefined): string { if (!value) { throw new Error(`Missing required env var ${name}.`); } return value; } export function loadEnv(env: NodeJS.ProcessEnv = process.env): ApiEnv { const nodeEnv = env.NODE_ENV ?? "development"; const databaseDriver = (env.DATABASE_DRIVER ?? "postgres") as ApiEnv["databaseDriver"]; if (databaseDriver !== "postgres" && databaseDriver !== "data-api") { throw new Error(`Invalid DATABASE_DRIVER: ${databaseDriver}`); } const devAuthBypass = env.DEV_AUTH_BYPASS === "true"; if (devAuthBypass && !LOCAL_NODE_ENVS.has(nodeEnv)) { throw new Error("DEV_AUTH_BYPASS is only allowed when NODE_ENV is development or test."); } const rawRole = env.DEV_AUTH_ROLE ?? "admin"; if (!isUserRole(rawRole)) { throw new Error(`Invalid DEV_AUTH_ROLE: ${rawRole}`); } const local = LOCAL_NODE_ENVS.has(nodeEnv); const stage = env.STAGE?.trim() || (local ? "local" : "dev"); // SHA is inlined at image build. Runtime GIT_SHA is a local-dev convenience // only and must not be the deployed source of truth. const sha = BUILD_GIT_SHA || env.GIT_SHA?.trim() || "unknown"; const base: ApiEnv = { nodeEnv, stage, sha, port: Number(env.API_PORT ?? "8787"), databaseDriver, databaseUrl: env.DATABASE_URL ?? "postgresql://seahaven:seahaven@127.0.0.1:5432/seahaven_ap", awsRegion: env.AWS_REGION ?? "us-east-1", rdsClusterArn: env.RDS_CLUSTER_ARN ?? "", rdsSecretArn: env.RDS_SECRET_ARN ?? "", rdsDatabase: env.RDS_DATABASE ?? "seahaven_ap", cognitoIssuer: env.COGNITO_ISSUER ?? "", cognitoAudience: env.COGNITO_AUDIENCE ?? "", cognitoDomain: env.COGNITO_DOMAIN?.trim() ?? "", appOrigin: env.APP_ORIGIN?.trim() || (local ? "http://127.0.0.1:3000" : ""), originVerifySecret: env.ORIGIN_VERIFY_SECRET?.trim() ?? "", devAuthBypass, devAuthSub: env.DEV_AUTH_SUB ?? "seed-sub-admin", devAuthEmail: env.DEV_AUTH_EMAIL ?? "admin@seahavenind.com", devAuthName: env.DEV_AUTH_NAME ?? "Dev Admin", devAuthRole: rawRole, }; if (databaseDriver === "data-api") { required("RDS_CLUSTER_ARN", base.rdsClusterArn); required("RDS_SECRET_ARN", base.rdsSecretArn); } if (!devAuthBypass && nodeEnv !== "test") { required("COGNITO_ISSUER", base.cognitoIssuer); required("COGNITO_AUDIENCE", base.cognitoAudience); } return base; }