import { readFileSync } from 'node:fs'; export type ServerConfig = { host: string; port: number; mongoUri: string; mongoDatabase: string; visitStore: 'mongo' | 'memory'; allowedOrigins: string[]; }; export function loadServerConfig(path: string | URL = new URL('../.config.json', import.meta.url)): ServerConfig { let contents: string; try { contents = readFileSync(path, 'utf8'); } catch { throw new Error('Cannot read .config.json; copy .config.example.json to .config.json and configure the server.'); } let value: unknown; try { value = JSON.parse(contents); } catch { throw new Error('Invalid JSON in .config.json'); } if (!value || typeof value !== 'object' || Array.isArray(value)) throw new Error('Invalid .config.json: expected an object'); const config = value as Record; const nonempty = (value: unknown): value is string => typeof value === 'string' && value.trim().length > 0; for (const field of ['host', 'mongoUri', 'mongoDatabase']) { if (!nonempty(config[field])) throw new Error(`Invalid .config.json field: ${field}`); } if (typeof config.port !== 'number' || !Number.isInteger(config.port) || config.port < 0 || config.port > 65535) { throw new Error('Invalid .config.json field: port'); } if (config.visitStore !== 'mongo' && config.visitStore !== 'memory') throw new Error('Invalid .config.json field: visitStore'); if (!Array.isArray(config.allowedOrigins) || !config.allowedOrigins.length || !config.allowedOrigins.every(nonempty)) { throw new Error('Invalid .config.json field: allowedOrigins'); } return config as ServerConfig; }