rekwest 4.2.3 → 4.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/formdata.js +3 -3
- package/dist/index.js +18 -4
- package/dist/mixin.js +99 -0
- package/dist/postflight.js +4 -3
- package/dist/utils.js +7 -111
- package/dist/validation.js +24 -0
- package/package.json +5 -5
- package/src/formdata.mjs +4 -4
- package/src/index.mjs +6 -4
- package/src/mixin.mjs +109 -0
- package/src/postflight.mjs +1 -1
- package/src/utils.mjs +2 -130
- package/src/validation.mjs +33 -0
package/README.md
CHANGED
|
@@ -121,6 +121,7 @@ console.log(res.body);
|
|
|
121
121
|
& [http2.ClientSessionRequestOptions](https://nodejs.org/api/http2.html#http2_clienthttp2session_request_headers_options)
|
|
122
122
|
and [tls.ConnectionOptions](https://nodejs.org/api/tls.html#tls_tls_connect_options_callback)
|
|
123
123
|
for HTTP/2 attunes
|
|
124
|
+
* `baseURL` **{string | URL}** The base URL to use in cases where `url` is a relative URL
|
|
124
125
|
* `body` **{string | Array | ArrayBuffer | ArrayBufferView | AsyncIterator | Blob | Buffer | DataView | File |
|
|
125
126
|
FormData | Iterator | Object | Readable | SharedArrayBuffer | URLSearchParams}** The body to send with the request
|
|
126
127
|
* `cookies` **{boolean | Array<[k, v]> | Cookies | Object | URLSearchParams}** `Default: true` The cookies to add to
|
package/dist/formdata.js
CHANGED
|
@@ -20,16 +20,16 @@ class FormData {
|
|
|
20
20
|
const contentType = `${_mediatypes.MULTIPART_FORM_DATA}; boundary=${boundary}`;
|
|
21
21
|
const prefix = `--${boundary}${CRLF}${HTTP2_HEADER_CONTENT_DISPOSITION}: form-data`;
|
|
22
22
|
const escape = str => str.replace(/\n/g, '%0A').replace(/\r/g, '%0D').replace(/"/g, '%22');
|
|
23
|
-
const
|
|
23
|
+
const redress = value => value.replace(/\r?\n|\r/g, CRLF);
|
|
24
24
|
return {
|
|
25
25
|
contentType,
|
|
26
26
|
async *[Symbol.asyncIterator]() {
|
|
27
27
|
const encoder = new TextEncoder();
|
|
28
28
|
for (const [name, value] of fd) {
|
|
29
29
|
if (value.constructor === String) {
|
|
30
|
-
yield encoder.encode(`${prefix}; name="${escape(
|
|
30
|
+
yield encoder.encode(`${prefix}; name="${escape(redress(name))}"${CRLF.repeat(2)}${redress(value)}${CRLF}`);
|
|
31
31
|
} else {
|
|
32
|
-
yield encoder.encode(`${prefix}; name="${escape(
|
|
32
|
+
yield encoder.encode(`${prefix}; name="${escape(redress(name))}"${value.name ? `; filename="${escape(value.name)}"` : ''}${CRLF}${HTTP2_HEADER_CONTENT_TYPE}: ${value.type || _mediatypes.APPLICATION_OCTET_STREAM}${CRLF.repeat(2)}`);
|
|
33
33
|
yield* (0, _utils.tap)(value);
|
|
34
34
|
yield new Uint8Array([13, 10]);
|
|
35
35
|
}
|
package/dist/index.js
CHANGED
|
@@ -30,6 +30,13 @@ Object.keys(_utils).forEach(function (key) {
|
|
|
30
30
|
if (key in exports && exports[key] === _utils[key]) return;
|
|
31
31
|
exports[key] = _utils[key];
|
|
32
32
|
});
|
|
33
|
+
var _validation = require("./validation");
|
|
34
|
+
Object.keys(_validation).forEach(function (key) {
|
|
35
|
+
if (key === "default" || key === "__esModule") return;
|
|
36
|
+
if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
|
|
37
|
+
if (key in exports && exports[key] === _validation[key]) return;
|
|
38
|
+
exports[key] = _validation[key];
|
|
39
|
+
});
|
|
33
40
|
var _ackn = require("./ackn");
|
|
34
41
|
Object.keys(_ackn).forEach(function (key) {
|
|
35
42
|
if (key === "default" || key === "__esModule") return;
|
|
@@ -65,6 +72,13 @@ Object.keys(_formdata).forEach(function (key) {
|
|
|
65
72
|
if (key in exports && exports[key] === _formdata[key]) return;
|
|
66
73
|
exports[key] = _formdata[key];
|
|
67
74
|
});
|
|
75
|
+
var _mixin = require("./mixin");
|
|
76
|
+
Object.keys(_mixin).forEach(function (key) {
|
|
77
|
+
if (key === "default" || key === "__esModule") return;
|
|
78
|
+
if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
|
|
79
|
+
if (key in exports && exports[key] === _mixin[key]) return;
|
|
80
|
+
exports[key] = _mixin[key];
|
|
81
|
+
});
|
|
68
82
|
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
69
83
|
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
70
84
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
@@ -72,21 +86,21 @@ const {
|
|
|
72
86
|
HTTP2_HEADER_CONTENT_TYPE
|
|
73
87
|
} = _nodeHttp2.default.constants;
|
|
74
88
|
function rekwest(...args) {
|
|
75
|
-
let options = (0, _utils.
|
|
89
|
+
let options = (0, _utils.normalize)(...args);
|
|
76
90
|
if (!options.redirected) {
|
|
77
91
|
options = (0, _utils.merge)(rekwest.defaults, options);
|
|
78
92
|
}
|
|
79
|
-
return (0, _utils.transfer)((0,
|
|
93
|
+
return (0, _utils.transfer)((0, _validation.validation)(options));
|
|
80
94
|
}
|
|
81
95
|
Reflect.defineProperty(rekwest, 'stream', {
|
|
82
96
|
enumerable: true,
|
|
83
97
|
value(...args) {
|
|
84
98
|
const options = (0, _preflight.preflight)({
|
|
85
|
-
...(0,
|
|
99
|
+
...(0, _validation.validation)((0, _utils.merge)(rekwest.defaults, {
|
|
86
100
|
headers: {
|
|
87
101
|
[HTTP2_HEADER_CONTENT_TYPE]: _mediatypes.APPLICATION_OCTET_STREAM
|
|
88
102
|
}
|
|
89
|
-
}, (0, _utils.
|
|
103
|
+
}, (0, _utils.normalize)(...args))),
|
|
90
104
|
redirect: _constants.requestRedirect.manual
|
|
91
105
|
});
|
|
92
106
|
const {
|
package/dist/mixin.js
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
exports.__esModule = true;
|
|
4
|
+
exports.mixin = void 0;
|
|
5
|
+
var _nodeBuffer = require("node:buffer");
|
|
6
|
+
var _nodeHttp = _interopRequireDefault(require("node:http2"));
|
|
7
|
+
var _utils = require("./utils");
|
|
8
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
9
|
+
const {
|
|
10
|
+
HTTP2_HEADER_CONTENT_ENCODING,
|
|
11
|
+
HTTP2_HEADER_CONTENT_TYPE
|
|
12
|
+
} = _nodeHttp.default.constants;
|
|
13
|
+
const mixin = (res, {
|
|
14
|
+
digest = false,
|
|
15
|
+
parse = false
|
|
16
|
+
} = {}) => {
|
|
17
|
+
if (!digest) {
|
|
18
|
+
Object.defineProperties(res, {
|
|
19
|
+
arrayBuffer: {
|
|
20
|
+
enumerable: true,
|
|
21
|
+
value: async function () {
|
|
22
|
+
(0, _utils.brandCheck)(this, res?.constructor);
|
|
23
|
+
parse &&= false;
|
|
24
|
+
const {
|
|
25
|
+
buffer,
|
|
26
|
+
byteLength,
|
|
27
|
+
byteOffset
|
|
28
|
+
} = await this.body();
|
|
29
|
+
return buffer.slice(byteOffset, byteOffset + byteLength);
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
blob: {
|
|
33
|
+
enumerable: true,
|
|
34
|
+
value: async function () {
|
|
35
|
+
(0, _utils.brandCheck)(this, res?.constructor);
|
|
36
|
+
const val = await this.arrayBuffer();
|
|
37
|
+
return new _nodeBuffer.Blob([val]);
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
json: {
|
|
41
|
+
enumerable: true,
|
|
42
|
+
value: async function () {
|
|
43
|
+
(0, _utils.brandCheck)(this, res?.constructor);
|
|
44
|
+
const val = await this.text();
|
|
45
|
+
return JSON.parse(val);
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
text: {
|
|
49
|
+
enumerable: true,
|
|
50
|
+
value: async function () {
|
|
51
|
+
(0, _utils.brandCheck)(this, res?.constructor);
|
|
52
|
+
const blob = await this.blob();
|
|
53
|
+
return blob.text();
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
return Object.defineProperties(res, {
|
|
59
|
+
body: {
|
|
60
|
+
enumerable: true,
|
|
61
|
+
value: async function () {
|
|
62
|
+
(0, _utils.brandCheck)(this, res?.constructor);
|
|
63
|
+
if (this.bodyUsed) {
|
|
64
|
+
throw new TypeError('Response stream already read');
|
|
65
|
+
}
|
|
66
|
+
let body = [];
|
|
67
|
+
for await (const chunk of (0, _utils.decompress)(this, this.headers[HTTP2_HEADER_CONTENT_ENCODING])) {
|
|
68
|
+
body.push(chunk);
|
|
69
|
+
}
|
|
70
|
+
body = Buffer.concat(body);
|
|
71
|
+
if (!body.length && parse) {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
if (body.length && parse) {
|
|
75
|
+
const contentType = this.headers[HTTP2_HEADER_CONTENT_TYPE] ?? '';
|
|
76
|
+
const charset = contentType.split(';').find(it => /charset=/i.test(it))?.toLowerCase().replace('charset=', '').replace('iso-8859-1', 'latin1').trim() || 'utf-8';
|
|
77
|
+
if (/\bjson\b/i.test(contentType)) {
|
|
78
|
+
body = JSON.parse(body.toString(charset));
|
|
79
|
+
} else if (/\b(?:text|xml)\b/i.test(contentType)) {
|
|
80
|
+
if (/\b(?:latin1|ucs-2|utf-(?:8|16le))\b/i.test(charset)) {
|
|
81
|
+
body = body.toString(charset);
|
|
82
|
+
} else {
|
|
83
|
+
body = new TextDecoder(charset).decode(body);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return body;
|
|
88
|
+
},
|
|
89
|
+
writable: true
|
|
90
|
+
},
|
|
91
|
+
bodyUsed: {
|
|
92
|
+
enumerable: true,
|
|
93
|
+
get() {
|
|
94
|
+
return this.readableEnded;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
};
|
|
99
|
+
exports.mixin = mixin;
|
package/dist/postflight.js
CHANGED
|
@@ -8,6 +8,7 @@ var _constants = require("./constants");
|
|
|
8
8
|
var _cookies = require("./cookies");
|
|
9
9
|
var _errors = require("./errors");
|
|
10
10
|
var _index = _interopRequireDefault(require("./index"));
|
|
11
|
+
var _mixin = require("./mixin");
|
|
11
12
|
var _utils = require("./utils");
|
|
12
13
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
13
14
|
const {
|
|
@@ -97,7 +98,7 @@ const postflight = (req, res, options, {
|
|
|
97
98
|
interval = Number(interval) * 1000 || new Date(interval) - Date.now();
|
|
98
99
|
if (interval > options.maxRetryAfter) {
|
|
99
100
|
return res.emit('error', (0, _utils.maxRetryAfterError)(interval, {
|
|
100
|
-
cause: (0,
|
|
101
|
+
cause: (0, _mixin.mixin)(res, options)
|
|
101
102
|
}));
|
|
102
103
|
}
|
|
103
104
|
return (0, _promises.setTimeout)(interval).then(() => (0, _index.default)(options.url, options).then(resolve, reject));
|
|
@@ -106,8 +107,8 @@ const postflight = (req, res, options, {
|
|
|
106
107
|
}
|
|
107
108
|
}
|
|
108
109
|
if (statusCode >= HTTP_STATUS_BAD_REQUEST) {
|
|
109
|
-
return reject((0,
|
|
110
|
+
return reject((0, _mixin.mixin)(res, options));
|
|
110
111
|
}
|
|
111
|
-
resolve((0,
|
|
112
|
+
resolve((0, _mixin.mixin)(res, options));
|
|
112
113
|
};
|
|
113
114
|
exports.postflight = postflight;
|
package/dist/utils.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
exports.__esModule = true;
|
|
4
|
-
exports.
|
|
4
|
+
exports.sameOrigin = exports.normalize = exports.merge = exports.maxRetryAfterError = exports.maxRetryAfter = exports.dispatch = exports.decompress = exports.compress = exports.brandCheck = exports.affix = exports.admix = void 0;
|
|
5
5
|
exports.tap = tap;
|
|
6
|
-
exports.
|
|
7
|
-
var _nodeBuffer = require("node:buffer");
|
|
6
|
+
exports.unwind = exports.transform = exports.transfer = void 0;
|
|
8
7
|
var _nodeHttp = _interopRequireDefault(require("node:http"));
|
|
9
8
|
var _nodeHttp2 = _interopRequireDefault(require("node:http2"));
|
|
10
9
|
var _nodeHttps = _interopRequireDefault(require("node:https"));
|
|
@@ -14,7 +13,6 @@ var _promises = require("node:timers/promises");
|
|
|
14
13
|
var _nodeUtil = require("node:util");
|
|
15
14
|
var _nodeZlib = _interopRequireDefault(require("node:zlib"));
|
|
16
15
|
var _ackn = require("./ackn");
|
|
17
|
-
var _constants = require("./constants");
|
|
18
16
|
var _errors = require("./errors");
|
|
19
17
|
var _file = require("./file");
|
|
20
18
|
var _formdata = require("./formdata");
|
|
@@ -28,9 +26,7 @@ const {
|
|
|
28
26
|
HTTP2_HEADER_CONTENT_LENGTH,
|
|
29
27
|
HTTP2_HEADER_CONTENT_TYPE,
|
|
30
28
|
HTTP2_HEADER_RETRY_AFTER,
|
|
31
|
-
HTTP2_HEADER_STATUS
|
|
32
|
-
HTTP2_METHOD_GET,
|
|
33
|
-
HTTP2_METHOD_HEAD
|
|
29
|
+
HTTP2_HEADER_STATUS
|
|
34
30
|
} = _nodeHttp2.default.constants;
|
|
35
31
|
const admix = (res, headers, options) => {
|
|
36
32
|
const {
|
|
@@ -151,103 +147,16 @@ const merge = (target = {}, ...rest) => {
|
|
|
151
147
|
return target;
|
|
152
148
|
};
|
|
153
149
|
exports.merge = merge;
|
|
154
|
-
const
|
|
155
|
-
digest = false,
|
|
156
|
-
parse = false
|
|
157
|
-
} = {}) => {
|
|
158
|
-
if (!digest) {
|
|
159
|
-
Object.defineProperties(res, {
|
|
160
|
-
arrayBuffer: {
|
|
161
|
-
enumerable: true,
|
|
162
|
-
value: async function () {
|
|
163
|
-
brandCheck(this, res?.constructor);
|
|
164
|
-
parse &&= false;
|
|
165
|
-
const {
|
|
166
|
-
buffer,
|
|
167
|
-
byteLength,
|
|
168
|
-
byteOffset
|
|
169
|
-
} = await this.body();
|
|
170
|
-
return buffer.slice(byteOffset, byteOffset + byteLength);
|
|
171
|
-
}
|
|
172
|
-
},
|
|
173
|
-
blob: {
|
|
174
|
-
enumerable: true,
|
|
175
|
-
value: async function () {
|
|
176
|
-
brandCheck(this, res?.constructor);
|
|
177
|
-
const val = await this.arrayBuffer();
|
|
178
|
-
return new _nodeBuffer.Blob([val]);
|
|
179
|
-
}
|
|
180
|
-
},
|
|
181
|
-
json: {
|
|
182
|
-
enumerable: true,
|
|
183
|
-
value: async function () {
|
|
184
|
-
brandCheck(this, res?.constructor);
|
|
185
|
-
const val = await this.text();
|
|
186
|
-
return JSON.parse(val);
|
|
187
|
-
}
|
|
188
|
-
},
|
|
189
|
-
text: {
|
|
190
|
-
enumerable: true,
|
|
191
|
-
value: async function () {
|
|
192
|
-
brandCheck(this, res?.constructor);
|
|
193
|
-
const blob = await this.blob();
|
|
194
|
-
return blob.text();
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
});
|
|
198
|
-
}
|
|
199
|
-
return Object.defineProperties(res, {
|
|
200
|
-
body: {
|
|
201
|
-
enumerable: true,
|
|
202
|
-
value: async function () {
|
|
203
|
-
brandCheck(this, res?.constructor);
|
|
204
|
-
if (this.bodyUsed) {
|
|
205
|
-
throw new TypeError('Response stream already read');
|
|
206
|
-
}
|
|
207
|
-
let body = [];
|
|
208
|
-
for await (const chunk of decompress(this, this.headers[HTTP2_HEADER_CONTENT_ENCODING])) {
|
|
209
|
-
body.push(chunk);
|
|
210
|
-
}
|
|
211
|
-
body = Buffer.concat(body);
|
|
212
|
-
if (!body.length && parse) {
|
|
213
|
-
return null;
|
|
214
|
-
}
|
|
215
|
-
if (body.length && parse) {
|
|
216
|
-
const contentType = this.headers[HTTP2_HEADER_CONTENT_TYPE] ?? '';
|
|
217
|
-
const charset = contentType.split(';').find(it => /charset=/i.test(it))?.toLowerCase().replace('charset=', '').replace('iso-8859-1', 'latin1').trim() || 'utf-8';
|
|
218
|
-
if (/\bjson\b/i.test(contentType)) {
|
|
219
|
-
body = JSON.parse(body.toString(charset));
|
|
220
|
-
} else if (/\b(?:text|xml)\b/i.test(contentType)) {
|
|
221
|
-
if (/\b(?:latin1|ucs-2|utf-(?:8|16le))\b/i.test(charset)) {
|
|
222
|
-
body = body.toString(charset);
|
|
223
|
-
} else {
|
|
224
|
-
body = new TextDecoder(charset).decode(body);
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
return body;
|
|
229
|
-
},
|
|
230
|
-
writable: true
|
|
231
|
-
},
|
|
232
|
-
bodyUsed: {
|
|
233
|
-
enumerable: true,
|
|
234
|
-
get() {
|
|
235
|
-
return this.readableEnded;
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
});
|
|
239
|
-
};
|
|
240
|
-
exports.mixin = mixin;
|
|
241
|
-
const sanitize = (url, options = {}) => {
|
|
150
|
+
const normalize = (url, options = {}) => {
|
|
242
151
|
if (options.trimTrailingSlashes) {
|
|
243
152
|
url = `${url}`.replace(/(?<!:)\/+/g, '/');
|
|
244
153
|
}
|
|
245
|
-
url = new URL(url);
|
|
154
|
+
url = new URL(url, options.baseURL);
|
|
246
155
|
return Object.assign(options, {
|
|
247
156
|
url
|
|
248
157
|
});
|
|
249
158
|
};
|
|
250
|
-
exports.
|
|
159
|
+
exports.normalize = normalize;
|
|
251
160
|
const sameOrigin = (a, b) => a.protocol === b.protocol && a.hostname === b.hostname && a.port === b.port;
|
|
252
161
|
exports.sameOrigin = sameOrigin;
|
|
253
162
|
async function* tap(value) {
|
|
@@ -407,17 +316,4 @@ const transform = async options => {
|
|
|
407
316
|
};
|
|
408
317
|
exports.transform = transform;
|
|
409
318
|
const unwind = encodings => encodings.split(',').map(it => it.trim());
|
|
410
|
-
exports.unwind = unwind;
|
|
411
|
-
const validation = (options = {}) => {
|
|
412
|
-
if (options.body && [HTTP2_METHOD_GET, HTTP2_METHOD_HEAD].includes(options.method)) {
|
|
413
|
-
throw new TypeError(`Request with ${HTTP2_METHOD_GET}/${HTTP2_METHOD_HEAD} method cannot have body.`);
|
|
414
|
-
}
|
|
415
|
-
if (!Object.values(_constants.requestCredentials).includes(options.credentials)) {
|
|
416
|
-
throw new TypeError(`Failed to read the 'credentials' property from 'options': The provided value '${options.credentials}' is not a valid enum value.`);
|
|
417
|
-
}
|
|
418
|
-
if (!Reflect.has(_constants.requestRedirect, options.redirect)) {
|
|
419
|
-
throw new TypeError(`Failed to read the 'redirect' property from 'options': The provided value '${options.redirect}' is not a valid enum value.`);
|
|
420
|
-
}
|
|
421
|
-
return options;
|
|
422
|
-
};
|
|
423
|
-
exports.validation = validation;
|
|
319
|
+
exports.unwind = unwind;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
exports.__esModule = true;
|
|
4
|
+
exports.validation = void 0;
|
|
5
|
+
var _nodeHttp = _interopRequireDefault(require("node:http2"));
|
|
6
|
+
var _constants = require("./constants");
|
|
7
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
8
|
+
const {
|
|
9
|
+
HTTP2_METHOD_GET,
|
|
10
|
+
HTTP2_METHOD_HEAD
|
|
11
|
+
} = _nodeHttp.default.constants;
|
|
12
|
+
const validation = (options = {}) => {
|
|
13
|
+
if (options.body && [HTTP2_METHOD_GET, HTTP2_METHOD_HEAD].includes(options.method)) {
|
|
14
|
+
throw new TypeError(`Request with ${HTTP2_METHOD_GET}/${HTTP2_METHOD_HEAD} method cannot have body.`);
|
|
15
|
+
}
|
|
16
|
+
if (!Object.values(_constants.requestCredentials).includes(options.credentials)) {
|
|
17
|
+
throw new TypeError(`Failed to read the 'credentials' property from 'options': The provided value '${options.credentials}' is not a valid enum value.`);
|
|
18
|
+
}
|
|
19
|
+
if (!Reflect.has(_constants.requestRedirect, options.redirect)) {
|
|
20
|
+
throw new TypeError(`Failed to read the 'redirect' property from 'options': The provided value '${options.redirect}' is not a valid enum value.`);
|
|
21
|
+
}
|
|
22
|
+
return options;
|
|
23
|
+
};
|
|
24
|
+
exports.validation = validation;
|
package/package.json
CHANGED
|
@@ -8,14 +8,14 @@
|
|
|
8
8
|
"url": "https://github.com/bricss/rekwest/issues"
|
|
9
9
|
},
|
|
10
10
|
"devDependencies": {
|
|
11
|
-
"@babel/cli": "^7.
|
|
12
|
-
"@babel/core": "^7.20.
|
|
11
|
+
"@babel/cli": "^7.20.7",
|
|
12
|
+
"@babel/core": "^7.20.12",
|
|
13
13
|
"@babel/eslint-parser": "^7.19.1",
|
|
14
14
|
"@babel/preset-env": "^7.20.2",
|
|
15
15
|
"c8": "^7.12.0",
|
|
16
|
-
"eslint": "^8.
|
|
16
|
+
"eslint": "^8.33.0",
|
|
17
17
|
"eslint-config-ultra-refined": "^2.10.0",
|
|
18
|
-
"mocha": "^10.
|
|
18
|
+
"mocha": "^10.2.0"
|
|
19
19
|
},
|
|
20
20
|
"description": "The robust request library that humanity deserves 🌐",
|
|
21
21
|
"engines": {
|
|
@@ -67,5 +67,5 @@
|
|
|
67
67
|
"test:bail": "mocha --bail",
|
|
68
68
|
"test:cover": "c8 --include=src --reporter=lcov --reporter=text npm test"
|
|
69
69
|
},
|
|
70
|
-
"version": "4.
|
|
70
|
+
"version": "4.3.0"
|
|
71
71
|
}
|
package/src/formdata.mjs
CHANGED
|
@@ -25,7 +25,7 @@ export class FormData {
|
|
|
25
25
|
const prefix = `--${ boundary }${ CRLF }${ HTTP2_HEADER_CONTENT_DISPOSITION }: form-data`;
|
|
26
26
|
|
|
27
27
|
const escape = (str) => str.replace(/\n/g, '%0A').replace(/\r/g, '%0D').replace(/"/g, '%22');
|
|
28
|
-
const
|
|
28
|
+
const redress = (value) => value.replace(/\r?\n|\r/g, CRLF);
|
|
29
29
|
|
|
30
30
|
return {
|
|
31
31
|
contentType,
|
|
@@ -35,11 +35,11 @@ export class FormData {
|
|
|
35
35
|
for (const [name, value] of fd) {
|
|
36
36
|
if (value.constructor === String) {
|
|
37
37
|
yield encoder.encode(`${ prefix }; name="${
|
|
38
|
-
escape(
|
|
39
|
-
}"${ CRLF.repeat(2) }${
|
|
38
|
+
escape(redress(name))
|
|
39
|
+
}"${ CRLF.repeat(2) }${ redress(value) }${ CRLF }`);
|
|
40
40
|
} else {
|
|
41
41
|
yield encoder.encode(`${ prefix }; name="${
|
|
42
|
-
escape(
|
|
42
|
+
escape(redress(name))
|
|
43
43
|
}"${ value.name ? `; filename="${ escape(value.name) }"` : '' }${ CRLF }${
|
|
44
44
|
HTTP2_HEADER_CONTENT_TYPE
|
|
45
45
|
}: ${
|
package/src/index.mjs
CHANGED
|
@@ -9,10 +9,10 @@ import {
|
|
|
9
9
|
admix,
|
|
10
10
|
affix,
|
|
11
11
|
merge,
|
|
12
|
-
|
|
12
|
+
normalize,
|
|
13
13
|
transfer,
|
|
14
|
-
validation,
|
|
15
14
|
} from './utils.mjs';
|
|
15
|
+
import { validation } from './validation.mjs';
|
|
16
16
|
|
|
17
17
|
export { constants } from 'node:http2';
|
|
18
18
|
|
|
@@ -23,14 +23,16 @@ export * from './errors.mjs';
|
|
|
23
23
|
export * from './file.mjs';
|
|
24
24
|
export * from './formdata.mjs';
|
|
25
25
|
export * as mediatypes from './mediatypes.mjs';
|
|
26
|
+
export * from './mixin.mjs';
|
|
26
27
|
export * from './utils.mjs';
|
|
28
|
+
export * from './validation.mjs';
|
|
27
29
|
|
|
28
30
|
const {
|
|
29
31
|
HTTP2_HEADER_CONTENT_TYPE,
|
|
30
32
|
} = http2.constants;
|
|
31
33
|
|
|
32
34
|
export default function rekwest(...args) {
|
|
33
|
-
let options =
|
|
35
|
+
let options = normalize(...args);
|
|
34
36
|
|
|
35
37
|
if (!options.redirected) {
|
|
36
38
|
options = merge(rekwest.defaults, options);
|
|
@@ -45,7 +47,7 @@ Reflect.defineProperty(rekwest, 'stream', {
|
|
|
45
47
|
const options = preflight({
|
|
46
48
|
...validation(merge(rekwest.defaults, {
|
|
47
49
|
headers: { [HTTP2_HEADER_CONTENT_TYPE]: APPLICATION_OCTET_STREAM },
|
|
48
|
-
},
|
|
50
|
+
}, normalize(...args))),
|
|
49
51
|
redirect: requestRedirect.manual,
|
|
50
52
|
});
|
|
51
53
|
|
package/src/mixin.mjs
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { Blob } from 'node:buffer';
|
|
2
|
+
import http2 from 'node:http2';
|
|
3
|
+
import {
|
|
4
|
+
brandCheck,
|
|
5
|
+
decompress,
|
|
6
|
+
} from './utils.mjs';
|
|
7
|
+
|
|
8
|
+
const {
|
|
9
|
+
HTTP2_HEADER_CONTENT_ENCODING,
|
|
10
|
+
HTTP2_HEADER_CONTENT_TYPE,
|
|
11
|
+
} = http2.constants;
|
|
12
|
+
|
|
13
|
+
export const mixin = (res, { digest = false, parse = false } = {}) => {
|
|
14
|
+
if (!digest) {
|
|
15
|
+
Object.defineProperties(res, {
|
|
16
|
+
arrayBuffer: {
|
|
17
|
+
enumerable: true,
|
|
18
|
+
value: async function () {
|
|
19
|
+
brandCheck(this, res?.constructor);
|
|
20
|
+
parse &&= false;
|
|
21
|
+
const { buffer, byteLength, byteOffset } = await this.body();
|
|
22
|
+
|
|
23
|
+
return buffer.slice(byteOffset, byteOffset + byteLength);
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
blob: {
|
|
27
|
+
enumerable: true,
|
|
28
|
+
value: async function () {
|
|
29
|
+
brandCheck(this, res?.constructor);
|
|
30
|
+
const val = await this.arrayBuffer();
|
|
31
|
+
|
|
32
|
+
return new Blob([val]);
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
json: {
|
|
36
|
+
enumerable: true,
|
|
37
|
+
value: async function () {
|
|
38
|
+
brandCheck(this, res?.constructor);
|
|
39
|
+
const val = await this.text();
|
|
40
|
+
|
|
41
|
+
return JSON.parse(val);
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
text: {
|
|
45
|
+
enumerable: true,
|
|
46
|
+
value: async function () {
|
|
47
|
+
brandCheck(this, res?.constructor);
|
|
48
|
+
const blob = await this.blob();
|
|
49
|
+
|
|
50
|
+
return blob.text();
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return Object.defineProperties(res, {
|
|
57
|
+
body: {
|
|
58
|
+
enumerable: true,
|
|
59
|
+
value: async function () {
|
|
60
|
+
brandCheck(this, res?.constructor);
|
|
61
|
+
|
|
62
|
+
if (this.bodyUsed) {
|
|
63
|
+
throw new TypeError('Response stream already read');
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
let body = [];
|
|
67
|
+
|
|
68
|
+
for await (const chunk of decompress(this, this.headers[HTTP2_HEADER_CONTENT_ENCODING])) {
|
|
69
|
+
body.push(chunk);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
body = Buffer.concat(body);
|
|
73
|
+
|
|
74
|
+
if (!body.length && parse) {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (body.length && parse) {
|
|
79
|
+
const contentType = this.headers[HTTP2_HEADER_CONTENT_TYPE] ?? '';
|
|
80
|
+
const charset = contentType.split(';')
|
|
81
|
+
.find((it) => /charset=/i.test(it))
|
|
82
|
+
?.toLowerCase()
|
|
83
|
+
.replace('charset=', '')
|
|
84
|
+
.replace('iso-8859-1', 'latin1')
|
|
85
|
+
.trim() || 'utf-8';
|
|
86
|
+
|
|
87
|
+
if (/\bjson\b/i.test(contentType)) {
|
|
88
|
+
body = JSON.parse(body.toString(charset));
|
|
89
|
+
} else if (/\b(?:text|xml)\b/i.test(contentType)) {
|
|
90
|
+
if (/\b(?:latin1|ucs-2|utf-(?:8|16le))\b/i.test(charset)) {
|
|
91
|
+
body = body.toString(charset);
|
|
92
|
+
} else {
|
|
93
|
+
body = new TextDecoder(charset).decode(body);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return body;
|
|
99
|
+
},
|
|
100
|
+
writable: true,
|
|
101
|
+
},
|
|
102
|
+
bodyUsed: {
|
|
103
|
+
enumerable: true,
|
|
104
|
+
get() {
|
|
105
|
+
return this.readableEnded;
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
};
|
package/src/postflight.mjs
CHANGED
|
@@ -8,10 +8,10 @@ import {
|
|
|
8
8
|
import { Cookies } from './cookies.mjs';
|
|
9
9
|
import { RequestError } from './errors.mjs';
|
|
10
10
|
import rekwest from './index.mjs';
|
|
11
|
+
import { mixin } from './mixin.mjs';
|
|
11
12
|
import {
|
|
12
13
|
admix,
|
|
13
14
|
maxRetryAfterError,
|
|
14
|
-
mixin,
|
|
15
15
|
sameOrigin,
|
|
16
16
|
} from './utils.mjs';
|
|
17
17
|
|
package/src/utils.mjs
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { Blob } from 'node:buffer';
|
|
2
1
|
import http from 'node:http';
|
|
3
2
|
import http2 from 'node:http2';
|
|
4
3
|
import https from 'node:https';
|
|
@@ -11,10 +10,6 @@ import { setTimeout as setTimeoutPromise } from 'node:timers/promises';
|
|
|
11
10
|
import { types } from 'node:util';
|
|
12
11
|
import zlib from 'node:zlib';
|
|
13
12
|
import { ackn } from './ackn.mjs';
|
|
14
|
-
import {
|
|
15
|
-
requestCredentials,
|
|
16
|
-
requestRedirect,
|
|
17
|
-
} from './constants.mjs';
|
|
18
13
|
import {
|
|
19
14
|
RequestError,
|
|
20
15
|
TimeoutError,
|
|
@@ -36,8 +31,6 @@ const {
|
|
|
36
31
|
HTTP2_HEADER_CONTENT_TYPE,
|
|
37
32
|
HTTP2_HEADER_RETRY_AFTER,
|
|
38
33
|
HTTP2_HEADER_STATUS,
|
|
39
|
-
HTTP2_METHOD_GET,
|
|
40
|
-
HTTP2_METHOD_HEAD,
|
|
41
34
|
} = http2.constants;
|
|
42
35
|
|
|
43
36
|
export const admix = (res, headers, options) => {
|
|
@@ -178,110 +171,12 @@ export const merge = (target = {}, ...rest) => {
|
|
|
178
171
|
return target;
|
|
179
172
|
};
|
|
180
173
|
|
|
181
|
-
export const
|
|
182
|
-
if (!digest) {
|
|
183
|
-
Object.defineProperties(res, {
|
|
184
|
-
arrayBuffer: {
|
|
185
|
-
enumerable: true,
|
|
186
|
-
value: async function () {
|
|
187
|
-
brandCheck(this, res?.constructor);
|
|
188
|
-
parse &&= false;
|
|
189
|
-
const { buffer, byteLength, byteOffset } = await this.body();
|
|
190
|
-
|
|
191
|
-
return buffer.slice(byteOffset, byteOffset + byteLength);
|
|
192
|
-
},
|
|
193
|
-
},
|
|
194
|
-
blob: {
|
|
195
|
-
enumerable: true,
|
|
196
|
-
value: async function () {
|
|
197
|
-
brandCheck(this, res?.constructor);
|
|
198
|
-
const val = await this.arrayBuffer();
|
|
199
|
-
|
|
200
|
-
return new Blob([val]);
|
|
201
|
-
},
|
|
202
|
-
},
|
|
203
|
-
json: {
|
|
204
|
-
enumerable: true,
|
|
205
|
-
value: async function () {
|
|
206
|
-
brandCheck(this, res?.constructor);
|
|
207
|
-
const val = await this.text();
|
|
208
|
-
|
|
209
|
-
return JSON.parse(val);
|
|
210
|
-
},
|
|
211
|
-
},
|
|
212
|
-
text: {
|
|
213
|
-
enumerable: true,
|
|
214
|
-
value: async function () {
|
|
215
|
-
brandCheck(this, res?.constructor);
|
|
216
|
-
const blob = await this.blob();
|
|
217
|
-
|
|
218
|
-
return blob.text();
|
|
219
|
-
},
|
|
220
|
-
},
|
|
221
|
-
});
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
return Object.defineProperties(res, {
|
|
225
|
-
body: {
|
|
226
|
-
enumerable: true,
|
|
227
|
-
value: async function () {
|
|
228
|
-
brandCheck(this, res?.constructor);
|
|
229
|
-
|
|
230
|
-
if (this.bodyUsed) {
|
|
231
|
-
throw new TypeError('Response stream already read');
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
let body = [];
|
|
235
|
-
|
|
236
|
-
for await (const chunk of decompress(this, this.headers[HTTP2_HEADER_CONTENT_ENCODING])) {
|
|
237
|
-
body.push(chunk);
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
body = Buffer.concat(body);
|
|
241
|
-
|
|
242
|
-
if (!body.length && parse) {
|
|
243
|
-
return null;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
if (body.length && parse) {
|
|
247
|
-
const contentType = this.headers[HTTP2_HEADER_CONTENT_TYPE] ?? '';
|
|
248
|
-
const charset = contentType.split(';')
|
|
249
|
-
.find((it) => /charset=/i.test(it))
|
|
250
|
-
?.toLowerCase()
|
|
251
|
-
.replace('charset=', '')
|
|
252
|
-
.replace('iso-8859-1', 'latin1')
|
|
253
|
-
.trim() || 'utf-8';
|
|
254
|
-
|
|
255
|
-
if (/\bjson\b/i.test(contentType)) {
|
|
256
|
-
body = JSON.parse(body.toString(charset));
|
|
257
|
-
} else if (/\b(?:text|xml)\b/i.test(contentType)) {
|
|
258
|
-
if (/\b(?:latin1|ucs-2|utf-(?:8|16le))\b/i.test(charset)) {
|
|
259
|
-
body = body.toString(charset);
|
|
260
|
-
} else {
|
|
261
|
-
body = new TextDecoder(charset).decode(body);
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
return body;
|
|
267
|
-
},
|
|
268
|
-
writable: true,
|
|
269
|
-
},
|
|
270
|
-
bodyUsed: {
|
|
271
|
-
enumerable: true,
|
|
272
|
-
get() {
|
|
273
|
-
return this.readableEnded;
|
|
274
|
-
},
|
|
275
|
-
},
|
|
276
|
-
});
|
|
277
|
-
};
|
|
278
|
-
|
|
279
|
-
export const sanitize = (url, options = {}) => {
|
|
174
|
+
export const normalize = (url, options = {}) => {
|
|
280
175
|
if (options.trimTrailingSlashes) {
|
|
281
176
|
url = `${ url }`.replace(/(?<!:)\/+/g, '/');
|
|
282
177
|
}
|
|
283
178
|
|
|
284
|
-
url = new URL(url);
|
|
179
|
+
url = new URL(url, options.baseURL);
|
|
285
180
|
|
|
286
181
|
return Object.assign(options, { url });
|
|
287
182
|
};
|
|
@@ -452,26 +347,3 @@ export const transform = async (options) => {
|
|
|
452
347
|
};
|
|
453
348
|
|
|
454
349
|
export const unwind = (encodings) => encodings.split(',').map((it) => it.trim());
|
|
455
|
-
|
|
456
|
-
export const validation = (options = {}) => {
|
|
457
|
-
if (options.body && [
|
|
458
|
-
HTTP2_METHOD_GET,
|
|
459
|
-
HTTP2_METHOD_HEAD,
|
|
460
|
-
].includes(options.method)) {
|
|
461
|
-
throw new TypeError(`Request with ${ HTTP2_METHOD_GET }/${ HTTP2_METHOD_HEAD } method cannot have body.`);
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
if (!Object.values(requestCredentials).includes(options.credentials)) {
|
|
465
|
-
throw new TypeError(`Failed to read the 'credentials' property from 'options': The provided value '${
|
|
466
|
-
options.credentials
|
|
467
|
-
}' is not a valid enum value.`);
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
if (!Reflect.has(requestRedirect, options.redirect)) {
|
|
471
|
-
throw new TypeError(`Failed to read the 'redirect' property from 'options': The provided value '${
|
|
472
|
-
options.redirect
|
|
473
|
-
}' is not a valid enum value.`);
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
return options;
|
|
477
|
-
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import http2 from 'node:http2';
|
|
2
|
+
import {
|
|
3
|
+
requestCredentials,
|
|
4
|
+
requestRedirect,
|
|
5
|
+
} from './constants.mjs';
|
|
6
|
+
|
|
7
|
+
const {
|
|
8
|
+
HTTP2_METHOD_GET,
|
|
9
|
+
HTTP2_METHOD_HEAD,
|
|
10
|
+
} = http2.constants;
|
|
11
|
+
|
|
12
|
+
export const validation = (options = {}) => {
|
|
13
|
+
if (options.body && [
|
|
14
|
+
HTTP2_METHOD_GET,
|
|
15
|
+
HTTP2_METHOD_HEAD,
|
|
16
|
+
].includes(options.method)) {
|
|
17
|
+
throw new TypeError(`Request with ${ HTTP2_METHOD_GET }/${ HTTP2_METHOD_HEAD } method cannot have body.`);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (!Object.values(requestCredentials).includes(options.credentials)) {
|
|
21
|
+
throw new TypeError(`Failed to read the 'credentials' property from 'options': The provided value '${
|
|
22
|
+
options.credentials
|
|
23
|
+
}' is not a valid enum value.`);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (!Reflect.has(requestRedirect, options.redirect)) {
|
|
27
|
+
throw new TypeError(`Failed to read the 'redirect' property from 'options': The provided value '${
|
|
28
|
+
options.redirect
|
|
29
|
+
}' is not a valid enum value.`);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return options;
|
|
33
|
+
};
|