@super-repo/envx 0.2.2 → 0.2.3-b.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.
Files changed (40) hide show
  1. package/dist/auto.js +3 -7
  2. package/dist/auto.js.map +1 -1
  3. package/dist/bin/dotenvx.d.ts +0 -2
  4. package/dist/bin/dotenvx.d.ts.map +1 -1
  5. package/dist/bin/dotenvx.js +0 -4
  6. package/dist/chunks/commands-BZv1l-0k.js +354 -0
  7. package/dist/chunks/commands-BZv1l-0k.js.map +1 -0
  8. package/dist/chunks/src-dIVfZVmT.js +0 -0
  9. package/dist/chunks/src-dIVfZVmT.js.map +1 -0
  10. package/dist/cli.d.ts +0 -1
  11. package/dist/cli.js +4 -1
  12. package/dist/cli.js.map +1 -1
  13. package/dist/commands/debug.d.ts +1 -1
  14. package/dist/commands/decrypt.d.ts +1 -1
  15. package/dist/commands/encrypt.d.ts +1 -1
  16. package/dist/commands/expand.d.ts +1 -1
  17. package/dist/commands/index.d.ts +1 -1
  18. package/dist/commands/index.d.ts.map +1 -1
  19. package/dist/commands/index.js +2 -159
  20. package/dist/commands/print.d.ts +1 -1
  21. package/dist/commands/run.d.ts +1 -1
  22. package/dist/index.d.ts +1 -1
  23. package/dist/index.js +32 -58
  24. package/dist/index.js.map +1 -1
  25. package/package.json +13 -6
  26. package/dist/.tsbuildinfo +0 -1
  27. package/dist/bin/dotenvx.js.map +0 -1
  28. package/dist/commands/debug.js +0 -21
  29. package/dist/commands/debug.js.map +0 -1
  30. package/dist/commands/decrypt.js +0 -73
  31. package/dist/commands/decrypt.js.map +0 -1
  32. package/dist/commands/encrypt.js +0 -82
  33. package/dist/commands/encrypt.js.map +0 -1
  34. package/dist/commands/expand.js +0 -83
  35. package/dist/commands/expand.js.map +0 -1
  36. package/dist/commands/index.js.map +0 -1
  37. package/dist/commands/print.js +0 -27
  38. package/dist/commands/print.js.map +0 -1
  39. package/dist/commands/run.js +0 -40
  40. package/dist/commands/run.js.map +0 -1
package/dist/auto.js CHANGED
@@ -1,10 +1,6 @@
1
- // #region -- Side-effect entry point ----------------------
2
- // `import "@honeycluster/envx/auto"` (or "/config") loads .env into
3
- // process.env on import — same ergonomics as `import "dotenv/config"`.
4
- // Picks up envx.config.* and the package.json `envx.config` discovery
5
- // chain automatically. Use the named/default export from the package
6
- // root when you want an explicit handle.
7
1
  import envx from "./index.js";
2
+ //#region src/auto.ts
8
3
  envx();
9
- // #endregion -----------------------------------------------
4
+ //#endregion
5
+
10
6
  //# sourceMappingURL=auto.js.map
package/dist/auto.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"auto.js","sourceRoot":"","sources":["../src/auto.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAE5D,oEAAoE;AACpE,uEAAuE;AACvE,sEAAsE;AACtE,qEAAqE;AACrE,yCAAyC;AAEzC,OAAO,IAAI,MAAM,YAAY,CAAC;AAE9B,IAAI,EAAE,CAAC;AAEP,6DAA6D"}
1
+ {"version":3,"file":"auto.js","names":[],"sources":["../src/auto.ts"],"sourcesContent":["// #region -- Side-effect entry point ----------------------\n\n// `import \"@honeycluster/envx/auto\"` (or \"/config\") loads .env into\n// process.env on import — same ergonomics as `import \"dotenv/config\"`.\n// Picks up envx.config.* and the package.json `envx.config` discovery\n// chain automatically. Use the named/default export from the package\n// root when you want an explicit handle.\n\nimport envx from \"./index.js\";\n\nenvx();\n\n// #endregion -----------------------------------------------\n"],"mappings":";;AAUA,MAAM"}
@@ -1,3 +1 @@
1
- #!/usr/bin/env node
2
- import "@dotenvx/dotenvx";
3
1
  //# sourceMappingURL=dotenvx.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"dotenvx.d.ts","sourceRoot":"","sources":["../../src/bin/dotenvx.ts"],"names":[],"mappings":";AAKA,OAAO,kBAAkB,CAAC"}
1
+ {"version":3,"file":"dotenvx.d.ts","sourceRoot":"","sources":["../../src/bin/dotenvx.ts"],"names":[],"mappings":"AAQA,OAAO,kBAAkB,CAAC"}
@@ -1,6 +1,2 @@
1
1
  #!/usr/bin/env node
2
- // Legacy passthrough — re-exposes the upstream `@dotenvx/dotenvx` package
3
- // under the `legacy` bin so callers that need the original CLI can opt in
4
- // without leaving this package.
5
2
  import "@dotenvx/dotenvx";
6
- //# sourceMappingURL=dotenvx.js.map
@@ -0,0 +1,354 @@
1
+ import { a as resolveEnvPaths, c as loadDotenvxConfig, d as encryptFiles, f as parseEnv, i as loadEnv, l as expandEnvSrc, n as findWorkspaceRoot, o as validateCmdVariable, p as isEncrypted, r as listEnvFiles, s as log, t as writeProcessed, u as decryptFiles } from "./src-dIVfZVmT.js";
2
+ import * as fs from "fs";
3
+ import * as path from "path";
4
+ import yargs from "yargs";
5
+ import { execSync } from "child_process";
6
+ //#region src/commands/debug.ts
7
+ var debugCommand = {
8
+ command: "debug",
9
+ describe: "Show which env files would be loaded and which variables would be applied, without loading them.",
10
+ handler: (argv) => {
11
+ const paths = resolveEnvPaths({
12
+ envFiles: argv["env"],
13
+ cascade: argv["cascade"]
14
+ });
15
+ const rawVars = argv["variables"];
16
+ const variables = rawVars ? Object.fromEntries(rawVars.map(validateCmdVariable)) : {};
17
+ log.info(`Paths: ${JSON.stringify(paths)}`);
18
+ log.info(`Variables: ${JSON.stringify(variables)}`);
19
+ }
20
+ };
21
+ //#endregion
22
+ //#region src/commands/decrypt.ts
23
+ /** Mirror of `dotenvx decrypt` from upstream — see also encrypt.ts. */
24
+ var decryptCommand = {
25
+ command: "decrypt",
26
+ describe: "Decrypt the values in one or more .env files in place using the matching private key in .env.keys.",
27
+ builder: (yargs) => yargs.option("env-keys-file", {
28
+ alias: "fk",
29
+ type: "string",
30
+ describe: "Path to the .env.keys file (default: alongside the env file)."
31
+ }).option("key", {
32
+ alias: "k",
33
+ type: "array",
34
+ string: true,
35
+ describe: "Specific keys (or picomatch globs) to decrypt. Default: all keys."
36
+ }).option("exclude-key", {
37
+ alias: "ek",
38
+ type: "array",
39
+ string: true,
40
+ describe: "Keys (or picomatch globs) to leave encrypted."
41
+ }).option("stdout", {
42
+ type: "boolean",
43
+ default: false,
44
+ describe: "Write the decrypted env contents to stdout instead of saving in place."
45
+ }).help("h").alias("h", "help"),
46
+ handler: (argv) => {
47
+ const envFiles = argv["env"] ?? [".env"];
48
+ const keys = argv["key"];
49
+ const excludeKeys = argv["exclude-key"];
50
+ const envKeysFile = argv["env-keys-file"];
51
+ const stdout = argv["stdout"] ?? false;
52
+ const result = decryptFiles({
53
+ envFiles,
54
+ ...keys ? { keys } : {},
55
+ ...excludeKeys ? { excludeKeys } : {},
56
+ ...envKeysFile ? { envKeysFile } : {}
57
+ });
58
+ let hadError = false;
59
+ for (const processed of result.processedEnvs) {
60
+ if (processed.error) {
61
+ hadError = true;
62
+ log.error(`${processed.envFilepath}: ${processed.error.message}`);
63
+ if (processed.error.help) log.dim(processed.error.help);
64
+ continue;
65
+ }
66
+ if (stdout) process.stdout.write(processed.envSrc);
67
+ }
68
+ if (!stdout) {
69
+ const { written } = writeProcessed(result.processedEnvs);
70
+ for (const w of written) log.success(`decrypted ${w}`);
71
+ if (written.length === 0 && result.unchangedFilepaths.length > 0 && !hadError) log.dim(`no changes (${result.unchangedFilepaths.join(", ")})`);
72
+ }
73
+ if (hadError) process.exitCode = 1;
74
+ }
75
+ };
76
+ //#endregion
77
+ //#region src/commands/encrypt.ts
78
+ /**
79
+ * Mirrors the upstream `dotenvx encrypt` flags so existing muscle
80
+ * memory carries over. The `--env` global doubles as the file list
81
+ * (the upstream calls it `--env-file`); this CLI keeps a single
82
+ * canonical name across subcommands.
83
+ */
84
+ var encryptCommand = {
85
+ command: "encrypt",
86
+ describe: "Encrypt the values in one or more .env files. Generates a private key in .env.keys on first run.",
87
+ builder: (yargs) => yargs.option("env-keys-file", {
88
+ alias: "fk",
89
+ type: "string",
90
+ describe: "Path to the .env.keys file (default: alongside the env file)."
91
+ }).option("key", {
92
+ alias: "k",
93
+ type: "array",
94
+ string: true,
95
+ describe: "Specific keys (or picomatch globs) to encrypt. Default: all keys."
96
+ }).option("exclude-key", {
97
+ alias: "ek",
98
+ type: "array",
99
+ string: true,
100
+ describe: "Keys (or picomatch globs) to leave plaintext."
101
+ }).option("stdout", {
102
+ type: "boolean",
103
+ default: false,
104
+ describe: "Write the encrypted env contents to stdout instead of saving in place."
105
+ }).help("h").alias("h", "help"),
106
+ handler: (argv) => {
107
+ const envFiles = argv["env"] ?? [".env"];
108
+ const keys = argv["key"];
109
+ const excludeKeys = argv["exclude-key"];
110
+ const envKeysFile = argv["env-keys-file"];
111
+ const stdout = argv["stdout"] ?? false;
112
+ const result = encryptFiles({
113
+ envFiles,
114
+ ...keys ? { keys } : {},
115
+ ...excludeKeys ? { excludeKeys } : {},
116
+ ...envKeysFile ? { envKeysFile } : {}
117
+ });
118
+ let hadError = false;
119
+ for (const processed of result.processedEnvs) {
120
+ if (processed.error) {
121
+ hadError = true;
122
+ log.error(`${processed.envFilepath}: ${processed.error.message}`);
123
+ if (processed.error.help) log.dim(processed.error.help);
124
+ continue;
125
+ }
126
+ if (stdout) {
127
+ process.stdout.write(processed.envSrc);
128
+ continue;
129
+ }
130
+ if (processed.privateKeyAdded) log.success(`key added to .env.keys (${processed.privateKeyName ?? "<unknown>"})`);
131
+ }
132
+ if (!stdout) {
133
+ const { written } = writeProcessed(result.processedEnvs);
134
+ for (const w of written) log.success(`encrypted ${w}`);
135
+ if (written.length === 0 && result.unchangedFilepaths.length > 0 && !hadError) log.dim(`no changes (${result.unchangedFilepaths.join(", ")})`);
136
+ }
137
+ if (hadError) process.exitCode = 1;
138
+ }
139
+ };
140
+ //#endregion
141
+ //#region src/commands/expand.ts
142
+ /**
143
+ * Decrypts (when needed) and expands variable references in an env
144
+ * file. Mirrors the workflow `decrypt-vault` action — but cycle-safe,
145
+ * supports `${VAR:-default}` / `${VAR:?msg}`, and never silently
146
+ * truncates after N passes.
147
+ */
148
+ var expandCommand = {
149
+ command: "expand",
150
+ describe: "Decrypt (if needed) and expand ${VAR}/$VAR references in an env file. Outputs to stdout by default.",
151
+ builder: (yargs) => yargs.option("output", {
152
+ type: "string",
153
+ describe: "Write the expanded result to this file (default: stdout)."
154
+ }).option("env-keys-file", {
155
+ alias: "fk",
156
+ type: "string",
157
+ describe: "Path to .env.keys (default: alongside the env file)."
158
+ }).option("on-missing", {
159
+ type: "string",
160
+ choices: [
161
+ "leave",
162
+ "empty",
163
+ "throw"
164
+ ],
165
+ default: "leave",
166
+ describe: "How to handle ${UNRESOLVED_VAR}: leave it literal, substitute empty, or fail."
167
+ }).help("h").alias("h", "help"),
168
+ handler: (argv) => {
169
+ const envFiles = argv["env"] ?? [".env"];
170
+ if (envFiles.length !== 1) {
171
+ log.error(`expand operates on a single env file at a time; got ${String(envFiles.length)}.`);
172
+ process.exit(1);
173
+ }
174
+ const envFile = envFiles[0];
175
+ const filepath = path.resolve(envFile);
176
+ if (!fs.existsSync(filepath)) {
177
+ log.error(`env file not found: ${envFile}`);
178
+ process.exit(1);
179
+ }
180
+ let envSrc = fs.readFileSync(filepath, "utf8");
181
+ if (parseEnv(envSrc).some((l) => l.type === "kv" && isEncrypted(l.value))) {
182
+ const envKeysFile = argv["env-keys-file"];
183
+ const processed = decryptFiles({
184
+ envFiles: [envFile],
185
+ ...envKeysFile ? { envKeysFile } : {}
186
+ }).processedEnvs[0];
187
+ if (processed?.error) {
188
+ log.error(`${envFile}: ${processed.error.message}`);
189
+ if (processed.error.help) log.dim(processed.error.help);
190
+ process.exit(1);
191
+ }
192
+ envSrc = processed.envSrc;
193
+ }
194
+ const onMissing = argv["on-missing"];
195
+ const result = expandEnvSrc(envSrc, { onMissing });
196
+ for (const v of result.unresolved) log.warn(`unresolved variable: ${v}`);
197
+ for (const cycle of result.cycles) log.warn(`cycle: ${cycle.join(" → ")}`);
198
+ const output = argv["output"];
199
+ if (output) {
200
+ fs.writeFileSync(path.resolve(output), result.envSrc);
201
+ log.success(`expanded ${envFile} → ${output}`);
202
+ } else {
203
+ process.stdout.write(result.envSrc);
204
+ if (!result.envSrc.endsWith("\n")) process.stdout.write("\n");
205
+ }
206
+ }
207
+ };
208
+ //#endregion
209
+ //#region src/commands/print.ts
210
+ var printCommand = {
211
+ command: "print <variable>",
212
+ describe: "Load env files and print the value of a single variable.",
213
+ builder: (yargs) => yargs.positional("variable", {
214
+ describe: "Name of the variable to print",
215
+ type: "string",
216
+ demandOption: true
217
+ }),
218
+ handler: (argv) => {
219
+ loadEnv({
220
+ envFiles: argv["env"],
221
+ variables: argv["variables"],
222
+ cascade: argv["cascade"],
223
+ vault: argv["vault"],
224
+ envPath: argv["env-path"],
225
+ override: argv["override"],
226
+ quiet: argv["quiet"]
227
+ });
228
+ const name = argv["variable"];
229
+ const value = process.env[name];
230
+ process.stdout.write(value != null ? `${value}\n` : "\n");
231
+ }
232
+ };
233
+ //#endregion
234
+ //#region src/commands/run.ts
235
+ var runCommand = {
236
+ command: "run [command..]",
237
+ aliases: ["$0"],
238
+ describe: "Load env files into process.env and execute a command. Default subcommand — `dotenvx-run [command]` is equivalent.",
239
+ builder: (yargs) => yargs.positional("command", {
240
+ describe: "Command to execute after loading env files",
241
+ type: "string",
242
+ array: true
243
+ }),
244
+ handler: (argv) => {
245
+ const command = (argv["command"] ?? []).join(" ");
246
+ loadEnv({
247
+ envFiles: argv["env"],
248
+ variables: argv["variables"],
249
+ cascade: argv["cascade"],
250
+ vault: argv["vault"],
251
+ envPath: argv["env-path"],
252
+ override: argv["override"],
253
+ quiet: argv["quiet"]
254
+ });
255
+ if (!command) return;
256
+ log.info(`Running: ${command}`);
257
+ try {
258
+ execSync(command, { stdio: "inherit" });
259
+ log.success(`Command completed: ${command}`);
260
+ } catch (error) {
261
+ const msg = error instanceof Error ? error.message : String(error);
262
+ log.error(`Command failed: ${msg}`);
263
+ process.exit(1);
264
+ }
265
+ }
266
+ };
267
+ //#endregion
268
+ //#region src/commands/index.ts
269
+ /**
270
+ * Build the yargs CLI for `dotenvx-run`. Global options (env, variables,
271
+ * cascade, vault, override, quiet) are registered on the root so every
272
+ * subcommand inherits them.
273
+ */
274
+ function createCli(argvInput) {
275
+ return yargs(argvInput).scriptName("envx").usage("$0 <command> [options]").option("config", {
276
+ alias: "c",
277
+ type: "string",
278
+ describe: "Path to an envx config file (default: discovered from package.json `envx.config` or envx.config.{ts,js,json})."
279
+ }).option("env", {
280
+ alias: "e",
281
+ type: "array",
282
+ describe: "Env files to load. Default: [\".env\"] (or `envFiles` from config; or every .env* under --env-path when set). Auto-detects environment when omitted."
283
+ }).option("env-path", {
284
+ alias: ["dir", "d"],
285
+ type: "string",
286
+ describe: "Subdirectory of the workspace root holding the env files (e.g. `vault`). When set and --env is omitted, every .env* file in that directory is included."
287
+ }).option("variables", {
288
+ alias: "v",
289
+ type: "array",
290
+ describe: "Inline variables in the form name=value (repeatable).",
291
+ default: []
292
+ }).option("cascade", {
293
+ type: "string",
294
+ describe: "Cascade load order: .env, .env.<cascade>, .env.local, .env.<cascade>.local"
295
+ }).option("vault", {
296
+ alias: "va",
297
+ type: "boolean",
298
+ describe: "Shortcut for `--env-path vault`."
299
+ }).option("override", {
300
+ alias: "o",
301
+ type: "boolean",
302
+ describe: "Override existing process.env values. Conflicts with --cascade."
303
+ }).option("quiet", {
304
+ alias: "q",
305
+ type: "boolean",
306
+ describe: "Suppress dotenv's own output."
307
+ }).middleware((argv) => {
308
+ const configPath = argv["config"];
309
+ let loaded;
310
+ try {
311
+ loaded = loadDotenvxConfig({ ...configPath ? { configPath } : {} });
312
+ } catch (e) {
313
+ log.error(`config error: ${e.message}`);
314
+ process.exit(1);
315
+ }
316
+ if (loaded.source) log.dim(`config: ${loaded.source} (${loaded.origin})`);
317
+ const cfg = loaded.config;
318
+ if (argv["cascade"] === void 0 && cfg.cascade !== void 0) argv["cascade"] = cfg.cascade;
319
+ if (argv["override"] === void 0) argv["override"] = cfg.override ?? false;
320
+ if (argv["quiet"] === void 0) argv["quiet"] = cfg.quiet ?? true;
321
+ if (argv["vault"] === void 0) argv["vault"] = false;
322
+ if (argv["env-keys-file"] === void 0 && cfg.envKeysFile !== void 0) argv["env-keys-file"] = cfg.envKeysFile;
323
+ if (argv["env-path"] === void 0) {
324
+ if (cfg.envPath !== void 0) argv["env-path"] = cfg.envPath;
325
+ else if (argv["vault"]) argv["env-path"] = "vault";
326
+ }
327
+ const userPassedEnv = Array.isArray(argv["env"]) && argv["env"].length > 0;
328
+ let files;
329
+ if (userPassedEnv) files = argv["env"];
330
+ else if (cfg.envFiles && cfg.envFiles.length > 0) files = [...cfg.envFiles];
331
+ else if (typeof argv["env-path"] === "string") {
332
+ const subdir = argv["env-path"];
333
+ const wsRoot = findWorkspaceRoot();
334
+ const discovered = listEnvFiles(path.resolve(wsRoot, subdir));
335
+ if (discovered.length > 0) {
336
+ files = discovered;
337
+ log.dim(`env-path ${subdir}: discovered ${String(discovered.length)} file(s) — ${discovered.join(", ")}`);
338
+ } else {
339
+ files = [".env"];
340
+ log.warn(`env-path ${subdir}: no .env* files found; falling back to [".env"]`);
341
+ }
342
+ } else files = [".env"];
343
+ if (typeof argv["env-path"] === "string") {
344
+ const wsRoot = findWorkspaceRoot();
345
+ const dir = path.resolve(wsRoot, argv["env-path"]);
346
+ files = files.map((f) => path.isAbsolute(f) ? f : path.join(dir, f));
347
+ }
348
+ argv["env"] = files;
349
+ }).command(runCommand).command(printCommand).command(debugCommand).command(encryptCommand).command(decryptCommand).command(expandCommand).help("h").alias("h", "help").version().strictCommands().demandCommand(0).recommendCommands().epilog("Examples:\n envx -- node app.js # load .env (auto-detected) and run\n envx --env dev -- pnpm start # load .env.dev\n envx print DATABASE_URL # print one variable\n envx debug --cascade prod # show resolved paths\n envx encrypt -e .env.prod # encrypt values in .env.prod\n envx decrypt -e .env.prod -k FOO # decrypt only FOO\n envx expand -e vault/.env.prod # decrypt + expand to stdout\n envx -c ./my.config.json run -- node app.js");
350
+ }
351
+ //#endregion
352
+ export { createCli as t };
353
+
354
+ //# sourceMappingURL=commands-BZv1l-0k.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands-BZv1l-0k.js","names":[],"sources":["../../src/commands/debug.ts","../../src/commands/decrypt.ts","../../src/commands/encrypt.ts","../../src/commands/expand.ts","../../src/commands/print.ts","../../src/commands/run.ts","../../src/commands/index.ts"],"sourcesContent":["import type { CommandModule } from \"yargs\";\n\nimport { resolveEnvPaths, validateCmdVariable } from \"@honeycluster/libs\";\nimport { log } from \"@honeycluster/common\";\n\n// #region -- debug command ---------------------------------\n\nexport const debugCommand: CommandModule = {\n command: \"debug\",\n describe:\n \"Show which env files would be loaded and which variables would be applied, without loading them.\",\n handler: (argv) => {\n const paths = resolveEnvPaths({\n envFiles: argv[\"env\"] as string[] | undefined,\n cascade: argv[\"cascade\"] as string | undefined,\n });\n\n const rawVars = argv[\"variables\"] as string[] | undefined;\n const variables = rawVars\n ? Object.fromEntries(rawVars.map(validateCmdVariable))\n : {};\n\n log.info(`Paths: ${JSON.stringify(paths)}`);\n log.info(`Variables: ${JSON.stringify(variables)}`);\n },\n};\n\n// #endregion -----------------------------------------------\n","import type { CommandModule } from \"yargs\";\n\nimport { decryptFiles, writeProcessed } from \"@honeycluster/libs\";\n\nimport { log } from \"@honeycluster/common\";\n\n// #region -- decrypt command -------------------------------\n\n/** Mirror of `dotenvx decrypt` from upstream — see also encrypt.ts. */\nexport const decryptCommand: CommandModule = {\n command: \"decrypt\",\n describe:\n \"Decrypt the values in one or more .env files in place using the matching private key in .env.keys.\",\n builder: (yargs) =>\n yargs\n .option(\"env-keys-file\", {\n alias: \"fk\",\n type: \"string\",\n describe:\n \"Path to the .env.keys file (default: alongside the env file).\",\n })\n .option(\"key\", {\n alias: \"k\",\n type: \"array\",\n string: true,\n describe:\n \"Specific keys (or picomatch globs) to decrypt. Default: all keys.\",\n })\n .option(\"exclude-key\", {\n alias: \"ek\",\n type: \"array\",\n string: true,\n describe: \"Keys (or picomatch globs) to leave encrypted.\",\n })\n .option(\"stdout\", {\n type: \"boolean\",\n default: false,\n describe:\n \"Write the decrypted env contents to stdout instead of saving in place.\",\n })\n .help(\"h\")\n .alias(\"h\", \"help\"),\n handler: (argv) => {\n const envFiles = (argv[\"env\"] as string[] | undefined) ?? [\".env\"];\n const keys = argv[\"key\"] as string[] | undefined;\n const excludeKeys = argv[\"exclude-key\"] as string[] | undefined;\n const envKeysFile = argv[\"env-keys-file\"] as string | undefined;\n const stdout = (argv[\"stdout\"] as boolean | undefined) ?? false;\n\n const result = decryptFiles({\n envFiles,\n ...(keys ? { keys } : {}),\n ...(excludeKeys ? { excludeKeys } : {}),\n ...(envKeysFile ? { envKeysFile } : {}),\n });\n\n let hadError = false;\n\n for (const processed of result.processedEnvs) {\n if (processed.error) {\n hadError = true;\n log.error(`${processed.envFilepath}: ${processed.error.message}`);\n if (processed.error.help) log.dim(processed.error.help);\n continue;\n }\n if (stdout) {\n process.stdout.write(processed.envSrc);\n }\n }\n\n if (!stdout) {\n const { written } = writeProcessed(result.processedEnvs);\n for (const w of written) log.success(`decrypted ${w}`);\n if (\n written.length === 0 &&\n result.unchangedFilepaths.length > 0 &&\n !hadError\n ) {\n log.dim(`no changes (${result.unchangedFilepaths.join(\", \")})`);\n }\n }\n\n if (hadError) process.exitCode = 1;\n },\n};\n\n// #endregion -----------------------------------------------\n","import type { CommandModule } from \"yargs\";\n\nimport { encryptFiles, writeProcessed } from \"@honeycluster/libs\";\n\nimport { log } from \"@honeycluster/common\";\n\n// #region -- encrypt command -------------------------------\n\n/**\n * Mirrors the upstream `dotenvx encrypt` flags so existing muscle\n * memory carries over. The `--env` global doubles as the file list\n * (the upstream calls it `--env-file`); this CLI keeps a single\n * canonical name across subcommands.\n */\nexport const encryptCommand: CommandModule = {\n command: \"encrypt\",\n describe:\n \"Encrypt the values in one or more .env files. Generates a private key in .env.keys on first run.\",\n builder: (yargs) =>\n yargs\n .option(\"env-keys-file\", {\n alias: \"fk\",\n type: \"string\",\n describe:\n \"Path to the .env.keys file (default: alongside the env file).\",\n })\n .option(\"key\", {\n alias: \"k\",\n type: \"array\",\n string: true,\n describe:\n \"Specific keys (or picomatch globs) to encrypt. Default: all keys.\",\n })\n .option(\"exclude-key\", {\n alias: \"ek\",\n type: \"array\",\n string: true,\n describe: \"Keys (or picomatch globs) to leave plaintext.\",\n })\n .option(\"stdout\", {\n type: \"boolean\",\n default: false,\n describe:\n \"Write the encrypted env contents to stdout instead of saving in place.\",\n })\n .help(\"h\")\n .alias(\"h\", \"help\"),\n handler: (argv) => {\n const envFiles = (argv[\"env\"] as string[] | undefined) ?? [\".env\"];\n const keys = argv[\"key\"] as string[] | undefined;\n const excludeKeys = argv[\"exclude-key\"] as string[] | undefined;\n const envKeysFile = argv[\"env-keys-file\"] as string | undefined;\n const stdout = (argv[\"stdout\"] as boolean | undefined) ?? false;\n\n const result = encryptFiles({\n envFiles,\n ...(keys ? { keys } : {}),\n ...(excludeKeys ? { excludeKeys } : {}),\n ...(envKeysFile ? { envKeysFile } : {}),\n });\n\n let hadError = false;\n\n for (const processed of result.processedEnvs) {\n if (processed.error) {\n hadError = true;\n log.error(`${processed.envFilepath}: ${processed.error.message}`);\n if (processed.error.help) log.dim(processed.error.help);\n continue;\n }\n\n if (stdout) {\n process.stdout.write(processed.envSrc);\n continue;\n }\n\n if (processed.privateKeyAdded) {\n log.success(\n `key added to .env.keys (${processed.privateKeyName ?? \"<unknown>\"})`,\n );\n }\n }\n\n if (!stdout) {\n const { written } = writeProcessed(result.processedEnvs);\n for (const w of written) log.success(`encrypted ${w}`);\n if (\n written.length === 0 &&\n result.unchangedFilepaths.length > 0 &&\n !hadError\n ) {\n log.dim(`no changes (${result.unchangedFilepaths.join(\", \")})`);\n }\n }\n\n if (hadError) process.exitCode = 1;\n },\n};\n\n// #endregion -----------------------------------------------\n","import * as fs from \"fs\";\nimport * as path from \"path\";\nimport type { CommandModule } from \"yargs\";\n\nimport {\n decryptFiles,\n expandEnvSrc,\n isEncrypted,\n parseEnv,\n} from \"@honeycluster/libs\";\n\nimport { log } from \"@honeycluster/common\";\n\n// #region -- expand command --------------------------------\n\n/**\n * Decrypts (when needed) and expands variable references in an env\n * file. Mirrors the workflow `decrypt-vault` action — but cycle-safe,\n * supports `${VAR:-default}` / `${VAR:?msg}`, and never silently\n * truncates after N passes.\n */\nexport const expandCommand: CommandModule = {\n command: \"expand\",\n describe:\n \"Decrypt (if needed) and expand ${VAR}/$VAR references in an env file. Outputs to stdout by default.\",\n builder: (yargs) =>\n yargs\n .option(\"output\", {\n type: \"string\",\n describe: \"Write the expanded result to this file (default: stdout).\",\n })\n .option(\"env-keys-file\", {\n alias: \"fk\",\n type: \"string\",\n describe: \"Path to .env.keys (default: alongside the env file).\",\n })\n .option(\"on-missing\", {\n type: \"string\",\n choices: [\"leave\", \"empty\", \"throw\"] as const,\n default: \"leave\" as const,\n describe:\n \"How to handle ${UNRESOLVED_VAR}: leave it literal, substitute empty, or fail.\",\n })\n .help(\"h\")\n .alias(\"h\", \"help\"),\n handler: (argv) => {\n const envFiles = (argv[\"env\"] as string[] | undefined) ?? [\".env\"];\n if (envFiles.length !== 1) {\n log.error(\n `expand operates on a single env file at a time; got ${String(envFiles.length)}.`,\n );\n process.exit(1);\n }\n const envFile = envFiles[0]!;\n const filepath = path.resolve(envFile);\n if (!fs.existsSync(filepath)) {\n log.error(`env file not found: ${envFile}`);\n process.exit(1);\n }\n\n let envSrc = fs.readFileSync(filepath, \"utf8\");\n const hasEncrypted = parseEnv(envSrc).some(\n (l) => l.type === \"kv\" && isEncrypted(l.value),\n );\n\n if (hasEncrypted) {\n const envKeysFile = argv[\"env-keys-file\"] as string | undefined;\n const dec = decryptFiles({\n envFiles: [envFile],\n ...(envKeysFile ? { envKeysFile } : {}),\n });\n const processed = dec.processedEnvs[0];\n if (processed?.error) {\n log.error(`${envFile}: ${processed.error.message}`);\n if (processed.error.help) log.dim(processed.error.help);\n process.exit(1);\n }\n envSrc = processed!.envSrc;\n }\n\n const onMissing = argv[\"on-missing\"] as \"leave\" | \"empty\" | \"throw\";\n const result = expandEnvSrc(envSrc, { onMissing });\n\n for (const v of result.unresolved) {\n log.warn(`unresolved variable: ${v}`);\n }\n for (const cycle of result.cycles) {\n log.warn(`cycle: ${cycle.join(\" → \")}`);\n }\n\n const output = argv[\"output\"] as string | undefined;\n if (output) {\n fs.writeFileSync(path.resolve(output), result.envSrc);\n log.success(`expanded ${envFile} → ${output}`);\n } else {\n process.stdout.write(result.envSrc);\n if (!result.envSrc.endsWith(\"\\n\")) process.stdout.write(\"\\n\");\n }\n },\n};\n\n// #endregion -----------------------------------------------\n","import type { CommandModule } from \"yargs\";\n\nimport { loadEnv } from \"@honeycluster/libs\";\n\n// #region -- print command ---------------------------------\n\nexport const printCommand: CommandModule = {\n command: \"print <variable>\",\n describe: \"Load env files and print the value of a single variable.\",\n builder: (yargs) =>\n yargs.positional(\"variable\", {\n describe: \"Name of the variable to print\",\n type: \"string\",\n demandOption: true,\n }),\n handler: (argv) => {\n loadEnv({\n envFiles: argv[\"env\"] as string[] | undefined,\n variables: argv[\"variables\"] as string[] | undefined,\n cascade: argv[\"cascade\"] as string | undefined,\n vault: argv[\"vault\"] as boolean | undefined,\n envPath: argv[\"env-path\"] as string | undefined,\n override: argv[\"override\"] as boolean | undefined,\n quiet: argv[\"quiet\"] as boolean | undefined,\n });\n\n const name = argv[\"variable\"] as string;\n const value = process.env[name];\n process.stdout.write(value != null ? `${value}\\n` : \"\\n\");\n },\n};\n\n// #endregion -----------------------------------------------\n","import { execSync } from \"child_process\";\nimport type { CommandModule } from \"yargs\";\n\nimport { loadEnv } from \"@honeycluster/libs\";\nimport { log } from \"@honeycluster/common\";\n\n// #region -- run command -----------------------------------\n\nexport const runCommand: CommandModule = {\n command: \"run [command..]\",\n aliases: [\"$0\"],\n describe:\n \"Load env files into process.env and execute a command. Default subcommand — `dotenvx-run [command]` is equivalent.\",\n builder: (yargs) =>\n yargs.positional(\"command\", {\n describe: \"Command to execute after loading env files\",\n type: \"string\",\n array: true,\n }),\n handler: (argv) => {\n const command = ((argv[\"command\"] as string[] | undefined) ?? []).join(\" \");\n\n loadEnv({\n envFiles: argv[\"env\"] as string[] | undefined,\n variables: argv[\"variables\"] as string[] | undefined,\n cascade: argv[\"cascade\"] as string | undefined,\n vault: argv[\"vault\"] as boolean | undefined,\n envPath: argv[\"env-path\"] as string | undefined,\n override: argv[\"override\"] as boolean | undefined,\n quiet: argv[\"quiet\"] as boolean | undefined,\n });\n\n if (!command) return;\n\n log.info(`Running: ${command}`);\n try {\n execSync(command, { stdio: \"inherit\" });\n log.success(`Command completed: ${command}`);\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n log.error(`Command failed: ${msg}`);\n process.exit(1);\n }\n },\n};\n\n// #endregion -----------------------------------------------\n","import yargs from \"yargs\";\nimport type { Argv } from \"yargs\";\n\nimport * as path from \"path\";\n\nimport {\n findWorkspaceRoot,\n listEnvFiles,\n loadDotenvxConfig,\n} from \"@honeycluster/libs\";\n\nimport { log } from \"@honeycluster/common\";\nimport { debugCommand } from \"./debug.js\";\nimport { decryptCommand } from \"./decrypt.js\";\nimport { encryptCommand } from \"./encrypt.js\";\nimport { expandCommand } from \"./expand.js\";\nimport { printCommand } from \"./print.js\";\nimport { runCommand } from \"./run.js\";\n\n// #region -- CLI Factory -----------------------------------\n\n/**\n * Build the yargs CLI for `dotenvx-run`. Global options (env, variables,\n * cascade, vault, override, quiet) are registered on the root so every\n * subcommand inherits them.\n */\nexport function createCli(argvInput: string[]): Argv {\n return yargs(argvInput)\n .scriptName(\"envx\")\n .usage(\"$0 <command> [options]\")\n .option(\"config\", {\n alias: \"c\",\n type: \"string\",\n describe:\n \"Path to an envx config file (default: discovered from package.json `envx.config` or envx.config.{ts,js,json}).\",\n })\n .option(\"env\", {\n alias: \"e\",\n type: \"array\",\n describe:\n \"Env files to load. Default: [\\\".env\\\"] (or `envFiles` from config; or every .env* under --env-path when set). Auto-detects environment when omitted.\",\n })\n .option(\"env-path\", {\n alias: [\"dir\", \"d\"],\n type: \"string\",\n describe:\n \"Subdirectory of the workspace root holding the env files (e.g. `vault`). When set and --env is omitted, every .env* file in that directory is included.\",\n })\n .option(\"variables\", {\n alias: \"v\",\n type: \"array\",\n describe: \"Inline variables in the form name=value (repeatable).\",\n default: [],\n })\n .option(\"cascade\", {\n type: \"string\",\n describe:\n \"Cascade load order: .env, .env.<cascade>, .env.local, .env.<cascade>.local\",\n })\n .option(\"vault\", {\n alias: \"va\",\n type: \"boolean\",\n describe: \"Shortcut for `--env-path vault`.\",\n })\n .option(\"override\", {\n alias: \"o\",\n type: \"boolean\",\n describe: \"Override existing process.env values. Conflicts with --cascade.\",\n })\n .option(\"quiet\", {\n alias: \"q\",\n type: \"boolean\",\n describe: \"Suppress dotenv's own output.\",\n })\n .middleware((argv) => {\n const configPath = argv[\"config\"] as string | undefined;\n let loaded;\n try {\n loaded = loadDotenvxConfig({\n ...(configPath ? { configPath } : {}),\n });\n } catch (e) {\n log.error(`config error: ${(e as Error).message}`);\n process.exit(1);\n }\n if (loaded.source) {\n log.dim(`config: ${loaded.source} (${loaded.origin})`);\n }\n const cfg = loaded.config;\n // Apply config defaults only where the CLI didn't supply a value.\n if (argv[\"cascade\"] === undefined && cfg.cascade !== undefined) {\n argv[\"cascade\"] = cfg.cascade;\n }\n if (argv[\"override\"] === undefined) {\n argv[\"override\"] = cfg.override ?? false;\n }\n if (argv[\"quiet\"] === undefined) {\n argv[\"quiet\"] = cfg.quiet ?? true;\n }\n if (argv[\"vault\"] === undefined) {\n argv[\"vault\"] = false;\n }\n if (argv[\"env-keys-file\"] === undefined && cfg.envKeysFile !== undefined) {\n argv[\"env-keys-file\"] = cfg.envKeysFile;\n }\n\n // env-path: CLI > config > --vault shortcut\n if (argv[\"env-path\"] === undefined) {\n if (cfg.envPath !== undefined) argv[\"env-path\"] = cfg.envPath;\n else if (argv[\"vault\"]) argv[\"env-path\"] = \"vault\";\n }\n\n // env files: CLI > config > \"all .env* in env-path\" > [\".env\"]\n const userPassedEnv = Array.isArray(argv[\"env\"]) && argv[\"env\"].length > 0;\n let files: string[];\n if (userPassedEnv) {\n files = argv[\"env\"] as string[];\n } else if (cfg.envFiles && cfg.envFiles.length > 0) {\n files = [...cfg.envFiles];\n } else if (typeof argv[\"env-path\"] === \"string\") {\n // \"all files in the env-path are included\" — discover them.\n const subdir = argv[\"env-path\"] as string;\n const wsRoot = findWorkspaceRoot();\n const dir = path.resolve(wsRoot, subdir);\n const discovered = listEnvFiles(dir);\n if (discovered.length > 0) {\n files = discovered;\n log.dim(\n `env-path ${subdir}: discovered ${String(discovered.length)} file(s) — ${discovered.join(\", \")}`,\n );\n } else {\n files = [\".env\"];\n log.warn(\n `env-path ${subdir}: no .env* files found; falling back to [\".env\"]`,\n );\n }\n } else {\n files = [\".env\"];\n }\n\n // When env-path is set, resolve every relative file against that\n // directory up-front. encrypt/decrypt/expand operate on the\n // resulting paths verbatim — no per-command envPath plumbing.\n if (typeof argv[\"env-path\"] === \"string\") {\n const wsRoot = findWorkspaceRoot();\n const dir = path.resolve(wsRoot, argv[\"env-path\"] as string);\n files = files.map((f) => (path.isAbsolute(f) ? f : path.join(dir, f)));\n }\n argv[\"env\"] = files;\n })\n .command(runCommand)\n .command(printCommand)\n .command(debugCommand)\n .command(encryptCommand)\n .command(decryptCommand)\n .command(expandCommand)\n .help(\"h\")\n .alias(\"h\", \"help\")\n .version()\n .strictCommands()\n .demandCommand(0)\n .recommendCommands()\n .epilog(\n \"Examples:\\n\" +\n \" envx -- node app.js # load .env (auto-detected) and run\\n\" +\n \" envx --env dev -- pnpm start # load .env.dev\\n\" +\n \" envx print DATABASE_URL # print one variable\\n\" +\n \" envx debug --cascade prod # show resolved paths\\n\" +\n \" envx encrypt -e .env.prod # encrypt values in .env.prod\\n\" +\n \" envx decrypt -e .env.prod -k FOO # decrypt only FOO\\n\" +\n \" envx expand -e vault/.env.prod # decrypt + expand to stdout\\n\" +\n \" envx -c ./my.config.json run -- node app.js\",\n );\n}\n\n// #endregion -----------------------------------------------\n"],"mappings":"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"}
Binary file
@@ -0,0 +1 @@
1
+ {"version":3,"file":"src-dIVfZVmT.js","names":[],"sources":["../../../libs/src/crypto.ts","../../../libs/src/parser.ts","../../../libs/src/keys.ts","../../../libs/src/match.ts","../../../libs/src/encrypt.ts","../../../libs/src/decrypt.ts","../../../libs/src/expand.ts","../../../libs/src/config.ts","../../../common/src/logger.ts","../../../libs/src/env.ts","../../../libs/src/index.ts"],"sourcesContent":["import * as crypto from \"crypto\";\n\n// #region -- Algorithm Parameters --------------------------\n\n/**\n * AES-256-GCM with a random 96-bit nonce. Format on the wire:\n *\n * \"encrypted:\" + base64( nonce(12) ‖ ciphertext ‖ tag(16) )\n *\n * The `encrypted:` prefix matches the visual convention used by\n * upstream dotenvx, so encrypted values are recognizable in diffs even\n * though our crypto scheme is independent.\n */\nconst ALGORITHM = \"aes-256-gcm\" as const;\nconst NONCE_BYTES = 12;\nconst TAG_BYTES = 16;\nconst KEY_BYTES = 32;\nexport const ENCRYPTED_PREFIX = \"encrypted:\";\n\n// #endregion -----------------------------------------------\n\n// #region -- Key Generation --------------------------------\n\n/** Generate a fresh 256-bit private key encoded as 64 hex chars. */\nexport function generatePrivateKey(): string {\n return crypto.randomBytes(KEY_BYTES).toString(\"hex\");\n}\n\nfunction decodeKey(keyHex: string): Buffer {\n const buf = Buffer.from(keyHex, \"hex\");\n if (buf.length !== KEY_BYTES) {\n throw new Error(\n `[INVALID_KEY] private key must decode to ${String(KEY_BYTES)} bytes, got ${String(buf.length)}`,\n );\n }\n return buf;\n}\n\n// #endregion -----------------------------------------------\n\n// #region -- Encrypt / Decrypt -----------------------------\n\n/** Returns true if `value` looks like one of our ciphertext blobs. */\nexport function isEncrypted(value: string): boolean {\n return value.startsWith(ENCRYPTED_PREFIX);\n}\n\n/** AES-256-GCM encrypt; returns the `encrypted:<base64>` form. */\nexport function encryptValue(plaintext: string, keyHex: string): string {\n const key = decodeKey(keyHex);\n const nonce = crypto.randomBytes(NONCE_BYTES);\n const cipher = crypto.createCipheriv(ALGORITHM, key, nonce);\n const ciphertext = Buffer.concat([\n cipher.update(plaintext, \"utf8\"),\n cipher.final(),\n ]);\n const tag = cipher.getAuthTag();\n return ENCRYPTED_PREFIX + Buffer.concat([nonce, ciphertext, tag]).toString(\"base64\");\n}\n\n/**\n * AES-256-GCM decrypt. Throws on a corrupt/truncated blob, an auth-tag\n * mismatch, or a wrong key. Throws Errors with `.code` set so callers\n * can distinguish failure modes.\n */\nexport function decryptValue(blob: string, keyHex: string): string {\n if (!isEncrypted(blob)) {\n throw makeError(\"INVALID_CIPHERTEXT\", `value does not start with \"${ENCRYPTED_PREFIX}\"`);\n }\n const key = decodeKey(keyHex);\n const data = Buffer.from(blob.slice(ENCRYPTED_PREFIX.length), \"base64\");\n if (data.length < NONCE_BYTES + TAG_BYTES) {\n throw makeError(\"INVALID_CIPHERTEXT\", `ciphertext too short (${String(data.length)} bytes)`);\n }\n const nonce = data.subarray(0, NONCE_BYTES);\n const tag = data.subarray(data.length - TAG_BYTES);\n const ciphertext = data.subarray(NONCE_BYTES, data.length - TAG_BYTES);\n const decipher = crypto.createDecipheriv(ALGORITHM, key, nonce);\n decipher.setAuthTag(tag);\n try {\n return Buffer.concat([decipher.update(ciphertext), decipher.final()]).toString(\"utf8\");\n } catch (e) {\n const code =\n (e as NodeJS.ErrnoException).code === \"ERR_OSSL_BAD_DECRYPT\" ||\n (e as NodeJS.ErrnoException).code === \"ERR_CRYPTO_INVALID_AUTH_TAG\"\n ? \"DECRYPTION_FAILED\"\n : \"INVALID_CIPHERTEXT\";\n throw makeError(code, \"decryption failed (wrong key or tampered ciphertext)\");\n }\n}\n\ninterface CryptoError extends Error {\n code: string;\n}\n\nfunction makeError(code: string, message: string): CryptoError {\n const e = new Error(message) as CryptoError;\n e.code = code;\n return e;\n}\n\n// #endregion -----------------------------------------------\n","// #region -- Env File Parser -------------------------------\n\n/**\n * Line-preserving env-file parser. We parse to a typed line array\n * rather than a flat key→value map so that round-tripping (encrypt\n * one value, write file back) preserves comments, blank lines, and\n * declaration order — the signal-to-noise ratio of an env file's diff\n * is critical when these files live in version control.\n */\nexport interface KvLine {\n readonly type: \"kv\";\n readonly key: string;\n /** Raw value as it appeared in the file (still quoted if it was). */\n readonly raw: string;\n /** Logical value — quotes stripped, escape sequences resolved. */\n value: string;\n /** Quote style for serialization. Mutable so transforms (e.g. encrypt)\n * can drop quotes when the new value is self-quote-safe (URL-safe base64). */\n quote: '\"' | \"'\" | \"\";\n /** Trailing comment, including the leading '#' and whitespace. */\n readonly trailing: string;\n}\n\nexport interface RawLine {\n readonly type: \"raw\";\n /** Comment lines, blank lines, malformed lines — preserved verbatim. */\n readonly raw: string;\n}\n\nexport type EnvLine = KvLine | RawLine;\n\nconst KV_REGEX = /^\\s*([A-Za-z_][A-Za-z0-9_]*)\\s*=\\s*(.*?)\\s*$/;\n\n/** Parse a raw env-file string into a line array. */\nexport function parseEnv(content: string): EnvLine[] {\n const lines = content.split(\"\\n\");\n // If the file has a trailing newline, split() leaves a trailing \"\".\n // Drop it so we don't emit an extra blank raw line on round-trip.\n const trailingEmpty = lines.length > 0 && lines[lines.length - 1] === \"\";\n const body = trailingEmpty ? lines.slice(0, -1) : lines;\n\n const out: EnvLine[] = body.map((line) => {\n if (line.trim() === \"\" || line.trim().startsWith(\"#\")) {\n return { type: \"raw\", raw: line };\n }\n const match = KV_REGEX.exec(line);\n if (!match) return { type: \"raw\", raw: line };\n\n const key = match[1]!;\n const rawValueAndComment = match[2]!;\n const { rawValue, trailing } = splitTrailingComment(rawValueAndComment);\n const { value, quote } = unquote(rawValue);\n\n return { type: \"kv\", key, raw: rawValue, value, quote, trailing };\n });\n\n if (trailingEmpty) out.push({ type: \"raw\", raw: \"\" });\n return out;\n}\n\n/** Re-serialize a parsed line array. Round-trip safe for unmodified inputs. */\nexport function serializeEnv(lines: readonly EnvLine[]): string {\n return lines\n .map((line) => {\n if (line.type === \"raw\") return line.raw;\n const valueText = renderValue(line.value, line.quote);\n return `${line.key}=${valueText}${line.trailing}`;\n })\n .join(\"\\n\");\n}\n\n// #endregion -----------------------------------------------\n\n// #region -- Internal helpers ------------------------------\n\nfunction splitTrailingComment(s: string): { rawValue: string; trailing: string } {\n // Quoted values: anything past the closing quote is trailing\n // whitespace + comment, returned verbatim so round-tripping is exact.\n if (s.startsWith('\"') || s.startsWith(\"'\")) {\n const quote = s[0]!;\n let i = 1;\n while (i < s.length) {\n if (s[i] === \"\\\\\") {\n i += 2;\n continue;\n }\n if (s[i] === quote) {\n i += 1;\n break;\n }\n i += 1;\n }\n return { rawValue: s.slice(0, i), trailing: s.slice(i) };\n }\n // Unquoted: # starts a comment when preceded by whitespace.\n const m = /\\s+#.*$/.exec(s);\n if (!m) return { rawValue: s, trailing: \"\" };\n return {\n rawValue: s.slice(0, m.index),\n trailing: s.slice(m.index),\n };\n}\n\nfunction unquote(raw: string): { value: string; quote: '\"' | \"'\" | \"\" } {\n if (raw.length >= 2 && raw.startsWith('\"') && raw.endsWith('\"')) {\n return { value: unescapeDoubleQuoted(raw.slice(1, -1)), quote: '\"' };\n }\n if (raw.length >= 2 && raw.startsWith(\"'\") && raw.endsWith(\"'\")) {\n return { value: raw.slice(1, -1), quote: \"'\" };\n }\n return { value: raw, quote: \"\" };\n}\n\nfunction unescapeDoubleQuoted(s: string): string {\n return s\n .replace(/\\\\\\\\/g, \"\u0000\")\n .replace(/\\\\n/g, \"\\n\")\n .replace(/\\\\r/g, \"\\r\")\n .replace(/\\\\t/g, \"\\t\")\n .replace(/\\\\\"/g, '\"')\n .replace(/\u0000/g, \"\\\\\");\n}\n\nfunction escapeDoubleQuoted(s: string): string {\n return s\n .replace(/\\\\/g, \"\\\\\\\\\")\n .replace(/\"/g, '\\\\\"')\n .replace(/\\n/g, \"\\\\n\")\n .replace(/\\r/g, \"\\\\r\")\n .replace(/\\t/g, \"\\\\t\");\n}\n\nfunction renderValue(value: string, originalQuote: '\"' | \"'\" | \"\"): string {\n // Decide a safe quote style. If the value contains characters that\n // would break unquoted form (whitespace, $, #, ', \"), force quoting.\n const needsQuotes = /[\\s#$\"'`\\\\]/.test(value) || value === \"\";\n if (originalQuote === \"'\" && !value.includes(\"'\")) {\n return `'${value}'`;\n }\n if (originalQuote === \"'\" && value.includes(\"'\")) {\n // Single quotes can't escape — fall back to double.\n return `\"${escapeDoubleQuoted(value)}\"`;\n }\n if (originalQuote === '\"') {\n return `\"${escapeDoubleQuoted(value)}\"`;\n }\n // No original quotes — keep unquoted unless we have to.\n if (!needsQuotes) return value;\n return `\"${escapeDoubleQuoted(value)}\"`;\n}\n\n// #endregion -----------------------------------------------\n\n// #region -- Convenience -----------------------------------\n\n/** Build a flat key→value map from a parsed line array. Last write wins. */\nexport function toRecord(lines: readonly EnvLine[]): Record<string, string> {\n const out: Record<string, string> = {};\n for (const line of lines) {\n if (line.type === \"kv\") out[line.key] = line.value;\n }\n return out;\n}\n\n// #endregion -----------------------------------------------\n","import * as fs from \"fs\";\nimport * as path from \"path\";\n\nimport { parseEnv, serializeEnv, toRecord } from \"./parser.js\";\n\n// #region -- Per-file Key Naming ---------------------------\n\n/**\n * Convention for the private-key variable name: `DOTENV_PRIVATE_KEY` for\n * the unsuffixed `.env`, `DOTENV_PRIVATE_KEY_PROD` for `.env.prod`, etc.\n * Mirrors the upstream dotenvx convention so an existing `.env.keys`\n * with the right names will Just Work for our consumers.\n */\nexport function privateKeyNameFor(envFilePath: string): string {\n const basename = path.basename(envFilePath);\n if (basename === \".env\") return \"DOTENV_PRIVATE_KEY\";\n const suffix = basename.replace(/^\\.env\\./, \"\");\n return `DOTENV_PRIVATE_KEY_${normalize(suffix)}`;\n}\n\nfunction normalize(s: string): string {\n return s.toUpperCase().replace(/[^A-Z0-9]/g, \"_\");\n}\n\n// #endregion -----------------------------------------------\n\n// #region -- .env.keys File I/O ----------------------------\n\n/** Read a .env.keys file as a key→value map. Returns an empty map when the file doesn't exist. */\nexport function readKeysFile(keysPath: string): Map<string, string> {\n if (!fs.existsSync(keysPath)) return new Map();\n const lines = parseEnv(fs.readFileSync(keysPath, \"utf8\"));\n return new Map(Object.entries(toRecord(lines)));\n}\n\n/**\n * Persist a key→value map to .env.keys. Overwrites the file. Preserves\n * order from the input map (so consumers get stable diffs).\n */\nexport function writeKeysFile(keysPath: string, keys: Map<string, string>): void {\n // Re-serialize using the parser/serializer so quoting follows the same\n // conventions as the .env files we read/write.\n const linesOut: import(\"./parser.js\").EnvLine[] = [];\n let first = true;\n for (const [key, value] of keys) {\n if (first) first = false;\n linesOut.push({\n type: \"kv\",\n key,\n value,\n raw: value,\n quote: '\"',\n trailing: \"\",\n });\n }\n fs.writeFileSync(keysPath, serializeEnv(linesOut) + \"\\n\");\n}\n\n/** Default location for .env.keys: alongside the env file. */\nexport function defaultKeysPathFor(envFilepath: string): string {\n return path.resolve(path.dirname(envFilepath), \".env.keys\");\n}\n\n// #endregion -----------------------------------------------\n","// #region -- Glob matching ---------------------------------\n\n/**\n * Tiny glob matcher: `*` matches any run of characters within a key\n * name, `?` matches a single character, anything else is literal.\n * Sufficient for the include/exclude key filters; for full picomatch\n * semantics, swap this out — the predicates only consume a string.\n */\nfunction compile(pattern: string): RegExp {\n const escaped = pattern.replace(/[.+^${}()|[\\]\\\\]/g, \"\\\\$&\");\n const body = escaped.replace(/\\*/g, \".*\").replace(/\\?/g, \".\");\n return new RegExp(`^${body}$`);\n}\n\nexport function matchesAny(key: string, patterns: readonly string[]): boolean {\n for (const pattern of patterns) {\n if (compile(pattern).test(key)) return true;\n }\n return false;\n}\n\n/**\n * Decide whether to operate on a key given include + exclude filters.\n * Empty includes means \"all keys\". Excludes always win.\n */\nexport function isSelected(\n key: string,\n includes: readonly string[],\n excludes: readonly string[],\n): boolean {\n if (excludes.length > 0 && matchesAny(key, excludes)) return false;\n if (includes.length === 0) return true;\n return matchesAny(key, includes);\n}\n\n// #endregion -----------------------------------------------\n","import * as fs from \"fs\";\nimport * as path from \"path\";\n\nimport {\n ENCRYPTED_PREFIX,\n encryptValue,\n generatePrivateKey,\n isEncrypted,\n} from \"./crypto.js\";\nimport { defaultKeysPathFor, privateKeyNameFor, readKeysFile, writeKeysFile } from \"./keys.js\";\nimport { isSelected } from \"./match.js\";\nimport { parseEnv, serializeEnv } from \"./parser.js\";\nimport type { ProcessedEnv, RunOptions, RunResult } from \"./types.js\";\n\n// #region -- encryptFiles ----------------------------------\n\n/**\n * Encrypt selected values across one or more env files. Pure: returns\n * new file contents but does not write to disk. Use {@link writeProcessed}\n * to persist. Will create a private key in `.env.keys` on first run for\n * each file (this is a side effect — the key file is written eagerly so\n * the returned envSrc is decryptable).\n */\nexport function encryptFiles(opts: RunOptions): RunResult {\n const includes = opts.keys ?? [];\n const excludes = opts.excludeKeys ?? [];\n const processedEnvs: ProcessedEnv[] = [];\n const changedFilepaths: string[] = [];\n const unchangedFilepaths: string[] = [];\n\n for (const envFilePath of opts.envFiles) {\n const filepath = path.resolve(envFilePath);\n const keysPath = opts.envKeysFile\n ? path.resolve(opts.envKeysFile)\n : defaultKeysPathFor(filepath);\n\n if (!fs.existsSync(filepath)) {\n processedEnvs.push({\n envFilepath: envFilePath,\n filepath,\n envSrc: \"\",\n changed: false,\n keys: [],\n error: {\n code: \"MISSING_ENV_FILE\",\n message: `env file not found: ${envFilePath}`,\n help: `add one with [echo \"HELLO=World\" > ${envFilePath}] and re-run`,\n },\n });\n continue;\n }\n\n const keysMap = readKeysFile(keysPath);\n const keyName = privateKeyNameFor(envFilePath);\n let keyHex = keysMap.get(keyName);\n let privateKeyAdded = false;\n if (!keyHex) {\n keyHex = generatePrivateKey();\n keysMap.set(keyName, keyHex);\n writeKeysFile(keysPath, keysMap);\n privateKeyAdded = true;\n }\n\n const lines = parseEnv(fs.readFileSync(filepath, \"utf8\"));\n const fileKeys: string[] = [];\n let changed = false;\n\n for (const line of lines) {\n if (line.type !== \"kv\") continue;\n fileKeys.push(line.key);\n if (isEncrypted(line.value)) continue;\n if (!isSelected(line.key, includes, excludes)) continue;\n line.value = encryptValue(line.value, keyHex);\n // `encrypted:<base64>` is URL-safe — drop any inherited quote style so\n // diffs stay minimal. Decrypt restores the value, render reapplies\n // quotes based on the plaintext's content if needed.\n line.quote = \"\";\n changed = true;\n }\n\n const envSrc = serializeEnv(lines);\n const processed: ProcessedEnv = {\n envFilepath: envFilePath,\n filepath,\n envSrc,\n changed,\n keys: fileKeys,\n ...(privateKeyAdded\n ? { privateKeyAdded: true, privateKeyName: keyName, privateKey: keyHex }\n : {}),\n };\n processedEnvs.push(processed);\n if (changed) changedFilepaths.push(filepath);\n else unchangedFilepaths.push(filepath);\n }\n\n return { processedEnvs, changedFilepaths, unchangedFilepaths };\n}\n\n// Re-export the prefix so callers can detect ciphertext at the consumer level.\nexport { ENCRYPTED_PREFIX };\n\n// #endregion -----------------------------------------------\n","import * as fs from \"fs\";\nimport * as path from \"path\";\n\nimport { decryptValue, isEncrypted } from \"./crypto.js\";\nimport { defaultKeysPathFor, privateKeyNameFor, readKeysFile } from \"./keys.js\";\nimport { isSelected } from \"./match.js\";\nimport { parseEnv, serializeEnv } from \"./parser.js\";\n\nfunction needsQuotes(value: string): boolean {\n return /[\\s#$\"'`\\\\]/.test(value) || value === \"\";\n}\nimport type { ProcessedEnv, ProcessingError, RunOptions, RunResult } from \"./types.js\";\n\n// #region -- decryptFiles ----------------------------------\n\n/**\n * Decrypt selected values across one or more env files. Pure: returns\n * new file contents but does not write to disk. Errors per-file (missing\n * env file, missing private key, bad ciphertext) surface in the\n * `processed.error` field so a single broken file doesn't kill the\n * whole batch.\n */\nexport function decryptFiles(opts: RunOptions): RunResult {\n const includes = opts.keys ?? [];\n const excludes = opts.excludeKeys ?? [];\n const processedEnvs: ProcessedEnv[] = [];\n const changedFilepaths: string[] = [];\n const unchangedFilepaths: string[] = [];\n\n for (const envFilePath of opts.envFiles) {\n const filepath = path.resolve(envFilePath);\n const keysPath = opts.envKeysFile\n ? path.resolve(opts.envKeysFile)\n : defaultKeysPathFor(filepath);\n\n if (!fs.existsSync(filepath)) {\n processedEnvs.push({\n envFilepath: envFilePath,\n filepath,\n envSrc: \"\",\n changed: false,\n keys: [],\n error: {\n code: \"MISSING_ENV_FILE\",\n message: `env file not found: ${envFilePath}`,\n },\n });\n continue;\n }\n\n const keysMap = readKeysFile(keysPath);\n const keyName = privateKeyNameFor(envFilePath);\n const keyHex = keysMap.get(keyName);\n\n const lines = parseEnv(fs.readFileSync(filepath, \"utf8\"));\n const fileKeys: string[] = [];\n let changed = false;\n let decryptError: ProcessingError | undefined;\n\n for (const line of lines) {\n if (line.type !== \"kv\") continue;\n fileKeys.push(line.key);\n if (!isEncrypted(line.value)) continue;\n if (!isSelected(line.key, includes, excludes)) continue;\n if (!keyHex) {\n decryptError = {\n code: \"MISSING_PRIVATE_KEY\",\n message: `no ${keyName} found in ${keysPath}`,\n help: `set ${keyName} in your .env.keys file or pass --env-keys-file`,\n };\n break;\n }\n try {\n line.value = decryptValue(line.value, keyHex);\n // Re-derive a sensible quote style from the decrypted content. We\n // can't recover the user's original quote choice (it was lost when\n // we encrypted), but we can quote whenever the value would be\n // ambiguous unquoted, and use double quotes by default so escape\n // sequences round-trip cleanly.\n line.quote = needsQuotes(line.value) ? '\"' : \"\";\n changed = true;\n } catch (e) {\n decryptError = {\n code:\n (e as { code?: string }).code === \"DECRYPTION_FAILED\"\n ? \"DECRYPTION_FAILED\"\n : \"INVALID_CIPHERTEXT\",\n message: `${envFilePath}: ${(e as Error).message} (key=${line.key})`,\n };\n break;\n }\n }\n\n const envSrc = serializeEnv(lines);\n const processed: ProcessedEnv = {\n envFilepath: envFilePath,\n filepath,\n envSrc: decryptError ? fs.readFileSync(filepath, \"utf8\") : envSrc,\n changed: !decryptError && changed,\n keys: fileKeys,\n ...(decryptError ? { error: decryptError } : {}),\n };\n processedEnvs.push(processed);\n if (processed.changed) changedFilepaths.push(filepath);\n else if (!decryptError) unchangedFilepaths.push(filepath);\n }\n\n return { processedEnvs, changedFilepaths, unchangedFilepaths };\n}\n\n// #endregion -----------------------------------------------\n","import { parseEnv, serializeEnv } from \"./parser.js\";\n\n// #region -- Variable Expansion ----------------------------\n\n/**\n * Expand `${VAR}`, `$VAR`, `${VAR:-default}`, and `${VAR:?error}` references\n * in env-file values. Iterative + cycle-safe: builds a dependency graph,\n * topologically substitutes, and bails with a clear error on cycles.\n *\n * More robust than the bash version in `.github/actions/decrypt-vault`:\n * - Handles `$VAR` (bare) and `${VAR}` syntactically.\n * - Supports `${VAR:-default}` (use default if VAR is unset/empty)\n * and `${VAR:?msg}` (error if unset/empty).\n * - Supports `\\${VAR}` and `\\$VAR` escapes for literal `${VAR}` / `$VAR`.\n * - Detects cycles instead of silently truncating after N passes.\n * - Reports each unresolved variable, doesn't silently leave them.\n */\n\nexport interface ExpandOptions {\n /**\n * Variables to layer in beneath the file's own values. The file's\n * values take precedence; this is the fallback (typically process.env).\n */\n readonly fallback?: Readonly<Record<string, string | undefined>>;\n /**\n * What to do when a `${UNSET_VAR}` reference can't be resolved.\n * - \"leave\" (default): keep the literal `${UNSET_VAR}` in place,\n * and add a warning to the result.\n * - \"empty\": substitute an empty string, add a warning.\n * - \"throw\": throw an Error listing all unresolved refs.\n */\n readonly onMissing?: \"leave\" | \"empty\" | \"throw\";\n}\n\nexport interface ExpandResult {\n /** Expanded key→value map (file-only — fallback is not included). */\n readonly values: Record<string, string>;\n /** Re-serialized env-file content with all values expanded. */\n readonly envSrc: string;\n /** Variables that were referenced but couldn't be resolved. */\n readonly unresolved: string[];\n /** Variables that participated in an unresolvable cycle. */\n readonly cycles: string[][];\n}\n\n/** Expand a key→value record. Returns the expanded record + diagnostics. */\nexport function expandRecord(\n values: Readonly<Record<string, string>>,\n opts: ExpandOptions = {},\n): { values: Record<string, string>; unresolved: string[]; cycles: string[][] } {\n const onMissing = opts.onMissing ?? \"leave\";\n const fallback = opts.fallback ?? {};\n\n // Iterative DFS-based resolution. Cache resolved values; track in-flight\n // keys to detect cycles.\n const resolved: Record<string, string> = {};\n const inFlight = new Set<string>();\n const unresolved = new Set<string>();\n const cycles: string[][] = [];\n\n function isDefined(name: string): boolean {\n if (Object.prototype.hasOwnProperty.call(values, name)) return true;\n if (Object.prototype.hasOwnProperty.call(fallback, name) && fallback[name] !== undefined) {\n return true;\n }\n return false;\n }\n\n function lookup(name: string, stack: string[]): string {\n if (Object.prototype.hasOwnProperty.call(resolved, name)) return resolved[name]!;\n if (inFlight.has(name)) {\n const cycleStart = stack.indexOf(name);\n cycles.push(stack.slice(cycleStart === -1 ? 0 : cycleStart).concat(name));\n return \"\";\n }\n if (Object.prototype.hasOwnProperty.call(values, name)) {\n inFlight.add(name);\n const result = expandString(values[name]!, [...stack, name]);\n inFlight.delete(name);\n resolved[name] = result;\n return result;\n }\n if (Object.prototype.hasOwnProperty.call(fallback, name)) {\n const v = fallback[name];\n if (v !== undefined) {\n resolved[name] = v;\n return v;\n }\n }\n return \"\";\n }\n\n function expandString(input: string, stack: string[]): string {\n return substitute(input, (varName, fallbackForm) => {\n const defined = isDefined(varName);\n\n // Fully unresolved: short-circuit on default/error before touching unresolved set.\n if (!defined) {\n if (fallbackForm?.kind === \"default\") {\n return expandString(fallbackForm.value, stack);\n }\n if (fallbackForm?.kind === \"error\") {\n throw new Error(\n `[${varName}:?] ${fallbackForm.value || \"variable is unset or empty\"}`,\n );\n }\n unresolved.add(varName);\n if (onMissing === \"empty\") return \"\";\n return \"${\" + varName + \"}\";\n }\n\n const v = lookup(varName, stack);\n // Defined but empty → POSIX :- and :? still treat empty as \"unset\".\n if (v === \"\" && fallbackForm?.kind === \"default\") {\n return expandString(fallbackForm.value, stack);\n }\n if (v === \"\" && fallbackForm?.kind === \"error\") {\n throw new Error(\n `[${varName}:?] ${fallbackForm.value || \"variable is unset or empty\"}`,\n );\n }\n return v;\n });\n }\n\n for (const key of Object.keys(values)) {\n if (resolved[key] === undefined && !inFlight.has(key)) {\n inFlight.add(key);\n try {\n resolved[key] = expandString(values[key]!, [key]);\n } finally {\n inFlight.delete(key);\n }\n }\n }\n\n if (onMissing === \"throw\" && (unresolved.size > 0 || cycles.length > 0)) {\n const parts: string[] = [];\n if (unresolved.size > 0) parts.push(`unresolved: ${[...unresolved].join(\", \")}`);\n if (cycles.length > 0) {\n parts.push(`cycles: ${cycles.map((c) => c.join(\" → \")).join(\"; \")}`);\n }\n throw new Error(`expansion failed — ${parts.join(\"; \")}`);\n }\n\n return { values: resolved, unresolved: [...unresolved], cycles };\n}\n\n/**\n * Expand variables in a parsed env file (string in, string out). The\n * file's own values take precedence; `opts.fallback` (default:\n * `process.env`) fills in the rest.\n */\nexport function expandEnvSrc(envSrc: string, opts: ExpandOptions = {}): ExpandResult {\n const lines = parseEnv(envSrc);\n const values: Record<string, string> = {};\n for (const line of lines) {\n if (line.type === \"kv\") values[line.key] = line.value;\n }\n const fallback = opts.fallback ?? process.env;\n const result = expandRecord(values, { ...opts, fallback });\n for (const line of lines) {\n if (line.type === \"kv\") line.value = result.values[line.key] ?? line.value;\n }\n return {\n values: result.values,\n envSrc: serializeEnv(lines),\n unresolved: result.unresolved,\n cycles: result.cycles,\n };\n}\n\n// #endregion -----------------------------------------------\n\n// #region -- Tokenization ----------------------------------\n\ninterface DefaultRef {\n readonly kind: \"default\";\n readonly value: string;\n}\n\ninterface ErrorRef {\n readonly kind: \"error\";\n readonly value: string;\n}\n\ntype FallbackForm = DefaultRef | ErrorRef | undefined;\n\ntype Substituter = (name: string, fallback: FallbackForm) => string;\n\n/**\n * Walk the input character-by-character. Recognizes:\n * - `\\$` — escape, keep literal `$`\n * - `\\${` — escape, keep literal `${`\n * - `${NAME}`, `${NAME:-default}`, `${NAME:?msg}`\n * - `$NAME`\n */\nfunction substitute(input: string, substituter: Substituter): string {\n let out = \"\";\n let i = 0;\n while (i < input.length) {\n const c = input[i]!;\n if (c === \"\\\\\" && (input[i + 1] === \"$\" || input[i + 1] === \"\\\\\")) {\n out += input[i + 1];\n i += 2;\n continue;\n }\n if (c !== \"$\") {\n out += c;\n i += 1;\n continue;\n }\n // Possible $... reference\n const next = input[i + 1];\n if (next === \"{\") {\n const close = findMatchingBrace(input, i + 1);\n if (close === -1) {\n // No closing brace; treat as literal\n out += c;\n i += 1;\n continue;\n }\n const inner = input.slice(i + 2, close);\n const { name, fallback } = parseRef(inner);\n if (!isValidName(name)) {\n out += input.slice(i, close + 1);\n } else {\n out += substituter(name, fallback);\n }\n i = close + 1;\n continue;\n }\n if (next !== undefined && /[A-Za-z_]/.test(next)) {\n let j = i + 1;\n while (j < input.length && /[A-Za-z0-9_]/.test(input[j]!)) j++;\n const name = input.slice(i + 1, j);\n out += substituter(name, undefined);\n i = j;\n continue;\n }\n // Lone $\n out += c;\n i += 1;\n }\n return out;\n}\n\nfunction findMatchingBrace(s: string, openIdx: number): number {\n let depth = 0;\n for (let i = openIdx; i < s.length; i++) {\n if (s[i] === \"{\") depth++;\n else if (s[i] === \"}\") {\n depth--;\n if (depth === 0) return i;\n }\n }\n return -1;\n}\n\nfunction parseRef(inner: string): { name: string; fallback: FallbackForm } {\n // ${NAME:-default}\n let idx = inner.indexOf(\":-\");\n if (idx !== -1) {\n return {\n name: inner.slice(0, idx),\n fallback: { kind: \"default\", value: inner.slice(idx + 2) },\n };\n }\n // ${NAME:?msg}\n idx = inner.indexOf(\":?\");\n if (idx !== -1) {\n return {\n name: inner.slice(0, idx),\n fallback: { kind: \"error\", value: inner.slice(idx + 2) },\n };\n }\n return { name: inner, fallback: undefined };\n}\n\nfunction isValidName(name: string): boolean {\n return /^[A-Za-z_][A-Za-z0-9_]*$/.test(name);\n}\n\n// #endregion -----------------------------------------------\n","import * as fs from \"fs\";\nimport * as path from \"path\";\nimport { createRequire } from \"module\";\nimport { pathToFileURL } from \"url\";\n\n// #region -- Schema ----------------------------------------\n\n/**\n * Mapping shape: per-file allowlist of keys (or globs). Used to decide\n * which env file an inline key belongs in, and to constrain\n * encrypt/decrypt to the right scope.\n *\n * {\n * '.env.shared': ['DATABASE_URL', 'REDIS_URL'],\n * '.env.app': ['APP_*'],\n * }\n */\nexport type EnvFileMapping = Readonly<Record<string, readonly string[]>>;\n\nexport interface DotenvxConfig {\n /** Default env files to load when --env is not supplied. */\n readonly envFiles?: readonly string[];\n /**\n * Subdirectory of the workspace root where env files live (e.g. \"vault\").\n * When set, relative env file paths resolve to `<workspaceRoot>/<envPath>/<file>`\n * instead of `<workspaceRoot>/<file>`. Equivalent to passing `--vault`\n * (which is a shortcut for `envPath: \"vault\"`).\n */\n readonly envPath?: string;\n /** Cascade strategy ('prod', 'dev', etc.) — see loadEnv. */\n readonly cascade?: string;\n /** Path to the keys file. Defaults to .env.keys alongside each env file. */\n readonly envKeysFile?: string;\n /** Per-file allowlist of keys (literal names or globs). */\n readonly mapping?: EnvFileMapping;\n /** Override existing process.env when loading. */\n readonly override?: boolean;\n /** Suppress dotenv-style logging. */\n readonly quiet?: boolean;\n}\n\n// #endregion -----------------------------------------------\n\n// #region -- Loader ----------------------------------------\n\nexport interface LoadConfigOptions {\n /** Explicit config path (highest precedence). */\n readonly configPath?: string;\n /** Where to start the search. Defaults to process.cwd(). */\n readonly cwd?: string;\n}\n\nexport interface LoadedConfig {\n /** Resolved config values. Always present (defaults merged in). */\n readonly config: DotenvxConfig;\n /** Absolute path the config was loaded from, or null if defaults. */\n readonly source: string | null;\n /** Source kind: how the config was discovered. */\n readonly origin: \"explicit\" | \"package.json\" | \"auto\" | \"defaults\";\n}\n\nconst AUTO_NAMES = [\n \"envx.config.ts\",\n \"envx.config.mts\",\n \"envx.config.js\",\n \"envx.config.mjs\",\n \"envx.config.cjs\",\n \"envx.config.json\",\n] as const;\n\n/**\n * Resolve the dotenvx config in this order:\n *\n * 1. `opts.configPath` (typically from `--config <path>`).\n * 2. `package.json` → `dotenvx.config` (string path) — walks upward\n * from `cwd` to find the nearest package.json.\n * 3. The first `dotenvx.config.{ts,js,json,…}` discovered at `cwd`.\n * 4. Built-in defaults (returns `source: null`, `origin: \"defaults\"`).\n */\nexport function loadDotenvxConfig(\n opts: LoadConfigOptions = {},\n): LoadedConfig {\n const cwd = opts.cwd ?? process.cwd();\n\n if (opts.configPath) {\n const resolved = path.resolve(cwd, opts.configPath);\n return {\n config: loadConfigFile(resolved),\n source: resolved,\n origin: \"explicit\",\n };\n }\n\n const fromPackageJson = findInPackageJson(cwd);\n if (fromPackageJson) {\n return {\n config: loadConfigFile(fromPackageJson.path),\n source: fromPackageJson.path,\n origin: \"package.json\",\n };\n }\n\n const fromAuto = findAutoConfig(cwd);\n if (fromAuto) {\n return {\n config: loadConfigFile(fromAuto),\n source: fromAuto,\n origin: \"auto\",\n };\n }\n\n return { config: {}, source: null, origin: \"defaults\" };\n}\n\n// #endregion -----------------------------------------------\n\n// #region -- Discovery ------------------------------------\n\nfunction findInPackageJson(\n startDir: string,\n): { path: string; pkgPath: string } | null {\n let dir = startDir;\n const root = path.parse(dir).root;\n while (true) {\n const pkgPath = path.join(dir, \"package.json\");\n if (fs.existsSync(pkgPath)) {\n try {\n const raw = JSON.parse(fs.readFileSync(pkgPath, \"utf8\")) as {\n envx?: { config?: string };\n // legacy spelling — read but don't write; we'll drop in a major bump.\n dotenvx?: { config?: string };\n };\n const ref = raw.envx?.config ?? raw.dotenvx?.config;\n if (typeof ref === \"string\" && ref.length > 0) {\n return { path: path.resolve(dir, ref), pkgPath };\n }\n } catch {\n // Ignore unreadable/malformed package.json — keep walking up.\n }\n }\n if (dir === root) return null;\n const parent = path.dirname(dir);\n if (parent === dir) return null;\n dir = parent;\n }\n}\n\nfunction findAutoConfig(startDir: string): string | null {\n for (const name of AUTO_NAMES) {\n const p = path.join(startDir, name);\n if (fs.existsSync(p)) return p;\n }\n return null;\n}\n\n// #endregion -----------------------------------------------\n\n// #region -- File loading ----------------------------------\n\nconst require_ = createRequire(import.meta.url);\n\nfunction loadConfigFile(filePath: string): DotenvxConfig {\n if (!fs.existsSync(filePath)) {\n throw new Error(`[CONFIG_NOT_FOUND] no config at ${filePath}`);\n }\n const ext = path.extname(filePath).toLowerCase();\n switch (ext) {\n case \".json\":\n return normalize(JSON.parse(fs.readFileSync(filePath, \"utf8\")));\n case \".cjs\":\n return normalize(require_(filePath));\n case \".js\":\n case \".mjs\":\n // .js files require sync loading. CJS works via require; ESM under\n // a \"type\": \"module\" parent doesn't. Try require first; if it\n // throws ERR_REQUIRE_ESM, fall back to dynamic import (caller must\n // be in an async context — we surface the limitation in the docs).\n return normalize(loadJsSync(filePath));\n case \".ts\":\n case \".mts\":\n // TypeScript configs require a runtime transpiler (tsx, ts-node).\n // We try to require via tsx if it's been installed, else throw a\n // clear error.\n return normalize(loadTsSync(filePath));\n default:\n throw new Error(`[CONFIG_BAD_EXT] unsupported config extension: ${ext}`);\n }\n}\n\nfunction loadJsSync(filePath: string): unknown {\n try {\n const mod = require_(filePath);\n return (mod as { default?: unknown }).default ?? mod;\n } catch (e) {\n if ((e as NodeJS.ErrnoException).code === \"ERR_REQUIRE_ESM\") {\n throw new Error(\n `[CONFIG_ESM_REQUIRES_ASYNC] ${filePath} is ESM. Either rename it to .cjs, ` +\n `add \"type\": \"commonjs\" to its package.json, or use loadDotenvxConfigAsync.`,\n );\n }\n throw e;\n }\n}\n\nfunction loadTsSync(filePath: string): unknown {\n // tsx registers a require hook when it's loaded. If the consumer has\n // it as a dev dep we'll find it; otherwise tell them how to enable it.\n try {\n require_(\"tsx/cjs\");\n } catch {\n throw new Error(\n `[CONFIG_TS_NEEDS_TSX] loading ${filePath} requires \"tsx\" to be installed. ` +\n `Add it as a devDependency, or use a .js / .json config instead.`,\n );\n }\n const mod = require_(filePath);\n return (mod as { default?: unknown }).default ?? mod;\n}\n\nfunction normalize(raw: unknown): DotenvxConfig {\n if (raw === null || typeof raw !== \"object\") {\n throw new Error(\"[CONFIG_BAD_SHAPE] config must export an object\");\n }\n // Trust but verify — coerce only the bits we touch.\n const r = raw as Record<string, unknown>;\n const out: { -readonly [K in keyof DotenvxConfig]: DotenvxConfig[K] } = {};\n if (Array.isArray(r[\"envFiles\"])) {\n out.envFiles = r[\"envFiles\"].filter((x): x is string => typeof x === \"string\");\n }\n if (typeof r[\"envPath\"] === \"string\") out.envPath = r[\"envPath\"];\n if (typeof r[\"cascade\"] === \"string\") out.cascade = r[\"cascade\"];\n if (typeof r[\"envKeysFile\"] === \"string\") out.envKeysFile = r[\"envKeysFile\"];\n if (typeof r[\"override\"] === \"boolean\") out.override = r[\"override\"];\n if (typeof r[\"quiet\"] === \"boolean\") out.quiet = r[\"quiet\"];\n if (r[\"mapping\"] && typeof r[\"mapping\"] === \"object\") {\n const mapping: Record<string, string[]> = {};\n for (const [file, keys] of Object.entries(r[\"mapping\"] as Record<string, unknown>)) {\n if (Array.isArray(keys)) {\n mapping[file] = keys.filter((x): x is string => typeof x === \"string\");\n }\n }\n out.mapping = mapping;\n }\n return out;\n}\n\n// #endregion -----------------------------------------------\n","// #region -- ANSI Color Codes -----------------------------\n\nconst RESET = '\\x1b[0m'\nconst RED = '\\x1b[31m'\nconst GREEN = '\\x1b[32m'\nconst YELLOW = '\\x1b[33m'\nconst CYAN = '\\x1b[36m'\nconst DIM = '\\x1b[2m'\n\n// #endregion -- ANSI Color Codes --------------------------\n\n// #region -- Logger Interface -----------------------------\n\nexport interface Logger {\n readonly success: (msg: string) => void\n readonly error: (msg: string) => void\n readonly warn: (msg: string) => void\n readonly info: (msg: string) => void\n readonly dim: (msg: string) => void\n}\n\n// #endregion -- Logger Interface --------------------------\n\n// #region -- Logger Implementation ------------------------\n\nexport const log: Logger = {\n success: (msg: string): void => {\n console.log(`${GREEN}${msg}${RESET}`)\n },\n error: (msg: string): void => {\n console.error(`${RED}${msg}${RESET}`)\n },\n warn: (msg: string): void => {\n console.log(`${YELLOW}${msg}${RESET}`)\n },\n info: (msg: string): void => {\n console.log(`${CYAN}${msg}${RESET}`)\n },\n dim: (msg: string): void => {\n console.log(`${DIM}${msg}${RESET}`)\n },\n}\n\n// #endregion -- Logger Implementation ---------------------\n","import * as fs from \"fs\";\nimport * as path from \"path\";\nimport * as dotenv from \"@dotenvx/dotenvx\";\n\nimport { log } from \"@honeycluster/common\";\n\n// #region -- Environment Detection -------------------------\n\n/**\n * Detect the deployment environment from well-known platform variables.\n * Order of precedence: Vercel → Netlify → NODE_ENV → 'root'.\n */\nexport function detectEnvironment(): string {\n if (process.env[\"VERCEL\"]) {\n if (process.env[\"VERCEL_ENV\"] === \"production\") return \"prod\";\n return \"dev\";\n }\n\n if (process.env[\"NETLIFY\"]) {\n if (process.env[\"CONTEXT\"] === \"production\") return \"prod\";\n if (\n process.env[\"CONTEXT\"] === \"deploy-preview\" ||\n process.env[\"CONTEXT\"] === \"branch-deploy\"\n ) {\n return \"dev\";\n }\n return \"dev\";\n }\n\n const nodeEnv = process.env[\"NODE_ENV\"];\n if (nodeEnv) {\n switch (nodeEnv.toLowerCase()) {\n case \"production\":\n return \"prod\";\n case \"development\":\n return \"dev\";\n case \"local\":\n return \"local\";\n default:\n return \"root\";\n }\n }\n\n return \"root\";\n}\n\n// #endregion -- Environment Detection ----------------------\n\n// #region -- CLI Variable Parsing --------------------------\n\n/**\n * Parse a `KEY=value` string from `-v KEY=value` into a `[key, value]` tuple.\n * Calls `process.exit(1)` on malformed input.\n */\nexport function validateCmdVariable(param: string): [string, string] {\n const match = param.match(/^(\\w+)=([\\s\\S]+)$/m);\n if (!match) {\n log.error(\n `Invalid variable. Expected '-v variable=value', got: \\`-v ${param}\\`.`,\n );\n process.exit(1);\n }\n const [, key, val] = match;\n if (!key || !val) {\n log.error(\n `Invalid variable. Expected '-v variable=value', got: \\`-v ${param}\\`.`,\n );\n process.exit(1);\n }\n return [key, val];\n}\n\n// #endregion -- CLI Variable Parsing -----------------------\n\n// #region -- Workspace Resolution --------------------------\n\nconst WORKSPACE_INDICATORS = [\n \"pnpm-workspace.yaml\",\n \"lerna.json\",\n \"nx.json\",\n \"rush.json\",\n \"yarn.lock\",\n \"pnpm-lock.yaml\",\n] as const;\n\n/**\n * Walk up from `startDir` looking for a `package.json` that declares\n * `workspaces` (npm/yarn) or `pnpm.workspaces`. Falls back to other\n * monorepo indicators (pnpm-workspace.yaml, nx.json, …). Returns\n * `startDir` if nothing is found.\n */\nexport function findWorkspaceRoot(startDir: string = process.cwd()): string {\n const root = path.parse(startDir).root;\n\n let currentDir = startDir;\n while (currentDir !== root) {\n const packageJsonPath = path.join(currentDir, \"package.json\");\n try {\n const packageJsonContent = fs.readFileSync(packageJsonPath, \"utf8\");\n const packageJson = JSON.parse(packageJsonContent);\n if (packageJson.workspaces || packageJson.pnpm?.workspaces) {\n return currentDir;\n }\n } catch {\n // package.json absent or unreadable — keep walking\n }\n currentDir = path.dirname(currentDir);\n }\n\n currentDir = startDir;\n while (currentDir !== root) {\n for (const indicator of WORKSPACE_INDICATORS) {\n if (fs.existsSync(path.join(currentDir, indicator))) {\n return currentDir;\n }\n }\n currentDir = path.dirname(currentDir);\n }\n\n return startDir;\n}\n\n// #endregion -- Workspace Resolution -----------------------\n\n// #region -- Env File Discovery ----------------------------\n\n/**\n * List every `.env*` file in `dir`, sorted by name. Skips dotfile\n * subdirectories. Returns the basenames (not absolute paths) so callers\n * can hand them straight to `loadEnv` / `encryptFiles` / `decryptFiles`.\n *\n * Used by the CLI when `envPath`/`--vault` is set and `--env` is\n * omitted: the user's intent is \"all of the vault\", not just `.env`.\n */\nexport function listEnvFiles(dir: string): string[] {\n if (!fs.existsSync(dir) || !fs.statSync(dir).isDirectory()) return [];\n return fs\n .readdirSync(dir, { withFileTypes: true })\n .filter((d) => d.isFile())\n .map((d) => d.name)\n .filter((n) => n === \".env\" || n.startsWith(\".env.\"))\n .filter((n) => n !== \".env.keys\") // never operate on the keys file itself\n .sort();\n}\n\n// #endregion -----------------------------------------------\n\n// #region -- Cascade Path Expansion ------------------------\n\n/**\n * Expand env file paths according to the cascade strategy. Order is\n * least- to most-specific so the caller (which loads them in order with\n * later entries overriding earlier ones) ends up with the most specific\n * values winning.\n */\nexport function expandCascadePaths(\n paths: string[],\n cascade: string | boolean,\n): string[] {\n return paths.reduce<string[]>(\n (accumulator, p) =>\n accumulator.concat(\n typeof cascade === \"string\"\n ? [`${p}.${cascade}.local`, `${p}.local`, `${p}.${cascade}`, p]\n : [`${p}.local`, p],\n ),\n [],\n );\n}\n\n// #endregion -- Cascade Path Expansion ---------------------\n\n// #region -- Env Loading -----------------------------------\n\nexport interface ResolveEnvOptions {\n readonly envFiles?: string[] | string;\n readonly cascade?: string | boolean;\n readonly autoDetect?: boolean;\n}\n\n/**\n * Resolve which `.env*` paths to load given the user's options. Handles\n * the auto-detect default (when only `.env` was passed), prefixing\n * bare names with `.env.`, and cascade expansion.\n */\nexport function resolveEnvPaths(opts: ResolveEnvOptions): string[] {\n const { cascade, autoDetect = true } = opts;\n const rawFiles = opts.envFiles ?? [\".env\"];\n const envFiles = Array.isArray(rawFiles) ? [...rawFiles] : [rawFiles];\n\n if (autoDetect && envFiles.length === 1 && envFiles[0] === \".env\") {\n const detected = detectEnvironment();\n if (detected !== \"root\") {\n envFiles[0] = `.env.${detected}`;\n log.dim(\n `Auto-detected environment: ${detected} ` +\n `(NODE_ENV=${process.env[\"NODE_ENV\"] ?? \"undefined\"}, ` +\n `VERCEL=${process.env[\"VERCEL\"] ?? \"undefined\"}, ` +\n `VERCEL_ENV=${process.env[\"VERCEL_ENV\"] ?? \"undefined\"}, ` +\n `NETLIFY=${process.env[\"NETLIFY\"] ?? \"undefined\"}, ` +\n `CONTEXT=${process.env[\"CONTEXT\"] ?? \"undefined\"})`,\n );\n }\n }\n\n let paths = envFiles.map((e) =>\n path.isAbsolute(e) || e.startsWith(\".env\") ? e : `.env.${e}`,\n );\n if (cascade) paths = expandCascadePaths(paths, cascade);\n return paths;\n}\n\nexport interface LoadEnvOptions {\n readonly envFiles?: string[] | string;\n readonly variables?: string[] | string;\n readonly cascade?: string | boolean;\n /**\n * `true` is shorthand for `envPath: \"vault\"`. A string sets the\n * subdirectory explicitly. Either way, relative env files resolve to\n * `<workspaceRoot>/<envPath>/<file>`.\n */\n readonly vault?: boolean;\n /** Subdirectory of the workspace root where env files live. */\n readonly envPath?: string;\n readonly override?: boolean;\n readonly quiet?: boolean;\n}\n\n/**\n * Load env files (resolving relative paths against both the workspace\n * root and CWD) and apply `KEY=value` overrides from `--variables`.\n * Mutates `process.env`.\n */\nexport function loadEnv(opts: LoadEnvOptions): { paths: string[] } {\n const {\n cascade,\n vault = false,\n envPath,\n override = false,\n quiet = true,\n variables,\n } = opts;\n\n if (cascade && override) {\n log.error(\"Invalid arguments. --cascade conflicts with --override.\");\n process.exit(1);\n }\n\n // envPath wins; --vault is a shortcut for \"vault\".\n const subdir = envPath ?? (vault ? \"vault\" : \"\");\n\n const paths = resolveEnvPaths({\n ...(opts.envFiles !== undefined ? { envFiles: opts.envFiles } : {}),\n ...(cascade !== undefined ? { cascade } : {}),\n });\n const workspaceRoot = findWorkspaceRoot();\n\n paths.forEach((env) => {\n if (path.isAbsolute(env)) {\n log.dim(`Loading environment from: ${env}`);\n dotenv.config({ path: env, override, quiet });\n return;\n }\n\n const workspacePath = subdir\n ? path.resolve(workspaceRoot, subdir, env)\n : path.resolve(workspaceRoot, env);\n const workspaceKeysPath = path.resolve(workspaceRoot, \".env.keys\");\n const currentDirPath = subdir\n ? path.resolve(process.cwd(), subdir, env)\n : path.resolve(process.cwd(), env);\n const currentDirKeysPath = path.resolve(process.cwd(), \".env.keys\");\n\n const workspaceExists = fs.existsSync(workspacePath);\n const currentDirExists = fs.existsSync(currentDirPath);\n\n if (workspaceExists) {\n log.dim(`Loading environment from: ${workspacePath}`);\n dotenv.config({\n path: workspacePath,\n envKeysFile: workspaceKeysPath,\n override,\n quiet,\n });\n }\n\n if (currentDirExists) {\n log.dim(`Loading environment from: ${currentDirPath}`);\n dotenv.config({\n path: currentDirPath,\n envKeysFile: currentDirKeysPath,\n override,\n quiet,\n });\n }\n\n if (!workspaceExists && !currentDirExists) {\n log.dim(`Loading environment from: ${workspacePath}`);\n dotenv.config({\n path: workspacePath,\n envKeysFile: workspaceKeysPath,\n override,\n quiet,\n });\n }\n });\n\n if (variables !== undefined) {\n const list = Array.isArray(variables) ? variables : [variables];\n const parsed = Object.fromEntries(list.map(validateCmdVariable));\n Object.assign(process.env, parsed);\n }\n\n return { paths };\n}\n\n// #endregion -- Env Loading --------------------------------\n","// #region -- Public API ------------------------------------\n\nexport type {\n ProcessedEnv,\n ProcessingError,\n ErrorCode,\n RunOptions,\n RunResult,\n} from \"./types.js\";\n\n// Crypto primitives + format constants\nexport {\n ENCRYPTED_PREFIX,\n encryptValue,\n decryptValue,\n generatePrivateKey,\n isEncrypted,\n} from \"./crypto.js\";\n\n// Env-file parsing\nexport {\n parseEnv,\n serializeEnv,\n toRecord,\n type EnvLine,\n type KvLine,\n type RawLine,\n} from \"./parser.js\";\n\n// Key file management\nexport {\n defaultKeysPathFor,\n privateKeyNameFor,\n readKeysFile,\n writeKeysFile,\n} from \"./keys.js\";\n\n// Glob filter helpers\nexport { isSelected, matchesAny } from \"./match.js\";\n\n// High-level operations\nexport { encryptFiles } from \"./encrypt.js\";\nexport { decryptFiles } from \"./decrypt.js\";\n\n// Variable expansion\nexport {\n expandRecord,\n expandEnvSrc,\n type ExpandOptions,\n type ExpandResult,\n} from \"./expand.js\";\n\n// Config loading\nexport {\n loadDotenvxConfig,\n type DotenvxConfig,\n type LoadConfigOptions,\n type LoadedConfig,\n} from \"./config.js\";\n\n// Env loading + resolution helpers (originally in core/src/lib)\nexport {\n detectEnvironment,\n validateCmdVariable,\n findWorkspaceRoot,\n expandCascadePaths,\n listEnvFiles,\n resolveEnvPaths,\n loadEnv,\n type ResolveEnvOptions,\n type LoadEnvOptions,\n} from \"./env.js\";\n\n// #endregion -----------------------------------------------\n\n// #region -- Persistence Helper ----------------------------\n\nimport * as fs from \"fs\";\n\nimport type { ProcessedEnv } from \"./types.js\";\n\n/**\n * Persist any changed processedEnvs to disk. Returns the absolute paths\n * that were actually written. Skips entries with errors and entries\n * marked unchanged.\n */\nexport function writeProcessed(\n processed: readonly ProcessedEnv[],\n): { written: string[] } {\n const written: string[] = [];\n for (const p of processed) {\n if (p.error || !p.changed) continue;\n fs.writeFileSync(p.filepath, p.envSrc);\n written.push(p.filepath);\n }\n return { written };\n}\n\n// #endregion -----------------------------------------------\n"],"mappings":"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"}