rekwest 7.2.2 → 7.2.4
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 +2 -3
- package/dist/cookies.cjs +45 -26
- package/dist/formdata.cjs +8 -9
- package/dist/preflight.cjs +1 -1
- package/dist/retries.cjs +2 -2
- package/dist/utils.cjs +23 -17
- package/package.json +1 -1
- package/src/cookies.js +47 -30
- package/src/formdata.js +8 -9
- package/src/preflight.js +1 -1
- package/src/retries.js +2 -2
- package/src/utils.js +23 -23
package/README.md
CHANGED
|
@@ -127,9 +127,8 @@ console.log(res.body);
|
|
|
127
127
|
with the request
|
|
128
128
|
* `bufferBody` **{boolean}** `Default: false` Toggles the buffering of the streamable request bodies for redirects and
|
|
129
129
|
retries
|
|
130
|
-
* `cookies` **{boolean | string[] |
|
|
131
|
-
cookies to add to
|
|
132
|
-
the request
|
|
130
|
+
* `cookies` **{boolean | string | string[] | [k, v][] | Cookies | Object | URLSearchParams}** `Default: true` The
|
|
131
|
+
cookies to add to the request. Manually set `cookie` header to override.
|
|
133
132
|
* `cookiesTTL` **{boolean}** `Default: false` Controls enablement of TTL for the cookies cache
|
|
134
133
|
* `credentials` **{include | omit | same-origin}** `Default: same-origin` Controls credentials in case of cross-origin
|
|
135
134
|
redirects
|
package/dist/cookies.cjs
CHANGED
|
@@ -3,10 +3,17 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.Cookies = void 0;
|
|
6
|
+
exports.splitCookie = exports.maxCookieSize = exports.maxCookieLifetimeCap = exports.isValidCookie = exports.illegalCookieChars = exports.cookieRex = exports.cookiePairRex = exports.Cookies = void 0;
|
|
7
7
|
var _utils = require("./utils.cjs");
|
|
8
|
-
const
|
|
9
|
-
|
|
8
|
+
const cookieRex = exports.cookieRex = /^[\w-]+=(?:"[^"]*"|[^\p{Control};]*)(?:;\s*(?:[\w-]+=(?:"[^"]*"|[^\p{Control};]*)|[\w-]+))*$/u;
|
|
9
|
+
const cookiePairRex = exports.cookiePairRex = /(?:[^;"\s]+="[^"]*"|[^;]+)(?=;|$)/g;
|
|
10
|
+
const illegalCookieChars = exports.illegalCookieChars = /\p{Control}/u;
|
|
11
|
+
const isValidCookie = str => str?.constructor === String && cookieRex.test(str);
|
|
12
|
+
exports.isValidCookie = isValidCookie;
|
|
13
|
+
const maxCookieLifetimeCap = exports.maxCookieLifetimeCap = 3456e7; // 400 days
|
|
14
|
+
const maxCookieSize = exports.maxCookieSize = 4096;
|
|
15
|
+
const splitCookie = str => str.match(cookiePairRex).map(str => str.trim());
|
|
16
|
+
exports.splitCookie = splitCookie;
|
|
10
17
|
class Cookies extends URLSearchParams {
|
|
11
18
|
static #finalizers = new Set();
|
|
12
19
|
static jar = new Map();
|
|
@@ -27,27 +34,39 @@ class Cookies extends URLSearchParams {
|
|
|
27
34
|
} = {
|
|
28
35
|
cookiesTTL: false
|
|
29
36
|
}) {
|
|
30
|
-
if (
|
|
31
|
-
input = input
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
37
|
+
if (isValidCookie(input)) {
|
|
38
|
+
input = splitCookie(input);
|
|
39
|
+
}
|
|
40
|
+
const ttlMap = new Map();
|
|
41
|
+
if (Array.isArray(input)) {
|
|
42
|
+
if (input.every(it => isValidCookie(it))) {
|
|
43
|
+
input = input.filter(it => !illegalCookieChars.test(it) && it.length <= maxCookieSize);
|
|
44
|
+
input = input.map(splitCookie).map(([cookie, ...attrs]) => {
|
|
45
|
+
try {
|
|
46
|
+
cookie = cookie.split('=').map(it => decodeURIComponent(it.trim()));
|
|
47
|
+
return cookie;
|
|
48
|
+
} finally {
|
|
49
|
+
if (cookiesTTL) {
|
|
50
|
+
for (const attr of attrs) {
|
|
51
|
+
if (/(?:expires|max-age)=/i.test(attr)) {
|
|
52
|
+
const [key, val] = attr.toLowerCase().split('=');
|
|
53
|
+
let interval = val * 1e3 || Date.parse(val) - Date.now();
|
|
54
|
+
if (interval < 0 || Number.isNaN(interval)) {
|
|
55
|
+
interval = 0;
|
|
56
|
+
}
|
|
57
|
+
ttlMap.set(cookie[0], {
|
|
58
|
+
[(0, _utils.toCamelCase)(key.trim())]: Math.min(interval, maxCookieLifetimeCap)
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
42
63
|
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
});
|
|
64
|
+
});
|
|
65
|
+
}
|
|
46
66
|
}
|
|
47
|
-
super(
|
|
48
|
-
if (
|
|
49
|
-
for (const [
|
|
50
|
-
const key = cookie.split('=').at(0);
|
|
67
|
+
super(input);
|
|
68
|
+
if (ttlMap.size) {
|
|
69
|
+
for (const [key, attrs] of ttlMap) {
|
|
51
70
|
if (this.#chronometry.has(key)) {
|
|
52
71
|
clearTimeout(this.#chronometry.get(key));
|
|
53
72
|
this.#chronometry.delete(key);
|
|
@@ -55,9 +74,9 @@ class Cookies extends URLSearchParams {
|
|
|
55
74
|
const {
|
|
56
75
|
expires,
|
|
57
76
|
maxAge
|
|
58
|
-
} =
|
|
59
|
-
for (const
|
|
60
|
-
if (!Number.isInteger(
|
|
77
|
+
} = attrs;
|
|
78
|
+
for (const interval of [maxAge, expires]) {
|
|
79
|
+
if (!Number.isInteger(interval)) {
|
|
61
80
|
continue;
|
|
62
81
|
}
|
|
63
82
|
const ref = new WeakRef(this);
|
|
@@ -67,7 +86,7 @@ class Cookies extends URLSearchParams {
|
|
|
67
86
|
ctx.#chronometry.delete(key);
|
|
68
87
|
ctx.delete(key);
|
|
69
88
|
}
|
|
70
|
-
}, Math.max(
|
|
89
|
+
}, Math.max(interval, 0));
|
|
71
90
|
this.constructor.#register(this, tid);
|
|
72
91
|
this.#chronometry.set(key, tid);
|
|
73
92
|
break;
|
package/dist/formdata.cjs
CHANGED
|
@@ -7,7 +7,6 @@ exports.FormData = void 0;
|
|
|
7
7
|
var _nodeBuffer = require("node:buffer");
|
|
8
8
|
var _nodeCrypto = require("node:crypto");
|
|
9
9
|
var _nodeHttp = _interopRequireDefault(require("node:http2"));
|
|
10
|
-
var _nodeUtil = require("node:util");
|
|
11
10
|
var _mediatypes = require("./mediatypes.cjs");
|
|
12
11
|
var _utils = require("./utils.cjs");
|
|
13
12
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
@@ -44,15 +43,15 @@ class FormData {
|
|
|
44
43
|
return FormData.name === val?.[Symbol.toStringTag];
|
|
45
44
|
}
|
|
46
45
|
static #enfoldEntry(name, value, filename) {
|
|
47
|
-
name = (
|
|
48
|
-
filename &&= (
|
|
46
|
+
name = String(name).toWellFormed();
|
|
47
|
+
filename &&= String(filename).toWellFormed();
|
|
49
48
|
if ((0, _utils.isFileLike)(value)) {
|
|
50
49
|
filename ??= value.name || 'blob';
|
|
51
50
|
value = new _nodeBuffer.File([value], filename, value);
|
|
52
51
|
} else if (this.#ensureInstance(value)) {
|
|
53
52
|
value.name = filename;
|
|
54
53
|
} else {
|
|
55
|
-
value = (
|
|
54
|
+
value = String(value).toWellFormed();
|
|
56
55
|
}
|
|
57
56
|
return {
|
|
58
57
|
name,
|
|
@@ -106,7 +105,7 @@ class FormData {
|
|
|
106
105
|
delete(...args) {
|
|
107
106
|
(0, _utils.brandCheck)(this, FormData);
|
|
108
107
|
this.#ensureArgs(args, 1, 'delete');
|
|
109
|
-
const name = (
|
|
108
|
+
const name = String(args[0]).toWellFormed();
|
|
110
109
|
this.#entries = this.#entries.filter(it => it.name !== name);
|
|
111
110
|
}
|
|
112
111
|
forEach(...args) {
|
|
@@ -120,19 +119,19 @@ class FormData {
|
|
|
120
119
|
get(...args) {
|
|
121
120
|
(0, _utils.brandCheck)(this, FormData);
|
|
122
121
|
this.#ensureArgs(args, 1, 'get');
|
|
123
|
-
const name = (
|
|
124
|
-
return
|
|
122
|
+
const name = String(args[0]).toWellFormed();
|
|
123
|
+
return this.#entries.find(it => it.name === name)?.value ?? null;
|
|
125
124
|
}
|
|
126
125
|
getAll(...args) {
|
|
127
126
|
(0, _utils.brandCheck)(this, FormData);
|
|
128
127
|
this.#ensureArgs(args, 1, 'getAll');
|
|
129
|
-
const name = (
|
|
128
|
+
const name = String(args[0]).toWellFormed();
|
|
130
129
|
return this.#entries.filter(it => it.name === name).map(it => it.value);
|
|
131
130
|
}
|
|
132
131
|
has(...args) {
|
|
133
132
|
(0, _utils.brandCheck)(this, FormData);
|
|
134
133
|
this.#ensureArgs(args, 1, 'has');
|
|
135
|
-
const name = (
|
|
134
|
+
const name = String(args[0]).toWellFormed();
|
|
136
135
|
return !!this.#entries.find(it => it.name === name);
|
|
137
136
|
}
|
|
138
137
|
set(...args) {
|
package/dist/preflight.cjs
CHANGED
package/dist/retries.cjs
CHANGED
|
@@ -35,7 +35,7 @@ const retries = (err, options) => {
|
|
|
35
35
|
} = retry;
|
|
36
36
|
if (retry.retryAfter && err.headers?.[HTTP2_HEADER_RETRY_AFTER]) {
|
|
37
37
|
interval = err.headers[HTTP2_HEADER_RETRY_AFTER];
|
|
38
|
-
interval =
|
|
38
|
+
interval = interval * 1e3 || Date.parse(interval) - Date.now();
|
|
39
39
|
if (interval > retry.maxRetryAfter) {
|
|
40
40
|
throw new _errors.RequestError(`Maximum '${HTTP2_HEADER_RETRY_AFTER}' limit exceeded: ${interval} ms`, {
|
|
41
41
|
cause: err
|
|
@@ -44,7 +44,7 @@ const retries = (err, options) => {
|
|
|
44
44
|
} else {
|
|
45
45
|
interval = new Function('interval', `return Math.ceil(${retry.backoffStrategy});`)(interval);
|
|
46
46
|
}
|
|
47
|
-
if (interval < 0) {
|
|
47
|
+
if (interval < 0 || Number.isNaN(interval)) {
|
|
48
48
|
interval = 0;
|
|
49
49
|
}
|
|
50
50
|
retry.attempts--;
|
package/dist/utils.cjs
CHANGED
|
@@ -118,37 +118,43 @@ const normalize = (url, options = {}) => {
|
|
|
118
118
|
if (!options.redirected) {
|
|
119
119
|
options = cloneWith(_config.default.defaults, options);
|
|
120
120
|
}
|
|
121
|
-
if (options.trimTrailingSlashes) {
|
|
122
|
-
url = `${url}`.replace(/(?<!:)\/+/g, '/');
|
|
123
|
-
}
|
|
124
|
-
if (options.stripTrailingSlash) {
|
|
125
|
-
url = `${url}`.replace(/\/$|\/(?=#)|\/(?=\?)/g, '');
|
|
126
|
-
}
|
|
127
121
|
return Object.assign(options, {
|
|
128
122
|
headers: normalizeHeaders(options.headers),
|
|
129
123
|
method: options.method.toUpperCase(),
|
|
130
|
-
url: addSearchParams(new URL(url, options.baseURL), options.params)
|
|
124
|
+
url: addSearchParams(normalizeUrl(new URL(url, options.baseURL), options), options.params)
|
|
131
125
|
});
|
|
132
126
|
};
|
|
133
127
|
exports.normalize = normalize;
|
|
134
128
|
const normalizeHeaders = (headers = {}) => {
|
|
135
129
|
const acc = {};
|
|
136
|
-
for (
|
|
137
|
-
|
|
130
|
+
for (let [key, val] of Object.entries(headers)) {
|
|
131
|
+
key = key.toLowerCase();
|
|
138
132
|
acc[key] = val;
|
|
139
133
|
if (key === HTTP2_HEADER_ACCEPT_ENCODING && !_config.isZstdSupported) {
|
|
140
|
-
|
|
141
|
-
if (
|
|
142
|
-
acc[key] =
|
|
134
|
+
val = val.replace(/\s?zstd,?/gi, '').trim();
|
|
135
|
+
if (val) {
|
|
136
|
+
acc[key] = val;
|
|
143
137
|
} else {
|
|
144
|
-
Reflect.deleteProperty(acc,
|
|
138
|
+
Reflect.deleteProperty(acc, key);
|
|
145
139
|
}
|
|
146
140
|
}
|
|
147
141
|
}
|
|
148
142
|
return acc;
|
|
149
143
|
};
|
|
150
144
|
exports.normalizeHeaders = normalizeHeaders;
|
|
151
|
-
|
|
145
|
+
function normalizeUrl(url, {
|
|
146
|
+
trimTrailingSlashes,
|
|
147
|
+
stripTrailingSlash
|
|
148
|
+
} = {}) {
|
|
149
|
+
if (trimTrailingSlashes) {
|
|
150
|
+
url.pathname = url.pathname.replace(/\/{2,}/g, '/');
|
|
151
|
+
}
|
|
152
|
+
if (stripTrailingSlash && url.pathname !== '/') {
|
|
153
|
+
url.pathname = url.pathname.replace(/\/$/, '');
|
|
154
|
+
}
|
|
155
|
+
return url;
|
|
156
|
+
}
|
|
157
|
+
const sameOrigin = (a, b) => a.origin === b.origin;
|
|
152
158
|
exports.sameOrigin = sameOrigin;
|
|
153
159
|
const snoop = (client, req, options) => {
|
|
154
160
|
req.once('close', () => client?.close());
|
|
@@ -162,9 +168,9 @@ const snoop = (client, req, options) => {
|
|
|
162
168
|
});
|
|
163
169
|
};
|
|
164
170
|
exports.snoop = snoop;
|
|
165
|
-
const stripHeaders = (headers = {},
|
|
166
|
-
|
|
167
|
-
return Object.fromEntries(Object.entries(headers).filter(([key]) => !
|
|
171
|
+
const stripHeaders = (headers = {}, keys = []) => {
|
|
172
|
+
keys = new Set(keys);
|
|
173
|
+
return Object.fromEntries(Object.entries(headers).filter(([key]) => !keys.has(key)));
|
|
168
174
|
};
|
|
169
175
|
exports.stripHeaders = stripHeaders;
|
|
170
176
|
async function* tap(val) {
|
package/package.json
CHANGED
package/src/cookies.js
CHANGED
|
@@ -3,7 +3,13 @@ import {
|
|
|
3
3
|
toCamelCase,
|
|
4
4
|
} from './utils.js';
|
|
5
5
|
|
|
6
|
-
const
|
|
6
|
+
export const cookieRex = /^[\w-]+=(?:"[^"]*"|[^\p{Control};]*)(?:;\s*(?:[\w-]+=(?:"[^"]*"|[^\p{Control};]*)|[\w-]+))*$/u;
|
|
7
|
+
export const cookiePairRex = /(?:[^;"\s]+="[^"]*"|[^;]+)(?=;|$)/g;
|
|
8
|
+
export const illegalCookieChars = /\p{Control}/u;
|
|
9
|
+
export const isValidCookie = (str) => str?.constructor === String && cookieRex.test(str);
|
|
10
|
+
export const maxCookieLifetimeCap = 3456e7; // 400 days
|
|
11
|
+
export const maxCookieSize = 4096;
|
|
12
|
+
export const splitCookie = (str) => str.match(cookiePairRex).map((str) => str.trim());
|
|
7
13
|
|
|
8
14
|
export class Cookies extends URLSearchParams {
|
|
9
15
|
|
|
@@ -27,49 +33,60 @@ export class Cookies extends URLSearchParams {
|
|
|
27
33
|
}
|
|
28
34
|
|
|
29
35
|
constructor(input, { cookiesTTL } = { cookiesTTL: false }) {
|
|
30
|
-
if (
|
|
31
|
-
input = input
|
|
32
|
-
|
|
33
|
-
return [it.split(';').at(0).trim()];
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const [cookie, ...attrs] = it.split(';').map((it) => it.trim());
|
|
37
|
-
const ttl = {};
|
|
38
|
-
|
|
39
|
-
for (const attr of attrs) {
|
|
40
|
-
if (/(?:expires|max-age)=/i.test(attr)) {
|
|
41
|
-
const [key, val] = attr.toLowerCase().split('=');
|
|
42
|
-
const ms = Number.isFinite(Number.parseInt(val, 10)) ? val * 1e3 : Date.parse(val) - Date.now();
|
|
36
|
+
if (isValidCookie(input)) {
|
|
37
|
+
input = splitCookie(input);
|
|
38
|
+
}
|
|
43
39
|
|
|
44
|
-
|
|
40
|
+
const ttlMap = new Map();
|
|
41
|
+
|
|
42
|
+
if (Array.isArray(input)) {
|
|
43
|
+
if (input.every((it) => isValidCookie(it))) {
|
|
44
|
+
input = input.filter((it) => !illegalCookieChars.test(it) && it.length <= maxCookieSize);
|
|
45
|
+
input = input.map(splitCookie).map(([cookie, ...attrs]) => {
|
|
46
|
+
try {
|
|
47
|
+
cookie = cookie.split('=').map((it) => decodeURIComponent(it.trim()));
|
|
48
|
+
|
|
49
|
+
return cookie;
|
|
50
|
+
} finally {
|
|
51
|
+
if (cookiesTTL) {
|
|
52
|
+
for (const attr of attrs) {
|
|
53
|
+
if (/(?:expires|max-age)=/i.test(attr)) {
|
|
54
|
+
const [key, val] = attr.toLowerCase().split('=');
|
|
55
|
+
let interval = val * 1e3 || Date.parse(val) - Date.now();
|
|
56
|
+
|
|
57
|
+
if (interval < 0 || Number.isNaN(interval)) {
|
|
58
|
+
interval = 0;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
ttlMap.set(
|
|
62
|
+
cookie[0],
|
|
63
|
+
{ [toCamelCase(key.trim())]: Math.min(interval, maxCookieLifetimeCap) },
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
45
68
|
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
return [
|
|
49
|
-
cookie.replace(/\u0022/g, ''),
|
|
50
|
-
Object.keys(ttl).length ? ttl : null,
|
|
51
|
-
];
|
|
52
|
-
});
|
|
69
|
+
});
|
|
70
|
+
}
|
|
53
71
|
}
|
|
54
72
|
|
|
55
|
-
super(
|
|
73
|
+
super(input);
|
|
56
74
|
|
|
57
|
-
if (
|
|
58
|
-
for (const [
|
|
59
|
-
const key = cookie.split('=').at(0);
|
|
75
|
+
if (ttlMap.size) {
|
|
76
|
+
for (const [key, attrs] of ttlMap) {
|
|
60
77
|
|
|
61
78
|
if (this.#chronometry.has(key)) {
|
|
62
79
|
clearTimeout(this.#chronometry.get(key));
|
|
63
80
|
this.#chronometry.delete(key);
|
|
64
81
|
}
|
|
65
82
|
|
|
66
|
-
const { expires, maxAge } =
|
|
83
|
+
const { expires, maxAge } = attrs;
|
|
67
84
|
|
|
68
|
-
for (const
|
|
85
|
+
for (const interval of [
|
|
69
86
|
maxAge,
|
|
70
87
|
expires,
|
|
71
88
|
]) {
|
|
72
|
-
if (!Number.isInteger(
|
|
89
|
+
if (!Number.isInteger(interval)) {
|
|
73
90
|
continue;
|
|
74
91
|
}
|
|
75
92
|
|
|
@@ -81,7 +98,7 @@ export class Cookies extends URLSearchParams {
|
|
|
81
98
|
ctx.#chronometry.delete(key);
|
|
82
99
|
ctx.delete(key);
|
|
83
100
|
}
|
|
84
|
-
}, Math.max(
|
|
101
|
+
}, Math.max(interval, 0));
|
|
85
102
|
|
|
86
103
|
this.constructor.#register(this, tid);
|
|
87
104
|
this.#chronometry.set(key, tid);
|
package/src/formdata.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { File } from 'node:buffer';
|
|
2
2
|
import { randomBytes } from 'node:crypto';
|
|
3
3
|
import http2 from 'node:http2';
|
|
4
|
-
import { toUSVString } from 'node:util';
|
|
5
4
|
import {
|
|
6
5
|
APPLICATION_OCTET_STREAM,
|
|
7
6
|
MULTIPART_FORM_DATA,
|
|
@@ -64,8 +63,8 @@ export class FormData {
|
|
|
64
63
|
}
|
|
65
64
|
|
|
66
65
|
static #enfoldEntry(name, value, filename) {
|
|
67
|
-
name =
|
|
68
|
-
filename &&=
|
|
66
|
+
name = String(name).toWellFormed();
|
|
67
|
+
filename &&= String(filename).toWellFormed();
|
|
69
68
|
|
|
70
69
|
if (isFileLike(value)) {
|
|
71
70
|
filename ??= value.name || 'blob';
|
|
@@ -73,7 +72,7 @@ export class FormData {
|
|
|
73
72
|
} else if (this.#ensureInstance(value)) {
|
|
74
73
|
value.name = filename;
|
|
75
74
|
} else {
|
|
76
|
-
value =
|
|
75
|
+
value = String(value).toWellFormed();
|
|
77
76
|
}
|
|
78
77
|
|
|
79
78
|
return {
|
|
@@ -152,7 +151,7 @@ export class FormData {
|
|
|
152
151
|
delete(...args) {
|
|
153
152
|
brandCheck(this, FormData);
|
|
154
153
|
this.#ensureArgs(args, 1, 'delete');
|
|
155
|
-
const name =
|
|
154
|
+
const name = String(args[0]).toWellFormed();
|
|
156
155
|
|
|
157
156
|
this.#entries = this.#entries.filter((it) => it.name !== name);
|
|
158
157
|
}
|
|
@@ -173,15 +172,15 @@ export class FormData {
|
|
|
173
172
|
get(...args) {
|
|
174
173
|
brandCheck(this, FormData);
|
|
175
174
|
this.#ensureArgs(args, 1, 'get');
|
|
176
|
-
const name =
|
|
175
|
+
const name = String(args[0]).toWellFormed();
|
|
177
176
|
|
|
178
|
-
return
|
|
177
|
+
return this.#entries.find((it) => it.name === name)?.value ?? null;
|
|
179
178
|
}
|
|
180
179
|
|
|
181
180
|
getAll(...args) {
|
|
182
181
|
brandCheck(this, FormData);
|
|
183
182
|
this.#ensureArgs(args, 1, 'getAll');
|
|
184
|
-
const name =
|
|
183
|
+
const name = String(args[0]).toWellFormed();
|
|
185
184
|
|
|
186
185
|
return this.#entries.filter((it) => it.name === name).map((it) => it.value);
|
|
187
186
|
}
|
|
@@ -189,7 +188,7 @@ export class FormData {
|
|
|
189
188
|
has(...args) {
|
|
190
189
|
brandCheck(this, FormData);
|
|
191
190
|
this.#ensureArgs(args, 1, 'has');
|
|
192
|
-
const name =
|
|
191
|
+
const name = String(args[0]).toWellFormed();
|
|
193
192
|
|
|
194
193
|
return !!this.#entries.find((it) => it.name === name);
|
|
195
194
|
}
|
package/src/preflight.js
CHANGED
package/src/retries.js
CHANGED
|
@@ -27,7 +27,7 @@ export const retries = (err, options) => {
|
|
|
27
27
|
|
|
28
28
|
if (retry.retryAfter && err.headers?.[HTTP2_HEADER_RETRY_AFTER]) {
|
|
29
29
|
interval = err.headers[HTTP2_HEADER_RETRY_AFTER];
|
|
30
|
-
interval =
|
|
30
|
+
interval = interval * 1e3 || Date.parse(interval) - Date.now();
|
|
31
31
|
if (interval > retry.maxRetryAfter) {
|
|
32
32
|
throw new RequestError(
|
|
33
33
|
`Maximum '${ HTTP2_HEADER_RETRY_AFTER }' limit exceeded: ${ interval } ms`,
|
|
@@ -38,7 +38,7 @@ export const retries = (err, options) => {
|
|
|
38
38
|
interval = new Function('interval', `return Math.ceil(${ retry.backoffStrategy });`)(interval);
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
if (interval < 0) {
|
|
41
|
+
if (interval < 0 || Number.isNaN(interval)) {
|
|
42
42
|
interval = 0;
|
|
43
43
|
}
|
|
44
44
|
|
package/src/utils.js
CHANGED
|
@@ -126,36 +126,28 @@ export const normalize = (url, options = {}) => {
|
|
|
126
126
|
options = cloneWith(config.defaults, options);
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
-
if (options.trimTrailingSlashes) {
|
|
130
|
-
url = `${ url }`.replace(/(?<!:)\/+/g, '/');
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
if (options.stripTrailingSlash) {
|
|
134
|
-
url = `${ url }`.replace(/\/$|\/(?=#)|\/(?=\?)/g, '');
|
|
135
|
-
}
|
|
136
|
-
|
|
137
129
|
return Object.assign(options, {
|
|
138
130
|
headers: normalizeHeaders(options.headers),
|
|
139
131
|
method: options.method.toUpperCase(),
|
|
140
|
-
url: addSearchParams(new URL(url, options.baseURL), options.params),
|
|
132
|
+
url: addSearchParams(normalizeUrl(new URL(url, options.baseURL), options), options.params),
|
|
141
133
|
});
|
|
142
134
|
};
|
|
143
135
|
|
|
144
136
|
export const normalizeHeaders = (headers = {}) => {
|
|
145
137
|
const acc = {};
|
|
146
138
|
|
|
147
|
-
for (
|
|
148
|
-
|
|
139
|
+
for (let [key, val] of Object.entries(headers)) {
|
|
140
|
+
key = key.toLowerCase();
|
|
149
141
|
|
|
150
142
|
acc[key] = val;
|
|
151
143
|
|
|
152
144
|
if (key === HTTP2_HEADER_ACCEPT_ENCODING && !isZstdSupported) {
|
|
153
|
-
|
|
145
|
+
val = val.replace(/\s?zstd,?/gi, '').trim();
|
|
154
146
|
|
|
155
|
-
if (
|
|
156
|
-
acc[key] =
|
|
147
|
+
if (val) {
|
|
148
|
+
acc[key] = val;
|
|
157
149
|
} else {
|
|
158
|
-
Reflect.deleteProperty(acc,
|
|
150
|
+
Reflect.deleteProperty(acc, key);
|
|
159
151
|
}
|
|
160
152
|
}
|
|
161
153
|
}
|
|
@@ -163,7 +155,19 @@ export const normalizeHeaders = (headers = {}) => {
|
|
|
163
155
|
return acc;
|
|
164
156
|
};
|
|
165
157
|
|
|
166
|
-
|
|
158
|
+
function normalizeUrl(url, { trimTrailingSlashes, stripTrailingSlash } = {}) {
|
|
159
|
+
if (trimTrailingSlashes) {
|
|
160
|
+
url.pathname = url.pathname.replace(/\/{2,}/g, '/');
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (stripTrailingSlash && url.pathname !== '/') {
|
|
164
|
+
url.pathname = url.pathname.replace(/\/$/, '');
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return url;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export const sameOrigin = (a, b) => a.origin === b.origin;
|
|
167
171
|
|
|
168
172
|
export const snoop = (client, req, options) => {
|
|
169
173
|
req.once('close', () => client?.close());
|
|
@@ -177,14 +181,10 @@ export const snoop = (client, req, options) => {
|
|
|
177
181
|
});
|
|
178
182
|
};
|
|
179
183
|
|
|
180
|
-
export const stripHeaders = (headers = {},
|
|
181
|
-
|
|
184
|
+
export const stripHeaders = (headers = {}, keys = []) => {
|
|
185
|
+
keys = new Set(keys);
|
|
182
186
|
|
|
183
|
-
return Object.fromEntries(
|
|
184
|
-
Object.entries(headers).filter(
|
|
185
|
-
([key]) => !names.has(key.toLowerCase()),
|
|
186
|
-
),
|
|
187
|
-
);
|
|
187
|
+
return Object.fromEntries(Object.entries(headers).filter(([key]) => !keys.has(key)));
|
|
188
188
|
};
|
|
189
189
|
|
|
190
190
|
export async function* tap(val) {
|