rekwest 7.1.1 → 7.2.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 CHANGED
@@ -49,8 +49,7 @@ const res = await rekwest(url, {
49
49
  headers: {
50
50
  [HTTP2_HEADER_AUTHORIZATION]: 'Bearer [token]',
51
51
  [HTTP2_HEADER_CONTENT_ENCODING]: 'br', // enables: body encoding
52
- /** [HTTP2_HEADER_CONTENT_TYPE]
53
- * is undue for
52
+ /** [HTTP2_HEADER_CONTENT_TYPE] is undue for
54
53
  * Array/Blob/File/FormData/Object/URLSearchParams body types
55
54
  * and will be set automatically, with an option to override it here
56
55
  */
@@ -82,7 +81,7 @@ const {
82
81
  } = constants;
83
82
 
84
83
  const blob = new Blob(['bits']);
85
- const file = new File(['bits'], 'file.dab');
84
+ const file = new File(['bits'], 'file.xyz');
86
85
  const readable = Readable.from('bits');
87
86
 
88
87
  const fd = new FormData({
@@ -90,9 +89,9 @@ const fd = new FormData({
90
89
  });
91
90
 
92
91
  fd.append('celestial', 'payload');
93
- fd.append('blob', blob, 'blob.dab');
92
+ fd.append('blob', blob, 'blob.xyz');
94
93
  fd.append('file', file);
95
- fd.append('readable', readable, 'readable.dab');
94
+ fd.append('readable', readable, 'readable.xyz');
96
95
 
97
96
  const url = 'https://somewhe.re/somewhat/endpoint';
98
97
 
@@ -121,36 +120,37 @@ console.log(res.body);
121
120
  & [http2.ClientSessionRequestOptions](https://nodejs.org/api/http2.html#clienthttp2sessionrequestheaders-options)
122
121
  and [tls.ConnectionOptions](https://nodejs.org/api/tls.html#tlsconnectoptions-callback)
123
122
  for HTTP/2 attunes
123
+ * `allowDowngrade` **{boolean}** `Default: false` Controls whether `https:` redirects to `http:` are allowed
124
124
  * `baseURL` **{string | URL}** The base URL to use in cases where `url` is a relative URL
125
125
  * `body` **{string | Array | ArrayBuffer | ArrayBufferView | AsyncIterator | Blob | Buffer | DataView | File |
126
126
  FormData | Iterator | Object | Readable | ReadableStream | SharedArrayBuffer | URLSearchParams}** The body to send
127
127
  with the request
128
128
  * `bufferBody` **{boolean}** `Default: false` Toggles the buffering of the streamable request bodies for redirects and
129
129
  retries
130
- * `cookies` **{boolean | Array<[k, v]> | Array<string\> | Cookies | Object | URLSearchParams}** `Default: true` The
130
+ * `cookies` **{boolean | string[] | Array<[k, v]> | Cookies | Object | URLSearchParams}** `Default: true` The
131
131
  cookies to add to
132
132
  the request
133
133
  * `cookiesTTL` **{boolean}** `Default: false` Controls enablement of TTL for the cookies cache
134
134
  * `credentials` **{include | omit | same-origin}** `Default: same-origin` Controls credentials in case of cross-origin
135
135
  redirects
136
- * `decodersOptions` **{Object}** Configures decoders options, e.g.: `brotli`, `zstd`, `zlib`
136
+ * `decodersOptions` **{Object}** Configures decoders options, e.g.: `brotli`, `zlib`, `zstd`
137
137
  * `digest` **{boolean}** `Default: true` Controls whether to read the response stream or add a mixin
138
- * `encodersOptions` **{Object}** Configures encoders options, e.g.: `brotli`, `zstd`, `zlib`
138
+ * `encodersOptions` **{Object}** Configures encoders options, e.g.: `brotli`, `zlib`, `zstd`
139
139
  * `follow` **{number}** `Default: 20` The number of redirects to follow
140
140
  * `h2` **{boolean}** `Default: false` Forces the use of HTTP/2 protocol
141
141
  * `headers` **{Object}** The headers to add to the request
142
- * `maxRetryAfter` **{number}** The upper limit of `retry-after` header. If unset, it will use `timeout` value
143
142
  * `params` **{Object}** The search params to add to the `url`
144
143
  * `parse` **{boolean}** `Default: true` Controls whether to parse response body or return a buffer
145
144
  * `redirect` **{error | follow | manual}** `Default: follow` Controls the redirect flows
146
145
  * `retry` **{Object}** Represents the retry options
147
146
  * `attempts` **{number}** `Default: 0` The number of retry attempts
148
147
  * `backoffStrategy` **{string}** `Default: interval * Math.log(Math.random() * (Math.E * Math.E - Math.E) + Math.E)`
149
- The backoff strategy algorithm that increases logarithmically. To fixate set value to `interval * 1`
148
+ The backoff strategy uses a log-uniform algorithm. To fix the interval, set the value to `interval * 1`.
150
149
  * `errorCodes` **{string[]}**
151
150
  `Default: ['ECONNREFUSED', 'ECONNRESET', 'EHOSTDOWN', 'EHOSTUNREACH', 'ENETDOWN', 'ENETUNREACH', 'ENOTFOUND', 'ERR_HTTP2_STREAM_ERROR']`
152
151
  The list of error codes to retry on
153
152
  * `interval` **{number}** `Default: 1e3` The initial retry interval
153
+ * `maxRetryAfter` **{number}** `Default: 3e5` The maximum `retry-after` limit in milliseconds
154
154
  * `retryAfter` **{boolean}** `Default: true` Controls `retry-after` header receptiveness
155
155
  * `statusCodes` **{number[]}** `Default: [429, 500, 502, 503, 504]` The list of status codes to retry on
156
156
  * `stripTrailingSlash` **{boolean}** `Default: false` Controls whether to strip trailing slash at the end of the URL
@@ -202,10 +202,16 @@ const rk = rekwest.extend({
202
202
  baseURL: 'https://somewhe.re',
203
203
  });
204
204
 
205
+ const params = {
206
+ id: '[uid]',
207
+ signature: '[code]',
208
+ variant: 'A',
209
+ };
205
210
  const signal = AbortSignal.timeout(1e4);
206
211
  const url = '/somewhat/endpoint';
207
212
 
208
213
  const res = await rk(url, {
214
+ params,
209
215
  signal,
210
216
  });
211
217
 
package/dist/config.cjs CHANGED
@@ -22,6 +22,7 @@ const {
22
22
  } = _nodeHttp.default.constants;
23
23
  const timeout = 3e5;
24
24
  const defaults = {
25
+ allowDowngrade: false,
25
26
  bufferBody: false,
26
27
  cookiesTTL: false,
27
28
  credentials: _constants.requestCredentials.sameOrigin,
@@ -45,16 +46,15 @@ const defaults = {
45
46
  [HTTP2_HEADER_ACCEPT]: `${_mediatypes.APPLICATION_JSON}, ${_mediatypes.TEXT_PLAIN}, ${_mediatypes.WILDCARD}`,
46
47
  [HTTP2_HEADER_ACCEPT_ENCODING]: `br,${isZstdSupported ? ' zstd, ' : ' '}gzip, deflate, deflate-raw`
47
48
  },
48
- maxRetryAfter: timeout,
49
49
  method: HTTP2_METHOD_GET,
50
50
  parse: true,
51
51
  redirect: _constants.requestRedirect.follow,
52
- redirected: false,
53
52
  retry: {
54
53
  attempts: 0,
55
54
  backoffStrategy: 'interval * Math.log(Math.random() * (Math.E * Math.E - Math.E) + Math.E)',
56
55
  errorCodes: ['ECONNREFUSED', 'ECONNRESET', 'EHOSTDOWN', 'EHOSTUNREACH', 'ENETDOWN', 'ENETUNREACH', 'ENOTFOUND', 'ERR_HTTP2_STREAM_ERROR'],
57
56
  interval: 1e3,
57
+ maxRetryAfter: timeout,
58
58
  retryAfter: true,
59
59
  statusCodes: [HTTP_STATUS_TOO_MANY_REQUESTS, HTTP_STATUS_INTERNAL_SERVER_ERROR, HTTP_STATUS_BAD_GATEWAY, HTTP_STATUS_SERVICE_UNAVAILABLE, HTTP_STATUS_GATEWAY_TIMEOUT]
60
60
  },
package/dist/cookies.cjs CHANGED
@@ -5,7 +5,7 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.Cookies = void 0;
7
7
  var _utils = require("./utils.cjs");
8
- const lifetimeCap = 3456e7; // pragma: 400 days
8
+ const lifetimeCap = 3456e7; // 400 days
9
9
 
10
10
  class Cookies extends URLSearchParams {
11
11
  static #finalizers = new Set();
@@ -37,7 +37,7 @@ class Cookies extends URLSearchParams {
37
37
  for (const attr of attrs) {
38
38
  if (/(?:expires|max-age)=/i.test(attr)) {
39
39
  const [key, val] = attr.toLowerCase().split('=');
40
- const ms = Number.isFinite(Number(val)) ? val * 1e3 : Date.parse(val) - Date.now();
40
+ const ms = Number.isFinite(Number.parseInt(val, 10)) ? val * 1e3 : Date.parse(val) - Date.now();
41
41
  ttl[(0, _utils.toCamelCase)(key)] = Math.min(ms, lifetimeCap);
42
42
  }
43
43
  }
@@ -48,13 +48,16 @@ const postflight = (req, res, options, {
48
48
  enumerable: true,
49
49
  value: cookies !== false && _cookies.Cookies.jar.has(url.origin) ? _cookies.Cookies.jar.get(url.origin) : void 0
50
50
  });
51
- const result = (0, _redirects.redirects)(res, options);
51
+ let result;
52
+ try {
53
+ result = (0, _redirects.redirects)(res, options);
54
+ } catch (err) {
55
+ res.emit('error', err);
56
+ return reject((0, _mixin.mixin)(res, options));
57
+ }
52
58
  if (Object(result) === result) {
53
59
  return result.then(resolve, reject);
54
60
  }
55
- if (result) {
56
- return reject((0, _mixin.mixin)(res, options));
57
- }
58
61
  if (res.statusCode >= HTTP_STATUS_BAD_REQUEST) {
59
62
  return reject((0, _mixin.mixin)(res, options));
60
63
  }
@@ -24,6 +24,7 @@ const {
24
24
  } = _nodeHttp.default.constants;
25
25
  const redirects = (res, options) => {
26
26
  const {
27
+ allowDowngrade,
27
28
  credentials,
28
29
  follow,
29
30
  redirect,
@@ -31,21 +32,24 @@ const redirects = (res, options) => {
31
32
  } = options;
32
33
  if (follow && /3\d{2}/.test(res.statusCode) && res.headers[HTTP2_HEADER_LOCATION]) {
33
34
  if (redirect === _constants.requestRedirect.error) {
34
- return res.emit('error', new _errors.RequestError(`Unexpected redirect, redirect mode is set to: ${redirect}`));
35
+ throw new _errors.RequestError(`Unexpected redirect, redirect mode is set to: ${redirect}`);
35
36
  }
36
37
  if (redirect === _constants.requestRedirect.follow) {
37
- const location = new URL(res.headers[HTTP2_HEADER_LOCATION], url);
38
- if (!/^https?:/i.test(location.protocol)) {
39
- return res.emit('error', new _errors.RequestError('URL scheme must be "http" or "https"'));
38
+ const loc = new URL(res.headers[HTTP2_HEADER_LOCATION], url);
39
+ if (!/^https?:/i.test(loc.protocol)) {
40
+ throw new _errors.RequestError('URL scheme must be "http" or "https"');
40
41
  }
41
- if (!(0, _utils.sameOrigin)(location, url)) {
42
+ if (!allowDowngrade && loc.protocol === 'http:' && url.protocol === 'https:') {
43
+ throw new _errors.RequestError(`Protocol downgrade detected, redirect from "${url.protocol}" to "${loc.protocol}": ${loc}`);
44
+ }
45
+ if (!(0, _utils.sameOrigin)(loc, url)) {
42
46
  if (credentials !== _constants.requestCredentials.include) {
43
47
  options.credentials = _constants.requestCredentials.omit;
44
48
  }
45
49
  options.h2 = false;
46
50
  }
47
51
  if ([HTTP_STATUS_PERMANENT_REDIRECT, HTTP_STATUS_TEMPORARY_REDIRECT].includes(res.statusCode) && (0, _utils.isPipeStream)(options.body) && !(0, _nodeStream.isReadable)(options.body)) {
48
- return res.emit('error', new _errors.RequestError(`Unable to ${redirect} redirect with streamable body`));
52
+ throw new _errors.RequestError(`Unable to ${redirect} redirect with streamable body`);
49
53
  }
50
54
  if ([HTTP_STATUS_MOVED_PERMANENTLY, HTTP_STATUS_FOUND].includes(res.statusCode) && options.method === HTTP2_METHOD_POST || res.statusCode === HTTP_STATUS_SEE_OTHER && ![HTTP2_METHOD_GET, HTTP2_METHOD_HEAD].includes(options.method)) {
51
55
  options.body = null;
@@ -53,7 +57,7 @@ const redirects = (res, options) => {
53
57
  }
54
58
  options.follow--;
55
59
  options.redirected = true;
56
- return (0, _index.default)(location, options);
60
+ return (0, _index.default)(loc, options);
57
61
  }
58
62
  }
59
63
  };
package/dist/retries.cjs CHANGED
@@ -19,7 +19,6 @@ const {
19
19
  const retries = (err, options) => {
20
20
  const {
21
21
  body,
22
- maxRetryAfter,
23
22
  method,
24
23
  retry,
25
24
  url
@@ -36,8 +35,8 @@ const retries = (err, options) => {
36
35
  } = retry;
37
36
  if (retry.retryAfter && err.headers?.[HTTP2_HEADER_RETRY_AFTER]) {
38
37
  interval = err.headers[HTTP2_HEADER_RETRY_AFTER];
39
- interval = Math.abs(Number(interval) * 1e3 || new Date(interval) - Date.now()) || 0;
40
- if (interval > maxRetryAfter) {
38
+ interval = Number.isFinite(Number.parseInt(interval, 10)) ? interval * 1e3 : new Date(interval) - Date.now();
39
+ if (interval > retry.maxRetryAfter) {
41
40
  throw new _errors.RequestError(`Maximum '${HTTP2_HEADER_RETRY_AFTER}' limit exceeded: ${interval} ms`, {
42
41
  cause: err
43
42
  });
@@ -50,7 +49,10 @@ const retries = (err, options) => {
50
49
  }
51
50
  retry.attempts--;
52
51
  retry.interval = interval;
53
- return (0, _promises.setTimeout)(interval).then(() => (0, _index.default)(url, options));
52
+ return _promises.scheduler.wait(interval).then(() => (0, _index.default)(url, {
53
+ ...options,
54
+ params: void 0
55
+ }));
54
56
  }
55
57
  }
56
58
  };
package/dist/utils.cjs CHANGED
@@ -127,15 +127,15 @@ const normalize = (url, options = {}) => {
127
127
  });
128
128
  };
129
129
  exports.normalize = normalize;
130
- const normalizeHeaders = headers => {
130
+ const normalizeHeaders = (headers = {}) => {
131
131
  const acc = {};
132
- for (const [key, val] of Object.entries(headers ?? {})) {
132
+ for (const [key, val] of Object.entries(headers)) {
133
133
  const name = key.toLowerCase();
134
134
  acc[key] = val;
135
135
  if (key === HTTP2_HEADER_ACCEPT_ENCODING && !_config.isZstdSupported) {
136
- const stripped = val.replace(/\s?zstd,?/gi, '').trim();
137
- if (stripped) {
138
- acc[key] = stripped;
136
+ const modified = val.replace(/\s?zstd,?/gi, '').trim();
137
+ if (modified) {
138
+ acc[key] = modified;
139
139
  } else {
140
140
  Reflect.deleteProperty(acc, name);
141
141
  }
package/package.json CHANGED
@@ -71,5 +71,5 @@
71
71
  "test:cover": "c8 --include=src --reporter=lcov --reporter=text npm test"
72
72
  },
73
73
  "type": "module",
74
- "version": "7.1.1"
74
+ "version": "7.2.0"
75
75
  }
package/src/codecs.js CHANGED
@@ -36,6 +36,7 @@ export const encodeCodecs = {
36
36
  gzip: (opts) => zlib.createGzip(opts?.zlib),
37
37
  zstd: (opts) => isZstdSupported && zlib.createZstdCompress(opts?.zstd),
38
38
  };
39
+
39
40
  export const encode = (readable, encodings = '', { encodersOptions } = {}) => {
40
41
  const encoders = [];
41
42
 
package/src/config.js CHANGED
@@ -26,6 +26,7 @@ const {
26
26
  const timeout = 3e5;
27
27
 
28
28
  const defaults = {
29
+ allowDowngrade: false,
29
30
  bufferBody: false,
30
31
  cookiesTTL: false,
31
32
  credentials: requestCredentials.sameOrigin,
@@ -49,11 +50,9 @@ const defaults = {
49
50
  [HTTP2_HEADER_ACCEPT]: `${ APPLICATION_JSON }, ${ TEXT_PLAIN }, ${ WILDCARD }`,
50
51
  [HTTP2_HEADER_ACCEPT_ENCODING]: `br,${ isZstdSupported ? ' zstd, ' : ' ' }gzip, deflate, deflate-raw`,
51
52
  },
52
- maxRetryAfter: timeout,
53
53
  method: HTTP2_METHOD_GET,
54
54
  parse: true,
55
55
  redirect: requestRedirect.follow,
56
- redirected: false,
57
56
  retry: {
58
57
  attempts: 0,
59
58
  backoffStrategy: 'interval * Math.log(Math.random() * (Math.E * Math.E - Math.E) + Math.E)',
@@ -68,6 +67,7 @@ const defaults = {
68
67
  'ERR_HTTP2_STREAM_ERROR',
69
68
  ],
70
69
  interval: 1e3,
70
+ maxRetryAfter: timeout,
71
71
  retryAfter: true,
72
72
  statusCodes: [
73
73
  HTTP_STATUS_TOO_MANY_REQUESTS,
package/src/cookies.js CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  toCamelCase,
4
4
  } from './utils.js';
5
5
 
6
- const lifetimeCap = 3456e7; // pragma: 400 days
6
+ const lifetimeCap = 3456e7; // 400 days
7
7
 
8
8
  export class Cookies extends URLSearchParams {
9
9
 
@@ -39,7 +39,7 @@ export class Cookies extends URLSearchParams {
39
39
  for (const attr of attrs) {
40
40
  if (/(?:expires|max-age)=/i.test(attr)) {
41
41
  const [key, val] = attr.toLowerCase().split('=');
42
- const ms = Number.isFinite(Number(val)) ? val * 1e3 : Date.parse(val) - Date.now();
42
+ const ms = Number.isFinite(Number.parseInt(val, 10)) ? val * 1e3 : Date.parse(val) - Date.now();
43
43
 
44
44
  ttl[toCamelCase(key)] = Math.min(ms, lifetimeCap);
45
45
  }
package/src/postflight.js CHANGED
@@ -42,16 +42,20 @@ export const postflight = (req, res, options, { reject, resolve }) => {
42
42
  value: cookies !== false && Cookies.jar.has(url.origin) ? Cookies.jar.get(url.origin) : void 0,
43
43
  });
44
44
 
45
- const result = redirects(res, options);
45
+ let result;
46
46
 
47
- if (Object(result) === result) {
48
- return result.then(resolve, reject);
49
- }
47
+ try {
48
+ result = redirects(res, options);
49
+ } catch (err) {
50
+ res.emit('error', err);
50
51
 
51
- if (result) {
52
52
  return reject(mixin(res, options));
53
53
  }
54
54
 
55
+ if (Object(result) === result) {
56
+ return result.then(resolve, reject);
57
+ }
58
+
55
59
  if (res.statusCode >= HTTP_STATUS_BAD_REQUEST) {
56
60
  return reject(mixin(res, options));
57
61
  }
package/src/redirects.js CHANGED
@@ -24,21 +24,33 @@ const {
24
24
  } = http2.constants;
25
25
 
26
26
  export const redirects = (res, options) => {
27
- const { credentials, follow, redirect, url } = options;
27
+ const {
28
+ allowDowngrade,
29
+ credentials,
30
+ follow,
31
+ redirect,
32
+ url,
33
+ } = options;
28
34
 
29
35
  if (follow && /3\d{2}/.test(res.statusCode) && res.headers[HTTP2_HEADER_LOCATION]) {
30
36
  if (redirect === requestRedirect.error) {
31
- return res.emit('error', new RequestError(`Unexpected redirect, redirect mode is set to: ${ redirect }`));
37
+ throw new RequestError(`Unexpected redirect, redirect mode is set to: ${ redirect }`);
32
38
  }
33
39
 
34
40
  if (redirect === requestRedirect.follow) {
35
- const location = new URL(res.headers[HTTP2_HEADER_LOCATION], url);
41
+ const loc = new URL(res.headers[HTTP2_HEADER_LOCATION], url);
36
42
 
37
- if (!/^https?:/i.test(location.protocol)) {
38
- return res.emit('error', new RequestError('URL scheme must be "http" or "https"'));
43
+ if (!/^https?:/i.test(loc.protocol)) {
44
+ throw new RequestError('URL scheme must be "http" or "https"');
39
45
  }
40
46
 
41
- if (!sameOrigin(location, url)) {
47
+ if (!allowDowngrade && loc.protocol === 'http:' && url.protocol === 'https:') {
48
+ throw new RequestError(
49
+ `Protocol downgrade detected, redirect from "${ url.protocol }" to "${ loc.protocol }": ${ loc }`,
50
+ );
51
+ }
52
+
53
+ if (!sameOrigin(loc, url)) {
42
54
  if (credentials !== requestCredentials.include) {
43
55
  options.credentials = requestCredentials.omit;
44
56
  }
@@ -50,7 +62,7 @@ export const redirects = (res, options) => {
50
62
  HTTP_STATUS_PERMANENT_REDIRECT,
51
63
  HTTP_STATUS_TEMPORARY_REDIRECT,
52
64
  ].includes(res.statusCode) && isPipeStream(options.body) && !isReadable(options.body)) {
53
- return res.emit('error', new RequestError(`Unable to ${ redirect } redirect with streamable body`));
65
+ throw new RequestError(`Unable to ${ redirect } redirect with streamable body`);
54
66
  }
55
67
 
56
68
  if (([
@@ -68,7 +80,7 @@ export const redirects = (res, options) => {
68
80
  options.follow--;
69
81
  options.redirected = true;
70
82
 
71
- return rekwest(location, options);
83
+ return rekwest(loc, options);
72
84
  }
73
85
  }
74
86
  };
package/src/retries.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import http2 from 'node:http2';
2
2
  import { isReadable } from 'node:stream';
3
- import { setTimeout as setTimeoutPromise } from 'node:timers/promises';
3
+ import { scheduler } from 'node:timers/promises';
4
4
  import { RequestError } from './errors.js';
5
5
  import rekwest from './index.js';
6
6
  import { isPipeStream } from './utils.js';
@@ -12,7 +12,7 @@ const {
12
12
  } = http2.constants;
13
13
 
14
14
  export const retries = (err, options) => {
15
- const { body, maxRetryAfter, method, retry, url } = options;
15
+ const { body, method, retry, url } = options;
16
16
 
17
17
  if (retry?.attempts > 0) {
18
18
  if (![
@@ -27,8 +27,8 @@ export const retries = (err, options) => {
27
27
 
28
28
  if (retry.retryAfter && err.headers?.[HTTP2_HEADER_RETRY_AFTER]) {
29
29
  interval = err.headers[HTTP2_HEADER_RETRY_AFTER];
30
- interval = Math.abs(Number(interval) * 1e3 || new Date(interval) - Date.now()) || 0;
31
- if (interval > maxRetryAfter) {
30
+ interval = Number.isFinite(Number.parseInt(interval, 10)) ? interval * 1e3 : new Date(interval) - Date.now();
31
+ if (interval > retry.maxRetryAfter) {
32
32
  throw new RequestError(
33
33
  `Maximum '${ HTTP2_HEADER_RETRY_AFTER }' limit exceeded: ${ interval } ms`,
34
34
  { cause: err },
@@ -45,7 +45,7 @@ export const retries = (err, options) => {
45
45
  retry.attempts--;
46
46
  retry.interval = interval;
47
47
 
48
- return setTimeoutPromise(interval).then(() => rekwest(url, options));
48
+ return scheduler.wait(interval).then(() => rekwest(url, { ...options, params: void 0 }));
49
49
  }
50
50
  }
51
51
  };
package/src/utils.js CHANGED
@@ -137,19 +137,19 @@ export const normalize = (url, options = {}) => {
137
137
  });
138
138
  };
139
139
 
140
- export const normalizeHeaders = (headers) => {
140
+ export const normalizeHeaders = (headers = {}) => {
141
141
  const acc = {};
142
142
 
143
- for (const [key, val] of Object.entries(headers ?? {})) {
143
+ for (const [key, val] of Object.entries(headers)) {
144
144
  const name = key.toLowerCase();
145
145
 
146
146
  acc[key] = val;
147
147
 
148
148
  if (key === HTTP2_HEADER_ACCEPT_ENCODING && !isZstdSupported) {
149
- const stripped = val.replace(/\s?zstd,?/gi, '').trim();
149
+ const modified = val.replace(/\s?zstd,?/gi, '').trim();
150
150
 
151
- if (stripped) {
152
- acc[key] = stripped;
151
+ if (modified) {
152
+ acc[key] = modified;
153
153
  } else {
154
154
  Reflect.deleteProperty(acc, name);
155
155
  }