rekwest 2.3.5 → 3.0.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 +30 -20
- package/dist/errors.js +8 -4
- package/dist/helpers.js +126 -70
- package/dist/index.js +142 -69
- package/package.json +9 -8
- package/src/ackn.mjs +33 -33
- package/src/cookies.mjs +24 -24
- package/src/errors.mjs +4 -2
- package/src/file.mjs +40 -40
- package/src/formdata.mjs +224 -224
- package/src/helpers.mjs +116 -61
- package/src/index.mjs +115 -66
package/src/formdata.mjs
CHANGED
|
@@ -1,224 +1,224 @@
|
|
|
1
|
-
import { randomBytes } from 'crypto';
|
|
2
|
-
import http2 from 'http2';
|
|
3
|
-
import { toUSVString } from 'util';
|
|
4
|
-
import { File } from './file.mjs';
|
|
5
|
-
import { tap } from './helpers.mjs';
|
|
6
|
-
import {
|
|
7
|
-
APPLICATION_OCTET_STREAM,
|
|
8
|
-
MULTIPART_FORM_DATA,
|
|
9
|
-
} from './mediatypes.mjs';
|
|
10
|
-
|
|
11
|
-
const CRLF = '\r\n';
|
|
12
|
-
const {
|
|
13
|
-
HTTP2_HEADER_CONTENT_DISPOSITION,
|
|
14
|
-
HTTP2_HEADER_CONTENT_TYPE,
|
|
15
|
-
} = http2.constants;
|
|
16
|
-
|
|
17
|
-
export class FormData {
|
|
18
|
-
|
|
19
|
-
static actuate(fd) {
|
|
20
|
-
const boundary = randomBytes(24).toString('hex');
|
|
21
|
-
const contentType = `${ MULTIPART_FORM_DATA }; boundary=${ boundary }`;
|
|
22
|
-
const prefix = `--${ boundary }${ CRLF }${ HTTP2_HEADER_CONTENT_DISPOSITION }: form-data`;
|
|
23
|
-
|
|
24
|
-
const escape = (str) => str.replace(/\n/g, '%0A').replace(/\r/g, '%0D').replace(/"/g, '%22');
|
|
25
|
-
const normalize = (value) => value.replace(/\r?\n|\r/g, CRLF);
|
|
26
|
-
|
|
27
|
-
return {
|
|
28
|
-
contentType,
|
|
29
|
-
async* [Symbol.asyncIterator]() {
|
|
30
|
-
const encoder = new TextEncoder();
|
|
31
|
-
|
|
32
|
-
for (const [name, value] of fd) {
|
|
33
|
-
if (value.constructor === String) {
|
|
34
|
-
yield encoder.encode(`${ prefix }; name="${
|
|
35
|
-
escape(normalize(name))
|
|
36
|
-
}"${ CRLF.repeat(2) }${ normalize(value) }${ CRLF }`);
|
|
37
|
-
} else {
|
|
38
|
-
yield encoder.encode(`${ prefix }; name="${
|
|
39
|
-
escape(normalize(name))
|
|
40
|
-
}"${ value.name ? `; filename="${ escape(value.name) }"` : '' }${ CRLF }${
|
|
41
|
-
HTTP2_HEADER_CONTENT_TYPE
|
|
42
|
-
}: ${
|
|
43
|
-
value.type || APPLICATION_OCTET_STREAM
|
|
44
|
-
}${ CRLF.repeat(2) }`);
|
|
45
|
-
yield* tap(value);
|
|
46
|
-
yield encoder.encode(CRLF);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
yield encoder.encode(`--${ boundary }--`);
|
|
51
|
-
},
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
static alike(instance) {
|
|
56
|
-
return instance?.constructor.name === FormData.name;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
static #enfoldEntry(name, value, filename) {
|
|
60
|
-
name = toUSVString(name);
|
|
61
|
-
filename &&= toUSVString(filename);
|
|
62
|
-
|
|
63
|
-
if (File.alike(value)) {
|
|
64
|
-
value = new File([value], filename, value);
|
|
65
|
-
} else if (this.#ensureInstance(value)) {
|
|
66
|
-
value.name = filename || value.name;
|
|
67
|
-
} else {
|
|
68
|
-
value = toUSVString(value);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
return {
|
|
72
|
-
name,
|
|
73
|
-
value,
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
static #ensureInstance(value) {
|
|
78
|
-
return File.alike(value) || (value === Object(value) && Reflect.has(value, Symbol.asyncIterator));
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
#entries = [];
|
|
82
|
-
|
|
83
|
-
get [Symbol.toStringTag]() {
|
|
84
|
-
return this.constructor.name;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
constructor(input) {
|
|
88
|
-
if (input === Object(input)
|
|
89
|
-
&& (input?.constructor === Object || Reflect.has(input, Symbol.iterator))) {
|
|
90
|
-
|
|
91
|
-
if (input.constructor !== Object) {
|
|
92
|
-
input = Array.from(input);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
if (Array.isArray(input)) {
|
|
96
|
-
if (!input.every((it) => Array.isArray(it))) {
|
|
97
|
-
throw new TypeError(`Failed to construct '${
|
|
98
|
-
this[Symbol.toStringTag]
|
|
99
|
-
}': The provided value cannot be converted to a sequence.`);
|
|
100
|
-
} else if (!input.every((it) => it.length === 2)) {
|
|
101
|
-
throw new TypeError(`Failed to construct '${
|
|
102
|
-
this[Symbol.toStringTag]
|
|
103
|
-
}': Sequence initializer must only contain pair elements.`);
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
if (input.constructor === Object) {
|
|
108
|
-
input = Object.entries(input);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
input.forEach(([key, value]) => this.append(key, value));
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
#ensureArgs(args, expected, method) {
|
|
116
|
-
if (args.length < expected) {
|
|
117
|
-
throw new TypeError(`Failed to execute '${ method }' on '${
|
|
118
|
-
this[Symbol.toStringTag]
|
|
119
|
-
}': ${ expected } arguments required, but only ${ args.length } present.`);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
if ([
|
|
123
|
-
'append',
|
|
124
|
-
'set',
|
|
125
|
-
].includes(method)) {
|
|
126
|
-
if (args.length === 3 && !this.constructor.#ensureInstance(args[1])) {
|
|
127
|
-
throw new TypeError(`Failed to execute '${ method }' on '${
|
|
128
|
-
this[Symbol.toStringTag]
|
|
129
|
-
}': parameter ${ expected } is not of type 'Blob', 'File' or async iterable.`);
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
if (method === 'forEach') {
|
|
134
|
-
if (args[0]?.constructor !== Function) {
|
|
135
|
-
throw new TypeError(`Failed to execute '${ method }' on '${
|
|
136
|
-
this[Symbol.toStringTag]
|
|
137
|
-
}': parameter ${ expected } is not of type 'Function'.`);
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
append(...args) {
|
|
143
|
-
this.#ensureArgs(args, 2, 'append');
|
|
144
|
-
this.#entries.push(this.constructor.#enfoldEntry(...args));
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
delete(...args) {
|
|
148
|
-
this.#ensureArgs(args, 1, 'delete');
|
|
149
|
-
const name = toUSVString(args[0]);
|
|
150
|
-
|
|
151
|
-
this.#entries = this.#entries.filter((it) => it.name !== name);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
forEach(...args) {
|
|
155
|
-
this.#ensureArgs(args, 1, 'forEach');
|
|
156
|
-
const [callback, thisArg] = args;
|
|
157
|
-
|
|
158
|
-
for (const entry of this) {
|
|
159
|
-
Reflect.apply(callback, thisArg, [
|
|
160
|
-
...(entry.reverse()),
|
|
161
|
-
this,
|
|
162
|
-
]);
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
get(...args) {
|
|
167
|
-
this.#ensureArgs(args, 1, 'get');
|
|
168
|
-
const name = toUSVString(args[0]);
|
|
169
|
-
|
|
170
|
-
return (this.#entries.find((it) => it.name === name) ?? {}).value ?? null;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
getAll(...args) {
|
|
174
|
-
this.#ensureArgs(args, 1, 'getAll');
|
|
175
|
-
const name = toUSVString(args[0]);
|
|
176
|
-
|
|
177
|
-
return this.#entries.filter((it) => it.name === name).map((it) => it.value);
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
has(...args) {
|
|
181
|
-
this.#ensureArgs(args, 1, 'has');
|
|
182
|
-
const name = toUSVString(args[0]);
|
|
183
|
-
|
|
184
|
-
return !!this.#entries.find((it) => it.name === name);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
set(...args) {
|
|
188
|
-
this.#ensureArgs(args, 2, 'set');
|
|
189
|
-
const entry = this.constructor.#enfoldEntry(...args);
|
|
190
|
-
const idx = this.#entries.findIndex((it) => it.name === entry.name);
|
|
191
|
-
|
|
192
|
-
if (idx !== -1) {
|
|
193
|
-
this.#entries.splice(idx, 1, entry);
|
|
194
|
-
} else {
|
|
195
|
-
this.#entries.push(entry);
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
* entries() {
|
|
200
|
-
for (const { name, value } of this.#entries) {
|
|
201
|
-
yield [
|
|
202
|
-
name,
|
|
203
|
-
value,
|
|
204
|
-
];
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
* keys() {
|
|
209
|
-
for (const [name] of this) {
|
|
210
|
-
yield name;
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
* values() {
|
|
215
|
-
for (const [, value] of this) {
|
|
216
|
-
yield value;
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
[Symbol.iterator]() {
|
|
221
|
-
return this.entries();
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
}
|
|
1
|
+
import { randomBytes } from 'crypto';
|
|
2
|
+
import http2 from 'http2';
|
|
3
|
+
import { toUSVString } from 'util';
|
|
4
|
+
import { File } from './file.mjs';
|
|
5
|
+
import { tap } from './helpers.mjs';
|
|
6
|
+
import {
|
|
7
|
+
APPLICATION_OCTET_STREAM,
|
|
8
|
+
MULTIPART_FORM_DATA,
|
|
9
|
+
} from './mediatypes.mjs';
|
|
10
|
+
|
|
11
|
+
const CRLF = '\r\n';
|
|
12
|
+
const {
|
|
13
|
+
HTTP2_HEADER_CONTENT_DISPOSITION,
|
|
14
|
+
HTTP2_HEADER_CONTENT_TYPE,
|
|
15
|
+
} = http2.constants;
|
|
16
|
+
|
|
17
|
+
export class FormData {
|
|
18
|
+
|
|
19
|
+
static actuate(fd) {
|
|
20
|
+
const boundary = randomBytes(24).toString('hex');
|
|
21
|
+
const contentType = `${ MULTIPART_FORM_DATA }; boundary=${ boundary }`;
|
|
22
|
+
const prefix = `--${ boundary }${ CRLF }${ HTTP2_HEADER_CONTENT_DISPOSITION }: form-data`;
|
|
23
|
+
|
|
24
|
+
const escape = (str) => str.replace(/\n/g, '%0A').replace(/\r/g, '%0D').replace(/"/g, '%22');
|
|
25
|
+
const normalize = (value) => value.replace(/\r?\n|\r/g, CRLF);
|
|
26
|
+
|
|
27
|
+
return {
|
|
28
|
+
contentType,
|
|
29
|
+
async* [Symbol.asyncIterator]() {
|
|
30
|
+
const encoder = new TextEncoder();
|
|
31
|
+
|
|
32
|
+
for (const [name, value] of fd) {
|
|
33
|
+
if (value.constructor === String) {
|
|
34
|
+
yield encoder.encode(`${ prefix }; name="${
|
|
35
|
+
escape(normalize(name))
|
|
36
|
+
}"${ CRLF.repeat(2) }${ normalize(value) }${ CRLF }`);
|
|
37
|
+
} else {
|
|
38
|
+
yield encoder.encode(`${ prefix }; name="${
|
|
39
|
+
escape(normalize(name))
|
|
40
|
+
}"${ value.name ? `; filename="${ escape(value.name) }"` : '' }${ CRLF }${
|
|
41
|
+
HTTP2_HEADER_CONTENT_TYPE
|
|
42
|
+
}: ${
|
|
43
|
+
value.type || APPLICATION_OCTET_STREAM
|
|
44
|
+
}${ CRLF.repeat(2) }`);
|
|
45
|
+
yield* tap(value);
|
|
46
|
+
yield encoder.encode(CRLF);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
yield encoder.encode(`--${ boundary }--`);
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
static alike(instance) {
|
|
56
|
+
return instance?.constructor.name === FormData.name;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
static #enfoldEntry(name, value, filename) {
|
|
60
|
+
name = toUSVString(name);
|
|
61
|
+
filename &&= toUSVString(filename);
|
|
62
|
+
|
|
63
|
+
if (File.alike(value)) {
|
|
64
|
+
value = new File([value], filename, value);
|
|
65
|
+
} else if (this.#ensureInstance(value)) {
|
|
66
|
+
value.name = filename || value.name;
|
|
67
|
+
} else {
|
|
68
|
+
value = toUSVString(value);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return {
|
|
72
|
+
name,
|
|
73
|
+
value,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
static #ensureInstance(value) {
|
|
78
|
+
return File.alike(value) || (value === Object(value) && Reflect.has(value, Symbol.asyncIterator));
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
#entries = [];
|
|
82
|
+
|
|
83
|
+
get [Symbol.toStringTag]() {
|
|
84
|
+
return this.constructor.name;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
constructor(input) {
|
|
88
|
+
if (input === Object(input)
|
|
89
|
+
&& (input?.constructor === Object || Reflect.has(input, Symbol.iterator))) {
|
|
90
|
+
|
|
91
|
+
if (input.constructor !== Object) {
|
|
92
|
+
input = Array.from(input);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (Array.isArray(input)) {
|
|
96
|
+
if (!input.every((it) => Array.isArray(it))) {
|
|
97
|
+
throw new TypeError(`Failed to construct '${
|
|
98
|
+
this[Symbol.toStringTag]
|
|
99
|
+
}': The provided value cannot be converted to a sequence.`);
|
|
100
|
+
} else if (!input.every((it) => it.length === 2)) {
|
|
101
|
+
throw new TypeError(`Failed to construct '${
|
|
102
|
+
this[Symbol.toStringTag]
|
|
103
|
+
}': Sequence initializer must only contain pair elements.`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (input.constructor === Object) {
|
|
108
|
+
input = Object.entries(input);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
input.forEach(([key, value]) => this.append(key, value));
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
#ensureArgs(args, expected, method) {
|
|
116
|
+
if (args.length < expected) {
|
|
117
|
+
throw new TypeError(`Failed to execute '${ method }' on '${
|
|
118
|
+
this[Symbol.toStringTag]
|
|
119
|
+
}': ${ expected } arguments required, but only ${ args.length } present.`);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if ([
|
|
123
|
+
'append',
|
|
124
|
+
'set',
|
|
125
|
+
].includes(method)) {
|
|
126
|
+
if (args.length === 3 && !this.constructor.#ensureInstance(args[1])) {
|
|
127
|
+
throw new TypeError(`Failed to execute '${ method }' on '${
|
|
128
|
+
this[Symbol.toStringTag]
|
|
129
|
+
}': parameter ${ expected } is not of type 'Blob', 'File' or async iterable.`);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (method === 'forEach') {
|
|
134
|
+
if (args[0]?.constructor !== Function) {
|
|
135
|
+
throw new TypeError(`Failed to execute '${ method }' on '${
|
|
136
|
+
this[Symbol.toStringTag]
|
|
137
|
+
}': parameter ${ expected } is not of type 'Function'.`);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
append(...args) {
|
|
143
|
+
this.#ensureArgs(args, 2, 'append');
|
|
144
|
+
this.#entries.push(this.constructor.#enfoldEntry(...args));
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
delete(...args) {
|
|
148
|
+
this.#ensureArgs(args, 1, 'delete');
|
|
149
|
+
const name = toUSVString(args[0]);
|
|
150
|
+
|
|
151
|
+
this.#entries = this.#entries.filter((it) => it.name !== name);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
forEach(...args) {
|
|
155
|
+
this.#ensureArgs(args, 1, 'forEach');
|
|
156
|
+
const [callback, thisArg] = args;
|
|
157
|
+
|
|
158
|
+
for (const entry of this) {
|
|
159
|
+
Reflect.apply(callback, thisArg, [
|
|
160
|
+
...(entry.reverse()),
|
|
161
|
+
this,
|
|
162
|
+
]);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
get(...args) {
|
|
167
|
+
this.#ensureArgs(args, 1, 'get');
|
|
168
|
+
const name = toUSVString(args[0]);
|
|
169
|
+
|
|
170
|
+
return (this.#entries.find((it) => it.name === name) ?? {}).value ?? null;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
getAll(...args) {
|
|
174
|
+
this.#ensureArgs(args, 1, 'getAll');
|
|
175
|
+
const name = toUSVString(args[0]);
|
|
176
|
+
|
|
177
|
+
return this.#entries.filter((it) => it.name === name).map((it) => it.value);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
has(...args) {
|
|
181
|
+
this.#ensureArgs(args, 1, 'has');
|
|
182
|
+
const name = toUSVString(args[0]);
|
|
183
|
+
|
|
184
|
+
return !!this.#entries.find((it) => it.name === name);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
set(...args) {
|
|
188
|
+
this.#ensureArgs(args, 2, 'set');
|
|
189
|
+
const entry = this.constructor.#enfoldEntry(...args);
|
|
190
|
+
const idx = this.#entries.findIndex((it) => it.name === entry.name);
|
|
191
|
+
|
|
192
|
+
if (idx !== -1) {
|
|
193
|
+
this.#entries.splice(idx, 1, entry);
|
|
194
|
+
} else {
|
|
195
|
+
this.#entries.push(entry);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
* entries() {
|
|
200
|
+
for (const { name, value } of this.#entries) {
|
|
201
|
+
yield [
|
|
202
|
+
name,
|
|
203
|
+
value,
|
|
204
|
+
];
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
* keys() {
|
|
209
|
+
for (const [name] of this) {
|
|
210
|
+
yield name;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
* values() {
|
|
215
|
+
for (const [, value] of this) {
|
|
216
|
+
yield value;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
[Symbol.iterator]() {
|
|
221
|
+
return this.entries();
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
}
|
package/src/helpers.mjs
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Blob } from 'buffer';
|
|
2
|
-
import { globalAgent } from 'http';
|
|
3
2
|
import http2 from 'http2';
|
|
4
3
|
import {
|
|
5
4
|
PassThrough,
|
|
@@ -11,6 +10,7 @@ import {
|
|
|
11
10
|
} from 'util';
|
|
12
11
|
import zlib from 'zlib';
|
|
13
12
|
import { Cookies } from './cookies.mjs';
|
|
13
|
+
import { TimeoutError } from './errors.mjs';
|
|
14
14
|
import { File } from './file.mjs';
|
|
15
15
|
import { FormData } from './formdata.mjs';
|
|
16
16
|
import {
|
|
@@ -32,6 +32,7 @@ const {
|
|
|
32
32
|
HTTP2_HEADER_METHOD,
|
|
33
33
|
HTTP2_HEADER_PATH,
|
|
34
34
|
HTTP2_HEADER_SCHEME,
|
|
35
|
+
HTTP2_HEADER_STATUS,
|
|
35
36
|
HTTP2_METHOD_GET,
|
|
36
37
|
HTTP2_METHOD_HEAD,
|
|
37
38
|
} = http2.constants;
|
|
@@ -43,6 +44,48 @@ const gunzip = promisify(zlib.gunzip);
|
|
|
43
44
|
const deflate = promisify(zlib.deflate);
|
|
44
45
|
const inflate = promisify(zlib.inflate);
|
|
45
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
|
+
|
|
46
89
|
export const compress = (buf, encoding, { async = false } = {}) => {
|
|
47
90
|
encoding &&= encoding.match(/(?<encoding>\bbr\b|\bdeflate\b|\bgzip\b)/i)?.groups.encoding.toLowerCase();
|
|
48
91
|
const compressor = {
|
|
@@ -119,65 +162,7 @@ export const merge = (target = {}, ...rest) => {
|
|
|
119
162
|
return target;
|
|
120
163
|
};
|
|
121
164
|
|
|
122
|
-
export const
|
|
123
|
-
const url = options.url = new URL(options.url);
|
|
124
|
-
const { cookies, h2 = false, method = HTTP2_METHOD_GET, headers, redirected } = options;
|
|
125
|
-
|
|
126
|
-
if (!h2) {
|
|
127
|
-
options.agent ??= url.protocol === 'http:' ? globalAgent : void 0;
|
|
128
|
-
} else {
|
|
129
|
-
options.endStream = [
|
|
130
|
-
HTTP2_METHOD_GET,
|
|
131
|
-
HTTP2_METHOD_HEAD,
|
|
132
|
-
].includes(method);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
if (cookies !== false) {
|
|
136
|
-
let cookie = Cookies.jar.get(url.origin);
|
|
137
|
-
|
|
138
|
-
if (cookies === Object(cookies) && !redirected) {
|
|
139
|
-
if (cookie) {
|
|
140
|
-
new Cookies(cookies).forEach(function (val, key) {
|
|
141
|
-
this.set(key, val);
|
|
142
|
-
}, cookie);
|
|
143
|
-
} else {
|
|
144
|
-
cookie = new Cookies(cookies);
|
|
145
|
-
Cookies.jar.set(url.origin, cookie);
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
options.headers = {
|
|
150
|
-
...cookie && { [HTTP2_HEADER_COOKIE]: cookie },
|
|
151
|
-
...headers,
|
|
152
|
-
};
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
options.digest ??= true;
|
|
156
|
-
options.follow ??= 20;
|
|
157
|
-
options.h2 ??= h2;
|
|
158
|
-
options.headers = {
|
|
159
|
-
[HTTP2_HEADER_ACCEPT]: `${ APPLICATION_JSON }, ${ TEXT_PLAIN }, ${ WILDCARD }`,
|
|
160
|
-
[HTTP2_HEADER_ACCEPT_ENCODING]: 'br, deflate, gzip, identity',
|
|
161
|
-
...Object.entries(options.headers ?? {})
|
|
162
|
-
.reduce((acc, [key, val]) => (acc[key.toLowerCase()] = val, acc), {}),
|
|
163
|
-
...h2 && {
|
|
164
|
-
[HTTP2_HEADER_AUTHORITY]: url.host,
|
|
165
|
-
[HTTP2_HEADER_METHOD]: method,
|
|
166
|
-
[HTTP2_HEADER_PATH]: `${ url.pathname }${ url.search }`,
|
|
167
|
-
[HTTP2_HEADER_SCHEME]: url.protocol.replace(/\p{Punctuation}/gu, ''),
|
|
168
|
-
},
|
|
169
|
-
};
|
|
170
|
-
|
|
171
|
-
options.method ??= method;
|
|
172
|
-
options.parse ??= true;
|
|
173
|
-
options.redirect ??= 'follow';
|
|
174
|
-
options.redirected ??= false;
|
|
175
|
-
options.thenable ??= false;
|
|
176
|
-
|
|
177
|
-
return options;
|
|
178
|
-
};
|
|
179
|
-
|
|
180
|
-
export const premix = (res, { digest = false, parse = false } = {}) => {
|
|
165
|
+
export const mixin = (res, { digest = false, parse = false } = {}) => {
|
|
181
166
|
if (!digest) {
|
|
182
167
|
Object.defineProperties(res, {
|
|
183
168
|
arrayBuffer: {
|
|
@@ -217,7 +202,7 @@ export const premix = (res, { digest = false, parse = false } = {}) => {
|
|
|
217
202
|
enumerable: true,
|
|
218
203
|
value: async function () {
|
|
219
204
|
if (this.bodyUsed) {
|
|
220
|
-
throw new TypeError('Response stream already read');
|
|
205
|
+
throw new TypeError('Response stream already read.');
|
|
221
206
|
}
|
|
222
207
|
|
|
223
208
|
let spool = [];
|
|
@@ -265,6 +250,76 @@ export const premix = (res, { digest = false, parse = false } = {}) => {
|
|
|
265
250
|
});
|
|
266
251
|
};
|
|
267
252
|
|
|
253
|
+
export const preflight = (options) => {
|
|
254
|
+
const url = options.url = new URL(options.url);
|
|
255
|
+
const { cookies, h2 = false, method = HTTP2_METHOD_GET, headers, redirected } = options;
|
|
256
|
+
|
|
257
|
+
if (h2) {
|
|
258
|
+
options.endStream = [
|
|
259
|
+
HTTP2_METHOD_GET,
|
|
260
|
+
HTTP2_METHOD_HEAD,
|
|
261
|
+
].includes(method);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
if (cookies !== false) {
|
|
265
|
+
let cookie = Cookies.jar.get(url.origin);
|
|
266
|
+
|
|
267
|
+
if (cookies === Object(cookies) && !redirected) {
|
|
268
|
+
if (cookie) {
|
|
269
|
+
new Cookies(cookies).forEach(function (val, key) {
|
|
270
|
+
this.set(key, val);
|
|
271
|
+
}, cookie);
|
|
272
|
+
} else {
|
|
273
|
+
cookie = new Cookies(cookies);
|
|
274
|
+
Cookies.jar.set(url.origin, cookie);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
options.headers = {
|
|
279
|
+
...cookie && { [HTTP2_HEADER_COOKIE]: cookie },
|
|
280
|
+
...headers,
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
options.digest ??= true;
|
|
285
|
+
options.follow ??= 20;
|
|
286
|
+
options.h2 ??= h2;
|
|
287
|
+
options.headers = {
|
|
288
|
+
[HTTP2_HEADER_ACCEPT]: `${ APPLICATION_JSON }, ${ TEXT_PLAIN }, ${ WILDCARD }`,
|
|
289
|
+
[HTTP2_HEADER_ACCEPT_ENCODING]: 'br, deflate, gzip, identity',
|
|
290
|
+
...Object.entries(options.headers ?? {})
|
|
291
|
+
.reduce((acc, [key, val]) => (acc[key.toLowerCase()] = val, acc), {}),
|
|
292
|
+
...h2 && {
|
|
293
|
+
[HTTP2_HEADER_AUTHORITY]: url.host,
|
|
294
|
+
[HTTP2_HEADER_METHOD]: method,
|
|
295
|
+
[HTTP2_HEADER_PATH]: `${ url.pathname }${ url.search }`,
|
|
296
|
+
[HTTP2_HEADER_SCHEME]: url.protocol.replace(/\p{Punctuation}/gu, ''),
|
|
297
|
+
},
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
options.method ??= method;
|
|
301
|
+
options.parse ??= true;
|
|
302
|
+
options.redirect ??= redirects.follow;
|
|
303
|
+
|
|
304
|
+
if (!Object.values(redirects).includes(options.redirect)) {
|
|
305
|
+
options.createConnection?.().destroy();
|
|
306
|
+
throw new TypeError(`Failed to read the 'redirect' property from 'options': The provided value '${
|
|
307
|
+
options.redirect
|
|
308
|
+
}' is not a valid enum value.`);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
options.redirected ??= false;
|
|
312
|
+
options.thenable ??= false;
|
|
313
|
+
|
|
314
|
+
return options;
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
export const redirects = {
|
|
318
|
+
error: 'error',
|
|
319
|
+
follow: 'follow',
|
|
320
|
+
manual: 'manual',
|
|
321
|
+
};
|
|
322
|
+
|
|
268
323
|
export async function* tap(value) {
|
|
269
324
|
if (Reflect.has(value, Symbol.asyncIterator)) {
|
|
270
325
|
yield* value;
|