@dvmkit/sdk 0.1.0-rc.1 → 0.1.0-rc.3
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 +10 -2
- package/dist/{revenue-reporter-M35KP6V7.js → chunk-2ABMGUDS.js} +78 -2
- package/dist/chunk-5SO7ZVOH.js +375 -0
- package/dist/chunk-66HGCPBU.js +25 -0
- package/dist/{chunk-KQAJVVZT.js → chunk-AZBXSXQT.js} +27 -287
- package/dist/chunk-C2DC4FKR.js +21424 -0
- package/dist/{chunk-H25M54MI.js → chunk-C3MTFLC6.js} +16 -0
- package/dist/{chunk-NTK5DJ6R.js → chunk-EXHBXA4U.js} +11 -1
- package/dist/chunk-FT7IM66W.js +1557 -0
- package/dist/{chunk-KXWROQGK.js → chunk-FUJ36YDV.js} +1 -24
- package/dist/{tempo-charge-store-6GJEMNUU.js → chunk-JZWELPFH.js} +1 -0
- package/dist/{chunk-RPXHKMYE.js → chunk-LWUR4CGG.js} +348 -34
- package/dist/chunk-RHP3BRTH.js +1090 -0
- package/dist/{tempo-session-store-FTEEGZXA.js → chunk-RU7SXHLO.js} +2 -1
- package/dist/{chunk-7IH5SG2A.js → chunk-TKA6ZP4M.js} +62 -41
- package/dist/chunk-TVI4V7GF.js +283 -0
- package/dist/chunk-X3IKFWJA.js +754 -0
- package/dist/{chunk-DCNT4PJS.js → chunk-XY5Y5REG.js} +6 -258
- package/dist/chunk-XYTSDAPH.js +232 -0
- package/dist/chunk-YD3TZNXV.js +1042 -0
- package/dist/{credit-ledger-EDMEZSA2.js → credit-ledger-ED6JXKVD.js} +2 -2
- package/dist/credit-menu-DONAtGVf.d.ts +5076 -0
- package/dist/{ssrf-BdHsrrIb.d.ts → fx-Bq4cvn16.d.ts} +37 -119
- package/dist/index.d.ts +8 -66
- package/dist/index.js +11 -219
- package/dist/internal/index.d.ts +5745 -0
- package/dist/internal/index.js +6379 -0
- package/dist/{job-store-C5n6bhap.d.ts → job-store-m2pYmvbr.d.ts} +1772 -31
- package/dist/{memory-credit-ledger-7TTZDSRS.js → memory-credit-ledger-XJ5VQEVP.js} +3 -3
- package/dist/payout-reporter-3UB5WRCV.js +13 -0
- package/dist/revenue-reporter-JIKUPXOK.js +7 -0
- package/dist/server/index.d.ts +14 -3530
- package/dist/server/index.js +327 -20636
- package/dist/ssrf-DbFkpDv0.d.ts +118 -0
- package/dist/tempo-charge-store-RIFTALZK.js +8 -0
- package/dist/tempo-session-store-DALMRIWN.js +11 -0
- package/dist/testing/index.d.ts +3 -2
- package/dist/testing/index.js +3 -2
- package/dist/usd-DjVAPMlf.d.ts +97 -0
- package/dist/x402-5EVIUSEP.js +81 -0
- package/package.json +6 -2
- package/dist/x402-35VLYFKZ.js +0 -1272
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
} from "./chunk-YG7G4DPZ.js";
|
|
5
5
|
import {
|
|
6
6
|
withPostgresTransactionRecovery
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-C3MTFLC6.js";
|
|
8
8
|
import {
|
|
9
9
|
withSdkInitLock
|
|
10
10
|
} from "./chunk-S3XAHZQY.js";
|
|
@@ -461,6 +461,7 @@ function acceptanceVoucherAmount(acceptance, key, current, next) {
|
|
|
461
461
|
const authorized = isRecord(current) ? asBigInt(current.highestVoucherAmount) : void 0;
|
|
462
462
|
return authorized !== void 0 && authorized >= acceptance.cumulativeAmount ? acceptance.cumulativeAmount : void 0;
|
|
463
463
|
}
|
|
464
|
+
|
|
464
465
|
export {
|
|
465
466
|
PostgresTempoSessionStore,
|
|
466
467
|
assertMonotonicTransition
|
|
@@ -1,32 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
|
-
initCallerLoggers
|
|
2
|
+
initCallerLoggers
|
|
3
|
+
} from "./chunk-66HGCPBU.js";
|
|
4
|
+
import {
|
|
3
5
|
redactUrl
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
|
|
6
|
-
// src/sdk/server/job-store.ts
|
|
7
|
-
function accumulateAskedTopUp(prior, ask) {
|
|
8
|
-
const poisoned = (reason) => ({
|
|
9
|
-
micro: UNCAPPABLE_ASK_TOTAL,
|
|
10
|
-
currency: prior.currency,
|
|
11
|
-
reason: prior.reason ?? reason
|
|
12
|
-
});
|
|
13
|
-
if (prior.micro === UNCAPPABLE_ASK_TOTAL) {
|
|
14
|
-
return { micro: prior.micro, currency: prior.currency, reason: prior.reason };
|
|
15
|
-
}
|
|
16
|
-
if (ask.micro === void 0) return poisoned("ask_unpriceable");
|
|
17
|
-
if (prior.micro === void 0) {
|
|
18
|
-
return { micro: ask.micro, currency: ask.currency, reason: prior.reason };
|
|
19
|
-
}
|
|
20
|
-
if (prior.currency !== ask.currency) return poisoned("ask_currency_switch");
|
|
21
|
-
return { micro: prior.micro + ask.micro, currency: prior.currency, reason: prior.reason };
|
|
22
|
-
}
|
|
23
|
-
var UNCAPPABLE_ASK_TOTAL = -1;
|
|
24
|
-
function isReceiptIssuingStore(store) {
|
|
25
|
-
return "claimReceiptSeq" in store && "saveReceipt" in store;
|
|
26
|
-
}
|
|
27
|
-
function isStreamableJobStore(store) {
|
|
28
|
-
return "appendOutgoing" in store && "recordInbound" in store && "verifyAndCredit" in store && "getVerifiedInbound" in store && "subscribeMessages" in store && "subscribeNotifications" in store && "getCounters" in store && "getMessages" in store && "cancelJob" in store && "initStreaming" in store;
|
|
29
|
-
}
|
|
6
|
+
} from "./chunk-FUJ36YDV.js";
|
|
30
7
|
|
|
31
8
|
// src/sdk/step-cache.ts
|
|
32
9
|
var StepCache = class _StepCache {
|
|
@@ -223,6 +200,34 @@ function isYieldMessage(msg) {
|
|
|
223
200
|
return msg.type === "prompt" || msg.type === "payment-request" || msg.type === "working" || msg.type === "complete" || msg.type === "cancel";
|
|
224
201
|
}
|
|
225
202
|
|
|
203
|
+
// src/sdk/server/job-store.ts
|
|
204
|
+
function accumulateAskedTopUp(prior, ask) {
|
|
205
|
+
const poisoned = (reason) => ({
|
|
206
|
+
micro: UNCAPPABLE_ASK_TOTAL,
|
|
207
|
+
currency: prior.currency,
|
|
208
|
+
reason: prior.reason ?? reason
|
|
209
|
+
});
|
|
210
|
+
if (prior.micro === UNCAPPABLE_ASK_TOTAL) {
|
|
211
|
+
return { micro: prior.micro, currency: prior.currency, reason: prior.reason };
|
|
212
|
+
}
|
|
213
|
+
if (ask.micro === void 0) return poisoned("ask_unpriceable");
|
|
214
|
+
if (prior.micro === void 0) {
|
|
215
|
+
return { micro: ask.micro, currency: ask.currency, reason: prior.reason };
|
|
216
|
+
}
|
|
217
|
+
if (prior.currency !== ask.currency) return poisoned("ask_currency_switch");
|
|
218
|
+
return { micro: prior.micro + ask.micro, currency: prior.currency, reason: prior.reason };
|
|
219
|
+
}
|
|
220
|
+
var UNCAPPABLE_ASK_TOTAL = -1;
|
|
221
|
+
function isReceiptIssuingStore(store) {
|
|
222
|
+
return "claimReceiptSeq" in store && "saveReceipt" in store;
|
|
223
|
+
}
|
|
224
|
+
function isStreamableJobStore(store) {
|
|
225
|
+
return "appendOutgoing" in store && "recordInbound" in store && "verifyAndCredit" in store && "getVerifiedInbound" in store && "subscribeMessages" in store && "subscribeNotifications" in store && "getCounters" in store && "getMessages" in store && "cancelJob" in store && "initStreaming" in store;
|
|
226
|
+
}
|
|
227
|
+
function isStaleJobReapable(store) {
|
|
228
|
+
return "findStaleJobs" in store && "cancelStaleJob" in store;
|
|
229
|
+
}
|
|
230
|
+
|
|
226
231
|
// src/sdk/server/memory-job-store.ts
|
|
227
232
|
var MemoryJobStore = class {
|
|
228
233
|
data = /* @__PURE__ */ new Map();
|
|
@@ -646,6 +651,17 @@ function createConsoleLogger(jobId) {
|
|
|
646
651
|
}
|
|
647
652
|
};
|
|
648
653
|
}
|
|
654
|
+
function createStdoutLogger(context) {
|
|
655
|
+
const emit = (sink, level) => (message, data) => {
|
|
656
|
+
sink(JSON.stringify({ level, msg: message, ...context, ...data }));
|
|
657
|
+
};
|
|
658
|
+
return {
|
|
659
|
+
debug: emit(console.debug.bind(console), "debug"),
|
|
660
|
+
info: emit(console.info.bind(console), "info"),
|
|
661
|
+
warn: emit(console.warn.bind(console), "warn"),
|
|
662
|
+
error: emit(console.error.bind(console), "error")
|
|
663
|
+
};
|
|
664
|
+
}
|
|
649
665
|
function createNoopLogger() {
|
|
650
666
|
const noop2 = () => {
|
|
651
667
|
};
|
|
@@ -695,20 +711,6 @@ function rawContext() {
|
|
|
695
711
|
return storage.getStore();
|
|
696
712
|
}
|
|
697
713
|
|
|
698
|
-
// src/observability/datasets.ts
|
|
699
|
-
var SPANS_DATASETS = [
|
|
700
|
-
{ name: "platform", retentionDays: 90 },
|
|
701
|
-
{ name: "cashu", retentionDays: 90 },
|
|
702
|
-
{ name: "lightning", retentionDays: 90 },
|
|
703
|
-
{ name: "stripe", retentionDays: 90 },
|
|
704
|
-
{ name: "x402", retentionDays: 90 },
|
|
705
|
-
{ name: "tempo", retentionDays: 90 },
|
|
706
|
-
{ name: "isolate", retentionDays: 90 },
|
|
707
|
-
{ name: "audit", retentionDays: 365 },
|
|
708
|
-
{ name: "cron", retentionDays: 30 }
|
|
709
|
-
];
|
|
710
|
-
var DATASET_NAMES = new Set(SPANS_DATASETS.map((d) => d.name));
|
|
711
|
-
|
|
712
714
|
// src/observability/with-span.ts
|
|
713
715
|
import { hostname } from "os";
|
|
714
716
|
|
|
@@ -850,6 +852,20 @@ async function withSpan(opts, fn) {
|
|
|
850
852
|
}
|
|
851
853
|
}
|
|
852
854
|
|
|
855
|
+
// src/observability/datasets.ts
|
|
856
|
+
var SPANS_DATASETS = [
|
|
857
|
+
{ name: "platform", retentionDays: 90 },
|
|
858
|
+
{ name: "cashu", retentionDays: 90 },
|
|
859
|
+
{ name: "lightning", retentionDays: 90 },
|
|
860
|
+
{ name: "stripe", retentionDays: 90 },
|
|
861
|
+
{ name: "x402", retentionDays: 90 },
|
|
862
|
+
{ name: "tempo", retentionDays: 90 },
|
|
863
|
+
{ name: "isolate", retentionDays: 90 },
|
|
864
|
+
{ name: "audit", retentionDays: 365 },
|
|
865
|
+
{ name: "cron", retentionDays: 30 }
|
|
866
|
+
];
|
|
867
|
+
var DATASET_NAMES = new Set(SPANS_DATASETS.map((d) => d.name));
|
|
868
|
+
|
|
853
869
|
// src/observability/loggers.ts
|
|
854
870
|
var noop = () => {
|
|
855
871
|
};
|
|
@@ -1025,11 +1041,16 @@ export {
|
|
|
1025
1041
|
UNCAPPABLE_ASK_TOTAL,
|
|
1026
1042
|
isReceiptIssuingStore,
|
|
1027
1043
|
isStreamableJobStore,
|
|
1044
|
+
isStaleJobReapable,
|
|
1028
1045
|
MemoryJobStore,
|
|
1029
1046
|
createConsoleLogger,
|
|
1047
|
+
createStdoutLogger,
|
|
1030
1048
|
createNoopLogger,
|
|
1049
|
+
randomTraceId,
|
|
1031
1050
|
withTraceContext,
|
|
1051
|
+
currentContext,
|
|
1032
1052
|
pinDimension,
|
|
1053
|
+
setEmitter,
|
|
1033
1054
|
withSpan,
|
|
1034
1055
|
loggers,
|
|
1035
1056
|
initLoggers,
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
// src/sdk/env.ts
|
|
2
|
+
function envFlag(value) {
|
|
3
|
+
return value === "1" || value === "true";
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
// src/sdk/server/ssrf.ts
|
|
7
|
+
import { lookup } from "dns/promises";
|
|
8
|
+
import { isIPv4, isIPv6 } from "net";
|
|
9
|
+
import { Agent } from "undici";
|
|
10
|
+
var SSRFError = class extends Error {
|
|
11
|
+
code = "ssrf_blocked";
|
|
12
|
+
reason;
|
|
13
|
+
constructor(reason, message) {
|
|
14
|
+
super(message);
|
|
15
|
+
this.reason = reason;
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
async function assertSafeUrl(url, opts) {
|
|
19
|
+
await resolveAndValidate(url, opts);
|
|
20
|
+
}
|
|
21
|
+
async function createPinnedFetch(url, opts) {
|
|
22
|
+
const validated = await resolveAndValidate(url, opts);
|
|
23
|
+
const baseFetch = opts?.baseFetch ?? fetch;
|
|
24
|
+
const initialUrl = new URL(url);
|
|
25
|
+
const agents = [];
|
|
26
|
+
const targets = /* @__PURE__ */ new Map();
|
|
27
|
+
const createTarget = (next) => {
|
|
28
|
+
if (next.kind === "literal") return {};
|
|
29
|
+
const agent = new Agent({
|
|
30
|
+
connect: { lookup: buildPinnedLookup(next.addresses) }
|
|
31
|
+
});
|
|
32
|
+
agents.push(agent);
|
|
33
|
+
return { agent };
|
|
34
|
+
};
|
|
35
|
+
targets.set(initialUrl.origin, createTarget(validated));
|
|
36
|
+
const targetFor = async (requestUrl) => {
|
|
37
|
+
const parsed = new URL(requestUrl);
|
|
38
|
+
const existing = targets.get(parsed.origin);
|
|
39
|
+
if (existing) return existing;
|
|
40
|
+
const target = createTarget(await resolveAndValidate(parsed.href, opts));
|
|
41
|
+
targets.set(parsed.origin, target);
|
|
42
|
+
return target;
|
|
43
|
+
};
|
|
44
|
+
const pinnedFetch = async (input, init) => {
|
|
45
|
+
let request = new Request(input, init);
|
|
46
|
+
let redirects = 0;
|
|
47
|
+
for (; ; ) {
|
|
48
|
+
const target = await targetFor(request.url);
|
|
49
|
+
const response = await baseFetch(
|
|
50
|
+
request,
|
|
51
|
+
target.agent ? { redirect: "manual", dispatcher: target.agent } : { redirect: "manual" }
|
|
52
|
+
);
|
|
53
|
+
if (!isRedirect(response.status) || request.redirect === "manual") return response;
|
|
54
|
+
const location = response.headers.get("location");
|
|
55
|
+
if (location === null) return response;
|
|
56
|
+
await discardResponse(response);
|
|
57
|
+
if (request.redirect === "error") {
|
|
58
|
+
throw new TypeError("fetch failed: redirect mode is set to error");
|
|
59
|
+
}
|
|
60
|
+
if (redirects >= MAX_PINNED_REDIRECTS) {
|
|
61
|
+
throw new TypeError("fetch failed: maximum redirect count exceeded");
|
|
62
|
+
}
|
|
63
|
+
request = requestForRedirect(request, new URL(location, request.url), response.status);
|
|
64
|
+
redirects += 1;
|
|
65
|
+
opts?.onRedirectFollowed?.();
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
return {
|
|
69
|
+
fetch: pinnedFetch,
|
|
70
|
+
address: validated.address,
|
|
71
|
+
family: validated.family,
|
|
72
|
+
close: async () => {
|
|
73
|
+
await Promise.all(agents.map((agent) => agent.close()));
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
var MAX_PINNED_REDIRECTS = 20;
|
|
78
|
+
function isRedirect(status) {
|
|
79
|
+
return status === 301 || status === 302 || status === 303 || status === 307 || status === 308;
|
|
80
|
+
}
|
|
81
|
+
async function discardResponse(response) {
|
|
82
|
+
await response.body?.cancel().catch(() => void 0);
|
|
83
|
+
}
|
|
84
|
+
function requestForRedirect(request, target, status) {
|
|
85
|
+
const headers = new Headers(request.headers);
|
|
86
|
+
if (new URL(request.url).origin !== target.origin) {
|
|
87
|
+
headers.delete("authorization");
|
|
88
|
+
headers.delete("cookie");
|
|
89
|
+
headers.delete("proxy-authorization");
|
|
90
|
+
headers.delete("host");
|
|
91
|
+
}
|
|
92
|
+
const method = request.method.toUpperCase();
|
|
93
|
+
const switchToGet = status === 303 && method !== "HEAD" || (status === 301 || status === 302) && method === "POST";
|
|
94
|
+
if (switchToGet) {
|
|
95
|
+
headers.delete("content-length");
|
|
96
|
+
headers.delete("content-type");
|
|
97
|
+
return redirectRequest(target, request, headers, "GET");
|
|
98
|
+
}
|
|
99
|
+
if (method !== "GET" && method !== "HEAD") {
|
|
100
|
+
throw new TypeError("fetch failed: cannot safely replay a request body across this redirect");
|
|
101
|
+
}
|
|
102
|
+
return redirectRequest(target, request, headers, method);
|
|
103
|
+
}
|
|
104
|
+
function redirectRequest(target, request, headers, method) {
|
|
105
|
+
return new Request(target, {
|
|
106
|
+
method,
|
|
107
|
+
headers,
|
|
108
|
+
signal: request.signal,
|
|
109
|
+
redirect: request.redirect,
|
|
110
|
+
cache: request.cache,
|
|
111
|
+
credentials: request.credentials,
|
|
112
|
+
integrity: request.integrity,
|
|
113
|
+
keepalive: request.keepalive,
|
|
114
|
+
mode: request.mode,
|
|
115
|
+
referrer: request.referrer,
|
|
116
|
+
referrerPolicy: request.referrerPolicy
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
function buildPinnedLookup(addresses) {
|
|
120
|
+
return ((_hostname, options, cb) => {
|
|
121
|
+
if (options.all === false) {
|
|
122
|
+
const first = addresses[0];
|
|
123
|
+
cb(
|
|
124
|
+
null,
|
|
125
|
+
first.address,
|
|
126
|
+
first.family
|
|
127
|
+
);
|
|
128
|
+
} else {
|
|
129
|
+
cb(
|
|
130
|
+
null,
|
|
131
|
+
addresses
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
async function resolveAndValidate(url, opts) {
|
|
137
|
+
const resolver = opts?.resolver ?? defaultResolver;
|
|
138
|
+
let parsed;
|
|
139
|
+
try {
|
|
140
|
+
parsed = new URL(url);
|
|
141
|
+
} catch {
|
|
142
|
+
throw new SSRFError("invalid_url", `url is not a valid URL: ${url}`);
|
|
143
|
+
}
|
|
144
|
+
if (parsed.protocol !== "https:") {
|
|
145
|
+
throw new SSRFError("insecure_scheme", `url must be https; got ${parsed.protocol}`);
|
|
146
|
+
}
|
|
147
|
+
const host = parsed.hostname.toLowerCase();
|
|
148
|
+
if (host === "") {
|
|
149
|
+
throw new SSRFError("invalid_url", "url has no host");
|
|
150
|
+
}
|
|
151
|
+
if (HOSTNAME_DENYLIST_EXACT.has(host) || matchesExtraExact(host, opts?.extraHostnamesExact)) {
|
|
152
|
+
throw new SSRFError("private_address", `url host "${host}" is on the SSRF denylist`);
|
|
153
|
+
}
|
|
154
|
+
for (const suffix of HOSTNAME_DENYLIST_SUFFIX) {
|
|
155
|
+
if (host === suffix.slice(1) || host.endsWith(suffix)) {
|
|
156
|
+
throw new SSRFError(
|
|
157
|
+
"private_address",
|
|
158
|
+
`url host "${host}" matches denied suffix "${suffix}"`
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
if (opts?.extraHostnameSuffixes) {
|
|
163
|
+
for (const suffix of opts.extraHostnameSuffixes) {
|
|
164
|
+
const s = suffix.toLowerCase();
|
|
165
|
+
if (host === s.slice(1) || host.endsWith(s)) {
|
|
166
|
+
throw new SSRFError("private_address", `url host "${host}" matches denied suffix "${s}"`);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
const stripped = host.startsWith("[") && host.endsWith("]") ? host.slice(1, -1) : host;
|
|
171
|
+
if (isIPv4(stripped) || isIPv6(stripped)) {
|
|
172
|
+
if (isUnsafeAddress(stripped, opts)) {
|
|
173
|
+
throw new SSRFError(
|
|
174
|
+
"private_address",
|
|
175
|
+
`url host "${stripped}" is in a blocked address range`
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
return { kind: "literal", address: stripped, family: isIPv4(stripped) ? 4 : 6 };
|
|
179
|
+
}
|
|
180
|
+
let addresses;
|
|
181
|
+
try {
|
|
182
|
+
addresses = await resolver(host);
|
|
183
|
+
} catch (err) {
|
|
184
|
+
throw new SSRFError(
|
|
185
|
+
"dns_failed",
|
|
186
|
+
`url host "${host}" failed DNS resolution: ${err instanceof Error ? err.message : String(err)}`
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
if (addresses.length === 0) {
|
|
190
|
+
throw new SSRFError("dns_failed", `url host "${host}" resolved to no addresses`);
|
|
191
|
+
}
|
|
192
|
+
for (const { address } of addresses) {
|
|
193
|
+
if (isUnsafeAddress(address, opts)) {
|
|
194
|
+
throw new SSRFError(
|
|
195
|
+
"private_address",
|
|
196
|
+
`url host "${host}" resolves to blocked address "${address}"`
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
const validated = addresses.map((a) => ({ address: a.address, family: a.family }));
|
|
201
|
+
const first = validated[0];
|
|
202
|
+
return { kind: "resolved", address: first.address, family: first.family, addresses: validated };
|
|
203
|
+
}
|
|
204
|
+
var HOSTNAME_DENYLIST_EXACT = /* @__PURE__ */ new Set([
|
|
205
|
+
"localhost",
|
|
206
|
+
"ip6-localhost",
|
|
207
|
+
"ip6-loopback",
|
|
208
|
+
"metadata.google.internal",
|
|
209
|
+
"metadata"
|
|
210
|
+
]);
|
|
211
|
+
var HOSTNAME_DENYLIST_SUFFIX = [".internal", ".local", ".localhost", ".lan"];
|
|
212
|
+
async function defaultResolver(host) {
|
|
213
|
+
return lookup(host, { all: true });
|
|
214
|
+
}
|
|
215
|
+
function matchesExtraExact(host, extras) {
|
|
216
|
+
if (!extras) return false;
|
|
217
|
+
for (const entry of extras) {
|
|
218
|
+
if (entry.toLowerCase() === host) return true;
|
|
219
|
+
}
|
|
220
|
+
return false;
|
|
221
|
+
}
|
|
222
|
+
function isUnsafeAddress(address, opts) {
|
|
223
|
+
if (isIPv4(address)) {
|
|
224
|
+
if (isUnsafeIPv4(address)) return true;
|
|
225
|
+
return opts?.extraUnsafeIPv4?.(address) === true;
|
|
226
|
+
}
|
|
227
|
+
if (isIPv6(address)) {
|
|
228
|
+
if (isUnsafeIPv6(address)) return true;
|
|
229
|
+
return opts?.extraUnsafeIPv6?.(address) === true;
|
|
230
|
+
}
|
|
231
|
+
return true;
|
|
232
|
+
}
|
|
233
|
+
function isUnsafeIPv4(address) {
|
|
234
|
+
const parts = address.split(".").map(Number);
|
|
235
|
+
if (parts.length !== 4 || parts.some((p) => !Number.isFinite(p) || p < 0 || p > 255)) {
|
|
236
|
+
return true;
|
|
237
|
+
}
|
|
238
|
+
const [a, b, c] = parts;
|
|
239
|
+
if (a === 0) return true;
|
|
240
|
+
if (a === 10) return true;
|
|
241
|
+
if (a === 100 && b >= 64 && b <= 127) return true;
|
|
242
|
+
if (a === 127) return true;
|
|
243
|
+
if (a === 169 && b === 254) return true;
|
|
244
|
+
if (a === 172 && b >= 16 && b <= 31) return true;
|
|
245
|
+
if (a === 192 && b === 0 && (c === 0 || c === 2)) return true;
|
|
246
|
+
if (a === 192 && b === 168) return true;
|
|
247
|
+
if (a === 198 && (b === 18 || b === 19)) return true;
|
|
248
|
+
if (a >= 224 && a <= 239) return true;
|
|
249
|
+
if (a >= 240) return true;
|
|
250
|
+
return false;
|
|
251
|
+
}
|
|
252
|
+
function isUnsafeIPv6(address) {
|
|
253
|
+
const lower = address.toLowerCase();
|
|
254
|
+
if (lower === "::1") return true;
|
|
255
|
+
if (lower === "::") return true;
|
|
256
|
+
if (lower.startsWith("fe8") || lower.startsWith("fe9") || lower.startsWith("fea") || lower.startsWith("feb")) {
|
|
257
|
+
return true;
|
|
258
|
+
}
|
|
259
|
+
if (lower.startsWith("fc") || lower.startsWith("fd")) return true;
|
|
260
|
+
if (lower.startsWith("::ffff:")) {
|
|
261
|
+
const tail = lower.slice("::ffff:".length);
|
|
262
|
+
if (isIPv4(tail)) return isUnsafeIPv4(tail);
|
|
263
|
+
const m = /^([0-9a-f]{1,4}):([0-9a-f]{1,4})$/.exec(tail);
|
|
264
|
+
if (m) {
|
|
265
|
+
const high = parseInt(m[1], 16);
|
|
266
|
+
const low = parseInt(m[2], 16);
|
|
267
|
+
const a = high >> 8 & 255;
|
|
268
|
+
const b = high & 255;
|
|
269
|
+
const c = low >> 8 & 255;
|
|
270
|
+
const d = low & 255;
|
|
271
|
+
return isUnsafeIPv4(`${a.toString()}.${b.toString()}.${c.toString()}.${d.toString()}`);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
if (lower.startsWith("ff")) return true;
|
|
275
|
+
return false;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
export {
|
|
279
|
+
envFlag,
|
|
280
|
+
SSRFError,
|
|
281
|
+
assertSafeUrl,
|
|
282
|
+
createPinnedFetch
|
|
283
|
+
};
|