import fs from 'fs'; import path from 'path'; import { logger } from './logger.js'; // ── Internal cache ────────────────────────────────────────────── let _cache: Record | null = null; /** Parse the entire .env file into a Record (no key filtering). */ function parseEnvFile(): Record { const envFile = path.join(process.cwd(), '.env'); let content: string; try { content = fs.readFileSync(envFile, 'utf-8'); } catch (err) { logger.debug({ err }, '.env file not found, using defaults'); return {}; } const result: Record = {}; for (const line of content.split('\n')) { const trimmed = line.trim(); if (!trimmed || trimmed.startsWith('#')) continue; const eqIdx = trimmed.indexOf('='); if (eqIdx === -1) continue; const key = trimmed.slice(0, eqIdx).trim(); let value = trimmed.slice(eqIdx + 1).trim(); if ( (value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'")) ) { value = value.slice(1, -1); } if (value) result[key] = value; } return result; } // ── Public API ────────────────────────────────────────────────── /** Load (or reload) the .env file into the in-memory cache. */ export function loadEnvFile(): void { _cache = parseEnvFile(); } /** * Look up a single env value. * Priority: process.env > .env cache > undefined */ export function getEnv(key: string): string | undefined { if (!_cache) loadEnvFile(); return process.env[key] || _cache![key] || undefined; } /** Force-reload the .env file (e.g. after token refresh writes new values). */ export function reloadEnvFile(): void { _cache = null; loadEnvFile(); } /** * Parse the .env file and return values for the requested keys. * Does NOT load anything into process.env — callers decide what to * do with the values. This keeps secrets out of the process environment * so they don't leak to child processes. * * Now backed by the in-memory cache (disk read happens at most once). */ export function readEnvFile(keys: string[]): Record { if (!_cache) loadEnvFile(); const result: Record = {}; const wanted = new Set(keys); for (const [key, value] of Object.entries(_cache!)) { if (wanted.has(key)) result[key] = value; } return result; }