rekwest 2.4.0 → 3.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/src/helpers.mjs CHANGED
@@ -1,331 +1,377 @@
1
- import { Blob } from 'buffer';
2
- import http2 from 'http2';
3
- import {
4
- PassThrough,
5
- Readable,
6
- } from 'stream';
7
- import {
8
- promisify,
9
- types,
10
- } from 'util';
11
- import zlib from 'zlib';
12
- import { Cookies } from './cookies.mjs';
13
- import { File } from './file.mjs';
14
- import { FormData } from './formdata.mjs';
15
- import {
16
- APPLICATION_FORM_URLENCODED,
17
- APPLICATION_JSON,
18
- APPLICATION_OCTET_STREAM,
19
- TEXT_PLAIN,
20
- WILDCARD,
21
- } from './mediatypes.mjs';
22
-
23
- const {
24
- HTTP2_HEADER_ACCEPT,
25
- HTTP2_HEADER_ACCEPT_ENCODING,
26
- HTTP2_HEADER_AUTHORITY,
27
- HTTP2_HEADER_CONTENT_ENCODING,
28
- HTTP2_HEADER_CONTENT_LENGTH,
29
- HTTP2_HEADER_CONTENT_TYPE,
30
- HTTP2_HEADER_COOKIE,
31
- HTTP2_HEADER_METHOD,
32
- HTTP2_HEADER_PATH,
33
- HTTP2_HEADER_SCHEME,
34
- HTTP2_METHOD_GET,
35
- HTTP2_METHOD_HEAD,
36
- } = http2.constants;
37
-
38
- const brotliCompress = promisify(zlib.brotliCompress);
39
- const brotliDecompress = promisify(zlib.brotliDecompress);
40
- const gzip = promisify(zlib.gzip);
41
- const gunzip = promisify(zlib.gunzip);
42
- const deflate = promisify(zlib.deflate);
43
- const inflate = promisify(zlib.inflate);
44
-
45
- export const compress = (buf, encoding, { async = false } = {}) => {
46
- encoding &&= encoding.match(/(?<encoding>\bbr\b|\bdeflate\b|\bgzip\b)/i)?.groups.encoding.toLowerCase();
47
- const compressor = {
48
- br: async ? brotliCompress : zlib.brotliCompressSync,
49
- deflate: async ? deflate : zlib.deflateSync,
50
- gzip: async ? gzip : zlib.gzipSync,
51
- }[encoding];
52
-
53
- return compressor?.(buf) ?? (async ? Promise.resolve(buf) : buf);
54
- };
55
-
56
- export const decompress = (buf, encoding, { async = false } = {}) => {
57
- encoding &&= encoding.match(/(?<encoding>\bbr\b|\bdeflate\b|\bgzip\b)/i)?.groups.encoding.toLowerCase();
58
- const decompressor = {
59
- br: async ? brotliDecompress : zlib.brotliDecompressSync,
60
- deflate: async ? inflate : zlib.inflateSync,
61
- gzip: async ? gunzip : zlib.gunzipSync,
62
- }[encoding];
63
-
64
- return decompressor?.(buf) ?? (async ? Promise.resolve(buf) : buf);
65
- };
66
-
67
- export const dispatch = (req, { body, headers }) => {
68
- if (types.isUint8Array(body)) {
69
- return req.end(body);
70
- }
71
-
72
- if (body === Object(body) && !Buffer.isBuffer(body)) {
73
- if (body.pipe?.constructor !== Function
74
- && (Reflect.has(body, Symbol.asyncIterator) || Reflect.has(body, Symbol.iterator))) {
75
- body = Readable.from(body);
76
- }
77
-
78
- const compressor = {
79
- br: zlib.createBrotliCompress,
80
- deflate: zlib.createDeflate,
81
- gzip: zlib.createGzip,
82
- }[headers[HTTP2_HEADER_CONTENT_ENCODING]] ?? PassThrough;
83
-
84
- body.pipe(compressor()).pipe(req);
85
- } else {
86
- req.end(body);
87
- }
88
- };
89
-
90
- export const merge = (target = {}, ...rest) => {
91
- target = JSON.parse(JSON.stringify(target));
92
- if (!rest.length) {
93
- return target;
94
- }
95
-
96
- rest.filter((it) => it === Object(it)).forEach((it) => {
97
- Object.entries(it).reduce((acc, [key, val]) => {
98
- if ([
99
- acc[key]?.constructor,
100
- val?.constructor,
101
- ].every((it) => [
102
- Array,
103
- Object,
104
- ].includes(it))) {
105
- if (acc[key]?.constructor === val.constructor) {
106
- acc[key] = merge(acc[key], val);
107
- } else {
108
- acc[key] = val;
109
- }
110
- } else {
111
- acc[key] = val;
112
- }
113
-
114
- return acc;
115
- }, target);
116
- });
117
-
118
- return target;
119
- };
120
-
121
- export const preflight = (options) => {
122
- const url = options.url = new URL(options.url);
123
- const { cookies, h2 = false, method = HTTP2_METHOD_GET, headers, redirected } = options;
124
-
125
- if (h2) {
126
- options.endStream = [
127
- HTTP2_METHOD_GET,
128
- HTTP2_METHOD_HEAD,
129
- ].includes(method);
130
- }
131
-
132
- if (cookies !== false) {
133
- let cookie = Cookies.jar.get(url.origin);
134
-
135
- if (cookies === Object(cookies) && !redirected) {
136
- if (cookie) {
137
- new Cookies(cookies).forEach(function (val, key) {
138
- this.set(key, val);
139
- }, cookie);
140
- } else {
141
- cookie = new Cookies(cookies);
142
- Cookies.jar.set(url.origin, cookie);
143
- }
144
- }
145
-
146
- options.headers = {
147
- ...cookie && { [HTTP2_HEADER_COOKIE]: cookie },
148
- ...headers,
149
- };
150
- }
151
-
152
- options.digest ??= true;
153
- options.follow ??= 20;
154
- options.h2 ??= h2;
155
- options.headers = {
156
- [HTTP2_HEADER_ACCEPT]: `${ APPLICATION_JSON }, ${ TEXT_PLAIN }, ${ WILDCARD }`,
157
- [HTTP2_HEADER_ACCEPT_ENCODING]: 'br, deflate, gzip, identity',
158
- ...Object.entries(options.headers ?? {})
159
- .reduce((acc, [key, val]) => (acc[key.toLowerCase()] = val, acc), {}),
160
- ...h2 && {
161
- [HTTP2_HEADER_AUTHORITY]: url.host,
162
- [HTTP2_HEADER_METHOD]: method,
163
- [HTTP2_HEADER_PATH]: `${ url.pathname }${ url.search }`,
164
- [HTTP2_HEADER_SCHEME]: url.protocol.replace(/\p{Punctuation}/gu, ''),
165
- },
166
- };
167
-
168
- options.method ??= method;
169
- options.parse ??= true;
170
- options.redirect ??= redirects.follow;
171
-
172
- if (!Object.values(redirects).includes(options.redirect)) {
173
- options.createConnection?.().destroy();
174
- throw new TypeError(`Failed to read the 'redirect' property from 'options': The provided value '${
175
- options.redirect
176
- }' is not a valid enum value.`);
177
- }
178
-
179
- options.redirected ??= false;
180
- options.thenable ??= false;
181
-
182
- return options;
183
- };
184
-
185
- export const premix = (res, { digest = false, parse = false } = {}) => {
186
- if (!digest) {
187
- Object.defineProperties(res, {
188
- arrayBuffer: {
189
- enumerable: true,
190
- value: function () {
191
- parse &&= false;
192
-
193
- return this.body().then(({ buffer, byteLength, byteOffset }) => buffer.slice(
194
- byteOffset,
195
- byteOffset + byteLength,
196
- ));
197
- },
198
- },
199
- blob: {
200
- enumerable: true,
201
- value: function () {
202
- return this.arrayBuffer().then((res) => new Blob([res]));
203
- },
204
- },
205
- json: {
206
- enumerable: true,
207
- value: function () {
208
- return this.text().then((res) => JSON.parse(res));
209
- },
210
- },
211
- text: {
212
- enumerable: true,
213
- value: function () {
214
- return this.blob().then((blob) => blob.text());
215
- },
216
- },
217
- });
218
- }
219
-
220
- return Object.defineProperties(res, {
221
- body: {
222
- enumerable: true,
223
- value: async function () {
224
- if (this.bodyUsed) {
225
- throw new TypeError('Response stream already read.');
226
- }
227
-
228
- let spool = [];
229
-
230
- for await (const chunk of this) {
231
- spool.push(chunk);
232
- }
233
-
234
- spool = Buffer.concat(spool);
235
-
236
- if (spool.length) {
237
- spool = await decompress(spool, this.headers[HTTP2_HEADER_CONTENT_ENCODING], { async: true });
238
- }
239
-
240
- if (spool.length && parse) {
241
- const contentType = this.headers[HTTP2_HEADER_CONTENT_TYPE] ?? '';
242
- const charset = contentType.split(';')
243
- .find((it) => /charset=/i.test(it))
244
- ?.toLowerCase()
245
- .replace('charset=', '')
246
- .replace('iso-8859-1', 'latin1')
247
- .trim() || 'utf-8';
248
-
249
- if (/\bjson\b/i.test(contentType)) {
250
- spool = JSON.parse(spool.toString(charset));
251
- } else if (/\b(text|xml)\b/i.test(contentType)) {
252
- if (/\b(latin1|ucs-2|utf-(8|16le))\b/.test(charset)) {
253
- spool = spool.toString(charset);
254
- } else {
255
- spool = new TextDecoder(charset).decode(spool);
256
- }
257
- }
258
- }
259
-
260
- return spool;
261
- },
262
- writable: true,
263
- },
264
- bodyUsed: {
265
- enumerable: true,
266
- get: function () {
267
- return this.readableEnded;
268
- },
269
- },
270
- });
271
- };
272
-
273
- export const redirects = {
274
- error: 'error',
275
- follow: 'follow',
276
- manual: 'manual',
277
- };
278
-
279
- export async function* tap(value) {
280
- if (Reflect.has(value, Symbol.asyncIterator)) {
281
- yield* value;
282
- } else if (value.stream) {
283
- yield* value.stream();
284
- } else {
285
- yield await value.arrayBuffer();
286
- }
287
- }
288
-
289
- export const transform = (body, options) => {
290
- let headers = {};
291
-
292
- if (File.alike(body)) {
293
- headers = {
294
- [HTTP2_HEADER_CONTENT_LENGTH]: body.size,
295
- [HTTP2_HEADER_CONTENT_TYPE]: body.type || APPLICATION_OCTET_STREAM,
296
- };
297
- body = body.stream?.() ?? Readable.from(tap(body));
298
- } else if (FormData.alike(body)) {
299
- body = FormData.actuate(body);
300
- headers = { [HTTP2_HEADER_CONTENT_TYPE]: body.contentType };
301
- } else if (body === Object(body) && !Reflect.has(body, Symbol.asyncIterator)) {
302
- if (body.constructor === URLSearchParams) {
303
- headers = { [HTTP2_HEADER_CONTENT_TYPE]: APPLICATION_FORM_URLENCODED };
304
- body = body.toString();
305
- } else if (!Buffer.isBuffer(body)
306
- && !(!Array.isArray(body) && Reflect.has(body, Symbol.iterator))) {
307
- headers = { [HTTP2_HEADER_CONTENT_TYPE]: APPLICATION_JSON };
308
- body = JSON.stringify(body);
309
- }
310
-
311
- if (types.isUint8Array(body) || Buffer.isBuffer(body) || body !== Object(body)) {
312
- if (options.headers[HTTP2_HEADER_CONTENT_ENCODING]) {
313
- body = compress(body, options.headers[HTTP2_HEADER_CONTENT_ENCODING]);
314
- }
315
-
316
- headers = {
317
- ...headers,
318
- [HTTP2_HEADER_CONTENT_LENGTH]: Buffer.byteLength(body),
319
- };
320
- }
321
- }
322
-
323
- Object.assign(options.headers, {
324
- ...headers,
325
- ...options.headers[HTTP2_HEADER_CONTENT_TYPE] && {
326
- [HTTP2_HEADER_CONTENT_TYPE]: options.headers[HTTP2_HEADER_CONTENT_TYPE],
327
- },
328
- });
329
-
330
- return body;
331
- };
1
+ import { Blob } from 'buffer';
2
+ import http2 from 'http2';
3
+ import {
4
+ PassThrough,
5
+ Readable,
6
+ } from 'stream';
7
+ import {
8
+ promisify,
9
+ types,
10
+ } from 'util';
11
+ import zlib from 'zlib';
12
+ import { Cookies } from './cookies.mjs';
13
+ import { TimeoutError } from './errors.mjs';
14
+ import { File } from './file.mjs';
15
+ import { FormData } from './formdata.mjs';
16
+ import {
17
+ APPLICATION_FORM_URLENCODED,
18
+ APPLICATION_JSON,
19
+ APPLICATION_OCTET_STREAM,
20
+ TEXT_PLAIN,
21
+ WILDCARD,
22
+ } from './mediatypes.mjs';
23
+
24
+ const {
25
+ HTTP2_HEADER_ACCEPT,
26
+ HTTP2_HEADER_ACCEPT_ENCODING,
27
+ HTTP2_HEADER_AUTHORITY,
28
+ HTTP2_HEADER_CONTENT_ENCODING,
29
+ HTTP2_HEADER_CONTENT_LENGTH,
30
+ HTTP2_HEADER_CONTENT_TYPE,
31
+ HTTP2_HEADER_COOKIE,
32
+ HTTP2_HEADER_METHOD,
33
+ HTTP2_HEADER_PATH,
34
+ HTTP2_HEADER_SCHEME,
35
+ HTTP2_HEADER_STATUS,
36
+ HTTP2_METHOD_GET,
37
+ HTTP2_METHOD_HEAD,
38
+ } = http2.constants;
39
+
40
+ const brotliCompress = promisify(zlib.brotliCompress);
41
+ const brotliDecompress = promisify(zlib.brotliDecompress);
42
+ const gzip = promisify(zlib.gzip);
43
+ const gunzip = promisify(zlib.gunzip);
44
+ const deflate = promisify(zlib.deflate);
45
+ const inflate = promisify(zlib.inflate);
46
+
47
+ export const admix = (res, headers, options) => {
48
+ const { h2 } = options;
49
+
50
+ if (h2) {
51
+ Reflect.defineProperty(res, 'headers', {
52
+ enumerable: true,
53
+ value: headers,
54
+ });
55
+
56
+ Reflect.defineProperty(res, 'httpVersion', {
57
+ enumerable: true,
58
+ value: `${ h2 + 1 }.0`,
59
+ });
60
+
61
+ Reflect.defineProperty(res, 'statusCode', {
62
+ enumerable: true,
63
+ value: headers[HTTP2_HEADER_STATUS],
64
+ });
65
+ }
66
+
67
+ Reflect.defineProperty(res, 'ok', {
68
+ enumerable: true,
69
+ value: /^2\d{2}$/.test(res.statusCode),
70
+ });
71
+
72
+ Reflect.defineProperty(res, 'redirected', {
73
+ enumerable: true,
74
+ value: !!options.redirected,
75
+ });
76
+ };
77
+
78
+ export const affix = (client, req, options) => {
79
+ req.once('end', () => client?.close());
80
+ req.once('timeout', () => req.destroy(new TimeoutError(`Timed out after ${ options.timeout } ms.`)));
81
+ req.once('trailers', (trailers) => {
82
+ Reflect.defineProperty(req, 'trailers', {
83
+ enumerable: true,
84
+ value: trailers,
85
+ });
86
+ });
87
+ };
88
+
89
+ export const compress = (buf, encoding, { async = false } = {}) => {
90
+ encoding &&= encoding.match(/(?<encoding>\bbr\b|\bdeflate\b|\bgzip\b)/i)?.groups.encoding.toLowerCase();
91
+ const compressor = {
92
+ br: async ? brotliCompress : zlib.brotliCompressSync,
93
+ deflate: async ? deflate : zlib.deflateSync,
94
+ gzip: async ? gzip : zlib.gzipSync,
95
+ }[encoding];
96
+
97
+ return compressor?.(buf) ?? (async ? Promise.resolve(buf) : buf);
98
+ };
99
+
100
+ export const decompress = (buf, encoding, { async = false } = {}) => {
101
+ encoding &&= encoding.match(/(?<encoding>\bbr\b|\bdeflate\b|\bgzip\b)/i)?.groups.encoding.toLowerCase();
102
+ const decompressor = {
103
+ br: async ? brotliDecompress : zlib.brotliDecompressSync,
104
+ deflate: async ? inflate : zlib.inflateSync,
105
+ gzip: async ? gunzip : zlib.gunzipSync,
106
+ }[encoding];
107
+
108
+ return decompressor?.(buf) ?? (async ? Promise.resolve(buf) : buf);
109
+ };
110
+
111
+ export const dispatch = (req, { body, headers }) => {
112
+ if (body === Object(body) && !Buffer.isBuffer(body)) {
113
+ if (body.pipe?.constructor !== Function
114
+ && (Reflect.has(body, Symbol.asyncIterator) || Reflect.has(body, Symbol.iterator))) {
115
+ body = Readable.from(body);
116
+ }
117
+
118
+ const compressor = {
119
+ br: zlib.createBrotliCompress,
120
+ deflate: zlib.createDeflate,
121
+ gzip: zlib.createGzip,
122
+ }[headers[HTTP2_HEADER_CONTENT_ENCODING]] ?? PassThrough;
123
+
124
+ body.pipe(compressor()).pipe(req);
125
+ } else {
126
+ req.end(body);
127
+ }
128
+ };
129
+
130
+ export const merge = (target = {}, ...rest) => {
131
+ target = JSON.parse(JSON.stringify(target));
132
+ if (!rest.length) {
133
+ return target;
134
+ }
135
+
136
+ rest.filter((it) => it === Object(it)).forEach((it) => {
137
+ Object.entries(it).reduce((acc, [key, val]) => {
138
+ if ([
139
+ acc[key]?.constructor,
140
+ val?.constructor,
141
+ ].every((it) => [
142
+ Array,
143
+ Object,
144
+ ].includes(it))) {
145
+ if (acc[key]?.constructor === val.constructor) {
146
+ acc[key] = merge(acc[key], val);
147
+ } else {
148
+ acc[key] = val;
149
+ }
150
+ } else {
151
+ acc[key] = val;
152
+ }
153
+
154
+ return acc;
155
+ }, target);
156
+ });
157
+
158
+ return target;
159
+ };
160
+
161
+ export const mixin = (res, { digest = false, parse = false } = {}) => {
162
+ if (!digest) {
163
+ Object.defineProperties(res, {
164
+ arrayBuffer: {
165
+ enumerable: true,
166
+ value: function () {
167
+ parse &&= false;
168
+
169
+ return this.body().then(({ buffer, byteLength, byteOffset }) => buffer.slice(
170
+ byteOffset,
171
+ byteOffset + byteLength,
172
+ ));
173
+ },
174
+ },
175
+ blob: {
176
+ enumerable: true,
177
+ value: function () {
178
+ return this.arrayBuffer().then((res) => new Blob([res]));
179
+ },
180
+ },
181
+ json: {
182
+ enumerable: true,
183
+ value: function () {
184
+ return this.text().then((res) => JSON.parse(res));
185
+ },
186
+ },
187
+ text: {
188
+ enumerable: true,
189
+ value: function () {
190
+ return this.blob().then((blob) => blob.text());
191
+ },
192
+ },
193
+ });
194
+ }
195
+
196
+ return Object.defineProperties(res, {
197
+ body: {
198
+ enumerable: true,
199
+ value: async function () {
200
+ if (this.bodyUsed) {
201
+ throw new TypeError('Response stream already read.');
202
+ }
203
+
204
+ let spool = [];
205
+
206
+ for await (const chunk of this) {
207
+ spool.push(chunk);
208
+ }
209
+
210
+ spool = Buffer.concat(spool);
211
+
212
+ if (spool.length) {
213
+ spool = await decompress(spool, this.headers[HTTP2_HEADER_CONTENT_ENCODING], { async: true });
214
+ }
215
+
216
+ if (spool.length && parse) {
217
+ const contentType = this.headers[HTTP2_HEADER_CONTENT_TYPE] ?? '';
218
+ const charset = contentType.split(';')
219
+ .find((it) => /charset=/i.test(it))
220
+ ?.toLowerCase()
221
+ .replace('charset=', '')
222
+ .replace('iso-8859-1', 'latin1')
223
+ .trim() || 'utf-8';
224
+
225
+ if (/\bjson\b/i.test(contentType)) {
226
+ spool = JSON.parse(spool.toString(charset));
227
+ } else if (/\b(text|xml)\b/i.test(contentType)) {
228
+ if (/\b(latin1|ucs-2|utf-(8|16le))\b/.test(charset)) {
229
+ spool = spool.toString(charset);
230
+ } else {
231
+ spool = new TextDecoder(charset).decode(spool);
232
+ }
233
+ }
234
+ }
235
+
236
+ return spool;
237
+ },
238
+ writable: true,
239
+ },
240
+ bodyUsed: {
241
+ enumerable: true,
242
+ get: function () {
243
+ return this.readableEnded;
244
+ },
245
+ },
246
+ });
247
+ };
248
+
249
+ export const preflight = (options) => {
250
+ const url = options.url = new URL(options.url);
251
+ const { cookies, h2 = false, method = HTTP2_METHOD_GET, headers, redirected } = options;
252
+
253
+ if (h2) {
254
+ options.endStream = [
255
+ HTTP2_METHOD_GET,
256
+ HTTP2_METHOD_HEAD,
257
+ ].includes(method);
258
+ }
259
+
260
+ if (cookies !== false) {
261
+ let cookie = Cookies.jar.get(url.origin);
262
+
263
+ if (cookies === Object(cookies) && !redirected) {
264
+ if (cookie) {
265
+ new Cookies(cookies).forEach(function (val, key) {
266
+ this.set(key, val);
267
+ }, cookie);
268
+ } else {
269
+ cookie = new Cookies(cookies);
270
+ Cookies.jar.set(url.origin, cookie);
271
+ }
272
+ }
273
+
274
+ options.headers = {
275
+ ...cookie && { [HTTP2_HEADER_COOKIE]: cookie },
276
+ ...headers,
277
+ };
278
+ }
279
+
280
+ options.digest ??= true;
281
+ options.follow ??= 20;
282
+ options.h2 ??= h2;
283
+ options.headers = {
284
+ [HTTP2_HEADER_ACCEPT]: `${ APPLICATION_JSON }, ${ TEXT_PLAIN }, ${ WILDCARD }`,
285
+ [HTTP2_HEADER_ACCEPT_ENCODING]: 'br, deflate, gzip, identity',
286
+ ...Object.entries(options.headers ?? {})
287
+ .reduce((acc, [key, val]) => (acc[key.toLowerCase()] = val, acc), {}),
288
+ ...h2 && {
289
+ [HTTP2_HEADER_AUTHORITY]: url.host,
290
+ [HTTP2_HEADER_METHOD]: method,
291
+ [HTTP2_HEADER_PATH]: `${ url.pathname }${ url.search }`,
292
+ [HTTP2_HEADER_SCHEME]: url.protocol.replace(/\p{Punctuation}/gu, ''),
293
+ },
294
+ };
295
+
296
+ options.method ??= method;
297
+ options.parse ??= true;
298
+ options.redirect ??= redirects.follow;
299
+
300
+ if (!Object.values(redirects).includes(options.redirect)) {
301
+ options.createConnection?.().destroy();
302
+ throw new TypeError(`Failed to read the 'redirect' property from 'options': The provided value '${
303
+ options.redirect
304
+ }' is not a valid enum value.`);
305
+ }
306
+
307
+ options.redirected ??= false;
308
+ options.thenable ??= false;
309
+
310
+ return options;
311
+ };
312
+
313
+ export const redirects = {
314
+ error: 'error',
315
+ follow: 'follow',
316
+ manual: 'manual',
317
+ };
318
+
319
+ export async function* tap(value) {
320
+ if (Reflect.has(value, Symbol.asyncIterator)) {
321
+ yield* value;
322
+ } else if (value.stream) {
323
+ yield* value.stream();
324
+ } else {
325
+ yield await value.arrayBuffer();
326
+ }
327
+ }
328
+
329
+ export const transform = (body, options) => {
330
+ let headers = {};
331
+
332
+ if (types.isAnyArrayBuffer(body) && !Buffer.isBuffer(body)) {
333
+ body = Buffer.from(body);
334
+ } else if (types.isArrayBufferView(body) && !Buffer.isBuffer(body)) {
335
+ body = Buffer.from(body.buffer, body.byteOffset, body.byteLength);
336
+ }
337
+
338
+ if (File.alike(body)) {
339
+ headers = {
340
+ [HTTP2_HEADER_CONTENT_LENGTH]: body.size,
341
+ [HTTP2_HEADER_CONTENT_TYPE]: body.type || APPLICATION_OCTET_STREAM,
342
+ };
343
+ body = body.stream?.() ?? Readable.from(tap(body));
344
+ } else if (FormData.alike(body)) {
345
+ body = FormData.actuate(body);
346
+ headers = { [HTTP2_HEADER_CONTENT_TYPE]: body.contentType };
347
+ } else if (body === Object(body) && !Reflect.has(body, Symbol.asyncIterator)) {
348
+ if (body.constructor === URLSearchParams) {
349
+ headers = { [HTTP2_HEADER_CONTENT_TYPE]: APPLICATION_FORM_URLENCODED };
350
+ body = body.toString();
351
+ } else if (!Buffer.isBuffer(body)
352
+ && !(!Array.isArray(body) && Reflect.has(body, Symbol.iterator))) {
353
+ headers = { [HTTP2_HEADER_CONTENT_TYPE]: APPLICATION_JSON };
354
+ body = JSON.stringify(body);
355
+ }
356
+
357
+ if (Buffer.isBuffer(body) || body !== Object(body)) {
358
+ if (options.headers[HTTP2_HEADER_CONTENT_ENCODING]) {
359
+ body = compress(body, options.headers[HTTP2_HEADER_CONTENT_ENCODING]);
360
+ }
361
+
362
+ headers = {
363
+ ...headers,
364
+ [HTTP2_HEADER_CONTENT_LENGTH]: Buffer.byteLength(body),
365
+ };
366
+ }
367
+ }
368
+
369
+ Object.assign(options.headers, {
370
+ ...headers,
371
+ ...options.headers[HTTP2_HEADER_CONTENT_TYPE] && {
372
+ [HTTP2_HEADER_CONTENT_TYPE]: options.headers[HTTP2_HEADER_CONTENT_TYPE],
373
+ },
374
+ });
375
+
376
+ return body;
377
+ };