-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathenv.ts
More file actions
90 lines (83 loc) · 3.44 KB
/
Copy pathenv.ts
File metadata and controls
90 lines (83 loc) · 3.44 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
/**
* Environment-variable helpers shared across `@objectstack/*` packages.
*
* The framework standardises on `OS_*` prefixed env vars (see AGENTS.md
* "Environment Variables" section). Some historical names predate this
* convention — `AUTH_SECRET`, `ROOT_DOMAIN`, `OBJECTSTACK_*`, …
*
* To migrate without breaking user `.env` files mid-release, call
* {@link readEnvWithDeprecation} at every legacy read site:
*
* const v = readEnvWithDeprecation('OS_AUTH_SECRET', 'AUTH_SECRET');
*
* If only the legacy name is set, the value is still returned but a
* one-shot `console.warn` fires (per-process per-variable) telling
* operators to rename it.
*/
const _warnedKeys = new Set<string>();
/**
* Read an env var, preferring the canonical `OS_*` name and falling
* back to one or more legacy aliases.
*
* When only a legacy alias is set, emits a one-shot deprecation warning.
* The warning is process-wide deduplicated: identical (preferred, legacy)
* pairs will only warn once even if read from multiple call sites.
*
* Legacy aliases are checked in order; the first one with a defined
* value wins (and triggers the warning for that specific alias).
*
* Safe to call from environments where `process` is unavailable (returns
* `undefined`); the warning is suppressed when running outside Node-like
* runtimes that lack `console.warn`.
*
* @param preferred Canonical OS_*-prefixed env var name.
* @param legacy Older name (or array of older names) to fall back on.
* @param options Optional behaviour flags. Set `silent: true` for aliases
* that remain accepted conventions rather than true legacy
* names — e.g. `PORT`, which PaaS platforms (Render, Railway,
* Heroku, Fly, …) inject automatically. Warning on those
* would nag operators about env they never set.
* @returns The resolved value, or `undefined` if neither is set.
*/
export function readEnvWithDeprecation(
preferred: string,
legacy: string | readonly string[],
options?: { silent?: boolean },
): string | undefined {
const env = (globalThis as { process?: { env?: Record<string, string | undefined> } })
.process?.env;
if (!env) return undefined;
const preferredValue = env[preferred];
if (preferredValue !== undefined) return preferredValue;
const legacyList = typeof legacy === 'string' ? [legacy] : legacy;
for (const legacyName of legacyList) {
const legacyValue = env[legacyName];
if (legacyValue !== undefined) {
const dedupeKey = `${preferred}|${legacyName}`;
if (!options?.silent && !_warnedKeys.has(dedupeKey)) {
_warnedKeys.add(dedupeKey);
const consoleRef = (globalThis as { console?: { warn?: (msg: string) => void } }).console;
try {
consoleRef?.warn?.(
`[ObjectStack] Env var \`${legacyName}\` is deprecated; rename it to \`${preferred}\`. ` +
`The legacy name still works for now but will be removed in a future major release.`,
);
} catch {
/* `console.warn` unavailable (exotic runtime) — ignore */
}
}
return legacyValue;
}
}
return undefined;
}
/**
* Internal: clear the dedupe set. Test-only; exposed so suite-wide
* deprecation warnings don't bleed between tests.
*
* @internal
*/
export function _resetEnvDeprecationWarnings(): void {
_warnedKeys.clear();
}