Files
supabase/apps/studio/scripts/lib/env.js
T
Alaister Young 2413adbb27 fix(studio): only skip missing env files, surface other read errors
readEnvFiles swallowed every readFileSync error, so an existing-but-
unreadable env file (bad permissions, IO error) was silently treated as
absent — dropping its values and potentially booting serve.js without
secrets like POSTGRES_PASSWORD. Skip only ENOENT and rethrow the rest.

Addresses PR review feedback.
2026-06-23 22:48:55 +08:00

53 lines
1.9 KiB
JavaScript

// Shared .env parsing for the studio build/serve scripts (dispatch.js,
// serve.js). We parse the small subset of the dotenv format we actually rely
// on — `KEY=value`, an optional `export` prefix, and surrounding single/double
// quotes — rather than taking on the `dotenv` dependency for a couple of build
// scripts. Crucially, nothing here touches `process.env`: callers decide what
// to do with the parsed values, which is what lets dispatch.js read a single
// key without leaking the whole file into the child process.
//
// dispatch.js and serve.js must agree on this format, so it lives here once.
import { readFileSync } from 'node:fs'
import path from 'node:path'
const ENV_LINE = /^\s*(?:export\s+)?([\w.-]+)\s*=\s*(.*?)\s*$/
// Parse the contents of a single env file into a plain key/value object.
export function parseEnv(content) {
const parsed = {}
for (const raw of content.split('\n')) {
const m = ENV_LINE.exec(raw)
if (!m) continue
let value = m[2]
if (
(value.startsWith('"') && value.endsWith('"')) ||
(value.startsWith("'") && value.endsWith("'"))
) {
value = value.slice(1, -1)
}
parsed[m[1]] = value
}
return parsed
}
// Read a cascade of env files from `dir`, with later files overriding earlier
// ones — matching the precedence vite/Next use
// (`.env` < `.env.local` < `.env.<mode>` < `.env.<mode>.local`). A missing file
// is skipped, but any other read error (permissions, IO) is surfaced rather
// than silently dropping that file's values. Returns the merged key/value
// object; never mutates process.env.
export function readEnvFiles(dir, files) {
const parsed = {}
for (const file of files) {
let content
try {
content = readFileSync(path.join(dir, file), 'utf8')
} catch (err) {
if (err && typeof err === 'object' && err.code === 'ENOENT') continue
throw err
}
Object.assign(parsed, parseEnv(content))
}
return parsed
}