import dotenv from 'dotenv'; dotenv.config(); function require_env(key: string): string { const val = process.env[key]; if (!val) throw new Error(`Missing required env variable: ${key}`); return val; } function optional_env(key: string, fallback: string): string { return process.env[key] || fallback; } export const CONFIG = { PORT: parseInt(optional_env('PORT', '7860'), 10), NODE_ENV: optional_env('NODE_ENV', 'production'), ALLOWED_ORIGINS: optional_env('ALLOWED_ORIGINS', '*').split(',').map(s => s.trim()), JWT_SECRET: require_env('JWT_SECRET'), REDIS_PRESENCE_URL: require_env('REDIS_PRESENCE_URL'), REDIS_MESSAGE_URL: require_env('REDIS_MESSAGE_URL'), MONGO_URI: require_env('MONGO_URI'), SUPABASE_URL: require_env('SUPABASE_URL'), SUPABASE_SERVICE_KEY: require_env('SUPABASE_SERVICE_KEY'), SUPABASE_BUCKET: optional_env('SUPABASE_BUCKET', 'media'), // STUN: comma-separated list of stun: URIs STUN_SERVERS: optional_env('STUN_SERVERS', 'stun:stun.l.google.com:19302') .split(',') .map(s => s.trim()) .filter(Boolean), // TURN: comma-separated list of turn:/turns: URIs (all share same credentials) TURN_URLS: optional_env('TURN_URL', '') .split(',') .map(s => s.trim()) .filter(Boolean), TURN_USERNAME: optional_env('TURN_USERNAME', ''), TURN_CREDENTIAL: optional_env('TURN_CREDENTIAL', ''), MAX_FILE_SIZE_BYTES: parseInt(optional_env('MAX_FILE_SIZE_MB', '99'), 10) * 1024 * 1024, MAX_FILE_COUNT: parseInt(optional_env('MAX_FILE_COUNT', '10'), 10), PRESENCE_TTL_S: parseInt(optional_env('PRESENCE_TTL_S', '60'), 10), OFFLINE_MSG_TTL_S: parseInt(optional_env('OFFLINE_MSG_TTL_S', '604800'), 10), HEARTBEAT_INTERVAL_MS: parseInt(optional_env('HEARTBEAT_INTERVAL_MS', '30000'), 10), } as const; interface RTCIceServerConfig { urls: string; username?: string; credential?: string; } /** * Builds the full ICE server array sent to clients on connect. * Supports multiple TURN URLs (comma-separated in env) — all share * the same username/credential pair (Metered format). */ export function buildIceServers(): RTCIceServerConfig[] { const servers: RTCIceServerConfig[] = CONFIG.STUN_SERVERS.map(url => ({ urls: url })); for (const url of CONFIG.TURN_URLS) { servers.push({ urls: url, username: CONFIG.TURN_USERNAME, credential: CONFIG.TURN_CREDENTIAL, }); } return servers; }