@dotenvx/dotenvx 2.3.4 → 2.4.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/CHANGELOG.md +8 -1
- package/README.md +75 -13
- package/package.json +1 -1
- package/src/cli/actions/get.js +4 -9
- package/src/cli/actions/run.js +4 -9
- package/src/cli/dotenvx.js +13 -6
- package/src/lib/helpers/buildCommandEnvs.js +40 -0
- package/src/lib/helpers/resolveDirectoryFilepath.js +16 -0
- package/src/lib/helpers/resolveEnvKeysFile.js +11 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,7 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
-
[Unreleased](https://github.com/dotenvx/dotenvx/compare/v2.
|
|
5
|
+
[Unreleased](https://github.com/dotenvx/dotenvx/compare/v2.4.0...main)
|
|
6
|
+
|
|
7
|
+
## [2.4.0](https://github.com/dotenvx/dotenvx/compare/v2.3.4...v2.4.0) (2026-07-10)
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
* Support multiple `-fk` flags for select commands ([#880](https://github.com/dotenvx/dotenvx/pull/880))
|
|
12
|
+
* Support `-f ../..` directories ([#881](https://github.com/dotenvx/dotenvx/pull/881))
|
|
6
13
|
|
|
7
14
|
## [2.3.4](https://github.com/dotenvx/dotenvx/compare/v2.3.3...v2.3.4) (2026-07-09)
|
|
8
15
|
|
package/README.md
CHANGED
|
@@ -843,25 +843,45 @@ Hello Dotenvx
|
|
|
843
843
|
Note the `DOTENV_PRIVATE_KEY` instructs `dotenvx run` to load the `.env` file and the `DOTENV_PRIVATE_KEY_PRODUCTION` instructs it to load the `.env.production` file. See the pattern?
|
|
844
844
|
|
|
845
845
|
</details>
|
|
846
|
-
<details><summary>
|
|
846
|
+
<details><summary>use directories with monorepos</summary><br>
|
|
847
|
+
|
|
848
|
+
Point `-f` at a directory to load the `.env` inside it. From a workspace, this makes a shared root `.env` available without repeating its filename.
|
|
849
|
+
|
|
850
|
+
```text
|
|
851
|
+
my-monorepo/
|
|
852
|
+
.env
|
|
853
|
+
.env.keys
|
|
854
|
+
apps/
|
|
855
|
+
web/
|
|
856
|
+
index.js
|
|
857
|
+
```
|
|
847
858
|
|
|
848
859
|
```sh
|
|
849
|
-
$
|
|
850
|
-
$ mkdir app2
|
|
851
|
-
$ dotenvx set HELLO app1 -f app1/.env.ci
|
|
852
|
-
$ dotenvx set HELLO app2 -f app2/.env.ci
|
|
853
|
-
$ echo "console.log('Hello ' + process.env.HELLO)" > index.js
|
|
860
|
+
$ cd apps/web
|
|
854
861
|
|
|
855
|
-
$
|
|
856
|
-
|
|
857
|
-
Hello app1
|
|
862
|
+
$ dotenvx get HELLO -f ../..
|
|
863
|
+
World
|
|
858
864
|
|
|
859
|
-
$
|
|
860
|
-
[dotenvx@1.X.X] injecting env (
|
|
861
|
-
Hello
|
|
865
|
+
$ dotenvx run -f ../.. -- node index.js
|
|
866
|
+
[dotenvx@1.X.X] injecting env (1) from ../../.env
|
|
867
|
+
Hello World
|
|
868
|
+
```
|
|
869
|
+
|
|
870
|
+
Encrypted values work without extra configuration when `.env.keys` sits beside the resolved `.env`.
|
|
871
|
+
|
|
872
|
+
The directory also becomes the base when using a convention:
|
|
873
|
+
|
|
874
|
+
```sh
|
|
875
|
+
$ dotenvx run -f ../.. --convention=nextjs -- node index.js
|
|
876
|
+
[dotenvx@1.X.X] injecting env (1) from ../../.env.development.local, ../../.env.local, ../../.env.development, ../../.env
|
|
877
|
+
Hello development local
|
|
862
878
|
```
|
|
863
879
|
|
|
864
|
-
|
|
880
|
+
If a workspace has its own `.env` but shares the root `.env.keys`, point `-fk` at the root directory:
|
|
881
|
+
|
|
882
|
+
```sh
|
|
883
|
+
$ dotenvx run -f . -fk ../.. -- node index.js
|
|
884
|
+
```
|
|
865
885
|
|
|
866
886
|
</details>
|
|
867
887
|
<details><summary>`--stdout`</summary><br>
|
|
@@ -1108,6 +1128,17 @@ $ dotenvx get GOODBYE
|
|
|
1108
1128
|
[MISSING_KEY] missing key (GOODBYE)
|
|
1109
1129
|
```
|
|
1110
1130
|
|
|
1131
|
+
</details>
|
|
1132
|
+
<details><summary>`run -f <directory>`</summary><br>
|
|
1133
|
+
|
|
1134
|
+
Run a command using the `.env` file in a directory. This is useful with monorepos.
|
|
1135
|
+
|
|
1136
|
+
```sh
|
|
1137
|
+
$ dotenvx run -f ../.. -- node index.js
|
|
1138
|
+
[dotenvx@1.X.X] injecting env (1) from ../../.env
|
|
1139
|
+
Hello World
|
|
1140
|
+
```
|
|
1141
|
+
|
|
1111
1142
|
</details>
|
|
1112
1143
|
<details><summary>`run` - multiple `-f` flags</summary><br>
|
|
1113
1144
|
|
|
@@ -1383,6 +1414,17 @@ Hello development local
|
|
|
1383
1414
|
|
|
1384
1415
|
(more conventions available upon request)
|
|
1385
1416
|
|
|
1417
|
+
</details>
|
|
1418
|
+
<details><summary>`run -f <directory> --convention=nextjs`</summary><br>
|
|
1419
|
+
|
|
1420
|
+
Run a command using Next.js' convention from a directory. This is useful with monorepos.
|
|
1421
|
+
|
|
1422
|
+
```sh
|
|
1423
|
+
$ dotenvx run -f ../.. --convention=nextjs -- node index.js
|
|
1424
|
+
[dotenvx@1.X.X] injecting env (1) from ../../.env.development.local, ../../.env.local, ../../.env.development, ../../.env
|
|
1425
|
+
Hello development local
|
|
1426
|
+
```
|
|
1427
|
+
|
|
1386
1428
|
</details>
|
|
1387
1429
|
<details><summary>`run --convention=flow`</summary><br>
|
|
1388
1430
|
|
|
@@ -1490,6 +1532,16 @@ $ dotenvx get HELLO -f .env.production
|
|
|
1490
1532
|
production
|
|
1491
1533
|
```
|
|
1492
1534
|
|
|
1535
|
+
</details>
|
|
1536
|
+
<details><summary>`get KEY -f <directory>`</summary><br>
|
|
1537
|
+
|
|
1538
|
+
Return a single environment variable's value from the `.env` file in a directory. This is useful with monorepos.
|
|
1539
|
+
|
|
1540
|
+
```sh
|
|
1541
|
+
$ dotenvx get HELLO -f ../..
|
|
1542
|
+
World
|
|
1543
|
+
```
|
|
1544
|
+
|
|
1493
1545
|
</details>
|
|
1494
1546
|
<details><summary>`get KEY -fk`</summary><br>
|
|
1495
1547
|
|
|
@@ -1561,6 +1613,16 @@ $ DOTENV_CONFIG_CONVENTION=nextjs dotenvx get HELLO
|
|
|
1561
1613
|
development local
|
|
1562
1614
|
```
|
|
1563
1615
|
|
|
1616
|
+
</details>
|
|
1617
|
+
<details><summary>`get KEY -f <directory> --convention=nextjs`</summary><br>
|
|
1618
|
+
|
|
1619
|
+
Return a single environment variable's value using Next.js' convention from a directory. This is useful with monorepos.
|
|
1620
|
+
|
|
1621
|
+
```sh
|
|
1622
|
+
$ dotenvx get HELLO -f ../.. --convention=nextjs
|
|
1623
|
+
development local
|
|
1624
|
+
```
|
|
1625
|
+
|
|
1564
1626
|
</details>
|
|
1565
1627
|
<details><summary>`get KEY --convention=flow`</summary><br>
|
|
1566
1628
|
|
package/package.json
CHANGED
package/src/cli/actions/get.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
const { logger } = require('./../../shared/logger')
|
|
2
2
|
|
|
3
|
-
const conventions = require('./../../lib/helpers/conventions')
|
|
4
3
|
const escape = require('./../../lib/helpers/escape')
|
|
5
4
|
const catchAndLog = require('./../../lib/helpers/catchAndLog')
|
|
6
5
|
const createSpinner = require('../../lib/helpers/createSpinner')
|
|
7
6
|
const Session = require('../../db/session')
|
|
8
7
|
const getResolver = require('./../../lib/resolvers/get')
|
|
9
8
|
const normalizeDotenvConfigConvention = require('../../lib/helpers/normalizeDotenvConfigConvention')
|
|
9
|
+
const buildCommandEnvs = require('../../lib/helpers/buildCommandEnvs')
|
|
10
|
+
const resolveEnvKeysFile = require('../../lib/helpers/resolveEnvKeysFile')
|
|
10
11
|
|
|
11
12
|
async function get (key) {
|
|
12
13
|
const options = normalizeDotenvConfigConvention(this.opts())
|
|
@@ -21,13 +22,7 @@ async function get (key) {
|
|
|
21
22
|
const ignore = options.ignore || []
|
|
22
23
|
let errorCount = 0
|
|
23
24
|
|
|
24
|
-
|
|
25
|
-
// handle shorthand conventions - like --convention=nextjs
|
|
26
|
-
if (options.convention) {
|
|
27
|
-
envs = conventions(options.convention).concat(this.envs)
|
|
28
|
-
} else {
|
|
29
|
-
envs = this.envs
|
|
30
|
-
}
|
|
25
|
+
const envs = buildCommandEnvs(this.envs, options.convention)
|
|
31
26
|
|
|
32
27
|
try {
|
|
33
28
|
const sesh = new Session()
|
|
@@ -38,7 +33,7 @@ async function get (key) {
|
|
|
38
33
|
envs,
|
|
39
34
|
overload: options.overload,
|
|
40
35
|
all: options.all,
|
|
41
|
-
envKeysFile: options.envKeysFile,
|
|
36
|
+
envKeysFile: resolveEnvKeysFile(options.envKeysFile),
|
|
42
37
|
noArmor,
|
|
43
38
|
noKeychain,
|
|
44
39
|
onStatus: (text) => {
|
package/src/cli/actions/run.js
CHANGED
|
@@ -8,8 +8,9 @@ const createSpinner = require('../../lib/helpers/createSpinner')
|
|
|
8
8
|
const Session = require('../../db/session')
|
|
9
9
|
const normalizeDotenvConfigQuiet = require('../../lib/helpers/normalizeDotenvConfigQuiet')
|
|
10
10
|
const normalizeDotenvConfigConvention = require('../../lib/helpers/normalizeDotenvConfigConvention')
|
|
11
|
+
const buildCommandEnvs = require('../../lib/helpers/buildCommandEnvs')
|
|
12
|
+
const resolveEnvKeysFile = require('../../lib/helpers/resolveEnvKeysFile')
|
|
11
13
|
|
|
12
|
-
const conventions = require('./../../lib/helpers/conventions')
|
|
13
14
|
const { determine } = require('./../../lib/helpers/envResolution')
|
|
14
15
|
|
|
15
16
|
function inferCommandArgsFromProcessArgv (argv) {
|
|
@@ -80,13 +81,7 @@ async function run () {
|
|
|
80
81
|
}
|
|
81
82
|
|
|
82
83
|
try {
|
|
83
|
-
let envs =
|
|
84
|
-
// handle shorthand conventions - like --convention=nextjs
|
|
85
|
-
if (options.convention) {
|
|
86
|
-
envs = conventions(options.convention).concat(this.envs)
|
|
87
|
-
} else {
|
|
88
|
-
envs = this.envs
|
|
89
|
-
}
|
|
84
|
+
let envs = buildCommandEnvs(this.envs, options.convention)
|
|
90
85
|
envs = determine(envs, process.env)
|
|
91
86
|
|
|
92
87
|
const {
|
|
@@ -96,7 +91,7 @@ async function run () {
|
|
|
96
91
|
envs,
|
|
97
92
|
overload: options.overload,
|
|
98
93
|
processEnv: process.env,
|
|
99
|
-
envKeysFile: options.envKeysFile,
|
|
94
|
+
envKeysFile: resolveEnvKeysFile(options.envKeysFile),
|
|
100
95
|
noArmor,
|
|
101
96
|
noKeychain,
|
|
102
97
|
token: options.token,
|
package/src/cli/dotenvx.js
CHANGED
|
@@ -17,10 +17,17 @@ const envs = []
|
|
|
17
17
|
function collectEnvs (type) {
|
|
18
18
|
return function (value, previous) {
|
|
19
19
|
envs.push({ type, value })
|
|
20
|
-
return previous.concat([value])
|
|
20
|
+
return (previous || []).concat([value])
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
function collectEnvKeys (value, previous) {
|
|
25
|
+
if (previous === undefined) return value
|
|
26
|
+
if (Array.isArray(previous)) return previous.concat([value])
|
|
27
|
+
|
|
28
|
+
return [previous, value]
|
|
29
|
+
}
|
|
30
|
+
|
|
24
31
|
// global log levels
|
|
25
32
|
program
|
|
26
33
|
.usage('run -- yourcommand')
|
|
@@ -56,7 +63,7 @@ program.command('run')
|
|
|
56
63
|
.addHelpText('after', examples.run)
|
|
57
64
|
.option('-e, --env <strings...>', 'environment variable(s) set as string (example: "HELLO=World")', collectEnvs('env'), [])
|
|
58
65
|
.option('-f, --env-file <path>', 'path(s) to your env file(s)', collectEnvs('envFile'), [])
|
|
59
|
-
.option('-fk, --env-keys-file <path>', 'path to your .env.keys file (default: same path as your env file)')
|
|
66
|
+
.option('-fk, --env-keys-file <path>', 'path(s) to your .env.keys file(s) (default: same path as your env file)', collectEnvKeys)
|
|
60
67
|
.option('-o, --overload', 'override existing env variables (by default, existing env vars take precedence over .env files)')
|
|
61
68
|
.option('--strict', 'process.exit(1) on any errors', false)
|
|
62
69
|
.option('--convention <name>', 'load a .env convention (available conventions: [\'nextjs\', \'flow\'])')
|
|
@@ -76,7 +83,7 @@ program.command('get')
|
|
|
76
83
|
.argument('[KEY]', 'environment variable name')
|
|
77
84
|
.option('-e, --env <strings...>', 'environment variable(s) set as string (example: "HELLO=World")', collectEnvs('env'), [])
|
|
78
85
|
.option('-f, --env-file <path>', 'path(s) to your env file(s)', collectEnvs('envFile'), [])
|
|
79
|
-
.option('-fk, --env-keys-file <path>', 'path to your .env.keys file (default: same path as your env file)')
|
|
86
|
+
.option('-fk, --env-keys-file <path>', 'path(s) to your .env.keys file(s) (default: same path as your env file)', collectEnvKeys)
|
|
80
87
|
.option('-o, --overload', 'override existing env variables (by default, existing env vars take precedence over .env files)')
|
|
81
88
|
.option('--strict', 'process.exit(1) on any errors', false)
|
|
82
89
|
.option('--convention <name>', 'load a .env convention (available conventions: [\'nextjs\', \'flow\'])')
|
|
@@ -133,7 +140,7 @@ program.command('encrypt')
|
|
|
133
140
|
program.command('decrypt')
|
|
134
141
|
.description('decrypt .env file(s)')
|
|
135
142
|
.option('-f, --env-file <path>', 'path(s) to your env file(s)', collectEnvs('envFile'), [])
|
|
136
|
-
.option('-fk, --env-keys-file <path>', 'path to your .env.keys file (default: same path as your env file)')
|
|
143
|
+
.option('-fk, --env-keys-file <path>', 'path(s) to your .env.keys file(s) (default: same path as your env file)', collectEnvKeys)
|
|
137
144
|
.option('-k, --key <keys...>', 'keys(s) to decrypt (default: all keys in file)')
|
|
138
145
|
.option('-ek, --exclude-key <excludeKeys...>', 'keys(s) to exclude from decryption (default: none)')
|
|
139
146
|
.option('--no-armor', 'disable Dotenvx Armor features')
|
|
@@ -149,8 +156,8 @@ program.command('keypair')
|
|
|
149
156
|
.usage('[KEY] [options]')
|
|
150
157
|
.description('print public/private keys for .env file(s)')
|
|
151
158
|
.argument('[KEY]', 'environment variable key name')
|
|
152
|
-
.option('-f, --env-file <path>', 'path(s) to your env file(s)')
|
|
153
|
-
.option('-fk, --env-keys-file <path>', 'path to your .env.keys file (default: same path as your env file)')
|
|
159
|
+
.option('-f, --env-file <path>', 'path(s) to your env file(s)', collectEnvs('envFile'))
|
|
160
|
+
.option('-fk, --env-keys-file <path>', 'path(s) to your .env.keys file(s) (default: same path as your env file)', collectEnvKeys)
|
|
154
161
|
.option('--no-armor', 'disable Dotenvx Armor features')
|
|
155
162
|
.option('--no-native', 'disable OS secret store features')
|
|
156
163
|
.option('-pp, --pretty-print', 'pretty print output')
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
const conventions = require('./conventions')
|
|
2
|
+
const resolveDirectoryFilepath = require('./resolveDirectoryFilepath')
|
|
3
|
+
|
|
4
|
+
function buildCommandEnvs (envs, convention) {
|
|
5
|
+
const resolvedEnvs = []
|
|
6
|
+
let hasDirectory = false
|
|
7
|
+
|
|
8
|
+
for (const env of envs) {
|
|
9
|
+
if (env.type !== 'envFile') {
|
|
10
|
+
resolvedEnvs.push(env)
|
|
11
|
+
continue
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const envFilepath = resolveDirectoryFilepath(env.value, '.env')
|
|
15
|
+
if (envFilepath === env.value) {
|
|
16
|
+
resolvedEnvs.push(env)
|
|
17
|
+
continue
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
hasDirectory = true
|
|
21
|
+
if (convention) {
|
|
22
|
+
for (const conventionEnv of conventions(convention)) {
|
|
23
|
+
resolvedEnvs.push({
|
|
24
|
+
...conventionEnv,
|
|
25
|
+
value: resolveDirectoryFilepath(env.value, conventionEnv.value)
|
|
26
|
+
})
|
|
27
|
+
}
|
|
28
|
+
} else {
|
|
29
|
+
resolvedEnvs.push({ ...env, value: envFilepath })
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (convention && !hasDirectory) {
|
|
34
|
+
return conventions(convention).concat(resolvedEnvs)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return resolvedEnvs
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
module.exports = buildCommandEnvs
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
const fs = require('fs')
|
|
2
|
+
const path = require('path')
|
|
3
|
+
|
|
4
|
+
function resolveDirectoryFilepath (filepath, filename) {
|
|
5
|
+
try {
|
|
6
|
+
if (fs.statSync(filepath).isDirectory()) {
|
|
7
|
+
return path.join(filepath, filename)
|
|
8
|
+
}
|
|
9
|
+
} catch (_error) {
|
|
10
|
+
// Preserve missing paths so the existing error handling can report them.
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return filepath
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
module.exports = resolveDirectoryFilepath
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
const resolveDirectoryFilepath = require('./resolveDirectoryFilepath')
|
|
2
|
+
|
|
3
|
+
function resolveEnvKeysFile (envKeysFile) {
|
|
4
|
+
if (Array.isArray(envKeysFile)) {
|
|
5
|
+
return envKeysFile.map(filepath => resolveDirectoryFilepath(filepath, '.env.keys'))
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
return envKeysFile && resolveDirectoryFilepath(envKeysFile, '.env.keys')
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
module.exports = resolveEnvKeysFile
|