@revenexx/integrations-node-sdk 1.8.0 → 1.9.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/dist/index.cjs +57 -2
- package/dist/index.js +57 -2
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -496,6 +496,43 @@ var CROSS_ORIGIN_SAFE_HEADERS = /* @__PURE__ */ new Set([
|
|
|
496
496
|
function headerCrossesOrigin(name) {
|
|
497
497
|
return CROSS_ORIGIN_SAFE_HEADERS.has(name.trim().toLowerCase());
|
|
498
498
|
}
|
|
499
|
+
var UNSENDABLE_IN_HEADER_VALUE = /[\0-\x08\x0a-\x1f\x7f\u0100-\uffff]/;
|
|
500
|
+
var HEADER_NAME_TOKEN = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
|
|
501
|
+
function isHttpWhitespace(code) {
|
|
502
|
+
return code === 9 || code === 10 || code === 13 || code === 32;
|
|
503
|
+
}
|
|
504
|
+
function trimHttpWhitespace(value) {
|
|
505
|
+
let start = 0;
|
|
506
|
+
let end = value.length;
|
|
507
|
+
while (start < end && isHttpWhitespace(value.charCodeAt(start))) start++;
|
|
508
|
+
while (end > start && isHttpWhitespace(value.charCodeAt(end - 1))) end--;
|
|
509
|
+
return value.slice(start, end);
|
|
510
|
+
}
|
|
511
|
+
function invalidHeader(detail) {
|
|
512
|
+
return new NodeError("INVALID_HEADER", detail, { status: 0 });
|
|
513
|
+
}
|
|
514
|
+
function sendableHeaders(headers) {
|
|
515
|
+
if (typeof headers !== "object" || headers === null) {
|
|
516
|
+
throw invalidHeader("Headers must be an object or a list of pairs");
|
|
517
|
+
}
|
|
518
|
+
if (!(Symbol.iterator in headers) && Object.getOwnPropertySymbols(headers).length > 0) {
|
|
519
|
+
throw invalidHeader("A header name must be a string, not a symbol");
|
|
520
|
+
}
|
|
521
|
+
const entries = Symbol.iterator in headers ? Array.from(headers) : Object.entries(headers);
|
|
522
|
+
return entries.map((entry, i) => {
|
|
523
|
+
const pair = typeof entry === "object" && entry !== null && Symbol.iterator in entry ? Array.from(entry) : [];
|
|
524
|
+
if (pair.length !== 2) throw invalidHeader(`Header entry ${i} is not a name/value pair`);
|
|
525
|
+
const name = String(pair[0]);
|
|
526
|
+
const value = String(pair[1]);
|
|
527
|
+
if (!HEADER_NAME_TOKEN.test(name)) {
|
|
528
|
+
throw invalidHeader(`Header name ${JSON.stringify(name)} cannot be sent`);
|
|
529
|
+
}
|
|
530
|
+
if (UNSENDABLE_IN_HEADER_VALUE.test(trimHttpWhitespace(value))) {
|
|
531
|
+
throw invalidHeader(`Header ${JSON.stringify(name)} has a character in its value that cannot be sent`);
|
|
532
|
+
}
|
|
533
|
+
return [name, value];
|
|
534
|
+
});
|
|
535
|
+
}
|
|
499
536
|
var DEFAULT_RETRY_ATTEMPTS = 0;
|
|
500
537
|
var MAX_RETRY_ATTEMPTS = 5;
|
|
501
538
|
var DEFAULT_RETRY_DELAY_MS = 1e3;
|
|
@@ -535,6 +572,15 @@ async function guardUrl(url, ctxSignal, effectiveMs) {
|
|
|
535
572
|
clearTimeout(timer);
|
|
536
573
|
}
|
|
537
574
|
}
|
|
575
|
+
function hasContent(body) {
|
|
576
|
+
if (body == null) return false;
|
|
577
|
+
if (typeof body === "string") return body.length > 0;
|
|
578
|
+
if (body instanceof ArrayBuffer) return body.byteLength > 0;
|
|
579
|
+
if (ArrayBuffer.isView(body)) return body.byteLength > 0;
|
|
580
|
+
if (body instanceof Blob) return body.size > 0;
|
|
581
|
+
if (body instanceof URLSearchParams) return body.toString().length > 0;
|
|
582
|
+
return true;
|
|
583
|
+
}
|
|
538
584
|
async function guardedFetch(url, fetchOptions, ctxSignal, effectiveMs) {
|
|
539
585
|
let currentUrl = url;
|
|
540
586
|
let currentInit = { ...fetchOptions, redirect: "manual" };
|
|
@@ -567,8 +613,7 @@ async function guardedFetch(url, fetchOptions, ctxSignal, effectiveMs) {
|
|
|
567
613
|
if (base.protocol === "https:" && nextUrl.protocol !== "https:") {
|
|
568
614
|
throw new NodeError("BLOCKED_ADDRESS", "Blocked https\u2192http downgrade on redirect", { status: 0 });
|
|
569
615
|
}
|
|
570
|
-
|
|
571
|
-
const headers = new Headers(currentInit.headers ?? void 0);
|
|
616
|
+
const headers = new Headers(currentInit.headers);
|
|
572
617
|
let method = (currentInit.method ?? "GET").toUpperCase();
|
|
573
618
|
let body = currentInit.body;
|
|
574
619
|
if (redirectStatus === 303 || (redirectStatus === 301 || redirectStatus === 302) && method === "POST") {
|
|
@@ -577,6 +622,14 @@ async function guardedFetch(url, fetchOptions, ctxSignal, effectiveMs) {
|
|
|
577
622
|
headers.delete("content-type");
|
|
578
623
|
headers.delete("content-length");
|
|
579
624
|
}
|
|
625
|
+
if (hasContent(body) && nextUrl.origin !== base.origin) {
|
|
626
|
+
throw new NodeError(
|
|
627
|
+
"BLOCKED_ADDRESS",
|
|
628
|
+
`Blocked ${redirectStatus} redirect to another origin: it would resend the request body to ${nextUrl.origin}`,
|
|
629
|
+
{ status: 0 }
|
|
630
|
+
);
|
|
631
|
+
}
|
|
632
|
+
await guardUrl(nextUrl, ctxSignal, effectiveMs);
|
|
580
633
|
if (nextUrl.origin !== base.origin) {
|
|
581
634
|
for (const name of [...headers.keys()]) {
|
|
582
635
|
if (!headerCrossesOrigin(name)) headers.delete(name);
|
|
@@ -593,6 +646,8 @@ async function safeFetch(url, options = {}) {
|
|
|
593
646
|
const safeAttempts = Number.isFinite(rawAttempts) ? Math.min(Math.max(0, rawAttempts), MAX_RETRY_ATTEMPTS) : DEFAULT_RETRY_ATTEMPTS;
|
|
594
647
|
const maxAttempts = safeAttempts + 1;
|
|
595
648
|
const retryDelayMs = retry?.delayMs ?? DEFAULT_RETRY_DELAY_MS;
|
|
649
|
+
if (ctxSignal?.aborted) throw ctxSignal.reason;
|
|
650
|
+
if (fetchOptions.headers !== void 0) fetchOptions.headers = sendableHeaders(fetchOptions.headers);
|
|
596
651
|
let lastError;
|
|
597
652
|
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
598
653
|
if (ctxSignal?.aborted) throw ctxSignal.reason;
|
package/dist/index.js
CHANGED
|
@@ -404,6 +404,43 @@ var CROSS_ORIGIN_SAFE_HEADERS = /* @__PURE__ */ new Set([
|
|
|
404
404
|
function headerCrossesOrigin(name) {
|
|
405
405
|
return CROSS_ORIGIN_SAFE_HEADERS.has(name.trim().toLowerCase());
|
|
406
406
|
}
|
|
407
|
+
var UNSENDABLE_IN_HEADER_VALUE = /[\0-\x08\x0a-\x1f\x7f\u0100-\uffff]/;
|
|
408
|
+
var HEADER_NAME_TOKEN = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
|
|
409
|
+
function isHttpWhitespace(code) {
|
|
410
|
+
return code === 9 || code === 10 || code === 13 || code === 32;
|
|
411
|
+
}
|
|
412
|
+
function trimHttpWhitespace(value) {
|
|
413
|
+
let start = 0;
|
|
414
|
+
let end = value.length;
|
|
415
|
+
while (start < end && isHttpWhitespace(value.charCodeAt(start))) start++;
|
|
416
|
+
while (end > start && isHttpWhitespace(value.charCodeAt(end - 1))) end--;
|
|
417
|
+
return value.slice(start, end);
|
|
418
|
+
}
|
|
419
|
+
function invalidHeader(detail) {
|
|
420
|
+
return new NodeError("INVALID_HEADER", detail, { status: 0 });
|
|
421
|
+
}
|
|
422
|
+
function sendableHeaders(headers) {
|
|
423
|
+
if (typeof headers !== "object" || headers === null) {
|
|
424
|
+
throw invalidHeader("Headers must be an object or a list of pairs");
|
|
425
|
+
}
|
|
426
|
+
if (!(Symbol.iterator in headers) && Object.getOwnPropertySymbols(headers).length > 0) {
|
|
427
|
+
throw invalidHeader("A header name must be a string, not a symbol");
|
|
428
|
+
}
|
|
429
|
+
const entries = Symbol.iterator in headers ? Array.from(headers) : Object.entries(headers);
|
|
430
|
+
return entries.map((entry, i) => {
|
|
431
|
+
const pair = typeof entry === "object" && entry !== null && Symbol.iterator in entry ? Array.from(entry) : [];
|
|
432
|
+
if (pair.length !== 2) throw invalidHeader(`Header entry ${i} is not a name/value pair`);
|
|
433
|
+
const name = String(pair[0]);
|
|
434
|
+
const value = String(pair[1]);
|
|
435
|
+
if (!HEADER_NAME_TOKEN.test(name)) {
|
|
436
|
+
throw invalidHeader(`Header name ${JSON.stringify(name)} cannot be sent`);
|
|
437
|
+
}
|
|
438
|
+
if (UNSENDABLE_IN_HEADER_VALUE.test(trimHttpWhitespace(value))) {
|
|
439
|
+
throw invalidHeader(`Header ${JSON.stringify(name)} has a character in its value that cannot be sent`);
|
|
440
|
+
}
|
|
441
|
+
return [name, value];
|
|
442
|
+
});
|
|
443
|
+
}
|
|
407
444
|
var DEFAULT_RETRY_ATTEMPTS = 0;
|
|
408
445
|
var MAX_RETRY_ATTEMPTS = 5;
|
|
409
446
|
var DEFAULT_RETRY_DELAY_MS = 1e3;
|
|
@@ -443,6 +480,15 @@ async function guardUrl(url, ctxSignal, effectiveMs) {
|
|
|
443
480
|
clearTimeout(timer);
|
|
444
481
|
}
|
|
445
482
|
}
|
|
483
|
+
function hasContent(body) {
|
|
484
|
+
if (body == null) return false;
|
|
485
|
+
if (typeof body === "string") return body.length > 0;
|
|
486
|
+
if (body instanceof ArrayBuffer) return body.byteLength > 0;
|
|
487
|
+
if (ArrayBuffer.isView(body)) return body.byteLength > 0;
|
|
488
|
+
if (body instanceof Blob) return body.size > 0;
|
|
489
|
+
if (body instanceof URLSearchParams) return body.toString().length > 0;
|
|
490
|
+
return true;
|
|
491
|
+
}
|
|
446
492
|
async function guardedFetch(url, fetchOptions, ctxSignal, effectiveMs) {
|
|
447
493
|
let currentUrl = url;
|
|
448
494
|
let currentInit = { ...fetchOptions, redirect: "manual" };
|
|
@@ -475,8 +521,7 @@ async function guardedFetch(url, fetchOptions, ctxSignal, effectiveMs) {
|
|
|
475
521
|
if (base.protocol === "https:" && nextUrl.protocol !== "https:") {
|
|
476
522
|
throw new NodeError("BLOCKED_ADDRESS", "Blocked https\u2192http downgrade on redirect", { status: 0 });
|
|
477
523
|
}
|
|
478
|
-
|
|
479
|
-
const headers = new Headers(currentInit.headers ?? void 0);
|
|
524
|
+
const headers = new Headers(currentInit.headers);
|
|
480
525
|
let method = (currentInit.method ?? "GET").toUpperCase();
|
|
481
526
|
let body = currentInit.body;
|
|
482
527
|
if (redirectStatus === 303 || (redirectStatus === 301 || redirectStatus === 302) && method === "POST") {
|
|
@@ -485,6 +530,14 @@ async function guardedFetch(url, fetchOptions, ctxSignal, effectiveMs) {
|
|
|
485
530
|
headers.delete("content-type");
|
|
486
531
|
headers.delete("content-length");
|
|
487
532
|
}
|
|
533
|
+
if (hasContent(body) && nextUrl.origin !== base.origin) {
|
|
534
|
+
throw new NodeError(
|
|
535
|
+
"BLOCKED_ADDRESS",
|
|
536
|
+
`Blocked ${redirectStatus} redirect to another origin: it would resend the request body to ${nextUrl.origin}`,
|
|
537
|
+
{ status: 0 }
|
|
538
|
+
);
|
|
539
|
+
}
|
|
540
|
+
await guardUrl(nextUrl, ctxSignal, effectiveMs);
|
|
488
541
|
if (nextUrl.origin !== base.origin) {
|
|
489
542
|
for (const name of [...headers.keys()]) {
|
|
490
543
|
if (!headerCrossesOrigin(name)) headers.delete(name);
|
|
@@ -501,6 +554,8 @@ async function safeFetch(url, options = {}) {
|
|
|
501
554
|
const safeAttempts = Number.isFinite(rawAttempts) ? Math.min(Math.max(0, rawAttempts), MAX_RETRY_ATTEMPTS) : DEFAULT_RETRY_ATTEMPTS;
|
|
502
555
|
const maxAttempts = safeAttempts + 1;
|
|
503
556
|
const retryDelayMs = retry?.delayMs ?? DEFAULT_RETRY_DELAY_MS;
|
|
557
|
+
if (ctxSignal?.aborted) throw ctxSignal.reason;
|
|
558
|
+
if (fetchOptions.headers !== void 0) fetchOptions.headers = sendableHeaders(fetchOptions.headers);
|
|
504
559
|
let lastError;
|
|
505
560
|
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
506
561
|
if (ctxSignal?.aborted) throw ctxSignal.reason;
|