/** * Simple ESM-compatible configuration loader * Loads JSON files: base.json -> environment.json -> secrets.json */ import { readFileSync, existsSync } from 'fs'; import { join, dirname } from 'path'; import { fileURLToPath } from 'url'; const __dirname = dirname(fileURLToPath(import.meta.url)); function deepMerge(target, source) { const result = { ...target }; for (const key of Object.keys(source)) { if (source[key] && typeof source[key] === 'object' && !Array.isArray(source[key])) { result[key] = deepMerge(result[key] || {}, source[key]); } else { result[key] = source[key]; } } return result; } function loadJsonFile(filename) { const path = join(__dirname, '..', 'conf', filename); if (!existsSync(path)) return {}; try { return JSON.parse(readFileSync(path, 'utf-8')); } catch (err) { console.warn(`Warning: Failed to load ${filename}:`, err.message); return {}; } } // Load configuration const environment = process.env.NODE_ENV || 'development'; const base = loadJsonFile('base.json'); const envConfig = loadJsonFile(`${environment}.json`); const secrets = loadJsonFile('secrets.json'); // Merge all configs const config = deepMerge(deepMerge(base, envConfig), secrets); // Add environment info config.environment = environment; // Allow env var overrides for critical settings if (process.env.PORT) { config.server = config.server || {}; config.server.port = parseInt(process.env.PORT); } if (process.env.OPENCLAW_GATEWAY) { config.gateway = config.gateway || {}; config.gateway.url = process.env.OPENCLAW_GATEWAY; } if (process.env.OPENCLAW_TOKEN) { config.gateway = config.gateway || {}; config.gateway.token = process.env.OPENCLAW_TOKEN; } if (process.env.SESSION_SECRET) { config.session = config.session || {}; config.session.secret = process.env.SESSION_SECRET; } if (process.env.LDAP_ENABLED === 'true') { config.auth = config.auth || {}; config.auth.ldap = config.auth.ldap || {}; config.auth.ldap.enabled = true; } export default config;