@mswjs/interceptors 0.41.9 → 0.42.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 (335) hide show
  1. package/README.md +274 -228
  2. package/lib/browser/{bufferUtils-BiiO6HZv.mjs → buffer-utils-DJj7YzLG.js} +3 -3
  3. package/lib/browser/buffer-utils-DJj7YzLG.js.map +1 -0
  4. package/lib/browser/create-request-id-DlEd4GOA.js +184 -0
  5. package/lib/browser/create-request-id-DlEd4GOA.js.map +1 -0
  6. package/lib/browser/{getRawRequest-B1BqgWG6.mjs → fetch-utils-zxA_SD66.js} +123 -52
  7. package/lib/browser/fetch-utils-zxA_SD66.js.map +1 -0
  8. package/lib/browser/handle-request-CIOa9O-N.js +167 -0
  9. package/lib/browser/handle-request-CIOa9O-N.js.map +1 -0
  10. package/lib/{node/hasConfigurableGlobal-BiTmog1u.mjs → browser/has-configurable-global-Cew-dYqk.js} +5 -7
  11. package/lib/browser/has-configurable-global-Cew-dYqk.js.map +1 -0
  12. package/lib/browser/http-CB9rQ7i_.d.ts +105 -0
  13. package/lib/browser/{index.d.cts → index.d.ts} +33 -38
  14. package/lib/browser/index.js +130 -0
  15. package/lib/browser/index.js.map +1 -0
  16. package/lib/browser/interceptor-dtJZ_9QT.d.ts +50 -0
  17. package/lib/browser/interceptors/WebSocket/index.d.ts +2 -0
  18. package/lib/browser/interceptors/WebSocket/{index.mjs → index.js} +39 -30
  19. package/lib/browser/interceptors/WebSocket/index.js.map +1 -0
  20. package/lib/browser/interceptors/XMLHttpRequest/web.d.ts +11 -0
  21. package/lib/browser/interceptors/XMLHttpRequest/web.js +2 -0
  22. package/lib/browser/interceptors/fetch/web.d.ts +14 -0
  23. package/lib/browser/interceptors/fetch/web.js +2 -0
  24. package/lib/browser/presets/browser.d.ts +11 -0
  25. package/lib/browser/presets/browser.js +12 -0
  26. package/lib/browser/presets/browser.js.map +1 -0
  27. package/lib/browser/{resolveWebSocketUrl-C83-x9iE.mjs → resolve-web-socket-url-CSvNPLGi.js} +3 -3
  28. package/lib/browser/resolve-web-socket-url-CSvNPLGi.js.map +1 -0
  29. package/lib/browser/web-BjVDkiX0.js +248 -0
  30. package/lib/browser/web-BjVDkiX0.js.map +1 -0
  31. package/lib/browser/{XMLHttpRequest-DrZAf3w6.mjs → web-C2oKsT3Q.js} +327 -255
  32. package/lib/browser/web-C2oKsT3Q.js.map +1 -0
  33. package/lib/browser/{interceptors/WebSocket/index.d.cts → websocket-CC0nB0md.d.ts} +41 -33
  34. package/lib/node/batch-interceptor-ByEZVih3.js +119 -0
  35. package/lib/node/batch-interceptor-ByEZVih3.js.map +1 -0
  36. package/lib/node/batch-interceptor-CPjFK2td.d.ts +28 -0
  37. package/lib/node/buffer-utils-BvPY1Tc-.js +187 -0
  38. package/lib/node/buffer-utils-BvPY1Tc-.js.map +1 -0
  39. package/lib/node/fetch-utils-Dw1PsmtX.js +568 -0
  40. package/lib/node/fetch-utils-Dw1PsmtX.js.map +1 -0
  41. package/lib/node/has-configurable-global-CJCh_g1I.js +22 -0
  42. package/lib/node/has-configurable-global-CJCh_g1I.js.map +1 -0
  43. package/lib/node/http-CB9rQ7i_.d.ts +105 -0
  44. package/lib/{browser/interceptors/WebSocket/index.d.mts → node/index.d.ts} +120 -60
  45. package/lib/node/{index.mjs → index.js} +8 -11
  46. package/lib/node/index.js.map +1 -0
  47. package/lib/node/interceptor-dtJZ_9QT.d.ts +50 -0
  48. package/lib/node/interceptors/ClientRequest/index.d.ts +14 -0
  49. package/lib/node/interceptors/ClientRequest/index.js +67 -0
  50. package/lib/node/interceptors/ClientRequest/index.js.map +1 -0
  51. package/lib/node/interceptors/XMLHttpRequest/node.d.ts +12 -0
  52. package/lib/node/interceptors/XMLHttpRequest/node.js +74 -0
  53. package/lib/node/interceptors/XMLHttpRequest/node.js.map +1 -0
  54. package/lib/node/interceptors/fetch/node.d.ts +18 -0
  55. package/lib/node/interceptors/fetch/node.js +83 -0
  56. package/lib/node/interceptors/fetch/node.js.map +1 -0
  57. package/lib/node/interceptors/http/index.d.ts +14 -0
  58. package/lib/node/interceptors/http/index.js +32 -0
  59. package/lib/node/interceptors/http/index.js.map +1 -0
  60. package/lib/node/interceptors/net/index.d.ts +203 -0
  61. package/lib/node/interceptors/net/index.js +2 -0
  62. package/lib/node/llhttp/constants.cjs +485 -0
  63. package/lib/node/llhttp/constants.d.cts +957 -0
  64. package/lib/node/llhttp/llhttp.wasm +0 -0
  65. package/lib/node/net-DtMnyEeg.js +1388 -0
  66. package/lib/node/net-DtMnyEeg.js.map +1 -0
  67. package/lib/node/presets/node.d.ts +12 -0
  68. package/lib/node/presets/node.js +17 -0
  69. package/lib/node/presets/node.js.map +1 -0
  70. package/lib/node/{RemoteHttpInterceptor.d.cts → remote-http-interceptor.d.ts} +12 -11
  71. package/lib/node/{RemoteHttpInterceptor.mjs → remote-http-interceptor.js} +38 -33
  72. package/lib/node/remote-http-interceptor.js.map +1 -0
  73. package/lib/node/source-lP0yyEtA.js +1990 -0
  74. package/lib/node/source-lP0yyEtA.js.map +1 -0
  75. package/package.json +79 -118
  76. package/src/batch-interceptor.test.ts +475 -0
  77. package/src/batch-interceptor.ts +244 -0
  78. package/src/{createRequestId.test.ts → create-request-id.test.ts} +1 -2
  79. package/src/disposable.ts +13 -0
  80. package/src/events/http.ts +92 -0
  81. package/src/events/websocket.ts +47 -0
  82. package/src/glossary.ts +1 -27
  83. package/src/index.ts +18 -10
  84. package/src/interceptor.test.ts +279 -0
  85. package/src/interceptor.ts +139 -0
  86. package/src/interceptors/ClientRequest/index.test.ts +21 -39
  87. package/src/interceptors/ClientRequest/index.ts +64 -179
  88. package/src/interceptors/ClientRequest/utils/{recordRawHeaders.test.ts → record-raw-headers.test.ts} +1 -2
  89. package/src/interceptors/ClientRequest/utils/{recordRawHeaders.ts → record-raw-headers.ts} +29 -2
  90. package/src/interceptors/WebSocket/index.ts +33 -50
  91. package/src/interceptors/WebSocket/utils/{bindEvent.test.ts → bind-event.test.ts} +1 -2
  92. package/src/interceptors/WebSocket/utils/events.test.ts +0 -1
  93. package/src/interceptors/WebSocket/{WebSocketClassTransport.ts → web-socket-class-transport.ts} +3 -3
  94. package/src/interceptors/WebSocket/{WebSocketClientConnection.ts → web-socket-client-connection.ts} +4 -4
  95. package/src/interceptors/WebSocket/{WebSocketOverride.ts → web-socket-override.ts} +6 -7
  96. package/src/interceptors/WebSocket/{WebSocketServerConnection.ts → web-socket-server-connection.ts} +4 -4
  97. package/src/interceptors/WebSocket/{WebSocketTransport.ts → web-socket-transport.ts} +1 -1
  98. package/src/interceptors/XMLHttpRequest/node.ts +104 -0
  99. package/src/interceptors/XMLHttpRequest/polyfills/{ProgressEventPolyfill.ts → progress-event-polyfill.ts} +1 -1
  100. package/src/interceptors/XMLHttpRequest/utils/{concateArrayBuffer.test.ts → concat-array-buffer.test.ts} +1 -2
  101. package/src/interceptors/XMLHttpRequest/utils/{concatArrayBuffer.ts → concat-array-buffer.ts} +1 -1
  102. package/src/interceptors/XMLHttpRequest/utils/{createEvent.test.ts → create-event.test.ts} +3 -4
  103. package/src/interceptors/XMLHttpRequest/utils/{createEvent.ts → create-event.ts} +2 -2
  104. package/src/interceptors/XMLHttpRequest/utils/{createResponse.ts → create-response.ts} +1 -1
  105. package/src/interceptors/XMLHttpRequest/utils/{getBodyByteLength.test.ts → get-body-byte-length.test.ts} +1 -2
  106. package/src/interceptors/XMLHttpRequest/web.ts +34 -0
  107. package/src/interceptors/XMLHttpRequest/{XMLHttpRequestController.ts → xml-http-request-controller.ts} +363 -204
  108. package/src/interceptors/XMLHttpRequest/{XMLHttpRequestProxy.ts → xml-http-request-proxy.ts} +28 -25
  109. package/src/interceptors/fetch/node.ts +103 -0
  110. package/src/interceptors/fetch/utils/{followRedirect.ts → follow-redirect.ts} +1 -1
  111. package/src/interceptors/fetch/web.ts +217 -0
  112. package/src/interceptors/http/forward-events.test.ts +86 -0
  113. package/src/interceptors/http/forward-events.ts +139 -0
  114. package/src/interceptors/http/http-parser/index.ts +310 -0
  115. package/src/interceptors/http/http-parser/llhttp/constants.cjs +485 -0
  116. package/src/interceptors/http/http-parser/llhttp/constants.d.cts +957 -0
  117. package/src/interceptors/http/http-parser/llhttp/llhttp.wasm +0 -0
  118. package/src/interceptors/http/http-parser.ts +138 -0
  119. package/src/interceptors/http/index.ts +34 -0
  120. package/src/interceptors/http/source.ts +688 -0
  121. package/src/interceptors/net/index.ts +368 -0
  122. package/src/interceptors/net/socket-controller.ts +1476 -0
  123. package/src/interceptors/net/utils/address-info.ts +54 -0
  124. package/src/interceptors/net/utils/connection-options-to-url.ts +56 -0
  125. package/src/interceptors/net/utils/flush-writes.ts +57 -0
  126. package/src/interceptors/net/utils/get-tls-connect-options.ts +23 -0
  127. package/src/interceptors/net/utils/normalize-net-connect-args.test.ts +233 -0
  128. package/src/interceptors/net/utils/normalize-net-connect-args.ts +121 -0
  129. package/src/interceptors/net/utils/normalize-tls-connect-args.ts +50 -0
  130. package/src/presets/browser.ts +4 -4
  131. package/src/presets/node.ts +4 -4
  132. package/src/{RemoteHttpInterceptor.ts → remote-http-interceptor.ts} +55 -42
  133. package/src/request-context.ts +40 -0
  134. package/src/{RequestController.test.ts → request-controller.test.ts} +37 -3
  135. package/src/{RequestController.ts → request-controller.ts} +33 -11
  136. package/src/utils/{bufferUtils.test.ts → buffer-utils.test.ts} +1 -2
  137. package/src/utils/buffer-utils.ts +37 -0
  138. package/src/utils/{cloneObject.test.ts → clone-object.test.ts} +1 -2
  139. package/src/utils/{cloneObject.ts → clone-object.ts} +8 -8
  140. package/src/utils/{createProxy.test.ts → create-proxy.test.ts} +6 -4
  141. package/src/utils/{createProxy.ts → create-proxy.ts} +1 -1
  142. package/src/utils/{fetchUtils.test.ts → fetch-utils.test.ts} +1 -1
  143. package/src/utils/{fetchUtils.ts → fetch-utils.ts} +28 -3
  144. package/src/utils/{findPropertySource.test.ts → find-property-source.test.ts} +1 -2
  145. package/src/utils/{getCleanUrl.test.ts → get-clean-url.test.ts} +1 -2
  146. package/src/utils/{getUrlByRequestOptions.test.ts → get-url-by-request-options.test.ts} +4 -8
  147. package/src/utils/{getUrlByRequestOptions.ts → get-url-by-request-options.ts} +16 -16
  148. package/src/utils/{getValueBySymbol.test.ts → get-value-by-symbol.test.ts} +1 -2
  149. package/src/utils/{handleRequest.ts → handle-request.ts} +61 -41
  150. package/src/utils/{hasConfigurableGlobal.test.ts → has-configurable-global.test.ts} +1 -2
  151. package/src/utils/{hasConfigurableGlobal.ts → has-configurable-global.ts} +2 -4
  152. package/src/utils/{isObject.test.ts → is-object.test.ts} +1 -2
  153. package/src/utils/logger.test.ts +154 -0
  154. package/src/utils/logger.ts +154 -0
  155. package/src/utils/{parseJson.test.ts → parse-json.test.ts} +1 -2
  156. package/src/utils/{patchesRegistry.test.ts → patches-registry.test.ts} +1 -1
  157. package/src/utils/{patchesRegistry.ts → patches-registry.ts} +1 -1
  158. package/src/utils/{responseUtils.ts → response-utils.ts} +25 -2
  159. package/ClientRequest/package.json +0 -11
  160. package/RemoteHttpInterceptor/package.json +0 -11
  161. package/WebSocket/package.json +0 -12
  162. package/XMLHttpRequest/package.json +0 -12
  163. package/fetch/package.json +0 -12
  164. package/lib/browser/Interceptor-Deczogc8.d.cts +0 -65
  165. package/lib/browser/Interceptor-gqKgs-aF.d.mts +0 -65
  166. package/lib/browser/XMLHttpRequest-DrZAf3w6.mjs.map +0 -1
  167. package/lib/browser/XMLHttpRequest-gXuzzX1g.cjs +0 -751
  168. package/lib/browser/XMLHttpRequest-gXuzzX1g.cjs.map +0 -1
  169. package/lib/browser/bufferUtils-BiiO6HZv.mjs.map +0 -1
  170. package/lib/browser/bufferUtils-Uc0eRItL.cjs +0 -38
  171. package/lib/browser/bufferUtils-Uc0eRItL.cjs.map +0 -1
  172. package/lib/browser/createRequestId-DOf8Ktjs.cjs +0 -205
  173. package/lib/browser/createRequestId-DOf8Ktjs.cjs.map +0 -1
  174. package/lib/browser/createRequestId-DYCsFHOi.mjs +0 -170
  175. package/lib/browser/createRequestId-DYCsFHOi.mjs.map +0 -1
  176. package/lib/browser/fetch-5IMPqr9e.mjs +0 -236
  177. package/lib/browser/fetch-5IMPqr9e.mjs.map +0 -1
  178. package/lib/browser/fetch-Bt9rMY9c.cjs +0 -241
  179. package/lib/browser/fetch-Bt9rMY9c.cjs.map +0 -1
  180. package/lib/browser/getRawRequest-B1BqgWG6.mjs.map +0 -1
  181. package/lib/browser/getRawRequest-DdfaiPVH.cjs +0 -376
  182. package/lib/browser/getRawRequest-DdfaiPVH.cjs.map +0 -1
  183. package/lib/browser/glossary-1lhZx6Aw.d.cts +0 -69
  184. package/lib/browser/glossary-nkHWcwvY.d.mts +0 -69
  185. package/lib/browser/handleRequest-CJim54xG.cjs +0 -191
  186. package/lib/browser/handleRequest-CJim54xG.cjs.map +0 -1
  187. package/lib/browser/handleRequest-CPPgsG7s.mjs +0 -180
  188. package/lib/browser/handleRequest-CPPgsG7s.mjs.map +0 -1
  189. package/lib/browser/hasConfigurableGlobal-C8zq1MCg.mjs +0 -109
  190. package/lib/browser/hasConfigurableGlobal-C8zq1MCg.mjs.map +0 -1
  191. package/lib/browser/hasConfigurableGlobal-CS7adEvV.cjs +0 -126
  192. package/lib/browser/hasConfigurableGlobal-CS7adEvV.cjs.map +0 -1
  193. package/lib/browser/index.cjs +0 -70
  194. package/lib/browser/index.cjs.map +0 -1
  195. package/lib/browser/index.d.mts +0 -125
  196. package/lib/browser/index.mjs +0 -56
  197. package/lib/browser/index.mjs.map +0 -1
  198. package/lib/browser/interceptors/WebSocket/index.cjs +0 -618
  199. package/lib/browser/interceptors/WebSocket/index.cjs.map +0 -1
  200. package/lib/browser/interceptors/WebSocket/index.mjs.map +0 -1
  201. package/lib/browser/interceptors/XMLHttpRequest/index.cjs +0 -8
  202. package/lib/browser/interceptors/XMLHttpRequest/index.d.cts +0 -15
  203. package/lib/browser/interceptors/XMLHttpRequest/index.d.mts +0 -15
  204. package/lib/browser/interceptors/XMLHttpRequest/index.mjs +0 -8
  205. package/lib/browser/interceptors/fetch/index.cjs +0 -7
  206. package/lib/browser/interceptors/fetch/index.d.cts +0 -13
  207. package/lib/browser/interceptors/fetch/index.d.mts +0 -13
  208. package/lib/browser/interceptors/fetch/index.mjs +0 -7
  209. package/lib/browser/presets/browser.cjs +0 -18
  210. package/lib/browser/presets/browser.cjs.map +0 -1
  211. package/lib/browser/presets/browser.d.cts +0 -12
  212. package/lib/browser/presets/browser.d.mts +0 -14
  213. package/lib/browser/presets/browser.mjs +0 -18
  214. package/lib/browser/presets/browser.mjs.map +0 -1
  215. package/lib/browser/resolveWebSocketUrl-6K6EgqsA.cjs +0 -31
  216. package/lib/browser/resolveWebSocketUrl-6K6EgqsA.cjs.map +0 -1
  217. package/lib/browser/resolveWebSocketUrl-C83-x9iE.mjs.map +0 -1
  218. package/lib/node/BatchInterceptor-BGhH8z1z.cjs +0 -49
  219. package/lib/node/BatchInterceptor-BGhH8z1z.cjs.map +0 -1
  220. package/lib/node/BatchInterceptor-C4-RX5rg.mjs +0 -44
  221. package/lib/node/BatchInterceptor-C4-RX5rg.mjs.map +0 -1
  222. package/lib/node/BatchInterceptor-KKF8Q47I.d.cts +0 -26
  223. package/lib/node/BatchInterceptor-rSr-NH_H.d.mts +0 -26
  224. package/lib/node/ClientRequest-2loAH7xM.cjs +0 -1058
  225. package/lib/node/ClientRequest-2loAH7xM.cjs.map +0 -1
  226. package/lib/node/ClientRequest-DGhBX21V.mjs +0 -1049
  227. package/lib/node/ClientRequest-DGhBX21V.mjs.map +0 -1
  228. package/lib/node/Interceptor-BsZ21ue0.d.cts +0 -132
  229. package/lib/node/Interceptor-soD-WpQO.d.mts +0 -132
  230. package/lib/node/RemoteHttpInterceptor.cjs +0 -155
  231. package/lib/node/RemoteHttpInterceptor.cjs.map +0 -1
  232. package/lib/node/RemoteHttpInterceptor.d.mts +0 -39
  233. package/lib/node/RemoteHttpInterceptor.mjs.map +0 -1
  234. package/lib/node/XMLHttpRequest-BtDNZipW.cjs +0 -752
  235. package/lib/node/XMLHttpRequest-BtDNZipW.cjs.map +0 -1
  236. package/lib/node/XMLHttpRequest-Dw6Wm-UU.mjs +0 -746
  237. package/lib/node/XMLHttpRequest-Dw6Wm-UU.mjs.map +0 -1
  238. package/lib/node/bufferUtils-DxPxwff_.mjs +0 -20
  239. package/lib/node/bufferUtils-DxPxwff_.mjs.map +0 -1
  240. package/lib/node/bufferUtils-S5_-2eN4.cjs +0 -38
  241. package/lib/node/bufferUtils-S5_-2eN4.cjs.map +0 -1
  242. package/lib/node/chunk-CbDLau6x.cjs +0 -34
  243. package/lib/node/fetch-CaC3rGEu.mjs +0 -252
  244. package/lib/node/fetch-CaC3rGEu.mjs.map +0 -1
  245. package/lib/node/fetch-D2ClLNN-.cjs +0 -259
  246. package/lib/node/fetch-D2ClLNN-.cjs.map +0 -1
  247. package/lib/node/fetchUtils-BKJ1XmiO.mjs +0 -480
  248. package/lib/node/fetchUtils-BKJ1XmiO.mjs.map +0 -1
  249. package/lib/node/fetchUtils-umV5xXBy.cjs +0 -546
  250. package/lib/node/fetchUtils-umV5xXBy.cjs.map +0 -1
  251. package/lib/node/getRawRequest-B6znU6il.cjs +0 -36
  252. package/lib/node/getRawRequest-B6znU6il.cjs.map +0 -1
  253. package/lib/node/getRawRequest-C2-1urzA.mjs +0 -24
  254. package/lib/node/getRawRequest-C2-1urzA.mjs.map +0 -1
  255. package/lib/node/handleRequest-C-cKYjIh.cjs +0 -222
  256. package/lib/node/handleRequest-C-cKYjIh.cjs.map +0 -1
  257. package/lib/node/handleRequest-FIQv5pwH.mjs +0 -192
  258. package/lib/node/handleRequest-FIQv5pwH.mjs.map +0 -1
  259. package/lib/node/hasConfigurableGlobal-BiTmog1u.mjs.map +0 -1
  260. package/lib/node/hasConfigurableGlobal-MjY06_Ok.cjs +0 -108
  261. package/lib/node/hasConfigurableGlobal-MjY06_Ok.cjs.map +0 -1
  262. package/lib/node/index-BJ5E5aW-.d.cts +0 -113
  263. package/lib/node/index-DfoF45ih.d.mts +0 -113
  264. package/lib/node/index.cjs +0 -53
  265. package/lib/node/index.cjs.map +0 -1
  266. package/lib/node/index.d.cts +0 -104
  267. package/lib/node/index.d.mts +0 -104
  268. package/lib/node/index.mjs.map +0 -1
  269. package/lib/node/interceptors/ClientRequest/index.cjs +0 -6
  270. package/lib/node/interceptors/ClientRequest/index.d.cts +0 -2
  271. package/lib/node/interceptors/ClientRequest/index.d.mts +0 -3
  272. package/lib/node/interceptors/ClientRequest/index.mjs +0 -6
  273. package/lib/node/interceptors/XMLHttpRequest/index.cjs +0 -7
  274. package/lib/node/interceptors/XMLHttpRequest/index.d.cts +0 -14
  275. package/lib/node/interceptors/XMLHttpRequest/index.d.mts +0 -14
  276. package/lib/node/interceptors/XMLHttpRequest/index.mjs +0 -7
  277. package/lib/node/interceptors/fetch/index.cjs +0 -6
  278. package/lib/node/interceptors/fetch/index.d.cts +0 -12
  279. package/lib/node/interceptors/fetch/index.d.mts +0 -12
  280. package/lib/node/interceptors/fetch/index.mjs +0 -6
  281. package/lib/node/node-DIKcnzhK.cjs +0 -39
  282. package/lib/node/node-DIKcnzhK.cjs.map +0 -1
  283. package/lib/node/node-lsdNwZEW.mjs +0 -27
  284. package/lib/node/node-lsdNwZEW.mjs.map +0 -1
  285. package/lib/node/presets/node.cjs +0 -23
  286. package/lib/node/presets/node.cjs.map +0 -1
  287. package/lib/node/presets/node.d.cts +0 -13
  288. package/lib/node/presets/node.d.mts +0 -15
  289. package/lib/node/presets/node.mjs +0 -23
  290. package/lib/node/presets/node.mjs.map +0 -1
  291. package/lib/node/utils/node/index.cjs +0 -4
  292. package/lib/node/utils/node/index.d.cts +0 -16
  293. package/lib/node/utils/node/index.d.mts +0 -16
  294. package/lib/node/utils/node/index.mjs +0 -3
  295. package/presets/browser/package.json +0 -5
  296. package/presets/node/package.json +0 -11
  297. package/src/BatchInterceptor.test.ts +0 -255
  298. package/src/BatchInterceptor.ts +0 -96
  299. package/src/Interceptor.test.ts +0 -205
  300. package/src/Interceptor.ts +0 -249
  301. package/src/getRawRequest.ts +0 -21
  302. package/src/interceptors/ClientRequest/MockHttpSocket.ts +0 -724
  303. package/src/interceptors/ClientRequest/agents.ts +0 -110
  304. package/src/interceptors/ClientRequest/utils/getIncomingMessageBody.test.ts +0 -54
  305. package/src/interceptors/ClientRequest/utils/getIncomingMessageBody.ts +0 -45
  306. package/src/interceptors/ClientRequest/utils/normalizeClientRequestArgs.test.ts +0 -427
  307. package/src/interceptors/ClientRequest/utils/normalizeClientRequestArgs.ts +0 -268
  308. package/src/interceptors/ClientRequest/utils/parserUtils.ts +0 -48
  309. package/src/interceptors/Socket/MockSocket.test.ts +0 -264
  310. package/src/interceptors/Socket/MockSocket.ts +0 -58
  311. package/src/interceptors/Socket/utils/baseUrlFromConnectionOptions.ts +0 -26
  312. package/src/interceptors/Socket/utils/normalizeSocketWriteArgs.test.ts +0 -52
  313. package/src/interceptors/Socket/utils/normalizeSocketWriteArgs.ts +0 -33
  314. package/src/interceptors/XMLHttpRequest/index.ts +0 -40
  315. package/src/interceptors/fetch/index.ts +0 -203
  316. package/src/utils/bufferUtils.ts +0 -22
  317. package/src/utils/canParseUrl.ts +0 -13
  318. package/src/utils/emitAsync.ts +0 -25
  319. package/src/utils/nextTick.ts +0 -11
  320. package/src/utils/node/index.ts +0 -39
  321. /package/src/{createRequestId.ts → create-request-id.ts} +0 -0
  322. /package/src/{InterceptorError.ts → interceptor-error.ts} +0 -0
  323. /package/src/interceptors/WebSocket/utils/{bindEvent.ts → bind-event.ts} +0 -0
  324. /package/src/interceptors/XMLHttpRequest/polyfills/{EventPolyfill.ts → event-polyfill.ts} +0 -0
  325. /package/src/interceptors/XMLHttpRequest/utils/{getBodyByteLength.ts → get-body-byte-length.ts} +0 -0
  326. /package/src/interceptors/XMLHttpRequest/utils/{isDomParserSupportedType.ts → is-dom-parser-supported-type.ts} +0 -0
  327. /package/src/interceptors/fetch/utils/{createNetworkError.ts → create-network-error.ts} +0 -0
  328. /package/src/utils/{findPropertySource.ts → find-property-source.ts} +0 -0
  329. /package/src/utils/{getCleanUrl.ts → get-clean-url.ts} +0 -0
  330. /package/src/utils/{getValueBySymbol.ts → get-value-by-symbol.ts} +0 -0
  331. /package/src/utils/{isNodeLikeError.ts → is-node-like-error.ts} +0 -0
  332. /package/src/utils/{isObject.ts → is-object.ts} +0 -0
  333. /package/src/utils/{isPropertyAccessible.ts → is-property-accessible.ts} +0 -0
  334. /package/src/utils/{parseJson.ts → parse-json.ts} +0 -0
  335. /package/src/utils/{resolveWebSocketUrl.ts → resolve-web-socket-url.ts} +0 -0
@@ -0,0 +1,475 @@
1
+ import { TypedEvent } from 'rettime'
2
+ import { Interceptor, InterceptorReadyState } from './interceptor'
3
+ import { BatchInterceptor } from './batch-interceptor'
4
+
5
+ afterEach(() => {
6
+ vi.resetAllMocks()
7
+ })
8
+
9
+ it('applies child interceptors', () => {
10
+ class PrimaryInterceptor extends Interceptor<any> {
11
+ protected predicate(): boolean {
12
+ return true
13
+ }
14
+ protected setup(): void {}
15
+ }
16
+
17
+ class SecondInterceptor extends Interceptor<any> {
18
+ protected predicate(): boolean {
19
+ return true
20
+ }
21
+ protected setup(): void {}
22
+ }
23
+
24
+ const instances = {
25
+ primary: new PrimaryInterceptor(),
26
+ secondary: new SecondInterceptor(),
27
+ }
28
+
29
+ const interceptor = new BatchInterceptor({
30
+ name: 'batch-apply',
31
+ interceptors: [instances.primary, instances.secondary],
32
+ })
33
+
34
+ const primaryApplySpy = vi.spyOn(instances.primary, 'apply')
35
+ const secondaryApplySpy = vi.spyOn(instances.secondary, 'apply')
36
+
37
+ interceptor.apply()
38
+
39
+ expect(primaryApplySpy).toHaveBeenCalledTimes(1)
40
+ expect(secondaryApplySpy).toHaveBeenCalledTimes(1)
41
+ })
42
+
43
+ it('applies duplicate child interceptors once', () => {
44
+ class ChildInterceptor extends Interceptor<{
45
+ request: TypedEvent
46
+ }> {
47
+ protected predicate(): boolean {
48
+ return true
49
+ }
50
+
51
+ protected setup(): void {}
52
+ }
53
+
54
+ const childInterceptor = new ChildInterceptor()
55
+ const interceptor = new BatchInterceptor({
56
+ name: 'batch-apply-duplicate',
57
+ interceptors: [childInterceptor, childInterceptor],
58
+ })
59
+ const applySpy = vi.spyOn(childInterceptor, 'apply')
60
+ const listener = vi.fn()
61
+
62
+ interceptor.on('request', listener)
63
+ interceptor.apply()
64
+
65
+ expect(applySpy).toHaveBeenCalledOnce()
66
+ expect(childInterceptor.listenerCount('request')).toBe(1)
67
+
68
+ interceptor.dispose()
69
+ })
70
+
71
+ it('proxies event listeners to the interceptors', () => {
72
+ class PrimaryInterceptor extends Interceptor<{
73
+ hello: TypedEvent<string>
74
+ }> {
75
+ protected predicate(): boolean {
76
+ return true
77
+ }
78
+ protected setup(): void {}
79
+ }
80
+
81
+ class SecondInterceptor extends Interceptor<{
82
+ goodbye: TypedEvent<string>
83
+ }> {
84
+ protected predicate(): boolean {
85
+ return true
86
+ }
87
+ protected setup(): void {}
88
+ }
89
+
90
+ const instances = {
91
+ primary: new PrimaryInterceptor(),
92
+ secondary: new SecondInterceptor(),
93
+ }
94
+
95
+ const interceptor = new BatchInterceptor({
96
+ name: 'batch-proxy',
97
+ interceptors: [instances.primary, instances.secondary],
98
+ })
99
+
100
+ const helloListener = vi.fn()
101
+ interceptor.on('hello', helloListener)
102
+
103
+ const goodbyeListener = vi.fn()
104
+ interceptor.on('goodbye', goodbyeListener)
105
+
106
+ // Emulate the child interceptor emitting events.
107
+ const helloEvent = new TypedEvent('hello', { data: 'John' })
108
+ instances.primary['emitter'].emit(helloEvent)
109
+
110
+ const goodbyeEvent = new TypedEvent('goodbye', { data: 'Kate' })
111
+ instances.secondary['emitter'].emit(goodbyeEvent)
112
+
113
+ // Must call the batch interceptor listener.
114
+ expect(helloListener).toHaveBeenCalledExactlyOnceWith(helloEvent)
115
+ expect(goodbyeListener).toHaveBeenCalledExactlyOnceWith(goodbyeEvent)
116
+ })
117
+
118
+ it('disposes of child interceptors', async () => {
119
+ class PrimaryInterceptor extends Interceptor<any> {
120
+ protected predicate(): boolean {
121
+ return true
122
+ }
123
+ protected setup(): void {}
124
+ }
125
+
126
+ class SecondInterceptor extends Interceptor<any> {
127
+ protected predicate(): boolean {
128
+ return true
129
+ }
130
+ protected setup(): void {}
131
+ }
132
+
133
+ const instances = {
134
+ primary: new PrimaryInterceptor(),
135
+ secondary: new SecondInterceptor(),
136
+ }
137
+
138
+ const interceptor = new BatchInterceptor({
139
+ name: 'batch-dispose',
140
+ interceptors: [instances.primary, instances.secondary],
141
+ })
142
+
143
+ const primaryDisposeSpy = vi.spyOn(instances.primary, 'dispose')
144
+ const secondaryDisposeSpy = vi.spyOn(instances.secondary, 'dispose')
145
+
146
+ interceptor.apply()
147
+ interceptor.dispose()
148
+
149
+ expect(primaryDisposeSpy).toHaveBeenCalledTimes(1)
150
+ expect(secondaryDisposeSpy).toHaveBeenCalledTimes(1)
151
+ })
152
+
153
+ it('bridges events to listeners added via "on()"', () => {
154
+ class FirstInterceptor extends Interceptor<any> {
155
+ protected predicate(): boolean {
156
+ return true
157
+ }
158
+ protected setup(): void {}
159
+ }
160
+ class SecondInterceptor extends Interceptor<any> {
161
+ protected predicate(): boolean {
162
+ return true
163
+ }
164
+ protected setup(): void {}
165
+ }
166
+
167
+ const firstInterceptor = new FirstInterceptor()
168
+ const secondInterceptor = new SecondInterceptor()
169
+
170
+ const interceptor = new BatchInterceptor({
171
+ name: 'batch',
172
+ interceptors: [firstInterceptor, secondInterceptor],
173
+ })
174
+
175
+ const listener = vi.fn()
176
+ interceptor.on('foo', listener)
177
+
178
+ expect(firstInterceptor['emitter'].listenerCount('foo')).toBe(1)
179
+ expect(secondInterceptor['emitter'].listenerCount('foo')).toBe(1)
180
+ expect(interceptor['emitter'].listenerCount('foo')).toBe(1)
181
+ })
182
+
183
+ it('forwards listeners removal via "removeListener()"', () => {
184
+ type Events = {
185
+ foo: TypedEvent
186
+ }
187
+
188
+ class FirstInterceptor extends Interceptor<Events> {
189
+ protected predicate(): boolean {
190
+ return true
191
+ }
192
+ protected setup(): void {}
193
+ }
194
+ class SecondInterceptor extends Interceptor<Events> {
195
+ protected predicate(): boolean {
196
+ return true
197
+ }
198
+ protected setup(): void {}
199
+ }
200
+
201
+ const firstInterceptor = new FirstInterceptor()
202
+ const secondInterceptor = new SecondInterceptor()
203
+
204
+ const interceptor = new BatchInterceptor({
205
+ name: 'batch',
206
+ interceptors: [firstInterceptor, secondInterceptor],
207
+ })
208
+
209
+ const listener = vi.fn()
210
+ interceptor.on('foo', listener)
211
+ interceptor.removeListener('foo', listener)
212
+
213
+ expect(firstInterceptor['emitter'].listenerCount('foo')).toBe(0)
214
+ expect(secondInterceptor['emitter'].listenerCount('foo')).toBe(0)
215
+ })
216
+
217
+ it('forwards removal of all listeners by name via ".removeAllListeners()"', () => {
218
+ type Events = {
219
+ foo: TypedEvent
220
+ bar: TypedEvent
221
+ }
222
+
223
+ class FirstInterceptor extends Interceptor<Events> {
224
+ protected predicate(): boolean {
225
+ return true
226
+ }
227
+ protected setup(): void {}
228
+ }
229
+ class SecondInterceptor extends Interceptor<Events> {
230
+ protected predicate(): boolean {
231
+ return true
232
+ }
233
+ protected setup(): void {}
234
+ }
235
+
236
+ const firstInterceptor = new FirstInterceptor()
237
+ const secondInterceptor = new SecondInterceptor()
238
+
239
+ const interceptor = new BatchInterceptor({
240
+ name: 'batch',
241
+ interceptors: [firstInterceptor, secondInterceptor],
242
+ })
243
+
244
+ const listener = vi.fn()
245
+ interceptor.on('foo', listener)
246
+ interceptor.on('foo', listener)
247
+ interceptor.on('bar', listener)
248
+
249
+ expect(firstInterceptor['emitter'].listenerCount('foo')).toBe(1)
250
+ expect(firstInterceptor['emitter'].listenerCount('bar')).toBe(1)
251
+
252
+ expect(secondInterceptor['emitter'].listenerCount('foo')).toBe(1)
253
+ expect(secondInterceptor['emitter'].listenerCount('bar')).toBe(1)
254
+ expect(interceptor.listenerCount('foo')).toBe(2)
255
+ expect(interceptor.listenerCount('bar')).toBe(1)
256
+
257
+ interceptor.removeAllListeners('foo')
258
+
259
+ expect(firstInterceptor['emitter'].listenerCount('foo')).toBe(0)
260
+ expect(firstInterceptor['emitter'].listenerCount('bar')).toBe(1)
261
+ expect(secondInterceptor['emitter'].listenerCount('foo')).toBe(0)
262
+ expect(secondInterceptor['emitter'].listenerCount('bar')).toBe(1)
263
+ expect(interceptor.listenerCount('foo')).toBe(0)
264
+ expect(interceptor.listenerCount('bar')).toBe(1)
265
+ })
266
+
267
+ it('forwards removal of all listeners via ".removeAllListeners()"', () => {
268
+ class FirstInterceptor extends Interceptor<any> {
269
+ protected predicate(): boolean {
270
+ return true
271
+ }
272
+ protected setup(): void {}
273
+ }
274
+ class SecondInterceptor extends Interceptor<any> {
275
+ protected predicate(): boolean {
276
+ return true
277
+ }
278
+ protected setup(): void {}
279
+ }
280
+
281
+ const firstInterceptor = new FirstInterceptor()
282
+ const secondInterceptor = new SecondInterceptor()
283
+
284
+ const interceptor = new BatchInterceptor({
285
+ name: 'batch',
286
+ interceptors: [firstInterceptor, secondInterceptor],
287
+ })
288
+
289
+ const listener = vi.fn()
290
+ interceptor.on('foo', listener)
291
+ interceptor.on('foo', listener)
292
+ interceptor.on('bar', listener)
293
+
294
+ expect(firstInterceptor['emitter'].listenerCount('foo')).toBe(1)
295
+ expect(firstInterceptor['emitter'].listenerCount('bar')).toBe(1)
296
+ expect(secondInterceptor['emitter'].listenerCount('foo')).toBe(1)
297
+ expect(secondInterceptor['emitter'].listenerCount('bar')).toBe(1)
298
+ expect(interceptor.listenerCount()).toBe(3)
299
+
300
+ interceptor.removeAllListeners()
301
+
302
+ expect(firstInterceptor['emitter'].listenerCount('foo')).toBe(0)
303
+ expect(secondInterceptor['emitter'].listenerCount('foo')).toBe(0)
304
+ expect(firstInterceptor['emitter'].listenerCount('bar')).toBe(0)
305
+ expect(secondInterceptor['emitter'].listenerCount('bar')).toBe(0)
306
+ expect(interceptor.listenerCount()).toBe(0)
307
+ })
308
+
309
+ it('handles the same event instance only once', () => {
310
+ type Events = {
311
+ request: TypedEvent<string>
312
+ }
313
+
314
+ class RequestInterceptor extends Interceptor<Events> {
315
+ protected predicate(): boolean {
316
+ return true
317
+ }
318
+
319
+ protected setup(): void {}
320
+ }
321
+
322
+ const firstInterceptor = new RequestInterceptor()
323
+ const secondInterceptor = new RequestInterceptor()
324
+ const interceptor = new BatchInterceptor({
325
+ name: 'batch',
326
+ interceptors: [firstInterceptor, secondInterceptor],
327
+ })
328
+ const listener = vi.fn()
329
+ const requestEvent = new TypedEvent('request', { data: 'first' })
330
+
331
+ interceptor.on('request', listener)
332
+ firstInterceptor['emitter'].emit(requestEvent)
333
+ secondInterceptor['emitter'].emit(requestEvent)
334
+
335
+ expect(listener).toHaveBeenCalledExactlyOnceWith(requestEvent)
336
+
337
+ const nextRequestEvent = new TypedEvent('request', { data: 'second' })
338
+ secondInterceptor['emitter'].emit(nextRequestEvent)
339
+
340
+ expect(listener).toHaveBeenCalledTimes(2)
341
+ expect(listener).toHaveBeenLastCalledWith(nextRequestEvent)
342
+ })
343
+
344
+ it('applies "once" across all child interceptors', () => {
345
+ type Events = {
346
+ request: TypedEvent<string>
347
+ }
348
+
349
+ class RequestInterceptor extends Interceptor<Events> {
350
+ protected predicate(): boolean {
351
+ return true
352
+ }
353
+
354
+ protected setup(): void {}
355
+ }
356
+
357
+ const firstInterceptor = new RequestInterceptor()
358
+ const secondInterceptor = new RequestInterceptor()
359
+ const interceptor = new BatchInterceptor({
360
+ name: 'batch',
361
+ interceptors: [firstInterceptor, secondInterceptor],
362
+ })
363
+ const listener = vi.fn()
364
+
365
+ interceptor.once('request', listener)
366
+ firstInterceptor['emitter'].emit(new TypedEvent('request', { data: 'first' }))
367
+ secondInterceptor['emitter'].emit(
368
+ new TypedEvent('request', { data: 'second' })
369
+ )
370
+
371
+ expect(listener).toHaveBeenCalledOnce()
372
+ expect(firstInterceptor.listenerCount('request')).toBe(0)
373
+ expect(secondInterceptor.listenerCount('request')).toBe(0)
374
+ })
375
+
376
+ it('keeps shared child interceptors active until all batches dispose', () => {
377
+ type Events = {
378
+ message: TypedEvent<string>
379
+ }
380
+
381
+ const setup = vi.fn()
382
+ const teardown = vi.fn()
383
+
384
+ class SharedInterceptor extends Interceptor<Events> {
385
+ protected predicate(): boolean {
386
+ return true
387
+ }
388
+
389
+ protected setup(): void {
390
+ setup()
391
+ this.subscriptions.push(teardown)
392
+ }
393
+ }
394
+
395
+ const sharedInterceptor = new SharedInterceptor()
396
+ const primaryBatch = new BatchInterceptor({
397
+ name: 'primary-batch',
398
+ interceptors: [sharedInterceptor],
399
+ })
400
+ const secondaryBatch = new BatchInterceptor({
401
+ name: 'secondary-batch',
402
+ interceptors: [sharedInterceptor],
403
+ })
404
+ const primaryListener = vi.fn()
405
+ const secondaryListener = vi.fn()
406
+
407
+ primaryBatch.apply()
408
+ secondaryBatch.apply()
409
+ primaryBatch.on('message', primaryListener)
410
+ secondaryBatch.on('message', secondaryListener)
411
+
412
+ expect(setup).toHaveBeenCalledOnce()
413
+
414
+ sharedInterceptor['emitter'].emit(
415
+ new TypedEvent('message', { data: 'first' })
416
+ )
417
+
418
+ expect(primaryListener).toHaveBeenCalledTimes(1)
419
+ expect(secondaryListener).toHaveBeenCalledTimes(1)
420
+
421
+ primaryBatch.dispose()
422
+
423
+ expect(sharedInterceptor.readyState).toBe(InterceptorReadyState.ACTIVE)
424
+ expect(teardown).not.toHaveBeenCalled()
425
+
426
+ sharedInterceptor['emitter'].emit(
427
+ new TypedEvent('message', { data: 'second' })
428
+ )
429
+
430
+ expect(primaryListener).toHaveBeenCalledTimes(1)
431
+ expect(secondaryListener).toHaveBeenCalledTimes(2)
432
+
433
+ secondaryBatch.dispose()
434
+
435
+ expect(sharedInterceptor.readyState).toBe(InterceptorReadyState.DISPOSED)
436
+ expect(teardown).toHaveBeenCalledOnce()
437
+ })
438
+
439
+ it('removes only listeners owned by the batch', () => {
440
+ type Events = {
441
+ message: TypedEvent<string>
442
+ }
443
+
444
+ class SharedInterceptor extends Interceptor<Events> {
445
+ protected predicate(): boolean {
446
+ return true
447
+ }
448
+
449
+ protected setup(): void {}
450
+ }
451
+
452
+ const sharedInterceptor = new SharedInterceptor()
453
+ const primaryBatch = new BatchInterceptor({
454
+ name: 'primary-batch',
455
+ interceptors: [sharedInterceptor],
456
+ })
457
+ const secondaryBatch = new BatchInterceptor({
458
+ name: 'secondary-batch',
459
+ interceptors: [sharedInterceptor],
460
+ })
461
+ const primaryListener = vi.fn()
462
+ const secondaryListener = vi.fn()
463
+
464
+ primaryBatch.on('message', primaryListener)
465
+ secondaryBatch.on('message', secondaryListener)
466
+
467
+ primaryBatch.removeAllListeners()
468
+
469
+ sharedInterceptor['emitter'].emit(
470
+ new TypedEvent('message', { data: 'hello' })
471
+ )
472
+
473
+ expect(primaryListener).not.toHaveBeenCalled()
474
+ expect(secondaryListener).toHaveBeenCalledOnce()
475
+ })
@@ -0,0 +1,244 @@
1
+ import {
2
+ type DefaultEventMap,
3
+ Emitter,
4
+ type TypedEvent,
5
+ type WithReservedEvents,
6
+ } from 'rettime'
7
+ import { Interceptor } from './interceptor'
8
+ import { type DisposableSubscription } from './disposable'
9
+
10
+ type GenericEventListener = Emitter.Listener<
11
+ Emitter<DefaultEventMap>,
12
+ string
13
+ >
14
+
15
+ function addEventBridge(
16
+ interceptor: Interceptor<DefaultEventMap>,
17
+ type: string,
18
+ listener: GenericEventListener
19
+ ): void {
20
+ interceptor.on(type, listener)
21
+ }
22
+
23
+ function removeEventBridge(
24
+ interceptor: Interceptor<DefaultEventMap>,
25
+ type: string,
26
+ listener: GenericEventListener
27
+ ): void {
28
+ interceptor.removeListener(type, listener)
29
+ }
30
+
31
+ export interface BatchInterceptorOptions<
32
+ InterceptorList extends ReadonlyArray<Interceptor<DefaultEventMap>>,
33
+ > {
34
+ name: string
35
+ interceptors: InterceptorList
36
+ }
37
+
38
+ type UnionToIntersection<Union> = (
39
+ Union extends unknown ? (argument: Union) => void : never
40
+ ) extends (argument: infer Intersection) => void
41
+ ? Intersection
42
+ : never
43
+
44
+ /**
45
+ * @note Merge the event maps of all the given interceptors into
46
+ * an intersection. A naive conditional type distributes over the
47
+ * interceptor union, producing a union of event maps whose `keyof`
48
+ * is `never` (no common keys), which would make `.on()` unusable.
49
+ */
50
+ export type ExtractEventMapType<
51
+ InterceptorList extends ReadonlyArray<Interceptor<DefaultEventMap>>,
52
+ > =
53
+ InterceptorList extends ReadonlyArray<infer InterceptorType>
54
+ ? UnionToIntersection<
55
+ InterceptorType extends Interceptor<infer EventMap> ? EventMap : never
56
+ >
57
+ : never
58
+
59
+ /**
60
+ * A batch interceptor that exposes a single interface
61
+ * to apply and operate with multiple interceptors at once.
62
+ */
63
+ export class BatchInterceptor<
64
+ InterceptorList extends ReadonlyArray<Interceptor<DefaultEventMap>>,
65
+ Events extends DefaultEventMap = ExtractEventMapType<InterceptorList>,
66
+ > extends Interceptor<Events> {
67
+ #interceptors: InterceptorList
68
+ #eventBridges: Map<string, DisposableSubscription>
69
+ #forwardedEvents: Map<string, WeakSet<object>>
70
+
71
+ constructor(options: BatchInterceptorOptions<InterceptorList>) {
72
+ super()
73
+
74
+ this.#interceptors = options.interceptors
75
+ this.#eventBridges = new Map()
76
+ this.#forwardedEvents = new Map()
77
+
78
+ this.emitter.hooks.on(
79
+ 'newListener',
80
+ (type) => {
81
+ this.#ensureEventBridge(type)
82
+ },
83
+ {
84
+ persist: true,
85
+ }
86
+ )
87
+
88
+ this.emitter.hooks.on(
89
+ 'removeListener',
90
+ (type) => {
91
+ if (this.emitter.listenerCount(type) === 0) {
92
+ this.#removeEventBridge(type)
93
+ }
94
+ },
95
+ {
96
+ persist: true,
97
+ }
98
+ )
99
+ }
100
+
101
+ protected predicate(): boolean {
102
+ for (const interceptor of this.#interceptors) {
103
+ if (interceptor['predicate']()) {
104
+ /**
105
+ * @note If at least one of the provided interceptors suits the environment,
106
+ * treat this batch interceptor as matching. Since all the interceptors abide
107
+ * by the same event map, it will handle the events from any that match.
108
+ */
109
+ return true
110
+ }
111
+ }
112
+
113
+ return false
114
+ }
115
+
116
+ protected setup(): void {
117
+ const interceptors = new Set(this.#interceptors)
118
+
119
+ this.#forwardedEvents = new Map()
120
+
121
+ this.logger.verbose(
122
+ 'applying batch %s with %d interceptors',
123
+ this.constructor.name,
124
+ interceptors.size
125
+ )
126
+
127
+ this.subscriptions.push(() => {
128
+ this.#removeAllEventBridges()
129
+ })
130
+
131
+ for (const interceptor of interceptors) {
132
+ this.logger.verbose(
133
+ 'applying "%s" interceptor...',
134
+ interceptor.constructor.name
135
+ )
136
+ interceptor.apply(this)
137
+
138
+ this.logger.verbose('adding interceptor dispose subscription')
139
+ this.subscriptions.push(() => {
140
+ interceptor.dispose(this)
141
+ })
142
+ }
143
+ }
144
+
145
+ #ensureEventBridge(
146
+ type: keyof WithReservedEvents<Events> & string
147
+ ): void {
148
+ if (this.#eventBridges.has(type)) {
149
+ return
150
+ }
151
+
152
+ if (type === '*') {
153
+ this.#ensureWildcardEventBridge()
154
+ return
155
+ }
156
+
157
+ this.#ensureTypedEventBridge(type)
158
+ }
159
+
160
+ #ensureTypedEventBridge(type: keyof Events & string): void {
161
+ const interceptors = new Set(this.#interceptors)
162
+ const batchEmitter = this.emitter as Emitter<DefaultEventMap>
163
+ const forwardEvent: GenericEventListener = async (event) => {
164
+ if (this.#recordForwardedEvent(event)) {
165
+ this.logger.verbose('skipping duplicate "%s" event', event.type)
166
+ return
167
+ }
168
+
169
+ this.logger.verbose('forwarding "%s" event', event.type)
170
+ await batchEmitter.emitAsPromise(event)
171
+ }
172
+
173
+ for (const interceptor of interceptors) {
174
+ addEventBridge(interceptor, type, forwardEvent)
175
+ }
176
+
177
+ this.#eventBridges.set(type, () => {
178
+ for (const interceptor of interceptors) {
179
+ removeEventBridge(interceptor, type, forwardEvent)
180
+ }
181
+ })
182
+ }
183
+
184
+ #ensureWildcardEventBridge(): void {
185
+ const interceptors = new Set(this.#interceptors)
186
+ const batchEmitter = this.emitter as Emitter<DefaultEventMap>
187
+ const forwardEvent: GenericEventListener = (event: TypedEvent): void => {
188
+ if (this.#recordForwardedEvent(event)) {
189
+ this.logger.verbose('skipping duplicate "%s" event', event.type)
190
+ return
191
+ }
192
+
193
+ this.logger.verbose('forwarding wildcard "%s" event', event.type)
194
+ void batchEmitter.emitAsPromise(event)
195
+ }
196
+
197
+ for (const interceptor of interceptors) {
198
+ addEventBridge(interceptor, '*', forwardEvent)
199
+ }
200
+
201
+ this.#eventBridges.set('*', () => {
202
+ for (const interceptor of interceptors) {
203
+ removeEventBridge(interceptor, '*', forwardEvent)
204
+ }
205
+ })
206
+ }
207
+
208
+ #recordForwardedEvent(event: TypedEvent): boolean {
209
+ const forwardedEvents = this.#forwardedEvents.get(event.type)
210
+
211
+ if (forwardedEvents?.has(event)) {
212
+ return true
213
+ }
214
+
215
+ if (forwardedEvents) {
216
+ forwardedEvents.add(event)
217
+ return false
218
+ }
219
+
220
+ this.#forwardedEvents.set(event.type, new WeakSet([event]))
221
+ return false
222
+ }
223
+
224
+ #removeEventBridge(
225
+ type: keyof WithReservedEvents<Events> & string
226
+ ): void {
227
+ const disposeEventBridge = this.#eventBridges.get(type)
228
+
229
+ if (!disposeEventBridge) {
230
+ return
231
+ }
232
+
233
+ disposeEventBridge()
234
+ this.#eventBridges.delete(type)
235
+ }
236
+
237
+ #removeAllEventBridges(): void {
238
+ for (const disposeEventBridge of this.#eventBridges.values()) {
239
+ disposeEventBridge()
240
+ }
241
+
242
+ this.#eventBridges.clear()
243
+ }
244
+ }