kinetex 1.2.0 → 1.3.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/README.md +919 -445
- package/dist/browser/kinetex.esm.js +18 -18
- package/dist/browser/kinetex.js +663 -246
- package/dist/browser/kinetex.min.js +18 -18
- package/dist/cjs/aws-sigv4.js +4 -1
- package/dist/cjs/cache.js +52 -14
- package/dist/cjs/circuit-breaker.js +24 -4
- package/dist/cjs/client.js +495 -131
- package/dist/cjs/cookie-parser.js +7 -4
- package/dist/cjs/cookie-store.js +16 -8
- package/dist/cjs/core.js +46 -7
- package/dist/cjs/dedup.js +9 -7
- package/dist/cjs/digest.js +26 -0
- package/dist/cjs/headers.js +64 -8
- package/dist/cjs/interceptors.js +64 -22
- package/dist/cjs/logging.js +1 -1
- package/dist/cjs/pagination.js +14 -6
- package/dist/cjs/progress.js +122 -42
- package/dist/cjs/socks5.js +36 -21
- package/dist/cjs/sse.js +48 -11
- package/dist/cjs/worker.js +6 -6
- package/dist/cjs/ws.js +13 -6
- package/dist/esm/aws-sigv4.js +4 -1
- package/dist/esm/aws-sigv4.js.map +1 -1
- package/dist/esm/cache.js +52 -14
- package/dist/esm/cache.js.map +1 -1
- package/dist/esm/circuit-breaker.js +24 -4
- package/dist/esm/circuit-breaker.js.map +1 -1
- package/dist/esm/client.js +495 -131
- package/dist/esm/client.js.map +1 -1
- package/dist/esm/cookie-parser.js +7 -4
- package/dist/esm/cookie-parser.js.map +1 -1
- package/dist/esm/cookie-store.js +16 -8
- package/dist/esm/cookie-store.js.map +1 -1
- package/dist/esm/core.js +46 -7
- package/dist/esm/core.js.map +1 -1
- package/dist/esm/dedup.js +9 -7
- package/dist/esm/dedup.js.map +1 -1
- package/dist/esm/digest.js +26 -0
- package/dist/esm/digest.js.map +1 -1
- package/dist/esm/headers.js +64 -8
- package/dist/esm/headers.js.map +1 -1
- package/dist/esm/interceptors.js +64 -22
- package/dist/esm/interceptors.js.map +1 -1
- package/dist/esm/logging.js +1 -1
- package/dist/esm/pagination.js +14 -6
- package/dist/esm/pagination.js.map +1 -1
- package/dist/esm/progress.js +122 -42
- package/dist/esm/progress.js.map +1 -1
- package/dist/esm/socks5.js +36 -21
- package/dist/esm/socks5.js.map +1 -1
- package/dist/esm/sse.js +48 -11
- package/dist/esm/sse.js.map +1 -1
- package/dist/esm/types.js.map +1 -1
- package/dist/esm/worker.js +6 -6
- package/dist/esm/worker.js.map +1 -1
- package/dist/esm/ws.js +13 -6
- package/dist/esm/ws.js.map +1 -1
- package/dist/types/aws-sigv4.d.ts.map +1 -1
- package/dist/types/cache.d.ts +8 -1
- package/dist/types/cache.d.ts.map +1 -1
- package/dist/types/circuit-breaker.d.ts.map +1 -1
- package/dist/types/client.d.ts +29 -12
- package/dist/types/client.d.ts.map +1 -1
- package/dist/types/cookie-parser.d.ts.map +1 -1
- package/dist/types/cookie-store.d.ts.map +1 -1
- package/dist/types/core.d.ts +6 -0
- package/dist/types/core.d.ts.map +1 -1
- package/dist/types/dedup.d.ts +0 -7
- package/dist/types/dedup.d.ts.map +1 -1
- package/dist/types/digest.d.ts +14 -0
- package/dist/types/digest.d.ts.map +1 -1
- package/dist/types/headers.d.ts +25 -10
- package/dist/types/headers.d.ts.map +1 -1
- package/dist/types/interceptors.d.ts.map +1 -1
- package/dist/types/logging.d.ts +1 -1
- package/dist/types/pagination.d.ts.map +1 -1
- package/dist/types/progress.d.ts.map +1 -1
- package/dist/types/socks5.d.ts.map +1 -1
- package/dist/types/sse.d.ts.map +1 -1
- package/dist/types/types.d.ts +25 -2
- package/dist/types/types.d.ts.map +1 -1
- package/dist/types/worker.d.ts +6 -6
- package/dist/types/worker.d.ts.map +1 -1
- package/dist/types/ws.d.ts.map +1 -1
- package/package.json +2 -2
package/dist/browser/kinetex.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* kinetex v1.
|
|
1
|
+
/* kinetex v1.3.0 | MIT | https://github.com/kinetexjs/kinetex */
|
|
2
2
|
"use strict";
|
|
3
3
|
var kinetex = (() => {
|
|
4
4
|
var __create = Object.create;
|
|
@@ -902,6 +902,7 @@ var kinetex = (() => {
|
|
|
902
902
|
// dist/esm/cache.js
|
|
903
903
|
var cache_exports = {};
|
|
904
904
|
__export(cache_exports, {
|
|
905
|
+
CREDENTIAL_HEADERS: () => CREDENTIAL_HEADERS,
|
|
905
906
|
CloudflareKVAdapter: () => CloudflareKVAdapter,
|
|
906
907
|
HTTPCache: () => HTTPCache,
|
|
907
908
|
MemoryStorageAdapter: () => MemoryStorageAdapter,
|
|
@@ -993,18 +994,16 @@ var kinetex = (() => {
|
|
|
993
994
|
return parts.join(";");
|
|
994
995
|
}
|
|
995
996
|
function normalizeCacheKeyPart(part) {
|
|
996
|
-
|
|
997
|
-
String.fromCharCode(0) + "-" + String.fromCharCode(31),
|
|
998
|
-
String.fromCharCode(127) + "-" + String.fromCharCode(159)
|
|
999
|
-
].join("");
|
|
1000
|
-
const controlRegex = new RegExp(`[${controlRanges}]`, "g");
|
|
1001
|
-
return part.replaceAll(controlRegex, "").replaceAll(/\s+/g, " ").trim();
|
|
997
|
+
return part.replaceAll(CONTROL_CHARS, "").replaceAll(/\s+/g, " ").trim();
|
|
1002
998
|
}
|
|
1003
999
|
async function getAuthFingerprint(headers) {
|
|
1004
|
-
const
|
|
1000
|
+
const lowered = /* @__PURE__ */ new Map();
|
|
1001
|
+
for (const [name, value] of Object.entries(headers)) {
|
|
1002
|
+
lowered.set(name.toLowerCase(), value);
|
|
1003
|
+
}
|
|
1005
1004
|
const parts = [];
|
|
1006
|
-
for (const header of
|
|
1007
|
-
const value =
|
|
1005
|
+
for (const header of CREDENTIAL_HEADERS) {
|
|
1006
|
+
const value = lowered.get(header);
|
|
1008
1007
|
if (value)
|
|
1009
1008
|
parts.push(`${header}=${value}`);
|
|
1010
1009
|
}
|
|
@@ -1118,7 +1117,7 @@ var kinetex = (() => {
|
|
|
1118
1117
|
function createTwoTierCache(l2, config) {
|
|
1119
1118
|
return new HTTPCache({ ...config, storage: new TwoTierStorageAdapter(l2) });
|
|
1120
1119
|
}
|
|
1121
|
-
var MemoryStorageAdapter, WebStorageAdapter, CloudflareKVAdapter, TwoTierStorageAdapter, LRUNode, LRUTracker, HTTPCache;
|
|
1120
|
+
var MemoryStorageAdapter, WebStorageAdapter, CloudflareKVAdapter, TwoTierStorageAdapter, CONTROL_CHARS, CREDENTIAL_HEADERS, LRUNode, LRUTracker, HTTPCache;
|
|
1122
1121
|
var init_cache = __esm({
|
|
1123
1122
|
"dist/esm/cache.js"() {
|
|
1124
1123
|
"use strict";
|
|
@@ -1286,6 +1285,24 @@ var kinetex = (() => {
|
|
|
1286
1285
|
await Promise.all([this.l1.clear(), this.l2.clear()]);
|
|
1287
1286
|
}
|
|
1288
1287
|
};
|
|
1288
|
+
CONTROL_CHARS = /[\u0000-\u001f\u007f-\u009f]/g;
|
|
1289
|
+
CREDENTIAL_HEADERS = [
|
|
1290
|
+
"authorization",
|
|
1291
|
+
"proxy-authorization",
|
|
1292
|
+
"cookie",
|
|
1293
|
+
"x-api-key",
|
|
1294
|
+
"apikey",
|
|
1295
|
+
"api-key",
|
|
1296
|
+
"x-auth-token",
|
|
1297
|
+
"x-access-token",
|
|
1298
|
+
"x-refresh-token",
|
|
1299
|
+
"x-session-id",
|
|
1300
|
+
"x-session-token",
|
|
1301
|
+
"x-secret",
|
|
1302
|
+
"x-secret-key",
|
|
1303
|
+
"x-private-key",
|
|
1304
|
+
"x-csrf-token"
|
|
1305
|
+
];
|
|
1289
1306
|
LRUNode = class {
|
|
1290
1307
|
constructor(key, prev = null, next = null) {
|
|
1291
1308
|
__publicField(this, "key");
|
|
@@ -1400,6 +1417,8 @@ var kinetex = (() => {
|
|
|
1400
1417
|
// 7 days
|
|
1401
1418
|
honorCacheControl: config.honorCacheControl ?? true,
|
|
1402
1419
|
cacheMethods: config.cacheMethods ?? ["GET", "HEAD"],
|
|
1420
|
+
// 304 is intentionally absent: the client revalidates rather than
|
|
1421
|
+
// storing a 304, so listing it only implied a guarantee that never held.
|
|
1403
1422
|
cacheStatuses: config.cacheStatuses ?? [
|
|
1404
1423
|
200,
|
|
1405
1424
|
203,
|
|
@@ -1407,7 +1426,6 @@ var kinetex = (() => {
|
|
|
1407
1426
|
206,
|
|
1408
1427
|
300,
|
|
1409
1428
|
301,
|
|
1410
|
-
304,
|
|
1411
1429
|
404,
|
|
1412
1430
|
405,
|
|
1413
1431
|
410,
|
|
@@ -1774,6 +1792,9 @@ var kinetex = (() => {
|
|
|
1774
1792
|
for (const tag of entry.tags) {
|
|
1775
1793
|
this.tagIndex.get(tag)?.delete(key);
|
|
1776
1794
|
}
|
|
1795
|
+
} else {
|
|
1796
|
+
for (const set of this.tagIndex.values())
|
|
1797
|
+
set.delete(key);
|
|
1777
1798
|
}
|
|
1778
1799
|
}
|
|
1779
1800
|
async _ensureCapacity(newEntrySize) {
|
|
@@ -1966,6 +1987,23 @@ var kinetex = (() => {
|
|
|
1966
1987
|
}
|
|
1967
1988
|
return out;
|
|
1968
1989
|
}
|
|
1990
|
+
function splitCacheControlDirectives(value) {
|
|
1991
|
+
const parts = [];
|
|
1992
|
+
let current = "";
|
|
1993
|
+
let inQuotes = false;
|
|
1994
|
+
for (const ch of value) {
|
|
1995
|
+
if (ch === '"')
|
|
1996
|
+
inQuotes = !inQuotes;
|
|
1997
|
+
if (ch === "," && !inQuotes) {
|
|
1998
|
+
parts.push(current);
|
|
1999
|
+
current = "";
|
|
2000
|
+
continue;
|
|
2001
|
+
}
|
|
2002
|
+
current += ch;
|
|
2003
|
+
}
|
|
2004
|
+
parts.push(current);
|
|
2005
|
+
return parts;
|
|
2006
|
+
}
|
|
1969
2007
|
function parseCacheControl2(value) {
|
|
1970
2008
|
const d = {
|
|
1971
2009
|
noCache: false,
|
|
@@ -1986,7 +2024,7 @@ var kinetex = (() => {
|
|
|
1986
2024
|
staleWhileRevalidate: null,
|
|
1987
2025
|
unknown: /* @__PURE__ */ new Map()
|
|
1988
2026
|
};
|
|
1989
|
-
for (const part of value
|
|
2027
|
+
for (const part of splitCacheControlDirectives(value)) {
|
|
1990
2028
|
const t = part.trim();
|
|
1991
2029
|
const eq = t.indexOf("=");
|
|
1992
2030
|
const k = (eq === -1 ? t : t.slice(0, eq)).trim().toLowerCase();
|
|
@@ -2310,11 +2348,30 @@ var kinetex = (() => {
|
|
|
2310
2348
|
proto: xproto ?? null
|
|
2311
2349
|
};
|
|
2312
2350
|
}
|
|
2313
|
-
function getClientIP(headers) {
|
|
2351
|
+
function getClientIP(headers, options = {}) {
|
|
2352
|
+
const trustedHops = Math.max(0, Math.trunc(options.trustedHops ?? 0));
|
|
2314
2353
|
const fwd = normalizeForwardedHeaders(headers);
|
|
2315
|
-
if (fwd.for.length > 0)
|
|
2316
|
-
|
|
2317
|
-
|
|
2354
|
+
if (fwd.for.length > 0) {
|
|
2355
|
+
const list = fwd.for;
|
|
2356
|
+
const index = trustedHops === 0 ? 0 : list.length - trustedHops;
|
|
2357
|
+
const value = list[index] ?? list[0];
|
|
2358
|
+
return stripIPPortAndBrackets(value);
|
|
2359
|
+
}
|
|
2360
|
+
return stripIPPortAndBrackets(headers.get(HeaderName.XRealIP) ?? "") || null;
|
|
2361
|
+
}
|
|
2362
|
+
function stripIPPortAndBrackets(value) {
|
|
2363
|
+
let v = value.trim();
|
|
2364
|
+
if (v.startsWith('"') && v.endsWith('"') && v.length >= 2)
|
|
2365
|
+
v = v.slice(1, -1);
|
|
2366
|
+
if (v.startsWith("[")) {
|
|
2367
|
+
const end = v.indexOf("]");
|
|
2368
|
+
if (end !== -1)
|
|
2369
|
+
return v.slice(1, end);
|
|
2370
|
+
}
|
|
2371
|
+
const m = /^(.*):\d+$/.exec(v);
|
|
2372
|
+
if (m && (m[1] ?? "").includes("."))
|
|
2373
|
+
return m[1];
|
|
2374
|
+
return v;
|
|
2318
2375
|
}
|
|
2319
2376
|
function parseRetryAfter(value) {
|
|
2320
2377
|
const t = value.trim();
|
|
@@ -4456,6 +4513,7 @@ var kinetex = (() => {
|
|
|
4456
4513
|
// dist/esm/core.js
|
|
4457
4514
|
var core_exports = {};
|
|
4458
4515
|
__export(core_exports, {
|
|
4516
|
+
DEFAULT_ACCEPT_ENCODING: () => DEFAULT_ACCEPT_ENCODING,
|
|
4459
4517
|
FetchTransport: () => FetchTransport,
|
|
4460
4518
|
HAS_NATIVE_FETCH: () => HAS_NATIVE_FETCH,
|
|
4461
4519
|
HTTP_STATUS_TEXTS: () => HTTP_STATUS_TEXTS,
|
|
@@ -4509,6 +4567,11 @@ var kinetex = (() => {
|
|
|
4509
4567
|
}
|
|
4510
4568
|
}
|
|
4511
4569
|
function createTransport(fetchFn, preferHTTP2 = true, sessionOptions, transportOptions) {
|
|
4570
|
+
if (IS_NODE && preferHTTP2 && fetchFn) {
|
|
4571
|
+
if (!isProductionEnvironment()) {
|
|
4572
|
+
console.warn('[kinetex] httpVersion: "HTTP/2" is ignored when a custom `fetch` is configured \u2014 NodeHTTP2Transport cannot use a custom fetch, so the request goes through FetchTransport (HTTP/1.1 semantics). Drop the `fetch` option to use HTTP/2.');
|
|
4573
|
+
}
|
|
4574
|
+
}
|
|
4512
4575
|
if (IS_NODE && preferHTTP2 && !fetchFn) {
|
|
4513
4576
|
return new NodeHTTP2Transport({
|
|
4514
4577
|
...sessionOptions?.sessionTTLMs !== void 0 ? { sessionTTLMs: sessionOptions.sessionTTLMs } : {},
|
|
@@ -4750,7 +4813,8 @@ var kinetex = (() => {
|
|
|
4750
4813
|
} else if (typeof body === "string") {
|
|
4751
4814
|
stream.end(body);
|
|
4752
4815
|
} else {
|
|
4753
|
-
|
|
4816
|
+
const bytes = await serializeRawBody(body);
|
|
4817
|
+
stream.end(bytes);
|
|
4754
4818
|
}
|
|
4755
4819
|
}
|
|
4756
4820
|
async function pipeBodyToNodeReq(req, body) {
|
|
@@ -4769,8 +4833,18 @@ var kinetex = (() => {
|
|
|
4769
4833
|
} else if (typeof body === "string") {
|
|
4770
4834
|
req.end(body);
|
|
4771
4835
|
} else {
|
|
4772
|
-
|
|
4836
|
+
const bytes = await serializeRawBody(body);
|
|
4837
|
+
req.end(bytes);
|
|
4838
|
+
}
|
|
4839
|
+
}
|
|
4840
|
+
async function serializeRawBody(body) {
|
|
4841
|
+
if (typeof URLSearchParams !== "undefined" && body instanceof URLSearchParams) {
|
|
4842
|
+
return new TextEncoder().encode(body.toString());
|
|
4843
|
+
}
|
|
4844
|
+
if (typeof Blob !== "undefined" && body instanceof Blob) {
|
|
4845
|
+
return new Uint8Array(await body.arrayBuffer());
|
|
4773
4846
|
}
|
|
4847
|
+
return new Uint8Array(0);
|
|
4774
4848
|
}
|
|
4775
4849
|
async function decompressBodyStream(body, headers) {
|
|
4776
4850
|
if (!body)
|
|
@@ -4795,7 +4869,7 @@ var kinetex = (() => {
|
|
|
4795
4869
|
const { applyDecompression: applyDecompression2 } = await Promise.resolve().then(() => (init_response(), response_exports));
|
|
4796
4870
|
return applyDecompression2(body, headers);
|
|
4797
4871
|
}
|
|
4798
|
-
var g, RUNTIME, _runtimeOverride, IS_NODE, HAS_NATIVE_FETCH, FetchTransport, NodeHTTP2Transport, nodeReadableToWebStream, HTTP_STATUS_TEXTS;
|
|
4872
|
+
var g, RUNTIME, _runtimeOverride, IS_NODE, HAS_NATIVE_FETCH, DEFAULT_ACCEPT_ENCODING, FetchTransport, NodeHTTP2Transport, nodeReadableToWebStream, HTTP_STATUS_TEXTS;
|
|
4799
4873
|
var init_core = __esm({
|
|
4800
4874
|
"dist/esm/core.js"() {
|
|
4801
4875
|
"use strict";
|
|
@@ -4808,6 +4882,7 @@ var kinetex = (() => {
|
|
|
4808
4882
|
_runtimeOverride = null;
|
|
4809
4883
|
IS_NODE = RUNTIME === "node";
|
|
4810
4884
|
HAS_NATIVE_FETCH = RUNTIME !== "node" || typeof globalThis.fetch === "function";
|
|
4885
|
+
DEFAULT_ACCEPT_ENCODING = "gzip, deflate, br";
|
|
4811
4886
|
FetchTransport = class {
|
|
4812
4887
|
/**
|
|
4813
4888
|
* @param fetchFnOrOptions - Custom fetch function or options object
|
|
@@ -4855,7 +4930,7 @@ var kinetex = (() => {
|
|
|
4855
4930
|
sanitizedHeaders[name] = value;
|
|
4856
4931
|
}
|
|
4857
4932
|
const ae = sanitizedHeaders["accept-encoding"];
|
|
4858
|
-
if (ae && ae.toLowerCase().
|
|
4933
|
+
if (ae && ae.toLowerCase().replace(/\s+/g, " ") === DEFAULT_ACCEPT_ENCODING) {
|
|
4859
4934
|
delete sanitizedHeaders["accept-encoding"];
|
|
4860
4935
|
}
|
|
4861
4936
|
const init = {
|
|
@@ -5659,8 +5734,7 @@ var kinetex = (() => {
|
|
|
5659
5734
|
return false;
|
|
5660
5735
|
if (isIPAddress(cd))
|
|
5661
5736
|
return false;
|
|
5662
|
-
|
|
5663
|
-
if (psl === rh)
|
|
5737
|
+
if (isPublicSuffix(cd))
|
|
5664
5738
|
return false;
|
|
5665
5739
|
return true;
|
|
5666
5740
|
}
|
|
@@ -7369,7 +7443,7 @@ var kinetex = (() => {
|
|
|
7369
7443
|
let cookieDomain;
|
|
7370
7444
|
let hostOnly;
|
|
7371
7445
|
if (parsed.domain !== null && parsed.domain !== "") {
|
|
7372
|
-
const cd = parsed.domain;
|
|
7446
|
+
const cd = parsed.domain.toLowerCase();
|
|
7373
7447
|
const matcher = this.domainMatcherFn ?? domainMatch;
|
|
7374
7448
|
if (!matcher(reqHost, cd))
|
|
7375
7449
|
return false;
|
|
@@ -7439,9 +7513,6 @@ var kinetex = (() => {
|
|
|
7439
7513
|
* @returns Array of matching Cookie objects (direct references into storage)
|
|
7440
7514
|
*/
|
|
7441
7515
|
getCookies(options) {
|
|
7442
|
-
if (Math.random() < 0.01) {
|
|
7443
|
-
this.clearExpired();
|
|
7444
|
-
}
|
|
7445
7516
|
const url = safeParseUrl(options.url);
|
|
7446
7517
|
if (!url)
|
|
7447
7518
|
return [];
|
|
@@ -7878,11 +7949,13 @@ var kinetex = (() => {
|
|
|
7878
7949
|
if (this.domainMatcherFn) {
|
|
7879
7950
|
return this.domainMatcherFn(reqHost, cookieDomain);
|
|
7880
7951
|
}
|
|
7881
|
-
|
|
7952
|
+
const host = reqHost.toLowerCase();
|
|
7953
|
+
const domain = cookieDomain.toLowerCase();
|
|
7954
|
+
if (host === domain)
|
|
7882
7955
|
return true;
|
|
7883
|
-
if (isIPAddress(
|
|
7956
|
+
if (isIPAddress(host))
|
|
7884
7957
|
return false;
|
|
7885
|
-
return
|
|
7958
|
+
return host.endsWith("." + domain);
|
|
7886
7959
|
}
|
|
7887
7960
|
};
|
|
7888
7961
|
}
|
|
@@ -8584,7 +8657,7 @@ var kinetex = (() => {
|
|
|
8584
8657
|
* ```ts
|
|
8585
8658
|
* const logger = createProductionLogger();
|
|
8586
8659
|
* const child = logger.child({ requestId: "req-123", userId: "user-456" });
|
|
8587
|
-
* child.logRequest(
|
|
8660
|
+
* child.logRequest("req-123", "GET", "/users", {}, null, 1); // Logs include both requestId and userId
|
|
8588
8661
|
* ```
|
|
8589
8662
|
*/
|
|
8590
8663
|
child(context) {
|
|
@@ -8697,8 +8770,23 @@ var kinetex = (() => {
|
|
|
8697
8770
|
events.push(final);
|
|
8698
8771
|
return events;
|
|
8699
8772
|
}
|
|
8700
|
-
function sleep3(ms) {
|
|
8701
|
-
return new Promise((r) =>
|
|
8773
|
+
function sleep3(ms, signal) {
|
|
8774
|
+
return new Promise((r) => {
|
|
8775
|
+
if (signal?.aborted) {
|
|
8776
|
+
r();
|
|
8777
|
+
return;
|
|
8778
|
+
}
|
|
8779
|
+
const onAbort = () => {
|
|
8780
|
+
clearTimeout(timer);
|
|
8781
|
+
signal?.removeEventListener("abort", onAbort);
|
|
8782
|
+
r();
|
|
8783
|
+
};
|
|
8784
|
+
const timer = setTimeout(() => {
|
|
8785
|
+
signal?.removeEventListener("abort", onAbort);
|
|
8786
|
+
r();
|
|
8787
|
+
}, ms);
|
|
8788
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
8789
|
+
});
|
|
8702
8790
|
}
|
|
8703
8791
|
var SSEParser, SSETransformStream, SSEClient, SSERouter, SSEServerResponse, SSEError, SSEMaxReconnectsError;
|
|
8704
8792
|
var init_sse = __esm({
|
|
@@ -9075,8 +9163,8 @@ var kinetex = (() => {
|
|
|
9075
9163
|
}
|
|
9076
9164
|
if (!cfg.reconnect)
|
|
9077
9165
|
throw err;
|
|
9078
|
-
if (cfg.maxReconnects > 0 &&
|
|
9079
|
-
throw new SSEMaxReconnectsError(
|
|
9166
|
+
if (cfg.maxReconnects > 0 && this.health.totalReconnects >= cfg.maxReconnects) {
|
|
9167
|
+
throw new SSEMaxReconnectsError(this.health.totalReconnects, cfg.url);
|
|
9080
9168
|
}
|
|
9081
9169
|
reconnectAttempt++;
|
|
9082
9170
|
this.health.totalReconnects++;
|
|
@@ -9089,25 +9177,31 @@ var kinetex = (() => {
|
|
|
9089
9177
|
clearTimeout(heartbeatTimer);
|
|
9090
9178
|
heartbeatTimer = null;
|
|
9091
9179
|
}
|
|
9092
|
-
await sleep3(delay2);
|
|
9180
|
+
await sleep3(delay2, cfg.signal);
|
|
9181
|
+
if (cfg.signal?.aborted)
|
|
9182
|
+
break;
|
|
9093
9183
|
parser.reset();
|
|
9094
9184
|
continue;
|
|
9095
9185
|
}
|
|
9096
9186
|
this.health.connected = false;
|
|
9097
9187
|
if (!cfg.reconnect)
|
|
9098
9188
|
break;
|
|
9099
|
-
if (cfg.maxReconnects > 0 &&
|
|
9100
|
-
throw new SSEMaxReconnectsError(
|
|
9189
|
+
if (cfg.maxReconnects > 0 && this.health.totalReconnects >= cfg.maxReconnects) {
|
|
9190
|
+
throw new SSEMaxReconnectsError(this.health.totalReconnects, cfg.url);
|
|
9101
9191
|
}
|
|
9102
9192
|
reconnectAttempt++;
|
|
9103
9193
|
this.health.totalReconnects++;
|
|
9104
|
-
|
|
9194
|
+
this.health.reconnectAttempt = reconnectAttempt;
|
|
9195
|
+
const delay = Math.min(reconnectDelay + reconnectDelay * cfg.reconnectJitter * Math.random(), cfg.maxReconnectDelayMs);
|
|
9196
|
+
reconnectDelay = Math.min(reconnectDelay * 2, cfg.maxReconnectDelayMs);
|
|
9105
9197
|
cfg.onReconnect(reconnectAttempt, delay);
|
|
9106
9198
|
if (heartbeatTimer) {
|
|
9107
9199
|
clearTimeout(heartbeatTimer);
|
|
9108
9200
|
heartbeatTimer = null;
|
|
9109
9201
|
}
|
|
9110
|
-
await sleep3(delay);
|
|
9202
|
+
await sleep3(delay, cfg.signal);
|
|
9203
|
+
if (cfg.signal?.aborted)
|
|
9204
|
+
break;
|
|
9111
9205
|
}
|
|
9112
9206
|
this.health.connected = false;
|
|
9113
9207
|
}
|
|
@@ -10593,12 +10687,16 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
10593
10687
|
r();
|
|
10594
10688
|
return;
|
|
10595
10689
|
}
|
|
10596
|
-
const
|
|
10597
|
-
|
|
10598
|
-
signal
|
|
10599
|
-
|
|
10600
|
-
|
|
10601
|
-
|
|
10690
|
+
const onAbort = () => {
|
|
10691
|
+
clearTimeout(timer);
|
|
10692
|
+
signal?.removeEventListener("abort", onAbort);
|
|
10693
|
+
r();
|
|
10694
|
+
};
|
|
10695
|
+
const timer = setTimeout(() => {
|
|
10696
|
+
signal?.removeEventListener("abort", onAbort);
|
|
10697
|
+
r();
|
|
10698
|
+
}, ms);
|
|
10699
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
10602
10700
|
});
|
|
10603
10701
|
}
|
|
10604
10702
|
function toPaginationIterator(source) {
|
|
@@ -11098,38 +11196,58 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
11098
11196
|
}
|
|
11099
11197
|
});
|
|
11100
11198
|
}
|
|
11199
|
+
let reader = null;
|
|
11200
|
+
let onUploadAbort = null;
|
|
11201
|
+
const detach = () => {
|
|
11202
|
+
if (onUploadAbort) {
|
|
11203
|
+
options.signal?.removeEventListener("abort", onUploadAbort);
|
|
11204
|
+
onUploadAbort = null;
|
|
11205
|
+
}
|
|
11206
|
+
};
|
|
11101
11207
|
const stream = new ReadableStream({
|
|
11102
|
-
|
|
11103
|
-
const reader = source.getReader();
|
|
11208
|
+
start(controller) {
|
|
11104
11209
|
if (options.signal?.aborted) {
|
|
11105
|
-
reader.cancel("aborted").catch(() => {
|
|
11106
|
-
});
|
|
11107
11210
|
controller.error(new DOMException("Upload aborted", "AbortError"));
|
|
11108
11211
|
return;
|
|
11109
11212
|
}
|
|
11110
|
-
|
|
11111
|
-
|
|
11213
|
+
reader = source.getReader();
|
|
11214
|
+
onUploadAbort = () => {
|
|
11215
|
+
const r = reader;
|
|
11216
|
+
reader = null;
|
|
11217
|
+
void r?.cancel("aborted").catch(() => {
|
|
11112
11218
|
});
|
|
11219
|
+
tracker.complete();
|
|
11113
11220
|
controller.error(new DOMException("Upload aborted", "AbortError"));
|
|
11114
11221
|
};
|
|
11115
11222
|
options.signal?.addEventListener("abort", onUploadAbort, { once: true });
|
|
11223
|
+
},
|
|
11224
|
+
async pull(controller) {
|
|
11225
|
+
if (!reader)
|
|
11226
|
+
return;
|
|
11116
11227
|
try {
|
|
11117
|
-
|
|
11118
|
-
|
|
11119
|
-
|
|
11120
|
-
|
|
11121
|
-
|
|
11122
|
-
|
|
11123
|
-
|
|
11124
|
-
|
|
11125
|
-
controller.enqueue(value);
|
|
11228
|
+
const { done, value } = await reader.read();
|
|
11229
|
+
if (done) {
|
|
11230
|
+
detach();
|
|
11231
|
+
reader.releaseLock();
|
|
11232
|
+
reader = null;
|
|
11233
|
+
tracker.complete();
|
|
11234
|
+
controller.close();
|
|
11235
|
+
return;
|
|
11126
11236
|
}
|
|
11237
|
+
tracker.update(value.byteLength);
|
|
11238
|
+
controller.enqueue(value);
|
|
11127
11239
|
} catch (err) {
|
|
11240
|
+
detach();
|
|
11128
11241
|
tracker.complete();
|
|
11129
11242
|
controller.error(err);
|
|
11130
|
-
} finally {
|
|
11131
|
-
options.signal?.removeEventListener("abort", onUploadAbort);
|
|
11132
11243
|
}
|
|
11244
|
+
},
|
|
11245
|
+
cancel(reason) {
|
|
11246
|
+
detach();
|
|
11247
|
+
const r = reader;
|
|
11248
|
+
reader = null;
|
|
11249
|
+
void r?.cancel(reason).catch(() => {
|
|
11250
|
+
});
|
|
11133
11251
|
}
|
|
11134
11252
|
});
|
|
11135
11253
|
return { stream, tracker };
|
|
@@ -11146,40 +11264,64 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
11146
11264
|
return { response, tracker };
|
|
11147
11265
|
}
|
|
11148
11266
|
const body = response.body;
|
|
11267
|
+
let reader = null;
|
|
11268
|
+
let aborted = false;
|
|
11269
|
+
let onAbort = null;
|
|
11270
|
+
const detach = () => {
|
|
11271
|
+
if (onAbort) {
|
|
11272
|
+
options.signal?.removeEventListener("abort", onAbort);
|
|
11273
|
+
onAbort = null;
|
|
11274
|
+
}
|
|
11275
|
+
};
|
|
11149
11276
|
const trackedStream = new ReadableStream({
|
|
11150
|
-
|
|
11151
|
-
|
|
11152
|
-
|
|
11153
|
-
|
|
11277
|
+
start(controller) {
|
|
11278
|
+
if (options.signal?.aborted) {
|
|
11279
|
+
aborted = true;
|
|
11280
|
+
controller.error(new DOMException("Download aborted", "AbortError"));
|
|
11281
|
+
return;
|
|
11282
|
+
}
|
|
11283
|
+
reader = body.getReader();
|
|
11284
|
+
onAbort = () => {
|
|
11154
11285
|
if (aborted)
|
|
11155
11286
|
return;
|
|
11156
11287
|
aborted = true;
|
|
11157
|
-
|
|
11288
|
+
const r = reader;
|
|
11289
|
+
reader = null;
|
|
11290
|
+
void r?.cancel("aborted").catch(() => {
|
|
11158
11291
|
});
|
|
11159
11292
|
controller.error(new DOMException("Download aborted", "AbortError"));
|
|
11160
11293
|
};
|
|
11161
11294
|
options.signal?.addEventListener("abort", onAbort, { once: true });
|
|
11295
|
+
},
|
|
11296
|
+
async pull(controller) {
|
|
11297
|
+
if (!reader)
|
|
11298
|
+
return;
|
|
11162
11299
|
try {
|
|
11163
|
-
|
|
11164
|
-
|
|
11165
|
-
|
|
11166
|
-
|
|
11167
|
-
|
|
11168
|
-
|
|
11169
|
-
|
|
11170
|
-
|
|
11171
|
-
controller.enqueue(value);
|
|
11300
|
+
const { done, value } = await reader.read();
|
|
11301
|
+
if (done) {
|
|
11302
|
+
detach();
|
|
11303
|
+
reader.releaseLock();
|
|
11304
|
+
reader = null;
|
|
11305
|
+
tracker.complete();
|
|
11306
|
+
controller.close();
|
|
11307
|
+
return;
|
|
11172
11308
|
}
|
|
11309
|
+
tracker.update(value.byteLength);
|
|
11310
|
+
controller.enqueue(value);
|
|
11173
11311
|
} catch (err) {
|
|
11312
|
+
detach();
|
|
11174
11313
|
if (!aborted) {
|
|
11175
11314
|
tracker.complete();
|
|
11176
11315
|
}
|
|
11177
11316
|
controller.error(err);
|
|
11178
|
-
} finally {
|
|
11179
|
-
if (!aborted) {
|
|
11180
|
-
options.signal?.removeEventListener("abort", onAbort);
|
|
11181
|
-
}
|
|
11182
11317
|
}
|
|
11318
|
+
},
|
|
11319
|
+
cancel(reason) {
|
|
11320
|
+
detach();
|
|
11321
|
+
const r = reader;
|
|
11322
|
+
reader = null;
|
|
11323
|
+
void r?.cancel(reason).catch(() => {
|
|
11324
|
+
});
|
|
11183
11325
|
}
|
|
11184
11326
|
});
|
|
11185
11327
|
const trackedResponse = new Response(trackedStream, {
|
|
@@ -11187,6 +11329,16 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
11187
11329
|
statusText: response.statusText,
|
|
11188
11330
|
headers: response.headers
|
|
11189
11331
|
});
|
|
11332
|
+
for (const prop of ["url", "redirected", "type"]) {
|
|
11333
|
+
try {
|
|
11334
|
+
Object.defineProperty(trackedResponse, prop, {
|
|
11335
|
+
value: response[prop],
|
|
11336
|
+
enumerable: true,
|
|
11337
|
+
configurable: true
|
|
11338
|
+
});
|
|
11339
|
+
} catch {
|
|
11340
|
+
}
|
|
11341
|
+
}
|
|
11190
11342
|
return { response: trackedResponse, tracker };
|
|
11191
11343
|
}
|
|
11192
11344
|
async function* streamWithProgress(stream, total, options = {}) {
|
|
@@ -11367,11 +11519,19 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
11367
11519
|
downloadTracker.update(e.loaded - downloadTracker.bytesLoaded);
|
|
11368
11520
|
});
|
|
11369
11521
|
}
|
|
11370
|
-
|
|
11522
|
+
const onAbort = () => {
|
|
11371
11523
|
xhr.abort();
|
|
11372
11524
|
reject(new DOMException("Request aborted", "AbortError"));
|
|
11373
|
-
}
|
|
11525
|
+
};
|
|
11526
|
+
const detach = () => options.signal?.removeEventListener("abort", onAbort);
|
|
11527
|
+
options.signal?.addEventListener("abort", onAbort, { once: true });
|
|
11528
|
+
if (options.signal?.aborted) {
|
|
11529
|
+
detach();
|
|
11530
|
+
onAbort();
|
|
11531
|
+
return;
|
|
11532
|
+
}
|
|
11374
11533
|
xhr.addEventListener("load", () => {
|
|
11534
|
+
detach();
|
|
11375
11535
|
downloadTracker.complete();
|
|
11376
11536
|
const rawHeaders = xhr.getAllResponseHeaders();
|
|
11377
11537
|
const headers = {};
|
|
@@ -11389,11 +11549,17 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
11389
11549
|
});
|
|
11390
11550
|
});
|
|
11391
11551
|
xhr.addEventListener("error", () => {
|
|
11552
|
+
detach();
|
|
11392
11553
|
reject(new TypeError("Network request failed"));
|
|
11393
11554
|
});
|
|
11394
11555
|
xhr.addEventListener("timeout", () => {
|
|
11556
|
+
detach();
|
|
11395
11557
|
reject(new TypeError("Request timed out"));
|
|
11396
11558
|
});
|
|
11559
|
+
xhr.addEventListener("abort", () => {
|
|
11560
|
+
detach();
|
|
11561
|
+
reject(new DOMException("Request aborted", "AbortError"));
|
|
11562
|
+
});
|
|
11397
11563
|
xhr.send(options.body ?? null);
|
|
11398
11564
|
});
|
|
11399
11565
|
}
|
|
@@ -11545,6 +11711,11 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
11545
11711
|
if (effectiveWindowMs <= 0) {
|
|
11546
11712
|
this.inflight.delete(key);
|
|
11547
11713
|
} else {
|
|
11714
|
+
const stale = this.timeouts.get(key);
|
|
11715
|
+
if (stale !== void 0) {
|
|
11716
|
+
clearTimeout(stale);
|
|
11717
|
+
this.timeouts.delete(key);
|
|
11718
|
+
}
|
|
11548
11719
|
const timeoutId = setTimeout(() => {
|
|
11549
11720
|
this.inflight.delete(key);
|
|
11550
11721
|
this.timeouts.delete(key);
|
|
@@ -11586,13 +11757,6 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
11586
11757
|
get keys() {
|
|
11587
11758
|
return [...this.inflight.keys()];
|
|
11588
11759
|
}
|
|
11589
|
-
/**
|
|
11590
|
-
* Get comprehensive deduplication statistics.
|
|
11591
|
-
* NOTE: inFlightCount and trackedKeys reflect snapshot time; entries may
|
|
11592
|
-
* resolve asynchronously between sampling and return (non-blocking, acceptable).
|
|
11593
|
-
*
|
|
11594
|
-
* @returns Snapshot of hits, misses, hit rate, and tracked entries
|
|
11595
|
-
*/
|
|
11596
11760
|
/**
|
|
11597
11761
|
* Get comprehensive deduplication statistics.
|
|
11598
11762
|
*
|
|
@@ -11735,9 +11899,16 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
11735
11899
|
}
|
|
11736
11900
|
/** Snapshot of all counters — suitable for logging or dashboards. */
|
|
11737
11901
|
get snapshot() {
|
|
11902
|
+
let failureCount = this._consecutiveFails;
|
|
11903
|
+
if (this.windowSize > 0) {
|
|
11904
|
+
failureCount = 0;
|
|
11905
|
+
for (const ok of this._window)
|
|
11906
|
+
if (!ok)
|
|
11907
|
+
failureCount++;
|
|
11908
|
+
}
|
|
11738
11909
|
return {
|
|
11739
11910
|
state: this._state,
|
|
11740
|
-
failureCount
|
|
11911
|
+
failureCount,
|
|
11741
11912
|
successCount: this._consecutiveSucc,
|
|
11742
11913
|
lastFailureAt: this._lastFailureAt,
|
|
11743
11914
|
lastSuccessAt: this._lastSuccessAt,
|
|
@@ -11763,6 +11934,7 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
11763
11934
|
this.cfg.onRejected?.(snap);
|
|
11764
11935
|
return Promise.reject(new CircuitOpenError(this.key, snap));
|
|
11765
11936
|
}
|
|
11937
|
+
let heldProbe = false;
|
|
11766
11938
|
if (this._state === "HALF_OPEN") {
|
|
11767
11939
|
if (this._inFlightProbes >= this.halfOpenConcurrency) {
|
|
11768
11940
|
this._totalRejected++;
|
|
@@ -11771,15 +11943,16 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
11771
11943
|
return Promise.reject(new CircuitOpenError(this.key, snap));
|
|
11772
11944
|
}
|
|
11773
11945
|
this._inFlightProbes++;
|
|
11946
|
+
heldProbe = true;
|
|
11774
11947
|
}
|
|
11775
11948
|
this._totalRequests++;
|
|
11776
|
-
return
|
|
11777
|
-
if (
|
|
11949
|
+
return Promise.resolve().then(fn).then((result) => {
|
|
11950
|
+
if (heldProbe)
|
|
11778
11951
|
this._inFlightProbes = Math.max(0, this._inFlightProbes - 1);
|
|
11779
11952
|
this._recordSuccess();
|
|
11780
11953
|
return result;
|
|
11781
11954
|
}, (err) => {
|
|
11782
|
-
if (
|
|
11955
|
+
if (heldProbe)
|
|
11783
11956
|
this._inFlightProbes = Math.max(0, this._inFlightProbes - 1);
|
|
11784
11957
|
if (this._isCountableFailure(err)) {
|
|
11785
11958
|
this._recordFailure();
|
|
@@ -12742,6 +12915,10 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
12742
12915
|
return this._maxReconnects === 0 || this._reconnAttempt < this._maxReconnects;
|
|
12743
12916
|
}
|
|
12744
12917
|
_scheduleRecon() {
|
|
12918
|
+
if (this._reconnTimer) {
|
|
12919
|
+
clearTimeout(this._reconnTimer);
|
|
12920
|
+
this._reconnTimer = null;
|
|
12921
|
+
}
|
|
12745
12922
|
this._state = "RECONNECTING";
|
|
12746
12923
|
this._reconnAttempt++;
|
|
12747
12924
|
const exp = this._reconnectBaseMs * Math.pow(2, this._reconnAttempt - 1);
|
|
@@ -12749,13 +12926,11 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
12749
12926
|
const delay = Math.floor(capped * (1 + this._reconnectJitter * Math.random()));
|
|
12750
12927
|
this._cbReconnect?.(this._reconnAttempt, delay);
|
|
12751
12928
|
this._reconnTimer = setTimeout(() => {
|
|
12929
|
+
this._reconnTimer = null;
|
|
12752
12930
|
if (!this._aborted)
|
|
12753
12931
|
this._doConnect(true).catch(() => {
|
|
12754
12932
|
});
|
|
12755
12933
|
}, delay);
|
|
12756
|
-
if (typeof this._reconnTimer === "object" && this._reconnTimer !== null && "unref" in this._reconnTimer) {
|
|
12757
|
-
this._reconnTimer.unref();
|
|
12758
|
-
}
|
|
12759
12934
|
}
|
|
12760
12935
|
_tx(data) {
|
|
12761
12936
|
const ws = this._ws;
|
|
@@ -12923,12 +13098,17 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
12923
13098
|
init_cache();
|
|
12924
13099
|
|
|
12925
13100
|
// dist/esm/interceptors.js
|
|
13101
|
+
init_cache();
|
|
12926
13102
|
var _idSeq = 0;
|
|
12927
13103
|
function nextId() {
|
|
12928
13104
|
return `interceptor_${++_idSeq}`;
|
|
12929
13105
|
}
|
|
12930
|
-
function
|
|
12931
|
-
|
|
13106
|
+
function insertByPriority(arr, entry) {
|
|
13107
|
+
const at = arr.findIndex((x) => x.priority > entry.priority);
|
|
13108
|
+
if (at === -1)
|
|
13109
|
+
arr.push(entry);
|
|
13110
|
+
else
|
|
13111
|
+
arr.splice(at, 0, entry);
|
|
12932
13112
|
}
|
|
12933
13113
|
var InterceptorManager = class {
|
|
12934
13114
|
constructor() {
|
|
@@ -12946,7 +13126,7 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
12946
13126
|
*/
|
|
12947
13127
|
useRequest(fn, opts = {}) {
|
|
12948
13128
|
const id = opts.id ?? nextId();
|
|
12949
|
-
this.requestInterceptors
|
|
13129
|
+
insertByPriority(this.requestInterceptors, {
|
|
12950
13130
|
id,
|
|
12951
13131
|
priority: opts.priority ?? 0,
|
|
12952
13132
|
once: opts.once ?? false,
|
|
@@ -12964,7 +13144,7 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
12964
13144
|
*/
|
|
12965
13145
|
useResponse(fn, opts = {}) {
|
|
12966
13146
|
const id = opts.id ?? nextId();
|
|
12967
|
-
this.responseInterceptors
|
|
13147
|
+
insertByPriority(this.responseInterceptors, {
|
|
12968
13148
|
id,
|
|
12969
13149
|
priority: opts.priority ?? 0,
|
|
12970
13150
|
once: opts.once ?? false,
|
|
@@ -12982,7 +13162,7 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
12982
13162
|
*/
|
|
12983
13163
|
useError(fn, opts = {}) {
|
|
12984
13164
|
const id = opts.id ?? nextId();
|
|
12985
|
-
this.errorInterceptors
|
|
13165
|
+
insertByPriority(this.errorInterceptors, {
|
|
12986
13166
|
id,
|
|
12987
13167
|
priority: opts.priority ?? 0,
|
|
12988
13168
|
once: opts.once ?? false,
|
|
@@ -13059,7 +13239,7 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
13059
13239
|
async _run(ctx, dispatcher) {
|
|
13060
13240
|
ctx.attempt++;
|
|
13061
13241
|
const toEject = /* @__PURE__ */ new Set();
|
|
13062
|
-
for (const interceptor of
|
|
13242
|
+
for (const interceptor of this.requestInterceptors) {
|
|
13063
13243
|
if (ctx.aborted)
|
|
13064
13244
|
break;
|
|
13065
13245
|
if (interceptor.condition && !interceptor.condition(ctx))
|
|
@@ -13099,7 +13279,7 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
13099
13279
|
}
|
|
13100
13280
|
async _runResponsePhase(ctx, dispatcher) {
|
|
13101
13281
|
const toEject = /* @__PURE__ */ new Set();
|
|
13102
|
-
for (const interceptor of
|
|
13282
|
+
for (const interceptor of this.responseInterceptors) {
|
|
13103
13283
|
if (ctx.aborted)
|
|
13104
13284
|
break;
|
|
13105
13285
|
if (interceptor.condition && !interceptor.condition(ctx))
|
|
@@ -13137,7 +13317,7 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
13137
13317
|
}
|
|
13138
13318
|
async _runErrorPhase(ctx, dispatcher) {
|
|
13139
13319
|
const toEject = /* @__PURE__ */ new Set();
|
|
13140
|
-
for (const interceptor of
|
|
13320
|
+
for (const interceptor of this.errorInterceptors) {
|
|
13141
13321
|
if (interceptor.condition && !interceptor.condition(ctx))
|
|
13142
13322
|
continue;
|
|
13143
13323
|
let result;
|
|
@@ -13549,13 +13729,15 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
13549
13729
|
var CACHE_STALE_KEY = /* @__PURE__ */ Symbol("cacheStale");
|
|
13550
13730
|
function createDedupeInterceptor() {
|
|
13551
13731
|
const inflight = /* @__PURE__ */ new Map();
|
|
13552
|
-
function key(req) {
|
|
13553
|
-
|
|
13732
|
+
async function key(req) {
|
|
13733
|
+
const authFp = await getAuthFingerprint(req.headers ?? {});
|
|
13734
|
+
return `${req.method.toUpperCase()}:${req.url}${authFp ? ":" + authFp : ""}`;
|
|
13554
13735
|
}
|
|
13555
|
-
const requestInterceptor = (ctx) => {
|
|
13736
|
+
const requestInterceptor = async (ctx) => {
|
|
13556
13737
|
if (ctx.request.method.toUpperCase() !== "GET" && ctx.request.method.toUpperCase() !== "HEAD")
|
|
13557
13738
|
return;
|
|
13558
|
-
const k = key(ctx.request);
|
|
13739
|
+
const k = await key(ctx.request);
|
|
13740
|
+
ctx.store.set(DEDUPE_KEY, k);
|
|
13559
13741
|
const slot = inflight.get(k);
|
|
13560
13742
|
if (!slot) {
|
|
13561
13743
|
inflight.set(k, {
|
|
@@ -13564,38 +13746,59 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
13564
13746
|
});
|
|
13565
13747
|
return;
|
|
13566
13748
|
}
|
|
13567
|
-
ctx.store.set(DEDUPE_QUEUED_KEY, k);
|
|
13568
13749
|
return new Promise((resolve, reject) => {
|
|
13569
|
-
|
|
13750
|
+
const signal = ctx.request.signal;
|
|
13751
|
+
const waiter = {
|
|
13570
13752
|
resolve: (res) => resolve(res),
|
|
13571
|
-
reject: (err) => reject(err)
|
|
13753
|
+
reject: (err) => reject(err),
|
|
13572
13754
|
// Properly reject instead of throwing
|
|
13573
|
-
|
|
13755
|
+
cleanup: () => signal?.removeEventListener("abort", onQueuedAbort)
|
|
13756
|
+
};
|
|
13757
|
+
const onQueuedAbort = () => {
|
|
13758
|
+
const at = slot.waiters.indexOf(waiter);
|
|
13759
|
+
if (at !== -1)
|
|
13760
|
+
slot.waiters.splice(at, 1);
|
|
13761
|
+
reject(new Error("Request aborted while queued for deduplication"));
|
|
13762
|
+
};
|
|
13763
|
+
if (signal?.aborted) {
|
|
13764
|
+
onQueuedAbort();
|
|
13765
|
+
return;
|
|
13766
|
+
}
|
|
13767
|
+
signal?.addEventListener("abort", onQueuedAbort, { once: true });
|
|
13768
|
+
slot.waiters.push(waiter);
|
|
13574
13769
|
});
|
|
13575
13770
|
};
|
|
13576
13771
|
const responseInterceptor = (ctx) => {
|
|
13577
13772
|
if (!ctx.response)
|
|
13578
13773
|
return;
|
|
13579
|
-
const k =
|
|
13774
|
+
const k = ctx.store.get(DEDUPE_KEY);
|
|
13775
|
+
if (!k)
|
|
13776
|
+
return;
|
|
13580
13777
|
const slot = inflight.get(k);
|
|
13581
13778
|
if (!slot)
|
|
13582
13779
|
return;
|
|
13583
13780
|
inflight.delete(k);
|
|
13584
|
-
for (const w of slot.waiters)
|
|
13781
|
+
for (const w of slot.waiters.splice(0)) {
|
|
13782
|
+
w.cleanup();
|
|
13585
13783
|
w.resolve(ctx.response);
|
|
13784
|
+
}
|
|
13586
13785
|
};
|
|
13587
13786
|
const errorInterceptor = (ctx) => {
|
|
13588
|
-
const k =
|
|
13787
|
+
const k = ctx.store.get(DEDUPE_KEY);
|
|
13788
|
+
if (!k)
|
|
13789
|
+
return;
|
|
13589
13790
|
const slot = inflight.get(k);
|
|
13590
13791
|
if (!slot)
|
|
13591
13792
|
return;
|
|
13592
13793
|
inflight.delete(k);
|
|
13593
|
-
for (const w of slot.waiters)
|
|
13794
|
+
for (const w of slot.waiters.splice(0)) {
|
|
13795
|
+
w.cleanup();
|
|
13594
13796
|
w.reject(ctx.error);
|
|
13797
|
+
}
|
|
13595
13798
|
};
|
|
13596
13799
|
return { requestInterceptor, responseInterceptor, errorInterceptor };
|
|
13597
13800
|
}
|
|
13598
|
-
var
|
|
13801
|
+
var DEDUPE_KEY = /* @__PURE__ */ Symbol("dedupeKey");
|
|
13599
13802
|
var RATE_LIMIT_DEFAULTS = {
|
|
13600
13803
|
limit: 60,
|
|
13601
13804
|
windowMs: 6e4,
|
|
@@ -13961,7 +14164,7 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
13961
14164
|
const role = roles[0]?.trim();
|
|
13962
14165
|
if (!role)
|
|
13963
14166
|
throw new NetworkError("No IAM role found in IMDS response");
|
|
13964
|
-
const credsRes = await fetchWithTimeout(`${endpoint}/latest/meta-data/iam/security-credentials/${role}`, { headers: { "x-aws-ec2-metadata-token": token } }, timeout);
|
|
14167
|
+
const credsRes = await fetchWithTimeout(`${endpoint}/latest/meta-data/iam/security-credentials/${encodeURIComponent(role)}`, { headers: { "x-aws-ec2-metadata-token": token } }, timeout);
|
|
13965
14168
|
if (!credsRes.ok)
|
|
13966
14169
|
throw new NetworkError(`IMDS credentials fetch failed: ${credsRes.status}`);
|
|
13967
14170
|
const data = await credsRes.json();
|
|
@@ -14962,9 +15165,24 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
14962
15165
|
const response = await computeDigestResponse(challenge, username, password, method, uri, cnonce, nc);
|
|
14963
15166
|
return formatDigestAuth(challenge, username, response, uri, cnonce, nc);
|
|
14964
15167
|
}
|
|
15168
|
+
function createDigestAuthorizer() {
|
|
15169
|
+
const counters = /* @__PURE__ */ new Map();
|
|
15170
|
+
return async (wwwAuth, username, password, method, uri) => {
|
|
15171
|
+
const challenge = parseDigestChallenge(wwwAuth);
|
|
15172
|
+
const cnonce = randomBytes(5);
|
|
15173
|
+
const scope = `${challenge.realm}\0${challenge.nonce}`;
|
|
15174
|
+
const next = (counters.get(scope) ?? 0) + 1;
|
|
15175
|
+
counters.set(scope, next);
|
|
15176
|
+
const nc = next.toString(16).padStart(8, "0");
|
|
15177
|
+
const response = await computeDigestResponse(challenge, username, password, method, uri, cnonce, nc);
|
|
15178
|
+
return formatDigestAuth(challenge, username, response, uri, cnonce, nc);
|
|
15179
|
+
};
|
|
15180
|
+
}
|
|
14965
15181
|
|
|
14966
15182
|
// dist/esm/client.js
|
|
14967
15183
|
init_core();
|
|
15184
|
+
init_core();
|
|
15185
|
+
var DEFAULT_MAX_REDIRECTS = 20;
|
|
14968
15186
|
var DEFAULT_RETRY = {
|
|
14969
15187
|
maxRetries: 3,
|
|
14970
15188
|
baseDelayMs: 300,
|
|
@@ -15083,6 +15301,59 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
15083
15301
|
"passwd",
|
|
15084
15302
|
"secret"
|
|
15085
15303
|
]);
|
|
15304
|
+
var INTERCEPTOR_RESEND_DEPTH = "__interceptorResendDepth";
|
|
15305
|
+
var MAX_INTERCEPTOR_RESENDS = 5;
|
|
15306
|
+
var HAR_REDACT_PARAMS = /* @__PURE__ */ new Set([
|
|
15307
|
+
"api_key",
|
|
15308
|
+
"apikey",
|
|
15309
|
+
"access_token",
|
|
15310
|
+
"refresh_token",
|
|
15311
|
+
"id_token",
|
|
15312
|
+
"token",
|
|
15313
|
+
"auth",
|
|
15314
|
+
"authorization",
|
|
15315
|
+
"key",
|
|
15316
|
+
"secret",
|
|
15317
|
+
"password",
|
|
15318
|
+
"passwd",
|
|
15319
|
+
"signature",
|
|
15320
|
+
"sig",
|
|
15321
|
+
"x-amz-signature",
|
|
15322
|
+
"x-amz-credential",
|
|
15323
|
+
"x-amz-security-token",
|
|
15324
|
+
"x-goog-signature",
|
|
15325
|
+
"sas",
|
|
15326
|
+
"session",
|
|
15327
|
+
"sessionid",
|
|
15328
|
+
"jwt",
|
|
15329
|
+
"code"
|
|
15330
|
+
]);
|
|
15331
|
+
var HAR_MAX_BODY_CHARS = 8192;
|
|
15332
|
+
function isHARBodySafeToRecord(contentType) {
|
|
15333
|
+
if (!contentType)
|
|
15334
|
+
return false;
|
|
15335
|
+
const ct = contentType.toLowerCase();
|
|
15336
|
+
return ct.includes("json") || ct.includes("xml") || ct.includes("text/plain") || ct.includes("application/javascript");
|
|
15337
|
+
}
|
|
15338
|
+
function redactHARUrl(url) {
|
|
15339
|
+
try {
|
|
15340
|
+
const u = new URL(url);
|
|
15341
|
+
let changed = false;
|
|
15342
|
+
for (const key of [...u.searchParams.keys()]) {
|
|
15343
|
+
if (HAR_REDACT_PARAMS.has(key.toLowerCase())) {
|
|
15344
|
+
u.searchParams.set(key, "***REDACTED***");
|
|
15345
|
+
changed = true;
|
|
15346
|
+
}
|
|
15347
|
+
}
|
|
15348
|
+
if (u.hash && (u.hash.includes("token") || u.hash.includes("sig") || u.hash.length > 1)) {
|
|
15349
|
+
u.hash = "#***REDACTED***";
|
|
15350
|
+
changed = true;
|
|
15351
|
+
}
|
|
15352
|
+
return changed ? u.toString() : url;
|
|
15353
|
+
} catch {
|
|
15354
|
+
return url.replace(/([?&])(api_key|apikey|access_token|refresh_token|token|secret|password|signature|sig)=([^&#]*)/gi, "$1$2=***REDACTED***");
|
|
15355
|
+
}
|
|
15356
|
+
}
|
|
15086
15357
|
function redactHARHeader(name, value) {
|
|
15087
15358
|
return HAR_REDACT_HEADERS.has(name.toLowerCase()) ? { name, value: "***REDACTED***" } : { name, value };
|
|
15088
15359
|
}
|
|
@@ -15118,9 +15389,9 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
15118
15389
|
let receiveMs = 0;
|
|
15119
15390
|
try {
|
|
15120
15391
|
if (typeof performance !== "undefined" && typeof performance.getEntriesByType === "function") {
|
|
15121
|
-
const entries = performance.getEntriesByType("resource");
|
|
15122
|
-
const entry2 = entries.
|
|
15123
|
-
if (entry2 && entry2.requestStart > 0) {
|
|
15392
|
+
const entries = typeof performance.getEntriesByName === "function" ? performance.getEntriesByName(res.url) : performance.getEntriesByType("resource").filter((e) => e.name === res.url);
|
|
15393
|
+
const entry2 = entries[entries.length - 1];
|
|
15394
|
+
if (entry2 && entry2.requestStart > 0 && Date.now() - entry2.startTime < 6e4) {
|
|
15124
15395
|
sendMs = Math.max(0, entry2.responseStart - entry2.requestStart);
|
|
15125
15396
|
receiveMs = Math.max(0, entry2.responseEnd - entry2.responseStart);
|
|
15126
15397
|
waitMs = Math.max(0, total - sendMs - receiveMs);
|
|
@@ -15135,12 +15406,16 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
15135
15406
|
time: total,
|
|
15136
15407
|
request: {
|
|
15137
15408
|
method: req.method,
|
|
15138
|
-
|
|
15409
|
+
// Redacted: HAR logs are routinely exported and shared, and a query
|
|
15410
|
+
// string is just as leaky as a header (?api_key=, ?access_token=,
|
|
15411
|
+
// ?signature=). Previously only headers were redacted, so the full URL
|
|
15412
|
+
// and every query value landed in the log verbatim.
|
|
15413
|
+
url: redactHARUrl(req.url),
|
|
15139
15414
|
httpVersion: res.httpVersion,
|
|
15140
15415
|
headers: Object.entries(req.headers).map(([name, value]) => redactHARHeader(name, value)),
|
|
15141
15416
|
queryString: (() => {
|
|
15142
15417
|
try {
|
|
15143
|
-
return Array.from(new URL(req.url).searchParams.entries()).map(([name, value]) => ({
|
|
15418
|
+
return Array.from(new URL(redactHARUrl(req.url)).searchParams.entries()).map(([name, value]) => ({
|
|
15144
15419
|
name,
|
|
15145
15420
|
value
|
|
15146
15421
|
}));
|
|
@@ -15168,9 +15443,12 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
15168
15443
|
content: {
|
|
15169
15444
|
size: res.rawBody?.byteLength ?? 0,
|
|
15170
15445
|
mimeType: res.headers["content-type"] ?? "application/octet-stream",
|
|
15171
|
-
|
|
15446
|
+
// Body text is only kept for non-HTML payloads and is truncated:
|
|
15447
|
+
// response bodies routinely carry tokens and PII.
|
|
15448
|
+
...typeof res.data === "string" && isHARBodySafeToRecord(res.headers["content-type"]) ? { text: res.data.slice(0, HAR_MAX_BODY_CHARS) } : {}
|
|
15172
15449
|
},
|
|
15173
|
-
|
|
15450
|
+
// The Location header can itself carry a signed URL — redact it too.
|
|
15451
|
+
redirectURL: res.headers["location"] ? redactHARUrl(res.headers["location"]) : "",
|
|
15174
15452
|
bodySize: res.rawBody?.byteLength ?? 0
|
|
15175
15453
|
},
|
|
15176
15454
|
timings: {
|
|
@@ -15262,22 +15540,25 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
15262
15540
|
}
|
|
15263
15541
|
return { ...req, headers };
|
|
15264
15542
|
}
|
|
15543
|
+
var FETCH_SPEC_STRIPPED_ON_REDIRECT = /* @__PURE__ */ new Set(["authorization", "cookie", "proxy-authorization"]);
|
|
15544
|
+
function hasForwardedCredentials(headers, auth) {
|
|
15545
|
+
if (auth && auth.type === "apikey")
|
|
15546
|
+
return true;
|
|
15547
|
+
if (!headers)
|
|
15548
|
+
return false;
|
|
15549
|
+
for (const name of Object.keys(headers)) {
|
|
15550
|
+
const lower = name.toLowerCase();
|
|
15551
|
+
if (CROSS_ORIGIN_STRIP_HEADERS.has(lower) && !FETCH_SPEC_STRIPPED_ON_REDIRECT.has(lower)) {
|
|
15552
|
+
return true;
|
|
15553
|
+
}
|
|
15554
|
+
}
|
|
15555
|
+
return false;
|
|
15556
|
+
}
|
|
15265
15557
|
var CROSS_ORIGIN_STRIP_HEADERS = /* @__PURE__ */ new Set([
|
|
15266
|
-
|
|
15267
|
-
|
|
15268
|
-
|
|
15269
|
-
|
|
15270
|
-
"x-auth-token",
|
|
15271
|
-
"x-access-token",
|
|
15272
|
-
"x-refresh-token",
|
|
15273
|
-
"x-csrf-token",
|
|
15274
|
-
"x-session-id",
|
|
15275
|
-
"x-session-token",
|
|
15276
|
-
"x-secret",
|
|
15277
|
-
"x-secret-key",
|
|
15278
|
-
"x-private-key",
|
|
15279
|
-
"api-key",
|
|
15280
|
-
"apikey",
|
|
15558
|
+
...CREDENTIAL_HEADERS,
|
|
15559
|
+
// Response-only per RFC 9110, so it can never legitimately appear on an
|
|
15560
|
+
// outgoing request — kept in the strip list as defence in depth for callers
|
|
15561
|
+
// that copy a full header bag (including response headers) onto a request.
|
|
15281
15562
|
"www-authenticate"
|
|
15282
15563
|
]);
|
|
15283
15564
|
function redactUserInfo(url) {
|
|
@@ -15557,6 +15838,7 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
15557
15838
|
}
|
|
15558
15839
|
if (config.auth?.type === "digest") {
|
|
15559
15840
|
const digestConfig = config.auth;
|
|
15841
|
+
const digestAuthorizer = createDigestAuthorizer();
|
|
15560
15842
|
this.interceptors.addResponse(async (ctx) => {
|
|
15561
15843
|
if (!ctx.response)
|
|
15562
15844
|
return;
|
|
@@ -15568,8 +15850,9 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
15568
15850
|
if (ctx.request.meta.__digestRetried)
|
|
15569
15851
|
return;
|
|
15570
15852
|
const method = ctx.request.method;
|
|
15571
|
-
const
|
|
15572
|
-
const
|
|
15853
|
+
const parsedUrl = new URL(ctx.request.url);
|
|
15854
|
+
const uri = parsedUrl.pathname + parsedUrl.search;
|
|
15855
|
+
const authHeader = await digestAuthorizer(wwwAuth, digestConfig.username, digestConfig.password, method, uri);
|
|
15573
15856
|
return {
|
|
15574
15857
|
...ctx.request,
|
|
15575
15858
|
headers: { ...ctx.request.headers, authorization: authHeader },
|
|
@@ -15665,22 +15948,24 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
15665
15948
|
const errEject = this.useError(async (ctx) => {
|
|
15666
15949
|
if (!ctx.error)
|
|
15667
15950
|
return;
|
|
15951
|
+
const hookReq = {
|
|
15952
|
+
url: ctx.request.url,
|
|
15953
|
+
method: ctx.request.method,
|
|
15954
|
+
headers: ctx.request.headers,
|
|
15955
|
+
body: ctx.request.body,
|
|
15956
|
+
signal: ctx.request.signal,
|
|
15957
|
+
meta: ctx.request.meta
|
|
15958
|
+
};
|
|
15959
|
+
const errResponse = toHookResponse(ctx.error.response, hookReq);
|
|
15668
15960
|
const hookErr = {
|
|
15669
15961
|
error: ctx.error,
|
|
15670
|
-
request:
|
|
15671
|
-
|
|
15672
|
-
method: ctx.request.method,
|
|
15673
|
-
headers: ctx.request.headers,
|
|
15674
|
-
body: ctx.request.body,
|
|
15675
|
-
signal: ctx.request.signal,
|
|
15676
|
-
meta: ctx.request.meta
|
|
15677
|
-
},
|
|
15678
|
-
response: null,
|
|
15962
|
+
request: hookReq,
|
|
15963
|
+
response: errResponse,
|
|
15679
15964
|
attempt: ctx.attempt
|
|
15680
15965
|
};
|
|
15681
15966
|
const hookCtx = {
|
|
15682
15967
|
request: hookErr.request,
|
|
15683
|
-
response:
|
|
15968
|
+
response: errResponse,
|
|
15684
15969
|
error: ctx.error,
|
|
15685
15970
|
startedAt: ctx.startedAt,
|
|
15686
15971
|
attempt: ctx.attempt,
|
|
@@ -16180,7 +16465,11 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
16180
16465
|
} else if (options.body instanceof ReadableStream) {
|
|
16181
16466
|
throw new KinetexError(`maxRequestSize cannot be enforced for ReadableStream bodies \u2014 pass maxRequestSize: 0 to opt out, or buffer the body first`, "EVALIDATION");
|
|
16182
16467
|
} else if (options.body && typeof options.body === "object") {
|
|
16183
|
-
|
|
16468
|
+
try {
|
|
16469
|
+
bodySize2 = new TextEncoder().encode(JSON.stringify(options.body)).byteLength;
|
|
16470
|
+
} catch (err) {
|
|
16471
|
+
throw new KinetexError(`Cannot measure request body size: ${err instanceof Error ? err.message : String(err)}`, "EVALIDATION");
|
|
16472
|
+
}
|
|
16184
16473
|
}
|
|
16185
16474
|
if (bodySize2 > maxRequestSize) {
|
|
16186
16475
|
throw new KinetexError(`Request body size ${bodySize2} bytes exceeds limit of ${maxRequestSize} bytes`, "EVALIDATION");
|
|
@@ -16188,10 +16477,22 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
16188
16477
|
}
|
|
16189
16478
|
let req = {
|
|
16190
16479
|
url: fullUrl,
|
|
16191
|
-
method,
|
|
16480
|
+
// Use the normalized method, not the caller's casing: `send(url, "patch")`
|
|
16481
|
+
// passed validation above but used to put the literal string "patch" on
|
|
16482
|
+
// the wire. fetch() only normalizes delete/get/head/options/post/put, so a
|
|
16483
|
+
// lowercase PATCH/CONNECT went out verbatim and servers answered 405.
|
|
16484
|
+
method: normalizedMethod,
|
|
16192
16485
|
headers: mergeHeaders(this.cfg.headers, options.headers),
|
|
16486
|
+
// A plain object/array is accepted by the public API (RequestBody) and is
|
|
16487
|
+
// JSON-encoded in the block immediately below, so the request object only
|
|
16488
|
+
// ever holds a real BodyInit by the time this function returns.
|
|
16193
16489
|
body: options.body ?? null,
|
|
16194
16490
|
signal: options.signal ?? null,
|
|
16491
|
+
// Resolved once here so the manual redirect follower sees the same
|
|
16492
|
+
// effective values the caller asked for. Spread (not `??`) because the
|
|
16493
|
+
// project uses exactOptionalPropertyTypes.
|
|
16494
|
+
...options.followRedirects !== void 0 || this.cfg.followRedirects !== void 0 ? { followRedirects: options.followRedirects ?? this.cfg.followRedirects } : {},
|
|
16495
|
+
...options.maxRedirects !== void 0 || this.cfg.maxRedirects !== void 0 ? { maxRedirects: options.maxRedirects ?? this.cfg.maxRedirects } : {},
|
|
16195
16496
|
meta: { ...options.meta },
|
|
16196
16497
|
httpVersion: options.httpVersion ?? this.cfg.httpVersion ?? "HTTP/2"
|
|
16197
16498
|
};
|
|
@@ -16202,6 +16503,12 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
16202
16503
|
body: JSON.stringify(req.body)
|
|
16203
16504
|
};
|
|
16204
16505
|
}
|
|
16506
|
+
if (req.body !== null && typeof URLSearchParams !== "undefined" && req.body instanceof URLSearchParams && !req.headers["content-type"]) {
|
|
16507
|
+
req = {
|
|
16508
|
+
...req,
|
|
16509
|
+
headers: { ...req.headers, "content-type": "application/x-www-form-urlencoded" }
|
|
16510
|
+
};
|
|
16511
|
+
}
|
|
16205
16512
|
const auth = options.auth !== false ? options.auth ?? this.cfg.auth : void 0;
|
|
16206
16513
|
if (auth)
|
|
16207
16514
|
req = await applyAuth(req, auth);
|
|
@@ -16214,31 +16521,44 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
16214
16521
|
req = { ...req, headers: { ...req.headers, cookie: cookieHeader } };
|
|
16215
16522
|
}
|
|
16216
16523
|
let _otelSpan = null;
|
|
16217
|
-
|
|
16218
|
-
|
|
16219
|
-
|
|
16220
|
-
|
|
16221
|
-
|
|
16222
|
-
|
|
16223
|
-
|
|
16224
|
-
|
|
16225
|
-
|
|
16226
|
-
|
|
16227
|
-
|
|
16524
|
+
try {
|
|
16525
|
+
if (this._otelTracer) {
|
|
16526
|
+
_otelSpan = this._otelTracer.startSpan(`HTTP ${req.method}`, {
|
|
16527
|
+
kind: 3
|
|
16528
|
+
/* CLIENT */
|
|
16529
|
+
});
|
|
16530
|
+
const { traceparent, traceId, spanId } = buildTraceparent(_otelSpan);
|
|
16531
|
+
_otelSpan.setAttribute("http.request.method", req.method);
|
|
16532
|
+
_otelSpan.setAttribute("url.full", req.url);
|
|
16533
|
+
try {
|
|
16534
|
+
_otelSpan.setAttribute("server.address", new URL(req.url).hostname);
|
|
16535
|
+
} catch {
|
|
16536
|
+
}
|
|
16537
|
+
req = {
|
|
16538
|
+
...req,
|
|
16539
|
+
headers: { ...req.headers, traceparent },
|
|
16540
|
+
meta: { ...req.meta, traceId, spanId }
|
|
16541
|
+
};
|
|
16542
|
+
} else if (req.meta["traceId"] && !req.headers["traceparent"]) {
|
|
16543
|
+
const traceId = String(req.meta["traceId"]);
|
|
16544
|
+
const spanId = randomHex(16);
|
|
16545
|
+
req = {
|
|
16546
|
+
...req,
|
|
16547
|
+
headers: { ...req.headers, traceparent: `00-${traceId}-${spanId}-01` },
|
|
16548
|
+
meta: { ...req.meta, spanId }
|
|
16549
|
+
};
|
|
16228
16550
|
}
|
|
16229
|
-
|
|
16230
|
-
|
|
16231
|
-
|
|
16232
|
-
|
|
16233
|
-
|
|
16234
|
-
|
|
16235
|
-
|
|
16236
|
-
|
|
16237
|
-
|
|
16238
|
-
|
|
16239
|
-
|
|
16240
|
-
meta: { ...req.meta, spanId }
|
|
16241
|
-
};
|
|
16551
|
+
} catch (tracingErr) {
|
|
16552
|
+
if (_otelSpan) {
|
|
16553
|
+
_otelSpan.setStatus({
|
|
16554
|
+
code: 2,
|
|
16555
|
+
message: tracingErr instanceof Error ? tracingErr.message : String(tracingErr)
|
|
16556
|
+
});
|
|
16557
|
+
if (tracingErr instanceof Error)
|
|
16558
|
+
_otelSpan.recordException(tracingErr);
|
|
16559
|
+
_otelSpan.end();
|
|
16560
|
+
}
|
|
16561
|
+
throw tracingErr;
|
|
16242
16562
|
}
|
|
16243
16563
|
let _cbOrigin;
|
|
16244
16564
|
if (this._circuitBreakerKeyFn) {
|
|
@@ -16255,8 +16575,11 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
16255
16575
|
}
|
|
16256
16576
|
}
|
|
16257
16577
|
const _execFactory = () => this._executeWithRetry(req, retryCfg, timeoutMs, options, startMs, wallClockMs);
|
|
16258
|
-
|
|
16259
|
-
|
|
16578
|
+
let _dedupKey = "";
|
|
16579
|
+
if (this._dedup) {
|
|
16580
|
+
const authFp = await getAuthFingerprint(req.headers ?? {});
|
|
16581
|
+
_dedupKey = `${req.method}:${req.url}${authFp ? ":" + authFp : ""}`;
|
|
16582
|
+
}
|
|
16260
16583
|
const _dedupedFactory = this._dedup ? () => this._dedup.execute(req.method, _dedupKey, _execFactory).then((r) => r) : _execFactory;
|
|
16261
16584
|
const _guardedFactory = this._circuitBreakers ? () => this._circuitBreakers.execute(_cbOrigin, _dedupedFactory).then((r) => r) : _dedupedFactory;
|
|
16262
16585
|
try {
|
|
@@ -16294,7 +16617,10 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
16294
16617
|
while (true) {
|
|
16295
16618
|
attempt++;
|
|
16296
16619
|
if (req.signal?.aborted) {
|
|
16297
|
-
throw createAbortError();
|
|
16620
|
+
throw createAbortError(req);
|
|
16621
|
+
}
|
|
16622
|
+
if (attempt > 1 && isNonReplayableBody(req.body)) {
|
|
16623
|
+
throw new KinetexError("Cannot retry a request whose body is a stream or Blob \u2014 the body was consumed by the first attempt. Buffer it first, or disable retry for this request.", "EVALIDATION", { request: req });
|
|
16298
16624
|
}
|
|
16299
16625
|
try {
|
|
16300
16626
|
const res = await this._executeOnce(req, timeout, options, startMs, attempt, wallClockMs, retryCfg);
|
|
@@ -16320,6 +16646,15 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
16320
16646
|
}
|
|
16321
16647
|
return res;
|
|
16322
16648
|
} catch (err) {
|
|
16649
|
+
if (globalThis.__KINETEX_DEBUG_RETRY) {
|
|
16650
|
+
console.log("DBG catch", {
|
|
16651
|
+
attempt,
|
|
16652
|
+
maxRetries: retryCfg === false ? "FALSE" : retryCfg?.maxRetries,
|
|
16653
|
+
methods: retryCfg === false ? "FALSE" : retryCfg?.methods,
|
|
16654
|
+
code: err?.code,
|
|
16655
|
+
method: req.method
|
|
16656
|
+
});
|
|
16657
|
+
}
|
|
16323
16658
|
if (retryCfg && attempt <= retryCfg.maxRetries) {
|
|
16324
16659
|
const retryCtx = {
|
|
16325
16660
|
request: req,
|
|
@@ -16354,11 +16689,22 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
16354
16689
|
// intermediate redirect responses. When a cookie jar is active we must follow
|
|
16355
16690
|
// redirects ourselves one hop at a time so we can capture cookies at each step.
|
|
16356
16691
|
/**
|
|
16357
|
-
* Follow redirects manually, one hop at a time
|
|
16358
|
-
*
|
|
16692
|
+
* Follow redirects manually, one hop at a time.
|
|
16693
|
+
*
|
|
16694
|
+
* Two independent reasons this path exists:
|
|
16695
|
+
* 1. fetch() auto-follows redirects but silently drops Set-Cookie from
|
|
16696
|
+
* intermediary hops, so an active cookie jar must see every hop itself.
|
|
16697
|
+
* 2. Per the Fetch spec, a cross-origin redirect only drops
|
|
16698
|
+
* `authorization` / `cookie` / `proxy-authorization`. Custom credential
|
|
16699
|
+
* headers (apikey, X-Company-Key, ...) are forwarded verbatim, so any
|
|
16700
|
+
* request carrying one must also be followed manually.
|
|
16701
|
+
*
|
|
16702
|
+
* @param jar - Optional cookie jar. When omitted, no cookie header is
|
|
16703
|
+
* rebuilt and intermediate Set-Cookie headers are ignored.
|
|
16359
16704
|
*/
|
|
16360
16705
|
async _sendFollowingRedirects(req, timeout, jar, appliedAuth) {
|
|
16361
|
-
const
|
|
16706
|
+
const maxRedirects = Math.max(0, req.maxRedirects ?? DEFAULT_MAX_REDIRECTS);
|
|
16707
|
+
const followRedirects = req.followRedirects !== false && maxRedirects > 0;
|
|
16362
16708
|
let currentReq = { ...req, redirect: "manual" };
|
|
16363
16709
|
const origin0 = (() => {
|
|
16364
16710
|
try {
|
|
@@ -16368,7 +16714,7 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
16368
16714
|
}
|
|
16369
16715
|
})();
|
|
16370
16716
|
const visited = /* @__PURE__ */ new Set();
|
|
16371
|
-
for (let hop = 0; hop <=
|
|
16717
|
+
for (let hop = 0; hop <= maxRedirects; hop++) {
|
|
16372
16718
|
if (hop > 0 && appliedAuth) {
|
|
16373
16719
|
const sameOrigin = (() => {
|
|
16374
16720
|
try {
|
|
@@ -16411,11 +16757,13 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
16411
16757
|
});
|
|
16412
16758
|
}
|
|
16413
16759
|
visited.add(raw.url);
|
|
16414
|
-
jar
|
|
16760
|
+
jar?.processResponseHeaders(raw.headers, {
|
|
16415
16761
|
url: raw.url
|
|
16416
16762
|
});
|
|
16417
|
-
if (
|
|
16418
|
-
|
|
16763
|
+
if (!followRedirects)
|
|
16764
|
+
return { ...raw, redirected: true };
|
|
16765
|
+
if (hop === maxRedirects) {
|
|
16766
|
+
throw new KinetexError(`Too many redirects (exceeded ${maxRedirects})`, "ENETWORK", {
|
|
16419
16767
|
request: req
|
|
16420
16768
|
});
|
|
16421
16769
|
}
|
|
@@ -16434,6 +16782,12 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
16434
16782
|
if (protocol !== "http:" && protocol !== "https:") {
|
|
16435
16783
|
throw new KinetexError(`Unsafe redirect to ${protocol} detected \u2014 only HTTP(S) allowed`, "ENETWORK", { request: req });
|
|
16436
16784
|
}
|
|
16785
|
+
if (!isSafeURL(nextUrl)) {
|
|
16786
|
+
throw new KinetexError(`Unsafe redirect target blocked: ${redactUserInfo(location)}`, "EVALIDATION", { request: req });
|
|
16787
|
+
}
|
|
16788
|
+
if (this.cfg.httpsOnly && protocol !== "https:") {
|
|
16789
|
+
throw new KinetexError(`HTTPS-only mode enabled but redirect target uses ${protocol}`, "EVALIDATION", { request: req });
|
|
16790
|
+
}
|
|
16437
16791
|
} catch (err) {
|
|
16438
16792
|
if (err instanceof KinetexError)
|
|
16439
16793
|
throw err;
|
|
@@ -16444,21 +16798,30 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
16444
16798
|
}
|
|
16445
16799
|
const nextMethod = raw.status === 301 || raw.status === 302 || raw.status === 303 ? "GET" : currentReq.method;
|
|
16446
16800
|
const nextBody = nextMethod === "GET" || nextMethod === "HEAD" ? null : currentReq.body;
|
|
16447
|
-
const cookieHeader = jar.getCookieHeader({ url: nextUrl, http: true });
|
|
16448
16801
|
const nextHeaders = { ...currentReq.headers };
|
|
16449
|
-
|
|
16450
|
-
nextHeaders["cookie"] = cookieHeader;
|
|
16451
|
-
} else {
|
|
16452
|
-
delete nextHeaders["cookie"];
|
|
16453
|
-
}
|
|
16802
|
+
let crossOrigin = false;
|
|
16454
16803
|
try {
|
|
16455
|
-
|
|
16456
|
-
for (const h of CROSS_ORIGIN_STRIP_HEADERS) {
|
|
16457
|
-
delete nextHeaders[h];
|
|
16458
|
-
}
|
|
16459
|
-
}
|
|
16804
|
+
crossOrigin = new URL(nextUrl).origin !== new URL(currentReq.url).origin;
|
|
16460
16805
|
} catch {
|
|
16461
16806
|
}
|
|
16807
|
+
if (crossOrigin) {
|
|
16808
|
+
for (const h of CROSS_ORIGIN_STRIP_HEADERS) {
|
|
16809
|
+
delete nextHeaders[h];
|
|
16810
|
+
}
|
|
16811
|
+
if (appliedAuth && appliedAuth.type === "apikey") {
|
|
16812
|
+
delete nextHeaders[appliedAuth.header.toLowerCase()];
|
|
16813
|
+
}
|
|
16814
|
+
}
|
|
16815
|
+
if (jar) {
|
|
16816
|
+
const cookieHeader = jar.getCookieHeader({ url: nextUrl, http: true });
|
|
16817
|
+
if (cookieHeader) {
|
|
16818
|
+
nextHeaders["cookie"] = cookieHeader;
|
|
16819
|
+
} else {
|
|
16820
|
+
delete nextHeaders["cookie"];
|
|
16821
|
+
}
|
|
16822
|
+
} else if (crossOrigin) {
|
|
16823
|
+
delete nextHeaders["cookie"];
|
|
16824
|
+
}
|
|
16462
16825
|
currentReq = {
|
|
16463
16826
|
...currentReq,
|
|
16464
16827
|
url: nextUrl,
|
|
@@ -16469,7 +16832,7 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
16469
16832
|
};
|
|
16470
16833
|
continue;
|
|
16471
16834
|
}
|
|
16472
|
-
return raw;
|
|
16835
|
+
return hop > 0 ? { ...raw, redirected: true } : raw;
|
|
16473
16836
|
}
|
|
16474
16837
|
throw new KinetexError("Redirect loop", "ENETWORK", { request: req });
|
|
16475
16838
|
}
|
|
@@ -16556,7 +16919,10 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
16556
16919
|
}
|
|
16557
16920
|
}
|
|
16558
16921
|
} finally {
|
|
16559
|
-
|
|
16922
|
+
try {
|
|
16923
|
+
(await this.getCache())?.clearSWRInFlight(cacheReq);
|
|
16924
|
+
} catch {
|
|
16925
|
+
}
|
|
16560
16926
|
}
|
|
16561
16927
|
})();
|
|
16562
16928
|
}
|
|
@@ -16634,15 +17000,17 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
16634
17000
|
...req,
|
|
16635
17001
|
headers: {
|
|
16636
17002
|
...req.headers,
|
|
16637
|
-
"accept-encoding":
|
|
17003
|
+
"accept-encoding": DEFAULT_ACCEPT_ENCODING
|
|
16638
17004
|
}
|
|
16639
17005
|
};
|
|
16640
17006
|
}
|
|
16641
17007
|
const dispatchJar = await this.getCookieJar();
|
|
17008
|
+
const effectiveAuth = options.auth !== false ? options.auth ?? this.cfg.auth : void 0;
|
|
17009
|
+
const needsManualRedirects = dispatchJar !== null || hasForwardedCredentials(req.headers, effectiveAuth);
|
|
16642
17010
|
this._trace(_traceId, "transport_send", "start", startMs, attempt);
|
|
16643
17011
|
let raw;
|
|
16644
17012
|
try {
|
|
16645
|
-
raw =
|
|
17013
|
+
raw = needsManualRedirects ? await this._sendFollowingRedirects(req, timeout, dispatchJar ?? void 0, effectiveAuth) : await sendWithTimeout(this.transport, req, timeout);
|
|
16646
17014
|
} catch (err) {
|
|
16647
17015
|
if (_uploadStreamForCleanup) {
|
|
16648
17016
|
try {
|
|
@@ -16686,9 +17054,10 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
16686
17054
|
},
|
|
16687
17055
|
...req.signal !== null ? { signal: req.signal } : {}
|
|
16688
17056
|
});
|
|
17057
|
+
const source = bodyStream;
|
|
16689
17058
|
bodyStream = new ReadableStream({
|
|
16690
17059
|
async start(controller) {
|
|
16691
|
-
const reader =
|
|
17060
|
+
const reader = source.getReader();
|
|
16692
17061
|
try {
|
|
16693
17062
|
while (true) {
|
|
16694
17063
|
const { done, value } = await reader.read();
|
|
@@ -16706,8 +17075,9 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
16706
17075
|
reader.releaseLock();
|
|
16707
17076
|
}
|
|
16708
17077
|
},
|
|
16709
|
-
cancel() {
|
|
16710
|
-
|
|
17078
|
+
cancel(reason) {
|
|
17079
|
+
void source.cancel(reason).catch(() => {
|
|
17080
|
+
});
|
|
16711
17081
|
}
|
|
16712
17082
|
});
|
|
16713
17083
|
}
|
|
@@ -16728,7 +17098,9 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
16728
17098
|
status: raw.status,
|
|
16729
17099
|
statusText: raw.statusText,
|
|
16730
17100
|
headers: raw.headers,
|
|
16731
|
-
|
|
17101
|
+
// transformResponse is applied below, once `res` exists, so it receives
|
|
17102
|
+
// the real response object instead of the `{}` placeholder it used to get.
|
|
17103
|
+
data,
|
|
16732
17104
|
rawBody,
|
|
16733
17105
|
url: raw.url,
|
|
16734
17106
|
cached: false,
|
|
@@ -16738,6 +17110,9 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
16738
17110
|
request: req,
|
|
16739
17111
|
attempt
|
|
16740
17112
|
};
|
|
17113
|
+
if (this.cfg.transformResponse) {
|
|
17114
|
+
res.data = this.cfg.transformResponse(res.data, res);
|
|
17115
|
+
}
|
|
16741
17116
|
if (options.cache !== false && this.cfg.cache) {
|
|
16742
17117
|
const cache = await this.getCache();
|
|
16743
17118
|
if (cache && raw.status !== 304) {
|
|
@@ -16806,6 +17181,10 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
16806
17181
|
if ("status" in result && "headers" in result) {
|
|
16807
17182
|
current = result;
|
|
16808
17183
|
} else if ("url" in result && "method" in result && !("status" in result)) {
|
|
17184
|
+
const resendDepth = Number(_req.meta[INTERCEPTOR_RESEND_DEPTH] ?? 0);
|
|
17185
|
+
if (resendDepth >= MAX_INTERCEPTOR_RESENDS) {
|
|
17186
|
+
throw new KinetexError(`Response interceptor re-send limit reached (${MAX_INTERCEPTOR_RESENDS}) \u2014 refusing to loop`, "EVALIDATION", { request: _req });
|
|
17187
|
+
}
|
|
16809
17188
|
if (retryCfg && attempt <= retryCfg.maxRetries) {
|
|
16810
17189
|
const retryCtx = {
|
|
16811
17190
|
request: _req,
|
|
@@ -16822,7 +17201,13 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
16822
17201
|
}, Promise.resolve());
|
|
16823
17202
|
await sleep6(delay, _req.signal);
|
|
16824
17203
|
}
|
|
16825
|
-
return this._executeOnce(
|
|
17204
|
+
return this._executeOnce({
|
|
17205
|
+
...result,
|
|
17206
|
+
meta: {
|
|
17207
|
+
...result.meta,
|
|
17208
|
+
[INTERCEPTOR_RESEND_DEPTH]: resendDepth + 1
|
|
17209
|
+
}
|
|
17210
|
+
}, timeout, options, startMs, attempt + 1, void 0, retryCfg);
|
|
16826
17211
|
}
|
|
16827
17212
|
}
|
|
16828
17213
|
return current;
|
|
@@ -17100,7 +17485,10 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
17100
17485
|
* Call this when the client is no longer needed to prevent memory leaks.
|
|
17101
17486
|
* @returns A promise that resolves when cleanup is complete.
|
|
17102
17487
|
*/
|
|
17103
|
-
async
|
|
17488
|
+
// Not `async`: nothing here awaits, so the returned promise is resolved
|
|
17489
|
+
// explicitly instead. The signature stays Promise<void> — callers and the
|
|
17490
|
+
// docs `await client.destroy()`.
|
|
17491
|
+
destroy() {
|
|
17104
17492
|
for (const ws of this._wsClients) {
|
|
17105
17493
|
try {
|
|
17106
17494
|
ws.close(1e3, "Client destroyed");
|
|
@@ -17108,12 +17496,6 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
17108
17496
|
}
|
|
17109
17497
|
}
|
|
17110
17498
|
this._wsClients.clear();
|
|
17111
|
-
if (this._cache) {
|
|
17112
|
-
try {
|
|
17113
|
-
await this._cache.clear();
|
|
17114
|
-
} catch {
|
|
17115
|
-
}
|
|
17116
|
-
}
|
|
17117
17499
|
if (IS_NODE && this.transport && "destroy" in this.transport) {
|
|
17118
17500
|
this.transport.destroy();
|
|
17119
17501
|
}
|
|
@@ -17123,6 +17505,7 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
17123
17505
|
this._circuitBreakers?.clear?.();
|
|
17124
17506
|
this._otelTracer = null;
|
|
17125
17507
|
this.interceptors.clear();
|
|
17508
|
+
return Promise.resolve();
|
|
17126
17509
|
}
|
|
17127
17510
|
};
|
|
17128
17511
|
var FluentRequest = class {
|
|
@@ -17351,13 +17734,19 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
17351
17734
|
}).catch((err) => onError?.(err instanceof KinetexError ? err : new KinetexError(String(err), "EUNKNOWN")));
|
|
17352
17735
|
}
|
|
17353
17736
|
};
|
|
17354
|
-
function
|
|
17355
|
-
if (
|
|
17356
|
-
return
|
|
17357
|
-
|
|
17358
|
-
|
|
17359
|
-
|
|
17360
|
-
|
|
17737
|
+
function toHookResponse(res, request) {
|
|
17738
|
+
if (!res)
|
|
17739
|
+
return null;
|
|
17740
|
+
return {
|
|
17741
|
+
status: res.status,
|
|
17742
|
+
statusText: res.statusText,
|
|
17743
|
+
headers: res.headers,
|
|
17744
|
+
body: res.rawBody ?? null,
|
|
17745
|
+
request
|
|
17746
|
+
};
|
|
17747
|
+
}
|
|
17748
|
+
function createAbortError(request) {
|
|
17749
|
+
return new AbortError(request);
|
|
17361
17750
|
}
|
|
17362
17751
|
function mergeParams(a, b) {
|
|
17363
17752
|
if (!a && !b)
|
|
@@ -17381,6 +17770,11 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
17381
17770
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
17382
17771
|
});
|
|
17383
17772
|
}
|
|
17773
|
+
function isNonReplayableBody(body) {
|
|
17774
|
+
if (body instanceof ReadableStream)
|
|
17775
|
+
return true;
|
|
17776
|
+
return typeof Blob !== "undefined" && body instanceof Blob;
|
|
17777
|
+
}
|
|
17384
17778
|
function perfNow4() {
|
|
17385
17779
|
return typeof performance !== "undefined" ? performance.now() : Date.now();
|
|
17386
17780
|
}
|
|
@@ -17399,7 +17793,13 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
17399
17793
|
constructor(client, options = {}) {
|
|
17400
17794
|
/** The parent Kinetex instance used to send requests. */
|
|
17401
17795
|
__publicField(this, "_client");
|
|
17402
|
-
/**
|
|
17796
|
+
/**
|
|
17797
|
+
* Maximum number of requests taken out of the queue per flush.
|
|
17798
|
+
* NOTE: this is a batching size, NOT a concurrency limit — every request in a
|
|
17799
|
+
* batch is dispatched immediately and in parallel, and `flush()` drains the
|
|
17800
|
+
* whole queue the same way. Use `maxBatch` to bound how much is dispatched per
|
|
17801
|
+
* tick, and a semaphore or rate limiter to bound actual parallelism.
|
|
17802
|
+
*/
|
|
17403
17803
|
__publicField(this, "_maxBatch");
|
|
17404
17804
|
/** Milliseconds to wait before flushing an incomplete batch. */
|
|
17405
17805
|
__publicField(this, "_flushMs");
|
|
@@ -17408,8 +17808,16 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
17408
17808
|
/** Timer handle for deferred flush. */
|
|
17409
17809
|
__publicField(this, "_timer", null);
|
|
17410
17810
|
this._client = client;
|
|
17411
|
-
|
|
17412
|
-
|
|
17811
|
+
const maxBatch = options.maxBatch ?? 100;
|
|
17812
|
+
if (!Number.isInteger(maxBatch) || maxBatch < 1) {
|
|
17813
|
+
throw new RangeError(`BatchQueue maxBatch must be a positive integer (got ${maxBatch})`);
|
|
17814
|
+
}
|
|
17815
|
+
this._maxBatch = maxBatch;
|
|
17816
|
+
const flushMs = options.flushMs ?? 0;
|
|
17817
|
+
if (!Number.isFinite(flushMs) || flushMs < 0) {
|
|
17818
|
+
throw new RangeError(`BatchQueue flushMs must be a non-negative finite number (got ${flushMs})`);
|
|
17819
|
+
}
|
|
17820
|
+
this._flushMs = flushMs;
|
|
17413
17821
|
}
|
|
17414
17822
|
/**
|
|
17415
17823
|
* Enqueue a request. Returns a promise that resolves when the batch
|
|
@@ -17462,7 +17870,8 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
17462
17870
|
* Loops until the queue is empty so items beyond maxBatch are not orphaned.
|
|
17463
17871
|
*/
|
|
17464
17872
|
flush() {
|
|
17465
|
-
|
|
17873
|
+
let guard = this._queue.length + 1;
|
|
17874
|
+
while (this._queue.length > 0 && guard-- > 0)
|
|
17466
17875
|
this._flushNow();
|
|
17467
17876
|
}
|
|
17468
17877
|
/** How many requests are currently queued (not yet sent). */
|
|
@@ -18457,28 +18866,27 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
18457
18866
|
}
|
|
18458
18867
|
var denoTcpConnector = async (host, port, timeoutMs) => {
|
|
18459
18868
|
const denoGlobal = globalThis;
|
|
18460
|
-
|
|
18461
|
-
|
|
18462
|
-
|
|
18463
|
-
|
|
18464
|
-
new Promise((_, rej) => setTimeout(() => rej(new Socks5Error("TCP connect to proxy timed out", "SOCKS5_TIMEOUT", true)), timeoutMs))
|
|
18465
|
-
]);
|
|
18466
|
-
} else {
|
|
18467
|
-
conn = await denoGlobal.Deno.connect({ hostname: host, port, transport: "tcp" });
|
|
18468
|
-
}
|
|
18469
|
-
const wrappedRead = async (buf) => {
|
|
18470
|
-
if (timeoutMs && timeoutMs > 0) {
|
|
18471
|
-
return Promise.race([
|
|
18472
|
-
conn.read(buf).catch(() => null),
|
|
18473
|
-
new Promise((_, rej) => setTimeout(() => rej(new Socks5Error("TCP read timed out", "SOCKS5_TIMEOUT", true)), timeoutMs))
|
|
18474
|
-
]);
|
|
18475
|
-
}
|
|
18869
|
+
const withTimeout2 = async (work, message) => {
|
|
18870
|
+
if (!timeoutMs || timeoutMs <= 0)
|
|
18871
|
+
return work;
|
|
18872
|
+
let timer;
|
|
18476
18873
|
try {
|
|
18477
|
-
return await
|
|
18478
|
-
|
|
18479
|
-
|
|
18874
|
+
return await Promise.race([
|
|
18875
|
+
work,
|
|
18876
|
+
new Promise((_, rej) => {
|
|
18877
|
+
timer = setTimeout(() => rej(new Socks5Error(message, "SOCKS5_TIMEOUT", true)), timeoutMs);
|
|
18878
|
+
})
|
|
18879
|
+
]);
|
|
18880
|
+
} finally {
|
|
18881
|
+
if (timer !== void 0)
|
|
18882
|
+
clearTimeout(timer);
|
|
18480
18883
|
}
|
|
18481
18884
|
};
|
|
18885
|
+
const conn = await withTimeout2(denoGlobal.Deno.connect({ hostname: host, port, transport: "tcp" }), "TCP connect to proxy timed out");
|
|
18886
|
+
const wrappedRead = (buf) => {
|
|
18887
|
+
const read = conn.read(buf).catch(() => null);
|
|
18888
|
+
return withTimeout2(read, "TCP read timed out");
|
|
18889
|
+
};
|
|
18482
18890
|
return {
|
|
18483
18891
|
read: wrappedRead,
|
|
18484
18892
|
write: (data) => conn.write(data),
|
|
@@ -18531,7 +18939,9 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
18531
18939
|
buffer = next;
|
|
18532
18940
|
flushBuffer();
|
|
18533
18941
|
});
|
|
18942
|
+
let ended = false;
|
|
18534
18943
|
socket.on("end", () => {
|
|
18944
|
+
ended = true;
|
|
18535
18945
|
if (pendingRead) {
|
|
18536
18946
|
pendingRead(null);
|
|
18537
18947
|
pendingRead = null;
|
|
@@ -18539,6 +18949,9 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
18539
18949
|
pendingBuf = null;
|
|
18540
18950
|
}
|
|
18541
18951
|
});
|
|
18952
|
+
socket.on("close", () => {
|
|
18953
|
+
ended = true;
|
|
18954
|
+
});
|
|
18542
18955
|
socket.once("error", (err) => {
|
|
18543
18956
|
clearTimeout(timer);
|
|
18544
18957
|
lastError = err;
|
|
@@ -18557,6 +18970,10 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
18557
18970
|
rej(lastError);
|
|
18558
18971
|
return;
|
|
18559
18972
|
}
|
|
18973
|
+
if (ended && buffer.length === 0) {
|
|
18974
|
+
res(null);
|
|
18975
|
+
return;
|
|
18976
|
+
}
|
|
18560
18977
|
if (buffer.length > 0) {
|
|
18561
18978
|
const n = Math.min(buffer.length, buf.length);
|
|
18562
18979
|
buf.set(buffer.subarray(0, n));
|