kinetex 1.0.0 → 1.2.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 +104 -16
- package/dist/browser/kinetex.esm.js +18 -18
- package/dist/browser/kinetex.js +581 -275
- package/dist/browser/kinetex.min.js +18 -18
- package/dist/cjs/client.js +180 -11
- package/dist/cjs/cookie-store.js +10 -0
- package/dist/cjs/core.js +53 -27
- package/dist/cjs/graphql.js +37 -8
- package/dist/cjs/interceptors.js +22 -11
- package/dist/cjs/logging.js +10 -2
- package/dist/cjs/mod.js +1 -1
- package/dist/cjs/pagination.js +6 -1
- package/dist/cjs/progress.js +13 -6
- package/dist/cjs/response.js +8 -6
- package/dist/cjs/sse.js +5 -2
- package/dist/cjs/utils.js +250 -57
- package/dist/cjs/ws.js +16 -2
- package/dist/esm/client.js +180 -11
- package/dist/esm/client.js.map +1 -1
- package/dist/esm/cookie-store.js +10 -0
- package/dist/esm/cookie-store.js.map +1 -1
- package/dist/esm/core.js +53 -27
- package/dist/esm/core.js.map +1 -1
- package/dist/esm/graphql.js +37 -8
- package/dist/esm/graphql.js.map +1 -1
- package/dist/esm/interceptors.js +22 -11
- package/dist/esm/interceptors.js.map +1 -1
- package/dist/esm/logging.js +10 -2
- package/dist/esm/logging.js.map +1 -1
- package/dist/esm/mod.js +1 -1
- package/dist/esm/mod.js.map +1 -1
- package/dist/esm/pagination.js +6 -1
- package/dist/esm/pagination.js.map +1 -1
- package/dist/esm/progress.js +13 -6
- package/dist/esm/progress.js.map +1 -1
- package/dist/esm/response.js +8 -6
- package/dist/esm/response.js.map +1 -1
- package/dist/esm/sse.js +5 -2
- package/dist/esm/sse.js.map +1 -1
- package/dist/esm/utils.js +250 -57
- package/dist/esm/utils.js.map +1 -1
- package/dist/esm/ws.js +16 -2
- package/dist/esm/ws.js.map +1 -1
- package/dist/types/client.d.ts.map +1 -1
- package/dist/types/cookie-store.d.ts.map +1 -1
- package/dist/types/core.d.ts +4 -0
- package/dist/types/core.d.ts.map +1 -1
- package/dist/types/graphql.d.ts.map +1 -1
- package/dist/types/interceptors.d.ts.map +1 -1
- package/dist/types/logging.d.ts.map +1 -1
- package/dist/types/mod.d.ts +1 -1
- package/dist/types/mod.d.ts.map +1 -1
- package/dist/types/pagination.d.ts.map +1 -1
- package/dist/types/progress.d.ts.map +1 -1
- package/dist/types/response.d.ts.map +1 -1
- package/dist/types/sse.d.ts.map +1 -1
- package/dist/types/utils.d.ts +18 -2
- package/dist/types/utils.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 +5 -5
package/dist/browser/kinetex.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* kinetex v1.
|
|
1
|
+
/* kinetex v1.2.0 | MIT | https://github.com/kinetexjs/kinetex */
|
|
2
2
|
"use strict";
|
|
3
3
|
var kinetex = (() => {
|
|
4
4
|
var __create = Object.create;
|
|
@@ -51,160 +51,6 @@ var kinetex = (() => {
|
|
|
51
51
|
var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
52
52
|
var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
|
|
53
53
|
|
|
54
|
-
// dist/esm/types.js
|
|
55
|
-
function toRequestId(id) {
|
|
56
|
-
return id;
|
|
57
|
-
}
|
|
58
|
-
function validateErrorCode(code) {
|
|
59
|
-
if (typeof code === "string") {
|
|
60
|
-
for (const valid of VALID_ERROR_CODES) {
|
|
61
|
-
if (valid === code)
|
|
62
|
-
return valid;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
return void 0;
|
|
66
|
-
}
|
|
67
|
-
var VALID_ERROR_CODES, KinetexError, SizeLimitError, HTTPStatusError, AbortError, NetworkError, ValidationError, AuthError, ProxyError, RedirectError, TimeoutError;
|
|
68
|
-
var init_types = __esm({
|
|
69
|
-
"dist/esm/types.js"() {
|
|
70
|
-
"use strict";
|
|
71
|
-
VALID_ERROR_CODES = [
|
|
72
|
-
"ENETWORK",
|
|
73
|
-
"ETIMEOUT",
|
|
74
|
-
"EABORT",
|
|
75
|
-
"EHTTPSTATUS",
|
|
76
|
-
"ESIZELIMIT",
|
|
77
|
-
"EPARSE",
|
|
78
|
-
"EVALIDATION",
|
|
79
|
-
"EAUTH",
|
|
80
|
-
"EPROXY",
|
|
81
|
-
"EREDIRECT",
|
|
82
|
-
"EUNKNOWN"
|
|
83
|
-
];
|
|
84
|
-
KinetexError = class extends Error {
|
|
85
|
-
/**
|
|
86
|
-
* @param message - Human-readable error description.
|
|
87
|
-
* @param code - Machine-readable error code.
|
|
88
|
-
* @param options - Additional context (request, response, cause).
|
|
89
|
-
*/
|
|
90
|
-
constructor(message, code, options) {
|
|
91
|
-
super(message);
|
|
92
|
-
/** Machine-readable error code. */
|
|
93
|
-
__publicField(this, "code");
|
|
94
|
-
/** Original request, if available. */
|
|
95
|
-
__publicField(this, "request");
|
|
96
|
-
/** Response, if available (for HTTP-level errors). */
|
|
97
|
-
__publicField(this, "response");
|
|
98
|
-
/** Underlying cause. */
|
|
99
|
-
__publicField(this, "cause");
|
|
100
|
-
this.name = "KinetexError";
|
|
101
|
-
this.code = code;
|
|
102
|
-
if (options?.request !== void 0)
|
|
103
|
-
this.request = options.request;
|
|
104
|
-
if (options?.response !== void 0)
|
|
105
|
-
this.response = options.response;
|
|
106
|
-
if (options?.cause !== void 0)
|
|
107
|
-
this.cause = options.cause;
|
|
108
|
-
}
|
|
109
|
-
/** True if the error is a network/transport failure (not proxy-related). */
|
|
110
|
-
get isNetwork() {
|
|
111
|
-
return this.code === "ENETWORK";
|
|
112
|
-
}
|
|
113
|
-
/** True if the error is a proxy-related failure. */
|
|
114
|
-
get isProxy() {
|
|
115
|
-
return this.code === "EPROXY";
|
|
116
|
-
}
|
|
117
|
-
/** True if the error is a timeout. */
|
|
118
|
-
get isTimeout() {
|
|
119
|
-
return this.code === "ETIMEOUT";
|
|
120
|
-
}
|
|
121
|
-
/** True if the request was aborted by the caller. */
|
|
122
|
-
get isAbort() {
|
|
123
|
-
return this.code === "EABORT";
|
|
124
|
-
}
|
|
125
|
-
/** True if the server returned a 4xx or 5xx status. */
|
|
126
|
-
get isHTTPError() {
|
|
127
|
-
return this.code === "EHTTPSTATUS";
|
|
128
|
-
}
|
|
129
|
-
/** HTTP status code shorthand (null for non-HTTP errors). */
|
|
130
|
-
get status() {
|
|
131
|
-
return this.response?.status ?? null;
|
|
132
|
-
}
|
|
133
|
-
};
|
|
134
|
-
SizeLimitError = class extends KinetexError {
|
|
135
|
-
constructor(bytesRead, limit, request) {
|
|
136
|
-
super(`Response size limit exceeded: ${bytesRead} bytes read, limit is ${limit} bytes`, "ESIZELIMIT", request !== void 0 ? { request } : {});
|
|
137
|
-
__publicField(this, "bytesRead");
|
|
138
|
-
__publicField(this, "limit");
|
|
139
|
-
this.bytesRead = bytesRead;
|
|
140
|
-
this.limit = limit;
|
|
141
|
-
this.name = "SizeLimitError";
|
|
142
|
-
}
|
|
143
|
-
};
|
|
144
|
-
HTTPStatusError = class extends KinetexError {
|
|
145
|
-
constructor(response, request) {
|
|
146
|
-
super(`HTTP ${response.status} ${response.statusText} \u2014 ${response.url}`, "EHTTPSTATUS", {
|
|
147
|
-
request,
|
|
148
|
-
response
|
|
149
|
-
});
|
|
150
|
-
this.name = "HTTPStatusError";
|
|
151
|
-
}
|
|
152
|
-
/** True if the status is a 4xx client error. */
|
|
153
|
-
get isClientError() {
|
|
154
|
-
return (this.status ?? 0) >= 400 && (this.status ?? 0) < 500;
|
|
155
|
-
}
|
|
156
|
-
/** True if the status is a 5xx server error. */
|
|
157
|
-
get isServerError() {
|
|
158
|
-
return (this.status ?? 0) >= 500;
|
|
159
|
-
}
|
|
160
|
-
};
|
|
161
|
-
AbortError = class extends KinetexError {
|
|
162
|
-
constructor(request) {
|
|
163
|
-
super("Request was aborted", "EABORT", request !== void 0 ? { request } : {});
|
|
164
|
-
this.name = "AbortError";
|
|
165
|
-
}
|
|
166
|
-
};
|
|
167
|
-
NetworkError = class extends KinetexError {
|
|
168
|
-
constructor(message, request) {
|
|
169
|
-
super(message, "ENETWORK", request !== void 0 ? { request } : {});
|
|
170
|
-
this.name = "NetworkError";
|
|
171
|
-
}
|
|
172
|
-
};
|
|
173
|
-
ValidationError = class extends KinetexError {
|
|
174
|
-
constructor(message, request) {
|
|
175
|
-
super(message, "EVALIDATION", request !== void 0 ? { request } : {});
|
|
176
|
-
this.name = "ValidationError";
|
|
177
|
-
}
|
|
178
|
-
};
|
|
179
|
-
AuthError = class extends KinetexError {
|
|
180
|
-
constructor(message, request) {
|
|
181
|
-
super(message, "EAUTH", request !== void 0 ? { request } : {});
|
|
182
|
-
this.name = "AuthError";
|
|
183
|
-
}
|
|
184
|
-
};
|
|
185
|
-
ProxyError = class extends KinetexError {
|
|
186
|
-
constructor(message, request) {
|
|
187
|
-
super(message, "EPROXY", request !== void 0 ? { request } : {});
|
|
188
|
-
this.name = "ProxyError";
|
|
189
|
-
}
|
|
190
|
-
};
|
|
191
|
-
RedirectError = class extends KinetexError {
|
|
192
|
-
constructor(message, request) {
|
|
193
|
-
super(message, "EREDIRECT", request !== void 0 ? { request } : {});
|
|
194
|
-
this.name = "RedirectError";
|
|
195
|
-
}
|
|
196
|
-
};
|
|
197
|
-
TimeoutError = class extends KinetexError {
|
|
198
|
-
constructor(timeoutMs, request) {
|
|
199
|
-
super(`Request timed out after ${timeoutMs}ms`, "ETIMEOUT", request !== void 0 ? { request } : {});
|
|
200
|
-
__publicField(this, "timeoutMs");
|
|
201
|
-
this.timeoutMs = timeoutMs;
|
|
202
|
-
this.name = "TimeoutError";
|
|
203
|
-
}
|
|
204
|
-
};
|
|
205
|
-
}
|
|
206
|
-
});
|
|
207
|
-
|
|
208
54
|
// dist/esm/utils.js
|
|
209
55
|
function getProcess() {
|
|
210
56
|
if (_process)
|
|
@@ -346,6 +192,25 @@ var kinetex = (() => {
|
|
|
346
192
|
const result = safeJSONParse(text);
|
|
347
193
|
return result.success ? result.value : text;
|
|
348
194
|
}
|
|
195
|
+
function sanitizeParsedJSON(value) {
|
|
196
|
+
if (value === null || typeof value !== "object")
|
|
197
|
+
return value;
|
|
198
|
+
if (Array.isArray(value)) {
|
|
199
|
+
for (let i = 0; i < value.length; i++) {
|
|
200
|
+
value[i] = sanitizeParsedJSON(value[i]);
|
|
201
|
+
}
|
|
202
|
+
return value;
|
|
203
|
+
}
|
|
204
|
+
const obj = value;
|
|
205
|
+
for (const key of Object.keys(obj)) {
|
|
206
|
+
if (key === "__proto__" || key === "constructor" || key === "prototype") {
|
|
207
|
+
delete obj[key];
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
sanitizeParsedJSON(obj[key]);
|
|
211
|
+
}
|
|
212
|
+
return value;
|
|
213
|
+
}
|
|
349
214
|
function parseUntrustedJSON(text) {
|
|
350
215
|
return safeJSONParse(text, {
|
|
351
216
|
maxDepth: 16,
|
|
@@ -401,6 +266,130 @@ var kinetex = (() => {
|
|
|
401
266
|
}
|
|
402
267
|
return true;
|
|
403
268
|
}
|
|
269
|
+
function isBlockedIPv4(n) {
|
|
270
|
+
return IPV4_BLOCKED_RANGES.some(([lo, hi]) => n >= lo && n <= hi);
|
|
271
|
+
}
|
|
272
|
+
function parseIPv4Component(p) {
|
|
273
|
+
if (p === "")
|
|
274
|
+
return null;
|
|
275
|
+
if (/^0[xX][0-9a-fA-F]+$/.test(p))
|
|
276
|
+
return parseInt(p, 16);
|
|
277
|
+
if (/^0[0-7]+$/.test(p))
|
|
278
|
+
return parseInt(p, 8);
|
|
279
|
+
if (/^\d+$/.test(p))
|
|
280
|
+
return parseInt(p, 10);
|
|
281
|
+
return null;
|
|
282
|
+
}
|
|
283
|
+
function parseIPv4Host(host) {
|
|
284
|
+
if (host.includes(":") || !/^[0-9a-fA-FxX.]+$/.test(host))
|
|
285
|
+
return null;
|
|
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)
|
|
291
|
+
return null;
|
|
292
|
+
if (parts.length === 1) {
|
|
293
|
+
const v = parseIPv4Component(parts[0]);
|
|
294
|
+
if (v === null || v > 4294967295)
|
|
295
|
+
return null;
|
|
296
|
+
return v >>> 0;
|
|
297
|
+
}
|
|
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)
|
|
302
|
+
return null;
|
|
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);
|
|
311
|
+
}
|
|
312
|
+
return (octets[0] << 24 | octets[1] << 16 | octets[2] << 8 | octets[3]) >>> 0;
|
|
313
|
+
}
|
|
314
|
+
function parseIPv6Host(host) {
|
|
315
|
+
if (!host.includes(":"))
|
|
316
|
+
return null;
|
|
317
|
+
const bare = host.split("%")[0];
|
|
318
|
+
const halves = bare.split("::");
|
|
319
|
+
if (halves.length > 2)
|
|
320
|
+
return null;
|
|
321
|
+
const expandGroups = (part) => {
|
|
322
|
+
if (part === "")
|
|
323
|
+
return [];
|
|
324
|
+
const groups = part.split(":");
|
|
325
|
+
const out = [];
|
|
326
|
+
for (let i = 0; i < groups.length; i++) {
|
|
327
|
+
const g2 = groups[i];
|
|
328
|
+
if (g2 === "")
|
|
329
|
+
return null;
|
|
330
|
+
if (g2.includes(".")) {
|
|
331
|
+
if (i !== groups.length - 1)
|
|
332
|
+
return null;
|
|
333
|
+
const n = parseIPv4Host(g2);
|
|
334
|
+
if (n === null)
|
|
335
|
+
return null;
|
|
336
|
+
out.push(n >>> 24 & 255, n >>> 16 & 255, n >>> 8 & 255, n & 255);
|
|
337
|
+
} else {
|
|
338
|
+
if (!/^[0-9a-fA-F]{1,4}$/.test(g2))
|
|
339
|
+
return null;
|
|
340
|
+
const v = parseInt(g2, 16);
|
|
341
|
+
out.push(v >>> 8 & 255, v & 255);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
return out;
|
|
345
|
+
};
|
|
346
|
+
let bytes;
|
|
347
|
+
if (halves.length === 2) {
|
|
348
|
+
const left = expandGroups(halves[0]);
|
|
349
|
+
const right = expandGroups(halves[1]);
|
|
350
|
+
if (!left || !right)
|
|
351
|
+
return null;
|
|
352
|
+
const fill = 16 - left.length - right.length;
|
|
353
|
+
if (fill < 0)
|
|
354
|
+
return null;
|
|
355
|
+
bytes = [...left, ...new Array(fill).fill(0), ...right];
|
|
356
|
+
} else {
|
|
357
|
+
const all = expandGroups(bare);
|
|
358
|
+
if (!all || all.length !== 16)
|
|
359
|
+
return null;
|
|
360
|
+
bytes = all;
|
|
361
|
+
}
|
|
362
|
+
return bytes.length === 16 ? new Uint8Array(bytes) : null;
|
|
363
|
+
}
|
|
364
|
+
function isBlockedIPv6(b) {
|
|
365
|
+
const read32 = (i) => (b[i] << 24 | b[i + 1] << 16 | b[i + 2] << 8 | b[i + 3]) >>> 0;
|
|
366
|
+
if (b.every((x) => x === 0))
|
|
367
|
+
return true;
|
|
368
|
+
if (b.slice(0, 15).every((x) => x === 0) && b[15] === 1)
|
|
369
|
+
return true;
|
|
370
|
+
const first = b[0];
|
|
371
|
+
if ((first & 254) === 252)
|
|
372
|
+
return true;
|
|
373
|
+
if (first === 254 && (b[1] & 192) === 128)
|
|
374
|
+
return true;
|
|
375
|
+
if (first === 255)
|
|
376
|
+
return true;
|
|
377
|
+
if (b[0] === 32 && b[1] === 1 && b[2] === 13 && b[3] === 184)
|
|
378
|
+
return true;
|
|
379
|
+
if (b.slice(0, 10).every((x) => x === 0) && b[10] === 255 && b[11] === 255) {
|
|
380
|
+
return isBlockedIPv4(read32(12));
|
|
381
|
+
}
|
|
382
|
+
if (b.slice(0, 12).every((x) => x === 0)) {
|
|
383
|
+
return isBlockedIPv4(read32(12));
|
|
384
|
+
}
|
|
385
|
+
if (b[0] === 0 && b[1] === 100 && b[2] === 255 && b[3] === 155 && b.slice(4, 12).every((x) => x === 0)) {
|
|
386
|
+
return isBlockedIPv4(read32(12));
|
|
387
|
+
}
|
|
388
|
+
if (b[0] === 32 && b[1] === 2) {
|
|
389
|
+
return isBlockedIPv4(read32(2));
|
|
390
|
+
}
|
|
391
|
+
return false;
|
|
392
|
+
}
|
|
404
393
|
function isSafeURL(url, allowedSchemes = ["http", "https"]) {
|
|
405
394
|
try {
|
|
406
395
|
const parsed = typeof url === "string" ? new URL(url) : url;
|
|
@@ -412,14 +401,20 @@ var kinetex = (() => {
|
|
|
412
401
|
return false;
|
|
413
402
|
}
|
|
414
403
|
let host = parsed.hostname.toLowerCase();
|
|
415
|
-
|
|
404
|
+
const isV6Literal = host.startsWith("[") && host.endsWith("]");
|
|
405
|
+
if (isV6Literal)
|
|
416
406
|
host = host.slice(1, -1);
|
|
417
|
-
if (host === "0
|
|
418
|
-
host = "::1";
|
|
419
|
-
if (host === "localhost" || host === "0.0.0.0")
|
|
420
|
-
return false;
|
|
421
|
-
if (PRIVATE_IP_RANGES.some((r) => r.test(host)))
|
|
407
|
+
if (host === "localhost" || host.endsWith(".localhost") || host === "0.0.0.0")
|
|
422
408
|
return false;
|
|
409
|
+
if (isV6Literal || host.includes(":")) {
|
|
410
|
+
const v6 = parseIPv6Host(host);
|
|
411
|
+
if (v6 === null || isBlockedIPv6(v6))
|
|
412
|
+
return false;
|
|
413
|
+
} else {
|
|
414
|
+
const v4 = parseIPv4Host(host);
|
|
415
|
+
if (v4 !== null && isBlockedIPv4(v4))
|
|
416
|
+
return false;
|
|
417
|
+
}
|
|
423
418
|
if (parsed.hostname.includes("..") || parsed.pathname.includes("..")) {
|
|
424
419
|
return false;
|
|
425
420
|
}
|
|
@@ -463,6 +458,8 @@ var kinetex = (() => {
|
|
|
463
458
|
}
|
|
464
459
|
const cloned = {};
|
|
465
460
|
for (const key in value) {
|
|
461
|
+
if (key === "__proto__" || key === "constructor" || key === "prototype")
|
|
462
|
+
continue;
|
|
466
463
|
if (Object.prototype.hasOwnProperty.call(value, key)) {
|
|
467
464
|
cloned[key] = deepClone(value[key]);
|
|
468
465
|
}
|
|
@@ -619,17 +616,14 @@ var kinetex = (() => {
|
|
|
619
616
|
return false;
|
|
620
617
|
}
|
|
621
618
|
function randomBytes(byteCount) {
|
|
619
|
+
if (!Number.isInteger(byteCount) || byteCount < 0 || byteCount > 65536) {
|
|
620
|
+
throw new Error(`randomBytes: invalid byteCount ${byteCount}`);
|
|
621
|
+
}
|
|
622
622
|
const arr = new Uint8Array(byteCount);
|
|
623
623
|
if (typeof crypto !== "undefined" && typeof crypto.getRandomValues === "function") {
|
|
624
624
|
crypto.getRandomValues(arr);
|
|
625
625
|
} else {
|
|
626
|
-
|
|
627
|
-
if (uuid.length >= byteCount * 2) {
|
|
628
|
-
return uuid.slice(0, byteCount * 2);
|
|
629
|
-
}
|
|
630
|
-
for (let i = 0; i < arr.length; i++) {
|
|
631
|
-
arr[i] = Math.floor(Math.random() * 256);
|
|
632
|
-
}
|
|
626
|
+
throw new Error("randomBytes: no CSPRNG available in this runtime \u2014 crypto.getRandomValues is required");
|
|
633
627
|
}
|
|
634
628
|
return Array.from(arr).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
635
629
|
}
|
|
@@ -681,7 +675,7 @@ var kinetex = (() => {
|
|
|
681
675
|
});
|
|
682
676
|
return result;
|
|
683
677
|
}
|
|
684
|
-
var _process, _Buffer, DEFAULT_LIMITS, HEADER_NAME_PATTERN, FORBIDDEN_SCHEMES,
|
|
678
|
+
var _process, _Buffer, DEFAULT_LIMITS, HEADER_NAME_PATTERN, FORBIDDEN_SCHEMES, IPV4_BLOCKED_RANGES, cachedRuntime;
|
|
685
679
|
var init_utils = __esm({
|
|
686
680
|
"dist/esm/utils.js"() {
|
|
687
681
|
"use strict";
|
|
@@ -717,53 +711,194 @@ var kinetex = (() => {
|
|
|
717
711
|
"webcal",
|
|
718
712
|
"urn"
|
|
719
713
|
]);
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
//
|
|
723
|
-
|
|
724
|
-
// RFC 1918
|
|
725
|
-
|
|
726
|
-
// RFC
|
|
727
|
-
|
|
728
|
-
//
|
|
729
|
-
|
|
730
|
-
// link-local (AWS IMDS
|
|
731
|
-
|
|
732
|
-
//
|
|
733
|
-
|
|
734
|
-
//
|
|
735
|
-
|
|
736
|
-
//
|
|
737
|
-
|
|
738
|
-
//
|
|
739
|
-
|
|
740
|
-
//
|
|
741
|
-
|
|
742
|
-
//
|
|
743
|
-
|
|
744
|
-
//
|
|
745
|
-
|
|
746
|
-
//
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
// IPv4-mapped loopback
|
|
750
|
-
/^::ffff:10\./i,
|
|
751
|
-
// IPv4-mapped RFC 1918
|
|
752
|
-
/^::ffff:192\.168\./i,
|
|
753
|
-
// IPv4-mapped RFC 1918
|
|
754
|
-
/^::ffff:172\.(1[6-9]|2\d|3[01])\./i,
|
|
755
|
-
// IPv4-mapped RFC 1918
|
|
756
|
-
/^::ffff:169\.254\./i,
|
|
757
|
-
// IPv4-mapped link-local
|
|
758
|
-
/^0:0:0:0:0:ffff:7f/i,
|
|
759
|
-
// compressed form of ::ffff:127.x
|
|
760
|
-
/^::$/i
|
|
761
|
-
// IPv4-compatible :: (any ::/96)
|
|
714
|
+
IPV4_BLOCKED_RANGES = [
|
|
715
|
+
[0, 16777215],
|
|
716
|
+
// 0.0.0.0/8 — this-network
|
|
717
|
+
[167772160, 184549375],
|
|
718
|
+
// 10.0.0.0/8 — RFC 1918 private
|
|
719
|
+
[1681915904, 1686110207],
|
|
720
|
+
// 100.64.0.0/10 — CGNAT (RFC 6598)
|
|
721
|
+
[2130706432, 2147483647],
|
|
722
|
+
// 127.0.0.0/8 — loopback
|
|
723
|
+
[2851995648, 2852061183],
|
|
724
|
+
// 169.254.0.0/16 — link-local (AWS IMDS etc.)
|
|
725
|
+
[2886729728, 2887778303],
|
|
726
|
+
// 172.16.0.0/12 — RFC 1918 private
|
|
727
|
+
[3221225472, 3221225727],
|
|
728
|
+
// 192.0.0.0/24 — IETF protocol assignments
|
|
729
|
+
[3221225984, 3221226239],
|
|
730
|
+
// 192.0.2.0/24 — TEST-NET-1
|
|
731
|
+
[3232235520, 3232301055],
|
|
732
|
+
// 192.168.0.0/16 — RFC 1918 private
|
|
733
|
+
[3323068416, 3323199487],
|
|
734
|
+
// 198.18.0.0/15 — benchmarking
|
|
735
|
+
[3325256704, 3325256959],
|
|
736
|
+
// 198.51.100.0/24 — TEST-NET-2
|
|
737
|
+
[3405803776, 3405804031],
|
|
738
|
+
// 203.0.113.0/24 — TEST-NET-3
|
|
739
|
+
[3758096384, 4026531839],
|
|
740
|
+
// 224.0.0.0/4 — multicast
|
|
741
|
+
[4026531840, 4294967295]
|
|
742
|
+
// 240.0.0.0/4 — reserved (incl. 255.255.255.255)
|
|
762
743
|
];
|
|
763
744
|
cachedRuntime = null;
|
|
764
745
|
}
|
|
765
746
|
});
|
|
766
747
|
|
|
748
|
+
// dist/esm/types.js
|
|
749
|
+
function toRequestId(id) {
|
|
750
|
+
return id;
|
|
751
|
+
}
|
|
752
|
+
function validateErrorCode(code) {
|
|
753
|
+
if (typeof code === "string") {
|
|
754
|
+
for (const valid of VALID_ERROR_CODES) {
|
|
755
|
+
if (valid === code)
|
|
756
|
+
return valid;
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
return void 0;
|
|
760
|
+
}
|
|
761
|
+
var VALID_ERROR_CODES, KinetexError, SizeLimitError, HTTPStatusError, AbortError, NetworkError, ValidationError, AuthError, ProxyError, RedirectError, TimeoutError;
|
|
762
|
+
var init_types = __esm({
|
|
763
|
+
"dist/esm/types.js"() {
|
|
764
|
+
"use strict";
|
|
765
|
+
VALID_ERROR_CODES = [
|
|
766
|
+
"ENETWORK",
|
|
767
|
+
"ETIMEOUT",
|
|
768
|
+
"EABORT",
|
|
769
|
+
"EHTTPSTATUS",
|
|
770
|
+
"ESIZELIMIT",
|
|
771
|
+
"EPARSE",
|
|
772
|
+
"EVALIDATION",
|
|
773
|
+
"EAUTH",
|
|
774
|
+
"EPROXY",
|
|
775
|
+
"EREDIRECT",
|
|
776
|
+
"EUNKNOWN"
|
|
777
|
+
];
|
|
778
|
+
KinetexError = class extends Error {
|
|
779
|
+
/**
|
|
780
|
+
* @param message - Human-readable error description.
|
|
781
|
+
* @param code - Machine-readable error code.
|
|
782
|
+
* @param options - Additional context (request, response, cause).
|
|
783
|
+
*/
|
|
784
|
+
constructor(message, code, options) {
|
|
785
|
+
super(message);
|
|
786
|
+
/** Machine-readable error code. */
|
|
787
|
+
__publicField(this, "code");
|
|
788
|
+
/** Original request, if available. */
|
|
789
|
+
__publicField(this, "request");
|
|
790
|
+
/** Response, if available (for HTTP-level errors). */
|
|
791
|
+
__publicField(this, "response");
|
|
792
|
+
/** Underlying cause. */
|
|
793
|
+
__publicField(this, "cause");
|
|
794
|
+
this.name = "KinetexError";
|
|
795
|
+
this.code = code;
|
|
796
|
+
if (options?.request !== void 0)
|
|
797
|
+
this.request = options.request;
|
|
798
|
+
if (options?.response !== void 0)
|
|
799
|
+
this.response = options.response;
|
|
800
|
+
if (options?.cause !== void 0)
|
|
801
|
+
this.cause = options.cause;
|
|
802
|
+
}
|
|
803
|
+
/** True if the error is a network/transport failure (not proxy-related). */
|
|
804
|
+
get isNetwork() {
|
|
805
|
+
return this.code === "ENETWORK";
|
|
806
|
+
}
|
|
807
|
+
/** True if the error is a proxy-related failure. */
|
|
808
|
+
get isProxy() {
|
|
809
|
+
return this.code === "EPROXY";
|
|
810
|
+
}
|
|
811
|
+
/** True if the error is a timeout. */
|
|
812
|
+
get isTimeout() {
|
|
813
|
+
return this.code === "ETIMEOUT";
|
|
814
|
+
}
|
|
815
|
+
/** True if the request was aborted by the caller. */
|
|
816
|
+
get isAbort() {
|
|
817
|
+
return this.code === "EABORT";
|
|
818
|
+
}
|
|
819
|
+
/** True if the server returned a 4xx or 5xx status. */
|
|
820
|
+
get isHTTPError() {
|
|
821
|
+
return this.code === "EHTTPSTATUS";
|
|
822
|
+
}
|
|
823
|
+
/** HTTP status code shorthand (null for non-HTTP errors). */
|
|
824
|
+
get status() {
|
|
825
|
+
return this.response?.status ?? null;
|
|
826
|
+
}
|
|
827
|
+
};
|
|
828
|
+
SizeLimitError = class extends KinetexError {
|
|
829
|
+
constructor(bytesRead, limit, request) {
|
|
830
|
+
super(`Response size limit exceeded: ${bytesRead} bytes read, limit is ${limit} bytes`, "ESIZELIMIT", request !== void 0 ? { request } : {});
|
|
831
|
+
__publicField(this, "bytesRead");
|
|
832
|
+
__publicField(this, "limit");
|
|
833
|
+
this.bytesRead = bytesRead;
|
|
834
|
+
this.limit = limit;
|
|
835
|
+
this.name = "SizeLimitError";
|
|
836
|
+
}
|
|
837
|
+
};
|
|
838
|
+
HTTPStatusError = class extends KinetexError {
|
|
839
|
+
constructor(response, request) {
|
|
840
|
+
super(`HTTP ${response.status} ${response.statusText} \u2014 ${response.url}`, "EHTTPSTATUS", {
|
|
841
|
+
request,
|
|
842
|
+
response
|
|
843
|
+
});
|
|
844
|
+
this.name = "HTTPStatusError";
|
|
845
|
+
}
|
|
846
|
+
/** True if the status is a 4xx client error. */
|
|
847
|
+
get isClientError() {
|
|
848
|
+
return (this.status ?? 0) >= 400 && (this.status ?? 0) < 500;
|
|
849
|
+
}
|
|
850
|
+
/** True if the status is a 5xx server error. */
|
|
851
|
+
get isServerError() {
|
|
852
|
+
return (this.status ?? 0) >= 500;
|
|
853
|
+
}
|
|
854
|
+
};
|
|
855
|
+
AbortError = class extends KinetexError {
|
|
856
|
+
constructor(request) {
|
|
857
|
+
super("Request was aborted", "EABORT", request !== void 0 ? { request } : {});
|
|
858
|
+
this.name = "AbortError";
|
|
859
|
+
}
|
|
860
|
+
};
|
|
861
|
+
NetworkError = class extends KinetexError {
|
|
862
|
+
constructor(message, request) {
|
|
863
|
+
super(message, "ENETWORK", request !== void 0 ? { request } : {});
|
|
864
|
+
this.name = "NetworkError";
|
|
865
|
+
}
|
|
866
|
+
};
|
|
867
|
+
ValidationError = class extends KinetexError {
|
|
868
|
+
constructor(message, request) {
|
|
869
|
+
super(message, "EVALIDATION", request !== void 0 ? { request } : {});
|
|
870
|
+
this.name = "ValidationError";
|
|
871
|
+
}
|
|
872
|
+
};
|
|
873
|
+
AuthError = class extends KinetexError {
|
|
874
|
+
constructor(message, request) {
|
|
875
|
+
super(message, "EAUTH", request !== void 0 ? { request } : {});
|
|
876
|
+
this.name = "AuthError";
|
|
877
|
+
}
|
|
878
|
+
};
|
|
879
|
+
ProxyError = class extends KinetexError {
|
|
880
|
+
constructor(message, request) {
|
|
881
|
+
super(message, "EPROXY", request !== void 0 ? { request } : {});
|
|
882
|
+
this.name = "ProxyError";
|
|
883
|
+
}
|
|
884
|
+
};
|
|
885
|
+
RedirectError = class extends KinetexError {
|
|
886
|
+
constructor(message, request) {
|
|
887
|
+
super(message, "EREDIRECT", request !== void 0 ? { request } : {});
|
|
888
|
+
this.name = "RedirectError";
|
|
889
|
+
}
|
|
890
|
+
};
|
|
891
|
+
TimeoutError = class extends KinetexError {
|
|
892
|
+
constructor(timeoutMs, request) {
|
|
893
|
+
super(`Request timed out after ${timeoutMs}ms`, "ETIMEOUT", request !== void 0 ? { request } : {});
|
|
894
|
+
__publicField(this, "timeoutMs");
|
|
895
|
+
this.timeoutMs = timeoutMs;
|
|
896
|
+
this.name = "TimeoutError";
|
|
897
|
+
}
|
|
898
|
+
};
|
|
899
|
+
}
|
|
900
|
+
});
|
|
901
|
+
|
|
767
902
|
// dist/esm/cache.js
|
|
768
903
|
var cache_exports = {};
|
|
769
904
|
__export(cache_exports, {
|
|
@@ -3706,7 +3841,7 @@ var kinetex = (() => {
|
|
|
3706
3841
|
const charset = options.charset ?? parseContentType2(ct ?? "")?.charset ?? null;
|
|
3707
3842
|
const text = decodeBody(bytes, charset, url);
|
|
3708
3843
|
try {
|
|
3709
|
-
return JSON.parse(text);
|
|
3844
|
+
return sanitizeParsedJSON(JSON.parse(text));
|
|
3710
3845
|
} catch (err) {
|
|
3711
3846
|
throw new ResponseDecodeError(`JSON parse failed: ${err}`, "json", url);
|
|
3712
3847
|
}
|
|
@@ -3761,7 +3896,7 @@ var kinetex = (() => {
|
|
|
3761
3896
|
const trimmed = buffer.trim();
|
|
3762
3897
|
if (trimmed) {
|
|
3763
3898
|
try {
|
|
3764
|
-
yield JSON.parse(trimmed);
|
|
3899
|
+
yield sanitizeParsedJSON(JSON.parse(trimmed));
|
|
3765
3900
|
} catch (err) {
|
|
3766
3901
|
options.onParseError?.(err, trimmed);
|
|
3767
3902
|
}
|
|
@@ -3776,7 +3911,7 @@ var kinetex = (() => {
|
|
|
3776
3911
|
if (!trimmed || trimmed.startsWith("#"))
|
|
3777
3912
|
continue;
|
|
3778
3913
|
try {
|
|
3779
|
-
yield JSON.parse(trimmed);
|
|
3914
|
+
yield sanitizeParsedJSON(JSON.parse(trimmed));
|
|
3780
3915
|
} catch (err) {
|
|
3781
3916
|
options.onParseError?.(err, trimmed);
|
|
3782
3917
|
}
|
|
@@ -3809,7 +3944,7 @@ var kinetex = (() => {
|
|
|
3809
3944
|
const remaining = flushBuffer();
|
|
3810
3945
|
if (remaining) {
|
|
3811
3946
|
try {
|
|
3812
|
-
const obj = JSON.parse(remaining);
|
|
3947
|
+
const obj = sanitizeParsedJSON(JSON.parse(remaining));
|
|
3813
3948
|
options.onObject?.(obj);
|
|
3814
3949
|
yield obj;
|
|
3815
3950
|
} catch (err) {
|
|
@@ -3830,7 +3965,7 @@ var kinetex = (() => {
|
|
|
3830
3965
|
if (depth === 0 && startIdx !== -1) {
|
|
3831
3966
|
const objStr = buffer.slice(startIdx, i + 1);
|
|
3832
3967
|
try {
|
|
3833
|
-
const obj = JSON.parse(objStr);
|
|
3968
|
+
const obj = sanitizeParsedJSON(JSON.parse(objStr));
|
|
3834
3969
|
options.onObject?.(obj);
|
|
3835
3970
|
yield obj;
|
|
3836
3971
|
} catch (err) {
|
|
@@ -4374,7 +4509,7 @@ var kinetex = (() => {
|
|
|
4374
4509
|
}
|
|
4375
4510
|
}
|
|
4376
4511
|
function createTransport(fetchFn, preferHTTP2 = true, sessionOptions, transportOptions) {
|
|
4377
|
-
if (IS_NODE && preferHTTP2) {
|
|
4512
|
+
if (IS_NODE && preferHTTP2 && !fetchFn) {
|
|
4378
4513
|
return new NodeHTTP2Transport({
|
|
4379
4514
|
...sessionOptions?.sessionTTLMs !== void 0 ? { sessionTTLMs: sessionOptions.sessionTTLMs } : {},
|
|
4380
4515
|
...sessionOptions?.pingIntervalMs !== void 0 ? { pingIntervalMs: sessionOptions.pingIntervalMs } : {},
|
|
@@ -4399,8 +4534,11 @@ var kinetex = (() => {
|
|
|
4399
4534
|
}, timeoutMs);
|
|
4400
4535
|
const signal = mergeSignals(request.signal, controller.signal) ?? null;
|
|
4401
4536
|
const req = { ...request, signal };
|
|
4537
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
4538
|
+
controller.signal.addEventListener("abort", () => reject(new TimeoutError(timeoutMs, request)), { once: true });
|
|
4539
|
+
});
|
|
4402
4540
|
try {
|
|
4403
|
-
const result = await transport.send(req);
|
|
4541
|
+
const result = await Promise.race([transport.send(req), timeoutPromise]);
|
|
4404
4542
|
clearTimeout(timer);
|
|
4405
4543
|
if (controller.signal.aborted) {
|
|
4406
4544
|
throw new TimeoutError(timeoutMs, request);
|
|
@@ -4408,7 +4546,7 @@ var kinetex = (() => {
|
|
|
4408
4546
|
return result;
|
|
4409
4547
|
} catch (err) {
|
|
4410
4548
|
clearTimeout(timer);
|
|
4411
|
-
if (controller.signal.aborted) {
|
|
4549
|
+
if (controller.signal.aborted && !(err instanceof TimeoutError)) {
|
|
4412
4550
|
throw new TimeoutError(timeoutMs, request);
|
|
4413
4551
|
}
|
|
4414
4552
|
throw err;
|
|
@@ -4782,6 +4920,8 @@ var kinetex = (() => {
|
|
|
4782
4920
|
__publicField(this, "sessionUsage", /* @__PURE__ */ new Map());
|
|
4783
4921
|
__publicField(this, "_strict");
|
|
4784
4922
|
__publicField(this, "_onDroppedHeader");
|
|
4923
|
+
/** Optional CA bundle for origins with self-signed / private-PKI certificates. */
|
|
4924
|
+
__publicField(this, "_ca");
|
|
4785
4925
|
/** FIX 11: Configurable connect timeout (replaces hardcoded 30 000 ms) */
|
|
4786
4926
|
__publicField(this, "_connectTimeoutMs");
|
|
4787
4927
|
/** FIX 11: Configurable per-request stream timeout (replaces hardcoded 30 000 ms) */
|
|
@@ -4793,6 +4933,7 @@ var kinetex = (() => {
|
|
|
4793
4933
|
this.maxSessions = options.maxSessions ?? 100;
|
|
4794
4934
|
this._strict = options.strict ?? false;
|
|
4795
4935
|
this._onDroppedHeader = options.onDroppedHeader;
|
|
4936
|
+
this._ca = options.ca;
|
|
4796
4937
|
this._connectTimeoutMs = options.connectTimeoutMs ?? 3e4;
|
|
4797
4938
|
this._requestTimeoutMs = options.requestTimeoutMs ?? 3e4;
|
|
4798
4939
|
}
|
|
@@ -4842,7 +4983,10 @@ var kinetex = (() => {
|
|
|
4842
4983
|
}
|
|
4843
4984
|
}
|
|
4844
4985
|
const session = await new Promise((resolve, reject) => {
|
|
4845
|
-
const s = http2.connect(origin, {
|
|
4986
|
+
const s = http2.connect(origin, {
|
|
4987
|
+
rejectUnauthorized: true,
|
|
4988
|
+
...this._ca !== void 0 ? { ca: this._ca } : {}
|
|
4989
|
+
});
|
|
4846
4990
|
const connectTimeout = setTimeout(() => {
|
|
4847
4991
|
s.destroy();
|
|
4848
4992
|
reject(new KinetexError(`HTTP/2 connection to ${origin} timed out`, "ETIMEOUT", {
|
|
@@ -4955,27 +5099,28 @@ var kinetex = (() => {
|
|
|
4955
5099
|
":authority": currentUrl.host,
|
|
4956
5100
|
...currentReq.headers
|
|
4957
5101
|
};
|
|
4958
|
-
|
|
4959
|
-
|
|
4960
|
-
|
|
4961
|
-
|
|
4962
|
-
|
|
4963
|
-
|
|
4964
|
-
|
|
4965
|
-
|
|
4966
|
-
|
|
4967
|
-
|
|
4968
|
-
break;
|
|
4969
|
-
}
|
|
5102
|
+
for (const [hName, hValue] of Object.entries(h2ReqHeaders)) {
|
|
5103
|
+
if (hName.startsWith(":"))
|
|
5104
|
+
continue;
|
|
5105
|
+
const hStr = Array.isArray(hValue) ? hValue.join(", ") : String(hValue);
|
|
5106
|
+
let hasForbidden = false;
|
|
5107
|
+
for (let ci = 0; ci < hStr.length; ci++) {
|
|
5108
|
+
const code = hStr.charCodeAt(ci);
|
|
5109
|
+
if (code >= 0 && code <= 8 || code >= 10 && code <= 31 || code === 127) {
|
|
5110
|
+
hasForbidden = true;
|
|
5111
|
+
break;
|
|
4970
5112
|
}
|
|
4971
|
-
|
|
4972
|
-
|
|
4973
|
-
|
|
4974
|
-
|
|
4975
|
-
} else {
|
|
4976
|
-
throw new KinetexError(`Strict mode: header "${hName}" contains forbidden control characters`, "EVALIDATION", { request: currentReq });
|
|
4977
|
-
}
|
|
5113
|
+
}
|
|
5114
|
+
if (hasForbidden) {
|
|
5115
|
+
if (this._strict) {
|
|
5116
|
+
throw new KinetexError(`Strict mode: header "${hName}" contains forbidden control characters`, "EVALIDATION", { request: currentReq });
|
|
4978
5117
|
}
|
|
5118
|
+
if (this._onDroppedHeader) {
|
|
5119
|
+
this._onDroppedHeader(hName, hStr);
|
|
5120
|
+
} else if (typeof console !== "undefined") {
|
|
5121
|
+
console.warn(`[kinetex] Invalid header dropped (HTTP/2): "${hName}" \u2014 value contains illegal control characters. Pass strictHeaders: true to throw instead.`);
|
|
5122
|
+
}
|
|
5123
|
+
delete h2ReqHeaders[hName];
|
|
4979
5124
|
}
|
|
4980
5125
|
}
|
|
4981
5126
|
const endStream = !currentReq.body || currentReq.method === "GET" || currentReq.method === "HEAD";
|
|
@@ -7325,6 +7470,10 @@ var kinetex = (() => {
|
|
|
7325
7470
|
continue;
|
|
7326
7471
|
if (!sameSiteAllows(cookie.sameSite, context))
|
|
7327
7472
|
continue;
|
|
7473
|
+
if (cookie.name.startsWith("__Secure-") && !(cookie.secure && isSecure))
|
|
7474
|
+
continue;
|
|
7475
|
+
if (cookie.name.startsWith("__Host-") && !(cookie.secure && isSecure && cookie.path === "/" && cookie.hostOnly))
|
|
7476
|
+
continue;
|
|
7328
7477
|
result.push(cookie);
|
|
7329
7478
|
}
|
|
7330
7479
|
}
|
|
@@ -7797,9 +7946,11 @@ var kinetex = (() => {
|
|
|
7797
7946
|
const [head, ...rest] = path;
|
|
7798
7947
|
if (head === void 0)
|
|
7799
7948
|
return;
|
|
7949
|
+
if (head === "__proto__" || head === "constructor" || head === "prototype")
|
|
7950
|
+
return;
|
|
7800
7951
|
const o = obj;
|
|
7801
7952
|
if (rest.length === 0) {
|
|
7802
|
-
if (head
|
|
7953
|
+
if (Object.prototype.hasOwnProperty.call(o, head))
|
|
7803
7954
|
o[head] = "***";
|
|
7804
7955
|
return;
|
|
7805
7956
|
}
|
|
@@ -7882,6 +8033,7 @@ var kinetex = (() => {
|
|
|
7882
8033
|
var init_logging = __esm({
|
|
7883
8034
|
"dist/esm/logging.js"() {
|
|
7884
8035
|
"use strict";
|
|
8036
|
+
init_utils();
|
|
7885
8037
|
getNodeEnv = () => {
|
|
7886
8038
|
try {
|
|
7887
8039
|
return globalThis.process?.env?.["NODE_ENV"];
|
|
@@ -8241,7 +8393,7 @@ var kinetex = (() => {
|
|
|
8241
8393
|
const size = str.length;
|
|
8242
8394
|
if (ct.includes("application/json") && this.bodyFields.length > 0) {
|
|
8243
8395
|
try {
|
|
8244
|
-
const parsed = JSON.parse(str);
|
|
8396
|
+
const parsed = sanitizeParsedJSON(JSON.parse(str));
|
|
8245
8397
|
for (const path of this.bodyFields)
|
|
8246
8398
|
redactObjectPath(parsed, path.split("."));
|
|
8247
8399
|
str = JSON.stringify(parsed);
|
|
@@ -8512,7 +8664,7 @@ var kinetex = (() => {
|
|
|
8512
8664
|
if (!evt.data && evt.data !== "")
|
|
8513
8665
|
continue;
|
|
8514
8666
|
try {
|
|
8515
|
-
const data = JSON.parse(evt.data, options.reviver);
|
|
8667
|
+
const data = sanitizeParsedJSON(JSON.parse(evt.data, options.reviver));
|
|
8516
8668
|
yield { event: evt.event, data, id: evt.id };
|
|
8517
8669
|
} catch (err) {
|
|
8518
8670
|
options.onError?.(err, evt);
|
|
@@ -8552,6 +8704,7 @@ var kinetex = (() => {
|
|
|
8552
8704
|
var init_sse = __esm({
|
|
8553
8705
|
"dist/esm/sse.js"() {
|
|
8554
8706
|
"use strict";
|
|
8707
|
+
init_utils();
|
|
8555
8708
|
SSEParser = class {
|
|
8556
8709
|
constructor() {
|
|
8557
8710
|
__publicField(this, "lines", []);
|
|
@@ -8991,7 +9144,7 @@ var kinetex = (() => {
|
|
|
8991
9144
|
onJSON(eventType, handler) {
|
|
8992
9145
|
return this.on(eventType, async (data, evt) => {
|
|
8993
9146
|
try {
|
|
8994
|
-
const parsed = JSON.parse(data);
|
|
9147
|
+
const parsed = sanitizeParsedJSON(JSON.parse(data));
|
|
8995
9148
|
await handler(parsed, evt);
|
|
8996
9149
|
} catch {
|
|
8997
9150
|
}
|
|
@@ -9315,11 +9468,18 @@ var kinetex = (() => {
|
|
|
9315
9468
|
let current = obj;
|
|
9316
9469
|
for (let i = 0; i < parts.length - 1; i++) {
|
|
9317
9470
|
const key = parts[i];
|
|
9471
|
+
if (key === "__proto__" || key === "constructor" || key === "prototype") {
|
|
9472
|
+
throw new ValidationError(`Invalid upload path: "${path}" \u2014 reserved key "${key}"`);
|
|
9473
|
+
}
|
|
9318
9474
|
if (!current[key] || typeof current[key] !== "object")
|
|
9319
9475
|
current[key] = {};
|
|
9320
9476
|
current = current[key];
|
|
9321
9477
|
}
|
|
9322
|
-
|
|
9478
|
+
const leaf = parts[parts.length - 1];
|
|
9479
|
+
if (leaf === "__proto__" || leaf === "constructor" || leaf === "prototype") {
|
|
9480
|
+
throw new ValidationError(`Invalid upload path: "${path}" \u2014 reserved key "${leaf}"`);
|
|
9481
|
+
}
|
|
9482
|
+
current[leaf] = value;
|
|
9323
9483
|
}
|
|
9324
9484
|
async function parseGraphQLResponse(response, req) {
|
|
9325
9485
|
const ct = response.headers.get("content-type") ?? "";
|
|
@@ -9330,7 +9490,7 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
9330
9490
|
}
|
|
9331
9491
|
let json;
|
|
9332
9492
|
try {
|
|
9333
|
-
json = await response.json();
|
|
9493
|
+
json = sanitizeParsedJSON(await response.json());
|
|
9334
9494
|
} catch (err) {
|
|
9335
9495
|
throw new GraphQLClientError("Failed to parse GraphQL response as JSON", "EPARSE", void 0, req, void 0, err);
|
|
9336
9496
|
}
|
|
@@ -9366,7 +9526,8 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
9366
9526
|
fetchHeaders["content-type"] = "application/json";
|
|
9367
9527
|
const controller = new AbortController();
|
|
9368
9528
|
const timer = config.timeoutMs > 0 ? setTimeout(() => controller.abort(), config.timeoutMs) : null;
|
|
9369
|
-
|
|
9529
|
+
const onExternalAbort = () => controller.abort();
|
|
9530
|
+
signal?.addEventListener("abort", onExternalAbort, { once: true });
|
|
9370
9531
|
let response;
|
|
9371
9532
|
try {
|
|
9372
9533
|
response = await config.fetch(fetchUrl, {
|
|
@@ -9385,6 +9546,7 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
9385
9546
|
} finally {
|
|
9386
9547
|
if (timer)
|
|
9387
9548
|
clearTimeout(timer);
|
|
9549
|
+
signal?.removeEventListener("abort", onExternalAbort);
|
|
9388
9550
|
}
|
|
9389
9551
|
return parseGraphQLResponse(response, req);
|
|
9390
9552
|
}
|
|
@@ -9477,6 +9639,7 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
9477
9639
|
"dist/esm/graphql.js"() {
|
|
9478
9640
|
"use strict";
|
|
9479
9641
|
init_types();
|
|
9642
|
+
init_utils();
|
|
9480
9643
|
GraphQLClientError = class extends Error {
|
|
9481
9644
|
/**
|
|
9482
9645
|
* @param message - Human-readable error description
|
|
@@ -9742,7 +9905,8 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
9742
9905
|
delete headers["content-type"];
|
|
9743
9906
|
const form = buildMultipartBody(req, uploads);
|
|
9744
9907
|
const controller = new AbortController();
|
|
9745
|
-
|
|
9908
|
+
const onExternalAbort = () => controller.abort();
|
|
9909
|
+
options.signal?.addEventListener("abort", onExternalAbort, { once: true });
|
|
9746
9910
|
this.config.onRequest(req);
|
|
9747
9911
|
let response;
|
|
9748
9912
|
try {
|
|
@@ -9756,6 +9920,8 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
9756
9920
|
const clientErr = new GraphQLClientError(err instanceof Error ? err.message : "Upload network error", "ENETWORK", void 0, req, void 0, err);
|
|
9757
9921
|
this.config.onError(clientErr, req);
|
|
9758
9922
|
throw clientErr;
|
|
9923
|
+
} finally {
|
|
9924
|
+
options.signal?.removeEventListener("abort", onExternalAbort);
|
|
9759
9925
|
}
|
|
9760
9926
|
const gqlRes = await parseGraphQLResponse(response, req);
|
|
9761
9927
|
this.config.onResponse(gqlRes, req);
|
|
@@ -9786,7 +9952,8 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
9786
9952
|
async batch(requests, options = {}) {
|
|
9787
9953
|
const headers = await buildHeaders(this.config);
|
|
9788
9954
|
const controller = new AbortController();
|
|
9789
|
-
|
|
9955
|
+
const onExternalAbort = () => controller.abort();
|
|
9956
|
+
options.signal?.addEventListener("abort", onExternalAbort, { once: true });
|
|
9790
9957
|
let response;
|
|
9791
9958
|
try {
|
|
9792
9959
|
response = await this.config.fetch(this.config.url, {
|
|
@@ -9797,8 +9964,10 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
9797
9964
|
});
|
|
9798
9965
|
} catch (err) {
|
|
9799
9966
|
throw new GraphQLClientError(err instanceof Error ? err.message : "Batch network error", "ENETWORK", void 0, requests[0], void 0, err);
|
|
9967
|
+
} finally {
|
|
9968
|
+
options.signal?.removeEventListener("abort", onExternalAbort);
|
|
9800
9969
|
}
|
|
9801
|
-
const rawResults = await response.json();
|
|
9970
|
+
const rawResults = sanitizeParsedJSON(await response.json());
|
|
9802
9971
|
if (!Array.isArray(rawResults)) {
|
|
9803
9972
|
throw new GraphQLClientError("Batch response must be an array of GraphQL responses", "EINVALIDRESPONSE", void 0, requests[0], rawResults);
|
|
9804
9973
|
}
|
|
@@ -9886,7 +10055,7 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
9886
10055
|
continue;
|
|
9887
10056
|
let gqlRes;
|
|
9888
10057
|
try {
|
|
9889
|
-
gqlRes = JSON.parse(event.data);
|
|
10058
|
+
gqlRes = sanitizeParsedJSON(JSON.parse(event.data));
|
|
9890
10059
|
} catch {
|
|
9891
10060
|
continue;
|
|
9892
10061
|
}
|
|
@@ -10413,7 +10582,7 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
10413
10582
|
}
|
|
10414
10583
|
function deserializePaginationState(serialized) {
|
|
10415
10584
|
try {
|
|
10416
|
-
return JSON.parse(atob(serialized));
|
|
10585
|
+
return sanitizeParsedJSON(JSON.parse(atob(serialized)));
|
|
10417
10586
|
} catch {
|
|
10418
10587
|
throw new Error("Invalid pagination state string");
|
|
10419
10588
|
}
|
|
@@ -10460,6 +10629,7 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
10460
10629
|
var init_pagination = __esm({
|
|
10461
10630
|
"dist/esm/pagination.js"() {
|
|
10462
10631
|
"use strict";
|
|
10632
|
+
init_utils();
|
|
10463
10633
|
}
|
|
10464
10634
|
});
|
|
10465
10635
|
|
|
@@ -10768,6 +10938,7 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
10768
10938
|
retryLink: () => retryLink,
|
|
10769
10939
|
safeJSONParse: () => safeJSONParse,
|
|
10770
10940
|
safeParseURL: () => safeParseURL,
|
|
10941
|
+
sanitizeParsedJSON: () => sanitizeParsedJSON,
|
|
10771
10942
|
sanitizeURL: () => sanitizeURL,
|
|
10772
10943
|
securityHeaders: () => securityHeaders,
|
|
10773
10944
|
sendWithTimeout: () => sendWithTimeout,
|
|
@@ -10936,11 +11107,12 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
10936
11107
|
controller.error(new DOMException("Upload aborted", "AbortError"));
|
|
10937
11108
|
return;
|
|
10938
11109
|
}
|
|
10939
|
-
|
|
11110
|
+
const onUploadAbort = () => {
|
|
10940
11111
|
reader.cancel("aborted").catch(() => {
|
|
10941
11112
|
});
|
|
10942
11113
|
controller.error(new DOMException("Upload aborted", "AbortError"));
|
|
10943
|
-
}
|
|
11114
|
+
};
|
|
11115
|
+
options.signal?.addEventListener("abort", onUploadAbort, { once: true });
|
|
10944
11116
|
try {
|
|
10945
11117
|
while (true) {
|
|
10946
11118
|
const { done, value } = await reader.read();
|
|
@@ -10955,6 +11127,8 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
10955
11127
|
} catch (err) {
|
|
10956
11128
|
tracker.complete();
|
|
10957
11129
|
controller.error(err);
|
|
11130
|
+
} finally {
|
|
11131
|
+
options.signal?.removeEventListener("abort", onUploadAbort);
|
|
10958
11132
|
}
|
|
10959
11133
|
}
|
|
10960
11134
|
});
|
|
@@ -11045,11 +11219,11 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
11045
11219
|
});
|
|
11046
11220
|
throw new DOMException("Stream aborted", "AbortError");
|
|
11047
11221
|
}
|
|
11222
|
+
const abortHandler = () => {
|
|
11223
|
+
reader.cancel("aborted").catch(() => {
|
|
11224
|
+
});
|
|
11225
|
+
};
|
|
11048
11226
|
if (options.signal) {
|
|
11049
|
-
const abortHandler = () => {
|
|
11050
|
-
reader.cancel("aborted").catch(() => {
|
|
11051
|
-
});
|
|
11052
|
-
};
|
|
11053
11227
|
options.signal.addEventListener("abort", abortHandler, { once: true });
|
|
11054
11228
|
}
|
|
11055
11229
|
try {
|
|
@@ -11062,6 +11236,7 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
11062
11236
|
}
|
|
11063
11237
|
} finally {
|
|
11064
11238
|
reader.releaseLock();
|
|
11239
|
+
options.signal?.removeEventListener("abort", abortHandler);
|
|
11065
11240
|
}
|
|
11066
11241
|
tracker.complete();
|
|
11067
11242
|
const totalBytes = chunks.reduce((acc, c) => acc + c.byteLength, 0);
|
|
@@ -11782,6 +11957,7 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
11782
11957
|
}
|
|
11783
11958
|
|
|
11784
11959
|
// dist/esm/ws.js
|
|
11960
|
+
init_utils();
|
|
11785
11961
|
var WSError = class extends Error {
|
|
11786
11962
|
/**
|
|
11787
11963
|
* @param message - Human-readable error description
|
|
@@ -11874,6 +12050,10 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
11874
12050
|
__publicField(this, "_openWaiters", []);
|
|
11875
12051
|
__publicField(this, "_correlations", /* @__PURE__ */ new Map());
|
|
11876
12052
|
__publicField(this, "_aborted", false);
|
|
12053
|
+
/** Optional external abort signal from config (listener detached on close). */
|
|
12054
|
+
__publicField(this, "_externalSignal", null);
|
|
12055
|
+
/** Bound abort handler for the optional external `cfg.signal` (removed on close). */
|
|
12056
|
+
__publicField(this, "_onExternalAbort", () => this.close(1e3, "AbortSignal aborted"));
|
|
11877
12057
|
// ── Async iterator ──────────────────────────────────────────────────────
|
|
11878
12058
|
__publicField(this, "_iterQueue", []);
|
|
11879
12059
|
__publicField(this, "_iterWaiter", null);
|
|
@@ -11937,7 +12117,8 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
11937
12117
|
this._rooms.push({ room: r, joinedAt: 0 });
|
|
11938
12118
|
}
|
|
11939
12119
|
}
|
|
11940
|
-
|
|
12120
|
+
this._externalSignal = cfg.signal ?? null;
|
|
12121
|
+
this._externalSignal?.addEventListener("abort", this._onExternalAbort, {
|
|
11941
12122
|
once: true
|
|
11942
12123
|
});
|
|
11943
12124
|
}
|
|
@@ -12018,6 +12199,8 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
12018
12199
|
*/
|
|
12019
12200
|
close(code = 1e3, reason = "Client closed") {
|
|
12020
12201
|
this._aborted = true;
|
|
12202
|
+
this._externalSignal?.removeEventListener("abort", this._onExternalAbort);
|
|
12203
|
+
this._externalSignal = null;
|
|
12021
12204
|
this._stopAll();
|
|
12022
12205
|
for (const w of this._drainWaiters.splice(0))
|
|
12023
12206
|
w();
|
|
@@ -12452,7 +12635,7 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
12452
12635
|
data = evt.data;
|
|
12453
12636
|
bytes = new TextEncoder().encode(data).byteLength;
|
|
12454
12637
|
try {
|
|
12455
|
-
json = JSON.parse(data);
|
|
12638
|
+
json = sanitizeParsedJSON(JSON.parse(data));
|
|
12456
12639
|
} catch {
|
|
12457
12640
|
}
|
|
12458
12641
|
} else if (evt.data instanceof ArrayBuffer) {
|
|
@@ -13157,27 +13340,33 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
13157
13340
|
}, ms);
|
|
13158
13341
|
const existing = ctx.request.signal;
|
|
13159
13342
|
if (existing) {
|
|
13160
|
-
|
|
13343
|
+
const onExistingAbort = () => {
|
|
13161
13344
|
clearTimeout(timer);
|
|
13162
13345
|
controller.abort(existing.reason);
|
|
13163
|
-
}
|
|
13346
|
+
};
|
|
13347
|
+
existing.addEventListener("abort", onExistingAbort, { once: true });
|
|
13348
|
+
ctx.store.set(TIMEOUT_SIGNAL_KEY, { existing, onExistingAbort });
|
|
13164
13349
|
}
|
|
13165
13350
|
ctx.request = { ...ctx.request, signal: controller.signal };
|
|
13166
13351
|
ctx.store.set(TIMEOUT_TIMER_KEY, timer);
|
|
13167
13352
|
};
|
|
13168
|
-
const
|
|
13353
|
+
const cleanupTimeout = (ctx) => {
|
|
13169
13354
|
const timer = ctx.store.get(TIMEOUT_TIMER_KEY);
|
|
13170
13355
|
if (timer) {
|
|
13171
13356
|
clearTimeout(timer);
|
|
13172
13357
|
ctx.store.delete(TIMEOUT_TIMER_KEY);
|
|
13173
13358
|
}
|
|
13359
|
+
const merged = ctx.store.get(TIMEOUT_SIGNAL_KEY);
|
|
13360
|
+
if (merged) {
|
|
13361
|
+
merged.existing.removeEventListener("abort", merged.onExistingAbort);
|
|
13362
|
+
ctx.store.delete(TIMEOUT_SIGNAL_KEY);
|
|
13363
|
+
}
|
|
13364
|
+
};
|
|
13365
|
+
const responseInterceptor = (ctx) => {
|
|
13366
|
+
cleanupTimeout(ctx);
|
|
13174
13367
|
};
|
|
13175
13368
|
const errorInterceptor = (ctx) => {
|
|
13176
|
-
|
|
13177
|
-
if (timer) {
|
|
13178
|
-
clearTimeout(timer);
|
|
13179
|
-
ctx.store.delete(TIMEOUT_TIMER_KEY);
|
|
13180
|
-
}
|
|
13369
|
+
cleanupTimeout(ctx);
|
|
13181
13370
|
};
|
|
13182
13371
|
return {
|
|
13183
13372
|
id: "timeout",
|
|
@@ -13187,6 +13376,7 @@ ${text}`, "ENETWORK", void 0, req, void 0, new Error(`HTTP ${response.status}`))
|
|
|
13187
13376
|
};
|
|
13188
13377
|
}
|
|
13189
13378
|
var TIMEOUT_TIMER_KEY = /* @__PURE__ */ Symbol("timeoutTimer");
|
|
13379
|
+
var TIMEOUT_SIGNAL_KEY = /* @__PURE__ */ Symbol("timeoutSignal");
|
|
13190
13380
|
var TimeoutError2 = class extends Error {
|
|
13191
13381
|
constructor(message, timeoutMs) {
|
|
13192
13382
|
super(message);
|
|
@@ -14868,6 +15058,34 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
14868
15058
|
function randomHex(len) {
|
|
14869
15059
|
return randomBytes(len / 2);
|
|
14870
15060
|
}
|
|
15061
|
+
var HAR_REDACT_HEADERS = /* @__PURE__ */ new Set([
|
|
15062
|
+
"authorization",
|
|
15063
|
+
"proxy-authorization",
|
|
15064
|
+
"cookie",
|
|
15065
|
+
"set-cookie",
|
|
15066
|
+
"x-api-key",
|
|
15067
|
+
"x-auth-token",
|
|
15068
|
+
"x-access-token",
|
|
15069
|
+
"x-refresh-token",
|
|
15070
|
+
"x-csrf-token",
|
|
15071
|
+
"x-session-id",
|
|
15072
|
+
"x-session-token",
|
|
15073
|
+
"x-secret",
|
|
15074
|
+
"x-secret-key",
|
|
15075
|
+
"x-private-key",
|
|
15076
|
+
"api-key",
|
|
15077
|
+
"apikey",
|
|
15078
|
+
"bearer",
|
|
15079
|
+
"token",
|
|
15080
|
+
"authentication",
|
|
15081
|
+
"credentials",
|
|
15082
|
+
"password",
|
|
15083
|
+
"passwd",
|
|
15084
|
+
"secret"
|
|
15085
|
+
]);
|
|
15086
|
+
function redactHARHeader(name, value) {
|
|
15087
|
+
return HAR_REDACT_HEADERS.has(name.toLowerCase()) ? { name, value: "***REDACTED***" } : { name, value };
|
|
15088
|
+
}
|
|
14871
15089
|
var HARRecorder = class {
|
|
14872
15090
|
/**
|
|
14873
15091
|
* @param maxEntries - Maximum number of entries before eviction (default 10000).
|
|
@@ -14919,7 +15137,7 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
14919
15137
|
method: req.method,
|
|
14920
15138
|
url: req.url,
|
|
14921
15139
|
httpVersion: res.httpVersion,
|
|
14922
|
-
headers: Object.entries(req.headers).map(([name, value]) => (
|
|
15140
|
+
headers: Object.entries(req.headers).map(([name, value]) => redactHARHeader(name, value)),
|
|
14923
15141
|
queryString: (() => {
|
|
14924
15142
|
try {
|
|
14925
15143
|
return Array.from(new URL(req.url).searchParams.entries()).map(([name, value]) => ({
|
|
@@ -14946,7 +15164,7 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
14946
15164
|
status: res.status,
|
|
14947
15165
|
statusText: res.statusText,
|
|
14948
15166
|
httpVersion: res.httpVersion,
|
|
14949
|
-
headers: Object.entries(res.headers).map(([name, value]) => (
|
|
15167
|
+
headers: Object.entries(res.headers).map(([name, value]) => redactHARHeader(name, value)),
|
|
14950
15168
|
content: {
|
|
14951
15169
|
size: res.rawBody?.byteLength ?? 0,
|
|
14952
15170
|
mimeType: res.headers["content-type"] ?? "application/octet-stream",
|
|
@@ -14994,7 +15212,11 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
14994
15212
|
switch (auth.type) {
|
|
14995
15213
|
case "bearer": {
|
|
14996
15214
|
const token = typeof auth.token === "function" ? await auth.token() : auth.token;
|
|
14997
|
-
|
|
15215
|
+
const headerValue = `Bearer ${token}`;
|
|
15216
|
+
if (!isValidHeaderValue(headerValue)) {
|
|
15217
|
+
throw new KinetexError("Invalid bearer token \u2014 contains forbidden characters (CRLF/CTL)", "EVALIDATION");
|
|
15218
|
+
}
|
|
15219
|
+
headers["authorization"] = headerValue;
|
|
14998
15220
|
break;
|
|
14999
15221
|
}
|
|
15000
15222
|
case "basic": {
|
|
@@ -15015,7 +15237,13 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
15015
15237
|
}
|
|
15016
15238
|
case "apikey": {
|
|
15017
15239
|
const key = typeof auth.key === "function" ? await auth.key() : auth.key;
|
|
15018
|
-
|
|
15240
|
+
if (!isValidHeaderName(auth.header)) {
|
|
15241
|
+
throw new KinetexError(`Invalid apikey auth header name: "${auth.header}"`, "EVALIDATION");
|
|
15242
|
+
}
|
|
15243
|
+
if (!isValidHeaderValue(String(key))) {
|
|
15244
|
+
throw new KinetexError(`Invalid apikey value for "${auth.header}" \u2014 contains forbidden characters`, "EVALIDATION");
|
|
15245
|
+
}
|
|
15246
|
+
headers[auth.header.toLowerCase()] = String(key);
|
|
15019
15247
|
break;
|
|
15020
15248
|
}
|
|
15021
15249
|
case "digest": {
|
|
@@ -15034,6 +15262,37 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
15034
15262
|
}
|
|
15035
15263
|
return { ...req, headers };
|
|
15036
15264
|
}
|
|
15265
|
+
var CROSS_ORIGIN_STRIP_HEADERS = /* @__PURE__ */ new Set([
|
|
15266
|
+
"authorization",
|
|
15267
|
+
"cookie",
|
|
15268
|
+
"proxy-authorization",
|
|
15269
|
+
"x-api-key",
|
|
15270
|
+
"x-auth-token",
|
|
15271
|
+
"x-access-token",
|
|
15272
|
+
"x-refresh-token",
|
|
15273
|
+
"x-csrf-token",
|
|
15274
|
+
"x-session-id",
|
|
15275
|
+
"x-session-token",
|
|
15276
|
+
"x-secret",
|
|
15277
|
+
"x-secret-key",
|
|
15278
|
+
"x-private-key",
|
|
15279
|
+
"api-key",
|
|
15280
|
+
"apikey",
|
|
15281
|
+
"www-authenticate"
|
|
15282
|
+
]);
|
|
15283
|
+
function redactUserInfo(url) {
|
|
15284
|
+
try {
|
|
15285
|
+
const u = new URL(url);
|
|
15286
|
+
if (u.username || u.password) {
|
|
15287
|
+
u.username = "";
|
|
15288
|
+
u.password = "";
|
|
15289
|
+
return u.toString();
|
|
15290
|
+
}
|
|
15291
|
+
return url;
|
|
15292
|
+
} catch {
|
|
15293
|
+
return url.replace(/\/\/[^/@]*@/, "//");
|
|
15294
|
+
}
|
|
15295
|
+
}
|
|
15037
15296
|
function buildURL(base, url, params) {
|
|
15038
15297
|
const MAX_QUERY_PARAM_COUNT = 100;
|
|
15039
15298
|
const MAX_URL_LENGTH = 8192;
|
|
@@ -15054,7 +15313,7 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
15054
15313
|
}
|
|
15055
15314
|
if (!params || Object.keys(params).length === 0) {
|
|
15056
15315
|
if (!isSafeURL(full)) {
|
|
15057
|
-
throw new KinetexError(`URL "${full}" failed safety check \u2014 blocked private/loopback address or forbidden scheme`, "EVALIDATION");
|
|
15316
|
+
throw new KinetexError(`URL "${redactUserInfo(full)}" failed safety check \u2014 blocked private/loopback address or forbidden scheme`, "EVALIDATION");
|
|
15058
15317
|
}
|
|
15059
15318
|
return full;
|
|
15060
15319
|
}
|
|
@@ -15088,7 +15347,7 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
15088
15347
|
throw new KinetexError(`URL length ${result.length} bytes exceeds limit of ${MAX_URL_LENGTH} bytes`, "EVALIDATION");
|
|
15089
15348
|
}
|
|
15090
15349
|
if (!isSafeURL(result)) {
|
|
15091
|
-
throw new KinetexError(`URL "${result}" failed safety check \u2014 blocked private/loopback address or forbidden scheme`, "EVALIDATION");
|
|
15350
|
+
throw new KinetexError(`URL "${redactUserInfo(result)}" failed safety check \u2014 blocked private/loopback address or forbidden scheme`, "EVALIDATION");
|
|
15092
15351
|
}
|
|
15093
15352
|
return result;
|
|
15094
15353
|
} catch (err) {
|
|
@@ -15126,6 +15385,9 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
15126
15385
|
if (result.length > MAX_URL_LENGTH) {
|
|
15127
15386
|
throw new KinetexError(`URL length ${result.length} bytes exceeds limit of ${MAX_URL_LENGTH} bytes`, "EVALIDATION");
|
|
15128
15387
|
}
|
|
15388
|
+
if (!isSafeURL(result)) {
|
|
15389
|
+
throw new KinetexError(`URL "${redactUserInfo(result)}" failed safety check \u2014 blocked private/loopback address or forbidden scheme`, "EVALIDATION");
|
|
15390
|
+
}
|
|
15129
15391
|
return result;
|
|
15130
15392
|
}
|
|
15131
15393
|
}
|
|
@@ -15873,6 +16135,10 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
15873
16135
|
throw new KinetexError(`Invalid HTTP method '${method}'. Valid methods: ${VALID_METHODS.join(", ")}`, "EVALIDATION");
|
|
15874
16136
|
}
|
|
15875
16137
|
const fullUrl = buildURL(options.baseURL ?? this.cfg.baseURL, url, mergeParams(this.cfg.params, options.params));
|
|
16138
|
+
const proxy = options.proxy ?? this.cfg.proxy;
|
|
16139
|
+
if (proxy) {
|
|
16140
|
+
throw new KinetexError("proxy is configured but kinetex's built-in transports cannot route through it: HTTP(S) proxies require a custom fetch with a proxy agent (e.g. undici ProxyAgent passed via the `fetch` option), and SOCKS5 requires createSocks5Tunnel() from kinetex/socks5. Set up one of those instead of relying on `proxy` silently doing nothing.", "EVALIDATION");
|
|
16141
|
+
}
|
|
15876
16142
|
if (this.cfg.httpsOnly) {
|
|
15877
16143
|
try {
|
|
15878
16144
|
const parsedUrl = new URL(fullUrl);
|
|
@@ -15896,9 +16162,25 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
15896
16162
|
bodySize2 = options.body.byteLength;
|
|
15897
16163
|
} else if (options.body instanceof Blob) {
|
|
15898
16164
|
bodySize2 = options.body.size;
|
|
16165
|
+
} else if (ArrayBuffer.isView(options.body)) {
|
|
16166
|
+
bodySize2 = options.body.byteLength;
|
|
16167
|
+
} else if (options.body instanceof URLSearchParams) {
|
|
16168
|
+
bodySize2 = new TextEncoder().encode(options.body.toString()).byteLength;
|
|
15899
16169
|
} else if (options.body instanceof FormData) {
|
|
16170
|
+
const boundaryOverhead = 76;
|
|
16171
|
+
for (const [name, value] of options.body) {
|
|
16172
|
+
bodySize2 += new TextEncoder().encode(name).byteLength + boundaryOverhead;
|
|
16173
|
+
if (typeof value === "string") {
|
|
16174
|
+
bodySize2 += new TextEncoder().encode(value).byteLength;
|
|
16175
|
+
} else {
|
|
16176
|
+
bodySize2 += value.size;
|
|
16177
|
+
}
|
|
16178
|
+
}
|
|
16179
|
+
bodySize2 += boundaryOverhead;
|
|
16180
|
+
} else if (options.body instanceof ReadableStream) {
|
|
16181
|
+
throw new KinetexError(`maxRequestSize cannot be enforced for ReadableStream bodies \u2014 pass maxRequestSize: 0 to opt out, or buffer the body first`, "EVALIDATION");
|
|
15900
16182
|
} else if (options.body && typeof options.body === "object") {
|
|
15901
|
-
bodySize2 = JSON.stringify(options.body).
|
|
16183
|
+
bodySize2 = new TextEncoder().encode(JSON.stringify(options.body)).byteLength;
|
|
15902
16184
|
}
|
|
15903
16185
|
if (bodySize2 > maxRequestSize) {
|
|
15904
16186
|
throw new KinetexError(`Request body size ${bodySize2} bytes exceeds limit of ${maxRequestSize} bytes`, "EVALIDATION");
|
|
@@ -16078,10 +16360,26 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
16078
16360
|
async _sendFollowingRedirects(req, timeout, jar, appliedAuth) {
|
|
16079
16361
|
const MAX_REDIRECTS = 20;
|
|
16080
16362
|
let currentReq = { ...req, redirect: "manual" };
|
|
16363
|
+
const origin0 = (() => {
|
|
16364
|
+
try {
|
|
16365
|
+
return new URL(req.url).origin;
|
|
16366
|
+
} catch {
|
|
16367
|
+
return null;
|
|
16368
|
+
}
|
|
16369
|
+
})();
|
|
16081
16370
|
const visited = /* @__PURE__ */ new Set();
|
|
16082
16371
|
for (let hop = 0; hop <= MAX_REDIRECTS; hop++) {
|
|
16083
16372
|
if (hop > 0 && appliedAuth) {
|
|
16084
|
-
|
|
16373
|
+
const sameOrigin = (() => {
|
|
16374
|
+
try {
|
|
16375
|
+
return new URL(currentReq.url).origin === origin0;
|
|
16376
|
+
} catch {
|
|
16377
|
+
return false;
|
|
16378
|
+
}
|
|
16379
|
+
})();
|
|
16380
|
+
if (sameOrigin) {
|
|
16381
|
+
currentReq = await applyAuth(currentReq, appliedAuth);
|
|
16382
|
+
}
|
|
16085
16383
|
}
|
|
16086
16384
|
if (hop > 0 && this.cfg.hooks?.onBeforeRequest) {
|
|
16087
16385
|
for (const fn of this.cfg.hooks.onBeforeRequest) {
|
|
@@ -16153,6 +16451,14 @@ ${errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
|
16153
16451
|
} else {
|
|
16154
16452
|
delete nextHeaders["cookie"];
|
|
16155
16453
|
}
|
|
16454
|
+
try {
|
|
16455
|
+
if (new URL(nextUrl).origin !== new URL(currentReq.url).origin) {
|
|
16456
|
+
for (const h of CROSS_ORIGIN_STRIP_HEADERS) {
|
|
16457
|
+
delete nextHeaders[h];
|
|
16458
|
+
}
|
|
16459
|
+
}
|
|
16460
|
+
} catch {
|
|
16461
|
+
}
|
|
16156
16462
|
currentReq = {
|
|
16157
16463
|
...currentReq,
|
|
16158
16464
|
url: nextUrl,
|