@mudah-cli/config 0.8.0 → 0.9.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +39 -0
- package/dist/config-repository.d.ts +60 -4
- package/dist/config-repository.js +129 -7
- package/dist/config-repository.js.map +1 -1
- package/dist/env.d.ts +5 -1
- package/dist/env.js +29 -8
- package/dist/env.js.map +1 -1
- package/dist/index.d.ts +7 -3
- package/dist/index.js +6 -2
- package/dist/index.js.map +1 -1
- package/dist/load-config-files.js.map +1 -1
- package/dist/paths.d.ts +11 -0
- package/dist/paths.js +45 -8
- package/dist/paths.js.map +1 -1
- package/dist/redact.d.ts +14 -0
- package/dist/redact.js +61 -0
- package/dist/redact.js.map +1 -0
- package/dist/remote.d.ts +47 -0
- package/dist/remote.js +266 -0
- package/dist/remote.js.map +1 -0
- package/dist/schema.d.ts +5 -0
- package/dist/schema.js +28 -4
- package/dist/schema.js.map +1 -1
- package/dist/secrets.d.ts +81 -0
- package/dist/secrets.js +302 -0
- package/dist/secrets.js.map +1 -0
- package/dist/watch.d.ts +36 -0
- package/dist/watch.js +57 -0
- package/dist/watch.js.map +1 -0
- package/package.json +15 -1
package/dist/redact.js
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { isPlainObject } from './paths.js';
|
|
2
|
+
/** Key names whose values are treated as secrets and masked in dumps. */
|
|
3
|
+
export const REDACT_KEYS = [
|
|
4
|
+
/password/i,
|
|
5
|
+
/passwd/i,
|
|
6
|
+
/secret/i,
|
|
7
|
+
/token/i,
|
|
8
|
+
/api[-_]?key/i,
|
|
9
|
+
/access[-_]?key/i,
|
|
10
|
+
/credential/i,
|
|
11
|
+
/private[-_]?key/i,
|
|
12
|
+
/^url$/i,
|
|
13
|
+
/^dsn$/i,
|
|
14
|
+
/^connection[-_]?string$/i,
|
|
15
|
+
/^authorization$/i,
|
|
16
|
+
/^bearer$/i,
|
|
17
|
+
/^pwd$/i,
|
|
18
|
+
/^pass$/i,
|
|
19
|
+
];
|
|
20
|
+
/**
|
|
21
|
+
* Recursively replace values whose key is sensitive. Scalars under matching
|
|
22
|
+
* keys become `mask`; objects/arrays recurse so sensitive leaves are masked
|
|
23
|
+
* regardless of depth. Non-sensitive scalars and arrays pass through unchanged.
|
|
24
|
+
*/
|
|
25
|
+
export function redactSecrets(value, options = {}) {
|
|
26
|
+
const patterns = options.keys ?? REDACT_KEYS;
|
|
27
|
+
const mask = options.mask ?? '[redacted]';
|
|
28
|
+
const matches = (name) => {
|
|
29
|
+
for (const pattern of patterns) {
|
|
30
|
+
// A caller-supplied `/g` pattern carries `lastIndex` between calls, which
|
|
31
|
+
// would make redaction alternate between masking and leaking. Test with a
|
|
32
|
+
// non-global clone.
|
|
33
|
+
const safe = pattern.global ? new RegExp(pattern.source, pattern.flags.replace(/g/g, '')) : pattern;
|
|
34
|
+
if (safe.test(name))
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
return false;
|
|
38
|
+
};
|
|
39
|
+
const seen = new WeakSet();
|
|
40
|
+
const walk = (input) => {
|
|
41
|
+
if (Array.isArray(input)) {
|
|
42
|
+
if (seen.has(input))
|
|
43
|
+
return mask;
|
|
44
|
+
seen.add(input);
|
|
45
|
+
return input.map(walk);
|
|
46
|
+
}
|
|
47
|
+
if (isPlainObject(input)) {
|
|
48
|
+
if (seen.has(input))
|
|
49
|
+
return mask;
|
|
50
|
+
seen.add(input);
|
|
51
|
+
const out = {};
|
|
52
|
+
for (const [key, v] of Object.entries(input)) {
|
|
53
|
+
out[key] = matches(key) ? mask : walk(v);
|
|
54
|
+
}
|
|
55
|
+
return out;
|
|
56
|
+
}
|
|
57
|
+
return input;
|
|
58
|
+
};
|
|
59
|
+
return walk(value);
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=redact.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redact.js","sourceRoot":"","sources":["../src/redact.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3C,yEAAyE;AACzE,MAAM,CAAC,MAAM,WAAW,GAA0B;IAChD,WAAW;IACX,SAAS;IACT,SAAS;IACT,QAAQ;IACR,cAAc;IACd,iBAAiB;IACjB,aAAa;IACb,kBAAkB;IAClB,QAAQ;IACR,QAAQ;IACR,0BAA0B;IAC1B,kBAAkB;IAClB,WAAW;IACX,QAAQ;IACR,SAAS;CACV,CAAC;AASF;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,KAAc,EAAE,OAAO,GAAkB,EAAE;IACvE,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,IAAI,WAAW,CAAC;IAC7C,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,YAAY,CAAC;IAE1C,MAAM,OAAO,GAAG,CAAC,IAAY,EAAW,EAAE;QACxC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,0EAA0E;YAC1E,0EAA0E;YAC1E,oBAAoB;YACpB,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;YACpG,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;gBAAE,OAAO,IAAI,CAAC;QACnC,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC,CAAC;IAEF,MAAM,IAAI,GAAG,IAAI,OAAO,EAAU,CAAC;IAEnC,MAAM,IAAI,GAAG,CAAC,KAAc,EAAW,EAAE;QACvC,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YACzB,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC;gBAAE,OAAO,IAAI,CAAC;YACjC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YAChB,OAAO,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACzB,CAAC;QACD,IAAI,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC;YACzB,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC;gBAAE,OAAO,IAAI,CAAC;YACjC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YAChB,MAAM,GAAG,GAA4B,EAAE,CAAC;YACxC,KAAK,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC7C,GAAG,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC3C,CAAC;YACD,OAAO,GAAG,CAAC;QACb,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC,CAAC;IAEF,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC;AACrB,CAAC"}
|
package/dist/remote.d.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/** Default cache lifetime — same 24h window as the update nudge. */
|
|
2
|
+
export declare const REMOTE_CONFIG_TTL_MS: number;
|
|
3
|
+
/** Filename written under `cacheDir` (or `.mudah/cache`). */
|
|
4
|
+
export declare const REMOTE_CONFIG_CACHE_FILE = "remote-config.json";
|
|
5
|
+
export interface LoadRemoteConfigOptions {
|
|
6
|
+
/** Directory that holds `remote-config.json`. Default `.mudah/cache`. */
|
|
7
|
+
cacheDir?: string;
|
|
8
|
+
/** Cache lifetime in milliseconds. Default 24h. */
|
|
9
|
+
ttlMs?: number;
|
|
10
|
+
/** Fetch implementation (tests inject a stub). */
|
|
11
|
+
fetch?: typeof fetch;
|
|
12
|
+
/** Clock used for cache freshness (tests inject a stub). */
|
|
13
|
+
now?: () => number;
|
|
14
|
+
/** Exact cache file path; wins over `cacheDir`. */
|
|
15
|
+
cachePath?: string;
|
|
16
|
+
/** Alternate URL (`{ remote: url }` form). Wins over the first argument. */
|
|
17
|
+
remote?: string;
|
|
18
|
+
/** Allow loopback and RFC1918 hosts. Default false. */
|
|
19
|
+
allowPrivate?: boolean;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Resolve a `remote:` URL. Accepts a bare URL, a `remote:`-prefixed URL, or
|
|
23
|
+
* an options object with `{ remote }`.
|
|
24
|
+
*/
|
|
25
|
+
export declare function resolveRemoteUrl(url: string | {
|
|
26
|
+
remote: string;
|
|
27
|
+
}, options?: Pick<LoadRemoteConfigOptions, 'remote'>): string;
|
|
28
|
+
/**
|
|
29
|
+
* Reject non-http(s) URLs, link-local / metadata hosts, and (unless
|
|
30
|
+
* `allowPrivate`) loopback plus RFC1918 addresses.
|
|
31
|
+
*/
|
|
32
|
+
export declare function assertRemoteUrl(url: string, options?: {
|
|
33
|
+
allowPrivate?: boolean;
|
|
34
|
+
}): string;
|
|
35
|
+
/**
|
|
36
|
+
* Load configuration from a remote URL.
|
|
37
|
+
*
|
|
38
|
+
* Fresh cache (younger than `ttlMs`, default 24h) is reused without hitting
|
|
39
|
+
* the network. A failed fetch returns the last cache entry when one exists,
|
|
40
|
+
* otherwise `{}` — so a machine that has cached once keeps working offline.
|
|
41
|
+
*
|
|
42
|
+
* The `remote:` prefix is stripped (`remote:https://…` and `{ remote: url }`
|
|
43
|
+
* are equivalent to the bare URL).
|
|
44
|
+
*/
|
|
45
|
+
export declare function loadRemoteConfig(url: string | (LoadRemoteConfigOptions & {
|
|
46
|
+
remote: string;
|
|
47
|
+
}), options?: LoadRemoteConfigOptions): Promise<Record<string, unknown>>;
|
package/dist/remote.js
ADDED
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { isPlainObject } from './paths.js';
|
|
4
|
+
/** Default cache lifetime — same 24h window as the update nudge. */
|
|
5
|
+
export const REMOTE_CONFIG_TTL_MS = 24 * 60 * 60 * 1000;
|
|
6
|
+
/** Filename written under `cacheDir` (or `.mudah/cache`). */
|
|
7
|
+
export const REMOTE_CONFIG_CACHE_FILE = 'remote-config.json';
|
|
8
|
+
/**
|
|
9
|
+
* Resolve a `remote:` URL. Accepts a bare URL, a `remote:`-prefixed URL, or
|
|
10
|
+
* an options object with `{ remote }`.
|
|
11
|
+
*/
|
|
12
|
+
export function resolveRemoteUrl(url, options = {}) {
|
|
13
|
+
const raw = options.remote ?? (typeof url === 'string' ? url : url.remote);
|
|
14
|
+
return raw.replace(/^remote:/i, '').trim();
|
|
15
|
+
}
|
|
16
|
+
const BLOCKED_HOSTS = new Set(['metadata.google.internal', 'metadata.goog', '169.254.169.254']);
|
|
17
|
+
function isIpv4(host) {
|
|
18
|
+
const parts = host.split('.');
|
|
19
|
+
if (parts.length !== 4)
|
|
20
|
+
return undefined;
|
|
21
|
+
const nums = parts.map((p) => Number(p));
|
|
22
|
+
if (nums.some((n) => !Number.isInteger(n) || n < 0 || n > 255))
|
|
23
|
+
return undefined;
|
|
24
|
+
return nums;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Unwrap an IPv6 literal into its 8 hextets, resolving `::`, or `undefined`
|
|
28
|
+
* when the text is not a valid IPv6 address. A trailing dotted-quad
|
|
29
|
+
* (`::ffff:127.0.0.1`) is folded into hex hextets.
|
|
30
|
+
*/
|
|
31
|
+
function parseIpv6(host) {
|
|
32
|
+
let text = host;
|
|
33
|
+
if (!text.includes(':'))
|
|
34
|
+
return undefined;
|
|
35
|
+
// Fold a trailing IPv4 dotted-quad into two hextets.
|
|
36
|
+
const lastColon = text.lastIndexOf(':');
|
|
37
|
+
const tail = text.slice(lastColon + 1);
|
|
38
|
+
const tailV4 = isIpv4(tail);
|
|
39
|
+
if (tailV4) {
|
|
40
|
+
const high = ((tailV4[0] << 8) | tailV4[1]).toString(16);
|
|
41
|
+
const low = ((tailV4[2] << 8) | tailV4[3]).toString(16);
|
|
42
|
+
text = `${text.slice(0, lastColon + 1)}${high}:${low}`;
|
|
43
|
+
}
|
|
44
|
+
const halves = text.split('::');
|
|
45
|
+
if (halves.length > 2)
|
|
46
|
+
return undefined;
|
|
47
|
+
const parseGroups = (part) => {
|
|
48
|
+
if (part === '')
|
|
49
|
+
return [];
|
|
50
|
+
const out = [];
|
|
51
|
+
for (const group of part.split(':')) {
|
|
52
|
+
if (!/^[0-9a-f]{1,4}$/.test(group))
|
|
53
|
+
return undefined;
|
|
54
|
+
out.push(Number.parseInt(group, 16));
|
|
55
|
+
}
|
|
56
|
+
return out;
|
|
57
|
+
};
|
|
58
|
+
const head = parseGroups(halves[0] ?? '');
|
|
59
|
+
const tailGroups = halves.length === 2 ? parseGroups(halves[1] ?? '') : [];
|
|
60
|
+
if (head === undefined || tailGroups === undefined)
|
|
61
|
+
return undefined;
|
|
62
|
+
if (halves.length === 1)
|
|
63
|
+
return head.length === 8 ? head : undefined;
|
|
64
|
+
const missing = 8 - head.length - tailGroups.length;
|
|
65
|
+
if (missing < 1)
|
|
66
|
+
return undefined;
|
|
67
|
+
return [...head, ...Array.from({ length: missing }, () => 0), ...tailGroups];
|
|
68
|
+
}
|
|
69
|
+
/** True for loopback, unspecified, link-local, ULA, and IPv4-mapped private hosts. */
|
|
70
|
+
function isPrivateIpv6(hextets) {
|
|
71
|
+
const [h0, h1, h2, h3, h4, h5] = hextets;
|
|
72
|
+
// ::1 loopback, :: unspecified
|
|
73
|
+
const allZeroPrefix = h0 === 0 && h1 === 0 && h2 === 0 && h3 === 0 && h4 === 0;
|
|
74
|
+
if (allZeroPrefix && h5 === 0 && hextets[6] === 0 && (hextets[7] === 1 || hextets[7] === 0)) {
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
77
|
+
// fe80::/10 link-local
|
|
78
|
+
if ((h0 & 0xffc0) === 0xfe80)
|
|
79
|
+
return true;
|
|
80
|
+
// fc00::/7 unique-local
|
|
81
|
+
if ((h0 & 0xfe00) === 0xfc00)
|
|
82
|
+
return true;
|
|
83
|
+
// ::ffff:a.b.c.d IPv4-mapped — re-check the embedded IPv4
|
|
84
|
+
if (h0 === 0 && h1 === 0 && h2 === 0 && h3 === 0 && h4 === 0 && h5 === 0xffff) {
|
|
85
|
+
const ip = [hextets[6] >> 8, hextets[6] & 0xff, hextets[7] >> 8, hextets[7] & 0xff];
|
|
86
|
+
return isPrivateIpv4(ip);
|
|
87
|
+
}
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
function isPrivateIpv4(ip) {
|
|
91
|
+
const [a, b] = ip;
|
|
92
|
+
if (a === undefined || b === undefined)
|
|
93
|
+
return false;
|
|
94
|
+
if (a === 127 || a === 0 || a === 10)
|
|
95
|
+
return true;
|
|
96
|
+
if (a === 192 && b === 168)
|
|
97
|
+
return true;
|
|
98
|
+
if (a === 172 && b >= 16 && b <= 31)
|
|
99
|
+
return true;
|
|
100
|
+
if (a === 169 && b === 254)
|
|
101
|
+
return true;
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
function isPrivateOrLocal(host) {
|
|
105
|
+
const h = host.toLowerCase().replace(/^\[|\]$/g, '');
|
|
106
|
+
if (h === 'localhost' || h === '0.0.0.0')
|
|
107
|
+
return true;
|
|
108
|
+
if (h.includes(':')) {
|
|
109
|
+
const hextets = parseIpv6(h);
|
|
110
|
+
return hextets === undefined ? true : isPrivateIpv6(hextets);
|
|
111
|
+
}
|
|
112
|
+
const ip = isIpv4(h);
|
|
113
|
+
if (!ip)
|
|
114
|
+
return false;
|
|
115
|
+
return isPrivateIpv4(ip);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Reject non-http(s) URLs, link-local / metadata hosts, and (unless
|
|
119
|
+
* `allowPrivate`) loopback plus RFC1918 addresses.
|
|
120
|
+
*/
|
|
121
|
+
export function assertRemoteUrl(url, options = {}) {
|
|
122
|
+
const trimmed = url.trim();
|
|
123
|
+
let parsed;
|
|
124
|
+
try {
|
|
125
|
+
parsed = new URL(trimmed);
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
throw new Error(`[config] Invalid remote URL "${url}".`);
|
|
129
|
+
}
|
|
130
|
+
if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:') {
|
|
131
|
+
throw new Error(`[config] Remote config must be http(s), got "${parsed.protocol}".`);
|
|
132
|
+
}
|
|
133
|
+
const host = parsed.hostname.toLowerCase();
|
|
134
|
+
if (BLOCKED_HOSTS.has(host) || host.endsWith('.internal')) {
|
|
135
|
+
throw new Error(`[config] Remote config host "${host}" is blocked.`);
|
|
136
|
+
}
|
|
137
|
+
const ip = isIpv4(host);
|
|
138
|
+
if (ip && ip[0] === 169 && ip[1] === 254) {
|
|
139
|
+
throw new Error(`[config] Remote config host "${host}" is blocked.`);
|
|
140
|
+
}
|
|
141
|
+
if (!options.allowPrivate && isPrivateOrLocal(host)) {
|
|
142
|
+
throw new Error(`[config] Remote config host "${host}" is private. Pass allowPrivate to permit it.`);
|
|
143
|
+
}
|
|
144
|
+
return parsed.href;
|
|
145
|
+
}
|
|
146
|
+
function defaultCacheDir() {
|
|
147
|
+
return join(process.cwd(), '.mudah', 'cache');
|
|
148
|
+
}
|
|
149
|
+
function cacheFile(options) {
|
|
150
|
+
if (options.cachePath !== undefined && options.cachePath.length > 0) {
|
|
151
|
+
return options.cachePath;
|
|
152
|
+
}
|
|
153
|
+
return join(options.cacheDir ?? defaultCacheDir(), REMOTE_CONFIG_CACHE_FILE);
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Read the cache entry for `url`. An entry written for a different URL (or a
|
|
157
|
+
* legacy entry with no recorded URL) is a miss, so two remote sources never
|
|
158
|
+
* share one cached payload.
|
|
159
|
+
*/
|
|
160
|
+
function readCache(file, url) {
|
|
161
|
+
try {
|
|
162
|
+
const parsed = JSON.parse(readFileSync(file, 'utf8'));
|
|
163
|
+
if (!isPlainObject(parsed))
|
|
164
|
+
return null;
|
|
165
|
+
const checkedAt = parsed['checkedAt'];
|
|
166
|
+
const data = parsed['data'];
|
|
167
|
+
const cachedUrl = parsed['url'];
|
|
168
|
+
if (typeof checkedAt !== 'number' || !isPlainObject(data))
|
|
169
|
+
return null;
|
|
170
|
+
if (typeof cachedUrl !== 'string' || cachedUrl !== url)
|
|
171
|
+
return null;
|
|
172
|
+
return { url: cachedUrl, checkedAt, data };
|
|
173
|
+
}
|
|
174
|
+
catch {
|
|
175
|
+
return null;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
function writeCache(file, entry) {
|
|
179
|
+
try {
|
|
180
|
+
mkdirSync(join(file, '..'), { recursive: true });
|
|
181
|
+
writeFileSync(file, JSON.stringify(entry), 'utf8');
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
// A read-only filesystem just means no caching next time.
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
/** Max redirect hops followed while validating every hop. */
|
|
188
|
+
const MAX_REDIRECTS = 5;
|
|
189
|
+
/**
|
|
190
|
+
* Fetch JSON, following redirects one hop at a time so each `Location` is
|
|
191
|
+
* re-checked. A plain `fetch` follows redirects automatically, which would let
|
|
192
|
+
* a public URL bounce the client to a private or link-local address after
|
|
193
|
+
* validation had already passed.
|
|
194
|
+
*/
|
|
195
|
+
async function fetchConfig(url, doFetch, options = {}) {
|
|
196
|
+
let current = url;
|
|
197
|
+
for (let hop = 0; hop <= MAX_REDIRECTS; hop++) {
|
|
198
|
+
let response;
|
|
199
|
+
try {
|
|
200
|
+
response = await doFetch(current, {
|
|
201
|
+
headers: { accept: 'application/json' },
|
|
202
|
+
redirect: 'manual',
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
catch {
|
|
206
|
+
// Offline / DNS failure / abort: fail soft.
|
|
207
|
+
return null;
|
|
208
|
+
}
|
|
209
|
+
const location = response.headers?.get?.('location') ?? null;
|
|
210
|
+
if (response.status >= 300 && response.status < 400 && location !== null) {
|
|
211
|
+
let next;
|
|
212
|
+
try {
|
|
213
|
+
next = new URL(location, current).href;
|
|
214
|
+
}
|
|
215
|
+
catch {
|
|
216
|
+
return null;
|
|
217
|
+
}
|
|
218
|
+
// A blocked/private redirect target is a configuration error, not an
|
|
219
|
+
// offline blip — surface it instead of silently returning null.
|
|
220
|
+
assertRemoteUrl(next, { allowPrivate: options.allowPrivate });
|
|
221
|
+
current = next;
|
|
222
|
+
continue;
|
|
223
|
+
}
|
|
224
|
+
if (!response.ok)
|
|
225
|
+
return null;
|
|
226
|
+
try {
|
|
227
|
+
const body = (await response.json());
|
|
228
|
+
return isPlainObject(body) ? body : null;
|
|
229
|
+
}
|
|
230
|
+
catch {
|
|
231
|
+
return null;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
return null;
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Load configuration from a remote URL.
|
|
238
|
+
*
|
|
239
|
+
* Fresh cache (younger than `ttlMs`, default 24h) is reused without hitting
|
|
240
|
+
* the network. A failed fetch returns the last cache entry when one exists,
|
|
241
|
+
* otherwise `{}` — so a machine that has cached once keeps working offline.
|
|
242
|
+
*
|
|
243
|
+
* The `remote:` prefix is stripped (`remote:https://…` and `{ remote: url }`
|
|
244
|
+
* are equivalent to the bare URL).
|
|
245
|
+
*/
|
|
246
|
+
export async function loadRemoteConfig(url, options = {}) {
|
|
247
|
+
const opts = typeof url === 'object' ? { ...options, ...url } : options;
|
|
248
|
+
const resolved = resolveRemoteUrl(typeof url === 'string' ? url : url.remote, opts);
|
|
249
|
+
if (resolved.length > 0)
|
|
250
|
+
assertRemoteUrl(resolved, { allowPrivate: opts.allowPrivate });
|
|
251
|
+
const ttlMs = opts.ttlMs ?? REMOTE_CONFIG_TTL_MS;
|
|
252
|
+
const now = opts.now ?? Date.now;
|
|
253
|
+
const file = cacheFile(opts);
|
|
254
|
+
const cached = readCache(file, resolved);
|
|
255
|
+
if (cached !== null && now() - cached.checkedAt < ttlMs) {
|
|
256
|
+
return cached.data;
|
|
257
|
+
}
|
|
258
|
+
const doFetch = opts.fetch ?? fetch;
|
|
259
|
+
const data = resolved.length === 0 ? null : await fetchConfig(resolved, doFetch, { allowPrivate: opts.allowPrivate });
|
|
260
|
+
if (data !== null) {
|
|
261
|
+
writeCache(file, { url: resolved, checkedAt: now(), data });
|
|
262
|
+
return data;
|
|
263
|
+
}
|
|
264
|
+
return cached !== null ? cached.data : {};
|
|
265
|
+
}
|
|
266
|
+
//# sourceMappingURL=remote.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remote.js","sourceRoot":"","sources":["../src/remote.ts"],"names":[],"mappings":"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"}
|
package/dist/schema.d.ts
CHANGED
|
@@ -115,6 +115,11 @@ export declare const s: {
|
|
|
115
115
|
/** Accept anything at this key. */
|
|
116
116
|
any(): AnySchemaBuilder;
|
|
117
117
|
};
|
|
118
|
+
/**
|
|
119
|
+
* Walk an object schema along a dotted path (`app.port`). Returns the node
|
|
120
|
+
* at that path, or `undefined` when a segment is missing or not an object.
|
|
121
|
+
*/
|
|
122
|
+
export declare function schemaAt(schema: Schema<unknown>, path: string): Schema<unknown> | undefined;
|
|
118
123
|
/** Validate `value` against `schema`. Collects every issue; never throws. */
|
|
119
124
|
export declare function validateSchema<T>(schema: Schema<T>, value: unknown, path?: string): SchemaResult<T>;
|
|
120
125
|
/**
|
package/dist/schema.js
CHANGED
|
@@ -59,8 +59,11 @@ class BaseSchema {
|
|
|
59
59
|
parse(value, path, issues) {
|
|
60
60
|
if (value === undefined) {
|
|
61
61
|
const fallback = this.fallback();
|
|
62
|
+
// Validate the default too, so an invalid default (or a defaulted object
|
|
63
|
+
// whose nested keys need their own defaults) is caught rather than
|
|
64
|
+
// silently accepted.
|
|
62
65
|
if (fallback !== undefined)
|
|
63
|
-
return fallback;
|
|
66
|
+
return this.check(fallback, path, issues);
|
|
64
67
|
if (!this.isOptional) {
|
|
65
68
|
issues.push({ path, message: `is required` });
|
|
66
69
|
}
|
|
@@ -141,6 +144,10 @@ class NumberSchema extends BaseSchema {
|
|
|
141
144
|
this.fail(issues, path, `expected number, got ${typeName(value)}`);
|
|
142
145
|
return 0;
|
|
143
146
|
}
|
|
147
|
+
if (!Number.isFinite(value)) {
|
|
148
|
+
this.fail(issues, path, `must be a finite number`);
|
|
149
|
+
return 0;
|
|
150
|
+
}
|
|
144
151
|
if (this.integerOnly && !Number.isInteger(value)) {
|
|
145
152
|
this.fail(issues, path, `must be an integer`);
|
|
146
153
|
}
|
|
@@ -219,14 +226,14 @@ class ObjectSchema extends BaseSchema {
|
|
|
219
226
|
const output = {};
|
|
220
227
|
for (const [key, node] of Object.entries(this.shape)) {
|
|
221
228
|
const childPath = path === '' ? key : `${path}.${key}`;
|
|
222
|
-
const present = Object.
|
|
229
|
+
const present = Object.hasOwn(source, key);
|
|
223
230
|
const parsed = node.parse(present ? source[key] : undefined, childPath, issues);
|
|
224
231
|
if (present || parsed !== undefined)
|
|
225
232
|
output[key] = parsed;
|
|
226
233
|
}
|
|
227
234
|
if (this.strictMode) {
|
|
228
235
|
for (const key of Object.keys(source)) {
|
|
229
|
-
if (!(
|
|
236
|
+
if (!Object.hasOwn(this.shape, key)) {
|
|
230
237
|
this.fail(issues, path === '' ? key : `${path}.${key}`, `is not a known key`);
|
|
231
238
|
}
|
|
232
239
|
}
|
|
@@ -234,7 +241,7 @@ class ObjectSchema extends BaseSchema {
|
|
|
234
241
|
else {
|
|
235
242
|
// Keep undeclared keys so partial schemas don't silently drop config.
|
|
236
243
|
for (const key of Object.keys(source)) {
|
|
237
|
-
if (!(
|
|
244
|
+
if (!Object.hasOwn(this.shape, key))
|
|
238
245
|
output[key] = source[key];
|
|
239
246
|
}
|
|
240
247
|
}
|
|
@@ -281,6 +288,23 @@ export const s = {
|
|
|
281
288
|
return new AnySchema();
|
|
282
289
|
},
|
|
283
290
|
};
|
|
291
|
+
/**
|
|
292
|
+
* Walk an object schema along a dotted path (`app.port`). Returns the node
|
|
293
|
+
* at that path, or `undefined` when a segment is missing or not an object.
|
|
294
|
+
*/
|
|
295
|
+
export function schemaAt(schema, path) {
|
|
296
|
+
if (path === '')
|
|
297
|
+
return schema;
|
|
298
|
+
let current = schema;
|
|
299
|
+
for (const part of path.split('.')) {
|
|
300
|
+
if (current === undefined || current.type !== 'object' || !('shape' in current)) {
|
|
301
|
+
return undefined;
|
|
302
|
+
}
|
|
303
|
+
const shape = current.shape;
|
|
304
|
+
current = shape[part];
|
|
305
|
+
}
|
|
306
|
+
return current;
|
|
307
|
+
}
|
|
284
308
|
/** Validate `value` against `schema`. Collects every issue; never throws. */
|
|
285
309
|
export function validateSchema(schema, value, path = '') {
|
|
286
310
|
const issues = [];
|
package/dist/schema.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAiBH,MAAM,OAAO,qBAAsB,SAAQ,KAAK;IACrC,MAAM,CAAyB;IAExC,YAAY,MAA8B;QACxC,KAAK,CACH,2BAA2B,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAClH,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,uBAAuB,CAAC;QACpC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;CACF;AAmBD,MAAe,UAAU;IAEvB,UAAU,GAAG,KAAK,CAAC;IACX,SAAS,GAA6B,SAAS,CAAC;IAChD,UAAU,GAAuB,SAAS,CAAC;IAInD,oCAAoC;IACpC,QAAQ;QACN,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QACvB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,2DAA2D;IAC3D,OAAO,CAAC,KAAQ;QACd,IAAI,CAAC,SAAS,GAAG,EAAE,KAAK,EAAE,CAAC;QAC3B,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QACvB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,yDAAyD;IACzD,QAAQ,CAAC,IAAY;QACnB,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QACvB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,cAAc;QACZ,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;IAED,QAAQ;QACN,OAAO,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC;IAC/B,CAAC;IAED,YAAY;QACV,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;IAED,sEAAsE;IACtE,KAAK,CAAC,KAAc,EAAE,IAAY,EAAE,MAAqB;QACvD,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;YACjC,IAAI,QAAQ,KAAK,SAAS;gBAAE,OAAO,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/** A backend that can store and retrieve named secrets. */
|
|
2
|
+
export interface SecretDriver {
|
|
3
|
+
readonly name: string;
|
|
4
|
+
get(name: string): string | undefined;
|
|
5
|
+
set(name: string, value: string): void;
|
|
6
|
+
delete(name: string): boolean;
|
|
7
|
+
list(): string[];
|
|
8
|
+
}
|
|
9
|
+
export interface SecretStoreOptions {
|
|
10
|
+
/** Drivers consulted in order. `get` is first-win. */
|
|
11
|
+
drivers: SecretDriver[];
|
|
12
|
+
}
|
|
13
|
+
export interface ResolveSecretOptions {
|
|
14
|
+
/** Env map used by `env:` refs (default `process.env`). */
|
|
15
|
+
env?: NodeJS.ProcessEnv;
|
|
16
|
+
/** Directory (or JSON file) used by `file:` refs. */
|
|
17
|
+
fileDir?: string;
|
|
18
|
+
/** Options forwarded to the keyring driver for `keyring:` refs. */
|
|
19
|
+
keyring?: KeyringDriverOptions;
|
|
20
|
+
}
|
|
21
|
+
export type KeyringSpawnResult = {
|
|
22
|
+
status: number;
|
|
23
|
+
stdout: string;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Injected process runner for the OS keyring. Return `null` when the
|
|
27
|
+
* command is not available (tests, missing tools).
|
|
28
|
+
*/
|
|
29
|
+
export type KeyringSpawn = (command: string, args: readonly string[], options?: {
|
|
30
|
+
input?: string;
|
|
31
|
+
}) => KeyringSpawnResult | null;
|
|
32
|
+
export interface KeyringDriverOptions {
|
|
33
|
+
/** Process runner (tests inject a stub). */
|
|
34
|
+
spawn?: KeyringSpawn;
|
|
35
|
+
/** Home directory for the file fallback. Default `os.homedir()`. */
|
|
36
|
+
home?: string;
|
|
37
|
+
/** Platform used to pick `security` vs `secret-tool`. */
|
|
38
|
+
platform?: NodeJS.Platform;
|
|
39
|
+
/** Exact fallback file path. Default `~/.mudah/keyring.json`. */
|
|
40
|
+
filePath?: string;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Read secrets from the environment. `get('FOO')` looks at
|
|
44
|
+
* `MUDAH_SECRET_FOO`, then `process.env.FOO`.
|
|
45
|
+
*/
|
|
46
|
+
export declare function envSecretDriver(env?: NodeJS.ProcessEnv): SecretDriver;
|
|
47
|
+
/**
|
|
48
|
+
* Persist secrets as a JSON object. `dir` is a directory (`secrets.json`
|
|
49
|
+
* inside it) or a `.json` file path.
|
|
50
|
+
*/
|
|
51
|
+
export declare function fileSecretDriver(dir: string): SecretDriver;
|
|
52
|
+
/**
|
|
53
|
+
* Best-effort OS keyring. Tries `secret-tool` (libsecret) or `security`
|
|
54
|
+
* (macOS) via an injectable spawn. When neither tool is available, secrets
|
|
55
|
+
* live in `~/.mudah/keyring.json`.
|
|
56
|
+
*/
|
|
57
|
+
export declare function keyringSecretDriver(options?: KeyringDriverOptions): SecretDriver;
|
|
58
|
+
/**
|
|
59
|
+
* First-win secret store. `get` returns the first driver that has the name;
|
|
60
|
+
* `set` writes to the first driver; `delete` removes the name from every
|
|
61
|
+
* driver so a later one can't resurrect it.
|
|
62
|
+
*/
|
|
63
|
+
export declare class SecretStore {
|
|
64
|
+
private readonly drivers;
|
|
65
|
+
constructor(options: SecretStoreOptions);
|
|
66
|
+
get(name: string): string | undefined;
|
|
67
|
+
set(name: string, value: string): void;
|
|
68
|
+
delete(name: string): boolean;
|
|
69
|
+
list(): string[];
|
|
70
|
+
/** Redacted view of every stored secret. Safe for `dump` / debug output. */
|
|
71
|
+
dump(): Record<string, unknown>;
|
|
72
|
+
/** Alias of {@link dump} for debug printers. */
|
|
73
|
+
debug(): Record<string, unknown>;
|
|
74
|
+
}
|
|
75
|
+
/** Build a {@link SecretStore} from an ordered driver list. */
|
|
76
|
+
export declare function createSecretStore(options: SecretStoreOptions): SecretStore;
|
|
77
|
+
/**
|
|
78
|
+
* Resolve a secret reference (`env:FOO`, `file:token`, `keyring:api`).
|
|
79
|
+
* Unknown or empty refs return `undefined`.
|
|
80
|
+
*/
|
|
81
|
+
export declare function resolveSecret(ref: string, options?: ResolveSecretOptions): string | undefined;
|