rekwest 3.3.1 → 3.3.3

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.
Files changed (4) hide show
  1. package/README.md +186 -186
  2. package/dist/utils.js +13 -17
  3. package/package.json +10 -9
  4. package/src/utils.mjs +12 -11
package/README.md CHANGED
@@ -1,186 +1,186 @@
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#https_https_request_url_options_callback)
5
- and [http2.request](https://nodejs.org/api/http2.html#http2_clienthttp2session_request_headers_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)
14
- * Automatic decompression (with opt-in body compression)
15
- * Built-in streamable `File` & `FormData` interfaces
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 `>= 16.x`
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 rekwest, {
69
- constants,
70
- Blob,
71
- File,
72
- FormData,
73
- } from 'rekwest';
74
- import { Readable } from 'node:stream';
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 [https.RequestOptions](https://nodejs.org/api/https.html#https_https_request_url_options_callback)
119
- along with
120
- extra [http2.ClientSessionOptions](https://nodejs.org/api/http2.html#http2_http2_connect_authority_options_listener)
121
- & [http2.ClientSessionRequestOptions](https://nodejs.org/api/http2.html#http2_clienthttp2session_request_headers_options)
122
- and [tls.ConnectionOptions](https://nodejs.org/api/tls.html#tls_tls_connect_options_callback)
123
- for HTTP/2 attunes
124
- * `body` **{string | Array | ArrayBuffer | ArrayBufferView | AsyncIterator | Blob | Buffer | DataView | File |
125
- FormData | Iterator | Object | Readable | SharedArrayBuffer | URLSearchParams}** The body to send with the request
126
- * `cookies` **{boolean | Array<[k, v]> | Cookies | Object | URLSearchParams}** `Default: true` The cookies to add to
127
- the request
128
- * `digest` **{boolean}** `Default: true` Controls whether to read the response stream or simply add a mixin
129
- * `follow` **{number}** `Default: 20` The number of redirects to follow
130
- * `h2` **{boolean}** `Default: false` Forces the use of HTTP/2 protocol
131
- * `headers` **{Object}** The headers to add to the request
132
- * `maxRetryAfter` **{number}** The upper limit of `retry-after` header. If unset, it will use `timeout` value
133
- * `parse` **{boolean}** `Default: true` Controls whether to parse response body or simply return a buffer
134
- * `redirect` **{error | follow | manual}** `Default: follow` Controls the redirect flows
135
- * `retry` **{Object}** Represents the retry options
136
- * `attempts` **{number}** `Default: 0` The number of retry attempts
137
- * `backoffStrategy` **{string}** `Default: interval * Math.log(Math.random() * (Math.E * Math.E - Math.E) + Math.E)`
138
- The backoff strategy algorithm that increases logarithmically. To fixate set value to `interval * 1`
139
- * `interval` **{number}** `Default: 1e3` The initial retry interval
140
- * `retryAfter` **{boolean}** `Default: true` Controls `retry-after` header receptiveness
141
- * `statusCodes` **{number[]}** `Default: [429, 503]` The list of status codes to retry on
142
- * `thenable` **{boolean}** `Default: false` Controls the promise resolutions
143
- * `timeout` **{number}** `Default: 3e5` The number of milliseconds a request can take before termination
144
- * `trimTrailingSlashes` **{boolean}** `Default: false` Controls whether to trim trailing slashes in the URL before
145
- proceed with the request
146
- * **Returns:** Promise that resolves to
147
- extended [http.IncomingMessage](https://nodejs.org/api/http.html#http_class_http_incomingmessage)
148
- or [http2.ClientHttp2Stream](https://nodejs.org/api/http2.html#http2_class_clienthttp2stream) which is respectively
149
- readable and duplex streams
150
- * if `degist: true` & `parse: true`
151
- * `body` **{string | Array | Buffer | Object}** The body based on its content type
152
- * if `degist: false`
153
- * `arrayBuffer` **{AsyncFunction}** Reads the response and returns **ArrayBuffer**
154
- * `blob` **{AsyncFunction}** Reads the response and returns **Blob**
155
- * `body` **{AsyncFunction}** Reads the response and returns **Buffer** if `parse: false`
156
- * `json` **{AsyncFunction}** Reads the response and returns **Object**
157
- * `text` **{AsyncFunction}** Reads the response and returns **String**
158
- * `bodyUsed` **{boolean}** Indicates whether the response were read or not
159
- * `cookies` **{undefined | Cookies}** The cookies sent and received with the response
160
- * `headers` **{Object}** The headers received with the response
161
- * `httpVersion` **{string}** Indicates protocol version negotiated with the server
162
- * `ok` **{boolean}** Indicates if the response was successful (statusCode: **200-299**)
163
- * `redirected` **{boolean}** Indicates if the response is the result of a redirect
164
- * `statusCode` **{number}** Indicates the status code of the response
165
- * `trailers` **{undefined | Object}** The trailer headers received with the response
166
-
167
- ---
168
-
169
- #### `rekwest.defaults`
170
-
171
- The object to fulfill with default [options](#rekwesturl-options)
172
-
173
- ---
174
-
175
- #### `rekwest.stream(url[, options])`
176
-
177
- The method with limited functionality to use with streams and/or pipes
178
-
179
- * No automata
180
- * No redirects
181
- * Pass `h2: true` in options to use HTTP/2 protocol
182
- * Or use `ackn({ url: URL })` method in advance to probe the available protocols
183
-
184
- ---
185
-
186
- 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#https_https_request_url_options_callback)
5
+ and [http2.request](https://nodejs.org/api/http2.html#http2_clienthttp2session_request_headers_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)
14
+ * Automatic decompression (with opt-in body compression)
15
+ * Built-in streamable `File` & `FormData` interfaces
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 `>= 16.5.x`
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 rekwest, {
69
+ constants,
70
+ Blob,
71
+ File,
72
+ FormData,
73
+ } from 'rekwest';
74
+ import { Readable } from 'node:stream';
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 [https.RequestOptions](https://nodejs.org/api/https.html#https_https_request_url_options_callback)
119
+ along with
120
+ extra [http2.ClientSessionOptions](https://nodejs.org/api/http2.html#http2_http2_connect_authority_options_listener)
121
+ & [http2.ClientSessionRequestOptions](https://nodejs.org/api/http2.html#http2_clienthttp2session_request_headers_options)
122
+ and [tls.ConnectionOptions](https://nodejs.org/api/tls.html#tls_tls_connect_options_callback)
123
+ for HTTP/2 attunes
124
+ * `body` **{string | Array | ArrayBuffer | ArrayBufferView | AsyncIterator | Blob | Buffer | DataView | File |
125
+ FormData | Iterator | Object | Readable | SharedArrayBuffer | URLSearchParams}** The body to send with the request
126
+ * `cookies` **{boolean | Array<[k, v]> | Cookies | Object | URLSearchParams}** `Default: true` The cookies to add to
127
+ the request
128
+ * `digest` **{boolean}** `Default: true` Controls whether to read the response stream or simply add a mixin
129
+ * `follow` **{number}** `Default: 20` The number of redirects to follow
130
+ * `h2` **{boolean}** `Default: false` Forces the use of HTTP/2 protocol
131
+ * `headers` **{Object}** The headers to add to the request
132
+ * `maxRetryAfter` **{number}** The upper limit of `retry-after` header. If unset, it will use `timeout` value
133
+ * `parse` **{boolean}** `Default: true` Controls whether to parse response body or simply return a buffer
134
+ * `redirect` **{error | follow | manual}** `Default: follow` Controls the redirect flows
135
+ * `retry` **{Object}** Represents the retry options
136
+ * `attempts` **{number}** `Default: 0` The number of retry attempts
137
+ * `backoffStrategy` **{string}** `Default: interval * Math.log(Math.random() * (Math.E * Math.E - Math.E) + Math.E)`
138
+ The backoff strategy algorithm that increases logarithmically. To fixate set value to `interval * 1`
139
+ * `interval` **{number}** `Default: 1e3` The initial retry interval
140
+ * `retryAfter` **{boolean}** `Default: true` Controls `retry-after` header receptiveness
141
+ * `statusCodes` **{number[]}** `Default: [429, 503]` The list of status codes to retry on
142
+ * `thenable` **{boolean}** `Default: false` Controls the promise resolutions
143
+ * `timeout` **{number}** `Default: 3e5` The number of milliseconds a request can take before termination
144
+ * `trimTrailingSlashes` **{boolean}** `Default: false` Controls whether to trim trailing slashes in the URL before
145
+ proceed with the request
146
+ * **Returns:** Promise that resolves to
147
+ extended [http.IncomingMessage](https://nodejs.org/api/http.html#http_class_http_incomingmessage)
148
+ or [http2.ClientHttp2Stream](https://nodejs.org/api/http2.html#http2_class_clienthttp2stream) which is respectively
149
+ readable and duplex streams
150
+ * if `degist: true` & `parse: true`
151
+ * `body` **{string | Array | Buffer | Object}** The body based on its content type
152
+ * if `degist: false`
153
+ * `arrayBuffer` **{AsyncFunction}** Reads the response and returns **ArrayBuffer**
154
+ * `blob` **{AsyncFunction}** Reads the response and returns **Blob**
155
+ * `body` **{AsyncFunction}** Reads the response and returns **Buffer** if `parse: false`
156
+ * `json` **{AsyncFunction}** Reads the response and returns **Object**
157
+ * `text` **{AsyncFunction}** Reads the response and returns **String**
158
+ * `bodyUsed` **{boolean}** Indicates whether the response were read or not
159
+ * `cookies` **{undefined | Cookies}** The cookies sent and received with the response
160
+ * `headers` **{Object}** The headers received with the response
161
+ * `httpVersion` **{string}** Indicates protocol version negotiated with the server
162
+ * `ok` **{boolean}** Indicates if the response was successful (statusCode: **200-299**)
163
+ * `redirected` **{boolean}** Indicates if the response is the result of a redirect
164
+ * `statusCode` **{number}** Indicates the status code of the response
165
+ * `trailers` **{undefined | Object}** The trailer headers received with the response
166
+
167
+ ---
168
+
169
+ #### `rekwest.defaults`
170
+
171
+ The object to fulfill with default [options](#rekwesturl-options)
172
+
173
+ ---
174
+
175
+ #### `rekwest.stream(url[, options])`
176
+
177
+ The method with limited functionality to use with streams and/or pipes
178
+
179
+ * No automata
180
+ * No redirects
181
+ * Pass `h2: true` in options to use HTTP/2 protocol
182
+ * Or use `ackn({ url: URL })` method in advance to probe the available protocols
183
+
184
+ ---
185
+
186
+ For more details, please check tests (coverage: **>97%**) in the repository
package/dist/utils.js CHANGED
@@ -187,44 +187,40 @@ const mixin = (res, {
187
187
  Object.defineProperties(res, {
188
188
  arrayBuffer: {
189
189
  enumerable: true,
190
-
191
- value() {
190
+ value: async function () {
192
191
  collate(this, res?.constructor);
193
192
  parse &&= false;
194
- return this.body().then(({
193
+ const {
195
194
  buffer,
196
195
  byteLength,
197
196
  byteOffset
198
- }) => buffer.slice(byteOffset, byteOffset + byteLength));
197
+ } = await this.body();
198
+ return buffer.slice(byteOffset, byteOffset + byteLength);
199
199
  }
200
-
201
200
  },
202
201
  blob: {
203
202
  enumerable: true,
204
-
205
- value() {
203
+ value: async function () {
206
204
  collate(this, res?.constructor);
207
- return this.arrayBuffer().then(res => new _nodeBuffer.Blob([res]));
205
+ const val = await this.arrayBuffer();
206
+ return new _nodeBuffer.Blob([val]);
208
207
  }
209
-
210
208
  },
211
209
  json: {
212
210
  enumerable: true,
213
-
214
- value() {
211
+ value: async function () {
215
212
  collate(this, res?.constructor);
216
- return this.text().then(res => JSON.parse(res));
213
+ const val = await this.text();
214
+ return JSON.parse(val);
217
215
  }
218
-
219
216
  },
220
217
  text: {
221
218
  enumerable: true,
222
-
223
- value() {
219
+ value: async function () {
224
220
  collate(this, res?.constructor);
225
- return this.blob().then(blob => blob.text());
221
+ const blob = await this.blob();
222
+ return blob.text();
226
223
  }
227
-
228
224
  }
229
225
  });
230
226
  }
package/package.json CHANGED
@@ -8,18 +8,18 @@
8
8
  "url": "https://github.com/bricss/rekwest/issues"
9
9
  },
10
10
  "devDependencies": {
11
- "@babel/cli": "^7.17.10",
12
- "@babel/core": "^7.17.10",
13
- "@babel/eslint-parser": "^7.17.0",
14
- "@babel/preset-env": "^7.17.10",
15
- "c8": "^7.11.2",
16
- "eslint": "^8.15.0",
11
+ "@babel/cli": "^7.18.10",
12
+ "@babel/core": "^7.19.1",
13
+ "@babel/eslint-parser": "^7.19.1",
14
+ "@babel/preset-env": "^7.19.1",
15
+ "c8": "^7.12.0",
16
+ "eslint": "^8.23.1",
17
17
  "eslint-config-ultra-refined": "^2.5.0",
18
18
  "mocha": "^10.0.0"
19
19
  },
20
20
  "description": "The robust request library that humanity deserves 🌐",
21
21
  "engines": {
22
- "node": ">=16.x"
22
+ "node": ">=16.5.x"
23
23
  },
24
24
  "exports": {
25
25
  "import": "./src/index.mjs",
@@ -45,7 +45,8 @@
45
45
  "multipart",
46
46
  "request",
47
47
  "redirect",
48
- "retry"
48
+ "retry",
49
+ "retry-after"
49
50
  ],
50
51
  "license": "MIT",
51
52
  "main": "./dist/index.js",
@@ -65,5 +66,5 @@
65
66
  "test:bail": "mocha --bail",
66
67
  "test:cover": "c8 --include=src --reporter=lcov --reporter=text npm test"
67
68
  },
68
- "version": "3.3.1"
69
+ "version": "3.3.3"
69
70
  }
package/src/utils.mjs CHANGED
@@ -169,38 +169,39 @@ export const mixin = (res, { digest = false, parse = false } = {}) => {
169
169
  Object.defineProperties(res, {
170
170
  arrayBuffer: {
171
171
  enumerable: true,
172
- value() {
172
+ value: async function () {
173
173
  collate(this, res?.constructor);
174
174
  parse &&= false;
175
+ const { buffer, byteLength, byteOffset } = await this.body();
175
176
 
176
- return this.body().then(({ buffer, byteLength, byteOffset }) => buffer.slice(
177
- byteOffset,
178
- byteOffset + byteLength,
179
- ));
177
+ return buffer.slice(byteOffset, byteOffset + byteLength);
180
178
  },
181
179
  },
182
180
  blob: {
183
181
  enumerable: true,
184
- value() {
182
+ value: async function () {
185
183
  collate(this, res?.constructor);
184
+ const val = await this.arrayBuffer();
186
185
 
187
- return this.arrayBuffer().then((res) => new Blob([res]));
186
+ return new Blob([val]);
188
187
  },
189
188
  },
190
189
  json: {
191
190
  enumerable: true,
192
- value() {
191
+ value: async function () {
193
192
  collate(this, res?.constructor);
193
+ const val = await this.text();
194
194
 
195
- return this.text().then((res) => JSON.parse(res));
195
+ return JSON.parse(val);
196
196
  },
197
197
  },
198
198
  text: {
199
199
  enumerable: true,
200
- value() {
200
+ value: async function () {
201
201
  collate(this, res?.constructor);
202
+ const blob = await this.blob();
202
203
 
203
- return this.blob().then((blob) => blob.text());
204
+ return blob.text();
204
205
  },
205
206
  },
206
207
  });