ultraenv 1.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 (89) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +2058 -0
  3. package/bin/ultraenv.mjs +3 -0
  4. package/dist/chunk-2USZPWLZ.js +288 -0
  5. package/dist/chunk-3UV2QNJL.js +270 -0
  6. package/dist/chunk-3VYXPTYV.js +179 -0
  7. package/dist/chunk-4XUYMRK5.js +366 -0
  8. package/dist/chunk-5G2DU52U.js +189 -0
  9. package/dist/chunk-6KS56D6E.js +172 -0
  10. package/dist/chunk-AWN6ADV7.js +328 -0
  11. package/dist/chunk-CHVO6NWI.js +203 -0
  12. package/dist/chunk-CIFMBJ4H.js +3975 -0
  13. package/dist/chunk-GC7RXHLA.js +253 -0
  14. package/dist/chunk-HFXQGJY3.js +445 -0
  15. package/dist/chunk-IGFVP24Q.js +91 -0
  16. package/dist/chunk-IKPTKALB.js +78 -0
  17. package/dist/chunk-JB7RKV3C.js +66 -0
  18. package/dist/chunk-MNVFG7H4.js +611 -0
  19. package/dist/chunk-MSXMESFP.js +1910 -0
  20. package/dist/chunk-N5PAV4NM.js +127 -0
  21. package/dist/chunk-NBOABPHM.js +158 -0
  22. package/dist/chunk-OMAOROL4.js +49 -0
  23. package/dist/chunk-R7PZRSZ7.js +105 -0
  24. package/dist/chunk-TE7HPLA6.js +73 -0
  25. package/dist/chunk-TMT5KCO3.js +101 -0
  26. package/dist/chunk-UEWYFN6A.js +189 -0
  27. package/dist/chunk-WMHN5RW2.js +128 -0
  28. package/dist/chunk-XC65ORJ5.js +70 -0
  29. package/dist/chunk-YMMP4VQL.js +118 -0
  30. package/dist/chunk-YN2KGTCB.js +33 -0
  31. package/dist/chunk-YTICOB5M.js +65 -0
  32. package/dist/chunk-YVWLXFUT.js +107 -0
  33. package/dist/ci-check-sync-VBMSVWIV.js +48 -0
  34. package/dist/ci-scan-24MT5XGS.js +41 -0
  35. package/dist/ci-setup-C2NKEFRD.js +135 -0
  36. package/dist/ci-validate-7AW24LSQ.js +57 -0
  37. package/dist/cli/index.cjs +9217 -0
  38. package/dist/cli/index.d.cts +9 -0
  39. package/dist/cli/index.d.ts +9 -0
  40. package/dist/cli/index.js +339 -0
  41. package/dist/comparator-RDKX3OI7.js +13 -0
  42. package/dist/completion-MW35C2XO.js +168 -0
  43. package/dist/config-O5YRQP5Z.js +13 -0
  44. package/dist/debug-PTPXAF3K.js +131 -0
  45. package/dist/declaration-LEME4AFZ.js +10 -0
  46. package/dist/doctor-FZAUPKHS.js +129 -0
  47. package/dist/envs-compare-5K3HESX5.js +49 -0
  48. package/dist/envs-create-2XXHXMGA.js +58 -0
  49. package/dist/envs-list-NQM5252B.js +59 -0
  50. package/dist/envs-switch-6L2AQYID.js +50 -0
  51. package/dist/envs-validate-FL73Q76T.js +89 -0
  52. package/dist/fs-VH7ATUS3.js +31 -0
  53. package/dist/generator-LFZBMZZS.js +14 -0
  54. package/dist/git-BZS4DPAI.js +30 -0
  55. package/dist/help-3XJBXEHE.js +121 -0
  56. package/dist/index.cjs +12907 -0
  57. package/dist/index.d.cts +2562 -0
  58. package/dist/index.d.ts +2562 -0
  59. package/dist/index.js +3212 -0
  60. package/dist/init-Y7JQ2KYJ.js +146 -0
  61. package/dist/install-hook-SKXIV6NV.js +111 -0
  62. package/dist/json-schema-I26YNQBH.js +10 -0
  63. package/dist/key-manager-O3G55WPU.js +25 -0
  64. package/dist/middleware/express.cjs +103 -0
  65. package/dist/middleware/express.d.cts +115 -0
  66. package/dist/middleware/express.d.ts +115 -0
  67. package/dist/middleware/express.js +8 -0
  68. package/dist/middleware/fastify.cjs +91 -0
  69. package/dist/middleware/fastify.d.cts +111 -0
  70. package/dist/middleware/fastify.d.ts +111 -0
  71. package/dist/middleware/fastify.js +8 -0
  72. package/dist/module-IDIZPP4M.js +10 -0
  73. package/dist/protect-NCWPM6VC.js +161 -0
  74. package/dist/scan-TRLY36TT.js +58 -0
  75. package/dist/schema/index.cjs +4074 -0
  76. package/dist/schema/index.d.cts +1244 -0
  77. package/dist/schema/index.d.ts +1244 -0
  78. package/dist/schema/index.js +152 -0
  79. package/dist/sync-TMHMTLH2.js +186 -0
  80. package/dist/typegen-SQOSXBWM.js +80 -0
  81. package/dist/validate-IOAM5HWS.js +100 -0
  82. package/dist/vault-decrypt-U6HJZNBV.js +111 -0
  83. package/dist/vault-diff-B3ZOQTWI.js +132 -0
  84. package/dist/vault-encrypt-GUSLCSKS.js +112 -0
  85. package/dist/vault-init-GUBOTOUL.js +106 -0
  86. package/dist/vault-rekey-DAHT7JCN.js +132 -0
  87. package/dist/vault-status-GDLRU2OK.js +90 -0
  88. package/dist/vault-verify-CD76FJSF.js +102 -0
  89. package/package.json +106 -0
@@ -0,0 +1,107 @@
1
+ import {
2
+ parseEnvFile
3
+ } from "./chunk-HFXQGJY3.js";
4
+ import {
5
+ readFile
6
+ } from "./chunk-3VYXPTYV.js";
7
+
8
+ // src/sync/comparator.ts
9
+ function parseToVars(content) {
10
+ const parsed = parseEnvFile(content);
11
+ const vars = {};
12
+ const keys = [];
13
+ for (const envVar of parsed.vars) {
14
+ if (!(envVar.key in vars)) {
15
+ vars[envVar.key] = envVar.value;
16
+ keys.push(envVar.key);
17
+ }
18
+ }
19
+ return { vars, keys };
20
+ }
21
+ async function compareSync(envPath, examplePath) {
22
+ const envContent = await readFile(envPath);
23
+ const exampleContent = await readFile(examplePath);
24
+ const envParsed = parseToVars(envContent);
25
+ const exampleParsed = parseToVars(exampleContent);
26
+ return compareValues(envParsed.vars, exampleParsed.vars);
27
+ }
28
+ function compareValues(envVars, exampleVars) {
29
+ const envKeys = new Set(Object.keys(envVars));
30
+ const exampleKeys = new Set(Object.keys(exampleVars));
31
+ const missing = [];
32
+ const extra = [];
33
+ const different = [];
34
+ const same = [];
35
+ for (const key of exampleKeys) {
36
+ if (!envKeys.has(key)) {
37
+ missing.push(key);
38
+ }
39
+ }
40
+ for (const key of envKeys) {
41
+ if (!exampleKeys.has(key)) {
42
+ extra.push(key);
43
+ }
44
+ }
45
+ for (const key of envKeys) {
46
+ if (!exampleKeys.has(key)) continue;
47
+ const envValue = envVars[key];
48
+ const exampleValue = exampleVars[key];
49
+ if (envValue === exampleValue) {
50
+ same.push(key);
51
+ } else {
52
+ different.push(key);
53
+ }
54
+ }
55
+ missing.sort();
56
+ extra.sort();
57
+ different.sort();
58
+ same.sort();
59
+ const inSync = missing.length === 0 && extra.length === 0;
60
+ return {
61
+ inSync,
62
+ missing,
63
+ extra,
64
+ different,
65
+ same
66
+ };
67
+ }
68
+ function formatSyncDiff(diff) {
69
+ const lines = [];
70
+ if (diff.inSync) {
71
+ lines.push("\u2713 .env is in sync with .env.example");
72
+ } else {
73
+ lines.push("\u2717 .env is out of sync with .env.example");
74
+ }
75
+ if (diff.missing.length > 0) {
76
+ lines.push("");
77
+ lines.push(`Missing (${diff.missing.length}):`);
78
+ for (const key of diff.missing) {
79
+ lines.push(` - ${key}`);
80
+ }
81
+ }
82
+ if (diff.extra.length > 0) {
83
+ lines.push("");
84
+ lines.push(`Extra (${diff.extra.length}):`);
85
+ for (const key of diff.extra) {
86
+ lines.push(` + ${key}`);
87
+ }
88
+ }
89
+ if (diff.different.length > 0) {
90
+ lines.push("");
91
+ lines.push(`Different (${diff.different.length}):`);
92
+ for (const key of diff.different) {
93
+ lines.push(` ~ ${key}`);
94
+ }
95
+ }
96
+ if (diff.same.length > 0 && diff.inSync) {
97
+ lines.push("");
98
+ lines.push(`${diff.same.length} variable(s) matched.`);
99
+ }
100
+ return lines.join("\n");
101
+ }
102
+
103
+ export {
104
+ compareSync,
105
+ compareValues,
106
+ formatSyncDiff
107
+ };
@@ -0,0 +1,48 @@
1
+ import {
2
+ compareSync
3
+ } from "./chunk-YVWLXFUT.js";
4
+ import "./chunk-HFXQGJY3.js";
5
+ import {
6
+ writeJson
7
+ } from "./chunk-YN2KGTCB.js";
8
+ import {
9
+ exists
10
+ } from "./chunk-3VYXPTYV.js";
11
+ import "./chunk-5G2DU52U.js";
12
+
13
+ // src/cli/commands/ci-check-sync.ts
14
+ import { resolve, join } from "path";
15
+ async function run(args, ctx) {
16
+ try {
17
+ const cwd = args.flags["--cwd"] ?? ctx.cwd;
18
+ const baseDir = resolve(cwd);
19
+ const envPath = args.flags["--file"] ?? join(baseDir, ".env");
20
+ const examplePath = args.flags["--example"] ?? join(baseDir, ".env.example");
21
+ const envExists = await exists(envPath);
22
+ const exampleExists = await exists(examplePath);
23
+ if (!envExists) {
24
+ writeJson({ inSync: false, error: ".env not found" });
25
+ return 1;
26
+ }
27
+ if (!exampleExists) {
28
+ writeJson({ inSync: false, error: ".env.example not found" });
29
+ return 1;
30
+ }
31
+ const diff = await compareSync(envPath, examplePath);
32
+ writeJson({
33
+ inSync: diff.inSync,
34
+ missing: diff.missing,
35
+ extra: diff.extra,
36
+ different: diff.different,
37
+ same: diff.same
38
+ });
39
+ return diff.inSync ? 0 : 1;
40
+ } catch (error) {
41
+ const msg = error instanceof Error ? error.message : String(error);
42
+ writeJson({ inSync: false, error: msg });
43
+ return 1;
44
+ }
45
+ }
46
+ export {
47
+ run
48
+ };
@@ -0,0 +1,41 @@
1
+ import {
2
+ formatScanResult,
3
+ scan
4
+ } from "./chunk-MSXMESFP.js";
5
+ import "./chunk-R7PZRSZ7.js";
6
+ import "./chunk-TE7HPLA6.js";
7
+
8
+ // src/cli/commands/ci-scan.ts
9
+ import { resolve } from "path";
10
+ async function run(args, ctx) {
11
+ const cwd = args.flags["--cwd"] ?? ctx.cwd;
12
+ const baseDir = resolve(cwd);
13
+ const outputFormat = args.flags["--format"] ?? "sarif";
14
+ try {
15
+ const result = await scan({
16
+ cwd: baseDir,
17
+ paths: args.positional.length > 0 ? args.positional : void 0,
18
+ scanGitHistory: args.flags["--git-history"] ?? false,
19
+ failFast: args.flags["--fail-fast"] ?? true,
20
+ outputFormat
21
+ });
22
+ const formatted = formatScanResult(
23
+ result,
24
+ outputFormat
25
+ );
26
+ process.stdout.write(formatted + "\n");
27
+ return result.found ? 1 : 0;
28
+ } catch (error) {
29
+ const msg = error instanceof Error ? error.message : String(error);
30
+ if (outputFormat === "sarif" || outputFormat === "json") {
31
+ process.stdout.write(JSON.stringify({ error: msg }) + "\n");
32
+ } else {
33
+ process.stderr.write(`Error: ${msg}
34
+ `);
35
+ }
36
+ return 1;
37
+ }
38
+ }
39
+ export {
40
+ run
41
+ };
@@ -0,0 +1,135 @@
1
+ import {
2
+ bold,
3
+ cyan,
4
+ green,
5
+ red,
6
+ yellow
7
+ } from "./chunk-OMAOROL4.js";
8
+ import {
9
+ writeError,
10
+ writeLine
11
+ } from "./chunk-YN2KGTCB.js";
12
+ import {
13
+ ensureDir,
14
+ exists,
15
+ writeFile
16
+ } from "./chunk-3VYXPTYV.js";
17
+ import "./chunk-5G2DU52U.js";
18
+
19
+ // src/cli/commands/ci-setup.ts
20
+ import { resolve, join } from "path";
21
+ var GITHUB_ACTIONS_TEMPLATE = `name: Ultraenv CI
22
+
23
+ on:
24
+ push:
25
+ branches: [main]
26
+ pull_request:
27
+ branches: [main]
28
+
29
+ jobs:
30
+ validate:
31
+ runs-on: ubuntu-latest
32
+ steps:
33
+ - uses: actions/checkout@v4
34
+
35
+ - name: Setup Node.js
36
+ uses: actions/setup-node@v4
37
+ with:
38
+ node-version: '20'
39
+
40
+ - name: Install ultraenv
41
+ run: npm install -g ultraenv
42
+
43
+ - name: Validate environment
44
+ run: ultraenv ci validate --strict
45
+
46
+ - name: Check .env sync
47
+ run: ultraenv ci check-sync
48
+
49
+ - name: Scan for secrets
50
+ run: ultraenv ci scan --format sarif --output results.sarif
51
+ continue-on-error: true
52
+
53
+ - name: Upload SARIF results
54
+ if: always()
55
+ uses: github/codeql-action/upload-sarif@v3
56
+ with:
57
+ sarif_file: results.sarif
58
+ continue-on-error: true
59
+ `;
60
+ var GITLAB_CI_TEMPLATE = `stages:
61
+ - validate
62
+ - scan
63
+
64
+ variables:
65
+ NODE_VERSION: "20"
66
+
67
+ .validate-env:
68
+ stage: validate
69
+ image: node:\${NODE_VERSION}
70
+ before_script:
71
+ - npm install -g ultraenv
72
+ script:
73
+ - ultraenv ci validate --strict
74
+ - ultraenv ci check-sync
75
+
76
+ .scan-secrets:
77
+ stage: scan
78
+ image: node:\${NODE_VERSION}
79
+ before_script:
80
+ - npm install -g ultraenv
81
+ script:
82
+ - ultraenv ci scan --format json > scan-results.json
83
+ artifacts:
84
+ paths:
85
+ - scan-results.json
86
+ when: always
87
+ `;
88
+ async function run(args, ctx) {
89
+ try {
90
+ const cwd = args.flags["--cwd"] ?? ctx.cwd;
91
+ const baseDir = resolve(cwd);
92
+ const platform = args.flags["--platform"] ?? "github";
93
+ writeLine(bold("\u{1F527} Generating CI configuration"));
94
+ writeLine("");
95
+ if (platform === "github") {
96
+ const workflowsDir = join(baseDir, ".github", "workflows");
97
+ await ensureDir(workflowsDir);
98
+ const workflowPath = join(workflowsDir, "ultraenv.yml");
99
+ if (await exists(workflowPath) && !args.flags["--force"]) {
100
+ writeLine(yellow(` ${workflowPath} already exists. Use --force to overwrite.`));
101
+ return 0;
102
+ }
103
+ await writeFile(workflowPath, GITHUB_ACTIONS_TEMPLATE);
104
+ writeLine(green(` \u2713 Created ${workflowPath}`));
105
+ } else if (platform === "gitlab") {
106
+ const gitlabPath = join(baseDir, ".gitlab-ci.yml");
107
+ if (await exists(gitlabPath) && !args.flags["--force"]) {
108
+ writeLine(yellow(` ${gitlabPath} already exists. Use --force to overwrite.`));
109
+ return 0;
110
+ }
111
+ await writeFile(gitlabPath, GITLAB_CI_TEMPLATE);
112
+ writeLine(green(` \u2713 Created ${gitlabPath}`));
113
+ } else {
114
+ writeError(red(` Unknown platform: ${platform}`));
115
+ writeError(yellow(" Supported: github, gitlab"));
116
+ return 1;
117
+ }
118
+ writeLine("");
119
+ writeLine(green(bold(" \u2705 CI configuration generated!")));
120
+ writeLine("");
121
+ writeLine(cyan(" The CI pipeline will:"));
122
+ writeLine(" 1. Validate environment variables");
123
+ writeLine(" 2. Check .env \u2194 .env.example sync");
124
+ writeLine(" 3. Scan for leaked secrets");
125
+ writeLine("");
126
+ return 0;
127
+ } catch (error) {
128
+ const msg = error instanceof Error ? error.message : String(error);
129
+ writeError(red(` Error: ${msg}`));
130
+ return 1;
131
+ }
132
+ }
133
+ export {
134
+ run
135
+ };
@@ -0,0 +1,57 @@
1
+ import {
2
+ loadWithResult
3
+ } from "./chunk-MNVFG7H4.js";
4
+ import "./chunk-HFXQGJY3.js";
5
+ import {
6
+ writeJson
7
+ } from "./chunk-YN2KGTCB.js";
8
+ import "./chunk-3VYXPTYV.js";
9
+ import "./chunk-XC65ORJ5.js";
10
+ import "./chunk-5G2DU52U.js";
11
+
12
+ // src/cli/commands/ci-validate.ts
13
+ async function run(args, ctx) {
14
+ try {
15
+ const strict = args.flags["--strict"];
16
+ const envDir = args.flags["--env-dir"] ?? ctx.config.envDir;
17
+ const result = loadWithResult({
18
+ envDir,
19
+ expandVariables: ctx.config.expandVariables,
20
+ overrideProcessEnv: false,
21
+ mergeStrategy: ctx.config.mergeStrategy
22
+ });
23
+ const warnings = [];
24
+ const errors = [];
25
+ if (result.metadata.totalVars === 0) {
26
+ errors.push("No environment variables loaded");
27
+ }
28
+ for (const [key, value] of Object.entries(result.env)) {
29
+ if (value === "" && strict) {
30
+ errors.push(`Empty value: ${key}`);
31
+ } else if (value === "") {
32
+ warnings.push(`Empty value: ${key}`);
33
+ }
34
+ }
35
+ const valid = errors.length === 0;
36
+ const output = {
37
+ valid,
38
+ errors,
39
+ warnings,
40
+ metadata: {
41
+ totalVars: result.metadata.totalVars,
42
+ filesParsed: result.metadata.filesParsed,
43
+ loadTimeMs: result.metadata.loadTimeMs
44
+ },
45
+ variables: Object.keys(result.env).length
46
+ };
47
+ writeJson(output);
48
+ return valid ? 0 : 1;
49
+ } catch (error) {
50
+ const msg = error instanceof Error ? error.message : String(error);
51
+ writeJson({ valid: false, errors: [msg], warnings: [] });
52
+ return 1;
53
+ }
54
+ }
55
+ export {
56
+ run
57
+ };