rekwest 5.0.3 → 5.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/src/mixin.mjs CHANGED
@@ -1,109 +1,109 @@
1
- import { Blob } from 'node:buffer';
2
- import http2 from 'node:http2';
3
- import {
4
- brandCheck,
5
- decompress,
6
- } from './utils.mjs';
7
-
8
- const {
9
- HTTP2_HEADER_CONTENT_ENCODING,
10
- HTTP2_HEADER_CONTENT_TYPE,
11
- } = http2.constants;
12
-
13
- export const mixin = (res, { digest = false, parse = false } = {}) => {
14
- if (!digest) {
15
- Object.defineProperties(res, {
16
- arrayBuffer: {
17
- enumerable: true,
18
- value: async function () {
19
- brandCheck(this, res?.constructor);
20
- parse &&= false;
21
- const { buffer, byteLength, byteOffset } = await this.body();
22
-
23
- return buffer.slice(byteOffset, byteOffset + byteLength);
24
- },
25
- },
26
- blob: {
27
- enumerable: true,
28
- value: async function () {
29
- brandCheck(this, res?.constructor);
30
- const val = await this.arrayBuffer();
31
-
32
- return new Blob([val]);
33
- },
34
- },
35
- json: {
36
- enumerable: true,
37
- value: async function () {
38
- brandCheck(this, res?.constructor);
39
- const val = await this.text();
40
-
41
- return JSON.parse(val);
42
- },
43
- },
44
- text: {
45
- enumerable: true,
46
- value: async function () {
47
- brandCheck(this, res?.constructor);
48
- const blob = await this.blob();
49
-
50
- return blob.text();
51
- },
52
- },
53
- });
54
- }
55
-
56
- return Object.defineProperties(res, {
57
- body: {
58
- enumerable: true,
59
- value: async function () {
60
- brandCheck(this, res?.constructor);
61
-
62
- if (this.bodyUsed) {
63
- throw new TypeError('Response stream already read');
64
- }
65
-
66
- let body = [];
67
-
68
- for await (const chunk of decompress(this, this.headers[HTTP2_HEADER_CONTENT_ENCODING])) {
69
- body.push(chunk);
70
- }
71
-
72
- body = Buffer.concat(body);
73
-
74
- if (!body.length && parse) {
75
- return null;
76
- }
77
-
78
- if (body.length && parse) {
79
- const contentType = this.headers[HTTP2_HEADER_CONTENT_TYPE] ?? '';
80
- const charset = contentType.split(';')
81
- .find((it) => /charset=/i.test(it))
82
- ?.toLowerCase()
83
- .replace('charset=', '')
84
- .replace('iso-8859-1', 'latin1')
85
- .trim() || 'utf-8';
86
-
87
- if (/\bjson\b/i.test(contentType)) {
88
- body = JSON.parse(body.toString(charset));
89
- } else if (/\b(?:text|xml)\b/i.test(contentType)) {
90
- if (/\b(?:latin1|ucs-2|utf-(?:8|16le))\b/i.test(charset)) {
91
- body = body.toString(charset);
92
- } else {
93
- body = new TextDecoder(charset).decode(body);
94
- }
95
- }
96
- }
97
-
98
- return body;
99
- },
100
- writable: true,
101
- },
102
- bodyUsed: {
103
- enumerable: true,
104
- get() {
105
- return this.readableEnded;
106
- },
107
- },
108
- });
109
- };
1
+ import { Blob } from 'node:buffer';
2
+ import http2 from 'node:http2';
3
+ import {
4
+ brandCheck,
5
+ decompress,
6
+ } from './utils.mjs';
7
+
8
+ const {
9
+ HTTP2_HEADER_CONTENT_ENCODING,
10
+ HTTP2_HEADER_CONTENT_TYPE,
11
+ } = http2.constants;
12
+
13
+ export const mixin = (res, { digest = false, parse = false } = {}) => {
14
+ if (!digest) {
15
+ Object.defineProperties(res, {
16
+ arrayBuffer: {
17
+ enumerable: true,
18
+ value: async function () {
19
+ brandCheck(this, res?.constructor);
20
+ parse &&= false;
21
+ const { buffer, byteLength, byteOffset } = await this.body();
22
+
23
+ return buffer.slice(byteOffset, byteOffset + byteLength);
24
+ },
25
+ },
26
+ blob: {
27
+ enumerable: true,
28
+ value: async function () {
29
+ brandCheck(this, res?.constructor);
30
+ const val = await this.arrayBuffer();
31
+
32
+ return new Blob([val]);
33
+ },
34
+ },
35
+ json: {
36
+ enumerable: true,
37
+ value: async function () {
38
+ brandCheck(this, res?.constructor);
39
+ const val = await this.text();
40
+
41
+ return JSON.parse(val);
42
+ },
43
+ },
44
+ text: {
45
+ enumerable: true,
46
+ value: async function () {
47
+ brandCheck(this, res?.constructor);
48
+ const blob = await this.blob();
49
+
50
+ return blob.text();
51
+ },
52
+ },
53
+ });
54
+ }
55
+
56
+ return Object.defineProperties(res, {
57
+ body: {
58
+ enumerable: true,
59
+ value: async function () {
60
+ brandCheck(this, res?.constructor);
61
+
62
+ if (this.bodyUsed) {
63
+ throw new TypeError('Response stream already read');
64
+ }
65
+
66
+ let body = [];
67
+
68
+ for await (const chunk of decompress(this, this.headers[HTTP2_HEADER_CONTENT_ENCODING])) {
69
+ body.push(chunk);
70
+ }
71
+
72
+ body = Buffer.concat(body);
73
+
74
+ if (!body.length && parse) {
75
+ return null;
76
+ }
77
+
78
+ if (body.length && parse) {
79
+ const contentType = this.headers[HTTP2_HEADER_CONTENT_TYPE] ?? '';
80
+ const charset = contentType.split(';')
81
+ .find((it) => /charset=/i.test(it))
82
+ ?.toLowerCase()
83
+ .replace('charset=', '')
84
+ .replace('iso-8859-1', 'latin1')
85
+ .trim() || 'utf-8';
86
+
87
+ if (/\bjson\b/i.test(contentType)) {
88
+ body = JSON.parse(body.toString(charset));
89
+ } else if (/\b(?:text|xml)\b/i.test(contentType)) {
90
+ if (/\b(?:latin1|ucs-2|utf-(?:8|16le))\b/i.test(charset)) {
91
+ body = body.toString(charset);
92
+ } else {
93
+ body = new TextDecoder(charset).decode(body);
94
+ }
95
+ }
96
+ }
97
+
98
+ return body;
99
+ },
100
+ writable: true,
101
+ },
102
+ bodyUsed: {
103
+ enumerable: true,
104
+ get() {
105
+ return this.readableEnded;
106
+ },
107
+ },
108
+ });
109
+ };
@@ -1,136 +1,136 @@
1
- import http2 from 'node:http2';
2
- import { setTimeout as setTimeoutPromise } from 'node:timers/promises';
3
- import {
4
- requestCredentials,
5
- requestRedirect,
6
- requestRedirectCodes,
7
- } from './constants.mjs';
8
- import { Cookies } from './cookies.mjs';
9
- import { RequestError } from './errors.mjs';
10
- import rekwest from './index.mjs';
11
- import { mixin } from './mixin.mjs';
12
- import {
13
- admix,
14
- maxRetryAfterError,
15
- sameOrigin,
16
- } from './utils.mjs';
17
-
18
- const {
19
- HTTP2_HEADER_LOCATION,
20
- HTTP2_HEADER_RETRY_AFTER,
21
- HTTP2_HEADER_SET_COOKIE,
22
- HTTP2_METHOD_GET,
23
- HTTP2_METHOD_HEAD,
24
- HTTP2_METHOD_POST,
25
- HTTP_STATUS_BAD_REQUEST,
26
- HTTP_STATUS_FOUND,
27
- HTTP_STATUS_MOVED_PERMANENTLY,
28
- HTTP_STATUS_SEE_OTHER,
29
- } = http2.constants;
30
-
31
- export const postflight = (req, res, options, { reject, resolve }) => {
32
- const { cookies, credentials, follow, h2, redirect, url } = options;
33
- let headers;
34
-
35
- if (h2) {
36
- headers = res;
37
- res = req;
38
- } else {
39
- res.once('error', reject);
40
- }
41
-
42
- admix(res, headers, options);
43
-
44
- if (cookies !== false && res.headers[HTTP2_HEADER_SET_COOKIE]) {
45
- if (Cookies.jar.has(url.origin)) {
46
- const cookie = new Cookies(res.headers[HTTP2_HEADER_SET_COOKIE], options);
47
-
48
- Cookies.jar.get(url.origin).forEach((val, key) => {
49
- if (!cookie.has(key)) {
50
- cookie.set(key, val);
51
- }
52
- });
53
- Cookies.jar.set(url.origin, cookie);
54
- } else {
55
- Cookies.jar.set(url.origin, new Cookies(res.headers[HTTP2_HEADER_SET_COOKIE], options));
56
- }
57
- }
58
-
59
- Reflect.defineProperty(res, 'cookies', {
60
- enumerable: true,
61
- value: cookies !== false && Cookies.jar.has(url.origin)
62
- ? Cookies.jar.get(url.origin)
63
- : void 0,
64
- });
65
-
66
- const { statusCode } = res;
67
-
68
- if (follow && /3\d{2}/.test(statusCode) && res.headers[HTTP2_HEADER_LOCATION]) {
69
- if (!requestRedirectCodes.includes(statusCode)) {
70
- return res.emit('error', new RangeError(`Invalid status code: ${ statusCode }`));
71
- }
72
-
73
- if (redirect === requestRedirect.error) {
74
- return res.emit('error', new RequestError(`Unexpected redirect, redirect mode is set to '${ redirect }'.`));
75
- }
76
-
77
- if (redirect === requestRedirect.follow) {
78
- const location = new URL(res.headers[HTTP2_HEADER_LOCATION], url);
79
-
80
- if (!/^https?:/i.test(location.protocol)) {
81
- return res.emit('error', new RequestError('URL scheme must be "http" or "https".'));
82
- }
83
-
84
- if (!sameOrigin(location, url)) {
85
- if (credentials !== requestCredentials.include) {
86
- options.credentials = requestCredentials.omit;
87
- }
88
-
89
- options.h2 = false;
90
- }
91
-
92
- if (statusCode !== HTTP_STATUS_SEE_OTHER && options.body?.pipe?.constructor === Function) {
93
- return res.emit('error', new RequestError(`Unable to ${ redirect } redirect with streamable body.`));
94
- }
95
-
96
- if (([
97
- HTTP_STATUS_MOVED_PERMANENTLY,
98
- HTTP_STATUS_FOUND,
99
- ].includes(statusCode) && options.method === HTTP2_METHOD_POST) || (statusCode === HTTP_STATUS_SEE_OTHER && ![
100
- HTTP2_METHOD_GET,
101
- HTTP2_METHOD_HEAD,
102
- ].includes(options.method))) {
103
- for (const it of Object.keys(options.headers).filter((val) => /^content-/i.test(val))) {
104
- Reflect.deleteProperty(options.headers, it);
105
- }
106
-
107
- options.body = null;
108
- options.method = HTTP2_METHOD_GET;
109
- }
110
-
111
- options.follow--;
112
- options.redirected = true;
113
- options.url = location;
114
-
115
- if (statusCode === HTTP_STATUS_MOVED_PERMANENTLY && res.headers[HTTP2_HEADER_RETRY_AFTER]) {
116
- let interval = res.headers[HTTP2_HEADER_RETRY_AFTER];
117
-
118
- interval = Number(interval) * 1000 || new Date(interval) - Date.now();
119
-
120
- if (interval > options.maxRetryAfter) {
121
- return res.emit('error', maxRetryAfterError(interval, { cause: mixin(res, options) }));
122
- }
123
-
124
- return setTimeoutPromise(interval).then(() => rekwest(options.url, options).then(resolve, reject));
125
- }
126
-
127
- return rekwest(options.url, options).then(resolve, reject);
128
- }
129
- }
130
-
131
- if (statusCode >= HTTP_STATUS_BAD_REQUEST) {
132
- return reject(mixin(res, options));
133
- }
134
-
135
- resolve(mixin(res, options));
136
- };
1
+ import http2 from 'node:http2';
2
+ import { setTimeout as setTimeoutPromise } from 'node:timers/promises';
3
+ import {
4
+ requestCredentials,
5
+ requestRedirect,
6
+ requestRedirectCodes,
7
+ } from './constants.mjs';
8
+ import { Cookies } from './cookies.mjs';
9
+ import { RequestError } from './errors.mjs';
10
+ import rekwest from './index.mjs';
11
+ import { mixin } from './mixin.mjs';
12
+ import {
13
+ admix,
14
+ maxRetryAfterError,
15
+ sameOrigin,
16
+ } from './utils.mjs';
17
+
18
+ const {
19
+ HTTP2_HEADER_LOCATION,
20
+ HTTP2_HEADER_RETRY_AFTER,
21
+ HTTP2_HEADER_SET_COOKIE,
22
+ HTTP2_METHOD_GET,
23
+ HTTP2_METHOD_HEAD,
24
+ HTTP2_METHOD_POST,
25
+ HTTP_STATUS_BAD_REQUEST,
26
+ HTTP_STATUS_FOUND,
27
+ HTTP_STATUS_MOVED_PERMANENTLY,
28
+ HTTP_STATUS_SEE_OTHER,
29
+ } = http2.constants;
30
+
31
+ export const postflight = (req, res, options, { reject, resolve }) => {
32
+ const { cookies, credentials, follow, h2, redirect, url } = options;
33
+ let headers;
34
+
35
+ if (h2) {
36
+ headers = res;
37
+ res = req;
38
+ } else {
39
+ res.once('error', reject);
40
+ }
41
+
42
+ admix(res, headers, options);
43
+
44
+ if (cookies !== false && res.headers[HTTP2_HEADER_SET_COOKIE]) {
45
+ if (Cookies.jar.has(url.origin)) {
46
+ const cookie = new Cookies(res.headers[HTTP2_HEADER_SET_COOKIE], options);
47
+
48
+ Cookies.jar.get(url.origin).forEach((val, key) => {
49
+ if (!cookie.has(key)) {
50
+ cookie.set(key, val);
51
+ }
52
+ });
53
+ Cookies.jar.set(url.origin, cookie);
54
+ } else {
55
+ Cookies.jar.set(url.origin, new Cookies(res.headers[HTTP2_HEADER_SET_COOKIE], options));
56
+ }
57
+ }
58
+
59
+ Reflect.defineProperty(res, 'cookies', {
60
+ enumerable: true,
61
+ value: cookies !== false && Cookies.jar.has(url.origin)
62
+ ? Cookies.jar.get(url.origin)
63
+ : void 0,
64
+ });
65
+
66
+ const { statusCode } = res;
67
+
68
+ if (follow && /3\d{2}/.test(statusCode) && res.headers[HTTP2_HEADER_LOCATION]) {
69
+ if (!requestRedirectCodes.includes(statusCode)) {
70
+ return res.emit('error', new RangeError(`Invalid status code: ${ statusCode }`));
71
+ }
72
+
73
+ if (redirect === requestRedirect.error) {
74
+ return res.emit('error', new RequestError(`Unexpected redirect, redirect mode is set to '${ redirect }'.`));
75
+ }
76
+
77
+ if (redirect === requestRedirect.follow) {
78
+ const location = new URL(res.headers[HTTP2_HEADER_LOCATION], url);
79
+
80
+ if (!/^https?:/i.test(location.protocol)) {
81
+ return res.emit('error', new RequestError('URL scheme must be "http" or "https".'));
82
+ }
83
+
84
+ if (!sameOrigin(location, url)) {
85
+ if (credentials !== requestCredentials.include) {
86
+ options.credentials = requestCredentials.omit;
87
+ }
88
+
89
+ options.h2 = false;
90
+ }
91
+
92
+ if (statusCode !== HTTP_STATUS_SEE_OTHER && options.body?.pipe?.constructor === Function) {
93
+ return res.emit('error', new RequestError(`Unable to ${ redirect } redirect with streamable body.`));
94
+ }
95
+
96
+ if (([
97
+ HTTP_STATUS_MOVED_PERMANENTLY,
98
+ HTTP_STATUS_FOUND,
99
+ ].includes(statusCode) && options.method === HTTP2_METHOD_POST) || (statusCode === HTTP_STATUS_SEE_OTHER && ![
100
+ HTTP2_METHOD_GET,
101
+ HTTP2_METHOD_HEAD,
102
+ ].includes(options.method))) {
103
+ for (const it of Object.keys(options.headers).filter((val) => /^content-/i.test(val))) {
104
+ Reflect.deleteProperty(options.headers, it);
105
+ }
106
+
107
+ options.body = null;
108
+ options.method = HTTP2_METHOD_GET;
109
+ }
110
+
111
+ options.follow--;
112
+ options.redirected = true;
113
+ options.url = location;
114
+
115
+ if (statusCode === HTTP_STATUS_MOVED_PERMANENTLY && res.headers[HTTP2_HEADER_RETRY_AFTER]) {
116
+ let interval = res.headers[HTTP2_HEADER_RETRY_AFTER];
117
+
118
+ interval = Number(interval) * 1e3 || new Date(interval) - Date.now();
119
+
120
+ if (interval > options.maxRetryAfter) {
121
+ return res.emit('error', maxRetryAfterError(interval, { cause: mixin(res, options) }));
122
+ }
123
+
124
+ return setTimeoutPromise(interval).then(() => rekwest(options.url, options).then(resolve, reject));
125
+ }
126
+
127
+ return rekwest(options.url, options).then(resolve, reject);
128
+ }
129
+ }
130
+
131
+ if (statusCode >= HTTP_STATUS_BAD_REQUEST) {
132
+ return reject(mixin(res, options));
133
+ }
134
+
135
+ resolve(mixin(res, options));
136
+ };
package/src/preflight.mjs CHANGED
@@ -1,87 +1,87 @@
1
- import http2 from 'node:http2';
2
- import { requestCredentials } from './constants.mjs';
3
- import { Cookies } from './cookies.mjs';
4
- import {
5
- APPLICATION_JSON,
6
- TEXT_PLAIN,
7
- WILDCARD,
8
- } from './mediatypes.mjs';
9
-
10
- const {
11
- HTTP2_HEADER_ACCEPT,
12
- HTTP2_HEADER_ACCEPT_ENCODING,
13
- HTTP2_HEADER_AUTHORITY,
14
- HTTP2_HEADER_AUTHORIZATION,
15
- HTTP2_HEADER_COOKIE,
16
- HTTP2_HEADER_METHOD,
17
- HTTP2_HEADER_PATH,
18
- HTTP2_HEADER_SCHEME,
19
- HTTP2_METHOD_GET,
20
- HTTP2_METHOD_HEAD,
21
- } = http2.constants;
22
-
23
- export const preflight = (options) => {
24
- const { cookies, credentials, h2, headers, method, url } = options;
25
-
26
- if (h2) {
27
- options.endStream = [
28
- HTTP2_METHOD_GET,
29
- HTTP2_METHOD_HEAD,
30
- ].includes(method);
31
- }
32
-
33
- if (cookies !== false && credentials !== requestCredentials.omit) {
34
- let cookie = Cookies.jar.has(url.origin);
35
-
36
- if (cookies === Object(cookies) && [
37
- requestCredentials.include,
38
- requestCredentials.sameOrigin,
39
- ].includes(credentials)) {
40
- if (cookie) {
41
- cookie = new Cookies(cookies, options);
42
-
43
- Cookies.jar.get(url.origin).forEach((val, key) => {
44
- if (!cookie.has(key)) {
45
- cookie.set(key, val);
46
- }
47
- });
48
- Cookies.jar.set(url.origin, cookie);
49
- } else {
50
- cookie = new Cookies(cookies, options);
51
- Cookies.jar.set(url.origin, cookie);
52
- }
53
- } else {
54
- cookie &&= Cookies.jar.get(url.origin);
55
- }
56
-
57
- options.headers = {
58
- ...cookie && { [HTTP2_HEADER_COOKIE]: cookie },
59
- ...headers,
60
- };
61
- }
62
-
63
- if (credentials === requestCredentials.omit) {
64
- options.cookies = false;
65
- for (const it of Object.keys(options.headers ?? {})
66
- .filter((val) => new RegExp(`^(${
67
- HTTP2_HEADER_AUTHORIZATION }|${ HTTP2_HEADER_COOKIE
68
- })$`, 'i').test(val))) { Reflect.deleteProperty(options.headers, it); }
69
-
70
- url.password = url.username = '';
71
- }
72
-
73
- options.headers = {
74
- [HTTP2_HEADER_ACCEPT]: `${ APPLICATION_JSON }, ${ TEXT_PLAIN }, ${ WILDCARD }`,
75
- [HTTP2_HEADER_ACCEPT_ENCODING]: 'br, deflate, deflate-raw, gzip, identity',
76
- ...Object.entries(options.headers ?? {})
77
- .reduce((acc, [key, val]) => (acc[key.toLowerCase()] = val, acc), {}),
78
- ...h2 && {
79
- [HTTP2_HEADER_AUTHORITY]: url.host,
80
- [HTTP2_HEADER_METHOD]: method,
81
- [HTTP2_HEADER_PATH]: `${ url.pathname }${ url.search }`,
82
- [HTTP2_HEADER_SCHEME]: url.protocol.replace(/\p{Punctuation}/gu, ''),
83
- },
84
- };
85
-
86
- return options;
87
- };
1
+ import http2 from 'node:http2';
2
+ import { requestCredentials } from './constants.mjs';
3
+ import { Cookies } from './cookies.mjs';
4
+ import {
5
+ APPLICATION_JSON,
6
+ TEXT_PLAIN,
7
+ WILDCARD,
8
+ } from './mediatypes.mjs';
9
+
10
+ const {
11
+ HTTP2_HEADER_ACCEPT,
12
+ HTTP2_HEADER_ACCEPT_ENCODING,
13
+ HTTP2_HEADER_AUTHORITY,
14
+ HTTP2_HEADER_AUTHORIZATION,
15
+ HTTP2_HEADER_COOKIE,
16
+ HTTP2_HEADER_METHOD,
17
+ HTTP2_HEADER_PATH,
18
+ HTTP2_HEADER_SCHEME,
19
+ HTTP2_METHOD_GET,
20
+ HTTP2_METHOD_HEAD,
21
+ } = http2.constants;
22
+
23
+ export const preflight = (options) => {
24
+ const { cookies, credentials, h2, headers, method, url } = options;
25
+
26
+ if (h2) {
27
+ options.endStream = [
28
+ HTTP2_METHOD_GET,
29
+ HTTP2_METHOD_HEAD,
30
+ ].includes(method);
31
+ }
32
+
33
+ if (cookies !== false && credentials !== requestCredentials.omit) {
34
+ let cookie = Cookies.jar.has(url.origin);
35
+
36
+ if (cookies === Object(cookies) && [
37
+ requestCredentials.include,
38
+ requestCredentials.sameOrigin,
39
+ ].includes(credentials)) {
40
+ if (cookie) {
41
+ cookie = new Cookies(cookies, options);
42
+
43
+ Cookies.jar.get(url.origin).forEach((val, key) => {
44
+ if (!cookie.has(key)) {
45
+ cookie.set(key, val);
46
+ }
47
+ });
48
+ Cookies.jar.set(url.origin, cookie);
49
+ } else {
50
+ cookie = new Cookies(cookies, options);
51
+ Cookies.jar.set(url.origin, cookie);
52
+ }
53
+ } else {
54
+ cookie &&= Cookies.jar.get(url.origin);
55
+ }
56
+
57
+ options.headers = {
58
+ ...cookie && { [HTTP2_HEADER_COOKIE]: cookie },
59
+ ...headers,
60
+ };
61
+ }
62
+
63
+ if (credentials === requestCredentials.omit) {
64
+ options.cookies = false;
65
+ for (const it of Object.keys(options.headers ?? {})
66
+ .filter((val) => new RegExp(`^(${
67
+ HTTP2_HEADER_AUTHORIZATION }|${ HTTP2_HEADER_COOKIE
68
+ })$`, 'i').test(val))) { Reflect.deleteProperty(options.headers, it); }
69
+
70
+ url.password = url.username = '';
71
+ }
72
+
73
+ options.headers = {
74
+ [HTTP2_HEADER_ACCEPT]: `${ APPLICATION_JSON }, ${ TEXT_PLAIN }, ${ WILDCARD }`,
75
+ [HTTP2_HEADER_ACCEPT_ENCODING]: 'br, deflate, deflate-raw, gzip, identity',
76
+ ...Object.entries(options.headers ?? {})
77
+ .reduce((acc, [key, val]) => (acc[key.toLowerCase()] = val, acc), {}),
78
+ ...h2 && {
79
+ [HTTP2_HEADER_AUTHORITY]: url.host,
80
+ [HTTP2_HEADER_METHOD]: method,
81
+ [HTTP2_HEADER_PATH]: `${ url.pathname }${ url.search }`,
82
+ [HTTP2_HEADER_SCHEME]: url.protocol.replace(/\p{Punctuation}/gu, ''),
83
+ },
84
+ };
85
+
86
+ return options;
87
+ };