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,189 @@
1
+ import {
2
+ base64ToBuffer,
3
+ bufferToBase64,
4
+ deriveKey,
5
+ encryptValue
6
+ } from "./chunk-2USZPWLZ.js";
7
+ import {
8
+ DEFAULT_KEY_LENGTH,
9
+ DEFAULT_SALT_LENGTH,
10
+ KEY_PREFIX
11
+ } from "./chunk-XC65ORJ5.js";
12
+ import {
13
+ EncryptionError
14
+ } from "./chunk-5G2DU52U.js";
15
+
16
+ // src/vault/key-manager.ts
17
+ import { randomBytes } from "crypto";
18
+ var HKDF_SALT = Buffer.from("ultraenv", "utf-8");
19
+ var HKDF_INFO_PREFIX = "ultraenv-environment:";
20
+ function generateMasterKey() {
21
+ return randomBytes(DEFAULT_KEY_LENGTH);
22
+ }
23
+ function deriveEnvironmentKey(masterKey, environment) {
24
+ if (masterKey.length !== DEFAULT_KEY_LENGTH) {
25
+ throw new EncryptionError(
26
+ `Invalid master key length: expected ${DEFAULT_KEY_LENGTH} bytes, got ${masterKey.length}`,
27
+ { hint: "Generate a new master key using generateMasterKey()." }
28
+ );
29
+ }
30
+ if (environment.length === 0) {
31
+ throw new EncryptionError(
32
+ "Environment name cannot be empty",
33
+ { hint: 'Provide a valid environment name (e.g., "development", "production").' }
34
+ );
35
+ }
36
+ if (HKDF_SALT.length < DEFAULT_SALT_LENGTH) {
37
+ const paddedSalt = Buffer.alloc(DEFAULT_SALT_LENGTH);
38
+ HKDF_SALT.copy(paddedSalt, 0);
39
+ return deriveKey(
40
+ masterKey,
41
+ paddedSalt,
42
+ `${HKDF_INFO_PREFIX}${environment}`,
43
+ DEFAULT_KEY_LENGTH
44
+ );
45
+ }
46
+ return deriveKey(
47
+ masterKey,
48
+ HKDF_SALT,
49
+ `${HKDF_INFO_PREFIX}${environment}`,
50
+ DEFAULT_KEY_LENGTH
51
+ );
52
+ }
53
+ function formatKey(key) {
54
+ if (key.length === 0) {
55
+ throw new EncryptionError("Cannot format an empty key");
56
+ }
57
+ const base64 = bufferToBase64(key);
58
+ return `${KEY_PREFIX}${base64}`;
59
+ }
60
+ function parseKey(formatted) {
61
+ if (!formatted.startsWith(KEY_PREFIX)) {
62
+ throw new EncryptionError(
63
+ `Invalid key format: expected prefix "${KEY_PREFIX}", got "${formatted.slice(0, KEY_PREFIX.length)}"`,
64
+ {
65
+ hint: "Ensure the key was generated by ultraenv and has not been modified. Expected format: ultraenv_key_v1_{base64}"
66
+ }
67
+ );
68
+ }
69
+ const base64Part = formatted.slice(KEY_PREFIX.length);
70
+ if (base64Part.length === 0) {
71
+ throw new EncryptionError(
72
+ "Invalid key format: base64 payload is empty after prefix",
73
+ { hint: "The key appears to be truncated. Generate a new key." }
74
+ );
75
+ }
76
+ try {
77
+ return base64ToBuffer(base64Part);
78
+ } catch (error) {
79
+ throw new EncryptionError(
80
+ "Failed to decode key: invalid base64 encoding",
81
+ {
82
+ cause: error instanceof Error ? error : void 0,
83
+ hint: 'The key may be corrupted. Generate a new key with "ultraenv key generate".'
84
+ }
85
+ );
86
+ }
87
+ }
88
+ function isValidKeyFormat(formatted) {
89
+ if (typeof formatted !== "string") return false;
90
+ if (formatted.length <= KEY_PREFIX.length) return false;
91
+ if (!formatted.startsWith(KEY_PREFIX)) return false;
92
+ const base64Part = formatted.slice(KEY_PREFIX.length);
93
+ if (base64Part.length === 0) return false;
94
+ try {
95
+ const decoded = base64ToBuffer(base64Part);
96
+ return decoded.length >= 16;
97
+ } catch {
98
+ return false;
99
+ }
100
+ }
101
+ function maskKey(formatted) {
102
+ if (formatted.length <= 14) {
103
+ return "***";
104
+ }
105
+ const visibleStart = 8;
106
+ const visibleEnd = 4;
107
+ const maskedLength = formatted.length - visibleStart - visibleEnd;
108
+ if (maskedLength <= 0) {
109
+ return "***";
110
+ }
111
+ const start = formatted.slice(0, visibleStart);
112
+ const end = formatted.slice(-visibleEnd);
113
+ const mask = "*".repeat(maskedLength);
114
+ return `${start}${mask}${end}`;
115
+ }
116
+ function generateKeysFile(environments) {
117
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
118
+ const lines = [
119
+ "# ultraenv encryption keys \u2014 DO NOT COMMIT",
120
+ `# Generated: ${timestamp}`,
121
+ "#",
122
+ "# Each environment has a unique key derived from the master key.",
123
+ "# Store this file securely and add it to .gitignore.",
124
+ ""
125
+ ];
126
+ for (const env of environments) {
127
+ const varName = `ULTRAENV_KEY_${env.toUpperCase()}`;
128
+ lines.push(`# Key for "${env}" environment`);
129
+ lines.push(`${varName}=""`);
130
+ lines.push("");
131
+ }
132
+ if (lines[lines.length - 1] === "") {
133
+ lines.pop();
134
+ }
135
+ return lines.join("\n");
136
+ }
137
+ function parseKeysFile(content) {
138
+ const result = /* @__PURE__ */ new Map();
139
+ const lines = content.split("\n");
140
+ for (let i = 0; i < lines.length; i++) {
141
+ const line = lines[i].trim();
142
+ if (line.length === 0 || line.startsWith("#")) continue;
143
+ const eqMatch = line.match(/^ULTRAENV_KEY_([A-Za-z0-9_]+)="(.*)"$/);
144
+ if (!eqMatch) {
145
+ const plainMatch = line.match(/^ULTRAENV_KEY_([A-Za-z0-9_]+)=(.*)$/);
146
+ if (!plainMatch) {
147
+ throw new EncryptionError(
148
+ `Invalid keys file format at line ${i + 1}: "${line}"`,
149
+ {
150
+ hint: 'Each key entry should be in the format: ULTRAENV_KEY_{ENVIRONMENT}="ultraenv_key_v1_..."'
151
+ }
152
+ );
153
+ }
154
+ const envName2 = plainMatch[1].toLowerCase();
155
+ const keyValue2 = plainMatch[2];
156
+ result.set(envName2, keyValue2);
157
+ continue;
158
+ }
159
+ const envName = eqMatch[1].toLowerCase();
160
+ const keyValue = eqMatch[2];
161
+ result.set(envName, keyValue);
162
+ }
163
+ return result;
164
+ }
165
+ function rotateKey(oldKey, newData, newKey) {
166
+ if (oldKey.length !== DEFAULT_KEY_LENGTH) {
167
+ throw new EncryptionError(
168
+ `Invalid old key length: expected ${DEFAULT_KEY_LENGTH} bytes, got ${oldKey.length}`
169
+ );
170
+ }
171
+ if (newKey.length !== DEFAULT_KEY_LENGTH) {
172
+ throw new EncryptionError(
173
+ `Invalid new key length: expected ${DEFAULT_KEY_LENGTH} bytes, got ${newKey.length}`
174
+ );
175
+ }
176
+ return encryptValue(newData, newKey);
177
+ }
178
+
179
+ export {
180
+ generateMasterKey,
181
+ deriveEnvironmentKey,
182
+ formatKey,
183
+ parseKey,
184
+ isValidKeyFormat,
185
+ maskKey,
186
+ generateKeysFile,
187
+ parseKeysFile,
188
+ rotateKey
189
+ };
@@ -0,0 +1,128 @@
1
+ // src/cli/ui/table.ts
2
+ var DEFAULT_OPTIONS = {
3
+ maxWidth: 0,
4
+ padding: 1,
5
+ align: "left"
6
+ };
7
+ function wrapText(text, width) {
8
+ const rawLines = text.split("\n");
9
+ const wrappedLines = [];
10
+ for (const rawLine of rawLines) {
11
+ if (width <= 0 || rawLine.length <= width) {
12
+ wrappedLines.push(rawLine);
13
+ continue;
14
+ }
15
+ let remaining = rawLine;
16
+ while (remaining.length > width) {
17
+ let breakAt = width;
18
+ const spaceIdx = remaining.lastIndexOf(" ", width);
19
+ if (spaceIdx > width * 0.4) {
20
+ breakAt = spaceIdx;
21
+ }
22
+ wrappedLines.push(remaining.slice(0, breakAt));
23
+ remaining = remaining.slice(breakAt).trimStart();
24
+ }
25
+ if (remaining.length > 0) {
26
+ wrappedLines.push(remaining);
27
+ }
28
+ }
29
+ return wrappedLines;
30
+ }
31
+ function alignText(text, width, alignment) {
32
+ const diff = width - text.length;
33
+ if (diff <= 0) return text;
34
+ switch (alignment) {
35
+ case "right":
36
+ return " ".repeat(diff) + text;
37
+ case "center": {
38
+ const left = Math.floor(diff / 2);
39
+ const right = diff - left;
40
+ return " ".repeat(left) + text + " ".repeat(right);
41
+ }
42
+ case "left":
43
+ default:
44
+ return text + " ".repeat(diff);
45
+ }
46
+ }
47
+ function calculateColumnWidths(headers, rows) {
48
+ const colCount = headers.length;
49
+ const widths = [];
50
+ for (let col = 0; col < colCount; col++) {
51
+ let maxWidth = (headers[col] ?? "").length;
52
+ for (const row of rows) {
53
+ const cellText = row[col] ?? "";
54
+ for (const line of cellText.split("\n")) {
55
+ if (line.length > maxWidth) {
56
+ maxWidth = line.length;
57
+ }
58
+ }
59
+ }
60
+ widths.push(maxWidth);
61
+ }
62
+ return widths;
63
+ }
64
+ function drawTable(headers, rows, options) {
65
+ const opts = { ...DEFAULT_OPTIONS, ...options };
66
+ const paddingStr = " ".repeat(opts.padding);
67
+ const naturalWidths = calculateColumnWidths(headers, rows);
68
+ let colWidths = naturalWidths;
69
+ if (opts.maxWidth > 0) {
70
+ const totalPadding = (headers.length * 2 + (headers.length - 1)) * opts.padding;
71
+ const separatorWidth = headers.length - 1 + 2;
72
+ const availableWidth = opts.maxWidth - totalPadding - separatorWidth;
73
+ if (availableWidth > 0) {
74
+ const avgWidth = Math.floor(availableWidth / headers.length);
75
+ colWidths = naturalWidths.map((w) => Math.min(w, Math.max(avgWidth, 4)));
76
+ }
77
+ }
78
+ const wrappedHeaders = headers.map(
79
+ (h, i) => wrapText(h, colWidths[i] ?? 8)
80
+ );
81
+ const wrappedRows = rows.map(
82
+ (row) => row.map(
83
+ (cell, i) => wrapText(cell, colWidths[i] ?? 8)
84
+ )
85
+ );
86
+ const maxHeaderLines = Math.max(...wrappedHeaders.map((lines2) => lines2.length));
87
+ const maxRowLines = rows.length > 0 ? Math.max(...wrappedRows.map(
88
+ (row) => Math.max(...row.map((cell) => cell.length))
89
+ )) : 1;
90
+ const maxLines = Math.max(maxHeaderLines, maxRowLines);
91
+ const lines = [];
92
+ const separatorParts = colWidths.map((w) => "\u2500".repeat(w + opts.padding * 2));
93
+ const separator = `\u250C${separatorParts.join("\u252C")}\u2510`;
94
+ const headerSep = `\u251C${separatorParts.join("\u253C")}\u2524`;
95
+ const bottomSep = `\u2514${separatorParts.join("\u2534")}\u2518`;
96
+ lines.push(separator);
97
+ for (let lineIdx = 0; lineIdx < maxLines; lineIdx++) {
98
+ const parts = [];
99
+ for (let col = 0; col < headers.length; col++) {
100
+ const cellLines = wrappedHeaders[col] ?? [""];
101
+ const cellText = cellLines[lineIdx] ?? "";
102
+ const colWidth = colWidths[col] ?? 8;
103
+ const aligned = alignText(cellText, colWidth, opts.align);
104
+ parts.push(`${paddingStr}${aligned}${paddingStr}`);
105
+ }
106
+ lines.push(`\u2502${parts.join("\u2502")}\u2502`);
107
+ }
108
+ lines.push(headerSep);
109
+ for (const wrappedRow of wrappedRows) {
110
+ for (let lineIdx = 0; lineIdx < maxLines; lineIdx++) {
111
+ const parts = [];
112
+ for (let col = 0; col < headers.length; col++) {
113
+ const cellLines = wrappedRow[col] ?? [""];
114
+ const cellText = cellLines[lineIdx] ?? "";
115
+ const colWidth = colWidths[col] ?? 8;
116
+ const aligned = alignText(cellText, colWidth, opts.align);
117
+ parts.push(`${paddingStr}${aligned}${paddingStr}`);
118
+ }
119
+ lines.push(`\u2502${parts.join("\u2502")}\u2502`);
120
+ }
121
+ }
122
+ lines.push(bottomSep);
123
+ return lines.join("\n");
124
+ }
125
+
126
+ export {
127
+ drawTable
128
+ };
@@ -0,0 +1,70 @@
1
+ // src/core/constants.ts
2
+ var VERSION = "1.0.0";
3
+ var DEFAULT_ENV_DIR = ".";
4
+ var ENCODING = "utf-8";
5
+ var MAX_INTERPOLATION_DEPTH = 10;
6
+ var MAX_VALUE_LENGTH = 1048576;
7
+ var ENCRYPTION_ALGORITHM = "aes-256-gcm";
8
+ var KEY_PREFIX = "ultraenv_key_v1_";
9
+ var ENCRYPTED_PREFIX = "encrypted:v1:aes-256-gcm:";
10
+ var KNOWN_ENV_ORDER = [
11
+ ".env" /* Env */,
12
+ ".env.local" /* EnvLocal */,
13
+ ".env.development" /* EnvDevelopment */,
14
+ ".env.development.local" /* EnvDevelopmentLocal */,
15
+ ".env.test" /* EnvTest */,
16
+ ".env.test.local" /* EnvTestLocal */,
17
+ ".env.production" /* EnvProduction */,
18
+ ".env.production.local" /* EnvProductionLocal */,
19
+ ".env.staging" /* EnvStaging */,
20
+ ".env.staging.local" /* EnvStagingLocal */,
21
+ ".env.ci" /* EnvCI */
22
+ ];
23
+ var DEFAULT_GITIGNORE_ENTRIES = [
24
+ "",
25
+ "# ultraenv \u2014 auto-generated entries",
26
+ ".env.vault",
27
+ ".env.keys",
28
+ ".env.*.local",
29
+ "",
30
+ "# End ultraenv entries"
31
+ ];
32
+ var ENVIRONMENT_VARIABLES = [
33
+ "NODE_ENV",
34
+ "APP_ENV",
35
+ "ENVIRONMENT",
36
+ "ENV",
37
+ "STAGE",
38
+ "ULTRAENV_ENV"
39
+ ];
40
+ var DEFAULT_KEY_LENGTH = 32;
41
+ var DEFAULT_SALT_LENGTH = 16;
42
+ var BANNER = `
43
+ \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557
44
+ \u2551 \u2551
45
+ \u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557 \u2551
46
+ \u2551 \u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2551 \u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u2588\u2588\u2554\u255D \u2551
47
+ \u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2554\u255D \u2588\u2588\u2588\u2588\u2588\u2554\u255D \u2551
48
+ \u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u255A\u2550\u2550\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2588\u2588\u2557 \u2588\u2588\u2554\u2550\u2588\u2588\u2557 \u2551
49
+ \u2551 \u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2557 \u2551
50
+ \u2551 \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D \u2551
51
+ \u2551 \u2551
52
+ \u2551 The Ultimate Environment Variable Manager \u2551
53
+ \u2551 v${VERSION.padEnd(42)}\u2551
54
+ \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D
55
+ `.trimStart();
56
+
57
+ export {
58
+ VERSION,
59
+ DEFAULT_ENV_DIR,
60
+ ENCODING,
61
+ MAX_INTERPOLATION_DEPTH,
62
+ MAX_VALUE_LENGTH,
63
+ ENCRYPTION_ALGORITHM,
64
+ KEY_PREFIX,
65
+ ENCRYPTED_PREFIX,
66
+ DEFAULT_GITIGNORE_ENTRIES,
67
+ ENVIRONMENT_VARIABLES,
68
+ DEFAULT_KEY_LENGTH,
69
+ DEFAULT_SALT_LENGTH
70
+ };
@@ -0,0 +1,118 @@
1
+ import {
2
+ writeFile
3
+ } from "./chunk-3VYXPTYV.js";
4
+
5
+ // src/typegen/module.ts
6
+ var DEFAULT_HEADER = "// Auto-generated by ultraenv \u2014 DO NOT EDIT";
7
+ function schemaToTsType(schema) {
8
+ const r = schema;
9
+ const schemaType = r.type;
10
+ if (schemaType === "string") {
11
+ const enumValues = r.enum;
12
+ if (Array.isArray(enumValues) && enumValues.length > 0) {
13
+ return enumValues.map((v) => `'${v}'`).join(" | ");
14
+ }
15
+ return "string";
16
+ }
17
+ if (schemaType === "number") return "number";
18
+ if (schemaType === "boolean") return "boolean";
19
+ if (schemaType === "enum") {
20
+ const values = r.values;
21
+ if (Array.isArray(values) && values.length > 0) {
22
+ return values.map((v) => `'${v}'`).join(" | ");
23
+ }
24
+ return "string";
25
+ }
26
+ if (schemaType === "array") return "string[]";
27
+ if (schemaType === "json") return "Record<string, unknown>";
28
+ if (schemaType === "date") return "string";
29
+ if (schemaType === "bigint") return "bigint";
30
+ return "string";
31
+ }
32
+ function generateModuleJSDoc(key, schema) {
33
+ const r = schema;
34
+ const lines = ["/**"];
35
+ if (schema.description !== void 0) {
36
+ lines.push(` * ${schema.description}`);
37
+ } else {
38
+ lines.push(` * ${key}`);
39
+ }
40
+ if (r.isSecret === true) {
41
+ lines.push(" * @secret This value should be kept confidential");
42
+ }
43
+ const hasDefault = schema.default !== void 0 || r.hasDefault === true;
44
+ if (hasDefault) {
45
+ const rawDefault = r.rawDefaultValue;
46
+ const defaultDisplay = r.isSecret === true ? "[REDACTED]" : rawDefault ?? String(schema.default ?? "");
47
+ lines.push(` * @default ${defaultDisplay}`);
48
+ }
49
+ if (r.isDeprecated === true) {
50
+ const msg = r.deprecationMessage;
51
+ lines.push(` * @deprecated ${msg ?? "This variable is deprecated"}`);
52
+ }
53
+ if (r.type === "enum") {
54
+ const values = r.values;
55
+ if (Array.isArray(values) && values.length > 0) {
56
+ lines.push(` * @enum {${values.map((v) => `'${v}'`).join("|")}}`);
57
+ }
58
+ }
59
+ lines.push(" */");
60
+ return lines.join("\n");
61
+ }
62
+ function isOptionalField(schema) {
63
+ const r = schema;
64
+ if (schema.optional === true) {
65
+ return true;
66
+ }
67
+ if (schema.default !== void 0) {
68
+ return false;
69
+ }
70
+ if (r.hasDefault === true) {
71
+ return false;
72
+ }
73
+ return false;
74
+ }
75
+ async function generateModule(schema, outputPath, options) {
76
+ const content = generateModuleContent(schema, options);
77
+ if (outputPath !== void 0) {
78
+ await writeFile(outputPath, content);
79
+ }
80
+ return content;
81
+ }
82
+ function generateModuleContent(schema, options) {
83
+ const includeJSDoc = options?.jsdoc ?? true;
84
+ const indent = options?.indent ?? 2;
85
+ const indentStr = " ".repeat(indent);
86
+ const header = options?.header ?? DEFAULT_HEADER;
87
+ const interfaceName = options?.interfaceName ?? "Env";
88
+ const exportAsDefault = options?.exportAsDefault ?? false;
89
+ const lines = [];
90
+ lines.push(header);
91
+ lines.push("");
92
+ if (exportAsDefault) {
93
+ lines.push("export default interface Env {");
94
+ } else {
95
+ lines.push(`export interface ${interfaceName} {`);
96
+ }
97
+ const sortedKeys = Object.keys(schema).sort();
98
+ for (const key of sortedKeys) {
99
+ const schemaEntry = schema[key];
100
+ if (schemaEntry === void 0) continue;
101
+ if (includeJSDoc) {
102
+ lines.push("");
103
+ lines.push(`${indentStr}${generateModuleJSDoc(key, schemaEntry)}`);
104
+ }
105
+ const tsType = schemaToTsType(schemaEntry);
106
+ const optional = isOptionalField(schemaEntry);
107
+ const optionalMarker = optional ? "?: " : ": ";
108
+ lines.push(`${indentStr}${key}${optionalMarker}${tsType};`);
109
+ }
110
+ lines.push("}");
111
+ lines.push("");
112
+ return lines.join("\n");
113
+ }
114
+
115
+ export {
116
+ generateModule,
117
+ generateModuleContent
118
+ };
@@ -0,0 +1,33 @@
1
+ // src/cli/ui/renderer.ts
2
+ var quietMode = false;
3
+ var debugMode = false;
4
+ var currentFormat = "terminal";
5
+ function configureRenderer(options) {
6
+ if (options.quiet !== void 0) {
7
+ quietMode = options.quiet;
8
+ }
9
+ if (options.debug !== void 0) {
10
+ debugMode = options.debug;
11
+ }
12
+ if (options.format !== void 0) {
13
+ currentFormat = options.format;
14
+ }
15
+ }
16
+ function writeLine(message) {
17
+ if (quietMode || currentFormat === "silent") return;
18
+ process.stdout.write(message + "\n");
19
+ }
20
+ function writeError(message) {
21
+ process.stderr.write(message + "\n");
22
+ }
23
+ function writeJson(data) {
24
+ if (quietMode || currentFormat === "silent") return;
25
+ process.stdout.write(JSON.stringify(data, null, 2) + "\n");
26
+ }
27
+
28
+ export {
29
+ configureRenderer,
30
+ writeLine,
31
+ writeError,
32
+ writeJson
33
+ };
@@ -0,0 +1,65 @@
1
+ // src/cli/ui/prompt.ts
2
+ import * as readline from "readline";
3
+ function createReadlineInterface() {
4
+ return readline.createInterface({
5
+ input: process.stdin,
6
+ output: process.stdout
7
+ });
8
+ }
9
+ function closeInterface(rl) {
10
+ rl.close();
11
+ }
12
+ function prompt(message, options) {
13
+ return new Promise((resolve) => {
14
+ const rl = createReadlineInterface();
15
+ const suffix = options?.default !== void 0 ? ` (${options.default})` : "";
16
+ const requiredMark = options?.required ? " *" : "";
17
+ rl.question(`${message}${suffix}${requiredMark}: `, (answer) => {
18
+ closeInterface(rl);
19
+ const trimmed = answer.trim();
20
+ if (options?.required && trimmed === "" && options.default === void 0) {
21
+ prompt(message, options).then(resolve);
22
+ return;
23
+ }
24
+ const value = trimmed === "" && options?.default !== void 0 ? options.default : trimmed;
25
+ if (options?.validate !== void 0) {
26
+ const error = options.validate(value);
27
+ if (error !== void 0) {
28
+ process.stderr.write(` ${error}
29
+ `);
30
+ prompt(message, options).then(resolve);
31
+ return;
32
+ }
33
+ }
34
+ resolve(value);
35
+ });
36
+ });
37
+ }
38
+ function confirm(message, defaultVal = true) {
39
+ return new Promise((resolve) => {
40
+ const rl = createReadlineInterface();
41
+ const hint = defaultVal ? "(Y/n)" : "(y/N)";
42
+ rl.question(`${message} ${hint}: `, (answer) => {
43
+ closeInterface(rl);
44
+ const trimmed = answer.trim().toLowerCase();
45
+ if (trimmed === "") {
46
+ resolve(defaultVal);
47
+ return;
48
+ }
49
+ if (trimmed === "y" || trimmed === "yes") {
50
+ resolve(true);
51
+ return;
52
+ }
53
+ if (trimmed === "n" || trimmed === "no") {
54
+ resolve(false);
55
+ return;
56
+ }
57
+ confirm(message, defaultVal).then(resolve);
58
+ });
59
+ });
60
+ }
61
+
62
+ export {
63
+ prompt,
64
+ confirm
65
+ };