@mswjs/interceptors 0.28.3 → 0.29.0

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 (98) hide show
  1. package/lib/browser/{chunk-F2F5QHHJ.js → chunk-2CRB3JAQ.js} +16 -2
  2. package/lib/browser/chunk-2CRB3JAQ.js.map +1 -0
  3. package/lib/browser/{chunk-PXSYFJ7G.mjs → chunk-732REFPX.mjs} +23 -4
  4. package/lib/browser/chunk-732REFPX.mjs.map +1 -0
  5. package/lib/browser/{chunk-NIWUC7GF.mjs → chunk-MAEPOYB6.mjs} +67 -35
  6. package/lib/browser/chunk-MAEPOYB6.mjs.map +1 -0
  7. package/lib/browser/{chunk-VISYSKLR.mjs → chunk-OMISYKWR.mjs} +16 -2
  8. package/lib/browser/chunk-OMISYKWR.mjs.map +1 -0
  9. package/lib/browser/{chunk-LAEV5ZGV.js → chunk-PSX5J3RF.js} +28 -9
  10. package/lib/browser/chunk-PSX5J3RF.js.map +1 -0
  11. package/lib/browser/{chunk-RLGVQZ5O.js → chunk-WBHIW62P.js} +69 -37
  12. package/lib/browser/chunk-WBHIW62P.js.map +1 -0
  13. package/lib/browser/{glossary-640c9679.d.ts → glossary-1c204f45.d.ts} +11 -0
  14. package/lib/browser/index.d.ts +1 -1
  15. package/lib/browser/index.js +2 -2
  16. package/lib/browser/index.mjs +1 -1
  17. package/lib/browser/interceptors/XMLHttpRequest/index.d.ts +1 -1
  18. package/lib/browser/interceptors/XMLHttpRequest/index.js +3 -3
  19. package/lib/browser/interceptors/XMLHttpRequest/index.mjs +2 -2
  20. package/lib/browser/interceptors/fetch/index.d.ts +1 -1
  21. package/lib/browser/interceptors/fetch/index.js +3 -3
  22. package/lib/browser/interceptors/fetch/index.mjs +2 -2
  23. package/lib/browser/presets/browser.d.ts +1 -1
  24. package/lib/browser/presets/browser.js +5 -5
  25. package/lib/browser/presets/browser.mjs +3 -3
  26. package/lib/node/{BatchInterceptor-cb145daa.d.ts → BatchInterceptor-2badedde.d.ts} +1 -1
  27. package/lib/node/{Interceptor-6696a18d.d.ts → Interceptor-88ee47c0.d.ts} +11 -0
  28. package/lib/node/RemoteHttpInterceptor.d.ts +2 -2
  29. package/lib/node/RemoteHttpInterceptor.js +9 -10
  30. package/lib/node/RemoteHttpInterceptor.js.map +1 -1
  31. package/lib/node/RemoteHttpInterceptor.mjs +5 -6
  32. package/lib/node/RemoteHttpInterceptor.mjs.map +1 -1
  33. package/lib/node/{chunk-2SC4AD6S.mjs → chunk-6FRASLM3.mjs} +2 -2
  34. package/lib/node/{chunk-M4JXH4RP.js → chunk-APT7KA3B.js} +32 -13
  35. package/lib/node/chunk-APT7KA3B.js.map +1 -0
  36. package/lib/node/{chunk-KRDNUBDZ.js → chunk-E4AC7YAC.js} +16 -2
  37. package/lib/node/chunk-E4AC7YAC.js.map +1 -0
  38. package/lib/node/{chunk-FZJKKO5H.js → chunk-EIBTX65O.js} +1 -1
  39. package/lib/node/{chunk-FZJKKO5H.js.map → chunk-EIBTX65O.js.map} +1 -1
  40. package/lib/node/{chunk-UXEUSYDY.js → chunk-HAIWBQD5.js} +48 -49
  41. package/lib/node/chunk-HAIWBQD5.js.map +1 -0
  42. package/lib/node/{chunk-L576JLIX.mjs → chunk-JMNEFEYU.mjs} +43 -44
  43. package/lib/node/chunk-JMNEFEYU.mjs.map +1 -0
  44. package/lib/node/{chunk-KGNKRQ7B.mjs → chunk-KSHIDGUL.mjs} +24 -5
  45. package/lib/node/chunk-KSHIDGUL.mjs.map +1 -0
  46. package/lib/node/{chunk-Z2DPXZWN.js → chunk-LTEXDYJ6.js} +3 -3
  47. package/lib/node/{chunk-HAGW22AN.mjs → chunk-OJ6O4LSC.mjs} +1 -1
  48. package/lib/node/{chunk-HAGW22AN.mjs.map → chunk-OJ6O4LSC.mjs.map} +1 -1
  49. package/lib/node/{chunk-DQ5DO3KN.mjs → chunk-Q7POAM5N.mjs} +16 -2
  50. package/lib/node/chunk-Q7POAM5N.mjs.map +1 -0
  51. package/lib/node/index.d.ts +2 -2
  52. package/lib/node/index.js +4 -4
  53. package/lib/node/index.mjs +3 -3
  54. package/lib/node/interceptors/ClientRequest/index.d.ts +1 -1
  55. package/lib/node/interceptors/ClientRequest/index.js +3 -4
  56. package/lib/node/interceptors/ClientRequest/index.mjs +2 -3
  57. package/lib/node/interceptors/XMLHttpRequest/index.d.ts +1 -1
  58. package/lib/node/interceptors/XMLHttpRequest/index.js +4 -4
  59. package/lib/node/interceptors/XMLHttpRequest/index.mjs +3 -3
  60. package/lib/node/interceptors/fetch/index.d.ts +1 -1
  61. package/lib/node/interceptors/fetch/index.js +71 -32
  62. package/lib/node/interceptors/fetch/index.js.map +1 -1
  63. package/lib/node/interceptors/fetch/index.mjs +67 -28
  64. package/lib/node/interceptors/fetch/index.mjs.map +1 -1
  65. package/lib/node/presets/node.d.ts +1 -1
  66. package/lib/node/presets/node.js +6 -7
  67. package/lib/node/presets/node.js.map +1 -1
  68. package/lib/node/presets/node.mjs +4 -5
  69. package/lib/node/presets/node.mjs.map +1 -1
  70. package/package.json +1 -1
  71. package/src/glossary.ts +11 -0
  72. package/src/interceptors/ClientRequest/NodeClientRequest.ts +46 -18
  73. package/src/interceptors/XMLHttpRequest/XMLHttpRequestController.ts +4 -7
  74. package/src/interceptors/XMLHttpRequest/XMLHttpRequestProxy.ts +36 -3
  75. package/src/interceptors/fetch/index.ts +88 -33
  76. package/src/utils/getUrlByRequestOptions.test.ts +31 -3
  77. package/src/utils/getUrlByRequestOptions.ts +14 -38
  78. package/src/utils/isObject.test.ts +4 -3
  79. package/src/utils/isObject.ts +4 -2
  80. package/src/utils/responseUtils.ts +16 -0
  81. package/lib/browser/chunk-F2F5QHHJ.js.map +0 -1
  82. package/lib/browser/chunk-LAEV5ZGV.js.map +0 -1
  83. package/lib/browser/chunk-NIWUC7GF.mjs.map +0 -1
  84. package/lib/browser/chunk-PXSYFJ7G.mjs.map +0 -1
  85. package/lib/browser/chunk-RLGVQZ5O.js.map +0 -1
  86. package/lib/browser/chunk-VISYSKLR.mjs.map +0 -1
  87. package/lib/node/chunk-DERTLGL3.mjs +0 -14
  88. package/lib/node/chunk-DERTLGL3.mjs.map +0 -1
  89. package/lib/node/chunk-DQ5DO3KN.mjs.map +0 -1
  90. package/lib/node/chunk-KGNKRQ7B.mjs.map +0 -1
  91. package/lib/node/chunk-KRDNUBDZ.js.map +0 -1
  92. package/lib/node/chunk-L576JLIX.mjs.map +0 -1
  93. package/lib/node/chunk-M4JXH4RP.js.map +0 -1
  94. package/lib/node/chunk-UXEUSYDY.js.map +0 -1
  95. package/lib/node/chunk-Y6GRL6UD.js +0 -14
  96. package/lib/node/chunk-Y6GRL6UD.js.map +0 -1
  97. /package/lib/node/{chunk-2SC4AD6S.mjs.map → chunk-6FRASLM3.mjs.map} +0 -0
  98. /package/lib/node/{chunk-Z2DPXZWN.js.map → chunk-LTEXDYJ6.js.map} +0 -0
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  XMLHttpRequestInterceptor
3
- } from "../../chunk-KGNKRQ7B.mjs";
3
+ } from "../../chunk-KSHIDGUL.mjs";
4
4
  import "../../chunk-6HYIRFX2.mjs";
5
- import "../../chunk-HAGW22AN.mjs";
5
+ import "../../chunk-OJ6O4LSC.mjs";
6
6
  import "../../chunk-OUWBQF3Z.mjs";
7
- import "../../chunk-DQ5DO3KN.mjs";
7
+ import "../../chunk-Q7POAM5N.mjs";
8
8
  export {
9
9
  XMLHttpRequestInterceptor
10
10
  };
@@ -1,4 +1,4 @@
1
- import { f as Interceptor, H as HttpRequestEventMap } from '../../Interceptor-6696a18d.js';
1
+ import { f as Interceptor, H as HttpRequestEventMap } from '../../Interceptor-88ee47c0.js';
2
2
  import '@open-draft/deferred-promise';
3
3
  import '@open-draft/logger';
4
4
  import 'strict-event-emitter';
@@ -1,9 +1,6 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
2
 
3
- var _chunkY6GRL6UDjs = require('../../chunk-Y6GRL6UD.js');
4
-
5
-
6
- var _chunkFZJKKO5Hjs = require('../../chunk-FZJKKO5H.js');
3
+ var _chunkEIBTX65Ojs = require('../../chunk-EIBTX65O.js');
7
4
 
8
5
 
9
6
 
@@ -12,7 +9,8 @@ var _chunkMQJ3JOOKjs = require('../../chunk-MQJ3JOOK.js');
12
9
 
13
10
 
14
11
 
15
- var _chunkKRDNUBDZjs = require('../../chunk-KRDNUBDZ.js');
12
+
13
+ var _chunkE4AC7YACjs = require('../../chunk-E4AC7YAC.js');
16
14
 
17
15
  // src/interceptors/fetch/index.ts
18
16
  var _outvariant = require('outvariant');
@@ -30,7 +28,7 @@ function canParseUrl(url) {
30
28
  }
31
29
 
32
30
  // src/interceptors/fetch/index.ts
33
- var _FetchInterceptor = class extends _chunkKRDNUBDZjs.Interceptor {
31
+ var _FetchInterceptor = class extends _chunkE4AC7YACjs.Interceptor {
34
32
  constructor() {
35
33
  super(_FetchInterceptor.symbol);
36
34
  }
@@ -40,12 +38,12 @@ var _FetchInterceptor = class extends _chunkKRDNUBDZjs.Interceptor {
40
38
  async setup() {
41
39
  const pureFetch = globalThis.fetch;
42
40
  _outvariant.invariant.call(void 0,
43
- !pureFetch[_chunkFZJKKO5Hjs.IS_PATCHED_MODULE],
41
+ !pureFetch[_chunkEIBTX65Ojs.IS_PATCHED_MODULE],
44
42
  'Failed to patch the "fetch" module: already patched.'
45
43
  );
46
44
  globalThis.fetch = async (input, init) => {
47
45
  var _a;
48
- const requestId = _chunkKRDNUBDZjs.createRequestId.call(void 0, );
46
+ const requestId = _chunkE4AC7YACjs.createRequestId.call(void 0, );
49
47
  const resolvedInput = typeof input === "string" && typeof location !== "undefined" && !canParseUrl(input) ? new URL(input, location.origin) : input;
50
48
  const request = new Request(resolvedInput, init);
51
49
  this.logger.info("[%s] %s", request.method, request.url);
@@ -74,21 +72,29 @@ var _FetchInterceptor = class extends _chunkKRDNUBDZjs.Interceptor {
74
72
  { once: true }
75
73
  );
76
74
  }
75
+ const responsePromise = new (0, _deferredpromise.DeferredPromise)();
77
76
  const respondWith = (response) => {
78
- const responseClone = response.clone();
79
- this.emitter.emit("response", {
80
- response: responseClone,
81
- isMockedResponse: true,
82
- request: interactiveRequest,
83
- requestId
84
- });
77
+ this.logger.info("responding with a mock response:", response);
78
+ if (this.emitter.listenerCount("response") > 0) {
79
+ this.logger.info('emitting the "response" event...');
80
+ const responseClone = response.clone();
81
+ this.emitter.emit("response", {
82
+ response: responseClone,
83
+ isMockedResponse: true,
84
+ request: interactiveRequest,
85
+ requestId
86
+ });
87
+ }
85
88
  Object.defineProperty(response, "url", {
86
89
  writable: false,
87
90
  enumerable: true,
88
91
  configurable: false,
89
92
  value: request.url
90
93
  });
91
- return response;
94
+ responsePromise.resolve(response);
95
+ };
96
+ const errorWith = (reason) => {
97
+ responsePromise.reject(reason);
92
98
  };
93
99
  const resolverResult = await _until.until.call(void 0,
94
100
  async () => {
@@ -111,45 +117,78 @@ var _FetchInterceptor = class extends _chunkKRDNUBDZjs.Interceptor {
111
117
  }
112
118
  );
113
119
  if (requestAborted.state === "rejected") {
114
- return Promise.reject(requestAborted.rejectionReason);
120
+ this.logger.info(
121
+ "request has been aborted:",
122
+ requestAborted.rejectionReason
123
+ );
124
+ responsePromise.reject(requestAborted.rejectionReason);
125
+ return responsePromise;
115
126
  }
116
127
  if (resolverResult.error) {
128
+ this.logger.info(
129
+ "request listerner threw an error:",
130
+ resolverResult.error
131
+ );
117
132
  if (resolverResult.error instanceof Response) {
118
- return respondWith(resolverResult.error);
133
+ if (_chunkE4AC7YACjs.isResponseError.call(void 0, resolverResult.error)) {
134
+ errorWith(createNetworkError(resolverResult.error));
135
+ } else {
136
+ respondWith(resolverResult.error);
137
+ }
119
138
  }
120
- return _chunkKRDNUBDZjs.createServerErrorResponse.call(void 0, resolverResult.error);
139
+ if (this.emitter.listenerCount("unhandledException") > 0) {
140
+ await _chunkMQJ3JOOKjs.emitAsync.call(void 0, this.emitter, "unhandledException", {
141
+ error: resolverResult.error,
142
+ request,
143
+ requestId,
144
+ controller: {
145
+ respondWith,
146
+ errorWith
147
+ }
148
+ });
149
+ if (responsePromise.state !== "pending") {
150
+ return responsePromise;
151
+ }
152
+ }
153
+ respondWith(_chunkE4AC7YACjs.createServerErrorResponse.call(void 0, resolverResult.error));
154
+ return responsePromise;
121
155
  }
122
156
  const mockedResponse = resolverResult.data;
123
157
  if (mockedResponse && !((_a = request.signal) == null ? void 0 : _a.aborted)) {
124
158
  this.logger.info("received mocked response:", mockedResponse);
125
- if (_chunkY6GRL6UDjs.isPropertyAccessible.call(void 0, mockedResponse, "type") && mockedResponse.type === "error") {
159
+ if (_chunkE4AC7YACjs.isResponseError.call(void 0, mockedResponse)) {
126
160
  this.logger.info(
127
161
  "received a network error response, rejecting the request promise..."
128
162
  );
129
- return Promise.reject(createNetworkError(mockedResponse));
163
+ errorWith(createNetworkError(mockedResponse));
164
+ } else {
165
+ respondWith(mockedResponse);
130
166
  }
131
- return respondWith(mockedResponse);
167
+ return responsePromise;
132
168
  }
133
169
  this.logger.info("no mocked response received!");
134
170
  return pureFetch(request).then((response) => {
135
- const responseClone = response.clone();
136
- this.logger.info("original fetch performed", responseClone);
137
- this.emitter.emit("response", {
138
- response: responseClone,
139
- isMockedResponse: false,
140
- request: interactiveRequest,
141
- requestId
142
- });
171
+ this.logger.info("original fetch performed", response);
172
+ if (this.emitter.listenerCount("response") > 0) {
173
+ this.logger.info('emitting the "response" event...');
174
+ const responseClone = response.clone();
175
+ this.emitter.emit("response", {
176
+ response: responseClone,
177
+ isMockedResponse: false,
178
+ request: interactiveRequest,
179
+ requestId
180
+ });
181
+ }
143
182
  return response;
144
183
  });
145
184
  };
146
- Object.defineProperty(globalThis.fetch, _chunkFZJKKO5Hjs.IS_PATCHED_MODULE, {
185
+ Object.defineProperty(globalThis.fetch, _chunkEIBTX65Ojs.IS_PATCHED_MODULE, {
147
186
  enumerable: true,
148
187
  configurable: true,
149
188
  value: true
150
189
  });
151
190
  this.subscriptions.push(() => {
152
- Object.defineProperty(globalThis.fetch, _chunkFZJKKO5Hjs.IS_PATCHED_MODULE, {
191
+ Object.defineProperty(globalThis.fetch, _chunkEIBTX65Ojs.IS_PATCHED_MODULE, {
153
192
  value: void 0
154
193
  });
155
194
  globalThis.fetch = pureFetch;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/interceptors/fetch/index.ts","../../../../src/utils/canParseUrl.ts"],"names":["mockedResponse"],"mappings":"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","sourcesContent":["import { invariant } from 'outvariant'\nimport { DeferredPromise } from '@open-draft/deferred-promise'\nimport { until } from '@open-draft/until'\nimport { HttpRequestEventMap, IS_PATCHED_MODULE } from '../../glossary'\nimport { Interceptor } from '../../Interceptor'\nimport { toInteractiveRequest } from '../../utils/toInteractiveRequest'\nimport { emitAsync } from '../../utils/emitAsync'\nimport { isPropertyAccessible } from '../../utils/isPropertyAccessible'\nimport { canParseUrl } from '../../utils/canParseUrl'\nimport { createRequestId } from '../../createRequestId'\nimport { createServerErrorResponse } from '../../utils/responseUtils'\n\nexport class FetchInterceptor extends Interceptor<HttpRequestEventMap> {\n static symbol = Symbol('fetch')\n\n constructor() {\n super(FetchInterceptor.symbol)\n }\n\n protected checkEnvironment() {\n return (\n typeof globalThis !== 'undefined' &&\n typeof globalThis.fetch !== 'undefined'\n )\n }\n\n protected async setup() {\n const pureFetch = globalThis.fetch\n\n invariant(\n !(pureFetch as any)[IS_PATCHED_MODULE],\n 'Failed to patch the \"fetch\" module: already patched.'\n )\n\n globalThis.fetch = async (input, init) => {\n const requestId = createRequestId()\n\n /**\n * @note Resolve potentially relative request URL\n * against the present `location`. This is mainly\n * for native `fetch` in JSDOM.\n * @see https://github.com/mswjs/msw/issues/1625\n */\n const resolvedInput =\n typeof input === 'string' &&\n typeof location !== 'undefined' &&\n !canParseUrl(input)\n ? new URL(input, location.origin)\n : input\n\n const request = new Request(resolvedInput, init)\n\n this.logger.info('[%s] %s', request.method, request.url)\n\n const { interactiveRequest, requestController } =\n toInteractiveRequest(request)\n\n this.logger.info(\n 'emitting the \"request\" event for %d listener(s)...',\n this.emitter.listenerCount('request')\n )\n\n this.emitter.once('request', ({ requestId: pendingRequestId }) => {\n if (pendingRequestId !== requestId) {\n return\n }\n\n if (requestController.responsePromise.state === 'pending') {\n requestController.responsePromise.resolve(undefined)\n }\n })\n\n this.logger.info('awaiting for the mocked response...')\n\n const signal = interactiveRequest.signal\n const requestAborted = new DeferredPromise()\n\n // Signal isn't always defined in react-native.\n if (signal) {\n signal.addEventListener(\n 'abort',\n () => {\n requestAborted.reject(signal.reason)\n },\n { once: true }\n )\n }\n\n const respondWith = (response: Response): Response => {\n // Clone the mocked response for the \"response\" event listener.\n // This way, the listener can read the response and not lock its body\n // for the actual fetch consumer.\n const responseClone = response.clone()\n\n this.emitter.emit('response', {\n response: responseClone,\n isMockedResponse: true,\n request: interactiveRequest,\n requestId,\n })\n\n // Set the \"response.url\" property to equal the intercepted request URL.\n Object.defineProperty(response, 'url', {\n writable: false,\n enumerable: true,\n configurable: false,\n value: request.url,\n })\n\n return response\n }\n\n const resolverResult = await until<unknown, Response | undefined>(\n async () => {\n const listenersFinished = emitAsync(this.emitter, 'request', {\n request: interactiveRequest,\n requestId,\n })\n\n await Promise.race([\n requestAborted,\n // Put the listeners invocation Promise in the same race condition\n // with the request abort Promise because otherwise awaiting the listeners\n // would always yield some response (or undefined).\n listenersFinished,\n requestController.responsePromise,\n ])\n\n this.logger.info('all request listeners have been resolved!')\n\n const mockedResponse = await requestController.responsePromise\n this.logger.info('event.respondWith called with:', mockedResponse)\n\n return mockedResponse\n }\n )\n\n if (requestAborted.state === 'rejected') {\n return Promise.reject(requestAborted.rejectionReason)\n }\n\n if (resolverResult.error) {\n // Treat thrown Responses as mocked responses.\n if (resolverResult.error instanceof Response) {\n return respondWith(resolverResult.error)\n }\n\n // Unhandled exceptions in the request listeners are\n // synonymous to unhandled exceptions on the server.\n // Those are represented as 500 error responses.\n return createServerErrorResponse(resolverResult.error)\n }\n\n const mockedResponse = resolverResult.data\n\n if (mockedResponse && !request.signal?.aborted) {\n this.logger.info('received mocked response:', mockedResponse)\n\n // Reject the request Promise on mocked \"Response.error\" responses.\n if (\n isPropertyAccessible(mockedResponse, 'type') &&\n mockedResponse.type === 'error'\n ) {\n this.logger.info(\n 'received a network error response, rejecting the request promise...'\n )\n\n /**\n * Set the cause of the request promise rejection to the\n * network error Response instance. This differs from Undici.\n * Undici will forward the \"response.error\" custom property\n * as the rejection reason but for \"Response.error()\" static method\n * \"response.error\" will equal to undefined, making \"cause\" an empty Error.\n * @see https://github.com/nodejs/undici/blob/83cb522ae0157a19d149d72c7d03d46e34510d0a/lib/fetch/response.js#L344\n */\n return Promise.reject(createNetworkError(mockedResponse))\n }\n\n return respondWith(mockedResponse)\n }\n\n this.logger.info('no mocked response received!')\n\n return pureFetch(request).then((response) => {\n const responseClone = response.clone()\n this.logger.info('original fetch performed', responseClone)\n\n this.emitter.emit('response', {\n response: responseClone,\n isMockedResponse: false,\n request: interactiveRequest,\n requestId,\n })\n\n return response\n })\n }\n\n Object.defineProperty(globalThis.fetch, IS_PATCHED_MODULE, {\n enumerable: true,\n configurable: true,\n value: true,\n })\n\n this.subscriptions.push(() => {\n Object.defineProperty(globalThis.fetch, IS_PATCHED_MODULE, {\n value: undefined,\n })\n\n globalThis.fetch = pureFetch\n\n this.logger.info(\n 'restored native \"globalThis.fetch\"!',\n globalThis.fetch.name\n )\n })\n }\n}\n\nfunction createNetworkError(cause: unknown) {\n return Object.assign(new TypeError('Failed to fetch'), {\n cause,\n })\n}\n","/**\n * Returns a boolean indicating whether the given URL string\n * can be parsed into a `URL` instance.\n * A substitute for `URL.canParse()` for Node.js 18.\n */\nexport function canParseUrl(url: string): boolean {\n try {\n new URL(url)\n return true\n } catch (_error) {\n return false\n }\n}\n"]}
1
+ {"version":3,"sources":["../../../../src/interceptors/fetch/index.ts","../../../../src/utils/canParseUrl.ts"],"names":["mockedResponse"],"mappings":"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","sourcesContent":["import { invariant } from 'outvariant'\nimport { DeferredPromise } from '@open-draft/deferred-promise'\nimport { until } from '@open-draft/until'\nimport { HttpRequestEventMap, IS_PATCHED_MODULE } from '../../glossary'\nimport { Interceptor } from '../../Interceptor'\nimport { toInteractiveRequest } from '../../utils/toInteractiveRequest'\nimport { emitAsync } from '../../utils/emitAsync'\nimport { canParseUrl } from '../../utils/canParseUrl'\nimport { createRequestId } from '../../createRequestId'\nimport {\n createServerErrorResponse,\n isResponseError,\n} from '../../utils/responseUtils'\n\nexport class FetchInterceptor extends Interceptor<HttpRequestEventMap> {\n static symbol = Symbol('fetch')\n\n constructor() {\n super(FetchInterceptor.symbol)\n }\n\n protected checkEnvironment() {\n return (\n typeof globalThis !== 'undefined' &&\n typeof globalThis.fetch !== 'undefined'\n )\n }\n\n protected async setup() {\n const pureFetch = globalThis.fetch\n\n invariant(\n !(pureFetch as any)[IS_PATCHED_MODULE],\n 'Failed to patch the \"fetch\" module: already patched.'\n )\n\n globalThis.fetch = async (input, init) => {\n const requestId = createRequestId()\n\n /**\n * @note Resolve potentially relative request URL\n * against the present `location`. This is mainly\n * for native `fetch` in JSDOM.\n * @see https://github.com/mswjs/msw/issues/1625\n */\n const resolvedInput =\n typeof input === 'string' &&\n typeof location !== 'undefined' &&\n !canParseUrl(input)\n ? new URL(input, location.origin)\n : input\n\n const request = new Request(resolvedInput, init)\n\n this.logger.info('[%s] %s', request.method, request.url)\n\n const { interactiveRequest, requestController } =\n toInteractiveRequest(request)\n\n this.logger.info(\n 'emitting the \"request\" event for %d listener(s)...',\n this.emitter.listenerCount('request')\n )\n\n this.emitter.once('request', ({ requestId: pendingRequestId }) => {\n if (pendingRequestId !== requestId) {\n return\n }\n\n if (requestController.responsePromise.state === 'pending') {\n requestController.responsePromise.resolve(undefined)\n }\n })\n\n this.logger.info('awaiting for the mocked response...')\n\n const signal = interactiveRequest.signal\n const requestAborted = new DeferredPromise()\n\n // Signal isn't always defined in react-native.\n if (signal) {\n signal.addEventListener(\n 'abort',\n () => {\n requestAborted.reject(signal.reason)\n },\n { once: true }\n )\n }\n\n const responsePromise = new DeferredPromise<Response>()\n\n const respondWith = (response: Response): void => {\n this.logger.info('responding with a mock response:', response)\n\n if (this.emitter.listenerCount('response') > 0) {\n this.logger.info('emitting the \"response\" event...')\n\n // Clone the mocked response for the \"response\" event listener.\n // This way, the listener can read the response and not lock its body\n // for the actual fetch consumer.\n const responseClone = response.clone()\n\n this.emitter.emit('response', {\n response: responseClone,\n isMockedResponse: true,\n request: interactiveRequest,\n requestId,\n })\n }\n\n // Set the \"response.url\" property to equal the intercepted request URL.\n Object.defineProperty(response, 'url', {\n writable: false,\n enumerable: true,\n configurable: false,\n value: request.url,\n })\n\n responsePromise.resolve(response)\n }\n\n const errorWith = (reason: unknown): void => {\n responsePromise.reject(reason)\n }\n\n const resolverResult = await until<unknown, Response | undefined>(\n async () => {\n const listenersFinished = emitAsync(this.emitter, 'request', {\n request: interactiveRequest,\n requestId,\n })\n\n await Promise.race([\n requestAborted,\n // Put the listeners invocation Promise in the same race condition\n // with the request abort Promise because otherwise awaiting the listeners\n // would always yield some response (or undefined).\n listenersFinished,\n requestController.responsePromise,\n ])\n\n this.logger.info('all request listeners have been resolved!')\n\n const mockedResponse = await requestController.responsePromise\n this.logger.info('event.respondWith called with:', mockedResponse)\n\n return mockedResponse\n }\n )\n\n if (requestAborted.state === 'rejected') {\n this.logger.info(\n 'request has been aborted:',\n requestAborted.rejectionReason\n )\n\n responsePromise.reject(requestAborted.rejectionReason)\n return responsePromise\n }\n\n if (resolverResult.error) {\n this.logger.info(\n 'request listerner threw an error:',\n resolverResult.error\n )\n\n // Treat thrown Responses as mocked responses.\n if (resolverResult.error instanceof Response) {\n // Treat thrown Response.error() as a request error.\n if (isResponseError(resolverResult.error)) {\n errorWith(createNetworkError(resolverResult.error))\n } else {\n // Treat the rest of thrown Responses as mocked responses.\n respondWith(resolverResult.error)\n }\n }\n\n // Emit the \"unhandledException\" interceptor event so the client\n // can opt-out from exceptions translating to 500 error responses.\n\n if (this.emitter.listenerCount('unhandledException') > 0) {\n await emitAsync(this.emitter, 'unhandledException', {\n error: resolverResult.error,\n request,\n requestId,\n controller: {\n respondWith,\n errorWith,\n },\n })\n\n if (responsePromise.state !== 'pending') {\n return responsePromise\n }\n }\n\n // Unhandled exceptions in the request listeners are\n // synonymous to unhandled exceptions on the server.\n // Those are represented as 500 error responses.\n respondWith(createServerErrorResponse(resolverResult.error))\n return responsePromise\n }\n\n const mockedResponse = resolverResult.data\n\n if (mockedResponse && !request.signal?.aborted) {\n this.logger.info('received mocked response:', mockedResponse)\n\n // Reject the request Promise on mocked \"Response.error\" responses.\n if (isResponseError(mockedResponse)) {\n this.logger.info(\n 'received a network error response, rejecting the request promise...'\n )\n\n /**\n * Set the cause of the request promise rejection to the\n * network error Response instance. This differs from Undici.\n * Undici will forward the \"response.error\" custom property\n * as the rejection reason but for \"Response.error()\" static method\n * \"response.error\" will equal to undefined, making \"cause\" an empty Error.\n * @see https://github.com/nodejs/undici/blob/83cb522ae0157a19d149d72c7d03d46e34510d0a/lib/fetch/response.js#L344\n */\n errorWith(createNetworkError(mockedResponse))\n } else {\n respondWith(mockedResponse)\n }\n\n return responsePromise\n }\n\n this.logger.info('no mocked response received!')\n\n return pureFetch(request).then((response) => {\n this.logger.info('original fetch performed', response)\n\n if (this.emitter.listenerCount('response') > 0) {\n this.logger.info('emitting the \"response\" event...')\n\n const responseClone = response.clone()\n\n this.emitter.emit('response', {\n response: responseClone,\n isMockedResponse: false,\n request: interactiveRequest,\n requestId,\n })\n }\n\n return response\n })\n }\n\n Object.defineProperty(globalThis.fetch, IS_PATCHED_MODULE, {\n enumerable: true,\n configurable: true,\n value: true,\n })\n\n this.subscriptions.push(() => {\n Object.defineProperty(globalThis.fetch, IS_PATCHED_MODULE, {\n value: undefined,\n })\n\n globalThis.fetch = pureFetch\n\n this.logger.info(\n 'restored native \"globalThis.fetch\"!',\n globalThis.fetch.name\n )\n })\n }\n}\n\nfunction createNetworkError(cause: unknown) {\n return Object.assign(new TypeError('Failed to fetch'), {\n cause,\n })\n}\n","/**\n * Returns a boolean indicating whether the given URL string\n * can be parsed into a `URL` instance.\n * A substitute for `URL.canParse()` for Node.js 18.\n */\nexport function canParseUrl(url: string): boolean {\n try {\n new URL(url)\n return true\n } catch (_error) {\n return false\n }\n}\n"]}
@@ -1,9 +1,6 @@
1
- import {
2
- isPropertyAccessible
3
- } from "../../chunk-DERTLGL3.mjs";
4
1
  import {
5
2
  IS_PATCHED_MODULE
6
- } from "../../chunk-HAGW22AN.mjs";
3
+ } from "../../chunk-OJ6O4LSC.mjs";
7
4
  import {
8
5
  emitAsync,
9
6
  toInteractiveRequest
@@ -11,8 +8,9 @@ import {
11
8
  import {
12
9
  Interceptor,
13
10
  createRequestId,
14
- createServerErrorResponse
15
- } from "../../chunk-DQ5DO3KN.mjs";
11
+ createServerErrorResponse,
12
+ isResponseError
13
+ } from "../../chunk-Q7POAM5N.mjs";
16
14
 
17
15
  // src/interceptors/fetch/index.ts
18
16
  import { invariant } from "outvariant";
@@ -74,21 +72,29 @@ var _FetchInterceptor = class extends Interceptor {
74
72
  { once: true }
75
73
  );
76
74
  }
75
+ const responsePromise = new DeferredPromise();
77
76
  const respondWith = (response) => {
78
- const responseClone = response.clone();
79
- this.emitter.emit("response", {
80
- response: responseClone,
81
- isMockedResponse: true,
82
- request: interactiveRequest,
83
- requestId
84
- });
77
+ this.logger.info("responding with a mock response:", response);
78
+ if (this.emitter.listenerCount("response") > 0) {
79
+ this.logger.info('emitting the "response" event...');
80
+ const responseClone = response.clone();
81
+ this.emitter.emit("response", {
82
+ response: responseClone,
83
+ isMockedResponse: true,
84
+ request: interactiveRequest,
85
+ requestId
86
+ });
87
+ }
85
88
  Object.defineProperty(response, "url", {
86
89
  writable: false,
87
90
  enumerable: true,
88
91
  configurable: false,
89
92
  value: request.url
90
93
  });
91
- return response;
94
+ responsePromise.resolve(response);
95
+ };
96
+ const errorWith = (reason) => {
97
+ responsePromise.reject(reason);
92
98
  };
93
99
  const resolverResult = await until(
94
100
  async () => {
@@ -111,35 +117,68 @@ var _FetchInterceptor = class extends Interceptor {
111
117
  }
112
118
  );
113
119
  if (requestAborted.state === "rejected") {
114
- return Promise.reject(requestAborted.rejectionReason);
120
+ this.logger.info(
121
+ "request has been aborted:",
122
+ requestAborted.rejectionReason
123
+ );
124
+ responsePromise.reject(requestAborted.rejectionReason);
125
+ return responsePromise;
115
126
  }
116
127
  if (resolverResult.error) {
128
+ this.logger.info(
129
+ "request listerner threw an error:",
130
+ resolverResult.error
131
+ );
117
132
  if (resolverResult.error instanceof Response) {
118
- return respondWith(resolverResult.error);
133
+ if (isResponseError(resolverResult.error)) {
134
+ errorWith(createNetworkError(resolverResult.error));
135
+ } else {
136
+ respondWith(resolverResult.error);
137
+ }
138
+ }
139
+ if (this.emitter.listenerCount("unhandledException") > 0) {
140
+ await emitAsync(this.emitter, "unhandledException", {
141
+ error: resolverResult.error,
142
+ request,
143
+ requestId,
144
+ controller: {
145
+ respondWith,
146
+ errorWith
147
+ }
148
+ });
149
+ if (responsePromise.state !== "pending") {
150
+ return responsePromise;
151
+ }
119
152
  }
120
- return createServerErrorResponse(resolverResult.error);
153
+ respondWith(createServerErrorResponse(resolverResult.error));
154
+ return responsePromise;
121
155
  }
122
156
  const mockedResponse = resolverResult.data;
123
157
  if (mockedResponse && !((_a = request.signal) == null ? void 0 : _a.aborted)) {
124
158
  this.logger.info("received mocked response:", mockedResponse);
125
- if (isPropertyAccessible(mockedResponse, "type") && mockedResponse.type === "error") {
159
+ if (isResponseError(mockedResponse)) {
126
160
  this.logger.info(
127
161
  "received a network error response, rejecting the request promise..."
128
162
  );
129
- return Promise.reject(createNetworkError(mockedResponse));
163
+ errorWith(createNetworkError(mockedResponse));
164
+ } else {
165
+ respondWith(mockedResponse);
130
166
  }
131
- return respondWith(mockedResponse);
167
+ return responsePromise;
132
168
  }
133
169
  this.logger.info("no mocked response received!");
134
170
  return pureFetch(request).then((response) => {
135
- const responseClone = response.clone();
136
- this.logger.info("original fetch performed", responseClone);
137
- this.emitter.emit("response", {
138
- response: responseClone,
139
- isMockedResponse: false,
140
- request: interactiveRequest,
141
- requestId
142
- });
171
+ this.logger.info("original fetch performed", response);
172
+ if (this.emitter.listenerCount("response") > 0) {
173
+ this.logger.info('emitting the "response" event...');
174
+ const responseClone = response.clone();
175
+ this.emitter.emit("response", {
176
+ response: responseClone,
177
+ isMockedResponse: false,
178
+ request: interactiveRequest,
179
+ requestId
180
+ });
181
+ }
143
182
  return response;
144
183
  });
145
184
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/interceptors/fetch/index.ts","../../../../src/utils/canParseUrl.ts"],"sourcesContent":["import { invariant } from 'outvariant'\nimport { DeferredPromise } from '@open-draft/deferred-promise'\nimport { until } from '@open-draft/until'\nimport { HttpRequestEventMap, IS_PATCHED_MODULE } from '../../glossary'\nimport { Interceptor } from '../../Interceptor'\nimport { toInteractiveRequest } from '../../utils/toInteractiveRequest'\nimport { emitAsync } from '../../utils/emitAsync'\nimport { isPropertyAccessible } from '../../utils/isPropertyAccessible'\nimport { canParseUrl } from '../../utils/canParseUrl'\nimport { createRequestId } from '../../createRequestId'\nimport { createServerErrorResponse } from '../../utils/responseUtils'\n\nexport class FetchInterceptor extends Interceptor<HttpRequestEventMap> {\n static symbol = Symbol('fetch')\n\n constructor() {\n super(FetchInterceptor.symbol)\n }\n\n protected checkEnvironment() {\n return (\n typeof globalThis !== 'undefined' &&\n typeof globalThis.fetch !== 'undefined'\n )\n }\n\n protected async setup() {\n const pureFetch = globalThis.fetch\n\n invariant(\n !(pureFetch as any)[IS_PATCHED_MODULE],\n 'Failed to patch the \"fetch\" module: already patched.'\n )\n\n globalThis.fetch = async (input, init) => {\n const requestId = createRequestId()\n\n /**\n * @note Resolve potentially relative request URL\n * against the present `location`. This is mainly\n * for native `fetch` in JSDOM.\n * @see https://github.com/mswjs/msw/issues/1625\n */\n const resolvedInput =\n typeof input === 'string' &&\n typeof location !== 'undefined' &&\n !canParseUrl(input)\n ? new URL(input, location.origin)\n : input\n\n const request = new Request(resolvedInput, init)\n\n this.logger.info('[%s] %s', request.method, request.url)\n\n const { interactiveRequest, requestController } =\n toInteractiveRequest(request)\n\n this.logger.info(\n 'emitting the \"request\" event for %d listener(s)...',\n this.emitter.listenerCount('request')\n )\n\n this.emitter.once('request', ({ requestId: pendingRequestId }) => {\n if (pendingRequestId !== requestId) {\n return\n }\n\n if (requestController.responsePromise.state === 'pending') {\n requestController.responsePromise.resolve(undefined)\n }\n })\n\n this.logger.info('awaiting for the mocked response...')\n\n const signal = interactiveRequest.signal\n const requestAborted = new DeferredPromise()\n\n // Signal isn't always defined in react-native.\n if (signal) {\n signal.addEventListener(\n 'abort',\n () => {\n requestAborted.reject(signal.reason)\n },\n { once: true }\n )\n }\n\n const respondWith = (response: Response): Response => {\n // Clone the mocked response for the \"response\" event listener.\n // This way, the listener can read the response and not lock its body\n // for the actual fetch consumer.\n const responseClone = response.clone()\n\n this.emitter.emit('response', {\n response: responseClone,\n isMockedResponse: true,\n request: interactiveRequest,\n requestId,\n })\n\n // Set the \"response.url\" property to equal the intercepted request URL.\n Object.defineProperty(response, 'url', {\n writable: false,\n enumerable: true,\n configurable: false,\n value: request.url,\n })\n\n return response\n }\n\n const resolverResult = await until<unknown, Response | undefined>(\n async () => {\n const listenersFinished = emitAsync(this.emitter, 'request', {\n request: interactiveRequest,\n requestId,\n })\n\n await Promise.race([\n requestAborted,\n // Put the listeners invocation Promise in the same race condition\n // with the request abort Promise because otherwise awaiting the listeners\n // would always yield some response (or undefined).\n listenersFinished,\n requestController.responsePromise,\n ])\n\n this.logger.info('all request listeners have been resolved!')\n\n const mockedResponse = await requestController.responsePromise\n this.logger.info('event.respondWith called with:', mockedResponse)\n\n return mockedResponse\n }\n )\n\n if (requestAborted.state === 'rejected') {\n return Promise.reject(requestAborted.rejectionReason)\n }\n\n if (resolverResult.error) {\n // Treat thrown Responses as mocked responses.\n if (resolverResult.error instanceof Response) {\n return respondWith(resolverResult.error)\n }\n\n // Unhandled exceptions in the request listeners are\n // synonymous to unhandled exceptions on the server.\n // Those are represented as 500 error responses.\n return createServerErrorResponse(resolverResult.error)\n }\n\n const mockedResponse = resolverResult.data\n\n if (mockedResponse && !request.signal?.aborted) {\n this.logger.info('received mocked response:', mockedResponse)\n\n // Reject the request Promise on mocked \"Response.error\" responses.\n if (\n isPropertyAccessible(mockedResponse, 'type') &&\n mockedResponse.type === 'error'\n ) {\n this.logger.info(\n 'received a network error response, rejecting the request promise...'\n )\n\n /**\n * Set the cause of the request promise rejection to the\n * network error Response instance. This differs from Undici.\n * Undici will forward the \"response.error\" custom property\n * as the rejection reason but for \"Response.error()\" static method\n * \"response.error\" will equal to undefined, making \"cause\" an empty Error.\n * @see https://github.com/nodejs/undici/blob/83cb522ae0157a19d149d72c7d03d46e34510d0a/lib/fetch/response.js#L344\n */\n return Promise.reject(createNetworkError(mockedResponse))\n }\n\n return respondWith(mockedResponse)\n }\n\n this.logger.info('no mocked response received!')\n\n return pureFetch(request).then((response) => {\n const responseClone = response.clone()\n this.logger.info('original fetch performed', responseClone)\n\n this.emitter.emit('response', {\n response: responseClone,\n isMockedResponse: false,\n request: interactiveRequest,\n requestId,\n })\n\n return response\n })\n }\n\n Object.defineProperty(globalThis.fetch, IS_PATCHED_MODULE, {\n enumerable: true,\n configurable: true,\n value: true,\n })\n\n this.subscriptions.push(() => {\n Object.defineProperty(globalThis.fetch, IS_PATCHED_MODULE, {\n value: undefined,\n })\n\n globalThis.fetch = pureFetch\n\n this.logger.info(\n 'restored native \"globalThis.fetch\"!',\n globalThis.fetch.name\n )\n })\n }\n}\n\nfunction createNetworkError(cause: unknown) {\n return Object.assign(new TypeError('Failed to fetch'), {\n cause,\n })\n}\n","/**\n * Returns a boolean indicating whether the given URL string\n * can be parsed into a `URL` instance.\n * A substitute for `URL.canParse()` for Node.js 18.\n */\nexport function canParseUrl(url: string): boolean {\n try {\n new URL(url)\n return true\n } catch (_error) {\n return false\n }\n}\n"],"mappings":"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","names":["mockedResponse"]}
1
+ {"version":3,"sources":["../../../../src/interceptors/fetch/index.ts","../../../../src/utils/canParseUrl.ts"],"sourcesContent":["import { invariant } from 'outvariant'\nimport { DeferredPromise } from '@open-draft/deferred-promise'\nimport { until } from '@open-draft/until'\nimport { HttpRequestEventMap, IS_PATCHED_MODULE } from '../../glossary'\nimport { Interceptor } from '../../Interceptor'\nimport { toInteractiveRequest } from '../../utils/toInteractiveRequest'\nimport { emitAsync } from '../../utils/emitAsync'\nimport { canParseUrl } from '../../utils/canParseUrl'\nimport { createRequestId } from '../../createRequestId'\nimport {\n createServerErrorResponse,\n isResponseError,\n} from '../../utils/responseUtils'\n\nexport class FetchInterceptor extends Interceptor<HttpRequestEventMap> {\n static symbol = Symbol('fetch')\n\n constructor() {\n super(FetchInterceptor.symbol)\n }\n\n protected checkEnvironment() {\n return (\n typeof globalThis !== 'undefined' &&\n typeof globalThis.fetch !== 'undefined'\n )\n }\n\n protected async setup() {\n const pureFetch = globalThis.fetch\n\n invariant(\n !(pureFetch as any)[IS_PATCHED_MODULE],\n 'Failed to patch the \"fetch\" module: already patched.'\n )\n\n globalThis.fetch = async (input, init) => {\n const requestId = createRequestId()\n\n /**\n * @note Resolve potentially relative request URL\n * against the present `location`. This is mainly\n * for native `fetch` in JSDOM.\n * @see https://github.com/mswjs/msw/issues/1625\n */\n const resolvedInput =\n typeof input === 'string' &&\n typeof location !== 'undefined' &&\n !canParseUrl(input)\n ? new URL(input, location.origin)\n : input\n\n const request = new Request(resolvedInput, init)\n\n this.logger.info('[%s] %s', request.method, request.url)\n\n const { interactiveRequest, requestController } =\n toInteractiveRequest(request)\n\n this.logger.info(\n 'emitting the \"request\" event for %d listener(s)...',\n this.emitter.listenerCount('request')\n )\n\n this.emitter.once('request', ({ requestId: pendingRequestId }) => {\n if (pendingRequestId !== requestId) {\n return\n }\n\n if (requestController.responsePromise.state === 'pending') {\n requestController.responsePromise.resolve(undefined)\n }\n })\n\n this.logger.info('awaiting for the mocked response...')\n\n const signal = interactiveRequest.signal\n const requestAborted = new DeferredPromise()\n\n // Signal isn't always defined in react-native.\n if (signal) {\n signal.addEventListener(\n 'abort',\n () => {\n requestAborted.reject(signal.reason)\n },\n { once: true }\n )\n }\n\n const responsePromise = new DeferredPromise<Response>()\n\n const respondWith = (response: Response): void => {\n this.logger.info('responding with a mock response:', response)\n\n if (this.emitter.listenerCount('response') > 0) {\n this.logger.info('emitting the \"response\" event...')\n\n // Clone the mocked response for the \"response\" event listener.\n // This way, the listener can read the response and not lock its body\n // for the actual fetch consumer.\n const responseClone = response.clone()\n\n this.emitter.emit('response', {\n response: responseClone,\n isMockedResponse: true,\n request: interactiveRequest,\n requestId,\n })\n }\n\n // Set the \"response.url\" property to equal the intercepted request URL.\n Object.defineProperty(response, 'url', {\n writable: false,\n enumerable: true,\n configurable: false,\n value: request.url,\n })\n\n responsePromise.resolve(response)\n }\n\n const errorWith = (reason: unknown): void => {\n responsePromise.reject(reason)\n }\n\n const resolverResult = await until<unknown, Response | undefined>(\n async () => {\n const listenersFinished = emitAsync(this.emitter, 'request', {\n request: interactiveRequest,\n requestId,\n })\n\n await Promise.race([\n requestAborted,\n // Put the listeners invocation Promise in the same race condition\n // with the request abort Promise because otherwise awaiting the listeners\n // would always yield some response (or undefined).\n listenersFinished,\n requestController.responsePromise,\n ])\n\n this.logger.info('all request listeners have been resolved!')\n\n const mockedResponse = await requestController.responsePromise\n this.logger.info('event.respondWith called with:', mockedResponse)\n\n return mockedResponse\n }\n )\n\n if (requestAborted.state === 'rejected') {\n this.logger.info(\n 'request has been aborted:',\n requestAborted.rejectionReason\n )\n\n responsePromise.reject(requestAborted.rejectionReason)\n return responsePromise\n }\n\n if (resolverResult.error) {\n this.logger.info(\n 'request listerner threw an error:',\n resolverResult.error\n )\n\n // Treat thrown Responses as mocked responses.\n if (resolverResult.error instanceof Response) {\n // Treat thrown Response.error() as a request error.\n if (isResponseError(resolverResult.error)) {\n errorWith(createNetworkError(resolverResult.error))\n } else {\n // Treat the rest of thrown Responses as mocked responses.\n respondWith(resolverResult.error)\n }\n }\n\n // Emit the \"unhandledException\" interceptor event so the client\n // can opt-out from exceptions translating to 500 error responses.\n\n if (this.emitter.listenerCount('unhandledException') > 0) {\n await emitAsync(this.emitter, 'unhandledException', {\n error: resolverResult.error,\n request,\n requestId,\n controller: {\n respondWith,\n errorWith,\n },\n })\n\n if (responsePromise.state !== 'pending') {\n return responsePromise\n }\n }\n\n // Unhandled exceptions in the request listeners are\n // synonymous to unhandled exceptions on the server.\n // Those are represented as 500 error responses.\n respondWith(createServerErrorResponse(resolverResult.error))\n return responsePromise\n }\n\n const mockedResponse = resolverResult.data\n\n if (mockedResponse && !request.signal?.aborted) {\n this.logger.info('received mocked response:', mockedResponse)\n\n // Reject the request Promise on mocked \"Response.error\" responses.\n if (isResponseError(mockedResponse)) {\n this.logger.info(\n 'received a network error response, rejecting the request promise...'\n )\n\n /**\n * Set the cause of the request promise rejection to the\n * network error Response instance. This differs from Undici.\n * Undici will forward the \"response.error\" custom property\n * as the rejection reason but for \"Response.error()\" static method\n * \"response.error\" will equal to undefined, making \"cause\" an empty Error.\n * @see https://github.com/nodejs/undici/blob/83cb522ae0157a19d149d72c7d03d46e34510d0a/lib/fetch/response.js#L344\n */\n errorWith(createNetworkError(mockedResponse))\n } else {\n respondWith(mockedResponse)\n }\n\n return responsePromise\n }\n\n this.logger.info('no mocked response received!')\n\n return pureFetch(request).then((response) => {\n this.logger.info('original fetch performed', response)\n\n if (this.emitter.listenerCount('response') > 0) {\n this.logger.info('emitting the \"response\" event...')\n\n const responseClone = response.clone()\n\n this.emitter.emit('response', {\n response: responseClone,\n isMockedResponse: false,\n request: interactiveRequest,\n requestId,\n })\n }\n\n return response\n })\n }\n\n Object.defineProperty(globalThis.fetch, IS_PATCHED_MODULE, {\n enumerable: true,\n configurable: true,\n value: true,\n })\n\n this.subscriptions.push(() => {\n Object.defineProperty(globalThis.fetch, IS_PATCHED_MODULE, {\n value: undefined,\n })\n\n globalThis.fetch = pureFetch\n\n this.logger.info(\n 'restored native \"globalThis.fetch\"!',\n globalThis.fetch.name\n )\n })\n }\n}\n\nfunction createNetworkError(cause: unknown) {\n return Object.assign(new TypeError('Failed to fetch'), {\n cause,\n })\n}\n","/**\n * Returns a boolean indicating whether the given URL string\n * can be parsed into a `URL` instance.\n * A substitute for `URL.canParse()` for Node.js 18.\n */\nexport function canParseUrl(url: string): boolean {\n try {\n new URL(url)\n return true\n } catch (_error) {\n return false\n }\n}\n"],"mappings":"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","names":["mockedResponse"]}
@@ -3,7 +3,7 @@ import { XMLHttpRequestInterceptor } from '../interceptors/XMLHttpRequest/index.
3
3
  import 'http';
4
4
  import 'https';
5
5
  import 'strict-event-emitter';
6
- import '../Interceptor-6696a18d.js';
6
+ import '../Interceptor-88ee47c0.js';
7
7
  import '@open-draft/deferred-promise';
8
8
  import '@open-draft/logger';
9
9
 
@@ -1,19 +1,18 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
2
 
3
- var _chunkUXEUSYDYjs = require('../chunk-UXEUSYDY.js');
3
+ var _chunkHAIWBQD5js = require('../chunk-HAIWBQD5.js');
4
4
 
5
5
 
6
- var _chunkM4JXH4RPjs = require('../chunk-M4JXH4RP.js');
6
+ var _chunkAPT7KA3Bjs = require('../chunk-APT7KA3B.js');
7
7
  require('../chunk-LK6DILFK.js');
8
- require('../chunk-Y6GRL6UD.js');
9
- require('../chunk-FZJKKO5H.js');
8
+ require('../chunk-EIBTX65O.js');
10
9
  require('../chunk-MQJ3JOOK.js');
11
- require('../chunk-KRDNUBDZ.js');
10
+ require('../chunk-E4AC7YAC.js');
12
11
 
13
12
  // src/presets/node.ts
14
13
  var node_default = [
15
- new (0, _chunkUXEUSYDYjs.ClientRequestInterceptor)(),
16
- new (0, _chunkM4JXH4RPjs.XMLHttpRequestInterceptor)()
14
+ new (0, _chunkHAIWBQD5js.ClientRequestInterceptor)(),
15
+ new (0, _chunkAPT7KA3Bjs.XMLHttpRequestInterceptor)()
17
16
  ];
18
17
 
19
18
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/presets/node.ts"],"names":[],"mappings":";;;;;;;;;;;;;AAOA,IAAO,eAAQ;AAAA,EACb,IAAI,yBAAyB;AAAA,EAC7B,IAAI,0BAA0B;AAChC","sourcesContent":["import { ClientRequestInterceptor } from '../interceptors/ClientRequest'\nimport { XMLHttpRequestInterceptor } from '../interceptors/XMLHttpRequest'\n\n/**\n * The default preset provisions the interception of requests\n * regardless of their type (http/https/XMLHttpRequest).\n */\nexport default [\n new ClientRequestInterceptor(),\n new XMLHttpRequestInterceptor(),\n] as const\n"]}
1
+ {"version":3,"sources":["../../../src/presets/node.ts"],"names":[],"mappings":";;;;;;;;;;;;AAOA,IAAO,eAAQ;AAAA,EACb,IAAI,yBAAyB;AAAA,EAC7B,IAAI,0BAA0B;AAChC","sourcesContent":["import { ClientRequestInterceptor } from '../interceptors/ClientRequest'\nimport { XMLHttpRequestInterceptor } from '../interceptors/XMLHttpRequest'\n\n/**\n * The default preset provisions the interception of requests\n * regardless of their type (http/https/XMLHttpRequest).\n */\nexport default [\n new ClientRequestInterceptor(),\n new XMLHttpRequestInterceptor(),\n] as const\n"]}
@@ -1,14 +1,13 @@
1
1
  import {
2
2
  ClientRequestInterceptor
3
- } from "../chunk-L576JLIX.mjs";
3
+ } from "../chunk-JMNEFEYU.mjs";
4
4
  import {
5
5
  XMLHttpRequestInterceptor
6
- } from "../chunk-KGNKRQ7B.mjs";
6
+ } from "../chunk-KSHIDGUL.mjs";
7
7
  import "../chunk-6HYIRFX2.mjs";
8
- import "../chunk-DERTLGL3.mjs";
9
- import "../chunk-HAGW22AN.mjs";
8
+ import "../chunk-OJ6O4LSC.mjs";
10
9
  import "../chunk-OUWBQF3Z.mjs";
11
- import "../chunk-DQ5DO3KN.mjs";
10
+ import "../chunk-Q7POAM5N.mjs";
12
11
 
13
12
  // src/presets/node.ts
14
13
  var node_default = [
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/presets/node.ts"],"sourcesContent":["import { ClientRequestInterceptor } from '../interceptors/ClientRequest'\nimport { XMLHttpRequestInterceptor } from '../interceptors/XMLHttpRequest'\n\n/**\n * The default preset provisions the interception of requests\n * regardless of their type (http/https/XMLHttpRequest).\n */\nexport default [\n new ClientRequestInterceptor(),\n new XMLHttpRequestInterceptor(),\n] as const\n"],"mappings":";;;;;;;;;;;;;AAOA,IAAO,eAAQ;AAAA,EACb,IAAI,yBAAyB;AAAA,EAC7B,IAAI,0BAA0B;AAChC;","names":[]}
1
+ {"version":3,"sources":["../../../src/presets/node.ts"],"sourcesContent":["import { ClientRequestInterceptor } from '../interceptors/ClientRequest'\nimport { XMLHttpRequestInterceptor } from '../interceptors/XMLHttpRequest'\n\n/**\n * The default preset provisions the interception of requests\n * regardless of their type (http/https/XMLHttpRequest).\n */\nexport default [\n new ClientRequestInterceptor(),\n new XMLHttpRequestInterceptor(),\n] as const\n"],"mappings":";;;;;;;;;;;;AAOA,IAAO,eAAQ;AAAA,EACb,IAAI,yBAAyB;AAAA,EAC7B,IAAI,0BAA0B;AAChC;","names":[]}
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.28.3",
4
+ "version": "0.29.0",
5
5
  "main": "./lib/node/index.js",
6
6
  "module": "./lib/node/index.mjs",
7
7
  "types": "./lib/node/index.d.ts",
package/src/glossary.ts CHANGED
@@ -19,4 +19,15 @@ export type HttpRequestEventMap = {
19
19
  requestId: string
20
20
  }
21
21
  ]
22
+ unhandledException: [
23
+ args: {
24
+ error: unknown
25
+ request: Request
26
+ requestId: string
27
+ controller: {
28
+ respondWith(response: Response): void
29
+ errorWith(error?: Error): void
30
+ }
31
+ }
32
+ ]
22
33
  }