@mswjs/interceptors 0.39.8 → 0.41.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 (282) hide show
  1. package/ClientRequest/package.json +7 -2
  2. package/RemoteHttpInterceptor/package.json +7 -2
  3. package/WebSocket/package.json +9 -2
  4. package/XMLHttpRequest/package.json +9 -3
  5. package/fetch/package.json +9 -3
  6. package/lib/browser/Interceptor-2mUoKZL1.d.mts +65 -0
  7. package/lib/browser/Interceptor-Deczogc8.d.cts +65 -0
  8. package/lib/browser/XMLHttpRequest-BUfglQD1.cjs +761 -0
  9. package/lib/browser/XMLHttpRequest-BUfglQD1.cjs.map +1 -0
  10. package/lib/browser/XMLHttpRequest-DS5fc8Qs.mjs +756 -0
  11. package/lib/browser/XMLHttpRequest-DS5fc8Qs.mjs.map +1 -0
  12. package/lib/browser/bufferUtils-BiiO6HZv.mjs +20 -0
  13. package/lib/browser/bufferUtils-BiiO6HZv.mjs.map +1 -0
  14. package/lib/browser/bufferUtils-Uc0eRItL.cjs +38 -0
  15. package/lib/browser/bufferUtils-Uc0eRItL.cjs.map +1 -0
  16. package/lib/browser/createRequestId-Cs4oXfa1.cjs +205 -0
  17. package/lib/browser/createRequestId-Cs4oXfa1.cjs.map +1 -0
  18. package/lib/browser/createRequestId-DQcIlohW.mjs +170 -0
  19. package/lib/browser/createRequestId-DQcIlohW.mjs.map +1 -0
  20. package/lib/browser/fetch-BHcqM3z7.cjs +253 -0
  21. package/lib/browser/fetch-BHcqM3z7.cjs.map +1 -0
  22. package/lib/browser/fetch-DSJoynSF.mjs +248 -0
  23. package/lib/browser/fetch-DSJoynSF.mjs.map +1 -0
  24. package/lib/browser/getRawRequest-BTaNLFr0.mjs +218 -0
  25. package/lib/browser/getRawRequest-BTaNLFr0.mjs.map +1 -0
  26. package/lib/browser/getRawRequest-zx8rUJL2.cjs +259 -0
  27. package/lib/browser/getRawRequest-zx8rUJL2.cjs.map +1 -0
  28. package/lib/browser/glossary-BdLS4k1H.d.cts +70 -0
  29. package/lib/browser/glossary-gEEJhK4S.d.mts +70 -0
  30. package/lib/browser/handleRequest-DI6a7Dty.cjs +189 -0
  31. package/lib/browser/handleRequest-DI6a7Dty.cjs.map +1 -0
  32. package/lib/browser/handleRequest-DxGbCTbb.mjs +178 -0
  33. package/lib/browser/handleRequest-DxGbCTbb.mjs.map +1 -0
  34. package/lib/browser/hasConfigurableGlobal-C8kXFDic.mjs +33 -0
  35. package/lib/browser/hasConfigurableGlobal-C8kXFDic.mjs.map +1 -0
  36. package/lib/browser/hasConfigurableGlobal-D7S3l5h6.cjs +45 -0
  37. package/lib/browser/hasConfigurableGlobal-D7S3l5h6.cjs.map +1 -0
  38. package/lib/browser/index.cjs +68 -0
  39. package/lib/browser/index.cjs.map +1 -0
  40. package/lib/browser/index.d.cts +87 -0
  41. package/lib/browser/index.d.mts +87 -0
  42. package/lib/browser/index.mjs +49 -75
  43. package/lib/browser/index.mjs.map +1 -1
  44. package/lib/browser/interceptors/WebSocket/index.cjs +621 -0
  45. package/lib/browser/interceptors/WebSocket/index.cjs.map +1 -0
  46. package/lib/browser/interceptors/WebSocket/index.d.cts +277 -0
  47. package/lib/browser/interceptors/WebSocket/index.d.mts +277 -0
  48. package/lib/browser/interceptors/WebSocket/index.mjs +587 -694
  49. package/lib/browser/interceptors/WebSocket/index.mjs.map +1 -1
  50. package/lib/browser/interceptors/XMLHttpRequest/index.cjs +7 -0
  51. package/lib/browser/interceptors/XMLHttpRequest/index.d.cts +15 -0
  52. package/lib/browser/interceptors/XMLHttpRequest/index.d.mts +15 -0
  53. package/lib/browser/interceptors/XMLHttpRequest/index.mjs +7 -12
  54. package/lib/browser/interceptors/fetch/index.cjs +6 -0
  55. package/lib/browser/interceptors/fetch/index.d.cts +13 -0
  56. package/lib/browser/interceptors/fetch/index.d.mts +13 -0
  57. package/lib/browser/interceptors/fetch/index.mjs +6 -11
  58. package/lib/browser/presets/browser.cjs +17 -0
  59. package/lib/browser/presets/browser.cjs.map +1 -0
  60. package/lib/browser/presets/browser.d.cts +12 -0
  61. package/lib/browser/presets/browser.d.mts +14 -0
  62. package/lib/browser/presets/browser.mjs +15 -19
  63. package/lib/browser/presets/browser.mjs.map +1 -1
  64. package/lib/node/BatchInterceptor-3LnAnLTx.cjs +49 -0
  65. package/lib/node/BatchInterceptor-3LnAnLTx.cjs.map +1 -0
  66. package/lib/node/BatchInterceptor-D7mXzHcQ.d.mts +26 -0
  67. package/lib/node/BatchInterceptor-DFaBPilf.mjs +44 -0
  68. package/lib/node/BatchInterceptor-DFaBPilf.mjs.map +1 -0
  69. package/lib/node/BatchInterceptor-D_YqR8qU.d.cts +26 -0
  70. package/lib/node/ClientRequest-2rDe54Ui.cjs +1043 -0
  71. package/lib/node/ClientRequest-2rDe54Ui.cjs.map +1 -0
  72. package/lib/node/ClientRequest-Ca8Qykuv.mjs +1034 -0
  73. package/lib/node/ClientRequest-Ca8Qykuv.mjs.map +1 -0
  74. package/lib/node/Interceptor-DEazpLJd.d.mts +133 -0
  75. package/lib/node/Interceptor-DJ2akVWI.d.cts +133 -0
  76. package/lib/node/RemoteHttpInterceptor.cjs +154 -0
  77. package/lib/node/RemoteHttpInterceptor.cjs.map +1 -0
  78. package/lib/node/RemoteHttpInterceptor.d.cts +39 -0
  79. package/lib/node/RemoteHttpInterceptor.d.mts +39 -0
  80. package/lib/node/RemoteHttpInterceptor.mjs +145 -186
  81. package/lib/node/RemoteHttpInterceptor.mjs.map +1 -1
  82. package/lib/node/XMLHttpRequest-B7kJdYYI.cjs +763 -0
  83. package/lib/node/XMLHttpRequest-B7kJdYYI.cjs.map +1 -0
  84. package/lib/node/XMLHttpRequest-C8dIZpds.mjs +757 -0
  85. package/lib/node/XMLHttpRequest-C8dIZpds.mjs.map +1 -0
  86. package/lib/node/bufferUtils-DiCTqG-7.cjs +38 -0
  87. package/lib/node/bufferUtils-DiCTqG-7.cjs.map +1 -0
  88. package/lib/node/bufferUtils-_8XfKIfX.mjs +20 -0
  89. package/lib/node/bufferUtils-_8XfKIfX.mjs.map +1 -0
  90. package/lib/node/chunk-CbDLau6x.cjs +34 -0
  91. package/lib/node/fetch-BmXpK10r.cjs +272 -0
  92. package/lib/node/fetch-BmXpK10r.cjs.map +1 -0
  93. package/lib/node/fetch-G1DVwDKG.mjs +265 -0
  94. package/lib/node/fetch-G1DVwDKG.mjs.map +1 -0
  95. package/lib/node/fetchUtils-BaY5iWXw.cjs +419 -0
  96. package/lib/node/fetchUtils-BaY5iWXw.cjs.map +1 -0
  97. package/lib/node/fetchUtils-CoU35g3M.mjs +359 -0
  98. package/lib/node/fetchUtils-CoU35g3M.mjs.map +1 -0
  99. package/lib/node/getRawRequest-BavnMWh_.cjs +36 -0
  100. package/lib/node/getRawRequest-BavnMWh_.cjs.map +1 -0
  101. package/lib/node/getRawRequest-DnwmXyOW.mjs +24 -0
  102. package/lib/node/getRawRequest-DnwmXyOW.mjs.map +1 -0
  103. package/lib/node/glossary-BLKRyLBd.cjs +12 -0
  104. package/lib/node/glossary-BLKRyLBd.cjs.map +1 -0
  105. package/lib/node/glossary-glQBRnVD.mjs +6 -0
  106. package/lib/node/glossary-glQBRnVD.mjs.map +1 -0
  107. package/lib/node/handleRequest-Bb7Y-XLw.cjs +220 -0
  108. package/lib/node/handleRequest-Bb7Y-XLw.cjs.map +1 -0
  109. package/lib/node/handleRequest-Y97UwBbF.mjs +190 -0
  110. package/lib/node/handleRequest-Y97UwBbF.mjs.map +1 -0
  111. package/lib/node/hasConfigurableGlobal-C97fWuaA.cjs +26 -0
  112. package/lib/node/hasConfigurableGlobal-C97fWuaA.cjs.map +1 -0
  113. package/lib/node/hasConfigurableGlobal-DBJA0vjm.mjs +20 -0
  114. package/lib/node/hasConfigurableGlobal-DBJA0vjm.mjs.map +1 -0
  115. package/lib/node/index-BMbJ8FXL.d.cts +113 -0
  116. package/lib/node/index-C0YAQ36w.d.mts +113 -0
  117. package/lib/node/index.cjs +30 -0
  118. package/lib/node/index.cjs.map +1 -0
  119. package/lib/node/index.d.cts +66 -0
  120. package/lib/node/index.d.mts +66 -0
  121. package/lib/node/index.mjs +13 -39
  122. package/lib/node/index.mjs.map +1 -1
  123. package/lib/node/interceptors/ClientRequest/index.cjs +6 -0
  124. package/lib/node/interceptors/ClientRequest/index.d.cts +2 -0
  125. package/lib/node/interceptors/ClientRequest/index.d.mts +3 -0
  126. package/lib/node/interceptors/ClientRequest/index.mjs +6 -11
  127. package/lib/node/interceptors/XMLHttpRequest/index.cjs +6 -0
  128. package/lib/node/interceptors/XMLHttpRequest/index.d.cts +14 -0
  129. package/lib/node/interceptors/XMLHttpRequest/index.d.mts +14 -0
  130. package/lib/node/interceptors/XMLHttpRequest/index.mjs +6 -13
  131. package/lib/node/interceptors/fetch/index.cjs +5 -0
  132. package/lib/node/interceptors/fetch/index.d.cts +12 -0
  133. package/lib/node/interceptors/fetch/index.d.mts +12 -0
  134. package/lib/node/interceptors/fetch/index.mjs +5 -12
  135. package/lib/node/node-DwCc6iuP.mjs +27 -0
  136. package/lib/node/node-DwCc6iuP.mjs.map +1 -0
  137. package/lib/node/node-dKdAf3tC.cjs +39 -0
  138. package/lib/node/node-dKdAf3tC.cjs.map +1 -0
  139. package/lib/node/presets/node.cjs +22 -0
  140. package/lib/node/presets/node.cjs.map +1 -0
  141. package/lib/node/presets/node.d.cts +13 -0
  142. package/lib/node/presets/node.d.mts +15 -0
  143. package/lib/node/presets/node.mjs +18 -23
  144. package/lib/node/presets/node.mjs.map +1 -1
  145. package/lib/node/utils/node/index.cjs +4 -0
  146. package/lib/node/utils/node/{index.d.ts → index.d.cts} +5 -2
  147. package/lib/node/utils/node/index.d.mts +16 -0
  148. package/lib/node/utils/node/index.mjs +3 -10
  149. package/package.json +34 -59
  150. package/presets/browser/package.json +2 -3
  151. package/presets/node/package.json +7 -2
  152. package/src/RemoteHttpInterceptor.ts +18 -13
  153. package/src/RequestController.test.ts +78 -31
  154. package/src/RequestController.ts +63 -39
  155. package/src/index.ts +4 -0
  156. package/src/interceptors/ClientRequest/MockHttpSocket.ts +43 -9
  157. package/src/interceptors/ClientRequest/index.ts +14 -18
  158. package/src/interceptors/ClientRequest/utils/parserUtils.ts +48 -0
  159. package/src/interceptors/WebSocket/index.ts +4 -1
  160. package/src/interceptors/XMLHttpRequest/XMLHttpRequestController.ts +45 -35
  161. package/src/interceptors/XMLHttpRequest/XMLHttpRequestProxy.ts +24 -21
  162. package/src/interceptors/XMLHttpRequest/utils/getBodyByteLength.test.ts +2 -2
  163. package/src/interceptors/fetch/index.ts +61 -50
  164. package/src/utils/handleRequest.ts +65 -95
  165. package/lib/browser/Interceptor-af98b768.d.ts +0 -63
  166. package/lib/browser/chunk-2HUMWGRD.js +0 -37
  167. package/lib/browser/chunk-2HUMWGRD.js.map +0 -1
  168. package/lib/browser/chunk-2QICSCCS.js +0 -238
  169. package/lib/browser/chunk-2QICSCCS.js.map +0 -1
  170. package/lib/browser/chunk-3RXCRGL2.mjs +0 -117
  171. package/lib/browser/chunk-3RXCRGL2.mjs.map +0 -1
  172. package/lib/browser/chunk-6HYIRFX2.mjs +0 -22
  173. package/lib/browser/chunk-6HYIRFX2.mjs.map +0 -1
  174. package/lib/browser/chunk-E3CCOBRX.js +0 -846
  175. package/lib/browser/chunk-E3CCOBRX.js.map +0 -1
  176. package/lib/browser/chunk-E7UVBHVO.mjs +0 -846
  177. package/lib/browser/chunk-E7UVBHVO.mjs.map +0 -1
  178. package/lib/browser/chunk-H74PGQ4Y.js +0 -296
  179. package/lib/browser/chunk-H74PGQ4Y.js.map +0 -1
  180. package/lib/browser/chunk-LK6DILFK.js +0 -22
  181. package/lib/browser/chunk-LK6DILFK.js.map +0 -1
  182. package/lib/browser/chunk-PTTUYYVR.mjs +0 -238
  183. package/lib/browser/chunk-PTTUYYVR.mjs.map +0 -1
  184. package/lib/browser/chunk-Q7K2XAEP.mjs +0 -296
  185. package/lib/browser/chunk-Q7K2XAEP.mjs.map +0 -1
  186. package/lib/browser/chunk-QED3Q6Z2.mjs +0 -169
  187. package/lib/browser/chunk-QED3Q6Z2.mjs.map +0 -1
  188. package/lib/browser/chunk-T7TBRNJZ.js +0 -117
  189. package/lib/browser/chunk-T7TBRNJZ.js.map +0 -1
  190. package/lib/browser/chunk-TIPR373R.js +0 -169
  191. package/lib/browser/chunk-TIPR373R.js.map +0 -1
  192. package/lib/browser/chunk-VYSDLBSS.mjs +0 -37
  193. package/lib/browser/chunk-VYSDLBSS.mjs.map +0 -1
  194. package/lib/browser/glossary-7152281e.d.ts +0 -69
  195. package/lib/browser/index.d.ts +0 -83
  196. package/lib/browser/index.js +0 -81
  197. package/lib/browser/index.js.map +0 -1
  198. package/lib/browser/interceptors/WebSocket/index.d.ts +0 -271
  199. package/lib/browser/interceptors/WebSocket/index.js +0 -721
  200. package/lib/browser/interceptors/WebSocket/index.js.map +0 -1
  201. package/lib/browser/interceptors/XMLHttpRequest/index.d.ts +0 -15
  202. package/lib/browser/interceptors/XMLHttpRequest/index.js +0 -12
  203. package/lib/browser/interceptors/XMLHttpRequest/index.js.map +0 -1
  204. package/lib/browser/interceptors/XMLHttpRequest/index.mjs.map +0 -1
  205. package/lib/browser/interceptors/fetch/index.d.ts +0 -14
  206. package/lib/browser/interceptors/fetch/index.js +0 -11
  207. package/lib/browser/interceptors/fetch/index.js.map +0 -1
  208. package/lib/browser/interceptors/fetch/index.mjs.map +0 -1
  209. package/lib/browser/presets/browser.d.ts +0 -15
  210. package/lib/browser/presets/browser.js +0 -21
  211. package/lib/browser/presets/browser.js.map +0 -1
  212. package/lib/node/BatchInterceptor-5b72232f.d.ts +0 -24
  213. package/lib/node/Interceptor-bc5a9d8e.d.ts +0 -130
  214. package/lib/node/RemoteHttpInterceptor.d.ts +0 -45
  215. package/lib/node/RemoteHttpInterceptor.js +0 -193
  216. package/lib/node/RemoteHttpInterceptor.js.map +0 -1
  217. package/lib/node/chunk-3CNGDJFB.mjs +0 -313
  218. package/lib/node/chunk-3CNGDJFB.mjs.map +0 -1
  219. package/lib/node/chunk-3GJB4JDF.mjs +0 -14
  220. package/lib/node/chunk-3GJB4JDF.mjs.map +0 -1
  221. package/lib/node/chunk-4NEYTVWD.mjs +0 -848
  222. package/lib/node/chunk-4NEYTVWD.mjs.map +0 -1
  223. package/lib/node/chunk-4YBV77DG.js +0 -32
  224. package/lib/node/chunk-4YBV77DG.js.map +0 -1
  225. package/lib/node/chunk-6HYIRFX2.mjs +0 -22
  226. package/lib/node/chunk-6HYIRFX2.mjs.map +0 -1
  227. package/lib/node/chunk-6YM4PLBI.mjs +0 -7
  228. package/lib/node/chunk-6YM4PLBI.mjs.map +0 -1
  229. package/lib/node/chunk-72ZIHMEB.js +0 -249
  230. package/lib/node/chunk-72ZIHMEB.js.map +0 -1
  231. package/lib/node/chunk-73NOP3T5.js +0 -7
  232. package/lib/node/chunk-73NOP3T5.js.map +0 -1
  233. package/lib/node/chunk-A7Q4RTDJ.mjs +0 -249
  234. package/lib/node/chunk-A7Q4RTDJ.mjs.map +0 -1
  235. package/lib/node/chunk-A7U44ARP.js +0 -268
  236. package/lib/node/chunk-A7U44ARP.js.map +0 -1
  237. package/lib/node/chunk-EKNRB5ZS.mjs +0 -1115
  238. package/lib/node/chunk-EKNRB5ZS.mjs.map +0 -1
  239. package/lib/node/chunk-IHJSPMYM.mjs +0 -268
  240. package/lib/node/chunk-IHJSPMYM.mjs.map +0 -1
  241. package/lib/node/chunk-LK6DILFK.js +0 -22
  242. package/lib/node/chunk-LK6DILFK.js.map +0 -1
  243. package/lib/node/chunk-N4ZZFE24.js +0 -1115
  244. package/lib/node/chunk-N4ZZFE24.js.map +0 -1
  245. package/lib/node/chunk-PFGO5BSM.js +0 -25
  246. package/lib/node/chunk-PFGO5BSM.js.map +0 -1
  247. package/lib/node/chunk-R6JVCM7X.js +0 -51
  248. package/lib/node/chunk-R6JVCM7X.js.map +0 -1
  249. package/lib/node/chunk-RC2XPCC4.mjs +0 -51
  250. package/lib/node/chunk-RC2XPCC4.mjs.map +0 -1
  251. package/lib/node/chunk-SMXZPJEA.js +0 -14
  252. package/lib/node/chunk-SMXZPJEA.js.map +0 -1
  253. package/lib/node/chunk-TJDMZZXE.mjs +0 -32
  254. package/lib/node/chunk-TJDMZZXE.mjs.map +0 -1
  255. package/lib/node/chunk-TX5GBTFY.mjs +0 -25
  256. package/lib/node/chunk-TX5GBTFY.mjs.map +0 -1
  257. package/lib/node/chunk-VV2LUF5K.js +0 -848
  258. package/lib/node/chunk-VV2LUF5K.js.map +0 -1
  259. package/lib/node/chunk-Z5LWCBZS.js +0 -313
  260. package/lib/node/chunk-Z5LWCBZS.js.map +0 -1
  261. package/lib/node/index.d.ts +0 -62
  262. package/lib/node/index.js +0 -43
  263. package/lib/node/index.js.map +0 -1
  264. package/lib/node/interceptors/ClientRequest/index.d.ts +0 -111
  265. package/lib/node/interceptors/ClientRequest/index.js +0 -11
  266. package/lib/node/interceptors/ClientRequest/index.js.map +0 -1
  267. package/lib/node/interceptors/ClientRequest/index.mjs.map +0 -1
  268. package/lib/node/interceptors/XMLHttpRequest/index.d.ts +0 -14
  269. package/lib/node/interceptors/XMLHttpRequest/index.js +0 -13
  270. package/lib/node/interceptors/XMLHttpRequest/index.js.map +0 -1
  271. package/lib/node/interceptors/XMLHttpRequest/index.mjs.map +0 -1
  272. package/lib/node/interceptors/fetch/index.d.ts +0 -13
  273. package/lib/node/interceptors/fetch/index.js +0 -12
  274. package/lib/node/interceptors/fetch/index.js.map +0 -1
  275. package/lib/node/interceptors/fetch/index.mjs.map +0 -1
  276. package/lib/node/presets/node.d.ts +0 -16
  277. package/lib/node/presets/node.js +0 -27
  278. package/lib/node/presets/node.js.map +0 -1
  279. package/lib/node/utils/node/index.js +0 -10
  280. package/lib/node/utils/node/index.js.map +0 -1
  281. package/lib/node/utils/node/index.mjs.map +0 -1
  282. package/src/utils/RequestController.ts +0 -21
@@ -1,4 +1,5 @@
1
1
  import { invariant } from 'outvariant'
2
+ import { until } from '@open-draft/until'
2
3
  import { DeferredPromise } from '@open-draft/deferred-promise'
3
4
  import { HttpRequestEventMap, IS_PATCHED_MODULE } from '../../glossary'
4
5
  import { Interceptor } from '../../Interceptor'
@@ -13,6 +14,7 @@ import { decompressResponse } from './utils/decompression'
13
14
  import { hasConfigurableGlobal } from '../../utils/hasConfigurableGlobal'
14
15
  import { FetchResponse } from '../../utils/fetchUtils'
15
16
  import { setRawRequest } from '../../getRawRequest'
17
+ import { isResponseError } from '../../utils/responseUtils'
16
18
 
17
19
  export class FetchInterceptor extends Interceptor<HttpRequestEventMap> {
18
20
  static symbol = Symbol('fetch')
@@ -59,22 +61,54 @@ export class FetchInterceptor extends Interceptor<HttpRequestEventMap> {
59
61
  }
60
62
 
61
63
  const responsePromise = new DeferredPromise<Response>()
62
- const controller = new RequestController(request)
63
64
 
64
- this.logger.info('[%s] %s', request.method, request.url)
65
- this.logger.info('awaiting for the mocked response...')
65
+ const controller = new RequestController(request, {
66
+ passthrough: async () => {
67
+ this.logger.info('request has not been handled, passthrough...')
66
68
 
67
- this.logger.info(
68
- 'emitting the "request" event for %s listener(s)...',
69
- this.emitter.listenerCount('request')
70
- )
69
+ /**
70
+ * @note Clone the request instance right before performing it.
71
+ * This preserves any modifications made to the intercepted request
72
+ * in the "request" listener. This also allows the user to read the
73
+ * request body in the "response" listener (otherwise "unusable").
74
+ */
75
+ const requestCloneForResponseEvent = request.clone()
76
+
77
+ // Perform the intercepted request as-is.
78
+ const { error: responseError, data: originalResponse } = await until(
79
+ () => pureFetch(request)
80
+ )
81
+
82
+ if (responseError) {
83
+ return responsePromise.reject(responseError)
84
+ }
85
+
86
+ this.logger.info('original fetch performed', originalResponse)
87
+
88
+ if (this.emitter.listenerCount('response') > 0) {
89
+ this.logger.info('emitting the "response" event...')
90
+
91
+ const responseClone = originalResponse.clone()
92
+ await emitAsync(this.emitter, 'response', {
93
+ response: responseClone,
94
+ isMockedResponse: false,
95
+ request: requestCloneForResponseEvent,
96
+ requestId,
97
+ })
98
+ }
99
+
100
+ // Resolve the response promise with the original response
101
+ // since the `fetch()` return this internal promise.
102
+ responsePromise.resolve(originalResponse)
103
+ },
104
+ respondWith: async (rawResponse) => {
105
+ // Handle mocked `Response.error()` (i.e. request errors).
106
+ if (isResponseError(rawResponse)) {
107
+ this.logger.info('request has errored!', { response: rawResponse })
108
+ responsePromise.reject(createNetworkError(rawResponse))
109
+ return
110
+ }
71
111
 
72
- const isRequestHandled = await handleRequest({
73
- request,
74
- requestId,
75
- emitter: this.emitter,
76
- controller,
77
- onResponse: async (rawResponse) => {
78
112
  this.logger.info('received mocked response!', {
79
113
  rawResponse,
80
114
  })
@@ -134,51 +168,28 @@ export class FetchInterceptor extends Interceptor<HttpRequestEventMap> {
134
168
 
135
169
  responsePromise.resolve(response)
136
170
  },
137
- onRequestError: (response) => {
138
- this.logger.info('request has errored!', { response })
139
- responsePromise.reject(createNetworkError(response))
140
- },
141
- onError: (error) => {
142
- this.logger.info('request has been aborted!', { error })
143
- responsePromise.reject(error)
171
+ errorWith: (reason) => {
172
+ this.logger.info('request has been aborted!', { reason })
173
+ responsePromise.reject(reason)
144
174
  },
145
175
  })
146
176
 
147
- if (isRequestHandled) {
148
- this.logger.info('request has been handled, returning mock promise...')
149
- return responsePromise
150
- }
177
+ this.logger.info('[%s] %s', request.method, request.url)
178
+ this.logger.info('awaiting for the mocked response...')
151
179
 
152
180
  this.logger.info(
153
- 'no mocked response received, performing request as-is...'
181
+ 'emitting the "request" event for %s listener(s)...',
182
+ this.emitter.listenerCount('request')
154
183
  )
155
184
 
156
- /**
157
- * @note Clone the request instance right before performing it.
158
- * This preserves any modifications made to the intercepted request
159
- * in the "request" listener. This also allows the user to read the
160
- * request body in the "response" listener (otherwise "unusable").
161
- */
162
- const requestCloneForResponseEvent = request.clone()
163
-
164
- return pureFetch(request).then(async (response) => {
165
- this.logger.info('original fetch performed', response)
166
-
167
- if (this.emitter.listenerCount('response') > 0) {
168
- this.logger.info('emitting the "response" event...')
169
-
170
- const responseClone = response.clone()
171
-
172
- await emitAsync(this.emitter, 'response', {
173
- response: responseClone,
174
- isMockedResponse: false,
175
- request: requestCloneForResponseEvent,
176
- requestId,
177
- })
178
- }
179
-
180
- return response
185
+ await handleRequest({
186
+ request,
187
+ requestId,
188
+ emitter: this.emitter,
189
+ controller,
181
190
  })
191
+
192
+ return responsePromise
182
193
  }
183
194
 
184
195
  Object.defineProperty(globalThis.fetch, IS_PATCHED_MODULE, {
@@ -3,12 +3,11 @@ import { DeferredPromise } from '@open-draft/deferred-promise'
3
3
  import { until } from '@open-draft/until'
4
4
  import type { HttpRequestEventMap } from '../glossary'
5
5
  import { emitAsync } from './emitAsync'
6
- import { kResponsePromise, RequestController } from '../RequestController'
6
+ import { RequestController } from '../RequestController'
7
7
  import {
8
8
  createServerErrorResponse,
9
9
  isResponseError,
10
10
  isResponseLike,
11
- ResponseError,
12
11
  } from './responseUtils'
13
12
  import { InterceptorError } from '../InterceptorError'
14
13
  import { isNodeLikeError } from './isNodeLikeError'
@@ -19,43 +18,22 @@ interface HandleRequestOptions {
19
18
  request: Request
20
19
  emitter: Emitter<HttpRequestEventMap>
21
20
  controller: RequestController
22
-
23
- /**
24
- * Called when the request has been handled
25
- * with the given `Response` instance.
26
- */
27
- onResponse: (response: Response) => void | Promise<void>
28
-
29
- /**
30
- * Called when the request has been handled
31
- * with the given `Response.error()` instance.
32
- */
33
- onRequestError: (response: ResponseError) => void
34
-
35
- /**
36
- * Called when an unhandled error happens during the
37
- * request handling. This is never a thrown error/response.
38
- */
39
- onError: (error: unknown) => void
40
21
  }
41
22
 
42
- /**
43
- * @returns {Promise<boolean>} Indicates whether the request has been handled.
44
- */
45
23
  export async function handleRequest(
46
24
  options: HandleRequestOptions
47
- ): Promise<boolean> {
25
+ ): Promise<void> {
48
26
  const handleResponse = async (
49
27
  response: Response | Error | Record<string, any>
50
28
  ) => {
51
29
  if (response instanceof Error) {
52
- options.onError(response)
30
+ await options.controller.errorWith(response)
53
31
  return true
54
32
  }
55
33
 
56
34
  // Handle "Response.error()" instances.
57
35
  if (isResponseError(response)) {
58
- options.onRequestError(response)
36
+ await options.controller.respondWith(response)
59
37
  return true
60
38
  }
61
39
 
@@ -65,13 +43,13 @@ export async function handleRequest(
65
43
  * since Response instances are, in fact, objects.
66
44
  */
67
45
  if (isResponseLike(response)) {
68
- await options.onResponse(response)
46
+ await options.controller.respondWith(response)
69
47
  return true
70
48
  }
71
49
 
72
50
  // Handle arbitrary objects provided to `.errorWith(reason)`.
73
51
  if (isObject(response)) {
74
- options.onError(response)
52
+ await options.controller.errorWith(response)
75
53
  return true
76
54
  }
77
55
 
@@ -87,7 +65,7 @@ export async function handleRequest(
87
65
 
88
66
  // Support mocking Node.js-like errors.
89
67
  if (isNodeLikeError(error)) {
90
- options.onError(error)
68
+ await options.controller.errorWith(error)
91
69
  return true
92
70
  }
93
71
 
@@ -102,15 +80,14 @@ export async function handleRequest(
102
80
  // Add the last "request" listener to check if the request
103
81
  // has been handled in any way. If it hasn't, resolve the
104
82
  // response promise with undefined.
105
- options.emitter.once('request', ({ requestId: pendingRequestId }) => {
106
- if (pendingRequestId !== options.requestId) {
107
- return
108
- }
109
-
110
- if (options.controller[kResponsePromise].state === 'pending') {
111
- options.controller[kResponsePromise].resolve(undefined)
112
- }
113
- })
83
+ // options.emitter.once('request', async ({ requestId: pendingRequestId }) => {
84
+ // if (
85
+ // pendingRequestId === options.requestId &&
86
+ // options.controller.readyState === RequestController.PENDING
87
+ // ) {
88
+ // await options.controller.passthrough()
89
+ // }
90
+ // })
114
91
 
115
92
  const requestAbortPromise = new DeferredPromise<void, unknown>()
116
93
 
@@ -119,16 +96,17 @@ export async function handleRequest(
119
96
  */
120
97
  if (options.request.signal) {
121
98
  if (options.request.signal.aborted) {
122
- requestAbortPromise.reject(options.request.signal.reason)
123
- } else {
124
- options.request.signal.addEventListener(
125
- 'abort',
126
- () => {
127
- requestAbortPromise.reject(options.request.signal.reason)
128
- },
129
- { once: true }
130
- )
99
+ await options.controller.errorWith(options.request.signal.reason)
100
+ return
131
101
  }
102
+
103
+ options.request.signal.addEventListener(
104
+ 'abort',
105
+ () => {
106
+ requestAbortPromise.reject(options.request.signal.reason)
107
+ },
108
+ { once: true }
109
+ )
132
110
  }
133
111
 
134
112
  const result = await until(async () => {
@@ -146,25 +124,21 @@ export async function handleRequest(
146
124
  // Short-circuit the request handling promise if the request gets aborted.
147
125
  requestAbortPromise,
148
126
  requestListenersPromise,
149
- options.controller[kResponsePromise],
127
+ options.controller.handled,
150
128
  ])
151
-
152
- // The response promise will settle immediately once
153
- // the developer calls either "respondWith" or "errorWith".
154
- return await options.controller[kResponsePromise]
155
129
  })
156
130
 
157
131
  // Handle the request being aborted while waiting for the request listeners.
158
132
  if (requestAbortPromise.state === 'rejected') {
159
- options.onError(requestAbortPromise.rejectionReason)
160
- return true
133
+ await options.controller.errorWith(requestAbortPromise.rejectionReason)
134
+ return
161
135
  }
162
136
 
163
137
  if (result.error) {
164
138
  // Handle the error during the request listener execution.
165
139
  // These can be thrown responses or request errors.
166
140
  if (await handleResponseError(result.error)) {
167
- return true
141
+ return
168
142
  }
169
143
 
170
144
  // If the developer has added "unhandledException" listeners,
@@ -175,7 +149,28 @@ export async function handleRequest(
175
149
  // This is needed because the original controller might have been already
176
150
  // interacted with (e.g. "respondWith" or "errorWith" called on it).
177
151
  const unhandledExceptionController = new RequestController(
178
- options.request
152
+ options.request,
153
+ {
154
+ /**
155
+ * @note Intentionally empty passthrough handle.
156
+ * This controller is created within another controller and we only need
157
+ * to know if `unhandledException` listeners handled the request.
158
+ */
159
+ passthrough() {},
160
+ async respondWith(response) {
161
+ await handleResponse(response)
162
+ },
163
+ async errorWith(reason) {
164
+ /**
165
+ * @note Handle the result of the unhandled controller
166
+ * in the same way as the original request controller.
167
+ * The exception here is that thrown errors within the
168
+ * "unhandledException" event do NOT result in another
169
+ * emit of the same event. They are forwarded as-is.
170
+ */
171
+ await options.controller.errorWith(reason)
172
+ },
173
+ }
179
174
  )
180
175
 
181
176
  await emitAsync(options.emitter, 'unhandledException', {
@@ -183,53 +178,28 @@ export async function handleRequest(
183
178
  request: options.request,
184
179
  requestId: options.requestId,
185
180
  controller: unhandledExceptionController,
186
- }).then(() => {
187
- // If all the "unhandledException" listeners have finished
188
- // but have not handled the response in any way, preemptively
189
- // resolve the pending response promise from the new controller.
190
- // This prevents it from hanging forever.
191
- if (
192
- unhandledExceptionController[kResponsePromise].state === 'pending'
193
- ) {
194
- unhandledExceptionController[kResponsePromise].resolve(undefined)
195
- }
196
181
  })
197
182
 
198
- const nextResult = await until(
199
- () => unhandledExceptionController[kResponsePromise]
200
- )
201
-
202
- /**
203
- * @note Handle the result of the unhandled controller
204
- * in the same way as the original request controller.
205
- * The exception here is that thrown errors within the
206
- * "unhandledException" event do NOT result in another
207
- * emit of the same event. They are forwarded as-is.
208
- */
209
- if (nextResult.error) {
210
- return handleResponseError(nextResult.error)
211
- }
212
-
213
- if (nextResult.data) {
214
- return handleResponse(nextResult.data)
183
+ // If all the "unhandledException" listeners have finished
184
+ // but have not handled the request in any way, passthrough.
185
+ if (
186
+ unhandledExceptionController.readyState !== RequestController.PENDING
187
+ ) {
188
+ return
215
189
  }
216
190
  }
217
191
 
218
192
  // Otherwise, coerce unhandled exceptions to a 500 Internal Server Error response.
219
- options.onResponse(createServerErrorResponse(result.error))
220
- return true
193
+ await options.controller.respondWith(
194
+ createServerErrorResponse(result.error)
195
+ )
196
+ return
221
197
  }
222
198
 
223
- /**
224
- * Handle a mocked Response instance.
225
- * @note That this can also be an Error in case
226
- * the developer called "errorWith". This differentiates
227
- * unhandled exceptions from intended errors.
228
- */
229
- if (result.data) {
230
- return handleResponse(result.data)
199
+ // If the request hasn't been handled by this point, passthrough.
200
+ if (options.controller.readyState === RequestController.PENDING) {
201
+ return await options.controller.passthrough()
231
202
  }
232
203
 
233
- // In all other cases, consider the request unhandled.
234
- return false
204
+ return options.controller.handled
235
205
  }
@@ -1,63 +0,0 @@
1
- import { Logger } from '@open-draft/logger';
2
- import { Emitter, Listener } from 'strict-event-emitter';
3
-
4
- type InterceptorEventMap = Record<string, any>;
5
- type InterceptorSubscription = () => void;
6
- /**
7
- * Request header name to detect when a single request
8
- * is being handled by nested interceptors (XHR -> ClientRequest).
9
- * Obscure by design to prevent collisions with user-defined headers.
10
- * Ideally, come up with the Interceptor-level mechanism for this.
11
- * @see https://github.com/mswjs/interceptors/issues/378
12
- */
13
- declare const INTERNAL_REQUEST_ID_HEADER_NAME = "x-interceptors-internal-request-id";
14
- declare function getGlobalSymbol<V>(symbol: Symbol): V | undefined;
15
- declare function deleteGlobalSymbol(symbol: Symbol): void;
16
- declare enum InterceptorReadyState {
17
- INACTIVE = "INACTIVE",
18
- APPLYING = "APPLYING",
19
- APPLIED = "APPLIED",
20
- DISPOSING = "DISPOSING",
21
- DISPOSED = "DISPOSED"
22
- }
23
- type ExtractEventNames<Events extends Record<string, any>> = Events extends Record<infer EventName, any> ? EventName : never;
24
- declare class Interceptor<Events extends InterceptorEventMap> {
25
- private readonly symbol;
26
- protected emitter: Emitter<Events>;
27
- protected subscriptions: Array<InterceptorSubscription>;
28
- protected logger: Logger;
29
- readyState: InterceptorReadyState;
30
- constructor(symbol: symbol);
31
- /**
32
- * Determine if this interceptor can be applied
33
- * in the current environment.
34
- */
35
- protected checkEnvironment(): boolean;
36
- /**
37
- * Apply this interceptor to the current process.
38
- * Returns an already running interceptor instance if it's present.
39
- */
40
- apply(): void;
41
- /**
42
- * Setup the module augments and stubs necessary for this interceptor.
43
- * This method is not run if there's a running interceptor instance
44
- * to prevent instantiating an interceptor multiple times.
45
- */
46
- protected setup(): void;
47
- /**
48
- * Listen to the interceptor's public events.
49
- */
50
- on<EventName extends ExtractEventNames<Events>>(event: EventName, listener: Listener<Events[EventName]>): this;
51
- once<EventName extends ExtractEventNames<Events>>(event: EventName, listener: Listener<Events[EventName]>): this;
52
- off<EventName extends ExtractEventNames<Events>>(event: EventName, listener: Listener<Events[EventName]>): this;
53
- removeAllListeners<EventName extends ExtractEventNames<Events>>(event?: EventName): this;
54
- /**
55
- * Disposes of any side-effects this interceptor has introduced.
56
- */
57
- dispose(): void;
58
- private getInstance;
59
- private setInstance;
60
- private clearInstance;
61
- }
62
-
63
- export { ExtractEventNames as E, Interceptor as I, InterceptorEventMap as a, InterceptorSubscription as b, INTERNAL_REQUEST_ID_HEADER_NAME as c, deleteGlobalSymbol as d, InterceptorReadyState as e, getGlobalSymbol as g };
@@ -1,37 +0,0 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true});// src/utils/emitAsync.ts
2
- async function emitAsync(emitter, eventName, ...data) {
3
- const listeners = emitter.listeners(eventName);
4
- if (listeners.length === 0) {
5
- return;
6
- }
7
- for (const listener of listeners) {
8
- await listener.apply(emitter, data);
9
- }
10
- }
11
-
12
- // src/utils/hasConfigurableGlobal.ts
13
- function hasConfigurableGlobal(propertyName) {
14
- const descriptor = Object.getOwnPropertyDescriptor(globalThis, propertyName);
15
- if (typeof descriptor === "undefined") {
16
- return false;
17
- }
18
- if (typeof descriptor.get === "function" && typeof descriptor.get() === "undefined") {
19
- return false;
20
- }
21
- if (typeof descriptor.get === "undefined" && descriptor.value == null) {
22
- return false;
23
- }
24
- if (typeof descriptor.set === "undefined" && !descriptor.configurable) {
25
- console.error(
26
- `[MSW] Failed to apply interceptor: the global \`${propertyName}\` property is non-configurable. This is likely an issue with your environment. If you are using a framework, please open an issue about this in their repository.`
27
- );
28
- return false;
29
- }
30
- return true;
31
- }
32
-
33
-
34
-
35
-
36
- exports.emitAsync = emitAsync; exports.hasConfigurableGlobal = hasConfigurableGlobal;
37
- //# sourceMappingURL=chunk-2HUMWGRD.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/utils/emitAsync.ts","../../src/utils/hasConfigurableGlobal.ts"],"names":[],"mappings":";AAOA,eAAsB,UAIpB,SACA,cACG,MACY;AACf,QAAM,YAAY,QAAQ,UAAU,SAAS;AAE7C,MAAI,UAAU,WAAW,GAAG;AAC1B;AAAA,EACF;AAEA,aAAW,YAAY,WAAW;AAChC,UAAM,SAAS,MAAM,SAAS,IAAI;AAAA,EACpC;AACF;;;ACpBO,SAAS,sBAAsB,cAA+B;AACnE,QAAM,aAAa,OAAO,yBAAyB,YAAY,YAAY;AAG3E,MAAI,OAAO,eAAe,aAAa;AACrC,WAAO;AAAA,EACT;AAGA,MACE,OAAO,WAAW,QAAQ,cAC1B,OAAO,WAAW,IAAI,MAAM,aAC5B;AACA,WAAO;AAAA,EACT;AAGA,MAAI,OAAO,WAAW,QAAQ,eAAe,WAAW,SAAS,MAAM;AACrE,WAAO;AAAA,EACT;AAEA,MAAI,OAAO,WAAW,QAAQ,eAAe,CAAC,WAAW,cAAc;AACrE,YAAQ;AAAA,MACN,mDAAmD;AAAA,IACrD;AACA,WAAO;AAAA,EACT;AAEA,SAAO;AACT","sourcesContent":["import { Emitter, EventMap } from 'strict-event-emitter'\n\n/**\n * Emits an event on the given emitter but executes\n * the listeners sequentially. This accounts for asynchronous\n * listeners (e.g. those having \"sleep\" and handling the request).\n */\nexport async function emitAsync<\n Events extends EventMap,\n EventName extends keyof Events\n>(\n emitter: Emitter<Events>,\n eventName: EventName,\n ...data: Events[EventName]\n): Promise<void> {\n const listeners = emitter.listeners(eventName)\n\n if (listeners.length === 0) {\n return\n }\n\n for (const listener of listeners) {\n await listener.apply(emitter, data)\n }\n}\n","/**\n * Returns a boolean indicating whether the given global property\n * is defined and is configurable.\n */\nexport function hasConfigurableGlobal(propertyName: string): boolean {\n const descriptor = Object.getOwnPropertyDescriptor(globalThis, propertyName)\n\n // The property is not set at all.\n if (typeof descriptor === 'undefined') {\n return false\n }\n\n // The property is set to a getter that returns undefined.\n if (\n typeof descriptor.get === 'function' &&\n typeof descriptor.get() === 'undefined'\n ) {\n return false\n }\n\n // The property is set to a value equal to undefined.\n if (typeof descriptor.get === 'undefined' && descriptor.value == null) {\n return false\n }\n\n if (typeof descriptor.set === 'undefined' && !descriptor.configurable) {\n console.error(\n `[MSW] Failed to apply interceptor: the global \\`${propertyName}\\` property is non-configurable. This is likely an issue with your environment. If you are using a framework, please open an issue about this in their repository.`\n )\n return false\n }\n\n return true\n}\n"]}