rekwest 7.0.3 → 7.1.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 +1 -0
- package/dist/ackn.cjs +1 -1
- package/dist/cookies.cjs +8 -8
- package/dist/formdata.cjs +13 -13
- package/dist/index.cjs +4 -4
- package/dist/retries.cjs +6 -6
- package/dist/transfer.cjs +8 -8
- package/dist/utils.cjs +56 -43
- package/package.json +3 -4
- package/src/ackn.js +1 -1
- package/src/cookies.js +8 -8
- package/src/formdata.js +14 -14
- package/src/index.js +4 -4
- package/src/retries.js +6 -6
- package/src/transfer.js +8 -8
- package/src/utils.js +58 -44
package/README.md
CHANGED
|
@@ -140,6 +140,7 @@ console.log(res.body);
|
|
|
140
140
|
* `h2` **{boolean}** `Default: false` Forces the use of HTTP/2 protocol
|
|
141
141
|
* `headers` **{Object}** The headers to add to the request
|
|
142
142
|
* `maxRetryAfter` **{number}** The upper limit of `retry-after` header. If unset, it will use `timeout` value
|
|
143
|
+
* `params` **{Object}** The search params to add to the `url`
|
|
143
144
|
* `parse` **{boolean}** `Default: true` Controls whether to parse response body or return a buffer
|
|
144
145
|
* `redirect` **{error | follow | manual}** `Default: follow` Controls the redirect flows
|
|
145
146
|
* `retry` **{Object}** Represents the retry options
|
package/dist/ackn.cjs
CHANGED
|
@@ -13,7 +13,7 @@ const ackn = options => new Promise((resolve, reject) => {
|
|
|
13
13
|
...options,
|
|
14
14
|
ALPNProtocols: ['h2', 'http/1.1'],
|
|
15
15
|
host: url.hostname,
|
|
16
|
-
port: parseInt(url.port) || 443,
|
|
16
|
+
port: parseInt(url.port, 10) || 443,
|
|
17
17
|
servername: url.hostname
|
|
18
18
|
}, () => {
|
|
19
19
|
socket.off('error', reject);
|
package/dist/cookies.cjs
CHANGED
|
@@ -10,12 +10,12 @@ const lifetimeCap = 3456e7; // pragma: 400 days
|
|
|
10
10
|
class Cookies extends URLSearchParams {
|
|
11
11
|
static #finalizers = new Set();
|
|
12
12
|
static jar = new Map();
|
|
13
|
-
static #register(target,
|
|
14
|
-
const finalizer = new FinalizationRegistry(
|
|
15
|
-
clearTimeout(
|
|
13
|
+
static #register(target, val) {
|
|
14
|
+
const finalizer = new FinalizationRegistry(heldVal => {
|
|
15
|
+
clearTimeout(heldVal);
|
|
16
16
|
this.#finalizers.delete(finalizer);
|
|
17
17
|
});
|
|
18
|
-
finalizer.register(target,
|
|
18
|
+
finalizer.register(target, val);
|
|
19
19
|
this.#finalizers.add(finalizer);
|
|
20
20
|
}
|
|
21
21
|
#chronometry = new Map();
|
|
@@ -34,10 +34,10 @@ class Cookies extends URLSearchParams {
|
|
|
34
34
|
}
|
|
35
35
|
const [cookie, ...attrs] = it.split(';').map(it => it.trim());
|
|
36
36
|
const ttl = {};
|
|
37
|
-
for (const
|
|
38
|
-
if (/(?:expires|max-age)=/i.test(
|
|
39
|
-
const [key,
|
|
40
|
-
const ms = Number.isFinite(Number(
|
|
37
|
+
for (const attr of attrs) {
|
|
38
|
+
if (/(?:expires|max-age)=/i.test(attr)) {
|
|
39
|
+
const [key, val] = attr.toLowerCase().split('=');
|
|
40
|
+
const ms = Number.isFinite(Number(val)) ? val * 1e3 : Date.parse(val) - Date.now();
|
|
41
41
|
ttl[(0, _utils.toCamelCase)(key)] = Math.min(ms, lifetimeCap);
|
|
42
42
|
}
|
|
43
43
|
}
|
package/dist/formdata.cjs
CHANGED
|
@@ -27,12 +27,12 @@ class FormData {
|
|
|
27
27
|
contentType,
|
|
28
28
|
async *[Symbol.asyncIterator]() {
|
|
29
29
|
const encoder = new TextEncoder();
|
|
30
|
-
for (const [name,
|
|
31
|
-
if (
|
|
32
|
-
yield encoder.encode(`${prefix}; name="${escape(redress(name))}"${CRLF.repeat(2)}${redress(
|
|
30
|
+
for (const [name, val] of fd) {
|
|
31
|
+
if (val.constructor === String) {
|
|
32
|
+
yield encoder.encode(`${prefix}; name="${escape(redress(name))}"${CRLF.repeat(2)}${redress(val)}${CRLF}`);
|
|
33
33
|
} else {
|
|
34
|
-
yield encoder.encode(`${prefix}; name="${escape(redress(name))}"${
|
|
35
|
-
yield* (0, _utils.tap)(
|
|
34
|
+
yield encoder.encode(`${prefix}; name="${escape(redress(name))}"${val.name ? `; filename="${escape(val.name)}"` : ''}${CRLF}${HTTP2_HEADER_CONTENT_TYPE}: ${val.type || _mediatypes.APPLICATION_OCTET_STREAM}${CRLF.repeat(2)}`);
|
|
35
|
+
yield* (0, _utils.tap)(val);
|
|
36
36
|
yield new Uint8Array([13, 10]);
|
|
37
37
|
}
|
|
38
38
|
}
|
|
@@ -40,8 +40,8 @@ class FormData {
|
|
|
40
40
|
}
|
|
41
41
|
};
|
|
42
42
|
}
|
|
43
|
-
static alike(
|
|
44
|
-
return FormData.name ===
|
|
43
|
+
static alike(val) {
|
|
44
|
+
return FormData.name === val?.[Symbol.toStringTag];
|
|
45
45
|
}
|
|
46
46
|
static #enfoldEntry(name, value, filename) {
|
|
47
47
|
name = (0, _nodeUtil.toUSVString)(name);
|
|
@@ -59,8 +59,8 @@ class FormData {
|
|
|
59
59
|
value
|
|
60
60
|
};
|
|
61
61
|
}
|
|
62
|
-
static #ensureInstance(
|
|
63
|
-
return (0, _utils.isFileLike)(
|
|
62
|
+
static #ensureInstance(val) {
|
|
63
|
+
return (0, _utils.isFileLike)(val) || Object(val) === val && Reflect.has(val, Symbol.asyncIterator);
|
|
64
64
|
}
|
|
65
65
|
#entries = [];
|
|
66
66
|
get [Symbol.toStringTag]() {
|
|
@@ -78,8 +78,8 @@ class FormData {
|
|
|
78
78
|
} else if (!Reflect.has(input, Symbol.iterator)) {
|
|
79
79
|
input = Object.entries(input);
|
|
80
80
|
}
|
|
81
|
-
for (const [key,
|
|
82
|
-
this.append(key,
|
|
81
|
+
for (const [key, val] of input) {
|
|
82
|
+
this.append(key, val);
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
85
|
}
|
|
@@ -163,8 +163,8 @@ class FormData {
|
|
|
163
163
|
}
|
|
164
164
|
*values() {
|
|
165
165
|
(0, _utils.brandCheck)(this, FormData);
|
|
166
|
-
for (const [,
|
|
167
|
-
yield
|
|
166
|
+
for (const [, val] of this) {
|
|
167
|
+
yield val;
|
|
168
168
|
}
|
|
169
169
|
}
|
|
170
170
|
[Symbol.iterator]() {
|
package/dist/index.cjs
CHANGED
|
@@ -160,20 +160,20 @@ Reflect.defineProperty(rekwest, 'defaults', {
|
|
|
160
160
|
get() {
|
|
161
161
|
return _config.default.defaults;
|
|
162
162
|
},
|
|
163
|
-
set(
|
|
164
|
-
_config.default.defaults = (0, _utils.
|
|
163
|
+
set(val) {
|
|
164
|
+
_config.default.defaults = (0, _utils.cloneWith)(_config.default.defaults, val);
|
|
165
165
|
}
|
|
166
166
|
});
|
|
167
167
|
Reflect.defineProperty(rekwest, 'extend', {
|
|
168
168
|
enumerable: true,
|
|
169
169
|
value(options) {
|
|
170
|
-
return (url, opts) => rekwest(url, (0, _utils.
|
|
170
|
+
return (url, opts) => rekwest(url, (0, _utils.cloneWith)(options, opts));
|
|
171
171
|
}
|
|
172
172
|
});
|
|
173
173
|
Reflect.defineProperty(rekwest, 'stream', {
|
|
174
174
|
enumerable: true,
|
|
175
175
|
value(url, options) {
|
|
176
|
-
options = (0, _preflight.preflight)((0, _validation.validation)((0, _utils.normalize)(url, (0, _utils.
|
|
176
|
+
options = (0, _preflight.preflight)((0, _validation.validation)((0, _utils.normalize)(url, (0, _utils.cloneWith)({}, options, {
|
|
177
177
|
headers: {
|
|
178
178
|
[HTTP2_HEADER_CONTENT_TYPE]: _mediatypes2.APPLICATION_OCTET_STREAM
|
|
179
179
|
},
|
package/dist/retries.cjs
CHANGED
|
@@ -16,7 +16,7 @@ const {
|
|
|
16
16
|
HTTP2_METHOD_GET,
|
|
17
17
|
HTTP2_METHOD_HEAD
|
|
18
18
|
} = _nodeHttp.default.constants;
|
|
19
|
-
const retries = (
|
|
19
|
+
const retries = (err, options) => {
|
|
20
20
|
const {
|
|
21
21
|
body,
|
|
22
22
|
maxRetryAfter,
|
|
@@ -27,19 +27,19 @@ const retries = (ex, options) => {
|
|
|
27
27
|
if (retry?.attempts > 0) {
|
|
28
28
|
if (![HTTP2_METHOD_GET, HTTP2_METHOD_HEAD].includes(method) && (0, _utils.isPipeStream)(body) && !(0, _nodeStream.isReadable)(body)) {
|
|
29
29
|
throw new _errors.RequestError('Request stream already read.', {
|
|
30
|
-
cause:
|
|
30
|
+
cause: err
|
|
31
31
|
});
|
|
32
32
|
}
|
|
33
|
-
if (retry.errorCodes?.includes(
|
|
33
|
+
if (retry.errorCodes?.includes(err.code) || retry.statusCodes?.includes(err.statusCode)) {
|
|
34
34
|
let {
|
|
35
35
|
interval
|
|
36
36
|
} = retry;
|
|
37
|
-
if (retry.retryAfter &&
|
|
38
|
-
interval =
|
|
37
|
+
if (retry.retryAfter && err.headers?.[HTTP2_HEADER_RETRY_AFTER]) {
|
|
38
|
+
interval = err.headers[HTTP2_HEADER_RETRY_AFTER];
|
|
39
39
|
interval = Math.abs(Number(interval) * 1e3 || new Date(interval) - Date.now()) || 0;
|
|
40
40
|
if (interval > maxRetryAfter) {
|
|
41
41
|
throw new _errors.RequestError(`Maximum '${HTTP2_HEADER_RETRY_AFTER}' limit exceeded: ${interval} ms.`, {
|
|
42
|
-
cause:
|
|
42
|
+
cause: err
|
|
43
43
|
});
|
|
44
44
|
}
|
|
45
45
|
} else {
|
package/dist/transfer.cjs
CHANGED
|
@@ -38,9 +38,9 @@ const transfer = async options => {
|
|
|
38
38
|
}
|
|
39
39
|
try {
|
|
40
40
|
options = await (0, _transform.transform)((0, _preflight.preflight)(options));
|
|
41
|
-
} catch (
|
|
41
|
+
} catch (err) {
|
|
42
42
|
options.createConnection?.().destroy();
|
|
43
|
-
throw
|
|
43
|
+
throw err;
|
|
44
44
|
}
|
|
45
45
|
const promise = new Promise((resolve, reject) => {
|
|
46
46
|
let client, req;
|
|
@@ -70,18 +70,18 @@ const transfer = async options => {
|
|
|
70
70
|
res.body = await res.body();
|
|
71
71
|
}
|
|
72
72
|
return res;
|
|
73
|
-
} catch (
|
|
74
|
-
const result = (0, _retries.retries)(
|
|
73
|
+
} catch (err) {
|
|
74
|
+
const result = (0, _retries.retries)(err, options);
|
|
75
75
|
if (result) {
|
|
76
76
|
return result;
|
|
77
77
|
}
|
|
78
|
-
if (digest && !redirected &&
|
|
79
|
-
|
|
78
|
+
if (digest && !redirected && err.body) {
|
|
79
|
+
err.body = await err.body();
|
|
80
80
|
}
|
|
81
81
|
if (!thenable) {
|
|
82
|
-
throw
|
|
82
|
+
throw err;
|
|
83
83
|
} else {
|
|
84
|
-
return
|
|
84
|
+
return err;
|
|
85
85
|
}
|
|
86
86
|
}
|
|
87
87
|
};
|
package/dist/utils.cjs
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.stripHeaders = exports.snoop = exports.sameOrigin = exports.normalizeHeaders = exports.normalize = exports.
|
|
6
|
+
exports.stripHeaders = exports.snoop = exports.sameOrigin = exports.normalizeHeaders = exports.normalize = exports.isReadableStream = exports.isPipeStream = exports.isFileLike = exports.dispatch = exports.deepMerge = exports.cloneWith = exports.brandCheck = exports.augment = exports.addSearchParams = void 0;
|
|
7
7
|
exports.tap = tap;
|
|
8
8
|
exports.unwind = exports.toCamelCase = void 0;
|
|
9
9
|
var _nodeBuffer = require("node:buffer");
|
|
@@ -17,6 +17,19 @@ const {
|
|
|
17
17
|
HTTP2_HEADER_ACCEPT_ENCODING,
|
|
18
18
|
HTTP2_HEADER_STATUS
|
|
19
19
|
} = _nodeHttp.default.constants;
|
|
20
|
+
const addSearchParams = (url, params = {}) => {
|
|
21
|
+
for (const [key, val] of Object.entries(params)) {
|
|
22
|
+
if (Array.isArray(val)) {
|
|
23
|
+
for (const v of val) {
|
|
24
|
+
url.searchParams.append(key, v);
|
|
25
|
+
}
|
|
26
|
+
} else {
|
|
27
|
+
url.searchParams.set(key, val);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return url;
|
|
31
|
+
};
|
|
32
|
+
exports.addSearchParams = addSearchParams;
|
|
20
33
|
const augment = (res, headers, options) => {
|
|
21
34
|
const {
|
|
22
35
|
h2
|
|
@@ -45,20 +58,36 @@ const augment = (res, headers, options) => {
|
|
|
45
58
|
});
|
|
46
59
|
};
|
|
47
60
|
exports.augment = augment;
|
|
48
|
-
const brandCheck = (
|
|
49
|
-
if (!(
|
|
61
|
+
const brandCheck = (val, ctor) => {
|
|
62
|
+
if (!(val instanceof ctor)) {
|
|
50
63
|
throw new TypeError('Illegal invocation.');
|
|
51
64
|
}
|
|
52
65
|
};
|
|
53
66
|
exports.brandCheck = brandCheck;
|
|
54
|
-
const
|
|
67
|
+
const cloneWith = (target, ...rest) => {
|
|
55
68
|
target = structuredClone(target);
|
|
56
69
|
if (!rest.length) {
|
|
57
70
|
return target;
|
|
58
71
|
}
|
|
59
|
-
return
|
|
72
|
+
return deepMerge(target, ...rest);
|
|
73
|
+
};
|
|
74
|
+
exports.cloneWith = cloneWith;
|
|
75
|
+
const deepMerge = (target, ...rest) => {
|
|
76
|
+
rest = rest.filter(it => Object(it) === it);
|
|
77
|
+
for (const source of rest) {
|
|
78
|
+
for (const key of Object.getOwnPropertyNames(source)) {
|
|
79
|
+
const sv = source[key];
|
|
80
|
+
const tv = target[key];
|
|
81
|
+
if (Object(sv) === sv && Object(tv) === tv) {
|
|
82
|
+
target[key] = deepMerge(tv, sv);
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
target[key] = source[key];
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return target;
|
|
60
89
|
};
|
|
61
|
-
exports.
|
|
90
|
+
exports.deepMerge = deepMerge;
|
|
62
91
|
const dispatch = (req, {
|
|
63
92
|
body
|
|
64
93
|
}) => {
|
|
@@ -69,37 +98,21 @@ const dispatch = (req, {
|
|
|
69
98
|
}
|
|
70
99
|
};
|
|
71
100
|
exports.dispatch = dispatch;
|
|
72
|
-
const isFileLike =
|
|
73
|
-
return [_nodeBuffer.Blob, _nodeBuffer.File].some(it =>
|
|
101
|
+
const isFileLike = val => {
|
|
102
|
+
return [_nodeBuffer.Blob, _nodeBuffer.File].some(it => val instanceof it);
|
|
74
103
|
};
|
|
75
104
|
exports.isFileLike = isFileLike;
|
|
76
|
-
const isPipeStream =
|
|
77
|
-
return
|
|
105
|
+
const isPipeStream = val => {
|
|
106
|
+
return val instanceof _nodeStream.Readable;
|
|
78
107
|
};
|
|
79
108
|
exports.isPipeStream = isPipeStream;
|
|
80
|
-
const isReadableStream =
|
|
81
|
-
return
|
|
109
|
+
const isReadableStream = val => {
|
|
110
|
+
return val instanceof ReadableStream;
|
|
82
111
|
};
|
|
83
112
|
exports.isReadableStream = isReadableStream;
|
|
84
|
-
const merge = (target, ...rest) => {
|
|
85
|
-
rest = rest.filter(it => Object(it) === it);
|
|
86
|
-
for (const source of rest) {
|
|
87
|
-
for (const key of Object.getOwnPropertyNames(source)) {
|
|
88
|
-
const sv = source[key];
|
|
89
|
-
const tv = target[key];
|
|
90
|
-
if (Object(sv) === sv && Object(tv) === tv) {
|
|
91
|
-
target[key] = merge(tv, sv);
|
|
92
|
-
continue;
|
|
93
|
-
}
|
|
94
|
-
target[key] = source[key];
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
return target;
|
|
98
|
-
};
|
|
99
|
-
exports.merge = merge;
|
|
100
113
|
const normalize = (url, options = {}) => {
|
|
101
114
|
if (!options.redirected) {
|
|
102
|
-
options =
|
|
115
|
+
options = cloneWith(_config.default.defaults, options);
|
|
103
116
|
}
|
|
104
117
|
if (options.trimTrailingSlashes) {
|
|
105
118
|
url = `${url}`.replace(/(?<!:)\/+/g, '/');
|
|
@@ -110,25 +123,25 @@ const normalize = (url, options = {}) => {
|
|
|
110
123
|
return Object.assign(options, {
|
|
111
124
|
headers: normalizeHeaders(options.headers),
|
|
112
125
|
method: options.method.toUpperCase(),
|
|
113
|
-
url: new URL(url, options.baseURL)
|
|
126
|
+
url: addSearchParams(new URL(url, options.baseURL), options.params)
|
|
114
127
|
});
|
|
115
128
|
};
|
|
116
129
|
exports.normalize = normalize;
|
|
117
130
|
const normalizeHeaders = headers => {
|
|
118
|
-
const
|
|
119
|
-
for (const [key,
|
|
131
|
+
const acc = {};
|
|
132
|
+
for (const [key, val] of Object.entries(headers ?? {})) {
|
|
120
133
|
const name = key.toLowerCase();
|
|
121
|
-
|
|
134
|
+
acc[key] = val;
|
|
122
135
|
if (key === HTTP2_HEADER_ACCEPT_ENCODING && !_config.isZstdSupported) {
|
|
123
|
-
const stripped =
|
|
136
|
+
const stripped = val.replace(/\s?zstd,?/gi, '').trim();
|
|
124
137
|
if (stripped) {
|
|
125
|
-
|
|
138
|
+
acc[key] = stripped;
|
|
126
139
|
} else {
|
|
127
|
-
Reflect.deleteProperty(
|
|
140
|
+
Reflect.deleteProperty(acc, name);
|
|
128
141
|
}
|
|
129
142
|
}
|
|
130
143
|
}
|
|
131
|
-
return
|
|
144
|
+
return acc;
|
|
132
145
|
};
|
|
133
146
|
exports.normalizeHeaders = normalizeHeaders;
|
|
134
147
|
const sameOrigin = (a, b) => a.protocol === b.protocol && a.hostname === b.hostname && a.port === b.port;
|
|
@@ -150,13 +163,13 @@ const stripHeaders = (headers = {}, names = []) => {
|
|
|
150
163
|
return Object.fromEntries(Object.entries(headers).filter(([key]) => !names.has(key.toLowerCase())));
|
|
151
164
|
};
|
|
152
165
|
exports.stripHeaders = stripHeaders;
|
|
153
|
-
async function* tap(
|
|
154
|
-
if (Reflect.has(
|
|
155
|
-
yield*
|
|
156
|
-
} else if (
|
|
157
|
-
yield*
|
|
166
|
+
async function* tap(val) {
|
|
167
|
+
if (Reflect.has(val, Symbol.asyncIterator)) {
|
|
168
|
+
yield* val;
|
|
169
|
+
} else if (val.stream) {
|
|
170
|
+
yield* val.stream();
|
|
158
171
|
} else {
|
|
159
|
-
yield await
|
|
172
|
+
yield await val.arrayBuffer();
|
|
160
173
|
}
|
|
161
174
|
}
|
|
162
175
|
const toCamelCase = str => str?.toLowerCase().replace(/\p{Punctuation}.|\p{White_Space}./gu, val => val.replace(/\p{Punctuation}+|\p{White_Space}+/gu, '').toUpperCase());
|
package/package.json
CHANGED
|
@@ -11,11 +11,10 @@
|
|
|
11
11
|
"devDependencies": {
|
|
12
12
|
"@babel/cli": "^7.28.6",
|
|
13
13
|
"@babel/core": "^7.29.0",
|
|
14
|
-
"@babel/eslint-parser": "^7.28.6",
|
|
15
14
|
"@babel/preset-env": "^7.29.0",
|
|
16
15
|
"c8": "^10.1.3",
|
|
17
|
-
"eslint": "^
|
|
18
|
-
"eslint-config-ultra-refined": "^
|
|
16
|
+
"eslint": "^10.0.0",
|
|
17
|
+
"eslint-config-ultra-refined": "^4.0.1",
|
|
19
18
|
"mocha": "^11.7.5"
|
|
20
19
|
},
|
|
21
20
|
"engines": {
|
|
@@ -72,5 +71,5 @@
|
|
|
72
71
|
"test:cover": "c8 --include=src --reporter=lcov --reporter=text npm test"
|
|
73
72
|
},
|
|
74
73
|
"type": "module",
|
|
75
|
-
"version": "7.0
|
|
74
|
+
"version": "7.1.0"
|
|
76
75
|
}
|
package/src/ackn.js
CHANGED
package/src/cookies.js
CHANGED
|
@@ -10,13 +10,13 @@ export class Cookies extends URLSearchParams {
|
|
|
10
10
|
static #finalizers = new Set();
|
|
11
11
|
static jar = new Map();
|
|
12
12
|
|
|
13
|
-
static #register(target,
|
|
14
|
-
const finalizer = new FinalizationRegistry((
|
|
15
|
-
clearTimeout(
|
|
13
|
+
static #register(target, val) {
|
|
14
|
+
const finalizer = new FinalizationRegistry((heldVal) => {
|
|
15
|
+
clearTimeout(heldVal);
|
|
16
16
|
this.#finalizers.delete(finalizer);
|
|
17
17
|
});
|
|
18
18
|
|
|
19
|
-
finalizer.register(target,
|
|
19
|
+
finalizer.register(target, val);
|
|
20
20
|
this.#finalizers.add(finalizer);
|
|
21
21
|
}
|
|
22
22
|
|
|
@@ -36,10 +36,10 @@ export class Cookies extends URLSearchParams {
|
|
|
36
36
|
const [cookie, ...attrs] = it.split(';').map((it) => it.trim());
|
|
37
37
|
const ttl = {};
|
|
38
38
|
|
|
39
|
-
for (const
|
|
40
|
-
if (/(?:expires|max-age)=/i.test(
|
|
41
|
-
const [key,
|
|
42
|
-
const ms = Number.isFinite(Number(
|
|
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(val)) ? val * 1e3 : Date.parse(val) - Date.now();
|
|
43
43
|
|
|
44
44
|
ttl[toCamelCase(key)] = Math.min(ms, lifetimeCap);
|
|
45
45
|
}
|
package/src/formdata.js
CHANGED
|
@@ -33,20 +33,20 @@ export class FormData {
|
|
|
33
33
|
async* [Symbol.asyncIterator]() {
|
|
34
34
|
const encoder = new TextEncoder();
|
|
35
35
|
|
|
36
|
-
for (const [name,
|
|
37
|
-
if (
|
|
36
|
+
for (const [name, val] of fd) {
|
|
37
|
+
if (val.constructor === String) {
|
|
38
38
|
yield encoder.encode(`${ prefix }; name="${
|
|
39
39
|
escape(redress(name))
|
|
40
|
-
}"${ CRLF.repeat(2) }${ redress(
|
|
40
|
+
}"${ CRLF.repeat(2) }${ redress(val) }${ CRLF }`);
|
|
41
41
|
} else {
|
|
42
42
|
yield encoder.encode(`${ prefix }; name="${
|
|
43
43
|
escape(redress(name))
|
|
44
|
-
}"${
|
|
44
|
+
}"${ val.name ? `; filename="${ escape(val.name) }"` : '' }${ CRLF }${
|
|
45
45
|
HTTP2_HEADER_CONTENT_TYPE
|
|
46
46
|
}: ${
|
|
47
|
-
|
|
47
|
+
val.type || APPLICATION_OCTET_STREAM
|
|
48
48
|
}${ CRLF.repeat(2) }`);
|
|
49
|
-
yield* tap(
|
|
49
|
+
yield* tap(val);
|
|
50
50
|
yield new Uint8Array([
|
|
51
51
|
13,
|
|
52
52
|
10,
|
|
@@ -59,8 +59,8 @@ export class FormData {
|
|
|
59
59
|
};
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
static alike(
|
|
63
|
-
return FormData.name ===
|
|
62
|
+
static alike(val) {
|
|
63
|
+
return FormData.name === val?.[Symbol.toStringTag];
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
static #enfoldEntry(name, value, filename) {
|
|
@@ -82,8 +82,8 @@ export class FormData {
|
|
|
82
82
|
};
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
static #ensureInstance(
|
|
86
|
-
return isFileLike(
|
|
85
|
+
static #ensureInstance(val) {
|
|
86
|
+
return isFileLike(val) || (Object(val) === val && Reflect.has(val, Symbol.asyncIterator));
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
#entries = [];
|
|
@@ -110,8 +110,8 @@ export class FormData {
|
|
|
110
110
|
input = Object.entries(input);
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
-
for (const [key,
|
|
114
|
-
this.append(key,
|
|
113
|
+
for (const [key, val] of input) {
|
|
114
|
+
this.append(key, val);
|
|
115
115
|
}
|
|
116
116
|
}
|
|
117
117
|
}
|
|
@@ -226,8 +226,8 @@ export class FormData {
|
|
|
226
226
|
|
|
227
227
|
* values() {
|
|
228
228
|
brandCheck(this, FormData);
|
|
229
|
-
for (const [,
|
|
230
|
-
yield
|
|
229
|
+
for (const [, val] of this) {
|
|
230
|
+
yield val;
|
|
231
231
|
}
|
|
232
232
|
}
|
|
233
233
|
|
package/src/index.js
CHANGED
|
@@ -8,7 +8,7 @@ import { preflight } from './preflight.js';
|
|
|
8
8
|
import { transfer } from './transfer.js';
|
|
9
9
|
import {
|
|
10
10
|
augment,
|
|
11
|
-
|
|
11
|
+
cloneWith,
|
|
12
12
|
normalize,
|
|
13
13
|
snoop,
|
|
14
14
|
} from './utils.js';
|
|
@@ -41,20 +41,20 @@ export default function rekwest(url, options) {
|
|
|
41
41
|
Reflect.defineProperty(rekwest, 'defaults', {
|
|
42
42
|
enumerable: true,
|
|
43
43
|
get() { return config.defaults; },
|
|
44
|
-
set(
|
|
44
|
+
set(val) { config.defaults = cloneWith(config.defaults, val); },
|
|
45
45
|
});
|
|
46
46
|
|
|
47
47
|
Reflect.defineProperty(rekwest, 'extend', {
|
|
48
48
|
enumerable: true,
|
|
49
49
|
value(options) {
|
|
50
|
-
return (url, opts) => rekwest(url,
|
|
50
|
+
return (url, opts) => rekwest(url, cloneWith(options, opts));
|
|
51
51
|
},
|
|
52
52
|
});
|
|
53
53
|
|
|
54
54
|
Reflect.defineProperty(rekwest, 'stream', {
|
|
55
55
|
enumerable: true,
|
|
56
56
|
value(url, options) {
|
|
57
|
-
options = preflight(validation(normalize(url,
|
|
57
|
+
options = preflight(validation(normalize(url, cloneWith({}, options, {
|
|
58
58
|
headers: { [HTTP2_HEADER_CONTENT_TYPE]: APPLICATION_OCTET_STREAM },
|
|
59
59
|
redirect: requestRedirect.manual,
|
|
60
60
|
}))));
|
package/src/retries.js
CHANGED
|
@@ -11,7 +11,7 @@ const {
|
|
|
11
11
|
HTTP2_METHOD_HEAD,
|
|
12
12
|
} = http2.constants;
|
|
13
13
|
|
|
14
|
-
export const retries = (
|
|
14
|
+
export const retries = (err, options) => {
|
|
15
15
|
const { body, maxRetryAfter, method, retry, url } = options;
|
|
16
16
|
|
|
17
17
|
if (retry?.attempts > 0) {
|
|
@@ -19,19 +19,19 @@ export const retries = (ex, options) => {
|
|
|
19
19
|
HTTP2_METHOD_GET,
|
|
20
20
|
HTTP2_METHOD_HEAD,
|
|
21
21
|
].includes(method) && isPipeStream(body) && !isReadable(body)) {
|
|
22
|
-
throw new RequestError('Request stream already read.', { cause:
|
|
22
|
+
throw new RequestError('Request stream already read.', { cause: err });
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
if (retry.errorCodes?.includes(
|
|
25
|
+
if (retry.errorCodes?.includes(err.code) || retry.statusCodes?.includes(err.statusCode)) {
|
|
26
26
|
let { interval } = retry;
|
|
27
27
|
|
|
28
|
-
if (retry.retryAfter &&
|
|
29
|
-
interval =
|
|
28
|
+
if (retry.retryAfter && err.headers?.[HTTP2_HEADER_RETRY_AFTER]) {
|
|
29
|
+
interval = err.headers[HTTP2_HEADER_RETRY_AFTER];
|
|
30
30
|
interval = Math.abs(Number(interval) * 1e3 || new Date(interval) - Date.now()) || 0;
|
|
31
31
|
if (interval > maxRetryAfter) {
|
|
32
32
|
throw new RequestError(
|
|
33
33
|
`Maximum '${ HTTP2_HEADER_RETRY_AFTER }' limit exceeded: ${ interval } ms.`,
|
|
34
|
-
{ cause:
|
|
34
|
+
{ cause: err },
|
|
35
35
|
);
|
|
36
36
|
}
|
|
37
37
|
} else {
|
package/src/transfer.js
CHANGED
|
@@ -34,9 +34,9 @@ export const transfer = async (options) => {
|
|
|
34
34
|
|
|
35
35
|
try {
|
|
36
36
|
options = await transform(preflight(options));
|
|
37
|
-
} catch (
|
|
37
|
+
} catch (err) {
|
|
38
38
|
options.createConnection?.().destroy();
|
|
39
|
-
throw
|
|
39
|
+
throw err;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
const promise = new Promise((resolve, reject) => {
|
|
@@ -72,21 +72,21 @@ export const transfer = async (options) => {
|
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
return res;
|
|
75
|
-
} catch (
|
|
76
|
-
const result = retries(
|
|
75
|
+
} catch (err) {
|
|
76
|
+
const result = retries(err, options);
|
|
77
77
|
|
|
78
78
|
if (result) {
|
|
79
79
|
return result;
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
if (digest && !redirected &&
|
|
83
|
-
|
|
82
|
+
if (digest && !redirected && err.body) {
|
|
83
|
+
err.body = await err.body();
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
if (!thenable) {
|
|
87
|
-
throw
|
|
87
|
+
throw err;
|
|
88
88
|
} else {
|
|
89
|
-
return
|
|
89
|
+
return err;
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
92
|
};
|
package/src/utils.js
CHANGED
|
@@ -15,6 +15,20 @@ const {
|
|
|
15
15
|
HTTP2_HEADER_STATUS,
|
|
16
16
|
} = http2.constants;
|
|
17
17
|
|
|
18
|
+
export const addSearchParams = (url, params = {}) => {
|
|
19
|
+
for (const [key, val] of Object.entries(params)) {
|
|
20
|
+
if (Array.isArray(val)) {
|
|
21
|
+
for (const v of val) {
|
|
22
|
+
url.searchParams.append(key, v);
|
|
23
|
+
}
|
|
24
|
+
} else {
|
|
25
|
+
url.searchParams.set(key, val);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return url;
|
|
30
|
+
};
|
|
31
|
+
|
|
18
32
|
export const augment = (res, headers, options) => {
|
|
19
33
|
const { h2 } = options;
|
|
20
34
|
|
|
@@ -46,45 +60,22 @@ export const augment = (res, headers, options) => {
|
|
|
46
60
|
});
|
|
47
61
|
};
|
|
48
62
|
|
|
49
|
-
export const brandCheck = (
|
|
50
|
-
if (!(
|
|
63
|
+
export const brandCheck = (val, ctor) => {
|
|
64
|
+
if (!(val instanceof ctor)) {
|
|
51
65
|
throw new TypeError('Illegal invocation.');
|
|
52
66
|
}
|
|
53
67
|
};
|
|
54
68
|
|
|
55
|
-
export const
|
|
69
|
+
export const cloneWith = (target, ...rest) => {
|
|
56
70
|
target = structuredClone(target);
|
|
57
71
|
if (!rest.length) {
|
|
58
72
|
return target;
|
|
59
73
|
}
|
|
60
74
|
|
|
61
|
-
return
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
export const dispatch = (req, { body }) => {
|
|
65
|
-
if (isReadable(body)) {
|
|
66
|
-
body.pipe(req);
|
|
67
|
-
} else {
|
|
68
|
-
req.end(body);
|
|
69
|
-
}
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
export const isFileLike = (value) => {
|
|
73
|
-
return [
|
|
74
|
-
Blob,
|
|
75
|
-
File,
|
|
76
|
-
].some((it) => value instanceof it);
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
export const isPipeStream = (value) => {
|
|
80
|
-
return value instanceof Readable;
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
export const isReadableStream = (value) => {
|
|
84
|
-
return value instanceof ReadableStream;
|
|
75
|
+
return deepMerge(target, ...rest);
|
|
85
76
|
};
|
|
86
77
|
|
|
87
|
-
export const
|
|
78
|
+
export const deepMerge = (target, ...rest) => {
|
|
88
79
|
rest = rest.filter((it) => Object(it) === it);
|
|
89
80
|
for (const source of rest) {
|
|
90
81
|
for (const key of Object.getOwnPropertyNames(source)) {
|
|
@@ -92,7 +83,7 @@ export const merge = (target, ...rest) => {
|
|
|
92
83
|
const tv = target[key];
|
|
93
84
|
|
|
94
85
|
if (Object(sv) === sv && Object(tv) === tv) {
|
|
95
|
-
target[key] =
|
|
86
|
+
target[key] = deepMerge(tv, sv);
|
|
96
87
|
continue;
|
|
97
88
|
}
|
|
98
89
|
|
|
@@ -103,9 +94,32 @@ export const merge = (target, ...rest) => {
|
|
|
103
94
|
return target;
|
|
104
95
|
};
|
|
105
96
|
|
|
97
|
+
export const dispatch = (req, { body }) => {
|
|
98
|
+
if (isReadable(body)) {
|
|
99
|
+
body.pipe(req);
|
|
100
|
+
} else {
|
|
101
|
+
req.end(body);
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
export const isFileLike = (val) => {
|
|
106
|
+
return [
|
|
107
|
+
Blob,
|
|
108
|
+
File,
|
|
109
|
+
].some((it) => val instanceof it);
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
export const isPipeStream = (val) => {
|
|
113
|
+
return val instanceof Readable;
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
export const isReadableStream = (val) => {
|
|
117
|
+
return val instanceof ReadableStream;
|
|
118
|
+
};
|
|
119
|
+
|
|
106
120
|
export const normalize = (url, options = {}) => {
|
|
107
121
|
if (!options.redirected) {
|
|
108
|
-
options =
|
|
122
|
+
options = cloneWith(config.defaults, options);
|
|
109
123
|
}
|
|
110
124
|
|
|
111
125
|
if (options.trimTrailingSlashes) {
|
|
@@ -119,30 +133,30 @@ export const normalize = (url, options = {}) => {
|
|
|
119
133
|
return Object.assign(options, {
|
|
120
134
|
headers: normalizeHeaders(options.headers),
|
|
121
135
|
method: options.method.toUpperCase(),
|
|
122
|
-
url: new URL(url, options.baseURL),
|
|
136
|
+
url: addSearchParams(new URL(url, options.baseURL), options.params),
|
|
123
137
|
});
|
|
124
138
|
};
|
|
125
139
|
|
|
126
140
|
export const normalizeHeaders = (headers) => {
|
|
127
|
-
const
|
|
141
|
+
const acc = {};
|
|
128
142
|
|
|
129
|
-
for (const [key,
|
|
143
|
+
for (const [key, val] of Object.entries(headers ?? {})) {
|
|
130
144
|
const name = key.toLowerCase();
|
|
131
145
|
|
|
132
|
-
|
|
146
|
+
acc[key] = val;
|
|
133
147
|
|
|
134
148
|
if (key === HTTP2_HEADER_ACCEPT_ENCODING && !isZstdSupported) {
|
|
135
|
-
const stripped =
|
|
149
|
+
const stripped = val.replace(/\s?zstd,?/gi, '').trim();
|
|
136
150
|
|
|
137
151
|
if (stripped) {
|
|
138
|
-
|
|
152
|
+
acc[key] = stripped;
|
|
139
153
|
} else {
|
|
140
|
-
Reflect.deleteProperty(
|
|
154
|
+
Reflect.deleteProperty(acc, name);
|
|
141
155
|
}
|
|
142
156
|
}
|
|
143
157
|
}
|
|
144
158
|
|
|
145
|
-
return
|
|
159
|
+
return acc;
|
|
146
160
|
};
|
|
147
161
|
|
|
148
162
|
export const sameOrigin = (a, b) => a.protocol === b.protocol && a.hostname === b.hostname && a.port === b.port;
|
|
@@ -169,13 +183,13 @@ export const stripHeaders = (headers = {}, names = []) => {
|
|
|
169
183
|
);
|
|
170
184
|
};
|
|
171
185
|
|
|
172
|
-
export async function* tap(
|
|
173
|
-
if (Reflect.has(
|
|
174
|
-
yield*
|
|
175
|
-
} else if (
|
|
176
|
-
yield*
|
|
186
|
+
export async function* tap(val) {
|
|
187
|
+
if (Reflect.has(val, Symbol.asyncIterator)) {
|
|
188
|
+
yield* val;
|
|
189
|
+
} else if (val.stream) {
|
|
190
|
+
yield* val.stream();
|
|
177
191
|
} else {
|
|
178
|
-
yield await
|
|
192
|
+
yield await val.arrayBuffer();
|
|
179
193
|
}
|
|
180
194
|
}
|
|
181
195
|
|