@mswjs/interceptors 0.25.1 → 0.25.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.
Files changed (77) hide show
  1. package/lib/browser/Interceptor-8d5fd4c6.d.ts +86 -0
  2. package/lib/browser/{chunk-4CFMDU7Z.js → chunk-CWVY2E3W.js} +20 -134
  3. package/lib/browser/{chunk-VMXB5F2J.mjs → chunk-HXJPKJY3.mjs} +25 -15
  4. package/lib/browser/{chunk-DBFLI5DJ.js → chunk-KITNLK66.js} +30 -20
  5. package/lib/browser/chunk-KK6APRON.mjs +58 -0
  6. package/lib/browser/{chunk-OSIUQA4X.js → chunk-NMG5MQJJ.js} +32 -29
  7. package/lib/browser/{chunk-GXJLJMOT.mjs → chunk-QPMXOLDO.mjs} +21 -135
  8. package/lib/browser/{chunk-ANLPTCZ5.mjs → chunk-TYEVJTWH.mjs} +27 -24
  9. package/lib/browser/chunk-X3NRJIZW.js +58 -0
  10. package/lib/browser/index.d.ts +7 -3
  11. package/lib/browser/index.js +24 -5
  12. package/lib/browser/index.mjs +22 -3
  13. package/lib/browser/interceptors/XMLHttpRequest/index.d.ts +4 -3
  14. package/lib/browser/interceptors/XMLHttpRequest/index.js +4 -4
  15. package/lib/browser/interceptors/XMLHttpRequest/index.mjs +3 -3
  16. package/lib/browser/interceptors/fetch/index.d.ts +2 -1
  17. package/lib/browser/interceptors/fetch/index.js +4 -4
  18. package/lib/browser/interceptors/fetch/index.mjs +3 -3
  19. package/lib/browser/presets/browser.d.ts +2 -1
  20. package/lib/browser/presets/browser.js +6 -6
  21. package/lib/browser/presets/browser.mjs +4 -4
  22. package/lib/node/{BatchInterceptor-c841b068.d.ts → BatchInterceptor-9785c567.d.ts} +5 -2
  23. package/lib/node/Interceptor-7a701c1f.d.ts +86 -0
  24. package/lib/node/RemoteHttpInterceptor.d.ts +3 -2
  25. package/lib/node/RemoteHttpInterceptor.js +18 -18
  26. package/lib/node/RemoteHttpInterceptor.mjs +14 -14
  27. package/lib/node/{chunk-XYZRP5S2.js → chunk-3XFLRXRY.js} +20 -134
  28. package/lib/node/chunk-5PTPJLB7.js +58 -0
  29. package/lib/node/{chunk-E6YC337Q.js → chunk-5YAV7CXX.js} +29 -26
  30. package/lib/node/{chunk-HSCXCLVT.mjs → chunk-7RGC35CC.mjs} +27 -24
  31. package/lib/node/{chunk-3MYUI4B2.js → chunk-B2CIOP5B.js} +22 -16
  32. package/lib/node/{chunk-RGYCLCLK.mjs → chunk-GM3YBSM3.mjs} +21 -135
  33. package/lib/node/{chunk-OL7OR4RL.mjs → chunk-OMRBBJT7.mjs} +20 -14
  34. package/lib/node/{chunk-VS3GJPUE.mjs → chunk-UBEFEZXT.mjs} +22 -3
  35. package/lib/node/{chunk-MVPEJK4V.js → chunk-UF7QIAQ5.js} +23 -4
  36. package/lib/node/chunk-YQGTMMOZ.mjs +58 -0
  37. package/lib/node/index.d.ts +3 -2
  38. package/lib/node/index.js +3 -3
  39. package/lib/node/index.mjs +2 -2
  40. package/lib/node/interceptors/ClientRequest/index.d.ts +4 -3
  41. package/lib/node/interceptors/ClientRequest/index.js +4 -4
  42. package/lib/node/interceptors/ClientRequest/index.mjs +3 -3
  43. package/lib/node/interceptors/XMLHttpRequest/index.d.ts +4 -3
  44. package/lib/node/interceptors/XMLHttpRequest/index.js +4 -4
  45. package/lib/node/interceptors/XMLHttpRequest/index.mjs +3 -3
  46. package/lib/node/interceptors/fetch/index.d.ts +2 -1
  47. package/lib/node/interceptors/fetch/index.js +27 -17
  48. package/lib/node/interceptors/fetch/index.mjs +25 -15
  49. package/lib/node/presets/node.d.ts +3 -2
  50. package/lib/node/presets/node.js +6 -6
  51. package/lib/node/presets/node.mjs +4 -4
  52. package/package.json +1 -1
  53. package/src/BatchInterceptor.test.ts +141 -0
  54. package/src/BatchInterceptor.ts +38 -4
  55. package/src/Interceptor.test.ts +46 -0
  56. package/src/Interceptor.ts +35 -16
  57. package/src/RemoteHttpInterceptor.ts +11 -9
  58. package/src/interceptors/ClientRequest/NodeClientRequest.test.ts +10 -10
  59. package/src/interceptors/ClientRequest/NodeClientRequest.ts +35 -18
  60. package/src/interceptors/ClientRequest/index.test.ts +2 -3
  61. package/src/interceptors/ClientRequest/index.ts +2 -2
  62. package/src/interceptors/ClientRequest/utils/createRequest.test.ts +2 -2
  63. package/src/interceptors/XMLHttpRequest/XMLHttpRequestProxy.ts +29 -25
  64. package/src/interceptors/XMLHttpRequest/index.ts +2 -2
  65. package/src/interceptors/fetch/index.ts +26 -13
  66. package/src/utils/RequestController.ts +21 -0
  67. package/src/utils/emitAsync.ts +25 -0
  68. package/src/utils/toInteractiveRequest.ts +17 -23
  69. package/lib/browser/Interceptor-0a020bc4.d.ts +0 -116
  70. package/lib/browser/chunk-PCFJD76X.js +0 -64
  71. package/lib/browser/chunk-RT3ATOJH.mjs +0 -64
  72. package/lib/node/Interceptor-738f79c5.d.ts +0 -116
  73. package/lib/node/chunk-STA6QBYM.mjs +0 -64
  74. package/lib/node/chunk-ZJOF5MEZ.js +0 -64
  75. package/src/utils/AsyncEventEmitter.test.ts +0 -102
  76. package/src/utils/AsyncEventEmitter.ts +0 -193
  77. package/src/utils/createLazyCallback.ts +0 -49
@@ -0,0 +1,86 @@
1
+ import { DeferredPromise } from '@open-draft/deferred-promise';
2
+ import { Logger } from '@open-draft/logger';
3
+ import { Emitter, Listener } from 'strict-event-emitter';
4
+
5
+ declare class RequestController {
6
+ protected request: Request;
7
+ responsePromise: DeferredPromise<Response | undefined>;
8
+ constructor(request: Request);
9
+ respondWith(response?: Response): void;
10
+ }
11
+
12
+ type InteractiveRequest = globalThis.Request & {
13
+ respondWith: RequestController['respondWith'];
14
+ };
15
+
16
+ declare const IS_PATCHED_MODULE: unique symbol;
17
+ type RequestCredentials = 'omit' | 'include' | 'same-origin';
18
+ type HttpRequestEventMap = {
19
+ request: [
20
+ args: {
21
+ request: InteractiveRequest;
22
+ requestId: string;
23
+ }
24
+ ];
25
+ response: [
26
+ args: {
27
+ response: Response;
28
+ isMockedResponse: boolean;
29
+ request: Request;
30
+ requestId: string;
31
+ }
32
+ ];
33
+ };
34
+
35
+ type InterceptorEventMap = Record<string, any>;
36
+ type InterceptorSubscription = () => void;
37
+ declare function getGlobalSymbol<V>(symbol: Symbol): V | undefined;
38
+ declare function deleteGlobalSymbol(symbol: Symbol): void;
39
+ declare enum InterceptorReadyState {
40
+ INACTIVE = "INACTIVE",
41
+ APPLYING = "APPLYING",
42
+ APPLIED = "APPLIED",
43
+ DISPOSING = "DISPOSING",
44
+ DISPOSED = "DISPOSED"
45
+ }
46
+ type ExtractEventNames<Events extends Record<string, any>> = Events extends Record<infer EventName, any> ? EventName : never;
47
+ declare class Interceptor<Events extends InterceptorEventMap> {
48
+ private readonly symbol;
49
+ protected emitter: Emitter<Events>;
50
+ protected subscriptions: Array<InterceptorSubscription>;
51
+ protected logger: Logger;
52
+ readyState: InterceptorReadyState;
53
+ constructor(symbol: symbol);
54
+ /**
55
+ * Determine if this interceptor can be applied
56
+ * in the current environment.
57
+ */
58
+ protected checkEnvironment(): boolean;
59
+ /**
60
+ * Apply this interceptor to the current process.
61
+ * Returns an already running interceptor instance if it's present.
62
+ */
63
+ apply(): void;
64
+ /**
65
+ * Setup the module augments and stubs necessary for this interceptor.
66
+ * This method is not run if there's a running interceptor instance
67
+ * to prevent instantiating an interceptor multiple times.
68
+ */
69
+ protected setup(): void;
70
+ /**
71
+ * Listen to the interceptor's public events.
72
+ */
73
+ on<EventName extends ExtractEventNames<Events>>(event: EventName, listener: Listener<Events[EventName]>): this;
74
+ once<EventName extends ExtractEventNames<Events>>(event: EventName, listener: Listener<Events[EventName]>): this;
75
+ off<EventName extends ExtractEventNames<Events>>(event: EventName, listener: Listener<Events[EventName]>): this;
76
+ removeAllListeners<EventName extends ExtractEventNames<Events>>(event?: EventName): this;
77
+ /**
78
+ * Disposes of any side-effects this interceptor has introduced.
79
+ */
80
+ dispose(): void;
81
+ private getInstance;
82
+ private setInstance;
83
+ private clearInstance;
84
+ }
85
+
86
+ export { ExtractEventNames as E, HttpRequestEventMap as H, Interceptor as I, RequestCredentials as R, IS_PATCHED_MODULE as a, InterceptorEventMap as b, InterceptorSubscription as c, deleteGlobalSymbol as d, InterceptorReadyState as e, InteractiveRequest as f, getGlobalSymbol as g };
@@ -3,133 +3,7 @@ var IS_PATCHED_MODULE = Symbol("isPatchedModule");
3
3
 
4
4
  // src/Interceptor.ts
5
5
  var _logger = require('@open-draft/logger');
6
-
7
- // src/utils/AsyncEventEmitter.ts
8
-
9
6
  var _stricteventemitter = require('strict-event-emitter');
10
-
11
- // src/utils/nextTick.ts
12
- function nextTick(callback) {
13
- setTimeout(callback, 0);
14
- }
15
-
16
- // src/utils/AsyncEventEmitter.ts
17
- var AsyncEventEmitter = class extends _stricteventemitter.Emitter {
18
- constructor() {
19
- super();
20
- this.logger = new (0, _logger.Logger)("async-event-emitter");
21
- this.queue = /* @__PURE__ */ new Map();
22
- this.readyState = "ACTIVE" /* ACTIVE */;
23
- }
24
- on(eventName, listener) {
25
- const logger = this.logger.extend("on");
26
- logger.info('adding "%s" listener...', eventName);
27
- if (this.readyState === "DEACTIVATED" /* DEACTIVATED */) {
28
- logger.info("the emitter is destroyed, skipping!");
29
- return this;
30
- }
31
- return super.on(eventName, async (...args) => {
32
- const queue = this.openListenerQueue(eventName);
33
- logger.info('awaiting the "%s" listener...', eventName);
34
- queue.push({
35
- args,
36
- done: new Promise(async (resolve, reject) => {
37
- try {
38
- await listener(...args);
39
- resolve();
40
- logger.info('"%s" listener has resolved!', eventName);
41
- } catch (error) {
42
- logger.info('"%s" listener has rejected!', error);
43
- reject(error);
44
- }
45
- })
46
- });
47
- });
48
- }
49
- emit(eventName, ...data) {
50
- const logger = this.logger.extend("emit");
51
- logger.info('emitting "%s" event...', eventName);
52
- if (this.readyState === "DEACTIVATED" /* DEACTIVATED */) {
53
- logger.info("the emitter is destroyed, skipping!");
54
- return false;
55
- }
56
- if (this.isInternalEventName(eventName)) {
57
- return super.emit(eventName, ...data);
58
- }
59
- this.openListenerQueue(eventName);
60
- logger.info('appending a one-time cleanup "%s" listener...', eventName);
61
- this.once(eventName, () => {
62
- nextTick(() => {
63
- this.queue.delete(eventName);
64
- logger.info('cleaned up "%s" listeners queue!', eventName);
65
- });
66
- });
67
- return super.emit(eventName, ...data);
68
- }
69
- /**
70
- * Returns a promise that resolves when all the listeners for the given event
71
- * has been called. Awaits asynchronous listeners.
72
- * If the event has no listeners, resolves immediately.
73
- */
74
- async untilIdle(eventName, filter = () => true) {
75
- const listenersQueue = this.queue.get(eventName) || [];
76
- await Promise.all(
77
- listenersQueue.filter(filter).map(({ done }) => done)
78
- ).finally(() => {
79
- this.queue.delete(eventName);
80
- });
81
- }
82
- openListenerQueue(eventName) {
83
- const logger = this.logger.extend("openListenerQueue");
84
- logger.info('opening "%s" listeners queue...', eventName);
85
- const queue = this.queue.get(eventName);
86
- if (!queue) {
87
- logger.info("no queue found, creating one...");
88
- this.queue.set(eventName, []);
89
- return [];
90
- }
91
- logger.info("returning an exising queue:", queue);
92
- return queue;
93
- }
94
- removeAllListeners(eventName) {
95
- const logger = this.logger.extend("removeAllListeners");
96
- logger.info("event:", eventName);
97
- if (eventName) {
98
- this.queue.delete(eventName);
99
- logger.info(
100
- 'cleared the "%s" listeners queue!',
101
- eventName,
102
- this.queue.get(eventName)
103
- );
104
- } else {
105
- this.queue.clear();
106
- logger.info("cleared the listeners queue!", this.queue);
107
- }
108
- return super.removeAllListeners(eventName);
109
- }
110
- activate() {
111
- const logger = this.logger.extend("activate");
112
- this.readyState = "ACTIVE" /* ACTIVE */;
113
- logger.info("set state to:", this.readyState);
114
- }
115
- /**
116
- * Deactivate this event emitter.
117
- * Deactivated emitter can no longer emit and listen to events
118
- * and needs to be activated again in order to do so.
119
- */
120
- deactivate() {
121
- const logger = this.logger.extend("deactivate");
122
- logger.info("removing all listeners...");
123
- this.removeAllListeners();
124
- this.readyState = "DEACTIVATED" /* DEACTIVATED */;
125
- logger.info("set state to:", this.readyState);
126
- }
127
- isInternalEventName(eventName) {
128
- return eventName === "newListener" || eventName === "removeListener";
129
- }
130
- };
131
-
132
- // src/Interceptor.ts
133
7
  function getGlobalSymbol(symbol) {
134
8
  return (
135
9
  // @ts-ignore https://github.com/Microsoft/TypeScript/issues/24587
@@ -154,7 +28,7 @@ var Interceptor = class {
154
28
  constructor(symbol) {
155
29
  this.symbol = symbol;
156
30
  this.readyState = "INACTIVE" /* INACTIVE */;
157
- this.emitter = new AsyncEventEmitter();
31
+ this.emitter = new (0, _stricteventemitter.Emitter)();
158
32
  this.subscriptions = [];
159
33
  this.logger = new (0, _logger.Logger)(symbol.description);
160
34
  this.emitter.setMaxListeners(0);
@@ -184,8 +58,6 @@ var Interceptor = class {
184
58
  return;
185
59
  }
186
60
  this.readyState = "APPLYING" /* APPLYING */;
187
- this.emitter.activate();
188
- logger.info("activated the emiter!", this.emitter.readyState);
189
61
  const runningInstance = this.getInstance();
190
62
  if (runningInstance) {
191
63
  logger.info("found a running instance, reusing...");
@@ -196,6 +68,7 @@ var Interceptor = class {
196
68
  runningInstance.emitter.removeListener(event, listener);
197
69
  logger.info('removed proxied "%s" listener!', event);
198
70
  });
71
+ return this;
199
72
  };
200
73
  this.readyState = "APPLIED" /* APPLIED */;
201
74
  return;
@@ -215,14 +88,27 @@ var Interceptor = class {
215
88
  /**
216
89
  * Listen to the interceptor's public events.
217
90
  */
218
- on(eventName, listener) {
91
+ on(event, listener) {
219
92
  const logger = this.logger.extend("on");
220
93
  if (this.readyState === "DISPOSING" /* DISPOSING */ || this.readyState === "DISPOSED" /* DISPOSED */) {
221
94
  logger.info("cannot listen to events, already disposed!");
222
- return;
95
+ return this;
223
96
  }
224
- logger.info('adding "%s" event listener:', eventName, listener.name);
225
- this.emitter.on(eventName, listener);
97
+ logger.info('adding "%s" event listener:', event, listener.name);
98
+ this.emitter.on(event, listener);
99
+ return this;
100
+ }
101
+ once(event, listener) {
102
+ this.emitter.once(event, listener);
103
+ return this;
104
+ }
105
+ off(event, listener) {
106
+ this.emitter.off(event, listener);
107
+ return this;
108
+ }
109
+ removeAllListeners(event) {
110
+ this.emitter.removeAllListeners(event);
111
+ return this;
226
112
  }
227
113
  /**
228
114
  * Disposes of any side-effects this interceptor has introduced.
@@ -249,7 +135,7 @@ var Interceptor = class {
249
135
  this.subscriptions = [];
250
136
  logger.info("disposed of all subscriptions!", this.subscriptions.length);
251
137
  }
252
- this.emitter.deactivate();
138
+ this.emitter.removeAllListeners();
253
139
  logger.info("destroyed the listener!");
254
140
  this.readyState = "DISPOSED" /* DISPOSED */;
255
141
  }
@@ -1,15 +1,16 @@
1
1
  import {
2
+ emitAsync,
2
3
  toInteractiveRequest,
3
4
  uuidv4
4
- } from "./chunk-RT3ATOJH.mjs";
5
+ } from "./chunk-KK6APRON.mjs";
5
6
  import {
6
7
  IS_PATCHED_MODULE,
7
8
  Interceptor
8
- } from "./chunk-GXJLJMOT.mjs";
9
+ } from "./chunk-QPMXOLDO.mjs";
9
10
 
10
11
  // src/interceptors/fetch/index.ts
11
- import { DeferredPromise } from "@open-draft/deferred-promise";
12
12
  import { invariant } from "outvariant";
13
+ import { DeferredPromise } from "@open-draft/deferred-promise";
13
14
  import { until } from "@open-draft/until";
14
15
  var _FetchInterceptor = class extends Interceptor {
15
16
  constructor() {
@@ -29,14 +30,18 @@ var _FetchInterceptor = class extends Interceptor {
29
30
  const requestId = uuidv4();
30
31
  const request = new Request(input, init);
31
32
  this.logger.info("[%s] %s", request.method, request.url);
32
- const interactiveRequest = toInteractiveRequest(request);
33
+ const { interactiveRequest, requestController } = toInteractiveRequest(request);
33
34
  this.logger.info(
34
35
  'emitting the "request" event for %d listener(s)...',
35
36
  this.emitter.listenerCount("request")
36
37
  );
37
- this.emitter.emit("request", {
38
- request: interactiveRequest,
39
- requestId
38
+ this.emitter.once("request", ({ requestId: pendingRequestId }) => {
39
+ if (pendingRequestId !== requestId) {
40
+ return;
41
+ }
42
+ if (requestController.responsePromise.state === "pending") {
43
+ requestController.responsePromise.resolve(void 0);
44
+ }
40
45
  });
41
46
  this.logger.info("awaiting for the mocked response...");
42
47
  const signal = interactiveRequest.signal;
@@ -49,15 +54,20 @@ var _FetchInterceptor = class extends Interceptor {
49
54
  { once: true }
50
55
  );
51
56
  const resolverResult = await until(async () => {
52
- const allListenersResolved = this.emitter.untilIdle(
53
- "request",
54
- ({ args: [{ requestId: pendingRequestId }] }) => {
55
- return pendingRequestId === requestId;
56
- }
57
- );
58
- await Promise.race([requestAborted, allListenersResolved]);
57
+ const listenersFinished = emitAsync(this.emitter, "request", {
58
+ request: interactiveRequest,
59
+ requestId
60
+ });
61
+ await Promise.race([
62
+ requestAborted,
63
+ // Put the listeners invocation Promise in the same race condition
64
+ // with the request abort Promise because otherwise awaiting the listeners
65
+ // would always yield some response (or undefined).
66
+ listenersFinished,
67
+ requestController.responsePromise
68
+ ]);
59
69
  this.logger.info("all request listeners have been resolved!");
60
- const [mockedResponse2] = await interactiveRequest.respondWith.invoked();
70
+ const mockedResponse2 = await requestController.responsePromise;
61
71
  this.logger.info("event.respondWith called with:", mockedResponse2);
62
72
  return mockedResponse2;
63
73
  });
@@ -1,17 +1,18 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
2
 
3
3
 
4
- var _chunkPCFJD76Xjs = require('./chunk-PCFJD76X.js');
5
4
 
5
+ var _chunkX3NRJIZWjs = require('./chunk-X3NRJIZW.js');
6
6
 
7
7
 
8
- var _chunk4CFMDU7Zjs = require('./chunk-4CFMDU7Z.js');
8
+
9
+ var _chunkCWVY2E3Wjs = require('./chunk-CWVY2E3W.js');
9
10
 
10
11
  // src/interceptors/fetch/index.ts
11
- var _deferredpromise = require('@open-draft/deferred-promise');
12
12
  var _outvariant = require('outvariant');
13
+ var _deferredpromise = require('@open-draft/deferred-promise');
13
14
  var _until = require('@open-draft/until');
14
- var _FetchInterceptor = class extends _chunk4CFMDU7Zjs.Interceptor {
15
+ var _FetchInterceptor = class extends _chunkCWVY2E3Wjs.Interceptor {
15
16
  constructor() {
16
17
  super(_FetchInterceptor.symbol);
17
18
  }
@@ -21,22 +22,26 @@ var _FetchInterceptor = class extends _chunk4CFMDU7Zjs.Interceptor {
21
22
  setup() {
22
23
  const pureFetch = globalThis.fetch;
23
24
  _outvariant.invariant.call(void 0,
24
- !pureFetch[_chunk4CFMDU7Zjs.IS_PATCHED_MODULE],
25
+ !pureFetch[_chunkCWVY2E3Wjs.IS_PATCHED_MODULE],
25
26
  'Failed to patch the "fetch" module: already patched.'
26
27
  );
27
28
  globalThis.fetch = async (input, init) => {
28
29
  var _a;
29
- const requestId = _chunkPCFJD76Xjs.uuidv4.call(void 0, );
30
+ const requestId = _chunkX3NRJIZWjs.uuidv4.call(void 0, );
30
31
  const request = new Request(input, init);
31
32
  this.logger.info("[%s] %s", request.method, request.url);
32
- const interactiveRequest = _chunkPCFJD76Xjs.toInteractiveRequest.call(void 0, request);
33
+ const { interactiveRequest, requestController } = _chunkX3NRJIZWjs.toInteractiveRequest.call(void 0, request);
33
34
  this.logger.info(
34
35
  'emitting the "request" event for %d listener(s)...',
35
36
  this.emitter.listenerCount("request")
36
37
  );
37
- this.emitter.emit("request", {
38
- request: interactiveRequest,
39
- requestId
38
+ this.emitter.once("request", ({ requestId: pendingRequestId }) => {
39
+ if (pendingRequestId !== requestId) {
40
+ return;
41
+ }
42
+ if (requestController.responsePromise.state === "pending") {
43
+ requestController.responsePromise.resolve(void 0);
44
+ }
40
45
  });
41
46
  this.logger.info("awaiting for the mocked response...");
42
47
  const signal = interactiveRequest.signal;
@@ -49,15 +54,20 @@ var _FetchInterceptor = class extends _chunk4CFMDU7Zjs.Interceptor {
49
54
  { once: true }
50
55
  );
51
56
  const resolverResult = await _until.until.call(void 0, async () => {
52
- const allListenersResolved = this.emitter.untilIdle(
53
- "request",
54
- ({ args: [{ requestId: pendingRequestId }] }) => {
55
- return pendingRequestId === requestId;
56
- }
57
- );
58
- await Promise.race([requestAborted, allListenersResolved]);
57
+ const listenersFinished = _chunkX3NRJIZWjs.emitAsync.call(void 0, this.emitter, "request", {
58
+ request: interactiveRequest,
59
+ requestId
60
+ });
61
+ await Promise.race([
62
+ requestAborted,
63
+ // Put the listeners invocation Promise in the same race condition
64
+ // with the request abort Promise because otherwise awaiting the listeners
65
+ // would always yield some response (or undefined).
66
+ listenersFinished,
67
+ requestController.responsePromise
68
+ ]);
59
69
  this.logger.info("all request listeners have been resolved!");
60
- const [mockedResponse2] = await interactiveRequest.respondWith.invoked();
70
+ const mockedResponse2 = await requestController.responsePromise;
61
71
  this.logger.info("event.respondWith called with:", mockedResponse2);
62
72
  return mockedResponse2;
63
73
  });
@@ -105,13 +115,13 @@ var _FetchInterceptor = class extends _chunk4CFMDU7Zjs.Interceptor {
105
115
  return response;
106
116
  });
107
117
  };
108
- Object.defineProperty(globalThis.fetch, _chunk4CFMDU7Zjs.IS_PATCHED_MODULE, {
118
+ Object.defineProperty(globalThis.fetch, _chunkCWVY2E3Wjs.IS_PATCHED_MODULE, {
109
119
  enumerable: true,
110
120
  configurable: true,
111
121
  value: true
112
122
  });
113
123
  this.subscriptions.push(() => {
114
- Object.defineProperty(globalThis.fetch, _chunk4CFMDU7Zjs.IS_PATCHED_MODULE, {
124
+ Object.defineProperty(globalThis.fetch, _chunkCWVY2E3Wjs.IS_PATCHED_MODULE, {
115
125
  value: void 0
116
126
  });
117
127
  globalThis.fetch = pureFetch;
@@ -0,0 +1,58 @@
1
+ // src/utils/uuid.ts
2
+ function uuidv4() {
3
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) {
4
+ const r = Math.random() * 16 | 0;
5
+ const v = c == "x" ? r : r & 3 | 8;
6
+ return v.toString(16);
7
+ });
8
+ }
9
+
10
+ // src/utils/RequestController.ts
11
+ import { invariant } from "outvariant";
12
+ import { DeferredPromise } from "@open-draft/deferred-promise";
13
+ var RequestController = class {
14
+ constructor(request) {
15
+ this.request = request;
16
+ this.responsePromise = new DeferredPromise();
17
+ }
18
+ respondWith(response) {
19
+ invariant(
20
+ this.responsePromise.state === "pending",
21
+ 'Failed to respond to "%s %s" request: the "request" event has already been responded to.',
22
+ this.request.method,
23
+ this.request.url
24
+ );
25
+ this.responsePromise.resolve(response);
26
+ }
27
+ };
28
+
29
+ // src/utils/toInteractiveRequest.ts
30
+ function toInteractiveRequest(request) {
31
+ const requestController = new RequestController(request);
32
+ Reflect.set(
33
+ request,
34
+ "respondWith",
35
+ requestController.respondWith.bind(requestController)
36
+ );
37
+ return {
38
+ interactiveRequest: request,
39
+ requestController
40
+ };
41
+ }
42
+
43
+ // src/utils/emitAsync.ts
44
+ async function emitAsync(emitter, eventName, ...data) {
45
+ const listners = emitter.listeners(eventName);
46
+ if (listners.length === 0) {
47
+ return;
48
+ }
49
+ for (const listener of listners) {
50
+ await listener.apply(emitter, data);
51
+ }
52
+ }
53
+
54
+ export {
55
+ uuidv4,
56
+ toInteractiveRequest,
57
+ emitAsync
58
+ };
@@ -6,11 +6,12 @@ var _chunk3LFH2WCFjs = require('./chunk-3LFH2WCF.js');
6
6
 
7
7
 
8
8
 
9
- var _chunkPCFJD76Xjs = require('./chunk-PCFJD76X.js');
10
9
 
10
+ var _chunkX3NRJIZWjs = require('./chunk-X3NRJIZW.js');
11
11
 
12
12
 
13
- var _chunk4CFMDU7Zjs = require('./chunk-4CFMDU7Z.js');
13
+
14
+ var _chunkCWVY2E3Wjs = require('./chunk-CWVY2E3W.js');
14
15
 
15
16
  // src/interceptors/XMLHttpRequest/index.ts
16
17
  var _outvariant = require('outvariant');
@@ -237,7 +238,7 @@ var XMLHttpRequestController = class {
237
238
  this.method = "GET";
238
239
  this.url = null;
239
240
  this.events = /* @__PURE__ */ new Map();
240
- this.requestId = _chunkPCFJD76Xjs.uuidv4.call(void 0, );
241
+ this.requestId = _chunkX3NRJIZWjs.uuidv4.call(void 0, );
241
242
  this.requestHeaders = new Headers();
242
243
  this.responseBuffer = new Uint8Array();
243
244
  this.request = createProxy(initialRequest, {
@@ -652,30 +653,32 @@ function createXMLHttpRequestProxy({
652
653
  prototypeDescriptors[propertyName]
653
654
  );
654
655
  }
655
- const requestController = new XMLHttpRequestController(
656
+ const xhrRequestController = new XMLHttpRequestController(
656
657
  originalRequest,
657
658
  logger
658
659
  );
659
- requestController.onRequest = async function({ request, requestId }) {
660
- const interactiveRequest = _chunkPCFJD76Xjs.toInteractiveRequest.call(void 0, request);
661
- this.logger.info(
662
- 'emitting the "request" event for %s listener(s)...',
663
- emitter.listenerCount("request")
664
- );
665
- emitter.emit("request", {
666
- request: interactiveRequest,
667
- requestId
668
- });
660
+ xhrRequestController.onRequest = async function({ request, requestId }) {
661
+ const { interactiveRequest, requestController } = _chunkX3NRJIZWjs.toInteractiveRequest.call(void 0, request);
669
662
  this.logger.info("awaiting mocked response...");
663
+ emitter.once("request", ({ requestId: pendingRequestId }) => {
664
+ if (pendingRequestId !== requestId) {
665
+ return;
666
+ }
667
+ if (requestController.responsePromise.state === "pending") {
668
+ requestController.respondWith(void 0);
669
+ }
670
+ });
670
671
  const resolverResult = await _until.until.call(void 0, async () => {
671
- await emitter.untilIdle(
672
- "request",
673
- ({ args: [{ requestId: pendingRequestId }] }) => {
674
- return pendingRequestId === requestId;
675
- }
672
+ this.logger.info(
673
+ 'emitting the "request" event for %s listener(s)...',
674
+ emitter.listenerCount("request")
676
675
  );
676
+ await _chunkX3NRJIZWjs.emitAsync.call(void 0, emitter, "request", {
677
+ request: interactiveRequest,
678
+ requestId
679
+ });
677
680
  this.logger.info('all "request" listeners settled!');
678
- const [mockedResponse2] = await interactiveRequest.respondWith.invoked();
681
+ const mockedResponse2 = await requestController.responsePromise;
679
682
  this.logger.info("event.respondWith called with:", mockedResponse2);
680
683
  return mockedResponse2;
681
684
  });
@@ -684,7 +687,7 @@ function createXMLHttpRequestProxy({
684
687
  "request listener threw an exception, aborting request...",
685
688
  resolverResult.error
686
689
  );
687
- requestController.errorWith(resolverResult.error);
690
+ xhrRequestController.errorWith(resolverResult.error);
688
691
  return;
689
692
  }
690
693
  const mockedResponse = resolverResult.data;
@@ -698,16 +701,16 @@ function createXMLHttpRequestProxy({
698
701
  this.logger.info(
699
702
  "received a network error response, rejecting the request promise..."
700
703
  );
701
- requestController.errorWith(new TypeError("Network error"));
704
+ xhrRequestController.errorWith(new TypeError("Network error"));
702
705
  return;
703
706
  }
704
- return requestController.respondWith(mockedResponse);
707
+ return xhrRequestController.respondWith(mockedResponse);
705
708
  }
706
709
  this.logger.info(
707
710
  "no mocked response received, performing request as-is..."
708
711
  );
709
712
  };
710
- requestController.onResponse = async function({
713
+ xhrRequestController.onResponse = async function({
711
714
  response,
712
715
  isMockedResponse,
713
716
  request,
@@ -724,14 +727,14 @@ function createXMLHttpRequestProxy({
724
727
  requestId
725
728
  });
726
729
  };
727
- return requestController.request;
730
+ return xhrRequestController.request;
728
731
  }
729
732
  });
730
733
  return XMLHttpRequestProxy;
731
734
  }
732
735
 
733
736
  // src/interceptors/XMLHttpRequest/index.ts
734
- var _XMLHttpRequestInterceptor = class extends _chunk4CFMDU7Zjs.Interceptor {
737
+ var _XMLHttpRequestInterceptor = class extends _chunkCWVY2E3Wjs.Interceptor {
735
738
  constructor() {
736
739
  super(_XMLHttpRequestInterceptor.interceptorSymbol);
737
740
  }
@@ -743,7 +746,7 @@ var _XMLHttpRequestInterceptor = class extends _chunk4CFMDU7Zjs.Interceptor {
743
746
  logger.info('patching "XMLHttpRequest" module...');
744
747
  const PureXMLHttpRequest = globalThis.XMLHttpRequest;
745
748
  _outvariant.invariant.call(void 0,
746
- !PureXMLHttpRequest[_chunk4CFMDU7Zjs.IS_PATCHED_MODULE],
749
+ !PureXMLHttpRequest[_chunkCWVY2E3Wjs.IS_PATCHED_MODULE],
747
750
  'Failed to patch the "XMLHttpRequest" module: already patched.'
748
751
  );
749
752
  globalThis.XMLHttpRequest = createXMLHttpRequestProxy({
@@ -754,13 +757,13 @@ var _XMLHttpRequestInterceptor = class extends _chunk4CFMDU7Zjs.Interceptor {
754
757
  'native "XMLHttpRequest" module patched!',
755
758
  globalThis.XMLHttpRequest.name
756
759
  );
757
- Object.defineProperty(globalThis.XMLHttpRequest, _chunk4CFMDU7Zjs.IS_PATCHED_MODULE, {
760
+ Object.defineProperty(globalThis.XMLHttpRequest, _chunkCWVY2E3Wjs.IS_PATCHED_MODULE, {
758
761
  enumerable: true,
759
762
  configurable: true,
760
763
  value: true
761
764
  });
762
765
  this.subscriptions.push(() => {
763
- Object.defineProperty(globalThis.XMLHttpRequest, _chunk4CFMDU7Zjs.IS_PATCHED_MODULE, {
766
+ Object.defineProperty(globalThis.XMLHttpRequest, _chunkCWVY2E3Wjs.IS_PATCHED_MODULE, {
764
767
  value: void 0
765
768
  });
766
769
  globalThis.XMLHttpRequest = PureXMLHttpRequest;