@cardanowall/sdk-ts 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/README.md +207 -0
- package/dist/client/index.cjs +2695 -0
- package/dist/client/index.cjs.map +1 -0
- package/dist/client/index.d.cts +397 -0
- package/dist/client/index.d.ts +397 -0
- package/dist/client/index.js +2641 -0
- package/dist/client/index.js.map +1 -0
- package/dist/conformance/cli.cjs +4901 -0
- package/dist/conformance/cli.cjs.map +1 -0
- package/dist/conformance/cli.d.cts +18 -0
- package/dist/conformance/cli.d.ts +18 -0
- package/dist/conformance/cli.js +4878 -0
- package/dist/conformance/cli.js.map +1 -0
- package/dist/fetch/index.cjs +335 -0
- package/dist/fetch/index.cjs.map +1 -0
- package/dist/fetch/index.d.cts +13 -0
- package/dist/fetch/index.d.ts +13 -0
- package/dist/fetch/index.js +323 -0
- package/dist/fetch/index.js.map +1 -0
- package/dist/fetch-outbound-BT5-NiYN.d.cts +76 -0
- package/dist/fetch-outbound-BT5-NiYN.d.ts +76 -0
- package/dist/hash/index.cjs +25 -0
- package/dist/hash/index.cjs.map +1 -0
- package/dist/hash/index.d.cts +1 -0
- package/dist/hash/index.d.ts +1 -0
- package/dist/hash/index.js +21 -0
- package/dist/hash/index.js.map +1 -0
- package/dist/identity/index.cjs +1388 -0
- package/dist/identity/index.cjs.map +1 -0
- package/dist/identity/index.d.cts +27 -0
- package/dist/identity/index.d.ts +27 -0
- package/dist/identity/index.js +1362 -0
- package/dist/identity/index.js.map +1 -0
- package/dist/ids/index.cjs +146 -0
- package/dist/ids/index.cjs.map +1 -0
- package/dist/ids/index.d.cts +55 -0
- package/dist/ids/index.d.ts +55 -0
- package/dist/ids/index.js +135 -0
- package/dist/ids/index.js.map +1 -0
- package/dist/index-BhnlWJAY.d.cts +10 -0
- package/dist/index-BhnlWJAY.d.ts +10 -0
- package/dist/index-Cg1QqVmA.d.cts +19 -0
- package/dist/index-Cg1QqVmA.d.ts +19 -0
- package/dist/index.cjs +7127 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +21 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +7004 -0
- package/dist/index.js.map +1 -0
- package/dist/merkle/index.cjs +396 -0
- package/dist/merkle/index.cjs.map +1 -0
- package/dist/merkle/index.d.cts +2 -0
- package/dist/merkle/index.d.ts +2 -0
- package/dist/merkle/index.js +387 -0
- package/dist/merkle/index.js.map +1 -0
- package/dist/types-B8Q3gW54.d.ts +123 -0
- package/dist/types-BQMtbRCb.d.cts +321 -0
- package/dist/types-BQMtbRCb.d.ts +321 -0
- package/dist/types-CLXdbjqr.d.cts +123 -0
- package/dist/verifier/index.cjs +4901 -0
- package/dist/verifier/index.cjs.map +1 -0
- package/dist/verifier/index.d.cts +176 -0
- package/dist/verifier/index.d.ts +176 -0
- package/dist/verifier/index.js +4848 -0
- package/dist/verifier/index.js.map +1 -0
- package/package.json +108 -0
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/fetch/fetch-outbound.ts
|
|
4
|
+
var DenyHostError = class extends Error {
|
|
5
|
+
code = "SERVICE_INDEPENDENCE_VIOLATION";
|
|
6
|
+
host;
|
|
7
|
+
url;
|
|
8
|
+
constructor(host, url) {
|
|
9
|
+
super(`SERVICE_INDEPENDENCE_VIOLATION: host "${host}" is in denyHosts (url=${url})`);
|
|
10
|
+
this.name = "DenyHostError";
|
|
11
|
+
this.host = host;
|
|
12
|
+
this.url = url;
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
var UnsupportedProtocolError = class extends Error {
|
|
16
|
+
code = "UNSUPPORTED_PROTOCOL";
|
|
17
|
+
protocol;
|
|
18
|
+
url;
|
|
19
|
+
constructor(protocol, url) {
|
|
20
|
+
super(`UNSUPPORTED_PROTOCOL: "${protocol}" not in {http:, https:} (url=${url})`);
|
|
21
|
+
this.name = "UnsupportedProtocolError";
|
|
22
|
+
this.protocol = protocol;
|
|
23
|
+
this.url = url;
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
var UnsupportedMethodError = class extends Error {
|
|
27
|
+
code = "UNSUPPORTED_METHOD";
|
|
28
|
+
method;
|
|
29
|
+
url;
|
|
30
|
+
constructor(method, url) {
|
|
31
|
+
super(`UNSUPPORTED_METHOD: "${method}" not in {GET, POST} (url=${url})`);
|
|
32
|
+
this.name = "UnsupportedMethodError";
|
|
33
|
+
this.method = method;
|
|
34
|
+
this.url = url;
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
var BodyTooLargeError = class extends Error {
|
|
38
|
+
code = "OUTBOUND_BODY_TOO_LARGE";
|
|
39
|
+
url;
|
|
40
|
+
limitBytes;
|
|
41
|
+
constructor(url, limitBytes) {
|
|
42
|
+
super(`OUTBOUND_BODY_TOO_LARGE: response exceeded ${limitBytes} bytes (url=${url})`);
|
|
43
|
+
this.name = "BodyTooLargeError";
|
|
44
|
+
this.url = url;
|
|
45
|
+
this.limitBytes = limitBytes;
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
var OutboundExhaustedError = class extends Error {
|
|
49
|
+
code = "OUTBOUND_EXHAUSTED";
|
|
50
|
+
url;
|
|
51
|
+
attempts;
|
|
52
|
+
lastStatus;
|
|
53
|
+
lastError;
|
|
54
|
+
constructor(args) {
|
|
55
|
+
super(
|
|
56
|
+
`OUTBOUND_EXHAUSTED: ${args.attempts} attempts exhausted (url=${args.url}, lastStatus=${args.lastStatus ?? "-"})`
|
|
57
|
+
);
|
|
58
|
+
this.name = "OutboundExhaustedError";
|
|
59
|
+
this.url = args.url;
|
|
60
|
+
this.attempts = args.attempts;
|
|
61
|
+
this.lastStatus = args.lastStatus;
|
|
62
|
+
this.lastError = args.lastError;
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
var DEFAULT_TIMEOUT_MS = 1e4;
|
|
66
|
+
var DEFAULT_OUTBOUND_MAX_BYTES = 64 * 1024 * 1024;
|
|
67
|
+
var DEFAULT_RETRYABLE_STATUSES = [502, 503, 504];
|
|
68
|
+
var BACKOFF_BASE_MS = [1e3, 2e3, 4e3];
|
|
69
|
+
var JITTER_RATIO = 0.25;
|
|
70
|
+
function canonicaliseHost(host) {
|
|
71
|
+
return host.replace(/^\[/, "").replace(/\]$/, "").replace(/\.$/, "").toLowerCase();
|
|
72
|
+
}
|
|
73
|
+
function matchesDenyList(host, denyHosts) {
|
|
74
|
+
const h = canonicaliseHost(host);
|
|
75
|
+
for (const raw of denyHosts) {
|
|
76
|
+
const pattern = raw.replace(/\.$/, "").toLowerCase();
|
|
77
|
+
if (pattern.startsWith("*.")) {
|
|
78
|
+
const suffix = pattern.slice(2);
|
|
79
|
+
if (h.endsWith("." + suffix)) return true;
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
if (h === pattern) return true;
|
|
83
|
+
if (pattern === "localhost") {
|
|
84
|
+
if (h === "::1" || h === "0.0.0.0" || h === "169.254.169.254") return true;
|
|
85
|
+
}
|
|
86
|
+
if (pattern === "127.0.0.1") {
|
|
87
|
+
if (/^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(h)) return true;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
function parseProtocol(url) {
|
|
93
|
+
try {
|
|
94
|
+
return new URL(url).protocol;
|
|
95
|
+
} catch {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
function isAllowedMethod(method) {
|
|
100
|
+
return method === "GET" || method === "POST";
|
|
101
|
+
}
|
|
102
|
+
function backoffJitteredMs(attemptIndex) {
|
|
103
|
+
const idx = Math.min(attemptIndex, BACKOFF_BASE_MS.length - 1);
|
|
104
|
+
const base = BACKOFF_BASE_MS[idx] ?? BACKOFF_BASE_MS[BACKOFF_BASE_MS.length - 1];
|
|
105
|
+
const jitter = 1 + (Math.random() - 0.5) * 2 * JITTER_RATIO;
|
|
106
|
+
return base * jitter;
|
|
107
|
+
}
|
|
108
|
+
function sleep(ms) {
|
|
109
|
+
return new Promise((resolve) => {
|
|
110
|
+
setTimeout(resolve, ms);
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
var defaultFetchOutbound = async (url, opts) => {
|
|
114
|
+
const t0 = Date.now();
|
|
115
|
+
const maxBytes = opts.maxBytes ?? DEFAULT_OUTBOUND_MAX_BYTES;
|
|
116
|
+
const controller = new AbortController();
|
|
117
|
+
const timeout = setTimeout(() => controller.abort(), DEFAULT_TIMEOUT_MS);
|
|
118
|
+
const init = {
|
|
119
|
+
method: opts.method,
|
|
120
|
+
signal: controller.signal
|
|
121
|
+
};
|
|
122
|
+
if (opts.headers) init.headers = { ...opts.headers };
|
|
123
|
+
if (opts.body !== void 0) init.body = opts.body;
|
|
124
|
+
try {
|
|
125
|
+
const res = await fetch(url, init);
|
|
126
|
+
const declared = res.headers.get("content-length");
|
|
127
|
+
if (declared !== null) {
|
|
128
|
+
const declaredLen = Number(declared);
|
|
129
|
+
if (Number.isFinite(declaredLen) && declaredLen > maxBytes) {
|
|
130
|
+
controller.abort();
|
|
131
|
+
throw new BodyTooLargeError(url, maxBytes);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
const bytes = await readBodyCapped(res, url, maxBytes, controller);
|
|
135
|
+
return { status: res.status, bytes, durationMs: Date.now() - t0 };
|
|
136
|
+
} finally {
|
|
137
|
+
clearTimeout(timeout);
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
async function readBodyCapped(res, url, maxBytes, controller) {
|
|
141
|
+
const body = res.body;
|
|
142
|
+
if (body === null) {
|
|
143
|
+
const buf = await res.arrayBuffer();
|
|
144
|
+
if (buf.byteLength > maxBytes) {
|
|
145
|
+
throw new BodyTooLargeError(url, maxBytes);
|
|
146
|
+
}
|
|
147
|
+
return new Uint8Array(buf);
|
|
148
|
+
}
|
|
149
|
+
const reader = body.getReader();
|
|
150
|
+
const chunks = [];
|
|
151
|
+
let total = 0;
|
|
152
|
+
try {
|
|
153
|
+
for (; ; ) {
|
|
154
|
+
const { done, value } = await reader.read();
|
|
155
|
+
if (done) break;
|
|
156
|
+
if (value === void 0) continue;
|
|
157
|
+
total += value.byteLength;
|
|
158
|
+
if (total > maxBytes) {
|
|
159
|
+
controller.abort();
|
|
160
|
+
throw new BodyTooLargeError(url, maxBytes);
|
|
161
|
+
}
|
|
162
|
+
chunks.push(value);
|
|
163
|
+
}
|
|
164
|
+
} finally {
|
|
165
|
+
reader.releaseLock();
|
|
166
|
+
}
|
|
167
|
+
const out = new Uint8Array(total);
|
|
168
|
+
let offset = 0;
|
|
169
|
+
for (const chunk of chunks) {
|
|
170
|
+
out.set(chunk, offset);
|
|
171
|
+
offset += chunk.byteLength;
|
|
172
|
+
}
|
|
173
|
+
return out;
|
|
174
|
+
}
|
|
175
|
+
function wrapFetchOutbound(inner, audit, config = void 0) {
|
|
176
|
+
const normConfig = config === void 0 ? {} : Array.isArray(config) ? { denyHosts: config } : config;
|
|
177
|
+
const denyHosts = normConfig.denyHosts ?? [];
|
|
178
|
+
const retries = normConfig.retries ?? 0;
|
|
179
|
+
const retryableStatuses = normConfig.retryableStatuses ?? DEFAULT_RETRYABLE_STATUSES;
|
|
180
|
+
return async (url, opts) => {
|
|
181
|
+
if (opts.purpose === "webhook") {
|
|
182
|
+
audit.push({
|
|
183
|
+
url,
|
|
184
|
+
method: "GET",
|
|
185
|
+
status: 0,
|
|
186
|
+
bytes: 0,
|
|
187
|
+
duration_ms: 0,
|
|
188
|
+
purpose: opts.purpose
|
|
189
|
+
});
|
|
190
|
+
throw new Error(
|
|
191
|
+
`webhook purpose must be sent via fetchWebhook, not fetchOutbound (url=${url})`
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
const protocol = parseProtocol(url);
|
|
195
|
+
if (protocol !== "http:" && protocol !== "https:") {
|
|
196
|
+
audit.push({
|
|
197
|
+
url,
|
|
198
|
+
method: "GET",
|
|
199
|
+
status: 0,
|
|
200
|
+
bytes: 0,
|
|
201
|
+
duration_ms: 0,
|
|
202
|
+
purpose: opts.purpose
|
|
203
|
+
});
|
|
204
|
+
throw new UnsupportedProtocolError(protocol ?? "", url);
|
|
205
|
+
}
|
|
206
|
+
if (!isAllowedMethod(opts.method)) {
|
|
207
|
+
audit.push({
|
|
208
|
+
url,
|
|
209
|
+
method: "GET",
|
|
210
|
+
status: 0,
|
|
211
|
+
bytes: 0,
|
|
212
|
+
duration_ms: 0,
|
|
213
|
+
purpose: opts.purpose
|
|
214
|
+
});
|
|
215
|
+
throw new UnsupportedMethodError(opts.method, url);
|
|
216
|
+
}
|
|
217
|
+
if (denyHosts.length > 0) {
|
|
218
|
+
const host = new URL(url).hostname;
|
|
219
|
+
if (matchesDenyList(host, denyHosts)) {
|
|
220
|
+
audit.push({
|
|
221
|
+
url,
|
|
222
|
+
method: opts.method,
|
|
223
|
+
status: 0,
|
|
224
|
+
bytes: 0,
|
|
225
|
+
duration_ms: 0,
|
|
226
|
+
purpose: opts.purpose
|
|
227
|
+
});
|
|
228
|
+
throw new DenyHostError(canonicaliseHost(host), url);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
let lastStatus;
|
|
232
|
+
let lastError;
|
|
233
|
+
const totalAttempts = retries + 1;
|
|
234
|
+
for (let attempt = 1; attempt <= totalAttempts; attempt++) {
|
|
235
|
+
const t0 = Date.now();
|
|
236
|
+
try {
|
|
237
|
+
const result = await inner(url, opts);
|
|
238
|
+
audit.push({
|
|
239
|
+
url,
|
|
240
|
+
method: opts.method,
|
|
241
|
+
status: result.status,
|
|
242
|
+
bytes: result.bytes.byteLength,
|
|
243
|
+
duration_ms: result.durationMs,
|
|
244
|
+
purpose: opts.purpose
|
|
245
|
+
});
|
|
246
|
+
if (retryableStatuses.includes(result.status) && retries > 0) {
|
|
247
|
+
lastStatus = result.status;
|
|
248
|
+
if (attempt < totalAttempts) {
|
|
249
|
+
await sleep(backoffJitteredMs(attempt - 1));
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
252
|
+
break;
|
|
253
|
+
}
|
|
254
|
+
return result;
|
|
255
|
+
} catch (e) {
|
|
256
|
+
const durationMs = Date.now() - t0;
|
|
257
|
+
if (e instanceof DenyHostError || e instanceof UnsupportedProtocolError || e instanceof UnsupportedMethodError) {
|
|
258
|
+
audit.push({
|
|
259
|
+
url,
|
|
260
|
+
method: opts.method,
|
|
261
|
+
status: 0,
|
|
262
|
+
bytes: 0,
|
|
263
|
+
duration_ms: durationMs,
|
|
264
|
+
purpose: opts.purpose
|
|
265
|
+
});
|
|
266
|
+
throw e;
|
|
267
|
+
}
|
|
268
|
+
audit.push({
|
|
269
|
+
url,
|
|
270
|
+
method: opts.method,
|
|
271
|
+
status: 0,
|
|
272
|
+
bytes: 0,
|
|
273
|
+
duration_ms: durationMs,
|
|
274
|
+
purpose: opts.purpose
|
|
275
|
+
});
|
|
276
|
+
lastError = e;
|
|
277
|
+
if (attempt < totalAttempts) {
|
|
278
|
+
await sleep(backoffJitteredMs(attempt - 1));
|
|
279
|
+
continue;
|
|
280
|
+
}
|
|
281
|
+
break;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
if (retries === 0 && lastError !== void 0) {
|
|
285
|
+
throw lastError;
|
|
286
|
+
}
|
|
287
|
+
throw new OutboundExhaustedError({ url, attempts: totalAttempts, lastStatus, lastError });
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
async function fetchOutbound(url, opts, audit, config = {}) {
|
|
291
|
+
const wrapped = wrapFetchOutbound(defaultFetchOutbound, audit, config);
|
|
292
|
+
return wrapped(url, opts);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// src/fetch/deny-hosts.ts
|
|
296
|
+
async function denyHostsFetch(url, init, opts) {
|
|
297
|
+
const rawMethod = init?.method ?? "GET";
|
|
298
|
+
const headers = init?.headers;
|
|
299
|
+
const bodyValue = init?.body;
|
|
300
|
+
const body = typeof bodyValue === "string" ? bodyValue : void 0;
|
|
301
|
+
const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
|
|
302
|
+
const innerOpts = headers ? body !== void 0 ? { method: rawMethod, purpose: opts.purpose, headers, body } : { method: rawMethod, purpose: opts.purpose, headers } : body !== void 0 ? { method: rawMethod, purpose: opts.purpose, body } : { method: rawMethod, purpose: opts.purpose };
|
|
303
|
+
let storedResponse = null;
|
|
304
|
+
const inner = async (innerUrl, innerOptsArg) => {
|
|
305
|
+
const t0 = Date.now();
|
|
306
|
+
const reqInit = { method: innerOptsArg.method };
|
|
307
|
+
if (innerOptsArg.headers) reqInit.headers = { ...innerOptsArg.headers };
|
|
308
|
+
if (innerOptsArg.body !== void 0) reqInit.body = innerOptsArg.body;
|
|
309
|
+
const response = await fetchImpl(innerUrl, reqInit);
|
|
310
|
+
storedResponse = response;
|
|
311
|
+
const buf = await response.clone().arrayBuffer();
|
|
312
|
+
return {
|
|
313
|
+
status: response.status,
|
|
314
|
+
bytes: new Uint8Array(buf),
|
|
315
|
+
durationMs: Date.now() - t0
|
|
316
|
+
};
|
|
317
|
+
};
|
|
318
|
+
const wrapped = wrapFetchOutbound(inner, opts.audit, { denyHosts: opts.denyHosts });
|
|
319
|
+
await wrapped(url, innerOpts);
|
|
320
|
+
return storedResponse;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
exports.BodyTooLargeError = BodyTooLargeError;
|
|
324
|
+
exports.DEFAULT_OUTBOUND_MAX_BYTES = DEFAULT_OUTBOUND_MAX_BYTES;
|
|
325
|
+
exports.DenyHostError = DenyHostError;
|
|
326
|
+
exports.OutboundExhaustedError = OutboundExhaustedError;
|
|
327
|
+
exports.UnsupportedMethodError = UnsupportedMethodError;
|
|
328
|
+
exports.UnsupportedProtocolError = UnsupportedProtocolError;
|
|
329
|
+
exports.defaultFetchOutbound = defaultFetchOutbound;
|
|
330
|
+
exports.denyHostsFetch = denyHostsFetch;
|
|
331
|
+
exports.fetchOutbound = fetchOutbound;
|
|
332
|
+
exports.matchesDenyList = matchesDenyList;
|
|
333
|
+
exports.wrapFetchOutbound = wrapFetchOutbound;
|
|
334
|
+
//# sourceMappingURL=index.cjs.map
|
|
335
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/fetch/fetch-outbound.ts","../../src/fetch/deny-hosts.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["// Canonical outbound HTTP wrapper: deny-list short-circuit, protocol/method\n// allowlist, bounded timeout, exp-backoff retry with jitter, audit trail.\n\n// Universal loopback deny-host list a service-independent verifier MUST reject\n// so a record can never be made to \"verify\" only because it reached a loopback\n// address. This default carries no operator-specific entries: a deployment that\n// wants to forbid its own gateway/viewer hosts appends those at construction\n// time. Producers SHOULD pass this through `denyHosts` on every verifier\n// invocation; the wrapper accepts arbitrary lists but exports the canonical\n// loopback set so callers don't duplicate it inline. (RFC-1918 / link-local IP\n// ranges are blocked separately by the SSRF guard, not by this name list.)\nexport const DENY_HOSTS_DEFAULT: ReadonlyArray<string> = ['localhost', '127.0.0.1'];\n\n// Every outbound call carries a purpose tag from the closed set\n// `{cardano, arweave, ipfs}` (the three v1 gateway-chain purposes).\n// `https` is a transitional legacy tag for non-storage HTTPS\n// auxiliaries; new code SHOULD pick one of the three normative purposes.\n// `webhook` is the user-supplied-URL purpose: it triggers the SSRF guard\n// (DNS resolution + IP range check + connection pinning + redirect-chain\n// re-checking + body-size cap), and MUST be used for any fetch where the\n// target URL came from end-user input.\nexport type HttpPurpose = 'cardano' | 'arweave' | 'ipfs' | 'https' | 'webhook';\nexport type HttpMethod = 'GET' | 'POST';\n\nexport interface FetchOutboundOptions {\n readonly method: HttpMethod;\n readonly purpose: HttpPurpose;\n readonly headers?: Readonly<Record<string, string>>;\n readonly body?: string;\n // Hard cap on the response body the primitive will buffer. Gateway content\n // (ar:// / ipfs:// / https) is producer-chosen and therefore UNTRUSTED — the\n // verifier never trusts the producer — so a malicious gateway could otherwise\n // stream unbounded bytes into memory. Omit to use DEFAULT_OUTBOUND_MAX_BYTES.\n readonly maxBytes?: number;\n}\n\nexport interface FetchOutboundResult {\n readonly status: number;\n readonly bytes: Uint8Array;\n readonly durationMs: number;\n}\n\nexport type FetchOutbound = (\n url: string,\n opts: FetchOutboundOptions,\n) => Promise<FetchOutboundResult>;\n\n// Audit-log entry for one outbound HTTP fetch. Field names are snake_case so\n// the record can land directly on `VerifyReport.http_calls[]` (which IS the\n// wire shape) without a key-renaming pass.\nexport interface HttpCallRecord {\n readonly url: string;\n readonly method: HttpMethod;\n readonly status: number;\n readonly bytes: number;\n readonly duration_ms: number;\n readonly purpose: HttpPurpose;\n}\n\nexport interface RetryConfig {\n readonly timeoutMs?: number;\n readonly retries?: number;\n readonly retryableStatuses?: ReadonlyArray<number>;\n}\n\nexport interface WrapFetchOutboundConfig extends RetryConfig {\n readonly denyHosts?: ReadonlyArray<string>;\n}\n\nexport class DenyHostError extends Error {\n readonly code = 'SERVICE_INDEPENDENCE_VIOLATION';\n readonly host: string;\n readonly url: string;\n constructor(host: string, url: string) {\n super(`SERVICE_INDEPENDENCE_VIOLATION: host \"${host}\" is in denyHosts (url=${url})`);\n this.name = 'DenyHostError';\n this.host = host;\n this.url = url;\n }\n}\n\nexport class UnsupportedProtocolError extends Error {\n readonly code = 'UNSUPPORTED_PROTOCOL';\n readonly protocol: string;\n readonly url: string;\n constructor(protocol: string, url: string) {\n super(`UNSUPPORTED_PROTOCOL: \"${protocol}\" not in {http:, https:} (url=${url})`);\n this.name = 'UnsupportedProtocolError';\n this.protocol = protocol;\n this.url = url;\n }\n}\n\nexport class UnsupportedMethodError extends Error {\n readonly code = 'UNSUPPORTED_METHOD';\n readonly method: string;\n readonly url: string;\n constructor(method: string, url: string) {\n super(`UNSUPPORTED_METHOD: \"${method}\" not in {GET, POST} (url=${url})`);\n this.name = 'UnsupportedMethodError';\n this.method = method;\n this.url = url;\n }\n}\n\nexport class BodyTooLargeError extends Error {\n readonly code = 'OUTBOUND_BODY_TOO_LARGE';\n readonly url: string;\n readonly limitBytes: number;\n constructor(url: string, limitBytes: number) {\n super(`OUTBOUND_BODY_TOO_LARGE: response exceeded ${limitBytes} bytes (url=${url})`);\n this.name = 'BodyTooLargeError';\n this.url = url;\n this.limitBytes = limitBytes;\n }\n}\n\nexport class OutboundExhaustedError extends Error {\n readonly code = 'OUTBOUND_EXHAUSTED';\n readonly url: string;\n readonly attempts: number;\n readonly lastStatus: number | undefined;\n readonly lastError: Error | undefined;\n constructor(args: {\n url: string;\n attempts: number;\n lastStatus?: number | undefined;\n lastError?: Error | undefined;\n }) {\n super(\n `OUTBOUND_EXHAUSTED: ${args.attempts} attempts exhausted (url=${args.url}, lastStatus=${args.lastStatus ?? '-'})`,\n );\n this.name = 'OutboundExhaustedError';\n this.url = args.url;\n this.attempts = args.attempts;\n this.lastStatus = args.lastStatus;\n this.lastError = args.lastError;\n }\n}\n\nexport const DEFAULT_TIMEOUT_MS = 10_000;\n// Default response-body cap for the verifier's gateway fetches. 64 MiB sits\n// well above any single sealed-PoE ciphertext or merkle-leaf payload a verifier\n// would realistically recompute a hash over, while bounding the memory a hostile\n// gateway can force the verifier to allocate for one request. Callers that\n// legitimately handle larger content raise it per-call via `opts.maxBytes`.\nexport const DEFAULT_OUTBOUND_MAX_BYTES = 64 * 1024 * 1024;\nexport const DEFAULT_RETRYABLE_STATUSES: ReadonlyArray<number> = [502, 503, 504];\nconst BACKOFF_BASE_MS: ReadonlyArray<number> = [1000, 2000, 4000];\nconst JITTER_RATIO = 0.25;\n\nfunction canonicaliseHost(host: string): string {\n return host.replace(/^\\[/, '').replace(/\\]$/, '').replace(/\\.$/, '').toLowerCase();\n}\n\nexport function matchesDenyList(host: string, denyHosts: ReadonlyArray<string>): boolean {\n const h = canonicaliseHost(host);\n for (const raw of denyHosts) {\n const pattern = raw.replace(/\\.$/, '').toLowerCase();\n if (pattern.startsWith('*.')) {\n const suffix = pattern.slice(2);\n if (h.endsWith('.' + suffix)) return true;\n continue;\n }\n if (h === pattern) return true;\n if (pattern === 'localhost') {\n if (h === '::1' || h === '0.0.0.0' || h === '169.254.169.254') return true;\n }\n if (pattern === '127.0.0.1') {\n if (/^127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$/.test(h)) return true;\n }\n }\n return false;\n}\n\nfunction parseProtocol(url: string): string | null {\n try {\n return new URL(url).protocol;\n } catch {\n return null;\n }\n}\n\nfunction isAllowedMethod(method: string): method is HttpMethod {\n return method === 'GET' || method === 'POST';\n}\n\nfunction backoffJitteredMs(attemptIndex: number): number {\n const idx = Math.min(attemptIndex, BACKOFF_BASE_MS.length - 1);\n const base = BACKOFF_BASE_MS[idx] ?? BACKOFF_BASE_MS[BACKOFF_BASE_MS.length - 1]!;\n const jitter = 1 + (Math.random() - 0.5) * 2 * JITTER_RATIO;\n return base * jitter;\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n}\n\nexport const defaultFetchOutbound: FetchOutbound = async (url, opts) => {\n const t0 = Date.now();\n const maxBytes = opts.maxBytes ?? DEFAULT_OUTBOUND_MAX_BYTES;\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), DEFAULT_TIMEOUT_MS);\n const init: RequestInit = {\n method: opts.method,\n signal: controller.signal,\n };\n if (opts.headers) init.headers = { ...opts.headers };\n if (opts.body !== undefined) init.body = opts.body;\n try {\n // allow-raw-fetch: canonical defaultFetchOutbound — single egress point\n const res = await fetch(url, init);\n\n // Fast path: a truthful Content-Length over the cap lets us bail before\n // reading a single body byte. A lying/absent header is still caught by the\n // streaming counter below — the header is an optimisation, not the guard.\n const declared = res.headers.get('content-length');\n if (declared !== null) {\n const declaredLen = Number(declared);\n if (Number.isFinite(declaredLen) && declaredLen > maxBytes) {\n controller.abort();\n throw new BodyTooLargeError(url, maxBytes);\n }\n }\n\n const bytes = await readBodyCapped(res, url, maxBytes, controller);\n return { status: res.status, bytes, durationMs: Date.now() - t0 };\n } finally {\n clearTimeout(timeout);\n }\n};\n\n// Stream the response body, aborting the underlying request the instant the\n// running byte count exceeds `maxBytes`. This is the actual OOM guard: a\n// gateway that withholds or lies about Content-Length still cannot make us\n// buffer more than the cap, because we stop reading and tear the socket down.\nasync function readBodyCapped(\n res: Response,\n url: string,\n maxBytes: number,\n controller: AbortController,\n): Promise<Uint8Array> {\n const body = res.body;\n if (body === null) {\n // No stream (e.g. a 204, or a fetch polyfill that buffered eagerly). Fall\n // back to arrayBuffer but still enforce the cap on the materialised length.\n const buf = await res.arrayBuffer();\n if (buf.byteLength > maxBytes) {\n throw new BodyTooLargeError(url, maxBytes);\n }\n return new Uint8Array(buf);\n }\n\n const reader = body.getReader();\n const chunks: Uint8Array[] = [];\n let total = 0;\n try {\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n if (value === undefined) continue;\n total += value.byteLength;\n if (total > maxBytes) {\n controller.abort();\n throw new BodyTooLargeError(url, maxBytes);\n }\n chunks.push(value);\n }\n } finally {\n reader.releaseLock();\n }\n\n const out = new Uint8Array(total);\n let offset = 0;\n for (const chunk of chunks) {\n out.set(chunk, offset);\n offset += chunk.byteLength;\n }\n return out;\n}\n\nexport function wrapFetchOutbound(\n inner: FetchOutbound,\n audit: HttpCallRecord[],\n config: WrapFetchOutboundConfig | ReadonlyArray<string> | undefined = undefined,\n): FetchOutbound {\n // Accept either a denyHosts array (positional) or the full config object.\n const normConfig: WrapFetchOutboundConfig =\n config === undefined\n ? {}\n : Array.isArray(config)\n ? { denyHosts: config as ReadonlyArray<string> }\n : (config as WrapFetchOutboundConfig);\n\n const denyHosts = normConfig.denyHosts ?? [];\n // Default retries=0 (single attempt). Callers opt in via explicit `retries`;\n // the top-level `fetchOutbound` entrypoint forwards caller config.\n const retries = normConfig.retries ?? 0;\n const retryableStatuses = normConfig.retryableStatuses ?? DEFAULT_RETRYABLE_STATUSES;\n\n return async (url, opts) => {\n // The `webhook` purpose has bespoke requirements (DNS pinning,\n // per-hop redirect re-checking, body-size cap) that the generic\n // wrapper cannot satisfy. Force callers to use `fetchWebhook`\n // instead of silently accepting the call here.\n if (opts.purpose === 'webhook') {\n audit.push({\n url,\n method: 'GET',\n status: 0,\n bytes: 0,\n duration_ms: 0,\n purpose: opts.purpose,\n });\n throw new Error(\n `webhook purpose must be sent via fetchWebhook, not fetchOutbound (url=${url})`,\n );\n }\n\n // Protocol allowlist.\n const protocol = parseProtocol(url);\n if (protocol !== 'http:' && protocol !== 'https:') {\n audit.push({\n url,\n method: 'GET',\n status: 0,\n bytes: 0,\n duration_ms: 0,\n purpose: opts.purpose,\n });\n throw new UnsupportedProtocolError(protocol ?? '', url);\n }\n\n // Method allowlist.\n if (!isAllowedMethod(opts.method)) {\n audit.push({\n url,\n method: 'GET',\n status: 0,\n bytes: 0,\n duration_ms: 0,\n purpose: opts.purpose,\n });\n throw new UnsupportedMethodError(opts.method, url);\n }\n\n // Deny-list short-circuit.\n if (denyHosts.length > 0) {\n const host = new URL(url).hostname;\n if (matchesDenyList(host, denyHosts)) {\n audit.push({\n url,\n method: opts.method,\n status: 0,\n bytes: 0,\n duration_ms: 0,\n purpose: opts.purpose,\n });\n throw new DenyHostError(canonicaliseHost(host), url);\n }\n }\n\n // Retry loop. retries=0 → single attempt, return-or-rethrow original.\n let lastStatus: number | undefined;\n let lastError: Error | undefined;\n const totalAttempts = retries + 1;\n for (let attempt = 1; attempt <= totalAttempts; attempt++) {\n const t0 = Date.now();\n try {\n const result = await inner(url, opts);\n audit.push({\n url,\n method: opts.method,\n status: result.status,\n bytes: result.bytes.byteLength,\n duration_ms: result.durationMs,\n purpose: opts.purpose,\n });\n if (retryableStatuses.includes(result.status) && retries > 0) {\n lastStatus = result.status;\n if (attempt < totalAttempts) {\n await sleep(backoffJitteredMs(attempt - 1));\n continue;\n }\n break;\n }\n return result;\n } catch (e) {\n const durationMs = Date.now() - t0;\n if (\n e instanceof DenyHostError ||\n e instanceof UnsupportedProtocolError ||\n e instanceof UnsupportedMethodError\n ) {\n audit.push({\n url,\n method: opts.method,\n status: 0,\n bytes: 0,\n duration_ms: durationMs,\n purpose: opts.purpose,\n });\n throw e;\n }\n audit.push({\n url,\n method: opts.method,\n status: 0,\n bytes: 0,\n duration_ms: durationMs,\n purpose: opts.purpose,\n });\n lastError = e as Error;\n if (attempt < totalAttempts) {\n await sleep(backoffJitteredMs(attempt - 1));\n continue;\n }\n break;\n }\n }\n // Single-attempt mode re-throws the original verbatim so callers can match\n // by identity; retry mode wraps the terminal failure in OutboundExhaustedError.\n if (retries === 0 && lastError !== undefined) {\n throw lastError;\n }\n throw new OutboundExhaustedError({ url, attempts: totalAttempts, lastStatus, lastError });\n };\n}\n\nexport async function fetchOutbound(\n url: string,\n opts: FetchOutboundOptions,\n audit: HttpCallRecord[],\n config: WrapFetchOutboundConfig = {},\n): Promise<FetchOutboundResult> {\n const wrapped = wrapFetchOutbound(defaultFetchOutbound, audit, config);\n return wrapped(url, opts);\n}\n","// Public denyHostsFetch surface — thin adapter over the canonical\n// fetchOutbound primitive in ./fetch-outbound.ts.\n\nimport {\n DenyHostError,\n type FetchOutbound,\n type FetchOutboundOptions,\n type HttpCallRecord,\n type HttpMethod,\n UnsupportedMethodError,\n UnsupportedProtocolError,\n wrapFetchOutbound,\n} from './fetch-outbound';\n\nexport { DenyHostError, UnsupportedMethodError, UnsupportedProtocolError };\n\nexport type HttpCall = HttpCallRecord;\n\nexport type DenyHostsFetchOptions = {\n readonly denyHosts: readonly string[];\n readonly audit: HttpCall[];\n readonly purpose: HttpCall['purpose'];\n readonly fetchImpl?: typeof fetch;\n};\n\nexport async function denyHostsFetch(\n url: string,\n init: RequestInit | undefined,\n opts: DenyHostsFetchOptions,\n): Promise<Response> {\n // Forward the raw method so the canonical wrap surfaces\n // UnsupportedMethodError instead of silently rewriting to GET.\n const rawMethod = (init?.method ?? 'GET') as HttpMethod;\n const headers = init?.headers as Record<string, string> | undefined;\n const bodyValue = init?.body;\n const body: string | undefined = typeof bodyValue === 'string' ? bodyValue : undefined;\n const fetchImpl: typeof fetch = opts.fetchImpl ?? globalThis.fetch;\n\n const innerOpts: FetchOutboundOptions = headers\n ? body !== undefined\n ? { method: rawMethod, purpose: opts.purpose, headers, body }\n : { method: rawMethod, purpose: opts.purpose, headers }\n : body !== undefined\n ? { method: rawMethod, purpose: opts.purpose, body }\n : { method: rawMethod, purpose: opts.purpose };\n\n let storedResponse: Response | null = null;\n const inner: FetchOutbound = async (innerUrl, innerOptsArg) => {\n const t0 = Date.now();\n const reqInit: RequestInit = { method: innerOptsArg.method };\n if (innerOptsArg.headers) reqInit.headers = { ...innerOptsArg.headers };\n if (innerOptsArg.body !== undefined) reqInit.body = innerOptsArg.body;\n const response = await fetchImpl(innerUrl, reqInit);\n storedResponse = response;\n const buf = await response.clone().arrayBuffer();\n return {\n status: response.status,\n bytes: new Uint8Array(buf),\n durationMs: Date.now() - t0,\n };\n };\n\n const wrapped = wrapFetchOutbound(inner, opts.audit, { denyHosts: opts.denyHosts });\n await wrapped(url, innerOpts);\n return storedResponse!;\n}\n"]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { H as HttpCallRecord } from '../fetch-outbound-BT5-NiYN.cjs';
|
|
2
|
+
export { B as BodyTooLargeError, D as DEFAULT_OUTBOUND_MAX_BYTES, b as DenyHostError, F as FetchOutbound, c as FetchOutboundOptions, d as FetchOutboundResult, e as HttpMethod, f as HttpPurpose, O as OutboundExhaustedError, R as RetryConfig, U as UnsupportedMethodError, g as UnsupportedProtocolError, W as WrapFetchOutboundConfig, h as defaultFetchOutbound, i as fetchOutbound, m as matchesDenyList, w as wrapFetchOutbound } from '../fetch-outbound-BT5-NiYN.cjs';
|
|
3
|
+
|
|
4
|
+
type HttpCall = HttpCallRecord;
|
|
5
|
+
type DenyHostsFetchOptions = {
|
|
6
|
+
readonly denyHosts: readonly string[];
|
|
7
|
+
readonly audit: HttpCall[];
|
|
8
|
+
readonly purpose: HttpCall['purpose'];
|
|
9
|
+
readonly fetchImpl?: typeof fetch;
|
|
10
|
+
};
|
|
11
|
+
declare function denyHostsFetch(url: string, init: RequestInit | undefined, opts: DenyHostsFetchOptions): Promise<Response>;
|
|
12
|
+
|
|
13
|
+
export { type DenyHostsFetchOptions, type HttpCall, HttpCallRecord, denyHostsFetch };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { H as HttpCallRecord } from '../fetch-outbound-BT5-NiYN.js';
|
|
2
|
+
export { B as BodyTooLargeError, D as DEFAULT_OUTBOUND_MAX_BYTES, b as DenyHostError, F as FetchOutbound, c as FetchOutboundOptions, d as FetchOutboundResult, e as HttpMethod, f as HttpPurpose, O as OutboundExhaustedError, R as RetryConfig, U as UnsupportedMethodError, g as UnsupportedProtocolError, W as WrapFetchOutboundConfig, h as defaultFetchOutbound, i as fetchOutbound, m as matchesDenyList, w as wrapFetchOutbound } from '../fetch-outbound-BT5-NiYN.js';
|
|
3
|
+
|
|
4
|
+
type HttpCall = HttpCallRecord;
|
|
5
|
+
type DenyHostsFetchOptions = {
|
|
6
|
+
readonly denyHosts: readonly string[];
|
|
7
|
+
readonly audit: HttpCall[];
|
|
8
|
+
readonly purpose: HttpCall['purpose'];
|
|
9
|
+
readonly fetchImpl?: typeof fetch;
|
|
10
|
+
};
|
|
11
|
+
declare function denyHostsFetch(url: string, init: RequestInit | undefined, opts: DenyHostsFetchOptions): Promise<Response>;
|
|
12
|
+
|
|
13
|
+
export { type DenyHostsFetchOptions, type HttpCall, HttpCallRecord, denyHostsFetch };
|