@achs/env 5.0.0-alpha.3 → 5.0.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 (41) hide show
  1. package/arguments.d.ts.map +1 -1
  2. package/arguments.js +13 -6
  3. package/arguments.js.map +1 -1
  4. package/commands/env.command.d.ts.map +1 -1
  5. package/commands/env.command.js +36 -26
  6. package/commands/env.command.js.map +1 -1
  7. package/commands/export.command.d.ts.map +1 -1
  8. package/commands/export.command.js +12 -11
  9. package/commands/export.command.js.map +1 -1
  10. package/commands/pull.command.js +8 -7
  11. package/commands/pull.command.js.map +1 -1
  12. package/commands/push.command.js +8 -7
  13. package/commands/push.command.js.map +1 -1
  14. package/commands/schema.command.d.ts.map +1 -1
  15. package/commands/schema.command.js +8 -7
  16. package/commands/schema.command.js.map +1 -1
  17. package/exec.d.ts.map +1 -1
  18. package/exec.js +46 -42
  19. package/exec.js.map +1 -1
  20. package/package.json +1 -1
  21. package/providers/azure-key-vault.provider.d.ts.map +1 -1
  22. package/providers/azure-key-vault.provider.js +48 -47
  23. package/providers/azure-key-vault.provider.js.map +1 -1
  24. package/utils/command.util.d.ts +1 -1
  25. package/utils/command.util.d.ts.map +1 -1
  26. package/utils/command.util.js +3 -3
  27. package/utils/command.util.js.map +1 -1
  28. package/utils/index.d.ts +1 -0
  29. package/utils/index.d.ts.map +1 -1
  30. package/utils/index.js +2 -1
  31. package/utils/json.util.d.ts.map +1 -1
  32. package/utils/json.util.js +7 -2
  33. package/utils/json.util.js.map +1 -1
  34. package/utils/schema.util.d.ts +6 -6
  35. package/utils/schema.util.d.ts.map +1 -1
  36. package/utils/schema.util.js +20 -19
  37. package/utils/schema.util.js.map +1 -1
  38. package/utils/ui.d.ts +14 -0
  39. package/utils/ui.d.ts.map +1 -0
  40. package/utils/ui.js +75 -0
  41. package/utils/ui.js.map +1 -0
package/exec.js CHANGED
@@ -2,23 +2,24 @@ import { getSubcommand as e, loadConfigFile as t, loadProjectInfo as n, loadSche
2
2
  import { interpolateJson as i } from "./utils/interpolate.util.js";
3
3
  import { resolvePath as a } from "./utils/json.util.js";
4
4
  import { configureLogger as o, logger as s } from "./utils/logger.js";
5
+ import { ui as c } from "./utils/ui.js";
5
6
  import "./utils/index.js";
6
- import { IntegratedProviders as c } from "./providers/index.js";
7
- import { args as l } from "./arguments.js";
8
- import { envCommand as u } from "./commands/env.command.js";
9
- import { exportCommand as d } from "./commands/export.command.js";
10
- import { pullCommand as f } from "./commands/pull.command.js";
11
- import { pushCommand as p } from "./commands/push.command.js";
12
- import { schemaCommand as m } from "./commands/schema.command.js";
7
+ import { IntegratedProviders as l } from "./providers/index.js";
8
+ import { args as u } from "./arguments.js";
9
+ import { envCommand as d } from "./commands/env.command.js";
10
+ import { exportCommand as f } from "./commands/export.command.js";
11
+ import { pullCommand as p } from "./commands/pull.command.js";
12
+ import { pushCommand as m } from "./commands/push.command.js";
13
+ import { schemaCommand as h } from "./commands/schema.command.js";
13
14
  import "./commands/index.js";
14
- import h from "picocolors";
15
- import { readFileSync as g } from "node:fs";
16
- import { fileURLToPath as _ } from "node:url";
17
- import v from "yargs";
18
- import { Parser as y } from "yargs/helpers";
15
+ import g from "picocolors";
16
+ import { readFileSync as _ } from "node:fs";
17
+ import { fileURLToPath as v } from "node:url";
18
+ import y from "yargs";
19
+ import { Parser as b } from "yargs/helpers";
19
20
  //#region src/exec.ts
20
- async function b(e, n, r) {
21
- let i = y.detailed(e, {
21
+ async function x(e, n, r) {
22
+ let i = b.detailed(e, {
22
23
  array: [
23
24
  "modes",
24
25
  "logMaskAnyRegEx",
@@ -34,55 +35,58 @@ async function b(e, n, r) {
34
35
  "logLevel"
35
36
  ],
36
37
  alias: {
37
- configFile: l.configFile.alias,
38
- env: l.env.alias,
39
- logLevel: l.logLevel.alias,
40
- logMaskAnyRegEx: l.logMaskAnyRegEx.alias,
41
- logMaskValuesOfKeys: l.logMaskValuesOfKeys.alias,
42
- modes: l.modes.alias
38
+ configFile: u.configFile.alias,
39
+ env: u.env.alias,
40
+ logLevel: u.logLevel.alias,
41
+ logMaskAnyRegEx: u.logMaskAnyRegEx.alias,
42
+ logMaskValuesOfKeys: u.logMaskValuesOfKeys.alias,
43
+ modes: u.modes.alias
43
44
  },
44
45
  default: {
45
- configFile: l.configFile.default,
46
- root: l.root.default
46
+ configFile: u.configFile.default,
47
+ root: u.root.default
47
48
  }
48
49
  }).argv;
49
- await t(i, r), i.logLevel ??= l.logLevel.default, i.logMaskAnyRegEx ??= l.logMaskAnyRegEx.default, i.logMaskValuesOfKeys ??= l.logMaskValuesOfKeys.default, i.providers ??= l.providers.default;
50
- let { logLevel: a, logMaskAnyRegEx: c, logMaskValuesOfKeys: u } = i;
50
+ await t(i, r), i.logLevel ??= u.logLevel.default, i.logMaskAnyRegEx ??= u.logMaskAnyRegEx.default, i.logMaskValuesOfKeys ??= u.logMaskValuesOfKeys.default, i.providers ??= u.providers.default;
51
+ let { logLevel: a, logMaskAnyRegEx: c, logMaskValuesOfKeys: l } = i;
51
52
  return o(s, {
52
53
  maskAnyRegEx: c,
53
- maskValuesOfKeys: u,
54
+ maskValuesOfKeys: l,
54
55
  minLevel: a
55
56
  }), (a === "silly" || a === "trace") && (process.env.AKV_DEBUG = "true"), i;
56
57
  }
57
- async function x(t) {
58
- let { config: n, version: r } = JSON.parse(g(_(new URL("package.json", "" + import.meta.url)), "utf8")), i = e(t, n.delimiters.subcommand), o = await b(t, n.parser, n.delimiters.template), { env: l, help: u, modes: d, providers: f } = o;
59
- u && S(t, o, i, n, r), (!Array.isArray(f) || f.length === 0) && (s.error("no providers found"), process.exit(1));
60
- let p = l ? ` ${h.bold(h.underline(h.green(l)))} environment` : "", m = d ? ` ${h.bold(h.magenta(d.join("+")))} mode` : "";
61
- s.info(`loading${p}${l && d ? " in" : ""}${m}`);
62
- for (let e of f) try {
63
- if (s.debug(`using ${h.yellow(e.path)} provider`), !e.type || e.type === "integrated") e.handler = c[e.path];
58
+ async function S(t) {
59
+ let { config: n, version: r } = JSON.parse(_(v(new URL("package.json", "" + import.meta.url)), "utf8")), i = e(t, n.delimiters.subcommand), o = await x(t, n.parser, n.delimiters.template), { env: u, help: d, modes: f, providers: p } = o;
60
+ d && C(t, o, i, n, r), (!Array.isArray(p) || p.length === 0) && (s.error("no providers found"), process.exit(1)), c.header(r, u, f);
61
+ for (let e of p) try {
62
+ if (s.debug(`using ${g.yellow(e.path)} provider`), !e.type || e.type === "integrated") e.handler = l[e.path];
64
63
  else {
65
64
  let { default: t } = await (e.type === "module" ? import(e.path) : import(a(e.path)));
66
65
  e.handler = t;
67
66
  }
68
67
  } catch {
69
- s.error(`${h.yellow(e.path)} provider not found or not compatible`), process.exit(1);
68
+ s.error(`${g.yellow(e.path)} provider not found or not compatible`), process.exit(1);
70
69
  }
71
- S(t, o, i, n, r);
70
+ C(t, o, i, n, r);
72
71
  }
73
- function S(e, t, a, o, c = "unknown") {
74
- let g = v(e).strict().scriptName("env").version(c).detectLocale(!1).showHelpOnFail(!1).parserConfiguration(o.parser).usage("Usage: $0 [command] [options..] [: subcmd [:]] [options..]").options(l).middleware(async (e) => {
75
- a?.length > 0 && (e.subcmd = a), Object.assign(e, t), s.silly("interpolating arguments surrounded by", h.bold(h.yellow(`${o.delimiters.template[0]} ${o.delimiters.template[1]}`)));
72
+ function C(e, t, a, o, c = "unknown") {
73
+ let l = g.dim(`v${c}`), _ = [
74
+ "",
75
+ `${g.bold(g.yellow("⚡ env"))} ${l} ${g.dim("· environment variables made easy")}`,
76
+ "",
77
+ `${g.bold("Usage:")} $0 [command] [options..] ${g.dim(": <subcmd> :")} [options..]`
78
+ ].join("\n"), v = [`${g.dim("Run")} ${g.cyan("env <command> --help")} ${g.dim("for command-specific options.")}`, `${g.dim("Use")} ${g.cyan("--log debug")} ${g.dim("to inspect the resolved environment (secrets stay masked).")}`].join("\n"), b = y(e).strict().scriptName("env").version(c).detectLocale(!1).showHelpOnFail(!1).parserConfiguration(o.parser).wrap(Math.min(110, process.stdout.columns ?? 110)).usage(_).epilog(v).options(u).middleware(async (e) => {
79
+ a?.length > 0 && (e.subcmd = a), Object.assign(e, t), s.silly("interpolating arguments surrounded by", g.bold(g.yellow(`${o.delimiters.template[0]} ${o.delimiters.template[1]}`)));
76
80
  let c = e.subcmd;
77
81
  if (i(e, e, o.delimiters.template), Array.isArray(e.subcmd)) for (let t in e.subcmd) e.subcmd[t]?.includes("undefined") && (e.subcmd[t] = c[t]);
78
82
  s.silly("config loaded:", e), [e.projectInfo, e.schema] = await Promise.all([n(e.packageJson ?? e.pkg), r(e, o.delimiters.template)]), e.schemaValidate && (e.schemaValidate = !!e.schema, e.schemaValidate && s.silly("schema loaded:", e.schema));
79
83
  });
80
- g.command(u), g.command(d), g.command(f), g.command(p), g.command(m);
81
- let { providers: _ } = t;
82
- for (let { handler: e } of _) e?.builder && e.builder(g);
83
- g.parse();
84
+ b.command(d), b.command(f), b.command(p), b.command(m), b.command(h);
85
+ let { providers: x } = t;
86
+ for (let { handler: e } of x) e?.builder && e.builder(b);
87
+ b.parse();
84
88
  }
85
89
  //#endregion
86
- export { x as exec };
90
+ export { S as exec };
87
91
 
88
92
  //# sourceMappingURL=exec.js.map
package/exec.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"exec.js","names":[],"sources":["../src/exec.ts"],"sourcesContent":["import { readFileSync } from 'node:fs';\r\nimport { fileURLToPath } from 'node:url';\r\nimport pc from 'picocolors';\r\nimport yargs from 'yargs';\r\nimport type { Arguments } from 'yargs';\r\nimport { Parser } from 'yargs/helpers';\r\nimport { args } from './arguments.js';\r\nimport type { CommandArguments } from './arguments.js';\r\nimport {\r\n\tenvCommand,\r\n\texportCommand,\r\n\tpullCommand,\r\n\tpushCommand,\r\n\tschemaCommand,\r\n} from './commands/index.js';\r\nimport { IntegratedProviders } from './providers/index.js';\r\nimport {\r\n\tconfigureLogger,\r\n\tgetSubcommand,\r\n\tinterpolateJson,\r\n\tloadConfigFile,\r\n\tloadProjectInfo,\r\n\tloadSchemaFile,\r\n\tlogger,\r\n\tresolvePath,\r\n} from './utils/index.js';\r\n\r\ntype Alias = string[] | string;\r\n\r\n/**\r\n * Preload basic config from command line and config file.\r\n *\r\n * @param {string[]} rawArgv process.argv\r\n * @param {Partial<yargsParser.Configuration>} parser yargs parser config\r\n * @param {[string, string]} delimiters\r\n *\r\n * @returns {Promise<Partial<CommandArguments>>} preloaded config\r\n */\r\nasync function preloadConfig(\r\n\trawArgv: string[],\r\n\tparser: Record<string, unknown>,\r\n\tdelimiters: [string, string],\r\n): Promise<Partial<CommandArguments>> {\r\n\t// preload base config\r\n\tconst preloadedArgv = Parser.detailed(rawArgv, {\r\n\t\tarray: ['modes', 'logMaskAnyRegEx', 'logMaskValuesOfKeys'],\r\n\t\tboolean: ['help'],\r\n\t\tconfiguration: parser as any,\r\n\t\tstring: ['root', 'env', 'configFile', 'schemaFile', 'logLevel'],\r\n\t\talias: {\r\n\t\t\tconfigFile: args.configFile.alias as Alias,\r\n\t\t\tenv: args.env.alias as Alias,\r\n\t\t\tlogLevel: args.logLevel.alias as Alias,\r\n\t\t\tlogMaskAnyRegEx: args.logMaskAnyRegEx.alias as Alias,\r\n\t\t\tlogMaskValuesOfKeys: args.logMaskValuesOfKeys.alias as Alias,\r\n\t\t\tmodes: args.modes.alias as Alias,\r\n\t\t},\r\n\t\tdefault: {\r\n\t\t\tconfigFile: args.configFile.default,\r\n\t\t\troot: args.root.default,\r\n\t\t},\r\n\t}).argv;\r\n\r\n\t// loads configuration file\r\n\tawait loadConfigFile(preloadedArgv, delimiters);\r\n\r\n\tpreloadedArgv.logLevel ??= args.logLevel.default;\r\n\tpreloadedArgv.logMaskAnyRegEx ??= args.logMaskAnyRegEx.default;\r\n\tpreloadedArgv.logMaskValuesOfKeys ??= args.logMaskValuesOfKeys.default;\r\n\tpreloadedArgv.providers ??= args.providers.default;\r\n\r\n\tconst { logLevel, logMaskAnyRegEx, logMaskValuesOfKeys } = preloadedArgv;\r\n\r\n\t// logging level\r\n\tconfigureLogger(logger, {\r\n\t\tmaskAnyRegEx: logMaskAnyRegEx,\r\n\t\tmaskValuesOfKeys: logMaskValuesOfKeys,\r\n\t\tminLevel: logLevel,\r\n\t});\r\n\r\n\tif (logLevel === 'silly' || logLevel === 'trace')\r\n\t\tprocess.env.AKV_DEBUG = 'true';\r\n\r\n\treturn preloadedArgv;\r\n}\r\n\r\n/**\r\n * Command preprocessing and lib info\r\n * reading from package.json.\r\n * Preloads config file and setup basic config.\r\n *\r\n * @param {string[]} rawArgv process.argv\r\n */\r\nexport async function exec(rawArgv: string[]) {\r\n\t// reads some lib base config from package.json\r\n\tconst pkg = JSON.parse(\r\n\t\treadFileSync(\r\n\t\t\tfileURLToPath(new URL('package.json', import.meta.url)),\r\n\t\t\t'utf8',\r\n\t\t),\r\n\t) as { config: Record<string, any>; version: string };\r\n\tconst { config, version } = pkg;\r\n\r\n\t// execs yargs\r\n\tconst subcommand = getSubcommand(rawArgv, config.delimiters.subcommand);\r\n\r\n\tconst preloadedArgv = await preloadConfig(\r\n\t\trawArgv,\r\n\t\tconfig.parser,\r\n\t\tconfig.delimiters.template,\r\n\t);\r\n\r\n\tconst { env, help, modes, providers } = preloadedArgv;\r\n\r\n\tif (help) build(rawArgv, preloadedArgv, subcommand, config, version);\r\n\r\n\tif (!Array.isArray(providers) || providers.length === 0) {\r\n\t\tlogger.error('no providers found');\r\n\r\n\t\tprocess.exit(1);\r\n\t}\r\n\r\n\tconst envMsg = env\r\n\t\t? ` ${pc.bold(pc.underline(pc.green(env)))} environment`\r\n\t\t: '';\r\n\tconst modesMsg = modes\r\n\t\t? ` ${pc.bold(pc.magenta(modes.join('+')))} mode`\r\n\t\t: '';\r\n\r\n\tlogger.info(`loading${envMsg}${env && modes ? ' in' : ''}${modesMsg}`);\r\n\r\n\t// read loaders from config\r\n\tfor (const provider of providers!) {\r\n\t\ttry {\r\n\t\t\tlogger.debug(`using ${pc.yellow(provider.path)} provider`);\r\n\r\n\t\t\tif (!provider.type || provider.type === 'integrated') {\r\n\t\t\t\tprovider.handler = IntegratedProviders[provider.path];\r\n\t\t\t} else {\r\n\t\t\t\tconst { default: module } = await import(\r\n\t\t\t\t\tprovider.type === 'module'\r\n\t\t\t\t\t\t? provider.path\r\n\t\t\t\t\t\t: resolvePath(provider.path)\r\n\t\t\t\t);\r\n\r\n\t\t\t\tprovider.handler = module;\r\n\t\t\t}\r\n\t\t} catch {\r\n\t\t\tlogger.error(\r\n\t\t\t\t`${pc.yellow(\r\n\t\t\t\t\tprovider.path,\r\n\t\t\t\t)} provider not found or not compatible`,\r\n\t\t\t);\r\n\r\n\t\t\tprocess.exit(1);\r\n\t\t}\r\n\t}\r\n\r\n\tbuild(rawArgv, preloadedArgv, subcommand, config, version);\r\n}\r\n\r\n/**\r\n * Builds commands and execs Yargs.\r\n *\r\n * @param {string[]} rawArgv process.argv.slice(2)\r\n * @param {Partial<Arguments<CommandArguments>>} preloadedArgv\r\n * @param {string[]} subcommand subcommand for wrap if exists\r\n * @param {Record<string, any>} config lib config from package.json\r\n * @param {string} version lib version from package.json\r\n */\r\nfunction build(\r\n\trawArgv: string[],\r\n\tpreloadedArgv: Partial<Arguments<CommandArguments>>,\r\n\tsubcommand: string[],\r\n\tconfig: Record<string, any>,\r\n\tversion = 'unknown',\r\n): void {\r\n\tconst builder = yargs(rawArgv)\r\n\t\t.strict()\r\n\t\t.scriptName('env')\r\n\t\t.version(version)\r\n\t\t.detectLocale(false)\r\n\t\t.showHelpOnFail(false)\r\n\t\t.parserConfiguration(config.parser)\r\n\t\t.usage('Usage: $0 [command] [options..] [: subcmd [:]] [options..]')\r\n\t\t.options(args)\r\n\t\t.middleware(async (argv): Promise<void> => {\r\n\t\t\t// in case of subcommand argument for main\r\n\t\t\tif (subcommand?.length > 0) argv.subcmd = subcommand;\r\n\r\n\t\t\t// merges preloaded args\r\n\t\t\tObject.assign(argv, preloadedArgv);\r\n\r\n\t\t\tlogger.silly(\r\n\t\t\t\t'interpolating arguments surrounded by',\r\n\t\t\t\tpc.bold(\r\n\t\t\t\t\tpc.yellow(\r\n\t\t\t\t\t\t`${config.delimiters.template[0]} ${config.delimiters.template[1]}`,\r\n\t\t\t\t\t),\r\n\t\t\t\t),\r\n\t\t\t);\r\n\r\n\t\t\tconst subcmdAux = argv.subcmd as string[];\r\n\t\t\t// applies string templating with current vars\r\n\t\t\tinterpolateJson(argv, argv, config.delimiters.template);\r\n\r\n\t\t\tif (Array.isArray(argv.subcmd)) {\r\n\t\t\t\t// fix for argv interpolation pre env interpolation for subcommand\r\n\t\t\t\tfor (const index in argv.subcmd) {\r\n\t\t\t\t\tif (argv.subcmd[index]?.includes('undefined'))\r\n\t\t\t\t\t\targv.subcmd[index] = subcmdAux[index];\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tlogger.silly('config loaded:', argv);\r\n\r\n\t\t\t// loads environment JSON schema if exists\r\n\t\t\t// and current project info from package.json\r\n\t\t\t[argv.projectInfo, argv.schema] = await Promise.all([\r\n\t\t\t\tloadProjectInfo((argv.packageJson ?? argv.pkg) as string),\r\n\t\t\t\tloadSchemaFile(argv, config.delimiters.template),\r\n\t\t\t]);\r\n\r\n\t\t\tif (argv.schemaValidate) {\r\n\t\t\t\targv.schemaValidate = !!argv.schema;\r\n\r\n\t\t\t\tif (argv.schemaValidate)\r\n\t\t\t\t\tlogger.silly('schema loaded:', argv.schema);\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t// integrated commands builder\r\n\tbuilder.command(envCommand);\r\n\tbuilder.command(exportCommand);\r\n\tbuilder.command(pullCommand);\r\n\tbuilder.command(pushCommand);\r\n\tbuilder.command(schemaCommand);\r\n\r\n\tconst { providers } = preloadedArgv;\r\n\r\n\t// extends command from plugins\r\n\tfor (const { handler } of providers!)\r\n\t\tif (handler?.builder) handler.builder(builder);\r\n\r\n\t// executes command processing\r\n\tvoid builder.parse();\r\n}\r\n"],"mappings":"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"}
1
+ {"version":3,"file":"exec.js","names":[],"sources":["../src/exec.ts"],"sourcesContent":["import { readFileSync } from 'node:fs';\r\nimport { fileURLToPath } from 'node:url';\r\nimport pc from 'picocolors';\r\nimport yargs from 'yargs';\r\nimport type { Arguments } from 'yargs';\r\nimport { Parser } from 'yargs/helpers';\r\nimport { args } from './arguments.js';\r\nimport type { CommandArguments } from './arguments.js';\r\nimport {\r\n\tenvCommand,\r\n\texportCommand,\r\n\tpullCommand,\r\n\tpushCommand,\r\n\tschemaCommand,\r\n} from './commands/index.js';\r\nimport { IntegratedProviders } from './providers/index.js';\r\nimport {\r\n\tconfigureLogger,\r\n\tgetSubcommand,\r\n\tinterpolateJson,\r\n\tloadConfigFile,\r\n\tloadProjectInfo,\r\n\tloadSchemaFile,\r\n\tlogger,\r\n\tresolvePath,\r\n\tui,\r\n} from './utils/index.js';\r\n\r\ntype Alias = string[] | string;\r\n\r\n/**\r\n * Preload basic config from command line and config file.\r\n *\r\n * @param {string[]} rawArgv process.argv\r\n * @param {Partial<yargsParser.Configuration>} parser yargs parser config\r\n * @param {[string, string]} delimiters\r\n *\r\n * @returns {Promise<Partial<CommandArguments>>} preloaded config\r\n */\r\nasync function preloadConfig(\r\n\trawArgv: string[],\r\n\tparser: Record<string, unknown>,\r\n\tdelimiters: [string, string],\r\n): Promise<Partial<CommandArguments>> {\r\n\t// preload base config\r\n\tconst preloadedArgv = Parser.detailed(rawArgv, {\r\n\t\tarray: ['modes', 'logMaskAnyRegEx', 'logMaskValuesOfKeys'],\r\n\t\tboolean: ['help'],\r\n\t\tconfiguration: parser as any,\r\n\t\tstring: ['root', 'env', 'configFile', 'schemaFile', 'logLevel'],\r\n\t\talias: {\r\n\t\t\tconfigFile: args.configFile.alias as Alias,\r\n\t\t\tenv: args.env.alias as Alias,\r\n\t\t\tlogLevel: args.logLevel.alias as Alias,\r\n\t\t\tlogMaskAnyRegEx: args.logMaskAnyRegEx.alias as Alias,\r\n\t\t\tlogMaskValuesOfKeys: args.logMaskValuesOfKeys.alias as Alias,\r\n\t\t\tmodes: args.modes.alias as Alias,\r\n\t\t},\r\n\t\tdefault: {\r\n\t\t\tconfigFile: args.configFile.default,\r\n\t\t\troot: args.root.default,\r\n\t\t},\r\n\t}).argv;\r\n\r\n\t// loads configuration file\r\n\tawait loadConfigFile(preloadedArgv, delimiters);\r\n\r\n\tpreloadedArgv.logLevel ??= args.logLevel.default;\r\n\tpreloadedArgv.logMaskAnyRegEx ??= args.logMaskAnyRegEx.default;\r\n\tpreloadedArgv.logMaskValuesOfKeys ??= args.logMaskValuesOfKeys.default;\r\n\tpreloadedArgv.providers ??= args.providers.default;\r\n\r\n\tconst { logLevel, logMaskAnyRegEx, logMaskValuesOfKeys } = preloadedArgv;\r\n\r\n\t// logging level\r\n\tconfigureLogger(logger, {\r\n\t\tmaskAnyRegEx: logMaskAnyRegEx,\r\n\t\tmaskValuesOfKeys: logMaskValuesOfKeys,\r\n\t\tminLevel: logLevel,\r\n\t});\r\n\r\n\tif (logLevel === 'silly' || logLevel === 'trace')\r\n\t\tprocess.env.AKV_DEBUG = 'true';\r\n\r\n\treturn preloadedArgv;\r\n}\r\n\r\n/**\r\n * Command preprocessing and lib info\r\n * reading from package.json.\r\n * Preloads config file and setup basic config.\r\n *\r\n * @param {string[]} rawArgv process.argv\r\n */\r\nexport async function exec(rawArgv: string[]) {\r\n\t// reads some lib base config from package.json\r\n\tconst pkg = JSON.parse(\r\n\t\treadFileSync(\r\n\t\t\tfileURLToPath(new URL('package.json', import.meta.url)),\r\n\t\t\t'utf8',\r\n\t\t),\r\n\t) as { config: Record<string, any>; version: string };\r\n\tconst { config, version } = pkg;\r\n\r\n\t// execs yargs\r\n\tconst subcommand = getSubcommand(rawArgv, config.delimiters.subcommand);\r\n\r\n\tconst preloadedArgv = await preloadConfig(\r\n\t\trawArgv,\r\n\t\tconfig.parser,\r\n\t\tconfig.delimiters.template,\r\n\t);\r\n\r\n\tconst { env, help, modes, providers } = preloadedArgv;\r\n\r\n\tif (help) build(rawArgv, preloadedArgv, subcommand, config, version);\r\n\r\n\tif (!Array.isArray(providers) || providers.length === 0) {\r\n\t\tlogger.error('no providers found');\r\n\r\n\t\tprocess.exit(1);\r\n\t}\r\n\r\n\tui.header(version, env, modes);\r\n\r\n\t// read loaders from config\r\n\tfor (const provider of providers!) {\r\n\t\ttry {\r\n\t\t\tlogger.debug(`using ${pc.yellow(provider.path)} provider`);\r\n\r\n\t\t\tif (!provider.type || provider.type === 'integrated') {\r\n\t\t\t\tprovider.handler = IntegratedProviders[provider.path];\r\n\t\t\t} else {\r\n\t\t\t\tconst { default: module } = await import(\r\n\t\t\t\t\tprovider.type === 'module'\r\n\t\t\t\t\t\t? provider.path\r\n\t\t\t\t\t\t: resolvePath(provider.path)\r\n\t\t\t\t);\r\n\r\n\t\t\t\tprovider.handler = module;\r\n\t\t\t}\r\n\t\t} catch {\r\n\t\t\tlogger.error(\r\n\t\t\t\t`${pc.yellow(\r\n\t\t\t\t\tprovider.path,\r\n\t\t\t\t)} provider not found or not compatible`,\r\n\t\t\t);\r\n\r\n\t\t\tprocess.exit(1);\r\n\t\t}\r\n\t}\r\n\r\n\tbuild(rawArgv, preloadedArgv, subcommand, config, version);\r\n}\r\n\r\n/**\r\n * Builds commands and execs Yargs.\r\n *\r\n * @param {string[]} rawArgv process.argv.slice(2)\r\n * @param {Partial<Arguments<CommandArguments>>} preloadedArgv\r\n * @param {string[]} subcommand subcommand for wrap if exists\r\n * @param {Record<string, any>} config lib config from package.json\r\n * @param {string} version lib version from package.json\r\n */\r\nfunction build(\r\n\trawArgv: string[],\r\n\tpreloadedArgv: Partial<Arguments<CommandArguments>>,\r\n\tsubcommand: string[],\r\n\tconfig: Record<string, any>,\r\n\tversion = 'unknown',\r\n): void {\r\n\tconst versionTag = pc.dim(`v${version}`);\r\n\tconst banner = [\r\n\t\t'',\r\n\t\t`${pc.bold(pc.yellow('⚡ env'))} ${versionTag} ${pc.dim('· environment variables made easy')}`,\r\n\t\t'',\r\n\t\t`${pc.bold('Usage:')} $0 [command] [options..] ${pc.dim(': <subcmd> :')} [options..]`,\r\n\t].join('\\n');\r\n\tconst epilog = [\r\n\t\t`${pc.dim('Run')} ${pc.cyan('env <command> --help')} ${pc.dim('for command-specific options.')}`,\r\n\t\t`${pc.dim('Use')} ${pc.cyan('--log debug')} ${pc.dim('to inspect the resolved environment (secrets stay masked).')}`,\r\n\t].join('\\n');\r\n\r\n\tconst builder = yargs(rawArgv)\r\n\t\t.strict()\r\n\t\t.scriptName('env')\r\n\t\t.version(version)\r\n\t\t.detectLocale(false)\r\n\t\t.showHelpOnFail(false)\r\n\t\t.parserConfiguration(config.parser)\r\n\t\t.wrap(Math.min(110, process.stdout.columns ?? 110))\r\n\t\t.usage(banner)\r\n\t\t.epilog(epilog)\r\n\t\t.options(args)\r\n\t\t.middleware(async (argv): Promise<void> => {\r\n\t\t\t// in case of subcommand argument for main\r\n\t\t\tif (subcommand?.length > 0) argv.subcmd = subcommand;\r\n\r\n\t\t\t// merges preloaded args\r\n\t\t\tObject.assign(argv, preloadedArgv);\r\n\r\n\t\t\tlogger.silly(\r\n\t\t\t\t'interpolating arguments surrounded by',\r\n\t\t\t\tpc.bold(\r\n\t\t\t\t\tpc.yellow(\r\n\t\t\t\t\t\t`${config.delimiters.template[0]} ${config.delimiters.template[1]}`,\r\n\t\t\t\t\t),\r\n\t\t\t\t),\r\n\t\t\t);\r\n\r\n\t\t\tconst subcmdAux = argv.subcmd as string[];\r\n\t\t\t// applies string templating with current vars\r\n\t\t\tinterpolateJson(argv, argv, config.delimiters.template);\r\n\r\n\t\t\tif (Array.isArray(argv.subcmd)) {\r\n\t\t\t\t// fix for argv interpolation pre env interpolation for subcommand\r\n\t\t\t\tfor (const index in argv.subcmd) {\r\n\t\t\t\t\tif (argv.subcmd[index]?.includes('undefined'))\r\n\t\t\t\t\t\targv.subcmd[index] = subcmdAux[index];\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tlogger.silly('config loaded:', argv);\r\n\r\n\t\t\t// loads environment JSON schema if exists\r\n\t\t\t// and current project info from package.json\r\n\t\t\t[argv.projectInfo, argv.schema] = await Promise.all([\r\n\t\t\t\tloadProjectInfo((argv.packageJson ?? argv.pkg) as string),\r\n\t\t\t\tloadSchemaFile(argv, config.delimiters.template),\r\n\t\t\t]);\r\n\r\n\t\t\tif (argv.schemaValidate) {\r\n\t\t\t\targv.schemaValidate = !!argv.schema;\r\n\r\n\t\t\t\tif (argv.schemaValidate)\r\n\t\t\t\t\tlogger.silly('schema loaded:', argv.schema);\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t// integrated commands builder\r\n\tbuilder.command(envCommand);\r\n\tbuilder.command(exportCommand);\r\n\tbuilder.command(pullCommand);\r\n\tbuilder.command(pushCommand);\r\n\tbuilder.command(schemaCommand);\r\n\r\n\tconst { providers } = preloadedArgv;\r\n\r\n\t// extends command from plugins\r\n\tfor (const { handler } of providers!)\r\n\t\tif (handler?.builder) handler.builder(builder);\r\n\r\n\t// executes command processing\r\n\tvoid builder.parse();\r\n}\r\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "5.0.0-alpha.3",
2
+ "version": "5.0.0",
3
3
  "project": "common",
4
4
  "name": "@achs/env",
5
5
  "type": "module",
@@ -1 +1 @@
1
- {"version":3,"file":"azure-key-vault.provider.d.ts","sourceRoot":"","sources":["../../src/providers/azure-key-vault.provider.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACxE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAe1D,UAAU,6BAA8B,SAAQ,gBAAgB;IAC/D,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,OAAO,CAAC;IACtB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,UAAU,0BAA0B;IACnC,CAAC,GAAG,EAAE,MAAM,GAAG;QACd,QAAQ,EAAE,MAAM,CAAC;KACjB,CAAC;CACF;AAED;;;GAGG;AACH,eAAO,MAAM,qBAAqB,EAAE,WAAW,CAC9C,6BAA6B,GAAG,oBAAoB,EACpD,0BAA0B,CAgJ1B,CAAC"}
1
+ {"version":3,"file":"azure-key-vault.provider.d.ts","sourceRoot":"","sources":["../../src/providers/azure-key-vault.provider.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACxE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAe1D,UAAU,6BAA8B,SAAQ,gBAAgB;IAC/D,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,OAAO,CAAC;IACtB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,UAAU,0BAA0B;IACnC,CAAC,GAAG,EAAE,MAAM,GAAG;QACd,QAAQ,EAAE,MAAM,CAAC;KACjB,CAAC;CACF;AAED;;;GAGG;AACH,eAAO,MAAM,qBAAqB,EAAE,WAAW,CAC9C,6BAA6B,GAAG,oBAAoB,EACpD,0BAA0B,CAgJ1B,CAAC"}
@@ -5,24 +5,23 @@ import { schemaToJson as i } from "../utils/schema.util.js";
5
5
  import "../utils/index.js";
6
6
  import a from "picocolors";
7
7
  import { existsSync as o } from "node:fs";
8
- import { AzureKeyVault as s, createAzureKeyVaultMock as c } from "@achs/azure-key-vault";
9
- import l from "node:dns";
8
+ import s from "node:dns";
10
9
  //#region src/providers/azure-key-vault.provider.ts
11
- var u = "azure-key-vault", d = r.getSubLogger({ prefix: [a.bold(a.blue(`[${u}]`))] }), f = {
12
- key: u,
10
+ var c = "azure-key-vault", l = r.getSubLogger({ prefix: [a.bold(a.blue(`[${c}]`))] }), u = {
11
+ key: c,
13
12
  builder: (e) => {
14
13
  e.options({
15
14
  keysFile: {
16
15
  alias: ["k", "keys"],
17
16
  default: ["[[root]]/keys.json", "../keys.json"],
18
17
  describe: "Azure Key Vault keys file path",
19
- group: u,
18
+ group: c,
20
19
  type: "array"
21
20
  },
22
21
  mock: {
23
22
  default: !1,
24
23
  describe: "Mocks Azure Key Vault client",
25
- group: u,
24
+ group: c,
26
25
  type: "boolean"
27
26
  },
28
27
  password: {
@@ -32,13 +31,13 @@ var u = "azure-key-vault", d = r.getSubLogger({ prefix: [a.bold(a.blue(`[${u}]`)
32
31
  "clientSecret"
33
32
  ],
34
33
  describe: "SPN Client Secret Password",
35
- group: u,
34
+ group: c,
36
35
  type: "string"
37
36
  },
38
37
  secretsFile: {
39
38
  default: "[[root]]/[[env]].env.json",
40
39
  describe: "Secret variables file path",
41
- group: u,
40
+ group: c,
42
41
  type: "string"
43
42
  },
44
43
  skipDnsCheck: {
@@ -50,94 +49,96 @@ var u = "azure-key-vault", d = r.getSubLogger({ prefix: [a.bold(a.blue(`[${u}]`)
50
49
  spn: {
51
50
  alias: ["clientId", "id"],
52
51
  describe: "SPN Client ID",
53
- group: u,
52
+ group: c,
54
53
  type: "string"
55
54
  },
56
55
  tenant: {
57
56
  alias: "t",
58
57
  describe: "Azure Tenant ID",
59
- group: u,
58
+ group: c,
60
59
  type: "string"
61
60
  },
62
61
  vaultUrl: {
63
62
  alias: "url",
64
63
  describe: "Azure Key Vault URL",
65
- group: u,
64
+ group: c,
66
65
  type: "string"
67
66
  }
68
67
  });
69
68
  },
70
69
  push: async (n, r) => {
71
70
  let [i, o] = await t(n.secretsFile);
72
- o || (d.error(`${a.blue(n.secretsFile)} not found`), process.exit(1)), d.silly("local secrets loaded:", i);
73
- let s = await h(n, r?.[n.env]?.vaultUrl);
74
- d.info("pushing variables to store");
75
- let c = await s.setAll(i);
76
- d.silly("secrets pushed:", c);
77
- let l = await e([{
78
- key: u,
71
+ o || (l.error(`${a.blue(n.secretsFile)} not found`), process.exit(1)), l.silly("local secrets loaded:", i);
72
+ let s = await p(n, r?.[n.env]?.vaultUrl);
73
+ l.info("pushing variables to store");
74
+ let u = await s.setAll(i);
75
+ l.silly("secrets pushed:", u);
76
+ let d = await e([{
77
+ key: c,
79
78
  value: i
80
79
  }], n);
81
- d.silly("schema for akv updated:", l);
80
+ l.silly("schema for akv updated:", d);
82
81
  },
83
82
  pull: async (e, t) => {
84
- let r = e.schema?.[u];
83
+ let r = e.schema?.[c];
85
84
  if (!r) {
86
- d.error("no schema found, you can gen one with \"env schema -e {env} -m {modes}\""), d.info(`generated empty ${a.bold(a.underline(a.yellowBright(e.secretsFile)))} file (you can retry the command)`), await n(e.secretsFile, {}, !1, !0);
85
+ l.error("no schema found, you can gen one with \"env schema -e {env} -m {modes}\""), l.info(`generated empty ${a.bold(a.underline(a.yellowBright(e.secretsFile)))} file (you can retry the command)`), await n(e.secretsFile, {}, !1, !0);
87
86
  return;
88
87
  }
89
88
  let o = i(r), s = t?.[e.env]?.vaultUrl;
90
89
  if (!s) return n(e.secretsFile, {}, !1, !0);
91
- let c = await h(e, s);
92
- d.info(`pulling stored secrets from ${a.underline(a.yellowBright(s))}`);
93
- let l = await c.getFor(o, !0);
94
- d.silly("remote secrets loaded:", l), await n(e.secretsFile, l, e.overwrite, !0);
90
+ let u = await p(e, s);
91
+ l.info(`pulling stored secrets from ${a.underline(a.yellowBright(s))}`);
92
+ let d = await u.getFor(o, !0);
93
+ l.silly("remote secrets loaded:", d), await n(e.secretsFile, d, e.overwrite, !0);
95
94
  },
96
95
  load: async (e, n) => {
97
96
  let { env: r, secretsFile: i } = e;
98
- if (!r) return d.silly("no env, so skipping provider"), [];
99
- o(i) || (d.warn("secrets file not found, pulling from store"), await f.pull(e, n));
97
+ if (!r) return l.silly("no env, so skipping provider"), [];
98
+ o(i) || (l.warn("secrets file not found, pulling from store"), await u.pull(e, n));
100
99
  let [a] = await t(i);
101
100
  return [a];
102
101
  }
103
102
  };
104
- function p(e) {
103
+ function d(e) {
105
104
  return !!(e && e.clientId && e.clientSecret && e.tenantId);
106
105
  }
107
- async function m(e, n) {
108
- d.debug(`searching keys at ${a.yellow(n.join(","))}`);
109
- let [r] = (await Promise.all(n.map((e) => t(e)))).find(([t, n]) => n && p(t[e])) ?? [null];
106
+ async function f(e, n) {
107
+ l.debug(`searching keys at ${a.yellow(n.join(","))}`);
108
+ let [r] = (await Promise.all(n.map((e) => t(e)))).find(([t, n]) => n && d(t[e])) ?? [null];
110
109
  return r?.[e] ?? {};
111
110
  }
112
- async function h({ env: e, keysFile: t, mock: n, password: r, projectInfo: i, skipDnsCheck: o, spn: l, tenant: u, vaultUrl: f }, h) {
113
- let _ = process.env.AZURE_VAULT_URL ?? f ?? h, v = {
111
+ async function p({ env: e, keysFile: t, mock: n, password: r, projectInfo: i, skipDnsCheck: o, spn: s, tenant: c, vaultUrl: u }, p) {
112
+ let h = process.env.AZURE_VAULT_URL ?? u ?? p, g = {
114
113
  env: e,
115
114
  group: process.env.AZURE_GROUP ?? i.name,
116
115
  project: process.env.AZURE_PROJECT ?? i.project
117
116
  };
118
- v.project || (d.error(`no project info from ${a.blue("package.json")} found`), process.exit(1));
119
- let y = {
120
- clientId: process.env.AZURE_CLIENT_ID ?? l,
121
- tenantId: process.env.AZURE_TENANT_ID ?? u,
117
+ g.project || (l.error(`no project info from ${a.blue("package.json")} found`), process.exit(1));
118
+ let _ = {
119
+ clientId: process.env.AZURE_CLIENT_ID ?? s,
120
+ tenantId: process.env.AZURE_TENANT_ID ?? c,
122
121
  clientSecret: process.env.AZURE_CLIENT_SECRET ?? r
123
122
  };
124
- if (t && t.length > 0 && !p(y)) {
125
- let n = await m(e, t);
126
- _ ??= n.vaultUrl, y.clientId ??= n.clientId, y.clientSecret ??= n.clientSecret, y.tenantId ??= n.tenantId;
123
+ if (t && t.length > 0 && !d(_)) {
124
+ let n = await f(e, t);
125
+ h ??= n.vaultUrl, _.clientId ??= n.clientId, _.clientSecret ??= n.clientSecret, _.tenantId ??= n.tenantId;
127
126
  }
128
- if (d.debug(`credentials loaded for project ${a.bold(a.underline(a.yellowBright(v.project)))} and group ${a.bold(a.underline(a.yellowBright(v.group)))}`), d.debug(`connected to ${a.bold(a.underline(a.greenBright(_)))}`), n) return c(v);
129
- let b = new s(_, v, y);
130
- return o || await g(_), b;
127
+ l.debug(`credentials loaded for project ${a.bold(a.underline(a.yellowBright(g.project)))} and group ${a.bold(a.underline(a.yellowBright(g.group)))}`), l.debug(`connected to ${a.bold(a.underline(a.greenBright(h)))}`);
128
+ let { AzureKeyVault: v, createAzureKeyVaultMock: y } = await import("@achs/azure-key-vault");
129
+ if (n) return y(g);
130
+ let b = new v(h, g, _);
131
+ return o || await m(h), b;
131
132
  }
132
- function g(e) {
133
- let t = new l.Resolver();
133
+ function m(e) {
134
+ let t = new s.Resolver();
134
135
  return t.setServers(["8.8.8.8", "1.1.1.1"]), new Promise((n) => {
135
136
  t.resolve4(new URL(e).hostname, (t) => {
136
- t && (d.error(`cannot resolve vault host ${a.red(e)}`, t), process.exit(1)), d.debug(`vault host reachable ${a.green(e)}`), n();
137
+ t && (l.error(`cannot resolve vault host ${a.red(e)}`, t), process.exit(1)), l.debug(`vault host reachable ${a.green(e)}`), n();
137
138
  });
138
139
  });
139
140
  }
140
141
  //#endregion
141
- export { f as AzureKeyVaultProvider };
142
+ export { u as AzureKeyVaultProvider };
142
143
 
143
144
  //# sourceMappingURL=azure-key-vault.provider.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"azure-key-vault.provider.js","names":[],"sources":["../../src/providers/azure-key-vault.provider.ts"],"sourcesContent":["import { AzureKeyVault, createAzureKeyVaultMock } from '@achs/azure-key-vault';\r\nimport type { AzureKeyVaultSecrets } from '@achs/azure-key-vault';\r\nimport dns from 'node:dns';\r\nimport { existsSync } from 'node:fs';\r\nimport pc from 'picocolors';\r\nimport type { Arguments } from 'yargs';\r\nimport type { CommandArguments } from '../arguments.js';\r\nimport type { PullCommandArguments } from '../commands/pull.command.js';\r\nimport type { EnvProvider } from '../interfaces/index.js';\r\nimport {\r\n\tgenerateSchemaFrom,\r\n\tlogger as globalLogger,\r\n\treadJson,\r\n\tschemaToJson,\r\n\twriteJson,\r\n} from '../utils/index.js';\r\n\r\nconst KEY = 'azure-key-vault';\r\n\r\nconst logger = globalLogger.getSubLogger({\r\n\tprefix: [pc.bold(pc.blue(`[${KEY}]`))],\r\n});\r\n\r\ninterface AzureKeyVaultCommandArguments extends CommandArguments {\r\n\tmock: boolean;\r\n\tpassword: string;\r\n\tsecretsFile: string;\r\n\tskipDnsCheck: boolean;\r\n\tspn: string;\r\n\ttenant: string;\r\n\tvaultUrl: string;\r\n\tkeysFile?: string[];\r\n}\r\n\r\ninterface AzureKeyVaultCommandConfig {\r\n\t[key: string]: {\r\n\t\tvaultUrl: string;\r\n\t};\r\n}\r\n\r\n/**\r\n * Loads secrets from env files in env/secrets\r\n * folder, loaded from Azure Key Vault.\r\n */\r\nexport const AzureKeyVaultProvider: EnvProvider<\r\n\tAzureKeyVaultCommandArguments & PullCommandArguments,\r\n\tAzureKeyVaultCommandConfig\r\n> = {\r\n\tkey: KEY,\r\n\r\n\tbuilder: (builder) => {\r\n\t\tbuilder.options({\r\n\t\t\tkeysFile: {\r\n\t\t\t\talias: ['k', 'keys'],\r\n\t\t\t\tdefault: ['[[root]]/keys.json', '../keys.json'],\r\n\t\t\t\tdescribe: 'Azure Key Vault keys file path',\r\n\t\t\t\tgroup: KEY,\r\n\t\t\t\ttype: 'array',\r\n\t\t\t},\r\n\t\t\tmock: {\r\n\t\t\t\tdefault: false,\r\n\t\t\t\tdescribe: 'Mocks Azure Key Vault client',\r\n\t\t\t\tgroup: KEY,\r\n\t\t\t\ttype: 'boolean',\r\n\t\t\t},\r\n\t\t\tpassword: {\r\n\t\t\t\talias: ['p', 'pass', 'clientSecret'],\r\n\t\t\t\tdescribe: 'SPN Client Secret Password',\r\n\t\t\t\tgroup: KEY,\r\n\t\t\t\ttype: 'string',\r\n\t\t\t},\r\n\t\t\tsecretsFile: {\r\n\t\t\t\tdefault: '[[root]]/[[env]].env.json',\r\n\t\t\t\tdescribe: 'Secret variables file path',\r\n\t\t\t\tgroup: KEY,\r\n\t\t\t\ttype: 'string',\r\n\t\t\t},\r\n\t\t\tskipDnsCheck: {\r\n\t\t\t\talias: 'dns',\r\n\t\t\t\tdefault: false,\r\n\t\t\t\tdescribe: 'Skips DNS checking when connect to Azure Key Vault',\r\n\t\t\t\ttype: 'boolean',\r\n\t\t\t},\r\n\t\t\tspn: {\r\n\t\t\t\talias: ['clientId', 'id'],\r\n\t\t\t\tdescribe: 'SPN Client ID',\r\n\t\t\t\tgroup: KEY,\r\n\t\t\t\ttype: 'string',\r\n\t\t\t},\r\n\t\t\ttenant: {\r\n\t\t\t\talias: 't',\r\n\t\t\t\tdescribe: 'Azure Tenant ID',\r\n\t\t\t\tgroup: KEY,\r\n\t\t\t\ttype: 'string',\r\n\t\t\t},\r\n\t\t\tvaultUrl: {\r\n\t\t\t\talias: 'url',\r\n\t\t\t\tdescribe: 'Azure Key Vault URL',\r\n\t\t\t\tgroup: KEY,\r\n\t\t\t\ttype: 'string',\r\n\t\t\t},\r\n\t\t});\r\n\t},\r\n\r\n\tpush: async (argv, config) => {\r\n\t\tconst [secrets, secretsWasFound] = await readJson(argv.secretsFile);\r\n\r\n\t\tif (!secretsWasFound) {\r\n\t\t\tlogger.error(`${pc.blue(argv.secretsFile)} not found`);\r\n\r\n\t\t\tprocess.exit(1);\r\n\t\t}\r\n\r\n\t\tlogger.silly('local secrets loaded:', secrets);\r\n\t\tconst akv = await loadAzureKeyVaultClient(\r\n\t\t\targv,\r\n\t\t\tconfig?.[argv.env]?.vaultUrl,\r\n\t\t);\r\n\t\tlogger.info('pushing variables to store');\r\n\t\tconst results = await akv.setAll(secrets);\r\n\t\tlogger.silly('secrets pushed:', results);\r\n\r\n\t\tconst schema = await generateSchemaFrom(\r\n\t\t\t[{ key: KEY, value: secrets }],\r\n\t\t\targv,\r\n\t\t);\r\n\r\n\t\tlogger.silly('schema for akv updated:', schema);\r\n\t},\r\n\r\n\tpull: async (argv, config) => {\r\n\t\tconst schema = argv.schema?.[KEY] as\r\n\t\t\t| Record<string, unknown>\r\n\t\t\t| undefined;\r\n\r\n\t\tif (!schema) {\r\n\t\t\tlogger.error(\r\n\t\t\t\t'no schema found, you can gen one with \"env schema -e {env} -m {modes}\"',\r\n\t\t\t);\r\n\r\n\t\t\tlogger.info(\r\n\t\t\t\t`generated empty ${pc.bold(\r\n\t\t\t\t\tpc.underline(pc.yellowBright(argv.secretsFile)),\r\n\t\t\t\t)} file (you can retry the command)`,\r\n\t\t\t);\r\n\t\t\tawait writeJson(argv.secretsFile, {}, false, true);\r\n\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst jsonTemplate = schemaToJson(schema) as Record<string, unknown>;\r\n\r\n\t\tconst vaultUrl = config?.[argv.env]?.vaultUrl;\r\n\t\tif (!vaultUrl) return writeJson(argv.secretsFile, {}, false, true);\r\n\r\n\t\tconst akv = await loadAzureKeyVaultClient(argv, vaultUrl);\r\n\r\n\t\tlogger.info(\r\n\t\t\t`pulling stored secrets from ${pc.underline(pc.yellowBright(vaultUrl))}`,\r\n\t\t);\r\n\r\n\t\tconst secrets = await akv.getFor(\r\n\t\t\tjsonTemplate as AzureKeyVaultSecrets,\r\n\t\t\ttrue,\r\n\t\t);\r\n\r\n\t\tlogger.silly('remote secrets loaded:', secrets);\r\n\r\n\t\tawait writeJson(argv.secretsFile, secrets, argv.overwrite, true);\r\n\t},\r\n\r\n\tload: async (argv, config) => {\r\n\t\tconst { env, secretsFile } = argv;\r\n\r\n\t\tif (!env) {\r\n\t\t\tlogger.silly('no env, so skipping provider');\r\n\r\n\t\t\treturn [];\r\n\t\t}\r\n\r\n\t\tif (!existsSync(secretsFile)) {\r\n\t\t\tlogger.warn('secrets file not found, pulling from store');\r\n\r\n\t\t\tawait AzureKeyVaultProvider.pull!(argv, config);\r\n\t\t}\r\n\r\n\t\tconst [secrets] = await readJson(secretsFile);\r\n\r\n\t\treturn [secrets];\r\n\t},\r\n};\r\n\r\n/**\r\n * Validate SPN credentials/keys.\r\n *\r\n * @param {(Record<string, any> | null)} keys\r\n *\r\n * @returns {boolean}\r\n */\r\nfunction keysAreValid(keys: Record<string, any> | null): boolean {\r\n\treturn Boolean(keys && keys.clientId && keys.clientSecret && keys.tenantId);\r\n}\r\n\r\n/**\r\n * Loads SPN Azure Key Vault credentials from keys file.\r\n *\r\n * @param {string} env\r\n * @param {string[]} paths\r\n *\r\n * @returns {Record<string, string>} credentials\r\n */\r\nasync function loadKeysFile(\r\n\tenv: string,\r\n\tpaths: string[],\r\n): Promise<Record<string, string>> {\r\n\tlogger.debug(`searching keys at ${pc.yellow(paths.join(','))}`);\r\n\r\n\tconst readers = await Promise.all(paths.map((path) => readJson(path)));\r\n\r\n\tconst [keys] = readers.find(\r\n\t\t([candidate, wasFound]) => wasFound && keysAreValid(candidate[env]),\r\n\t) ?? [null];\r\n\r\n\treturn keys?.[env] ?? {};\r\n}\r\n\r\n/**\r\n * Loads credentials and initializes Azure Key Vault client.\r\n *\r\n * @param {Arguments<AzureKeyVaultCommandArguments>} argv command arguments\r\n *\r\n * @returns {*} {Promise<AzureKeyVault>}\r\n */\r\n// linear credential-resolution (env vars → args → keys file precedence);\r\n// complexity comes from `??` fallbacks, not tangled control flow\r\n// eslint-disable-next-line complexity\r\nasync function loadAzureKeyVaultClient(\r\n\t{\r\n\t\tenv,\r\n\t\tkeysFile,\r\n\t\tmock,\r\n\t\tpassword,\r\n\t\tprojectInfo,\r\n\t\tskipDnsCheck,\r\n\t\tspn,\r\n\t\ttenant,\r\n\t\tvaultUrl,\r\n\t}: Arguments<AzureKeyVaultCommandArguments>,\r\n\tconfigVaultUrl?: string,\r\n): Promise<AzureKeyVault> {\r\n\tlet url = process.env.AZURE_VAULT_URL ?? vaultUrl ?? configVaultUrl;\r\n\r\n\tconst config = {\r\n\t\tenv,\r\n\t\tgroup: process.env.AZURE_GROUP ?? projectInfo.name,\r\n\t\tproject: process.env.AZURE_PROJECT ?? projectInfo.project,\r\n\t};\r\n\r\n\tif (!config.project) {\r\n\t\tlogger.error(`no project info from ${pc.blue('package.json')} found`);\r\n\r\n\t\tprocess.exit(1);\r\n\t}\r\n\r\n\tconst credentials = {\r\n\t\tclientId: process.env.AZURE_CLIENT_ID ?? spn,\r\n\t\ttenantId: process.env.AZURE_TENANT_ID ?? tenant,\r\n\t\tclientSecret: process.env.AZURE_CLIENT_SECRET ?? password,\r\n\t};\r\n\r\n\tif (keysFile && keysFile.length > 0 && !keysAreValid(credentials)) {\r\n\t\tconst keys = await loadKeysFile(env, keysFile);\r\n\r\n\t\turl ??= keys.vaultUrl;\r\n\t\tcredentials.clientId ??= keys.clientId;\r\n\t\tcredentials.clientSecret ??= keys.clientSecret;\r\n\t\tcredentials.tenantId ??= keys.tenantId;\r\n\t}\r\n\r\n\tlogger.debug(\r\n\t\t`credentials loaded for project ${pc.bold(\r\n\t\t\tpc.underline(pc.yellowBright(config.project)),\r\n\t\t)} and group ${pc.bold(pc.underline(pc.yellowBright(config.group)))}`,\r\n\t);\r\n\r\n\tlogger.debug(`connected to ${pc.bold(pc.underline(pc.greenBright(url)))}`);\r\n\r\n\tif (mock) return createAzureKeyVaultMock(config);\r\n\r\n\tconst akv = new AzureKeyVault(url, config, credentials);\r\n\r\n\tif (!skipDnsCheck) await verifyVaultReachable(url);\r\n\r\n\treturn akv;\r\n}\r\n\r\n/**\r\n * Best-effort DNS reachability check for the vault host. Resolves the hostname\r\n * via public resolvers; logs and exits on failure. Does NOT issue a\r\n * guaranteed-failing secret call (the old `getSecret('')` probe).\r\n */\r\nfunction verifyVaultReachable(url: string): Promise<void> {\r\n\tconst resolver = new dns.Resolver();\r\n\r\n\tresolver.setServers(['8.8.8.8', '1.1.1.1']);\r\n\r\n\treturn new Promise<void>((resolve) => {\r\n\t\tresolver.resolve4(new URL(url).hostname, (error) => {\r\n\t\t\tif (error) {\r\n\t\t\t\tlogger.error(`cannot resolve vault host ${pc.red(url)}`, error);\r\n\t\t\t\tprocess.exit(1);\r\n\t\t\t}\r\n\r\n\t\t\tlogger.debug(`vault host reachable ${pc.green(url)}`);\r\n\t\t\tresolve();\r\n\t\t});\r\n\t});\r\n}\r\n"],"mappings":"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"}
1
+ {"version":3,"file":"azure-key-vault.provider.js","names":[],"sources":["../../src/providers/azure-key-vault.provider.ts"],"sourcesContent":["import type {\r\n\tAzureKeyVault,\r\n\tAzureKeyVaultSecrets,\r\n} from '@achs/azure-key-vault';\r\nimport dns from 'node:dns';\r\nimport { existsSync } from 'node:fs';\r\nimport pc from 'picocolors';\r\nimport type { Arguments } from 'yargs';\r\nimport type { CommandArguments } from '../arguments.js';\r\nimport type { PullCommandArguments } from '../commands/pull.command.js';\r\nimport type { EnvProvider } from '../interfaces/index.js';\r\nimport {\r\n\tgenerateSchemaFrom,\r\n\tlogger as globalLogger,\r\n\treadJson,\r\n\tschemaToJson,\r\n\twriteJson,\r\n} from '../utils/index.js';\r\n\r\nconst KEY = 'azure-key-vault';\r\n\r\nconst logger = globalLogger.getSubLogger({\r\n\tprefix: [pc.bold(pc.blue(`[${KEY}]`))],\r\n});\r\n\r\ninterface AzureKeyVaultCommandArguments extends CommandArguments {\r\n\tmock: boolean;\r\n\tpassword: string;\r\n\tsecretsFile: string;\r\n\tskipDnsCheck: boolean;\r\n\tspn: string;\r\n\ttenant: string;\r\n\tvaultUrl: string;\r\n\tkeysFile?: string[];\r\n}\r\n\r\ninterface AzureKeyVaultCommandConfig {\r\n\t[key: string]: {\r\n\t\tvaultUrl: string;\r\n\t};\r\n}\r\n\r\n/**\r\n * Loads secrets from env files in env/secrets\r\n * folder, loaded from Azure Key Vault.\r\n */\r\nexport const AzureKeyVaultProvider: EnvProvider<\r\n\tAzureKeyVaultCommandArguments & PullCommandArguments,\r\n\tAzureKeyVaultCommandConfig\r\n> = {\r\n\tkey: KEY,\r\n\r\n\tbuilder: (builder) => {\r\n\t\tbuilder.options({\r\n\t\t\tkeysFile: {\r\n\t\t\t\talias: ['k', 'keys'],\r\n\t\t\t\tdefault: ['[[root]]/keys.json', '../keys.json'],\r\n\t\t\t\tdescribe: 'Azure Key Vault keys file path',\r\n\t\t\t\tgroup: KEY,\r\n\t\t\t\ttype: 'array',\r\n\t\t\t},\r\n\t\t\tmock: {\r\n\t\t\t\tdefault: false,\r\n\t\t\t\tdescribe: 'Mocks Azure Key Vault client',\r\n\t\t\t\tgroup: KEY,\r\n\t\t\t\ttype: 'boolean',\r\n\t\t\t},\r\n\t\t\tpassword: {\r\n\t\t\t\talias: ['p', 'pass', 'clientSecret'],\r\n\t\t\t\tdescribe: 'SPN Client Secret Password',\r\n\t\t\t\tgroup: KEY,\r\n\t\t\t\ttype: 'string',\r\n\t\t\t},\r\n\t\t\tsecretsFile: {\r\n\t\t\t\tdefault: '[[root]]/[[env]].env.json',\r\n\t\t\t\tdescribe: 'Secret variables file path',\r\n\t\t\t\tgroup: KEY,\r\n\t\t\t\ttype: 'string',\r\n\t\t\t},\r\n\t\t\tskipDnsCheck: {\r\n\t\t\t\talias: 'dns',\r\n\t\t\t\tdefault: false,\r\n\t\t\t\tdescribe: 'Skips DNS checking when connect to Azure Key Vault',\r\n\t\t\t\ttype: 'boolean',\r\n\t\t\t},\r\n\t\t\tspn: {\r\n\t\t\t\talias: ['clientId', 'id'],\r\n\t\t\t\tdescribe: 'SPN Client ID',\r\n\t\t\t\tgroup: KEY,\r\n\t\t\t\ttype: 'string',\r\n\t\t\t},\r\n\t\t\ttenant: {\r\n\t\t\t\talias: 't',\r\n\t\t\t\tdescribe: 'Azure Tenant ID',\r\n\t\t\t\tgroup: KEY,\r\n\t\t\t\ttype: 'string',\r\n\t\t\t},\r\n\t\t\tvaultUrl: {\r\n\t\t\t\talias: 'url',\r\n\t\t\t\tdescribe: 'Azure Key Vault URL',\r\n\t\t\t\tgroup: KEY,\r\n\t\t\t\ttype: 'string',\r\n\t\t\t},\r\n\t\t});\r\n\t},\r\n\r\n\tpush: async (argv, config) => {\r\n\t\tconst [secrets, secretsWasFound] = await readJson(argv.secretsFile);\r\n\r\n\t\tif (!secretsWasFound) {\r\n\t\t\tlogger.error(`${pc.blue(argv.secretsFile)} not found`);\r\n\r\n\t\t\tprocess.exit(1);\r\n\t\t}\r\n\r\n\t\tlogger.silly('local secrets loaded:', secrets);\r\n\t\tconst akv = await loadAzureKeyVaultClient(\r\n\t\t\targv,\r\n\t\t\tconfig?.[argv.env]?.vaultUrl,\r\n\t\t);\r\n\t\tlogger.info('pushing variables to store');\r\n\t\tconst results = await akv.setAll(secrets);\r\n\t\tlogger.silly('secrets pushed:', results);\r\n\r\n\t\tconst schema = await generateSchemaFrom(\r\n\t\t\t[{ key: KEY, value: secrets }],\r\n\t\t\targv,\r\n\t\t);\r\n\r\n\t\tlogger.silly('schema for akv updated:', schema);\r\n\t},\r\n\r\n\tpull: async (argv, config) => {\r\n\t\tconst schema = argv.schema?.[KEY] as\r\n\t\t\t| Record<string, unknown>\r\n\t\t\t| undefined;\r\n\r\n\t\tif (!schema) {\r\n\t\t\tlogger.error(\r\n\t\t\t\t'no schema found, you can gen one with \"env schema -e {env} -m {modes}\"',\r\n\t\t\t);\r\n\r\n\t\t\tlogger.info(\r\n\t\t\t\t`generated empty ${pc.bold(\r\n\t\t\t\t\tpc.underline(pc.yellowBright(argv.secretsFile)),\r\n\t\t\t\t)} file (you can retry the command)`,\r\n\t\t\t);\r\n\t\t\tawait writeJson(argv.secretsFile, {}, false, true);\r\n\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst jsonTemplate = schemaToJson(schema) as Record<string, unknown>;\r\n\r\n\t\tconst vaultUrl = config?.[argv.env]?.vaultUrl;\r\n\t\tif (!vaultUrl) return writeJson(argv.secretsFile, {}, false, true);\r\n\r\n\t\tconst akv = await loadAzureKeyVaultClient(argv, vaultUrl);\r\n\r\n\t\tlogger.info(\r\n\t\t\t`pulling stored secrets from ${pc.underline(pc.yellowBright(vaultUrl))}`,\r\n\t\t);\r\n\r\n\t\tconst secrets = await akv.getFor(\r\n\t\t\tjsonTemplate as AzureKeyVaultSecrets,\r\n\t\t\ttrue,\r\n\t\t);\r\n\r\n\t\tlogger.silly('remote secrets loaded:', secrets);\r\n\r\n\t\tawait writeJson(argv.secretsFile, secrets, argv.overwrite, true);\r\n\t},\r\n\r\n\tload: async (argv, config) => {\r\n\t\tconst { env, secretsFile } = argv;\r\n\r\n\t\tif (!env) {\r\n\t\t\tlogger.silly('no env, so skipping provider');\r\n\r\n\t\t\treturn [];\r\n\t\t}\r\n\r\n\t\tif (!existsSync(secretsFile)) {\r\n\t\t\tlogger.warn('secrets file not found, pulling from store');\r\n\r\n\t\t\tawait AzureKeyVaultProvider.pull!(argv, config);\r\n\t\t}\r\n\r\n\t\tconst [secrets] = await readJson(secretsFile);\r\n\r\n\t\treturn [secrets];\r\n\t},\r\n};\r\n\r\n/**\r\n * Validate SPN credentials/keys.\r\n *\r\n * @param {(Record<string, any> | null)} keys\r\n *\r\n * @returns {boolean}\r\n */\r\nfunction keysAreValid(keys: Record<string, any> | null): boolean {\r\n\treturn Boolean(keys && keys.clientId && keys.clientSecret && keys.tenantId);\r\n}\r\n\r\n/**\r\n * Loads SPN Azure Key Vault credentials from keys file.\r\n *\r\n * @param {string} env\r\n * @param {string[]} paths\r\n *\r\n * @returns {Record<string, string>} credentials\r\n */\r\nasync function loadKeysFile(\r\n\tenv: string,\r\n\tpaths: string[],\r\n): Promise<Record<string, string>> {\r\n\tlogger.debug(`searching keys at ${pc.yellow(paths.join(','))}`);\r\n\r\n\tconst readers = await Promise.all(paths.map((path) => readJson(path)));\r\n\r\n\tconst [keys] = readers.find(\r\n\t\t([candidate, wasFound]) => wasFound && keysAreValid(candidate[env]),\r\n\t) ?? [null];\r\n\r\n\treturn keys?.[env] ?? {};\r\n}\r\n\r\n/**\r\n * Loads credentials and initializes Azure Key Vault client.\r\n *\r\n * @param {Arguments<AzureKeyVaultCommandArguments>} argv command arguments\r\n *\r\n * @returns {*} {Promise<AzureKeyVault>}\r\n */\r\n// linear credential-resolution (env vars → args → keys file precedence);\r\n// complexity comes from `??` fallbacks, not tangled control flow\r\n// eslint-disable-next-line complexity\r\nasync function loadAzureKeyVaultClient(\r\n\t{\r\n\t\tenv,\r\n\t\tkeysFile,\r\n\t\tmock,\r\n\t\tpassword,\r\n\t\tprojectInfo,\r\n\t\tskipDnsCheck,\r\n\t\tspn,\r\n\t\ttenant,\r\n\t\tvaultUrl,\r\n\t}: Arguments<AzureKeyVaultCommandArguments>,\r\n\tconfigVaultUrl?: string,\r\n): Promise<AzureKeyVault> {\r\n\tlet url = process.env.AZURE_VAULT_URL ?? vaultUrl ?? configVaultUrl;\r\n\r\n\tconst config = {\r\n\t\tenv,\r\n\t\tgroup: process.env.AZURE_GROUP ?? projectInfo.name,\r\n\t\tproject: process.env.AZURE_PROJECT ?? projectInfo.project,\r\n\t};\r\n\r\n\tif (!config.project) {\r\n\t\tlogger.error(`no project info from ${pc.blue('package.json')} found`);\r\n\r\n\t\tprocess.exit(1);\r\n\t}\r\n\r\n\tconst credentials = {\r\n\t\tclientId: process.env.AZURE_CLIENT_ID ?? spn,\r\n\t\ttenantId: process.env.AZURE_TENANT_ID ?? tenant,\r\n\t\tclientSecret: process.env.AZURE_CLIENT_SECRET ?? password,\r\n\t};\r\n\r\n\tif (keysFile && keysFile.length > 0 && !keysAreValid(credentials)) {\r\n\t\tconst keys = await loadKeysFile(env, keysFile);\r\n\r\n\t\turl ??= keys.vaultUrl;\r\n\t\tcredentials.clientId ??= keys.clientId;\r\n\t\tcredentials.clientSecret ??= keys.clientSecret;\r\n\t\tcredentials.tenantId ??= keys.tenantId;\r\n\t}\r\n\r\n\tlogger.debug(\r\n\t\t`credentials loaded for project ${pc.bold(\r\n\t\t\tpc.underline(pc.yellowBright(config.project)),\r\n\t\t)} and group ${pc.bold(pc.underline(pc.yellowBright(config.group)))}`,\r\n\t);\r\n\r\n\tlogger.debug(`connected to ${pc.bold(pc.underline(pc.greenBright(url)))}`);\r\n\r\n\tconst { AzureKeyVault, createAzureKeyVaultMock } =\r\n\t\tawait import('@achs/azure-key-vault');\r\n\r\n\tif (mock) return createAzureKeyVaultMock(config);\r\n\r\n\tconst akv = new AzureKeyVault(url, config, credentials);\r\n\r\n\tif (!skipDnsCheck) await verifyVaultReachable(url);\r\n\r\n\treturn akv;\r\n}\r\n\r\n/**\r\n * Best-effort DNS reachability check for the vault host. Resolves the hostname\r\n * via public resolvers; logs and exits on failure. Does NOT issue a\r\n * guaranteed-failing secret call (the old `getSecret('')` probe).\r\n */\r\nfunction verifyVaultReachable(url: string): Promise<void> {\r\n\tconst resolver = new dns.Resolver();\r\n\r\n\tresolver.setServers(['8.8.8.8', '1.1.1.1']);\r\n\r\n\treturn new Promise<void>((resolve) => {\r\n\t\tresolver.resolve4(new URL(url).hostname, (error) => {\r\n\t\t\tif (error) {\r\n\t\t\t\tlogger.error(`cannot resolve vault host ${pc.red(url)}`, error);\r\n\t\t\t\tprocess.exit(1);\r\n\t\t\t}\r\n\r\n\t\t\tlogger.debug(`vault host reachable ${pc.green(url)}`);\r\n\t\t\tresolve();\r\n\t\t});\r\n\t});\r\n}\r\n"],"mappings":"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"}
@@ -65,7 +65,7 @@ export declare function flatResults(results: EnvProviderResult[], nestingDelimit
65
65
  *
66
66
  * @returns {EnvProviderResult[]}
67
67
  */
68
- export declare function flatAndValidateResults(results: EnvProviderResult[], argv: Partial<Arguments<EnvCommandArguments>>): EnvProviderResult[] | never;
68
+ export declare function flatAndValidateResults(results: EnvProviderResult[], argv: Partial<Arguments<EnvCommandArguments>>): Promise<EnvProviderResult[]>;
69
69
  /**
70
70
  * Creates or updates JSON schema from
71
71
  * environment variables grouped by provider key.
@@ -1 +1 @@
1
- {"version":3,"file":"command.util.d.ts","sourceRoot":"","sources":["../../src/utils/command.util.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACtE,OAAO,KAAK,EACX,iBAAiB,EACjB,iBAAiB,EACjB,MAAM,wBAAwB,CAAC;AAWhC;;;;;GAKG;AACH,wBAAsB,cAAc,CACnC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,GAC1B,OAAO,CAAC,IAAI,CAAC,CAOf;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,YAkB5E;AAED;;;;;;;GAOG;AACH,wBAAsB,cAAc,CACnC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,GAC1B,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC,CAS9C;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAC9B,YAAY,SAAK,GACf,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAiBlC;AAED;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CACzC,SAAS,EAAE,iBAAiB,EAAE,EAC9B,IAAI,EAAE,OAAO,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC,GAC3C,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAY9B;AAED;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAC1B,OAAO,EAAE,iBAAiB,EAAE,EAC5B,gBAAgB,SAAO,GACrB,iBAAiB,EAAE,GAAG,KAAK,CAO7B;AAED;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CACrC,OAAO,EAAE,iBAAiB,EAAE,EAC5B,IAAI,EAAE,OAAO,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC,GAC3C,iBAAiB,EAAE,GAAG,KAAK,CA6B7B;AAED;;;;;;;;;GASG;AACH,wBAAsB,kBAAkB,CACvC,GAAG,EAAE,iBAAiB,EAAE,EACxB,IAAI,EAAE,SAAS,CAAC,gBAAgB,CAAC,GAC/B,OAAO,CAAC,MAAM,CAAC,CAqBjB"}
1
+ {"version":3,"file":"command.util.d.ts","sourceRoot":"","sources":["../../src/utils/command.util.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACtE,OAAO,KAAK,EACX,iBAAiB,EACjB,iBAAiB,EACjB,MAAM,wBAAwB,CAAC;AAWhC;;;;;GAKG;AACH,wBAAsB,cAAc,CACnC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,GAC1B,OAAO,CAAC,IAAI,CAAC,CAOf;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,YAkB5E;AAED;;;;;;;GAOG;AACH,wBAAsB,cAAc,CACnC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,GAC1B,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC,CAS9C;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAC9B,YAAY,SAAK,GACf,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAiBlC;AAED;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CACzC,SAAS,EAAE,iBAAiB,EAAE,EAC9B,IAAI,EAAE,OAAO,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC,GAC3C,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAY9B;AAED;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAC1B,OAAO,EAAE,iBAAiB,EAAE,EAC5B,gBAAgB,SAAO,GACrB,iBAAiB,EAAE,GAAG,KAAK,CAO7B;AAED;;;;;;;;;GASG;AACH,wBAAsB,sBAAsB,CAC3C,OAAO,EAAE,iBAAiB,EAAE,EAC5B,IAAI,EAAE,OAAO,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC,GAC3C,OAAO,CAAC,iBAAiB,EAAE,CAAC,CA6B9B;AAED;;;;;;;;;GASG;AACH,wBAAsB,kBAAkB,CACvC,GAAG,EAAE,iBAAiB,EAAE,EACxB,IAAI,EAAE,SAAS,CAAC,gBAAgB,CAAC,GAC/B,OAAO,CAAC,MAAM,CAAC,CAqBjB"}
@@ -43,9 +43,9 @@ function h(e, t) {
43
43
  function g(e, t = "__") {
44
44
  return e.flatMap(({ value: e }) => Array.isArray(e) ? c({}, ...e.map((e) => i(e, t))) : i(e, t));
45
45
  }
46
- function _(e, t) {
46
+ async function _(e, t) {
47
47
  if (!t.schemaValidate) return g(e, t.nestingDelimiter);
48
- let n = a(t.schema, t.detectFormat);
48
+ let n = await a(t.schema, t.detectFormat);
49
49
  return e.flatMap(({ key: e, value: a }) => {
50
50
  let o = a;
51
51
  Array.isArray(a) ? (a = c({}, ...a), o = c({}, ...o.map((e) => i(e, t.nestingDelimiter)))) : o = i(a, t.nestingDelimiter);
@@ -56,7 +56,7 @@ function _(e, t) {
56
56
  }
57
57
  async function v(e, t) {
58
58
  let { detectFormat: r, nullable: i, resolve: a, schemaFile: s } = t, l = {};
59
- for (let { key: t, value: n } of e) l[t] = o(Array.isArray(n) ? c({}, ...n) : n, {
59
+ for (let { key: t, value: n } of e) l[t] = await o(Array.isArray(n) ? c({}, ...n) : n, {
60
60
  nullable: i,
61
61
  strings: { detectFormat: r }
62
62
  });
@@ -1 +1 @@
1
- {"version":3,"file":"command.util.js","names":[],"sources":["../../src/utils/command.util.ts"],"sourcesContent":["import merge from 'merge-deep';\r\nimport { readFileSync } from 'node:fs';\r\nimport Path from 'node:path';\r\nimport pc from 'picocolors';\r\nimport type { Arguments } from 'yargs';\r\nimport type { CommandArguments } from '../arguments.js';\r\nimport type { EnvCommandArguments } from '../commands/env.command.js';\r\nimport type {\r\n\tEnvProviderConfig,\r\n\tEnvProviderResult,\r\n} from '../interfaces/index.js';\r\nimport {\r\n\tcreateValidators,\r\n\tflatten,\r\n\tinterpolate,\r\n\tlogger,\r\n\treadJson,\r\n\tschemaFrom,\r\n\twriteJson,\r\n} from './index.js';\r\n\r\n/**\r\n * Injects config to command arguments from file.\r\n *\r\n * @param {Record<string, unknown>} argv\r\n * @param {[string, string]} delimiters\r\n */\r\nexport async function loadConfigFile(\r\n\targv: Record<string, unknown>,\r\n\tdelimiters: [string, string],\r\n): Promise<void> {\r\n\tif (typeof argv.configFile === 'string') {\r\n\t\tconst path = interpolate(argv.configFile, argv, delimiters);\r\n\t\tconst [config, success] = await readJson(path);\r\n\r\n\t\tif (success) for (const key in config) argv[key] ??= config[key];\r\n\t}\r\n}\r\n\r\n/**\r\n * Extracts subcommand from command line parameters.\r\n *\r\n * @export\r\n * @param {string[]} rawArgv process.argv.slice(2)\r\n * @param {[string, string]} delimiters\r\n *\r\n * @returns {string[]} subcommand for wrap if exists\r\n */\r\nexport function getSubcommand(rawArgv: string[], delimiters: [string, string]) {\r\n\tlet subcommand: string[] = [];\r\n\r\n\t// subcommand delimiter indexes\r\n\r\n\tconst begin = rawArgv.indexOf(delimiters[0]);\r\n\r\n\tconst count = rawArgv.lastIndexOf(delimiters[1]) - begin;\r\n\r\n\t// calculates subcommand surrounded by delimiters\r\n\tif (begin > 0) {\r\n\t\tsubcommand =\r\n\t\t\tcount > 0\r\n\t\t\t\t? rawArgv.splice(begin, count + 1).slice(1, -1)\r\n\t\t\t\t: rawArgv.splice(begin).slice(1);\r\n\t}\r\n\r\n\treturn subcommand;\r\n}\r\n\r\n/**\r\n * Loads providers JSON schema from file.\r\n *\r\n * @param {Record<string, unknown>} argv\r\n * @param {[string, string]} delimiters\r\n *\r\n * @returns {Promise<Record<string, unknown>>}\r\n */\r\nexport async function loadSchemaFile(\r\n\targv: Record<string, unknown>,\r\n\tdelimiters: [string, string],\r\n): Promise<Record<string, unknown> | undefined> {\r\n\tif (typeof argv.schemaFile === 'string') {\r\n\t\tconst path = interpolate(argv.schemaFile, argv, delimiters);\r\n\t\tconst [schema, success] = await readJson(path);\r\n\r\n\t\treturn success ? schema : undefined;\r\n\t}\r\n\r\n\treturn undefined;\r\n}\r\n\r\n/**\r\n * Reads project package.json.\r\n *\r\n * @export\r\n * @returns {Promise<Record<string, unknown>> | never}\r\n */\r\nexport function loadProjectInfo(\r\n\trelativePath = '',\r\n): Promise<Record<string, unknown>> {\r\n\ttry {\r\n\t\tconst filePath = Path.join(process.cwd(), relativePath, 'package.json');\r\n\r\n\t\treturn Promise.resolve(\r\n\t\t\tJSON.parse(readFileSync(filePath, 'utf8')) as Record<\r\n\t\t\t\tstring,\r\n\t\t\t\tunknown\r\n\t\t\t>,\r\n\t\t);\r\n\t} catch {\r\n\t\tlogger.warn(\r\n\t\t\t`project file ${pc.underline(pc.yellow('package.json'))} not found`,\r\n\t\t);\r\n\r\n\t\treturn Promise.resolve({});\r\n\t}\r\n}\r\n\r\n/**\r\n * Executes load functions from provider handlers.\r\n *\r\n * @param {EnvProviderConfig[]} providers\r\n * @param {Partial<Arguments<EnvCommandArguments>>} argv\r\n *\r\n * @returns {EnvProviderResult[]}\r\n */\r\nexport function loadVariablesFromProviders(\r\n\tproviders: EnvProviderConfig[],\r\n\targv: Partial<Arguments<EnvCommandArguments>>,\r\n): Promise<EnvProviderResult[]> {\r\n\tif (!providers) return Promise.resolve([]) as Promise<EnvProviderResult[]>;\r\n\r\n\treturn Promise.all(\r\n\t\tproviders.map(async ({ config, handler: { key, load } }) => {\r\n\t\t\tlogger.silly(`executing ${pc.yellow(key)} provider`);\r\n\r\n\t\t\tconst value = await load(argv, config);\r\n\r\n\t\t\treturn { config, key, value };\r\n\t\t}),\r\n\t);\r\n}\r\n\r\n/**\r\n * Flattern environment provider results.\r\n *\r\n * @param {EnvProviderResult[]} results\r\n * @param {Partial<Arguments<EnvCommandArguments>>} argv\r\n *\r\n * @throws {Error} on schema validation failed\r\n *\r\n * @returns {EnvProviderResult[]} flatten results\r\n */\r\nexport function flatResults(\r\n\tresults: EnvProviderResult[],\r\n\tnestingDelimiter = '__',\r\n): EnvProviderResult[] | never {\r\n\treturn results.flatMap(({ value }) => {\r\n\t\tif (Array.isArray(value))\r\n\t\t\treturn merge({}, ...value.map((v) => flatten(v, nestingDelimiter)));\r\n\r\n\t\treturn flatten(value, nestingDelimiter);\r\n\t});\r\n}\r\n\r\n/**\r\n * Flattern and validates environment provider results.\r\n *\r\n * @param {EnvProviderResult[]} results\r\n * @param {Partial<Arguments<EnvCommandArguments>>} argv\r\n *\r\n * @throws {Error} on schema validation failed\r\n *\r\n * @returns {EnvProviderResult[]}\r\n */\r\nexport function flatAndValidateResults(\r\n\tresults: EnvProviderResult[],\r\n\targv: Partial<Arguments<EnvCommandArguments>>,\r\n): EnvProviderResult[] | never {\r\n\tif (!argv.schemaValidate)\r\n\t\treturn flatResults(results, argv.nestingDelimiter);\r\n\r\n\tconst validators = createValidators(argv.schema!, argv.detectFormat);\r\n\r\n\treturn results.flatMap(({ key, value }) => {\r\n\t\tlet baseValue = value;\r\n\t\tif (Array.isArray(value)) {\r\n\t\t\tvalue = merge({}, ...value);\r\n\t\t\tbaseValue = merge(\r\n\t\t\t\t{},\r\n\t\t\t\t...baseValue.map((v: any) => flatten(v, argv.nestingDelimiter)),\r\n\t\t\t);\r\n\t\t} else {\r\n\t\t\tbaseValue = flatten(value, argv.nestingDelimiter);\r\n\t\t}\r\n\r\n\t\tconst validator = validators![key];\r\n\r\n\t\tif (!validator || validator?.(value)) return baseValue;\r\n\r\n\t\tlogger.error(\r\n\t\t\t`schema validation failed for ${pc.yellow(key)}`,\r\n\t\t\tvalidator?.errors,\r\n\t\t);\r\n\r\n\t\tthrow new Error(`schema validation failed for ${key}`);\r\n\t});\r\n}\r\n\r\n/**\r\n * Creates or updates JSON schema from\r\n * environment variables grouped by provider key.\r\n *\r\n * @export\r\n * @param {EnvProviderResult[]} env\r\n * @param {Arguments<EnvCommandArguments>} argv\r\n *\r\n * @returns {Promise<object>} JSON schema grouped by provider key.\r\n */\r\nexport async function generateSchemaFrom(\r\n\tenv: EnvProviderResult[],\r\n\targv: Arguments<CommandArguments>,\r\n): Promise<object> {\r\n\tconst { detectFormat, nullable, resolve, schemaFile } = argv;\r\n\r\n\t// generates schemas from providers results\r\n\tconst schemaEntries: Record<string, unknown> = {};\r\n\tfor (const { key, value } of env) {\r\n\t\tconst merged = Array.isArray(value) ? merge({}, ...value) : value;\r\n\r\n\t\tschemaEntries[key] = schemaFrom(merged, {\r\n\t\t\tnullable,\r\n\t\t\tstrings: { detectFormat },\r\n\t\t});\r\n\t}\r\n\r\n\tlet schema: Record<string, unknown> = schemaEntries;\r\n\r\n\tif (resolve === 'merge') schema = merge(argv.schema, schema);\r\n\r\n\tawait writeJson(schemaFile, schema, true);\r\n\r\n\treturn schema;\r\n}\r\n"],"mappings":"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"}
1
+ {"version":3,"file":"command.util.js","names":[],"sources":["../../src/utils/command.util.ts"],"sourcesContent":["import merge from 'merge-deep';\r\nimport { readFileSync } from 'node:fs';\r\nimport Path from 'node:path';\r\nimport pc from 'picocolors';\r\nimport type { Arguments } from 'yargs';\r\nimport type { CommandArguments } from '../arguments.js';\r\nimport type { EnvCommandArguments } from '../commands/env.command.js';\r\nimport type {\r\n\tEnvProviderConfig,\r\n\tEnvProviderResult,\r\n} from '../interfaces/index.js';\r\nimport {\r\n\tcreateValidators,\r\n\tflatten,\r\n\tinterpolate,\r\n\tlogger,\r\n\treadJson,\r\n\tschemaFrom,\r\n\twriteJson,\r\n} from './index.js';\r\n\r\n/**\r\n * Injects config to command arguments from file.\r\n *\r\n * @param {Record<string, unknown>} argv\r\n * @param {[string, string]} delimiters\r\n */\r\nexport async function loadConfigFile(\r\n\targv: Record<string, unknown>,\r\n\tdelimiters: [string, string],\r\n): Promise<void> {\r\n\tif (typeof argv.configFile === 'string') {\r\n\t\tconst path = interpolate(argv.configFile, argv, delimiters);\r\n\t\tconst [config, success] = await readJson(path);\r\n\r\n\t\tif (success) for (const key in config) argv[key] ??= config[key];\r\n\t}\r\n}\r\n\r\n/**\r\n * Extracts subcommand from command line parameters.\r\n *\r\n * @export\r\n * @param {string[]} rawArgv process.argv.slice(2)\r\n * @param {[string, string]} delimiters\r\n *\r\n * @returns {string[]} subcommand for wrap if exists\r\n */\r\nexport function getSubcommand(rawArgv: string[], delimiters: [string, string]) {\r\n\tlet subcommand: string[] = [];\r\n\r\n\t// subcommand delimiter indexes\r\n\r\n\tconst begin = rawArgv.indexOf(delimiters[0]);\r\n\r\n\tconst count = rawArgv.lastIndexOf(delimiters[1]) - begin;\r\n\r\n\t// calculates subcommand surrounded by delimiters\r\n\tif (begin > 0) {\r\n\t\tsubcommand =\r\n\t\t\tcount > 0\r\n\t\t\t\t? rawArgv.splice(begin, count + 1).slice(1, -1)\r\n\t\t\t\t: rawArgv.splice(begin).slice(1);\r\n\t}\r\n\r\n\treturn subcommand;\r\n}\r\n\r\n/**\r\n * Loads providers JSON schema from file.\r\n *\r\n * @param {Record<string, unknown>} argv\r\n * @param {[string, string]} delimiters\r\n *\r\n * @returns {Promise<Record<string, unknown>>}\r\n */\r\nexport async function loadSchemaFile(\r\n\targv: Record<string, unknown>,\r\n\tdelimiters: [string, string],\r\n): Promise<Record<string, unknown> | undefined> {\r\n\tif (typeof argv.schemaFile === 'string') {\r\n\t\tconst path = interpolate(argv.schemaFile, argv, delimiters);\r\n\t\tconst [schema, success] = await readJson(path);\r\n\r\n\t\treturn success ? schema : undefined;\r\n\t}\r\n\r\n\treturn undefined;\r\n}\r\n\r\n/**\r\n * Reads project package.json.\r\n *\r\n * @export\r\n * @returns {Promise<Record<string, unknown>> | never}\r\n */\r\nexport function loadProjectInfo(\r\n\trelativePath = '',\r\n): Promise<Record<string, unknown>> {\r\n\ttry {\r\n\t\tconst filePath = Path.join(process.cwd(), relativePath, 'package.json');\r\n\r\n\t\treturn Promise.resolve(\r\n\t\t\tJSON.parse(readFileSync(filePath, 'utf8')) as Record<\r\n\t\t\t\tstring,\r\n\t\t\t\tunknown\r\n\t\t\t>,\r\n\t\t);\r\n\t} catch {\r\n\t\tlogger.warn(\r\n\t\t\t`project file ${pc.underline(pc.yellow('package.json'))} not found`,\r\n\t\t);\r\n\r\n\t\treturn Promise.resolve({});\r\n\t}\r\n}\r\n\r\n/**\r\n * Executes load functions from provider handlers.\r\n *\r\n * @param {EnvProviderConfig[]} providers\r\n * @param {Partial<Arguments<EnvCommandArguments>>} argv\r\n *\r\n * @returns {EnvProviderResult[]}\r\n */\r\nexport function loadVariablesFromProviders(\r\n\tproviders: EnvProviderConfig[],\r\n\targv: Partial<Arguments<EnvCommandArguments>>,\r\n): Promise<EnvProviderResult[]> {\r\n\tif (!providers) return Promise.resolve([]) as Promise<EnvProviderResult[]>;\r\n\r\n\treturn Promise.all(\r\n\t\tproviders.map(async ({ config, handler: { key, load } }) => {\r\n\t\t\tlogger.silly(`executing ${pc.yellow(key)} provider`);\r\n\r\n\t\t\tconst value = await load(argv, config);\r\n\r\n\t\t\treturn { config, key, value };\r\n\t\t}),\r\n\t);\r\n}\r\n\r\n/**\r\n * Flattern environment provider results.\r\n *\r\n * @param {EnvProviderResult[]} results\r\n * @param {Partial<Arguments<EnvCommandArguments>>} argv\r\n *\r\n * @throws {Error} on schema validation failed\r\n *\r\n * @returns {EnvProviderResult[]} flatten results\r\n */\r\nexport function flatResults(\r\n\tresults: EnvProviderResult[],\r\n\tnestingDelimiter = '__',\r\n): EnvProviderResult[] | never {\r\n\treturn results.flatMap(({ value }) => {\r\n\t\tif (Array.isArray(value))\r\n\t\t\treturn merge({}, ...value.map((v) => flatten(v, nestingDelimiter)));\r\n\r\n\t\treturn flatten(value, nestingDelimiter);\r\n\t});\r\n}\r\n\r\n/**\r\n * Flattern and validates environment provider results.\r\n *\r\n * @param {EnvProviderResult[]} results\r\n * @param {Partial<Arguments<EnvCommandArguments>>} argv\r\n *\r\n * @throws {Error} on schema validation failed\r\n *\r\n * @returns {EnvProviderResult[]}\r\n */\r\nexport async function flatAndValidateResults(\r\n\tresults: EnvProviderResult[],\r\n\targv: Partial<Arguments<EnvCommandArguments>>,\r\n): Promise<EnvProviderResult[]> {\r\n\tif (!argv.schemaValidate)\r\n\t\treturn flatResults(results, argv.nestingDelimiter);\r\n\r\n\tconst validators = await createValidators(argv.schema!, argv.detectFormat);\r\n\r\n\treturn results.flatMap(({ key, value }) => {\r\n\t\tlet baseValue = value;\r\n\t\tif (Array.isArray(value)) {\r\n\t\t\tvalue = merge({}, ...value);\r\n\t\t\tbaseValue = merge(\r\n\t\t\t\t{},\r\n\t\t\t\t...baseValue.map((v: any) => flatten(v, argv.nestingDelimiter)),\r\n\t\t\t);\r\n\t\t} else {\r\n\t\t\tbaseValue = flatten(value, argv.nestingDelimiter);\r\n\t\t}\r\n\r\n\t\tconst validator = validators![key];\r\n\r\n\t\tif (!validator || validator?.(value)) return baseValue;\r\n\r\n\t\tlogger.error(\r\n\t\t\t`schema validation failed for ${pc.yellow(key)}`,\r\n\t\t\tvalidator?.errors,\r\n\t\t);\r\n\r\n\t\tthrow new Error(`schema validation failed for ${key}`);\r\n\t});\r\n}\r\n\r\n/**\r\n * Creates or updates JSON schema from\r\n * environment variables grouped by provider key.\r\n *\r\n * @export\r\n * @param {EnvProviderResult[]} env\r\n * @param {Arguments<EnvCommandArguments>} argv\r\n *\r\n * @returns {Promise<object>} JSON schema grouped by provider key.\r\n */\r\nexport async function generateSchemaFrom(\r\n\tenv: EnvProviderResult[],\r\n\targv: Arguments<CommandArguments>,\r\n): Promise<object> {\r\n\tconst { detectFormat, nullable, resolve, schemaFile } = argv;\r\n\r\n\t// generates schemas from providers results\r\n\tconst schemaEntries: Record<string, unknown> = {};\r\n\tfor (const { key, value } of env) {\r\n\t\tconst merged = Array.isArray(value) ? merge({}, ...value) : value;\r\n\r\n\t\tschemaEntries[key] = await schemaFrom(merged, {\r\n\t\t\tnullable,\r\n\t\t\tstrings: { detectFormat },\r\n\t\t});\r\n\t}\r\n\r\n\tlet schema: Record<string, unknown> = schemaEntries;\r\n\r\n\tif (resolve === 'merge') schema = merge(argv.schema, schema);\r\n\r\n\tawait writeJson(schemaFile, schema, true);\r\n\r\n\treturn schema;\r\n}\r\n"],"mappings":"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"}
package/utils/index.d.ts CHANGED
@@ -5,4 +5,5 @@ export * from './json.util.js';
5
5
  export * from './logger.js';
6
6
  export * from './normalize.util.js';
7
7
  export * from './schema.util.js';
8
+ export * from './ui.js';
8
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AACtC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AACtC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,cAAc,SAAS,CAAC"}
package/utils/index.js CHANGED
@@ -5,4 +5,5 @@ import { readJson as f, resolvePath as p, writeEnvFromJson as m, writeJson as h
5
5
  import { LOG_LEVELS as g, configureLogger as _, createLogger as v, logger as y } from "./logger.js";
6
6
  import { flatten as b, normalize as x } from "./normalize.util.js";
7
7
  import { createValidator as S, createValidators as C, flatSchema as w, isJsonSchemaObject as T, schemaFrom as E, schemaToJson as D } from "./schema.util.js";
8
- export { g as LOG_LEVELS, _ as configureLogger, v as createLogger, S as createValidator, C as createValidators, t as flatAndValidateResults, n as flatResults, w as flatSchema, b as flatten, r as generateSchemaFrom, i as getSubcommand, l as interpolate, u as interpolateJson, T as isJsonSchemaObject, d as isRecord, a as loadConfigFile, o as loadProjectInfo, s as loadSchemaFile, c as loadVariablesFromProviders, y as logger, x as normalize, e as normalizeRawArgv, f as readJson, p as resolvePath, E as schemaFrom, D as schemaToJson, m as writeEnvFromJson, h as writeJson };
8
+ import { formatDuration as O, ui as k } from "./ui.js";
9
+ export { g as LOG_LEVELS, _ as configureLogger, v as createLogger, S as createValidator, C as createValidators, t as flatAndValidateResults, n as flatResults, w as flatSchema, b as flatten, O as formatDuration, r as generateSchemaFrom, i as getSubcommand, l as interpolate, u as interpolateJson, T as isJsonSchemaObject, d as isRecord, a as loadConfigFile, o as loadProjectInfo, s as loadSchemaFile, c as loadVariablesFromProviders, y as logger, x as normalize, e as normalizeRawArgv, f as readJson, p as resolvePath, E as schemaFrom, D as schemaToJson, k as ui, m as writeEnvFromJson, h as writeJson };
@@ -1 +1 @@
1
- {"version":3,"file":"json.util.d.ts","sourceRoot":"","sources":["../../src/utils/json.util.ts"],"names":[],"mappings":"AAgBA;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAMpD;AAED;;;;;;;;GAQG;AACH,wBAAsB,QAAQ,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACrD,IAAI,EAAE,MAAM,GACV,OAAO,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC,CAAC,CAI7C;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,SAAS,CAC9B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,SAAS,UAAQ,EACjB,eAAe,UAAQ,GACrB,OAAO,CAAC,OAAO,CAAC,CAgBlB;AAED;;;;;;;;;GASG;AACH,wBAAsB,gBAAgB,CACrC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,SAAS,UAAQ,EACjB,MAAM,UAAQ,GACZ,OAAO,CAAC,OAAO,CAAC,CAiBlB"}
1
+ {"version":3,"file":"json.util.d.ts","sourceRoot":"","sources":["../../src/utils/json.util.ts"],"names":[],"mappings":"AAgBA;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAMpD;AAED;;;;;;;;GAQG;AACH,wBAAsB,QAAQ,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACrD,IAAI,EAAE,MAAM,GACV,OAAO,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC,CAAC,CAS7C;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,SAAS,CAC9B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,SAAS,UAAQ,EACjB,eAAe,UAAQ,GACrB,OAAO,CAAC,OAAO,CAAC,CAgBlB;AAED;;;;;;;;;GASG;AACH,wBAAsB,gBAAgB,CACrC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,SAAS,UAAQ,EACjB,MAAM,UAAQ,GACZ,OAAO,CAAC,OAAO,CAAC,CAiBlB"}
@@ -8,8 +8,13 @@ function o(e) {
8
8
  let n = i.homedir();
9
9
  return n && (e = e.replace(/^~($|\/|\\)/, `${n}$1`)), t.resolve(process.cwd(), e);
10
10
  }
11
- async function s(t) {
12
- return e(t) ? [JSON.parse(await n(t, "utf8")), !0] : [{}, !1];
11
+ async function s(e) {
12
+ try {
13
+ return [JSON.parse(await n(e, "utf8")), !0];
14
+ } catch (e) {
15
+ if (e.code === "ENOENT") return [{}, !1];
16
+ throw e;
17
+ }
13
18
  }
14
19
  async function c(t, n, i = !1, o = !1) {
15
20
  return e(t) && !i ? !1 : (await r(t, `${JSON.stringify(n, o ? a : void 0, 4)}\n`, "utf8"), !0);
@@ -1 +1 @@
1
- {"version":3,"file":"json.util.js","names":[],"sources":["../../src/utils/json.util.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\r\nimport { readFile, writeFile } from 'node:fs/promises';\r\nimport os from 'node:os';\r\nimport path from 'node:path';\r\n\r\n/**\r\n * Replaces undefined by null in JSON.stringify()\r\n *\r\n * @param {string} _ property key\r\n * @param {any} value property value\r\n *\r\n * @returns {any} value\r\n */\r\nconst replacer = (_: string, value: any): any =>\r\n\tvalue === undefined ? null : value;\r\n\r\n/**\r\n * Resolve a relative path for os.\r\n *\r\n * @export\r\n * @param {string} filePath relative path from project root\r\n *\r\n * @returns {string} path\r\n */\r\nexport function resolvePath(filePath: string): string {\r\n\tconst home = os.homedir();\r\n\r\n\tif (home) filePath = filePath.replace(/^~($|\\/|\\\\)/, `${home}$1`);\r\n\r\n\treturn path.resolve(process.cwd(), filePath);\r\n}\r\n\r\n/**\r\n * Reads and parses a JSON file.\r\n *\r\n * @export\r\n * @template T\r\n * @param {string} path\r\n *\r\n * @returns {Promise<[Record<string, any>, boolean]>}\r\n */\r\nexport async function readJson<T = Record<string, any>>(\r\n\tpath: string,\r\n): Promise<[Record<string, any> | T, boolean]> {\r\n\tif (!existsSync(path)) return [{}, false];\r\n\r\n\treturn [JSON.parse(await readFile(path, 'utf8')), true];\r\n}\r\n\r\n/**\r\n * Saves a JSON into a file.\r\n *\r\n * @export\r\n * @param {string} path\r\n * @param {unknown} content\r\n * @param {false} overwrite\r\n * @param {false} undefinedAsNull replaces undefined by null\r\n *\r\n * @returns {Promise<boolean>}\r\n */\r\nexport async function writeJson(\r\n\tpath: string,\r\n\tcontent: Record<string, unknown>,\r\n\toverwrite = false,\r\n\tundefinedAsNull = false,\r\n): Promise<boolean> {\r\n\tconst exists = existsSync(path);\r\n\r\n\tif (exists && !overwrite) return false;\r\n\r\n\tawait writeFile(\r\n\t\tpath,\r\n\t\t`${JSON.stringify(\r\n\t\t\tcontent,\r\n\t\t\tundefinedAsNull ? replacer : undefined,\r\n\t\t\t4,\r\n\t\t)}\\n`,\r\n\t\t'utf8',\r\n\t);\r\n\r\n\treturn true;\r\n}\r\n\r\n/**\r\n * Saves a JSON into a file as dotenv.\r\n *\r\n * @export\r\n * @param {string} path\r\n * @param {unknown} content\r\n * @param {false} overwrite\r\n *\r\n * @returns {Promise<boolean>}\r\n */\r\nexport async function writeEnvFromJson(\r\n\tpath: string,\r\n\tcontent: Record<string, unknown>,\r\n\toverwrite = false,\r\n\tquotes = false,\r\n): Promise<boolean> {\r\n\tconst exists = existsSync(path);\r\n\r\n\tif (exists && !overwrite) return false;\r\n\r\n\tlet data = '';\r\n\r\n\tfor (const key in content) {\r\n\t\tlet value = content[key];\r\n\t\tif (quotes) value = `\"${value}\"`;\r\n\r\n\t\tdata += `${key}=${value}\\n`;\r\n\t}\r\n\r\n\tawait writeFile(path, data, 'utf8');\r\n\r\n\treturn true;\r\n}\r\n"],"mappings":";;;;;AAaA,IAAM,KAAY,GAAW,MAC5B,MAAU,KAAA,IAAY,OAAO;AAU9B,SAAgB,EAAY,GAA0B;CACrD,IAAM,IAAO,EAAG,QAAQ;CAIxB,OAFI,MAAM,IAAW,EAAS,QAAQ,eAAe,GAAG,EAAK,GAAG,IAEzD,EAAK,QAAQ,QAAQ,IAAI,GAAG,CAAQ;AAC5C;AAWA,eAAsB,EACrB,GAC8C;CAG9C,OAFK,EAAW,CAAI,IAEb,CAAC,KAAK,MAAM,MAAM,EAAS,GAAM,MAAM,CAAC,GAAG,EAAI,IAFxB,CAAC,CAAC,GAAG,EAAK;AAGzC;AAaA,eAAsB,EACrB,GACA,GACA,IAAY,IACZ,IAAkB,IACC;CAenB,OAde,EAAW,CAEtB,KAAU,CAAC,IAAkB,MAEjC,MAAM,EACL,GACA,GAAG,KAAK,UACP,GACA,IAAkB,IAAW,KAAA,GAC7B,CACD,EAAE,KACF,MACD,GAEO;AACR;AAYA,eAAsB,EACrB,GACA,GACA,IAAY,IACZ,IAAS,IACU;CAGnB,IAFe,EAAW,CAEtB,KAAU,CAAC,GAAW,OAAO;CAEjC,IAAI,IAAO;CAEX,KAAK,IAAM,KAAO,GAAS;EAC1B,IAAI,IAAQ,EAAQ;EAGpB,AAFI,MAAQ,IAAQ,IAAI,EAAM,KAE9B,KAAQ,GAAG,EAAI,GAAG,EAAM;CACzB;CAIA,OAFA,MAAM,EAAU,GAAM,GAAM,MAAM,GAE3B;AACR"}
1
+ {"version":3,"file":"json.util.js","names":[],"sources":["../../src/utils/json.util.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\r\nimport { readFile, writeFile } from 'node:fs/promises';\r\nimport os from 'node:os';\r\nimport path from 'node:path';\r\n\r\n/**\r\n * Replaces undefined by null in JSON.stringify()\r\n *\r\n * @param {string} _ property key\r\n * @param {any} value property value\r\n *\r\n * @returns {any} value\r\n */\r\nconst replacer = (_: string, value: any): any =>\r\n\tvalue === undefined ? null : value;\r\n\r\n/**\r\n * Resolve a relative path for os.\r\n *\r\n * @export\r\n * @param {string} filePath relative path from project root\r\n *\r\n * @returns {string} path\r\n */\r\nexport function resolvePath(filePath: string): string {\r\n\tconst home = os.homedir();\r\n\r\n\tif (home) filePath = filePath.replace(/^~($|\\/|\\\\)/, `${home}$1`);\r\n\r\n\treturn path.resolve(process.cwd(), filePath);\r\n}\r\n\r\n/**\r\n * Reads and parses a JSON file.\r\n *\r\n * @export\r\n * @template T\r\n * @param {string} path\r\n *\r\n * @returns {Promise<[Record<string, any>, boolean]>}\r\n */\r\nexport async function readJson<T = Record<string, any>>(\r\n\tpath: string,\r\n): Promise<[Record<string, any> | T, boolean]> {\r\n\ttry {\r\n\t\treturn [JSON.parse(await readFile(path, 'utf8')), true];\r\n\t} catch (error) {\r\n\t\tif ((error as NodeJS.ErrnoException).code === 'ENOENT')\r\n\t\t\treturn [{}, false];\r\n\r\n\t\tthrow error; // invalid JSON or other IO error must still surface\r\n\t}\r\n}\r\n\r\n/**\r\n * Saves a JSON into a file.\r\n *\r\n * @export\r\n * @param {string} path\r\n * @param {unknown} content\r\n * @param {false} overwrite\r\n * @param {false} undefinedAsNull replaces undefined by null\r\n *\r\n * @returns {Promise<boolean>}\r\n */\r\nexport async function writeJson(\r\n\tpath: string,\r\n\tcontent: Record<string, unknown>,\r\n\toverwrite = false,\r\n\tundefinedAsNull = false,\r\n): Promise<boolean> {\r\n\tconst exists = existsSync(path);\r\n\r\n\tif (exists && !overwrite) return false;\r\n\r\n\tawait writeFile(\r\n\t\tpath,\r\n\t\t`${JSON.stringify(\r\n\t\t\tcontent,\r\n\t\t\tundefinedAsNull ? replacer : undefined,\r\n\t\t\t4,\r\n\t\t)}\\n`,\r\n\t\t'utf8',\r\n\t);\r\n\r\n\treturn true;\r\n}\r\n\r\n/**\r\n * Saves a JSON into a file as dotenv.\r\n *\r\n * @export\r\n * @param {string} path\r\n * @param {unknown} content\r\n * @param {false} overwrite\r\n *\r\n * @returns {Promise<boolean>}\r\n */\r\nexport async function writeEnvFromJson(\r\n\tpath: string,\r\n\tcontent: Record<string, unknown>,\r\n\toverwrite = false,\r\n\tquotes = false,\r\n): Promise<boolean> {\r\n\tconst exists = existsSync(path);\r\n\r\n\tif (exists && !overwrite) return false;\r\n\r\n\tlet data = '';\r\n\r\n\tfor (const key in content) {\r\n\t\tlet value = content[key];\r\n\t\tif (quotes) value = `\"${value}\"`;\r\n\r\n\t\tdata += `${key}=${value}\\n`;\r\n\t}\r\n\r\n\tawait writeFile(path, data, 'utf8');\r\n\r\n\treturn true;\r\n}\r\n"],"mappings":";;;;;AAaA,IAAM,KAAY,GAAW,MAC5B,MAAU,KAAA,IAAY,OAAO;AAU9B,SAAgB,EAAY,GAA0B;CACrD,IAAM,IAAO,EAAG,QAAQ;CAIxB,OAFI,MAAM,IAAW,EAAS,QAAQ,eAAe,GAAG,EAAK,GAAG,IAEzD,EAAK,QAAQ,QAAQ,IAAI,GAAG,CAAQ;AAC5C;AAWA,eAAsB,EACrB,GAC8C;CAC9C,IAAI;EACH,OAAO,CAAC,KAAK,MAAM,MAAM,EAAS,GAAM,MAAM,CAAC,GAAG,EAAI;CACvD,SAAS,GAAO;EACf,IAAK,EAAgC,SAAS,UAC7C,OAAO,CAAC,CAAC,GAAG,EAAK;EAElB,MAAM;CACP;AACD;AAaA,eAAsB,EACrB,GACA,GACA,IAAY,IACZ,IAAkB,IACC;CAenB,OAde,EAAW,CAEtB,KAAU,CAAC,IAAkB,MAEjC,MAAM,EACL,GACA,GAAG,KAAK,UACP,GACA,IAAkB,IAAW,KAAA,GAC7B,CACD,EAAE,KACF,MACD,GAEO;AACR;AAYA,eAAsB,EACrB,GACA,GACA,IAAY,IACZ,IAAS,IACU;CAGnB,IAFe,EAAW,CAEtB,KAAU,CAAC,GAAW,OAAO;CAEjC,IAAI,IAAO;CAEX,KAAK,IAAM,KAAO,GAAS;EAC1B,IAAI,IAAQ,EAAQ;EAGpB,AAFI,MAAQ,IAAQ,IAAI,EAAM,KAE9B,KAAQ,GAAG,EAAI,GAAG,EAAM;CACzB;CAIA,OAFA,MAAM,EAAU,GAAM,GAAM,MAAM,GAE3B;AACR"}