@whatwg-node/node-fetch 0.8.0-alpha-20241212154840-0a0effe808a6614e0a3afd853126a38641485756 → 0.8.0-alpha-20250917012053-36c9ccdc3e94ee8d0961f17398a9053fa55df37b
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/cjs/AbortError.js +5 -3
- package/cjs/Blob.js +21 -19
- package/cjs/Body.js +146 -76
- package/cjs/FormData.js +54 -41
- package/cjs/Headers.js +54 -15
- package/cjs/ReadableStream.js +62 -26
- package/cjs/Request.js +9 -16
- package/cjs/Response.js +56 -10
- package/cjs/TextEncoderDecoder.js +6 -5
- package/cjs/TextEncoderDecoderStream.js +2 -6
- package/cjs/TransformStream.js +2 -1
- package/cjs/URL.js +10 -66
- package/cjs/URLSearchParams.js +1 -117
- package/cjs/WritableStream.js +35 -111
- package/cjs/fetch.js +37 -8
- package/cjs/fetchCurl.js +30 -61
- package/cjs/fetchNodeHttp.js +60 -64
- package/cjs/index.js +1 -7
- package/cjs/utils.js +76 -55
- package/esm/AbortError.js +5 -3
- package/esm/Blob.js +6 -4
- package/esm/Body.js +134 -63
- package/esm/FormData.js +54 -41
- package/esm/Headers.js +54 -15
- package/esm/ReadableStream.js +57 -21
- package/esm/Request.js +7 -14
- package/esm/Response.js +55 -9
- package/esm/TextEncoderDecoder.js +1 -0
- package/esm/TextEncoderDecoderStream.js +2 -6
- package/esm/TransformStream.js +2 -1
- package/esm/URL.js +9 -64
- package/esm/URLSearchParams.js +1 -115
- package/esm/WritableStream.js +33 -109
- package/esm/fetch.js +35 -6
- package/esm/fetchCurl.js +28 -59
- package/esm/fetchNodeHttp.js +55 -59
- package/esm/index.js +0 -3
- package/esm/utils.js +70 -53
- package/package.json +4 -5
- package/typings/AbortError.d.cts +1 -1
- package/typings/AbortError.d.ts +1 -1
- package/typings/Blob.d.cts +5 -4
- package/typings/Blob.d.ts +5 -4
- package/typings/Body.d.cts +11 -6
- package/typings/Body.d.ts +11 -6
- package/typings/Headers.d.cts +1 -1
- package/typings/Headers.d.ts +1 -1
- package/typings/ReadableStream.d.cts +8 -2
- package/typings/ReadableStream.d.ts +8 -2
- package/typings/Request.d.cts +9 -10
- package/typings/Request.d.ts +9 -10
- package/typings/Response.d.cts +6 -5
- package/typings/Response.d.ts +6 -5
- package/typings/TextEncoderDecoder.d.cts +2 -1
- package/typings/TextEncoderDecoder.d.ts +2 -1
- package/typings/URL.d.cts +12 -16
- package/typings/URL.d.ts +12 -16
- package/typings/URLSearchParams.d.cts +4 -21
- package/typings/URLSearchParams.d.ts +4 -21
- package/typings/WritableStream.d.cts +1 -1
- package/typings/WritableStream.d.ts +1 -1
- package/typings/index.d.cts +0 -3
- package/typings/index.d.ts +0 -3
- package/typings/utils.d.cts +13 -8
- package/typings/utils.d.ts +13 -8
- package/cjs/AbortController.js +0 -18
- package/cjs/AbortSignal.js +0 -85
- package/esm/AbortController.js +0 -14
- package/esm/AbortSignal.js +0 -81
- package/typings/AbortController.d.cts +0 -8
- package/typings/AbortController.d.ts +0 -8
- package/typings/AbortSignal.d.cts +0 -15
- package/typings/AbortSignal.d.ts +0 -15
package/esm/Body.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
1
|
+
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
|
2
|
+
import { Buffer } from 'node:buffer';
|
|
3
|
+
import { addAbortSignal, Readable } from 'node:stream';
|
|
4
|
+
import { Busboy } from '@fastify/busboy';
|
|
5
|
+
import { handleMaybePromise } from '@whatwg-node/promise-helpers';
|
|
3
6
|
import { hasArrayBufferMethod, hasBufferMethod, hasBytesMethod, PonyfillBlob } from './Blob.js';
|
|
4
7
|
import { PonyfillFile } from './File.js';
|
|
5
8
|
import { getStreamFromFormData, PonyfillFormData } from './FormData.js';
|
|
@@ -30,11 +33,13 @@ export class PonyfillBody {
|
|
|
30
33
|
this.contentLength = contentLength;
|
|
31
34
|
this.bodyType = bodyType;
|
|
32
35
|
this._buffer = buffer;
|
|
36
|
+
this._signal = options.signal;
|
|
33
37
|
}
|
|
34
38
|
bodyType;
|
|
35
39
|
_bodyFactory = () => null;
|
|
36
40
|
_generatedBody = null;
|
|
37
41
|
_buffer;
|
|
42
|
+
_signal;
|
|
38
43
|
generateBody() {
|
|
39
44
|
if (this._generatedBody?.readable?.destroyed && this._buffer) {
|
|
40
45
|
this._generatedBody.readable = Readable.from(this._buffer);
|
|
@@ -97,48 +102,66 @@ export class PonyfillBody {
|
|
|
97
102
|
return null;
|
|
98
103
|
}
|
|
99
104
|
_chunks = null;
|
|
100
|
-
|
|
101
|
-
if (this._chunks) {
|
|
102
|
-
return fakePromise(this._chunks);
|
|
103
|
-
}
|
|
105
|
+
_doCollectChunksFromReadableJob() {
|
|
104
106
|
if (this.bodyType === BodyInitType.AsyncIterable) {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
this._chunks ||= [];
|
|
109
|
-
if (value) {
|
|
110
|
-
this._chunks.push(value);
|
|
111
|
-
}
|
|
112
|
-
if (!done) {
|
|
113
|
-
return collectValue();
|
|
114
|
-
}
|
|
107
|
+
if (Array.fromAsync) {
|
|
108
|
+
return handleMaybePromise(() => Array.fromAsync(this.bodyInit), chunks => {
|
|
109
|
+
this._chunks = chunks;
|
|
115
110
|
return this._chunks;
|
|
116
111
|
});
|
|
117
|
-
}
|
|
112
|
+
}
|
|
113
|
+
const iterator = this.bodyInit[Symbol.asyncIterator]();
|
|
114
|
+
const chunks = [];
|
|
115
|
+
const collectValue = () => handleMaybePromise(() => iterator.next(), ({ value, done }) => {
|
|
116
|
+
if (value) {
|
|
117
|
+
chunks.push(value);
|
|
118
|
+
}
|
|
119
|
+
if (!done) {
|
|
120
|
+
return collectValue();
|
|
121
|
+
}
|
|
122
|
+
this._chunks = chunks;
|
|
123
|
+
return this._chunks;
|
|
124
|
+
});
|
|
118
125
|
return collectValue();
|
|
119
126
|
}
|
|
120
127
|
const _body = this.generateBody();
|
|
121
128
|
if (!_body) {
|
|
122
|
-
|
|
129
|
+
this._chunks = [];
|
|
130
|
+
return fakePromise(this._chunks);
|
|
123
131
|
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
132
|
+
if (_body.readable.destroyed) {
|
|
133
|
+
return fakePromise((this._chunks = []));
|
|
134
|
+
}
|
|
135
|
+
const chunks = [];
|
|
128
136
|
return new Promise((resolve, reject) => {
|
|
129
|
-
_body.readable.
|
|
130
|
-
|
|
137
|
+
_body.readable.on('data', chunk => {
|
|
138
|
+
chunks.push(chunk);
|
|
131
139
|
});
|
|
132
|
-
_body.readable.once('error',
|
|
133
|
-
|
|
140
|
+
_body.readable.once('error', reject);
|
|
141
|
+
_body.readable.once('end', () => {
|
|
142
|
+
resolve((this._chunks = chunks));
|
|
134
143
|
});
|
|
135
144
|
});
|
|
136
145
|
}
|
|
146
|
+
_collectChunksFromReadable() {
|
|
147
|
+
if (this._chunks) {
|
|
148
|
+
return fakePromise(this._chunks);
|
|
149
|
+
}
|
|
150
|
+
this._chunks ||= this._doCollectChunksFromReadableJob();
|
|
151
|
+
return this._chunks;
|
|
152
|
+
}
|
|
137
153
|
_blob = null;
|
|
138
154
|
blob() {
|
|
139
155
|
if (this._blob) {
|
|
140
156
|
return fakePromise(this._blob);
|
|
141
157
|
}
|
|
158
|
+
if (this.bodyType === BodyInitType.String) {
|
|
159
|
+
this._text = this.bodyInit;
|
|
160
|
+
this._blob = new PonyfillBlob([this._text], {
|
|
161
|
+
type: this.contentType || 'text/plain;charset=UTF-8',
|
|
162
|
+
size: this.contentLength,
|
|
163
|
+
});
|
|
164
|
+
}
|
|
142
165
|
if (this.bodyType === BodyInitType.Blob) {
|
|
143
166
|
this._blob = this.bodyInit;
|
|
144
167
|
return fakePromise(this._blob);
|
|
@@ -150,13 +173,13 @@ export class PonyfillBody {
|
|
|
150
173
|
});
|
|
151
174
|
return fakePromise(this._blob);
|
|
152
175
|
}
|
|
153
|
-
return this._collectChunksFromReadable()
|
|
176
|
+
return fakePromise(handleMaybePromise(() => this._collectChunksFromReadable(), chunks => {
|
|
154
177
|
this._blob = new PonyfillBlob(chunks, {
|
|
155
178
|
type: this.contentType || '',
|
|
156
179
|
size: this.contentLength,
|
|
157
180
|
});
|
|
158
181
|
return this._blob;
|
|
159
|
-
});
|
|
182
|
+
}));
|
|
160
183
|
}
|
|
161
184
|
_formData = null;
|
|
162
185
|
formData(opts) {
|
|
@@ -177,61 +200,108 @@ export class PonyfillBody {
|
|
|
177
200
|
...opts?.formDataLimits,
|
|
178
201
|
};
|
|
179
202
|
return new Promise((resolve, reject) => {
|
|
180
|
-
const
|
|
203
|
+
const stream = this.body?.readable;
|
|
204
|
+
if (!stream) {
|
|
205
|
+
return reject(new Error('No stream available'));
|
|
206
|
+
}
|
|
207
|
+
// form data file that is currently being processed, it's
|
|
208
|
+
// important to keep track of it in case the stream ends early
|
|
209
|
+
let currFile = null;
|
|
210
|
+
const bb = new Busboy({
|
|
181
211
|
headers: {
|
|
212
|
+
'content-length': typeof this.contentLength === 'number'
|
|
213
|
+
? this.contentLength.toString()
|
|
214
|
+
: this.contentLength || '',
|
|
182
215
|
'content-type': this.contentType || '',
|
|
183
216
|
},
|
|
184
217
|
limits: formDataLimits,
|
|
185
|
-
|
|
218
|
+
defCharset: 'utf-8',
|
|
186
219
|
});
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
220
|
+
if (this._signal) {
|
|
221
|
+
addAbortSignal(this._signal, bb);
|
|
222
|
+
}
|
|
223
|
+
let completed = false;
|
|
224
|
+
const complete = (err) => {
|
|
225
|
+
if (completed)
|
|
226
|
+
return;
|
|
227
|
+
completed = true;
|
|
228
|
+
stream.unpipe(bb);
|
|
229
|
+
bb.destroy();
|
|
230
|
+
if (currFile) {
|
|
231
|
+
currFile.destroy();
|
|
232
|
+
currFile = null;
|
|
233
|
+
}
|
|
234
|
+
if (err) {
|
|
235
|
+
reject(err);
|
|
236
|
+
}
|
|
237
|
+
else {
|
|
238
|
+
// no error occured, this is a successful end/complete/finish
|
|
239
|
+
resolve(this._formData);
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
// we dont need to listen to the stream close event because bb will close or error when necessary
|
|
243
|
+
// stream.on('close', complete);
|
|
244
|
+
// stream can be aborted, for example
|
|
245
|
+
stream.on('error', complete);
|
|
246
|
+
bb.on('field', (name, value, fieldnameTruncated, valueTruncated) => {
|
|
247
|
+
if (fieldnameTruncated) {
|
|
248
|
+
return complete(new Error(`Field name size exceeded: ${formDataLimits?.fieldNameSize} bytes`));
|
|
190
249
|
}
|
|
191
250
|
if (valueTruncated) {
|
|
192
|
-
|
|
251
|
+
return complete(new Error(`Field value size exceeded: ${formDataLimits?.fieldSize} bytes`));
|
|
193
252
|
}
|
|
194
253
|
this._formData.set(name, value);
|
|
195
254
|
});
|
|
196
|
-
bb.on('
|
|
197
|
-
|
|
198
|
-
});
|
|
199
|
-
bb.on('file', (name, fileStream, { filename, mimeType }) => {
|
|
255
|
+
bb.on('file', (name, fileStream, filename, _transferEncoding, mimeType) => {
|
|
256
|
+
currFile = fileStream;
|
|
200
257
|
const chunks = [];
|
|
201
|
-
fileStream.on('limit', () => {
|
|
202
|
-
reject(new Error(`File size limit exceeded: ${formDataLimits?.fileSize} bytes`));
|
|
203
|
-
});
|
|
204
258
|
fileStream.on('data', chunk => {
|
|
205
259
|
chunks.push(chunk);
|
|
206
260
|
});
|
|
261
|
+
fileStream.on('error', complete);
|
|
262
|
+
fileStream.on('limit', () => {
|
|
263
|
+
complete(new Error(`File size limit exceeded: ${formDataLimits?.fileSize} bytes`));
|
|
264
|
+
});
|
|
207
265
|
fileStream.on('close', () => {
|
|
208
266
|
if (fileStream.truncated) {
|
|
209
|
-
|
|
267
|
+
complete(new Error(`File size limit exceeded: ${formDataLimits?.fileSize} bytes`));
|
|
210
268
|
}
|
|
269
|
+
currFile = null;
|
|
211
270
|
const file = new PonyfillFile(chunks, filename, { type: mimeType });
|
|
212
271
|
this._formData.set(name, file);
|
|
213
272
|
});
|
|
214
273
|
});
|
|
274
|
+
bb.on('fieldsLimit', () => {
|
|
275
|
+
complete(new Error(`Fields limit exceeded: ${formDataLimits?.fields}`));
|
|
276
|
+
});
|
|
215
277
|
bb.on('filesLimit', () => {
|
|
216
|
-
|
|
278
|
+
complete(new Error(`Files limit exceeded: ${formDataLimits?.files}`));
|
|
217
279
|
});
|
|
218
280
|
bb.on('partsLimit', () => {
|
|
219
|
-
|
|
281
|
+
complete(new Error(`Parts limit exceeded: ${formDataLimits?.parts}`));
|
|
220
282
|
});
|
|
221
|
-
bb.on('
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
bb.on('error',
|
|
225
|
-
|
|
226
|
-
reject(new TypeError(errMessage, err.cause));
|
|
227
|
-
});
|
|
228
|
-
_body?.readable.pipe(bb);
|
|
283
|
+
bb.on('end', complete);
|
|
284
|
+
bb.on('finish', complete);
|
|
285
|
+
bb.on('close', complete);
|
|
286
|
+
bb.on('error', complete);
|
|
287
|
+
stream.pipe(bb);
|
|
229
288
|
});
|
|
230
289
|
}
|
|
231
290
|
buffer() {
|
|
232
291
|
if (this._buffer) {
|
|
233
292
|
return fakePromise(this._buffer);
|
|
234
293
|
}
|
|
294
|
+
if (this._text) {
|
|
295
|
+
this._buffer = Buffer.from(this._text, 'utf-8');
|
|
296
|
+
return fakePromise(this._buffer);
|
|
297
|
+
}
|
|
298
|
+
if (this.bodyType === BodyInitType.String) {
|
|
299
|
+
return this.text().then(text => {
|
|
300
|
+
this._text = text;
|
|
301
|
+
this._buffer = Buffer.from(text, 'utf-8');
|
|
302
|
+
return this._buffer;
|
|
303
|
+
});
|
|
304
|
+
}
|
|
235
305
|
if (this.bodyType === BodyInitType.Blob) {
|
|
236
306
|
if (hasBufferMethod(this.bodyInit)) {
|
|
237
307
|
return this.bodyInit.buffer().then(buf => {
|
|
@@ -252,20 +322,20 @@ export class PonyfillBody {
|
|
|
252
322
|
});
|
|
253
323
|
}
|
|
254
324
|
}
|
|
255
|
-
return this._collectChunksFromReadable()
|
|
325
|
+
return fakePromise(handleMaybePromise(() => this._collectChunksFromReadable(), chunks => {
|
|
256
326
|
if (chunks.length === 1) {
|
|
257
327
|
this._buffer = chunks[0];
|
|
258
328
|
return this._buffer;
|
|
259
329
|
}
|
|
260
330
|
this._buffer = Buffer.concat(chunks);
|
|
261
331
|
return this._buffer;
|
|
262
|
-
});
|
|
332
|
+
}));
|
|
263
333
|
}
|
|
264
334
|
bytes() {
|
|
265
335
|
return this.buffer();
|
|
266
336
|
}
|
|
267
337
|
arrayBuffer() {
|
|
268
|
-
// @ts-
|
|
338
|
+
// @ts-ignore - Mismatch between Buffer and ArrayBuffer
|
|
269
339
|
return this.buffer();
|
|
270
340
|
}
|
|
271
341
|
_json = null;
|
|
@@ -310,27 +380,26 @@ function processBodyInit(bodyInit) {
|
|
|
310
380
|
};
|
|
311
381
|
}
|
|
312
382
|
if (typeof bodyInit === 'string') {
|
|
313
|
-
const
|
|
314
|
-
const contentLength = buffer.byteLength;
|
|
383
|
+
const contentLength = Buffer.byteLength(bodyInit);
|
|
315
384
|
return {
|
|
316
385
|
bodyType: BodyInitType.String,
|
|
317
386
|
contentType: 'text/plain;charset=UTF-8',
|
|
318
387
|
contentLength,
|
|
319
|
-
buffer,
|
|
320
388
|
bodyFactory() {
|
|
321
|
-
const readable = Readable.from(
|
|
389
|
+
const readable = Readable.from(Buffer.from(bodyInit, 'utf-8'));
|
|
322
390
|
return new PonyfillReadableStream(readable);
|
|
323
391
|
},
|
|
324
392
|
};
|
|
325
393
|
}
|
|
326
394
|
if (Buffer.isBuffer(bodyInit)) {
|
|
395
|
+
const buffer = bodyInit;
|
|
327
396
|
return {
|
|
328
397
|
bodyType: BodyInitType.Buffer,
|
|
329
398
|
contentType: null,
|
|
330
399
|
contentLength: bodyInit.length,
|
|
331
400
|
buffer: bodyInit,
|
|
332
401
|
bodyFactory() {
|
|
333
|
-
const readable = Readable.from(
|
|
402
|
+
const readable = Readable.from(buffer);
|
|
334
403
|
const body = new PonyfillReadableStream(readable);
|
|
335
404
|
return body;
|
|
336
405
|
},
|
|
@@ -351,20 +420,22 @@ function processBodyInit(bodyInit) {
|
|
|
351
420
|
};
|
|
352
421
|
}
|
|
353
422
|
if (bodyInit instanceof PonyfillReadableStream && bodyInit.readable != null) {
|
|
423
|
+
const readableStream = bodyInit;
|
|
354
424
|
return {
|
|
355
425
|
bodyType: BodyInitType.ReadableStream,
|
|
356
|
-
bodyFactory: () =>
|
|
426
|
+
bodyFactory: () => readableStream,
|
|
357
427
|
contentType: null,
|
|
358
428
|
contentLength: null,
|
|
359
429
|
};
|
|
360
430
|
}
|
|
361
431
|
if (isBlob(bodyInit)) {
|
|
432
|
+
const blob = bodyInit;
|
|
362
433
|
return {
|
|
363
434
|
bodyType: BodyInitType.Blob,
|
|
364
435
|
contentType: bodyInit.type,
|
|
365
436
|
contentLength: bodyInit.size,
|
|
366
437
|
bodyFactory() {
|
|
367
|
-
return
|
|
438
|
+
return blob.stream();
|
|
368
439
|
},
|
|
369
440
|
};
|
|
370
441
|
}
|
|
@@ -444,7 +515,7 @@ function isFormData(value) {
|
|
|
444
515
|
return value?.forEach != null;
|
|
445
516
|
}
|
|
446
517
|
function isBlob(value) {
|
|
447
|
-
return value?.stream != null;
|
|
518
|
+
return value?.stream != null && typeof value.stream === 'function';
|
|
448
519
|
}
|
|
449
520
|
function isURLSearchParams(value) {
|
|
450
521
|
return value?.sort != null;
|
package/esm/FormData.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Buffer } from 'node:buffer';
|
|
1
2
|
import { PonyfillIteratorObject } from './IteratorObject.js';
|
|
2
3
|
import { PonyfillReadableStream } from './ReadableStream.js';
|
|
3
4
|
export class PonyfillFormData {
|
|
@@ -68,54 +69,66 @@ export class PonyfillFormData {
|
|
|
68
69
|
}
|
|
69
70
|
}
|
|
70
71
|
export function getStreamFromFormData(formData, boundary = '---') {
|
|
71
|
-
|
|
72
|
+
let entriesIterator;
|
|
72
73
|
let sentInitialHeader = false;
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
74
|
+
let currentAsyncIterator;
|
|
75
|
+
let hasBefore = false;
|
|
76
|
+
function handleNextEntry(controller) {
|
|
77
|
+
const { done, value } = entriesIterator.next();
|
|
78
|
+
if (done) {
|
|
79
|
+
controller.enqueue(Buffer.from(`\r\n--${boundary}--\r\n`));
|
|
80
|
+
return controller.close();
|
|
81
|
+
}
|
|
82
|
+
if (hasBefore) {
|
|
83
|
+
controller.enqueue(Buffer.from(`\r\n--${boundary}\r\n`));
|
|
84
|
+
}
|
|
85
|
+
if (value) {
|
|
86
|
+
const [key, blobOrString] = value;
|
|
87
|
+
if (typeof blobOrString === 'string') {
|
|
88
|
+
controller.enqueue(Buffer.from(`Content-Disposition: form-data; name="${key}"\r\n\r\n`));
|
|
89
|
+
controller.enqueue(Buffer.from(blobOrString));
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
let filenamePart = '';
|
|
93
|
+
if (blobOrString.name) {
|
|
94
|
+
filenamePart = `; filename="${blobOrString.name}"`;
|
|
79
95
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
96
|
+
controller.enqueue(Buffer.from(`Content-Disposition: form-data; name="${key}"${filenamePart}\r\n`));
|
|
97
|
+
controller.enqueue(Buffer.from(`Content-Type: ${blobOrString.type || 'application/octet-stream'}\r\n\r\n`));
|
|
98
|
+
const entryStream = blobOrString.stream();
|
|
99
|
+
// @ts-expect-error - ReadableStream is async iterable
|
|
100
|
+
currentAsyncIterator = entryStream[Symbol.asyncIterator]();
|
|
85
101
|
}
|
|
102
|
+
hasBefore = true;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return new PonyfillReadableStream({
|
|
106
|
+
start: () => {
|
|
107
|
+
entriesIterator = formData.entries();
|
|
86
108
|
},
|
|
87
|
-
pull:
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
let filenamePart = '';
|
|
97
|
-
if (value.name) {
|
|
98
|
-
filenamePart = `; filename="${value.name}"`;
|
|
109
|
+
pull: controller => {
|
|
110
|
+
if (!sentInitialHeader) {
|
|
111
|
+
sentInitialHeader = true;
|
|
112
|
+
return controller.enqueue(Buffer.from(`--${boundary}\r\n`));
|
|
113
|
+
}
|
|
114
|
+
if (currentAsyncIterator) {
|
|
115
|
+
return currentAsyncIterator.next().then(({ done, value }) => {
|
|
116
|
+
if (done) {
|
|
117
|
+
currentAsyncIterator = undefined;
|
|
99
118
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
const entryStream = value.stream();
|
|
103
|
-
for await (const chunk of entryStream) {
|
|
104
|
-
controller.enqueue(chunk);
|
|
119
|
+
if (value) {
|
|
120
|
+
return controller.enqueue(value);
|
|
105
121
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
}
|
|
111
|
-
else {
|
|
112
|
-
controller.enqueue(Buffer.from(`\r\n--${boundary}\r\n`));
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
else {
|
|
116
|
-
controller.enqueue(Buffer.from(`\r\n--${boundary}--\r\n`));
|
|
117
|
-
controller.close();
|
|
122
|
+
else {
|
|
123
|
+
return handleNextEntry(controller);
|
|
124
|
+
}
|
|
125
|
+
});
|
|
118
126
|
}
|
|
127
|
+
return handleNextEntry(controller);
|
|
128
|
+
},
|
|
129
|
+
cancel: err => {
|
|
130
|
+
entriesIterator?.return?.(err);
|
|
131
|
+
currentAsyncIterator?.return?.(err);
|
|
119
132
|
},
|
|
120
133
|
});
|
|
121
134
|
}
|
package/esm/Headers.js
CHANGED
|
@@ -8,14 +8,14 @@ export class PonyfillHeaders {
|
|
|
8
8
|
_map;
|
|
9
9
|
objectNormalizedKeysOfHeadersInit = [];
|
|
10
10
|
objectOriginalKeysOfHeadersInit = [];
|
|
11
|
-
_setCookies
|
|
11
|
+
_setCookies;
|
|
12
12
|
constructor(headersInit) {
|
|
13
13
|
this.headersInit = headersInit;
|
|
14
14
|
}
|
|
15
15
|
// perf: we don't need to build `this.map` for Requests, as we can access the headers directly
|
|
16
16
|
_get(key) {
|
|
17
17
|
const normalized = key.toLowerCase();
|
|
18
|
-
if (normalized === 'set-cookie') {
|
|
18
|
+
if (normalized === 'set-cookie' && this._setCookies?.length) {
|
|
19
19
|
return this._setCookies.join(', ');
|
|
20
20
|
}
|
|
21
21
|
// If the map is built, reuse it
|
|
@@ -27,7 +27,14 @@ export class PonyfillHeaders {
|
|
|
27
27
|
return null;
|
|
28
28
|
}
|
|
29
29
|
if (Array.isArray(this.headersInit)) {
|
|
30
|
-
|
|
30
|
+
const found = this.headersInit.filter(([headerKey]) => headerKey.toLowerCase() === normalized);
|
|
31
|
+
if (found.length === 0) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
if (found.length === 1) {
|
|
35
|
+
return found[0][1];
|
|
36
|
+
}
|
|
37
|
+
return found.map(([, value]) => value).join(', ');
|
|
31
38
|
}
|
|
32
39
|
else if (isHeadersLike(this.headersInit)) {
|
|
33
40
|
return this.headersInit.get(normalized);
|
|
@@ -55,22 +62,24 @@ export class PonyfillHeaders {
|
|
|
55
62
|
// I could do a getter here, but I'm too lazy to type `getter`.
|
|
56
63
|
getMap() {
|
|
57
64
|
if (!this._map) {
|
|
65
|
+
this._setCookies ||= [];
|
|
58
66
|
if (this.headersInit != null) {
|
|
59
67
|
if (Array.isArray(this.headersInit)) {
|
|
60
68
|
this._map = new Map();
|
|
61
|
-
|
|
69
|
+
for (const [key, value] of this.headersInit) {
|
|
62
70
|
const normalizedKey = key.toLowerCase();
|
|
63
71
|
if (normalizedKey === 'set-cookie') {
|
|
64
72
|
this._setCookies.push(value);
|
|
65
|
-
|
|
73
|
+
continue;
|
|
66
74
|
}
|
|
67
75
|
this._map.set(normalizedKey, value);
|
|
68
|
-
}
|
|
76
|
+
}
|
|
69
77
|
}
|
|
70
78
|
else if (isHeadersLike(this.headersInit)) {
|
|
71
79
|
this._map = new Map();
|
|
72
80
|
this.headersInit.forEach((value, key) => {
|
|
73
81
|
if (key === 'set-cookie') {
|
|
82
|
+
this._setCookies ||= [];
|
|
74
83
|
this._setCookies.push(value);
|
|
75
84
|
return;
|
|
76
85
|
}
|
|
@@ -84,6 +93,7 @@ export class PonyfillHeaders {
|
|
|
84
93
|
if (initValue != null) {
|
|
85
94
|
const normalizedKey = initKey.toLowerCase();
|
|
86
95
|
if (normalizedKey === 'set-cookie') {
|
|
96
|
+
this._setCookies ||= [];
|
|
87
97
|
this._setCookies.push(initValue);
|
|
88
98
|
continue;
|
|
89
99
|
}
|
|
@@ -101,6 +111,7 @@ export class PonyfillHeaders {
|
|
|
101
111
|
append(name, value) {
|
|
102
112
|
const key = name.toLowerCase();
|
|
103
113
|
if (key === 'set-cookie') {
|
|
114
|
+
this._setCookies ||= [];
|
|
104
115
|
this._setCookies.push(value);
|
|
105
116
|
return;
|
|
106
117
|
}
|
|
@@ -113,11 +124,12 @@ export class PonyfillHeaders {
|
|
|
113
124
|
if (value == null) {
|
|
114
125
|
return null;
|
|
115
126
|
}
|
|
116
|
-
return value;
|
|
127
|
+
return value.toString();
|
|
117
128
|
}
|
|
118
129
|
has(name) {
|
|
119
|
-
|
|
120
|
-
|
|
130
|
+
const key = name.toLowerCase();
|
|
131
|
+
if (key === 'set-cookie') {
|
|
132
|
+
return !!this._setCookies?.length;
|
|
121
133
|
}
|
|
122
134
|
return !!this._get(name); // we might need to check if header exists and not just check if it's not nullable
|
|
123
135
|
}
|
|
@@ -127,6 +139,26 @@ export class PonyfillHeaders {
|
|
|
127
139
|
this._setCookies = [value];
|
|
128
140
|
return;
|
|
129
141
|
}
|
|
142
|
+
if (!this._map && this.headersInit != null) {
|
|
143
|
+
if (Array.isArray(this.headersInit)) {
|
|
144
|
+
const found = this.headersInit.find(([headerKey]) => headerKey.toLowerCase() === key);
|
|
145
|
+
if (found) {
|
|
146
|
+
found[1] = value;
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
this.headersInit.push([key, value]);
|
|
150
|
+
}
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
else if (isHeadersLike(this.headersInit)) {
|
|
154
|
+
this.headersInit.set(key, value);
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
this.headersInit[key] = value;
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
130
162
|
this.getMap().set(key, value);
|
|
131
163
|
}
|
|
132
164
|
delete(name) {
|
|
@@ -138,7 +170,7 @@ export class PonyfillHeaders {
|
|
|
138
170
|
this.getMap().delete(key);
|
|
139
171
|
}
|
|
140
172
|
forEach(callback) {
|
|
141
|
-
this._setCookies
|
|
173
|
+
this._setCookies?.forEach(setCookie => {
|
|
142
174
|
callback(setCookie, 'set-cookie', this);
|
|
143
175
|
});
|
|
144
176
|
if (!this._map) {
|
|
@@ -166,7 +198,7 @@ export class PonyfillHeaders {
|
|
|
166
198
|
});
|
|
167
199
|
}
|
|
168
200
|
*_keys() {
|
|
169
|
-
if (this._setCookies
|
|
201
|
+
if (this._setCookies?.length) {
|
|
170
202
|
yield 'set-cookie';
|
|
171
203
|
}
|
|
172
204
|
if (!this._map) {
|
|
@@ -189,7 +221,9 @@ export class PonyfillHeaders {
|
|
|
189
221
|
return new PonyfillIteratorObject(this._keys(), 'HeadersIterator');
|
|
190
222
|
}
|
|
191
223
|
*_values() {
|
|
192
|
-
|
|
224
|
+
if (this._setCookies?.length) {
|
|
225
|
+
yield* this._setCookies;
|
|
226
|
+
}
|
|
193
227
|
if (!this._map) {
|
|
194
228
|
if (this.headersInit) {
|
|
195
229
|
if (Array.isArray(this.headersInit)) {
|
|
@@ -210,7 +244,9 @@ export class PonyfillHeaders {
|
|
|
210
244
|
return new PonyfillIteratorObject(this._values(), 'HeadersIterator');
|
|
211
245
|
}
|
|
212
246
|
*_entries() {
|
|
213
|
-
|
|
247
|
+
if (this._setCookies?.length) {
|
|
248
|
+
yield* this._setCookies.map(cookie => ['set-cookie', cookie]);
|
|
249
|
+
}
|
|
214
250
|
if (!this._map) {
|
|
215
251
|
if (this.headersInit) {
|
|
216
252
|
if (Array.isArray(this.headersInit)) {
|
|
@@ -231,6 +267,9 @@ export class PonyfillHeaders {
|
|
|
231
267
|
return new PonyfillIteratorObject(this._entries(), 'HeadersIterator');
|
|
232
268
|
}
|
|
233
269
|
getSetCookie() {
|
|
270
|
+
if (!this._setCookies) {
|
|
271
|
+
this.getMap();
|
|
272
|
+
}
|
|
234
273
|
return this._setCookies;
|
|
235
274
|
}
|
|
236
275
|
[Symbol.iterator]() {
|
|
@@ -240,10 +279,10 @@ export class PonyfillHeaders {
|
|
|
240
279
|
const record = {};
|
|
241
280
|
this.forEach((value, key) => {
|
|
242
281
|
if (key === 'set-cookie') {
|
|
243
|
-
record['set-cookie'] = this._setCookies;
|
|
282
|
+
record['set-cookie'] = this._setCookies || [];
|
|
244
283
|
}
|
|
245
284
|
else {
|
|
246
|
-
record[key] = value
|
|
285
|
+
record[key] = value?.includes(',') ? value.split(',').map(el => el.trim()) : value;
|
|
247
286
|
}
|
|
248
287
|
});
|
|
249
288
|
return `Headers ${inspect(record)}`;
|