@karmaniverous/get-dotenv 5.0.0-1 → 5.0.0
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/README.md +50 -64
- package/dist/index.cjs +11 -4
- package/dist/index.mjs +11 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,14 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
## Requirements
|
|
4
|
-
|
|
5
|
-
- Node.js >= 20 (this repository pins 22.19.0 for CI/reproducibility)
|
|
1
|
+
> **_Load, expand, and compose environment variables from a deterministic dotenv cascade, then execute commands under that context. Use `get-dotenv` as a library, a CLI, or a plugin-first host to build dotenv-aware tooling with cross‑platform shell control, CI‑friendly capture, and clear diagnostics._**
|
|
6
2
|
|
|
7
|
-
|
|
8
|
-
Generated API documentation is hosted at:
|
|
9
|
-
- https://docs.karmanivero.us/get-dotenv
|
|
3
|
+
# get-dotenv
|
|
10
4
|
|
|
11
|
-
|
|
5
|
+
[](https://www.npmjs.com/package/@karmaniverous/get-dotenv)
|
|
6
|
+
 <!-- TYPEDOC_EXCLUDE -->
|
|
7
|
+
[](https://docs.karmanivero.us/get-dotenv)
|
|
8
|
+
[](https://github.com/karmaniverous/get-dotenv/tree/main/CHANGELOG.md)<!-- /TYPEDOC_EXCLUDE -->
|
|
9
|
+
[](https://github.com/karmaniverous/get-dotenv/tree/main/LICENSE.md)
|
|
12
10
|
|
|
13
11
|
Load environment variables with a cascade of environment-aware dotenv files. You can:
|
|
14
12
|
|
|
@@ -44,6 +42,18 @@ You can always use `getdotenv` directly on the command line, but its REAL power
|
|
|
44
42
|
|
|
45
43
|
When you plug your own [`commander`](https://www.npmjs.com/package/commander) CLI commands into the `getdotenv` base, they will execute within all of the environmental context created above!
|
|
46
44
|
|
|
45
|
+
## Requirements
|
|
46
|
+
|
|
47
|
+
- Node.js >= 20 (this repository pins 22.19.0 for CI/reproducibility)
|
|
48
|
+
|
|
49
|
+
## API Reference
|
|
50
|
+
|
|
51
|
+
Generated API documentation is hosted at:
|
|
52
|
+
|
|
53
|
+
- https://docs.karmanivero.us/get-dotenv
|
|
54
|
+
|
|
55
|
+
The site is built with TypeDoc from the source code in this repository.
|
|
56
|
+
|
|
47
57
|
## Testing
|
|
48
58
|
|
|
49
59
|
This project uses Vitest with the V8 coverage provider. Run:
|
|
@@ -60,8 +70,7 @@ npm install @karmaniverous/get-dotenv
|
|
|
60
70
|
|
|
61
71
|
## Scaffold
|
|
62
72
|
|
|
63
|
-
You can scaffold config files and a host-based CLI skeleton using the built-in
|
|
64
|
-
init command. Templates are shipped with the package and copied verbatim.
|
|
73
|
+
You can scaffold config files and a host-based CLI skeleton using the built-in init command. Templates are shipped with the package and copied verbatim.
|
|
65
74
|
|
|
66
75
|
Examples:
|
|
67
76
|
|
|
@@ -83,20 +92,13 @@ npx getdotenv init ./apps/toolbox \
|
|
|
83
92
|
|
|
84
93
|
Collision flow (when a destination file exists):
|
|
85
94
|
|
|
86
|
-
- Interactive prompt: [o]verwrite, [e]xample, [s]kip, or their “all” variants
|
|
87
|
-
|
|
88
|
-
-
|
|
89
|
-
- Treated as `--yes` (Skip All) unless `--force` is provided (Overwrite All).
|
|
90
|
-
- Considered non-interactive when stdin or stdout is not a TTY OR when a
|
|
91
|
-
CI-like environment variable is present (`CI`, `GITHUB_ACTIONS`,
|
|
92
|
-
`BUILDKITE`, `TEAMCITY_VERSION`, `TF_BUILD`).
|
|
93
|
-
- Precedence:
|
|
94
|
-
- `--force` > `--yes` > auto-detect (non-interactive => Skip All).
|
|
95
|
+
- Interactive prompt: [o]verwrite, [e]xample, [s]kip, or their “all” variants [O]/[E]/[S].
|
|
96
|
+
- Non-interactive detection: Treated as `--yes` (Skip All) unless `--force` is provided (Overwrite All). Considered non-interactive when stdin or stdout is not a TTY OR when a CI-like environment variable is present (`CI`, `GITHUB_ACTIONS`, `BUILDKITE`, `TEAMCITY_VERSION`, `TF_BUILD`).
|
|
97
|
+
- Precedence: `--force` > `--yes` > auto-detect (non-interactive => Skip All).
|
|
95
98
|
- Options overview:
|
|
96
99
|
- `--config-format <json|yaml|js|ts>`
|
|
97
100
|
- `--with-local` to generate `.local` alongside public config (JSON/YAML)
|
|
98
|
-
- `--cli-name <string>` for token substitution (`__CLI_NAME__`) in the CLI
|
|
99
|
-
skeleton
|
|
101
|
+
- `--cli-name <string>` for token substitution (`__CLI_NAME__`) in the CLI skeleton
|
|
100
102
|
- `--force` to overwrite all; `--yes` to skip all
|
|
101
103
|
|
|
102
104
|
Notes:
|
|
@@ -106,14 +108,15 @@ Notes:
|
|
|
106
108
|
|
|
107
109
|
## Usage
|
|
108
110
|
|
|
109
|
-
|
|
111
|
+
```js
|
|
110
112
|
import { getDotenv } from '@karmaniverous/get-dotenv';
|
|
111
113
|
|
|
112
|
-
const dotenv = await getDotenv(options)
|
|
114
|
+
const dotenv = await getDotenv(options);
|
|
115
|
+
```
|
|
113
116
|
|
|
114
117
|
Options can be passed programmatically or set in a `getdotenv.config.json` file in your project root directory. The same file also sets default options for the `getdotenv` CLI or any child CLI you spawn from it.
|
|
115
118
|
|
|
116
|
-
See the [child CLI example repo](https://github.com/karmaniverous/get-dotenv-child#configuration) for an
|
|
119
|
+
See the [child CLI example repo](https://github.com/karmaniverous/get-dotenv-child#configuration) for an extensive discussion of the various config options and how & where to set them.
|
|
117
120
|
|
|
118
121
|
## Dynamic Processing
|
|
119
122
|
|
|
@@ -126,10 +129,10 @@ export default {
|
|
|
126
129
|
SOME_DYNAMIC_VARIABLE: (dotenv) => someLogic(dotenv),
|
|
127
130
|
ANOTHER_DYNAMIC_VARIABLE: (dotenv) =>
|
|
128
131
|
someOtherLogic(dotenv.SOME_DYNAMIC_VARIABLE),
|
|
129
|
-
ONE_MORE_TIME: ({
|
|
130
|
-
|
|
132
|
+
ONE_MORE_TIME: ({ DESTRUCTURED_VARIABLE, ANOTHER_DYNAMIC_VARIABLE }) =>
|
|
133
|
+
DESTRUCTURED_VARIABLE + ANOTHER_DYNAMIC_VARIABLE,
|
|
131
134
|
};
|
|
132
|
-
|
|
135
|
+
```
|
|
133
136
|
|
|
134
137
|
If the value corresponding to a key is a function, it will be executed with the current state of `dotenv` as its single argument and the result applied back to the `dotenv` object. Otherwise, the value will just be applied back to `dotenv`. (Although if you're going to do that then you might as well just create a public global variable in the first place.)
|
|
135
138
|
|
|
@@ -146,9 +149,7 @@ export default {
|
|
|
146
149
|
};
|
|
147
150
|
```
|
|
148
151
|
|
|
149
|
-
If `esbuild` is not installed and a direct import fails, get-dotenv attempts a
|
|
150
|
-
simple fallback for single-file `.ts` modules without imports; otherwise it will
|
|
151
|
-
throw with clear guidance to install `esbuild`.
|
|
152
|
+
If `esbuild` is not installed and a direct import fails, get-dotenv attempts a simple fallback for single-file `.ts` modules without imports; otherwise it will throw with clear guidance to install `esbuild`.
|
|
152
153
|
|
|
153
154
|
Programmatic users can skip files entirely and pass dynamic variables directly:
|
|
154
155
|
|
|
@@ -175,8 +176,7 @@ Notes:
|
|
|
175
176
|
- Install `esbuild` (`npm i -D esbuild`).
|
|
176
177
|
|
|
177
178
|
- “Unable to load dynamic TypeScript file …”:
|
|
178
|
-
- Install `esbuild`. A simple transpile fallback exists only for trivial
|
|
179
|
-
single-file modules; any imports in `dynamic.ts` require `esbuild` bundling.
|
|
179
|
+
- Install `esbuild`. A simple transpile fallback exists only for trivial single-file modules; any imports in `dynamic.ts` require `esbuild` bundling.
|
|
180
180
|
|
|
181
181
|
## Command Line Interface
|
|
182
182
|
|
|
@@ -218,7 +218,8 @@ You can also use `getdotenv` from the command line:
|
|
|
218
218
|
# --dynamic-path <string> dynamic variables path (.js or .ts; .ts is auto-compiled when esbuild is available, otherwise precompile)
|
|
219
219
|
# --paths <string> dotenv-expanded delimited list of paths to dotenv directory (default: "./")
|
|
220
220
|
# --paths-delimiter <string> paths delimiter string (default: " ")
|
|
221
|
-
# --paths-delimiter-pattern <string> paths delimiter regex pattern
|
|
221
|
+
# --paths-delimiter-pattern <string> paths delimiter regex pattern
|
|
222
|
+
# --private-token <string> dotenv-expanded token indicating private variables (default: "local")
|
|
222
223
|
# --vars-delimiter <string> vars delimiter string (default: " ")
|
|
223
224
|
# --vars-delimiter-pattern <string> vars delimiter regex pattern
|
|
224
225
|
# --vars-assignor <string> vars assignment operator string (default: "=")
|
|
@@ -277,7 +278,7 @@ Note that `batch` executes its commands in sequence, rather than in parallel!
|
|
|
277
278
|
|
|
278
279
|
To understand why, imagine running `npm install` in a dozen repos from the same command line. The visual feedback would be impossible to follow, and if something broke you'd have a really hard time figuring out why.
|
|
279
280
|
|
|
280
|
-
Instead, everything runs in sequence, and you get a clear record of exactly what
|
|
281
|
+
Instead, everything runs in sequence, and you get a clear record of exactly what happened and where. Also worth noting that many complex processes are resource hogs: you would not _want_ to run a dozen Serverless deployments at once!
|
|
281
282
|
|
|
282
283
|
Meanwhile, [this issue](https://github.com/karmaniverous/get-dotenv/issues/7) documents the parallel-processing option requirement. Feel free to submit a PR!
|
|
283
284
|
|
|
@@ -285,9 +286,7 @@ Meanwhile, [this issue](https://github.com/karmaniverous/get-dotenv/issues/7) do
|
|
|
285
286
|
|
|
286
287
|
### Authoring npm scripts and the `-c`/`--cmd` alias
|
|
287
288
|
|
|
288
|
-
When you run commands via `npm run`, flags after `--` are forwarded to your script
|
|
289
|
-
and may be applied to the inner shell command instead of `getdotenv` unless you
|
|
290
|
-
structure your script carefully.
|
|
289
|
+
When you run commands via `npm run`, flags after `--` are forwarded to your script and may be applied to the inner shell command instead of `getdotenv` unless you structure your script carefully.
|
|
291
290
|
|
|
292
291
|
- Anti-pattern:
|
|
293
292
|
|
|
@@ -301,22 +300,17 @@ structure your script carefully.
|
|
|
301
300
|
```json
|
|
302
301
|
{ "scripts": { "script": "getdotenv -c 'echo $APP_SETTING'" } }
|
|
303
302
|
```
|
|
304
|
-
Now `npm run script -- -e dev` applies `-e` to `getdotenv`, which loads and expands
|
|
305
|
-
variables before executing the inner command.
|
|
303
|
+
Now `npm run script -- -e dev` applies `-e` to `getdotenv`, which loads and expands variables before executing the inner command.
|
|
306
304
|
|
|
307
305
|
Notes:
|
|
308
306
|
|
|
309
307
|
- `-c`/`--cmd` is an alias of the `cmd` subcommand; do not use both in a single invocation.
|
|
310
|
-
- On POSIX shells, prefer single quotes to prevent the outer shell from expanding `$VAR`
|
|
311
|
-
|
|
312
|
-
- Script-level shell overrides (`scripts[name].shell`) still take precedence over the global
|
|
313
|
-
`--shell`.
|
|
308
|
+
- On POSIX shells, prefer single quotes to prevent the outer shell from expanding `$VAR` before Node sees it. On PowerShell, single quotes are also literal.
|
|
309
|
+
- Script-level shell overrides (`scripts[name].shell`) still take precedence over the global `--shell`.
|
|
314
310
|
|
|
315
311
|
Important:
|
|
316
312
|
|
|
317
|
-
- When using the parent alias `--cmd` with a Node eval payload, quote the entire
|
|
318
|
-
payload as a single token so Commander does not treat `-e/--eval` as
|
|
319
|
-
getdotenv’s `-e, --env` flag.
|
|
313
|
+
- When using the parent alias `--cmd` with a Node eval payload, quote the entire payload as a single token so Commander does not treat `-e/--eval` as getdotenv’s `-e, --env` flag.
|
|
320
314
|
- POSIX example:
|
|
321
315
|
```
|
|
322
316
|
getdotenv --cmd 'node -e "console.log(process.env.APP_SETTING ?? \"\")"'
|
|
@@ -325,23 +319,19 @@ Important:
|
|
|
325
319
|
```
|
|
326
320
|
getdotenv --cmd 'node -e "console.log(process.env.APP_SETTING ?? \"\")"'
|
|
327
321
|
```
|
|
328
|
-
- If you do not need to pass additional parent flags after the command, you can
|
|
329
|
-
prefer the subcommand form instead:
|
|
322
|
+
- If you do not need to pass additional parent flags after the command, you can prefer the subcommand form instead:
|
|
330
323
|
```
|
|
331
324
|
getdotenv --shell-off cmd node -e "console.log(process.env.APP_SETTING ?? '')"
|
|
332
325
|
```
|
|
333
326
|
|
|
334
327
|
Diagnostics and CI capture:
|
|
335
328
|
|
|
336
|
-
- To capture child stdout/stderr deterministically (e.g., in CI), either set
|
|
337
|
-
the environment variable `GETDOTENV_STDIO=pipe` or pass `--capture`. Outputs
|
|
338
|
-
are buffered and re-emitted after completion.
|
|
329
|
+
- To capture child stdout/stderr deterministically (e.g., in CI), either set the environment variable `GETDOTENV_STDIO=pipe` or pass `--capture`. Outputs are buffered and re-emitted after completion.
|
|
339
330
|
- For debugging environment composition, use:
|
|
340
331
|
```
|
|
341
332
|
getdotenv --trace [keys...] cmd node -e "0"
|
|
342
333
|
```
|
|
343
|
-
When provided without keys, `--trace` emits a concise origin line for every
|
|
344
|
-
key (parent | dotenv | unset) to stderr before the child process launches.
|
|
334
|
+
When provided without keys, `--trace` emits a concise origin line for every key (parent | dotenv | unset) to stderr before the child process launches.
|
|
345
335
|
|
|
346
336
|
---
|
|
347
337
|
|
|
@@ -349,21 +339,17 @@ Diagnostics and CI capture:
|
|
|
349
339
|
|
|
350
340
|
- [Cascade and precedence](./guides/cascade.md)
|
|
351
341
|
- [Shell execution behavior and quoting](./guides/shell.md)
|
|
342
|
+
- [Config files and overlays](./guides/config.md)
|
|
343
|
+
- [Plugin-first host and plugins](./guides/plugins.md)
|
|
352
344
|
|
|
353
345
|
The guides are also included in the [hosted API docs](https://docs.karmanivero.us/get-dotenv).
|
|
354
346
|
|
|
355
|
-
---
|
|
356
|
-
|
|
357
347
|
## Generated CLI
|
|
358
348
|
|
|
359
|
-
This package still supports generating a standalone CLI for your projects.
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
better subprocess control and diagnostics. If you prefer a thin, fixed
|
|
363
|
-
command surface with defaults baked into config, the generated CLI can be a
|
|
364
|
-
good fit.
|
|
349
|
+
This package still supports generating a standalone CLI for your projects. For most use cases we recommend the new plugin-first host because it resolves dotenv context once per invocation, supports composable plugins, and provides better subprocess control and diagnostics. If you prefer a thin, fixed command surface with defaults baked into config, the generated CLI can be a good fit.
|
|
350
|
+
|
|
351
|
+
See the [Generated CLI guide](https://docs.karmanivero.us/get-dotenv/guides/generated-cli) for details
|
|
365
352
|
|
|
366
|
-
|
|
367
|
-
https://docs.karmanivero.us/get-dotenv/guides/generated-cli
|
|
353
|
+
---
|
|
368
354
|
|
|
369
355
|
See more great templates & tools on [my GitHub Profile](https://github.com/karmaniverous)!
|
package/dist/index.cjs
CHANGED
|
@@ -498,7 +498,8 @@ const cmdCommand$1 = new commander.Command()
|
|
|
498
498
|
.description('execute command, conflicts with --command option (default subcommand)')
|
|
499
499
|
.enablePositionalOptions()
|
|
500
500
|
.passThroughOptions()
|
|
501
|
-
.
|
|
501
|
+
.argument('[command...]')
|
|
502
|
+
.action(async (commandParts, _options, thisCommand) => {
|
|
502
503
|
if (!thisCommand.parent)
|
|
503
504
|
throw new Error(`unable to resolve parent command`);
|
|
504
505
|
if (!thisCommand.parent.parent)
|
|
@@ -511,7 +512,12 @@ const cmdCommand$1 = new commander.Command()
|
|
|
511
512
|
const pkgCwd = !!raw.pkgCwd;
|
|
512
513
|
const rootPath = typeof raw.rootPath === 'string' ? raw.rootPath : './';
|
|
513
514
|
// Execute command.
|
|
514
|
-
const
|
|
515
|
+
const args = Array.isArray(commandParts) ? commandParts : [];
|
|
516
|
+
// When no positional tokens are provided (e.g., option form `-c/--command`),
|
|
517
|
+
// the preSubcommand hook handles execution. Avoid a duplicate call here.
|
|
518
|
+
if (args.length === 0)
|
|
519
|
+
return;
|
|
520
|
+
const command = args.map(String).join(' ');
|
|
515
521
|
await execShellCommandBatch({
|
|
516
522
|
command: resolveCommand(getDotenvCliOptions.scripts, command),
|
|
517
523
|
getDotenvCliOptions,
|
|
@@ -578,8 +584,9 @@ const cmdCommand = new commander.Command()
|
|
|
578
584
|
.configureHelp({ showGlobalOptions: true })
|
|
579
585
|
.enablePositionalOptions()
|
|
580
586
|
.passThroughOptions()
|
|
581
|
-
.
|
|
582
|
-
|
|
587
|
+
.argument('[command...]')
|
|
588
|
+
.action(async (commandParts, _options, thisCommand) => {
|
|
589
|
+
const args = Array.isArray(commandParts) ? commandParts : [];
|
|
583
590
|
if (args.length === 0)
|
|
584
591
|
return;
|
|
585
592
|
if (!thisCommand.parent)
|
package/dist/index.mjs
CHANGED
|
@@ -495,7 +495,8 @@ const cmdCommand$1 = new Command()
|
|
|
495
495
|
.description('execute command, conflicts with --command option (default subcommand)')
|
|
496
496
|
.enablePositionalOptions()
|
|
497
497
|
.passThroughOptions()
|
|
498
|
-
.
|
|
498
|
+
.argument('[command...]')
|
|
499
|
+
.action(async (commandParts, _options, thisCommand) => {
|
|
499
500
|
if (!thisCommand.parent)
|
|
500
501
|
throw new Error(`unable to resolve parent command`);
|
|
501
502
|
if (!thisCommand.parent.parent)
|
|
@@ -508,7 +509,12 @@ const cmdCommand$1 = new Command()
|
|
|
508
509
|
const pkgCwd = !!raw.pkgCwd;
|
|
509
510
|
const rootPath = typeof raw.rootPath === 'string' ? raw.rootPath : './';
|
|
510
511
|
// Execute command.
|
|
511
|
-
const
|
|
512
|
+
const args = Array.isArray(commandParts) ? commandParts : [];
|
|
513
|
+
// When no positional tokens are provided (e.g., option form `-c/--command`),
|
|
514
|
+
// the preSubcommand hook handles execution. Avoid a duplicate call here.
|
|
515
|
+
if (args.length === 0)
|
|
516
|
+
return;
|
|
517
|
+
const command = args.map(String).join(' ');
|
|
512
518
|
await execShellCommandBatch({
|
|
513
519
|
command: resolveCommand(getDotenvCliOptions.scripts, command),
|
|
514
520
|
getDotenvCliOptions,
|
|
@@ -575,8 +581,9 @@ const cmdCommand = new Command()
|
|
|
575
581
|
.configureHelp({ showGlobalOptions: true })
|
|
576
582
|
.enablePositionalOptions()
|
|
577
583
|
.passThroughOptions()
|
|
578
|
-
.
|
|
579
|
-
|
|
584
|
+
.argument('[command...]')
|
|
585
|
+
.action(async (commandParts, _options, thisCommand) => {
|
|
586
|
+
const args = Array.isArray(commandParts) ? commandParts : [];
|
|
580
587
|
if (args.length === 0)
|
|
581
588
|
return;
|
|
582
589
|
if (!thisCommand.parent)
|
package/package.json
CHANGED