import { resolve } from "node:path"; export interface AppConfig { databaseUrl: string; jwtSecret: string; jwtTtlHours: number; adminUsername: string; adminPasswordHash: string; serverPort: number; staticDir: string | null; logLevel: string; /** Portal SSO — when true, require portal JWT with apps includes cdn */ authRequired: boolean; authIssuer: string; authPortalUrl: string; /** Bearer secret for POST {authPortalUrl}/api/v1/ingest/audit */ authAuditIngestSecret: string | null; } function boolEnv(v: string | undefined, fallback: boolean): boolean { if (v === undefined || v === "") return fallback; return v === "1" || v.toLowerCase() === "true"; } export function loadConfig(): AppConfig { const isProd = process.env.NODE_ENV === "production"; const jwtSecret = process.env.AUTH_JWT_SECRET ?? process.env.JWT_SECRET ?? (isProd ? "" : "dev-secret-change-me"); return { databaseUrl: process.env.DATABASE_URL ?? "sqlite:data/app.db", jwtSecret: jwtSecret || "dev-secret-change-me", jwtTtlHours: Number(process.env.JWT_TTL_HOURS ?? "24") || 24, adminUsername: process.env.ADMIN_USERNAME ?? "admin", adminPasswordHash: process.env.ADMIN_PASSWORD_HASH?.trim() || "devplaceholder", serverPort: Number(process.env.SERVER_PORT ?? "8081") || 8081, staticDir: process.env.STATIC_DIR ? resolve(process.env.STATIC_DIR) : null, logLevel: process.env.LOG_LEVEL ?? "info", authRequired: boolEnv(process.env.AUTH_REQUIRED, false), authIssuer: process.env.AUTH_ISSUER ?? process.env.ISSUER ?? "https://auth.shnt.top", authPortalUrl: ( process.env.AUTH_PORTAL_URL ?? process.env.VITE_AUTH_PORTAL_URL ?? "http://localhost:5175" ).replace(/\/$/, ""), authAuditIngestSecret: process.env.AUTH_AUDIT_INGEST_SECRET?.trim() || (!isProd ? "dev-audit-ingest-secret" : null), }; }