envlock-core 0.3.0 → 0.5.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/dist/cli/index.js +76 -8
- package/dist/index.d.ts +9 -1
- package/dist/index.js +38 -2
- package/package.json +8 -8
- package/LICENSE +0 -21
package/dist/cli/index.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
// src/cli/index.ts
|
|
4
4
|
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
5
|
+
import { realpathSync } from "fs";
|
|
5
6
|
|
|
6
7
|
// src/types.ts
|
|
7
8
|
var ENVIRONMENTS = {
|
|
@@ -15,6 +16,32 @@ import { spawnSync } from "child_process";
|
|
|
15
16
|
|
|
16
17
|
// src/detect.ts
|
|
17
18
|
import { execFileSync } from "child_process";
|
|
19
|
+
|
|
20
|
+
// src/logger.ts
|
|
21
|
+
var verbose = false;
|
|
22
|
+
function setVerbose(flag) {
|
|
23
|
+
verbose = flag;
|
|
24
|
+
}
|
|
25
|
+
var log = {
|
|
26
|
+
debug: (msg) => {
|
|
27
|
+
if (verbose) process.stderr.write(`[envlock:debug] ${msg}
|
|
28
|
+
`);
|
|
29
|
+
},
|
|
30
|
+
info: (msg) => {
|
|
31
|
+
process.stderr.write(`[envlock] ${msg}
|
|
32
|
+
`);
|
|
33
|
+
},
|
|
34
|
+
warn: (msg) => {
|
|
35
|
+
process.stderr.write(`[envlock] Warning: ${msg}
|
|
36
|
+
`);
|
|
37
|
+
},
|
|
38
|
+
error: (msg) => {
|
|
39
|
+
process.stderr.write(`[envlock] Error: ${msg}
|
|
40
|
+
`);
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// src/detect.ts
|
|
18
45
|
var WHICH = process.platform === "win32" ? "where" : "which";
|
|
19
46
|
function hasBinary(name) {
|
|
20
47
|
try {
|
|
@@ -26,10 +53,10 @@ function hasBinary(name) {
|
|
|
26
53
|
}
|
|
27
54
|
function checkBinary(name, installHint) {
|
|
28
55
|
if (!hasBinary(name)) {
|
|
29
|
-
|
|
56
|
+
throw new Error(`[envlock] '${name}' not found in PATH.
|
|
30
57
|
${installHint}`);
|
|
31
|
-
process.exit(1);
|
|
32
58
|
}
|
|
59
|
+
log.debug(`Binary check: ${name} found`);
|
|
33
60
|
}
|
|
34
61
|
|
|
35
62
|
// src/invoke.ts
|
|
@@ -43,16 +70,21 @@ function runWithSecrets(options) {
|
|
|
43
70
|
const keyAlreadyInjected = !!process.env[privateKeyVar];
|
|
44
71
|
let result;
|
|
45
72
|
if (keyAlreadyInjected) {
|
|
73
|
+
log.debug(`Spawning: dotenvx run -f ${envFile} -- ${command} ${args.join(" ")}`);
|
|
46
74
|
result = spawnSync(
|
|
47
75
|
"dotenvx",
|
|
48
76
|
["run", "-f", envFile, "--", command, ...args],
|
|
49
77
|
{ stdio: "inherit" }
|
|
50
78
|
);
|
|
79
|
+
if (result.error) {
|
|
80
|
+
throw new Error(`[envlock] Failed to spawn 'dotenvx': ${result.error.message}`);
|
|
81
|
+
}
|
|
51
82
|
} else {
|
|
52
83
|
checkBinary(
|
|
53
84
|
"op",
|
|
54
85
|
"Install 1Password CLI: brew install --cask 1password-cli@beta\nThen sign in: op signin"
|
|
55
86
|
);
|
|
87
|
+
log.debug(`Spawning: op run --environment ${onePasswordEnvId} -- dotenvx run -f ${envFile} -- ${command} ${args.join(" ")}`);
|
|
56
88
|
result = spawnSync(
|
|
57
89
|
"op",
|
|
58
90
|
[
|
|
@@ -70,6 +102,9 @@ function runWithSecrets(options) {
|
|
|
70
102
|
],
|
|
71
103
|
{ stdio: "inherit" }
|
|
72
104
|
);
|
|
105
|
+
if (result.error) {
|
|
106
|
+
throw new Error(`[envlock] Failed to spawn 'op': ${result.error.message}`);
|
|
107
|
+
}
|
|
73
108
|
}
|
|
74
109
|
process.exit(result.status ?? 1);
|
|
75
110
|
}
|
|
@@ -114,12 +149,12 @@ async function resolveConfig(cwd) {
|
|
|
114
149
|
const mod = await import(pathToFileURL(fullPath).href);
|
|
115
150
|
const config = mod.default ?? mod;
|
|
116
151
|
if (config && typeof config === "object") {
|
|
152
|
+
log.debug(`Config loaded from ${candidate}`);
|
|
117
153
|
return config;
|
|
118
154
|
}
|
|
119
155
|
} catch (err) {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
);
|
|
156
|
+
log.warn(`Failed to load ${candidate}: ${err instanceof Error ? err.message : String(err)}`);
|
|
157
|
+
log.debug(`Stack: ${err instanceof Error ? err.stack ?? "" : ""}`);
|
|
123
158
|
}
|
|
124
159
|
}
|
|
125
160
|
return null;
|
|
@@ -145,6 +180,11 @@ function splitCommand(cmd) {
|
|
|
145
180
|
return parts;
|
|
146
181
|
}
|
|
147
182
|
async function run(argv, cwd = process.cwd()) {
|
|
183
|
+
const debugIdx = argv.findIndex((a) => a === "--debug" || a === "-d");
|
|
184
|
+
if (debugIdx !== -1) {
|
|
185
|
+
setVerbose(true);
|
|
186
|
+
argv = argv.filter((_, i) => i !== debugIdx);
|
|
187
|
+
}
|
|
148
188
|
const environment = argv.includes(ARGUMENT_FLAGS.production) ? ENVIRONMENTS.production : argv.includes(ARGUMENT_FLAGS.staging) ? ENVIRONMENTS.staging : ENVIRONMENTS.development;
|
|
149
189
|
const passthrough = argv.filter(
|
|
150
190
|
(f) => f !== ARGUMENT_FLAGS.staging && f !== ARGUMENT_FLAGS.production
|
|
@@ -157,7 +197,21 @@ async function run(argv, cwd = process.cwd()) {
|
|
|
157
197
|
const available = config?.commands ? Object.keys(config.commands).join(", ") : "none";
|
|
158
198
|
throw new Error(`[envlock] No command specified. Available commands: ${available}`);
|
|
159
199
|
}
|
|
160
|
-
if (
|
|
200
|
+
if (firstArg === "run") {
|
|
201
|
+
if (config?.commands?.["run"]) {
|
|
202
|
+
log.warn(
|
|
203
|
+
'"run" is a reserved subcommand. The config command named "run" is ignored.\nRename it in envlock.config.js to use it as a named command.'
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
const runArgs = passthrough.slice(1);
|
|
207
|
+
if (runArgs.length === 0) {
|
|
208
|
+
throw new Error(
|
|
209
|
+
"[envlock] Usage: envlock run <command> [args...]\nExample: envlock run node server.js --port 4000"
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
command = runArgs[0];
|
|
213
|
+
args = runArgs.slice(1);
|
|
214
|
+
} else if (config?.commands && firstArg in config.commands) {
|
|
161
215
|
const cmdString = config.commands[firstArg];
|
|
162
216
|
if (!cmdString || cmdString.trim() === "") {
|
|
163
217
|
throw new Error(`[envlock] Command "${firstArg}" is empty in envlock.config.js.`);
|
|
@@ -182,11 +236,25 @@ async function run(argv, cwd = process.cwd()) {
|
|
|
182
236
|
validateOnePasswordEnvId(onePasswordEnvId);
|
|
183
237
|
const envFile = config?.envFiles?.[environment] ?? DEFAULT_ENV_FILES[environment];
|
|
184
238
|
validateEnvFilePath(envFile, cwd);
|
|
239
|
+
log.debug(`Environment: ${environment}`);
|
|
240
|
+
log.debug(`Env file: ${envFile}`);
|
|
241
|
+
log.debug(`Command: ${command} ${args.join(" ")}`);
|
|
185
242
|
runWithSecrets({ envFile, environment, onePasswordEnvId, command, args });
|
|
186
243
|
}
|
|
187
|
-
|
|
244
|
+
var _resolvedArgv1 = (() => {
|
|
245
|
+
try {
|
|
246
|
+
return realpathSync(process.argv[1] ?? "");
|
|
247
|
+
} catch {
|
|
248
|
+
return process.argv[1] ?? "";
|
|
249
|
+
}
|
|
250
|
+
})();
|
|
251
|
+
if (import.meta.url === pathToFileURL2(_resolvedArgv1).href) {
|
|
252
|
+
if (process.argv.includes("--debug") || process.argv.includes("-d")) {
|
|
253
|
+
setVerbose(true);
|
|
254
|
+
}
|
|
255
|
+
log.debug(`Resolved argv[1]: ${_resolvedArgv1}`);
|
|
188
256
|
run(process.argv.slice(2)).catch((err) => {
|
|
189
|
-
|
|
257
|
+
log.error(err instanceof Error ? err.message : String(err));
|
|
190
258
|
process.exit(1);
|
|
191
259
|
});
|
|
192
260
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -33,4 +33,12 @@ declare function checkBinary(name: string, installHint: string): void;
|
|
|
33
33
|
declare function validateOnePasswordEnvId(id: string): void;
|
|
34
34
|
declare function validateEnvFilePath(envFile: string, cwd: string): void;
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
declare function setVerbose(flag: boolean): void;
|
|
37
|
+
declare const log: {
|
|
38
|
+
debug: (msg: string) => void;
|
|
39
|
+
info: (msg: string) => void;
|
|
40
|
+
warn: (msg: string) => void;
|
|
41
|
+
error: (msg: string) => void;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export { ENVIRONMENTS, type Environment, type EnvlockConfig, type EnvlockOptions, type RunWithSecretsOptions, checkBinary, hasBinary, log, runWithSecrets, setVerbose, validateEnvFilePath, validateOnePasswordEnvId };
|
package/dist/index.js
CHANGED
|
@@ -3,6 +3,32 @@ import { spawnSync } from "child_process";
|
|
|
3
3
|
|
|
4
4
|
// src/detect.ts
|
|
5
5
|
import { execFileSync } from "child_process";
|
|
6
|
+
|
|
7
|
+
// src/logger.ts
|
|
8
|
+
var verbose = false;
|
|
9
|
+
function setVerbose(flag) {
|
|
10
|
+
verbose = flag;
|
|
11
|
+
}
|
|
12
|
+
var log = {
|
|
13
|
+
debug: (msg) => {
|
|
14
|
+
if (verbose) process.stderr.write(`[envlock:debug] ${msg}
|
|
15
|
+
`);
|
|
16
|
+
},
|
|
17
|
+
info: (msg) => {
|
|
18
|
+
process.stderr.write(`[envlock] ${msg}
|
|
19
|
+
`);
|
|
20
|
+
},
|
|
21
|
+
warn: (msg) => {
|
|
22
|
+
process.stderr.write(`[envlock] Warning: ${msg}
|
|
23
|
+
`);
|
|
24
|
+
},
|
|
25
|
+
error: (msg) => {
|
|
26
|
+
process.stderr.write(`[envlock] Error: ${msg}
|
|
27
|
+
`);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// src/detect.ts
|
|
6
32
|
var WHICH = process.platform === "win32" ? "where" : "which";
|
|
7
33
|
function hasBinary(name) {
|
|
8
34
|
try {
|
|
@@ -14,10 +40,10 @@ function hasBinary(name) {
|
|
|
14
40
|
}
|
|
15
41
|
function checkBinary(name, installHint) {
|
|
16
42
|
if (!hasBinary(name)) {
|
|
17
|
-
|
|
43
|
+
throw new Error(`[envlock] '${name}' not found in PATH.
|
|
18
44
|
${installHint}`);
|
|
19
|
-
process.exit(1);
|
|
20
45
|
}
|
|
46
|
+
log.debug(`Binary check: ${name} found`);
|
|
21
47
|
}
|
|
22
48
|
|
|
23
49
|
// src/invoke.ts
|
|
@@ -31,16 +57,21 @@ function runWithSecrets(options) {
|
|
|
31
57
|
const keyAlreadyInjected = !!process.env[privateKeyVar];
|
|
32
58
|
let result;
|
|
33
59
|
if (keyAlreadyInjected) {
|
|
60
|
+
log.debug(`Spawning: dotenvx run -f ${envFile} -- ${command} ${args.join(" ")}`);
|
|
34
61
|
result = spawnSync(
|
|
35
62
|
"dotenvx",
|
|
36
63
|
["run", "-f", envFile, "--", command, ...args],
|
|
37
64
|
{ stdio: "inherit" }
|
|
38
65
|
);
|
|
66
|
+
if (result.error) {
|
|
67
|
+
throw new Error(`[envlock] Failed to spawn 'dotenvx': ${result.error.message}`);
|
|
68
|
+
}
|
|
39
69
|
} else {
|
|
40
70
|
checkBinary(
|
|
41
71
|
"op",
|
|
42
72
|
"Install 1Password CLI: brew install --cask 1password-cli@beta\nThen sign in: op signin"
|
|
43
73
|
);
|
|
74
|
+
log.debug(`Spawning: op run --environment ${onePasswordEnvId} -- dotenvx run -f ${envFile} -- ${command} ${args.join(" ")}`);
|
|
44
75
|
result = spawnSync(
|
|
45
76
|
"op",
|
|
46
77
|
[
|
|
@@ -58,6 +89,9 @@ function runWithSecrets(options) {
|
|
|
58
89
|
],
|
|
59
90
|
{ stdio: "inherit" }
|
|
60
91
|
);
|
|
92
|
+
if (result.error) {
|
|
93
|
+
throw new Error(`[envlock] Failed to spawn 'op': ${result.error.message}`);
|
|
94
|
+
}
|
|
61
95
|
}
|
|
62
96
|
process.exit(result.status ?? 1);
|
|
63
97
|
}
|
|
@@ -96,7 +130,9 @@ export {
|
|
|
96
130
|
ENVIRONMENTS,
|
|
97
131
|
checkBinary,
|
|
98
132
|
hasBinary,
|
|
133
|
+
log,
|
|
99
134
|
runWithSecrets,
|
|
135
|
+
setVerbose,
|
|
100
136
|
validateEnvFilePath,
|
|
101
137
|
validateOnePasswordEnvId
|
|
102
138
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "envlock-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Core 1Password + dotenvx secret injection logic for envlock",
|
|
6
6
|
"license": "MIT",
|
|
@@ -29,16 +29,16 @@
|
|
|
29
29
|
"files": [
|
|
30
30
|
"dist"
|
|
31
31
|
],
|
|
32
|
-
"devDependencies": {
|
|
33
|
-
"@types/node": "^20.14.10",
|
|
34
|
-
"tsup": "^8.0.0",
|
|
35
|
-
"typescript": "^5.8.2",
|
|
36
|
-
"vitest": "^3.0.0"
|
|
37
|
-
},
|
|
38
32
|
"scripts": {
|
|
39
33
|
"build": "tsup",
|
|
40
34
|
"dev": "tsup --watch",
|
|
41
35
|
"test": "vitest run",
|
|
42
36
|
"test:watch": "vitest"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@types/node": "^20.14.10",
|
|
40
|
+
"tsup": "^8.0.0",
|
|
41
|
+
"typescript": "^5.8.2",
|
|
42
|
+
"vitest": "^3.0.0"
|
|
43
43
|
}
|
|
44
|
-
}
|
|
44
|
+
}
|
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 Benjamin Davies
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|