@dotenvx/dotenvx 1.59.0 → 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.
Files changed (52) hide show
  1. package/CHANGELOG.md +18 -1
  2. package/README.md +130 -137
  3. package/package.json +7 -6
  4. package/src/cli/actions/decrypt.js +15 -8
  5. package/src/cli/actions/encrypt.js +15 -8
  6. package/src/cli/actions/ext/genexample.js +2 -2
  7. package/src/cli/actions/ext/gitignore.js +3 -3
  8. package/src/cli/actions/get.js +12 -7
  9. package/src/cli/actions/keypair.js +13 -5
  10. package/src/cli/actions/rotate.js +16 -9
  11. package/src/cli/actions/run.js +13 -6
  12. package/src/cli/actions/set.js +19 -12
  13. package/src/cli/dotenvx.js +19 -21
  14. package/src/cli/examples.js +1 -1
  15. package/src/db/session.js +10 -6
  16. package/src/lib/extensions/ops.js +112 -63
  17. package/src/lib/helpers/catchAndLog.js +1 -1
  18. package/src/lib/helpers/createSpinner.js +24 -0
  19. package/src/lib/helpers/cryptography/index.js +4 -0
  20. package/src/lib/helpers/cryptography/mutateKeysSrc.js +4 -4
  21. package/src/lib/helpers/cryptography/mutateKeysSrcSync.js +38 -0
  22. package/src/lib/helpers/cryptography/opsKeypair.js +2 -2
  23. package/src/lib/helpers/cryptography/opsKeypairSync.js +14 -0
  24. package/src/lib/helpers/cryptography/provision.js +7 -7
  25. package/src/lib/helpers/cryptography/provisionSync.js +47 -0
  26. package/src/lib/helpers/cryptography/provisionWithPrivateKey.js +1 -1
  27. package/src/lib/helpers/detectEncoding.js +2 -2
  28. package/src/lib/helpers/detectEncodingSync.js +22 -0
  29. package/src/lib/helpers/errors.js +15 -0
  30. package/src/lib/helpers/fsx.js +27 -3
  31. package/src/lib/helpers/installPrecommitHook.js +2 -2
  32. package/src/lib/helpers/isIgnoringDotenvKeys.js +1 -1
  33. package/src/lib/helpers/keyResolution/index.js +3 -1
  34. package/src/lib/helpers/keyResolution/keyValues.js +12 -12
  35. package/src/lib/helpers/keyResolution/keyValuesSync.js +85 -0
  36. package/src/lib/helpers/keyResolution/readFileKey.js +10 -8
  37. package/src/lib/helpers/keyResolution/readFileKeySync.js +15 -0
  38. package/src/lib/helpers/kits/sample.js +11 -21
  39. package/src/lib/main.d.ts +18 -3
  40. package/src/lib/main.js +18 -18
  41. package/src/lib/services/decrypt.js +8 -8
  42. package/src/lib/services/encrypt.js +17 -11
  43. package/src/lib/services/genexample.js +2 -2
  44. package/src/lib/services/get.js +30 -21
  45. package/src/lib/services/keypair.js +21 -5
  46. package/src/lib/services/prebuild.js +7 -12
  47. package/src/lib/services/precommit.js +7 -11
  48. package/src/lib/services/rotate.js +22 -18
  49. package/src/lib/services/run.js +82 -9
  50. package/src/lib/services/sets.js +139 -12
  51. package/src/shared/logger.js +3 -3
  52. package/src/lib/helpers/sleep.js +0 -5
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
- "version": "1.59.0",
2
+ "version": "1.60.0",
3
3
  "name": "@dotenvx/dotenvx",
4
- "description": "a secure dotenv–from the creator of `dotenv`",
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=DOTENVX_OPS_OFF=true --allow-empty-coverage --disable-coverage --timeout=60000",
39
- "test-coverage": "tap run --test-env=DOTENVX_OPS_OFF=true --show-full-coverage --timeout=60000",
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": "^5.14.2",
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 opsOn = options.opsOff !== true
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, opsOn).run()
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, opsOn).run()
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 changes ${processedEnv.envFilepath} (${processedEnv.filepath})`)
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 changes (${unchangedFilepaths})`)
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 opsOn = options.opsOff !== true
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, opsOn, noCreate).run()
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, opsOn, noCreate).run()
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 changes ${processedEnv.envFilepath} (${processedEnv.filepath})`)
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 changes (${unchangedFilepaths})`)
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.writeFileX(exampleFilepath, envExampleFile)
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 changes (.env.example)')
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.writeFileX(this.filename, '')
21
+ fsx.writeFileXSync(this.filename, '')
22
22
  } else {
23
23
  return
24
24
  }
25
25
  }
26
26
 
27
- const lines = fsx.readFileX(this.filename).split(/\r?\n/)
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 changes (${this.filename})`)
39
+ logger.info(`○ no change (${this.filename})`)
40
40
  }
41
41
  }
42
42
  }
@@ -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 opsOn = options.opsOff !== true
30
- const { parsed, errors } = new Get(key, envs, options.overload, options.all, options.envKeysFile, opsOn).run()
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 main = require('./../../lib/main')
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 results = main.keypair(options.envFile, key, options.envKeysFile, options.opsOff)
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 opsOn = options.opsOff !== true
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, opsOn).run()
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, opsOn).run()
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 changes ${processedEnv.envFilepath} (${processedEnv.filepath})`)
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 changes (${unchangedFilepaths})`)
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
  }
@@ -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
- logger.debug(`process command [${commandArgs.join(' ')}]`)
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
- // dotenvx-ops related
20
- const opsOn = options.opsOff !== true
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, opsOn).run()
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 = `injecting env (${uniqueInjectedKeys.length})`
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
  }
@@ -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 opsOn = options.opsOff !== true
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, opsOn, noCreate).run()
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 changes (${unchangedFilepaths})`)
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
  }
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  /* c8 ignore start */
4
- const { Command } = require('commander')
4
+ const { Command, Option } = require('commander')
5
5
  const program = new Command()
6
6
 
7
7
  const { setLogLevel, logger } = require('../shared/logger')
@@ -13,9 +13,6 @@ const executeDynamic = require('./../lib/helpers/executeDynamic')
13
13
  const removeDynamicHelpSection = require('./../lib/helpers/removeDynamicHelpSection')
14
14
  const removeOptionsHelpParts = require('./../lib/helpers/removeOptionsHelpParts')
15
15
 
16
- const Session = require('./../db/session')
17
- const sesh = new Session()
18
-
19
16
  // for use with run
20
17
  const envs = []
21
18
  function collectEnvs (type) {
@@ -74,10 +71,11 @@ program.command('run')
74
71
  .option('--strict', 'process.exit(1) on any errors', false)
75
72
  .option('--convention <name>', 'load a .env convention (available conventions: [\'nextjs\', \'flow\'])')
76
73
  .option('--ignore <errorCodes...>', 'error code(s) to ignore (example: --ignore=MISSING_ENV_FILE)')
77
- .option('--ops-off', 'disable dotenvx-ops features', sesh.opsOff())
74
+ .option('--no-ops', 'disable dotenvx-ops features')
75
+ .addOption(new Option('--ops-off', 'DEPRECATED: use --no-ops').hideHelp())
78
76
  .action(function (...args) {
79
77
  this.envs = envs
80
- runAction.apply(this, args)
78
+ return runAction.apply(this, args)
81
79
  })
82
80
 
83
81
  // dotenvx get
@@ -97,10 +95,10 @@ program.command('get')
97
95
  .option('-pp, --pretty-print', 'pretty print output')
98
96
  .option('--pp', 'pretty print output (alias)')
99
97
  .option('--format <type>', 'format of the output (json, shell, eval)', 'json')
100
- .option('--ops-off', 'disable dotenvx-ops features', sesh.opsOff())
98
+ .option('--no-ops', 'disable dotenvx-ops features')
101
99
  .action(function (...args) {
102
100
  this.envs = envs
103
- getAction.apply(this, args)
101
+ return getAction.apply(this, args)
104
102
  })
105
103
 
106
104
  // dotenvx set
@@ -117,10 +115,10 @@ program.command('set')
117
115
  .option('-c, --encrypt', 'encrypt value', true)
118
116
  .option('-p, --plain', 'store value as plain text', false)
119
117
  .option('--no-create', 'do not create .env file(s) when missing')
120
- .option('--ops-off', 'disable dotenvx-ops features', sesh.opsOff())
118
+ .option('--no-ops', 'disable dotenvx-ops features')
121
119
  .action(function (...args) {
122
120
  this.envs = envs
123
- setAction.apply(this, args)
121
+ return setAction.apply(this, args)
124
122
  })
125
123
 
126
124
  // dotenvx encrypt
@@ -131,12 +129,12 @@ program.command('encrypt')
131
129
  .option('-fk, --env-keys-file <path>', 'path to your .env.keys file (default: same path as your env file)')
132
130
  .option('-k, --key <keys...>', 'keys(s) to encrypt (default: all keys in file)')
133
131
  .option('-ek, --exclude-key <excludeKeys...>', 'keys(s) to exclude from encryption (default: none)')
134
- .option('--no-create', 'do not create .env file(s) when missing')
135
- .option('--ops-off', 'disable dotenvx-ops features', sesh.opsOff())
136
132
  .option('--stdout', 'send to stdout')
133
+ .option('--no-create', 'do not create .env file(s) when missing')
134
+ .option('--no-ops', 'disable dotenvx-ops features')
137
135
  .action(function (...args) {
138
136
  this.envs = envs
139
- encryptAction.apply(this, args)
137
+ return encryptAction.apply(this, args)
140
138
  })
141
139
 
142
140
  // dotenvx decrypt
@@ -147,11 +145,11 @@ program.command('decrypt')
147
145
  .option('-fk, --env-keys-file <path>', 'path to your .env.keys file (default: same path as your env file)')
148
146
  .option('-k, --key <keys...>', 'keys(s) to decrypt (default: all keys in file)')
149
147
  .option('-ek, --exclude-key <excludeKeys...>', 'keys(s) to exclude from decryption (default: none)')
150
- .option('--ops-off', 'disable dotenvx-ops features', sesh.opsOff())
148
+ .option('--no-ops', 'disable dotenvx-ops features')
151
149
  .option('--stdout', 'send to stdout')
152
150
  .action(function (...args) {
153
151
  this.envs = envs
154
- decryptAction.apply(this, args)
152
+ return decryptAction.apply(this, args)
155
153
  })
156
154
 
157
155
  // dotenvx rotate
@@ -162,11 +160,11 @@ program.command('rotate')
162
160
  .option('-fk, --env-keys-file <path>', 'path to your .env.keys file (default: same path as your env file)')
163
161
  .option('-k, --key <keys...>', 'keys(s) to encrypt (default: all keys in file)')
164
162
  .option('-ek, --exclude-key <excludeKeys...>', 'keys(s) to exclude from encryption (default: none)')
165
- .option('--ops-off', 'disable dotenvx-ops features', sesh.opsOff())
163
+ .option('--no-ops', 'disable dotenvx-ops features')
166
164
  .option('--stdout', 'send to stdout')
167
165
  .action(function (...args) {
168
166
  this.envs = envs
169
- rotateAction.apply(this, args)
167
+ return rotateAction.apply(this, args)
170
168
  })
171
169
 
172
170
  // dotenvx keypair
@@ -177,7 +175,7 @@ program.command('keypair')
177
175
  .argument('[KEY]', 'environment variable key name')
178
176
  .option('-f, --env-file <paths...>', 'path(s) to your env file(s)')
179
177
  .option('-fk, --env-keys-file <path>', 'path to your .env.keys file (default: same path as your env file)')
180
- .option('--ops-off', 'disable dotenvx-ops features', sesh.opsOff())
178
+ .option('--no-ops', 'disable dotenvx-ops features')
181
179
  .option('-pp, --pretty-print', 'pretty print output')
182
180
  .option('--pp', 'pretty print output (alias)')
183
181
  .option('--format <type>', 'format of the output (json, shell)', 'json')
@@ -208,11 +206,11 @@ program.command('help [command]')
208
206
  }
209
207
  })
210
208
 
211
- // dotenvx pro
209
+ // dotenvx ops
212
210
  program.addHelpText('after', ' ')
213
211
  program.addHelpText('after', 'Advanced: ')
214
- program.addHelpText('after', ' ops ⛨ Ops [www.dotenvx.com/ops]')
215
- program.addHelpText('after', ' ext 🔌 extensions')
212
+ program.addHelpText('after', ' ops ⛨ Ops [www.dotenvx.com/ops]')
213
+ program.addHelpText('after', ' ext 🔌 extensions')
216
214
 
217
215
  // dotenvx ext
218
216
  program.addCommand(require('./commands/ext'))
@@ -16,7 +16,7 @@ Try it:
16
16
  $ echo "console.log('Hello ' + process.env.HELLO)" > index.js
17
17
 
18
18
  $ dotenvx run -f .env -- node index.js
19
- [dotenvx] injecting env (1) from .env
19
+ [dotenvx] injected env (1) from .env
20
20
  Hello World
21
21
  \`\`\`
22
22
  `