@dotenvx/dotenvx 2.17.0 → 2.17.2
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 +13 -1
- package/README.md +32 -1
- package/package.json +2 -2
- package/src/cli/actions/get.js +6 -1
- package/src/cli/actions/run.js +6 -1
- package/src/cli/actions/validate.js +2 -1
- package/src/lib/helpers/normalizeDotenvConfigConvention.js +3 -1
- package/src/lib/helpers/normalizeDotenvConfigIgnore.js +17 -0
- package/src/lib/helpers/normalizeDotenvConfigQuiet.js +3 -1
- package/src/lib/helpers/resolveBitwardenPassword.js +1 -0
- package/src/lib/main.js +3 -0
- package/src/lib/resolvers/envs.js +14 -8
package/CHANGELOG.md
CHANGED
|
@@ -2,7 +2,19 @@
|
|
|
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.17.
|
|
5
|
+
[Unreleased](https://github.com/dotenvx/dotenvx/compare/v2.17.2...main)
|
|
6
|
+
|
|
7
|
+
## [2.17.2](https://github.com/dotenvx/dotenvx/compare/v2.17.1...v2.17.2) (2026-07-22)
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
* Add support for `DOTENV_CONFIG_IGNORE` global convenience ([#919](https://github.com/dotenvx/dotenvx/pull/919))
|
|
12
|
+
|
|
13
|
+
## [2.17.1](https://github.com/dotenvx/dotenvx/compare/v2.17.0...v2.17.1) (2026-07-21)
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
* Handle `ctrl + c` better ([#916](https://github.com/dotenvx/dotenvx/pull/916))
|
|
6
18
|
|
|
7
19
|
## [2.17.0](https://github.com/dotenvx/dotenvx/compare/v2.16.1...v2.17.0) (2026-07-21)
|
|
8
20
|
|
package/README.md
CHANGED
|
@@ -167,7 +167,7 @@ Hello World
|
|
|
167
167
|
see [1Password guide](https://dotenvx.com/docs/secrets-in-1password)
|
|
168
168
|
|
|
169
169
|
</details>
|
|
170
|
-
<details><summary>Bitwarden
|
|
170
|
+
<details><summary>Bitwarden 🛡️</summary><br>
|
|
171
171
|
|
|
172
172
|
Run with secrets resolved directly from Bitwarden Password Manager.
|
|
173
173
|
|
|
@@ -1586,6 +1586,11 @@ $ dotenvx run -f .env.missing --ignore=MISSING_ENV_FILE -- node index.js
|
|
|
1586
1586
|
...
|
|
1587
1587
|
```
|
|
1588
1588
|
|
|
1589
|
+
You can also set `DOTENV_CONFIG_IGNORE="MISSING_ENV_FILE"`. It is parsed as a comma-separated list.
|
|
1590
|
+
|
|
1591
|
+
```sh
|
|
1592
|
+
$ DOTENV_CONFIG_IGNORE="MISSING_ENV_FILE,OTHER_ERROR_CODE" dotenvx run -f .env.missing -- node index.js
|
|
1593
|
+
```
|
|
1589
1594
|
</details>
|
|
1590
1595
|
<details><summary>`run --convention=nextjs`</summary><br>
|
|
1591
1596
|
|
|
@@ -3039,6 +3044,8 @@ X.X.X
|
|
|
3039
3044
|
|
|
3040
3045
|
</details>
|
|
3041
3046
|
|
|
3047
|
+
|
|
3048
|
+
|
|
3042
3049
|
### Library 📦
|
|
3043
3050
|
|
|
3044
3051
|
Use dotenvx directly in code.
|
|
@@ -3491,6 +3498,29 @@ Set `mask: 0` to fully mask values.
|
|
|
3491
3498
|
|
|
3492
3499
|
|
|
3493
3500
|
|
|
3501
|
+
### Settings ⚙️
|
|
3502
|
+
|
|
3503
|
+
There are global settings available that can be configured as environment variables.
|
|
3504
|
+
|
|
3505
|
+
<details><summary>Environment variables</summary><br>
|
|
3506
|
+
|
|
3507
|
+
```ini
|
|
3508
|
+
# dotenvx native settings
|
|
3509
|
+
DOTENV_CONFIG_CONVENTION= # set to a default convention like 'nextjs' or 'flow'
|
|
3510
|
+
DOTENV_CONFIG_IGNORE= # MISSING_ENV_FILE,OTHER
|
|
3511
|
+
DOTENV_CONFIG_QUIET= # set to "true" to default to --quiet
|
|
3512
|
+
DOTENVX_NO_ARMOR= # set to "true" to turn off Armor support
|
|
3513
|
+
DOTENVX_NO_1PASSWORD= # set to "true" to turn off 1Password support
|
|
3514
|
+
DOTENVX_NO_BITWARDEN= # set to "true" to turn off Bitwarden support
|
|
3515
|
+
|
|
3516
|
+
# other machine settings respected by dotenvx
|
|
3517
|
+
BW_SESSION= # set to bitwarden session token to bypass password prompt
|
|
3518
|
+
```
|
|
3519
|
+
|
|
3520
|
+
</details>
|
|
3521
|
+
|
|
3522
|
+
|
|
3523
|
+
|
|
3494
3524
|
## Armor ⛨
|
|
3495
3525
|
|
|
3496
3526
|
[](https://dotenvx.com/armor)
|
|
@@ -3513,6 +3543,7 @@ Set `mask: 0` to fully mask values.
|
|
|
3513
3543
|
* [Claude](https://dotenvx.com/docs/secrets-in-claude)
|
|
3514
3544
|
* [Codex](https://dotenvx.com/docs/secrets-in-codex)
|
|
3515
3545
|
* [1Password](https://dotenvx.com/docs/secrets-in-1password)
|
|
3546
|
+
* [Bitwarden](https://dotenvx.com/docs/secrets-in-bitwarden)
|
|
3516
3547
|
* [Node.js](https://dotenvx.com/docs/secrets-in-nodejs)
|
|
3517
3548
|
* [Next.js](https://dotenvx.com/docs/secrets-in-nextjs)
|
|
3518
3549
|
* [Express](https://dotenvx.com/docs/secrets-in-express)
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "2.17.
|
|
2
|
+
"version": "2.17.2",
|
|
3
3
|
"name": "@dotenvx/dotenvx",
|
|
4
4
|
"description": "a secure dotenv–from the creator of `dotenv`",
|
|
5
5
|
"author": "@motdotla",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"funding": "https://dotenvx.com",
|
|
54
54
|
"dependencies": {
|
|
55
55
|
"@dotenvx/primitives": "^2.1.0",
|
|
56
|
-
"@dotenvx/tooling": "^1.0.
|
|
56
|
+
"@dotenvx/tooling": "^1.0.3",
|
|
57
57
|
"yocto-spinner": "^1.2.1"
|
|
58
58
|
},
|
|
59
59
|
"devDependencies": {
|
package/src/cli/actions/get.js
CHANGED
|
@@ -6,13 +6,14 @@ const createSpinner = require('../../lib/helpers/createSpinner')
|
|
|
6
6
|
const Session = require('../../db/session')
|
|
7
7
|
const getResolver = require('./../../lib/resolvers/get')
|
|
8
8
|
const normalizeDotenvConfigConvention = require('../../lib/helpers/normalizeDotenvConfigConvention')
|
|
9
|
+
const normalizeDotenvConfigIgnore = require('../../lib/helpers/normalizeDotenvConfigIgnore')
|
|
9
10
|
const buildCommandEnvs = require('../../lib/helpers/buildCommandEnvs')
|
|
10
11
|
const resolveEnvKeysFile = require('../../lib/helpers/resolveEnvKeysFile')
|
|
11
12
|
const mask = require('../../lib/helpers/mask')
|
|
12
13
|
const filterKeys = require('../../lib/helpers/filterKeys')
|
|
13
14
|
|
|
14
15
|
async function get (key) {
|
|
15
|
-
const options = normalizeDotenvConfigConvention(this.opts())
|
|
16
|
+
const options = normalizeDotenvConfigIgnore(normalizeDotenvConfigConvention(this.opts()))
|
|
16
17
|
const spinnerOptions = typeof this.optsWithGlobals === 'function' ? this.optsWithGlobals() : options
|
|
17
18
|
const spinner = await createSpinner({ ...spinnerOptions, ...options, text: 'decrypting' })
|
|
18
19
|
|
|
@@ -120,6 +121,10 @@ async function get (key) {
|
|
|
120
121
|
}
|
|
121
122
|
} catch (error) {
|
|
122
123
|
if (spinner) spinner.stop()
|
|
124
|
+
if (error.code === 'PROMPT_CANCELLED') {
|
|
125
|
+
process.exit(130)
|
|
126
|
+
return
|
|
127
|
+
}
|
|
123
128
|
catchAndLog(error)
|
|
124
129
|
process.exit(1)
|
|
125
130
|
}
|
package/src/cli/actions/run.js
CHANGED
|
@@ -8,6 +8,7 @@ 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 normalizeDotenvConfigIgnore = require('../../lib/helpers/normalizeDotenvConfigIgnore')
|
|
11
12
|
const buildCommandEnvs = require('../../lib/helpers/buildCommandEnvs')
|
|
12
13
|
const resolveEnvKeysFile = require('../../lib/helpers/resolveEnvKeysFile')
|
|
13
14
|
const mask = require('../../lib/helpers/mask')
|
|
@@ -53,7 +54,7 @@ function uniqueInjectedKeys (processedEnvs) {
|
|
|
53
54
|
}
|
|
54
55
|
|
|
55
56
|
async function run () {
|
|
56
|
-
const options = normalizeDotenvConfigConvention(normalizeDotenvConfigQuiet(this.opts()))
|
|
57
|
+
const options = normalizeDotenvConfigIgnore(normalizeDotenvConfigConvention(normalizeDotenvConfigQuiet(this.opts())))
|
|
57
58
|
const spinnerOptions = typeof this.optsWithGlobals === 'function' ? this.optsWithGlobals() : options
|
|
58
59
|
const maskEnabled = options.mask !== undefined
|
|
59
60
|
const redactEnabled = options.redact === true
|
|
@@ -210,6 +211,10 @@ async function run () {
|
|
|
210
211
|
logger.success(`⟐ ${msg}`)
|
|
211
212
|
} catch (error) {
|
|
212
213
|
if (spinner) spinner.stop()
|
|
214
|
+
if (error.code === 'PROMPT_CANCELLED') {
|
|
215
|
+
process.exit(130)
|
|
216
|
+
return
|
|
217
|
+
}
|
|
213
218
|
catchAndLog(error)
|
|
214
219
|
process.exit(1)
|
|
215
220
|
}
|
|
@@ -6,6 +6,7 @@ const createSpinner = require('../../lib/helpers/createSpinner')
|
|
|
6
6
|
const Session = require('../../db/session')
|
|
7
7
|
const normalizeDotenvConfigQuiet = require('../../lib/helpers/normalizeDotenvConfigQuiet')
|
|
8
8
|
const normalizeDotenvConfigConvention = require('../../lib/helpers/normalizeDotenvConfigConvention')
|
|
9
|
+
const normalizeDotenvConfigIgnore = require('../../lib/helpers/normalizeDotenvConfigIgnore')
|
|
9
10
|
const buildCommandEnvs = require('../../lib/helpers/buildCommandEnvs')
|
|
10
11
|
const resolveEnvKeysFile = require('../../lib/helpers/resolveEnvKeysFile')
|
|
11
12
|
const validateEnvExample = require('../../lib/helpers/validateEnvExample')
|
|
@@ -13,7 +14,7 @@ const validateEnvExample = require('../../lib/helpers/validateEnvExample')
|
|
|
13
14
|
const { determine } = require('./../../lib/helpers/envResolution')
|
|
14
15
|
|
|
15
16
|
async function validate () {
|
|
16
|
-
const options = normalizeDotenvConfigConvention(normalizeDotenvConfigQuiet(this.opts()))
|
|
17
|
+
const options = normalizeDotenvConfigIgnore(normalizeDotenvConfigConvention(normalizeDotenvConfigQuiet(this.opts())))
|
|
17
18
|
const spinnerOptions = typeof this.optsWithGlobals === 'function' ? this.optsWithGlobals() : options
|
|
18
19
|
const spinner = await createSpinner({ ...spinnerOptions, ...options, text: 'validating' })
|
|
19
20
|
const ignore = options.ignore || []
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
function normalizeDotenvConfigConvention (
|
|
1
|
+
function normalizeDotenvConfigConvention (
|
|
2
|
+
/** @type {import('../main').DotenvConfigOptions} */ options
|
|
3
|
+
) {
|
|
2
4
|
if (!options.convention && process.env.DOTENV_CONFIG_CONVENTION) {
|
|
3
5
|
options.convention = process.env.DOTENV_CONFIG_CONVENTION
|
|
4
6
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
function normalizeDotenvConfigIgnore (
|
|
2
|
+
/** @type {import('../main').DotenvConfigOptions} */ options
|
|
3
|
+
) {
|
|
4
|
+
const configIgnore = (process.env.DOTENV_CONFIG_IGNORE || '')
|
|
5
|
+
.split(',')
|
|
6
|
+
.map(code => code.trim())
|
|
7
|
+
.filter(Boolean)
|
|
8
|
+
|
|
9
|
+
if (configIgnore.length < 1) return options
|
|
10
|
+
|
|
11
|
+
return {
|
|
12
|
+
...options,
|
|
13
|
+
ignore: [...(options.ignore || []), ...configIgnore]
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
module.exports = normalizeDotenvConfigIgnore
|
|
@@ -117,6 +117,7 @@ async function resolveBitwardenPassword (parsed, options = {}) {
|
|
|
117
117
|
})
|
|
118
118
|
parsed[key] = secretValue(stdout)
|
|
119
119
|
} catch (error) {
|
|
120
|
+
if (error && error.code === 'PROMPT_CANCELLED') throw error
|
|
120
121
|
errors.push(resolutionError(key, error))
|
|
121
122
|
unresolved.push(key)
|
|
122
123
|
}
|
package/src/lib/main.js
CHANGED
|
@@ -26,6 +26,7 @@ const decryptKeyValue = require('./helpers/cryptography/decryptKeyValue')
|
|
|
26
26
|
const Errors = require('./helpers/errors')
|
|
27
27
|
const normalizeDotenvConfigQuiet = require('./helpers/normalizeDotenvConfigQuiet')
|
|
28
28
|
const normalizeDotenvConfigConvention = require('./helpers/normalizeDotenvConfigConvention')
|
|
29
|
+
const normalizeDotenvConfigIgnore = require('./helpers/normalizeDotenvConfigIgnore')
|
|
29
30
|
const mask = require('./helpers/mask')
|
|
30
31
|
const maskProcessedEnvs = require('./helpers/maskProcessedEnvs')
|
|
31
32
|
|
|
@@ -43,6 +44,7 @@ function uniqueInjectedKeys (processedEnvs) {
|
|
|
43
44
|
const config = function (options = {}) {
|
|
44
45
|
options = normalizeDotenvConfigQuiet(options)
|
|
45
46
|
options = normalizeDotenvConfigConvention(options)
|
|
47
|
+
options = normalizeDotenvConfigIgnore(options)
|
|
46
48
|
|
|
47
49
|
// allow user to set processEnv to write to
|
|
48
50
|
let processEnv = process.env
|
|
@@ -318,6 +320,7 @@ const set = async function (key, value, options = {}) {
|
|
|
318
320
|
/* @type {import('./main').get} */
|
|
319
321
|
const get = async function (key, options = {}) {
|
|
320
322
|
options = normalizeDotenvConfigConvention(options)
|
|
323
|
+
options = normalizeDotenvConfigIgnore(options)
|
|
321
324
|
|
|
322
325
|
const envs = buildEnvs(options)
|
|
323
326
|
const noArmor = resolveNoArmor(options)
|
|
@@ -118,6 +118,7 @@ async function injectEnv ({ env, overload, processEnv, envKeysFilepath, provider
|
|
|
118
118
|
|
|
119
119
|
inject(processEnv, row.parsed)
|
|
120
120
|
} catch (e) {
|
|
121
|
+
if (e.code === 'PROMPT_CANCELLED') throw e
|
|
121
122
|
row.errors = [e]
|
|
122
123
|
}
|
|
123
124
|
|
|
@@ -225,6 +226,7 @@ async function injectEnvFile ({ env, overload, processEnv, envKeysFilepath, prov
|
|
|
225
226
|
|
|
226
227
|
inject(processEnv, parsed)
|
|
227
228
|
} catch (e) {
|
|
229
|
+
if (e.code === 'PROMPT_CANCELLED') throw e
|
|
228
230
|
if (e.code === 'ENOENT' || e.code === 'EISDIR') {
|
|
229
231
|
row.errors = [new Errors({ envFilepath: env.value, filepath }).missingEnvFile()]
|
|
230
232
|
} else {
|
|
@@ -299,6 +301,8 @@ async function envs (options = {}) {
|
|
|
299
301
|
const readableFilepaths = new Set()
|
|
300
302
|
const processEnv = options.processEnv || process.env
|
|
301
303
|
const envKeysFilepath = options.envKeysFilepath || options.envKeysFile || null
|
|
304
|
+
const no1Password = options.no1Password === true || process.env.DOTENVX_NO_1PASSWORD === 'true'
|
|
305
|
+
const noBitwarden = options.noBitwarden === true || process.env.DOTENVX_NO_BITWARDEN === 'true'
|
|
302
306
|
const provider = await providers(options)
|
|
303
307
|
const decryptor = await decryptors(options)
|
|
304
308
|
for (const env of options.envs || []) {
|
|
@@ -311,8 +315,8 @@ async function envs (options = {}) {
|
|
|
311
315
|
provider,
|
|
312
316
|
decryptor,
|
|
313
317
|
readableFilepaths,
|
|
314
|
-
no1Password
|
|
315
|
-
noBitwarden
|
|
318
|
+
no1Password,
|
|
319
|
+
noBitwarden,
|
|
316
320
|
onStatus: options.onStatus
|
|
317
321
|
}))
|
|
318
322
|
} else if (env.type === TYPE_ENV) {
|
|
@@ -323,8 +327,8 @@ async function envs (options = {}) {
|
|
|
323
327
|
envKeysFilepath,
|
|
324
328
|
provider,
|
|
325
329
|
decryptor,
|
|
326
|
-
no1Password
|
|
327
|
-
noBitwarden
|
|
330
|
+
no1Password,
|
|
331
|
+
noBitwarden,
|
|
328
332
|
onStatus: options.onStatus
|
|
329
333
|
}))
|
|
330
334
|
}
|
|
@@ -341,6 +345,8 @@ function envsSync (options = {}) {
|
|
|
341
345
|
const readableFilepaths = new Set()
|
|
342
346
|
const processEnv = options.processEnv || process.env
|
|
343
347
|
const envKeysFilepath = options.envKeysFilepath || options.envKeysFile || null
|
|
348
|
+
const no1Password = options.no1Password === true || process.env.DOTENVX_NO_1PASSWORD === 'true'
|
|
349
|
+
const noBitwarden = options.noBitwarden === true || process.env.DOTENVX_NO_BITWARDEN === 'true'
|
|
344
350
|
const provider = providers.sync(options)
|
|
345
351
|
const decryptor = decryptors.sync(options)
|
|
346
352
|
|
|
@@ -354,8 +360,8 @@ function envsSync (options = {}) {
|
|
|
354
360
|
provider,
|
|
355
361
|
decryptor,
|
|
356
362
|
readableFilepaths,
|
|
357
|
-
no1Password
|
|
358
|
-
noBitwarden
|
|
363
|
+
no1Password,
|
|
364
|
+
noBitwarden
|
|
359
365
|
}))
|
|
360
366
|
} else if (env.type === TYPE_ENV) {
|
|
361
367
|
processedEnvs.push(injectEnvSync({
|
|
@@ -365,8 +371,8 @@ function envsSync (options = {}) {
|
|
|
365
371
|
envKeysFilepath,
|
|
366
372
|
provider,
|
|
367
373
|
decryptor,
|
|
368
|
-
no1Password
|
|
369
|
-
noBitwarden
|
|
374
|
+
no1Password,
|
|
375
|
+
noBitwarden
|
|
370
376
|
}))
|
|
371
377
|
}
|
|
372
378
|
}
|