@dotenvx/dotenvx 1.61.3 → 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,13 @@
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.3...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))
6
12
 
7
13
  ## [1.61.3](https://github.com/dotenvx/dotenvx/compare/v1.61.2...v1.61.3) (2026-04-21)
8
14
 
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
@@ -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.3",
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