kinetex 1.1.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 +749 -295
- 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 +83 -35
- package/dist/cjs/dedup.js +9 -7
- package/dist/cjs/digest.js +26 -0
- package/dist/cjs/graphql.js +19 -4
- package/dist/cjs/headers.js +64 -8
- package/dist/cjs/interceptors.js +86 -33
- package/dist/cjs/logging.js +1 -1
- package/dist/cjs/pagination.js +14 -6
- package/dist/cjs/progress.js +129 -42
- package/dist/cjs/socks5.js +36 -21
- package/dist/cjs/sse.js +48 -11
- package/dist/cjs/utils.js +24 -12
- package/dist/cjs/worker.js +6 -6
- package/dist/cjs/ws.js +23 -7
- 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 +83 -35
- 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/graphql.js +19 -4
- package/dist/esm/graphql.js.map +1 -1
- package/dist/esm/headers.js +64 -8
- package/dist/esm/headers.js.map +1 -1
- package/dist/esm/interceptors.js +86 -33
- 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 +129 -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/utils.js +24 -12
- package/dist/esm/utils.js.map +1 -1
- package/dist/esm/worker.js +6 -6
- package/dist/esm/worker.js.map +1 -1
- package/dist/esm/ws.js +23 -7
- 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 +10 -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/graphql.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/utils.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 +4 -0
- package/dist/types/ws.d.ts.map +1 -1
- package/package.json +4 -4
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;
|
|
@@ -283,8 +283,11 @@ var kinetex = (() => {
|
|
|
283
283
|
function parseIPv4Host(host) {
|
|
284
284
|
if (host.includes(":") || !/^[0-9a-fA-FxX.]+$/.test(host))
|
|
285
285
|
return null;
|
|
286
|
-
const
|
|
287
|
-
if (
|
|
286
|
+
const bare = host.endsWith(".") ? host.slice(0, -1) : host;
|
|
287
|
+
if (bare === "")
|
|
288
|
+
return null;
|
|
289
|
+
const parts = bare.split(".");
|
|
290
|
+
if (parts.length > 4 || parts.length < 1)
|
|
288
291
|
return null;
|
|
289
292
|
if (parts.length === 1) {
|
|
290
293
|
const v = parseIPv4Component(parts[0]);
|
|
@@ -292,17 +295,21 @@ var kinetex = (() => {
|
|
|
292
295
|
return null;
|
|
293
296
|
return v >>> 0;
|
|
294
297
|
}
|
|
295
|
-
const
|
|
296
|
-
for (
|
|
297
|
-
const v = parseIPv4Component(
|
|
298
|
-
|
|
299
|
-
if (v === null || v > (isLast && nums.length === 3 ? 255 : 255))
|
|
298
|
+
const octets = [];
|
|
299
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
300
|
+
const v = parseIPv4Component(parts[i]);
|
|
301
|
+
if (v === null || v > 255)
|
|
300
302
|
return null;
|
|
301
|
-
|
|
303
|
+
octets.push(v);
|
|
304
|
+
}
|
|
305
|
+
const last = parseIPv4Component(parts[parts.length - 1]);
|
|
306
|
+
const lastCap = 2 ** (8 * (5 - parts.length));
|
|
307
|
+
if (last === null || last >= lastCap)
|
|
308
|
+
return null;
|
|
309
|
+
for (let shift = 8 * (4 - parts.length); shift >= 0; shift -= 8) {
|
|
310
|
+
octets.push(last >>> shift & 255);
|
|
302
311
|
}
|
|
303
|
-
|
|
304
|
-
nums.push(0);
|
|
305
|
-
return (nums[0] << 24 | nums[1] << 16 | nums[2] << 8 | nums[3]) >>> 0;
|
|
312
|
+
return (octets[0] << 24 | octets[1] << 16 | octets[2] << 8 | octets[3]) >>> 0;
|
|
306
313
|
}
|
|
307
314
|
function parseIPv6Host(host) {
|
|
308
315
|
if (!host.includes(":"))
|
|
@@ -895,6 +902,7 @@ var kinetex = (() => {
|
|
|
895
902
|
// dist/esm/cache.js
|
|
896
903
|
var cache_exports = {};
|
|
897
904
|
__export(cache_exports, {
|
|
905
|
+
CREDENTIAL_HEADERS: () => CREDENTIAL_HEADERS,
|
|
898
906
|
CloudflareKVAdapter: () => CloudflareKVAdapter,
|
|
899
907
|
HTTPCache: () => HTTPCache,
|
|
900
908
|
MemoryStorageAdapter: () => MemoryStorageAdapter,
|
|
@@ -986,18 +994,16 @@ var kinetex = (() => {
|
|
|
986
994
|
return parts.join(";");
|
|
987
995
|
}
|
|
988
996
|
function normalizeCacheKeyPart(part) {
|
|
989
|
-
|
|
990
|
-
String.fromCharCode(0) + "-" + String.fromCharCode(31),
|
|
991
|
-
String.fromCharCode(127) + "-" + String.fromCharCode(159)
|
|
992
|
-
].join("");
|
|
993
|
-
const controlRegex = new RegExp(`[${controlRanges}]`, "g");
|
|
994
|
-
return part.replaceAll(controlRegex, "").replaceAll(/\s+/g, " ").trim();
|
|
997
|
+
return part.replaceAll(CONTROL_CHARS, "").replaceAll(/\s+/g, " ").trim();
|
|
995
998
|
}
|
|
996
999
|
async function getAuthFingerprint(headers) {
|
|
997
|
-
const
|
|
1000
|
+
const lowered = /* @__PURE__ */ new Map();
|
|
1001
|
+
for (const [name, value] of Object.entries(headers)) {
|
|
1002
|
+
lowered.set(name.toLowerCase(), value);
|
|
1003
|
+
}
|
|
998
1004
|
const parts = [];
|
|
999
|
-
for (const header of
|
|
1000
|
-
const value =
|
|
1005
|
+
for (const header of CREDENTIAL_HEADERS) {
|
|
1006
|
+
const value = lowered.get(header);
|
|
1001
1007
|
if (value)
|
|
1002
1008
|
parts.push(`${header}=${value}`);
|
|
1003
1009
|
}
|
|
@@ -1111,7 +1117,7 @@ var kinetex = (() => {
|
|
|
1111
1117
|
function createTwoTierCache(l2, config) {
|
|
1112
1118
|
return new HTTPCache({ ...config, storage: new TwoTierStorageAdapter(l2) });
|
|
1113
1119
|
}
|
|
1114
|
-
var MemoryStorageAdapter, WebStorageAdapter, CloudflareKVAdapter, TwoTierStorageAdapter, LRUNode, LRUTracker, HTTPCache;
|
|
1120
|
+
var MemoryStorageAdapter, WebStorageAdapter, CloudflareKVAdapter, TwoTierStorageAdapter, CONTROL_CHARS, CREDENTIAL_HEADERS, LRUNode, LRUTracker, HTTPCache;
|
|
1115
1121
|
var init_cache = __esm({
|
|
1116
1122
|
"dist/esm/cache.js"() {
|
|
1117
1123
|
"use strict";
|
|
@@ -1279,6 +1285,24 @@ var kinetex = (() => {
|
|
|
1279
1285
|
await Promise.all([this.l1.clear(), this.l2.clear()]);
|
|
1280
1286
|
}
|
|
1281
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
|
+
];
|
|
1282
1306
|
LRUNode = class {
|
|
1283
1307
|
constructor(key, prev = null, next = null) {
|
|
1284
1308
|
__publicField(this, "key");
|
|
@@ -1393,6 +1417,8 @@ var kinetex = (() => {
|
|
|
1393
1417
|
// 7 days
|
|
1394
1418
|
honorCacheControl: config.honorCacheControl ?? true,
|
|
1395
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.
|
|
1396
1422
|
cacheStatuses: config.cacheStatuses ?? [
|
|
1397
1423
|
200,
|
|
1398
1424
|
203,
|
|
@@ -1400,7 +1426,6 @@ var kinetex = (() => {
|
|
|
1400
1426
|
206,
|
|
1401
1427
|
300,
|
|
1402
1428
|
301,
|
|
1403
|
-
304,
|
|
1404
1429
|
404,
|
|
1405
1430
|
405,
|
|
1406
1431
|
410,
|
|
@@ -1767,6 +1792,9 @@ var kinetex = (() => {
|
|
|
1767
1792
|
for (const tag of entry.tags) {
|
|
1768
1793
|
this.tagIndex.get(tag)?.delete(key);
|
|
1769
1794
|
}
|
|
1795
|
+
} else {
|
|
1796
|
+
for (const set of this.tagIndex.values())
|
|
1797
|
+
set.delete(key);
|
|
1770
1798
|
}
|
|
1771
1799
|
}
|
|
1772
1800
|
async _ensureCapacity(newEntrySize) {
|
|
@@ -1959,6 +1987,23 @@ var kinetex = (() => {
|
|
|
1959
1987
|
}
|
|
1960
1988
|
return out;
|
|
1961
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
|
+
}
|
|
1962
2007
|
function parseCacheControl2(value) {
|
|
1963
2008
|
const d = {
|
|
1964
2009
|
noCache: false,
|
|
@@ -1979,7 +2024,7 @@ var kinetex = (() => {
|
|
|
1979
2024
|
staleWhileRevalidate: null,
|
|
1980
2025
|
unknown: /* @__PURE__ */ new Map()
|
|
1981
2026
|
};
|
|
1982
|
-
for (const part of value
|
|
2027
|
+
for (const part of splitCacheControlDirectives(value)) {
|
|
1983
2028
|
const t = part.trim();
|
|
1984
2029
|
const eq = t.indexOf("=");
|
|
1985
2030
|
const k = (eq === -1 ? t : t.slice(0, eq)).trim().toLowerCase();
|
|
@@ -2303,11 +2348,30 @@ var kinetex = (() => {
|
|
|
2303
2348
|
proto: xproto ?? null
|
|
2304
2349
|
};
|
|
2305
2350
|
}
|
|
2306
|
-
function getClientIP(headers) {
|
|
2351
|
+
function getClientIP(headers, options = {}) {
|
|
2352
|
+
const trustedHops = Math.max(0, Math.trunc(options.trustedHops ?? 0));
|
|
2307
2353
|
const fwd = normalizeForwardedHeaders(headers);
|
|
2308
|
-
if (fwd.for.length > 0)
|
|
2309
|
-
|
|
2310
|
-
|
|
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;
|
|
2311
2375
|
}
|
|
2312
2376
|
function parseRetryAfter(value) {
|
|
2313
2377
|
const t = value.trim();
|
|
@@ -4449,6 +4513,7 @@ var kinetex = (() => {
|
|
|
4449
4513
|
// dist/esm/core.js
|
|
4450
4514
|
var core_exports = {};
|
|
4451
4515
|
__export(core_exports, {
|
|
4516
|
+
DEFAULT_ACCEPT_ENCODING: () => DEFAULT_ACCEPT_ENCODING,
|
|
4452
4517
|
FetchTransport: () => FetchTransport,
|
|
4453
4518
|
HAS_NATIVE_FETCH: () => HAS_NATIVE_FETCH,
|
|
4454
4519
|
HTTP_STATUS_TEXTS: () => HTTP_STATUS_TEXTS,
|
|
@@ -4502,6 +4567,11 @@ var kinetex = (() => {
|
|
|
4502
4567
|
}
|
|
4503
4568
|
}
|
|
4504
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
|
+
}
|
|
4505
4575
|
if (IS_NODE && preferHTTP2 && !fetchFn) {
|
|
4506
4576
|
return new NodeHTTP2Transport({
|
|
4507
4577
|
...sessionOptions?.sessionTTLMs !== void 0 ? { sessionTTLMs: sessionOptions.sessionTTLMs } : {},
|
|
@@ -4743,7 +4813,8 @@ var kinetex = (() => {
|
|
|
4743
4813
|
} else if (typeof body === "string") {
|
|
4744
4814
|
stream.end(body);
|
|
4745
4815
|
} else {
|
|
4746
|
-
|
|
4816
|
+
const bytes = await serializeRawBody(body);
|
|
4817
|
+
stream.end(bytes);
|
|
4747
4818
|
}
|
|
4748
4819
|
}
|
|
4749
4820
|
async function pipeBodyToNodeReq(req, body) {
|
|
@@ -4762,8 +4833,18 @@ var kinetex = (() => {
|
|
|
4762
4833
|
} else if (typeof body === "string") {
|
|
4763
4834
|
req.end(body);
|
|
4764
4835
|
} else {
|
|
4765
|
-
|
|
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());
|
|
4766
4843
|
}
|
|
4844
|
+
if (typeof Blob !== "undefined" && body instanceof Blob) {
|
|
4845
|
+
return new Uint8Array(await body.arrayBuffer());
|
|
4846
|
+
}
|
|
4847
|
+
return new Uint8Array(0);
|
|
4767
4848
|
}
|
|
4768
4849
|
async function decompressBodyStream(body, headers) {
|
|
4769
4850
|
if (!body)
|
|
@@ -4788,7 +4869,7 @@ var kinetex = (() => {
|
|
|
4788
4869
|
const { applyDecompression: applyDecompression2 } = await Promise.resolve().then(() => (init_response(), response_exports));
|
|
4789
4870
|
return applyDecompression2(body, headers);
|
|
4790
4871
|
}
|
|
4791
|
-
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;
|
|
4792
4873
|
var init_core = __esm({
|
|
4793
4874
|
"dist/esm/core.js"() {
|
|
4794
4875
|
"use strict";
|
|
@@ -4801,6 +4882,7 @@ var kinetex = (() => {
|
|
|
4801
4882
|
_runtimeOverride = null;
|
|
4802
4883
|
IS_NODE = RUNTIME === "node";
|
|
4803
4884
|
HAS_NATIVE_FETCH = RUNTIME !== "node" || typeof globalThis.fetch === "function";
|
|
4885
|
+
DEFAULT_ACCEPT_ENCODING = "gzip, deflate, br";
|
|
4804
4886
|
FetchTransport = class {
|
|
4805
4887
|
/**
|
|
4806
4888
|
* @param fetchFnOrOptions - Custom fetch function or options object
|
|
@@ -4848,7 +4930,7 @@ var kinetex = (() => {
|
|
|
4848
4930
|
sanitizedHeaders[name] = value;
|
|
4849
4931
|
}
|
|
4850
4932
|
const ae = sanitizedHeaders["accept-encoding"];
|
|
4851
|
-
if (ae && ae.toLowerCase().
|
|
4933
|
+
if (ae && ae.toLowerCase().replace(/\s+/g, " ") === DEFAULT_ACCEPT_ENCODING) {
|
|
4852
4934
|
delete sanitizedHeaders["accept-encoding"];
|
|
4853
4935
|
}
|
|
4854
4936
|
const init = {
|
|
@@ -4913,6 +4995,8 @@ var kinetex = (() => {
|
|
|
4913
4995
|
__publicField(this, "sessionUsage", /* @__PURE__ */ new Map());
|
|
4914
4996
|
__publicField(this, "_strict");
|
|
4915
4997
|
__publicField(this, "_onDroppedHeader");
|
|
4998
|
+
/** Optional CA bundle for origins with self-signed / private-PKI certificates. */
|
|
4999
|
+
__publicField(this, "_ca");
|
|
4916
5000
|
/** FIX 11: Configurable connect timeout (replaces hardcoded 30 000 ms) */
|
|
4917
5001
|
__publicField(this, "_connectTimeoutMs");
|
|
4918
5002
|
/** FIX 11: Configurable per-request stream timeout (replaces hardcoded 30 000 ms) */
|
|
@@ -4924,6 +5008,7 @@ var kinetex = (() => {
|
|
|
4924
5008
|
this.maxSessions = options.maxSessions ?? 100;
|
|
4925
5009
|
this._strict = options.strict ?? false;
|
|
4926
5010
|
this._onDroppedHeader = options.onDroppedHeader;
|
|
5011
|
+
this._ca = options.ca;
|
|
4927
5012
|
this._connectTimeoutMs = options.connectTimeoutMs ?? 3e4;
|
|
4928
5013
|
this._requestTimeoutMs = options.requestTimeoutMs ?? 3e4;
|
|
4929
5014
|
}
|
|
@@ -4973,7 +5058,10 @@ var kinetex = (() => {
|
|
|
4973
5058
|
}
|
|
4974
5059
|
}
|
|
4975
5060
|
const session = await new Promise((resolve, reject) => {
|
|
4976
|
-
const s = http2.connect(origin, {
|
|
5061
|
+
const s = http2.connect(origin, {
|
|
5062
|
+
rejectUnauthorized: true,
|
|
5063
|
+
...this._ca !== void 0 ? { ca: this._ca } : {}
|
|
5064
|
+
});
|
|
4977
5065
|
const connectTimeout = setTimeout(() => {
|
|
4978
5066
|
s.destroy();
|
|
4979
5067
|
reject(new KinetexError(`HTTP/2 connection to ${origin} timed out`, "ETIMEOUT", {
|
|
@@ -5086,30 +5174,28 @@ var kinetex = (() => {
|
|
|
5086
5174
|
":authority": currentUrl.host,
|
|
5087
5175
|
...currentReq.headers
|
|
5088
5176
|
};
|
|
5089
|
-
|
|
5090
|
-
|
|
5091
|
-
|
|
5092
|
-
|
|
5093
|
-
|
|
5094
|
-
|
|
5095
|
-
|
|
5096
|
-
|
|
5097
|
-
|
|
5098
|
-
|
|
5099
|
-
break;
|
|
5100
|
-
}
|
|
5177
|
+
for (const [hName, hValue] of Object.entries(h2ReqHeaders)) {
|
|
5178
|
+
if (hName.startsWith(":"))
|
|
5179
|
+
continue;
|
|
5180
|
+
const hStr = Array.isArray(hValue) ? hValue.join(", ") : String(hValue);
|
|
5181
|
+
let hasForbidden = false;
|
|
5182
|
+
for (let ci = 0; ci < hStr.length; ci++) {
|
|
5183
|
+
const code = hStr.charCodeAt(ci);
|
|
5184
|
+
if (code >= 0 && code <= 8 || code >= 10 && code <= 31 || code === 127) {
|
|
5185
|
+
hasForbidden = true;
|
|
5186
|
+
break;
|
|
5101
5187
|
}
|
|
5102
|
-
|
|
5103
|
-
|
|
5104
|
-
|
|
5105
|
-
}
|
|
5106
|
-
|
|
5107
|
-
|
|
5108
|
-
|
|
5109
|
-
|
|
5110
|
-
}
|
|
5111
|
-
delete h2ReqHeaders[hName];
|
|
5188
|
+
}
|
|
5189
|
+
if (hasForbidden) {
|
|
5190
|
+
if (this._strict) {
|
|
5191
|
+
throw new KinetexError(`Strict mode: header "${hName}" contains forbidden control characters`, "EVALIDATION", { request: currentReq });
|
|
5192
|
+
}
|
|
5193
|
+
if (this._onDroppedHeader) {
|
|
5194
|
+
this._onDroppedHeader(hName, hStr);
|
|
5195
|
+
} else if (typeof console !== "undefined") {
|
|
5196
|
+
console.warn(`[kinetex] Invalid header dropped (HTTP/2): "${hName}" \u2014 value contains illegal control characters. Pass strictHeaders: true to throw instead.`);
|
|
5112
5197
|
}
|
|
5198
|
+
delete h2ReqHeaders[hName];
|
|
5113
5199
|
}
|
|
5114
5200
|
}
|
|
5115
5201
|
const endStream = !currentReq.body || currentReq.method === "GET" || currentReq.method === "HEAD";
|
|
@@ -5648,8 +5734,7 @@ var kinetex = (() => {
|
|
|
5648
5734
|
return false;
|
|
5649
5735
|
if (isIPAddress(cd))
|
|
5650
5736
|
return false;
|
|
5651
|
-
|
|
5652
|
-
if (psl === rh)
|
|
5737
|
+
if (isPublicSuffix(cd))
|
|
5653
5738
|
return false;
|
|
5654
5739
|
return true;
|
|
5655
5740
|
}
|
|
@@ -7358,7 +7443,7 @@ var kinetex = (() => {
|
|
|
7358
7443
|
let cookieDomain;
|
|
7359
7444
|
let hostOnly;
|
|
7360
7445
|
if (parsed.domain !== null && parsed.domain !== "") {
|
|
7361
|
-
const cd = parsed.domain;
|
|
7446
|
+
const cd = parsed.domain.toLowerCase();
|
|
7362
7447
|
const matcher = this.domainMatcherFn ?? domainMatch;
|
|
7363
7448
|
if (!matcher(reqHost, cd))
|
|
7364
7449
|
return false;
|
|
@@ -7428,9 +7513,6 @@ var kinetex = (() => {
|
|
|
7428
7513
|
* @returns Array of matching Cookie objects (direct references into storage)
|
|
7429
7514
|
*/
|
|
7430
7515
|
getCookies(options) {
|
|
7431
|
-
if (Math.random() < 0.01) {
|
|
7432
|
-
this.clearExpired();
|
|
7433
|
-
}
|
|
7434
7516
|
const url = safeParseUrl(options.url);
|
|
7435
7517
|
if (!url)
|
|
7436
7518
|
return [];
|
|
@@ -7867,11 +7949,13 @@ var kinetex = (() => {
|
|
|
7867
7949
|
if (this.domainMatcherFn) {
|
|
7868
7950
|
return this.domainMatcherFn(reqHost, cookieDomain);
|
|
7869
7951
|
}
|
|
7870
|
-
|
|
7952
|
+
const host = reqHost.toLowerCase();
|
|
7953
|
+
const domain = cookieDomain.toLowerCase();
|
|
7954
|
+
if (host === domain)
|
|
7871
7955
|
return true;
|
|
7872
|
-
if (isIPAddress(
|
|
7956
|
+
if (isIPAddress(host))
|
|
7873
7957
|
return false;
|
|
7874
|
-
return
|
|
7958
|
+
return host.endsWith("." + domain);
|
|
7875
7959
|
}
|
|
7876
7960
|
};
|
|
7877
7961
|
}
|
|
@@ -8573,7 +8657,7 @@ var kinetex = (() => {
|
|
|
8573
8657
|
* ```ts
|
|
8574
8658
|
* const logger = createProductionLogger();
|
|
8575
8659
|
* const child = logger.child({ requestId: "req-123", userId: "user-456" });
|
|
8576
|
-
* child.logRequest(
|
|
8660
|
+
* child.logRequest("req-123", "GET", "/users", {}, null, 1); // Logs include both requestId and userId
|
|
8577
8661
|
* ```
|
|
8578
8662
|
*/
|
|
8579
8663
|
child(context) {
|
|
@@ -8686,8 +8770,23 @@ var kinetex = (() => {
|
|
|
8686
8770
|
events.push(final);
|
|
8687
8771
|
return events;
|
|
8688
8772
|
}
|
|
8689
|
-
function sleep3(ms) {
|
|
8690
|
-
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
|
+
});
|
|
8691
8790
|
}
|
|
8692
8791
|
var SSEParser, SSETransformStream, SSEClient, SSERouter, SSEServerResponse, SSEError, SSEMaxReconnectsError;
|
|
8693
8792
|
var init_sse = __esm({
|
|
@@ -9064,8 +9163,8 @@ var kinetex = (() => {
|
|
|
9064
9163
|
}
|
|
9065
9164
|
if (!cfg.reconnect)
|
|
9066
9165
|
throw err;
|
|
9067
|
-
if (cfg.maxReconnects > 0 &&
|
|
9068
|
-
throw new SSEMaxReconnectsError(
|
|
9166
|
+
if (cfg.maxReconnects > 0 && this.health.totalReconnects >= cfg.maxReconnects) {
|
|
9167
|
+
throw new SSEMaxReconnectsError(this.health.totalReconnects, cfg.url);
|
|
9069
9168
|
}
|
|
9070
9169
|
reconnectAttempt++;
|
|
9071
9170
|
this.health.totalReconnects++;
|
|
@@ -9078,25 +9177,31 @@ var kinetex = (() => {
|
|
|
9078
9177
|
clearTimeout(heartbeatTimer);
|
|
9079
9178
|
heartbeatTimer = null;
|
|
9080
9179
|
}
|
|
9081
|
-
await sleep3(delay2);
|
|
9180
|
+
await sleep3(delay2, cfg.signal);
|
|
9181
|
+
if (cfg.signal?.aborted)
|
|
9182
|
+
break;
|
|
9082
9183
|
parser.reset();
|
|
9083
9184
|
continue;
|
|
9084
9185
|
}
|
|
9085
9186
|
this.health.connected = false;
|
|
9086
9187
|
if (!cfg.reconnect)
|
|
9087
9188
|
break;
|
|
9088
|
-
if (cfg.maxReconnects > 0 &&
|
|
9089
|
-
throw new SSEMaxReconnectsError(
|
|
9189
|
+
if (cfg.maxReconnects > 0 && this.health.totalReconnects >= cfg.maxReconnects) {
|
|
9190
|
+
throw new SSEMaxReconnectsError(this.health.totalReconnects, cfg.url);
|
|
9090
9191
|
}
|
|
9091
9192
|
reconnectAttempt++;
|
|
9092
9193
|
this.health.totalReconnects++;
|
|
9093
|
-
|
|
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);
|
|
9094
9197
|
cfg.onReconnect(reconnectAttempt, delay);
|
|
9095
9198
|
if (heartbeatTimer) {
|
|
9096
9199
|
clearTimeout(heartbeatTimer);
|
|
9097
9200
|
heartbeatTimer = null;
|
|
9098
9201
|
}
|
|
9099
|
-
await sleep3(delay);
|
|
9202
|
+
await sleep3(delay, cfg.signal);
|
|
9203
|
+
if (cfg.signal?.aborted)
|
|
9204
|
+
break;
|
|
9100
9205
|
}
|
|
9101
9206
|
this.health.connected = false;
|
|
9102
9207
|
}
|
|
@@ -9515,7 +9620,8 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
9515
9620
|
fetchHeaders["content-type"] = "application/json";
|
|
9516
9621
|
const controller = new AbortController();
|
|
9517
9622
|
const timer = config.timeoutMs > 0 ? setTimeout(() => controller.abort(), config.timeoutMs) : null;
|
|
9518
|
-
|
|
9623
|
+
const onExternalAbort = () => controller.abort();
|
|
9624
|
+
signal?.addEventListener("abort", onExternalAbort, { once: true });
|
|
9519
9625
|
let response;
|
|
9520
9626
|
try {
|
|
9521
9627
|
response = await config.fetch(fetchUrl, {
|
|
@@ -9534,6 +9640,7 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
9534
9640
|
} finally {
|
|
9535
9641
|
if (timer)
|
|
9536
9642
|
clearTimeout(timer);
|
|
9643
|
+
signal?.removeEventListener("abort", onExternalAbort);
|
|
9537
9644
|
}
|
|
9538
9645
|
return parseGraphQLResponse(response, req);
|
|
9539
9646
|
}
|
|
@@ -9892,7 +9999,8 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
9892
9999
|
delete headers["content-type"];
|
|
9893
10000
|
const form = buildMultipartBody(req, uploads);
|
|
9894
10001
|
const controller = new AbortController();
|
|
9895
|
-
|
|
10002
|
+
const onExternalAbort = () => controller.abort();
|
|
10003
|
+
options.signal?.addEventListener("abort", onExternalAbort, { once: true });
|
|
9896
10004
|
this.config.onRequest(req);
|
|
9897
10005
|
let response;
|
|
9898
10006
|
try {
|
|
@@ -9906,6 +10014,8 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
9906
10014
|
const clientErr = new GraphQLClientError(err instanceof Error ? err.message : "Upload network error", "ENETWORK", void 0, req, void 0, err);
|
|
9907
10015
|
this.config.onError(clientErr, req);
|
|
9908
10016
|
throw clientErr;
|
|
10017
|
+
} finally {
|
|
10018
|
+
options.signal?.removeEventListener("abort", onExternalAbort);
|
|
9909
10019
|
}
|
|
9910
10020
|
const gqlRes = await parseGraphQLResponse(response, req);
|
|
9911
10021
|
this.config.onResponse(gqlRes, req);
|
|
@@ -9936,7 +10046,8 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
9936
10046
|
async batch(requests, options = {}) {
|
|
9937
10047
|
const headers = await buildHeaders(this.config);
|
|
9938
10048
|
const controller = new AbortController();
|
|
9939
|
-
|
|
10049
|
+
const onExternalAbort = () => controller.abort();
|
|
10050
|
+
options.signal?.addEventListener("abort", onExternalAbort, { once: true });
|
|
9940
10051
|
let response;
|
|
9941
10052
|
try {
|
|
9942
10053
|
response = await this.config.fetch(this.config.url, {
|
|
@@ -9947,6 +10058,8 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
9947
10058
|
});
|
|
9948
10059
|
} catch (err) {
|
|
9949
10060
|
throw new GraphQLClientError(err instanceof Error ? err.message : "Batch network error", "ENETWORK", void 0, requests[0], void 0, err);
|
|
10061
|
+
} finally {
|
|
10062
|
+
options.signal?.removeEventListener("abort", onExternalAbort);
|
|
9950
10063
|
}
|
|
9951
10064
|
const rawResults = sanitizeParsedJSON(await response.json());
|
|
9952
10065
|
if (!Array.isArray(rawResults)) {
|
|
@@ -10574,12 +10687,16 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
10574
10687
|
r();
|
|
10575
10688
|
return;
|
|
10576
10689
|
}
|
|
10577
|
-
const
|
|
10578
|
-
|
|
10579
|
-
signal
|
|
10580
|
-
|
|
10581
|
-
|
|
10582
|
-
|
|
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 });
|
|
10583
10700
|
});
|
|
10584
10701
|
}
|
|
10585
10702
|
function toPaginationIterator(source) {
|
|
@@ -11079,35 +11196,58 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
11079
11196
|
}
|
|
11080
11197
|
});
|
|
11081
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
|
+
};
|
|
11082
11207
|
const stream = new ReadableStream({
|
|
11083
|
-
|
|
11084
|
-
const reader = source.getReader();
|
|
11208
|
+
start(controller) {
|
|
11085
11209
|
if (options.signal?.aborted) {
|
|
11086
|
-
reader.cancel("aborted").catch(() => {
|
|
11087
|
-
});
|
|
11088
11210
|
controller.error(new DOMException("Upload aborted", "AbortError"));
|
|
11089
11211
|
return;
|
|
11090
11212
|
}
|
|
11091
|
-
|
|
11092
|
-
|
|
11213
|
+
reader = source.getReader();
|
|
11214
|
+
onUploadAbort = () => {
|
|
11215
|
+
const r = reader;
|
|
11216
|
+
reader = null;
|
|
11217
|
+
void r?.cancel("aborted").catch(() => {
|
|
11093
11218
|
});
|
|
11219
|
+
tracker.complete();
|
|
11094
11220
|
controller.error(new DOMException("Upload aborted", "AbortError"));
|
|
11095
|
-
}
|
|
11221
|
+
};
|
|
11222
|
+
options.signal?.addEventListener("abort", onUploadAbort, { once: true });
|
|
11223
|
+
},
|
|
11224
|
+
async pull(controller) {
|
|
11225
|
+
if (!reader)
|
|
11226
|
+
return;
|
|
11096
11227
|
try {
|
|
11097
|
-
|
|
11098
|
-
|
|
11099
|
-
|
|
11100
|
-
|
|
11101
|
-
|
|
11102
|
-
|
|
11103
|
-
|
|
11104
|
-
|
|
11105
|
-
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;
|
|
11106
11236
|
}
|
|
11237
|
+
tracker.update(value.byteLength);
|
|
11238
|
+
controller.enqueue(value);
|
|
11107
11239
|
} catch (err) {
|
|
11240
|
+
detach();
|
|
11108
11241
|
tracker.complete();
|
|
11109
11242
|
controller.error(err);
|
|
11110
11243
|
}
|
|
11244
|
+
},
|
|
11245
|
+
cancel(reason) {
|
|
11246
|
+
detach();
|
|
11247
|
+
const r = reader;
|
|
11248
|
+
reader = null;
|
|
11249
|
+
void r?.cancel(reason).catch(() => {
|
|
11250
|
+
});
|
|
11111
11251
|
}
|
|
11112
11252
|
});
|
|
11113
11253
|
return { stream, tracker };
|
|
@@ -11124,40 +11264,64 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
11124
11264
|
return { response, tracker };
|
|
11125
11265
|
}
|
|
11126
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
|
+
};
|
|
11127
11276
|
const trackedStream = new ReadableStream({
|
|
11128
|
-
|
|
11129
|
-
|
|
11130
|
-
|
|
11131
|
-
|
|
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 = () => {
|
|
11132
11285
|
if (aborted)
|
|
11133
11286
|
return;
|
|
11134
11287
|
aborted = true;
|
|
11135
|
-
|
|
11288
|
+
const r = reader;
|
|
11289
|
+
reader = null;
|
|
11290
|
+
void r?.cancel("aborted").catch(() => {
|
|
11136
11291
|
});
|
|
11137
11292
|
controller.error(new DOMException("Download aborted", "AbortError"));
|
|
11138
11293
|
};
|
|
11139
11294
|
options.signal?.addEventListener("abort", onAbort, { once: true });
|
|
11295
|
+
},
|
|
11296
|
+
async pull(controller) {
|
|
11297
|
+
if (!reader)
|
|
11298
|
+
return;
|
|
11140
11299
|
try {
|
|
11141
|
-
|
|
11142
|
-
|
|
11143
|
-
|
|
11144
|
-
|
|
11145
|
-
|
|
11146
|
-
|
|
11147
|
-
|
|
11148
|
-
|
|
11149
|
-
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;
|
|
11150
11308
|
}
|
|
11309
|
+
tracker.update(value.byteLength);
|
|
11310
|
+
controller.enqueue(value);
|
|
11151
11311
|
} catch (err) {
|
|
11312
|
+
detach();
|
|
11152
11313
|
if (!aborted) {
|
|
11153
11314
|
tracker.complete();
|
|
11154
11315
|
}
|
|
11155
11316
|
controller.error(err);
|
|
11156
|
-
} finally {
|
|
11157
|
-
if (!aborted) {
|
|
11158
|
-
options.signal?.removeEventListener("abort", onAbort);
|
|
11159
|
-
}
|
|
11160
11317
|
}
|
|
11318
|
+
},
|
|
11319
|
+
cancel(reason) {
|
|
11320
|
+
detach();
|
|
11321
|
+
const r = reader;
|
|
11322
|
+
reader = null;
|
|
11323
|
+
void r?.cancel(reason).catch(() => {
|
|
11324
|
+
});
|
|
11161
11325
|
}
|
|
11162
11326
|
});
|
|
11163
11327
|
const trackedResponse = new Response(trackedStream, {
|
|
@@ -11165,6 +11329,16 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
11165
11329
|
statusText: response.statusText,
|
|
11166
11330
|
headers: response.headers
|
|
11167
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
|
+
}
|
|
11168
11342
|
return { response: trackedResponse, tracker };
|
|
11169
11343
|
}
|
|
11170
11344
|
async function* streamWithProgress(stream, total, options = {}) {
|
|
@@ -11197,11 +11371,11 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
11197
11371
|
});
|
|
11198
11372
|
throw new DOMException("Stream aborted", "AbortError");
|
|
11199
11373
|
}
|
|
11374
|
+
const abortHandler = () => {
|
|
11375
|
+
reader.cancel("aborted").catch(() => {
|
|
11376
|
+
});
|
|
11377
|
+
};
|
|
11200
11378
|
if (options.signal) {
|
|
11201
|
-
const abortHandler = () => {
|
|
11202
|
-
reader.cancel("aborted").catch(() => {
|
|
11203
|
-
});
|
|
11204
|
-
};
|
|
11205
11379
|
options.signal.addEventListener("abort", abortHandler, { once: true });
|
|
11206
11380
|
}
|
|
11207
11381
|
try {
|
|
@@ -11214,6 +11388,7 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
11214
11388
|
}
|
|
11215
11389
|
} finally {
|
|
11216
11390
|
reader.releaseLock();
|
|
11391
|
+
options.signal?.removeEventListener("abort", abortHandler);
|
|
11217
11392
|
}
|
|
11218
11393
|
tracker.complete();
|
|
11219
11394
|
const totalBytes = chunks.reduce((acc, c) => acc + c.byteLength, 0);
|
|
@@ -11344,11 +11519,19 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
11344
11519
|
downloadTracker.update(e.loaded - downloadTracker.bytesLoaded);
|
|
11345
11520
|
});
|
|
11346
11521
|
}
|
|
11347
|
-
|
|
11522
|
+
const onAbort = () => {
|
|
11348
11523
|
xhr.abort();
|
|
11349
11524
|
reject(new DOMException("Request aborted", "AbortError"));
|
|
11350
|
-
}
|
|
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
|
+
}
|
|
11351
11533
|
xhr.addEventListener("load", () => {
|
|
11534
|
+
detach();
|
|
11352
11535
|
downloadTracker.complete();
|
|
11353
11536
|
const rawHeaders = xhr.getAllResponseHeaders();
|
|
11354
11537
|
const headers = {};
|
|
@@ -11366,11 +11549,17 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
11366
11549
|
});
|
|
11367
11550
|
});
|
|
11368
11551
|
xhr.addEventListener("error", () => {
|
|
11552
|
+
detach();
|
|
11369
11553
|
reject(new TypeError("Network request failed"));
|
|
11370
11554
|
});
|
|
11371
11555
|
xhr.addEventListener("timeout", () => {
|
|
11556
|
+
detach();
|
|
11372
11557
|
reject(new TypeError("Request timed out"));
|
|
11373
11558
|
});
|
|
11559
|
+
xhr.addEventListener("abort", () => {
|
|
11560
|
+
detach();
|
|
11561
|
+
reject(new DOMException("Request aborted", "AbortError"));
|
|
11562
|
+
});
|
|
11374
11563
|
xhr.send(options.body ?? null);
|
|
11375
11564
|
});
|
|
11376
11565
|
}
|
|
@@ -11522,6 +11711,11 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
11522
11711
|
if (effectiveWindowMs <= 0) {
|
|
11523
11712
|
this.inflight.delete(key);
|
|
11524
11713
|
} else {
|
|
11714
|
+
const stale = this.timeouts.get(key);
|
|
11715
|
+
if (stale !== void 0) {
|
|
11716
|
+
clearTimeout(stale);
|
|
11717
|
+
this.timeouts.delete(key);
|
|
11718
|
+
}
|
|
11525
11719
|
const timeoutId = setTimeout(() => {
|
|
11526
11720
|
this.inflight.delete(key);
|
|
11527
11721
|
this.timeouts.delete(key);
|
|
@@ -11563,13 +11757,6 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
11563
11757
|
get keys() {
|
|
11564
11758
|
return [...this.inflight.keys()];
|
|
11565
11759
|
}
|
|
11566
|
-
/**
|
|
11567
|
-
* Get comprehensive deduplication statistics.
|
|
11568
|
-
* NOTE: inFlightCount and trackedKeys reflect snapshot time; entries may
|
|
11569
|
-
* resolve asynchronously between sampling and return (non-blocking, acceptable).
|
|
11570
|
-
*
|
|
11571
|
-
* @returns Snapshot of hits, misses, hit rate, and tracked entries
|
|
11572
|
-
*/
|
|
11573
11760
|
/**
|
|
11574
11761
|
* Get comprehensive deduplication statistics.
|
|
11575
11762
|
*
|
|
@@ -11712,9 +11899,16 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
11712
11899
|
}
|
|
11713
11900
|
/** Snapshot of all counters — suitable for logging or dashboards. */
|
|
11714
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
|
+
}
|
|
11715
11909
|
return {
|
|
11716
11910
|
state: this._state,
|
|
11717
|
-
failureCount
|
|
11911
|
+
failureCount,
|
|
11718
11912
|
successCount: this._consecutiveSucc,
|
|
11719
11913
|
lastFailureAt: this._lastFailureAt,
|
|
11720
11914
|
lastSuccessAt: this._lastSuccessAt,
|
|
@@ -11740,6 +11934,7 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
11740
11934
|
this.cfg.onRejected?.(snap);
|
|
11741
11935
|
return Promise.reject(new CircuitOpenError(this.key, snap));
|
|
11742
11936
|
}
|
|
11937
|
+
let heldProbe = false;
|
|
11743
11938
|
if (this._state === "HALF_OPEN") {
|
|
11744
11939
|
if (this._inFlightProbes >= this.halfOpenConcurrency) {
|
|
11745
11940
|
this._totalRejected++;
|
|
@@ -11748,15 +11943,16 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
11748
11943
|
return Promise.reject(new CircuitOpenError(this.key, snap));
|
|
11749
11944
|
}
|
|
11750
11945
|
this._inFlightProbes++;
|
|
11946
|
+
heldProbe = true;
|
|
11751
11947
|
}
|
|
11752
11948
|
this._totalRequests++;
|
|
11753
|
-
return
|
|
11754
|
-
if (
|
|
11949
|
+
return Promise.resolve().then(fn).then((result) => {
|
|
11950
|
+
if (heldProbe)
|
|
11755
11951
|
this._inFlightProbes = Math.max(0, this._inFlightProbes - 1);
|
|
11756
11952
|
this._recordSuccess();
|
|
11757
11953
|
return result;
|
|
11758
11954
|
}, (err) => {
|
|
11759
|
-
if (
|
|
11955
|
+
if (heldProbe)
|
|
11760
11956
|
this._inFlightProbes = Math.max(0, this._inFlightProbes - 1);
|
|
11761
11957
|
if (this._isCountableFailure(err)) {
|
|
11762
11958
|
this._recordFailure();
|
|
@@ -12027,6 +12223,10 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
12027
12223
|
__publicField(this, "_openWaiters", []);
|
|
12028
12224
|
__publicField(this, "_correlations", /* @__PURE__ */ new Map());
|
|
12029
12225
|
__publicField(this, "_aborted", false);
|
|
12226
|
+
/** Optional external abort signal from config (listener detached on close). */
|
|
12227
|
+
__publicField(this, "_externalSignal", null);
|
|
12228
|
+
/** Bound abort handler for the optional external `cfg.signal` (removed on close). */
|
|
12229
|
+
__publicField(this, "_onExternalAbort", () => this.close(1e3, "AbortSignal aborted"));
|
|
12030
12230
|
// ── Async iterator ──────────────────────────────────────────────────────
|
|
12031
12231
|
__publicField(this, "_iterQueue", []);
|
|
12032
12232
|
__publicField(this, "_iterWaiter", null);
|
|
@@ -12090,7 +12290,8 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
12090
12290
|
this._rooms.push({ room: r, joinedAt: 0 });
|
|
12091
12291
|
}
|
|
12092
12292
|
}
|
|
12093
|
-
|
|
12293
|
+
this._externalSignal = cfg.signal ?? null;
|
|
12294
|
+
this._externalSignal?.addEventListener("abort", this._onExternalAbort, {
|
|
12094
12295
|
once: true
|
|
12095
12296
|
});
|
|
12096
12297
|
}
|
|
@@ -12171,6 +12372,8 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
12171
12372
|
*/
|
|
12172
12373
|
close(code = 1e3, reason = "Client closed") {
|
|
12173
12374
|
this._aborted = true;
|
|
12375
|
+
this._externalSignal?.removeEventListener("abort", this._onExternalAbort);
|
|
12376
|
+
this._externalSignal = null;
|
|
12174
12377
|
this._stopAll();
|
|
12175
12378
|
for (const w of this._drainWaiters.splice(0))
|
|
12176
12379
|
w();
|
|
@@ -12712,6 +12915,10 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
12712
12915
|
return this._maxReconnects === 0 || this._reconnAttempt < this._maxReconnects;
|
|
12713
12916
|
}
|
|
12714
12917
|
_scheduleRecon() {
|
|
12918
|
+
if (this._reconnTimer) {
|
|
12919
|
+
clearTimeout(this._reconnTimer);
|
|
12920
|
+
this._reconnTimer = null;
|
|
12921
|
+
}
|
|
12715
12922
|
this._state = "RECONNECTING";
|
|
12716
12923
|
this._reconnAttempt++;
|
|
12717
12924
|
const exp = this._reconnectBaseMs * Math.pow(2, this._reconnAttempt - 1);
|
|
@@ -12719,13 +12926,11 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
12719
12926
|
const delay = Math.floor(capped * (1 + this._reconnectJitter * Math.random()));
|
|
12720
12927
|
this._cbReconnect?.(this._reconnAttempt, delay);
|
|
12721
12928
|
this._reconnTimer = setTimeout(() => {
|
|
12929
|
+
this._reconnTimer = null;
|
|
12722
12930
|
if (!this._aborted)
|
|
12723
12931
|
this._doConnect(true).catch(() => {
|
|
12724
12932
|
});
|
|
12725
12933
|
}, delay);
|
|
12726
|
-
if (typeof this._reconnTimer === "object" && this._reconnTimer !== null && "unref" in this._reconnTimer) {
|
|
12727
|
-
this._reconnTimer.unref();
|
|
12728
|
-
}
|
|
12729
12934
|
}
|
|
12730
12935
|
_tx(data) {
|
|
12731
12936
|
const ws = this._ws;
|
|
@@ -12893,12 +13098,17 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
12893
13098
|
init_cache();
|
|
12894
13099
|
|
|
12895
13100
|
// dist/esm/interceptors.js
|
|
13101
|
+
init_cache();
|
|
12896
13102
|
var _idSeq = 0;
|
|
12897
13103
|
function nextId() {
|
|
12898
13104
|
return `interceptor_${++_idSeq}`;
|
|
12899
13105
|
}
|
|
12900
|
-
function
|
|
12901
|
-
|
|
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);
|
|
12902
13112
|
}
|
|
12903
13113
|
var InterceptorManager = class {
|
|
12904
13114
|
constructor() {
|
|
@@ -12916,7 +13126,7 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
12916
13126
|
*/
|
|
12917
13127
|
useRequest(fn, opts = {}) {
|
|
12918
13128
|
const id = opts.id ?? nextId();
|
|
12919
|
-
this.requestInterceptors
|
|
13129
|
+
insertByPriority(this.requestInterceptors, {
|
|
12920
13130
|
id,
|
|
12921
13131
|
priority: opts.priority ?? 0,
|
|
12922
13132
|
once: opts.once ?? false,
|
|
@@ -12934,7 +13144,7 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
12934
13144
|
*/
|
|
12935
13145
|
useResponse(fn, opts = {}) {
|
|
12936
13146
|
const id = opts.id ?? nextId();
|
|
12937
|
-
this.responseInterceptors
|
|
13147
|
+
insertByPriority(this.responseInterceptors, {
|
|
12938
13148
|
id,
|
|
12939
13149
|
priority: opts.priority ?? 0,
|
|
12940
13150
|
once: opts.once ?? false,
|
|
@@ -12952,7 +13162,7 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
12952
13162
|
*/
|
|
12953
13163
|
useError(fn, opts = {}) {
|
|
12954
13164
|
const id = opts.id ?? nextId();
|
|
12955
|
-
this.errorInterceptors
|
|
13165
|
+
insertByPriority(this.errorInterceptors, {
|
|
12956
13166
|
id,
|
|
12957
13167
|
priority: opts.priority ?? 0,
|
|
12958
13168
|
once: opts.once ?? false,
|
|
@@ -13029,7 +13239,7 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
13029
13239
|
async _run(ctx, dispatcher) {
|
|
13030
13240
|
ctx.attempt++;
|
|
13031
13241
|
const toEject = /* @__PURE__ */ new Set();
|
|
13032
|
-
for (const interceptor of
|
|
13242
|
+
for (const interceptor of this.requestInterceptors) {
|
|
13033
13243
|
if (ctx.aborted)
|
|
13034
13244
|
break;
|
|
13035
13245
|
if (interceptor.condition && !interceptor.condition(ctx))
|
|
@@ -13069,7 +13279,7 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
13069
13279
|
}
|
|
13070
13280
|
async _runResponsePhase(ctx, dispatcher) {
|
|
13071
13281
|
const toEject = /* @__PURE__ */ new Set();
|
|
13072
|
-
for (const interceptor of
|
|
13282
|
+
for (const interceptor of this.responseInterceptors) {
|
|
13073
13283
|
if (ctx.aborted)
|
|
13074
13284
|
break;
|
|
13075
13285
|
if (interceptor.condition && !interceptor.condition(ctx))
|
|
@@ -13107,7 +13317,7 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
13107
13317
|
}
|
|
13108
13318
|
async _runErrorPhase(ctx, dispatcher) {
|
|
13109
13319
|
const toEject = /* @__PURE__ */ new Set();
|
|
13110
|
-
for (const interceptor of
|
|
13320
|
+
for (const interceptor of this.errorInterceptors) {
|
|
13111
13321
|
if (interceptor.condition && !interceptor.condition(ctx))
|
|
13112
13322
|
continue;
|
|
13113
13323
|
let result;
|
|
@@ -13310,27 +13520,33 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
13310
13520
|
}, ms);
|
|
13311
13521
|
const existing = ctx.request.signal;
|
|
13312
13522
|
if (existing) {
|
|
13313
|
-
|
|
13523
|
+
const onExistingAbort = () => {
|
|
13314
13524
|
clearTimeout(timer);
|
|
13315
13525
|
controller.abort(existing.reason);
|
|
13316
|
-
}
|
|
13526
|
+
};
|
|
13527
|
+
existing.addEventListener("abort", onExistingAbort, { once: true });
|
|
13528
|
+
ctx.store.set(TIMEOUT_SIGNAL_KEY, { existing, onExistingAbort });
|
|
13317
13529
|
}
|
|
13318
13530
|
ctx.request = { ...ctx.request, signal: controller.signal };
|
|
13319
13531
|
ctx.store.set(TIMEOUT_TIMER_KEY, timer);
|
|
13320
13532
|
};
|
|
13321
|
-
const
|
|
13533
|
+
const cleanupTimeout = (ctx) => {
|
|
13322
13534
|
const timer = ctx.store.get(TIMEOUT_TIMER_KEY);
|
|
13323
13535
|
if (timer) {
|
|
13324
13536
|
clearTimeout(timer);
|
|
13325
13537
|
ctx.store.delete(TIMEOUT_TIMER_KEY);
|
|
13326
13538
|
}
|
|
13539
|
+
const merged = ctx.store.get(TIMEOUT_SIGNAL_KEY);
|
|
13540
|
+
if (merged) {
|
|
13541
|
+
merged.existing.removeEventListener("abort", merged.onExistingAbort);
|
|
13542
|
+
ctx.store.delete(TIMEOUT_SIGNAL_KEY);
|
|
13543
|
+
}
|
|
13544
|
+
};
|
|
13545
|
+
const responseInterceptor = (ctx) => {
|
|
13546
|
+
cleanupTimeout(ctx);
|
|
13327
13547
|
};
|
|
13328
13548
|
const errorInterceptor = (ctx) => {
|
|
13329
|
-
|
|
13330
|
-
if (timer) {
|
|
13331
|
-
clearTimeout(timer);
|
|
13332
|
-
ctx.store.delete(TIMEOUT_TIMER_KEY);
|
|
13333
|
-
}
|
|
13549
|
+
cleanupTimeout(ctx);
|
|
13334
13550
|
};
|
|
13335
13551
|
return {
|
|
13336
13552
|
id: "timeout",
|
|
@@ -13340,6 +13556,7 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
13340
13556
|
};
|
|
13341
13557
|
}
|
|
13342
13558
|
var TIMEOUT_TIMER_KEY = /* @__PURE__ */ Symbol("timeoutTimer");
|
|
13559
|
+
var TIMEOUT_SIGNAL_KEY = /* @__PURE__ */ Symbol("timeoutSignal");
|
|
13343
13560
|
var TimeoutError2 = class extends Error {
|
|
13344
13561
|
constructor(message, timeoutMs) {
|
|
13345
13562
|
super(message);
|
|
@@ -13512,13 +13729,15 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
13512
13729
|
var CACHE_STALE_KEY = /* @__PURE__ */ Symbol("cacheStale");
|
|
13513
13730
|
function createDedupeInterceptor() {
|
|
13514
13731
|
const inflight = /* @__PURE__ */ new Map();
|
|
13515
|
-
function key(req) {
|
|
13516
|
-
|
|
13732
|
+
async function key(req) {
|
|
13733
|
+
const authFp = await getAuthFingerprint(req.headers ?? {});
|
|
13734
|
+
return `${req.method.toUpperCase()}:${req.url}${authFp ? ":" + authFp : ""}`;
|
|
13517
13735
|
}
|
|
13518
|
-
const requestInterceptor = (ctx) => {
|
|
13736
|
+
const requestInterceptor = async (ctx) => {
|
|
13519
13737
|
if (ctx.request.method.toUpperCase() !== "GET" && ctx.request.method.toUpperCase() !== "HEAD")
|
|
13520
13738
|
return;
|
|
13521
|
-
const k = key(ctx.request);
|
|
13739
|
+
const k = await key(ctx.request);
|
|
13740
|
+
ctx.store.set(DEDUPE_KEY, k);
|
|
13522
13741
|
const slot = inflight.get(k);
|
|
13523
13742
|
if (!slot) {
|
|
13524
13743
|
inflight.set(k, {
|
|
@@ -13527,38 +13746,59 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
13527
13746
|
});
|
|
13528
13747
|
return;
|
|
13529
13748
|
}
|
|
13530
|
-
ctx.store.set(DEDUPE_QUEUED_KEY, k);
|
|
13531
13749
|
return new Promise((resolve, reject) => {
|
|
13532
|
-
|
|
13750
|
+
const signal = ctx.request.signal;
|
|
13751
|
+
const waiter = {
|
|
13533
13752
|
resolve: (res) => resolve(res),
|
|
13534
|
-
reject: (err) => reject(err)
|
|
13753
|
+
reject: (err) => reject(err),
|
|
13535
13754
|
// Properly reject instead of throwing
|
|
13536
|
-
|
|
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);
|
|
13537
13769
|
});
|
|
13538
13770
|
};
|
|
13539
13771
|
const responseInterceptor = (ctx) => {
|
|
13540
13772
|
if (!ctx.response)
|
|
13541
13773
|
return;
|
|
13542
|
-
const k =
|
|
13774
|
+
const k = ctx.store.get(DEDUPE_KEY);
|
|
13775
|
+
if (!k)
|
|
13776
|
+
return;
|
|
13543
13777
|
const slot = inflight.get(k);
|
|
13544
13778
|
if (!slot)
|
|
13545
13779
|
return;
|
|
13546
13780
|
inflight.delete(k);
|
|
13547
|
-
for (const w of slot.waiters)
|
|
13781
|
+
for (const w of slot.waiters.splice(0)) {
|
|
13782
|
+
w.cleanup();
|
|
13548
13783
|
w.resolve(ctx.response);
|
|
13784
|
+
}
|
|
13549
13785
|
};
|
|
13550
13786
|
const errorInterceptor = (ctx) => {
|
|
13551
|
-
const k =
|
|
13787
|
+
const k = ctx.store.get(DEDUPE_KEY);
|
|
13788
|
+
if (!k)
|
|
13789
|
+
return;
|
|
13552
13790
|
const slot = inflight.get(k);
|
|
13553
13791
|
if (!slot)
|
|
13554
13792
|
return;
|
|
13555
13793
|
inflight.delete(k);
|
|
13556
|
-
for (const w of slot.waiters)
|
|
13794
|
+
for (const w of slot.waiters.splice(0)) {
|
|
13795
|
+
w.cleanup();
|
|
13557
13796
|
w.reject(ctx.error);
|
|
13797
|
+
}
|
|
13558
13798
|
};
|
|
13559
13799
|
return { requestInterceptor, responseInterceptor, errorInterceptor };
|
|
13560
13800
|
}
|
|
13561
|
-
var
|
|
13801
|
+
var DEDUPE_KEY = /* @__PURE__ */ Symbol("dedupeKey");
|
|
13562
13802
|
var RATE_LIMIT_DEFAULTS = {
|
|
13563
13803
|
limit: 60,
|
|
13564
13804
|
windowMs: 6e4,
|
|
@@ -13924,7 +14164,7 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
13924
14164
|
const role = roles[0]?.trim();
|
|
13925
14165
|
if (!role)
|
|
13926
14166
|
throw new NetworkError("No IAM role found in IMDS response");
|
|
13927
|
-
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);
|
|
13928
14168
|
if (!credsRes.ok)
|
|
13929
14169
|
throw new NetworkError(`IMDS credentials fetch failed: ${credsRes.status}`);
|
|
13930
14170
|
const data = await credsRes.json();
|
|
@@ -14925,9 +15165,24 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
14925
15165
|
const response = await computeDigestResponse(challenge, username, password, method, uri, cnonce, nc);
|
|
14926
15166
|
return formatDigestAuth(challenge, username, response, uri, cnonce, nc);
|
|
14927
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
|
+
}
|
|
14928
15181
|
|
|
14929
15182
|
// dist/esm/client.js
|
|
14930
15183
|
init_core();
|
|
15184
|
+
init_core();
|
|
15185
|
+
var DEFAULT_MAX_REDIRECTS = 20;
|
|
14931
15186
|
var DEFAULT_RETRY = {
|
|
14932
15187
|
maxRetries: 3,
|
|
14933
15188
|
baseDelayMs: 300,
|
|
@@ -15046,6 +15301,59 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
15046
15301
|
"passwd",
|
|
15047
15302
|
"secret"
|
|
15048
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
|
+
}
|
|
15049
15357
|
function redactHARHeader(name, value) {
|
|
15050
15358
|
return HAR_REDACT_HEADERS.has(name.toLowerCase()) ? { name, value: "***REDACTED***" } : { name, value };
|
|
15051
15359
|
}
|
|
@@ -15081,9 +15389,9 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
15081
15389
|
let receiveMs = 0;
|
|
15082
15390
|
try {
|
|
15083
15391
|
if (typeof performance !== "undefined" && typeof performance.getEntriesByType === "function") {
|
|
15084
|
-
const entries = performance.getEntriesByType("resource");
|
|
15085
|
-
const entry2 = entries.
|
|
15086
|
-
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) {
|
|
15087
15395
|
sendMs = Math.max(0, entry2.responseStart - entry2.requestStart);
|
|
15088
15396
|
receiveMs = Math.max(0, entry2.responseEnd - entry2.responseStart);
|
|
15089
15397
|
waitMs = Math.max(0, total - sendMs - receiveMs);
|
|
@@ -15098,12 +15406,16 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
15098
15406
|
time: total,
|
|
15099
15407
|
request: {
|
|
15100
15408
|
method: req.method,
|
|
15101
|
-
|
|
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),
|
|
15102
15414
|
httpVersion: res.httpVersion,
|
|
15103
15415
|
headers: Object.entries(req.headers).map(([name, value]) => redactHARHeader(name, value)),
|
|
15104
15416
|
queryString: (() => {
|
|
15105
15417
|
try {
|
|
15106
|
-
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]) => ({
|
|
15107
15419
|
name,
|
|
15108
15420
|
value
|
|
15109
15421
|
}));
|
|
@@ -15131,9 +15443,12 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
15131
15443
|
content: {
|
|
15132
15444
|
size: res.rawBody?.byteLength ?? 0,
|
|
15133
15445
|
mimeType: res.headers["content-type"] ?? "application/octet-stream",
|
|
15134
|
-
|
|
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) } : {}
|
|
15135
15449
|
},
|
|
15136
|
-
|
|
15450
|
+
// The Location header can itself carry a signed URL — redact it too.
|
|
15451
|
+
redirectURL: res.headers["location"] ? redactHARUrl(res.headers["location"]) : "",
|
|
15137
15452
|
bodySize: res.rawBody?.byteLength ?? 0
|
|
15138
15453
|
},
|
|
15139
15454
|
timings: {
|
|
@@ -15225,22 +15540,25 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
15225
15540
|
}
|
|
15226
15541
|
return { ...req, headers };
|
|
15227
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
|
+
}
|
|
15228
15557
|
var CROSS_ORIGIN_STRIP_HEADERS = /* @__PURE__ */ new Set([
|
|
15229
|
-
|
|
15230
|
-
|
|
15231
|
-
|
|
15232
|
-
|
|
15233
|
-
"x-auth-token",
|
|
15234
|
-
"x-access-token",
|
|
15235
|
-
"x-refresh-token",
|
|
15236
|
-
"x-csrf-token",
|
|
15237
|
-
"x-session-id",
|
|
15238
|
-
"x-session-token",
|
|
15239
|
-
"x-secret",
|
|
15240
|
-
"x-secret-key",
|
|
15241
|
-
"x-private-key",
|
|
15242
|
-
"api-key",
|
|
15243
|
-
"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.
|
|
15244
15562
|
"www-authenticate"
|
|
15245
15563
|
]);
|
|
15246
15564
|
function redactUserInfo(url) {
|
|
@@ -15520,6 +15838,7 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
15520
15838
|
}
|
|
15521
15839
|
if (config.auth?.type === "digest") {
|
|
15522
15840
|
const digestConfig = config.auth;
|
|
15841
|
+
const digestAuthorizer = createDigestAuthorizer();
|
|
15523
15842
|
this.interceptors.addResponse(async (ctx) => {
|
|
15524
15843
|
if (!ctx.response)
|
|
15525
15844
|
return;
|
|
@@ -15531,8 +15850,9 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
15531
15850
|
if (ctx.request.meta.__digestRetried)
|
|
15532
15851
|
return;
|
|
15533
15852
|
const method = ctx.request.method;
|
|
15534
|
-
const
|
|
15535
|
-
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);
|
|
15536
15856
|
return {
|
|
15537
15857
|
...ctx.request,
|
|
15538
15858
|
headers: { ...ctx.request.headers, authorization: authHeader },
|
|
@@ -15628,22 +15948,24 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
15628
15948
|
const errEject = this.useError(async (ctx) => {
|
|
15629
15949
|
if (!ctx.error)
|
|
15630
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);
|
|
15631
15960
|
const hookErr = {
|
|
15632
15961
|
error: ctx.error,
|
|
15633
|
-
request:
|
|
15634
|
-
|
|
15635
|
-
method: ctx.request.method,
|
|
15636
|
-
headers: ctx.request.headers,
|
|
15637
|
-
body: ctx.request.body,
|
|
15638
|
-
signal: ctx.request.signal,
|
|
15639
|
-
meta: ctx.request.meta
|
|
15640
|
-
},
|
|
15641
|
-
response: null,
|
|
15962
|
+
request: hookReq,
|
|
15963
|
+
response: errResponse,
|
|
15642
15964
|
attempt: ctx.attempt
|
|
15643
15965
|
};
|
|
15644
15966
|
const hookCtx = {
|
|
15645
15967
|
request: hookErr.request,
|
|
15646
|
-
response:
|
|
15968
|
+
response: errResponse,
|
|
15647
15969
|
error: ctx.error,
|
|
15648
15970
|
startedAt: ctx.startedAt,
|
|
15649
15971
|
attempt: ctx.attempt,
|
|
@@ -16143,7 +16465,11 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
16143
16465
|
} else if (options.body instanceof ReadableStream) {
|
|
16144
16466
|
throw new KinetexError(`maxRequestSize cannot be enforced for ReadableStream bodies \u2014 pass maxRequestSize: 0 to opt out, or buffer the body first`, "EVALIDATION");
|
|
16145
16467
|
} else if (options.body && typeof options.body === "object") {
|
|
16146
|
-
|
|
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
|
+
}
|
|
16147
16473
|
}
|
|
16148
16474
|
if (bodySize2 > maxRequestSize) {
|
|
16149
16475
|
throw new KinetexError(`Request body size ${bodySize2} bytes exceeds limit of ${maxRequestSize} bytes`, "EVALIDATION");
|
|
@@ -16151,10 +16477,22 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
16151
16477
|
}
|
|
16152
16478
|
let req = {
|
|
16153
16479
|
url: fullUrl,
|
|
16154
|
-
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,
|
|
16155
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.
|
|
16156
16489
|
body: options.body ?? null,
|
|
16157
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 } : {},
|
|
16158
16496
|
meta: { ...options.meta },
|
|
16159
16497
|
httpVersion: options.httpVersion ?? this.cfg.httpVersion ?? "HTTP/2"
|
|
16160
16498
|
};
|
|
@@ -16165,6 +16503,12 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
16165
16503
|
body: JSON.stringify(req.body)
|
|
16166
16504
|
};
|
|
16167
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
|
+
}
|
|
16168
16512
|
const auth = options.auth !== false ? options.auth ?? this.cfg.auth : void 0;
|
|
16169
16513
|
if (auth)
|
|
16170
16514
|
req = await applyAuth(req, auth);
|
|
@@ -16177,31 +16521,44 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
16177
16521
|
req = { ...req, headers: { ...req.headers, cookie: cookieHeader } };
|
|
16178
16522
|
}
|
|
16179
16523
|
let _otelSpan = null;
|
|
16180
|
-
|
|
16181
|
-
|
|
16182
|
-
|
|
16183
|
-
|
|
16184
|
-
|
|
16185
|
-
|
|
16186
|
-
|
|
16187
|
-
|
|
16188
|
-
|
|
16189
|
-
|
|
16190
|
-
|
|
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
|
+
};
|
|
16191
16550
|
}
|
|
16192
|
-
|
|
16193
|
-
|
|
16194
|
-
|
|
16195
|
-
|
|
16196
|
-
|
|
16197
|
-
|
|
16198
|
-
|
|
16199
|
-
|
|
16200
|
-
|
|
16201
|
-
|
|
16202
|
-
|
|
16203
|
-
meta: { ...req.meta, spanId }
|
|
16204
|
-
};
|
|
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;
|
|
16205
16562
|
}
|
|
16206
16563
|
let _cbOrigin;
|
|
16207
16564
|
if (this._circuitBreakerKeyFn) {
|
|
@@ -16218,8 +16575,11 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
16218
16575
|
}
|
|
16219
16576
|
}
|
|
16220
16577
|
const _execFactory = () => this._executeWithRetry(req, retryCfg, timeoutMs, options, startMs, wallClockMs);
|
|
16221
|
-
|
|
16222
|
-
|
|
16578
|
+
let _dedupKey = "";
|
|
16579
|
+
if (this._dedup) {
|
|
16580
|
+
const authFp = await getAuthFingerprint(req.headers ?? {});
|
|
16581
|
+
_dedupKey = `${req.method}:${req.url}${authFp ? ":" + authFp : ""}`;
|
|
16582
|
+
}
|
|
16223
16583
|
const _dedupedFactory = this._dedup ? () => this._dedup.execute(req.method, _dedupKey, _execFactory).then((r) => r) : _execFactory;
|
|
16224
16584
|
const _guardedFactory = this._circuitBreakers ? () => this._circuitBreakers.execute(_cbOrigin, _dedupedFactory).then((r) => r) : _dedupedFactory;
|
|
16225
16585
|
try {
|
|
@@ -16257,7 +16617,10 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
16257
16617
|
while (true) {
|
|
16258
16618
|
attempt++;
|
|
16259
16619
|
if (req.signal?.aborted) {
|
|
16260
|
-
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 });
|
|
16261
16624
|
}
|
|
16262
16625
|
try {
|
|
16263
16626
|
const res = await this._executeOnce(req, timeout, options, startMs, attempt, wallClockMs, retryCfg);
|
|
@@ -16283,6 +16646,15 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
16283
16646
|
}
|
|
16284
16647
|
return res;
|
|
16285
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
|
+
}
|
|
16286
16658
|
if (retryCfg && attempt <= retryCfg.maxRetries) {
|
|
16287
16659
|
const retryCtx = {
|
|
16288
16660
|
request: req,
|
|
@@ -16317,11 +16689,22 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
16317
16689
|
// intermediate redirect responses. When a cookie jar is active we must follow
|
|
16318
16690
|
// redirects ourselves one hop at a time so we can capture cookies at each step.
|
|
16319
16691
|
/**
|
|
16320
|
-
* Follow redirects manually, one hop at a time
|
|
16321
|
-
*
|
|
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.
|
|
16322
16704
|
*/
|
|
16323
16705
|
async _sendFollowingRedirects(req, timeout, jar, appliedAuth) {
|
|
16324
|
-
const
|
|
16706
|
+
const maxRedirects = Math.max(0, req.maxRedirects ?? DEFAULT_MAX_REDIRECTS);
|
|
16707
|
+
const followRedirects = req.followRedirects !== false && maxRedirects > 0;
|
|
16325
16708
|
let currentReq = { ...req, redirect: "manual" };
|
|
16326
16709
|
const origin0 = (() => {
|
|
16327
16710
|
try {
|
|
@@ -16331,7 +16714,7 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
16331
16714
|
}
|
|
16332
16715
|
})();
|
|
16333
16716
|
const visited = /* @__PURE__ */ new Set();
|
|
16334
|
-
for (let hop = 0; hop <=
|
|
16717
|
+
for (let hop = 0; hop <= maxRedirects; hop++) {
|
|
16335
16718
|
if (hop > 0 && appliedAuth) {
|
|
16336
16719
|
const sameOrigin = (() => {
|
|
16337
16720
|
try {
|
|
@@ -16374,11 +16757,13 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
16374
16757
|
});
|
|
16375
16758
|
}
|
|
16376
16759
|
visited.add(raw.url);
|
|
16377
|
-
jar
|
|
16760
|
+
jar?.processResponseHeaders(raw.headers, {
|
|
16378
16761
|
url: raw.url
|
|
16379
16762
|
});
|
|
16380
|
-
if (
|
|
16381
|
-
|
|
16763
|
+
if (!followRedirects)
|
|
16764
|
+
return { ...raw, redirected: true };
|
|
16765
|
+
if (hop === maxRedirects) {
|
|
16766
|
+
throw new KinetexError(`Too many redirects (exceeded ${maxRedirects})`, "ENETWORK", {
|
|
16382
16767
|
request: req
|
|
16383
16768
|
});
|
|
16384
16769
|
}
|
|
@@ -16397,6 +16782,12 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
16397
16782
|
if (protocol !== "http:" && protocol !== "https:") {
|
|
16398
16783
|
throw new KinetexError(`Unsafe redirect to ${protocol} detected \u2014 only HTTP(S) allowed`, "ENETWORK", { request: req });
|
|
16399
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
|
+
}
|
|
16400
16791
|
} catch (err) {
|
|
16401
16792
|
if (err instanceof KinetexError)
|
|
16402
16793
|
throw err;
|
|
@@ -16407,21 +16798,30 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
16407
16798
|
}
|
|
16408
16799
|
const nextMethod = raw.status === 301 || raw.status === 302 || raw.status === 303 ? "GET" : currentReq.method;
|
|
16409
16800
|
const nextBody = nextMethod === "GET" || nextMethod === "HEAD" ? null : currentReq.body;
|
|
16410
|
-
const cookieHeader = jar.getCookieHeader({ url: nextUrl, http: true });
|
|
16411
16801
|
const nextHeaders = { ...currentReq.headers };
|
|
16412
|
-
|
|
16413
|
-
nextHeaders["cookie"] = cookieHeader;
|
|
16414
|
-
} else {
|
|
16415
|
-
delete nextHeaders["cookie"];
|
|
16416
|
-
}
|
|
16802
|
+
let crossOrigin = false;
|
|
16417
16803
|
try {
|
|
16418
|
-
|
|
16419
|
-
for (const h of CROSS_ORIGIN_STRIP_HEADERS) {
|
|
16420
|
-
delete nextHeaders[h];
|
|
16421
|
-
}
|
|
16422
|
-
}
|
|
16804
|
+
crossOrigin = new URL(nextUrl).origin !== new URL(currentReq.url).origin;
|
|
16423
16805
|
} catch {
|
|
16424
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
|
+
}
|
|
16425
16825
|
currentReq = {
|
|
16426
16826
|
...currentReq,
|
|
16427
16827
|
url: nextUrl,
|
|
@@ -16432,7 +16832,7 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
16432
16832
|
};
|
|
16433
16833
|
continue;
|
|
16434
16834
|
}
|
|
16435
|
-
return raw;
|
|
16835
|
+
return hop > 0 ? { ...raw, redirected: true } : raw;
|
|
16436
16836
|
}
|
|
16437
16837
|
throw new KinetexError("Redirect loop", "ENETWORK", { request: req });
|
|
16438
16838
|
}
|
|
@@ -16519,7 +16919,10 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
16519
16919
|
}
|
|
16520
16920
|
}
|
|
16521
16921
|
} finally {
|
|
16522
|
-
|
|
16922
|
+
try {
|
|
16923
|
+
(await this.getCache())?.clearSWRInFlight(cacheReq);
|
|
16924
|
+
} catch {
|
|
16925
|
+
}
|
|
16523
16926
|
}
|
|
16524
16927
|
})();
|
|
16525
16928
|
}
|
|
@@ -16597,15 +17000,17 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
16597
17000
|
...req,
|
|
16598
17001
|
headers: {
|
|
16599
17002
|
...req.headers,
|
|
16600
|
-
"accept-encoding":
|
|
17003
|
+
"accept-encoding": DEFAULT_ACCEPT_ENCODING
|
|
16601
17004
|
}
|
|
16602
17005
|
};
|
|
16603
17006
|
}
|
|
16604
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);
|
|
16605
17010
|
this._trace(_traceId, "transport_send", "start", startMs, attempt);
|
|
16606
17011
|
let raw;
|
|
16607
17012
|
try {
|
|
16608
|
-
raw =
|
|
17013
|
+
raw = needsManualRedirects ? await this._sendFollowingRedirects(req, timeout, dispatchJar ?? void 0, effectiveAuth) : await sendWithTimeout(this.transport, req, timeout);
|
|
16609
17014
|
} catch (err) {
|
|
16610
17015
|
if (_uploadStreamForCleanup) {
|
|
16611
17016
|
try {
|
|
@@ -16649,9 +17054,10 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
16649
17054
|
},
|
|
16650
17055
|
...req.signal !== null ? { signal: req.signal } : {}
|
|
16651
17056
|
});
|
|
17057
|
+
const source = bodyStream;
|
|
16652
17058
|
bodyStream = new ReadableStream({
|
|
16653
17059
|
async start(controller) {
|
|
16654
|
-
const reader =
|
|
17060
|
+
const reader = source.getReader();
|
|
16655
17061
|
try {
|
|
16656
17062
|
while (true) {
|
|
16657
17063
|
const { done, value } = await reader.read();
|
|
@@ -16669,8 +17075,9 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
16669
17075
|
reader.releaseLock();
|
|
16670
17076
|
}
|
|
16671
17077
|
},
|
|
16672
|
-
cancel() {
|
|
16673
|
-
|
|
17078
|
+
cancel(reason) {
|
|
17079
|
+
void source.cancel(reason).catch(() => {
|
|
17080
|
+
});
|
|
16674
17081
|
}
|
|
16675
17082
|
});
|
|
16676
17083
|
}
|
|
@@ -16691,7 +17098,9 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
16691
17098
|
status: raw.status,
|
|
16692
17099
|
statusText: raw.statusText,
|
|
16693
17100
|
headers: raw.headers,
|
|
16694
|
-
|
|
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,
|
|
16695
17104
|
rawBody,
|
|
16696
17105
|
url: raw.url,
|
|
16697
17106
|
cached: false,
|
|
@@ -16701,6 +17110,9 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
16701
17110
|
request: req,
|
|
16702
17111
|
attempt
|
|
16703
17112
|
};
|
|
17113
|
+
if (this.cfg.transformResponse) {
|
|
17114
|
+
res.data = this.cfg.transformResponse(res.data, res);
|
|
17115
|
+
}
|
|
16704
17116
|
if (options.cache !== false && this.cfg.cache) {
|
|
16705
17117
|
const cache = await this.getCache();
|
|
16706
17118
|
if (cache && raw.status !== 304) {
|
|
@@ -16769,6 +17181,10 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
16769
17181
|
if ("status" in result && "headers" in result) {
|
|
16770
17182
|
current = result;
|
|
16771
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
|
+
}
|
|
16772
17188
|
if (retryCfg && attempt <= retryCfg.maxRetries) {
|
|
16773
17189
|
const retryCtx = {
|
|
16774
17190
|
request: _req,
|
|
@@ -16785,7 +17201,13 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
16785
17201
|
}, Promise.resolve());
|
|
16786
17202
|
await sleep6(delay, _req.signal);
|
|
16787
17203
|
}
|
|
16788
|
-
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);
|
|
16789
17211
|
}
|
|
16790
17212
|
}
|
|
16791
17213
|
return current;
|
|
@@ -17063,7 +17485,10 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
17063
17485
|
* Call this when the client is no longer needed to prevent memory leaks.
|
|
17064
17486
|
* @returns A promise that resolves when cleanup is complete.
|
|
17065
17487
|
*/
|
|
17066
|
-
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() {
|
|
17067
17492
|
for (const ws of this._wsClients) {
|
|
17068
17493
|
try {
|
|
17069
17494
|
ws.close(1e3, "Client destroyed");
|
|
@@ -17071,12 +17496,6 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
17071
17496
|
}
|
|
17072
17497
|
}
|
|
17073
17498
|
this._wsClients.clear();
|
|
17074
|
-
if (this._cache) {
|
|
17075
|
-
try {
|
|
17076
|
-
await this._cache.clear();
|
|
17077
|
-
} catch {
|
|
17078
|
-
}
|
|
17079
|
-
}
|
|
17080
17499
|
if (IS_NODE && this.transport && "destroy" in this.transport) {
|
|
17081
17500
|
this.transport.destroy();
|
|
17082
17501
|
}
|
|
@@ -17086,6 +17505,7 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
17086
17505
|
this._circuitBreakers?.clear?.();
|
|
17087
17506
|
this._otelTracer = null;
|
|
17088
17507
|
this.interceptors.clear();
|
|
17508
|
+
return Promise.resolve();
|
|
17089
17509
|
}
|
|
17090
17510
|
};
|
|
17091
17511
|
var FluentRequest = class {
|
|
@@ -17314,13 +17734,19 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
17314
17734
|
}).catch((err) => onError?.(err instanceof KinetexError ? err : new KinetexError(String(err), "EUNKNOWN")));
|
|
17315
17735
|
}
|
|
17316
17736
|
};
|
|
17317
|
-
function
|
|
17318
|
-
if (
|
|
17319
|
-
return
|
|
17320
|
-
|
|
17321
|
-
|
|
17322
|
-
|
|
17323
|
-
|
|
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);
|
|
17324
17750
|
}
|
|
17325
17751
|
function mergeParams(a, b) {
|
|
17326
17752
|
if (!a && !b)
|
|
@@ -17344,6 +17770,11 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
17344
17770
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
17345
17771
|
});
|
|
17346
17772
|
}
|
|
17773
|
+
function isNonReplayableBody(body) {
|
|
17774
|
+
if (body instanceof ReadableStream)
|
|
17775
|
+
return true;
|
|
17776
|
+
return typeof Blob !== "undefined" && body instanceof Blob;
|
|
17777
|
+
}
|
|
17347
17778
|
function perfNow4() {
|
|
17348
17779
|
return typeof performance !== "undefined" ? performance.now() : Date.now();
|
|
17349
17780
|
}
|
|
@@ -17362,7 +17793,13 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
17362
17793
|
constructor(client, options = {}) {
|
|
17363
17794
|
/** The parent Kinetex instance used to send requests. */
|
|
17364
17795
|
__publicField(this, "_client");
|
|
17365
|
-
/**
|
|
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
|
+
*/
|
|
17366
17803
|
__publicField(this, "_maxBatch");
|
|
17367
17804
|
/** Milliseconds to wait before flushing an incomplete batch. */
|
|
17368
17805
|
__publicField(this, "_flushMs");
|
|
@@ -17371,8 +17808,16 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
17371
17808
|
/** Timer handle for deferred flush. */
|
|
17372
17809
|
__publicField(this, "_timer", null);
|
|
17373
17810
|
this._client = client;
|
|
17374
|
-
|
|
17375
|
-
|
|
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;
|
|
17376
17821
|
}
|
|
17377
17822
|
/**
|
|
17378
17823
|
* Enqueue a request. Returns a promise that resolves when the batch
|
|
@@ -17425,7 +17870,8 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
17425
17870
|
* Loops until the queue is empty so items beyond maxBatch are not orphaned.
|
|
17426
17871
|
*/
|
|
17427
17872
|
flush() {
|
|
17428
|
-
|
|
17873
|
+
let guard = this._queue.length + 1;
|
|
17874
|
+
while (this._queue.length > 0 && guard-- > 0)
|
|
17429
17875
|
this._flushNow();
|
|
17430
17876
|
}
|
|
17431
17877
|
/** How many requests are currently queued (not yet sent). */
|
|
@@ -18420,28 +18866,27 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
18420
18866
|
}
|
|
18421
18867
|
var denoTcpConnector = async (host, port, timeoutMs) => {
|
|
18422
18868
|
const denoGlobal = globalThis;
|
|
18423
|
-
|
|
18424
|
-
|
|
18425
|
-
|
|
18426
|
-
|
|
18427
|
-
new Promise((_, rej) => setTimeout(() => rej(new Socks5Error("TCP connect to proxy timed out", "SOCKS5_TIMEOUT", true)), timeoutMs))
|
|
18428
|
-
]);
|
|
18429
|
-
} else {
|
|
18430
|
-
conn = await denoGlobal.Deno.connect({ hostname: host, port, transport: "tcp" });
|
|
18431
|
-
}
|
|
18432
|
-
const wrappedRead = async (buf) => {
|
|
18433
|
-
if (timeoutMs && timeoutMs > 0) {
|
|
18434
|
-
return Promise.race([
|
|
18435
|
-
conn.read(buf).catch(() => null),
|
|
18436
|
-
new Promise((_, rej) => setTimeout(() => rej(new Socks5Error("TCP read timed out", "SOCKS5_TIMEOUT", true)), timeoutMs))
|
|
18437
|
-
]);
|
|
18438
|
-
}
|
|
18869
|
+
const withTimeout2 = async (work, message) => {
|
|
18870
|
+
if (!timeoutMs || timeoutMs <= 0)
|
|
18871
|
+
return work;
|
|
18872
|
+
let timer;
|
|
18439
18873
|
try {
|
|
18440
|
-
return await
|
|
18441
|
-
|
|
18442
|
-
|
|
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);
|
|
18443
18883
|
}
|
|
18444
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
|
+
};
|
|
18445
18890
|
return {
|
|
18446
18891
|
read: wrappedRead,
|
|
18447
18892
|
write: (data) => conn.write(data),
|
|
@@ -18494,7 +18939,9 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
18494
18939
|
buffer = next;
|
|
18495
18940
|
flushBuffer();
|
|
18496
18941
|
});
|
|
18942
|
+
let ended = false;
|
|
18497
18943
|
socket.on("end", () => {
|
|
18944
|
+
ended = true;
|
|
18498
18945
|
if (pendingRead) {
|
|
18499
18946
|
pendingRead(null);
|
|
18500
18947
|
pendingRead = null;
|
|
@@ -18502,6 +18949,9 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
18502
18949
|
pendingBuf = null;
|
|
18503
18950
|
}
|
|
18504
18951
|
});
|
|
18952
|
+
socket.on("close", () => {
|
|
18953
|
+
ended = true;
|
|
18954
|
+
});
|
|
18505
18955
|
socket.once("error", (err) => {
|
|
18506
18956
|
clearTimeout(timer);
|
|
18507
18957
|
lastError = err;
|
|
@@ -18520,6 +18970,10 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
18520
18970
|
rej(lastError);
|
|
18521
18971
|
return;
|
|
18522
18972
|
}
|
|
18973
|
+
if (ended && buffer.length === 0) {
|
|
18974
|
+
res(null);
|
|
18975
|
+
return;
|
|
18976
|
+
}
|
|
18523
18977
|
if (buffer.length > 0) {
|
|
18524
18978
|
const n = Math.min(buffer.length, buf.length);
|
|
18525
18979
|
buf.set(buffer.subarray(0, n));
|