ultraenv 1.0.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +67 -1857
- package/dist/{chunk-GC7RXHLA.js → chunk-2MBSLURI.js} +16 -17
- package/dist/{chunk-IGFVP24Q.js → chunk-3AF476D7.js} +1 -1
- package/dist/{chunk-N5PAV4NM.js → chunk-5WUBB633.js} +17 -26
- package/dist/{chunk-2USZPWLZ.js → chunk-6NFA23AY.js} +28 -39
- package/dist/{chunk-AWN6ADV7.js → chunk-6X3BUE5S.js} +45 -54
- package/dist/{chunk-NBOABPHM.js → chunk-72UKVOO5.js} +24 -40
- package/dist/{chunk-JB7RKV3C.js → chunk-7AHG2IP4.js} +1 -7
- package/dist/{chunk-6KS56D6E.js → chunk-7VJ7LK2M.js} +1 -1
- package/dist/{chunk-CIFMBJ4H.js → chunk-BNUHE2ZI.js} +57 -21
- package/dist/{chunk-HFXQGJY3.js → chunk-CVJPO3QY.js} +13 -27
- package/dist/{chunk-IKPTKALB.js → chunk-F7YSINGU.js} +1 -3
- package/dist/{chunk-3VYXPTYV.js → chunk-FSKVYBEP.js} +1 -1
- package/dist/{chunk-4XUYMRK5.js → chunk-GJC64ZG7.js} +4 -3
- package/dist/{chunk-YMMP4VQL.js → chunk-H3QEGEZ6.js} +1 -1
- package/dist/{chunk-CHVO6NWI.js → chunk-LFIKYFPS.js} +2 -2
- package/dist/{chunk-3UV2QNJL.js → chunk-LJSCUOD4.js} +19 -21
- package/dist/{chunk-YVWLXFUT.js → chunk-LQZK6BBQ.js} +2 -2
- package/dist/{chunk-5G2DU52U.js → chunk-N7GOHQBF.js} +7 -1
- package/dist/{chunk-MSXMESFP.js → chunk-OBLMAUCF.js} +8 -14
- package/dist/{chunk-UEWYFN6A.js → chunk-RJTUAMK3.js} +16 -29
- package/dist/{chunk-MNVFG7H4.js → chunk-XPZC32UY.js} +16 -25
- package/dist/{chunk-WMHN5RW2.js → chunk-YLGJQOMM.js} +3 -9
- package/dist/{ci-check-sync-VBMSVWIV.js → ci-check-sync-UO5PARKO.js} +4 -4
- package/dist/{ci-scan-24MT5XGS.js → ci-scan-5D7QBN5X.js} +2 -5
- package/dist/{ci-setup-C2NKEFRD.js → ci-setup-J34DS6KD.js} +2 -2
- package/dist/{ci-validate-7AW24LSQ.js → ci-validate-LWP5NBDN.js} +4 -4
- package/dist/cli/index.cjs +470 -390
- package/dist/cli/index.js +130 -55
- package/dist/comparator-AIRTWBOL.js +13 -0
- package/dist/{config-O5YRQP5Z.js → config-67GDO3CW.js} +3 -3
- package/dist/{debug-PTPXAF3K.js → debug-6VCX3QSP.js} +6 -6
- package/dist/{declaration-LEME4AFZ.js → declaration-YGOVZOXG.js} +3 -3
- package/dist/{doctor-FZAUPKHS.js → doctor-FF7QOTP2.js} +7 -5
- package/dist/{envs-compare-5K3HESX5.js → envs-compare-P7GPKGQX.js} +4 -4
- package/dist/{envs-create-2XXHXMGA.js → envs-create-ISG4SECU.js} +4 -4
- package/dist/{envs-list-NQM5252B.js → envs-list-PUW67HOC.js} +5 -5
- package/dist/{envs-switch-6L2AQYID.js → envs-switch-P4YDJ6LG.js} +4 -4
- package/dist/{envs-validate-FL73Q76T.js → envs-validate-VNKBKYO3.js} +6 -9
- package/dist/{fs-VH7ATUS3.js → fs-7HKOZY5K.js} +2 -2
- package/dist/{generator-LFZBMZZS.js → generator-O23ATCIY.js} +4 -4
- package/dist/{help-3XJBXEHE.js → help-THFLI6YT.js} +108 -26
- package/dist/index.cjs +295 -381
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +81 -100
- package/dist/{init-Y7JQ2KYJ.js → init-KBLVTHQW.js} +15 -11
- package/dist/{install-hook-SKXIV6NV.js → install-hook-42F22BLY.js} +2 -2
- package/dist/{json-schema-I26YNQBH.js → json-schema-YULPWDKA.js} +3 -3
- package/dist/{key-manager-O3G55WPU.js → key-manager-WDWPX3IQ.js} +3 -3
- package/dist/middleware/express.cjs +1 -3
- package/dist/middleware/express.js +1 -1
- package/dist/middleware/fastify.cjs +1 -7
- package/dist/middleware/fastify.js +1 -1
- package/dist/{module-IDIZPP4M.js → module-FGH2V6N2.js} +3 -3
- package/dist/{protect-NCWPM6VC.js → protect-A4G7LQFJ.js} +26 -24
- package/dist/{scan-TRLY36TT.js → scan-4BXGHR33.js} +1 -1
- package/dist/schema/index.cjs +57 -21
- package/dist/schema/index.js +1 -1
- package/dist/{sync-TMHMTLH2.js → sync-MYLMDDY6.js} +23 -14
- package/dist/{typegen-SQOSXBWM.js → typegen-GLBRHWSK.js} +17 -23
- package/dist/{validate-IOAM5HWS.js → validate-J73ETKXD.js} +5 -5
- package/dist/{vault-decrypt-U6HJZNBV.js → vault-decrypt-V3GY5HES.js} +7 -7
- package/dist/{vault-diff-B3ZOQTWI.js → vault-diff-QVE6S6KP.js} +5 -5
- package/dist/{vault-encrypt-GUSLCSKS.js → vault-encrypt-WUBY3OVF.js} +7 -7
- package/dist/{vault-init-GUBOTOUL.js → vault-init-EWSAED44.js} +5 -5
- package/dist/{vault-rekey-DAHT7JCN.js → vault-rekey-VODMGCNA.js} +7 -7
- package/dist/{vault-status-GDLRU2OK.js → vault-status-YXDK6O7X.js} +4 -4
- package/dist/{vault-verify-CD76FJSF.js → vault-verify-SSXGTVBK.js} +7 -7
- package/package.json +1 -1
- package/dist/comparator-RDKX3OI7.js +0 -13
package/dist/index.cjs
CHANGED
|
@@ -470,7 +470,13 @@ var FileSystemError = class extends UltraenvError {
|
|
|
470
470
|
code;
|
|
471
471
|
constructor(message, options = {}) {
|
|
472
472
|
const fsCode = options.code ?? options.cause?.code ?? "UNKNOWN";
|
|
473
|
-
const opHint = options.path !== void 0 ?
|
|
473
|
+
const opHint = options.path !== void 0 ? (
|
|
474
|
+
/* v8 ignore start */
|
|
475
|
+
`Could not ${options.operation ?? "access"} "${options.path}".`
|
|
476
|
+
) : (
|
|
477
|
+
/* v8 ignore stop */
|
|
478
|
+
""
|
|
479
|
+
);
|
|
474
480
|
super(message, {
|
|
475
481
|
code: `FS_${fsCode}`,
|
|
476
482
|
hint: options.hint ?? `${opHint} Ensure the file exists and you have the necessary permissions.`,
|
|
@@ -526,14 +532,11 @@ function resolveEscapeSequence(chars, startIndex, filePath, lineNumber) {
|
|
|
526
532
|
}
|
|
527
533
|
return { resolved: String.fromCodePoint(codePoint), charsConsumed: 4 };
|
|
528
534
|
}
|
|
529
|
-
throw new ParseError(
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
hint: "Hex escapes must be exactly 2 hex digits, e.g. \\x0A for newline."
|
|
535
|
-
}
|
|
536
|
-
);
|
|
535
|
+
throw new ParseError(`Invalid hex escape sequence: ${"\\"}x${hex}`, {
|
|
536
|
+
line: lineNumber,
|
|
537
|
+
filePath,
|
|
538
|
+
hint: "Hex escapes must be exactly 2 hex digits, e.g. \\x0A for newline."
|
|
539
|
+
});
|
|
537
540
|
}
|
|
538
541
|
case "u":
|
|
539
542
|
case "U": {
|
|
@@ -548,14 +551,11 @@ function resolveEscapeSequence(chars, startIndex, filePath, lineNumber) {
|
|
|
548
551
|
}
|
|
549
552
|
return { resolved: String.fromCodePoint(codePoint), charsConsumed: 6 };
|
|
550
553
|
}
|
|
551
|
-
throw new ParseError(
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
hint: 'Unicode escapes must be exactly 4 hex digits, e.g. \\u0041 for "A".'
|
|
557
|
-
}
|
|
558
|
-
);
|
|
554
|
+
throw new ParseError(`Invalid unicode escape sequence: ${"\\"}u${hexDigits}`, {
|
|
555
|
+
line: lineNumber,
|
|
556
|
+
filePath,
|
|
557
|
+
hint: 'Unicode escapes must be exactly 4 hex digits, e.g. \\u0041 for "A".'
|
|
558
|
+
});
|
|
559
559
|
}
|
|
560
560
|
/* v8 ignore start */
|
|
561
561
|
default: {
|
|
@@ -837,11 +837,7 @@ function parseEnvFile(content, filePath) {
|
|
|
837
837
|
comment = trimmedAfter.slice(1).trim();
|
|
838
838
|
}
|
|
839
839
|
} else if (firstChar === "'") {
|
|
840
|
-
const result = parseSingleQuotedValue(
|
|
841
|
-
lines,
|
|
842
|
-
lineIndex,
|
|
843
|
-
valueStartIndex + 1
|
|
844
|
-
);
|
|
840
|
+
const result = parseSingleQuotedValue(lines, lineIndex, valueStartIndex + 1);
|
|
845
841
|
if (!result.closed) {
|
|
846
842
|
throw new ParseError("Unterminated single-quoted string", {
|
|
847
843
|
line: oneBasedLine,
|
|
@@ -862,11 +858,7 @@ function parseEnvFile(content, filePath) {
|
|
|
862
858
|
comment = trimmedAfter.slice(1).trim();
|
|
863
859
|
}
|
|
864
860
|
} else if (firstChar === "`") {
|
|
865
|
-
const result = parseBacktickQuotedValue(
|
|
866
|
-
lines,
|
|
867
|
-
lineIndex,
|
|
868
|
-
valueStartIndex + 1
|
|
869
|
-
);
|
|
861
|
+
const result = parseBacktickQuotedValue(lines, lineIndex, valueStartIndex + 1);
|
|
870
862
|
if (!result.closed) {
|
|
871
863
|
throw new ParseError("Unterminated backtick-quoted string", {
|
|
872
864
|
line: oneBasedLine,
|
|
@@ -1087,12 +1079,9 @@ function expandVariables(vars, env, options) {
|
|
|
1087
1079
|
const resolving = /* @__PURE__ */ new Set();
|
|
1088
1080
|
function expandValue(raw, depth) {
|
|
1089
1081
|
if (depth > maxDepth) {
|
|
1090
|
-
throw new InterpolationError(
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
hint: "Check for deeply nested variable references. Consider simplifying your variable definitions."
|
|
1094
|
-
}
|
|
1095
|
-
);
|
|
1082
|
+
throw new InterpolationError(`Maximum interpolation depth (${maxDepth}) exceeded`, {
|
|
1083
|
+
hint: "Check for deeply nested variable references. Consider simplifying your variable definitions."
|
|
1084
|
+
});
|
|
1096
1085
|
}
|
|
1097
1086
|
const result2 = [];
|
|
1098
1087
|
let i = 0;
|
|
@@ -1128,14 +1117,11 @@ function expandVariables(vars, env, options) {
|
|
|
1128
1117
|
const parsed = parseExpression(inner);
|
|
1129
1118
|
if (resolving.has(parsed.varName)) {
|
|
1130
1119
|
const chain = Array.from(resolving).concat(parsed.varName).join(" \u2192 ");
|
|
1131
|
-
throw new InterpolationError(
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
hint: "Break the cycle by removing one of the circular references."
|
|
1137
|
-
}
|
|
1138
|
-
);
|
|
1120
|
+
throw new InterpolationError(`Circular variable reference detected: ${chain}`, {
|
|
1121
|
+
variable: parsed.varName,
|
|
1122
|
+
circular: true,
|
|
1123
|
+
hint: "Break the cycle by removing one of the circular references."
|
|
1124
|
+
});
|
|
1139
1125
|
}
|
|
1140
1126
|
resolving.add(parsed.varName);
|
|
1141
1127
|
if (parsed.varName in vars && !(parsed.varName in resolvedMap)) {
|
|
@@ -1166,14 +1152,11 @@ function expandVariables(vars, env, options) {
|
|
|
1166
1152
|
const varName = raw.slice(i, nameEnd);
|
|
1167
1153
|
if (resolving.has(varName)) {
|
|
1168
1154
|
const chain = Array.from(resolving).concat(varName).join(" \u2192 ");
|
|
1169
|
-
throw new InterpolationError(
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
hint: "Break the cycle by removing one of the circular references."
|
|
1175
|
-
}
|
|
1176
|
-
);
|
|
1155
|
+
throw new InterpolationError(`Circular variable reference detected: ${chain}`, {
|
|
1156
|
+
variable: varName,
|
|
1157
|
+
circular: true,
|
|
1158
|
+
hint: "Break the cycle by removing one of the circular references."
|
|
1159
|
+
});
|
|
1177
1160
|
}
|
|
1178
1161
|
resolving.add(varName);
|
|
1179
1162
|
if (varName in vars && !(varName in resolvedMap)) {
|
|
@@ -1949,7 +1932,8 @@ function parseYamlScalar(value) {
|
|
|
1949
1932
|
if (cleanValue === "") return "";
|
|
1950
1933
|
if (cleanValue === "true" || cleanValue === "True" || cleanValue === "TRUE") return true;
|
|
1951
1934
|
if (cleanValue === "false" || cleanValue === "False" || cleanValue === "FALSE") return false;
|
|
1952
|
-
if (cleanValue === "null" || cleanValue === "Null" || cleanValue === "NULL" || cleanValue === "~")
|
|
1935
|
+
if (cleanValue === "null" || cleanValue === "Null" || cleanValue === "NULL" || cleanValue === "~")
|
|
1936
|
+
return null;
|
|
1953
1937
|
if (/^-?\d+$/.test(cleanValue)) return parseInt(cleanValue, 10);
|
|
1954
1938
|
if (/^-?\d+\.\d+$/.test(cleanValue)) return parseFloat(cleanValue);
|
|
1955
1939
|
if (cleanValue.startsWith('"') && cleanValue.endsWith('"') || cleanValue.startsWith("'") && cleanValue.endsWith("'")) {
|
|
@@ -2329,9 +2313,7 @@ function resolveVariables(vars, schema, aliasMap) {
|
|
|
2329
2313
|
result[key] = vars[key];
|
|
2330
2314
|
continue;
|
|
2331
2315
|
}
|
|
2332
|
-
const caseInsensitiveKey = Object.keys(vars).find(
|
|
2333
|
-
(k) => k.toLowerCase() === key.toLowerCase()
|
|
2334
|
-
);
|
|
2316
|
+
const caseInsensitiveKey = Object.keys(vars).find((k) => k.toLowerCase() === key.toLowerCase());
|
|
2335
2317
|
if (caseInsensitiveKey !== void 0 && vars[caseInsensitiveKey] !== void 0) {
|
|
2336
2318
|
result[key] = vars[caseInsensitiveKey];
|
|
2337
2319
|
continue;
|
|
@@ -2344,9 +2326,7 @@ function resolveVariables(vars, schema, aliasMap) {
|
|
|
2344
2326
|
foundAlias = true;
|
|
2345
2327
|
break;
|
|
2346
2328
|
}
|
|
2347
|
-
const ciAlias = Object.keys(vars).find(
|
|
2348
|
-
(k) => k.toLowerCase() === alias.toLowerCase()
|
|
2349
|
-
);
|
|
2329
|
+
const ciAlias = Object.keys(vars).find((k) => k.toLowerCase() === alias.toLowerCase());
|
|
2350
2330
|
if (ciAlias !== void 0 && vars[ciAlias] !== void 0) {
|
|
2351
2331
|
result[key] = vars[ciAlias];
|
|
2352
2332
|
foundAlias = true;
|
|
@@ -3496,7 +3476,10 @@ function parseAndValidateEmail(raw, opts) {
|
|
|
3496
3476
|
return { success: false, error: "Email must not be empty" };
|
|
3497
3477
|
}
|
|
3498
3478
|
if (trimmed.length > maxLen) {
|
|
3499
|
-
return {
|
|
3479
|
+
return {
|
|
3480
|
+
success: false,
|
|
3481
|
+
error: `Email must be at most ${maxLen} characters, got ${trimmed.length}`
|
|
3482
|
+
};
|
|
3500
3483
|
}
|
|
3501
3484
|
if (!EMAIL_REGEX2.test(trimmed)) {
|
|
3502
3485
|
return { success: false, error: `"${trimmed}" is not a valid email address` };
|
|
@@ -3505,7 +3488,10 @@ function parseAndValidateEmail(raw, opts) {
|
|
|
3505
3488
|
const localPart = trimmed.slice(0, atIndex);
|
|
3506
3489
|
const domain = trimmed.slice(atIndex + 1);
|
|
3507
3490
|
if (localPart.length > maxLocal) {
|
|
3508
|
-
return {
|
|
3491
|
+
return {
|
|
3492
|
+
success: false,
|
|
3493
|
+
error: `Email local part must be at most ${maxLocal} characters, got ${localPart.length}`
|
|
3494
|
+
};
|
|
3509
3495
|
}
|
|
3510
3496
|
if (opts.allowPlusAddressing === false && localPart.includes("+")) {
|
|
3511
3497
|
return { success: false, error: "Plus addressing (+) is not allowed" };
|
|
@@ -3514,7 +3500,10 @@ function parseAndValidateEmail(raw, opts) {
|
|
|
3514
3500
|
const tld = domain.split(".").pop() ?? "";
|
|
3515
3501
|
const allowed = opts.allowedTlds.map((t2) => t2.toLowerCase());
|
|
3516
3502
|
if (!allowed.includes(tld.toLowerCase())) {
|
|
3517
|
-
return {
|
|
3503
|
+
return {
|
|
3504
|
+
success: false,
|
|
3505
|
+
error: `Email TLD must be one of: ${allowed.join(", ")}. Got ".${tld}"`
|
|
3506
|
+
};
|
|
3518
3507
|
}
|
|
3519
3508
|
}
|
|
3520
3509
|
if (opts.blockedDomains !== void 0) {
|
|
@@ -3549,7 +3538,10 @@ function parseAndValidateIp(raw, opts) {
|
|
|
3549
3538
|
}
|
|
3550
3539
|
if (version === "6" && !isV6) {
|
|
3551
3540
|
if (opts.allowMappedV4 === false && isMappedV4) {
|
|
3552
|
-
return {
|
|
3541
|
+
return {
|
|
3542
|
+
success: false,
|
|
3543
|
+
error: `"${trimmed}" is an IPv4-mapped IPv6 address, which is not allowed`
|
|
3544
|
+
};
|
|
3553
3545
|
}
|
|
3554
3546
|
return { success: false, error: `"${trimmed}" is not a valid IPv6 address` };
|
|
3555
3547
|
}
|
|
@@ -3557,7 +3549,10 @@ function parseAndValidateIp(raw, opts) {
|
|
|
3557
3549
|
return { success: false, error: `"${trimmed}" is not a valid IP address` };
|
|
3558
3550
|
}
|
|
3559
3551
|
if (version === "6" && isMappedV4 && opts.allowMappedV4 === false) {
|
|
3560
|
-
return {
|
|
3552
|
+
return {
|
|
3553
|
+
success: false,
|
|
3554
|
+
error: `"${trimmed}" is an IPv4-mapped IPv6 address, which is not allowed`
|
|
3555
|
+
};
|
|
3561
3556
|
}
|
|
3562
3557
|
return { success: true, value: trimmed };
|
|
3563
3558
|
}
|
|
@@ -3906,7 +3901,9 @@ function createBase64Schema(opts) {
|
|
|
3906
3901
|
var SEMVER_CORE = "(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)";
|
|
3907
3902
|
var SEMVER_PRERELEASE = "(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))";
|
|
3908
3903
|
var SEMVER_BUILD = "(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))";
|
|
3909
|
-
var STRICT_SEMVER_REGEX = new RegExp(
|
|
3904
|
+
var STRICT_SEMVER_REGEX = new RegExp(
|
|
3905
|
+
`^${SEMVER_CORE}(?:${SEMVER_PRERELEASE})?(?:${SEMVER_BUILD})?$`
|
|
3906
|
+
);
|
|
3910
3907
|
var LOOSE_SEMVER_REGEX = /^v?(0|[1-9]\d*)(?:\.(0|[1-9]\d*))?(?:\.(0|[1-9]\d*))?(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/;
|
|
3911
3908
|
function parseAndValidateSemver(raw, opts) {
|
|
3912
3909
|
const trimmed = raw.trim();
|
|
@@ -3928,7 +3925,9 @@ function parseAndValidateSemver(raw, opts) {
|
|
|
3928
3925
|
};
|
|
3929
3926
|
}
|
|
3930
3927
|
if (!loose) {
|
|
3931
|
-
const match = content.match(
|
|
3928
|
+
const match = content.match(
|
|
3929
|
+
new RegExp(`^${SEMVER_CORE}(?:${SEMVER_PRERELEASE})?(?:${SEMVER_BUILD})?$`)
|
|
3930
|
+
);
|
|
3932
3931
|
if (match) {
|
|
3933
3932
|
const prerelease = match[4];
|
|
3934
3933
|
const build = match[5];
|
|
@@ -4032,7 +4031,14 @@ function parseAndValidateCron(raw, opts) {
|
|
|
4032
4031
|
}
|
|
4033
4032
|
const fields = trimmed.split(/\s+/);
|
|
4034
4033
|
if (opts.allowSeconds === true && fields.length === 6) {
|
|
4035
|
-
const ranges = [
|
|
4034
|
+
const ranges = [
|
|
4035
|
+
[0, 59],
|
|
4036
|
+
[0, 59],
|
|
4037
|
+
[0, 23],
|
|
4038
|
+
[1, 31],
|
|
4039
|
+
[1, 12],
|
|
4040
|
+
[0, 6]
|
|
4041
|
+
];
|
|
4036
4042
|
for (let i = 0; i < fields.length; i++) {
|
|
4037
4043
|
const range = ranges[i] ?? [0, 59];
|
|
4038
4044
|
const error = validateCronField(fields[i] ?? "", range[0] ?? 0, range[1] ?? 0);
|
|
@@ -4041,7 +4047,14 @@ function parseAndValidateCron(raw, opts) {
|
|
|
4041
4047
|
return { success: true, value: trimmed };
|
|
4042
4048
|
}
|
|
4043
4049
|
if (opts.allowYear === true && fields.length === 6) {
|
|
4044
|
-
const ranges = [
|
|
4050
|
+
const ranges = [
|
|
4051
|
+
[0, 59],
|
|
4052
|
+
[0, 23],
|
|
4053
|
+
[1, 31],
|
|
4054
|
+
[1, 12],
|
|
4055
|
+
[0, 6],
|
|
4056
|
+
[1970, 2099]
|
|
4057
|
+
];
|
|
4045
4058
|
for (let i = 0; i < fields.length; i++) {
|
|
4046
4059
|
const range = ranges[i] ?? [0, 59];
|
|
4047
4060
|
const error = validateCronField(fields[i] ?? "", range[0] ?? 0, range[1] ?? 0);
|
|
@@ -4050,7 +4063,13 @@ function parseAndValidateCron(raw, opts) {
|
|
|
4050
4063
|
return { success: true, value: trimmed };
|
|
4051
4064
|
}
|
|
4052
4065
|
if (fields.length === 5) {
|
|
4053
|
-
const ranges = [
|
|
4066
|
+
const ranges = [
|
|
4067
|
+
[0, 59],
|
|
4068
|
+
[0, 23],
|
|
4069
|
+
[1, 31],
|
|
4070
|
+
[1, 12],
|
|
4071
|
+
[0, 6]
|
|
4072
|
+
];
|
|
4054
4073
|
for (let i = 0; i < fields.length; i++) {
|
|
4055
4074
|
const range = ranges[i] ?? [0, 59];
|
|
4056
4075
|
const error = validateCronField(fields[i] ?? "", range[0] ?? 0, range[1] ?? 0);
|
|
@@ -5639,10 +5658,8 @@ function defineEnv(schema, vars, options) {
|
|
|
5639
5658
|
const messages = result.errors.map((e) => ` - ${e.field}: ${e.message}`).join("\n");
|
|
5640
5659
|
const unknownMsg = result.unknown.length > 0 ? `
|
|
5641
5660
|
Unknown variables: ${result.unknown.join(", ")}` : "";
|
|
5642
|
-
throw new Error(
|
|
5643
|
-
|
|
5644
|
-
${messages}${unknownMsg}`
|
|
5645
|
-
);
|
|
5661
|
+
throw new Error(`Environment validation failed:
|
|
5662
|
+
${messages}${unknownMsg}`);
|
|
5646
5663
|
}
|
|
5647
5664
|
return result.values;
|
|
5648
5665
|
}
|
|
@@ -5789,11 +5806,15 @@ var EnvFileWatcher = class {
|
|
|
5789
5806
|
if (this.state.nativeWatchers.has(filePath)) return;
|
|
5790
5807
|
if (this.shouldIgnore(filePath)) return;
|
|
5791
5808
|
try {
|
|
5792
|
-
const nativeWatcher = (0, import_node_fs4.watch)(
|
|
5793
|
-
|
|
5794
|
-
|
|
5795
|
-
|
|
5796
|
-
|
|
5809
|
+
const nativeWatcher = (0, import_node_fs4.watch)(
|
|
5810
|
+
filePath,
|
|
5811
|
+
{
|
|
5812
|
+
persistent: true
|
|
5813
|
+
},
|
|
5814
|
+
(eventType, filename) => {
|
|
5815
|
+
this.handleFileEvent(eventType, filePath, filename);
|
|
5816
|
+
}
|
|
5817
|
+
);
|
|
5797
5818
|
nativeWatcher.on("error", () => {
|
|
5798
5819
|
this.emitChangeEvent(filePath);
|
|
5799
5820
|
this.state.nativeWatchers.delete(filePath);
|
|
@@ -5819,27 +5840,31 @@ var EnvFileWatcher = class {
|
|
|
5819
5840
|
const dirWatchKey = `__dir__:${dirPath}`;
|
|
5820
5841
|
if (this.state.nativeWatchers.has(dirWatchKey)) return;
|
|
5821
5842
|
try {
|
|
5822
|
-
const nativeWatcher = (0, import_node_fs4.watch)(
|
|
5823
|
-
|
|
5824
|
-
|
|
5825
|
-
|
|
5826
|
-
|
|
5827
|
-
|
|
5828
|
-
if (
|
|
5829
|
-
|
|
5830
|
-
|
|
5831
|
-
|
|
5832
|
-
|
|
5833
|
-
|
|
5834
|
-
|
|
5835
|
-
|
|
5836
|
-
this.state.nativeWatchers.
|
|
5843
|
+
const nativeWatcher = (0, import_node_fs4.watch)(
|
|
5844
|
+
dirPath,
|
|
5845
|
+
{
|
|
5846
|
+
persistent: true
|
|
5847
|
+
},
|
|
5848
|
+
(eventType, filename) => {
|
|
5849
|
+
if (filename === null) return;
|
|
5850
|
+
const fullPath = (0, import_node_path4.resolve)((0, import_node_path4.join)(dirPath, filename));
|
|
5851
|
+
if (isEnvFileName(filename) && !this.shouldIgnore(fullPath)) {
|
|
5852
|
+
if (eventType === "rename") {
|
|
5853
|
+
if ((0, import_node_fs5.existsSync)(fullPath) && !this.state.nativeWatchers.has(fullPath)) {
|
|
5854
|
+
this.watchFile(fullPath);
|
|
5855
|
+
this.debouncedEmit(fullPath, "add");
|
|
5856
|
+
} else if (!(0, import_node_fs5.existsSync)(fullPath) && this.state.nativeWatchers.has(fullPath)) {
|
|
5857
|
+
const watcher = this.state.nativeWatchers.get(fullPath);
|
|
5858
|
+
if (watcher !== void 0) {
|
|
5859
|
+
watcher.close();
|
|
5860
|
+
this.state.nativeWatchers.delete(fullPath);
|
|
5861
|
+
}
|
|
5862
|
+
this.debouncedEmit(fullPath, "unlink");
|
|
5837
5863
|
}
|
|
5838
|
-
this.debouncedEmit(fullPath, "unlink");
|
|
5839
5864
|
}
|
|
5840
5865
|
}
|
|
5841
5866
|
}
|
|
5842
|
-
|
|
5867
|
+
);
|
|
5843
5868
|
nativeWatcher.on("error", () => {
|
|
5844
5869
|
this.state.nativeWatchers.delete(dirWatchKey);
|
|
5845
5870
|
setTimeout(() => {
|
|
@@ -5964,11 +5989,7 @@ function manualHkdf(ikm, salt, info, length) {
|
|
|
5964
5989
|
const okm = Buffer.alloc(length);
|
|
5965
5990
|
let previous = Buffer.alloc(0);
|
|
5966
5991
|
for (let i = 1; i <= n; i++) {
|
|
5967
|
-
const hmacData = Buffer.concat([
|
|
5968
|
-
previous,
|
|
5969
|
-
infoBuffer,
|
|
5970
|
-
Buffer.from([i])
|
|
5971
|
-
]);
|
|
5992
|
+
const hmacData = Buffer.concat([previous, infoBuffer, Buffer.from([i])]);
|
|
5972
5993
|
previous = (0, import_node_crypto.createHmac)("sha256", prk).update(hmacData).digest();
|
|
5973
5994
|
const offset = (i - 1) * hashLen;
|
|
5974
5995
|
const copyLen = Math.min(hashLen, length - offset);
|
|
@@ -5985,10 +6006,7 @@ function encrypt(key, plaintext) {
|
|
|
5985
6006
|
const iv = (0, import_node_crypto.randomBytes)(12);
|
|
5986
6007
|
const algo = `aes-${key.length * 8}-gcm`;
|
|
5987
6008
|
const cipher = (0, import_node_crypto.createCipheriv)(algo, key, iv);
|
|
5988
|
-
const ciphertext = Buffer.concat([
|
|
5989
|
-
cipher.update(plaintext),
|
|
5990
|
-
cipher.final()
|
|
5991
|
-
]);
|
|
6009
|
+
const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);
|
|
5992
6010
|
const authTag = cipher.getAuthTag();
|
|
5993
6011
|
return { iv, authTag, ciphertext };
|
|
5994
6012
|
}
|
|
@@ -6002,10 +6020,7 @@ function decrypt(key, iv, authTag, ciphertext) {
|
|
|
6002
6020
|
const decipher = (0, import_node_crypto.createDecipheriv)(algo, key, iv);
|
|
6003
6021
|
decipher.setAuthTag(authTag);
|
|
6004
6022
|
try {
|
|
6005
|
-
return Buffer.concat([
|
|
6006
|
-
decipher.update(ciphertext),
|
|
6007
|
-
decipher.final()
|
|
6008
|
-
]);
|
|
6023
|
+
return Buffer.concat([decipher.update(ciphertext), decipher.final()]);
|
|
6009
6024
|
} catch (error) {
|
|
6010
6025
|
const message = error instanceof Error ? error.message : String(error);
|
|
6011
6026
|
throw new Error(
|
|
@@ -6037,14 +6052,15 @@ function encryptEnvironment(data, key) {
|
|
|
6037
6052
|
if (key.length !== 32) {
|
|
6038
6053
|
throw new EncryptionError(
|
|
6039
6054
|
`Invalid key length: expected 32 bytes for AES-256, got ${key.length}`,
|
|
6040
|
-
{
|
|
6055
|
+
{
|
|
6056
|
+
hint: "Generate a new key using generateMasterKey() or ensure you are using the correct key file."
|
|
6057
|
+
}
|
|
6041
6058
|
);
|
|
6042
6059
|
}
|
|
6043
6060
|
if (Object.keys(data).length === 0) {
|
|
6044
|
-
throw new EncryptionError(
|
|
6045
|
-
"
|
|
6046
|
-
|
|
6047
|
-
);
|
|
6061
|
+
throw new EncryptionError("Cannot encrypt empty environment data", {
|
|
6062
|
+
hint: "Provide at least one environment variable to encrypt."
|
|
6063
|
+
});
|
|
6048
6064
|
}
|
|
6049
6065
|
try {
|
|
6050
6066
|
const serialized = serializeEnvData(data);
|
|
@@ -6073,7 +6089,9 @@ function decryptEnvironment(encrypted, key) {
|
|
|
6073
6089
|
if (encrypted.algorithm !== ENCRYPTION_ALGORITHM) {
|
|
6074
6090
|
throw new EncryptionError(
|
|
6075
6091
|
`Unsupported algorithm: "${encrypted.algorithm}". Expected "${ENCRYPTION_ALGORITHM}".`,
|
|
6076
|
-
{
|
|
6092
|
+
{
|
|
6093
|
+
hint: "This vault was encrypted with a different algorithm. You may need to migrate the vault."
|
|
6094
|
+
}
|
|
6077
6095
|
);
|
|
6078
6096
|
}
|
|
6079
6097
|
if (encrypted.iv.length !== IV_LENGTH) {
|
|
@@ -6130,12 +6148,9 @@ function decryptValue(encrypted, key) {
|
|
|
6130
6148
|
);
|
|
6131
6149
|
}
|
|
6132
6150
|
if (!encrypted.startsWith(ENCRYPTED_PREFIX)) {
|
|
6133
|
-
throw new EncryptionError(
|
|
6134
|
-
"
|
|
6135
|
-
|
|
6136
|
-
hint: `Expected the value to start with "${ENCRYPTED_PREFIX}". This value may not have been encrypted by ultraenv.`
|
|
6137
|
-
}
|
|
6138
|
-
);
|
|
6151
|
+
throw new EncryptionError("Invalid encrypted value format: missing required prefix", {
|
|
6152
|
+
hint: `Expected the value to start with "${ENCRYPTED_PREFIX}". This value may not have been encrypted by ultraenv.`
|
|
6153
|
+
});
|
|
6139
6154
|
}
|
|
6140
6155
|
const payload = encrypted.slice(ENCRYPTED_PREFIX.length);
|
|
6141
6156
|
const parts = payload.split(":");
|
|
@@ -6151,16 +6166,14 @@ function decryptValue(encrypted, key) {
|
|
|
6151
6166
|
const authTagB64 = parts[1];
|
|
6152
6167
|
const ciphertextB64 = parts[2];
|
|
6153
6168
|
if (ivB64 === void 0 || authTagB64 === void 0 || ciphertextB64 === void 0) {
|
|
6154
|
-
throw new EncryptionError(
|
|
6155
|
-
"
|
|
6156
|
-
|
|
6157
|
-
);
|
|
6169
|
+
throw new EncryptionError("Invalid encrypted value: unexpected component structure", {
|
|
6170
|
+
hint: "The encrypted data may be corrupted. Try re-encrypting the value."
|
|
6171
|
+
});
|
|
6158
6172
|
}
|
|
6159
6173
|
if (ivB64.length === 0 || authTagB64.length === 0 || ciphertextB64.length === 0) {
|
|
6160
|
-
throw new EncryptionError(
|
|
6161
|
-
"
|
|
6162
|
-
|
|
6163
|
-
);
|
|
6174
|
+
throw new EncryptionError("Invalid encrypted value: one or more base64 components are empty", {
|
|
6175
|
+
hint: "The encrypted data may be corrupted. Try re-encrypting the value."
|
|
6176
|
+
});
|
|
6164
6177
|
}
|
|
6165
6178
|
try {
|
|
6166
6179
|
const iv = base64ToBuffer(ivB64);
|
|
@@ -6169,7 +6182,9 @@ function decryptValue(encrypted, key) {
|
|
|
6169
6182
|
if (iv.length !== IV_LENGTH) {
|
|
6170
6183
|
throw new EncryptionError(
|
|
6171
6184
|
`Invalid IV length: expected ${IV_LENGTH} bytes, got ${iv.length}`,
|
|
6172
|
-
{
|
|
6185
|
+
{
|
|
6186
|
+
hint: "The encrypted data may be corrupted or was produced by a different version of ultraenv."
|
|
6187
|
+
}
|
|
6173
6188
|
);
|
|
6174
6189
|
}
|
|
6175
6190
|
if (authTag.length !== AUTH_TAG_LENGTH) {
|
|
@@ -6184,10 +6199,9 @@ function decryptValue(encrypted, key) {
|
|
|
6184
6199
|
if (error instanceof EncryptionError) throw error;
|
|
6185
6200
|
const message = error instanceof Error ? error.message : String(error);
|
|
6186
6201
|
if (message.includes("Invalid") || message.includes("base64")) {
|
|
6187
|
-
throw new EncryptionError(
|
|
6188
|
-
"
|
|
6189
|
-
|
|
6190
|
-
);
|
|
6202
|
+
throw new EncryptionError("Invalid base64 encoding in encrypted value", {
|
|
6203
|
+
hint: "The encrypted data may be corrupted. Ensure the value was not modified."
|
|
6204
|
+
});
|
|
6191
6205
|
}
|
|
6192
6206
|
throw new EncryptionError(
|
|
6193
6207
|
"Failed to decrypt value. The key may be incorrect or the ciphertext was tampered with.",
|
|
@@ -6217,10 +6231,9 @@ function deriveEnvironmentKey(masterKey, environment) {
|
|
|
6217
6231
|
);
|
|
6218
6232
|
}
|
|
6219
6233
|
if (environment.length === 0) {
|
|
6220
|
-
throw new EncryptionError(
|
|
6221
|
-
|
|
6222
|
-
|
|
6223
|
-
);
|
|
6234
|
+
throw new EncryptionError("Environment name cannot be empty", {
|
|
6235
|
+
hint: 'Provide a valid environment name (e.g., "development", "production").'
|
|
6236
|
+
});
|
|
6224
6237
|
}
|
|
6225
6238
|
if (HKDF_SALT.length < DEFAULT_SALT_LENGTH) {
|
|
6226
6239
|
const paddedSalt = Buffer.alloc(DEFAULT_SALT_LENGTH);
|
|
@@ -6232,12 +6245,7 @@ function deriveEnvironmentKey(masterKey, environment) {
|
|
|
6232
6245
|
DEFAULT_KEY_LENGTH
|
|
6233
6246
|
);
|
|
6234
6247
|
}
|
|
6235
|
-
return deriveKey(
|
|
6236
|
-
masterKey,
|
|
6237
|
-
HKDF_SALT,
|
|
6238
|
-
`${HKDF_INFO_PREFIX}${environment}`,
|
|
6239
|
-
DEFAULT_KEY_LENGTH
|
|
6240
|
-
);
|
|
6248
|
+
return deriveKey(masterKey, HKDF_SALT, `${HKDF_INFO_PREFIX}${environment}`, DEFAULT_KEY_LENGTH);
|
|
6241
6249
|
}
|
|
6242
6250
|
function formatKey(key) {
|
|
6243
6251
|
if (key.length === 0) {
|
|
@@ -6257,21 +6265,17 @@ function parseKey2(formatted) {
|
|
|
6257
6265
|
}
|
|
6258
6266
|
const base64Part = formatted.slice(KEY_PREFIX.length);
|
|
6259
6267
|
if (base64Part.length === 0) {
|
|
6260
|
-
throw new EncryptionError(
|
|
6261
|
-
"
|
|
6262
|
-
|
|
6263
|
-
);
|
|
6268
|
+
throw new EncryptionError("Invalid key format: base64 payload is empty after prefix", {
|
|
6269
|
+
hint: "The key appears to be truncated. Generate a new key."
|
|
6270
|
+
});
|
|
6264
6271
|
}
|
|
6265
6272
|
try {
|
|
6266
6273
|
return base64ToBuffer(base64Part);
|
|
6267
6274
|
} catch (error) {
|
|
6268
|
-
throw new EncryptionError(
|
|
6269
|
-
|
|
6270
|
-
|
|
6271
|
-
|
|
6272
|
-
hint: 'The key may be corrupted. Generate a new key with "ultraenv key generate".'
|
|
6273
|
-
}
|
|
6274
|
-
);
|
|
6275
|
+
throw new EncryptionError("Failed to decode key: invalid base64 encoding", {
|
|
6276
|
+
cause: error instanceof Error ? error : void 0,
|
|
6277
|
+
hint: 'The key may be corrupted. Generate a new key with "ultraenv key generate".'
|
|
6278
|
+
});
|
|
6275
6279
|
}
|
|
6276
6280
|
}
|
|
6277
6281
|
function isValidKeyFormat(formatted) {
|
|
@@ -6333,12 +6337,9 @@ function parseKeysFile(content) {
|
|
|
6333
6337
|
if (!eqMatch) {
|
|
6334
6338
|
const plainMatch = line.match(/^ULTRAENV_KEY_([A-Za-z0-9_]+)=(.*)$/);
|
|
6335
6339
|
if (!plainMatch) {
|
|
6336
|
-
throw new EncryptionError(
|
|
6337
|
-
|
|
6338
|
-
|
|
6339
|
-
hint: 'Each key entry should be in the format: ULTRAENV_KEY_{ENVIRONMENT}="ultraenv_key_v1_..."'
|
|
6340
|
-
}
|
|
6341
|
-
);
|
|
6340
|
+
throw new EncryptionError(`Invalid keys file format at line ${i + 1}: "${line}"`, {
|
|
6341
|
+
hint: 'Each key entry should be in the format: ULTRAENV_KEY_{ENVIRONMENT}="ultraenv_key_v1_..."'
|
|
6342
|
+
});
|
|
6342
6343
|
}
|
|
6343
6344
|
const envName2 = plainMatch[1].toLowerCase();
|
|
6344
6345
|
const keyValue2 = plainMatch[2];
|
|
@@ -6379,21 +6380,14 @@ function parseVaultFile(content) {
|
|
|
6379
6380
|
if (rawLine === void 0) continue;
|
|
6380
6381
|
const line = rawLine.trim();
|
|
6381
6382
|
if (line.length === 0 || line.startsWith("#")) continue;
|
|
6382
|
-
const match = line.match(
|
|
6383
|
-
new RegExp(`^${VAULT_VAR_PREFIX}([A-Za-z0-9_]+)="(.*)"$`)
|
|
6384
|
-
);
|
|
6383
|
+
const match = line.match(new RegExp(`^${VAULT_VAR_PREFIX}([A-Za-z0-9_]+)="(.*)"$`));
|
|
6385
6384
|
if (!match) {
|
|
6386
|
-
const plainMatch = line.match(
|
|
6387
|
-
new RegExp(`^${VAULT_VAR_PREFIX}([A-Za-z0-9_]+)=(.*)$`)
|
|
6388
|
-
);
|
|
6385
|
+
const plainMatch = line.match(new RegExp(`^${VAULT_VAR_PREFIX}([A-Za-z0-9_]+)=(.*)$`));
|
|
6389
6386
|
if (!plainMatch) {
|
|
6390
|
-
throw new VaultError(
|
|
6391
|
-
|
|
6392
|
-
{
|
|
6393
|
-
|
|
6394
|
-
hint: `Each environment entry should be in the format: ${VAULT_VAR_PREFIX}{ENVIRONMENT}="encrypted:..."`
|
|
6395
|
-
}
|
|
6396
|
-
);
|
|
6387
|
+
throw new VaultError(`Invalid vault file format at line ${lineNumber}: "${line}"`, {
|
|
6388
|
+
operation: "parse",
|
|
6389
|
+
hint: `Each environment entry should be in the format: ${VAULT_VAR_PREFIX}{ENVIRONMENT}="encrypted:..."`
|
|
6390
|
+
});
|
|
6397
6391
|
}
|
|
6398
6392
|
const envName2 = plainMatch[1].toLowerCase();
|
|
6399
6393
|
const encryptedValue2 = plainMatch[2];
|
|
@@ -6446,41 +6440,32 @@ async function readVaultFile(path) {
|
|
|
6446
6440
|
return parseVaultFile(content);
|
|
6447
6441
|
} catch (error) {
|
|
6448
6442
|
if (error instanceof VaultError) throw error;
|
|
6449
|
-
throw new VaultError(
|
|
6450
|
-
|
|
6451
|
-
|
|
6452
|
-
|
|
6453
|
-
|
|
6454
|
-
|
|
6455
|
-
/* v8 ignore stop */
|
|
6456
|
-
}
|
|
6457
|
-
);
|
|
6443
|
+
throw new VaultError(`Failed to read vault file "${path}"`, {
|
|
6444
|
+
operation: "read",
|
|
6445
|
+
/* v8 ignore start */
|
|
6446
|
+
cause: error instanceof Error ? error : void 0
|
|
6447
|
+
/* v8 ignore stop */
|
|
6448
|
+
});
|
|
6458
6449
|
}
|
|
6459
6450
|
}
|
|
6460
6451
|
async function writeVaultFile(path, environments) {
|
|
6461
6452
|
if (environments.size === 0) {
|
|
6462
|
-
throw new VaultError(
|
|
6463
|
-
"
|
|
6464
|
-
|
|
6465
|
-
|
|
6466
|
-
hint: "Add at least one environment to the vault before writing."
|
|
6467
|
-
}
|
|
6468
|
-
);
|
|
6453
|
+
throw new VaultError("Cannot write an empty vault file", {
|
|
6454
|
+
operation: "write",
|
|
6455
|
+
hint: "Add at least one environment to the vault before writing."
|
|
6456
|
+
});
|
|
6469
6457
|
}
|
|
6470
6458
|
try {
|
|
6471
6459
|
const content = serializeVaultFile(environments);
|
|
6472
6460
|
await writeFile(path, content, "utf-8");
|
|
6473
6461
|
} catch (error) {
|
|
6474
6462
|
if (error instanceof VaultError) throw error;
|
|
6475
|
-
throw new VaultError(
|
|
6476
|
-
|
|
6477
|
-
|
|
6478
|
-
|
|
6479
|
-
|
|
6480
|
-
|
|
6481
|
-
/* v8 ignore stop */
|
|
6482
|
-
}
|
|
6483
|
-
);
|
|
6463
|
+
throw new VaultError(`Failed to write vault file "${path}"`, {
|
|
6464
|
+
operation: "write",
|
|
6465
|
+
/* v8 ignore start */
|
|
6466
|
+
cause: error instanceof Error ? error : void 0
|
|
6467
|
+
/* v8 ignore stop */
|
|
6468
|
+
});
|
|
6484
6469
|
}
|
|
6485
6470
|
}
|
|
6486
6471
|
function getEnvironmentData(vault, env) {
|
|
@@ -6513,16 +6498,14 @@ var HMAC_ALGORITHM = "sha256";
|
|
|
6513
6498
|
var HMAC_DIGEST_LENGTH = 64;
|
|
6514
6499
|
function computeIntegrity(data, key) {
|
|
6515
6500
|
if (key.length === 0) {
|
|
6516
|
-
throw new EncryptionError(
|
|
6517
|
-
"
|
|
6518
|
-
|
|
6519
|
-
);
|
|
6501
|
+
throw new EncryptionError("Cannot compute integrity with an empty key", {
|
|
6502
|
+
hint: "Provide a valid encryption key for integrity computation."
|
|
6503
|
+
});
|
|
6520
6504
|
}
|
|
6521
6505
|
if (data.length === 0) {
|
|
6522
|
-
throw new EncryptionError(
|
|
6523
|
-
"
|
|
6524
|
-
|
|
6525
|
-
);
|
|
6506
|
+
throw new EncryptionError("Cannot compute integrity for empty data", {
|
|
6507
|
+
hint: "Provide non-empty data for integrity computation."
|
|
6508
|
+
});
|
|
6526
6509
|
}
|
|
6527
6510
|
const hmac = (0, import_node_crypto3.createHmac)(HMAC_ALGORITHM, key);
|
|
6528
6511
|
hmac.update(data, "utf-8");
|
|
@@ -6530,21 +6513,20 @@ function computeIntegrity(data, key) {
|
|
|
6530
6513
|
}
|
|
6531
6514
|
function verifyIntegrity(data, key, expected) {
|
|
6532
6515
|
if (key.length === 0) {
|
|
6533
|
-
throw new EncryptionError(
|
|
6534
|
-
"Cannot verify integrity with an empty key"
|
|
6535
|
-
);
|
|
6516
|
+
throw new EncryptionError("Cannot verify integrity with an empty key");
|
|
6536
6517
|
}
|
|
6537
6518
|
if (expected.length !== HMAC_DIGEST_LENGTH) {
|
|
6538
6519
|
throw new EncryptionError(
|
|
6539
6520
|
`Invalid expected digest length: expected ${HMAC_DIGEST_LENGTH} hex characters, got ${expected.length}`,
|
|
6540
|
-
{
|
|
6521
|
+
{
|
|
6522
|
+
hint: "The integrity digest should be a 64-character lowercase hex string from computeIntegrity()."
|
|
6523
|
+
}
|
|
6541
6524
|
);
|
|
6542
6525
|
}
|
|
6543
6526
|
if (!/^[0-9a-f]{64}$/.test(expected)) {
|
|
6544
|
-
throw new EncryptionError(
|
|
6545
|
-
"
|
|
6546
|
-
|
|
6547
|
-
);
|
|
6527
|
+
throw new EncryptionError("Invalid expected digest format: must be a lowercase hex string", {
|
|
6528
|
+
hint: "Ensure the stored digest is a 64-character lowercase hex string."
|
|
6529
|
+
});
|
|
6548
6530
|
}
|
|
6549
6531
|
try {
|
|
6550
6532
|
const computed = computeIntegrity(data, key);
|
|
@@ -6558,14 +6540,10 @@ function verifyIntegrity(data, key, expected) {
|
|
|
6558
6540
|
}
|
|
6559
6541
|
function computeVaultChecksum(environments, key) {
|
|
6560
6542
|
if (key.length === 0) {
|
|
6561
|
-
throw new EncryptionError(
|
|
6562
|
-
"Cannot compute vault checksum with an empty key"
|
|
6563
|
-
);
|
|
6543
|
+
throw new EncryptionError("Cannot compute vault checksum with an empty key");
|
|
6564
6544
|
}
|
|
6565
6545
|
if (environments.size === 0) {
|
|
6566
|
-
throw new EncryptionError(
|
|
6567
|
-
"Cannot compute vault checksum for empty environment set"
|
|
6568
|
-
);
|
|
6546
|
+
throw new EncryptionError("Cannot compute vault checksum for empty environment set");
|
|
6569
6547
|
}
|
|
6570
6548
|
const sortedNames = Array.from(environments.keys()).sort();
|
|
6571
6549
|
const parts = [];
|
|
@@ -6581,9 +6559,7 @@ function computeVaultChecksum(environments, key) {
|
|
|
6581
6559
|
}
|
|
6582
6560
|
function verifyVaultChecksum(environments, key, expected) {
|
|
6583
6561
|
if (key.length === 0) {
|
|
6584
|
-
throw new EncryptionError(
|
|
6585
|
-
"Cannot verify vault checksum with an empty key"
|
|
6586
|
-
);
|
|
6562
|
+
throw new EncryptionError("Cannot verify vault checksum with an empty key");
|
|
6587
6563
|
}
|
|
6588
6564
|
if (expected.length !== HMAC_DIGEST_LENGTH) {
|
|
6589
6565
|
throw new EncryptionError(
|
|
@@ -6644,9 +6620,7 @@ var SecureBuffer = class _SecureBuffer {
|
|
|
6644
6620
|
*/
|
|
6645
6621
|
constructor(size) {
|
|
6646
6622
|
if (size < 1 || !Number.isInteger(size)) {
|
|
6647
|
-
throw new RangeError(
|
|
6648
|
-
`SecureBuffer: size must be a positive integer, got ${size}`
|
|
6649
|
-
);
|
|
6623
|
+
throw new RangeError(`SecureBuffer: size must be a positive integer, got ${size}`);
|
|
6650
6624
|
}
|
|
6651
6625
|
this._buffer = Buffer.alloc(size);
|
|
6652
6626
|
this._length = size;
|
|
@@ -6700,9 +6674,7 @@ var SecureBuffer = class _SecureBuffer {
|
|
|
6700
6674
|
*/
|
|
6701
6675
|
fill(value) {
|
|
6702
6676
|
if (value < 0 || value > 255 || !Number.isInteger(value)) {
|
|
6703
|
-
throw new RangeError(
|
|
6704
|
-
`SecureBuffer.fill: value must be an integer 0-255, got ${value}`
|
|
6705
|
-
);
|
|
6677
|
+
throw new RangeError(`SecureBuffer.fill: value must be an integer 0-255, got ${value}`);
|
|
6706
6678
|
}
|
|
6707
6679
|
this._buffer.fill(value);
|
|
6708
6680
|
this._zeroed = value === 0;
|
|
@@ -7143,7 +7115,7 @@ var SECRET_PATTERNS = [
|
|
|
7143
7115
|
{
|
|
7144
7116
|
id: "google-oauth-client-secret",
|
|
7145
7117
|
name: "Google OAuth Client Secret",
|
|
7146
|
-
pattern: /(?:^|["'\s:=,`]GOCSPX-[A-Za-z0-9_-]{28,})(?:["'\s,`;]|$)/gm,
|
|
7118
|
+
pattern: /(?:^|["'\s:=,`])(GOCSPX-[A-Za-z0-9_-]{28,})(?:["'\s,`;]|$)/gm,
|
|
7147
7119
|
confidence: 0.9,
|
|
7148
7120
|
severity: "critical",
|
|
7149
7121
|
description: "Google OAuth Client Secret (new format). Used for OAuth authentication flows.",
|
|
@@ -8018,9 +7990,7 @@ function extractCandidates(line) {
|
|
|
8018
7990
|
const captured = tokenMatch[1];
|
|
8019
7991
|
if (captured === void 0) continue;
|
|
8020
7992
|
const tokenIndex = tokenMatch.index + 1;
|
|
8021
|
-
const existing = candidates.some(
|
|
8022
|
-
(c) => c.value === captured && c.column === tokenIndex
|
|
8023
|
-
);
|
|
7993
|
+
const existing = candidates.some((c) => c.value === captured && c.column === tokenIndex);
|
|
8024
7994
|
if (!existing) {
|
|
8025
7995
|
candidates.push({ value: captured, column: tokenMatch.index + 1 });
|
|
8026
7996
|
}
|
|
@@ -8587,15 +8557,9 @@ var DIM = "\x1B[2m";
|
|
|
8587
8557
|
function formatTerminal(result) {
|
|
8588
8558
|
const lines = [];
|
|
8589
8559
|
const totalCount = result.secrets.length;
|
|
8590
|
-
const criticalCount = result.secrets.filter(
|
|
8591
|
-
|
|
8592
|
-
).length;
|
|
8593
|
-
const highCount = result.secrets.filter(
|
|
8594
|
-
(s) => getSeverity(s.pattern) === "high"
|
|
8595
|
-
).length;
|
|
8596
|
-
const mediumCount = result.secrets.filter(
|
|
8597
|
-
(s) => getSeverity(s.pattern) === "medium"
|
|
8598
|
-
).length;
|
|
8560
|
+
const criticalCount = result.secrets.filter((s) => getSeverity(s.pattern) === "critical").length;
|
|
8561
|
+
const highCount = result.secrets.filter((s) => getSeverity(s.pattern) === "high").length;
|
|
8562
|
+
const mediumCount = result.secrets.filter((s) => getSeverity(s.pattern) === "medium").length;
|
|
8599
8563
|
lines.push("");
|
|
8600
8564
|
lines.push(`${BOLD}=== ultraenv Secret Scan Report ===${RESET}`);
|
|
8601
8565
|
lines.push("");
|
|
@@ -8611,7 +8575,9 @@ function formatTerminal(result) {
|
|
|
8611
8575
|
}
|
|
8612
8576
|
const summaryParts = [];
|
|
8613
8577
|
if (criticalCount > 0) {
|
|
8614
|
-
summaryParts.push(
|
|
8578
|
+
summaryParts.push(
|
|
8579
|
+
`${SEVERITY_CONFIG.critical.terminalColor}${BOLD}${criticalCount} critical${RESET}`
|
|
8580
|
+
);
|
|
8615
8581
|
}
|
|
8616
8582
|
if (highCount > 0) {
|
|
8617
8583
|
summaryParts.push(`${SEVERITY_CONFIG.high.terminalColor}${BOLD}${highCount} high${RESET}`);
|
|
@@ -9248,16 +9214,12 @@ var SyncWatcher = class {
|
|
|
9248
9214
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
9249
9215
|
};
|
|
9250
9216
|
try {
|
|
9251
|
-
const needs = await needsUpdate(
|
|
9252
|
-
|
|
9253
|
-
this.options.
|
|
9254
|
-
|
|
9255
|
-
|
|
9256
|
-
|
|
9257
|
-
includeTypes: this.options.includeTypes,
|
|
9258
|
-
includeDefaults: this.options.includeDefaults
|
|
9259
|
-
}
|
|
9260
|
-
);
|
|
9217
|
+
const needs = await needsUpdate(this.options.envPath, this.options.examplePath, {
|
|
9218
|
+
schemaPath: void 0,
|
|
9219
|
+
includeDescriptions: this.options.includeDescriptions,
|
|
9220
|
+
includeTypes: this.options.includeTypes,
|
|
9221
|
+
includeDefaults: this.options.includeDefaults
|
|
9222
|
+
});
|
|
9261
9223
|
if (!needs) {
|
|
9262
9224
|
result.success = true;
|
|
9263
9225
|
if (this.options.onSync !== void 0) {
|
|
@@ -9265,16 +9227,12 @@ var SyncWatcher = class {
|
|
|
9265
9227
|
}
|
|
9266
9228
|
return;
|
|
9267
9229
|
}
|
|
9268
|
-
await generateExampleFile(
|
|
9269
|
-
|
|
9270
|
-
this.options.
|
|
9271
|
-
|
|
9272
|
-
|
|
9273
|
-
|
|
9274
|
-
includeTypes: this.options.includeTypes,
|
|
9275
|
-
includeDefaults: this.options.includeDefaults
|
|
9276
|
-
}
|
|
9277
|
-
);
|
|
9230
|
+
await generateExampleFile(this.options.envPath, this.options.examplePath, {
|
|
9231
|
+
schemaPath: void 0,
|
|
9232
|
+
includeDescriptions: this.options.includeDescriptions,
|
|
9233
|
+
includeTypes: this.options.includeTypes,
|
|
9234
|
+
includeDefaults: this.options.includeDefaults
|
|
9235
|
+
});
|
|
9278
9236
|
result.success = true;
|
|
9279
9237
|
this.emitEvent({
|
|
9280
9238
|
type: "change",
|
|
@@ -10079,12 +10037,14 @@ async function validateAllEnvironments(schema, cwd) {
|
|
|
10079
10037
|
const message = error instanceof Error ? error.message : String(error);
|
|
10080
10038
|
results.set(envName ?? pattern, {
|
|
10081
10039
|
valid: false,
|
|
10082
|
-
errors: [
|
|
10083
|
-
|
|
10084
|
-
|
|
10085
|
-
|
|
10086
|
-
|
|
10087
|
-
|
|
10040
|
+
errors: [
|
|
10041
|
+
{
|
|
10042
|
+
field: "",
|
|
10043
|
+
value: "",
|
|
10044
|
+
message: `Failed to read/parse file: ${message}`,
|
|
10045
|
+
hint: "Check that the file is a valid .env file."
|
|
10046
|
+
}
|
|
10047
|
+
],
|
|
10088
10048
|
warnings: []
|
|
10089
10049
|
});
|
|
10090
10050
|
}
|
|
@@ -10095,14 +10055,11 @@ async function switchEnvironment(envName, cwd) {
|
|
|
10095
10055
|
const baseDir = (0, import_node_path7.resolve)(cwd ?? process.cwd());
|
|
10096
10056
|
const envFile = (0, import_node_path7.join)(baseDir, `.env.${envName}`);
|
|
10097
10057
|
if (!await exists(envFile)) {
|
|
10098
|
-
throw new FileSystemError(
|
|
10099
|
-
|
|
10100
|
-
|
|
10101
|
-
|
|
10102
|
-
|
|
10103
|
-
hint: `Create a ".env.${envName}" file first, or use "ultraenv env create ${envName}".`
|
|
10104
|
-
}
|
|
10105
|
-
);
|
|
10058
|
+
throw new FileSystemError(`Environment file ".env.${envName}" not found`, {
|
|
10059
|
+
path: envFile,
|
|
10060
|
+
operation: "read",
|
|
10061
|
+
hint: `Create a ".env.${envName}" file first, or use "ultraenv env create ${envName}".`
|
|
10062
|
+
});
|
|
10106
10063
|
}
|
|
10107
10064
|
const content = await readFile(envFile);
|
|
10108
10065
|
const header = [
|
|
@@ -10276,24 +10233,18 @@ async function compareEnvironments(env1, env2, cwd, _schema) {
|
|
|
10276
10233
|
const resolvedEnv1Path = env1.includes("/") || env1.includes("\\") ? (0, import_node_path8.resolve)(env1) : env1Path;
|
|
10277
10234
|
const resolvedEnv2Path = env2.includes("/") || env2.includes("\\") ? (0, import_node_path8.resolve)(env2) : env2Path;
|
|
10278
10235
|
if (!await exists(resolvedEnv1Path)) {
|
|
10279
|
-
throw new FileSystemError(
|
|
10280
|
-
|
|
10281
|
-
|
|
10282
|
-
|
|
10283
|
-
|
|
10284
|
-
hint: `Ensure ".env.${env1}" exists in the project directory.`
|
|
10285
|
-
}
|
|
10286
|
-
);
|
|
10236
|
+
throw new FileSystemError(`Environment file not found: "${resolvedEnv1Path}"`, {
|
|
10237
|
+
path: resolvedEnv1Path,
|
|
10238
|
+
operation: "read",
|
|
10239
|
+
hint: `Ensure ".env.${env1}" exists in the project directory.`
|
|
10240
|
+
});
|
|
10287
10241
|
}
|
|
10288
10242
|
if (!await exists(resolvedEnv2Path)) {
|
|
10289
|
-
throw new FileSystemError(
|
|
10290
|
-
|
|
10291
|
-
|
|
10292
|
-
|
|
10293
|
-
|
|
10294
|
-
hint: `Ensure ".env.${env2}" exists in the project directory.`
|
|
10295
|
-
}
|
|
10296
|
-
);
|
|
10243
|
+
throw new FileSystemError(`Environment file not found: "${resolvedEnv2Path}"`, {
|
|
10244
|
+
path: resolvedEnv2Path,
|
|
10245
|
+
operation: "read",
|
|
10246
|
+
hint: `Ensure ".env.${env2}" exists in the project directory.`
|
|
10247
|
+
});
|
|
10297
10248
|
}
|
|
10298
10249
|
const env1Content = await readFile(resolvedEnv1Path);
|
|
10299
10250
|
const env2Content = await readFile(resolvedEnv2Path);
|
|
@@ -10386,14 +10337,18 @@ function formatComparison(comparison) {
|
|
|
10386
10337
|
lines.push("");
|
|
10387
10338
|
lines.push(`Only in ${comparison.env1Name} (${comparison.onlyInEnv1.length}):`);
|
|
10388
10339
|
for (const diff of comparison.onlyInEnv1) {
|
|
10389
|
-
lines.push(
|
|
10340
|
+
lines.push(
|
|
10341
|
+
` - ${diff.key}${diff.isSecret ? " [SECRET]" : ""} = ${diff.value1 || "(empty)"}`
|
|
10342
|
+
);
|
|
10390
10343
|
}
|
|
10391
10344
|
}
|
|
10392
10345
|
if (comparison.onlyInEnv2.length > 0) {
|
|
10393
10346
|
lines.push("");
|
|
10394
10347
|
lines.push(`Only in ${comparison.env2Name} (${comparison.onlyInEnv2.length}):`);
|
|
10395
10348
|
for (const diff of comparison.onlyInEnv2) {
|
|
10396
|
-
lines.push(
|
|
10349
|
+
lines.push(
|
|
10350
|
+
` + ${diff.key}${diff.isSecret ? " [SECRET]" : ""} = ${diff.value2 || "(empty)"}`
|
|
10351
|
+
);
|
|
10397
10352
|
}
|
|
10398
10353
|
}
|
|
10399
10354
|
if (comparison.different.length > 0) {
|
|
@@ -10574,14 +10529,11 @@ function validateEnvironmentName(name) {
|
|
|
10574
10529
|
});
|
|
10575
10530
|
}
|
|
10576
10531
|
if (name.length > 64) {
|
|
10577
|
-
throw new FileSystemError(
|
|
10578
|
-
|
|
10579
|
-
|
|
10580
|
-
|
|
10581
|
-
|
|
10582
|
-
hint: "Use a shorter environment name."
|
|
10583
|
-
}
|
|
10584
|
-
);
|
|
10532
|
+
throw new FileSystemError(`Environment name too long: ${name.length} characters (max 64)`, {
|
|
10533
|
+
path: "",
|
|
10534
|
+
operation: "validate",
|
|
10535
|
+
hint: "Use a shorter environment name."
|
|
10536
|
+
});
|
|
10585
10537
|
}
|
|
10586
10538
|
if (!/^[a-zA-Z0-9_-]+$/.test(name)) {
|
|
10587
10539
|
throw new FileSystemError(
|
|
@@ -10595,14 +10547,11 @@ function validateEnvironmentName(name) {
|
|
|
10595
10547
|
}
|
|
10596
10548
|
const reserved = ["local", "example", "template", "bak", "backup", "old", "tmp", "temp"];
|
|
10597
10549
|
if (reserved.includes(name.toLowerCase())) {
|
|
10598
|
-
throw new FileSystemError(
|
|
10599
|
-
|
|
10600
|
-
|
|
10601
|
-
|
|
10602
|
-
|
|
10603
|
-
hint: `The name "${name}" is reserved. Choose a different name.`
|
|
10604
|
-
}
|
|
10605
|
-
);
|
|
10550
|
+
throw new FileSystemError(`Reserved environment name: "${name}"`, {
|
|
10551
|
+
path: "",
|
|
10552
|
+
operation: "validate",
|
|
10553
|
+
hint: `The name "${name}" is reserved. Choose a different name.`
|
|
10554
|
+
});
|
|
10606
10555
|
}
|
|
10607
10556
|
}
|
|
10608
10557
|
async function createEnvironment(name, options) {
|
|
@@ -10610,28 +10559,22 @@ async function createEnvironment(name, options) {
|
|
|
10610
10559
|
const baseDir = (0, import_node_path9.resolve)(options?.cwd ?? process.cwd());
|
|
10611
10560
|
const outputPath = (0, import_node_path9.join)(baseDir, `.env.${name}`);
|
|
10612
10561
|
if (await exists(outputPath)) {
|
|
10613
|
-
throw new FileSystemError(
|
|
10614
|
-
|
|
10615
|
-
|
|
10616
|
-
|
|
10617
|
-
|
|
10618
|
-
hint: "Delete the existing file first, or use a different environment name."
|
|
10619
|
-
}
|
|
10620
|
-
);
|
|
10562
|
+
throw new FileSystemError(`Environment file already exists: ".env.${name}"`, {
|
|
10563
|
+
path: outputPath,
|
|
10564
|
+
operation: "create",
|
|
10565
|
+
hint: "Delete the existing file first, or use a different environment name."
|
|
10566
|
+
});
|
|
10621
10567
|
}
|
|
10622
10568
|
let content;
|
|
10623
10569
|
let variables = [];
|
|
10624
10570
|
if (options?.copyFrom !== void 0) {
|
|
10625
10571
|
const sourcePath = (0, import_node_path9.join)(baseDir, `.env.${options.copyFrom}`);
|
|
10626
10572
|
if (!await exists(sourcePath)) {
|
|
10627
|
-
throw new FileSystemError(
|
|
10628
|
-
|
|
10629
|
-
|
|
10630
|
-
|
|
10631
|
-
|
|
10632
|
-
hint: `Ensure ".env.${options.copyFrom}" exists before copying.`
|
|
10633
|
-
}
|
|
10634
|
-
);
|
|
10573
|
+
throw new FileSystemError(`Source environment not found: ".env.${options.copyFrom}"`, {
|
|
10574
|
+
path: sourcePath,
|
|
10575
|
+
operation: "read",
|
|
10576
|
+
hint: `Ensure ".env.${options.copyFrom}" exists before copying.`
|
|
10577
|
+
});
|
|
10635
10578
|
}
|
|
10636
10579
|
content = await readFile(sourcePath);
|
|
10637
10580
|
variables = extractVariables(content, options?.schema);
|
|
@@ -10652,14 +10595,11 @@ async function createEnvironment(name, options) {
|
|
|
10652
10595
|
} else if (await exists(templatePath)) {
|
|
10653
10596
|
content = await readFile(templatePath);
|
|
10654
10597
|
} else {
|
|
10655
|
-
throw new FileSystemError(
|
|
10656
|
-
|
|
10657
|
-
|
|
10658
|
-
|
|
10659
|
-
|
|
10660
|
-
hint: "Use a built-in template name (nodejs, nextjs, docker) or a valid file path."
|
|
10661
|
-
}
|
|
10662
|
-
);
|
|
10598
|
+
throw new FileSystemError(`Template not found: "${options.fromTemplate}"`, {
|
|
10599
|
+
path: templatePath,
|
|
10600
|
+
operation: "read",
|
|
10601
|
+
hint: "Use a built-in template name (nodejs, nextjs, docker) or a valid file path."
|
|
10602
|
+
});
|
|
10663
10603
|
}
|
|
10664
10604
|
variables = extractVariables(content, options?.schema);
|
|
10665
10605
|
const values = collectValues(variables, options?.values);
|
|
@@ -10696,14 +10636,11 @@ async function removeEnvironment(name, cwd) {
|
|
|
10696
10636
|
const baseDir = (0, import_node_path9.resolve)(cwd ?? process.cwd());
|
|
10697
10637
|
const filePath = (0, import_node_path9.join)(baseDir, `.env.${name}`);
|
|
10698
10638
|
if (!await exists(filePath)) {
|
|
10699
|
-
throw new FileSystemError(
|
|
10700
|
-
|
|
10701
|
-
|
|
10702
|
-
|
|
10703
|
-
|
|
10704
|
-
hint: "The environment does not exist."
|
|
10705
|
-
}
|
|
10706
|
-
);
|
|
10639
|
+
throw new FileSystemError(`Environment file not found: ".env.${name}"`, {
|
|
10640
|
+
path: filePath,
|
|
10641
|
+
operation: "unlink",
|
|
10642
|
+
hint: "The environment does not exist."
|
|
10643
|
+
});
|
|
10707
10644
|
}
|
|
10708
10645
|
await removeFile(filePath);
|
|
10709
10646
|
}
|
|
@@ -10855,11 +10792,7 @@ var nextjsPreset = {
|
|
|
10855
10792
|
};
|
|
10856
10793
|
|
|
10857
10794
|
// src/presets/vite.ts
|
|
10858
|
-
var VITE_MODES = [
|
|
10859
|
-
"development",
|
|
10860
|
-
"production",
|
|
10861
|
-
"test"
|
|
10862
|
-
];
|
|
10795
|
+
var VITE_MODES = ["development", "production", "test"];
|
|
10863
10796
|
var viteSchema = {
|
|
10864
10797
|
// ── Public (client-exposed) Variables ──────────────────────────────
|
|
10865
10798
|
VITE_API_URL: {
|
|
@@ -12081,10 +12014,8 @@ var awsLambdaPreset = {
|
|
|
12081
12014
|
var presets = {};
|
|
12082
12015
|
function registerPreset(name, preset) {
|
|
12083
12016
|
if (presets[name] !== void 0) {
|
|
12084
|
-
process.stderr.write(
|
|
12085
|
-
|
|
12086
|
-
`
|
|
12087
|
-
);
|
|
12017
|
+
process.stderr.write(`[ultraenv] Warning: overwriting existing preset "${name}"
|
|
12018
|
+
`);
|
|
12088
12019
|
}
|
|
12089
12020
|
presets[name] = preset;
|
|
12090
12021
|
}
|
|
@@ -12181,9 +12112,7 @@ function buildFilteredEnv(source, prefixes, allowSet, denySet, exposePublic, exp
|
|
|
12181
12112
|
function healthCheckRoute(options = {}) {
|
|
12182
12113
|
const { source = process.env, metadata = {} } = options;
|
|
12183
12114
|
return (_req, res) => {
|
|
12184
|
-
const envKeys = Object.keys(source).filter(
|
|
12185
|
-
(k) => source[k] !== void 0 && source[k] !== ""
|
|
12186
|
-
);
|
|
12115
|
+
const envKeys = Object.keys(source).filter((k) => source[k] !== void 0 && source[k] !== "");
|
|
12187
12116
|
const nodeEnv = source["NODE_ENV"] ?? "unknown";
|
|
12188
12117
|
const response = {
|
|
12189
12118
|
status: "ok",
|
|
@@ -12218,13 +12147,7 @@ function ultraenvPlugin(fastify, options = {}, done) {
|
|
|
12218
12147
|
}
|
|
12219
12148
|
const allowSet = new Set(allowList.map((k) => k.toUpperCase()));
|
|
12220
12149
|
const denySet = new Set(denyList.map((k) => k.toUpperCase()));
|
|
12221
|
-
const filteredEnv = buildFastifyEnv(
|
|
12222
|
-
source,
|
|
12223
|
-
allPrefixes,
|
|
12224
|
-
allowSet,
|
|
12225
|
-
denySet,
|
|
12226
|
-
exposeNodeEnv
|
|
12227
|
-
);
|
|
12150
|
+
const filteredEnv = buildFastifyEnv(source, allPrefixes, allowSet, denySet, exposeNodeEnv);
|
|
12228
12151
|
fastify.decorate("env", filteredEnv);
|
|
12229
12152
|
done();
|
|
12230
12153
|
}
|
|
@@ -12266,9 +12189,7 @@ function healthCheck(options = {}) {
|
|
|
12266
12189
|
validCount,
|
|
12267
12190
|
metadata = {}
|
|
12268
12191
|
} = options;
|
|
12269
|
-
const envKeys = Object.entries(source).filter(
|
|
12270
|
-
([, value]) => value !== void 0 && value !== ""
|
|
12271
|
-
);
|
|
12192
|
+
const envKeys = Object.entries(source).filter(([, value]) => value !== void 0 && value !== "");
|
|
12272
12193
|
const loaded = envKeys.length;
|
|
12273
12194
|
const environment = detectEnvironment2(source);
|
|
12274
12195
|
const valid = validCount ?? loaded;
|
|
@@ -12311,13 +12232,7 @@ function readinessCheck(requiredVars, source) {
|
|
|
12311
12232
|
};
|
|
12312
12233
|
}
|
|
12313
12234
|
function detectEnvironment2(env) {
|
|
12314
|
-
const candidates = [
|
|
12315
|
-
"NODE_ENV",
|
|
12316
|
-
"APP_ENV",
|
|
12317
|
-
"ENVIRONMENT",
|
|
12318
|
-
"ENV",
|
|
12319
|
-
"STAGE"
|
|
12320
|
-
];
|
|
12235
|
+
const candidates = ["NODE_ENV", "APP_ENV", "ENVIRONMENT", "ENV", "STAGE"];
|
|
12321
12236
|
for (const candidate of candidates) {
|
|
12322
12237
|
const value = env[candidate];
|
|
12323
12238
|
if (value !== void 0 && value !== "") {
|
|
@@ -12349,11 +12264,7 @@ function drawTitledBox(title, lines, chars = DOUBLE) {
|
|
|
12349
12264
|
if (lines.length === 0) {
|
|
12350
12265
|
return [hRuleTitled(title, 0, chars), boxLine("", 0, chars), hRuleBottom(0, chars)].join("\n");
|
|
12351
12266
|
}
|
|
12352
|
-
const innerWidth = Math.max(
|
|
12353
|
-
...lines.map((line) => stripAnsi(line).length),
|
|
12354
|
-
title.length + 2,
|
|
12355
|
-
0
|
|
12356
|
-
);
|
|
12267
|
+
const innerWidth = Math.max(...lines.map((line) => stripAnsi(line).length), title.length + 2, 0);
|
|
12357
12268
|
const result = [];
|
|
12358
12269
|
result.push(hRuleTitled(title, innerWidth, chars));
|
|
12359
12270
|
for (const line of lines) {
|
|
@@ -12408,7 +12319,9 @@ function reportValidation(result, options = {}) {
|
|
|
12408
12319
|
const c = color ? ANSI : noColorANSI();
|
|
12409
12320
|
if (result.valid) {
|
|
12410
12321
|
const lines = [];
|
|
12411
|
-
lines.push(
|
|
12322
|
+
lines.push(
|
|
12323
|
+
`${c.green}${c.bold} \u2713${c.reset} All ${Object.keys(result.validated).length} variables passed validation`
|
|
12324
|
+
);
|
|
12412
12325
|
if (result.warnings.length > 0) {
|
|
12413
12326
|
lines.push("");
|
|
12414
12327
|
for (const warning of result.warnings) {
|
|
@@ -12438,13 +12351,17 @@ function reportValidation(result, options = {}) {
|
|
|
12438
12351
|
output.push("");
|
|
12439
12352
|
const warningLines = [];
|
|
12440
12353
|
for (const warning of result.warnings) {
|
|
12441
|
-
warningLines.push(
|
|
12354
|
+
warningLines.push(
|
|
12355
|
+
`${c.yellow}\u26A0${c.reset} ${warning.field}: ${warning.message} ${c.dim}[${warning.code}]${c.reset}`
|
|
12356
|
+
);
|
|
12442
12357
|
}
|
|
12443
12358
|
output.push(warningLines.join("\n"));
|
|
12444
12359
|
}
|
|
12445
12360
|
if (result.unknown.length > 0) {
|
|
12446
12361
|
output.push("");
|
|
12447
|
-
output.push(
|
|
12362
|
+
output.push(
|
|
12363
|
+
`${c.gray}?${c.reset} Unknown variables: ${result.unknown.map((u) => `${c.dim}${u}${c.reset}`).join(", ")}`
|
|
12364
|
+
);
|
|
12448
12365
|
}
|
|
12449
12366
|
return output.join("\n");
|
|
12450
12367
|
}
|
|
@@ -12452,10 +12369,7 @@ function reportError(error, options = {}) {
|
|
|
12452
12369
|
const { color = true, boxStyle = DEFAULT_BOX } = options;
|
|
12453
12370
|
const c = color ? ANSI : noColorANSI();
|
|
12454
12371
|
const code = error.code ?? "ULTRAENV_ERROR";
|
|
12455
|
-
const lines = [
|
|
12456
|
-
`${c.red}${c.bold}Error [${code}]${c.reset}`,
|
|
12457
|
-
` ${error.message}`
|
|
12458
|
-
];
|
|
12372
|
+
const lines = [`${c.red}${c.bold}Error [${code}]${c.reset}`, ` ${error.message}`];
|
|
12459
12373
|
if (error.hint !== void 0) {
|
|
12460
12374
|
lines.push("");
|
|
12461
12375
|
lines.push(`${c.cyan} \u{1F4A1} ${error.hint}${c.reset}`);
|