@dotenvx/dotenvx 1.61.5 → 1.62.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 CHANGED
@@ -2,7 +2,32 @@
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.61.5...main)
5
+ [Unreleased](https://github.com/dotenvx/dotenvx/compare/v1.62.0...main)
6
+
7
+ ## [1.62.0](https://github.com/dotenvx/dotenvx/compare/v1.61.6...v1.62.0) (2026-04-23)
8
+
9
+ ### Added
10
+
11
+ * Add support for `config({ envs })`. unlocks simpler cloudflare worker integration ([#803](https://github.com/dotenvx/dotenvx/pull/803))
12
+
13
+ ```js
14
+ import envSrc from '../.env.txt'
15
+ import dotenvx from '@dotenvx/dotenvx'
16
+
17
+ export default {
18
+ async fetch(request, env, ctx) {
19
+ dotenvx.config({ envs: [{ type: 'env', value: envSrc, privateKeyName: 'DOTENV_PRIVATE_KEY' }] processEnv: env })
20
+
21
+ return new Response(`Hello ${env.HELLO}`)
22
+ },
23
+ };
24
+ ```
25
+
26
+ ## [1.61.6](https://github.com/dotenvx/dotenvx/compare/v1.61.5...v1.61.6) (2026-04-23)
27
+
28
+ ### Changed
29
+
30
+ * Guard against command substitution following `encrypted:` ([#802](https://github.com/dotenvx/dotenvx/pull/802))
6
31
 
7
32
  ## [1.61.5](https://github.com/dotenvx/dotenvx/compare/v1.61.4...v1.61.5) (2026-04-22)
8
33
 
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.61.5",
2
+ "version": "1.62.0",
3
3
  "name": "@dotenvx/dotenvx",
4
4
  "description": "secrets for agents–from the creator of `dotenv`",
5
5
  "author": "@motdotla",
@@ -8,6 +8,7 @@ const createSpinner = require('../../lib/helpers/createSpinner')
8
8
  const Session = require('../../db/session')
9
9
 
10
10
  const conventions = require('./../../lib/helpers/conventions')
11
+ const { determine } = require('./../../lib/helpers/envResolution')
11
12
 
12
13
  async function run () {
13
14
  const options = this.opts()
@@ -45,6 +46,7 @@ async function run () {
45
46
  } else {
46
47
  envs = this.envs
47
48
  }
49
+ envs = determine(envs, process.env)
48
50
 
49
51
  const {
50
52
  processedEnvs,
@@ -2,6 +2,10 @@ const conventions = require('./conventions')
2
2
  const dotenvOptionPaths = require('./dotenvOptionPaths')
3
3
 
4
4
  function buildEnvs (options) {
5
+ if (options.envs) {
6
+ return options.envs
7
+ }
8
+
5
9
  // build envs using user set option.path
6
10
  const optionPaths = dotenvOptionPaths(options) // [ '.env' ]
7
11
 
@@ -23,7 +23,7 @@ function executeExtension (ext, command, rawArgs) {
23
23
  const result = childProcess.spawnSync(`dotenvx-ext-${command}`, forwardedArgs, { stdio: 'inherit', env })
24
24
  if (result.error) {
25
25
  // list known extension here for convenience to the user
26
- if (['vault', 'hub'].includes(command)) {
26
+ if (['vault'].includes(command)) {
27
27
  logger.warn(`[INSTALLATION_NEEDED] install dotenvx-ext-${command} to use [dotenvx ext ${command}] commands`)
28
28
  logger.help('? see installation instructions [https://github.com/dotenvx/dotenvx-ext-vault]')
29
29
  } else {
@@ -1,4 +1,5 @@
1
1
  const decryptKeyValue = require('./cryptography/decryptKeyValue')
2
+ const isEncrypted = require('./cryptography/isEncrypted')
2
3
  const evalKeyValue = require('./evalKeyValue')
3
4
  const resolveEscapeSequences = require('./resolveEscapeSequences')
4
5
 
@@ -44,9 +45,11 @@ class Parse {
44
45
  this.errors.push(e)
45
46
  }
46
47
 
48
+ const encryptedPrefixed = isEncrypted(this.parsed[key]) // do not eval encrypted prefix
49
+
47
50
  // eval empty, double, or backticks
48
51
  let evaled = false
49
- if (quote !== "'" && (!this.inProcessEnv(key) || this.processEnv[key] === this.parsed[key])) {
52
+ if (!encryptedPrefixed && quote !== "'" && (!this.inProcessEnv(key) || this.processEnv[key] === this.parsed[key])) {
50
53
  const priorEvaled = this.parsed[key]
51
54
  // eval
52
55
  try {
@@ -60,7 +63,7 @@ class Parse {
60
63
  }
61
64
 
62
65
  // expand empty, double, or backticks
63
- if (!evaled && quote !== "'" && (!this.processEnv[key] || this.overload)) {
66
+ if (!encryptedPrefixed && !evaled && quote !== "'" && (!this.processEnv[key] || this.overload)) {
64
67
  this.parsed[key] = resolveEscapeSequences(this.expand(this.parsed[key]))
65
68
  }
66
69
 
package/src/lib/main.d.ts CHANGED
@@ -50,6 +50,15 @@ export function parse<T extends DotenvParseOutput = DotenvParseOutput>(
50
50
  ): T;
51
51
 
52
52
  export interface DotenvConfigOptions {
53
+ /**
54
+ * Specify explicit env sources. When set, `path` and `convention` are ignored.
55
+ *
56
+ * @default undefined
57
+ * @example require('@dotenvx/dotenvx').config({ envs: [{ type: 'envFile', value: '.env' }] })
58
+ * @example require('@dotenvx/dotenvx').config({ envs: [{ type: 'env', value: 'HELLO=World', privateKeyName: 'DOTENV_PRIVATE_KEY' }] })
59
+ */
60
+ envs?: DotenvConfigEnv[];
61
+
53
62
  /**
54
63
  * Specify a custom path if your file containing environment variables is located elsewhere.
55
64
  * Can also be an array of strings, specifying multiple paths.
@@ -161,6 +170,21 @@ export interface DotenvConfigOptions {
161
170
  opsOff?: boolean;
162
171
  }
163
172
 
173
+ export type DotenvConfigEnv =
174
+ | DotenvConfigEnvFile
175
+ | DotenvConfigEnvSrc;
176
+
177
+ export interface DotenvConfigEnvFile {
178
+ type: 'envFile';
179
+ value: string | URL;
180
+ }
181
+
182
+ export interface DotenvConfigEnvSrc {
183
+ type: 'env';
184
+ value: string | Buffer;
185
+ privateKeyName?: string;
186
+ }
187
+
164
188
  export interface DotenvConfigOutput {
165
189
  error?: Error;
166
190
  parsed?: DotenvParseOutput;
package/src/lib/main.js CHANGED
@@ -16,6 +16,7 @@ const Session = require('./../db/session')
16
16
 
17
17
  // helpers
18
18
  const buildEnvs = require('./helpers/buildEnvs')
19
+ const { determine } = require('./helpers/envResolution')
19
20
  const Parse = require('./helpers/parse')
20
21
  const fsx = require('./helpers/fsx')
21
22
  const localDisplayPath = require('./helpers/localDisplayPath')
@@ -50,7 +51,10 @@ const config = function (options = {}) {
50
51
  const noOps = resolveNoOps(options)
51
52
 
52
53
  try {
53
- const envs = buildEnvs(options)
54
+ let envs = buildEnvs(options)
55
+ if (!options.envs) {
56
+ envs = determine(envs, processEnv)
57
+ }
54
58
  const {
55
59
  processedEnvs,
56
60
  readableFilepaths,
@@ -103,7 +107,7 @@ const config = function (options = {}) {
103
107
  }
104
108
  }
105
109
 
106
- let msg = `injecting env (${uniqueInjectedKeys.length})`
110
+ let msg = `injected env (${uniqueInjectedKeys.length})`
107
111
  if (readableFilepaths.length > 0) {
108
112
  msg += ` from ${readableFilepaths.join(', ')}`
109
113
  }
@@ -1,5 +1,6 @@
1
1
  const Run = require('./run')
2
2
  const Errors = require('./../helpers/errors')
3
+ const { determine } = require('./../helpers/envResolution')
3
4
 
4
5
  class Get {
5
6
  constructor (key, envs = [], overload = false, all = false, envKeysFilepath = null, noOps = false) {
@@ -13,13 +14,15 @@ class Get {
13
14
 
14
15
  runSync () {
15
16
  const processEnv = { ...process.env }
16
- const { processedEnvs } = new Run(this.envs, this.overload, processEnv, this.envKeysFilepath, this.noOps).runSync()
17
+ const envs = determine(this.envs, processEnv)
18
+ const { processedEnvs } = new Run(envs, this.overload, processEnv, this.envKeysFilepath, this.noOps).runSync()
17
19
  return this._result(processedEnvs, processEnv)
18
20
  }
19
21
 
20
22
  async run () {
21
23
  const processEnv = { ...process.env }
22
- const { processedEnvs } = await new Run(this.envs, this.overload, processEnv, this.envKeysFilepath, this.noOps).run()
24
+ const envs = determine(this.envs, processEnv)
25
+ const { processedEnvs } = await new Run(envs, this.overload, processEnv, this.envKeysFilepath, this.noOps).run()
23
26
  return this._result(processedEnvs, processEnv)
24
27
  }
25
28
 
@@ -15,13 +15,9 @@ const {
15
15
  keyValuesSync
16
16
  } = require('./../helpers/keyResolution')
17
17
 
18
- const {
19
- determine
20
- } = require('./../helpers/envResolution')
21
-
22
18
  class Run {
23
19
  constructor (envs = [], overload = false, processEnv = process.env, envKeysFilepath = null, noOps = false) {
24
- this.envs = determine(envs, processEnv)
20
+ this.envs = envs
25
21
  this.overload = overload
26
22
  this.processEnv = processEnv
27
23
  this.envKeysFilepath = envKeysFilepath
@@ -46,7 +42,7 @@ class Run {
46
42
  if (env.type === TYPE_ENV_FILE) {
47
43
  this._injectEnvFileSync(env.value)
48
44
  } else if (env.type === TYPE_ENV) {
49
- this._injectEnv(env.value)
45
+ this._injectEnv(env.value, env.privateKeyName)
50
46
  }
51
47
  }
52
48
 
@@ -72,7 +68,7 @@ class Run {
72
68
  if (env.type === TYPE_ENV_FILE) {
73
69
  await this._injectEnvFile(env.value)
74
70
  } else if (env.type === TYPE_ENV) {
75
- this._injectEnv(env.value)
71
+ this._injectEnv(env.value, env.privateKeyName)
76
72
  }
77
73
  }
78
74
 
@@ -86,19 +82,23 @@ class Run {
86
82
  }
87
83
  }
88
84
 
89
- _injectEnv (env) {
85
+ _injectEnv (env, privateKeyName = null) {
90
86
  const row = {}
91
87
  row.type = TYPE_ENV
92
88
  row.string = env
93
89
 
94
90
  try {
91
+ const privateKey = privateKeyName ? this.processEnv[privateKeyName] || null : null
92
+
95
93
  const {
96
94
  parsed,
97
95
  errors,
98
96
  injected,
99
97
  preExisted
100
- } = new Parse(env, null, this.processEnv, this.overload).run()
98
+ } = new Parse(env, privateKey, this.processEnv, this.overload, privateKeyName).run()
101
99
 
100
+ row.privateKeyName = privateKeyName
101
+ row.privateKey = privateKey
102
102
  row.parsed = parsed
103
103
  row.errors = errors
104
104
  row.injected = injected