@dotenvx/dotenvx 1.61.6 → 1.63.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,43 @@
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.6...main)
5
+ [Unreleased](https://github.com/dotenvx/dotenvx/compare/v1.63.0...main)
6
+
7
+ ## [1.63.0](https://github.com/dotenvx/dotenvx/compare/v1.62.0...v1.63.0) (2026-04-24)
8
+
9
+ ### Added
10
+
11
+ * Add support for encrypted values passed to `--env` flag ([#804](https://github.com/dotenvx/dotenvx/pull/804))
12
+ * Add support for `--format=colon` in order to support cloudflare's wrangler `--var` flag format ([#804](https://github.com/dotenvx/dotenvx/pull/804))
13
+
14
+ ## [1.62.0](https://github.com/dotenvx/dotenvx/compare/v1.61.6...v1.62.0) (2026-04-23)
15
+
16
+ ### Added
17
+
18
+ * Add support for `config({ envs })`. unlocks simpler cloudflare worker integration ([#803](https://github.com/dotenvx/dotenvx/pull/803))
19
+
20
+ ```js
21
+ // src/index.js
22
+ import envSrc from '../.env.txt'
23
+ import dotenvx from '@dotenvx/dotenvx'
24
+
25
+ const config = dotenvx.config({ envs: [{ type: 'env', value: envSrc, privateKeyName: 'DOTENV_PRIVATE_KEY' }] })
26
+ const envx = config.parsed
27
+
28
+ export default {
29
+ async fetch(request, env, ctx) {
30
+ return new Response(`Hello ${envx.HELLO}`)
31
+ }
32
+ }
33
+ ```
34
+ ```json
35
+ "scripts": {
36
+ "deploy": "wrangler deploy",
37
+ "dev": "wrangler dev --var $(dotenvx keypair -f .env.txt --format=colon)",
38
+ "start": "wrangler dev --var $(dotenvx keypair -f .env.txt --format=colon)",
39
+ "test": "vitest"
40
+ },
41
+ ```
6
42
 
7
43
  ## [1.61.6](https://github.com/dotenvx/dotenvx/compare/v1.61.5...v1.61.6) (2026-04-23)
8
44
 
package/README.md CHANGED
@@ -150,6 +150,28 @@ $ dotenvx run -- npx tsx index.ts
150
150
  Hello Dotenvx
151
151
  ```
152
152
 
153
+ </details>
154
+ <details><summary>Cloudflare Workers ⛅️</summary><br>
155
+
156
+ ```sh
157
+ cp .env .env.txt
158
+ ```
159
+
160
+ ```js
161
+ import envSrc from '../.env.txt' // txt so cloudflare includes it in deployment
162
+ import dotenvx from '@dotenvx/dotenvx'
163
+
164
+ // use `wrangler secret put DOTENV_PRIVATE_KEY` to set decryption key once
165
+ const config = dotenvx.config({ envs: [{ type: 'env', value: envSrc, privateKeyName: 'DOTENV_PRIVATE_KEY' }] })
166
+ const envx = config.parsed
167
+
168
+ export default {
169
+ async fetch(request, env, ctx) {
170
+ return new Response(`Hello ${envx.HELLO}`)
171
+ }
172
+ }
173
+ ```
174
+
153
175
  </details>
154
176
  <details><summary>Deno 🦕</summary><br>
155
177
 
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.61.6",
2
+ "version": "1.63.0",
3
3
  "name": "@dotenvx/dotenvx",
4
4
  "description": "secrets for agents–from the creator of `dotenv`",
5
5
  "author": "@motdotla",
@@ -66,6 +66,14 @@ async function get (key) {
66
66
  }
67
67
  inline = inline.trim()
68
68
 
69
+ console.log(inline)
70
+ } else if (options.format === 'colon') {
71
+ let inline = ''
72
+ for (const [key, value] of Object.entries(parsed)) {
73
+ inline += `${key}:${value} `
74
+ }
75
+ inline = inline.trim()
76
+
69
77
  console.log(inline)
70
78
  } else {
71
79
  let space = 0
@@ -22,11 +22,18 @@ async function keypair (key) {
22
22
 
23
23
  if (spinner) spinner.stop()
24
24
  if (typeof results === 'object' && results !== null) {
25
- // inline shell format - env $(dotenvx keypair --format=shell) your-command
26
25
  if (options.format === 'shell') {
27
26
  let inline = ''
28
- for (const [key, value] of Object.entries(results)) {
29
- inline += `${key}=${value || ''} `
27
+ for (const [keyName, value] of Object.entries(results)) {
28
+ inline += `${keyName}=${value || ''} `
29
+ }
30
+ inline = inline.trim()
31
+
32
+ console.log(inline)
33
+ } else if (options.format === 'colon') {
34
+ let inline = ''
35
+ for (const [keyName, value] of Object.entries(results)) {
36
+ inline += `${keyName}:${value || ''} `
30
37
  }
31
38
  inline = inline.trim()
32
39
 
@@ -44,6 +51,8 @@ async function keypair (key) {
44
51
  if (results === undefined) {
45
52
  console.log('')
46
53
  process.exit(1)
54
+ } else if (options.format === 'colon' && key) {
55
+ console.log(`${key}:${results}`)
47
56
  } else {
48
57
  console.log(results)
49
58
  }
@@ -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,
@@ -92,7 +92,7 @@ program.command('get')
92
92
  .option('-a, --all', 'include all machine envs as well')
93
93
  .option('-pp, --pretty-print', 'pretty print output')
94
94
  .option('--pp', 'pretty print output (alias)')
95
- .option('--format <type>', 'format of the output (json, shell, eval)', 'json')
95
+ .option('--format <type>', 'format of the output (json, shell, colon, eval)', 'json')
96
96
  .option('--no-ops', 'disable dotenvx-ops features')
97
97
  .action(function (...args) {
98
98
  this.envs = envs
@@ -171,7 +171,7 @@ program.command('keypair')
171
171
  .option('--no-ops', 'disable dotenvx-ops features')
172
172
  .option('-pp, --pretty-print', 'pretty print output')
173
173
  .option('--pp', 'pretty print output (alias)')
174
- .option('--format <type>', 'format of the output (json, shell)', 'json')
174
+ .option('--format <type>', 'format of the output (json, shell, colon)', 'json')
175
175
  .action(function (...args) {
176
176
  return require('./actions/keypair').apply(this, args)
177
177
  })
@@ -1,6 +1,7 @@
1
1
  const path = require('path')
2
2
  const childProcess = require('child_process')
3
3
  const util = require('util')
4
+ const { logger } = require('../../shared/logger')
4
5
 
5
6
  const execFile = util.promisify(childProcess.execFile)
6
7
 
@@ -98,6 +99,8 @@ class Ops {
98
99
  }
99
100
 
100
101
  _execSync (binary, args) {
102
+ logger.debug(binary)
103
+ logger.debug(args)
101
104
  return childProcess.execFileSync(binary, args).toString().trim()
102
105
  }
103
106
 
@@ -130,13 +133,17 @@ class Ops {
130
133
  this._execSync(npmBin, ['--version'])
131
134
  this._binarySync = npmBin
132
135
  return this._binarySync
133
- } catch (_e) {}
136
+ } catch (err) {
137
+ logger.debug(err.message)
138
+ }
134
139
 
135
140
  try {
136
141
  this._execSync('dotenvx-ops', ['--version'])
137
142
  this._binarySync = 'dotenvx-ops'
138
143
  return this._binarySync
139
- } catch (_e) {}
144
+ } catch (err) {
145
+ logger.debug(err.message)
146
+ }
140
147
 
141
148
  this._binarySync = null
142
149
  return null
@@ -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
 
@@ -0,0 +1,13 @@
1
+ const path = require('path')
2
+
3
+ function canonicalEnvFilename (filepath) {
4
+ let filename = path.basename(filepath).toLowerCase()
5
+
6
+ if (filename.startsWith('.env') && filename.endsWith('.txt')) {
7
+ filename = filename.slice(0, -4)
8
+ }
9
+
10
+ return filename
11
+ }
12
+
13
+ module.exports = canonicalEnvFilename
@@ -1,7 +1,7 @@
1
- const path = require('path')
1
+ const canonicalEnvFilename = require('./../canonicalEnvFilename')
2
2
 
3
3
  function environment (filepath) {
4
- const filename = path.basename(filepath).toLowerCase()
4
+ const filename = canonicalEnvFilename(filepath)
5
5
 
6
6
  const parts = filename.split('.')
7
7
  const possibleEnvironmentList = [...parts.slice(2)]
@@ -2,6 +2,7 @@ module.exports = {
2
2
  keyNames: require('./keyNames'),
3
3
  keyValues: require('./keyValues'),
4
4
  keyValuesSync: require('./keyValuesSync'),
5
+ keyValuesFromEnvSrc: require('./keyValuesFromEnvSrc'),
5
6
 
6
7
  // private
7
8
  // private keys are resolved via keyValuesSync()
@@ -1,8 +1,8 @@
1
- const path = require('path')
1
+ const canonicalEnvFilename = require('./../canonicalEnvFilename')
2
2
  const environment = require('./../envResolution/environment')
3
3
 
4
4
  function keyNames (filepath) {
5
- const filename = path.basename(filepath).toLowerCase()
5
+ const filename = canonicalEnvFilename(filepath)
6
6
 
7
7
  // .env
8
8
  if (filename === '.env') {
@@ -0,0 +1,66 @@
1
+ const path = require('path')
2
+
3
+ const dotenvParse = require('./../dotenvParse')
4
+ const readFileKeySync = require('./readFileKeySync')
5
+ const opsKeypairSync = require('../cryptography/opsKeypairSync')
6
+
7
+ const PUBLIC_KEY_SCHEMA = 'DOTENV_PUBLIC_KEY'
8
+ const PRIVATE_KEY_SCHEMA = 'DOTENV_PRIVATE_KEY'
9
+
10
+ function readProcessKey (processEnv, keyName) {
11
+ if (processEnv[keyName] && processEnv[keyName].length > 0) {
12
+ return processEnv[keyName]
13
+ }
14
+ }
15
+
16
+ function publicKeyNameFromEnvSrc (envParsed) {
17
+ for (const keyName of Object.keys(envParsed)) {
18
+ if (keyName === PUBLIC_KEY_SCHEMA || keyName.startsWith(PUBLIC_KEY_SCHEMA)) {
19
+ return keyName
20
+ }
21
+ }
22
+
23
+ return null
24
+ }
25
+
26
+ function keyValuesFromEnvSrc (src, privateKeyName = null, opts = {}) {
27
+ let keysFilepath = opts.keysFilepath || null
28
+ const noOps = opts.noOps === true
29
+ const processEnv = opts.processEnv || process.env
30
+ const envParsed = dotenvParse(src)
31
+
32
+ const publicKeyName = publicKeyNameFromEnvSrc(envParsed)
33
+ const publicKeyValue = publicKeyName ? readProcessKey(processEnv, publicKeyName) || envParsed[publicKeyName] || null : null
34
+
35
+ if (!privateKeyName && publicKeyName) {
36
+ privateKeyName = publicKeyName.replace(PUBLIC_KEY_SCHEMA, PRIVATE_KEY_SCHEMA)
37
+ }
38
+
39
+ let privateKeyValue = null
40
+ if (privateKeyName) {
41
+ privateKeyValue = readProcessKey(processEnv, privateKeyName)
42
+
43
+ if (!privateKeyValue) {
44
+ if (keysFilepath) {
45
+ keysFilepath = path.resolve(keysFilepath)
46
+ } else {
47
+ keysFilepath = path.resolve('.env.keys')
48
+ }
49
+
50
+ privateKeyValue = readFileKeySync(privateKeyName, keysFilepath)
51
+ }
52
+ }
53
+
54
+ if (!noOps && !privateKeyValue && publicKeyValue && publicKeyValue.length > 0) {
55
+ const kp = opsKeypairSync(publicKeyValue)
56
+ privateKeyValue = kp.privateKey
57
+ }
58
+
59
+ return {
60
+ publicKeyValue: publicKeyValue || null,
61
+ privateKeyValue: privateKeyValue || null,
62
+ privateKeyName: privateKeyName || null
63
+ }
64
+ }
65
+
66
+ module.exports = keyValuesFromEnvSrc
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,
@@ -272,6 +276,14 @@ const get = function (key, options = {}) {
272
276
  }
273
277
  inline = inline.trim()
274
278
 
279
+ return inline
280
+ } else if (options.format === 'colon') {
281
+ let inline = ''
282
+ for (const [key, value] of Object.entries(parsed)) {
283
+ inline += `${key}:${value} `
284
+ }
285
+ inline = inline.trim()
286
+
275
287
  return inline
276
288
  } else {
277
289
  return parsed
@@ -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
 
@@ -12,16 +12,13 @@ const detectEncodingSync = require('./../helpers/detectEncodingSync')
12
12
  const {
13
13
  keyNames,
14
14
  keyValues,
15
- keyValuesSync
15
+ keyValuesSync,
16
+ keyValuesFromEnvSrc
16
17
  } = require('./../helpers/keyResolution')
17
18
 
18
- const {
19
- determine
20
- } = require('./../helpers/envResolution')
21
-
22
19
  class Run {
23
20
  constructor (envs = [], overload = false, processEnv = process.env, envKeysFilepath = null, noOps = false) {
24
- this.envs = determine(envs, processEnv)
21
+ this.envs = envs
25
22
  this.overload = overload
26
23
  this.processEnv = processEnv
27
24
  this.envKeysFilepath = envKeysFilepath
@@ -46,7 +43,7 @@ class Run {
46
43
  if (env.type === TYPE_ENV_FILE) {
47
44
  this._injectEnvFileSync(env.value)
48
45
  } else if (env.type === TYPE_ENV) {
49
- this._injectEnv(env.value)
46
+ this._injectEnv(env.value, env.privateKeyName)
50
47
  }
51
48
  }
52
49
 
@@ -72,7 +69,7 @@ class Run {
72
69
  if (env.type === TYPE_ENV_FILE) {
73
70
  await this._injectEnvFile(env.value)
74
71
  } else if (env.type === TYPE_ENV) {
75
- this._injectEnv(env.value)
72
+ this._injectEnv(env.value, env.privateKeyName)
76
73
  }
77
74
  }
78
75
 
@@ -86,19 +83,26 @@ class Run {
86
83
  }
87
84
  }
88
85
 
89
- _injectEnv (env) {
86
+ _injectEnv (env, privateKeyName = null) {
90
87
  const row = {}
91
88
  row.type = TYPE_ENV
92
89
  row.string = env
93
90
 
94
91
  try {
92
+ const {
93
+ privateKeyName: resolvedPrivateKeyName,
94
+ privateKeyValue
95
+ } = keyValuesFromEnvSrc(env, privateKeyName, { keysFilepath: this.envKeysFilepath, noOps: this.noOps, processEnv: this.processEnv })
96
+
95
97
  const {
96
98
  parsed,
97
99
  errors,
98
100
  injected,
99
101
  preExisted
100
- } = new Parse(env, null, this.processEnv, this.overload).run()
102
+ } = new Parse(env, privateKeyValue, this.processEnv, this.overload, resolvedPrivateKeyName).run()
101
103
 
104
+ row.privateKeyName = resolvedPrivateKeyName
105
+ row.privateKey = privateKeyValue
102
106
  row.parsed = parsed
103
107
  row.errors = errors
104
108
  row.injected = injected