@dotenvx/dotenvx 1.61.2 → 1.61.4

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,19 @@
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.2...main)
5
+ [Unreleased](https://github.com/dotenvx/dotenvx/compare/v1.61.4...main)
6
+
7
+ ## [1.61.4](https://github.com/dotenvx/dotenvx/compare/v1.61.3...v1.61.4) (2026-04-21)
8
+
9
+ ### Changed
10
+
11
+ * Respect SIGINT handler completion ([#798](https://github.com/dotenvx/dotenvx/pull/798))
12
+
13
+ ## [1.61.3](https://github.com/dotenvx/dotenvx/compare/v1.61.2...v1.61.3) (2026-04-21)
14
+
15
+ ### Changed
16
+
17
+ * Tighten up `ext precommit --install` message ([#797](https://github.com/dotenvx/dotenvx/pull/797))
6
18
 
7
19
  ## [1.61.2](https://github.com/dotenvx/dotenvx/compare/v1.61.1...v1.61.2) (2026-04-21)
8
20
 
package/README.md CHANGED
@@ -349,11 +349,11 @@ $ docker run -it --rm -v $(pwd):/app dotenv/dotenvx run -- node index.js
349
349
 
350
350
  Or in any image:
351
351
 
352
- ```sh
352
+ ```Containerfile
353
353
  FROM node:latest
354
354
  RUN echo "HELLO=Dotenvx" > .env && echo "console.log('Hello ' + process.env.HELLO)" > index.js
355
355
  RUN curl -fsS https://dotenvx.sh/install.sh | sh
356
- CMD ["dotenvx", "run", "--", "echo", "Hello $HELLO"]
356
+ CMD ["/usr/local/bin/dotenvx", "run", "--", "echo", "Hello $HELLO"]
357
357
  ```
358
358
 
359
359
  see [docker guide](https://dotenvx.com/docs/platforms/docker)
@@ -388,7 +388,7 @@ see [github actions guide](https://dotenvx.com/docs/cis/github-actions)
388
388
  heroku buildpacks:add https://github.com/dotenvx/heroku-buildpack-dotenvx
389
389
 
390
390
  # docker
391
- RUN curl -fsS https://dotenvx.sh/install.sh | sh
391
+ RUN curl -fsS https://dotenvx.sh | sh
392
392
 
393
393
  # vercel
394
394
  npm install @dotenvx/dotenvx --save
@@ -2217,7 +2217,7 @@ Prevent `.env` files from being committed to code.
2217
2217
 
2218
2218
  ```sh
2219
2219
  $ dotenvx ext precommit
2220
- [dotenvx][precommit] .env files (1) protected (encrypted or gitignored)
2220
+ .env files (1) protected (encrypted or gitignored)
2221
2221
  ```
2222
2222
 
2223
2223
  </details>
@@ -2227,7 +2227,7 @@ Install a shell script to `.git/hooks/pre-commit` to prevent accidentally commit
2227
2227
 
2228
2228
  ```sh
2229
2229
  $ dotenvx ext precommit --install
2230
- [dotenvx][precommit] dotenvx ext precommit installed [.git/hooks/pre-commit]
2230
+ dotenvx ext precommit installed [.git/hooks/pre-commit]
2231
2231
  ```
2232
2232
 
2233
2233
  </details>
@@ -2241,7 +2241,7 @@ $ mkdir -p apps/backend
2241
2241
  $ echo "HELLO=Backend" > apps/backend/.env
2242
2242
 
2243
2243
  $ dotenvx ext precommit apps/backend
2244
- [dotenvx][precommit] apps/backend/.env not protected (encrypted or gitignored)
2244
+ apps/backend/.env not protected (encrypted or gitignored)
2245
2245
  ```
2246
2246
 
2247
2247
  </details>
@@ -2251,14 +2251,17 @@ Prevent `.env` files from being built into your docker containers.
2251
2251
 
2252
2252
  Add it to your `Dockerfile`.
2253
2253
 
2254
- ```sh
2255
- # Dockerfile
2254
+ ```Containerfile
2255
+ # Install via script
2256
2256
  RUN curl -fsS https://dotenvx.sh | sh
2257
2257
 
2258
- ...
2258
+ # Or copy binary from official image
2259
+ COPY --from=dotenv/dotenvx:latest /usr/local/bin/dotenvx /bin/local/bin
2260
+
2261
+ # ... orther container commands
2259
2262
 
2260
2263
  RUN dotenvx ext prebuild
2261
- CMD ["dotenvx", "run", "--", "node", "index.js"]
2264
+ CMD ["/usr/local/bin/dotenvx", "run", "--", "node", "index.js"]
2262
2265
  ```
2263
2266
 
2264
2267
  </details>
@@ -2268,14 +2271,17 @@ Prevent `.env` files from being built into your docker containers inside a speci
2268
2271
 
2269
2272
  Add it to your `Dockerfile`.
2270
2273
 
2271
- ```sh
2272
- # Dockerfile
2274
+ ```Containerfile
2275
+ # Install via script
2273
2276
  RUN curl -fsS https://dotenvx.sh | sh
2274
2277
 
2275
- ...
2278
+ # Or copy binary from official image
2279
+ COPY --from=dotenv/dotenvx:latest /usr/local/bin/dotenvx /bin/local/bin
2280
+
2281
+ # ... orther container commands
2276
2282
 
2277
2283
  RUN dotenvx ext prebuild apps/backend
2278
- CMD ["dotenvx", "run", "--", "node", "apps/backend/index.js"]
2284
+ CMD ["/usr/local/bin/dotenvx", "run", "--", "node", "apps/backend/index.js"]
2279
2285
  ```
2280
2286
 
2281
2287
  </details>
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.61.2",
2
+ "version": "1.61.4",
3
3
  "name": "@dotenvx/dotenvx",
4
4
  "description": "secrets for agents–from the creator of `dotenv`",
5
5
  "author": "@motdotla",
@@ -5,6 +5,8 @@ const { logger } = require('./../../shared/logger')
5
5
  const Errors = require('./errors')
6
6
 
7
7
  async function executeCommand (commandArgs, env) {
8
+ const FORWARD_SIGNAL_GRACE_MS = 1000
9
+ const FORCE_KILL_GRACE_MS = 1000
8
10
  const signals = [
9
11
  'SIGHUP', 'SIGQUIT', 'SIGILL', 'SIGTRAP', 'SIGABRT',
10
12
  'SIGBUS', 'SIGFPE', 'SIGUSR1', 'SIGSEGV', 'SIGUSR2'
@@ -14,6 +16,51 @@ async function executeCommand (commandArgs, env) {
14
16
 
15
17
  let child
16
18
  let signalSent
19
+ let sigintCount = 0
20
+ const signalForwardTimers = new Set()
21
+ const otherSignalHandlers = new Map()
22
+ const isInteractiveTTY = Boolean(process.stdin && process.stdin.isTTY)
23
+
24
+ const isChildRunning = () => {
25
+ return child && child.exitCode === null && child.signalCode === null
26
+ }
27
+
28
+ const queueSignalForward = (signal) => {
29
+ logger.debug(`queueing ${signal} to command process after ${FORWARD_SIGNAL_GRACE_MS}ms`)
30
+ const timer = setTimeout(() => {
31
+ signalForwardTimers.delete(timer)
32
+
33
+ if (!isChildRunning()) {
34
+ logger.debug(`skipping ${signal} forward because command process is already exiting`)
35
+ return
36
+ }
37
+
38
+ logger.debug(`sending ${signal} to command process`)
39
+ signalSent = signal
40
+ child.kill(signal)
41
+ }, FORWARD_SIGNAL_GRACE_MS)
42
+
43
+ if (typeof timer.unref === 'function') timer.unref()
44
+ signalForwardTimers.add(timer)
45
+ }
46
+
47
+ const queueForceKill = () => {
48
+ logger.debug(`queueing SIGKILL to command process after ${FORCE_KILL_GRACE_MS}ms`)
49
+ const timer = setTimeout(() => {
50
+ signalForwardTimers.delete(timer)
51
+
52
+ if (!isChildRunning()) {
53
+ logger.debug('skipping SIGKILL because command process is already exiting')
54
+ return
55
+ }
56
+
57
+ logger.debug('sending SIGKILL to command process')
58
+ child.kill('SIGKILL')
59
+ }, FORCE_KILL_GRACE_MS)
60
+
61
+ if (typeof timer.unref === 'function') timer.unref()
62
+ signalForwardTimers.add(timer)
63
+ }
17
64
 
18
65
  /* c8 ignore start */
19
66
  const sigintHandler = () => {
@@ -21,13 +68,25 @@ async function executeCommand (commandArgs, env) {
21
68
  logger.debug('checking command process')
22
69
  logger.debug(child)
23
70
 
24
- if (child) {
25
- logger.debug('sending SIGINT to command process')
26
- signalSent = 'SIGINT'
27
- child.kill('SIGINT') // Send SIGINT to the command process
28
- } else {
29
- logger.debug('no command process to send SIGINT to')
71
+ if (!child) return
72
+
73
+ sigintCount += 1
74
+
75
+ if (isInteractiveTTY) {
76
+ if (sigintCount === 1) {
77
+ logger.debug('TTY mode: not forwarding first SIGINT to command process')
78
+ return
79
+ }
80
+
81
+ logger.debug('TTY mode: forwarding SIGTERM on second SIGINT to command process')
82
+ signalSent = 'SIGTERM'
83
+ child.kill('SIGTERM')
84
+
85
+ if (sigintCount === 2) queueForceKill()
86
+ return
30
87
  }
88
+
89
+ queueSignalForward('SIGINT')
31
90
  }
32
91
 
33
92
  const sigtermHandler = () => {
@@ -35,18 +94,14 @@ async function executeCommand (commandArgs, env) {
35
94
  logger.debug('checking command process')
36
95
  logger.debug(child)
37
96
 
38
- if (child) {
39
- logger.debug('sending SIGTERM to command process')
40
- signalSent = 'SIGTERM'
41
- child.kill('SIGTERM') // Send SIGTERM to the command process
42
- } else {
43
- logger.debug('no command process to send SIGTERM to')
44
- }
97
+ if (!child) return
98
+
99
+ queueSignalForward('SIGTERM')
45
100
  }
46
101
 
47
102
  const handleOtherSignal = (signal) => {
48
103
  logger.debug(`received ${signal}`)
49
- child.kill(signal)
104
+ if (child) child.kill(signal)
50
105
  }
51
106
  /* c8 ignore stop */
52
107
 
@@ -84,7 +139,9 @@ async function executeCommand (commandArgs, env) {
84
139
  process.on('SIGTERM', sigtermHandler)
85
140
 
86
141
  signals.forEach(signal => {
87
- process.on(signal, () => handleOtherSignal(signal))
142
+ const handler = () => handleOtherSignal(signal)
143
+ otherSignalHandlers.set(signal, handler)
144
+ process.on(signal, handler)
88
145
  })
89
146
 
90
147
  // Wait for the command process to finish
@@ -107,10 +164,17 @@ async function executeCommand (commandArgs, env) {
107
164
  // Exit with the error code from the command process, or 1 if unavailable
108
165
  process.exit(error.exitCode || 1)
109
166
  } finally {
167
+ signalForwardTimers.forEach(timer => clearTimeout(timer))
168
+ signalForwardTimers.clear()
169
+
110
170
  // Clean up: Remove the SIGINT handler
111
171
  process.removeListener('SIGINT', sigintHandler)
112
172
  // Clean up: Remove the SIGTERM handler
113
173
  process.removeListener('SIGTERM', sigtermHandler)
174
+
175
+ otherSignalHandlers.forEach((handler, signal) => {
176
+ process.removeListener(signal, handler)
177
+ })
114
178
  }
115
179
  }
116
180
 
@@ -11,9 +11,15 @@ elif npx dotenvx -V >/dev/null 2>&1
11
11
  then
12
12
  npx dotenvx ext precommit
13
13
  else
14
- echo "[dotenvx][precommit] 'dotenvx' command not found"
15
- echo "[dotenvx][precommit] ? install it with [curl -fsS https://dotenvx.sh | sh]"
16
- echo "[dotenvx][precommit] ? other install options [https://dotenvx.com/docs/install]"
14
+ if [ -t 2 ]; then
15
+ RED="$(printf '\\033[31m')"
16
+ RESET="$(printf '\\033[0m')"
17
+ else
18
+ RED=""
19
+ RESET=""
20
+ fi
21
+
22
+ printf "%s☠ 'dotenvx ext precommit' command not found (.git/hooks/precommit) fix: [curl -sfS https://dotenvx.sh | sh]%s\n" "$RED" "$RESET" >&2
17
23
  exit 1
18
24
  fi
19
25
  `
@@ -32,14 +38,14 @@ class InstallPrecommitHook {
32
38
  // Check if 'dotenvx precommit' already exists in the file
33
39
  if (this._currentHook().includes('dotenvx ext precommit')) {
34
40
  // do nothing
35
- successMessage = `dotenvx ext precommit exists [${this.hookPath}]`
41
+ successMessage = `▣ dotenvx ext precommit exists [${this.hookPath}]`
36
42
  } else {
37
43
  this._appendHook()
38
- successMessage = `dotenvx ext precommit appended [${this.hookPath}]`
44
+ successMessage = `▣ dotenvx ext precommit appended [${this.hookPath}]`
39
45
  }
40
46
  } else {
41
47
  this._createHook()
42
- successMessage = `dotenvx ext precommit installed [${this.hookPath}]`
48
+ successMessage = `▣ dotenvx ext precommit installed [${this.hookPath}]`
43
49
  }
44
50
 
45
51
  return {