@mswjs/interceptors 0.32.2 → 0.33.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 (118) hide show
  1. package/README.md +35 -7
  2. package/lib/browser/{chunk-732REFPX.mjs → chunk-5ETVT6GU.mjs} +28 -79
  3. package/lib/browser/chunk-5ETVT6GU.mjs.map +1 -0
  4. package/lib/browser/chunk-6MBJUL74.js +142 -0
  5. package/lib/browser/chunk-6MBJUL74.js.map +1 -0
  6. package/lib/browser/chunk-7A4UJNSW.mjs +196 -0
  7. package/lib/browser/chunk-7A4UJNSW.mjs.map +1 -0
  8. package/lib/browser/{chunk-PSX5J3RF.js → chunk-7GVJEW45.js} +30 -81
  9. package/lib/browser/chunk-7GVJEW45.js.map +1 -0
  10. package/lib/browser/{chunk-2CRB3JAQ.js → chunk-FXSPMSSQ.js} +1 -1
  11. package/lib/browser/chunk-FXSPMSSQ.js.map +1 -0
  12. package/lib/browser/{chunk-OMISYKWR.mjs → chunk-GGUENBDN.mjs} +1 -1
  13. package/lib/browser/chunk-GGUENBDN.mjs.map +1 -0
  14. package/lib/browser/chunk-NU2MPFD6.mjs +142 -0
  15. package/lib/browser/chunk-NU2MPFD6.mjs.map +1 -0
  16. package/lib/browser/chunk-VRKVKT62.js +196 -0
  17. package/lib/browser/chunk-VRKVKT62.js.map +1 -0
  18. package/lib/browser/glossary-7d7adb4b.d.ts +66 -0
  19. package/lib/browser/index.d.ts +1 -1
  20. package/lib/browser/index.js +2 -2
  21. package/lib/browser/index.mjs +1 -1
  22. package/lib/browser/interceptors/XMLHttpRequest/index.d.ts +2 -6
  23. package/lib/browser/interceptors/XMLHttpRequest/index.js +4 -4
  24. package/lib/browser/interceptors/XMLHttpRequest/index.mjs +3 -3
  25. package/lib/browser/interceptors/fetch/index.d.ts +1 -1
  26. package/lib/browser/interceptors/fetch/index.js +4 -4
  27. package/lib/browser/interceptors/fetch/index.mjs +3 -3
  28. package/lib/browser/presets/browser.d.ts +1 -1
  29. package/lib/browser/presets/browser.js +6 -6
  30. package/lib/browser/presets/browser.mjs +4 -4
  31. package/lib/node/{BatchInterceptor-2badedde.d.ts → BatchInterceptor-13d40c95.d.ts} +1 -1
  32. package/lib/node/{Interceptor-88ee47c0.d.ts → Interceptor-a31b1217.d.ts} +35 -13
  33. package/lib/node/RemoteHttpInterceptor.d.ts +2 -2
  34. package/lib/node/RemoteHttpInterceptor.js +55 -52
  35. package/lib/node/RemoteHttpInterceptor.js.map +1 -1
  36. package/lib/node/RemoteHttpInterceptor.mjs +53 -50
  37. package/lib/node/RemoteHttpInterceptor.mjs.map +1 -1
  38. package/lib/node/{chunk-CFRXZJO4.js → chunk-2MWIWEWV.js} +31 -72
  39. package/lib/node/chunk-2MWIWEWV.js.map +1 -0
  40. package/lib/node/{chunk-2COJKQQB.js → chunk-42632LKH.js} +3 -3
  41. package/lib/node/chunk-5WWNCLB3.js +196 -0
  42. package/lib/node/chunk-5WWNCLB3.js.map +1 -0
  43. package/lib/node/{chunk-TGTPXCLF.mjs → chunk-BUCULLYM.mjs} +1 -1
  44. package/lib/node/{chunk-TGTPXCLF.mjs.map → chunk-BUCULLYM.mjs.map} +1 -1
  45. package/lib/node/{chunk-OJ6O4LSC.mjs → chunk-BZ3Y7YV5.mjs} +1 -1
  46. package/lib/node/chunk-BZ3Y7YV5.mjs.map +1 -0
  47. package/lib/node/{chunk-CMVICWQS.mjs → chunk-CU3YXMM4.mjs} +23 -64
  48. package/lib/node/chunk-CU3YXMM4.mjs.map +1 -0
  49. package/lib/node/{chunk-PNWPIDEL.mjs → chunk-HGQLG7KE.mjs} +2 -2
  50. package/lib/node/{chunk-EIBTX65O.js → chunk-IDEEMJ3F.js} +1 -1
  51. package/lib/node/chunk-IDEEMJ3F.js.map +1 -0
  52. package/lib/node/chunk-KY3RJ2M3.mjs +196 -0
  53. package/lib/node/chunk-KY3RJ2M3.mjs.map +1 -0
  54. package/lib/node/{chunk-PYD4E2EJ.js → chunk-P6QG76R3.js} +34 -85
  55. package/lib/node/chunk-P6QG76R3.js.map +1 -0
  56. package/lib/node/{chunk-DV4PBH4D.mjs → chunk-TOV4TYIX.mjs} +29 -80
  57. package/lib/node/chunk-TOV4TYIX.mjs.map +1 -0
  58. package/lib/node/{chunk-BFLYGQ6D.js → chunk-YGM3BCJU.js} +1 -1
  59. package/lib/node/chunk-YGM3BCJU.js.map +1 -0
  60. package/lib/node/index.d.ts +2 -2
  61. package/lib/node/index.js +4 -4
  62. package/lib/node/index.mjs +3 -3
  63. package/lib/node/interceptors/ClientRequest/index.d.ts +2 -2
  64. package/lib/node/interceptors/ClientRequest/index.js +4 -4
  65. package/lib/node/interceptors/ClientRequest/index.mjs +3 -3
  66. package/lib/node/interceptors/XMLHttpRequest/index.d.ts +2 -6
  67. package/lib/node/interceptors/XMLHttpRequest/index.js +5 -5
  68. package/lib/node/interceptors/XMLHttpRequest/index.mjs +4 -4
  69. package/lib/node/interceptors/fetch/index.d.ts +1 -1
  70. package/lib/node/interceptors/fetch/index.js +52 -123
  71. package/lib/node/interceptors/fetch/index.js.map +1 -1
  72. package/lib/node/interceptors/fetch/index.mjs +50 -121
  73. package/lib/node/interceptors/fetch/index.mjs.map +1 -1
  74. package/lib/node/presets/node.d.ts +1 -1
  75. package/lib/node/presets/node.js +7 -7
  76. package/lib/node/presets/node.mjs +5 -5
  77. package/package.json +2 -2
  78. package/src/InterceptorError.ts +7 -0
  79. package/src/RemoteHttpInterceptor.ts +62 -57
  80. package/src/RequestController.test.ts +49 -0
  81. package/src/RequestController.ts +81 -0
  82. package/src/glossary.ts +4 -6
  83. package/src/interceptors/ClientRequest/MockHttpSocket.ts +1 -1
  84. package/src/interceptors/ClientRequest/index.test.ts +2 -33
  85. package/src/interceptors/ClientRequest/index.ts +21 -82
  86. package/src/interceptors/XMLHttpRequest/XMLHttpRequestController.ts +1 -1
  87. package/src/interceptors/XMLHttpRequest/XMLHttpRequestProxy.ts +27 -108
  88. package/src/interceptors/XMLHttpRequest/index.ts +0 -6
  89. package/src/interceptors/fetch/index.ts +52 -169
  90. package/src/utils/handleRequest.ts +213 -0
  91. package/src/utils/responseUtils.ts +4 -4
  92. package/lib/browser/chunk-2CRB3JAQ.js.map +0 -1
  93. package/lib/browser/chunk-732REFPX.mjs.map +0 -1
  94. package/lib/browser/chunk-MAEPOYB6.mjs +0 -213
  95. package/lib/browser/chunk-MAEPOYB6.mjs.map +0 -1
  96. package/lib/browser/chunk-MQJ3JOOK.js +0 -49
  97. package/lib/browser/chunk-MQJ3JOOK.js.map +0 -1
  98. package/lib/browser/chunk-OMISYKWR.mjs.map +0 -1
  99. package/lib/browser/chunk-OUWBQF3Z.mjs +0 -49
  100. package/lib/browser/chunk-OUWBQF3Z.mjs.map +0 -1
  101. package/lib/browser/chunk-PSX5J3RF.js.map +0 -1
  102. package/lib/browser/chunk-WBHIW62P.js +0 -213
  103. package/lib/browser/chunk-WBHIW62P.js.map +0 -1
  104. package/lib/browser/glossary-1c204f45.d.ts +0 -44
  105. package/lib/node/chunk-BFLYGQ6D.js.map +0 -1
  106. package/lib/node/chunk-CFRXZJO4.js.map +0 -1
  107. package/lib/node/chunk-CMVICWQS.mjs.map +0 -1
  108. package/lib/node/chunk-DV4PBH4D.mjs.map +0 -1
  109. package/lib/node/chunk-EIBTX65O.js.map +0 -1
  110. package/lib/node/chunk-KWV3JXSI.mjs +0 -49
  111. package/lib/node/chunk-KWV3JXSI.mjs.map +0 -1
  112. package/lib/node/chunk-OJ6O4LSC.mjs.map +0 -1
  113. package/lib/node/chunk-PYD4E2EJ.js.map +0 -1
  114. package/lib/node/chunk-UXCYRE4F.js +0 -49
  115. package/lib/node/chunk-UXCYRE4F.js.map +0 -1
  116. package/src/utils/toInteractiveRequest.ts +0 -23
  117. /package/lib/node/{chunk-2COJKQQB.js.map → chunk-42632LKH.js.map} +0 -0
  118. /package/lib/node/{chunk-PNWPIDEL.mjs.map → chunk-HGQLG7KE.mjs.map} +0 -0
@@ -214,4 +214,4 @@ function isResponseError(response) {
214
214
 
215
215
 
216
216
  exports.INTERNAL_REQUEST_ID_HEADER_NAME = INTERNAL_REQUEST_ID_HEADER_NAME; exports.getGlobalSymbol = getGlobalSymbol; exports.deleteGlobalSymbol = deleteGlobalSymbol; exports.InterceptorReadyState = InterceptorReadyState; exports.Interceptor = Interceptor; exports.createRequestId = createRequestId; exports.isPropertyAccessible = isPropertyAccessible; exports.RESPONSE_STATUS_CODES_WITHOUT_BODY = RESPONSE_STATUS_CODES_WITHOUT_BODY; exports.isResponseWithoutBody = isResponseWithoutBody; exports.createServerErrorResponse = createServerErrorResponse; exports.isResponseError = isResponseError;
217
- //# sourceMappingURL=chunk-BFLYGQ6D.js.map
217
+ //# sourceMappingURL=chunk-YGM3BCJU.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/Interceptor.ts","../../src/createRequestId.ts","../../src/utils/isPropertyAccessible.ts","../../src/utils/responseUtils.ts"],"names":["InterceptorReadyState"],"mappings":"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","sourcesContent":["import { Logger } from '@open-draft/logger'\nimport { Emitter, Listener } from 'strict-event-emitter'\n\nexport type InterceptorEventMap = Record<string, any>\nexport type InterceptorSubscription = () => void\n\n/**\n * Request header name to detect when a single request\n * is being handled by nested interceptors (XHR -> ClientRequest).\n * Obscure by design to prevent collisions with user-defined headers.\n * Ideally, come up with the Interceptor-level mechanism for this.\n * @see https://github.com/mswjs/interceptors/issues/378\n */\nexport const INTERNAL_REQUEST_ID_HEADER_NAME =\n 'x-interceptors-internal-request-id'\n\nexport function getGlobalSymbol<V>(symbol: Symbol): V | undefined {\n return (\n // @ts-ignore https://github.com/Microsoft/TypeScript/issues/24587\n globalThis[symbol] || undefined\n )\n}\n\nfunction setGlobalSymbol(symbol: Symbol, value: any): void {\n // @ts-ignore\n globalThis[symbol] = value\n}\n\nexport function deleteGlobalSymbol(symbol: Symbol): void {\n // @ts-ignore\n delete globalThis[symbol]\n}\n\nexport enum InterceptorReadyState {\n INACTIVE = 'INACTIVE',\n APPLYING = 'APPLYING',\n APPLIED = 'APPLIED',\n DISPOSING = 'DISPOSING',\n DISPOSED = 'DISPOSED',\n}\n\nexport type ExtractEventNames<Events extends Record<string, any>> =\n Events extends Record<infer EventName, any> ? EventName : never\n\nexport class Interceptor<Events extends InterceptorEventMap> {\n protected emitter: Emitter<Events>\n protected subscriptions: Array<InterceptorSubscription>\n protected logger: Logger\n\n public readyState: InterceptorReadyState\n\n constructor(private readonly symbol: symbol) {\n this.readyState = InterceptorReadyState.INACTIVE\n\n this.emitter = new Emitter()\n this.subscriptions = []\n this.logger = new Logger(symbol.description!)\n\n // Do not limit the maximum number of listeners\n // so not to limit the maximum amount of parallel events emitted.\n this.emitter.setMaxListeners(0)\n\n this.logger.info('constructing the interceptor...')\n }\n\n /**\n * Determine if this interceptor can be applied\n * in the current environment.\n */\n protected checkEnvironment(): boolean {\n return true\n }\n\n /**\n * Apply this interceptor to the current process.\n * Returns an already running interceptor instance if it's present.\n */\n public apply(): void {\n const logger = this.logger.extend('apply')\n logger.info('applying the interceptor...')\n\n if (this.readyState === InterceptorReadyState.APPLIED) {\n logger.info('intercepted already applied!')\n return\n }\n\n const shouldApply = this.checkEnvironment()\n\n if (!shouldApply) {\n logger.info('the interceptor cannot be applied in this environment!')\n return\n }\n\n this.readyState = InterceptorReadyState.APPLYING\n\n // Whenever applying a new interceptor, check if it hasn't been applied already.\n // This enables to apply the same interceptor multiple times, for example from a different\n // interceptor, only proxying events but keeping the stubs in a single place.\n const runningInstance = this.getInstance()\n\n if (runningInstance) {\n logger.info('found a running instance, reusing...')\n\n // Proxy any listeners you set on this instance to the running instance.\n this.on = (event, listener) => {\n logger.info('proxying the \"%s\" listener', event)\n\n // Add listeners to the running instance so they appear\n // at the top of the event listeners list and are executed first.\n runningInstance.emitter.addListener(event, listener)\n\n // Ensure that once this interceptor instance is disposed,\n // it removes all listeners it has appended to the running interceptor instance.\n this.subscriptions.push(() => {\n runningInstance.emitter.removeListener(event, listener)\n logger.info('removed proxied \"%s\" listener!', event)\n })\n\n return this\n }\n\n this.readyState = InterceptorReadyState.APPLIED\n\n return\n }\n\n logger.info('no running instance found, setting up a new instance...')\n\n // Setup the interceptor.\n this.setup()\n\n // Store the newly applied interceptor instance globally.\n this.setInstance()\n\n this.readyState = InterceptorReadyState.APPLIED\n }\n\n /**\n * Setup the module augments and stubs necessary for this interceptor.\n * This method is not run if there's a running interceptor instance\n * to prevent instantiating an interceptor multiple times.\n */\n protected setup(): void {}\n\n /**\n * Listen to the interceptor's public events.\n */\n public on<EventName extends ExtractEventNames<Events>>(\n event: EventName,\n listener: Listener<Events[EventName]>\n ): this {\n const logger = this.logger.extend('on')\n\n if (\n this.readyState === InterceptorReadyState.DISPOSING ||\n this.readyState === InterceptorReadyState.DISPOSED\n ) {\n logger.info('cannot listen to events, already disposed!')\n return this\n }\n\n logger.info('adding \"%s\" event listener:', event, listener)\n\n this.emitter.on(event, listener)\n return this\n }\n\n public once<EventName extends ExtractEventNames<Events>>(\n event: EventName,\n listener: Listener<Events[EventName]>\n ): this {\n this.emitter.once(event, listener)\n return this\n }\n\n public off<EventName extends ExtractEventNames<Events>>(\n event: EventName,\n listener: Listener<Events[EventName]>\n ): this {\n this.emitter.off(event, listener)\n return this\n }\n\n public removeAllListeners<EventName extends ExtractEventNames<Events>>(\n event?: EventName\n ): this {\n this.emitter.removeAllListeners(event)\n return this\n }\n\n /**\n * Disposes of any side-effects this interceptor has introduced.\n */\n public dispose(): void {\n const logger = this.logger.extend('dispose')\n\n if (this.readyState === InterceptorReadyState.DISPOSED) {\n logger.info('cannot dispose, already disposed!')\n return\n }\n\n logger.info('disposing the interceptor...')\n this.readyState = InterceptorReadyState.DISPOSING\n\n if (!this.getInstance()) {\n logger.info('no interceptors running, skipping dispose...')\n return\n }\n\n // Delete the global symbol as soon as possible,\n // indicating that the interceptor is no longer running.\n this.clearInstance()\n\n logger.info('global symbol deleted:', getGlobalSymbol(this.symbol))\n\n if (this.subscriptions.length > 0) {\n logger.info('disposing of %d subscriptions...', this.subscriptions.length)\n\n for (const dispose of this.subscriptions) {\n dispose()\n }\n\n this.subscriptions = []\n\n logger.info('disposed of all subscriptions!', this.subscriptions.length)\n }\n\n this.emitter.removeAllListeners()\n logger.info('destroyed the listener!')\n\n this.readyState = InterceptorReadyState.DISPOSED\n }\n\n private getInstance(): this | undefined {\n const instance = getGlobalSymbol<this>(this.symbol)\n this.logger.info('retrieved global instance:', instance?.constructor?.name)\n return instance\n }\n\n private setInstance(): void {\n setGlobalSymbol(this.symbol, this)\n this.logger.info('set global instance!', this.symbol.description)\n }\n\n private clearInstance(): void {\n deleteGlobalSymbol(this.symbol)\n this.logger.info('cleared global instance!', this.symbol.description)\n }\n}\n","/**\n * Generate a random ID string to represent a request.\n * @example\n * createRequestId()\n * // \"f774b6c9c600f\"\n */\nexport function createRequestId(): string {\n return Math.random().toString(16).slice(2)\n}\n","/**\n * A function that validates if property access is possible on an object\n * without throwing. It returns `true` if the property access is possible\n * and `false` otherwise.\n *\n * Environments like miniflare will throw on property access on certain objects\n * like Request and Response, for unimplemented properties.\n */\nexport function isPropertyAccessible<Obj extends Record<string, any>>(\n obj: Obj,\n key: keyof Obj\n) {\n try {\n obj[key]\n return true\n } catch {\n return false\n }\n}\n","import { isPropertyAccessible } from './isPropertyAccessible'\n\n/**\n * Response status codes for responses that cannot have body.\n * @see https://fetch.spec.whatwg.org/#statuses\n */\nexport const RESPONSE_STATUS_CODES_WITHOUT_BODY = new Set([\n 101, 103, 204, 205, 304,\n])\n\n/**\n * Returns a boolean indicating whether the given response status\n * code represents a response that cannot have a body.\n */\nexport function isResponseWithoutBody(status: number): boolean {\n return RESPONSE_STATUS_CODES_WITHOUT_BODY.has(status)\n}\n\n/**\n * Creates a generic 500 Unhandled Exception response.\n */\nexport function createServerErrorResponse(body: unknown): Response {\n return new Response(\n JSON.stringify(\n body instanceof Error\n ? {\n name: body.name,\n message: body.message,\n stack: body.stack,\n }\n : body\n ),\n {\n status: 500,\n statusText: 'Unhandled Exception',\n headers: {\n 'Content-Type': 'application/json',\n },\n }\n )\n}\n\nexport type ResponseError = Response & { type: 'error' }\n\n/**\n * Check if the given response is a `Response.error()`.\n *\n * @note Some environments, like Miniflare (Cloudflare) do not\n * implement the \"Response.type\" property and throw on its access.\n * Safely check if we can access \"type\" on \"Response\" before continuing.\n * @see https://github.com/mswjs/msw/issues/1834\n */\nexport function isResponseError(response: Response): response is ResponseError {\n return isPropertyAccessible(response, 'type') && response.type === 'error'\n}\n"]}
@@ -1,5 +1,5 @@
1
- export { E as ExtractEventNames, H as HttpRequestEventMap, c as INTERNAL_REQUEST_ID_HEADER_NAME, I as IS_PATCHED_MODULE, f as Interceptor, a as InterceptorEventMap, e as InterceptorReadyState, b as InterceptorSubscription, R as RequestCredentials, d as deleteGlobalSymbol, g as getGlobalSymbol } from './Interceptor-88ee47c0.js';
2
- export { a as BatchInterceptor, B as BatchInterceptorOptions, E as ExtractEventMapType } from './BatchInterceptor-2badedde.js';
1
+ export { E as ExtractEventNames, H as HttpRequestEventMap, c as INTERNAL_REQUEST_ID_HEADER_NAME, I as IS_PATCHED_MODULE, f as Interceptor, a as InterceptorEventMap, e as InterceptorReadyState, b as InterceptorSubscription, R as RequestCredentials, d as deleteGlobalSymbol, g as getGlobalSymbol } from './Interceptor-a31b1217.js';
2
+ export { a as BatchInterceptor, B as BatchInterceptorOptions, E as ExtractEventMapType } from './BatchInterceptor-13d40c95.js';
3
3
  import '@open-draft/deferred-promise';
4
4
  import '@open-draft/logger';
5
5
  import 'strict-event-emitter';
package/lib/node/index.js CHANGED
@@ -1,13 +1,13 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
2
 
3
- var _chunk2COJKQQBjs = require('./chunk-2COJKQQB.js');
3
+ var _chunk42632LKHjs = require('./chunk-42632LKH.js');
4
4
 
5
5
 
6
6
 
7
7
  var _chunkLK6DILFKjs = require('./chunk-LK6DILFK.js');
8
8
 
9
9
 
10
- var _chunkEIBTX65Ojs = require('./chunk-EIBTX65O.js');
10
+ var _chunkIDEEMJ3Fjs = require('./chunk-IDEEMJ3F.js');
11
11
 
12
12
 
13
13
 
@@ -16,7 +16,7 @@ var _chunkEIBTX65Ojs = require('./chunk-EIBTX65O.js');
16
16
 
17
17
 
18
18
 
19
- var _chunkBFLYGQ6Djs = require('./chunk-BFLYGQ6D.js');
19
+ var _chunkYGM3BCJUjs = require('./chunk-YGM3BCJU.js');
20
20
 
21
21
  // src/utils/getCleanUrl.ts
22
22
  function getCleanUrl(url, isAbsolute = true) {
@@ -35,5 +35,5 @@ function getCleanUrl(url, isAbsolute = true) {
35
35
 
36
36
 
37
37
 
38
- exports.BatchInterceptor = _chunk2COJKQQBjs.BatchInterceptor; exports.INTERNAL_REQUEST_ID_HEADER_NAME = _chunkBFLYGQ6Djs.INTERNAL_REQUEST_ID_HEADER_NAME; exports.IS_PATCHED_MODULE = _chunkEIBTX65Ojs.IS_PATCHED_MODULE; exports.Interceptor = _chunkBFLYGQ6Djs.Interceptor; exports.InterceptorReadyState = _chunkBFLYGQ6Djs.InterceptorReadyState; exports.createRequestId = _chunkBFLYGQ6Djs.createRequestId; exports.decodeBuffer = _chunkLK6DILFKjs.decodeBuffer; exports.deleteGlobalSymbol = _chunkBFLYGQ6Djs.deleteGlobalSymbol; exports.encodeBuffer = _chunkLK6DILFKjs.encodeBuffer; exports.getCleanUrl = getCleanUrl; exports.getGlobalSymbol = _chunkBFLYGQ6Djs.getGlobalSymbol; exports.isResponseWithoutBody = _chunkBFLYGQ6Djs.isResponseWithoutBody;
38
+ exports.BatchInterceptor = _chunk42632LKHjs.BatchInterceptor; exports.INTERNAL_REQUEST_ID_HEADER_NAME = _chunkYGM3BCJUjs.INTERNAL_REQUEST_ID_HEADER_NAME; exports.IS_PATCHED_MODULE = _chunkIDEEMJ3Fjs.IS_PATCHED_MODULE; exports.Interceptor = _chunkYGM3BCJUjs.Interceptor; exports.InterceptorReadyState = _chunkYGM3BCJUjs.InterceptorReadyState; exports.createRequestId = _chunkYGM3BCJUjs.createRequestId; exports.decodeBuffer = _chunkLK6DILFKjs.decodeBuffer; exports.deleteGlobalSymbol = _chunkYGM3BCJUjs.deleteGlobalSymbol; exports.encodeBuffer = _chunkLK6DILFKjs.encodeBuffer; exports.getCleanUrl = getCleanUrl; exports.getGlobalSymbol = _chunkYGM3BCJUjs.getGlobalSymbol; exports.isResponseWithoutBody = _chunkYGM3BCJUjs.isResponseWithoutBody;
39
39
  //# sourceMappingURL=index.js.map
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  BatchInterceptor
3
- } from "./chunk-PNWPIDEL.mjs";
3
+ } from "./chunk-HGQLG7KE.mjs";
4
4
  import {
5
5
  decodeBuffer,
6
6
  encodeBuffer
7
7
  } from "./chunk-6HYIRFX2.mjs";
8
8
  import {
9
9
  IS_PATCHED_MODULE
10
- } from "./chunk-OJ6O4LSC.mjs";
10
+ } from "./chunk-BZ3Y7YV5.mjs";
11
11
  import {
12
12
  INTERNAL_REQUEST_ID_HEADER_NAME,
13
13
  Interceptor,
@@ -16,7 +16,7 @@ import {
16
16
  deleteGlobalSymbol,
17
17
  getGlobalSymbol,
18
18
  isResponseWithoutBody
19
- } from "./chunk-TGTPXCLF.mjs";
19
+ } from "./chunk-BUCULLYM.mjs";
20
20
 
21
21
  // src/utils/getCleanUrl.ts
22
22
  function getCleanUrl(url, isAbsolute = true) {
@@ -1,4 +1,4 @@
1
- import { f as Interceptor, H as HttpRequestEventMap } from '../../Interceptor-88ee47c0.js';
1
+ import { f as Interceptor, H as HttpRequestEventMap } from '../../Interceptor-a31b1217.js';
2
2
  import net from 'node:net';
3
3
  import '@open-draft/deferred-promise';
4
4
  import '@open-draft/logger';
@@ -70,7 +70,7 @@ declare class MockHttpSocket extends MockSocket {
70
70
  /**
71
71
  * Close this socket connection with the given error.
72
72
  */
73
- errorWith(error: Error): void;
73
+ errorWith(error?: Error): void;
74
74
  private mockConnect;
75
75
  private flushWriteBuffer;
76
76
  private onRequestStart;
@@ -1,9 +1,9 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
2
 
3
- var _chunkCFRXZJO4js = require('../../chunk-CFRXZJO4.js');
4
- require('../../chunk-UXCYRE4F.js');
5
- require('../../chunk-BFLYGQ6D.js');
3
+ var _chunk2MWIWEWVjs = require('../../chunk-2MWIWEWV.js');
4
+ require('../../chunk-5WWNCLB3.js');
5
+ require('../../chunk-YGM3BCJU.js');
6
6
 
7
7
 
8
- exports.ClientRequestInterceptor = _chunkCFRXZJO4js.ClientRequestInterceptor;
8
+ exports.ClientRequestInterceptor = _chunk2MWIWEWVjs.ClientRequestInterceptor;
9
9
  //# sourceMappingURL=index.js.map
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  ClientRequestInterceptor
3
- } from "../../chunk-CMVICWQS.mjs";
4
- import "../../chunk-KWV3JXSI.mjs";
5
- import "../../chunk-TGTPXCLF.mjs";
3
+ } from "../../chunk-CU3YXMM4.mjs";
4
+ import "../../chunk-KY3RJ2M3.mjs";
5
+ import "../../chunk-BUCULLYM.mjs";
6
6
  export {
7
7
  ClientRequestInterceptor
8
8
  };
@@ -1,12 +1,8 @@
1
1
  import { Emitter } from 'strict-event-emitter';
2
- import { h as InteractiveRequest, H as HttpRequestEventMap, f as Interceptor } from '../../Interceptor-88ee47c0.js';
2
+ import { H as HttpRequestEventMap, f as Interceptor } from '../../Interceptor-a31b1217.js';
3
3
  import '@open-draft/deferred-promise';
4
4
  import '@open-draft/logger';
5
5
 
6
- type XMLHttpRequestEventListener = (args: {
7
- request: InteractiveRequest;
8
- requestId: string;
9
- }) => Promise<void> | void;
10
6
  type XMLHttpRequestEmitter = Emitter<HttpRequestEventMap>;
11
7
  declare class XMLHttpRequestInterceptor extends Interceptor<HttpRequestEventMap> {
12
8
  static interceptorSymbol: symbol;
@@ -15,4 +11,4 @@ declare class XMLHttpRequestInterceptor extends Interceptor<HttpRequestEventMap>
15
11
  protected setup(): void;
16
12
  }
17
13
 
18
- export { XMLHttpRequestEmitter, XMLHttpRequestEventListener, XMLHttpRequestInterceptor };
14
+ export { XMLHttpRequestEmitter, XMLHttpRequestInterceptor };
@@ -1,11 +1,11 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
2
 
3
- var _chunkPYD4E2EJjs = require('../../chunk-PYD4E2EJ.js');
3
+ var _chunkP6QG76R3js = require('../../chunk-P6QG76R3.js');
4
4
  require('../../chunk-LK6DILFK.js');
5
- require('../../chunk-EIBTX65O.js');
6
- require('../../chunk-UXCYRE4F.js');
7
- require('../../chunk-BFLYGQ6D.js');
5
+ require('../../chunk-IDEEMJ3F.js');
6
+ require('../../chunk-5WWNCLB3.js');
7
+ require('../../chunk-YGM3BCJU.js');
8
8
 
9
9
 
10
- exports.XMLHttpRequestInterceptor = _chunkPYD4E2EJjs.XMLHttpRequestInterceptor;
10
+ exports.XMLHttpRequestInterceptor = _chunkP6QG76R3js.XMLHttpRequestInterceptor;
11
11
  //# sourceMappingURL=index.js.map
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  XMLHttpRequestInterceptor
3
- } from "../../chunk-DV4PBH4D.mjs";
3
+ } from "../../chunk-TOV4TYIX.mjs";
4
4
  import "../../chunk-6HYIRFX2.mjs";
5
- import "../../chunk-OJ6O4LSC.mjs";
6
- import "../../chunk-KWV3JXSI.mjs";
7
- import "../../chunk-TGTPXCLF.mjs";
5
+ import "../../chunk-BZ3Y7YV5.mjs";
6
+ import "../../chunk-KY3RJ2M3.mjs";
7
+ import "../../chunk-BUCULLYM.mjs";
8
8
  export {
9
9
  XMLHttpRequestInterceptor
10
10
  };
@@ -1,4 +1,4 @@
1
- import { f as Interceptor, H as HttpRequestEventMap } from '../../Interceptor-88ee47c0.js';
1
+ import { f as Interceptor, H as HttpRequestEventMap } from '../../Interceptor-a31b1217.js';
2
2
  import '@open-draft/deferred-promise';
3
3
  import '@open-draft/logger';
4
4
  import 'strict-event-emitter';
@@ -1,21 +1,19 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
2
 
3
- var _chunkEIBTX65Ojs = require('../../chunk-EIBTX65O.js');
3
+ var _chunkIDEEMJ3Fjs = require('../../chunk-IDEEMJ3F.js');
4
4
 
5
5
 
6
6
 
7
- var _chunkUXCYRE4Fjs = require('../../chunk-UXCYRE4F.js');
8
7
 
8
+ var _chunk5WWNCLB3js = require('../../chunk-5WWNCLB3.js');
9
9
 
10
10
 
11
11
 
12
-
13
- var _chunkBFLYGQ6Djs = require('../../chunk-BFLYGQ6D.js');
12
+ var _chunkYGM3BCJUjs = require('../../chunk-YGM3BCJU.js');
14
13
 
15
14
  // src/interceptors/fetch/index.ts
16
15
  var _outvariant = require('outvariant');
17
16
  var _deferredpromise = require('@open-draft/deferred-promise');
18
- var _until = require('@open-draft/until');
19
17
 
20
18
  // src/utils/canParseUrl.ts
21
19
  function canParseUrl(url) {
@@ -28,7 +26,7 @@ function canParseUrl(url) {
28
26
  }
29
27
 
30
28
  // src/interceptors/fetch/index.ts
31
- var _FetchInterceptor = class extends _chunkBFLYGQ6Djs.Interceptor {
29
+ var _FetchInterceptor = class extends _chunkYGM3BCJUjs.Interceptor {
32
30
  constructor() {
33
31
  super(_FetchInterceptor.symbol);
34
32
  }
@@ -38,135 +36,66 @@ var _FetchInterceptor = class extends _chunkBFLYGQ6Djs.Interceptor {
38
36
  async setup() {
39
37
  const pureFetch = globalThis.fetch;
40
38
  _outvariant.invariant.call(void 0,
41
- !pureFetch[_chunkEIBTX65Ojs.IS_PATCHED_MODULE],
39
+ !pureFetch[_chunkIDEEMJ3Fjs.IS_PATCHED_MODULE],
42
40
  'Failed to patch the "fetch" module: already patched.'
43
41
  );
44
42
  globalThis.fetch = async (input, init) => {
45
- var _a;
46
- const requestId = _chunkBFLYGQ6Djs.createRequestId.call(void 0, );
43
+ const requestId = _chunkYGM3BCJUjs.createRequestId.call(void 0, );
47
44
  const resolvedInput = typeof input === "string" && typeof location !== "undefined" && !canParseUrl(input) ? new URL(input, location.origin) : input;
48
45
  const request = new Request(resolvedInput, init);
46
+ const responsePromise = new (0, _deferredpromise.DeferredPromise)();
47
+ const controller = new (0, _chunk5WWNCLB3js.RequestController)(request);
49
48
  this.logger.info("[%s] %s", request.method, request.url);
50
- const { interactiveRequest, requestController } = _chunkUXCYRE4Fjs.toInteractiveRequest.call(void 0, request);
49
+ this.logger.info("awaiting for the mocked response...");
51
50
  this.logger.info(
52
- 'emitting the "request" event for %d listener(s)...',
51
+ 'emitting the "request" event for %s listener(s)...',
53
52
  this.emitter.listenerCount("request")
54
53
  );
55
- this.emitter.once("request", ({ requestId: pendingRequestId }) => {
56
- if (pendingRequestId !== requestId) {
57
- return;
58
- }
59
- if (requestController.responsePromise.state === "pending") {
60
- requestController.responsePromise.resolve(void 0);
61
- }
62
- });
63
- this.logger.info("awaiting for the mocked response...");
64
- const signal = interactiveRequest.signal;
65
- const requestAborted = new (0, _deferredpromise.DeferredPromise)();
66
- if (signal) {
67
- signal.addEventListener(
68
- "abort",
69
- () => {
70
- requestAborted.reject(signal.reason);
71
- },
72
- { once: true }
73
- );
74
- }
75
- const responsePromise = new (0, _deferredpromise.DeferredPromise)();
76
- const respondWith = (response) => {
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
- }
88
- Object.defineProperty(response, "url", {
89
- writable: false,
90
- enumerable: true,
91
- configurable: false,
92
- value: request.url
93
- });
94
- responsePromise.resolve(response);
95
- };
96
- const errorWith = (reason) => {
97
- responsePromise.reject(reason);
98
- };
99
- const resolverResult = await _until.until.call(void 0,
100
- async () => {
101
- const listenersFinished = _chunkUXCYRE4Fjs.emitAsync.call(void 0, this.emitter, "request", {
102
- request: interactiveRequest,
103
- requestId
54
+ const isRequestHandled = await _chunk5WWNCLB3js.handleRequest.call(void 0, {
55
+ request,
56
+ requestId,
57
+ emitter: this.emitter,
58
+ controller,
59
+ onResponse: async (response) => {
60
+ this.logger.info("received mocked response!", {
61
+ response
104
62
  });
105
- await Promise.race([
106
- requestAborted,
107
- // Put the listeners invocation Promise in the same race condition
108
- // with the request abort Promise because otherwise awaiting the listeners
109
- // would always yield some response (or undefined).
110
- listenersFinished,
111
- requestController.responsePromise
112
- ]);
113
- this.logger.info("all request listeners have been resolved!");
114
- const mockedResponse2 = await requestController.responsePromise;
115
- this.logger.info("event.respondWith called with:", mockedResponse2);
116
- return mockedResponse2;
117
- }
118
- );
119
- if (requestAborted.state === "rejected") {
120
- this.logger.info(
121
- "request has been aborted:",
122
- requestAborted.rejectionReason
123
- );
124
- responsePromise.reject(requestAborted.rejectionReason);
125
- return responsePromise;
126
- }
127
- if (resolverResult.error) {
128
- this.logger.info(
129
- "request listerner threw an error:",
130
- resolverResult.error
131
- );
132
- if (resolverResult.error instanceof Response) {
133
- if (_chunkBFLYGQ6Djs.isResponseError.call(void 0, resolverResult.error)) {
134
- errorWith(createNetworkError(resolverResult.error));
135
- } else {
136
- respondWith(resolverResult.error);
63
+ if (this.emitter.listenerCount("response") > 0) {
64
+ this.logger.info('emitting the "response" event...');
65
+ await _chunk5WWNCLB3js.emitAsync.call(void 0, this.emitter, "response", {
66
+ // Clone the mocked response for the "response" event listener.
67
+ // This way, the listener can read the response and not lock its body
68
+ // for the actual fetch consumer.
69
+ response: response.clone(),
70
+ isMockedResponse: true,
71
+ request,
72
+ requestId
73
+ });
137
74
  }
138
- }
139
- if (this.emitter.listenerCount("unhandledException") > 0) {
140
- await _chunkUXCYRE4Fjs.emitAsync.call(void 0, this.emitter, "unhandledException", {
141
- error: resolverResult.error,
142
- request,
143
- requestId,
144
- controller: {
145
- respondWith,
146
- errorWith
147
- }
75
+ Object.defineProperty(response, "url", {
76
+ writable: false,
77
+ enumerable: true,
78
+ configurable: false,
79
+ value: request.url
148
80
  });
149
- if (responsePromise.state !== "pending") {
150
- return responsePromise;
151
- }
152
- }
153
- respondWith(_chunkBFLYGQ6Djs.createServerErrorResponse.call(void 0, resolverResult.error));
154
- return responsePromise;
155
- }
156
- const mockedResponse = resolverResult.data;
157
- if (mockedResponse && !((_a = request.signal) == null ? void 0 : _a.aborted)) {
158
- this.logger.info("received mocked response:", mockedResponse);
159
- if (_chunkBFLYGQ6Djs.isResponseError.call(void 0, mockedResponse)) {
160
- this.logger.info(
161
- "received a network error response, rejecting the request promise..."
162
- );
163
- errorWith(createNetworkError(mockedResponse));
164
- } else {
165
- respondWith(mockedResponse);
81
+ responsePromise.resolve(response);
82
+ },
83
+ onRequestError: (response) => {
84
+ this.logger.info("request has errored!", { response });
85
+ responsePromise.reject(createNetworkError(response));
86
+ },
87
+ onError: (error) => {
88
+ this.logger.info("request has been aborted!", { error });
89
+ responsePromise.reject(error);
166
90
  }
91
+ });
92
+ if (isRequestHandled) {
93
+ this.logger.info("request has been handled, returning mock promise...");
167
94
  return responsePromise;
168
95
  }
169
- this.logger.info("no mocked response received!");
96
+ this.logger.info(
97
+ "no mocked response received, performing request as-is..."
98
+ );
170
99
  return pureFetch(request).then((response) => {
171
100
  this.logger.info("original fetch performed", response);
172
101
  if (this.emitter.listenerCount("response") > 0) {
@@ -175,20 +104,20 @@ var _FetchInterceptor = class extends _chunkBFLYGQ6Djs.Interceptor {
175
104
  this.emitter.emit("response", {
176
105
  response: responseClone,
177
106
  isMockedResponse: false,
178
- request: interactiveRequest,
107
+ request,
179
108
  requestId
180
109
  });
181
110
  }
182
111
  return response;
183
112
  });
184
113
  };
185
- Object.defineProperty(globalThis.fetch, _chunkEIBTX65Ojs.IS_PATCHED_MODULE, {
114
+ Object.defineProperty(globalThis.fetch, _chunkIDEEMJ3Fjs.IS_PATCHED_MODULE, {
186
115
  enumerable: true,
187
116
  configurable: true,
188
117
  value: true
189
118
  });
190
119
  this.subscriptions.push(() => {
191
- Object.defineProperty(globalThis.fetch, _chunkEIBTX65Ojs.IS_PATCHED_MODULE, {
120
+ Object.defineProperty(globalThis.fetch, _chunkIDEEMJ3Fjs.IS_PATCHED_MODULE, {
192
121
  value: void 0
193
122
  });
194
123
  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 { 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
+ {"version":3,"sources":["../../../../src/interceptors/fetch/index.ts","../../../../src/utils/canParseUrl.ts"],"names":[],"mappings":"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","sourcesContent":["import { invariant } from 'outvariant'\nimport { DeferredPromise } from '@open-draft/deferred-promise'\nimport { HttpRequestEventMap, IS_PATCHED_MODULE } from '../../glossary'\nimport { Interceptor } from '../../Interceptor'\nimport { RequestController } from '../../RequestController'\nimport { emitAsync } from '../../utils/emitAsync'\nimport { handleRequest } from '../../utils/handleRequest'\nimport { canParseUrl } from '../../utils/canParseUrl'\nimport { createRequestId } from '../../createRequestId'\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 const responsePromise = new DeferredPromise<Response>()\n const controller = new RequestController(request)\n\n this.logger.info('[%s] %s', request.method, request.url)\n this.logger.info('awaiting for the mocked response...')\n\n this.logger.info(\n 'emitting the \"request\" event for %s listener(s)...',\n this.emitter.listenerCount('request')\n )\n\n const isRequestHandled = await handleRequest({\n request,\n requestId,\n emitter: this.emitter,\n controller,\n onResponse: async (response) => {\n this.logger.info('received mocked response!', {\n response,\n })\n\n if (this.emitter.listenerCount('response') > 0) {\n this.logger.info('emitting the \"response\" event...')\n\n // Await the response listeners to finish before resolving\n // the response promise. This ensures all your logic finishes\n // before the interceptor resolves the pending response.\n await emitAsync(this.emitter, '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 response: response.clone(),\n isMockedResponse: true,\n request,\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 onRequestError: (response) => {\n this.logger.info('request has errored!', { response })\n responsePromise.reject(createNetworkError(response))\n },\n onError: (error) => {\n this.logger.info('request has been aborted!', { error })\n responsePromise.reject(error)\n },\n })\n\n if (isRequestHandled) {\n this.logger.info('request has been handled, returning mock promise...')\n return responsePromise\n }\n\n this.logger.info(\n 'no mocked response received, performing request as-is...'\n )\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,\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"]}