@karmaniverous/get-dotenv 6.2.3 → 6.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunks/AwsRestJsonProtocol-Bq1HE-Ln.mjs +932 -0
- package/dist/chunks/createCli-BY6_cfZr.mjs +439 -0
- package/dist/chunks/externalDataInterceptor-CbsdEYa-.mjs +19 -0
- package/dist/chunks/getSSOTokenFromFile-hUSpR7Wf.mjs +22 -0
- package/dist/chunks/helpConfig-CGejgwWW.mjs +12 -0
- package/dist/chunks/index-B5JKTBOL.mjs +443 -0
- package/dist/chunks/index-BEJFiHMX.mjs +522 -0
- package/dist/chunks/index-BPYF6K_G.mjs +82 -0
- package/dist/chunks/index-Bc3h0a95.mjs +374 -0
- package/dist/chunks/index-BpCF5UKx.mjs +272 -0
- package/dist/chunks/index-C_wqbTwI.mjs +187 -0
- package/dist/chunks/index-CeCufHlm.mjs +9374 -0
- package/dist/chunks/index-Cu7rdyqN.mjs +102 -0
- package/dist/chunks/index-DWAtHEA-.mjs +379 -0
- package/dist/chunks/index-Dp1Ip6Ra.mjs +354 -0
- package/dist/chunks/index-DyU5pKKi.mjs +24 -0
- package/dist/chunks/index-c7zKtEuy.mjs +578 -0
- package/dist/chunks/index-cIunyiUQ.mjs +702 -0
- package/dist/chunks/invoke-DuRPU1oC.mjs +60 -0
- package/dist/chunks/loadModuleDefault-Dj8B3Stt.mjs +123 -0
- package/dist/chunks/loadSso-w1eTVg0O.mjs +412 -0
- package/dist/chunks/loader-DnhPeGfq.mjs +346 -0
- package/dist/chunks/overlayEnv-Bs2kVayG.mjs +234 -0
- package/dist/chunks/package-boo9EyYs.mjs +5 -0
- package/dist/chunks/parseKnownFiles-B9cDK21V.mjs +23 -0
- package/dist/chunks/readMergedOptions-Nt0TR7dX.mjs +1626 -0
- package/dist/chunks/resolveCliOptions-TFRzhB2c.mjs +138 -0
- package/dist/chunks/sdk-stream-mixin-BZoJ5jy9.mjs +167 -0
- package/dist/chunks/spawnEnv-CN8a7cNR.mjs +306 -0
- package/dist/chunks/types-DJ-BGABd.mjs +59 -0
- package/dist/chunks/validate-CDl0rE6k.mjs +61 -0
- package/dist/cli.mjs +39 -19307
- package/dist/cliHost.mjs +20 -2800
- package/dist/config.mjs +10 -509
- package/dist/env-overlay.mjs +6 -337
- package/dist/getdotenv.cli.mjs +39 -19305
- package/dist/index.mjs +39 -19396
- package/dist/plugins-aws.d.ts +1 -4
- package/dist/plugins-aws.mjs +65 -2568
- package/dist/plugins-batch.mjs +16 -2573
- package/dist/plugins-cmd.mjs +19 -3094
- package/dist/plugins-init.d.ts +8 -0
- package/dist/plugins-init.mjs +85 -2297
- package/dist/plugins.mjs +36 -18817
- package/package.json +1 -2
- package/dist/templates/cli/index.ts +0 -25
- package/dist/templates/cli/plugins/hello/defaultAction.ts +0 -27
- package/dist/templates/cli/plugins/hello/index.ts +0 -26
- package/dist/templates/cli/plugins/hello/options.ts +0 -31
- package/dist/templates/cli/plugins/hello/strangerAction.ts +0 -20
- package/dist/templates/cli/plugins/hello/types.ts +0 -13
- package/dist/templates/config/js/getdotenv.config.js +0 -20
- package/dist/templates/config/json/local/getdotenv.config.local.json +0 -7
- package/dist/templates/config/json/public/getdotenv.config.json +0 -9
- package/dist/templates/config/public/getdotenv.config.json +0 -8
- package/dist/templates/config/ts/getdotenv.config.ts +0 -28
- package/dist/templates/config/yaml/local/getdotenv.config.local.yaml +0 -7
- package/dist/templates/config/yaml/public/getdotenv.config.yaml +0 -7
- package/dist/templates/defaultAction.ts +0 -27
- package/dist/templates/getdotenv.config.js +0 -20
- package/dist/templates/getdotenv.config.json +0 -9
- package/dist/templates/getdotenv.config.local.json +0 -7
- package/dist/templates/getdotenv.config.local.yaml +0 -7
- package/dist/templates/getdotenv.config.ts +0 -28
- package/dist/templates/getdotenv.config.yaml +0 -7
- package/dist/templates/hello/defaultAction.ts +0 -27
- package/dist/templates/hello/index.ts +0 -26
- package/dist/templates/hello/options.ts +0 -31
- package/dist/templates/hello/strangerAction.ts +0 -20
- package/dist/templates/hello/types.ts +0 -13
- package/dist/templates/index.ts +0 -26
- package/dist/templates/js/getdotenv.config.js +0 -20
- package/dist/templates/json/local/getdotenv.config.local.json +0 -7
- package/dist/templates/json/public/getdotenv.config.json +0 -9
- package/dist/templates/local/getdotenv.config.local.json +0 -7
- package/dist/templates/local/getdotenv.config.local.yaml +0 -7
- package/dist/templates/options.ts +0 -31
- package/dist/templates/plugins/hello/defaultAction.ts +0 -27
- package/dist/templates/plugins/hello/index.ts +0 -26
- package/dist/templates/plugins/hello/options.ts +0 -31
- package/dist/templates/plugins/hello/strangerAction.ts +0 -20
- package/dist/templates/plugins/hello/types.ts +0 -13
- package/dist/templates/public/getdotenv.config.json +0 -9
- package/dist/templates/public/getdotenv.config.yaml +0 -7
- package/dist/templates/strangerAction.ts +0 -20
- package/dist/templates/ts/getdotenv.config.ts +0 -28
- package/dist/templates/types.ts +0 -13
- package/dist/templates/yaml/local/getdotenv.config.local.yaml +0 -7
- package/dist/templates/yaml/public/getdotenv.config.yaml +0 -7
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import { packageDirectory } from 'package-directory';
|
|
3
|
+
import path, { join, extname } from 'path';
|
|
4
|
+
import { fileURLToPath, pathToFileURL } from 'url';
|
|
5
|
+
import YAML from 'yaml';
|
|
6
|
+
import { z } from 'zod';
|
|
7
|
+
import { l as loadModuleDefault } from './loadModuleDefault-Dj8B3Stt.mjs';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Zod schemas for programmatic GetDotenv options.
|
|
11
|
+
*
|
|
12
|
+
* Canonical source of truth for options shape. Public types are derived
|
|
13
|
+
* from these schemas (see consumers via z.output\<\>).
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* Minimal process env representation used by options and helpers.
|
|
17
|
+
* Values may be `undefined` to indicate "unset".
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* Schema for an env-like record.
|
|
21
|
+
*
|
|
22
|
+
* Keys are environment variable names and values are either strings or `undefined`
|
|
23
|
+
* (to represent “unset”).
|
|
24
|
+
*
|
|
25
|
+
* @public
|
|
26
|
+
*/
|
|
27
|
+
const processEnvSchema = z.record(z.string(), z.string().optional());
|
|
28
|
+
// RAW: all fields optional — undefined means "inherit" from lower layers.
|
|
29
|
+
/**
|
|
30
|
+
* Programmatic options schema (raw).
|
|
31
|
+
*
|
|
32
|
+
* This schema is the canonical runtime source of truth for the `getDotenv()` programmatic API.
|
|
33
|
+
* All fields are optional; `undefined` generally means “inherit default/lower layer”.
|
|
34
|
+
*
|
|
35
|
+
* @public
|
|
36
|
+
*/
|
|
37
|
+
const getDotenvOptionsSchemaRaw = z.object({
|
|
38
|
+
/** Default environment name when `env` is not provided. */
|
|
39
|
+
defaultEnv: z.string().optional(),
|
|
40
|
+
/** Base dotenv filename token (default `.env`). */
|
|
41
|
+
dotenvToken: z.string().optional(),
|
|
42
|
+
/** Path to a dynamic variables module (JS/TS) to load and apply. */
|
|
43
|
+
dynamicPath: z.string().optional(),
|
|
44
|
+
/** Dynamic map is intentionally wide for now; refine once sources are normalized. */
|
|
45
|
+
dynamic: z.record(z.string(), z.unknown()).optional(),
|
|
46
|
+
/** Selected environment name for this invocation (for env-scoped files and overlays). */
|
|
47
|
+
env: z.string().optional(),
|
|
48
|
+
/** When true, skip applying dynamic variables. */
|
|
49
|
+
excludeDynamic: z.boolean().optional(),
|
|
50
|
+
/** When true, skip environment-scoped dotenv files. */
|
|
51
|
+
excludeEnv: z.boolean().optional(),
|
|
52
|
+
/** When true, skip global dotenv files. */
|
|
53
|
+
excludeGlobal: z.boolean().optional(),
|
|
54
|
+
/** When true, skip private dotenv files. */
|
|
55
|
+
excludePrivate: z.boolean().optional(),
|
|
56
|
+
/** When true, skip public dotenv files. */
|
|
57
|
+
excludePublic: z.boolean().optional(),
|
|
58
|
+
/** When true, merge the final composed environment into `process.env`. */
|
|
59
|
+
loadProcess: z.boolean().optional(),
|
|
60
|
+
/** When true, log the final environment map via `logger`. */
|
|
61
|
+
log: z.boolean().optional(),
|
|
62
|
+
/** Logger used when `log` is enabled (console-compatible). */
|
|
63
|
+
logger: z.unknown().default(console),
|
|
64
|
+
/** Optional output dotenv file path to write after composition. */
|
|
65
|
+
outputPath: z.string().optional(),
|
|
66
|
+
/** Dotenv search paths (ordered). */
|
|
67
|
+
paths: z.array(z.string()).optional(),
|
|
68
|
+
/** Private token suffix for private dotenv files (default `local`). */
|
|
69
|
+
privateToken: z.string().optional(),
|
|
70
|
+
/** Explicit variables to overlay onto the composed dotenv map. */
|
|
71
|
+
vars: processEnvSchema.optional(),
|
|
72
|
+
});
|
|
73
|
+
/**
|
|
74
|
+
* Resolved programmatic options schema (post-inheritance).
|
|
75
|
+
* For now, this mirrors the RAW schema; future stages may materialize defaults
|
|
76
|
+
* and narrow shapes as resolution is wired into the host.
|
|
77
|
+
*/
|
|
78
|
+
/**
|
|
79
|
+
* Programmatic options schema (resolved).
|
|
80
|
+
*
|
|
81
|
+
* Today this mirrors {@link getDotenvOptionsSchemaRaw}, but is kept as a distinct export
|
|
82
|
+
* so future resolution steps can narrow or materialize defaults without breaking the API.
|
|
83
|
+
*
|
|
84
|
+
* @public
|
|
85
|
+
*/
|
|
86
|
+
const getDotenvOptionsSchemaResolved = getDotenvOptionsSchemaRaw;
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Zod schemas for CLI-facing GetDotenv options (raw/resolved stubs).
|
|
90
|
+
*
|
|
91
|
+
* RAW allows stringly inputs (paths/vars + splitters). RESOLVED will later
|
|
92
|
+
* reflect normalized types (paths: string[], vars: ProcessEnv), applied in the
|
|
93
|
+
* CLI resolution pipeline.
|
|
94
|
+
*/
|
|
95
|
+
/**
|
|
96
|
+
* CLI options schema (raw).
|
|
97
|
+
*
|
|
98
|
+
* Extends the programmatic options schema with CLI-only flags and stringly inputs
|
|
99
|
+
* which are normalized later by the host resolution pipeline.
|
|
100
|
+
*
|
|
101
|
+
* @public
|
|
102
|
+
*/
|
|
103
|
+
const getDotenvCliOptionsSchemaRaw = getDotenvOptionsSchemaRaw.extend({
|
|
104
|
+
// CLI-specific fields (stringly inputs before preprocessing)
|
|
105
|
+
/** Enable verbose debug output (host-specific). */
|
|
106
|
+
debug: z.boolean().optional(),
|
|
107
|
+
/** Fail on validation errors (schema/requiredKeys). */
|
|
108
|
+
strict: z.boolean().optional(),
|
|
109
|
+
/** Capture child process stdio (useful for CI/tests). */
|
|
110
|
+
capture: z.boolean().optional(),
|
|
111
|
+
/** Emit child env diagnostics (boolean or selected keys). */
|
|
112
|
+
trace: z.union([z.boolean(), z.array(z.string())]).optional(),
|
|
113
|
+
/** Enable presentation-time redaction in trace/log output. */
|
|
114
|
+
redact: z.boolean().optional(),
|
|
115
|
+
/** Enable entropy warnings in trace/log output. */
|
|
116
|
+
warnEntropy: z.boolean().optional(),
|
|
117
|
+
/** Entropy threshold (bits/char) for warnings. */
|
|
118
|
+
entropyThreshold: z.number().optional(),
|
|
119
|
+
/** Minimum value length to consider for entropy warnings. */
|
|
120
|
+
entropyMinLength: z.number().optional(),
|
|
121
|
+
/** Regex patterns (strings) to suppress entropy warnings by key. */
|
|
122
|
+
entropyWhitelist: z.array(z.string()).optional(),
|
|
123
|
+
/** Additional key-match patterns (strings) for redaction. */
|
|
124
|
+
redactPatterns: z.array(z.string()).optional(),
|
|
125
|
+
/** Dotenv search paths provided as a single delimited string. */
|
|
126
|
+
paths: z.string().optional(),
|
|
127
|
+
/** Delimiter string used to split `paths`. */
|
|
128
|
+
pathsDelimiter: z.string().optional(),
|
|
129
|
+
/** Regex pattern used to split `paths` (takes precedence over delimiter). */
|
|
130
|
+
pathsDelimiterPattern: z.string().optional(),
|
|
131
|
+
/** Scripts table in a permissive shape at parse time (validated elsewhere). */
|
|
132
|
+
scripts: z.record(z.string(), z.unknown()).optional(),
|
|
133
|
+
/** Shell selection (`false` for shell-off, string for explicit shell). */
|
|
134
|
+
shell: z.union([z.boolean(), z.string()]).optional(),
|
|
135
|
+
/** Extra variables expressed as a single delimited string of assignments. */
|
|
136
|
+
vars: z.string().optional(),
|
|
137
|
+
/** Assignment operator used when parsing `vars`. */
|
|
138
|
+
varsAssignor: z.string().optional(),
|
|
139
|
+
/** Regex pattern used as the assignment operator for `vars` parsing. */
|
|
140
|
+
varsAssignorPattern: z.string().optional(),
|
|
141
|
+
/** Delimiter string used to split `vars`. */
|
|
142
|
+
varsDelimiter: z.string().optional(),
|
|
143
|
+
/** Regex pattern used to split `vars` (takes precedence over delimiter). */
|
|
144
|
+
varsDelimiterPattern: z.string().optional(),
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
const visibilityMap = z.record(z.string(), z.boolean());
|
|
148
|
+
/**
|
|
149
|
+
* Zod schemas for configuration files discovered by the new loader.
|
|
150
|
+
*
|
|
151
|
+
* Notes:
|
|
152
|
+
* - RAW: all fields optional; only allowed top-level keys are:
|
|
153
|
+
* - rootOptionDefaults, rootOptionVisibility
|
|
154
|
+
* - scripts, vars, envVars
|
|
155
|
+
* - dynamic (JS/TS only), schema (JS/TS only)
|
|
156
|
+
* - plugins, requiredKeys
|
|
157
|
+
* - RESOLVED: mirrors RAW (no path normalization).
|
|
158
|
+
* - For JSON/YAML configs, the loader rejects "dynamic" and "schema" (JS/TS only).
|
|
159
|
+
*/
|
|
160
|
+
// String-only env value map
|
|
161
|
+
const stringMap = z.record(z.string(), z.string());
|
|
162
|
+
const envStringMap = z.record(z.string(), stringMap);
|
|
163
|
+
/**
|
|
164
|
+
* Raw configuration schema for get‑dotenv config files (JSON/YAML/JS/TS).
|
|
165
|
+
* Validates allowed top‑level keys without performing path normalization.
|
|
166
|
+
*/
|
|
167
|
+
/**
|
|
168
|
+
* Config schema for discovered get-dotenv configuration documents (raw).
|
|
169
|
+
*
|
|
170
|
+
* This schema validates the allowed top-level keys for configuration files.
|
|
171
|
+
* It does not normalize paths or coerce types beyond Zod’s parsing.
|
|
172
|
+
*
|
|
173
|
+
* @public
|
|
174
|
+
*/
|
|
175
|
+
const getDotenvConfigSchemaRaw = z.object({
|
|
176
|
+
/** Root option defaults applied by the host (CLI-like, collapsed families). */
|
|
177
|
+
rootOptionDefaults: getDotenvCliOptionsSchemaRaw.optional(),
|
|
178
|
+
/** Help-time visibility map for root flags (false hides). */
|
|
179
|
+
rootOptionVisibility: visibilityMap.optional(),
|
|
180
|
+
/** Scripts table used by cmd/batch resolution (validation intentionally permissive here). */
|
|
181
|
+
scripts: z.record(z.string(), z.unknown()).optional(),
|
|
182
|
+
/** Keys required to be present in the final composed environment. */
|
|
183
|
+
requiredKeys: z.array(z.string()).optional(),
|
|
184
|
+
/** Validation schema (JS/TS only; JSON/YAML loader rejects). */
|
|
185
|
+
schema: z.unknown().optional(), // JS/TS-only; loader rejects in JSON/YAML
|
|
186
|
+
/** Public global variables (string-only). */
|
|
187
|
+
vars: stringMap.optional(), // public, global
|
|
188
|
+
/** Public per-environment variables (string-only). */
|
|
189
|
+
envVars: envStringMap.optional(), // public, per-env
|
|
190
|
+
// Dynamic in config (JS/TS only). JSON/YAML loader will reject if set.
|
|
191
|
+
/** Dynamic variable definitions (JS/TS only). */
|
|
192
|
+
dynamic: z.unknown().optional(),
|
|
193
|
+
// Per-plugin config bag; validated by plugins/host when used.
|
|
194
|
+
/** Per-plugin config slices keyed by realized mount path (for example, `aws/whoami`). */
|
|
195
|
+
plugins: z.record(z.string(), z.unknown()).optional(),
|
|
196
|
+
});
|
|
197
|
+
/**
|
|
198
|
+
* Resolved configuration schema which preserves the raw shape while narrowing
|
|
199
|
+
* the output to {@link GetDotenvConfigResolved}. Consumers get a strongly typed
|
|
200
|
+
* object, while the underlying validation remains Zod‑driven.
|
|
201
|
+
*/
|
|
202
|
+
const getDotenvConfigSchemaResolved = getDotenvConfigSchemaRaw.transform((raw) => raw);
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* @packageDocumentation
|
|
206
|
+
* Configuration discovery and loading for get‑dotenv. Discovers config files
|
|
207
|
+
* in the packaged root and project root, loads JSON/YAML/JS/TS documents, and
|
|
208
|
+
* validates them against Zod schemas.
|
|
209
|
+
*/
|
|
210
|
+
// Discovery candidates (first match wins per scope/privacy).
|
|
211
|
+
// Order preserves historical JSON/YAML precedence; JS/TS added afterwards.
|
|
212
|
+
const PUBLIC_FILENAMES = [
|
|
213
|
+
'getdotenv.config.json',
|
|
214
|
+
'getdotenv.config.yaml',
|
|
215
|
+
'getdotenv.config.yml',
|
|
216
|
+
'getdotenv.config.js',
|
|
217
|
+
'getdotenv.config.mjs',
|
|
218
|
+
'getdotenv.config.cjs',
|
|
219
|
+
'getdotenv.config.ts',
|
|
220
|
+
'getdotenv.config.mts',
|
|
221
|
+
'getdotenv.config.cts',
|
|
222
|
+
];
|
|
223
|
+
const LOCAL_FILENAMES = [
|
|
224
|
+
'getdotenv.config.local.json',
|
|
225
|
+
'getdotenv.config.local.yaml',
|
|
226
|
+
'getdotenv.config.local.yml',
|
|
227
|
+
'getdotenv.config.local.js',
|
|
228
|
+
'getdotenv.config.local.mjs',
|
|
229
|
+
'getdotenv.config.local.cjs',
|
|
230
|
+
'getdotenv.config.local.ts',
|
|
231
|
+
'getdotenv.config.local.mts',
|
|
232
|
+
'getdotenv.config.local.cts',
|
|
233
|
+
];
|
|
234
|
+
const isYaml = (p) => ['.yaml', '.yml'].includes(extname(p).toLowerCase());
|
|
235
|
+
const isJson = (p) => extname(p).toLowerCase() === '.json';
|
|
236
|
+
const isJsOrTs = (p) => ['.js', '.mjs', '.cjs', '.ts', '.mts', '.cts'].includes(extname(p).toLowerCase());
|
|
237
|
+
/**
|
|
238
|
+
* Discover JSON/YAML config files in the packaged root and project root.
|
|
239
|
+
* Order: packaged public → project public → project local. */
|
|
240
|
+
const discoverConfigFiles = async (importMetaUrl) => {
|
|
241
|
+
const files = [];
|
|
242
|
+
// Packaged root via importMetaUrl (optional)
|
|
243
|
+
if (importMetaUrl) {
|
|
244
|
+
const fromUrl = fileURLToPath(importMetaUrl);
|
|
245
|
+
const packagedRoot = await packageDirectory({ cwd: fromUrl });
|
|
246
|
+
if (packagedRoot) {
|
|
247
|
+
for (const name of PUBLIC_FILENAMES) {
|
|
248
|
+
const p = join(packagedRoot, name);
|
|
249
|
+
if (await fs.pathExists(p)) {
|
|
250
|
+
files.push({ path: p, privacy: 'public', scope: 'packaged' });
|
|
251
|
+
break; // only one public file expected per scope
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
// By policy, packaged .local is not expected; skip even if present.
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
// Project root (from current working directory)
|
|
258
|
+
const projectRoot = await packageDirectory();
|
|
259
|
+
if (projectRoot) {
|
|
260
|
+
for (const name of PUBLIC_FILENAMES) {
|
|
261
|
+
const p = join(projectRoot, name);
|
|
262
|
+
if (await fs.pathExists(p)) {
|
|
263
|
+
files.push({ path: p, privacy: 'public', scope: 'project' });
|
|
264
|
+
break;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
for (const name of LOCAL_FILENAMES) {
|
|
268
|
+
const p = join(projectRoot, name);
|
|
269
|
+
if (await fs.pathExists(p)) {
|
|
270
|
+
files.push({ path: p, privacy: 'local', scope: 'project' });
|
|
271
|
+
break;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
return files;
|
|
276
|
+
};
|
|
277
|
+
/**
|
|
278
|
+
* Load a single config file (JSON/YAML). JS/TS is not supported in this step.
|
|
279
|
+
* Validates with Zod RAW schema, then normalizes to RESOLVED.
|
|
280
|
+
*
|
|
281
|
+
* For JSON/YAML: if a "dynamic" property is present, throws with guidance.
|
|
282
|
+
* For JS/TS: default export is loaded; "dynamic" is allowed.
|
|
283
|
+
*/
|
|
284
|
+
const loadConfigFile = async (filePath) => {
|
|
285
|
+
let raw = {};
|
|
286
|
+
try {
|
|
287
|
+
const abs = path.resolve(filePath);
|
|
288
|
+
if (isJsOrTs(abs)) {
|
|
289
|
+
// JS/TS support: load default export via shared robust pipeline.
|
|
290
|
+
const mod = await loadModuleDefault(abs, 'getdotenv-config');
|
|
291
|
+
raw = mod ?? {};
|
|
292
|
+
}
|
|
293
|
+
else {
|
|
294
|
+
const txt = await fs.readFile(abs, 'utf-8');
|
|
295
|
+
raw = isJson(abs) ? JSON.parse(txt) : isYaml(abs) ? YAML.parse(txt) : {};
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
catch (err) {
|
|
299
|
+
throw new Error(`Failed to read/parse config: ${filePath}. ${String(err)}`);
|
|
300
|
+
}
|
|
301
|
+
// Validate RAW
|
|
302
|
+
const parsed = getDotenvConfigSchemaRaw.safeParse(raw);
|
|
303
|
+
if (!parsed.success) {
|
|
304
|
+
const msgs = parsed.error.issues
|
|
305
|
+
.map((i) => `${i.path.join('.')}: ${i.message}`)
|
|
306
|
+
.join('\n');
|
|
307
|
+
throw new Error(`Invalid config ${filePath}:\n${msgs}`);
|
|
308
|
+
}
|
|
309
|
+
// Disallow dynamic and schema in JSON/YAML; allow both in JS/TS.
|
|
310
|
+
if (!isJsOrTs(filePath) &&
|
|
311
|
+
(parsed.data.dynamic !== undefined || parsed.data.schema !== undefined)) {
|
|
312
|
+
throw new Error(`Config ${filePath} specifies unsupported keys for JSON/YAML. ` +
|
|
313
|
+
`Use JS/TS config for "dynamic" or "schema".`);
|
|
314
|
+
}
|
|
315
|
+
return getDotenvConfigSchemaResolved.parse(parsed.data);
|
|
316
|
+
};
|
|
317
|
+
/**
|
|
318
|
+
* Discover and load configs into resolved shapes, ordered by scope/privacy.
|
|
319
|
+
* JSON/YAML/JS/TS supported; first match per scope/privacy applies.
|
|
320
|
+
*/
|
|
321
|
+
const resolveGetDotenvConfigSources = async (importMetaUrl) => {
|
|
322
|
+
const discovered = await discoverConfigFiles(importMetaUrl);
|
|
323
|
+
const result = {};
|
|
324
|
+
for (const f of discovered) {
|
|
325
|
+
const cfg = await loadConfigFile(f.path);
|
|
326
|
+
if (f.scope === 'packaged') {
|
|
327
|
+
// packaged public only
|
|
328
|
+
result.packaged = cfg;
|
|
329
|
+
}
|
|
330
|
+
else {
|
|
331
|
+
result.project ??= {};
|
|
332
|
+
if (f.privacy === 'public')
|
|
333
|
+
result.project.public = cfg;
|
|
334
|
+
else
|
|
335
|
+
result.project.local = cfg;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
return result;
|
|
339
|
+
};
|
|
340
|
+
/**
|
|
341
|
+
* Utility primarily for tests: create a file: URL string from a path.
|
|
342
|
+
* @param p - File path.
|
|
343
|
+
*/
|
|
344
|
+
const toFileUrl = (p) => pathToFileURL(path.resolve(p)).toString();
|
|
345
|
+
|
|
346
|
+
export { discoverConfigFiles as d, getDotenvOptionsSchemaResolved as g, loadConfigFile as l, resolveGetDotenvConfigSources as r, toFileUrl as t };
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import { l as loadModuleDefault } from './loadModuleDefault-Dj8B3Stt.mjs';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Dotenv expansion utilities.
|
|
6
|
+
*
|
|
7
|
+
* This module implements recursive expansion of environment-variable
|
|
8
|
+
* references in strings and records. It supports both whitespace and
|
|
9
|
+
* bracket syntaxes with optional defaults:
|
|
10
|
+
*
|
|
11
|
+
* - Whitespace: `$VAR[:default]`
|
|
12
|
+
* - Bracketed: `${VAR[:default]}`
|
|
13
|
+
*
|
|
14
|
+
* Escaped dollar signs (`\$`) are preserved.
|
|
15
|
+
* Unknown variables resolve to empty string unless a default is provided.
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* Like String.prototype.search but returns the last index.
|
|
19
|
+
* @internal
|
|
20
|
+
*/
|
|
21
|
+
const searchLast = (str, rgx) => {
|
|
22
|
+
const matches = Array.from(str.matchAll(rgx));
|
|
23
|
+
return matches.length > 0 ? (matches.slice(-1)[0]?.index ?? -1) : -1;
|
|
24
|
+
};
|
|
25
|
+
const replaceMatch = (value, match, ref) => {
|
|
26
|
+
/**
|
|
27
|
+
* @internal
|
|
28
|
+
*/
|
|
29
|
+
const group = match[0];
|
|
30
|
+
const key = match[1];
|
|
31
|
+
const defaultValue = match[2];
|
|
32
|
+
if (!key)
|
|
33
|
+
return value;
|
|
34
|
+
const replacement = value.replace(group, ref[key] ?? defaultValue ?? '');
|
|
35
|
+
return interpolate(replacement, ref);
|
|
36
|
+
};
|
|
37
|
+
const interpolate = (value = '', ref = {}) => {
|
|
38
|
+
/**
|
|
39
|
+
* @internal
|
|
40
|
+
*/
|
|
41
|
+
// if value is falsy, return it as is
|
|
42
|
+
if (!value)
|
|
43
|
+
return value;
|
|
44
|
+
// get position of last unescaped dollar sign
|
|
45
|
+
const lastUnescapedDollarSignIndex = searchLast(value, /(?!(?<=\\))\$/g);
|
|
46
|
+
// return value if none found
|
|
47
|
+
if (lastUnescapedDollarSignIndex === -1)
|
|
48
|
+
return value;
|
|
49
|
+
// evaluate the value tail
|
|
50
|
+
const tail = value.slice(lastUnescapedDollarSignIndex);
|
|
51
|
+
// find whitespace pattern: $KEY:DEFAULT
|
|
52
|
+
const whitespacePattern = /^\$([\w]+)(?::([^\s]*))?/;
|
|
53
|
+
const whitespaceMatch = whitespacePattern.exec(tail);
|
|
54
|
+
if (whitespaceMatch != null)
|
|
55
|
+
return replaceMatch(value, whitespaceMatch, ref);
|
|
56
|
+
else {
|
|
57
|
+
// find bracket pattern: ${KEY:DEFAULT}
|
|
58
|
+
const bracketPattern = /^\${([\w]+)(?::([^}]*))?}/;
|
|
59
|
+
const bracketMatch = bracketPattern.exec(tail);
|
|
60
|
+
if (bracketMatch != null)
|
|
61
|
+
return replaceMatch(value, bracketMatch, ref);
|
|
62
|
+
}
|
|
63
|
+
return value;
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* Recursively expands environment variables in a string. Variables may be
|
|
67
|
+
* presented with optional default as `$VAR[:default]` or `${VAR[:default]}`.
|
|
68
|
+
* Unknown variables will expand to an empty string.
|
|
69
|
+
*
|
|
70
|
+
* @param value - The string to expand.
|
|
71
|
+
* @param ref - The reference object to use for variable expansion.
|
|
72
|
+
* @returns The expanded string.
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```ts
|
|
76
|
+
* process.env.FOO = 'bar';
|
|
77
|
+
* dotenvExpand('Hello $FOO'); // "Hello bar"
|
|
78
|
+
* dotenvExpand('Hello $BAZ:world'); // "Hello world"
|
|
79
|
+
* ```
|
|
80
|
+
*
|
|
81
|
+
* @remarks
|
|
82
|
+
* The expansion is recursive. If a referenced variable itself contains
|
|
83
|
+
* references, those will also be expanded until a stable value is reached.
|
|
84
|
+
* Escaped references (e.g. `\$FOO`) are preserved as literals.
|
|
85
|
+
*/
|
|
86
|
+
const dotenvExpand = (value, ref = process.env) => {
|
|
87
|
+
const result = interpolate(value, ref);
|
|
88
|
+
return result ? result.replace(/\\\$/g, '$') : undefined;
|
|
89
|
+
};
|
|
90
|
+
/**
|
|
91
|
+
* Recursively expands environment variables in the values of a JSON object.
|
|
92
|
+
* Variables may be presented with optional default as `$VAR[:default]` or
|
|
93
|
+
* `${VAR[:default]}`. Unknown variables will expand to an empty string.
|
|
94
|
+
*
|
|
95
|
+
* @param values - The values object to expand.
|
|
96
|
+
* @param options - Expansion options.
|
|
97
|
+
* @returns The value object with expanded string values.
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* ```ts
|
|
101
|
+
* process.env.FOO = 'bar';
|
|
102
|
+
* dotenvExpandAll({ A: '$FOO', B: 'x${FOO}y' });
|
|
103
|
+
* // => { A: "bar", B: "xbary" }
|
|
104
|
+
* ```
|
|
105
|
+
*
|
|
106
|
+
* @remarks
|
|
107
|
+
* Options:
|
|
108
|
+
* - ref: The reference object to use for expansion (defaults to process.env).
|
|
109
|
+
* - progressive: Whether to progressively add expanded values to the set of
|
|
110
|
+
* reference keys.
|
|
111
|
+
*
|
|
112
|
+
* When `progressive` is true, each expanded key becomes available for
|
|
113
|
+
* subsequent expansions in the same object (left-to-right by object key order).
|
|
114
|
+
*/
|
|
115
|
+
function dotenvExpandAll(values, options = {}) {
|
|
116
|
+
const { ref = process.env, progressive = false, } = options;
|
|
117
|
+
const out = Object.keys(values).reduce((acc, key) => {
|
|
118
|
+
acc[key] = dotenvExpand(values[key], {
|
|
119
|
+
...ref,
|
|
120
|
+
...(progressive ? acc : {}),
|
|
121
|
+
});
|
|
122
|
+
return acc;
|
|
123
|
+
}, {});
|
|
124
|
+
// Key-preserving return with a permissive index signature to allow later additions.
|
|
125
|
+
return out;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Recursively expands environment variables in a string using `process.env` as
|
|
129
|
+
* the expansion reference. Variables may be presented with optional default as
|
|
130
|
+
* `$VAR[:default]` or `${VAR[:default]}`. Unknown variables will expand to an
|
|
131
|
+
* empty string.
|
|
132
|
+
*
|
|
133
|
+
* @param value - The string to expand.
|
|
134
|
+
* @returns The expanded string.
|
|
135
|
+
*
|
|
136
|
+
* @example
|
|
137
|
+
* ```ts
|
|
138
|
+
* process.env.FOO = 'bar';
|
|
139
|
+
* dotenvExpandFromProcessEnv('Hello $FOO'); // "Hello bar"
|
|
140
|
+
* ```
|
|
141
|
+
*/
|
|
142
|
+
const dotenvExpandFromProcessEnv = (value) => dotenvExpand(value, process.env);
|
|
143
|
+
|
|
144
|
+
/** src/env/dynamic.ts
|
|
145
|
+
* Helpers for applying and loading dynamic variables (JS/TS).
|
|
146
|
+
*
|
|
147
|
+
* Requirements addressed:
|
|
148
|
+
* - Single service to apply a dynamic map progressively.
|
|
149
|
+
* - Single service to load a JS/TS dynamic module with robust fallbacks (util/loadModuleDefault).
|
|
150
|
+
* - Unify error messaging so callers show consistent guidance.
|
|
151
|
+
*/
|
|
152
|
+
/**
|
|
153
|
+
* Apply a dynamic map to the target progressively.
|
|
154
|
+
* - Functions receive (target, env) and may return string | undefined.
|
|
155
|
+
* - Literals are assigned directly (including undefined).
|
|
156
|
+
*
|
|
157
|
+
* @param target - Mutable target environment to assign into.
|
|
158
|
+
* @param map - Dynamic map to apply (functions and/or literal values).
|
|
159
|
+
* @param env - Selected environment name (if any) passed through to dynamic functions.
|
|
160
|
+
* @returns Nothing.
|
|
161
|
+
*/
|
|
162
|
+
function applyDynamicMap(target, map, env) {
|
|
163
|
+
if (!map)
|
|
164
|
+
return;
|
|
165
|
+
for (const key of Object.keys(map)) {
|
|
166
|
+
const val = typeof map[key] === 'function'
|
|
167
|
+
? map[key](target, env)
|
|
168
|
+
: map[key];
|
|
169
|
+
Object.assign(target, { [key]: val });
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Load a default-export dynamic map from a JS/TS file and apply it.
|
|
174
|
+
* Uses util/loadModuleDefault for robust TS handling (direct import, esbuild,
|
|
175
|
+
* typescript.transpile fallback).
|
|
176
|
+
*
|
|
177
|
+
* Error behavior:
|
|
178
|
+
* - On failure to load/compile/evaluate the module, throws a unified message:
|
|
179
|
+
* "Unable to load dynamic TypeScript file: <absPath>. Install 'esbuild'..."
|
|
180
|
+
*
|
|
181
|
+
* @param target - Mutable target environment to assign into.
|
|
182
|
+
* @param absPath - Absolute path to the dynamic module file.
|
|
183
|
+
* @param env - Selected environment name (if any).
|
|
184
|
+
* @param cacheDirName - Cache subdirectory under `.tsbuild/` for compiled artifacts.
|
|
185
|
+
* @returns A `Promise\<void\>` which resolves after the module (if present) has been applied.
|
|
186
|
+
*/
|
|
187
|
+
async function loadAndApplyDynamic(target, absPath, env, cacheDirName) {
|
|
188
|
+
if (!(await fs.exists(absPath)))
|
|
189
|
+
return;
|
|
190
|
+
let dyn;
|
|
191
|
+
try {
|
|
192
|
+
dyn = await loadModuleDefault(absPath, cacheDirName);
|
|
193
|
+
}
|
|
194
|
+
catch {
|
|
195
|
+
// Preserve legacy/clear guidance used by tests and docs.
|
|
196
|
+
throw new Error(`Unable to load dynamic TypeScript file: ${absPath}. ` +
|
|
197
|
+
`Install 'esbuild' (devDependency) to enable TypeScript dynamic modules.`);
|
|
198
|
+
}
|
|
199
|
+
applyDynamicMap(target, dyn, env);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const applyKv = (current, kv) => {
|
|
203
|
+
if (!kv || Object.keys(kv).length === 0)
|
|
204
|
+
return current;
|
|
205
|
+
const expanded = dotenvExpandAll(kv, { ref: current, progressive: true });
|
|
206
|
+
return { ...current, ...expanded };
|
|
207
|
+
};
|
|
208
|
+
const applyConfigSlice = (current, cfg, env) => {
|
|
209
|
+
if (!cfg)
|
|
210
|
+
return current;
|
|
211
|
+
// kind axis: global then env (env overrides global)
|
|
212
|
+
const afterGlobal = applyKv(current, cfg.vars);
|
|
213
|
+
const envKv = env && cfg.envVars ? cfg.envVars[env] : undefined;
|
|
214
|
+
return applyKv(afterGlobal, envKv);
|
|
215
|
+
};
|
|
216
|
+
function overlayEnv(args) {
|
|
217
|
+
const { base, env, configs } = args;
|
|
218
|
+
let current = { ...base };
|
|
219
|
+
// Source: packaged (public -> local)
|
|
220
|
+
current = applyConfigSlice(current, configs.packaged, env);
|
|
221
|
+
// Packaged "local" is not expected by policy; if present, honor it.
|
|
222
|
+
// We do not have a separate object for packaged.local in sources, keep as-is.
|
|
223
|
+
// Source: project (public -> local)
|
|
224
|
+
current = applyConfigSlice(current, configs.project?.public, env);
|
|
225
|
+
current = applyConfigSlice(current, configs.project?.local, env);
|
|
226
|
+
// Programmatic explicit vars (top of static tier)
|
|
227
|
+
if ('programmaticVars' in args) {
|
|
228
|
+
const toApply = Object.fromEntries(Object.entries(args.programmaticVars).filter(([_k, v]) => typeof v === 'string'));
|
|
229
|
+
current = applyKv(current, toApply);
|
|
230
|
+
}
|
|
231
|
+
return current;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
export { dotenvExpandAll as a, dotenvExpandFromProcessEnv as b, applyDynamicMap as c, dotenvExpand as d, loadAndApplyDynamic as l, overlayEnv as o };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { l as loadSharedConfigFiles } from './index-CeCufHlm.mjs';
|
|
2
|
+
|
|
3
|
+
const mergeConfigFiles = (...files) => {
|
|
4
|
+
const merged = {};
|
|
5
|
+
for (const file of files) {
|
|
6
|
+
for (const [key, values] of Object.entries(file)) {
|
|
7
|
+
if (merged[key] !== undefined) {
|
|
8
|
+
Object.assign(merged[key], values);
|
|
9
|
+
}
|
|
10
|
+
else {
|
|
11
|
+
merged[key] = values;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return merged;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const parseKnownFiles = async (init) => {
|
|
19
|
+
const parsedFiles = await loadSharedConfigFiles(init);
|
|
20
|
+
return mergeConfigFiles(parsedFiles.configFile, parsedFiles.credentialsFile);
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export { parseKnownFiles as p };
|