@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
@@ -7,15 +7,15 @@ const readProcessKey = require('./readProcessKey')
7
7
  const readFileKey = require('./readFileKey')
8
8
  const opsKeypair = require('../cryptography/opsKeypair')
9
9
 
10
- function invertForPrivateKeyName (filepath) {
10
+ async function invertForPrivateKeyName (filepath) {
11
11
  const PUBLIC_KEY_SCHEMA = 'DOTENV_PUBLIC_KEY'
12
12
  const PRIVATE_KEY_SCHEMA = 'DOTENV_PRIVATE_KEY'
13
13
 
14
- if (!fsx.existsSync(filepath)) {
14
+ if (!(await fsx.exists(filepath))) {
15
15
  return null
16
16
  }
17
17
 
18
- const envSrc = fsx.readFileX(filepath)
18
+ const envSrc = await fsx.readFileX(filepath)
19
19
  const envParsed = dotenvParse(envSrc)
20
20
 
21
21
  let publicKeyName
@@ -32,9 +32,9 @@ function invertForPrivateKeyName (filepath) {
32
32
  return null
33
33
  }
34
34
 
35
- function keyValues (filepath, opts = {}) {
35
+ async function keyValues (filepath, opts = {}) {
36
36
  let keysFilepath = opts.keysFilepath || null
37
- const opsOn = opts.opsOn === true
37
+ const noOps = opts.noOps === true
38
38
  const names = keyNames(filepath)
39
39
  const publicKeyName = names.publicKeyName // DOTENV_PUBLIC_KEY_${ENVIRONMENT}
40
40
  let privateKeyName = names.privateKeyName // DOTENV_PRIVATE_KEY_${ENVIRONMENT}
@@ -45,7 +45,7 @@ function keyValues (filepath, opts = {}) {
45
45
  // public key: process.env first, then .env*
46
46
  publicKey = readProcessKey(publicKeyName)
47
47
  if (!publicKey) {
48
- publicKey = readFileKey(publicKeyName, filepath) || null
48
+ publicKey = await readFileKey(publicKeyName, filepath) || null
49
49
  }
50
50
 
51
51
  // private key: process.env first, then .env.keys, then invert public key
@@ -57,28 +57,28 @@ function keyValues (filepath, opts = {}) {
57
57
  keysFilepath = path.resolve(path.dirname(filepath), '.env.keys') // typical scenario
58
58
  }
59
59
 
60
- privateKey = readFileKey(privateKeyName, keysFilepath)
60
+ privateKey = await readFileKey(privateKeyName, keysFilepath)
61
61
  }
62
62
  // invert
63
63
  if (!privateKey) {
64
- privateKeyName = invertForPrivateKeyName(filepath)
64
+ privateKeyName = await invertForPrivateKeyName(filepath)
65
65
  if (privateKeyName) {
66
66
  privateKey = readProcessKey(privateKeyName)
67
67
  if (!privateKey) {
68
- privateKey = readFileKey(privateKeyName, keysFilepath)
68
+ privateKey = await readFileKey(privateKeyName, keysFilepath)
69
69
  }
70
70
  }
71
71
  }
72
72
 
73
73
  // ops
74
- if (opsOn && !privateKey && publicKey && publicKey.length > 0) {
75
- const kp = opsKeypair(publicKey)
74
+ if (!noOps && !privateKey && publicKey && publicKey.length > 0) {
75
+ const kp = await opsKeypair(publicKey)
76
76
  privateKey = kp.privateKey
77
77
  }
78
78
 
79
79
  return {
80
80
  publicKeyValue: publicKey || null, // important to make sure name is rendered
81
- privateKeyValue: privateKey || null // importan to make sure name is rendered
81
+ privateKeyValue: privateKey || null // important to make sure name is rendered
82
82
  }
83
83
  }
84
84
 
@@ -0,0 +1,85 @@
1
+ const path = require('path')
2
+
3
+ const fsx = require('./../fsx')
4
+ const dotenvParse = require('./../dotenvParse')
5
+ const keyNames = require('./keyNames')
6
+ const readProcessKey = require('./readProcessKey')
7
+ const readFileKeySync = require('./readFileKeySync')
8
+ const opsKeypairSync = require('../cryptography/opsKeypairSync')
9
+
10
+ function invertForPrivateKeyName (filepath) {
11
+ const PUBLIC_KEY_SCHEMA = 'DOTENV_PUBLIC_KEY'
12
+ const PRIVATE_KEY_SCHEMA = 'DOTENV_PRIVATE_KEY'
13
+
14
+ if (!fsx.existsSync(filepath)) {
15
+ return null
16
+ }
17
+
18
+ const envSrc = fsx.readFileXSync(filepath)
19
+ const envParsed = dotenvParse(envSrc)
20
+
21
+ let publicKeyName
22
+ for (const keyName of Object.keys(envParsed)) {
23
+ if (keyName === PUBLIC_KEY_SCHEMA || keyName.startsWith(PUBLIC_KEY_SCHEMA)) {
24
+ publicKeyName = keyName // find DOTENV_PUBLIC_KEY* in filename
25
+ }
26
+ }
27
+
28
+ if (publicKeyName) {
29
+ return publicKeyName.replace(PUBLIC_KEY_SCHEMA, PRIVATE_KEY_SCHEMA) // return inverted (DOTENV_PUBLIC_KEY* -> DOTENV_PRIVATE_KEY*) if found
30
+ }
31
+
32
+ return null
33
+ }
34
+
35
+ function keyValuesSync (filepath, opts = {}) {
36
+ let keysFilepath = opts.keysFilepath || null
37
+ const noOps = opts.noOps === true
38
+ const names = keyNames(filepath)
39
+ const publicKeyName = names.publicKeyName // DOTENV_PUBLIC_KEY_${ENVIRONMENT}
40
+ let privateKeyName = names.privateKeyName // DOTENV_PRIVATE_KEY_${ENVIRONMENT}
41
+
42
+ let publicKey = null
43
+ let privateKey = null
44
+
45
+ // public key: process.env first, then .env*
46
+ publicKey = readProcessKey(publicKeyName)
47
+ if (!publicKey) {
48
+ publicKey = readFileKeySync(publicKeyName, filepath) || null
49
+ }
50
+
51
+ // private key: process.env first, then .env.keys, then invert public key
52
+ privateKey = readProcessKey(privateKeyName)
53
+ if (!privateKey) {
54
+ if (keysFilepath) { // user specified -fk flag
55
+ keysFilepath = path.resolve(keysFilepath)
56
+ } else {
57
+ keysFilepath = path.resolve(path.dirname(filepath), '.env.keys') // typical scenario
58
+ }
59
+
60
+ privateKey = readFileKeySync(privateKeyName, keysFilepath)
61
+ }
62
+ // invert
63
+ if (!privateKey) {
64
+ privateKeyName = invertForPrivateKeyName(filepath)
65
+ if (privateKeyName) {
66
+ privateKey = readProcessKey(privateKeyName)
67
+ if (!privateKey) {
68
+ privateKey = readFileKeySync(privateKeyName, keysFilepath)
69
+ }
70
+ }
71
+ }
72
+
73
+ // ops
74
+ if (!noOps && !privateKey && publicKey && publicKey.length > 0) {
75
+ const kp = opsKeypairSync(publicKey)
76
+ privateKey = kp.privateKey
77
+ }
78
+
79
+ return {
80
+ publicKeyValue: publicKey || null, // important to make sure name is rendered
81
+ privateKeyValue: privateKey || null // important to make sure name is rendered
82
+ }
83
+ }
84
+
85
+ module.exports = keyValuesSync
@@ -1,14 +1,16 @@
1
1
  const fsx = require('./../fsx')
2
2
  const dotenvParse = require('./../dotenvParse')
3
3
 
4
- function readFileKey (keyName, filepath) {
5
- if (fsx.existsSync(filepath)) {
6
- const src = fsx.readFileX(filepath)
7
- const parsed = dotenvParse(src)
8
-
9
- if (parsed[keyName] && parsed[keyName].length > 0) {
10
- return parsed[keyName]
11
- }
4
+ async function readFileKey (keyName, filepath) {
5
+ if (!(await fsx.exists(filepath))) {
6
+ return undefined
7
+ }
8
+
9
+ const src = await fsx.readFileX(filepath)
10
+ const parsed = dotenvParse(src)
11
+
12
+ if (parsed[keyName] && parsed[keyName].length > 0) {
13
+ return parsed[keyName]
12
14
  }
13
15
  }
14
16
 
@@ -0,0 +1,15 @@
1
+ const fsx = require('./../fsx')
2
+ const dotenvParse = require('./../dotenvParse')
3
+
4
+ function readFileKeySync (keyName, filepath) {
5
+ if (fsx.existsSync(filepath)) {
6
+ const src = fsx.readFileXSync(filepath)
7
+ const parsed = dotenvParse(src)
8
+
9
+ if (parsed[keyName] && parsed[keyName].length > 0) {
10
+ return parsed[keyName]
11
+ }
12
+ }
13
+ }
14
+
15
+ module.exports = readFileKeySync
@@ -1,33 +1,23 @@
1
1
  const SAMPLE_ENV_KIT = `
2
- # ── Database ─────────────────────────────────────
3
- DATABASE_URL="postgresql://postgres:pass@db.ref.supabase.co:5432/postgres"
2
+ HELLO="Dotenvx"
4
3
 
5
- # ── Auth ─────────────────────────────────────────
6
- AUTH0_CLIENT_ID="xxxx"
7
- AUTH0_CLIENT_SECRET="xxxx"
4
+ # ── Hosting ──────────────────────────────────────
5
+ AWS_ACCESS_KEY_ID="xxxx"
6
+ AWS_SECRET_ACCESS_KEY="xxxx"
7
+ DATABASE_URL="postgresql://postgres:pass@db.ref.supabase.co:5432/postgres"
8
+ VERCEL_TOKEN="vcp_xxxx"
8
9
 
9
- # ── AI / LLM ────────────────────────────────────
10
+ # ── AI ───────────────────────────────────────────
10
11
  OPENAI_API_KEY="sk-xxxx"
11
12
  ANTHROPIC_API_KEY="sk-ant-xxxx"
12
13
 
13
- # ── Email ────────────────────────────────────────
14
+ # ── Infrastructure ───────────────────────────────
15
+ AUTH0_CLIENT_ID="xxxx"
16
+ AUTH0_CLIENT_SECRET="xxxx"
14
17
  RESEND_API_KEY="re_xxxx"
15
-
16
- # ── Cloud Storage ────────────────────────────────
17
- AWS_ACCESS_KEY_ID="xxxx"
18
- AWS_SECRET_ACCESS_KEY="xxxx"
19
-
20
- # ── Analytics / Monitoring ───────────────────────
21
- SENTRY_DSN="https://hex@o1234.ingest.us.sentry.io/1234567"
22
-
23
- # ── Payments ─────────────────────────────────────
24
18
  STRIPE_API_KEY="sk_test_xxxx"
25
-
26
- # ── Feature Flags ────────────────────────────────
27
19
  FLAGSMITH_ENV_ID="xxxx"
28
-
29
- # ── CI/CD / Deployment ──────────────────────────
30
- VERCEL_TOKEN="vcp_xxxx"
20
+ SENTRY_DSN="https://hex@o1234.ingest.us.sentry.io/1234567"
31
21
  `.trimStart()
32
22
 
33
23
  module.exports = SAMPLE_ENV_KIT
package/src/lib/main.d.ts CHANGED
@@ -151,7 +151,12 @@ export interface DotenvConfigOptions {
151
151
  * Turn off Dotenvx Ops features - https://dotenvx.com/ops
152
152
  *
153
153
  * @default false
154
- * @example require('@dotenvx/dotenvx').config({ opsOff: true })
154
+ * @example require('@dotenvx/dotenvx').config({ noOps: true })
155
+ */
156
+ noOps?: boolean;
157
+
158
+ /**
159
+ * @deprecated use `noOps` instead.
155
160
  */
156
161
  opsOff?: boolean;
157
162
  }
@@ -210,7 +215,12 @@ export interface SetOptions {
210
215
  * Turn off Dotenvx Ops features - https://dotenvx.com/ops
211
216
  *
212
217
  * @default false
213
- * @example require('@dotenvx/dotenvx').set(key, value, { opsOff: true })
218
+ * @example require('@dotenvx/dotenvx').set(key, value, { noOps: true })
219
+ */
220
+ noOps?: boolean;
221
+
222
+ /**
223
+ * @deprecated use `noOps` instead.
214
224
  */
215
225
  opsOff?: boolean;
216
226
  }
@@ -285,7 +295,12 @@ export interface GetOptions {
285
295
  * Turn off Dotenvx Ops features - https://dotenvx.com/ops
286
296
  *
287
297
  * @default false
288
- * @example require('@dotenvx/dotenvx').get('KEY', { opsOff: true })
298
+ * @example require('@dotenvx/dotenvx').get('KEY', { noOps: true })
299
+ */
300
+ noOps?: boolean;
301
+
302
+ /**
303
+ * @deprecated use `noOps` instead.
289
304
  */
290
305
  opsOff?: boolean;
291
306
  }
package/src/lib/main.js CHANGED
@@ -12,6 +12,7 @@ const Sets = require('./services/sets')
12
12
  const Get = require('./services/get')
13
13
  const Keypair = require('./services/keypair')
14
14
  const Genexample = require('./services/genexample')
15
+ const Session = require('./../db/session')
15
16
 
16
17
  // helpers
17
18
  const buildEnvs = require('./helpers/buildEnvs')
@@ -39,27 +40,22 @@ const config = function (options = {}) {
39
40
  // envKeysFile
40
41
  const envKeysFile = options.envKeysFile
41
42
 
42
- // dotenvx-ops related
43
- const opsOn = options.opsOff !== true
44
-
45
43
  if (options) {
46
44
  setLogLevel(options)
47
45
  setLogName(options)
48
46
  setLogVersion(options)
49
47
  }
50
48
 
49
+ // dotenvx-ops related
50
+ const noOps = resolveNoOps(options)
51
+
51
52
  try {
52
53
  const envs = buildEnvs(options)
53
54
  const {
54
55
  processedEnvs,
55
56
  readableFilepaths,
56
57
  uniqueInjectedKeys
57
- } = new Run(envs, overload, processEnv, envKeysFile, opsOn).run()
58
-
59
- if (opsOn) {
60
- // removed radar feature for now. contact me at mot@dotenvx.com if still needed for your organization.
61
- // try { new Ops().observe({ beforeEnv, processedEnvs, afterEnv }) } catch {}
62
- }
58
+ } = new Run(envs, overload, processEnv, envKeysFile, noOps).runSync()
63
59
 
64
60
  let lastError
65
61
  /** @type {Record<string, string>} */
@@ -169,13 +165,13 @@ const set = function (key, value, options = {}) {
169
165
 
170
166
  const envs = buildEnvs(options)
171
167
  const envKeysFilepath = options.envKeysFile
172
- const opsOn = options.opsOff !== true
168
+ const noOps = resolveNoOps(options)
173
169
 
174
170
  const {
175
171
  processedEnvs,
176
172
  changedFilepaths,
177
173
  unchangedFilepaths
178
- } = new Sets(key, value, envs, encrypt, envKeysFilepath, opsOn).run()
174
+ } = new Sets(key, value, envs, encrypt, envKeysFilepath, noOps).runSync()
179
175
 
180
176
  let withEncryption = ''
181
177
 
@@ -191,7 +187,7 @@ const set = function (key, value, options = {}) {
191
187
  const message = error.messageWithHelp || (error.help ? `${error.message}. ${error.help}` : error.message)
192
188
  logger.warn(message)
193
189
  } else {
194
- fsx.writeFileX(processedEnv.filepath, processedEnv.envSrc)
190
+ fsx.writeFileXSync(processedEnv.filepath, processedEnv.envSrc)
195
191
 
196
192
  logger.verbose(`${processedEnv.key} set${withEncryption} (${processedEnv.envFilepath})`)
197
193
  logger.debug(`${processedEnv.key} set${withEncryption} to ${processedEnv.value} (${processedEnv.envFilepath})`)
@@ -211,7 +207,7 @@ const set = function (key, value, options = {}) {
211
207
  const keyAddedEnvFilepath = keyAddedEnv.envFilepath || changedFilepaths[0] || '.env'
212
208
  logger.success(`◈ encrypted ${key} (${keyAddedEnvFilepath})${keyAddedSuffix}`)
213
209
  } else if (unchangedFilepaths.length > 0) {
214
- logger.info(`○ no changes (${unchangedFilepaths})`)
210
+ logger.info(`○ no change (${unchangedFilepaths})`)
215
211
  } else {
216
212
  // do nothing
217
213
  }
@@ -228,12 +224,12 @@ const set = function (key, value, options = {}) {
228
224
  /* @type {import('./main').get} */
229
225
  const get = function (key, options = {}) {
230
226
  const envs = buildEnvs(options)
231
- const opsOn = options.opsOff !== true
227
+ const noOps = resolveNoOps(options)
232
228
 
233
229
  // ignore
234
230
  const ignore = options.ignore || []
235
231
 
236
- const { parsed, errors } = new Get(key, envs, options.overload, options.all, options.envKeysFile, opsOn).run()
232
+ const { parsed, errors } = new Get(key, envs, options.overload, options.all, options.envKeysFile, noOps).runSync()
237
233
 
238
234
  for (const error of errors || []) {
239
235
  if (ignore.includes(error.code)) {
@@ -286,9 +282,8 @@ const genexample = function (directory, envFile) {
286
282
  }
287
283
 
288
284
  /** @type {import('./main').keypair} */
289
- const keypair = function (envFile, key, envKeysFile = null, opsOff = false) {
290
- const opsOn = opsOff !== true
291
- const keypairs = new Keypair(envFile, envKeysFile, opsOn).run()
285
+ const keypair = function (envFile, key, envKeysFile = null, noOps = false) {
286
+ const keypairs = new Keypair(envFile, envKeysFile, noOps).runSync()
292
287
  if (key) {
293
288
  return keypairs[key]
294
289
  } else {
@@ -296,6 +291,11 @@ const keypair = function (envFile, key, envKeysFile = null, opsOff = false) {
296
291
  }
297
292
  }
298
293
 
294
+ function resolveNoOps (options = {}) {
295
+ const sesh = new Session()
296
+ return options.noOps === true || options.opsOff === true || sesh.noOpsSync()
297
+ }
298
+
299
299
  module.exports = {
300
300
  // dotenv proxies
301
301
  config,
@@ -25,19 +25,19 @@ const dotenvParse = require('./../helpers/dotenvParse')
25
25
  const detectEncoding = require('./../helpers/detectEncoding')
26
26
 
27
27
  class Decrypt {
28
- constructor (envs = [], key = [], excludeKey = [], envKeysFilepath = null, opsOn = false) {
28
+ constructor (envs = [], key = [], excludeKey = [], envKeysFilepath = null, noOps = false) {
29
29
  this.envs = determine(envs, process.env)
30
30
  this.key = key
31
31
  this.excludeKey = excludeKey
32
32
  this.envKeysFilepath = envKeysFilepath
33
- this.opsOn = opsOn
33
+ this.noOps = noOps
34
34
 
35
35
  this.processedEnvs = []
36
36
  this.changedFilepaths = new Set()
37
37
  this.unchangedFilepaths = new Set()
38
38
  }
39
39
 
40
- run () {
40
+ async run () {
41
41
  // example
42
42
  // envs [
43
43
  // { type: 'envFile', value: '.env' }
@@ -51,7 +51,7 @@ class Decrypt {
51
51
 
52
52
  for (const env of this.envs) {
53
53
  if (env.type === TYPE_ENV_FILE) {
54
- this._decryptEnvFile(env.value)
54
+ await this._decryptEnvFile(env.value)
55
55
  }
56
56
  }
57
57
 
@@ -62,7 +62,7 @@ class Decrypt {
62
62
  }
63
63
  }
64
64
 
65
- _decryptEnvFile (envFilepath) {
65
+ async _decryptEnvFile (envFilepath) {
66
66
  const row = {}
67
67
  row.keys = []
68
68
  row.type = TYPE_ENV_FILE
@@ -72,12 +72,12 @@ class Decrypt {
72
72
  row.envFilepath = envFilepath
73
73
 
74
74
  try {
75
- const encoding = detectEncoding(filepath)
76
- let envSrc = fsx.readFileX(filepath, { encoding })
75
+ const encoding = await detectEncoding(filepath)
76
+ let envSrc = await fsx.readFileX(filepath, { encoding })
77
77
  const envParsed = dotenvParse(envSrc)
78
78
 
79
79
  const { privateKeyName } = keyNames(envFilepath)
80
- const { privateKeyValue } = keyValues(envFilepath, { keysFilepath: this.envKeysFilepath, opsOn: this.opsOn })
80
+ const { privateKeyValue } = await keyValues(envFilepath, { keysFilepath: this.envKeysFilepath, noOps: this.noOps })
81
81
 
82
82
  row.privateKey = privateKeyValue
83
83
  row.privateKeyName = privateKeyName
@@ -29,12 +29,12 @@ const detectEncoding = require('./../helpers/detectEncoding')
29
29
  const SAMPLE_ENV_KIT = require('./../helpers/kits/sample')
30
30
 
31
31
  class Encrypt {
32
- constructor (envs = [], key = [], excludeKey = [], envKeysFilepath = null, opsOn = false, noCreate = false) {
32
+ constructor (envs = [], key = [], excludeKey = [], envKeysFilepath = null, noOps = false, noCreate = false) {
33
33
  this.envs = determine(envs, process.env)
34
34
  this.key = key
35
35
  this.excludeKey = excludeKey
36
36
  this.envKeysFilepath = envKeysFilepath
37
- this.opsOn = opsOn
37
+ this.noOps = noOps
38
38
  this.noCreate = noCreate
39
39
 
40
40
  this.processedEnvs = []
@@ -42,7 +42,7 @@ class Encrypt {
42
42
  this.unchangedFilepaths = new Set()
43
43
  }
44
44
 
45
- run () {
45
+ async run () {
46
46
  // example
47
47
  // envs [
48
48
  // { type: 'envFile', value: '.env' }
@@ -56,7 +56,7 @@ class Encrypt {
56
56
 
57
57
  for (const env of this.envs) {
58
58
  if (env.type === TYPE_ENV_FILE) {
59
- this._encryptEnvFile(env.value)
59
+ await this._encryptEnvFile(env.value)
60
60
  }
61
61
  }
62
62
 
@@ -67,10 +67,11 @@ class Encrypt {
67
67
  }
68
68
  }
69
69
 
70
- _encryptEnvFile (envFilepath) {
70
+ async _encryptEnvFile (envFilepath) {
71
71
  const row = {}
72
72
  row.keys = []
73
73
  row.type = TYPE_ENV_FILE
74
+ let fileCreated = false
74
75
 
75
76
  const filepath = path.resolve(envFilepath)
76
77
  row.filepath = filepath
@@ -79,14 +80,16 @@ class Encrypt {
79
80
  try {
80
81
  // if noCreate is on then detectEncoding will throw and we'll halt the calls
81
82
  // but if noCreate is false then create the file if it doesn't exist
82
- if (!fsx.existsSync(filepath) && !this.noCreate) {
83
- fsx.writeFileX(filepath, SAMPLE_ENV_KIT)
83
+ if (!(await fsx.exists(filepath)) && !this.noCreate) {
84
+ await fsx.writeFileX(filepath, SAMPLE_ENV_KIT)
85
+ fileCreated = true
84
86
  }
85
- const encoding = detectEncoding(filepath)
86
- let envSrc = fsx.readFileX(filepath, { encoding })
87
+ const encoding = await detectEncoding(filepath)
88
+ let envSrc = await fsx.readFileX(filepath, { encoding })
87
89
  if (envSrc.trim().length === 0) {
88
90
  envSrc = SAMPLE_ENV_KIT
89
91
  row.kitCreated = 'sample'
92
+ row.changed = true
90
93
  }
91
94
  const envParsed = dotenvParse(envSrc)
92
95
 
@@ -94,11 +97,11 @@ class Encrypt {
94
97
  let privateKey
95
98
 
96
99
  const { publicKeyName, privateKeyName } = keyNames(envFilepath)
97
- const { publicKeyValue, privateKeyValue } = keyValues(envFilepath, { keysFilepath: this.envKeysFilepath, opsOn: this.opsOn })
100
+ const { publicKeyValue, privateKeyValue } = await keyValues(envFilepath, { keysFilepath: this.envKeysFilepath, noOps: this.noOps })
98
101
 
99
102
  // first pass - provision
100
103
  if (!privateKeyValue && !publicKeyValue) {
101
- const prov = provision({ envSrc, envFilepath, keysFilepath: this.envKeysFilepath, opsOn: this.opsOn })
104
+ const prov = await provision({ envSrc, envFilepath, keysFilepath: this.envKeysFilepath, noOps: this.noOps })
102
105
  envSrc = prov.envSrc
103
106
  publicKey = prov.publicKey
104
107
  privateKey = prov.privateKey
@@ -148,6 +151,9 @@ class Encrypt {
148
151
  }
149
152
 
150
153
  row.envSrc = envSrc
154
+ if (fileCreated) {
155
+ row.changed = true
156
+ }
151
157
  if (row.changed) {
152
158
  this.changedFilepaths.add(envFilepath)
153
159
  } else {
@@ -39,7 +39,7 @@ class Genexample {
39
39
  }
40
40
 
41
41
  // get the original src
42
- let src = fsx.readFileX(filepath)
42
+ let src = fsx.readFileXSync(filepath)
43
43
  const parsed = dotenvParse(src)
44
44
  for (const key in parsed) {
45
45
  // used later
@@ -63,7 +63,7 @@ class Genexample {
63
63
  }
64
64
  } else {
65
65
  // it already exists (which means the user might have it modified a way in which they prefer, so replace exampleSrc with their existing .env.example)
66
- exampleSrc = fsx.readFileX(this.exampleFilepath)
66
+ exampleSrc = fsx.readFileXSync(this.exampleFilepath)
67
67
 
68
68
  const parsed = dotenvParse(exampleSrc)
69
69
  for (const key of [...keys]) {
@@ -2,19 +2,28 @@ const Run = require('./run')
2
2
  const Errors = require('./../helpers/errors')
3
3
 
4
4
  class Get {
5
- constructor (key, envs = [], overload = false, all = false, envKeysFilepath = null, opsOn = true) {
5
+ constructor (key, envs = [], overload = false, all = false, envKeysFilepath = null, noOps = false) {
6
6
  this.key = key
7
7
  this.envs = envs
8
8
  this.overload = overload
9
9
  this.all = all
10
10
  this.envKeysFilepath = envKeysFilepath
11
- this.opsOn = opsOn
11
+ this.noOps = noOps
12
12
  }
13
13
 
14
- run () {
14
+ runSync () {
15
15
  const processEnv = { ...process.env }
16
- const { processedEnvs } = new Run(this.envs, this.overload, processEnv, this.envKeysFilepath, this.opsOn).run()
16
+ const { processedEnvs } = new Run(this.envs, this.overload, processEnv, this.envKeysFilepath, this.noOps).runSync()
17
+ return this._result(processedEnvs, processEnv)
18
+ }
19
+
20
+ async run () {
21
+ const processEnv = { ...process.env }
22
+ const { processedEnvs } = await new Run(this.envs, this.overload, processEnv, this.envKeysFilepath, this.noOps).run()
23
+ return this._result(processedEnvs, processEnv)
24
+ }
17
25
 
26
+ _result (processedEnvs, processEnv) {
18
27
  const errors = []
19
28
  for (const processedEnv of processedEnvs) {
20
29
  for (const error of processedEnv.errors) {
@@ -32,27 +41,27 @@ class Get {
32
41
  }
33
42
 
34
43
  return { parsed, errors }
35
- } else {
36
- // if user wants to return ALL envs (even prior set on machine)
37
- if (this.all) {
38
- return { parsed: processEnv, errors }
39
- }
44
+ }
40
45
 
41
- // typical scenario - return only envs that were identified in the .env file
42
- // iterate over all processedEnvs.parsed and grab from processEnv
43
- /** @type {Record<string, string>} */
44
- const parsed = {}
45
- for (const processedEnv of processedEnvs) {
46
- // parsed means we saw the key in a file or --env flag. this effectively filters out any preset machine envs - while still respecting complex evaluating, expansion, and overload. in other words, the value might be the machine value because the key was displayed in a .env file
47
- if (processedEnv.parsed) {
48
- for (const key of Object.keys(processedEnv.parsed)) {
49
- parsed[key] = processEnv[key]
50
- }
46
+ // if user wants to return ALL envs (even prior set on machine)
47
+ if (this.all) {
48
+ return { parsed: processEnv, errors }
49
+ }
50
+
51
+ // typical scenario - return only envs that were identified in the .env file
52
+ // iterate over all processedEnvs.parsed and grab from processEnv
53
+ /** @type {Record<string, string>} */
54
+ const parsed = {}
55
+ for (const processedEnv of processedEnvs) {
56
+ // parsed means we saw the key in a file or --env flag. this effectively filters out any preset machine envs - while still respecting complex evaluating, expansion, and overload. in other words, the value might be the machine value because the key was displayed in a .env file
57
+ if (processedEnv.parsed) {
58
+ for (const key of Object.keys(processedEnv.parsed)) {
59
+ parsed[key] = processEnv[key]
51
60
  }
52
61
  }
53
-
54
- return { parsed, errors }
55
62
  }
63
+
64
+ return { parsed, errors }
56
65
  }
57
66
  }
58
67