@@ -13,10 +13,9 @@ import WebStreams from 'web-streams-polyfill';
13
13
14
14
import { FetchError } from './errors/fetch-error.js' ;
15
15
import { FetchBaseError } from './errors/base.js' ;
16
- import { formDataIterator , getBoundary , getFormDataLength } from './utils/form-data.js' ;
16
+ import { formDataIterator , getBoundary , getFormDataLength , toFormData } from './utils/form-data.js' ;
17
17
import { isBlob , isURLSearchParameters , isFormData , isMultipartFormDataStream , isReadableStream } from './utils/is.js' ;
18
18
import * as utf8 from './utils/utf8.js' ;
19
-
20
19
const { readableHighWaterMark} = new Stream . Readable ( ) ;
21
20
22
21
const { ReadableStream} = WebStreams ;
@@ -26,15 +25,12 @@ const INTERNALS = Symbol('Body internals');
26
25
* Body mixin
27
26
*
28
27
* Ref: https://fetch.spec.whatwg.org/#body
29
- *
30
- * @param {BodyInit } body Readable stream
31
- * @param Object opts Response options
32
- * @return Void
28
+ * @implements {globalThis.Body}
33
29
*/
34
30
35
31
export default class Body {
36
32
/**
37
- * @param {BodyInit|Stream } body
33
+ * @param {BodyInit|Stream|null } body
38
34
* @param {{size?:number} } options
39
35
*/
40
36
constructor ( body , {
@@ -123,7 +119,7 @@ export default class Body {
123
119
/** @type {Headers|undefined } */
124
120
/* c8 ignore next 3 */
125
121
get headers ( ) {
126
- return null ;
122
+ return undefined ;
127
123
}
128
124
129
125
get body ( ) {
@@ -176,6 +172,14 @@ export default class Body {
176
172
const buffer = await consumeBody ( this ) ;
177
173
return utf8 . decode ( buffer ) ;
178
174
}
175
+
176
+ /**
177
+ * @returns {Promise<FormData> }
178
+ */
179
+
180
+ async formData ( ) {
181
+ return toFormData ( this )
182
+ }
179
183
}
180
184
181
185
// In browsers, all properties are enumerable.
@@ -185,7 +189,8 @@ Object.defineProperties(Body.prototype, {
185
189
arrayBuffer : { enumerable : true } ,
186
190
blob : { enumerable : true } ,
187
191
json : { enumerable : true } ,
188
- text : { enumerable : true }
192
+ text : { enumerable : true } ,
193
+ formData : { enumerable : true }
189
194
} ) ;
190
195
191
196
/**
@@ -217,8 +222,9 @@ async function consumeBody(data) {
217
222
218
223
// Body is stream
219
224
// get ready to actually consume the body
225
+ /** @type {[Uint8Array|null, Uint8Array[], number] } */
220
226
const [ buffer , chunks , limit ] = data . size > 0 ?
221
- [ new Uint8Array ( data . size ) , null , data . size ] :
227
+ [ new Uint8Array ( data . size ) , [ ] , data . size ] :
222
228
[ null , [ ] , Infinity ] ;
223
229
let offset = 0 ;
224
230
@@ -244,7 +250,7 @@ async function consumeBody(data) {
244
250
245
251
if ( buffer ) {
246
252
if ( offset < buffer . byteLength ) {
247
- throw new FetchError ( `Premature close of server response while trying to fetch ${ data . url } ` ) ;
253
+ throw new FetchError ( `Premature close of server response while trying to fetch ${ data . url } ` , 'premature-close' ) ;
248
254
} else {
249
255
return buffer ;
250
256
}
@@ -254,11 +260,13 @@ async function consumeBody(data) {
254
260
} catch ( error ) {
255
261
if ( error instanceof FetchBaseError ) {
256
262
throw error ;
263
+ // @ts -expect-error - we know it will have a name
257
264
} else if ( error && error . name === 'AbortError' ) {
258
265
throw error ;
259
266
} else {
267
+ const e = /** @type {import('./errors/fetch-error').SystemError } */ ( error )
260
268
// Other errors, such as incorrect content-encoding
261
- throw new FetchError ( `Invalid response body while trying to fetch ${ data . url } : ${ error . message } ` , 'system' , error ) ;
269
+ throw new FetchError ( `Invalid response body while trying to fetch ${ data . url } : ${ e . message } ` , 'system' , e ) ;
262
270
}
263
271
}
264
272
}
@@ -277,6 +285,7 @@ export const clone = instance => {
277
285
throw new Error ( 'cannot clone body after it is used' ) ;
278
286
}
279
287
288
+ // @ts -expect-error - could be null
280
289
const [ left , right ] = body . tee ( ) ;
281
290
instance [ INTERNALS ] . body = left ;
282
291
return right ;
@@ -332,7 +341,6 @@ class StreamIterableIterator {
332
341
constructor ( stream ) {
333
342
this . stream = stream ;
334
343
this . reader = null ;
335
- this . state = null ;
336
344
}
337
345
338
346
/**
@@ -359,6 +367,9 @@ class StreamIterableIterator {
359
367
return /** @type {Promise<IteratorResult<T, void>> } */ ( this . getReader ( ) . read ( ) ) ;
360
368
}
361
369
370
+ /**
371
+ * @returns {Promise<IteratorResult<T, void>> }
372
+ */
362
373
async return ( ) {
363
374
if ( this . reader ) {
364
375
await this . reader . cancel ( ) ;
@@ -367,6 +378,11 @@ class StreamIterableIterator {
367
378
return { done : true , value : undefined } ;
368
379
}
369
380
381
+ /**
382
+ *
383
+ * @param {any } error
384
+ * @returns {Promise<IteratorResult<T, void>> }
385
+ */
370
386
async throw ( error ) {
371
387
await this . getReader ( ) . cancel ( error ) ;
372
388
return { done : true , value : undefined } ;
@@ -429,7 +445,7 @@ class AsyncIterablePump {
429
445
*/
430
446
async pull ( controller ) {
431
447
try {
432
- while ( controller . desiredSize > 0 ) {
448
+ while ( controller . desiredSize || 0 > 0 ) {
433
449
// eslint-disable-next-line no-await-in-loop
434
450
const next = await this . source . next ( ) ;
435
451
if ( next . done ) {
@@ -444,6 +460,9 @@ class AsyncIterablePump {
444
460
}
445
461
}
446
462
463
+ /**
464
+ * @param {any } [reason]
465
+ */
447
466
cancel ( reason ) {
448
467
if ( reason ) {
449
468
if ( typeof this . source . throw === 'function' ) {
@@ -463,8 +482,8 @@ class AsyncIterablePump {
463
482
*/
464
483
export const fromStream = source => {
465
484
const pump = new StreamPump ( source ) ;
466
- const stream =
467
- /** @type { ReadableStream<Uint8Array> } */ ( new ReadableStream ( pump , pump ) ) ;
485
+ const stream = new ReadableStream ( pump , pump ) ;
486
+ // @ts -ignore - web-streams-polyfill API is incompatible
468
487
return stream ;
469
488
} ;
470
489
@@ -490,6 +509,10 @@ class StreamPump {
490
509
this . close = this . close . bind ( this ) ;
491
510
}
492
511
512
+ /**
513
+ * @param {Uint8Array } chunk
514
+ * @returns
515
+ */
493
516
size ( chunk ) {
494
517
return chunk . byteLength ;
495
518
}
@@ -509,6 +532,9 @@ class StreamPump {
509
532
this . resume ( ) ;
510
533
}
511
534
535
+ /**
536
+ * @param {any } [reason]
537
+ */
512
538
cancel ( reason ) {
513
539
if ( this . stream . destroy ) {
514
540
this . stream . destroy ( reason ) ;
@@ -530,7 +556,7 @@ class StreamPump {
530
556
chunk :
531
557
Buffer . from ( chunk ) ;
532
558
533
- const available = this . controller . desiredSize - bytes . byteLength ;
559
+ const available = ( this . controller . desiredSize || 0 ) - bytes . byteLength ;
534
560
this . controller . enqueue ( bytes ) ;
535
561
if ( available <= 0 ) {
536
562
this . pause ( ) ;
@@ -561,6 +587,9 @@ class StreamPump {
561
587
}
562
588
}
563
589
590
+ /**
591
+ * @param {Error } error
592
+ */
564
593
error ( error ) {
565
594
if ( this . controller ) {
566
595
this . controller . error ( error ) ;
0 commit comments