Repository Public
1/**2 * Tiny, dependency-free `.env` loader. Only the file named by `AOS_ENV_FILE` is read (never a file3 * found by walking directories). `KEY=VALUE` lines, `#` comments, optional `export ` prefix and4 * matching single/double quotes around the value. A variable already set in the process environment5 * is never overridden. Values are never logged; an unreadable file is an error, because a6 * deployment that names a file expects its content.7 */8import fs from 'node:fs';910export function parseEnvFile(text: string): Record<string, string> {11 const out: Record<string, string> = {};12 for (const raw of text.split(/\r?\n/)) {13 const line = raw.trim();14 if (line.length === 0 || line.startsWith('#')) continue;15 const m = /^(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)$/.exec(line);16 if (!m) continue;17 let value = (m[2] ?? '').trim();18 const q = value[0];19 if ((q === '"' || q === "'") && value.length >= 2 && value.endsWith(q)) value = value.slice(1, -1);20 out[m[1] as string] = value;21 }22 return out;23}2425/** Loads `env.AOS_ENV_FILE` into `env` (no override). Returns the NAMES that were set — never the values. */26export function loadEnvFile(env: NodeJS.ProcessEnv = process.env): string[] {27 const file = env.AOS_ENV_FILE;28 if (!file || file.trim().length === 0) return [];29 let text: string;30 try {31 text = fs.readFileSync(file, 'utf8');32 } catch (err) {33 throw new Error(`AOS_ENV_FILE cannot be read (${(err as NodeJS.ErrnoException).code ?? 'error'}): ${file}`);34 }35 const set: string[] = [];36 for (const [k, v] of Object.entries(parseEnvFile(text))) {37 if (env[k] === undefined || env[k] === '') {38 env[k] = v;39 set.push(k);40 }41 }42 return set;43}44