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 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
- console.error(`[envlock] '${name}' not found in PATH.
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
- console.warn(
121
- `[envlock] Failed to load ${candidate}: ${err instanceof Error ? err.message : String(err)}`
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
- console.warn(
163
- '[envlock] Warning: "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.'
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
- if (import.meta.url === pathToFileURL2(process.argv[1] ?? "").href) {
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
- console.error(err instanceof Error ? err.message : String(err));
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
- export { ENVIRONMENTS, type Environment, type EnvlockConfig, type EnvlockOptions, type RunWithSecretsOptions, checkBinary, hasBinary, runWithSecrets, validateEnvFilePath, validateOnePasswordEnvId };
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
- console.error(`[envlock] '${name}' not found in PATH.
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.4.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": ["dist"],
29
+ "files": [
30
+ "dist"
31
+ ],
30
32
  "scripts": {
31
33
  "build": "tsup",
32
34
  "dev": "tsup --watch",