typed-settings 0.1.4 → 0.2.1

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 (81) hide show
  1. package/README.md +14 -7
  2. package/bin/typed-settings.mjs +5 -0
  3. package/dist/adapters/joi.cjs +1 -26
  4. package/dist/adapters/joi.d.cts +2 -1
  5. package/dist/adapters/joi.d.ts +2 -1
  6. package/dist/adapters/joi.js +1 -1
  7. package/dist/adapters/superstruct.cjs +1 -26
  8. package/dist/adapters/superstruct.js +1 -1
  9. package/dist/adapters/yup.cjs +1 -25
  10. package/dist/adapters/yup.js +1 -1
  11. package/dist/adapters/zod.cjs +3 -36
  12. package/dist/adapters/zod.js +1 -33
  13. package/dist/check-XVFZEVNV.js +1 -0
  14. package/dist/chunk-4EAMKDNK.js +3 -0
  15. package/dist/chunk-5D2AQWDG.js +1 -0
  16. package/dist/chunk-C6CG2D4B.js +2 -0
  17. package/dist/chunk-FQYD5ZKE.js +1 -0
  18. package/dist/chunk-NQDE3WLR.js +3 -0
  19. package/dist/chunk-RURPDXIJ.js +1 -0
  20. package/dist/cli/main.cjs +36 -2225
  21. package/dist/cli/main.js +32 -806
  22. package/dist/errors-JkkOM0u-.d.cts +25 -0
  23. package/dist/errors-JkkOM0u-.d.ts +25 -0
  24. package/dist/framework/next.cjs +5 -1158
  25. package/dist/framework/next.d.cts +3 -3
  26. package/dist/framework/next.d.ts +3 -3
  27. package/dist/framework/next.js +1 -15
  28. package/dist/framework/vite.cjs +5 -1156
  29. package/dist/framework/vite.d.cts +8 -3
  30. package/dist/framework/vite.d.ts +8 -3
  31. package/dist/framework/vite.js +1 -14
  32. package/dist/index.cjs +5 -1181
  33. package/dist/index.d.cts +38 -7
  34. package/dist/index.d.ts +38 -7
  35. package/dist/index.js +1 -6
  36. package/dist/node.cjs +6 -1241
  37. package/dist/node.d.cts +23 -9
  38. package/dist/node.d.ts +23 -9
  39. package/dist/node.js +1 -7
  40. package/dist/{types-B_Dc2L4T.d.cts → types-CcsYDAdO.d.cts} +23 -1
  41. package/dist/{types-B_Dc2L4T.d.ts → types-CcsYDAdO.d.ts} +23 -1
  42. package/dist/vault/aws.cjs +4 -217
  43. package/dist/vault/aws.d.cts +1 -1
  44. package/dist/vault/aws.d.ts +1 -1
  45. package/dist/vault/aws.js +2 -167
  46. package/dist/vault/hashicorp.cjs +4 -183
  47. package/dist/vault/hashicorp.d.cts +1 -1
  48. package/dist/vault/hashicorp.d.ts +1 -1
  49. package/dist/vault/hashicorp.js +2 -77
  50. package/dist/vault/http.cjs +4 -185
  51. package/dist/vault/http.d.cts +1 -1
  52. package/dist/vault/http.d.ts +1 -1
  53. package/dist/vault/http.js +2 -79
  54. package/package.json +2 -3
  55. package/dist/chunk-33M5GIKQ.js +0 -13
  56. package/dist/chunk-A5TCQJ7L.js +0 -65
  57. package/dist/chunk-DEP5SD4J.js +0 -233
  58. package/dist/chunk-EE6LXNJV.js +0 -34
  59. package/dist/chunk-F6DX3HXZ.js +0 -101
  60. package/dist/chunk-OVFMKC2O.js +0 -15
  61. package/dist/chunk-RQC6OMVV.js +0 -86
  62. package/dist/chunk-UFUHHR2J.js +0 -38
  63. package/dist/chunk-YVJEZPPZ.js +0 -989
  64. package/dist/errors-itGaU4Q8.d.cts +0 -17
  65. package/dist/errors-itGaU4Q8.d.ts +0 -17
  66. package/dist/formats/env.cjs +0 -103
  67. package/dist/formats/env.d.cts +0 -8
  68. package/dist/formats/env.d.ts +0 -8
  69. package/dist/formats/env.js +0 -1
  70. package/dist/formats/json.cjs +0 -15
  71. package/dist/formats/json.d.cts +0 -7
  72. package/dist/formats/json.d.ts +0 -7
  73. package/dist/formats/json.js +0 -1
  74. package/dist/formats/toml.cjs +0 -17
  75. package/dist/formats/toml.d.cts +0 -7
  76. package/dist/formats/toml.d.ts +0 -7
  77. package/dist/formats/toml.js +0 -1
  78. package/dist/formats/yaml.cjs +0 -40
  79. package/dist/formats/yaml.d.cts +0 -8
  80. package/dist/formats/yaml.d.ts +0 -8
  81. package/dist/formats/yaml.js +0 -1
@@ -1,1158 +1,5 @@
1
- 'use strict';
2
-
3
- var yaml = require('yaml');
4
- var smolToml = require('smol-toml');
5
-
6
- // src/errors.ts
7
- var SECRET_RE = /key|secret|token|password|private/i;
8
- function redactValue(key, value) {
9
- if (SECRET_RE.test(key) && typeof value === "string" && value.length > 0) {
10
- if (value.length <= 8) return "(redacted)";
11
- return `${value.slice(0, 3)}-*** (${value.length} chars)`;
12
- }
13
- return String(value);
14
- }
15
- function byteLengthUtf8(text) {
16
- try {
17
- const g = globalThis;
18
- if (g.TextEncoder) return new g.TextEncoder().encode(text).length;
19
- if (g.Buffer) return g.Buffer.byteLength(text, "utf8");
20
- } catch {
21
- }
22
- return text.length;
23
- }
24
- var ConfigError = class extends Error {
25
- code = "E_INVALID_CONFIG";
26
- issues;
27
- constructor(issues, code = "E_INVALID_CONFIG") {
28
- const lines = issues.map(
29
- (i) => `- ${i.path} (from ${i.from}): ${i.message}`
30
- );
31
- super(`Invalid config (${issues.length} issue${issues.length === 1 ? "" : "s"}):
32
- ${lines.join("\n")}`);
33
- this.name = "ConfigError";
34
- this.code = code;
35
- this.issues = issues;
36
- }
37
- };
38
-
39
- // src/formats/env.ts
40
- function parseEnvText(text) {
41
- const out = {};
42
- if (text.charCodeAt(0) === 65279) text = text.slice(1);
43
- const lines = splitLogicalLines(text);
44
- for (const rawLine of lines) {
45
- let line = rawLine.trim();
46
- if (!line || line.startsWith("#")) continue;
47
- if (line.startsWith("export ")) line = line.slice(7).trimStart();
48
- const eq = line.indexOf("=");
49
- if (eq === -1) {
50
- throw new Error(`ParseError: bare key without '=': ${JSON.stringify(line)}`);
51
- }
52
- const key = line.slice(0, eq).trim();
53
- let rest = line.slice(eq + 1).trimStart();
54
- if (!key) throw new Error("ParseError: empty key");
55
- out[key] = parseValue(rest);
56
- }
57
- return out;
58
- }
59
- function splitLogicalLines(text) {
60
- const physical = text.split(/\r?\n/);
61
- const out = [];
62
- let buf = "";
63
- let inDouble = false;
64
- for (const pl of physical) {
65
- if (!inDouble) {
66
- const opens = countUnescapedQuotes(pl);
67
- if (opens % 2 === 1 && isValueStartDoubleQuoted(pl)) {
68
- buf = pl;
69
- inDouble = true;
70
- } else {
71
- out.push(pl);
72
- }
73
- } else {
74
- buf += "\n" + pl;
75
- const opens = countUnescapedQuotes(buf.split("=").slice(1).join("="));
76
- if (opens % 2 === 0) {
77
- inDouble = false;
78
- out.push(buf);
79
- buf = "";
80
- }
81
- }
82
- }
83
- if (inDouble) throw new Error("ParseError: unterminated double-quoted value");
84
- return out;
85
- }
86
- function isValueStartDoubleQuoted(line) {
87
- const eq = line.indexOf("=");
88
- if (eq === -1) return false;
89
- const rest = line.slice(eq + 1).trimStart();
90
- return rest.startsWith('"') && !rest.endsWith('"');
91
- }
92
- function countUnescapedQuotes(s) {
93
- let n = 0;
94
- for (let i = 0; i < s.length; i++) {
95
- if (s[i] === '"' && s[i - 1] !== "\\") n++;
96
- }
97
- return n;
98
- }
99
- function parseValue(rest) {
100
- if (!rest) return "";
101
- if (rest.startsWith("'")) {
102
- const end = rest.indexOf("'", 1);
103
- if (end === -1) throw new Error("ParseError: unterminated single-quoted value");
104
- return rest.slice(1, end);
105
- }
106
- if (rest.startsWith('"')) {
107
- let i = 1;
108
- let val = "";
109
- while (i < rest.length) {
110
- const c = rest[i];
111
- if (c === "\\" && i + 1 < rest.length) {
112
- const n = rest[i + 1];
113
- if (n === "n") val += "\n";
114
- else if (n === "r") val += "\r";
115
- else if (n === "t") val += " ";
116
- else val += n;
117
- i += 2;
118
- continue;
119
- }
120
- if (c === '"') break;
121
- val += c;
122
- i++;
123
- }
124
- if (rest[i] !== '"') throw new Error("ParseError: unterminated double-quoted value");
125
- return val;
126
- }
127
- if (rest.startsWith("`")) throw new Error("ParseError: backtick values not supported");
128
- const hash = findCommentStart(rest);
129
- const v = (hash === -1 ? rest : rest.slice(0, hash)).trim();
130
- return v;
131
- }
132
- function findCommentStart(s) {
133
- for (let i = 0; i < s.length; i++) {
134
- if (s[i] === "#" && (i === 0 || /\s/.test(s[i - 1]))) return i;
135
- }
136
- return -1;
137
- }
138
-
139
- // src/formats/json.ts
140
- function parseJsonText(text, from = "json") {
141
- const stripped = text.charCodeAt(0) === 65279 ? text.slice(1) : text;
142
- if (!stripped.trim()) return {};
143
- try {
144
- return JSON.parse(stripped);
145
- } catch (e) {
146
- const err = e;
147
- throw new Error(`ParseError (${from}): ${err.message}`);
148
- }
149
- }
150
- function parseYamlText(text, from = "yaml") {
151
- const stripped = text.charCodeAt(0) === 65279 ? text.slice(1) : text;
152
- if (!stripped.trim()) return {};
153
- const docs = yaml.parseAllDocuments(stripped, {
154
- version: "1.2",
155
- uniqueKeys: true
156
- }).filter((d) => {
157
- if (d.errors.length > 0) return true;
158
- try {
159
- const v = d.toJS();
160
- return v !== null && v !== void 0;
161
- } catch {
162
- return true;
163
- }
164
- });
165
- if (docs.length === 0) return {};
166
- if (docs.length > 1) {
167
- throw new Error(`ParseError (${from}): multi-doc YAML not supported (got ${docs.length} documents)`);
168
- }
169
- const doc = docs[0];
170
- if (doc.errors.length > 0) {
171
- const first = doc.errors[0];
172
- const line = first.linePos?.[0]?.line ?? "?";
173
- throw new Error(`ParseError (${from}:${line}): ${first.message}`);
174
- }
175
- let value;
176
- try {
177
- value = doc.toJS();
178
- } catch (e) {
179
- throw new Error(`ParseError (${from}): ${e.message}`);
180
- }
181
- return value;
182
- }
183
- function parseTomlText(text, from = "toml") {
184
- const stripped = text.charCodeAt(0) === 65279 ? text.slice(1) : text;
185
- if (!stripped.trim()) return {};
186
- try {
187
- return smolToml.parse(stripped);
188
- } catch (e) {
189
- const err = e;
190
- throw new Error(`ParseError (${from}): ${err.message}`);
191
- }
192
- }
193
-
194
- // src/expand.ts
195
- var NAME_RE = "[A-Za-z_][A-Za-z0-9_]*";
196
- function expandValue(input, lookup, opts) {
197
- let out = "";
198
- let i = 0;
199
- while (i < input.length) {
200
- const c = input[i];
201
- if (c === "$" && input[i + 1] === "$") {
202
- out += "$";
203
- i += 2;
204
- continue;
205
- }
206
- if (c === "\\" && input[i + 1] === "$") {
207
- out += "$";
208
- i += 2;
209
- continue;
210
- }
211
- if (c !== "$") {
212
- out += c;
213
- i++;
214
- continue;
215
- }
216
- const rest = input.slice(i);
217
- if (rest.startsWith("${")) {
218
- const parsed = parseBraced(input, i);
219
- if (!parsed) {
220
- out += "$";
221
- i++;
222
- continue;
223
- }
224
- const { name: name2, op, def, end } = parsed;
225
- if (op && op !== ":-" && op !== "-") {
226
- throw new ConfigError([
227
- { path: name2, from: opts?.from ?? "env", message: `E_BAD_OP: only :- and - supported, got ${op}` }
228
- ], "E_BAD_OP");
229
- }
230
- const val2 = lookup(name2);
231
- const missing = val2 === void 0 || op === ":-" && val2 === "";
232
- if (!missing) {
233
- out += val2;
234
- } else if (def !== void 0) {
235
- out += expandValue(def, lookup, opts);
236
- } else if (opts?.allowUnresolved) {
237
- out += input.slice(i, end);
238
- } else {
239
- throw new ConfigError([
240
- { path: name2, from: opts?.from ?? "env", message: `E_UNRESOLVED: ${name2} missing (expand)` }
241
- ], "E_UNRESOLVED");
242
- }
243
- i = end;
244
- continue;
245
- }
246
- const m = new RegExp(`^\\$(?<name>${NAME_RE})`).exec(rest);
247
- if (!m || !m.groups) {
248
- out += "$";
249
- i++;
250
- continue;
251
- }
252
- const name = m.groups["name"];
253
- const val = lookup(name);
254
- if (val === void 0) {
255
- if (opts?.allowUnresolved) {
256
- out += "$" + name;
257
- } else {
258
- throw new ConfigError([
259
- { path: name, from: opts?.from ?? "env", message: `E_UNRESOLVED: ${name} missing (expand)` }
260
- ], "E_UNRESOLVED");
261
- }
262
- } else {
263
- out += val;
264
- }
265
- i += 1 + name.length;
266
- }
267
- return out;
268
- }
269
- function parseBraced(input, start) {
270
- let i = start + 2;
271
- const nameMatch = new RegExp(`^(?<name>${NAME_RE})`).exec(input.slice(i));
272
- if (!nameMatch?.groups) return null;
273
- const name = nameMatch.groups["name"];
274
- i += name.length;
275
- if (input[i] === "}") return { name, end: i + 1 };
276
- if (input[i] === ":") {
277
- const two = input.slice(i, i + 2);
278
- if (two !== ":-") return { name, op: two[0] + (input[i + 1] ?? ""), def: "", end: input.length };
279
- i += 2;
280
- const { value, end } = readUntilCloseBrace(input, i);
281
- return { name, op: ":-", def: value, end };
282
- }
283
- if (input[i] === "-") {
284
- i += 1;
285
- const { value, end } = readUntilCloseBrace(input, i);
286
- return { name, op: "-", def: value, end };
287
- }
288
- return null;
289
- }
290
- function readUntilCloseBrace(input, start) {
291
- let depth = 0;
292
- let i = start;
293
- let val = "";
294
- while (i < input.length) {
295
- if (input[i] === "\\" && input[i + 1] === "}") {
296
- val += "}";
297
- i += 2;
298
- continue;
299
- }
300
- if (input[i] === "{") depth++;
301
- if (input[i] === "}") {
302
- if (depth === 0) return { value: val, end: i + 1 };
303
- depth--;
304
- }
305
- val += input[i];
306
- i++;
307
- }
308
- throw new Error("ParseError: unterminated ${}");
309
- }
310
-
311
- // src/coerce.ts
312
- function tryParseEnvValue(input) {
313
- return tryParse(input, true);
314
- }
315
- function tryParse(input, allowSplit) {
316
- if (typeof input !== "string") return input;
317
- const s = input;
318
- if (s === "") return "";
319
- const low = s.toLowerCase();
320
- if (low === "true" || low === "false") return low === "true";
321
- if (low === "null") return null;
322
- if (low === "undefined") return void 0;
323
- if (/^-?\d+$/.test(s)) {
324
- const n = Number(s);
325
- if (Number.isSafeInteger(n)) return n;
326
- return s;
327
- }
328
- if (/^-?(\d+\.\d*|\.\d+|\d+)(e[+-]?\d+)?$/i.test(s) && s !== "-" && s !== ".") {
329
- const n = Number(s);
330
- if (Number.isFinite(n)) return n;
331
- return s;
332
- }
333
- if (["yes", "y", "on"].includes(low)) return true;
334
- if (["no", "n", "off"].includes(low)) return false;
335
- const t = s.trim();
336
- if (t.startsWith("{") && t.endsWith("}") || t.startsWith("[") && t.endsWith("]")) {
337
- try {
338
- return JSON.parse(t);
339
- } catch {
340
- return input;
341
- }
342
- }
343
- if (allowSplit && s.includes(",")) {
344
- const parts = splitCsv(s);
345
- if (parts !== null) return parts.map((p) => tryParse(p, false));
346
- }
347
- return input;
348
- }
349
- function splitCsv(s) {
350
- const out = [];
351
- let cur = "";
352
- let quote = null;
353
- for (let i = 0; i < s.length; i++) {
354
- const c = s[i];
355
- if (quote) {
356
- if (c === "\\" && i + 1 < s.length) {
357
- cur += c + s[i + 1];
358
- i++;
359
- continue;
360
- }
361
- if (c === quote) {
362
- quote = null;
363
- cur += c;
364
- continue;
365
- }
366
- cur += c;
367
- continue;
368
- }
369
- if (c === '"' || c === "'") {
370
- quote = c;
371
- cur += c;
372
- continue;
373
- }
374
- if (c === "\\" && s[i + 1] === ",") {
375
- cur += ",";
376
- i++;
377
- continue;
378
- }
379
- if (c === ",") {
380
- out.push(cur.trim());
381
- cur = "";
382
- continue;
383
- }
384
- cur += c;
385
- }
386
- if (quote) return null;
387
- out.push(cur.trim());
388
- return out.map((p) => {
389
- if (p.length >= 2 && p.startsWith("'") && p.endsWith("'")) return p.slice(1, -1).replace(/\\,/g, ",");
390
- if (p.length >= 2 && p.startsWith('"') && p.endsWith('"')) return p.slice(1, -1);
391
- return p.replace(/\\,/g, ",");
392
- });
393
- }
394
- function coerceDeep(value) {
395
- if (typeof value === "string") return tryParseEnvValue(value);
396
- if (Array.isArray(value)) return value.map(coerceDeep);
397
- if (value && typeof value === "object") {
398
- const o = {};
399
- for (const [k, v] of Object.entries(value)) o[k] = coerceDeep(v);
400
- return o;
401
- }
402
- return value;
403
- }
404
-
405
- // src/merge.ts
406
- var FORBIDDEN = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
407
- var INDEX_RE = /^(0|[1-9][0-9]*)$/;
408
- function stripPrefix(key, prefix) {
409
- return key;
410
- }
411
- function expandKeys(flat, opts) {
412
- const out = {};
413
- const topKinds = /* @__PURE__ */ new Map();
414
- const kindOf = (top) => {
415
- let k = topKinds.get(top);
416
- if (!k) {
417
- k = { indexed: false, named: false, scalar: false };
418
- topKinds.set(top, k);
419
- }
420
- return k;
421
- };
422
- const lookupEnvMap = (rawKey) => {
423
- if (!opts?.envMap) return void 0;
424
- for (const cand of [rawKey, rawKey.toLowerCase(), rawKey.toUpperCase()]) {
425
- const hit = opts.envMap[cand];
426
- if (hit !== void 0) return hit;
427
- }
428
- return void 0;
429
- };
430
- for (const [rawKey, value] of Object.entries(flat)) {
431
- if (!/^[A-Za-z0-9_]+$/.test(rawKey)) continue;
432
- const escaped = lookupEnvMap(rawKey);
433
- const effective = escaped ?? rawKey;
434
- if (escaped !== void 0) {
435
- const k = effective.toLowerCase();
436
- if (FORBIDDEN.has(k)) throw new ConfigError([{ path: rawKey, from: "keys", message: "E_PROTO" }], "E_PROTO");
437
- out[k] = value;
438
- continue;
439
- }
440
- const stripped = stripPrefix(rawKey);
441
- if (stripped === null) continue;
442
- const useKey = stripped;
443
- if (FORBIDDEN.has(useKey.toLowerCase())) throw new ConfigError([{ path: rawKey, from: "keys", message: "E_PROTO: forbidden key" }], "E_PROTO");
444
- const parts = useKey.split("__");
445
- const cleanSplit = parts.length > 1 && parts.every((p) => p !== "");
446
- if (cleanSplit) {
447
- for (const p of parts) {
448
- if (FORBIDDEN.has(p.toLowerCase())) throw new ConfigError([{ path: rawKey, from: "keys", message: "E_PROTO: forbidden key" }], "E_PROTO");
449
- }
450
- const lowered = parts.map((p) => p.toLowerCase());
451
- const top = lowered[0];
452
- const kind = kindOf(top);
453
- const childIsIndex = lowered.length > 1 && INDEX_RE.test(lowered[1]);
454
- if (kind.scalar && childIsIndex) {
455
- throw new ConfigError(
456
- [{ path: rawKey, from: "keys", message: `E_ARRAY_MIX: '${top}' has both scalar/list and indexed (__0) values in the same layer` }],
457
- "E_ARRAY_MIX"
458
- );
459
- }
460
- if (childIsIndex) {
461
- if (kind.named) {
462
- throw new ConfigError(
463
- [{ path: rawKey, from: "keys", message: `E_ARRAY_MIX: '${top}' mixes indexed (__0) and named children in the same layer` }],
464
- "E_ARRAY_MIX"
465
- );
466
- }
467
- kind.indexed = true;
468
- } else if (lowered.length > 1) {
469
- if (kind.indexed) {
470
- throw new ConfigError(
471
- [{ path: rawKey, from: "keys", message: `E_ARRAY_MIX: '${top}' mixes named and indexed (__0) children in the same layer` }],
472
- "E_ARRAY_MIX"
473
- );
474
- }
475
- kind.named = true;
476
- }
477
- setPath(out, lowered, value);
478
- } else {
479
- const k = useKey.toLowerCase();
480
- const kind = kindOf(k);
481
- if (kind.indexed) {
482
- throw new ConfigError(
483
- [{ path: rawKey, from: "keys", message: `E_ARRAY_MIX: '${k}' has both indexed (__0) and scalar/list values in the same layer` }],
484
- "E_ARRAY_MIX"
485
- );
486
- }
487
- kind.scalar = true;
488
- out[k] = value;
489
- }
490
- }
491
- return out;
492
- }
493
- function normalizeIndexedObjects(value, path = "<root>") {
494
- if (Array.isArray(value)) return value.map((x, i) => normalizeIndexedObjects(x, `${path}[${i}]`));
495
- if (!isPlainObject(value)) return value;
496
- const entries = Object.entries(value);
497
- const normalized = {};
498
- for (const [k, v] of entries) {
499
- normalized[k] = normalizeIndexedObjects(v, path === "<root>" ? k : `${path}.${k}`);
500
- }
501
- if (entries.length > 0 && entries.every(([k]) => INDEX_RE.test(k))) {
502
- const idx = entries.map(([k]) => Number(k)).sort((a, b) => a - b);
503
- if (idx.length > 1024) {
504
- throw new ConfigError([{ path, from: "keys", message: "E_ARRAY_CAP: >1024 elements" }], "E_ARRAY_CAP");
505
- }
506
- for (let i = 0; i < idx.length; i++) {
507
- if (idx[i] !== i) {
508
- throw new ConfigError(
509
- [{ path, from: "keys", message: `E_SPARSE_ARRAY: indexes [${idx.join(",")}] are not dense 0..${idx.length - 1}` }],
510
- "E_SPARSE_ARRAY"
511
- );
512
- }
513
- }
514
- return idx.map((_, i) => normalized[String(i)]);
515
- }
516
- return normalized;
517
- }
518
- function setPath(root, parts, value) {
519
- let cur = root;
520
- for (let i = 0; i < parts.length - 1; i++) {
521
- const p = parts[i];
522
- const existing = cur[p];
523
- if (existing && typeof existing === "object" && !Array.isArray(existing)) {
524
- cur = existing;
525
- } else {
526
- const n = {};
527
- cur[p] = n;
528
- cur = n;
529
- }
530
- }
531
- cur[parts[parts.length - 1]] = value;
532
- }
533
- function isPlainObject(v) {
534
- if (!v || typeof v !== "object") return false;
535
- const proto = Object.getPrototypeOf(v);
536
- return proto === Object.prototype || proto === null;
537
- }
538
- function deepMerge(base, override, arrayStrategy = "replace") {
539
- if (override === void 0) return base;
540
- if (base === void 0) return override;
541
- if (override === null) return null;
542
- if (Array.isArray(base) && Array.isArray(override)) {
543
- if (arrayStrategy === "replace") return override;
544
- if (arrayStrategy === "concat") return [...base, ...override];
545
- const len = Math.max(base.length, override.length);
546
- if (len > 1024) throw new ConfigError([{ path: "<array>", from: "merge", message: "E_ARRAY_CAP: >1024" }], "E_ARRAY_CAP");
547
- const out = [];
548
- for (let i = 0; i < len; i++) {
549
- if (i in override) {
550
- out[i] = i in base ? deepMerge(base[i], override[i], arrayStrategy) : override[i];
551
- } else if (i in base) {
552
- out[i] = base[i];
553
- }
554
- }
555
- for (let i = 0; i < len; i++) {
556
- if (!(i in out)) {
557
- throw new ConfigError(
558
- [{ path: `<array>[${i}]`, from: "merge", message: "E_SPARSE_ARRAY: hole at index " + i }],
559
- "E_SPARSE_ARRAY"
560
- );
561
- }
562
- }
563
- return out;
564
- }
565
- if (isPlainObject(base) && isPlainObject(override)) {
566
- const out = { ...base };
567
- for (const [k, v] of Object.entries(override)) {
568
- if (FORBIDDEN.has(k)) throw new ConfigError([{ path: k, from: "merge", message: "E_PROTO" }], "E_PROTO");
569
- out[k] = k in out ? deepMerge(out[k], v, arrayStrategy) : v;
570
- }
571
- return out;
572
- }
573
- return override;
574
- }
575
-
576
- // src/adapter.ts
577
- function normalizePath(path) {
578
- if (!path || path.length === 0) return "<root>";
579
- const parts = [];
580
- for (const seg of path) {
581
- if (seg !== null && typeof seg === "object" && "key" in seg) {
582
- parts.push(String(seg.key));
583
- } else {
584
- parts.push(String(seg));
585
- }
586
- }
587
- return parts.join(".");
588
- }
589
- function validateStandard(schema, input) {
590
- let r;
591
- try {
592
- r = schema["~standard"].validate(input);
593
- } catch (e) {
594
- const msg = e instanceof Error ? e.message : String(e);
595
- return { issues: [{ path: "<root>", message: msg }], async: false };
596
- }
597
- if (typeof r?.then === "function") {
598
- const p = r.then(
599
- (resolved) => normalizeResult(resolved),
600
- (e) => ({ ok: false, issues: [{ path: "<root>", message: e instanceof Error ? e.message : String(e) }] })
601
- );
602
- return { promise: p };
603
- }
604
- const n = normalizeResult(r);
605
- if (!n.ok) return { issues: n.issues, async: false };
606
- return { value: n.value };
607
- }
608
- function normalizeResult(r) {
609
- if (!r.issues || r.issues.length === 0) {
610
- return { ok: true, value: r.value };
611
- }
612
- return {
613
- ok: false,
614
- issues: r.issues.map((i) => ({ path: normalizePath(i.path), message: i.message }))
615
- };
616
- }
617
-
618
- // src/index.ts
619
- function getEnvSnapshot(injected) {
620
- if (injected) return injected;
621
- const g = globalThis;
622
- if (g.process?.env) return { ...g.process.env };
623
- return {};
624
- }
625
- function isSecretKey(key) {
626
- return /key|secret|token|password|private/i.test(key);
627
- }
628
- function pickPublic(cfg, keys) {
629
- const out = {};
630
- for (const k of keys) if (k in cfg) out[k] = cfg[k];
631
- return out;
632
- }
633
- function readFileSyncSafe(path, maxBytes = 2 * 1024 * 1024) {
634
- const getFs = () => {
635
- const injected = globalThis.__typedSettingsFs;
636
- if (injected) return injected;
637
- const g = globalThis;
638
- if (g.process) {
639
- const fn = new Function('return typeof require !== "undefined" ? require("node:fs") : null')();
640
- if (!fn) {
641
- throw new ConfigError(
642
- [{ path, from: path, message: "E_NO_FS: file sources need `typed-settings/node` under ESM (or pass { text }/{ map })" }],
643
- "E_NO_FS"
644
- );
645
- }
646
- return fn;
647
- }
648
- return null;
649
- };
650
- try {
651
- const fs = getFs();
652
- if (!fs) return void 0;
653
- const text = fs.readFileSync(path, "utf8");
654
- if (byteLengthUtf8(text) > maxBytes) {
655
- throw new ConfigError(
656
- [{ path, from: path, message: `E_FILE_TOO_LARGE: >${maxBytes} bytes` }],
657
- "E_FILE_TOO_LARGE"
658
- );
659
- }
660
- return text;
661
- } catch (e) {
662
- if (e instanceof ConfigError) throw e;
663
- const err = e;
664
- if (err?.code === "ENOENT") return void 0;
665
- throw e;
666
- }
667
- }
668
- function parseStructuredFile(path, text) {
669
- const lower = path.toLowerCase();
670
- try {
671
- if (lower.endsWith(".json")) return parseJsonText(text, path);
672
- if (lower.endsWith(".yaml") || lower.endsWith(".yml")) return parseYamlText(text, path);
673
- return parseTomlText(text, path);
674
- } catch (e) {
675
- const err = e;
676
- throw new ConfigError([{ path, from: path, message: err.message }], "E_PARSE");
677
- }
678
- }
679
- function stripFlatKey(key, effPrefix) {
680
- if (!effPrefix) return key;
681
- if (key.length <= effPrefix.length) return null;
682
- if (key.slice(0, effPrefix.length).toLowerCase() !== effPrefix.toLowerCase()) return null;
683
- return key.slice(effPrefix.length);
684
- }
685
- function assertAcyclic(value, label) {
686
- const visiting = /* @__PURE__ */ new Set();
687
- const visit = (v, path) => {
688
- if (!v || typeof v !== "object") return;
689
- if (visiting.has(v)) {
690
- throw new ConfigError(
691
- [{ path, from: label, message: `E_CYCLE: cyclic value at ${path} (from ${label})` }],
692
- "E_CYCLE"
693
- );
694
- }
695
- visiting.add(v);
696
- try {
697
- for (const [k, child] of Object.entries(v)) visit(child, path ? `${path}.${k}` : k);
698
- } finally {
699
- visiting.delete(v);
700
- }
701
- };
702
- visit(value, "");
703
- }
704
- function flatToLayer(m, label, srcPrefix, globalPrefix, opts, skipExpand) {
705
- assertAcyclic(m, label);
706
- const effPrefix = srcPrefix ?? globalPrefix;
707
- const stripped = {};
708
- for (const [k, v] of Object.entries(m)) {
709
- const s = stripFlatKey(k, effPrefix);
710
- if (s === null) continue;
711
- stripped[s] = v;
712
- }
713
- const node = normalizeIndexedObjects(
714
- expandKeys(stripped, { envMap: opts.envMap })
715
- );
716
- return { node, label, skipExpand };
717
- }
718
- function structuredToLayer(value, label, prefix) {
719
- assertAcyclic(value, label);
720
- if (!isPlainObject(value)) return { node: value ?? {}, label, skipExpand: false };
721
- const out = {};
722
- for (const [k, v] of Object.entries(value)) {
723
- if (["__proto__", "constructor", "prototype"].includes(k)) {
724
- throw new ConfigError([{ path: k, from: label, message: "E_PROTO: forbidden key" }], "E_PROTO");
725
- }
726
- if (prefix) {
727
- const s = stripFlatKey(k, prefix);
728
- if (s === null) continue;
729
- out[s] = v;
730
- } else {
731
- out[k] = v;
732
- }
733
- }
734
- return { node: out, label, skipExpand: false };
735
- }
736
- function recordLayerFrom(fromMap, layer) {
737
- const node = layer.node;
738
- if (node && typeof node === "object" && !Array.isArray(node)) {
739
- for (const k of Object.keys(node)) fromMap.set(k.toLowerCase(), layer.label);
740
- }
741
- }
742
- function isThenable(v) {
743
- return !!v && (typeof v === "object" || typeof v === "function") && typeof v.then === "function";
744
- }
745
- function asProvider(src) {
746
- if (!("provider" in src || "load" in src)) return null;
747
- const prov = "provider" in src ? src.provider : src;
748
- if (!prov || typeof prov.load !== "function") return null;
749
- return { load: prov.load, name: typeof prov.name === "string" ? prov.name : "<provider>" };
750
- }
751
- function timeoutError(name) {
752
- return new ConfigError([{ path: name, from: name, message: "E_TIMEOUT: provider load timed out" }], "E_TIMEOUT");
753
- }
754
- function collectSources(opts, envSnapshot) {
755
- const sources = opts.sources ?? [".env", "env"];
756
- const prefix = opts.prefix;
757
- const layers = [];
758
- const fromMap = /* @__PURE__ */ new Map();
759
- const maxBytes = opts.maxBytes ?? 2 * 1024 * 1024;
760
- const push = (layer) => {
761
- layers.push(layer);
762
- recordLayerFrom(fromMap, layer);
763
- };
764
- const parseEnv = (text, label) => {
765
- try {
766
- return parseEnvText(text);
767
- } catch (e) {
768
- const err = e;
769
- throw new ConfigError([{ path: label, from: label, message: err.message }], "E_PARSE");
770
- }
771
- };
772
- for (const src of sources) {
773
- if (src === "env") {
774
- push(flatToLayer({ ...envSnapshot }, "env", void 0, prefix, opts, false));
775
- } else if (src === ".env" || src === ".env.local") {
776
- const text = readFileSyncSafe(src, maxBytes);
777
- if (text === void 0) continue;
778
- push(flatToLayer(parseEnv(text, src), src, void 0, prefix, opts, false));
779
- } else if (typeof src === "string") {
780
- const text = readFileSyncSafe(src, maxBytes);
781
- if (text === void 0) continue;
782
- const lower = src.toLowerCase();
783
- if (lower.endsWith(".json") || lower.endsWith(".yaml") || lower.endsWith(".yml") || lower.endsWith(".toml")) {
784
- push(structuredToLayer(parseStructuredFile(src, text), src, prefix));
785
- } else {
786
- push(flatToLayer(parseEnv(text, src), src, void 0, prefix, opts, false));
787
- }
788
- } else if (src && typeof src === "object" && "text" in src) {
789
- push(flatToLayer(parseEnv(src.text, "text"), "text", void 0, prefix, opts, false));
790
- } else if (src && typeof src === "object" && "map" in src) {
791
- const m = src;
792
- push(flatToLayer(m.map ?? {}, "overrides", m.prefix, prefix, opts, false));
793
- } else if (src && typeof src === "object" && "file" in src) {
794
- const p = src.file;
795
- const text = readFileSyncSafe(p, maxBytes);
796
- if (text === void 0) continue;
797
- const lower = p.toLowerCase();
798
- if (lower.endsWith(".json") || lower.endsWith(".yaml") || lower.endsWith(".yml") || lower.endsWith(".toml")) {
799
- push(structuredToLayer(parseStructuredFile(p, text), p, prefix));
800
- } else {
801
- push(flatToLayer(parseEnv(text, p), p, void 0, prefix, opts, false));
802
- }
803
- } else if (src && typeof src === "object" && "dir" in src) {
804
- continue;
805
- } else if (src && typeof src === "object") {
806
- const prov = asProvider(src);
807
- if (prov) {
808
- const srcPrefix = "prefix" in src ? src.prefix : void 0;
809
- const loaded = prov.load();
810
- if (isThenable(loaded)) {
811
- throw new ConfigError(
812
- [{ path: "<provider>", from: prov.name, message: "USE_ASYNC: provider is async, use settingsAsync()" }],
813
- "USE_ASYNC"
814
- );
815
- }
816
- push(flatToLayer(loaded ?? {}, prov.name, srcPrefix, prefix, opts, !opts.expandSecrets));
817
- } else {
818
- push(flatToLayer(src, "overrides", void 0, prefix, opts, false));
819
- }
820
- }
821
- }
822
- return { layers, fromMap };
823
- }
824
- async function collectSourcesAsync(opts, envSnapshot) {
825
- const timeoutMs = opts.timeoutMs ?? 5e3;
826
- const needsAsync = (opts.sources ?? []).some((s) => s && typeof s === "object" && asProvider(s) !== null);
827
- if (!needsAsync) return collectSources(opts, envSnapshot);
828
- const sources = opts.sources;
829
- const prefix = opts.prefix;
830
- const layers = [];
831
- const fromMap = /* @__PURE__ */ new Map();
832
- const maxBytes = opts.maxBytes ?? 2 * 1024 * 1024;
833
- const push = (layer) => {
834
- layers.push(layer);
835
- recordLayerFrom(fromMap, layer);
836
- };
837
- const parseEnv = (text, label) => {
838
- try {
839
- return parseEnvText(text);
840
- } catch (e) {
841
- const err = e;
842
- throw new ConfigError([{ path: label, from: label, message: err.message }], "E_PARSE");
843
- }
844
- };
845
- const withTimeout = async (name, fn) => {
846
- let t;
847
- const timeout = new Promise((_, rej) => {
848
- t = setTimeout(() => rej(timeoutError(name)), timeoutMs);
849
- });
850
- const winner = await Promise.race([Promise.resolve().then(fn), timeout]).catch((e) => {
851
- clearTimeout(t);
852
- if (e instanceof ConfigError) throw e;
853
- const err = e;
854
- throw new ConfigError(
855
- [{ path: name, from: name, message: `E_PROVIDER: ${err?.message ?? String(e)}` }],
856
- "E_PROVIDER"
857
- );
858
- });
859
- clearTimeout(t);
860
- return winner;
861
- };
862
- for (const src of sources) {
863
- if (src === "env") {
864
- push(flatToLayer({ ...envSnapshot }, "env", void 0, prefix, opts, false));
865
- } else if (src === ".env" || src === ".env.local") {
866
- const text = readFileSyncSafe(src, maxBytes);
867
- if (text === void 0) continue;
868
- push(flatToLayer(parseEnv(text, src), src, void 0, prefix, opts, false));
869
- } else if (typeof src === "string") {
870
- const text = readFileSyncSafe(src, maxBytes);
871
- if (text === void 0) continue;
872
- const lower = src.toLowerCase();
873
- if (lower.endsWith(".json") || lower.endsWith(".yaml") || lower.endsWith(".yml") || lower.endsWith(".toml")) {
874
- push(structuredToLayer(parseStructuredFile(src, text), src, prefix));
875
- } else {
876
- push(flatToLayer(parseEnv(text, src), src, void 0, prefix, opts, false));
877
- }
878
- } else if (src && typeof src === "object" && "text" in src) {
879
- push(flatToLayer(parseEnv(src.text, "text"), "text", void 0, prefix, opts, false));
880
- } else if (src && typeof src === "object" && "map" in src) {
881
- const m = src;
882
- push(flatToLayer(m.map ?? {}, "overrides", m.prefix, prefix, opts, false));
883
- } else if (src && typeof src === "object" && "file" in src) {
884
- const p = src.file;
885
- const text = readFileSyncSafe(p, maxBytes);
886
- if (text === void 0) continue;
887
- const lower = p.toLowerCase();
888
- if (lower.endsWith(".json") || lower.endsWith(".yaml") || lower.endsWith(".yml") || lower.endsWith(".toml")) {
889
- push(structuredToLayer(parseStructuredFile(p, text), p, prefix));
890
- } else {
891
- push(flatToLayer(parseEnv(text, p), p, void 0, prefix, opts, false));
892
- }
893
- } else if (src && typeof src === "object" && "dir" in src) {
894
- continue;
895
- } else if (src && typeof src === "object") {
896
- const prov = asProvider(src);
897
- if (prov) {
898
- const srcPrefix = "prefix" in src ? src.prefix : void 0;
899
- const loaded = await withTimeout(prov.name, () => prov.load());
900
- push(flatToLayer(loaded ?? {}, prov.name, srcPrefix, prefix, opts, !opts.expandSecrets));
901
- } else {
902
- push(flatToLayer(src, "overrides", void 0, prefix, opts, false));
903
- }
904
- }
905
- }
906
- return { layers, fromMap };
907
- }
908
- function buildConfigObject(opts, envSnapshot) {
909
- const { layers, fromMap } = collectSources(opts, envSnapshot);
910
- const arrayStrategy = opts.arrayStrategy ?? "replace";
911
- let merged = {};
912
- for (const layer of layers) {
913
- merged = deepMerge(merged, layer.node, arrayStrategy);
914
- }
915
- const skipTops = new Set(
916
- layers.filter((l) => l.skipExpand).flatMap((l) => Object.keys(l.node)).map((k) => k.toLowerCase())
917
- );
918
- if (opts.expand !== false) {
919
- merged = expandDeepStrings(merged, makeLookup(merged, envSnapshot), {
920
- allowUnresolved: opts.allowUnresolved,
921
- fromMap,
922
- skipTops
923
- });
924
- }
925
- if (opts.coerce !== false) {
926
- merged = coerceDeep(merged);
927
- }
928
- const fromFor = (path) => {
929
- const top = path.split(".")[0].toLowerCase();
930
- if (top === "<root>") return "schema";
931
- return fromMap.get(top) ?? "defaults";
932
- };
933
- return { input: merged, fromFor };
934
- }
935
- function makeLookup(merged, envSnapshot) {
936
- const rec = merged && typeof merged === "object" && !Array.isArray(merged) ? merged : {};
937
- const ciKeys = new Map(Object.keys(rec).map((k) => [k.toLowerCase(), k]));
938
- return (name) => {
939
- const hit = ciKeys.get(name.toLowerCase());
940
- if (hit !== void 0) {
941
- const direct = rec[hit];
942
- if (typeof direct === "string") return direct;
943
- if (direct !== void 0 && direct !== null) return String(direct);
944
- }
945
- return envSnapshot[name] ?? envSnapshot[name.toUpperCase()] ?? envSnapshot[name.toLowerCase()];
946
- };
947
- }
948
- function expandDeepStrings(obj, lookup, ctx, path = []) {
949
- if (typeof obj === "string") {
950
- const top = (path[0] ?? "<root>").toLowerCase();
951
- const from = ctx.fromMap.get(top) ?? "config";
952
- try {
953
- return expandLeaf(obj, lookup, { ...ctx, from }, path.map((p) => p.toLowerCase()));
954
- } catch (e) {
955
- if (from === "env") return obj;
956
- throw e;
957
- }
958
- }
959
- if (Array.isArray(obj)) return obj.map((x, i) => expandDeepStrings(x, lookup, ctx, [...path, String(i)]));
960
- if (obj && typeof obj === "object") {
961
- if (path.length === 0) {
962
- const o2 = {};
963
- for (const [k, v] of Object.entries(obj)) {
964
- o2[k] = ctx.skipTops.has(k.toLowerCase()) ? v : expandDeepStrings(v, lookup, ctx, [k]);
965
- }
966
- return o2;
967
- }
968
- const o = {};
969
- for (const [k, v] of Object.entries(obj)) o[k] = expandDeepStrings(v, lookup, ctx, [...path, k]);
970
- return o;
971
- }
972
- return obj;
973
- }
974
- function expandLeaf(value, lookup, ctx, stack) {
975
- return expandValue(
976
- value,
977
- (name) => {
978
- const lower = name.toLowerCase();
979
- if (stack.includes(lower)) {
980
- throw new ConfigError(
981
- [{ path: name, from: ctx.from, message: `E_CIRCULAR: $${[...stack, name].join("->$")}` }],
982
- "E_CIRCULAR"
983
- );
984
- }
985
- const raw = lookup(name);
986
- if (raw === void 0) return void 0;
987
- if (raw.includes("$")) return expandLeaf(raw, lookup, ctx, [...stack, lower]);
988
- return raw;
989
- },
990
- { allowUnresolved: ctx.allowUnresolved, from: ctx.from }
991
- );
992
- }
993
- function collectLeafPaths(v, prefix = "") {
994
- if (Array.isArray(v)) {
995
- const out = [];
996
- v.forEach((x, i) => out.push(...collectLeafPaths(x, prefix ? `${prefix}.${i}` : `${i}`)));
997
- return out;
998
- }
999
- if (isPlainObject(v)) {
1000
- const out = [];
1001
- for (const [k, val] of Object.entries(v)) {
1002
- const p = prefix ? `${prefix}.${k.toLowerCase()}` : k.toLowerCase();
1003
- if (isPlainObject(val) || Array.isArray(val)) out.push(...collectLeafPaths(val, p));
1004
- else out.push(p);
1005
- }
1006
- return out;
1007
- }
1008
- return prefix ? [prefix.toLowerCase()] : [];
1009
- }
1010
- function applyUnknownKeys(input, value, mode) {
1011
- if (mode === "strip" || mode === void 0) return value;
1012
- if (mode === "preserve") {
1013
- if (isPlainObject(input) && isPlainObject(value)) return deepMerge(input, value, "replace");
1014
- return value;
1015
- }
1016
- const inputPaths = new Set(collectLeafPaths(input));
1017
- const valuePaths = new Set(collectLeafPaths(value));
1018
- const unknown = [...inputPaths].filter((p) => !valuePaths.has(p));
1019
- if (unknown.length > 0) {
1020
- throw new ConfigError(
1021
- unknown.map((p) => ({ path: p, from: "schema", message: "E_UNKNOWN_KEY: unknown key (unknownKeys=reject)" })),
1022
- "E_UNKNOWN_KEY"
1023
- );
1024
- }
1025
- return value;
1026
- }
1027
- function freezeDeep(v) {
1028
- if (Array.isArray(v)) {
1029
- for (const x of v) freezeDeep(x);
1030
- return Object.freeze(v);
1031
- }
1032
- if (v && typeof v === "object") {
1033
- for (const k of Object.keys(v)) freezeDeep(v[k]);
1034
- return Object.freeze(v);
1035
- }
1036
- return v;
1037
- }
1038
- function settings(opts) {
1039
- const envSnapshot = getEnvSnapshot(opts.env);
1040
- const { input, fromFor } = buildConfigObject(opts, envSnapshot);
1041
- const r = validateStandard(opts.schema, input);
1042
- if ("promise" in r) {
1043
- throw new ConfigError(
1044
- [{ path: "<root>", from: "schema", message: "USE_ASYNC: schema is async, use settingsAsync()" }],
1045
- "USE_ASYNC"
1046
- );
1047
- }
1048
- if ("issues" in r) {
1049
- throw new ConfigError(
1050
- r.issues.map((i) => ({ path: i.path, from: fromFor(i.path), message: maskIfSecret(i.path, i.message, input) }))
1051
- );
1052
- }
1053
- const value = r.value;
1054
- const final = applyUnknownKeys(input, value, opts.unknownKeys ?? "strip");
1055
- return opts.freeze === false ? final : freezeDeep(final);
1056
- }
1057
- async function settingsAsync(opts) {
1058
- const timeoutMs = opts.timeoutMs ?? 5e3;
1059
- const envSnapshot = getEnvSnapshot(opts.env);
1060
- const { input, fromFor } = await buildConfigObjectAsync(opts, envSnapshot);
1061
- const r = validateStandard(opts.schema, input);
1062
- if ("promise" in r) {
1063
- const raced = await Promise.race([
1064
- r.promise,
1065
- new Promise((_, rej) => setTimeout(() => rej(new ConfigError([{ path: "<root>", from: "schema", message: "E_TIMEOUT" }], "E_TIMEOUT")), timeoutMs))
1066
- ]);
1067
- if (!raced.ok) {
1068
- throw new ConfigError(raced.issues.map((i) => ({ path: i.path, from: fromFor(i.path), message: maskIfSecret(i.path, i.message, input) })));
1069
- }
1070
- const value2 = raced.value;
1071
- const final2 = applyUnknownKeys(input, value2, opts.unknownKeys ?? "strip");
1072
- return opts.freeze === false ? final2 : freezeDeep(final2);
1073
- }
1074
- if ("issues" in r) {
1075
- throw new ConfigError(r.issues.map((i) => ({ path: i.path, from: fromFor(i.path), message: maskIfSecret(i.path, i.message, input) })));
1076
- }
1077
- const value = r.value;
1078
- const final = applyUnknownKeys(input, value, opts.unknownKeys ?? "strip");
1079
- return opts.freeze === false ? final : freezeDeep(final);
1080
- }
1081
- async function buildConfigObjectAsync(opts, envSnapshot) {
1082
- const { layers, fromMap } = await collectSourcesAsync(opts, envSnapshot);
1083
- const arrayStrategy = opts.arrayStrategy ?? "replace";
1084
- let merged = {};
1085
- for (const layer of layers) {
1086
- merged = deepMerge(merged, layer.node, arrayStrategy);
1087
- }
1088
- const skipTops = new Set(
1089
- layers.filter((l) => l.skipExpand).flatMap((l) => Object.keys(l.node)).map((k) => k.toLowerCase())
1090
- );
1091
- if (opts.expand !== false) {
1092
- merged = expandDeepStrings(merged, makeLookup(merged, envSnapshot), {
1093
- allowUnresolved: opts.allowUnresolved,
1094
- fromMap,
1095
- skipTops
1096
- });
1097
- }
1098
- if (opts.coerce !== false) merged = coerceDeep(merged);
1099
- const fromFor = (path) => {
1100
- const top = path.split(".")[0].toLowerCase();
1101
- if (top === "<root>") return "schema";
1102
- return fromMap.get(top) ?? "defaults";
1103
- };
1104
- return { input: merged, fromFor };
1105
- }
1106
- function getLeafByPath(input, path) {
1107
- const parts = path.split(".");
1108
- let cur = input;
1109
- for (const part of parts) {
1110
- if (cur === null || typeof cur !== "object") return void 0;
1111
- if (Array.isArray(cur)) {
1112
- const m = /\[(\d+)\]/.exec(part);
1113
- const idx = m ? Number(m[1]) : Number(part);
1114
- if (!Number.isInteger(idx)) return void 0;
1115
- cur = cur[idx];
1116
- continue;
1117
- }
1118
- const rec = cur;
1119
- const found = Object.keys(rec).find((k) => k.toLowerCase() === part.toLowerCase());
1120
- if (!found) return void 0;
1121
- cur = rec[found];
1122
- }
1123
- return cur;
1124
- }
1125
- function base64Of(s) {
1126
- try {
1127
- const g = globalThis;
1128
- if (g.btoa) return g.btoa(s);
1129
- if (g.Buffer) return g.Buffer.from(s, "utf8").toString("base64");
1130
- } catch {
1131
- }
1132
- return null;
1133
- }
1134
- function maskIfSecret(path, message, input) {
1135
- if (!isSecretKey(path)) return message;
1136
- let out = message;
1137
- const leaf = getLeafByPath(input, path);
1138
- if (typeof leaf === "string" && leaf.length > 0) {
1139
- const redacted = redactValue(path, leaf);
1140
- out = out.split(leaf).join(redacted);
1141
- const b64 = base64Of(leaf);
1142
- if (b64 && b64.length > 8) out = out.split(b64).join(redacted);
1143
- }
1144
- return `${out} (redacted)`;
1145
- }
1146
-
1147
- // src/framework/next.ts
1148
- function publicSettings(cfg, keys) {
1149
- const out = {};
1150
- for (const k of keys) if (k in cfg) out[k] = cfg[k];
1151
- return out;
1152
- }
1153
-
1154
- exports.ConfigError = ConfigError;
1155
- exports.pickPublic = pickPublic;
1156
- exports.publicSettings = publicSettings;
1157
- exports.settings = settings;
1158
- exports.settingsAsync = settingsAsync;
1
+ 'use strict';var yaml=require('yaml'),smolToml=require('smol-toml');var we=/key|secret|token|password|private/i;function C(e,n){if(we.test(e))return true;if(n){for(let t of n)if(typeof t=="string"){if(t&&e.toLowerCase().includes(t.toLowerCase()))return true}else if(t instanceof RegExp){if(t.lastIndex=0,t.test(e))return true}else if(t!==null&&typeof t=="object"&&typeof t.test=="function"&&t.test(e))return true}return false}function q(e,n,t){return C(e,t)&&typeof n=="string"&&n.length>0?n.length<=8?"(redacted)":`(redacted: ${n.length} chars)`:String(n)}function G(e){try{let n=globalThis;if(n.TextEncoder)return new n.TextEncoder().encode(e).length;if(n.Buffer)return n.Buffer.byteLength(e,"utf8")}catch{}return e.length}var l=class extends Error{code="E_INVALID_CONFIG";issues;static[Symbol.hasInstance](n){return typeof n=="object"&&n!==null&&n.name==="ConfigError"&&typeof n.code=="string"&&Array.isArray(n.issues)}constructor(n=[],t="E_INVALID_CONFIG"){let s=n.map(r=>`- ${r.path} (from ${r.from}): ${r.message}`);super(n.length===0?"Invalid config: unknown error (no issues attached)":`Invalid config (${n.length} issue${n.length===1?"":"s"}):
2
+ ${s.join(`
3
+ `)}`),this.name="ConfigError",this.code=t,this.issues=n;}};function F(e){let n={};e.charCodeAt(0)===65279&&(e=e.slice(1));let t=Se(e);for(let s of t){let r=s.trim();if(!r||r.startsWith("#"))continue;r.startsWith("export ")&&(r=r.slice(7).trimStart());let o=r.indexOf("=");if(o===-1)throw new Error(`ParseError: bare key without '=': ${JSON.stringify(r)}`);let i=r.slice(0,o).trim(),a=r.slice(o+1).trimStart();if(!i)throw new Error("ParseError: empty key");let{value:f,quoted:c}=_e(a,r);n[i]=c&&!ye(f)?Ee(f):f;}return n}function ye(e){let n=e.trim();return n.startsWith("{")&&n.endsWith("}")||n.startsWith("[")&&n.endsWith("]")}function Ee(e){let n="";for(let t=0;t<e.length;t++){let s=e[t];if(s==="\\"&&t+1<e.length){n+=s+e[t+1],t++;continue}if(s===","){n+="\\,";continue}n+=s;}return n}function Se(e){let n=e.split(/\r?\n/),t=[],s="",r=false;for(let o of n)r?(s+=`
4
+ `+o,H(s.split("=").slice(1).join("="))%2===0&&(r=false,t.push(s),s="")):H(o)%2===1&&ke(o)?(s=o,r=true):t.push(o);if(r)throw new Error("ParseError: unterminated double-quoted value");return t}function ke(e){let n=e.indexOf("=");if(n===-1)return false;let t=e.slice(n+1).trimStart();return t.startsWith('"')&&!t.endsWith('"')}function H(e){let n=0;for(let t=0;t<e.length;t++)e[t]==='"'&&e[t-1]!=="\\"&&n++;return n}function _e(e,n){if(!e)return {value:"",quoted:false};if(e.startsWith("'")){let r=e.indexOf("'",1);if(r===-1)throw new Error("ParseError: unterminated single-quoted value");return J(e.slice(r+1),n),{value:e.slice(1,r),quoted:true}}if(e.startsWith('"')){let r=1,o="";for(;r<e.length;){let i=e[r];if(i==="\\"&&r+1<e.length){let a=e[r+1];a==="n"?o+=`
5
+ `:a==="r"?o+="\r":a==="t"?o+=" ":o+=a,r+=2;continue}if(i==='"')break;o+=i,r++;}if(e[r]!=='"')throw new Error("ParseError: unterminated double-quoted value");return J(e.slice(r+1),n),{value:o,quoted:true}}if(e.startsWith("`"))throw new Error("ParseError: backtick values not supported");let t=Re(e);return {value:(t===-1?e:e.slice(0,t)).trim(),quoted:false}}function J(e,n){if(!/^\s*(#.*)?$/.test(e))throw new Error(`ParseError: trailing characters after quoted value: ${JSON.stringify(n)}`)}function Re(e){for(let n=0;n<e.length;n++)if(e[n]==="#"&&(n===0||/\s/.test(e[n-1])))return n;return -1}function Z(e,n="json"){let t=e.charCodeAt(0)===65279?e.slice(1):e;if(!t.trim())return {};try{return JSON.parse(t)}catch(s){let r=s;throw new Error(`ParseError (${n}): ${r.message}`)}}function Q(e,n="yaml"){let t=e.charCodeAt(0)===65279?e.slice(1):e;if(!t.trim())return {};let s=yaml.parseAllDocuments(t,{version:"1.2",uniqueKeys:true,maxAliasCount:100}).filter(i=>{if(i.errors.length>0)return true;try{let a=i.toJS();return a!=null}catch{return true}});if(s.length===0)return {};if(s.length>1)throw new Error(`ParseError (${n}): multi-doc YAML not supported (got ${s.length} documents)`);let r=s[0];if(r.errors.length>0){let i=r.errors[0],a=i.linePos?.[0]?.line??"?";throw new Error(`ParseError (${n}:${a}): ${i.message}`)}let o;try{o=r.toJS();}catch(i){throw new Error(`ParseError (${n}): ${i.message}`)}return o}function ee(e,n="toml"){let t=e.charCodeAt(0)===65279?e.slice(1):e;if(!t.trim())return {};try{return smolToml.parse(t)}catch(s){let r=s;throw new Error(`ParseError (${n}): ${r.message}`)}}var re="[A-Za-z_][A-Za-z0-9_]*",Oe=new RegExp(`^\\$(?<name>${re})`),xe=new RegExp(`^(?<name>${re})`),ne=50;function U(e,n,t,s=0){if(s>ne)throw new l([{path:t?.leafPath??"<expand>",from:t?.from??"config",message:`E_DEPTH: \${} nesting too deep (>${ne})`}],"E_DEPTH");let r="",o=0;for(;o<e.length;){let i=e[o];if(i==="$"&&e[o+1]==="$"){r+="$",o+=2;continue}if(i==="\\"&&e[o+1]==="$"){r+="\\$",o+=2;continue}if(i!=="$"){r+=i,o++;continue}let a=e.slice(o);if(a.startsWith("${")){let p=Pe(e,o,t);if(!p){r+="$",o++;continue}let{name:h,op:u,def:m,end:g}=p,w=t?.leafPath??h,S=t?.from??"config";if(u&&u!==":-"&&u!=="-")throw new l([{path:w,from:S,message:`E_BAD_OP: only :- and - supported, got ${u}`}],"E_BAD_OP");let _=n(h);if(!(_===void 0||u===":-"&&_===""))r+=_;else if(m!==void 0)r+=U(m,n,t,s+1);else if(t?.allowUnresolved)r+=e.slice(o,g);else throw new l([{path:w,from:S,message:`E_UNRESOLVED: ${h} missing (expand)`}],"E_UNRESOLVED");o=g;continue}let f=Oe.exec(a);if(!f||!f.groups){r+="$",o++;continue}let c=f.groups.name,d=n(c);if(d===void 0)if(t?.allowUnresolved)r+="$"+c;else throw new l([{path:t?.leafPath??c,from:t?.from??"config",message:`E_UNRESOLVED: ${c} missing (expand)`}],"E_UNRESOLVED");else r+=d;o+=1+c.length;}return r}function Pe(e,n,t){let s=n+2,r=xe.exec(e.slice(s));if(!r?.groups)return null;let o=r.groups.name;if(s+=o.length,e[s]==="}")return {name:o,end:s+1};if(s>=e.length)throw new l([{path:t?.leafPath??o,from:t?.from??"config",message:"E_EXPAND: unterminated ${}"}],"E_EXPAND");if(e[s]===":"){if(e.slice(s,s+2)!==":-"){let c=e.slice(s).split("}")[0].slice(0,12);return {name:o,op:c,def:"",end:e.length}}s+=2;let{value:a,end:f}=te(e,s);return {name:o,op:":-",def:a,end:f}}if(e[s]==="-"){s+=1;let{value:i,end:a}=te(e,s);return {name:o,op:"-",def:i,end:a}}return null}function te(e,n){let t=0,s=n,r="";for(;s<e.length;){if(e[s]==="\\"&&e[s+1]==="}"){r+="}",s+=2;continue}if(e[s]==="{"&&t++,e[s]==="}"){if(t===0)return {value:r,end:s+1};t--;}r+=e[s],s++;}throw new l([{path:"<expand>",from:"expand",message:"E_EXPAND: unterminated ${}"}],"E_EXPAND")}var W=/^(0|[1-9][0-9]*)$/;function R(e){return e.toLowerCase()==="__proto__"}function Te(e,n){return e;}function oe(e,n){let t={},s=new Map,r=f=>{let c=s.get(f);return c||(c={indexed:false,named:false},s.set(f,c)),c},o=new Map,i=f=>{if(!n?.envMap)return;let c=f.toLowerCase();for(let[d,p]of Object.entries(n.envMap))if(d.toLowerCase()===c)return p},a=(f,c,d)=>{throw new l([{path:f,from:"keys",message:`E_COLLISION: '${f}' ${d} (already claimed by '${o.get(c)}')`}],"E_COLLISION")};for(let[f,c]of Object.entries(e)){let d=i(f);if(d!==void 0){let g=d.toLowerCase();if(R(g))throw new l([{path:f,from:"keys",message:"E_PROTO: forbidden key"}],"E_PROTO");t[g]=c;continue}if(!/^[A-Za-z0-9_]+$/.test(f)){if(n?.tolerantKeys)continue;throw new l([{path:f,from:"keys",message:`E_BAD_KEY: '${f}' cannot be a config key (allowed: A-Z a-z 0-9 _, nesting with __) \u2014 bridge it with envMap`}],"E_BAD_KEY")}let p=Te(f);if(p===null)continue;let h=p;if(R(h))throw new l([{path:f,from:"keys",message:"E_PROTO: forbidden key"}],"E_PROTO");let u=h.split("__");if(u.length>1&&u.every(g=>g!=="")){let g=u.map(O=>O.toLowerCase()),w=g.join("."),S=g.slice(0,-1).join("."),_=g[0];if(o.get(w)!==void 0&&a(f,w,"duplicates a claimed path"),g.length===2&&o.has(_)&&W.test(g[1]))throw new l([{path:f,from:"keys",message:`E_ARRAY_MIX: '${_}' has both scalar/list and indexed (__0) values in the same layer`}],"E_ARRAY_MIX");for(let[O]of o)(O.startsWith(`${w}.`)||w.startsWith(`${O}.`))&&a(f,O,"collides with a conflicting value at");let k=r(S);if(W.test(g[g.length-1])){if(k.named)throw new l([{path:f,from:"keys",message:`E_ARRAY_MIX: '${S}' mixes indexed (__0) and named children in the same layer`}],"E_ARRAY_MIX");k.indexed=true;}else {if(k.indexed)throw new l([{path:f,from:"keys",message:`E_ARRAY_MIX: '${S}' mixes named and indexed (__0) children in the same layer`}],"E_ARRAY_MIX");k.named=true;}o.set(w,f),$e(t,g,c);}else {let g=h.toLowerCase();if(s.get(g)?.indexed)throw new l([{path:f,from:"keys",message:`E_ARRAY_MIX: '${g}' has both indexed (__0) and scalar/list values in the same layer`}],"E_ARRAY_MIX");o.get(g)!==void 0&&a(f,g,"duplicates a claimed path");for(let[S]of o)S.startsWith(`${g}.`)&&a(f,S,"collides with a conflicting value at");o.set(g,f),t[g]=c;}}return t}function x(e,n="<root>"){if(Array.isArray(e))return e.map((r,o)=>x(r,`${n}[${o}]`));if(!E(e))return e;let t=Object.entries(e),s={};for(let[r,o]of t)s[r]=x(o,n==="<root>"?r:`${n}.${r}`);if(t.length>0&&t.every(([r])=>W.test(r))){let r=t.map(([o])=>Number(o)).sort((o,i)=>o-i);if(r.length>1024)throw new l([{path:n,from:"keys",message:"E_ARRAY_CAP: >1024 elements"}],"E_ARRAY_CAP");for(let o=0;o<r.length;o++)if(r[o]!==o)throw new l([{path:n,from:"keys",message:`E_SPARSE_ARRAY: indexes [${r.join(",")}] are not dense 0..${r[r.length-1]}`}],"E_SPARSE_ARRAY");return r.map((o,i)=>s[String(i)])}return s}function $e(e,n,t){let s=e;for(let r=0;r<n.length-1;r++){let o=n[r],i=s[o];if(i&&typeof i=="object"&&!Array.isArray(i))s=i;else {let a={};s[o]=a,s=a;}}s[n[n.length-1]]=t;}function E(e){if(!e||typeof e!="object")return false;let n=Object.getPrototypeOf(e);return n===Object.prototype||n===null}function L(e,n,t="replace"){return K(n),D(e,n,t)}function D(e,n,t){if(n===void 0)return e;if(e===void 0)return n;if(n===null)return null;if(Array.isArray(e)!==Array.isArray(n)&&(E(e)||E(n))){let s=r=>r!=null&&typeof r=="object"&&(Array.isArray(r)?r.length===0:E(r)&&Object.keys(r).length===0);if(!s(e)&&!s(n))throw new l([{path:"<array>",from:"merge",message:`E_ARRAY_MIX: cannot merge object with array across layers (arrayStrategy '${t}' only merges arrays with arrays) \u2014 use matching shapes`}],"E_ARRAY_MIX")}if(Array.isArray(e)&&Array.isArray(n)){if(t==="replace")return n;if(t==="concat"){if(e.length+n.length>1024)throw new l([{path:"<array>",from:"merge",message:"E_ARRAY_CAP: concat would exceed 1024 elements"}],"E_ARRAY_CAP");return [...e,...n]}let s=Math.max(e.length,n.length);if(s>1024)throw new l([{path:"<array>",from:"merge",message:"E_ARRAY_CAP: >1024"}],"E_ARRAY_CAP");let r=[];for(let o=0;o<s;o++)o in n?r[o]=o in e?D(e[o],n[o],t):n[o]:o in e&&(r[o]=e[o]);for(let o=0;o<s;o++)if(!(o in r))throw new l([{path:`<array>[${o}]`,from:"merge",message:"E_SPARSE_ARRAY: hole at index "+o}],"E_SPARSE_ARRAY");return r}if(E(e)&&E(n)){let s={...e};for(let[r,o]of Object.entries(n))s[r]=r in s?D(s[r],o,t):o;return s}return n}function K(e){if(Array.isArray(e)){for(let n of e)K(n);return}if(e!==null&&typeof e=="object")for(let[n,t]of Object.entries(e)){if(R(n))throw new l([{path:n,from:"merge",message:"E_PROTO"}],"E_PROTO");K(t);}}var ve=/^-?\d+$/,Ce=/^-?(\d+\.\d*|\.\d+|\d+)(e[+-]?\d+)?$/i;function Le(e){return se(e,true)}function se(e,n){if(typeof e!="string")return e;let t=e;if(t==="")return "";let s=t.toLowerCase();if(s==="true"||s==="false")return s==="true";if(s==="null")return null;if(ve.test(t)){let o=Number(t);return Number.isSafeInteger(o)?o:t}if(Ce.test(t)&&t!=="-"&&t!=="."){let o=Number(t);return Number.isFinite(o)?o:t}let r=t.trim();if(r.startsWith("{")&&r.endsWith("}")||r.startsWith("[")&&r.endsWith("]"))try{return JSON.parse(r)}catch{return e}if(n&&t.includes(",")){if(!je(t))return t.replace(/\\,/g,",");let o=Ie(t);if(o!==null)return o.map(i=>se(i,false))}return e}function je(e){let n=null;for(let t=0;t<e.length;t++){let s=e[t];if(n){if(s==="\\"&&t+1<e.length){t++;continue}s===n&&(n=null);continue}if(s==='"'||s==="'"){n=s;continue}if(s==="\\"&&e[t+1]===","){t++;continue}if(s===",")return true}return false}function Ie(e){let n=[],t="",s=null;for(let r=0;r<e.length;r++){let o=e[r];if(s){if(o==="\\"&&r+1<e.length){t+=o+e[r+1],r++;continue}if(o===s){s=null,t+=o;continue}t+=o;continue}if(o==='"'||o==="'"){s=o,t+=o;continue}if(o==="\\"&&e[r+1]===","){t+=",",r++;continue}if(o===","){n.push(t.trim()),t="";continue}t+=o;}return s?null:(n.push(t.trim()),n.map(r=>r.length>=2&&r.startsWith("'")&&r.endsWith("'")?r.slice(1,-1).replace(/\\,/g,","):r.length>=2&&r.startsWith('"')&&r.endsWith('"')?r.slice(1,-1):r.replace(/\\,/g,",")))}function P(e){if(typeof e=="string")return Le(e);if(Array.isArray(e))return e.map(P);if(e&&typeof e=="object"){let n=Object.getPrototypeOf(e);if(n!==Object.prototype&&n!==null)return e;let t={};for(let[s,r]of Object.entries(e)){if(R(s))throw new l([{path:s,from:"coerce",message:"E_PROTO: forbidden key"}],"E_PROTO");t[s]=P(r);}return t}return e}function Me(e){if(!e||e.length===0)return "<root>";let n=[];for(let t of e)t!==null&&typeof t=="object"&&"key"in t?n.push(String(t.key)):n.push(String(t));return n.join(".")}function j(e,n){let t;try{t=e["~standard"].validate(n);}catch(r){return {issues:[{path:"<root>",message:r instanceof Error?r.message:String(r)}],async:false}}if(typeof t?.then=="function")return {promise:t.then(o=>ie(o),o=>({ok:false,issues:[{path:"<root>",message:o instanceof Error?o.message:String(o)}]}))};let s=ie(t);return s.ok?{value:s.value}:{issues:s.issues,async:false}}function ie(e){return !e.issues||e.issues.length===0?{ok:true,value:e.value}:{ok:false,issues:e.issues.map(n=>({path:Me(n.path),message:n.message}))}}var ae=50;function ce(e){if(e)return {...e};let n=globalThis;return n.process?.env?{...n.process.env}:{}}function Ne(e,n){let t={};for(let s of n){let r=String(s);r==="__proto__"||r==="constructor"||r==="prototype"||Object.hasOwn(e,s)&&(t[s]=e[s]);}return t}function b(e,n=2*1024*1024,t){let s=()=>{if(t)return t;let r=globalThis.__typedSettingsFs;if(r)return r;if(globalThis.process){let i;try{i=new Function('return typeof require !== "undefined" ? require("node:fs") : null')();}catch{i=null;}if(!i)throw new l([{path:"<root>",from:e,message:`E_NO_FS: cannot read '${e}' under ESM \u2014 import 'typed-settings/node', pass opts.fs, or use { text }/{ map }`}],"E_NO_FS");return i}return null};try{let r=s();if(!r)return;if(r.statSync)try{if(r.statSync(e).size>n)throw new l([{path:"<root>",from:e,message:`E_FILE_TOO_LARGE: '${e}' >${n} bytes \u2014 raise maxBytes or shrink the file`}],"E_FILE_TOO_LARGE")}catch(i){if(i instanceof l)throw i}let o=r.readFileSync(e,"utf8");if(G(o)>n)throw new l([{path:"<root>",from:e,message:`E_FILE_TOO_LARGE: '${e}' >${n} bytes \u2014 raise maxBytes or shrink the file`}],"E_FILE_TOO_LARGE");return o}catch(r){if(r instanceof l)throw r;if(r?.code==="ENOENT")return;throw r}}function fe(e){if(e.maxBytes!==void 0&&(!Number.isFinite(e.maxBytes)||e.maxBytes<=0))throw new l([{path:"maxBytes",from:"options",message:"E_USAGE: maxBytes must be a positive finite number"}],"E_USAGE");if(e.timeoutMs!==void 0&&(!Number.isFinite(e.timeoutMs)||e.timeoutMs<=0))throw new l([{path:"timeoutMs",from:"options",message:"E_USAGE: timeoutMs must be a positive finite number"}],"E_USAGE")}function A(e,n){try{return n()}catch(t){throw t instanceof l?t:t instanceof RangeError&&/call stack|recursion|too much/i.test(t.message)?new l([{path:"<root>",from:e,message:"E_DEPTH: nesting too deep (possible hostile input)"}],"E_DEPTH"):t}}function I(e,n){let t=e.toLowerCase();try{return t.endsWith(".json")?Z(n,e):t.endsWith(".yaml")||t.endsWith(".yml")?Q(n,e):ee(n,e)}catch(s){let r=s;throw new l([{path:"<root>",from:e,message:r.message}],"E_PARSE")}}function ue(e,n){if(!n)return e;if(e.length<=n.length||e.slice(0,n.length).toLowerCase()!==n.toLowerCase())return null;let t=e.slice(n.length);return /[A-Za-z0-9]$/.test(n)&&/^[A-Za-z0-9]/.test(t)?null:t}function le(e,n){let t=new Set,s=(r,o)=>{if(!(!r||typeof r!="object")){if(t.has(r))throw new l([{path:o,from:n,message:`E_CIRCULAR: cyclic value at '${o}' \u2014 remove the self-reference (shared DAG refs are fine, true cycles are not)`}],"E_CIRCULAR");t.add(r);try{for(let[i,a]of Object.entries(r))s(a,o?`${o}.${i}`:i);}finally{t.delete(r);}}};s(e,"");}function y(e,n,t,s,r,o,i=false){le(e,n);let a=t??s,f={};for(let[d,p]of Object.entries(e)){let h=ue(d,a);if(h!==null){if(R(h))throw new l([{path:d,from:n,message:"E_PROTO: forbidden key"}],"E_PROTO");f[h]=p;}}return {node:x(oe(f,{envMap:r.envMap,tolerantKeys:i})),label:n,skipExpand:o}}function M(e,n,t){if(le(e,n),Y(e,n),!E(e))return {node:e??{},label:n,skipExpand:false};let s={};for(let[r,o]of Object.entries(e))if(t){let i=ue(r,t);if(i===null)continue;if(R(i))throw new l([{path:r,from:n,message:"E_PROTO: forbidden key"}],"E_PROTO");s[i]=o;}else s[r]=o;return {node:x(s,n),label:n,skipExpand:false}}function Y(e,n){if(Array.isArray(e)){for(let t of e)Y(t,n);return}if(e&&typeof e=="object")for(let[t,s]of Object.entries(e)){if(R(t))throw new l([{path:t,from:n,message:"E_PROTO: forbidden key"}],"E_PROTO");Y(s,n);}}function de(e,n){let t=n.node;if(t&&typeof t=="object"&&!Array.isArray(t))for(let s of Object.keys(t))e.set(s.toLowerCase(),n.label);}function Ve(e){return !!e&&(typeof e=="object"||typeof e=="function")&&typeof e.then=="function"}function z(e){if(!("provider"in e||"load"in e))return null;let n="provider"in e?e.provider:e;return !n||typeof n.load!="function"?null:{load:n.load,name:typeof n.name=="string"?n.name:"<provider>"}}function Fe(e,n){return new l([{path:"<root>",from:e,message:`E_TIMEOUT: provider '${e}' load outran timeoutMs (${n}ms) \u2014 raise timeoutMs or fix the backend`}],"E_TIMEOUT")}function ge(e,n){let t=e.sources??[".env","env"],s=e.prefix,r=[],o=new Map,i=e.maxBytes??2*1024*1024,a=c=>{r.push(c),de(o,c);},f=(c,d)=>{try{return F(c)}catch(p){let h=p;throw new l([{path:"<root>",from:d,message:h.message}],"E_PARSE")}};for(let c of t)if(c==="env")a(y({...n},"env",void 0,s,e,false,true));else if(c===".env"||c===".env.local"){let d=b(c,i,e.fs);if(d===void 0)continue;a(y(f(d,c),c,void 0,s,e,false));}else if(typeof c=="string"){let d=b(c,i,e.fs);if(d===void 0)continue;let p=c.toLowerCase();p.endsWith(".json")||p.endsWith(".yaml")||p.endsWith(".yml")||p.endsWith(".toml")?a(M(I(c,d),c,s)):a(y(f(d,c),c,void 0,s,e,false));}else if(c&&typeof c=="object"&&"text"in c)a(y(f(c.text,"text"),"text",void 0,s,e,false));else if(c&&typeof c=="object"&&"map"in c){let d=c;a(y(d.map??{},"overrides",d.prefix,s,e,false));}else if(c&&typeof c=="object"&&"file"in c){let d=c.file,p=b(d,i,e.fs);if(p===void 0)continue;let h=d.toLowerCase();h.endsWith(".json")||h.endsWith(".yaml")||h.endsWith(".yml")||h.endsWith(".toml")?a(M(I(d,p),d,s)):a(y(f(p,d),d,void 0,s,e,false));}else {if(c&&typeof c=="object"&&"dir"in c)throw new l([{path:c.dir,from:"config",message:"E_USAGE: { dir } sources need loadSecretsDir() from typed-settings/node, passed back as { map }"}],"E_USAGE");if(c&&typeof c=="object"){let d=z(c);if(d){let p="prefix"in c?c.prefix:void 0,h;try{h=d.load();}catch(u){if(u instanceof l)throw u;let m=u;throw new l([{path:d.name,from:d.name,message:`E_PROVIDER: ${m?.message??String(u)}`}],"E_PROVIDER")}if(Ve(h))throw new l([{path:"<root>",from:d.name,message:`USE_ASYNC: provider '${d.name}' is async \u2014 switch to settingsAsync()`}],"USE_ASYNC");a(y(h??{},d.name,p,s,e,!e.expandSecrets));}else a(y(c,"overrides",void 0,s,e,false));}}return {layers:r,fromMap:o}}async function Ue(e,n){let t=e.timeoutMs??5e3;if(!(e.sources??[]).some(u=>u&&typeof u=="object"&&z(u)!==null))return ge(e,n);let r=Date.now()+t,o=e.sources,i=e.prefix,a=[],f=new Map,c=e.maxBytes??2*1024*1024,d=u=>{a.push(u),de(f,u);},p=(u,m)=>{try{return F(u)}catch(g){let w=g;throw new l([{path:"<root>",from:m,message:w.message}],"E_PARSE")}},h=async(u,m)=>{let g=Math.max(1,r-Date.now()),w,S=new Promise((k,v)=>{w=setTimeout(()=>v(Fe(u,t)),g);}),_=Promise.resolve().then(m);_.catch(()=>{});let V=await Promise.race([_,S]).catch(k=>{if(clearTimeout(w),k instanceof l)throw k;let v=k;throw new l([{path:u,from:u,message:`E_PROVIDER: ${v?.message??String(k)}`}],"E_PROVIDER")});return clearTimeout(w),V};for(let u of o)if(u==="env")d(y({...n},"env",void 0,i,e,false,true));else if(u===".env"||u===".env.local"){let m=b(u,c,e.fs);if(m===void 0)continue;d(y(p(m,u),u,void 0,i,e,false));}else if(typeof u=="string"){let m=b(u,c,e.fs);if(m===void 0)continue;let g=u.toLowerCase();g.endsWith(".json")||g.endsWith(".yaml")||g.endsWith(".yml")||g.endsWith(".toml")?d(M(I(u,m),u,i)):d(y(p(m,u),u,void 0,i,e,false));}else if(u&&typeof u=="object"&&"text"in u)d(y(p(u.text,"text"),"text",void 0,i,e,false));else if(u&&typeof u=="object"&&"map"in u){let m=u;d(y(m.map??{},"overrides",m.prefix,i,e,false));}else if(u&&typeof u=="object"&&"file"in u){let m=u.file,g=b(m,c,e.fs);if(g===void 0)continue;let w=m.toLowerCase();w.endsWith(".json")||w.endsWith(".yaml")||w.endsWith(".yml")||w.endsWith(".toml")?d(M(I(m,g),m,i)):d(y(p(g,m),m,void 0,i,e,false));}else {if(u&&typeof u=="object"&&"dir"in u)throw new l([{path:u.dir,from:"config",message:"E_USAGE: { dir } sources need loadSecretsDir() from typed-settings/node, passed back as { map }"}],"E_USAGE");if(u&&typeof u=="object"){let m=z(u);if(m){let g="prefix"in u?u.prefix:void 0,w=await h(m.name,()=>m.load());d(y(w??{},m.name,g,i,e,!e.expandSecrets));}else d(y(u,"overrides",void 0,i,e,false));}}return {layers:a,fromMap:f}}function me(e){return new Set(e.filter(n=>n.skipExpand).flatMap(n=>Object.keys(n.node)).map(n=>n.toLowerCase()))}function We(e,n){let{layers:t,fromMap:s}=ge(e,n),r=e.arrayStrategy??"replace",o={};for(let f of t)o=L(o,f.node,r);let i=me(t);return e.expand!==false&&(o=T(o,pe(o,n),{allowUnresolved:e.allowUnresolved,fromMap:s,skipTops:i})),e.coerce!==false&&(o=P(o)),{input:o,fromFor:f=>{let c=f.split(".")[0].toLowerCase();return c==="<root>"?"schema":s.get(c)??"defaults"}}}function pe(e,n){let t=e&&typeof e=="object"&&!Array.isArray(e)?e:{},s=new Map(Object.keys(t).map(o=>[o.toLowerCase(),o])),r=new Map;for(let[o,i]of Object.entries(n))r.set(o.toLowerCase(),i);return o=>{let i=s.get(o.toLowerCase());if(i!==void 0){let a=t[i];return typeof a=="string"?a:typeof a=="number"||typeof a=="boolean"||typeof a=="bigint"?String(a):a==null?n[o]??r.get(o.toLowerCase()):void 0}return n[o]??r.get(o.toLowerCase())}}function T(e,n,t,s=[]){if(typeof e=="string"){if(!e.includes("$"))return e;let r=(s[0]??"<root>").toLowerCase(),o=t.fromMap.get(r)??"config",i=s.map(a=>String(a).toLowerCase()).join(".")||"<root>";try{return he(e,n,{...t,from:o},[],i)}catch(a){if(o==="env"&&a instanceof l&&a.code==="E_UNRESOLVED")return e;throw a}}if(Array.isArray(e))return e.map((r,o)=>T(r,n,t,[...s,String(o)]));if(e&&typeof e=="object"){if(s.length===0){let o={};for(let[i,a]of Object.entries(e))o[i]=t.skipTops.has(i.toLowerCase())?a:T(a,n,t,[i]);return o}let r={};for(let[o,i]of Object.entries(e))r[o]=T(i,n,t,[...s,o]);return r}return e}function he(e,n,t,s,r){return U(e,o=>{let i=o.toLowerCase();if(s.includes(i))throw new l([{path:r,from:t.from,message:`E_CIRCULAR: $${[...s,o].join("->$")} reachable from '${r}' \u2014 unwind the $VAR references`}],"E_CIRCULAR");if(s.length>=ae)throw new l([{path:r,from:t.from,message:`E_CIRCULAR: $VAR chain from '${r}' exceeded ${ae} links \u2014 flatten the indirection`}],"E_CIRCULAR");let a=n(o);if(a!==void 0)return a.includes("$")?he(a,n,t,[...s,i],r):a},{allowUnresolved:t.allowUnresolved,from:t.from,leafPath:r})}function N(e,n=""){if(Array.isArray(e)){let t=[];return e.forEach((s,r)=>t.push(...N(s,n?`${n}.${r}`:`${r}`))),t}if(E(e)){let t=[];for(let[s,r]of Object.entries(e)){let o=n?`${n}.${s.toLowerCase()}`:s.toLowerCase();E(r)||Array.isArray(r)?t.push(...N(r,o)):t.push(o);}return t}return n?[n.toLowerCase()]:[]}function B(e,n,t,s){if(t==="strip"||t===void 0)return n;if(t==="preserve")return E(e)&&E(n)?L(e,n,"replace"):n;let r=new Set(N(e)),o=new Set(N(n)),i=[...r].filter(a=>!o.has(a));if(i.length>0)throw new l(i.map(a=>({path:a,from:s(a),message:`E_UNKNOWN_KEY: '${a}' is not in the schema \u2014 remove it, or use unknownKeys 'strip'/'preserve'`})),"E_UNKNOWN_KEY");return n}function $(e){if(Array.isArray(e)){for(let n of e)$(n);return Object.freeze(e)}if(e&&typeof e=="object"){for(let n of Object.keys(e))$(e[n]);return Object.freeze(e)}return e}function De(e){fe(e);let n=e.secretKeys,t=ce(e.env),{input:s,fromFor:r}=A("config",()=>We(e,t)),o=A("schema",()=>j(e.schema,s));if("promise"in o)throw new l([{path:"<root>",from:"schema",message:"USE_ASYNC: schema is async, use settingsAsync()"}],"USE_ASYNC");if("issues"in o)throw new l(o.issues.map(f=>({path:f.path,from:r(f.path),message:X(f.path,f.message,s,n)})));let i=o.value,a=A("config",()=>B(s,i,e.unknownKeys??"strip",r));return e.freeze===false?a:A("config",()=>$(a))}async function Ke(e){let n=e.timeoutMs??5e3;fe(e);let t=e.secretKeys,s=ce(e.env),{input:r,fromFor:o}=await Ye(e,s).catch(c=>{throw c instanceof l?c:c instanceof RangeError?new l([{path:"<root>",from:"config",message:"E_DEPTH: nesting too deep (possible hostile input)"}],"E_DEPTH"):c}),i=j(e.schema,r);if("promise"in i){i.promise.catch(()=>{});let c,d=new Promise((m,g)=>{c=setTimeout(()=>g(new l([{path:"<root>",from:"schema",message:`E_TIMEOUT: async validation outran timeoutMs (${n}ms) \u2014 raise timeoutMs or fix the validator`}],"E_TIMEOUT")),n);}),p;try{p=await Promise.race([i.promise,d]);}finally{c&&clearTimeout(c);}if(!p.ok)throw new l(p.issues.map(m=>({path:m.path,from:o(m.path),message:X(m.path,m.message,r,t)})));let h=p.value,u=A("config",()=>B(r,h,e.unknownKeys??"strip",o));return e.freeze===false?u:A("config",()=>$(u))}if("issues"in i)throw new l(i.issues.map(c=>({path:c.path,from:o(c.path),message:X(c.path,c.message,r,t)})));let a=i.value,f=A("config",()=>B(r,a,e.unknownKeys??"strip",o));return e.freeze===false?f:A("config",()=>$(f))}async function Ye(e,n){let{layers:t,fromMap:s}=await Ue(e,n),r=e.arrayStrategy??"replace",o={};for(let f of t)o=L(o,f.node,r);let i=me(t);return e.expand!==false&&(o=T(o,pe(o,n),{allowUnresolved:e.allowUnresolved,fromMap:s,skipTops:i})),e.coerce!==false&&(o=P(o)),{input:o,fromFor:f=>{let c=f.split(".")[0].toLowerCase();return c==="<root>"?"schema":s.get(c)??"defaults"}}}function ze(e,n){let t=[];for(let r of n.split(".")){let o=/^([^\[\]]+)\[(\d+)\]$/.exec(r);o?t.push(o[1],Number(o[2])):t.push(r);}let s=e;for(let r of t){if(s===null||typeof s!="object")return;if(Array.isArray(s)){let a=typeof r=="number"?r:Number(r);if(!Number.isInteger(a))return;s=s[a];continue}let o=s,i=Object.keys(o).find(a=>a.toLowerCase()===String(r).toLowerCase());if(!i)return;s=o[i];}return s}function Be(e){let n=globalThis;if(n.btoa)try{return n.btoa(e)}catch{}try{if(n.Buffer)return n.Buffer.from(e,"utf8").toString("base64")}catch{}return null}function X(e,n,t,s){if(!C(e,s))return n;let r=n,o=ze(t,e),i=typeof o=="string"?o:typeof o=="number"||typeof o=="boolean"||typeof o=="bigint"?String(o):void 0;if(i!==void 0&&i.length>=4){let a=q(e,i,s);r=r.split(i).join(a);let f=Be(i);f&&f.length>8&&(r=r.split(f).join(a));}return `${r} (redacted)`}function _n(e,n){let t={};for(let s of n){let r=String(s);r==="__proto__"||r==="constructor"||r==="prototype"||Object.hasOwn(e,s)&&(t[s]=e[s]);}return t}exports.ConfigError=l;exports.pickPublic=Ne;exports.publicSettings=_n;exports.settings=De;exports.settingsAsync=Ke;