envlock-core 0.4.0 → 0.6.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 +63 -9
- package/dist/index.d.ts +11 -1
- package/dist/index.js +58 -2
- package/package.json +4 -2
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
|
|
@@ -159,8 +199,8 @@ async function run(argv, cwd = process.cwd()) {
|
|
|
159
199
|
}
|
|
160
200
|
if (firstArg === "run") {
|
|
161
201
|
if (config?.commands?.["run"]) {
|
|
162
|
-
|
|
163
|
-
'
|
|
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.'
|
|
164
204
|
);
|
|
165
205
|
}
|
|
166
206
|
const runArgs = passthrough.slice(1);
|
|
@@ -196,11 +236,25 @@ async function run(argv, cwd = process.cwd()) {
|
|
|
196
236
|
validateOnePasswordEnvId(onePasswordEnvId);
|
|
197
237
|
const envFile = config?.envFiles?.[environment] ?? DEFAULT_ENV_FILES[environment];
|
|
198
238
|
validateEnvFilePath(envFile, cwd);
|
|
239
|
+
log.debug(`Environment: ${environment}`);
|
|
240
|
+
log.debug(`Env file: ${envFile}`);
|
|
241
|
+
log.debug(`Command: ${command} ${args.join(" ")}`);
|
|
199
242
|
runWithSecrets({ envFile, environment, onePasswordEnvId, command, args });
|
|
200
243
|
}
|
|
201
|
-
|
|
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}`);
|
|
202
256
|
run(process.argv.slice(2)).catch((err) => {
|
|
203
|
-
|
|
257
|
+
log.error(err instanceof Error ? err.message : String(err));
|
|
204
258
|
process.exit(1);
|
|
205
259
|
});
|
|
206
260
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -33,4 +33,14 @@ 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
|
+
declare function findFreePort(preferred: number): Promise<number>;
|
|
45
|
+
|
|
46
|
+
export { ENVIRONMENTS, type Environment, type EnvlockConfig, type EnvlockOptions, type RunWithSecretsOptions, checkBinary, findFreePort, 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
|
}
|
|
@@ -92,11 +126,33 @@ var ENVIRONMENTS = {
|
|
|
92
126
|
staging: "staging",
|
|
93
127
|
production: "production"
|
|
94
128
|
};
|
|
129
|
+
|
|
130
|
+
// src/find-port.ts
|
|
131
|
+
import { createServer } from "net";
|
|
132
|
+
function isPortFree(port) {
|
|
133
|
+
return new Promise((resolve2) => {
|
|
134
|
+
const server = createServer();
|
|
135
|
+
server.once("error", () => resolve2(false));
|
|
136
|
+
server.once("listening", () => server.close(() => resolve2(true)));
|
|
137
|
+
server.listen(port, "127.0.0.1");
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
async function findFreePort(preferred) {
|
|
141
|
+
for (let port = preferred; port <= preferred + 10; port++) {
|
|
142
|
+
if (await isPortFree(port)) return port;
|
|
143
|
+
}
|
|
144
|
+
throw new Error(
|
|
145
|
+
`[envlock] No free port found in range ${preferred}\u2013${preferred + 10}.`
|
|
146
|
+
);
|
|
147
|
+
}
|
|
95
148
|
export {
|
|
96
149
|
ENVIRONMENTS,
|
|
97
150
|
checkBinary,
|
|
151
|
+
findFreePort,
|
|
98
152
|
hasBinary,
|
|
153
|
+
log,
|
|
99
154
|
runWithSecrets,
|
|
155
|
+
setVerbose,
|
|
100
156
|
validateEnvFilePath,
|
|
101
157
|
validateOnePasswordEnvId
|
|
102
158
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "envlock-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Core 1Password + dotenvx secret injection logic for envlock",
|
|
6
6
|
"license": "MIT",
|
|
@@ -26,7 +26,9 @@
|
|
|
26
26
|
"types": "./dist/index.d.ts"
|
|
27
27
|
}
|
|
28
28
|
},
|
|
29
|
-
"files": [
|
|
29
|
+
"files": [
|
|
30
|
+
"dist"
|
|
31
|
+
],
|
|
30
32
|
"scripts": {
|
|
31
33
|
"build": "tsup",
|
|
32
34
|
"dev": "tsup --watch",
|