@dotenvx/dotenvx 1.59.1 → 1.60.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 +12 -1
- package/README.md +14 -4
- package/package.json +7 -6
- package/src/cli/actions/decrypt.js +15 -8
- package/src/cli/actions/encrypt.js +15 -8
- package/src/cli/actions/ext/genexample.js +2 -2
- package/src/cli/actions/ext/gitignore.js +3 -3
- package/src/cli/actions/get.js +12 -7
- package/src/cli/actions/keypair.js +13 -5
- package/src/cli/actions/rotate.js +16 -9
- package/src/cli/actions/run.js +13 -6
- package/src/cli/actions/set.js +19 -12
- package/src/cli/dotenvx.js +19 -21
- package/src/cli/examples.js +1 -1
- package/src/db/session.js +10 -6
- package/src/lib/extensions/ops.js +112 -63
- package/src/lib/helpers/catchAndLog.js +1 -1
- package/src/lib/helpers/createSpinner.js +24 -0
- package/src/lib/helpers/cryptography/index.js +4 -0
- package/src/lib/helpers/cryptography/mutateKeysSrc.js +4 -4
- package/src/lib/helpers/cryptography/mutateKeysSrcSync.js +38 -0
- package/src/lib/helpers/cryptography/opsKeypair.js +2 -2
- package/src/lib/helpers/cryptography/opsKeypairSync.js +14 -0
- package/src/lib/helpers/cryptography/provision.js +7 -7
- package/src/lib/helpers/cryptography/provisionSync.js +47 -0
- package/src/lib/helpers/cryptography/provisionWithPrivateKey.js +1 -1
- package/src/lib/helpers/detectEncoding.js +2 -2
- package/src/lib/helpers/detectEncodingSync.js +22 -0
- package/src/lib/helpers/errors.js +15 -0
- package/src/lib/helpers/fsx.js +27 -3
- package/src/lib/helpers/installPrecommitHook.js +2 -2
- package/src/lib/helpers/isIgnoringDotenvKeys.js +1 -1
- package/src/lib/helpers/keyResolution/index.js +3 -1
- package/src/lib/helpers/keyResolution/keyValues.js +12 -12
- package/src/lib/helpers/keyResolution/keyValuesSync.js +85 -0
- package/src/lib/helpers/keyResolution/readFileKey.js +10 -8
- package/src/lib/helpers/keyResolution/readFileKeySync.js +15 -0
- package/src/lib/helpers/kits/sample.js +9 -21
- package/src/lib/main.d.ts +18 -3
- package/src/lib/main.js +18 -18
- package/src/lib/services/decrypt.js +8 -8
- package/src/lib/services/encrypt.js +17 -11
- package/src/lib/services/genexample.js +2 -2
- package/src/lib/services/get.js +30 -21
- package/src/lib/services/keypair.js +21 -5
- package/src/lib/services/prebuild.js +7 -12
- package/src/lib/services/precommit.js +7 -11
- package/src/lib/services/rotate.js +22 -18
- package/src/lib/services/run.js +82 -9
- package/src/lib/services/sets.js +139 -12
- package/src/shared/logger.js +3 -3
- package/src/lib/helpers/sleep.js +0 -5
package/CHANGELOG.md
CHANGED
|
@@ -2,7 +2,18 @@
|
|
|
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/v1.
|
|
5
|
+
[Unreleased](https://github.com/dotenvx/dotenvx/compare/v1.60.0...main)
|
|
6
|
+
|
|
7
|
+
## [1.60.0](https://github.com/dotenvx/dotenvx/compare/v1.59.1...v1.60.0) (2026-04-04)
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
* Add spinner with loading messages
|
|
12
|
+
* `injecting` (`run`)
|
|
13
|
+
* `encrypting` (`encrypt`, `set`)
|
|
14
|
+
* `decrypting` (`decrypt`, `get`)
|
|
15
|
+
* `rotating` (`rotate`)
|
|
16
|
+
* `retrieving` (`keypair`)
|
|
6
17
|
|
|
7
18
|
## [1.59.1](https://github.com/dotenvx/dotenvx/compare/v1.59.0...v1.59.1) (2026-03-28)
|
|
8
19
|
|
package/README.md
CHANGED
|
@@ -1258,12 +1258,12 @@ $ dotenvx run -fk .env.keys -f apps/app1/.env -- yourcommand
|
|
|
1258
1258
|
```
|
|
1259
1259
|
|
|
1260
1260
|
</details>
|
|
1261
|
-
<details><summary>`run --ops
|
|
1261
|
+
<details><summary>`run --no-ops`</summary><br>
|
|
1262
1262
|
|
|
1263
1263
|
Turn off [Dotenvx Ops](https://dotenvx.com/ops) features.
|
|
1264
1264
|
|
|
1265
1265
|
```sh
|
|
1266
|
-
$ dotenvx run --ops
|
|
1266
|
+
$ dotenvx run --no-ops -- yourcommand
|
|
1267
1267
|
```
|
|
1268
1268
|
|
|
1269
1269
|
</details>
|
|
@@ -1592,6 +1592,16 @@ $ dotenvx encrypt -f .env.production
|
|
|
1592
1592
|
⮕ next run [DOTENV_PRIVATE_KEY='bff...bc4' dotenvx run -- yourcommand] to test decryption locally
|
|
1593
1593
|
```
|
|
1594
1594
|
|
|
1595
|
+
</details>
|
|
1596
|
+
<details><summary>`encrypt --no-ops`</summary><br>
|
|
1597
|
+
|
|
1598
|
+
Turn off [Dotenvx Ops](https://dotenvx.com/ops) features for encrypt.
|
|
1599
|
+
|
|
1600
|
+
```sh
|
|
1601
|
+
$ dotenvx encrypt --no-ops
|
|
1602
|
+
◈ encrypted (.env)
|
|
1603
|
+
```
|
|
1604
|
+
|
|
1595
1605
|
</details>
|
|
1596
1606
|
<details><summary>`encrypt -fk`</summary><br>
|
|
1597
1607
|
|
|
@@ -2503,13 +2513,13 @@ $ dotenvx run --convention=nextjs -- node index.js
|
|
|
2503
2513
|
```
|
|
2504
2514
|
|
|
2505
2515
|
</details>
|
|
2506
|
-
<details><summary>`config(
|
|
2516
|
+
<details><summary>`config(noOps:)` - noOps</summary><br>
|
|
2507
2517
|
|
|
2508
2518
|
Turn off [Dotenvx Ops](https://dotenvx.com/ops) features.
|
|
2509
2519
|
|
|
2510
2520
|
```js
|
|
2511
2521
|
// index.js
|
|
2512
|
-
require('@dotenvx/dotenvx').config({
|
|
2522
|
+
require('@dotenvx/dotenvx').config({noOps: true})
|
|
2513
2523
|
```
|
|
2514
2524
|
|
|
2515
2525
|
</details>
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.
|
|
2
|
+
"version": "1.60.0",
|
|
3
3
|
"name": "@dotenvx/dotenvx",
|
|
4
|
-
"description": "
|
|
4
|
+
"description": "secrets for agents–from the creator of `dotenv`",
|
|
5
5
|
"author": "@motdotla",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"dotenv",
|
|
@@ -35,8 +35,8 @@
|
|
|
35
35
|
"scripts": {
|
|
36
36
|
"standard": "standard",
|
|
37
37
|
"standard:fix": "standard --fix",
|
|
38
|
-
"test": "tap run --test-env=
|
|
39
|
-
"test-coverage": "tap run --test-env=
|
|
38
|
+
"test": "tap run --test-env=DOTENVX_NO_OPS=true --allow-empty-coverage --disable-coverage --timeout=60000",
|
|
39
|
+
"test-coverage": "tap run --test-env=DOTENVX_NO_OPS=true --show-full-coverage --timeout=60000",
|
|
40
40
|
"testshell": "bash shellspec",
|
|
41
41
|
"prerelease": "npm test && npm run testshell",
|
|
42
42
|
"release": "standard-version"
|
|
@@ -51,10 +51,11 @@
|
|
|
51
51
|
"ignore": "^5.3.0",
|
|
52
52
|
"object-treeify": "1.1.33",
|
|
53
53
|
"picomatch": "^4.0.2",
|
|
54
|
-
"which": "^4.0.0"
|
|
54
|
+
"which": "^4.0.0",
|
|
55
|
+
"yocto-spinner": "^1.1.0"
|
|
55
56
|
},
|
|
56
57
|
"devDependencies": {
|
|
57
|
-
"@yao-pkg/pkg": "^
|
|
58
|
+
"@yao-pkg/pkg": "^6.14.2",
|
|
58
59
|
"capture-console": "^1.0.2",
|
|
59
60
|
"esbuild": "^0.25.8",
|
|
60
61
|
"proxyquire": "^2.1.3",
|
|
@@ -3,13 +3,18 @@ const { logger } = require('./../../shared/logger')
|
|
|
3
3
|
|
|
4
4
|
const Decrypt = require('./../../lib/services/decrypt')
|
|
5
5
|
const catchAndLog = require('../../lib/helpers/catchAndLog')
|
|
6
|
+
const createSpinner = require('../../lib/helpers/createSpinner')
|
|
7
|
+
const Session = require('../../db/session')
|
|
6
8
|
|
|
7
|
-
function decrypt () {
|
|
9
|
+
async function decrypt () {
|
|
8
10
|
const options = this.opts()
|
|
11
|
+
const spinner = await createSpinner({ ...options, text: 'decrypting' })
|
|
12
|
+
|
|
9
13
|
logger.debug(`options: ${JSON.stringify(options)}`)
|
|
10
14
|
|
|
15
|
+
const sesh = new Session()
|
|
11
16
|
const envs = this.envs
|
|
12
|
-
const
|
|
17
|
+
const noOps = options.ops === false || (await sesh.noOps())
|
|
13
18
|
|
|
14
19
|
let errorCount = 0
|
|
15
20
|
|
|
@@ -17,8 +22,8 @@ function decrypt () {
|
|
|
17
22
|
if (options.stdout) {
|
|
18
23
|
const {
|
|
19
24
|
processedEnvs
|
|
20
|
-
} = new Decrypt(envs, options.key, options.excludeKey, options.envKeysFile,
|
|
21
|
-
|
|
25
|
+
} = await new Decrypt(envs, options.key, options.excludeKey, options.envKeysFile, noOps).run()
|
|
26
|
+
if (spinner) spinner.stop()
|
|
22
27
|
for (const processedEnv of processedEnvs) {
|
|
23
28
|
if (processedEnv.error) {
|
|
24
29
|
errorCount += 1
|
|
@@ -39,7 +44,7 @@ function decrypt () {
|
|
|
39
44
|
processedEnvs,
|
|
40
45
|
changedFilepaths,
|
|
41
46
|
unchangedFilepaths
|
|
42
|
-
} = new Decrypt(envs, options.key, options.excludeKey, options.envKeysFile,
|
|
47
|
+
} = await new Decrypt(envs, options.key, options.excludeKey, options.envKeysFile, noOps).run()
|
|
43
48
|
|
|
44
49
|
for (const processedEnv of processedEnvs) {
|
|
45
50
|
logger.verbose(`decrypting ${processedEnv.envFilepath} (${processedEnv.filepath})`)
|
|
@@ -48,18 +53,19 @@ function decrypt () {
|
|
|
48
53
|
errorCount += 1
|
|
49
54
|
logger.error(processedEnv.error.messageWithHelp)
|
|
50
55
|
} else if (processedEnv.changed) {
|
|
51
|
-
fsx.writeFileX(processedEnv.filepath, processedEnv.envSrc)
|
|
56
|
+
await fsx.writeFileX(processedEnv.filepath, processedEnv.envSrc)
|
|
52
57
|
|
|
53
58
|
logger.verbose(`decrypted ${processedEnv.envFilepath} (${processedEnv.filepath})`)
|
|
54
59
|
} else {
|
|
55
|
-
logger.verbose(`no
|
|
60
|
+
logger.verbose(`no change ${processedEnv.envFilepath} (${processedEnv.filepath})`)
|
|
56
61
|
}
|
|
57
62
|
}
|
|
58
63
|
|
|
64
|
+
if (spinner) spinner.stop()
|
|
59
65
|
if (changedFilepaths.length > 0) {
|
|
60
66
|
logger.success(`◇ decrypted (${changedFilepaths.join(',')})`)
|
|
61
67
|
} else if (unchangedFilepaths.length > 0) {
|
|
62
|
-
logger.info(`○ no
|
|
68
|
+
logger.info(`○ no change (${unchangedFilepaths})`)
|
|
63
69
|
} else {
|
|
64
70
|
// do nothing - scenario when no .env files found
|
|
65
71
|
}
|
|
@@ -68,6 +74,7 @@ function decrypt () {
|
|
|
68
74
|
process.exit(1)
|
|
69
75
|
}
|
|
70
76
|
} catch (error) {
|
|
77
|
+
if (spinner) spinner.stop()
|
|
71
78
|
catchAndLog(error)
|
|
72
79
|
process.exit(1)
|
|
73
80
|
}
|
|
@@ -5,21 +5,26 @@ const Encrypt = require('./../../lib/services/encrypt')
|
|
|
5
5
|
|
|
6
6
|
const catchAndLog = require('../../lib/helpers/catchAndLog')
|
|
7
7
|
const localDisplayPath = require('../../lib/helpers/localDisplayPath')
|
|
8
|
+
const createSpinner = require('../../lib/helpers/createSpinner')
|
|
9
|
+
const Session = require('../../db/session')
|
|
8
10
|
|
|
9
|
-
function encrypt () {
|
|
11
|
+
async function encrypt () {
|
|
10
12
|
const options = this.opts()
|
|
13
|
+
const spinner = await createSpinner({ ...options, text: 'encrypting' })
|
|
14
|
+
|
|
11
15
|
logger.debug(`options: ${JSON.stringify(options)}`)
|
|
12
16
|
|
|
17
|
+
const sesh = new Session()
|
|
13
18
|
const envs = this.envs
|
|
14
|
-
const
|
|
19
|
+
const noOps = options.ops === false || (await sesh.noOps())
|
|
15
20
|
const noCreate = options.create === false
|
|
16
21
|
|
|
17
22
|
// stdout - should not have a try so that exit codes can surface to stdout
|
|
18
23
|
if (options.stdout) {
|
|
19
24
|
const {
|
|
20
25
|
processedEnvs
|
|
21
|
-
} = new Encrypt(envs, options.key, options.excludeKey, options.envKeysFile,
|
|
22
|
-
|
|
26
|
+
} = await new Encrypt(envs, options.key, options.excludeKey, options.envKeysFile, noOps, noCreate).run()
|
|
27
|
+
if (spinner) spinner.stop()
|
|
23
28
|
for (const processedEnv of processedEnvs) {
|
|
24
29
|
console.log(processedEnv.envSrc)
|
|
25
30
|
}
|
|
@@ -30,21 +35,22 @@ function encrypt () {
|
|
|
30
35
|
processedEnvs,
|
|
31
36
|
changedFilepaths,
|
|
32
37
|
unchangedFilepaths
|
|
33
|
-
} = new Encrypt(envs, options.key, options.excludeKey, options.envKeysFile,
|
|
38
|
+
} = await new Encrypt(envs, options.key, options.excludeKey, options.envKeysFile, noOps, noCreate).run()
|
|
34
39
|
|
|
35
40
|
for (const processedEnv of processedEnvs) {
|
|
36
41
|
logger.verbose(`encrypting ${processedEnv.envFilepath} (${processedEnv.filepath})`)
|
|
37
42
|
if (processedEnv.error) {
|
|
38
43
|
logger.warn(processedEnv.error.messageWithHelp)
|
|
39
44
|
} else if (processedEnv.changed) {
|
|
40
|
-
fsx.writeFileX(processedEnv.filepath, processedEnv.envSrc)
|
|
45
|
+
await fsx.writeFileX(processedEnv.filepath, processedEnv.envSrc)
|
|
41
46
|
|
|
42
47
|
logger.verbose(`encrypted ${processedEnv.envFilepath} (${processedEnv.filepath})`)
|
|
43
48
|
} else {
|
|
44
|
-
logger.verbose(`no
|
|
49
|
+
logger.verbose(`no change ${processedEnv.envFilepath} (${processedEnv.filepath})`)
|
|
45
50
|
}
|
|
46
51
|
}
|
|
47
52
|
|
|
53
|
+
if (spinner) spinner.stop()
|
|
48
54
|
if (changedFilepaths.length > 0) {
|
|
49
55
|
const keyAddedEnv = processedEnvs.find((processedEnv) => processedEnv.privateKeyAdded)
|
|
50
56
|
let msg = `◈ encrypted (${changedFilepaths.join(',')})`
|
|
@@ -54,7 +60,7 @@ function encrypt () {
|
|
|
54
60
|
}
|
|
55
61
|
logger.success(msg)
|
|
56
62
|
} else if (unchangedFilepaths.length > 0) {
|
|
57
|
-
logger.info(`○ no
|
|
63
|
+
logger.info(`○ no change (${unchangedFilepaths})`)
|
|
58
64
|
} else {
|
|
59
65
|
// do nothing - scenario when no .env files found
|
|
60
66
|
}
|
|
@@ -65,6 +71,7 @@ function encrypt () {
|
|
|
65
71
|
}
|
|
66
72
|
}
|
|
67
73
|
} catch (error) {
|
|
74
|
+
if (spinner) spinner.stop()
|
|
68
75
|
catchAndLog(error)
|
|
69
76
|
process.exit(1)
|
|
70
77
|
}
|
|
@@ -20,12 +20,12 @@ function genexample (directory) {
|
|
|
20
20
|
|
|
21
21
|
logger.verbose(`loading env from ${envFile}`)
|
|
22
22
|
|
|
23
|
-
fsx.
|
|
23
|
+
fsx.writeFileXSync(exampleFilepath, envExampleFile)
|
|
24
24
|
|
|
25
25
|
if (addedKeys.length > 0) {
|
|
26
26
|
logger.success(`▣ generated (${path.basename(exampleFilepath)})`)
|
|
27
27
|
} else {
|
|
28
|
-
logger.info('○ no
|
|
28
|
+
logger.info('○ no change (.env.example)')
|
|
29
29
|
}
|
|
30
30
|
} catch (error) {
|
|
31
31
|
catchAndLog(error)
|
|
@@ -18,13 +18,13 @@ class Generic {
|
|
|
18
18
|
const changedPatterns = []
|
|
19
19
|
if (!fsx.existsSync(this.filename)) {
|
|
20
20
|
if (this.touchFile === true && this.patterns.length > 0) {
|
|
21
|
-
fsx.
|
|
21
|
+
fsx.writeFileXSync(this.filename, '')
|
|
22
22
|
} else {
|
|
23
23
|
return
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
const lines = fsx.
|
|
27
|
+
const lines = fsx.readFileXSync(this.filename).split(/\r?\n/)
|
|
28
28
|
this.patterns.forEach(pattern => {
|
|
29
29
|
if (!lines.includes(pattern.trim())) {
|
|
30
30
|
this.append(pattern)
|
|
@@ -36,7 +36,7 @@ class Generic {
|
|
|
36
36
|
if (changedPatterns.length > 0) {
|
|
37
37
|
logger.success(`▣ ignored ${this.patterns} (${this.filename})`)
|
|
38
38
|
} else {
|
|
39
|
-
logger.info(`○ no
|
|
39
|
+
logger.info(`○ no change (${this.filename})`)
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
42
|
}
|
package/src/cli/actions/get.js
CHANGED
|
@@ -3,18 +3,20 @@ const { logger } = require('./../../shared/logger')
|
|
|
3
3
|
const conventions = require('./../../lib/helpers/conventions')
|
|
4
4
|
const escape = require('./../../lib/helpers/escape')
|
|
5
5
|
const catchAndLog = require('./../../lib/helpers/catchAndLog')
|
|
6
|
-
|
|
6
|
+
const createSpinner = require('../../lib/helpers/createSpinner')
|
|
7
|
+
const Session = require('../../db/session')
|
|
7
8
|
const Get = require('./../../lib/services/get')
|
|
8
9
|
|
|
9
|
-
function get (key) {
|
|
10
|
+
async function get (key) {
|
|
11
|
+
const options = this.opts()
|
|
12
|
+
const spinner = await createSpinner({ ...options, text: 'decrypting' })
|
|
13
|
+
|
|
14
|
+
logger.debug(`options: ${JSON.stringify(options)}`)
|
|
10
15
|
if (key) {
|
|
11
16
|
logger.debug(`key: ${key}`)
|
|
12
17
|
}
|
|
13
18
|
|
|
14
|
-
const options = this.opts()
|
|
15
|
-
logger.debug(`options: ${JSON.stringify(options)}`)
|
|
16
19
|
const prettyPrint = options.prettyPrint || options.pp
|
|
17
|
-
|
|
18
20
|
const ignore = options.ignore || []
|
|
19
21
|
|
|
20
22
|
let envs = []
|
|
@@ -26,8 +28,9 @@ function get (key) {
|
|
|
26
28
|
}
|
|
27
29
|
|
|
28
30
|
try {
|
|
29
|
-
const
|
|
30
|
-
const
|
|
31
|
+
const sesh = new Session()
|
|
32
|
+
const noOps = options.ops === false || (await sesh.noOps())
|
|
33
|
+
const { parsed, errors } = await new Get(key, envs, options.overload, options.all, options.envKeysFile, noOps).run()
|
|
31
34
|
|
|
32
35
|
for (const error of errors || []) {
|
|
33
36
|
if (options.strict) throw error // throw immediately if strict
|
|
@@ -39,6 +42,7 @@ function get (key) {
|
|
|
39
42
|
logger.error(error.messageWithHelp)
|
|
40
43
|
}
|
|
41
44
|
|
|
45
|
+
if (spinner) spinner.stop()
|
|
42
46
|
if (key) {
|
|
43
47
|
const single = parsed[key]
|
|
44
48
|
if (single === undefined) {
|
|
@@ -73,6 +77,7 @@ function get (key) {
|
|
|
73
77
|
}
|
|
74
78
|
}
|
|
75
79
|
} catch (error) {
|
|
80
|
+
if (spinner) spinner.stop()
|
|
76
81
|
catchAndLog(error)
|
|
77
82
|
process.exit(1)
|
|
78
83
|
}
|
|
@@ -1,18 +1,26 @@
|
|
|
1
1
|
const { logger } = require('./../../shared/logger')
|
|
2
2
|
|
|
3
|
-
const
|
|
3
|
+
const Keypair = require('./../../lib/services/keypair')
|
|
4
|
+
const createSpinner = require('../../lib/helpers/createSpinner')
|
|
5
|
+
const Session = require('../../db/session')
|
|
4
6
|
|
|
5
|
-
function keypair (key) {
|
|
7
|
+
async function keypair (key) {
|
|
8
|
+
const options = this.opts()
|
|
9
|
+
const spinner = await createSpinner({ ...options, text: 'retrieving' })
|
|
10
|
+
|
|
11
|
+
logger.debug(`options: ${JSON.stringify(options)}`)
|
|
6
12
|
if (key) {
|
|
7
13
|
logger.debug(`key: ${key}`)
|
|
8
14
|
}
|
|
9
15
|
|
|
10
|
-
const options = this.opts()
|
|
11
|
-
logger.debug(`options: ${JSON.stringify(options)}`)
|
|
12
16
|
const prettyPrint = options.prettyPrint || options.pp
|
|
13
17
|
|
|
14
|
-
const
|
|
18
|
+
const sesh = new Session()
|
|
19
|
+
const noOps = options.ops === false || await sesh.noOps()
|
|
20
|
+
const keypairs = await new Keypair(options.envFile, options.envKeysFile, noOps).run()
|
|
21
|
+
const results = key ? keypairs[key] : keypairs
|
|
15
22
|
|
|
23
|
+
if (spinner) spinner.stop()
|
|
16
24
|
if (typeof results === 'object' && results !== null) {
|
|
17
25
|
// inline shell format - env $(dotenvx keypair --format=shell) your-command
|
|
18
26
|
if (options.format === 'shell') {
|
|
@@ -4,21 +4,26 @@ const { logger } = require('./../../shared/logger')
|
|
|
4
4
|
const Rotate = require('./../../lib/services/rotate')
|
|
5
5
|
|
|
6
6
|
const catchAndLog = require('../../lib/helpers/catchAndLog')
|
|
7
|
+
const createSpinner = require('../../lib/helpers/createSpinner')
|
|
7
8
|
const localDisplayPath = require('../../lib/helpers/localDisplayPath')
|
|
9
|
+
const Session = require('../../db/session')
|
|
8
10
|
|
|
9
|
-
function rotate () {
|
|
11
|
+
async function rotate () {
|
|
10
12
|
const options = this.opts()
|
|
13
|
+
const spinner = await createSpinner({ ...options, text: 'rotating', frames: ['⟳', '⤾', '⥁'] })
|
|
14
|
+
|
|
11
15
|
logger.debug(`options: ${JSON.stringify(options)}`)
|
|
12
16
|
|
|
13
17
|
const envs = this.envs
|
|
14
|
-
const
|
|
18
|
+
const sesh = new Session()
|
|
19
|
+
const noOps = options.ops === false || (await sesh.noOps())
|
|
15
20
|
|
|
16
21
|
// stdout - should not have a try so that exit codes can surface to stdout
|
|
17
22
|
if (options.stdout) {
|
|
18
23
|
const {
|
|
19
24
|
processedEnvs
|
|
20
|
-
} = new Rotate(envs, options.key, options.excludeKey, options.envKeysFile,
|
|
21
|
-
|
|
25
|
+
} = await new Rotate(envs, options.key, options.excludeKey, options.envKeysFile, noOps).run()
|
|
26
|
+
if (spinner) spinner.stop()
|
|
22
27
|
for (const processedEnv of processedEnvs) {
|
|
23
28
|
console.log(processedEnv.envSrc)
|
|
24
29
|
if (processedEnv.privateKeyAdded) {
|
|
@@ -33,24 +38,25 @@ function rotate () {
|
|
|
33
38
|
processedEnvs,
|
|
34
39
|
changedFilepaths,
|
|
35
40
|
unchangedFilepaths
|
|
36
|
-
} = new Rotate(envs, options.key, options.excludeKey, options.envKeysFile,
|
|
41
|
+
} = await new Rotate(envs, options.key, options.excludeKey, options.envKeysFile, noOps).run()
|
|
37
42
|
|
|
38
43
|
for (const processedEnv of processedEnvs) {
|
|
39
44
|
logger.verbose(`rotating ${processedEnv.envFilepath} (${processedEnv.filepath})`)
|
|
40
45
|
if (processedEnv.error) {
|
|
41
46
|
logger.warn(processedEnv.error.messageWithHelp)
|
|
42
47
|
} else if (processedEnv.changed) {
|
|
43
|
-
fsx.writeFileX(processedEnv.filepath, processedEnv.envSrc)
|
|
48
|
+
await fsx.writeFileX(processedEnv.filepath, processedEnv.envSrc)
|
|
44
49
|
if (processedEnv.privateKeyAdded) {
|
|
45
|
-
fsx.writeFileX(processedEnv.envKeysFilepath, processedEnv.envKeysSrc)
|
|
50
|
+
await fsx.writeFileX(processedEnv.envKeysFilepath, processedEnv.envKeysSrc)
|
|
46
51
|
}
|
|
47
52
|
|
|
48
53
|
logger.verbose(`rotated ${processedEnv.envFilepath} (${processedEnv.filepath})`)
|
|
49
54
|
} else {
|
|
50
|
-
logger.verbose(`no
|
|
55
|
+
logger.verbose(`no change ${processedEnv.envFilepath} (${processedEnv.filepath})`)
|
|
51
56
|
}
|
|
52
57
|
}
|
|
53
58
|
|
|
59
|
+
if (spinner) spinner.stop()
|
|
54
60
|
if (changedFilepaths.length > 0) {
|
|
55
61
|
const keyAddedEnv = processedEnvs.find((processedEnv) => processedEnv.privateKeyAdded)
|
|
56
62
|
let msg = `⟳ rotated (${changedFilepaths.join(',')})`
|
|
@@ -60,11 +66,12 @@ function rotate () {
|
|
|
60
66
|
}
|
|
61
67
|
logger.success(msg)
|
|
62
68
|
} else if (unchangedFilepaths.length > 0) {
|
|
63
|
-
logger.info(`○ no
|
|
69
|
+
logger.info(`○ no change (${unchangedFilepaths})`)
|
|
64
70
|
} else {
|
|
65
71
|
// do nothing - scenario when no .env files found
|
|
66
72
|
}
|
|
67
73
|
} catch (error) {
|
|
74
|
+
if (spinner) spinner.stop()
|
|
68
75
|
catchAndLog(error)
|
|
69
76
|
process.exit(1)
|
|
70
77
|
}
|
package/src/cli/actions/run.js
CHANGED
|
@@ -4,22 +4,27 @@ const { logger } = require('./../../shared/logger')
|
|
|
4
4
|
const executeCommand = require('./../../lib/helpers/executeCommand')
|
|
5
5
|
const Run = require('./../../lib/services/run')
|
|
6
6
|
const catchAndLog = require('./../../lib/helpers/catchAndLog')
|
|
7
|
+
const createSpinner = require('../../lib/helpers/createSpinner')
|
|
8
|
+
const Session = require('../../db/session')
|
|
7
9
|
|
|
8
10
|
const conventions = require('./../../lib/helpers/conventions')
|
|
9
11
|
|
|
10
12
|
async function run () {
|
|
13
|
+
const options = this.opts()
|
|
11
14
|
const commandArgs = this.args
|
|
12
|
-
|
|
15
|
+
const spinner = await createSpinner({ ...options, text: 'injecting' })
|
|
13
16
|
|
|
14
|
-
const options = this.opts()
|
|
15
17
|
logger.debug(`options: ${JSON.stringify(options)}`)
|
|
18
|
+
logger.debug(`process command [${commandArgs.join(' ')}]`)
|
|
16
19
|
|
|
17
20
|
const ignore = options.ignore || []
|
|
18
21
|
|
|
19
|
-
|
|
20
|
-
const
|
|
22
|
+
const sesh = new Session()
|
|
23
|
+
const noOps = options.ops === false || options.opsOff === true || (await sesh.noOps())
|
|
21
24
|
|
|
22
25
|
if (commandArgs.length < 1) {
|
|
26
|
+
if (spinner) spinner.stop()
|
|
27
|
+
|
|
23
28
|
const hasSeparator = process.argv.indexOf('--') !== -1
|
|
24
29
|
|
|
25
30
|
if (hasSeparator) {
|
|
@@ -46,7 +51,7 @@ async function run () {
|
|
|
46
51
|
readableStrings,
|
|
47
52
|
readableFilepaths,
|
|
48
53
|
uniqueInjectedKeys
|
|
49
|
-
} = new Run(envs, options.overload, process.env, options.envKeysFile,
|
|
54
|
+
} = await new Run(envs, options.overload, process.env, options.envKeysFile, noOps).run()
|
|
50
55
|
|
|
51
56
|
for (const processedEnv of processedEnvs) {
|
|
52
57
|
if (processedEnv.type === 'envFile') {
|
|
@@ -88,7 +93,7 @@ async function run () {
|
|
|
88
93
|
}
|
|
89
94
|
}
|
|
90
95
|
|
|
91
|
-
let msg = `
|
|
96
|
+
let msg = `injected env (${uniqueInjectedKeys.length})`
|
|
92
97
|
if (readableFilepaths.length > 0 && readableStrings.length > 0) {
|
|
93
98
|
msg += ` from ${readableFilepaths.join(', ')}, and --env flag${readableStrings.length > 1 ? 's' : ''}`
|
|
94
99
|
} else if (readableFilepaths.length > 0) {
|
|
@@ -97,8 +102,10 @@ async function run () {
|
|
|
97
102
|
msg += ` from --env flag${readableStrings.length > 1 ? 's' : ''}`
|
|
98
103
|
}
|
|
99
104
|
|
|
105
|
+
if (spinner) spinner.stop()
|
|
100
106
|
logger.successv(msg)
|
|
101
107
|
} catch (error) {
|
|
108
|
+
if (spinner) spinner.stop()
|
|
102
109
|
catchAndLog(error)
|
|
103
110
|
process.exit(1)
|
|
104
111
|
}
|
package/src/cli/actions/set.js
CHANGED
|
@@ -1,35 +1,40 @@
|
|
|
1
1
|
const fsx = require('./../../lib/helpers/fsx')
|
|
2
2
|
const { logger } = require('./../../shared/logger')
|
|
3
3
|
|
|
4
|
-
const Sets = require('./../../lib/services/sets')
|
|
5
|
-
|
|
6
4
|
const catchAndLog = require('../../lib/helpers/catchAndLog')
|
|
5
|
+
const createSpinner = require('../../lib/helpers/createSpinner')
|
|
7
6
|
const localDisplayPath = require('../../lib/helpers/localDisplayPath')
|
|
7
|
+
const Session = require('../../db/session')
|
|
8
|
+
const Sets = require('./../../lib/services/sets')
|
|
8
9
|
|
|
9
|
-
function set (key, value) {
|
|
10
|
-
logger.debug(`key: ${key}`)
|
|
11
|
-
logger.debug(`value: ${value}`)
|
|
12
|
-
|
|
10
|
+
async function set (key, value) {
|
|
13
11
|
const options = this.opts()
|
|
14
|
-
logger.debug(`options: ${JSON.stringify(options)}`)
|
|
15
12
|
|
|
16
|
-
// encrypt
|
|
17
13
|
let encrypt = true
|
|
14
|
+
let settingMessage = 'encrypting'
|
|
18
15
|
if (options.plain) {
|
|
19
16
|
encrypt = false
|
|
17
|
+
settingMessage = 'setting'
|
|
20
18
|
}
|
|
21
19
|
|
|
20
|
+
const spinner = await createSpinner({ ...options, text: settingMessage })
|
|
21
|
+
|
|
22
|
+
logger.debug(`key: ${key}`)
|
|
23
|
+
logger.debug(`value: ${value}`)
|
|
24
|
+
logger.debug(`options: ${JSON.stringify(options)}`)
|
|
25
|
+
|
|
22
26
|
try {
|
|
27
|
+
const sesh = new Session()
|
|
23
28
|
const envs = this.envs
|
|
24
29
|
const envKeysFilepath = options.envKeysFile
|
|
25
|
-
const
|
|
30
|
+
const noOps = options.ops === false || (await sesh.noOps())
|
|
26
31
|
const noCreate = options.create === false
|
|
27
32
|
|
|
28
33
|
const {
|
|
29
34
|
processedEnvs,
|
|
30
35
|
changedFilepaths,
|
|
31
36
|
unchangedFilepaths
|
|
32
|
-
} = new Sets(key, value, envs, encrypt, envKeysFilepath,
|
|
37
|
+
} = await new Sets(key, value, envs, encrypt, envKeysFilepath, noOps, noCreate).run()
|
|
33
38
|
|
|
34
39
|
let withEncryption = ''
|
|
35
40
|
|
|
@@ -43,7 +48,7 @@ function set (key, value) {
|
|
|
43
48
|
if (processedEnv.error) {
|
|
44
49
|
logger.warn(processedEnv.error.messageWithHelp)
|
|
45
50
|
} else {
|
|
46
|
-
fsx.writeFileX(processedEnv.filepath, processedEnv.envSrc)
|
|
51
|
+
await fsx.writeFileX(processedEnv.filepath, processedEnv.envSrc)
|
|
47
52
|
|
|
48
53
|
logger.verbose(`${processedEnv.key} set${withEncryption} (${processedEnv.envFilepath})`)
|
|
49
54
|
logger.debug(`${processedEnv.key} set${withEncryption} to ${processedEnv.value} (${processedEnv.envFilepath})`)
|
|
@@ -53,6 +58,7 @@ function set (key, value) {
|
|
|
53
58
|
const keyAddedEnv = processedEnvs.find((processedEnv) => processedEnv.privateKeyAdded)
|
|
54
59
|
const keyAddedSuffix = keyAddedEnv ? ` + key (${localDisplayPath(keyAddedEnv.envKeysFilepath)})` : ''
|
|
55
60
|
|
|
61
|
+
if (spinner) spinner.stop()
|
|
56
62
|
if (changedFilepaths.length > 0) {
|
|
57
63
|
if (encrypt) {
|
|
58
64
|
logger.success(`◈ encrypted ${key} (${changedFilepaths.join(',')})${keyAddedSuffix}`)
|
|
@@ -63,13 +69,14 @@ function set (key, value) {
|
|
|
63
69
|
const keyAddedEnvFilepath = keyAddedEnv.envFilepath || changedFilepaths[0] || '.env'
|
|
64
70
|
logger.success(`◈ encrypted ${key} (${keyAddedEnvFilepath})${keyAddedSuffix}`)
|
|
65
71
|
} else if (unchangedFilepaths.length > 0) {
|
|
66
|
-
logger.info(`○ no
|
|
72
|
+
logger.info(`○ no change (${unchangedFilepaths})`)
|
|
67
73
|
} else {
|
|
68
74
|
// do nothing
|
|
69
75
|
}
|
|
70
76
|
|
|
71
77
|
// intentionally quiet: success line communicates key creation
|
|
72
78
|
} catch (error) {
|
|
79
|
+
if (spinner) spinner.stop()
|
|
73
80
|
catchAndLog(error)
|
|
74
81
|
process.exit(1)
|
|
75
82
|
}
|