import { resolve } from 'node:path'; import { CANARY_DEFAULT_PORT, CANARY_DEFAULT_UPSTREAM_PORT, type CanaryGatewayOptions, } from './canary-gateway.js'; export interface CanaryRuntimeEnvironment { readonly CANARY_DIST_DIR?: string; readonly CANARY_PORT?: string; readonly CANARY_UPSTREAM_PORT?: string; readonly MULTI_SIMADMIN_GATEWAY_HOST?: string; readonly MULTI_SIMADMIN_GATEWAY_ALLOWED_HOSTS?: string; readonly MULTI_SIMADMIN_GATEWAY_TOKEN?: string; readonly MULTI_SIMADMIN_CUTOVER_ACK?: string; } export const PRODUCTION_CUTOVER_ACK = 'I ACKNOWLEDGE MULTI-SIMADMIN OWNS PORT 8788'; function environmentPort(value: string | undefined, name: string, fallback: number): number { if (value === undefined || value === '') return fallback; const port = Number(value); if (!Number.isInteger(port) || port < 1 || port > 65_535) throw new Error(`${name} must be an integer port`); return port; } export function readCanaryRuntimeOptions( environment: CanaryRuntimeEnvironment, ): CanaryGatewayOptions { const gatewayToken = environment.MULTI_SIMADMIN_GATEWAY_TOKEN; if ( !gatewayToken || Buffer.byteLength(gatewayToken) < 32 || Buffer.byteLength(gatewayToken) > 512 ) throw new Error('Gateway token must contain between 32 and 512 bytes'); return Object.freeze({ distDir: resolve(environment.CANARY_DIST_DIR ?? 'apps/web/dist'), port: environmentPort(environment.CANARY_PORT, 'CANARY_PORT', CANARY_DEFAULT_PORT), upstreamPort: environmentPort( environment.CANARY_UPSTREAM_PORT, 'CANARY_UPSTREAM_PORT', CANARY_DEFAULT_UPSTREAM_PORT, ), gatewayToken, }); } export function readProductionGatewayRuntimeOptions( environment: CanaryRuntimeEnvironment, ): CanaryGatewayOptions { if (environment.MULTI_SIMADMIN_CUTOVER_ACK !== PRODUCTION_CUTOVER_ACK) { throw new Error( `Production gateway requires MULTI_SIMADMIN_CUTOVER_ACK=${PRODUCTION_CUTOVER_ACK}`, ); } const options = readCanaryRuntimeOptions({ ...environment, CANARY_PORT: '8788' }); const host = environment.MULTI_SIMADMIN_GATEWAY_HOST ?? options.host; const allowedHosts = environment.MULTI_SIMADMIN_GATEWAY_ALLOWED_HOSTS?.split(',') .map((value) => value.trim()) .filter(Boolean); return Object.freeze({ ...options, ...(host === undefined ? {} : { host }), ...(allowedHosts === undefined ? {} : { allowedHosts }), ownsProductionPort: true, }); }