@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 +13 -1
- package/README.md +20 -14
- package/package.json +1 -1
- package/src/lib/helpers/executeCommand.js +79 -15
- package/src/lib/helpers/installPrecommitHook.js +12 -6
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.
|
|
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
|
-
```
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
```
|
|
2255
|
-
#
|
|
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
|
-
```
|
|
2272
|
-
#
|
|
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
|
@@ -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
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
-
|
|
40
|
-
|
|
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
|
-
|
|
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
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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 =
|
|
41
|
+
successMessage = `▣ dotenvx ext precommit exists [${this.hookPath}]`
|
|
36
42
|
} else {
|
|
37
43
|
this._appendHook()
|
|
38
|
-
successMessage =
|
|
44
|
+
successMessage = `▣ dotenvx ext precommit appended [${this.hookPath}]`
|
|
39
45
|
}
|
|
40
46
|
} else {
|
|
41
47
|
this._createHook()
|
|
42
|
-
successMessage =
|
|
48
|
+
successMessage = `▣ dotenvx ext precommit installed [${this.hookPath}]`
|
|
43
49
|
}
|
|
44
50
|
|
|
45
51
|
return {
|