@@ -66,12 +66,14 @@ export interface FetchOptions<R extends ResponseType = ResponseType>
66
66
onRequestError ?(
67
67
context : FetchContext & { error : Error }
68
68
) : Promise < void > | void ;
69
+ onRequestProgress ?( progress : number ) : Promise < void > | void ;
69
70
onResponse ?(
70
71
context : FetchContext & { response : FetchResponse < R > }
71
72
) : Promise < void > | void ;
72
73
onResponseError ?(
73
74
context : FetchContext & { response : FetchResponse < R > }
74
75
) : Promise < void > | void ;
76
+ onResponseProgress ?( progress : number ) : Promise < void > | void ;
75
77
}
76
78
77
79
export interface $Fetch {
@@ -196,6 +198,28 @@ export function createFetch(globalOptions: CreateFetchOptions = {}): $Fetch {
196
198
? context . options . body
197
199
: JSON . stringify ( context . options . body ) ;
198
200
201
+ if ( context . options . onRequestProgress ) {
202
+ const { readable, writable } = new TransformStream ( ) ;
203
+ const _writer = writable . getWriter ( ) ;
204
+ const _encoder = new TextEncoder ( ) ;
205
+ const contentLength = _encoder . encode (
206
+ context . options . body
207
+ ) . byteLength ;
208
+ let loaded = 0 ;
209
+
210
+ for ( const char of context . options . body ) {
211
+ const chunk = _encoder . encode ( char ) ;
212
+ loaded += chunk . byteLength ;
213
+ _writer . write ( chunk ) ;
214
+ context . options . onRequestProgress (
215
+ Math . round ( ( loaded / contentLength ) * 100 )
216
+ ) ;
217
+ }
218
+
219
+ context . options . body = readable ;
220
+ context . options . duplex = "half" ;
221
+ }
222
+
199
223
// Set Content-Type and Accept headers to application/json by default
200
224
// for JSON serializable request bodies.
201
225
// Pass empty object as older browsers don't support undefined.
@@ -255,7 +279,37 @@ export function createFetch(globalOptions: CreateFetchOptions = {}): $Fetch {
255
279
// We override the `.json()` method to parse the body more securely with `destr`
256
280
switch ( responseType ) {
257
281
case "json" : {
258
- const data = await context . response . text ( ) ;
282
+ const data = await ( async function ( ) {
283
+ /* Custom response.text() function to retrieve text from response and get progress values */
284
+ let loaded = 0 ;
285
+ const contentLength =
286
+ context . response ! . headers . get ( "content-length" ) ! ;
287
+ const _reader = context . response ! . body ! . getReader ( ) ;
288
+ const _decoder = new TextDecoder ( ) ;
289
+ const _chunks : string [ ] = [ ] ;
290
+
291
+ async function read ( ) : Promise < string > {
292
+ const { done, value } = await _reader . read ( ) ;
293
+
294
+ if ( done ) {
295
+ return _chunks . join ( "" ) ;
296
+ }
297
+
298
+ loaded += value . byteLength ;
299
+
300
+ if ( context . options . onResponseProgress ) {
301
+ context . options . onResponseProgress (
302
+ Math . round ( ( loaded / Number . parseInt ( contentLength ) ) * 100 )
303
+ ) ;
304
+ }
305
+
306
+ const chunk = _decoder . decode ( value , { stream : true } ) ;
307
+ _chunks . push ( chunk ) ;
308
+ return await read ( ) ; // read the next chunk
309
+ }
310
+
311
+ return await read ( ) ;
312
+ } ) ( ) ;
259
313
const parseFunction = context . options . parseResponse || destr ;
260
314
context . response . _data = parseFunction ( data ) ;
261
315
break ;
0 commit comments