rekwest 5.3.1 → 5.4.1

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 CHANGED
@@ -1,245 +1,245 @@
1
- The robust request library that humanity deserves 🌐
2
- ---
3
- This package provides highly likely functional and **easy-to-use** abstraction atop of
4
- native [http(s).request](https://nodejs.org/api/https.html#httpsrequesturl-options-callback)
5
- and [http2.request](https://nodejs.org/api/http2.html#clienthttp2sessionrequestheaders-options).
6
-
7
- ## Abstract
8
-
9
- * Fetch-alike
10
- * Cool-beans 🫐 config options (with defaults)
11
- * Automatic HTTP/2 support (ALPN negotiation)
12
- * Automatic or opt-in body parse (with non-UTF-8 charset decoding)
13
- * Automatic and simplistic `Cookies` treatment (with built-in **jar** & **ttl**)
14
- * Automatic decompression (with opt-in body compression)
15
- * Built-in streamable `FormData` interface
16
- * Support redirects & retries with fine-grained tune-ups
17
- * Support all legit request body types (include blobs & streams)
18
- * Support both CJS and ESM module systems
19
- * Fully promise-able and pipe-able
20
- * Zero dependencies
21
-
22
- ## Prerequisites
23
-
24
- * Node.js `>= 18.13.0`
25
-
26
- ## Installation
27
-
28
- ```bash
29
- npm install rekwest --save
30
- ```
31
-
32
- ### Usage
33
-
34
- ```javascript
35
- import rekwest, { constants } from 'rekwest';
36
-
37
- const {
38
- HTTP2_HEADER_AUTHORIZATION,
39
- HTTP2_HEADER_CONTENT_ENCODING,
40
- HTTP2_METHOD_POST,
41
- HTTP_STATUS_OK,
42
- } = constants;
43
-
44
- const url = 'https://somewhe.re/somewhat/endpoint';
45
-
46
- const res = await rekwest(url, {
47
- body: { celestial: 'payload' },
48
- headers: {
49
- [HTTP2_HEADER_AUTHORIZATION]: 'Bearer [token]',
50
- [HTTP2_HEADER_CONTENT_ENCODING]: 'br', // enables: body compression
51
- /** [HTTP2_HEADER_CONTENT_TYPE]
52
- * is undue for
53
- * Array/Blob/File/FormData/Object/URLSearchParams body types
54
- * and will be set automatically, with an option to override it here
55
- */
56
- },
57
- method: HTTP2_METHOD_POST,
58
- });
59
-
60
- console.assert(res.statusCode === HTTP_STATUS_OK);
61
- console.info(res.headers);
62
- console.log(res.body);
63
- ```
64
-
65
- ---
66
-
67
- ```javascript
68
- import { Readable } from 'node:stream';
69
- import rekwest, {
70
- constants,
71
- Blob,
72
- File,
73
- FormData,
74
- } from 'rekwest';
75
-
76
- const {
77
- HTTP2_HEADER_AUTHORIZATION,
78
- HTTP2_HEADER_CONTENT_ENCODING,
79
- HTTP2_METHOD_POST,
80
- HTTP_STATUS_OK,
81
- } = constants;
82
-
83
- const blob = new Blob(['bits']);
84
- const file = new File(['bits'], 'file.dab');
85
- const readable = Readable.from('bits');
86
-
87
- const fd = new FormData({
88
- aux: Date.now(), // either [[key, value]] or kv sequenceable
89
- });
90
-
91
- fd.append('celestial', 'payload');
92
- fd.append('blob', blob, 'blob.dab');
93
- fd.append('file', file);
94
- fd.append('readable', readable, 'readable.dab');
95
-
96
- const url = 'https://somewhe.re/somewhat/endpoint';
97
-
98
- const res = await rekwest(url, {
99
- body: fd,
100
- headers: {
101
- [HTTP2_HEADER_AUTHORIZATION]: 'Bearer [token]',
102
- [HTTP2_HEADER_CONTENT_ENCODING]: 'br', // enables: body compression
103
- },
104
- method: HTTP2_METHOD_POST,
105
- });
106
-
107
- console.assert(res.statusCode === HTTP_STATUS_OK);
108
- console.info(res.headers);
109
- console.log(res.body);
110
- ```
111
-
112
- ### API
113
-
114
- #### `rekwest(url[, options])`
115
-
116
- * `url` **{string | URL}** The URL to send the request to
117
- * `options` **{Object}**
118
- Extends [http(s).RequestOptions](https://nodejs.org/api/https.html#httpsrequesturl-options-callback) along with
119
- extra [http2.ClientSessionOptions](https://nodejs.org/api/http2.html#http2connectauthority-options-listener)
120
- & [http2.ClientSessionRequestOptions](https://nodejs.org/api/http2.html#clienthttp2sessionrequestheaders-options)
121
- and [tls.ConnectionOptions](https://nodejs.org/api/tls.html#tlsconnectoptions-callback)
122
- for HTTP/2 attunes
123
- * `baseURL` **{string | URL}** The base URL to use in cases where `url` is a relative URL
124
- * `body` **{string | Array | ArrayBuffer | ArrayBufferView | AsyncIterator | Blob | Buffer | DataView | File |
125
- FormData | Iterator | Object | Readable | ReadableStream | SharedArrayBuffer | URLSearchParams}** The body to send
126
- with the request
127
- * `cookies` **{boolean | Array<[k, v]> | Array<string\> | Cookies | Object | URLSearchParams}** `Default: true` The
128
- cookies to add to
129
- the request
130
- * `cookiesTTL` **{boolean}** `Default: false` Controls enablement of TTL for the cookies cache
131
- * `credentials` **{include | omit | same-origin}** `Default: same-origin` Controls credentials in case of cross-origin
132
- redirects
133
- * `digest` **{boolean}** `Default: true` Controls whether to read the response stream or simply add a mixin
134
- * `follow` **{number}** `Default: 20` The number of redirects to follow
135
- * `h2` **{boolean}** `Default: false` Forces the use of HTTP/2 protocol
136
- * `headers` **{Object}** The headers to add to the request
137
- * `maxRetryAfter` **{number}** The upper limit of `retry-after` header. If unset, it will use `timeout` value
138
- * `parse` **{boolean}** `Default: true` Controls whether to parse response body or simply return a buffer
139
- * `redirect` **{error | follow | manual}** `Default: follow` Controls the redirect flows
140
- * `retry` **{Object}** Represents the retry options
141
- * `attempts` **{number}** `Default: 0` The number of retry attempts
142
- * `backoffStrategy` **{string}** `Default: interval * Math.log(Math.random() * (Math.E * Math.E - Math.E) + Math.E)`
143
- The backoff strategy algorithm that increases logarithmically. To fixate set value to `interval * 1`
144
- * `errorCodes` **{string[]}**
145
- `Default: ['EAI_AGAIN', 'ECONNREFUSED', 'ECONNRESET', 'EHOSTDOWN', 'EHOSTUNREACH', 'ENETDOWN', 'ENETUNREACH', 'ENOTFOUND', 'EPIPE', 'ERR_HTTP2_STREAM_ERROR']`
146
- The list of error codes to retry on
147
- * `interval` **{number}** `Default: 1e3` The initial retry interval
148
- * `retryAfter` **{boolean}** `Default: true` Controls `retry-after` header receptiveness
149
- * `statusCodes` **{number[]}** `Default: [429, 500, 502, 503, 504]` The list of status codes to retry on
150
- * `stripTrailingSlash` **{boolean}** `Default: false` Controls whether to strip trailing slash at the end of the URL
151
- * `thenable` **{boolean}** `Default: false` Controls the promise resolutions
152
- * `timeout` **{number}** `Default: 3e5` The number of milliseconds a request can take before termination
153
- * `trimTrailingSlashes` **{boolean}** `Default: false` Controls whether to trim trailing slashes within the URL
154
- * **Returns:** Promise that resolves to
155
- extended [http.IncomingMessage](https://nodejs.org/api/http.html#class-httpincomingmessage)
156
- or [http2.ClientHttp2Stream](https://nodejs.org/api/http2.html#class-clienthttp2stream) which is respectively
157
- readable and duplex streams
158
- * if `digest: true` & `parse: true`
159
- * `body` **{string | Array | Buffer | Object}** The body based on its content type
160
- * if `digest: false`
161
- * `arrayBuffer` **{AsyncFunction}** Reads the response and returns **ArrayBuffer**
162
- * `blob` **{AsyncFunction}** Reads the response and returns **Blob**
163
- * `body` **{AsyncFunction}** Reads the response and returns **Buffer** if `parse: false`
164
- * `bytes` **{AsyncFunction}** Reads the response and returns **Uint8Array**
165
- * `json` **{AsyncFunction}** Reads the response and returns **Object**
166
- * `text` **{AsyncFunction}** Reads the response and returns **String**
167
- * `bodyUsed` **{boolean}** Indicates whether the response were read or not
168
- * `cookies` **{undefined | Cookies}** The cookies sent and received with the response
169
- * `headers` **{Object}** The headers received with the response
170
- * `httpVersion` **{string}** Indicates protocol version negotiated with the server
171
- * `ok` **{boolean}** Indicates if the response was successful (statusCode: **200-299**)
172
- * `redirected` **{boolean}** Indicates if the response is the result of a redirect
173
- * `statusCode` **{number}** Indicates the status code of the response
174
- * `trailers` **{undefined | Object}** The trailer headers received with the response
175
-
176
- ---
177
-
178
- #### `rekwest.defaults`
179
-
180
- The object to fulfill with default [options](#rekwesturl-options).
181
-
182
- ---
183
-
184
- #### `rekwest.extend(options)`
185
-
186
- The method to extend default [options](#rekwesturl-options) per instance.
187
-
188
- ```javascript
189
- import rekwest, { constants } from 'rekwest';
190
-
191
- const {
192
- HTTP_STATUS_OK,
193
- } = constants;
194
-
195
- const rk = rekwest.extend({
196
- baseURL: 'https://somewhe.re',
197
- });
198
-
199
- const signal = AbortSignal.timeout(1e4);
200
- const url = '/somewhat/endpoint';
201
-
202
- const res = await rk(url, {
203
- signal,
204
- });
205
-
206
- console.assert(res.statusCode === HTTP_STATUS_OK);
207
- console.info(res.headers);
208
- console.log(res.body);
209
- ```
210
-
211
- ---
212
-
213
- #### `rekwest.stream(url[, options])`
214
-
215
- The method with limited functionality to use with streams and/or pipes.
216
-
217
- * No automata (redirects & retries)
218
- * Pass `h2: true` in options to use HTTP/2 protocol
219
- * Use `ackn({ url: URL })` method in advance to check the available protocols
220
-
221
- ```javascript
222
- import fs from 'node:fs';
223
- import { pipeline } from 'node:stream/promises';
224
- import rekwest, {
225
- ackn,
226
- constants,
227
- } from 'rekwest';
228
-
229
- const {
230
- HTTP2_METHOD_POST,
231
- } = constants;
232
-
233
- const url = new URL('https://somewhe.re/somewhat/endpoint');
234
- const options = await ackn({ url });
235
-
236
- await pipeline(
237
- fs.createReadStream('/path/to/read/inlet.xyz'),
238
- rekwest.stream(url, { ...options, method: HTTP2_METHOD_POST }),
239
- fs.createWriteStream('/path/to/write/outlet.xyz'),
240
- );
241
- ```
242
-
243
- ---
244
-
245
- For more details, please check tests (coverage: **>97%**) in the repository.
1
+ The robust request library that humanity deserves 🌐
2
+ ---
3
+ This package provides highly likely functional and **easy-to-use** abstraction atop of
4
+ native [http(s).request](https://nodejs.org/api/https.html#httpsrequesturl-options-callback)
5
+ and [http2.request](https://nodejs.org/api/http2.html#clienthttp2sessionrequestheaders-options).
6
+
7
+ ## Abstract
8
+
9
+ * Fetch-alike 🥏
10
+ * Cool-beans 🫐 config options (with defaults)
11
+ * Automatic HTTP/2 support (ALPN negotiation) 💼
12
+ * Automatic or opt-in body parse (with non-UTF-8 charset decoding) 🉑
13
+ * Automatic and simplistic `Cookies` treatment (with built-in **jar** & **ttl**) 🍪
14
+ * Automatic decompression (with opt-in body compression) 🗜️
15
+ * Built-in streamable `FormData` interface 🔌
16
+ * Support redirects & retries with fine-grained tune-ups 🪛
17
+ * Support all legit request body types (include blobs & streams) 📦
18
+ * Support both CJS and ESM module systems 🧩
19
+ * Fully promise-able and pipe-able 🔗
20
+ * Zero dependencies 🗽
21
+
22
+ ## Prerequisites
23
+
24
+ * Node.js `>= 18.13.0`
25
+
26
+ ## Installation
27
+
28
+ ```bash
29
+ npm install rekwest --save
30
+ ```
31
+
32
+ ### Usage
33
+
34
+ ```javascript
35
+ import rekwest, { constants } from 'rekwest';
36
+
37
+ const {
38
+ HTTP2_HEADER_AUTHORIZATION,
39
+ HTTP2_HEADER_CONTENT_ENCODING,
40
+ HTTP2_METHOD_POST,
41
+ HTTP_STATUS_OK,
42
+ } = constants;
43
+
44
+ const url = 'https://somewhe.re/somewhat/endpoint';
45
+
46
+ const res = await rekwest(url, {
47
+ body: { celestial: 'payload' },
48
+ headers: {
49
+ [HTTP2_HEADER_AUTHORIZATION]: 'Bearer [token]',
50
+ [HTTP2_HEADER_CONTENT_ENCODING]: 'br', // enables: body compression
51
+ /** [HTTP2_HEADER_CONTENT_TYPE]
52
+ * is undue for
53
+ * Array/Blob/File/FormData/Object/URLSearchParams body types
54
+ * and will be set automatically, with an option to override it here
55
+ */
56
+ },
57
+ method: HTTP2_METHOD_POST,
58
+ });
59
+
60
+ console.assert(res.statusCode === HTTP_STATUS_OK);
61
+ console.info(res.headers);
62
+ console.log(res.body);
63
+ ```
64
+
65
+ ---
66
+
67
+ ```javascript
68
+ import { Readable } from 'node:stream';
69
+ import rekwest, {
70
+ constants,
71
+ Blob,
72
+ File,
73
+ FormData,
74
+ } from 'rekwest';
75
+
76
+ const {
77
+ HTTP2_HEADER_AUTHORIZATION,
78
+ HTTP2_HEADER_CONTENT_ENCODING,
79
+ HTTP2_METHOD_POST,
80
+ HTTP_STATUS_OK,
81
+ } = constants;
82
+
83
+ const blob = new Blob(['bits']);
84
+ const file = new File(['bits'], 'file.dab');
85
+ const readable = Readable.from('bits');
86
+
87
+ const fd = new FormData({
88
+ aux: Date.now(), // either [[key, value]] or kv sequenceable
89
+ });
90
+
91
+ fd.append('celestial', 'payload');
92
+ fd.append('blob', blob, 'blob.dab');
93
+ fd.append('file', file);
94
+ fd.append('readable', readable, 'readable.dab');
95
+
96
+ const url = 'https://somewhe.re/somewhat/endpoint';
97
+
98
+ const res = await rekwest(url, {
99
+ body: fd,
100
+ headers: {
101
+ [HTTP2_HEADER_AUTHORIZATION]: 'Bearer [token]',
102
+ [HTTP2_HEADER_CONTENT_ENCODING]: 'zstd', // enables: body compression
103
+ },
104
+ method: HTTP2_METHOD_POST,
105
+ });
106
+
107
+ console.assert(res.statusCode === HTTP_STATUS_OK);
108
+ console.info(res.headers);
109
+ console.log(res.body);
110
+ ```
111
+
112
+ ### API
113
+
114
+ #### `rekwest(url[, options])`
115
+
116
+ * `url` **{string | URL}** The URL to send the request to
117
+ * `options` **{Object}**
118
+ Extends [http(s).RequestOptions](https://nodejs.org/api/https.html#httpsrequesturl-options-callback) along with
119
+ extra [http2.ClientSessionOptions](https://nodejs.org/api/http2.html#http2connectauthority-options-listener)
120
+ & [http2.ClientSessionRequestOptions](https://nodejs.org/api/http2.html#clienthttp2sessionrequestheaders-options)
121
+ and [tls.ConnectionOptions](https://nodejs.org/api/tls.html#tlsconnectoptions-callback)
122
+ for HTTP/2 attunes
123
+ * `baseURL` **{string | URL}** The base URL to use in cases where `url` is a relative URL
124
+ * `body` **{string | Array | ArrayBuffer | ArrayBufferView | AsyncIterator | Blob | Buffer | DataView | File |
125
+ FormData | Iterator | Object | Readable | ReadableStream | SharedArrayBuffer | URLSearchParams}** The body to send
126
+ with the request
127
+ * `cookies` **{boolean | Array<[k, v]> | Array<string\> | Cookies | Object | URLSearchParams}** `Default: true` The
128
+ cookies to add to
129
+ the request
130
+ * `cookiesTTL` **{boolean}** `Default: false` Controls enablement of TTL for the cookies cache
131
+ * `credentials` **{include | omit | same-origin}** `Default: same-origin` Controls credentials in case of cross-origin
132
+ redirects
133
+ * `digest` **{boolean}** `Default: true` Controls whether to read the response stream or simply add a mixin
134
+ * `follow` **{number}** `Default: 20` The number of redirects to follow
135
+ * `h2` **{boolean}** `Default: false` Forces the use of HTTP/2 protocol
136
+ * `headers` **{Object}** The headers to add to the request
137
+ * `maxRetryAfter` **{number}** The upper limit of `retry-after` header. If unset, it will use `timeout` value
138
+ * `parse` **{boolean}** `Default: true` Controls whether to parse response body or simply return a buffer
139
+ * `redirect` **{error | follow | manual}** `Default: follow` Controls the redirect flows
140
+ * `retry` **{Object}** Represents the retry options
141
+ * `attempts` **{number}** `Default: 0` The number of retry attempts
142
+ * `backoffStrategy` **{string}** `Default: interval * Math.log(Math.random() * (Math.E * Math.E - Math.E) + Math.E)`
143
+ The backoff strategy algorithm that increases logarithmically. To fixate set value to `interval * 1`
144
+ * `errorCodes` **{string[]}**
145
+ `Default: ['EAI_AGAIN', 'ECONNREFUSED', 'ECONNRESET', 'EHOSTDOWN', 'EHOSTUNREACH', 'ENETDOWN', 'ENETUNREACH', 'ENOTFOUND', 'EPIPE', 'ERR_HTTP2_STREAM_ERROR']`
146
+ The list of error codes to retry on
147
+ * `interval` **{number}** `Default: 1e3` The initial retry interval
148
+ * `retryAfter` **{boolean}** `Default: true` Controls `retry-after` header receptiveness
149
+ * `statusCodes` **{number[]}** `Default: [429, 500, 502, 503, 504]` The list of status codes to retry on
150
+ * `stripTrailingSlash` **{boolean}** `Default: false` Controls whether to strip trailing slash at the end of the URL
151
+ * `thenable` **{boolean}** `Default: false` Controls the promise resolutions
152
+ * `timeout` **{number}** `Default: 3e5` The number of milliseconds a request can take before termination
153
+ * `trimTrailingSlashes` **{boolean}** `Default: false` Controls whether to trim trailing slashes within the URL
154
+ * **Returns:** Promise that resolves to
155
+ extended [http.IncomingMessage](https://nodejs.org/api/http.html#class-httpincomingmessage)
156
+ or [http2.ClientHttp2Stream](https://nodejs.org/api/http2.html#class-clienthttp2stream) which is respectively
157
+ readable and duplex streams
158
+ * if `digest: true` & `parse: true`
159
+ * `body` **{string | Array | Buffer | Object}** The body based on its content type
160
+ * if `digest: false`
161
+ * `arrayBuffer` **{AsyncFunction}** Reads the response and returns **ArrayBuffer**
162
+ * `blob` **{AsyncFunction}** Reads the response and returns **Blob**
163
+ * `body` **{AsyncFunction}** Reads the response and returns **Buffer** if `parse: false`
164
+ * `bytes` **{AsyncFunction}** Reads the response and returns **Uint8Array**
165
+ * `json` **{AsyncFunction}** Reads the response and returns **Object**
166
+ * `text` **{AsyncFunction}** Reads the response and returns **String**
167
+ * `bodyUsed` **{boolean}** Indicates whether the response were read or not
168
+ * `cookies` **{undefined | Cookies}** The cookies sent and received with the response
169
+ * `headers` **{Object}** The headers received with the response
170
+ * `httpVersion` **{string}** Indicates protocol version negotiated with the server
171
+ * `ok` **{boolean}** Indicates if the response was successful (statusCode: **200-299**)
172
+ * `redirected` **{boolean}** Indicates if the response is the result of a redirect
173
+ * `statusCode` **{number}** Indicates the status code of the response
174
+ * `trailers` **{undefined | Object}** The trailer headers received with the response
175
+
176
+ ---
177
+
178
+ #### `rekwest.defaults`
179
+
180
+ The object to fulfill with default [options](#rekwesturl-options).
181
+
182
+ ---
183
+
184
+ #### `rekwest.extend(options)`
185
+
186
+ The method to extend default [options](#rekwesturl-options) per instance.
187
+
188
+ ```javascript
189
+ import rekwest, { constants } from 'rekwest';
190
+
191
+ const {
192
+ HTTP_STATUS_OK,
193
+ } = constants;
194
+
195
+ const rk = rekwest.extend({
196
+ baseURL: 'https://somewhe.re',
197
+ });
198
+
199
+ const signal = AbortSignal.timeout(1e4);
200
+ const url = '/somewhat/endpoint';
201
+
202
+ const res = await rk(url, {
203
+ signal,
204
+ });
205
+
206
+ console.assert(res.statusCode === HTTP_STATUS_OK);
207
+ console.info(res.headers);
208
+ console.log(res.body);
209
+ ```
210
+
211
+ ---
212
+
213
+ #### `rekwest.stream(url[, options])`
214
+
215
+ The method with limited functionality to use with streams and/or pipes.
216
+
217
+ * No automata (redirects & retries)
218
+ * Pass `h2: true` in options to use HTTP/2 protocol
219
+ * Use `ackn({ url: URL })` method in advance to check the available protocols
220
+
221
+ ```javascript
222
+ import fs from 'node:fs';
223
+ import { pipeline } from 'node:stream/promises';
224
+ import rekwest, {
225
+ ackn,
226
+ constants,
227
+ } from 'rekwest';
228
+
229
+ const {
230
+ HTTP2_METHOD_POST,
231
+ } = constants;
232
+
233
+ const url = new URL('https://somewhe.re/somewhat/endpoint');
234
+ const options = await ackn({ url });
235
+
236
+ await pipeline(
237
+ fs.createReadStream('/path/to/read/inlet.xyz'),
238
+ rekwest.stream(url, { ...options, method: HTTP2_METHOD_POST }),
239
+ fs.createWriteStream('/path/to/write/outlet.xyz'),
240
+ );
241
+ ```
242
+
243
+ ---
244
+
245
+ For more details, please check tests (coverage: **>97%**) in the repository.
@@ -3,12 +3,16 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.default = void 0;
6
+ exports.isZstdSupported = exports.default = void 0;
7
7
  var _nodeHttp = _interopRequireDefault(require("node:http2"));
8
+ var _nodeZlib = _interopRequireDefault(require("node:zlib"));
8
9
  var _constants = require("./constants");
10
+ var _mediatypes = require("./mediatypes");
9
11
  var _utils = require("./utils");
10
12
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
11
13
  const {
14
+ HTTP2_HEADER_ACCEPT,
15
+ HTTP2_HEADER_ACCEPT_ENCODING,
12
16
  HTTP2_METHOD_GET,
13
17
  HTTP_STATUS_BAD_GATEWAY,
14
18
  HTTP_STATUS_GATEWAY_TIMEOUT,
@@ -16,12 +20,17 @@ const {
16
20
  HTTP_STATUS_SERVICE_UNAVAILABLE,
17
21
  HTTP_STATUS_TOO_MANY_REQUESTS
18
22
  } = _nodeHttp.default.constants;
19
- const stash = {
23
+ const isZstdSupported = exports.isZstdSupported = !!_nodeZlib.default.constants.ZSTD_CLEVEL_DEFAULT;
24
+ const defaults = {
20
25
  cookiesTTL: false,
21
26
  credentials: _constants.requestCredentials.sameOrigin,
22
27
  digest: true,
23
28
  follow: 20,
24
29
  h2: false,
30
+ headers: {
31
+ [HTTP2_HEADER_ACCEPT]: `${_mediatypes.APPLICATION_JSON}, ${_mediatypes.TEXT_PLAIN}, ${_mediatypes.WILDCARD}`,
32
+ [HTTP2_HEADER_ACCEPT_ENCODING]: `br,${isZstdSupported ? ' zstd, ' : ' '}gzip, deflate, deflate-raw`
33
+ },
25
34
  get maxRetryAfter() {
26
35
  return this[_utils.maxRetryAfter] ?? this.timeout;
27
36
  },
@@ -46,5 +55,5 @@ const stash = {
46
55
  trimTrailingSlashes: false
47
56
  };
48
57
  var _default = exports.default = {
49
- stash
58
+ defaults
50
59
  };
package/dist/index.js CHANGED
@@ -32,6 +32,7 @@ exports.mediatypes = void 0;
32
32
  var _nodeHttp = _interopRequireDefault(require("node:http"));
33
33
  var _nodeHttp2 = _interopRequireWildcard(require("node:http2"));
34
34
  var _nodeHttps = _interopRequireDefault(require("node:https"));
35
+ var _config = _interopRequireDefault(require("./config"));
35
36
  var _constants = require("./constants");
36
37
  Object.keys(_constants).forEach(function (key) {
37
38
  if (key === "default" || key === "__esModule") return;
@@ -44,7 +45,6 @@ Object.keys(_constants).forEach(function (key) {
44
45
  }
45
46
  });
46
47
  });
47
- var _defaults = _interopRequireDefault(require("./defaults"));
48
48
  var _mediatypes2 = _interopRequireWildcard(require("./mediatypes"));
49
49
  var _mediatypes = _mediatypes2;
50
50
  exports.mediatypes = _mediatypes2;
@@ -147,10 +147,10 @@ function rekwest(url, options) {
147
147
  Reflect.defineProperty(rekwest, 'defaults', {
148
148
  enumerable: true,
149
149
  get() {
150
- return _defaults.default.stash;
150
+ return _config.default.defaults;
151
151
  },
152
152
  set(value) {
153
- _defaults.default.stash = (0, _utils.copyWithMerge)(_defaults.default.stash, value);
153
+ _config.default.defaults = (0, _utils.copyWithMerge)(_config.default.defaults, value);
154
154
  }
155
155
  });
156
156
  Reflect.defineProperty(rekwest, 'extend', {
package/dist/preflight.js CHANGED
@@ -5,12 +5,11 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.preflight = void 0;
7
7
  var _nodeHttp = _interopRequireDefault(require("node:http2"));
8
+ var _config = require("./config");
8
9
  var _constants = require("./constants");
9
10
  var _cookies = require("./cookies");
10
- var _mediatypes = require("./mediatypes");
11
11
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
12
12
  const {
13
- HTTP2_HEADER_ACCEPT,
14
13
  HTTP2_HEADER_ACCEPT_ENCODING,
15
14
  HTTP2_HEADER_AUTHORITY,
16
15
  HTTP2_HEADER_AUTHORIZATION,
@@ -66,9 +65,16 @@ const preflight = options => {
66
65
  url.password = url.username = '';
67
66
  }
68
67
  options.headers = {
69
- [HTTP2_HEADER_ACCEPT]: `${_mediatypes.APPLICATION_JSON}, ${_mediatypes.TEXT_PLAIN}, ${_mediatypes.WILDCARD}`,
70
- [HTTP2_HEADER_ACCEPT_ENCODING]: 'br, deflate, deflate-raw, gzip, identity',
71
- ...Object.entries(options.headers ?? {}).reduce((acc, [key, val]) => (acc[key.toLowerCase()] = val, acc), {}),
68
+ ...Object.entries(options.headers ?? {}).reduce((acc, [key, val]) => {
69
+ acc[key.toLowerCase()] = val;
70
+ if (acc[HTTP2_HEADER_ACCEPT_ENCODING]?.match(/\bzstd\b/i) && !_config.isZstdSupported) {
71
+ acc[HTTP2_HEADER_ACCEPT_ENCODING] = val.replace(/\s?zstd,?/i, '').trim();
72
+ if (!acc[HTTP2_HEADER_ACCEPT_ENCODING]) {
73
+ Reflect.deleteProperty(acc, HTTP2_HEADER_ACCEPT_ENCODING);
74
+ }
75
+ }
76
+ return acc;
77
+ }, {}),
72
78
  ...(h2 && {
73
79
  [HTTP2_HEADER_AUTHORITY]: url.host,
74
80
  [HTTP2_HEADER_METHOD]: method,
package/dist/utils.js CHANGED
@@ -10,8 +10,10 @@ var _nodeBuffer = require("node:buffer");
10
10
  var _nodeHttp = _interopRequireDefault(require("node:http2"));
11
11
  var _nodeStream = require("node:stream");
12
12
  var _nodeZlib = _interopRequireDefault(require("node:zlib"));
13
- var _defaults = _interopRequireDefault(require("./defaults"));
13
+ var _config = _interopRequireWildcard(require("./config"));
14
14
  var _errors = require("./errors");
15
+ function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
16
+ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
15
17
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
16
18
  const {
17
19
  HTTP2_HEADER_RETRY_AFTER,
@@ -75,6 +77,8 @@ const compress = (readable, encodings = '') => {
75
77
  encoders.push(_nodeZlib.default.createDeflateRaw());
76
78
  } else if (/\bgzip\b/i.test(encoding)) {
77
79
  encoders.push(_nodeZlib.default.createGzip());
80
+ } else if (_config.isZstdSupported && /\bzstd\b/i.test(encoding)) {
81
+ encoders.push(_nodeZlib.default.createZstdCompress());
78
82
  } else {
79
83
  return readable;
80
84
  }
@@ -102,6 +106,8 @@ const decompress = (readable, encodings = '') => {
102
106
  decoders.push(_nodeZlib.default.createInflateRaw());
103
107
  } else if (/\bgzip\b/i.test(encoding)) {
104
108
  decoders.push(_nodeZlib.default.createGunzip());
109
+ } else if (_config.isZstdSupported && /\bzstd\b/i.test(encoding)) {
110
+ decoders.push(_nodeZlib.default.createZstdDecompress());
105
111
  } else {
106
112
  return readable;
107
113
  }
@@ -148,7 +154,7 @@ const merge = (target, ...rest) => {
148
154
  exports.merge = merge;
149
155
  const normalize = (url, options = {}) => {
150
156
  if (!options.redirected) {
151
- options = copyWithMerge(_defaults.default.stash, options);
157
+ options = copyWithMerge(_config.default.defaults, options);
152
158
  }
153
159
  if (options.trimTrailingSlashes) {
154
160
  url = `${url}`.replace(/(?<!:)\/+/g, '/');
package/package.json CHANGED
@@ -9,14 +9,13 @@
9
9
  },
10
10
  "devDependencies": {
11
11
  "@babel/cli": "^7.26.4",
12
- "@babel/core": "^7.26.0",
13
- "@babel/eslint-parser": "^7.25.9",
14
- "@babel/preset-env": "^7.26.0",
15
- "@stylistic/eslint-plugin-js": "^2.12.1",
12
+ "@babel/core": "^7.26.9",
13
+ "@babel/eslint-parser": "^7.26.8",
14
+ "@babel/preset-env": "^7.26.9",
16
15
  "c8": "^10.1.3",
17
- "eslint": "^9.17.0",
18
- "eslint-config-ultra-refined": "^3.3.1",
19
- "mocha": "^11.0.1"
16
+ "eslint": "^9.20.1",
17
+ "eslint-config-ultra-refined": "^3.4.2",
18
+ "mocha": "^11.1.0"
20
19
  },
21
20
  "description": "The robust request library that humanity deserves 🌐",
22
21
  "engines": {
@@ -37,6 +36,7 @@
37
36
  "brotli",
38
37
  "cookie",
39
38
  "deflate",
39
+ "deflate-raw",
40
40
  "fetch",
41
41
  "formdata",
42
42
  "gzip",
@@ -51,7 +51,8 @@
51
51
  "retry",
52
52
  "retry-after",
53
53
  "stream",
54
- "upload"
54
+ "upload",
55
+ "zstd"
55
56
  ],
56
57
  "license": "MIT",
57
58
  "name": "rekwest",
@@ -70,5 +71,5 @@
70
71
  "test:bail": "mocha --bail",
71
72
  "test:cover": "c8 --include=src --reporter=lcov --reporter=text npm test"
72
73
  },
73
- "version": "5.3.1"
74
+ "version": "5.4.1"
74
75
  }
@@ -1,11 +1,19 @@
1
1
  import http2 from 'node:http2';
2
+ import zlib from 'node:zlib';
2
3
  import {
3
4
  requestCredentials,
4
5
  requestRedirect,
5
6
  } from './constants.mjs';
7
+ import {
8
+ APPLICATION_JSON,
9
+ TEXT_PLAIN,
10
+ WILDCARD,
11
+ } from './mediatypes.mjs';
6
12
  import { maxRetryAfter } from './utils.mjs';
7
13
 
8
14
  const {
15
+ HTTP2_HEADER_ACCEPT,
16
+ HTTP2_HEADER_ACCEPT_ENCODING,
9
17
  HTTP2_METHOD_GET,
10
18
  HTTP_STATUS_BAD_GATEWAY,
11
19
  HTTP_STATUS_GATEWAY_TIMEOUT,
@@ -14,12 +22,18 @@ const {
14
22
  HTTP_STATUS_TOO_MANY_REQUESTS,
15
23
  } = http2.constants;
16
24
 
17
- const stash = {
25
+ export const isZstdSupported = !!zlib.constants.ZSTD_CLEVEL_DEFAULT;
26
+
27
+ const defaults = {
18
28
  cookiesTTL: false,
19
29
  credentials: requestCredentials.sameOrigin,
20
30
  digest: true,
21
31
  follow: 20,
22
32
  h2: false,
33
+ headers: {
34
+ [HTTP2_HEADER_ACCEPT]: `${ APPLICATION_JSON }, ${ TEXT_PLAIN }, ${ WILDCARD }`,
35
+ [HTTP2_HEADER_ACCEPT_ENCODING]: `br,${ isZstdSupported ? ' zstd, ' : ' ' }gzip, deflate, deflate-raw`,
36
+ },
23
37
  get maxRetryAfter() {
24
38
  return this[maxRetryAfter] ?? this.timeout;
25
39
  },
@@ -62,5 +76,5 @@ const stash = {
62
76
  };
63
77
 
64
78
  export default {
65
- stash,
79
+ defaults,
66
80
  };
package/src/index.mjs CHANGED
@@ -1,8 +1,8 @@
1
1
  import http from 'node:http';
2
2
  import http2 from 'node:http2';
3
3
  import https from 'node:https';
4
+ import config from './config.mjs';
4
5
  import { requestRedirect } from './constants.mjs';
5
- import defaults from './defaults.mjs';
6
6
  import { APPLICATION_OCTET_STREAM } from './mediatypes.mjs';
7
7
  import { preflight } from './preflight.mjs';
8
8
  import { transfer } from './transfer.mjs';
@@ -40,8 +40,8 @@ export default function rekwest(url, options) {
40
40
 
41
41
  Reflect.defineProperty(rekwest, 'defaults', {
42
42
  enumerable: true,
43
- get() { return defaults.stash; },
44
- set(value) { defaults.stash = copyWithMerge(defaults.stash, value); },
43
+ get() { return config.defaults; },
44
+ set(value) { config.defaults = copyWithMerge(config.defaults, value); },
45
45
  });
46
46
 
47
47
  Reflect.defineProperty(rekwest, 'extend', {
package/src/preflight.mjs CHANGED
@@ -1,14 +1,9 @@
1
1
  import http2 from 'node:http2';
2
+ import { isZstdSupported } from './config.mjs';
2
3
  import { requestCredentials } from './constants.mjs';
3
4
  import { Cookies } from './cookies.mjs';
4
- import {
5
- APPLICATION_JSON,
6
- TEXT_PLAIN,
7
- WILDCARD,
8
- } from './mediatypes.mjs';
9
5
 
10
6
  const {
11
- HTTP2_HEADER_ACCEPT,
12
7
  HTTP2_HEADER_ACCEPT_ENCODING,
13
8
  HTTP2_HEADER_AUTHORITY,
14
9
  HTTP2_HEADER_AUTHORIZATION,
@@ -71,10 +66,19 @@ export const preflight = (options) => {
71
66
  }
72
67
 
73
68
  options.headers = {
74
- [HTTP2_HEADER_ACCEPT]: `${ APPLICATION_JSON }, ${ TEXT_PLAIN }, ${ WILDCARD }`,
75
- [HTTP2_HEADER_ACCEPT_ENCODING]: 'br, deflate, deflate-raw, gzip, identity',
76
69
  ...Object.entries(options.headers ?? {})
77
- .reduce((acc, [key, val]) => (acc[key.toLowerCase()] = val, acc), {}),
70
+ .reduce((acc, [key, val]) => {
71
+ acc[key.toLowerCase()] = val;
72
+
73
+ if (acc[HTTP2_HEADER_ACCEPT_ENCODING]?.match(/\bzstd\b/i) && !isZstdSupported) {
74
+ acc[HTTP2_HEADER_ACCEPT_ENCODING] = val.replace(/\s?zstd,?/i, '').trim();
75
+ if (!acc[HTTP2_HEADER_ACCEPT_ENCODING]) {
76
+ Reflect.deleteProperty(acc, HTTP2_HEADER_ACCEPT_ENCODING);
77
+ }
78
+ }
79
+
80
+ return acc;
81
+ }, {}),
78
82
  ...h2 && {
79
83
  [HTTP2_HEADER_AUTHORITY]: url.host,
80
84
  [HTTP2_HEADER_METHOD]: method,
package/src/utils.mjs CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  import http2 from 'node:http2';
6
6
  import { pipeline } from 'node:stream';
7
7
  import zlib from 'node:zlib';
8
- import defaults from './defaults.mjs';
8
+ import config, { isZstdSupported } from './config.mjs';
9
9
  import {
10
10
  RequestError,
11
11
  TimeoutError,
@@ -79,6 +79,8 @@ export const compress = (readable, encodings = '') => {
79
79
  encoders.push(zlib.createDeflateRaw());
80
80
  } else if (/\bgzip\b/i.test(encoding)) {
81
81
  encoders.push(zlib.createGzip());
82
+ } else if (isZstdSupported && /\bzstd\b/i.test(encoding)) {
83
+ encoders.push(zlib.createZstdCompress());
82
84
  } else {
83
85
  return readable;
84
86
  }
@@ -110,6 +112,8 @@ export const decompress = (readable, encodings = '') => {
110
112
  decoders.push(zlib.createInflateRaw());
111
113
  } else if (/\bgzip\b/i.test(encoding)) {
112
114
  decoders.push(zlib.createGunzip());
115
+ } else if (isZstdSupported && /\bzstd\b/i.test(encoding)) {
116
+ decoders.push(zlib.createZstdDecompress());
113
117
  } else {
114
118
  return readable;
115
119
  }
@@ -165,7 +169,7 @@ export const merge = (target, ...rest) => {
165
169
 
166
170
  export const normalize = (url, options = {}) => {
167
171
  if (!options.redirected) {
168
- options = copyWithMerge(defaults.stash, options);
172
+ options = copyWithMerge(config.defaults, options);
169
173
  }
170
174
 
171
175
  if (options.trimTrailingSlashes) {