@mswjs/interceptors 0.34.1 → 0.34.2
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/lib/browser/{chunk-7A4UJNSW.mjs → chunk-73X2CAEH.mjs} +6 -6
- package/lib/browser/chunk-73X2CAEH.mjs.map +1 -0
- package/lib/browser/{chunk-ZXJSL23E.mjs → chunk-7BTAMQ4I.mjs} +119 -22
- package/lib/browser/chunk-7BTAMQ4I.mjs.map +1 -0
- package/lib/browser/{chunk-VRKVKT62.js → chunk-EJYZ4HR3.js} +6 -6
- package/lib/browser/chunk-EJYZ4HR3.js.map +1 -0
- package/lib/browser/{chunk-6MBJUL74.js → chunk-TPZUQHHY.js} +5 -5
- package/lib/browser/{chunk-NU2MPFD6.mjs → chunk-W7UG7MBM.mjs} +2 -2
- package/lib/browser/{chunk-LERABB57.js → chunk-YP3NI6UP.js} +121 -24
- package/lib/browser/chunk-YP3NI6UP.js.map +1 -0
- package/lib/browser/interceptors/XMLHttpRequest/index.js +3 -3
- package/lib/browser/interceptors/XMLHttpRequest/index.mjs +2 -2
- package/lib/browser/interceptors/fetch/index.js +3 -3
- package/lib/browser/interceptors/fetch/index.mjs +2 -2
- package/lib/browser/presets/browser.js +5 -5
- package/lib/browser/presets/browser.mjs +3 -3
- package/lib/node/RemoteHttpInterceptor.js +7 -7
- package/lib/node/RemoteHttpInterceptor.mjs +3 -3
- package/lib/node/{chunk-RJGP7FQP.mjs → chunk-3ROKKA34.mjs} +119 -22
- package/lib/node/chunk-3ROKKA34.mjs.map +1 -0
- package/lib/node/{chunk-I57YSVAV.js → chunk-CQAXV6QM.js} +5 -5
- package/lib/node/{chunk-RTGLFNO3.mjs → chunk-GILG336Y.mjs} +2 -2
- package/lib/node/{chunk-T34TGCMR.js → chunk-MFGG7XIP.js} +121 -24
- package/lib/node/chunk-MFGG7XIP.js.map +1 -0
- package/lib/node/{chunk-5WWNCLB3.js → chunk-TQD7SQGP.js} +6 -6
- package/lib/node/chunk-TQD7SQGP.js.map +1 -0
- package/lib/node/{chunk-UN335ZTD.js → chunk-W4AQXISM.js} +5 -5
- package/lib/node/{chunk-DCMEIPZN.mjs → chunk-WCTY6JTP.mjs} +2 -2
- package/lib/node/{chunk-KY3RJ2M3.mjs → chunk-XSXCGXEY.mjs} +6 -6
- package/lib/node/chunk-XSXCGXEY.mjs.map +1 -0
- package/lib/node/interceptors/ClientRequest/index.js +3 -3
- package/lib/node/interceptors/ClientRequest/index.mjs +2 -2
- package/lib/node/interceptors/XMLHttpRequest/index.js +3 -3
- package/lib/node/interceptors/XMLHttpRequest/index.mjs +2 -2
- package/lib/node/interceptors/fetch/index.js +3 -3
- package/lib/node/interceptors/fetch/index.mjs +2 -2
- package/lib/node/presets/node.js +7 -7
- package/lib/node/presets/node.mjs +4 -4
- package/package.json +3 -1
- package/src/interceptors/XMLHttpRequest/XMLHttpRequestController.ts +159 -16
- package/src/interceptors/XMLHttpRequest/XMLHttpRequestProxy.ts +2 -2
- package/src/interceptors/XMLHttpRequest/polyfills/EventPolyfill.ts +4 -4
- package/src/interceptors/XMLHttpRequest/utils/createEvent.ts +1 -1
- package/src/utils/handleRequest.ts +6 -6
- package/lib/browser/chunk-7A4UJNSW.mjs.map +0 -1
- package/lib/browser/chunk-LERABB57.js.map +0 -1
- package/lib/browser/chunk-VRKVKT62.js.map +0 -1
- package/lib/browser/chunk-ZXJSL23E.mjs.map +0 -1
- package/lib/node/chunk-5WWNCLB3.js.map +0 -1
- package/lib/node/chunk-KY3RJ2M3.mjs.map +0 -1
- package/lib/node/chunk-RJGP7FQP.mjs.map +0 -1
- package/lib/node/chunk-T34TGCMR.js.map +0 -1
- /package/lib/browser/{chunk-6MBJUL74.js.map → chunk-TPZUQHHY.js.map} +0 -0
- /package/lib/browser/{chunk-NU2MPFD6.mjs.map → chunk-W7UG7MBM.mjs.map} +0 -0
- /package/lib/node/{chunk-I57YSVAV.js.map → chunk-CQAXV6QM.js.map} +0 -0
- /package/lib/node/{chunk-RTGLFNO3.mjs.map → chunk-GILG336Y.mjs.map} +0 -0
- /package/lib/node/{chunk-UN335ZTD.js.map → chunk-W4AQXISM.js.map} +0 -0
- /package/lib/node/{chunk-DCMEIPZN.mjs.map → chunk-WCTY6JTP.mjs.map} +0 -0
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
"use strict";Object.defineProperty(exports, "__esModule", {value: true});
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var _chunkMFGG7XIPjs = require('../../chunk-MFGG7XIP.js');
|
|
4
4
|
require('../../chunk-LK6DILFK.js');
|
|
5
5
|
require('../../chunk-IDEEMJ3F.js');
|
|
6
|
-
require('../../chunk-
|
|
6
|
+
require('../../chunk-TQD7SQGP.js');
|
|
7
7
|
require('../../chunk-YGM3BCJU.js');
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
exports.XMLHttpRequestInterceptor =
|
|
10
|
+
exports.XMLHttpRequestInterceptor = _chunkMFGG7XIPjs.XMLHttpRequestInterceptor;
|
|
11
11
|
//# sourceMappingURL=index.js.map
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
XMLHttpRequestInterceptor
|
|
3
|
-
} from "../../chunk-
|
|
3
|
+
} from "../../chunk-3ROKKA34.mjs";
|
|
4
4
|
import "../../chunk-6HYIRFX2.mjs";
|
|
5
5
|
import "../../chunk-BZ3Y7YV5.mjs";
|
|
6
|
-
import "../../chunk-
|
|
6
|
+
import "../../chunk-XSXCGXEY.mjs";
|
|
7
7
|
import "../../chunk-BUCULLYM.mjs";
|
|
8
8
|
export {
|
|
9
9
|
XMLHttpRequestInterceptor
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
"use strict";Object.defineProperty(exports, "__esModule", {value: true});
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var _chunkW4AQXISMjs = require('../../chunk-W4AQXISM.js');
|
|
4
4
|
require('../../chunk-IDEEMJ3F.js');
|
|
5
|
-
require('../../chunk-
|
|
5
|
+
require('../../chunk-TQD7SQGP.js');
|
|
6
6
|
require('../../chunk-YGM3BCJU.js');
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
exports.FetchInterceptor =
|
|
9
|
+
exports.FetchInterceptor = _chunkW4AQXISMjs.FetchInterceptor;
|
|
10
10
|
//# sourceMappingURL=index.js.map
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
FetchInterceptor
|
|
3
|
-
} from "../../chunk-
|
|
3
|
+
} from "../../chunk-GILG336Y.mjs";
|
|
4
4
|
import "../../chunk-BZ3Y7YV5.mjs";
|
|
5
|
-
import "../../chunk-
|
|
5
|
+
import "../../chunk-XSXCGXEY.mjs";
|
|
6
6
|
import "../../chunk-BUCULLYM.mjs";
|
|
7
7
|
export {
|
|
8
8
|
FetchInterceptor
|
package/lib/node/presets/node.js
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
"use strict";Object.defineProperty(exports, "__esModule", {value: true});
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var _chunkCQAXV6QMjs = require('../chunk-CQAXV6QM.js');
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
var
|
|
6
|
+
var _chunkMFGG7XIPjs = require('../chunk-MFGG7XIP.js');
|
|
7
7
|
require('../chunk-LK6DILFK.js');
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
var
|
|
10
|
+
var _chunkW4AQXISMjs = require('../chunk-W4AQXISM.js');
|
|
11
11
|
require('../chunk-IDEEMJ3F.js');
|
|
12
|
-
require('../chunk-
|
|
12
|
+
require('../chunk-TQD7SQGP.js');
|
|
13
13
|
require('../chunk-YGM3BCJU.js');
|
|
14
14
|
|
|
15
15
|
// src/presets/node.ts
|
|
16
16
|
var node_default = [
|
|
17
|
-
new (0,
|
|
18
|
-
new (0,
|
|
19
|
-
new (0,
|
|
17
|
+
new (0, _chunkCQAXV6QMjs.ClientRequestInterceptor)(),
|
|
18
|
+
new (0, _chunkMFGG7XIPjs.XMLHttpRequestInterceptor)(),
|
|
19
|
+
new (0, _chunkW4AQXISMjs.FetchInterceptor)()
|
|
20
20
|
];
|
|
21
21
|
|
|
22
22
|
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ClientRequestInterceptor
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-WCTY6JTP.mjs";
|
|
4
4
|
import {
|
|
5
5
|
XMLHttpRequestInterceptor
|
|
6
|
-
} from "../chunk-
|
|
6
|
+
} from "../chunk-3ROKKA34.mjs";
|
|
7
7
|
import "../chunk-6HYIRFX2.mjs";
|
|
8
8
|
import {
|
|
9
9
|
FetchInterceptor
|
|
10
|
-
} from "../chunk-
|
|
10
|
+
} from "../chunk-GILG336Y.mjs";
|
|
11
11
|
import "../chunk-BZ3Y7YV5.mjs";
|
|
12
|
-
import "../chunk-
|
|
12
|
+
import "../chunk-XSXCGXEY.mjs";
|
|
13
13
|
import "../chunk-BUCULLYM.mjs";
|
|
14
14
|
|
|
15
15
|
// src/presets/node.ts
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mswjs/interceptors",
|
|
3
3
|
"description": "Low-level HTTP/HTTPS/XHR/fetch request interception library.",
|
|
4
|
-
"version": "0.34.
|
|
4
|
+
"version": "0.34.2",
|
|
5
5
|
"main": "./lib/node/index.js",
|
|
6
6
|
"module": "./lib/node/index.mjs",
|
|
7
7
|
"types": "./lib/node/index.d.ts",
|
|
@@ -117,6 +117,7 @@
|
|
|
117
117
|
"@playwright/test": "^1.37.1",
|
|
118
118
|
"@types/cors": "^2.8.12",
|
|
119
119
|
"@types/express": "^4.17.13",
|
|
120
|
+
"@types/express-fileupload": "^1.5.0",
|
|
120
121
|
"@types/express-rate-limit": "^6.0.0",
|
|
121
122
|
"@types/follow-redirects": "^1.14.1",
|
|
122
123
|
"@types/jest": "^27.0.3",
|
|
@@ -132,6 +133,7 @@
|
|
|
132
133
|
"cz-conventional-changelog": "3.3.0",
|
|
133
134
|
"engine.io-parser": "^5.2.1",
|
|
134
135
|
"express": "^4.17.3",
|
|
136
|
+
"express-fileupload": "^1.5.1",
|
|
135
137
|
"express-rate-limit": "^6.3.0",
|
|
136
138
|
"follow-redirects": "^1.15.1",
|
|
137
139
|
"got": "^11.8.3",
|
|
@@ -48,9 +48,14 @@ export class XMLHttpRequestController {
|
|
|
48
48
|
private requestBody?: XMLHttpRequestBodyInit | Document | null
|
|
49
49
|
private responseBuffer: Uint8Array
|
|
50
50
|
private events: Map<keyof XMLHttpRequestEventTargetEventMap, Array<Function>>
|
|
51
|
+
private uploadEvents: Map<
|
|
52
|
+
keyof XMLHttpRequestEventTargetEventMap,
|
|
53
|
+
Array<Function>
|
|
54
|
+
>
|
|
51
55
|
|
|
52
56
|
constructor(readonly initialRequest: XMLHttpRequest, public logger: Logger) {
|
|
53
57
|
this.events = new Map()
|
|
58
|
+
this.uploadEvents = new Map()
|
|
54
59
|
this.requestId = createRequestId()
|
|
55
60
|
this.requestHeaders = new Headers()
|
|
56
61
|
this.responseBuffer = new Uint8Array()
|
|
@@ -200,6 +205,49 @@ export class XMLHttpRequestController {
|
|
|
200
205
|
}
|
|
201
206
|
},
|
|
202
207
|
})
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Proxy the `.upload` property to gather the event listeners/callbacks.
|
|
211
|
+
*/
|
|
212
|
+
define(
|
|
213
|
+
this.request,
|
|
214
|
+
'upload',
|
|
215
|
+
createProxy(this.request.upload, {
|
|
216
|
+
setProperty: ([propertyName, nextValue], invoke) => {
|
|
217
|
+
switch (propertyName) {
|
|
218
|
+
case 'onloadstart':
|
|
219
|
+
case 'onprogress':
|
|
220
|
+
case 'onaboart':
|
|
221
|
+
case 'onerror':
|
|
222
|
+
case 'onload':
|
|
223
|
+
case 'ontimeout':
|
|
224
|
+
case 'onloadend': {
|
|
225
|
+
const eventName = propertyName.slice(
|
|
226
|
+
2
|
|
227
|
+
) as keyof XMLHttpRequestEventTargetEventMap
|
|
228
|
+
|
|
229
|
+
this.registerUploadEvent(eventName, nextValue as Function)
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return invoke()
|
|
234
|
+
},
|
|
235
|
+
methodCall: ([methodName, args], invoke) => {
|
|
236
|
+
switch (methodName) {
|
|
237
|
+
case 'addEventListener': {
|
|
238
|
+
const [eventName, listener] = args as [
|
|
239
|
+
keyof XMLHttpRequestEventTargetEventMap,
|
|
240
|
+
Function
|
|
241
|
+
]
|
|
242
|
+
this.registerUploadEvent(eventName, listener)
|
|
243
|
+
this.logger.info('upload.addEventListener', eventName, listener)
|
|
244
|
+
|
|
245
|
+
return invoke()
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
},
|
|
249
|
+
})
|
|
250
|
+
)
|
|
203
251
|
}
|
|
204
252
|
|
|
205
253
|
private registerEvent(
|
|
@@ -213,11 +261,52 @@ export class XMLHttpRequestController {
|
|
|
213
261
|
this.logger.info('registered event "%s"', eventName, listener)
|
|
214
262
|
}
|
|
215
263
|
|
|
264
|
+
private registerUploadEvent(
|
|
265
|
+
eventName: keyof XMLHttpRequestEventTargetEventMap,
|
|
266
|
+
listener: Function
|
|
267
|
+
): void {
|
|
268
|
+
const prevEvents = this.uploadEvents.get(eventName) || []
|
|
269
|
+
const nextEvents = prevEvents.concat(listener)
|
|
270
|
+
this.uploadEvents.set(eventName, nextEvents)
|
|
271
|
+
|
|
272
|
+
this.logger.info('registered upload event "%s"', eventName, listener)
|
|
273
|
+
}
|
|
274
|
+
|
|
216
275
|
/**
|
|
217
276
|
* Responds to the current request with the given
|
|
218
277
|
* Fetch API `Response` instance.
|
|
219
278
|
*/
|
|
220
|
-
public respondWith(response: Response): void {
|
|
279
|
+
public async respondWith(response: Response): Promise<void> {
|
|
280
|
+
/**
|
|
281
|
+
* Dispatch request upload events for requests with a body.
|
|
282
|
+
* @see https://github.com/mswjs/interceptors/issues/573
|
|
283
|
+
*/
|
|
284
|
+
if (this.requestBody != null) {
|
|
285
|
+
const totalRequestBodyLength = this.requestHeaders.has('content-length')
|
|
286
|
+
? Number(this.requestHeaders.get('content-length'))
|
|
287
|
+
: await getXMLHttpRequestBodyInitLength(
|
|
288
|
+
this.requestBody,
|
|
289
|
+
this.requestHeaders
|
|
290
|
+
)
|
|
291
|
+
|
|
292
|
+
this.trigger('loadstart', this.request.upload, {
|
|
293
|
+
loaded: 0,
|
|
294
|
+
total: totalRequestBodyLength,
|
|
295
|
+
})
|
|
296
|
+
this.trigger('progress', this.request.upload, {
|
|
297
|
+
loaded: totalRequestBodyLength,
|
|
298
|
+
total: totalRequestBodyLength,
|
|
299
|
+
})
|
|
300
|
+
this.trigger('load', this.request.upload, {
|
|
301
|
+
loaded: totalRequestBodyLength,
|
|
302
|
+
total: totalRequestBodyLength,
|
|
303
|
+
})
|
|
304
|
+
this.trigger('loadend', this.request.upload, {
|
|
305
|
+
loaded: totalRequestBodyLength,
|
|
306
|
+
total: totalRequestBodyLength,
|
|
307
|
+
})
|
|
308
|
+
}
|
|
309
|
+
|
|
221
310
|
this.logger.info(
|
|
222
311
|
'responding with a mocked response: %d %s',
|
|
223
312
|
response.status,
|
|
@@ -303,7 +392,7 @@ export class XMLHttpRequestController {
|
|
|
303
392
|
},
|
|
304
393
|
})
|
|
305
394
|
|
|
306
|
-
const totalResponseBodyLength = response.headers.has('
|
|
395
|
+
const totalResponseBodyLength = response.headers.has('content-length')
|
|
307
396
|
? Number(response.headers.get('Content-Length'))
|
|
308
397
|
: /**
|
|
309
398
|
* @todo Infer the response body length from the response body.
|
|
@@ -312,7 +401,7 @@ export class XMLHttpRequestController {
|
|
|
312
401
|
|
|
313
402
|
this.logger.info('calculated response body length', totalResponseBodyLength)
|
|
314
403
|
|
|
315
|
-
this.trigger('loadstart', {
|
|
404
|
+
this.trigger('loadstart', this.request, {
|
|
316
405
|
loaded: 0,
|
|
317
406
|
total: totalResponseBodyLength,
|
|
318
407
|
})
|
|
@@ -325,12 +414,12 @@ export class XMLHttpRequestController {
|
|
|
325
414
|
|
|
326
415
|
this.setReadyState(this.request.DONE)
|
|
327
416
|
|
|
328
|
-
this.trigger('load', {
|
|
417
|
+
this.trigger('load', this.request, {
|
|
329
418
|
loaded: this.responseBuffer.byteLength,
|
|
330
419
|
total: totalResponseBodyLength,
|
|
331
420
|
})
|
|
332
421
|
|
|
333
|
-
this.trigger('loadend', {
|
|
422
|
+
this.trigger('loadend', this.request, {
|
|
334
423
|
loaded: this.responseBuffer.byteLength,
|
|
335
424
|
total: totalResponseBodyLength,
|
|
336
425
|
})
|
|
@@ -354,7 +443,7 @@ export class XMLHttpRequestController {
|
|
|
354
443
|
this.logger.info('read response body chunk:', value)
|
|
355
444
|
this.responseBuffer = concatArrayBuffer(this.responseBuffer, value)
|
|
356
445
|
|
|
357
|
-
this.trigger('progress', {
|
|
446
|
+
this.trigger('progress', this.request, {
|
|
358
447
|
loaded: this.responseBuffer.byteLength,
|
|
359
448
|
total: totalResponseBodyLength,
|
|
360
449
|
})
|
|
@@ -485,8 +574,8 @@ export class XMLHttpRequestController {
|
|
|
485
574
|
this.logger.info('responding with an error')
|
|
486
575
|
|
|
487
576
|
this.setReadyState(this.request.DONE)
|
|
488
|
-
this.trigger('error')
|
|
489
|
-
this.trigger('loadend')
|
|
577
|
+
this.trigger('error', this.request)
|
|
578
|
+
this.trigger('loadend', this.request)
|
|
490
579
|
}
|
|
491
580
|
|
|
492
581
|
/**
|
|
@@ -511,7 +600,7 @@ export class XMLHttpRequestController {
|
|
|
511
600
|
if (nextReadyState !== this.request.UNSENT) {
|
|
512
601
|
this.logger.info('triggerring "readystatechange" event...')
|
|
513
602
|
|
|
514
|
-
this.trigger('readystatechange')
|
|
603
|
+
this.trigger('readystatechange', this.request)
|
|
515
604
|
}
|
|
516
605
|
}
|
|
517
606
|
|
|
@@ -522,20 +611,27 @@ export class XMLHttpRequestController {
|
|
|
522
611
|
EventName extends keyof (XMLHttpRequestEventTargetEventMap & {
|
|
523
612
|
readystatechange: ProgressEvent<XMLHttpRequestEventTarget>
|
|
524
613
|
})
|
|
525
|
-
>(
|
|
526
|
-
|
|
527
|
-
|
|
614
|
+
>(
|
|
615
|
+
eventName: EventName,
|
|
616
|
+
target: XMLHttpRequest | XMLHttpRequestUpload,
|
|
617
|
+
options?: ProgressEventInit
|
|
618
|
+
): void {
|
|
619
|
+
const callback = (target as XMLHttpRequest)[`on${eventName}`]
|
|
620
|
+
const event = createEvent(target, eventName, options)
|
|
528
621
|
|
|
529
622
|
this.logger.info('trigger "%s"', eventName, options || '')
|
|
530
623
|
|
|
531
624
|
// Invoke direct callbacks.
|
|
532
625
|
if (typeof callback === 'function') {
|
|
533
626
|
this.logger.info('found a direct "%s" callback, calling...', eventName)
|
|
534
|
-
callback.call(
|
|
627
|
+
callback.call(target as XMLHttpRequest, event)
|
|
535
628
|
}
|
|
536
629
|
|
|
537
630
|
// Invoke event listeners.
|
|
538
|
-
|
|
631
|
+
const events =
|
|
632
|
+
target instanceof XMLHttpRequestUpload ? this.uploadEvents : this.events
|
|
633
|
+
|
|
634
|
+
for (const [registeredEventName, listeners] of events) {
|
|
539
635
|
if (registeredEventName === eventName) {
|
|
540
636
|
this.logger.info(
|
|
541
637
|
'found %d listener(s) for "%s" event, calling...',
|
|
@@ -543,7 +639,7 @@ export class XMLHttpRequestController {
|
|
|
543
639
|
eventName
|
|
544
640
|
)
|
|
545
641
|
|
|
546
|
-
listeners.forEach((listener) => listener.call(
|
|
642
|
+
listeners.forEach((listener) => listener.call(target, event))
|
|
547
643
|
}
|
|
548
644
|
}
|
|
549
645
|
}
|
|
@@ -551,7 +647,7 @@ export class XMLHttpRequestController {
|
|
|
551
647
|
/**
|
|
552
648
|
* Converts this `XMLHttpRequest` instance into a Fetch API `Request` instance.
|
|
553
649
|
*/
|
|
554
|
-
|
|
650
|
+
private toFetchApiRequest(): Request {
|
|
555
651
|
this.logger.info('converting request to a Fetch API Request...')
|
|
556
652
|
|
|
557
653
|
const fetchRequest = new Request(this.url.href, {
|
|
@@ -626,3 +722,50 @@ function define(
|
|
|
626
722
|
value,
|
|
627
723
|
})
|
|
628
724
|
}
|
|
725
|
+
|
|
726
|
+
async function getXMLHttpRequestBodyInitLength(
|
|
727
|
+
body: XMLHttpRequestBodyInit | Document,
|
|
728
|
+
headers: Headers
|
|
729
|
+
): Promise<number> {
|
|
730
|
+
if (typeof body === 'object' && 'byteLength' in body) {
|
|
731
|
+
return body.byteLength
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
if (body instanceof Blob) {
|
|
735
|
+
return body.size
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
if (body instanceof FormData) {
|
|
739
|
+
const lines: Array<string> = []
|
|
740
|
+
const contentType =
|
|
741
|
+
headers.get('content-type') || 'application/octet-stream'
|
|
742
|
+
|
|
743
|
+
for (const [name, entry] of body) {
|
|
744
|
+
lines.push(`------WebKitFormBoundary1234567890123456`)
|
|
745
|
+
lines.push(`content-type: ${contentType}`)
|
|
746
|
+
|
|
747
|
+
if (typeof entry === 'string') {
|
|
748
|
+
lines.push(`content-disposition: form-data; name="${name}"`)
|
|
749
|
+
lines.push(``)
|
|
750
|
+
lines.push(entry)
|
|
751
|
+
} else {
|
|
752
|
+
lines.push(
|
|
753
|
+
`content-disposition: form-data; name="${name}"; filename="${entry.name}"`
|
|
754
|
+
)
|
|
755
|
+
lines.push(``)
|
|
756
|
+
lines.push(await entry.text())
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
lines.push('------WebKitFormBoundary1234567890123456--')
|
|
761
|
+
lines.push(``)
|
|
762
|
+
|
|
763
|
+
return lines.join('\r\n').length
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
if (body instanceof Document) {
|
|
767
|
+
return body.documentElement.innerHTML.length
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
return body.toString().length
|
|
771
|
+
}
|
|
@@ -66,8 +66,8 @@ export function createXMLHttpRequestProxy({
|
|
|
66
66
|
requestId,
|
|
67
67
|
controller,
|
|
68
68
|
emitter,
|
|
69
|
-
onResponse: (response) => {
|
|
70
|
-
this.respondWith(response)
|
|
69
|
+
onResponse: async (response) => {
|
|
70
|
+
await this.respondWith(response)
|
|
71
71
|
},
|
|
72
72
|
onRequestError: () => {
|
|
73
73
|
this.errorWith(new TypeError('Network error'))
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
export class EventPolyfill implements Event {
|
|
2
|
-
readonly
|
|
3
|
-
readonly
|
|
4
|
-
readonly
|
|
5
|
-
readonly
|
|
2
|
+
readonly NONE = 0
|
|
3
|
+
readonly CAPTURING_PHASE = 1
|
|
4
|
+
readonly AT_TARGET = 2
|
|
5
|
+
readonly BUBBLING_PHASE = 3
|
|
6
6
|
|
|
7
7
|
public type: string = ''
|
|
8
8
|
public srcElement: EventTarget | null = null
|
|
@@ -4,7 +4,7 @@ import { ProgressEventPolyfill } from '../polyfills/ProgressEventPolyfill'
|
|
|
4
4
|
const SUPPORTS_PROGRESS_EVENT = typeof ProgressEvent !== 'undefined'
|
|
5
5
|
|
|
6
6
|
export function createEvent(
|
|
7
|
-
target: XMLHttpRequest,
|
|
7
|
+
target: XMLHttpRequest | XMLHttpRequestUpload,
|
|
8
8
|
type: string,
|
|
9
9
|
init?: ProgressEventInit
|
|
10
10
|
): EventPolyfill {
|
|
@@ -22,7 +22,7 @@ interface HandleRequestOptions {
|
|
|
22
22
|
* Called when the request has been handled
|
|
23
23
|
* with the given `Response` instance.
|
|
24
24
|
*/
|
|
25
|
-
onResponse: (response: Response) => void
|
|
25
|
+
onResponse: (response: Response) => void | Promise<void>
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
28
|
* Called when the request has been handled
|
|
@@ -43,7 +43,7 @@ interface HandleRequestOptions {
|
|
|
43
43
|
export async function handleRequest(
|
|
44
44
|
options: HandleRequestOptions
|
|
45
45
|
): Promise<boolean> {
|
|
46
|
-
const handleResponse = (response: Response | Error)
|
|
46
|
+
const handleResponse = async (response: Response | Error) => {
|
|
47
47
|
if (response instanceof Error) {
|
|
48
48
|
options.onError(response)
|
|
49
49
|
}
|
|
@@ -52,13 +52,13 @@ export async function handleRequest(
|
|
|
52
52
|
else if (isResponseError(response)) {
|
|
53
53
|
options.onRequestError(response)
|
|
54
54
|
} else {
|
|
55
|
-
options.onResponse(response)
|
|
55
|
+
await options.onResponse(response)
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
return true
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
const handleResponseError = (error: unknown): boolean => {
|
|
61
|
+
const handleResponseError = async (error: unknown): Promise<boolean> => {
|
|
62
62
|
// Forward the special interceptor error instances
|
|
63
63
|
// to the developer. These must not be handled in any way.
|
|
64
64
|
if (error instanceof InterceptorError) {
|
|
@@ -73,7 +73,7 @@ export async function handleRequest(
|
|
|
73
73
|
|
|
74
74
|
// Handle thrown responses.
|
|
75
75
|
if (error instanceof Response) {
|
|
76
|
-
return handleResponse(error)
|
|
76
|
+
return await handleResponse(error)
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
return false
|
|
@@ -140,7 +140,7 @@ export async function handleRequest(
|
|
|
140
140
|
if (result.error) {
|
|
141
141
|
// Handle the error during the request listener execution.
|
|
142
142
|
// These can be thrown responses or request errors.
|
|
143
|
-
if (handleResponseError(result.error)) {
|
|
143
|
+
if (await handleResponseError(result.error)) {
|
|
144
144
|
return true
|
|
145
145
|
}
|
|
146
146
|
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/RequestController.ts","../../src/InterceptorError.ts","../../src/utils/emitAsync.ts","../../src/utils/handleRequest.ts","../../src/utils/isNodeLikeError.ts"],"sourcesContent":["import { invariant } from 'outvariant'\nimport { DeferredPromise } from '@open-draft/deferred-promise'\nimport { InterceptorError } from './InterceptorError'\n\nconst kRequestHandled = Symbol('kRequestHandled')\nexport const kResponsePromise = Symbol('kResponsePromise')\n\nexport class RequestController {\n /**\n * Internal response promise.\n * Available only for the library internals to grab the\n * response instance provided by the developer.\n * @note This promise cannot be rejected. It's either infinitely\n * pending or resolved with whichever Response was passed to `respondWith()`.\n */\n [kResponsePromise]: DeferredPromise<Response | Error | undefined>;\n\n /**\n * Internal flag indicating if this request has been handled.\n * @note The response promise becomes \"fulfilled\" on the next tick.\n */\n [kRequestHandled]: boolean\n\n constructor(private request: Request) {\n this[kRequestHandled] = false\n this[kResponsePromise] = new DeferredPromise()\n }\n\n /**\n * Respond to this request with the given `Response` instance.\n * @example\n * controller.respondWith(new Response())\n * controller.respondWith(Response.json({ id }))\n * controller.respondWith(Response.error())\n */\n public respondWith(response: Response): void {\n invariant.as(\n InterceptorError,\n !this[kRequestHandled],\n 'Failed to respond to the \"%s %s\" request: the \"request\" event has already been handled.',\n this.request.method,\n this.request.url\n )\n\n this[kRequestHandled] = true\n this[kResponsePromise].resolve(response)\n\n /**\n * @note The request conrtoller doesn't do anything\n * apart from letting the interceptor await the response\n * provided by the developer through the response promise.\n * Each interceptor implements the actual respondWith/errorWith\n * logic based on that interceptor's needs.\n */\n }\n\n /**\n * Error this request with the given error.\n * @example\n * controller.errorWith()\n * controller.errorWith(new Error('Oops!'))\n */\n public errorWith(error?: Error): void {\n invariant.as(\n InterceptorError,\n !this[kRequestHandled],\n 'Failed to error the \"%s %s\" request: the \"request\" event has already been handled.',\n this.request.method,\n this.request.url\n )\n\n this[kRequestHandled] = true\n\n /**\n * @note Resolve the response promise, not reject.\n * This helps us differentiate between unhandled exceptions\n * and intended errors (\"errorWith\") while waiting for the response.\n */\n this[kResponsePromise].resolve(error)\n }\n}\n","export class InterceptorError extends Error {\n constructor(message?: string) {\n super(message)\n this.name = 'InterceptorError'\n Object.setPrototypeOf(this, InterceptorError.prototype)\n }\n}\n","import { Emitter, EventMap } from 'strict-event-emitter'\n\n/**\n * Emits an event on the given emitter but executes\n * the listeners sequentially. This accounts for asynchronous\n * listeners (e.g. those having \"sleep\" and handling the request).\n */\nexport async function emitAsync<\n Events extends EventMap,\n EventName extends keyof Events\n>(\n emitter: Emitter<Events>,\n eventName: EventName,\n ...data: Events[EventName]\n): Promise<void> {\n const listners = emitter.listeners(eventName)\n\n if (listners.length === 0) {\n return\n }\n\n for (const listener of listners) {\n await listener.apply(emitter, data)\n }\n}\n","import type { Emitter } from 'strict-event-emitter'\nimport { DeferredPromise } from '@open-draft/deferred-promise'\nimport { until } from '@open-draft/until'\nimport type { HttpRequestEventMap } from '../glossary'\nimport { emitAsync } from './emitAsync'\nimport { kResponsePromise, RequestController } from '../RequestController'\nimport {\n createServerErrorResponse,\n isResponseError,\n ResponseError,\n} from './responseUtils'\nimport { InterceptorError } from '../InterceptorError'\nimport { isNodeLikeError } from './isNodeLikeError'\n\ninterface HandleRequestOptions {\n requestId: string\n request: Request\n emitter: Emitter<HttpRequestEventMap>\n controller: RequestController\n\n /**\n * Called when the request has been handled\n * with the given `Response` instance.\n */\n onResponse: (response: Response) => void\n\n /**\n * Called when the request has been handled\n * with the given `Response.error()` instance.\n */\n onRequestError: (response: ResponseError) => void\n\n /**\n * Called when an unhandled error happens during the\n * request handling. This is never a thrown error/response.\n */\n onError: (error: unknown) => void\n}\n\n/**\n * @returns {Promise<boolean>} Indicates whether the request has been handled.\n */\nexport async function handleRequest(\n options: HandleRequestOptions\n): Promise<boolean> {\n const handleResponse = (response: Response | Error): true => {\n if (response instanceof Error) {\n options.onError(response)\n }\n\n // Handle \"Response.error()\" instances.\n else if (isResponseError(response)) {\n options.onRequestError(response)\n } else {\n options.onResponse(response)\n }\n\n return true\n }\n\n const handleResponseError = (error: unknown): boolean => {\n // Forward the special interceptor error instances\n // to the developer. These must not be handled in any way.\n if (error instanceof InterceptorError) {\n throw result.error\n }\n\n // Support mocking Node.js-like errors.\n if (isNodeLikeError(error)) {\n options.onError(error)\n return true\n }\n\n // Handle thrown responses.\n if (error instanceof Response) {\n return handleResponse(error)\n }\n\n return false\n }\n\n // Add the last \"request\" listener to check if the request\n // has been handled in any way. If it hasn't, resolve the\n // response promise with undefined.\n options.emitter.once('request', ({ requestId: pendingRequestId }) => {\n if (pendingRequestId !== options.requestId) {\n return\n }\n\n if (options.controller[kResponsePromise].state === 'pending') {\n options.controller[kResponsePromise].resolve(undefined)\n }\n })\n\n const requestAbortPromise = new DeferredPromise<void, unknown>()\n\n /**\n * @note `signal` is not always defined in React Native.\n */\n if (options.request.signal) {\n options.request.signal.addEventListener(\n 'abort',\n () => {\n requestAbortPromise.reject(options.request.signal.reason)\n },\n { once: true }\n )\n }\n\n const result = await until(async () => {\n // Emit the \"request\" event and wait until all the listeners\n // for that event are finished (e.g. async listeners awaited).\n // By the end of this promise, the developer cannot affect the\n // request anymore.\n const requestListtenersPromise = emitAsync(options.emitter, 'request', {\n requestId: options.requestId,\n request: options.request,\n controller: options.controller,\n })\n\n await Promise.race([\n // Short-circuit the request handling promise if the request gets aborted.\n requestAbortPromise,\n requestListtenersPromise,\n options.controller[kResponsePromise],\n ])\n\n // The response promise will settle immediately once\n // the developer calls either \"respondWith\" or \"errorWith\".\n const mockedResponse = await options.controller[kResponsePromise]\n return mockedResponse\n })\n\n // Handle the request being aborted while waiting for the request listeners.\n if (requestAbortPromise.state === 'rejected') {\n options.onError(requestAbortPromise.rejectionReason)\n return true\n }\n\n if (result.error) {\n // Handle the error during the request listener execution.\n // These can be thrown responses or request errors.\n if (handleResponseError(result.error)) {\n return true\n }\n\n // If the developer has added \"unhandledException\" listeners,\n // allow them to handle the error. They can translate it to a\n // mocked response, network error, or forward it as-is.\n if (options.emitter.listenerCount('unhandledException') > 0) {\n // Create a new request controller just for the unhandled exception case.\n // This is needed because the original controller might have been already\n // interacted with (e.g. \"respondWith\" or \"errorWith\" called on it).\n const unhandledExceptionController = new RequestController(\n options.request\n )\n\n await emitAsync(options.emitter, 'unhandledException', {\n error: result.error,\n request: options.request,\n requestId: options.requestId,\n controller: unhandledExceptionController,\n }).then(() => {\n // If all the \"unhandledException\" listeners have finished\n // but have not handled the response in any way, preemptively\n // resolve the pending response promise from the new controller.\n // This prevents it from hanging forever.\n if (\n unhandledExceptionController[kResponsePromise].state === 'pending'\n ) {\n unhandledExceptionController[kResponsePromise].resolve(undefined)\n }\n })\n\n const nextResult = await until(\n () => unhandledExceptionController[kResponsePromise]\n )\n\n /**\n * @note Handle the result of the unhandled controller\n * in the same way as the original request controller.\n * The exception here is that thrown errors within the\n * \"unhandledException\" event do NOT result in another\n * emit of the same event. They are forwarded as-is.\n */\n if (nextResult.error) {\n return handleResponseError(nextResult.error)\n }\n\n if (nextResult.data) {\n return handleResponse(nextResult.data)\n }\n }\n\n // Otherwise, coerce unhandled exceptions to a 500 Internal Server Error response.\n options.onResponse(createServerErrorResponse(result.error))\n return true\n }\n\n /**\n * Handle a mocked Response instance.\n * @note That this can also be an Error in case\n * the developer called \"errorWith\". This differentiates\n * unhandled exceptions from intended errors.\n */\n if (result.data) {\n return handleResponse(result.data)\n }\n\n // In all other cases, consider the request unhandled.\n // The interceptor must perform it as-is.\n return false\n}\n","export function isNodeLikeError(\n error: unknown\n): error is NodeJS.ErrnoException {\n if (error == null) {\n return false\n }\n\n if (!(error instanceof Error)) {\n return false\n }\n\n return 'code' in error && 'errno' in error\n}\n"],"mappings":"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","names":["DeferredPromise","DeferredPromise"]}
|