typed-settings 0.1.1 → 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.
- package/README.md +18 -9
- package/bin/typed-settings.mjs +5 -0
- package/dist/adapters/joi.cjs +1 -26
- package/dist/adapters/joi.d.cts +2 -1
- package/dist/adapters/joi.d.ts +2 -1
- package/dist/adapters/joi.js +1 -1
- package/dist/adapters/superstruct.cjs +1 -26
- package/dist/adapters/superstruct.js +1 -1
- package/dist/adapters/yup.cjs +1 -25
- package/dist/adapters/yup.js +1 -1
- package/dist/adapters/zod.cjs +3 -36
- package/dist/adapters/zod.d.cts +2 -0
- package/dist/adapters/zod.d.ts +2 -0
- package/dist/adapters/zod.js +1 -33
- package/dist/check-XVFZEVNV.js +1 -0
- package/dist/chunk-4EAMKDNK.js +3 -0
- package/dist/chunk-5D2AQWDG.js +1 -0
- package/dist/chunk-C6CG2D4B.js +2 -0
- package/dist/chunk-FQYD5ZKE.js +1 -0
- package/dist/chunk-NQDE3WLR.js +3 -0
- package/dist/chunk-RURPDXIJ.js +1 -0
- package/dist/cli/main.cjs +36 -2220
- package/dist/cli/main.js +32 -806
- package/dist/errors-JkkOM0u-.d.cts +25 -0
- package/dist/errors-JkkOM0u-.d.ts +25 -0
- package/dist/framework/next.cjs +5 -1153
- package/dist/framework/next.d.cts +5 -3
- package/dist/framework/next.d.ts +5 -3
- package/dist/framework/next.js +1 -15
- package/dist/framework/vite.cjs +5 -1151
- package/dist/framework/vite.d.cts +10 -3
- package/dist/framework/vite.d.ts +10 -3
- package/dist/framework/vite.js +1 -14
- package/dist/index.cjs +5 -1176
- package/dist/index.d.cts +46 -10
- package/dist/index.d.ts +46 -10
- package/dist/index.js +1 -6
- package/dist/node.cjs +6 -1236
- package/dist/node.d.cts +23 -9
- package/dist/node.d.ts +23 -9
- package/dist/node.js +1 -7
- package/dist/{types-CClP1lxq.d.ts → types-CcsYDAdO.d.cts} +27 -3
- package/dist/{types-CClP1lxq.d.cts → types-CcsYDAdO.d.ts} +27 -3
- package/dist/vault/aws.cjs +4 -217
- package/dist/vault/aws.d.cts +3 -1
- package/dist/vault/aws.d.ts +3 -1
- package/dist/vault/aws.js +2 -167
- package/dist/vault/hashicorp.cjs +4 -183
- package/dist/vault/hashicorp.d.cts +3 -1
- package/dist/vault/hashicorp.d.ts +3 -1
- package/dist/vault/hashicorp.js +2 -77
- package/dist/vault/http.cjs +4 -185
- package/dist/vault/http.d.cts +3 -1
- package/dist/vault/http.d.ts +3 -1
- package/dist/vault/http.js +2 -79
- package/package.json +10 -3
- package/dist/chunk-33M5GIKQ.js +0 -13
- package/dist/chunk-A5TCQJ7L.js +0 -65
- package/dist/chunk-EE6LXNJV.js +0 -34
- package/dist/chunk-F6DX3HXZ.js +0 -101
- package/dist/chunk-OVFMKC2O.js +0 -15
- package/dist/chunk-RCO6K3WQ.js +0 -984
- package/dist/chunk-RQC6OMVV.js +0 -86
- package/dist/chunk-UFUHHR2J.js +0 -38
- package/dist/chunk-VTIYOSG2.js +0 -233
- package/dist/errors-itGaU4Q8.d.cts +0 -17
- package/dist/errors-itGaU4Q8.d.ts +0 -17
- package/dist/formats/env.cjs +0 -103
- package/dist/formats/env.d.cts +0 -8
- package/dist/formats/env.d.ts +0 -8
- package/dist/formats/env.js +0 -1
- package/dist/formats/json.cjs +0 -15
- package/dist/formats/json.d.cts +0 -7
- package/dist/formats/json.d.ts +0 -7
- package/dist/formats/json.js +0 -1
- package/dist/formats/toml.cjs +0 -17
- package/dist/formats/toml.d.cts +0 -7
- package/dist/formats/toml.d.ts +0 -7
- package/dist/formats/toml.js +0 -1
- package/dist/formats/yaml.cjs +0 -40
- package/dist/formats/yaml.d.cts +0 -8
- package/dist/formats/yaml.d.ts +0 -8
- package/dist/formats/yaml.js +0 -1
package/dist/chunk-RQC6OMVV.js
DELETED
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
import { ConfigError } from './chunk-EE6LXNJV.js';
|
|
2
|
-
|
|
3
|
-
// src/vault/shared.ts
|
|
4
|
-
function getFetch(fetchFn) {
|
|
5
|
-
if (fetchFn) return fetchFn;
|
|
6
|
-
const g = globalThis;
|
|
7
|
-
if (g.fetch) return g.fetch.bind(globalThis);
|
|
8
|
-
throw new ConfigError(
|
|
9
|
-
[{ path: "<provider>", from: "vault", message: "E_NO_FETCH: global fetch unavailable" }],
|
|
10
|
-
"E_NO_FETCH"
|
|
11
|
-
);
|
|
12
|
-
}
|
|
13
|
-
function sameHost(a, b) {
|
|
14
|
-
return new URL(a).host === new URL(b).host;
|
|
15
|
-
}
|
|
16
|
-
var SENSITIVE_HEADER_RE = /authorization|token|secret|api[-_]?key|cookie|auth/i;
|
|
17
|
-
function stripSensitiveForCrossHost(headers) {
|
|
18
|
-
const next = new Headers();
|
|
19
|
-
headers.forEach((value, key) => {
|
|
20
|
-
if (!SENSITIVE_HEADER_RE.test(key)) next.set(key, value);
|
|
21
|
-
});
|
|
22
|
-
return next;
|
|
23
|
-
}
|
|
24
|
-
async function fetchWithRedirectGuard(url, init, fetchFn, maxRedirects = 2) {
|
|
25
|
-
let current = url;
|
|
26
|
-
let headers = new Headers(init.headers);
|
|
27
|
-
for (let i = 0; i <= maxRedirects; i++) {
|
|
28
|
-
const res = await fetchFn(current, { ...init, headers, redirect: "manual" });
|
|
29
|
-
const status = res.status;
|
|
30
|
-
if (![301, 302, 303, 307, 308].includes(status)) return res;
|
|
31
|
-
const loc = res.headers.get("location");
|
|
32
|
-
if (!loc) return res;
|
|
33
|
-
let next;
|
|
34
|
-
try {
|
|
35
|
-
next = new URL(loc, current).toString();
|
|
36
|
-
} catch {
|
|
37
|
-
throw new ConfigError(
|
|
38
|
-
[{ path: current, from: "vault", message: "E_REDIRECT: invalid Location header" }],
|
|
39
|
-
"E_REDIRECT"
|
|
40
|
-
);
|
|
41
|
-
}
|
|
42
|
-
if (i === maxRedirects) {
|
|
43
|
-
throw new ConfigError(
|
|
44
|
-
[{ path: next, from: "vault", message: "E_REDIRECT: too many redirects" }],
|
|
45
|
-
"E_REDIRECT"
|
|
46
|
-
);
|
|
47
|
-
}
|
|
48
|
-
if (!sameHost(current, next)) headers = stripSensitiveForCrossHost(headers);
|
|
49
|
-
current = next;
|
|
50
|
-
}
|
|
51
|
-
throw new ConfigError([{ path: url, from: "vault", message: "E_REDIRECT" }], "E_REDIRECT");
|
|
52
|
-
}
|
|
53
|
-
function normalizeSecretMap(raw, providerName, opts) {
|
|
54
|
-
const trim = opts?.trimNewline !== false;
|
|
55
|
-
const clean = (v) => {
|
|
56
|
-
if (v === null || v === void 0) return void 0;
|
|
57
|
-
let s = typeof v === "string" ? v : String(v);
|
|
58
|
-
if (trim) s = s.replace(/\r?\n$/, "");
|
|
59
|
-
return s;
|
|
60
|
-
};
|
|
61
|
-
const out = {};
|
|
62
|
-
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
63
|
-
throw new ConfigError(
|
|
64
|
-
[{ path: "<root>", from: providerName, message: "E_SHAPE: provider returned non-object" }],
|
|
65
|
-
"E_SHAPE"
|
|
66
|
-
);
|
|
67
|
-
}
|
|
68
|
-
for (const [k, v] of Object.entries(raw)) {
|
|
69
|
-
if (v !== null && typeof v === "object" && !Array.isArray(v)) {
|
|
70
|
-
out[k] = v;
|
|
71
|
-
continue;
|
|
72
|
-
}
|
|
73
|
-
const c = clean(v);
|
|
74
|
-
if (c !== void 0) out[k] = c;
|
|
75
|
-
}
|
|
76
|
-
return out;
|
|
77
|
-
}
|
|
78
|
-
function statusToCode(status) {
|
|
79
|
-
if (status === 403 || status === 401) return "E_DENIED";
|
|
80
|
-
if (status === 404) return "E_NOT_FOUND";
|
|
81
|
-
if (status === 429) return "E_THROTTLED";
|
|
82
|
-
if (status >= 500) return "E_UPSTREAM";
|
|
83
|
-
return "E_PROVIDER";
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
export { fetchWithRedirectGuard, getFetch, normalizeSecretMap, statusToCode };
|
package/dist/chunk-UFUHHR2J.js
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { parseAllDocuments } from 'yaml';
|
|
2
|
-
|
|
3
|
-
// src/formats/yaml.ts
|
|
4
|
-
function parseYamlText(text, from = "yaml") {
|
|
5
|
-
const stripped = text.charCodeAt(0) === 65279 ? text.slice(1) : text;
|
|
6
|
-
if (!stripped.trim()) return {};
|
|
7
|
-
const docs = parseAllDocuments(stripped, {
|
|
8
|
-
version: "1.2",
|
|
9
|
-
uniqueKeys: true
|
|
10
|
-
}).filter((d) => {
|
|
11
|
-
if (d.errors.length > 0) return true;
|
|
12
|
-
try {
|
|
13
|
-
const v = d.toJS();
|
|
14
|
-
return v !== null && v !== void 0;
|
|
15
|
-
} catch {
|
|
16
|
-
return true;
|
|
17
|
-
}
|
|
18
|
-
});
|
|
19
|
-
if (docs.length === 0) return {};
|
|
20
|
-
if (docs.length > 1) {
|
|
21
|
-
throw new Error(`ParseError (${from}): multi-doc YAML not supported (got ${docs.length} documents)`);
|
|
22
|
-
}
|
|
23
|
-
const doc = docs[0];
|
|
24
|
-
if (doc.errors.length > 0) {
|
|
25
|
-
const first = doc.errors[0];
|
|
26
|
-
const line = first.linePos?.[0]?.line ?? "?";
|
|
27
|
-
throw new Error(`ParseError (${from}:${line}): ${first.message}`);
|
|
28
|
-
}
|
|
29
|
-
let value;
|
|
30
|
-
try {
|
|
31
|
-
value = doc.toJS();
|
|
32
|
-
} catch (e) {
|
|
33
|
-
throw new Error(`ParseError (${from}): ${e.message}`);
|
|
34
|
-
}
|
|
35
|
-
return value;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export { parseYamlText };
|
package/dist/chunk-VTIYOSG2.js
DELETED
|
@@ -1,233 +0,0 @@
|
|
|
1
|
-
import { settings } from './chunk-RCO6K3WQ.js';
|
|
2
|
-
import { parseEnvText } from './chunk-F6DX3HXZ.js';
|
|
3
|
-
import { readFileSync, readdirSync, statSync, watch } from 'fs';
|
|
4
|
-
import { join, dirname, basename, resolve } from 'path';
|
|
5
|
-
|
|
6
|
-
globalThis.__typedSettingsFs ??= {
|
|
7
|
-
readFileSync: (p, e) => readFileSync(p, e)
|
|
8
|
-
};
|
|
9
|
-
function loadEnvFiles(paths) {
|
|
10
|
-
const parts = [];
|
|
11
|
-
for (const p of paths) {
|
|
12
|
-
try {
|
|
13
|
-
parts.push(readFileSync(p, "utf8"));
|
|
14
|
-
} catch (e) {
|
|
15
|
-
const err = e;
|
|
16
|
-
if (err?.code === "ENOENT") continue;
|
|
17
|
-
throw e;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
return { text: parts.join("\n") };
|
|
21
|
-
}
|
|
22
|
-
function loadSecretsDir(dir) {
|
|
23
|
-
const out = {};
|
|
24
|
-
let entries;
|
|
25
|
-
try {
|
|
26
|
-
entries = readdirSync(dir);
|
|
27
|
-
} catch (e) {
|
|
28
|
-
const err = e;
|
|
29
|
-
if (err?.code === "ENOENT") return out;
|
|
30
|
-
throw e;
|
|
31
|
-
}
|
|
32
|
-
for (const name of entries) {
|
|
33
|
-
const full = join(dir, name);
|
|
34
|
-
try {
|
|
35
|
-
const st = statSync(full);
|
|
36
|
-
if (!st.isFile()) continue;
|
|
37
|
-
} catch (e) {
|
|
38
|
-
const err = e;
|
|
39
|
-
if (err?.code === "ENOENT") continue;
|
|
40
|
-
throw e;
|
|
41
|
-
}
|
|
42
|
-
if (name.startsWith("..")) continue;
|
|
43
|
-
let v;
|
|
44
|
-
try {
|
|
45
|
-
v = readFileSync(full, "utf8").replace(/\r?\n$/, "");
|
|
46
|
-
} catch (e) {
|
|
47
|
-
const err = e;
|
|
48
|
-
if (err?.code === "ENOENT") continue;
|
|
49
|
-
throw e;
|
|
50
|
-
}
|
|
51
|
-
if (!v) continue;
|
|
52
|
-
out[name.toUpperCase()] = v;
|
|
53
|
-
}
|
|
54
|
-
return out;
|
|
55
|
-
}
|
|
56
|
-
function parseEnvFile(path) {
|
|
57
|
-
try {
|
|
58
|
-
const text = readFileSync(path, "utf8");
|
|
59
|
-
return parseEnvText(text);
|
|
60
|
-
} catch (e) {
|
|
61
|
-
const err = e;
|
|
62
|
-
if (err?.code === "ENOENT") return {};
|
|
63
|
-
throw e;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
function extractWatchFiles(sources) {
|
|
67
|
-
const out = [];
|
|
68
|
-
for (const s of sources ?? []) {
|
|
69
|
-
if (s === "env") continue;
|
|
70
|
-
if (s === ".env" || s === ".env.local") out.push(resolve(s));
|
|
71
|
-
else if (typeof s === "string") {
|
|
72
|
-
const lower = s.toLowerCase();
|
|
73
|
-
if (lower.endsWith(".env") || s === ".env.local" || lower.endsWith(".json") || lower.endsWith(".yaml") || lower.endsWith(".yml") || lower.endsWith(".toml")) {
|
|
74
|
-
out.push(resolve(s));
|
|
75
|
-
} else if (!lower.endsWith(".env")) {
|
|
76
|
-
out.push(resolve(s));
|
|
77
|
-
}
|
|
78
|
-
} else if (s && typeof s === "object" && "file" in s) {
|
|
79
|
-
out.push(resolve(s.file));
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
return [...new Set(out)];
|
|
83
|
-
}
|
|
84
|
-
function hasPollSources(sources) {
|
|
85
|
-
return (sources ?? []).some(
|
|
86
|
-
(s) => s && typeof s === "object" && ("dir" in s || "provider" in s || "load" in s)
|
|
87
|
-
);
|
|
88
|
-
}
|
|
89
|
-
function diffLeafPaths(a, b, prefix = "") {
|
|
90
|
-
if (Array.isArray(a) && Array.isArray(b)) {
|
|
91
|
-
const out = [];
|
|
92
|
-
const len = Math.max(a.length, b.length);
|
|
93
|
-
for (let i = 0; i < len; i++) {
|
|
94
|
-
const p = prefix ? `${prefix}[${i}]` : `[${i}]`;
|
|
95
|
-
if (i >= a.length || i >= b.length) out.push(p);
|
|
96
|
-
else out.push(...diffLeafPaths(a[i], b[i], p));
|
|
97
|
-
}
|
|
98
|
-
return out;
|
|
99
|
-
}
|
|
100
|
-
if (a && typeof a === "object" && b && typeof b === "object" && !Array.isArray(a) && !Array.isArray(b)) {
|
|
101
|
-
const out = [];
|
|
102
|
-
const keys = /* @__PURE__ */ new Set([...Object.keys(a), ...Object.keys(b)]);
|
|
103
|
-
for (const k of keys) {
|
|
104
|
-
const p = prefix ? `${prefix}.${k}` : k;
|
|
105
|
-
if (!(k in a) || !(k in b)) out.push(p);
|
|
106
|
-
else out.push(...diffLeafPaths(a[k], b[k], p));
|
|
107
|
-
}
|
|
108
|
-
return out;
|
|
109
|
-
}
|
|
110
|
-
return JSON.stringify(a) === JSON.stringify(b) ? [] : [prefix || "<root>"];
|
|
111
|
-
}
|
|
112
|
-
async function stableSize(path, retries = 3) {
|
|
113
|
-
for (let i = 0; i < retries; i++) {
|
|
114
|
-
let s1 = null;
|
|
115
|
-
let s2 = null;
|
|
116
|
-
try {
|
|
117
|
-
const st = statSync(path);
|
|
118
|
-
s1 = { size: st.size, mtimeMs: st.mtimeMs };
|
|
119
|
-
} catch {
|
|
120
|
-
return;
|
|
121
|
-
}
|
|
122
|
-
await new Promise((r) => setTimeout(r, 20));
|
|
123
|
-
try {
|
|
124
|
-
const st = statSync(path);
|
|
125
|
-
s2 = { size: st.size, mtimeMs: st.mtimeMs };
|
|
126
|
-
} catch {
|
|
127
|
-
return;
|
|
128
|
-
}
|
|
129
|
-
if (s1.size === s2.size && s1.mtimeMs === s2.mtimeMs) return;
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
function watchSettings(opts, cb = {}) {
|
|
133
|
-
const debounceMs = cb.debounceMs ?? 100;
|
|
134
|
-
const refreshMs = cb.refreshMs ?? (hasPollSources(opts.sources) ? 6e4 : 0);
|
|
135
|
-
const pollMs = cb.pollMs ?? 0;
|
|
136
|
-
let current = settings(opts);
|
|
137
|
-
let version = 0;
|
|
138
|
-
let reloadId = 0;
|
|
139
|
-
let disposed = false;
|
|
140
|
-
let timer = null;
|
|
141
|
-
const watchers = [];
|
|
142
|
-
const intervals = [];
|
|
143
|
-
const watchedDirs = /* @__PURE__ */ new Set();
|
|
144
|
-
const handle = {
|
|
145
|
-
get: () => current,
|
|
146
|
-
reload: async () => {
|
|
147
|
-
await doReload();
|
|
148
|
-
},
|
|
149
|
-
dispose: async () => {
|
|
150
|
-
if (disposed) return;
|
|
151
|
-
disposed = true;
|
|
152
|
-
if (timer) clearTimeout(timer);
|
|
153
|
-
for (const iv of intervals) clearInterval(iv);
|
|
154
|
-
for (const w of watchers) {
|
|
155
|
-
try {
|
|
156
|
-
w.close();
|
|
157
|
-
} catch {
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
},
|
|
161
|
-
get version() {
|
|
162
|
-
return version;
|
|
163
|
-
}
|
|
164
|
-
};
|
|
165
|
-
async function doReload() {
|
|
166
|
-
const myId = ++reloadId;
|
|
167
|
-
ensureWatchers();
|
|
168
|
-
const files = extractWatchFiles(opts.sources);
|
|
169
|
-
await Promise.all(
|
|
170
|
-
files.map(
|
|
171
|
-
(f) => stableSize(f).catch(() => {
|
|
172
|
-
})
|
|
173
|
-
)
|
|
174
|
-
);
|
|
175
|
-
if (disposed || myId !== reloadId) return;
|
|
176
|
-
let next;
|
|
177
|
-
try {
|
|
178
|
-
next = settings(opts);
|
|
179
|
-
} catch (e) {
|
|
180
|
-
try {
|
|
181
|
-
cb.onError?.(e, { version });
|
|
182
|
-
} catch {
|
|
183
|
-
}
|
|
184
|
-
return;
|
|
185
|
-
}
|
|
186
|
-
if (disposed || myId !== reloadId) return;
|
|
187
|
-
const changed = diffLeafPaths(current, next);
|
|
188
|
-
current = next;
|
|
189
|
-
version++;
|
|
190
|
-
try {
|
|
191
|
-
cb.onUpdate?.(current, changed);
|
|
192
|
-
} catch {
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
function scheduleReload() {
|
|
196
|
-
if (disposed) return;
|
|
197
|
-
if (timer) clearTimeout(timer);
|
|
198
|
-
timer = setTimeout(() => {
|
|
199
|
-
timer = null;
|
|
200
|
-
void doReload();
|
|
201
|
-
}, debounceMs);
|
|
202
|
-
}
|
|
203
|
-
function ensureWatchers() {
|
|
204
|
-
for (const file of extractWatchFiles(opts.sources)) {
|
|
205
|
-
const dir = dirname(file);
|
|
206
|
-
const base = basename(file);
|
|
207
|
-
const key = dir + "\0" + base;
|
|
208
|
-
if (watchedDirs.has(key)) continue;
|
|
209
|
-
try {
|
|
210
|
-
const w = watch(dir, (_event, filename) => {
|
|
211
|
-
const name = typeof filename === "string" ? filename : filename ? String(filename) : null;
|
|
212
|
-
if (name && name !== base) return;
|
|
213
|
-
scheduleReload();
|
|
214
|
-
});
|
|
215
|
-
w.on("error", () => {
|
|
216
|
-
});
|
|
217
|
-
watchers.push(w);
|
|
218
|
-
watchedDirs.add(key);
|
|
219
|
-
} catch {
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
ensureWatchers();
|
|
224
|
-
if (pollMs > 0) {
|
|
225
|
-
intervals.push(setInterval(scheduleReload, pollMs));
|
|
226
|
-
}
|
|
227
|
-
if (refreshMs > 0) {
|
|
228
|
-
intervals.push(setInterval(scheduleReload, refreshMs));
|
|
229
|
-
}
|
|
230
|
-
return handle;
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
export { loadEnvFiles, loadSecretsDir, parseEnvFile, watchSettings };
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
/** One validation failure: the key path, the winning source, and what went wrong. */
|
|
2
|
-
interface ConfigIssue {
|
|
3
|
-
path: string;
|
|
4
|
-
from: string;
|
|
5
|
-
message: string;
|
|
6
|
-
}
|
|
7
|
-
/**
|
|
8
|
-
* Every settings failure. Carries machine-readable `issues` plus a `code`
|
|
9
|
-
* (`E_INVALID_CONFIG` by default, e.g. `E_UNKNOWN_KEY`, `E_TIMEOUT`).
|
|
10
|
-
*/
|
|
11
|
-
declare class ConfigError extends Error {
|
|
12
|
-
code: string;
|
|
13
|
-
issues: ConfigIssue[];
|
|
14
|
-
constructor(issues: ConfigIssue[], code?: string);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export { ConfigError as C };
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
/** One validation failure: the key path, the winning source, and what went wrong. */
|
|
2
|
-
interface ConfigIssue {
|
|
3
|
-
path: string;
|
|
4
|
-
from: string;
|
|
5
|
-
message: string;
|
|
6
|
-
}
|
|
7
|
-
/**
|
|
8
|
-
* Every settings failure. Carries machine-readable `issues` plus a `code`
|
|
9
|
-
* (`E_INVALID_CONFIG` by default, e.g. `E_UNKNOWN_KEY`, `E_TIMEOUT`).
|
|
10
|
-
*/
|
|
11
|
-
declare class ConfigError extends Error {
|
|
12
|
-
code: string;
|
|
13
|
-
issues: ConfigIssue[];
|
|
14
|
-
constructor(issues: ConfigIssue[], code?: string);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export { ConfigError as C };
|
package/dist/formats/env.cjs
DELETED
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
// src/formats/env.ts
|
|
4
|
-
function parseEnvText(text) {
|
|
5
|
-
const out = {};
|
|
6
|
-
if (text.charCodeAt(0) === 65279) text = text.slice(1);
|
|
7
|
-
const lines = splitLogicalLines(text);
|
|
8
|
-
for (const rawLine of lines) {
|
|
9
|
-
let line = rawLine.trim();
|
|
10
|
-
if (!line || line.startsWith("#")) continue;
|
|
11
|
-
if (line.startsWith("export ")) line = line.slice(7).trimStart();
|
|
12
|
-
const eq = line.indexOf("=");
|
|
13
|
-
if (eq === -1) {
|
|
14
|
-
throw new Error(`ParseError: bare key without '=': ${JSON.stringify(line)}`);
|
|
15
|
-
}
|
|
16
|
-
const key = line.slice(0, eq).trim();
|
|
17
|
-
let rest = line.slice(eq + 1).trimStart();
|
|
18
|
-
if (!key) throw new Error("ParseError: empty key");
|
|
19
|
-
out[key] = parseValue(rest);
|
|
20
|
-
}
|
|
21
|
-
return out;
|
|
22
|
-
}
|
|
23
|
-
function splitLogicalLines(text) {
|
|
24
|
-
const physical = text.split(/\r?\n/);
|
|
25
|
-
const out = [];
|
|
26
|
-
let buf = "";
|
|
27
|
-
let inDouble = false;
|
|
28
|
-
for (const pl of physical) {
|
|
29
|
-
if (!inDouble) {
|
|
30
|
-
const opens = countUnescapedQuotes(pl);
|
|
31
|
-
if (opens % 2 === 1 && isValueStartDoubleQuoted(pl)) {
|
|
32
|
-
buf = pl;
|
|
33
|
-
inDouble = true;
|
|
34
|
-
} else {
|
|
35
|
-
out.push(pl);
|
|
36
|
-
}
|
|
37
|
-
} else {
|
|
38
|
-
buf += "\n" + pl;
|
|
39
|
-
const opens = countUnescapedQuotes(buf.split("=").slice(1).join("="));
|
|
40
|
-
if (opens % 2 === 0) {
|
|
41
|
-
inDouble = false;
|
|
42
|
-
out.push(buf);
|
|
43
|
-
buf = "";
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
if (inDouble) throw new Error("ParseError: unterminated double-quoted value");
|
|
48
|
-
return out;
|
|
49
|
-
}
|
|
50
|
-
function isValueStartDoubleQuoted(line) {
|
|
51
|
-
const eq = line.indexOf("=");
|
|
52
|
-
if (eq === -1) return false;
|
|
53
|
-
const rest = line.slice(eq + 1).trimStart();
|
|
54
|
-
return rest.startsWith('"') && !rest.endsWith('"');
|
|
55
|
-
}
|
|
56
|
-
function countUnescapedQuotes(s) {
|
|
57
|
-
let n = 0;
|
|
58
|
-
for (let i = 0; i < s.length; i++) {
|
|
59
|
-
if (s[i] === '"' && s[i - 1] !== "\\") n++;
|
|
60
|
-
}
|
|
61
|
-
return n;
|
|
62
|
-
}
|
|
63
|
-
function parseValue(rest) {
|
|
64
|
-
if (!rest) return "";
|
|
65
|
-
if (rest.startsWith("'")) {
|
|
66
|
-
const end = rest.indexOf("'", 1);
|
|
67
|
-
if (end === -1) throw new Error("ParseError: unterminated single-quoted value");
|
|
68
|
-
return rest.slice(1, end);
|
|
69
|
-
}
|
|
70
|
-
if (rest.startsWith('"')) {
|
|
71
|
-
let i = 1;
|
|
72
|
-
let val = "";
|
|
73
|
-
while (i < rest.length) {
|
|
74
|
-
const c = rest[i];
|
|
75
|
-
if (c === "\\" && i + 1 < rest.length) {
|
|
76
|
-
const n = rest[i + 1];
|
|
77
|
-
if (n === "n") val += "\n";
|
|
78
|
-
else if (n === "r") val += "\r";
|
|
79
|
-
else if (n === "t") val += " ";
|
|
80
|
-
else val += n;
|
|
81
|
-
i += 2;
|
|
82
|
-
continue;
|
|
83
|
-
}
|
|
84
|
-
if (c === '"') break;
|
|
85
|
-
val += c;
|
|
86
|
-
i++;
|
|
87
|
-
}
|
|
88
|
-
if (rest[i] !== '"') throw new Error("ParseError: unterminated double-quoted value");
|
|
89
|
-
return val;
|
|
90
|
-
}
|
|
91
|
-
if (rest.startsWith("`")) throw new Error("ParseError: backtick values not supported");
|
|
92
|
-
const hash = findCommentStart(rest);
|
|
93
|
-
const v = (hash === -1 ? rest : rest.slice(0, hash)).trim();
|
|
94
|
-
return v;
|
|
95
|
-
}
|
|
96
|
-
function findCommentStart(s) {
|
|
97
|
-
for (let i = 0; i < s.length; i++) {
|
|
98
|
-
if (s[i] === "#" && (i === 0 || /\s/.test(s[i - 1]))) return i;
|
|
99
|
-
}
|
|
100
|
-
return -1;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
exports.parseEnvText = parseEnvText;
|
package/dist/formats/env.d.cts
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Parses dotenv text into a flat map. Strips one BOM, joins multiline
|
|
3
|
-
* double-quoted values, lets the last duplicate win. Throws `ParseError` on
|
|
4
|
-
* backticks, unterminated quotes, bare keys, and empty keys.
|
|
5
|
-
*/
|
|
6
|
-
declare function parseEnvText(text: string): Record<string, string>;
|
|
7
|
-
|
|
8
|
-
export { parseEnvText };
|
package/dist/formats/env.d.ts
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Parses dotenv text into a flat map. Strips one BOM, joins multiline
|
|
3
|
-
* double-quoted values, lets the last duplicate win. Throws `ParseError` on
|
|
4
|
-
* backticks, unterminated quotes, bare keys, and empty keys.
|
|
5
|
-
*/
|
|
6
|
-
declare function parseEnvText(text: string): Record<string, string>;
|
|
7
|
-
|
|
8
|
-
export { parseEnvText };
|
package/dist/formats/env.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { parseEnvText } from '../chunk-F6DX3HXZ.js';
|
package/dist/formats/json.cjs
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
// src/formats/json.ts
|
|
4
|
-
function parseJsonText(text, from = "json") {
|
|
5
|
-
const stripped = text.charCodeAt(0) === 65279 ? text.slice(1) : text;
|
|
6
|
-
if (!stripped.trim()) return {};
|
|
7
|
-
try {
|
|
8
|
-
return JSON.parse(stripped);
|
|
9
|
-
} catch (e) {
|
|
10
|
-
const err = e;
|
|
11
|
-
throw new Error(`ParseError (${from}): ${err.message}`);
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
exports.parseJsonText = parseJsonText;
|
package/dist/formats/json.d.cts
DELETED
package/dist/formats/json.d.ts
DELETED
package/dist/formats/json.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { parseJsonText } from '../chunk-33M5GIKQ.js';
|
package/dist/formats/toml.cjs
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var smolToml = require('smol-toml');
|
|
4
|
-
|
|
5
|
-
// src/formats/toml.ts
|
|
6
|
-
function parseTomlText(text, from = "toml") {
|
|
7
|
-
const stripped = text.charCodeAt(0) === 65279 ? text.slice(1) : text;
|
|
8
|
-
if (!stripped.trim()) return {};
|
|
9
|
-
try {
|
|
10
|
-
return smolToml.parse(stripped);
|
|
11
|
-
} catch (e) {
|
|
12
|
-
const err = e;
|
|
13
|
-
throw new Error(`ParseError (${from}): ${err.message}`);
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
exports.parseTomlText = parseTomlText;
|
package/dist/formats/toml.d.cts
DELETED
package/dist/formats/toml.d.ts
DELETED
package/dist/formats/toml.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { parseTomlText } from '../chunk-OVFMKC2O.js';
|
package/dist/formats/yaml.cjs
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var yaml = require('yaml');
|
|
4
|
-
|
|
5
|
-
// src/formats/yaml.ts
|
|
6
|
-
function parseYamlText(text, from = "yaml") {
|
|
7
|
-
const stripped = text.charCodeAt(0) === 65279 ? text.slice(1) : text;
|
|
8
|
-
if (!stripped.trim()) return {};
|
|
9
|
-
const docs = yaml.parseAllDocuments(stripped, {
|
|
10
|
-
version: "1.2",
|
|
11
|
-
uniqueKeys: true
|
|
12
|
-
}).filter((d) => {
|
|
13
|
-
if (d.errors.length > 0) return true;
|
|
14
|
-
try {
|
|
15
|
-
const v = d.toJS();
|
|
16
|
-
return v !== null && v !== void 0;
|
|
17
|
-
} catch {
|
|
18
|
-
return true;
|
|
19
|
-
}
|
|
20
|
-
});
|
|
21
|
-
if (docs.length === 0) return {};
|
|
22
|
-
if (docs.length > 1) {
|
|
23
|
-
throw new Error(`ParseError (${from}): multi-doc YAML not supported (got ${docs.length} documents)`);
|
|
24
|
-
}
|
|
25
|
-
const doc = docs[0];
|
|
26
|
-
if (doc.errors.length > 0) {
|
|
27
|
-
const first = doc.errors[0];
|
|
28
|
-
const line = first.linePos?.[0]?.line ?? "?";
|
|
29
|
-
throw new Error(`ParseError (${from}:${line}): ${first.message}`);
|
|
30
|
-
}
|
|
31
|
-
let value;
|
|
32
|
-
try {
|
|
33
|
-
value = doc.toJS();
|
|
34
|
-
} catch (e) {
|
|
35
|
-
throw new Error(`ParseError (${from}): ${e.message}`);
|
|
36
|
-
}
|
|
37
|
-
return value;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
exports.parseYamlText = parseYamlText;
|
package/dist/formats/yaml.d.cts
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Single-doc YAML parse (1.2, duplicate keys rejected). A trailing lone `---`
|
|
3
|
-
* still parses; multi-doc payloads, bad indentation, and unresolvable aliases
|
|
4
|
-
* throw `ParseError` naming the source. Explicit `null` reads as `{}`.
|
|
5
|
-
*/
|
|
6
|
-
declare function parseYamlText(text: string, from?: string): unknown;
|
|
7
|
-
|
|
8
|
-
export { parseYamlText };
|
package/dist/formats/yaml.d.ts
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Single-doc YAML parse (1.2, duplicate keys rejected). A trailing lone `---`
|
|
3
|
-
* still parses; multi-doc payloads, bad indentation, and unresolvable aliases
|
|
4
|
-
* throw `ParseError` naming the source. Explicit `null` reads as `{}`.
|
|
5
|
-
*/
|
|
6
|
-
declare function parseYamlText(text: string, from?: string): unknown;
|
|
7
|
-
|
|
8
|
-
export { parseYamlText };
|
package/dist/formats/yaml.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { parseYamlText } from '../chunk-UFUHHR2J.js';
|