load-env.js
1 /** 2 * Centralised environment loader. 3 * 4 * Loads three .env files in order (values set first win): 5 * 1. .env — core config (pipeline, browser, dashboard, compliance) 6 * 2. .env.secrets — API keys, tokens, passwords 7 * 3. .env.agents — agent system, reaper, spawn settings 8 * 9 * Usage: import './utils/load-env.js'; (from src/) 10 * or: import '../utils/load-env.js'; (from src/cli/) 11 * or: import '../../src/utils/load-env.js'; (from tests/) 12 * 13 * Existing vars (e.g. from shell) are never overwritten. 14 */ 15 16 import { config } from 'dotenv'; 17 import { resolve, dirname } from 'path'; 18 import { fileURLToPath } from 'url'; 19 20 const __dirname = dirname(fileURLToPath(import.meta.url)); 21 const root = resolve(__dirname, '../..'); 22 23 // Load in priority order — dotenv never overwrites existing values 24 // quiet: true suppresses dotenv v17 stdout tip messages (important for scripts that parse stdout) 25 config({ path: resolve(root, '.env'), quiet: true }); 26 config({ path: resolve(root, '.env.secrets'), quiet: true }); 27 config({ path: resolve(root, '.env.agents'), quiet: true }); 28 29 /** 30 * Parse a comma-separated env var into a Set of non-empty uppercase strings. 31 * Used for country lists, channel blocklists, etc. 32 * @param {string|undefined} value - The raw env var value 33 * @returns {Set<string>} 34 */ 35 export function parseEnvSet(value) { 36 return new Set( 37 (value || '').split(',').map(s => s.trim().toUpperCase()).filter(Boolean) 38 ); 39 }