@mswjs/interceptors 0.41.9 → 0.42.1

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-Bk5YX1AM.js +720 -0
  5. package/lib/browser/create-request-id-Bk5YX1AM.js.map +1 -0
  6. package/lib/browser/{getRawRequest-B1BqgWG6.mjs → fetch-utils-CUOrwEQf.js} +123 -52
  7. package/lib/browser/fetch-utils-CUOrwEQf.js.map +1 -0
  8. package/lib/browser/handle-request-CqVvBhcw.js +167 -0
  9. package/lib/browser/handle-request-CqVvBhcw.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/{XMLHttpRequest-DrZAf3w6.mjs → web-BcKSQghf.js} +327 -255
  30. package/lib/browser/web-BcKSQghf.js.map +1 -0
  31. package/lib/browser/web-CdcYFjgm.js +248 -0
  32. package/lib/browser/web-CdcYFjgm.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
@@ -1,8 +1,8 @@
1
- import { Agent } from 'http'
2
- import { RequestOptions, Agent as HttpsAgent } from 'https'
3
- import { Logger } from '@open-draft/logger'
1
+ import { Agent } from 'node:http'
2
+ import { RequestOptions, Agent as HttpsAgent } from 'node:https'
3
+ import { createLogger } from './logger'
4
4
 
5
- const logger = new Logger('utils getUrlByRequestOptions')
5
+ const logger = createLogger('get-url-by-request-options')
6
6
 
7
7
  // Request instance constructed by the "request" library
8
8
  // has a "self" property that has a "uri" field. This is
@@ -13,7 +13,7 @@ export interface RequestSelf {
13
13
 
14
14
  export type ResolvedRequestOptions = RequestOptions & RequestSelf
15
15
 
16
- export const DEFAULT_PATH = '/'
16
+ const DEFAULT_PATH = '/'
17
17
  const DEFAULT_PROTOCOL = 'http:'
18
18
  const DEFAULT_HOSTNAME = 'localhost'
19
19
  const SSL_PORT = 443
@@ -94,7 +94,7 @@ function getHostname(options: ResolvedRequestOptions): string | undefined {
94
94
 
95
95
  if (host) {
96
96
  if (isRawIPv6Address(host)) {
97
- host = `[${host}]`
97
+ host = `[${host}]`
98
98
  }
99
99
 
100
100
  // Check the presence of the port, and if it's present,
@@ -109,44 +109,44 @@ function getHostname(options: ResolvedRequestOptions): string | undefined {
109
109
  * Creates a `URL` instance from a given `RequestOptions` object.
110
110
  */
111
111
  export function getUrlByRequestOptions(options: ResolvedRequestOptions): URL {
112
- logger.info('request options', options)
112
+ logger.verbose('request options %o', options)
113
113
 
114
114
  if (options.uri) {
115
- logger.info(
115
+ logger.verbose(
116
116
  'constructing url from explicitly provided "options.uri": %s',
117
117
  options.uri
118
118
  )
119
119
  return new URL(options.uri.href)
120
120
  }
121
121
 
122
- logger.info('figuring out url from request options...')
122
+ logger.verbose('figuring out URL from request options')
123
123
 
124
124
  const protocol = getProtocolByRequestOptions(options)
125
- logger.info('protocol', protocol)
125
+ logger.verbose('protocol: %s', protocol)
126
126
 
127
127
  const port = getPortByRequestOptions(options)
128
- logger.info('port', port)
128
+ logger.verbose('port: %s', port)
129
129
 
130
130
  const hostname = getHostname(options)
131
- logger.info('hostname', hostname)
131
+ logger.verbose('hostname: %s', hostname)
132
132
 
133
133
  const path = options.path || DEFAULT_PATH
134
- logger.info('path', path)
134
+ logger.verbose('path: %s', path)
135
135
 
136
136
  const credentials = getAuthByRequestOptions(options)
137
- logger.info('credentials', credentials)
137
+ logger.verbose('credentials %o', credentials)
138
138
 
139
139
  const authString = credentials
140
140
  ? `${credentials.username}:${credentials.password}@`
141
141
  : ''
142
- logger.info('auth string:', authString)
142
+ logger.verbose('auth string: %s', authString)
143
143
 
144
144
  const portString = typeof port !== 'undefined' ? `:${port}` : ''
145
145
  const url = new URL(`${protocol}//${hostname}${portString}${path}`)
146
146
  url.username = credentials?.username || ''
147
147
  url.password = credentials?.password || ''
148
148
 
149
- logger.info('created url:', url)
149
+ logger.verbose('created URL: %s', url.href)
150
150
 
151
151
  return url
152
152
  }
@@ -1,5 +1,4 @@
1
- import { it, expect } from 'vitest'
2
- import { getValueBySymbol } from './getValueBySymbol'
1
+ import { getValueBySymbol } from './get-value-by-symbol'
3
2
 
4
3
  it('returns undefined given a non-existing symbol', () => {
5
4
  expect(getValueBySymbol('non-existing', {})).toBeUndefined()
@@ -1,28 +1,40 @@
1
- import type { Emitter } from 'strict-event-emitter'
2
- import { DeferredPromise } from '@open-draft/deferred-promise'
1
+ import type { Emitter } from 'rettime'
3
2
  import { until } from '@open-draft/until'
4
- import type { HttpRequestEventMap } from '../glossary'
5
- import { emitAsync } from './emitAsync'
6
- import { RequestController } from '../RequestController'
3
+ import {
4
+ HttpRequestEvent,
5
+ HttpRequestEventData,
6
+ UnhandledHttpException,
7
+ type HttpRequestEventMap,
8
+ } from '../events/http'
9
+ import { RequestController } from '../request-controller'
7
10
  import {
8
11
  createServerErrorResponse,
9
12
  isResponseError,
10
13
  isResponseLike,
11
- } from './responseUtils'
12
- import { InterceptorError } from '../InterceptorError'
13
- import { isNodeLikeError } from './isNodeLikeError'
14
- import { isObject } from './isObject'
15
-
16
- interface HandleRequestOptions {
14
+ } from './response-utils'
15
+ import { InterceptorError } from '../interceptor-error'
16
+ import { isNodeLikeError } from './is-node-like-error'
17
+ import { isObject } from './is-object'
18
+ import { formatRequest, type Logger } from './logger'
19
+
20
+ export interface HandleRequestOptions {
21
+ initiator: unknown
17
22
  requestId: string
18
23
  request: Request
19
24
  emitter: Emitter<HttpRequestEventMap>
20
25
  controller: RequestController
26
+ logger?: Logger
21
27
  }
22
28
 
23
29
  export async function handleRequest(
24
30
  options: HandleRequestOptions
25
31
  ): Promise<void> {
32
+ if (options.logger?.isEnabled('default')) {
33
+ void formatRequest(options.request).then((message) => {
34
+ options.logger?.info('[%s] %s', options.requestId, message)
35
+ })
36
+ }
37
+
26
38
  const handleResponse = async (
27
39
  response: Response | Error | Record<string, any>
28
40
  ) => {
@@ -60,7 +72,7 @@ export async function handleRequest(
60
72
  // Forward the special interceptor error instances
61
73
  // to the developer. These must not be handled in any way.
62
74
  if (error instanceof InterceptorError) {
63
- throw result.error
75
+ throw resultError
64
76
  }
65
77
 
66
78
  // Support mocking Node.js-like errors.
@@ -77,21 +89,13 @@ export async function handleRequest(
77
89
  return false
78
90
  }
79
91
 
80
- // Add the last "request" listener to check if the request
81
- // has been handled in any way. If it hasn't, resolve the
82
- // response promise with undefined.
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
- // })
91
-
92
- const requestAbortPromise = new DeferredPromise<void, unknown>()
92
+ const requestAbortPromise = Promise.withResolvers<void>()
93
+ let requestAbortReason: unknown
94
+ let isRequestAborted = false
93
95
  const onAbort = () => {
94
- requestAbortPromise.reject(options.request.signal?.reason)
96
+ isRequestAborted = true
97
+ requestAbortReason = options.request.signal?.reason
98
+ requestAbortPromise.reject(requestAbortReason)
95
99
  }
96
100
 
97
101
  /**
@@ -106,37 +110,50 @@ export async function handleRequest(
106
110
  options.request.signal.addEventListener('abort', onAbort, { once: true })
107
111
  }
108
112
 
109
- const result = await until(async () => {
113
+ const [resultError] = await until(async () => {
110
114
  // Emit the "request" event and wait until all the listeners
111
115
  // for that event are finished (e.g. async listeners awaited).
112
116
  // By the end of this promise, the developer cannot affect the
113
117
  // request anymore.
114
- const requestListenersPromise = emitAsync(options.emitter, 'request', {
118
+ const requestEventData: HttpRequestEventData = {
119
+ initiator: options.initiator,
115
120
  requestId: options.requestId,
116
121
  request: options.request,
117
122
  controller: options.controller,
118
- })
123
+ }
124
+ const requestEvent = new HttpRequestEvent(requestEventData)
125
+ const requestListenersPromise = options.emitter.emitAsPromise(requestEvent)
119
126
 
120
127
  await Promise.race([
121
128
  // Short-circuit the request handling promise if the request gets aborted.
122
- requestAbortPromise,
129
+ requestAbortPromise.promise,
123
130
  requestListenersPromise,
124
131
  options.controller.handled,
125
132
  ])
133
+
134
+ /**
135
+ * @note If the "request" listener has replaced the request instance,
136
+ * propagate that mutation back to the underlying insterceptor.
137
+ * This happens with XMLHttpRequest that replaces request instances
138
+ * to correctly reflect the "withCredentials" option on the Fetch API request.
139
+ */
140
+ if (requestEvent.request !== options.request) {
141
+ options.request = requestEvent.request
142
+ }
126
143
  })
127
144
 
128
145
  options.request.signal?.removeEventListener('abort', onAbort)
129
146
 
130
147
  // Handle the request being aborted while waiting for the request listeners.
131
- if (requestAbortPromise.state === 'rejected') {
132
- await options.controller.errorWith(requestAbortPromise.rejectionReason)
148
+ if (isRequestAborted) {
149
+ await options.controller.errorWith(requestAbortReason)
133
150
  return
134
151
  }
135
152
 
136
- if (result.error) {
153
+ if (resultError) {
137
154
  // Handle the error during the request listener execution.
138
155
  // These can be thrown responses or request errors.
139
- if (await handleResponseError(result.error)) {
156
+ if (await handleResponseError(resultError)) {
140
157
  return
141
158
  }
142
159
 
@@ -172,12 +189,15 @@ export async function handleRequest(
172
189
  }
173
190
  )
174
191
 
175
- await emitAsync(options.emitter, 'unhandledException', {
176
- error: result.error,
177
- request: options.request,
178
- requestId: options.requestId,
179
- controller: unhandledExceptionController,
180
- })
192
+ await options.emitter.emitAsPromise(
193
+ new UnhandledHttpException({
194
+ initiator: options.initiator,
195
+ error: resultError,
196
+ request: options.request,
197
+ requestId: options.requestId,
198
+ controller: unhandledExceptionController,
199
+ })
200
+ )
181
201
 
182
202
  // If all the "unhandledException" listeners have finished
183
203
  // but have not handled the request in any way, passthrough.
@@ -190,7 +210,7 @@ export async function handleRequest(
190
210
 
191
211
  // Otherwise, coerce unhandled exceptions to a 500 Internal Server Error response.
192
212
  await options.controller.respondWith(
193
- createServerErrorResponse(result.error)
213
+ createServerErrorResponse(resultError)
194
214
  )
195
215
  return
196
216
  }
@@ -1,5 +1,4 @@
1
- import { vi, beforeAll, afterEach, afterAll, it, expect } from 'vitest'
2
- import { hasConfigurableGlobal } from './hasConfigurableGlobal'
1
+ import { hasConfigurableGlobal } from './has-configurable-global'
3
2
 
4
3
  let originalGlobalPrototype = Object.getPrototypeOf(globalThis)
5
4
 
@@ -1,12 +1,10 @@
1
- import { getDeepPropertyDescriptor } from './patchesRegistry'
1
+ import { getDeepPropertyDescriptor } from './patches-registry'
2
2
 
3
3
  /**
4
4
  * Returns a boolean indicating whether the given global property
5
5
  * is defined and is configurable.
6
6
  */
7
- export function hasConfigurableGlobal(
8
- propertyName: keyof typeof globalThis
9
- ): boolean {
7
+ export function hasConfigurableGlobal(propertyName: string): boolean {
10
8
  const match = getDeepPropertyDescriptor(globalThis, propertyName)
11
9
 
12
10
  // The property is not set at all.
@@ -1,5 +1,4 @@
1
- import { it, expect } from 'vitest'
2
- import { isObject } from './isObject'
1
+ import { isObject } from './is-object'
3
2
 
4
3
  it('returns true given an object', () => {
5
4
  expect(isObject({})).toBe(true)
@@ -0,0 +1,154 @@
1
+ import debug from 'debug'
2
+ import { createLogger, formatRequest, formatResponse } from './logger'
3
+ import { Interceptor } from '../interceptor'
4
+
5
+ let previousNamespaces: string
6
+ let previousDebugLevel: string | undefined
7
+
8
+ beforeEach(() => {
9
+ previousNamespaces = debug.disable()
10
+ previousDebugLevel = process.env.DEBUG_LEVEL
11
+ delete process.env.DEBUG_LEVEL
12
+ })
13
+
14
+ afterEach(() => {
15
+ debug.enable(previousNamespaces)
16
+
17
+ if (previousDebugLevel === undefined) {
18
+ delete process.env.DEBUG_LEVEL
19
+ } else {
20
+ process.env.DEBUG_LEVEL = previousDebugLevel
21
+ }
22
+
23
+ vi.restoreAllMocks()
24
+ })
25
+
26
+ it('writes default logs with a normalized namespace and concise timestamp', () => {
27
+ const writeLog = vi.spyOn(debug, 'log').mockImplementation(() => {
28
+ return undefined
29
+ })
30
+ debug.enable('interceptors:client-request')
31
+
32
+ const logger = createLogger('ClientRequest')
33
+ logger.info('apply')
34
+ logger.verbose('socket packet')
35
+
36
+ expect(writeLog).toHaveBeenCalledOnce()
37
+ expect(writeLog.mock.calls[0][0]).toMatch(
38
+ /^\d{2}:\d{2}:\d{2}\.\d{3} \u001b\[.*interceptors:client-request.* apply$/
39
+ )
40
+ expect(writeLog.mock.calls[0][0]).toContain('\u001b[')
41
+ })
42
+
43
+ it('writes verbose logs under the interceptor namespace', () => {
44
+ const writeLog = vi.spyOn(debug, 'log').mockImplementation(() => {
45
+ return undefined
46
+ })
47
+ debug.enable('interceptors:xhr')
48
+ process.env.DEBUG_LEVEL = 'verbose'
49
+
50
+ const logger = createLogger('xhr')
51
+ logger.info('apply')
52
+ logger.verbose('socket packet')
53
+
54
+ expect(writeLog).toHaveBeenCalledTimes(2)
55
+ expect(writeLog.mock.calls[1][0]).toMatch(
56
+ /^\d{2}:\d{2}:\d{2}\.\d{3} .*interceptors:xhr.* socket packet$/
57
+ )
58
+ })
59
+
60
+ it('formats a request as an HTTP message without consuming it', async () => {
61
+ const request = new Request('https://example.com/resource', {
62
+ method: 'POST',
63
+ headers: {
64
+ 'content-type': 'text/plain',
65
+ 'x-example': 'yes',
66
+ },
67
+ body: 'request body',
68
+ })
69
+
70
+ await expect(formatRequest(request)).resolves.toBe(
71
+ [
72
+ 'POST https://example.com/resource',
73
+ 'content-type: text/plain',
74
+ 'x-example: yes',
75
+ '',
76
+ 'request body',
77
+ ].join('\n')
78
+ )
79
+ await expect(request.text()).resolves.toBe('request body')
80
+ })
81
+
82
+ it('formats a response as an HTTP message without consuming it', async () => {
83
+ const response = new Response('response body', {
84
+ status: 201,
85
+ statusText: 'Created',
86
+ headers: {
87
+ 'content-type': 'text/plain',
88
+ 'x-example': 'yes',
89
+ },
90
+ })
91
+
92
+ await expect(formatResponse(response)).resolves.toBe(
93
+ [
94
+ 'HTTP 201 Created',
95
+ 'content-type: text/plain',
96
+ 'x-example: yes',
97
+ '',
98
+ 'response body',
99
+ ].join('\n')
100
+ )
101
+ await expect(response.text()).resolves.toBe('response body')
102
+ })
103
+
104
+ it('omits an unreadable body', async () => {
105
+ const response = new Response('response body')
106
+ await response.text()
107
+
108
+ await expect(formatResponse(response)).resolves.toBe(
109
+ ['HTTP 200', 'content-type: text/plain;charset=UTF-8', '', ''].join(
110
+ '\n'
111
+ )
112
+ )
113
+ })
114
+
115
+ it('omits an empty body', async () => {
116
+ const response = new Response('')
117
+
118
+ await expect(formatResponse(response)).resolves.toBe(
119
+ ['HTTP 200', 'content-type: text/plain;charset=UTF-8', '', ''].join(
120
+ '\n'
121
+ )
122
+ )
123
+ })
124
+
125
+ it('logs interceptor lifecycle operations', () => {
126
+ const writeLog = vi.spyOn(debug, 'log').mockImplementation(() => {
127
+ return undefined
128
+ })
129
+ debug.enable('interceptors:test')
130
+
131
+ class TestInterceptor extends Interceptor<{}> {
132
+ static symbol = Symbol.for('test-interceptor')
133
+
134
+ protected predicate(): boolean {
135
+ return true
136
+ }
137
+
138
+ protected setup(): void {
139
+ // Intentionally empty.
140
+ }
141
+ }
142
+
143
+ const interceptor = new TestInterceptor()
144
+ interceptor.apply()
145
+ interceptor.removeAllListeners()
146
+ interceptor.dispose()
147
+
148
+ expect(writeLog).toHaveBeenCalledTimes(3)
149
+ expect(writeLog.mock.calls[0][0]).toMatch(/ apply$/)
150
+ expect(writeLog.mock.calls[1][0]).toContain(' removeAllListeners ')
151
+ expect(writeLog.mock.calls[1][0]).toContain('eventType:')
152
+ expect(writeLog.mock.calls[1][0]).toContain("'*'")
153
+ expect(writeLog.mock.calls[2][0]).toMatch(/ disable$/)
154
+ })
@@ -0,0 +1,154 @@
1
+ import debug from 'debug'
2
+
3
+ export type LogLevel = 'default' | 'verbose'
4
+
5
+ export interface Logger {
6
+ info(message: string, ...positionals: Array<unknown>): void
7
+ verbose(message: string, ...positionals: Array<unknown>): void
8
+ isEnabled(level: LogLevel): boolean
9
+ }
10
+
11
+ const LOG_TIMESTAMP_REGEXP = /\d{2}:\d{2}:\d{2}\.\d{3}/
12
+
13
+ function normalizeNamespace(namespace: string): string {
14
+ return namespace
15
+ .split(':')
16
+ .map((segment) => {
17
+ return segment
18
+ .replace(/([a-z0-9])([A-Z])/g, '$1-$2')
19
+ .replace(/[^a-zA-Z0-9]+/g, '-')
20
+ .replace(/^-|-$/g, '')
21
+ .toLowerCase()
22
+ })
23
+ .filter(Boolean)
24
+ .join(':')
25
+ }
26
+
27
+ function getTimestamp(): string {
28
+ return new Date().toISOString().slice(11, 23)
29
+ }
30
+
31
+ async function readBody(message: Request | Response): Promise<string | null> {
32
+ if (message.body == null) {
33
+ return null
34
+ }
35
+
36
+ try {
37
+ return await message.clone().text()
38
+ } catch {
39
+ return null
40
+ }
41
+ }
42
+
43
+ function formatHeaders(headers: Headers): Array<string> {
44
+ return Array.from(headers.entries()).map(([name, value]) => {
45
+ return `${name}: ${value}`
46
+ })
47
+ }
48
+
49
+ async function formatHttpMessage(
50
+ startLine: string,
51
+ message: Request | Response
52
+ ): Promise<string> {
53
+ const lines = [startLine, ...formatHeaders(message.headers)]
54
+ const body = await readBody(message)
55
+
56
+ lines.push('', body ?? '')
57
+
58
+ return lines.join('\n')
59
+ }
60
+
61
+ export async function formatRequest(request: Request): Promise<string> {
62
+ return formatHttpMessage(`${request.method} ${request.url}`, request)
63
+ }
64
+
65
+ export async function formatResponse(response: Response): Promise<string> {
66
+ const statusText = response.statusText ? ` ${response.statusText}` : ''
67
+ return formatHttpMessage(
68
+ `HTTP ${response.status}${statusText}`,
69
+ response
70
+ )
71
+ }
72
+
73
+ function formatLogArguments(arguments_: Array<unknown>): void {
74
+ const message = arguments_[0]
75
+
76
+ if (typeof message === 'string') {
77
+ const messageWithoutDebugTimestamp = message.replace(
78
+ /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z /,
79
+ ''
80
+ )
81
+ const timestampMatch = messageWithoutDebugTimestamp.match(
82
+ LOG_TIMESTAMP_REGEXP
83
+ )
84
+
85
+ if (!timestampMatch || timestampMatch.index === undefined) {
86
+ arguments_[0] = messageWithoutDebugTimestamp
87
+ return
88
+ }
89
+
90
+ const messagePrefix = messageWithoutDebugTimestamp
91
+ .slice(0, timestampMatch.index)
92
+ .trim()
93
+ const messageBody = messageWithoutDebugTimestamp
94
+ .slice(timestampMatch.index + timestampMatch[0].length)
95
+ .trimStart()
96
+
97
+ arguments_[0] = `${timestampMatch[0]} ${messagePrefix} ${messageBody}`
98
+ }
99
+ }
100
+
101
+ function useConciseTimestamp(logger: debug.Debugger): void {
102
+ logger.log = (...arguments_) => {
103
+ formatLogArguments(arguments_)
104
+ debug.log(...arguments_)
105
+ }
106
+ }
107
+
108
+ function isVerboseLoggingEnabled(): boolean {
109
+ if (typeof process !== 'undefined' && process.env.DEBUG_LEVEL === 'verbose') {
110
+ return true
111
+ }
112
+
113
+ /**
114
+ * @note Consult the localStorage only in browser-like environments.
115
+ * In Node.js 26+, reading "globalThis.localStorage" without the
116
+ * "--localstorage-file" flag set emits an experimental warning
117
+ * (a try/catch cannot suppress it). Node.js consumers control the
118
+ * log level via the "DEBUG_LEVEL" environment variable above.
119
+ */
120
+ if (typeof document === 'undefined') {
121
+ return false
122
+ }
123
+
124
+ try {
125
+ return globalThis.localStorage?.getItem('debugLevel') === 'verbose'
126
+ } catch {
127
+ return false
128
+ }
129
+ }
130
+
131
+ export function createLogger(namespace: string): Logger {
132
+ const normalizedNamespace = normalizeNamespace(namespace)
133
+ const logger = debug(`interceptors:${normalizedNamespace}`)
134
+ Reflect.set(logger, 'useColors', true)
135
+ useConciseTimestamp(logger)
136
+
137
+ return {
138
+ info(message, ...positionals) {
139
+ logger(`${getTimestamp()} ${message}`, ...positionals)
140
+ },
141
+ verbose(message, ...positionals) {
142
+ if (!isVerboseLoggingEnabled()) {
143
+ return
144
+ }
145
+
146
+ logger(`${getTimestamp()} ${message}`, ...positionals)
147
+ },
148
+ isEnabled(level) {
149
+ return (
150
+ logger.enabled && (level === 'default' || isVerboseLoggingEnabled())
151
+ )
152
+ },
153
+ }
154
+ }
@@ -1,5 +1,4 @@
1
- import { it, expect } from 'vitest'
2
- import { parseJson } from './parseJson'
1
+ import { parseJson } from './parse-json'
3
2
 
4
3
  it('parses a given string into JSON', () => {
5
4
  expect(parseJson('{"id":1}')).toEqual({ id: 1 })
@@ -1,5 +1,5 @@
1
1
  import { it, beforeEach, afterEach, expect, vi } from 'vitest'
2
- import { patchesRegistry } from './patchesRegistry'
2
+ import { patchesRegistry } from './patches-registry'
3
3
 
4
4
  declare global {
5
5
  var foo: { original: boolean }
@@ -114,7 +114,7 @@ interface DeepDescriptorMatch {
114
114
  */
115
115
  export function getDeepPropertyDescriptor<Owner extends object>(
116
116
  owner: Owner,
117
- key: keyof Owner
117
+ key: PropertyKey
118
118
  ): DeepDescriptorMatch | undefined {
119
119
  let currentOwner: Owner | null = owner
120
120
  let descriptor: PropertyDescriptor | undefined
@@ -1,5 +1,5 @@
1
- import { isObject } from './isObject'
2
- import { isPropertyAccessible } from './isPropertyAccessible'
1
+ import { isObject } from './is-object'
2
+ import { isPropertyAccessible } from './is-property-accessible'
3
3
 
4
4
  /**
5
5
  * Creates a generic 500 Unhandled Exception response.
@@ -27,6 +27,29 @@ export function createServerErrorResponse(body: unknown): Response {
27
27
 
28
28
  export type ResponseError = Response & { type: 'error' }
29
29
 
30
+ /**
31
+ * A key on the error a mocked `Response.error()` destroys the socket
32
+ * with, referencing that error response. Allows the client-side
33
+ * interceptors (e.g. fetch) to surface the error response to the
34
+ * consumer instead of the internal socket error.
35
+ */
36
+ export const kErrorResponse = Symbol('kErrorResponse')
37
+
38
+ /**
39
+ * Get the mocked error response that caused the given error, if any.
40
+ */
41
+ export function getErrorResponse(error: unknown): ResponseError | undefined {
42
+ if (
43
+ error instanceof Error &&
44
+ kErrorResponse in error &&
45
+ isResponseError(error[kErrorResponse])
46
+ ) {
47
+ return error[kErrorResponse]
48
+ }
49
+
50
+ return undefined
51
+ }
52
+
30
53
  /**
31
54
  * Check if the given response is a `Response.error()`.
32
55
  *