@mswjs/interceptors 0.41.8 → 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.
- package/README.md +274 -228
- package/lib/browser/{bufferUtils-BiiO6HZv.mjs → buffer-utils-DJj7YzLG.js} +3 -3
- package/lib/browser/buffer-utils-DJj7YzLG.js.map +1 -0
- package/lib/browser/create-request-id-DlEd4GOA.js +184 -0
- package/lib/browser/create-request-id-DlEd4GOA.js.map +1 -0
- package/lib/browser/{getRawRequest-B1BqgWG6.mjs → fetch-utils-zxA_SD66.js} +123 -52
- package/lib/browser/fetch-utils-zxA_SD66.js.map +1 -0
- package/lib/browser/handle-request-CIOa9O-N.js +167 -0
- package/lib/browser/handle-request-CIOa9O-N.js.map +1 -0
- package/lib/{node/hasConfigurableGlobal-BiTmog1u.mjs → browser/has-configurable-global-Cew-dYqk.js} +5 -7
- package/lib/browser/has-configurable-global-Cew-dYqk.js.map +1 -0
- package/lib/browser/http-CB9rQ7i_.d.ts +105 -0
- package/lib/browser/{index.d.cts → index.d.ts} +33 -38
- package/lib/browser/index.js +130 -0
- package/lib/browser/index.js.map +1 -0
- package/lib/browser/interceptor-dtJZ_9QT.d.ts +50 -0
- package/lib/browser/interceptors/WebSocket/index.d.ts +2 -0
- package/lib/browser/interceptors/WebSocket/{index.mjs → index.js} +40 -31
- package/lib/browser/interceptors/WebSocket/index.js.map +1 -0
- package/lib/browser/interceptors/XMLHttpRequest/web.d.ts +11 -0
- package/lib/browser/interceptors/XMLHttpRequest/web.js +2 -0
- package/lib/browser/interceptors/fetch/web.d.ts +14 -0
- package/lib/browser/interceptors/fetch/web.js +2 -0
- package/lib/browser/presets/browser.d.ts +11 -0
- package/lib/browser/presets/browser.js +12 -0
- package/lib/browser/presets/browser.js.map +1 -0
- package/lib/browser/{resolveWebSocketUrl-C83-x9iE.mjs → resolve-web-socket-url-CSvNPLGi.js} +3 -3
- package/lib/browser/resolve-web-socket-url-CSvNPLGi.js.map +1 -0
- package/lib/browser/web-BjVDkiX0.js +248 -0
- package/lib/browser/web-BjVDkiX0.js.map +1 -0
- package/lib/{node/XMLHttpRequest-DhupxLHX.mjs → browser/web-C2oKsT3Q.js} +328 -256
- package/lib/browser/web-C2oKsT3Q.js.map +1 -0
- package/lib/browser/{interceptors/WebSocket/index.d.cts → websocket-CC0nB0md.d.ts} +41 -33
- package/lib/node/batch-interceptor-ByEZVih3.js +119 -0
- package/lib/node/batch-interceptor-ByEZVih3.js.map +1 -0
- package/lib/node/batch-interceptor-CPjFK2td.d.ts +28 -0
- package/lib/node/buffer-utils-BvPY1Tc-.js +187 -0
- package/lib/node/buffer-utils-BvPY1Tc-.js.map +1 -0
- package/lib/node/fetch-utils-Dw1PsmtX.js +568 -0
- package/lib/node/fetch-utils-Dw1PsmtX.js.map +1 -0
- package/lib/node/has-configurable-global-CJCh_g1I.js +22 -0
- package/lib/node/has-configurable-global-CJCh_g1I.js.map +1 -0
- package/lib/node/http-CB9rQ7i_.d.ts +105 -0
- package/lib/{browser/interceptors/WebSocket/index.d.mts → node/index.d.ts} +120 -60
- package/lib/node/{index.mjs → index.js} +8 -11
- package/lib/node/index.js.map +1 -0
- package/lib/node/interceptor-dtJZ_9QT.d.ts +50 -0
- package/lib/node/interceptors/ClientRequest/index.d.ts +14 -0
- package/lib/node/interceptors/ClientRequest/index.js +67 -0
- package/lib/node/interceptors/ClientRequest/index.js.map +1 -0
- package/lib/node/interceptors/XMLHttpRequest/node.d.ts +12 -0
- package/lib/node/interceptors/XMLHttpRequest/node.js +74 -0
- package/lib/node/interceptors/XMLHttpRequest/node.js.map +1 -0
- package/lib/node/interceptors/fetch/node.d.ts +18 -0
- package/lib/node/interceptors/fetch/node.js +83 -0
- package/lib/node/interceptors/fetch/node.js.map +1 -0
- package/lib/node/interceptors/http/index.d.ts +14 -0
- package/lib/node/interceptors/http/index.js +32 -0
- package/lib/node/interceptors/http/index.js.map +1 -0
- package/lib/node/interceptors/net/index.d.ts +203 -0
- package/lib/node/interceptors/net/index.js +2 -0
- package/lib/node/llhttp/constants.cjs +485 -0
- package/lib/node/llhttp/constants.d.cts +957 -0
- package/lib/node/llhttp/llhttp.wasm +0 -0
- package/lib/node/net-DtMnyEeg.js +1388 -0
- package/lib/node/net-DtMnyEeg.js.map +1 -0
- package/lib/node/presets/node.d.ts +12 -0
- package/lib/node/presets/node.js +17 -0
- package/lib/node/presets/node.js.map +1 -0
- package/lib/node/{RemoteHttpInterceptor.d.cts → remote-http-interceptor.d.ts} +12 -11
- package/lib/node/{RemoteHttpInterceptor.mjs → remote-http-interceptor.js} +38 -33
- package/lib/node/remote-http-interceptor.js.map +1 -0
- package/lib/node/source-lP0yyEtA.js +1990 -0
- package/lib/node/source-lP0yyEtA.js.map +1 -0
- package/package.json +79 -118
- package/src/batch-interceptor.test.ts +475 -0
- package/src/batch-interceptor.ts +244 -0
- package/src/{createRequestId.test.ts → create-request-id.test.ts} +1 -2
- package/src/disposable.ts +13 -0
- package/src/events/http.ts +92 -0
- package/src/events/websocket.ts +47 -0
- package/src/glossary.ts +1 -27
- package/src/index.ts +18 -10
- package/src/interceptor.test.ts +279 -0
- package/src/interceptor.ts +139 -0
- package/src/interceptors/ClientRequest/index.test.ts +21 -39
- package/src/interceptors/ClientRequest/index.ts +65 -180
- package/src/interceptors/ClientRequest/utils/{recordRawHeaders.test.ts → record-raw-headers.test.ts} +1 -2
- package/src/interceptors/ClientRequest/utils/{recordRawHeaders.ts → record-raw-headers.ts} +29 -2
- package/src/interceptors/WebSocket/index.ts +34 -51
- package/src/interceptors/WebSocket/utils/{bindEvent.test.ts → bind-event.test.ts} +1 -2
- package/src/interceptors/WebSocket/utils/events.test.ts +0 -1
- package/src/interceptors/WebSocket/{WebSocketClassTransport.ts → web-socket-class-transport.ts} +3 -3
- package/src/interceptors/WebSocket/{WebSocketClientConnection.ts → web-socket-client-connection.ts} +4 -4
- package/src/interceptors/WebSocket/{WebSocketOverride.ts → web-socket-override.ts} +6 -7
- package/src/interceptors/WebSocket/{WebSocketServerConnection.ts → web-socket-server-connection.ts} +4 -4
- package/src/interceptors/WebSocket/{WebSocketTransport.ts → web-socket-transport.ts} +1 -1
- package/src/interceptors/XMLHttpRequest/node.ts +104 -0
- package/src/interceptors/XMLHttpRequest/polyfills/{ProgressEventPolyfill.ts → progress-event-polyfill.ts} +1 -1
- package/src/interceptors/XMLHttpRequest/utils/{concateArrayBuffer.test.ts → concat-array-buffer.test.ts} +1 -2
- package/src/interceptors/XMLHttpRequest/utils/{concatArrayBuffer.ts → concat-array-buffer.ts} +1 -1
- package/src/interceptors/XMLHttpRequest/utils/{createEvent.test.ts → create-event.test.ts} +3 -4
- package/src/interceptors/XMLHttpRequest/utils/{createEvent.ts → create-event.ts} +2 -2
- package/src/interceptors/XMLHttpRequest/utils/{createResponse.ts → create-response.ts} +1 -1
- package/src/interceptors/XMLHttpRequest/utils/{getBodyByteLength.test.ts → get-body-byte-length.test.ts} +1 -2
- package/src/interceptors/XMLHttpRequest/web.ts +34 -0
- package/src/interceptors/XMLHttpRequest/{XMLHttpRequestController.ts → xml-http-request-controller.ts} +363 -204
- package/src/interceptors/XMLHttpRequest/{XMLHttpRequestProxy.ts → xml-http-request-proxy.ts} +28 -25
- package/src/interceptors/fetch/node.ts +103 -0
- package/src/interceptors/fetch/utils/{followRedirect.ts → follow-redirect.ts} +1 -1
- package/src/interceptors/fetch/web.ts +217 -0
- package/src/interceptors/http/forward-events.test.ts +86 -0
- package/src/interceptors/http/forward-events.ts +139 -0
- package/src/interceptors/http/http-parser/index.ts +310 -0
- package/src/interceptors/http/http-parser/llhttp/constants.cjs +485 -0
- package/src/interceptors/http/http-parser/llhttp/constants.d.cts +957 -0
- package/src/interceptors/http/http-parser/llhttp/llhttp.wasm +0 -0
- package/src/interceptors/http/http-parser.ts +138 -0
- package/src/interceptors/http/index.ts +34 -0
- package/src/interceptors/http/source.ts +688 -0
- package/src/interceptors/net/index.ts +368 -0
- package/src/interceptors/net/socket-controller.ts +1476 -0
- package/src/interceptors/net/utils/address-info.ts +54 -0
- package/src/interceptors/net/utils/connection-options-to-url.ts +56 -0
- package/src/interceptors/net/utils/flush-writes.ts +57 -0
- package/src/interceptors/net/utils/get-tls-connect-options.ts +23 -0
- package/src/interceptors/net/utils/normalize-net-connect-args.test.ts +233 -0
- package/src/interceptors/net/utils/normalize-net-connect-args.ts +121 -0
- package/src/interceptors/net/utils/normalize-tls-connect-args.ts +50 -0
- package/src/presets/browser.ts +4 -4
- package/src/presets/node.ts +4 -4
- package/src/{RemoteHttpInterceptor.ts → remote-http-interceptor.ts} +55 -42
- package/src/request-context.ts +40 -0
- package/src/{RequestController.test.ts → request-controller.test.ts} +37 -3
- package/src/{RequestController.ts → request-controller.ts} +33 -11
- package/src/utils/{bufferUtils.test.ts → buffer-utils.test.ts} +1 -2
- package/src/utils/buffer-utils.ts +37 -0
- package/src/utils/{cloneObject.test.ts → clone-object.test.ts} +1 -2
- package/src/utils/{cloneObject.ts → clone-object.ts} +8 -8
- package/src/utils/{createProxy.test.ts → create-proxy.test.ts} +6 -4
- package/src/utils/{createProxy.ts → create-proxy.ts} +1 -1
- package/src/utils/{fetchUtils.test.ts → fetch-utils.test.ts} +1 -1
- package/src/utils/{fetchUtils.ts → fetch-utils.ts} +28 -3
- package/src/utils/{findPropertySource.test.ts → find-property-source.test.ts} +1 -2
- package/src/utils/{getCleanUrl.test.ts → get-clean-url.test.ts} +1 -2
- package/src/utils/{getUrlByRequestOptions.test.ts → get-url-by-request-options.test.ts} +4 -8
- package/src/utils/{getUrlByRequestOptions.ts → get-url-by-request-options.ts} +16 -16
- package/src/utils/{getValueBySymbol.test.ts → get-value-by-symbol.test.ts} +1 -2
- package/src/utils/{handleRequest.ts → handle-request.ts} +66 -47
- package/src/utils/{hasConfigurableGlobal.test.ts → has-configurable-global.test.ts} +1 -2
- package/src/utils/{hasConfigurableGlobal.ts → has-configurable-global.ts} +2 -4
- package/src/utils/{isObject.test.ts → is-object.test.ts} +1 -2
- package/src/utils/logger.test.ts +154 -0
- package/src/utils/logger.ts +154 -0
- package/src/utils/{parseJson.test.ts → parse-json.test.ts} +1 -2
- package/src/utils/{patchesRegistry.test.ts → patches-registry.test.ts} +1 -1
- package/src/utils/{patchesRegistry.ts → patches-registry.ts} +1 -1
- package/src/utils/{responseUtils.ts → response-utils.ts} +25 -2
- package/ClientRequest/package.json +0 -11
- package/RemoteHttpInterceptor/package.json +0 -11
- package/WebSocket/package.json +0 -12
- package/XMLHttpRequest/package.json +0 -12
- package/fetch/package.json +0 -12
- package/lib/browser/Interceptor-Deczogc8.d.cts +0 -65
- package/lib/browser/Interceptor-gqKgs-aF.d.mts +0 -65
- package/lib/browser/XMLHttpRequest-B11I9TBx.cjs +0 -751
- package/lib/browser/XMLHttpRequest-B11I9TBx.cjs.map +0 -1
- package/lib/browser/XMLHttpRequest-DHEkSoRN.mjs +0 -746
- package/lib/browser/XMLHttpRequest-DHEkSoRN.mjs.map +0 -1
- package/lib/browser/bufferUtils-BiiO6HZv.mjs.map +0 -1
- package/lib/browser/bufferUtils-Uc0eRItL.cjs +0 -38
- package/lib/browser/bufferUtils-Uc0eRItL.cjs.map +0 -1
- package/lib/browser/createRequestId-DOf8Ktjs.cjs +0 -205
- package/lib/browser/createRequestId-DOf8Ktjs.cjs.map +0 -1
- package/lib/browser/createRequestId-DYCsFHOi.mjs +0 -170
- package/lib/browser/createRequestId-DYCsFHOi.mjs.map +0 -1
- package/lib/browser/fetch-BJwfdses.mjs +0 -236
- package/lib/browser/fetch-BJwfdses.mjs.map +0 -1
- package/lib/browser/fetch-M8iXkZ3L.cjs +0 -241
- package/lib/browser/fetch-M8iXkZ3L.cjs.map +0 -1
- package/lib/browser/getRawRequest-B1BqgWG6.mjs.map +0 -1
- package/lib/browser/getRawRequest-DdfaiPVH.cjs +0 -376
- package/lib/browser/getRawRequest-DdfaiPVH.cjs.map +0 -1
- package/lib/browser/glossary-1lhZx6Aw.d.cts +0 -69
- package/lib/browser/glossary-nkHWcwvY.d.mts +0 -69
- package/lib/browser/handleRequest-1Yqu_ho_.mjs +0 -178
- package/lib/browser/handleRequest-1Yqu_ho_.mjs.map +0 -1
- package/lib/browser/handleRequest-Cz4_wmQ9.cjs +0 -189
- package/lib/browser/handleRequest-Cz4_wmQ9.cjs.map +0 -1
- package/lib/browser/hasConfigurableGlobal-C8zq1MCg.mjs +0 -109
- package/lib/browser/hasConfigurableGlobal-C8zq1MCg.mjs.map +0 -1
- package/lib/browser/hasConfigurableGlobal-CS7adEvV.cjs +0 -126
- package/lib/browser/hasConfigurableGlobal-CS7adEvV.cjs.map +0 -1
- package/lib/browser/index.cjs +0 -70
- package/lib/browser/index.cjs.map +0 -1
- package/lib/browser/index.d.mts +0 -125
- package/lib/browser/index.mjs +0 -56
- package/lib/browser/index.mjs.map +0 -1
- package/lib/browser/interceptors/WebSocket/index.cjs +0 -618
- package/lib/browser/interceptors/WebSocket/index.cjs.map +0 -1
- package/lib/browser/interceptors/WebSocket/index.mjs.map +0 -1
- package/lib/browser/interceptors/XMLHttpRequest/index.cjs +0 -8
- package/lib/browser/interceptors/XMLHttpRequest/index.d.cts +0 -15
- package/lib/browser/interceptors/XMLHttpRequest/index.d.mts +0 -15
- package/lib/browser/interceptors/XMLHttpRequest/index.mjs +0 -8
- package/lib/browser/interceptors/fetch/index.cjs +0 -7
- package/lib/browser/interceptors/fetch/index.d.cts +0 -13
- package/lib/browser/interceptors/fetch/index.d.mts +0 -13
- package/lib/browser/interceptors/fetch/index.mjs +0 -7
- package/lib/browser/presets/browser.cjs +0 -18
- package/lib/browser/presets/browser.cjs.map +0 -1
- package/lib/browser/presets/browser.d.cts +0 -12
- package/lib/browser/presets/browser.d.mts +0 -14
- package/lib/browser/presets/browser.mjs +0 -18
- package/lib/browser/presets/browser.mjs.map +0 -1
- package/lib/browser/resolveWebSocketUrl-6K6EgqsA.cjs +0 -31
- package/lib/browser/resolveWebSocketUrl-6K6EgqsA.cjs.map +0 -1
- package/lib/browser/resolveWebSocketUrl-C83-x9iE.mjs.map +0 -1
- package/lib/node/BatchInterceptor-DdMNfSUY.mjs +0 -44
- package/lib/node/BatchInterceptor-DdMNfSUY.mjs.map +0 -1
- package/lib/node/BatchInterceptor-KKF8Q47I.d.cts +0 -26
- package/lib/node/BatchInterceptor-Z1lwK23r.cjs +0 -49
- package/lib/node/BatchInterceptor-Z1lwK23r.cjs.map +0 -1
- package/lib/node/BatchInterceptor-rSr-NH_H.d.mts +0 -26
- package/lib/node/ClientRequest-DFs7FPNi.cjs +0 -1058
- package/lib/node/ClientRequest-DFs7FPNi.cjs.map +0 -1
- package/lib/node/ClientRequest-dRpI9v1o.mjs +0 -1049
- package/lib/node/ClientRequest-dRpI9v1o.mjs.map +0 -1
- package/lib/node/Interceptor-BsZ21ue0.d.cts +0 -132
- package/lib/node/Interceptor-soD-WpQO.d.mts +0 -132
- package/lib/node/RemoteHttpInterceptor.cjs +0 -155
- package/lib/node/RemoteHttpInterceptor.cjs.map +0 -1
- package/lib/node/RemoteHttpInterceptor.d.mts +0 -39
- package/lib/node/RemoteHttpInterceptor.mjs.map +0 -1
- package/lib/node/XMLHttpRequest-DhupxLHX.mjs.map +0 -1
- package/lib/node/XMLHttpRequest-Dyi6ahGz.cjs +0 -752
- package/lib/node/XMLHttpRequest-Dyi6ahGz.cjs.map +0 -1
- package/lib/node/bufferUtils-DxPxwff_.mjs +0 -20
- package/lib/node/bufferUtils-DxPxwff_.mjs.map +0 -1
- package/lib/node/bufferUtils-S5_-2eN4.cjs +0 -38
- package/lib/node/bufferUtils-S5_-2eN4.cjs.map +0 -1
- package/lib/node/chunk-CbDLau6x.cjs +0 -34
- package/lib/node/fetch-BqMcbuYR.mjs +0 -252
- package/lib/node/fetch-BqMcbuYR.mjs.map +0 -1
- package/lib/node/fetch-aQJu1Gf_.cjs +0 -259
- package/lib/node/fetch-aQJu1Gf_.cjs.map +0 -1
- package/lib/node/fetchUtils-BKJ1XmiO.mjs +0 -480
- package/lib/node/fetchUtils-BKJ1XmiO.mjs.map +0 -1
- package/lib/node/fetchUtils-umV5xXBy.cjs +0 -546
- package/lib/node/fetchUtils-umV5xXBy.cjs.map +0 -1
- package/lib/node/getRawRequest-B6znU6il.cjs +0 -36
- package/lib/node/getRawRequest-B6znU6il.cjs.map +0 -1
- package/lib/node/getRawRequest-C2-1urzA.mjs +0 -24
- package/lib/node/getRawRequest-C2-1urzA.mjs.map +0 -1
- package/lib/node/handleRequest-DCLzePtS.mjs +0 -190
- package/lib/node/handleRequest-DCLzePtS.mjs.map +0 -1
- package/lib/node/handleRequest-DVOthWJo.cjs +0 -220
- package/lib/node/handleRequest-DVOthWJo.cjs.map +0 -1
- package/lib/node/hasConfigurableGlobal-BiTmog1u.mjs.map +0 -1
- package/lib/node/hasConfigurableGlobal-MjY06_Ok.cjs +0 -108
- package/lib/node/hasConfigurableGlobal-MjY06_Ok.cjs.map +0 -1
- package/lib/node/index-BJ5E5aW-.d.cts +0 -113
- package/lib/node/index-DfoF45ih.d.mts +0 -113
- package/lib/node/index.cjs +0 -53
- package/lib/node/index.cjs.map +0 -1
- package/lib/node/index.d.cts +0 -104
- package/lib/node/index.d.mts +0 -104
- package/lib/node/index.mjs.map +0 -1
- package/lib/node/interceptors/ClientRequest/index.cjs +0 -6
- package/lib/node/interceptors/ClientRequest/index.d.cts +0 -2
- package/lib/node/interceptors/ClientRequest/index.d.mts +0 -3
- package/lib/node/interceptors/ClientRequest/index.mjs +0 -6
- package/lib/node/interceptors/XMLHttpRequest/index.cjs +0 -7
- package/lib/node/interceptors/XMLHttpRequest/index.d.cts +0 -14
- package/lib/node/interceptors/XMLHttpRequest/index.d.mts +0 -14
- package/lib/node/interceptors/XMLHttpRequest/index.mjs +0 -7
- package/lib/node/interceptors/fetch/index.cjs +0 -6
- package/lib/node/interceptors/fetch/index.d.cts +0 -12
- package/lib/node/interceptors/fetch/index.d.mts +0 -12
- package/lib/node/interceptors/fetch/index.mjs +0 -6
- package/lib/node/node-DIKcnzhK.cjs +0 -39
- package/lib/node/node-DIKcnzhK.cjs.map +0 -1
- package/lib/node/node-lsdNwZEW.mjs +0 -27
- package/lib/node/node-lsdNwZEW.mjs.map +0 -1
- package/lib/node/presets/node.cjs +0 -23
- package/lib/node/presets/node.cjs.map +0 -1
- package/lib/node/presets/node.d.cts +0 -13
- package/lib/node/presets/node.d.mts +0 -15
- package/lib/node/presets/node.mjs +0 -23
- package/lib/node/presets/node.mjs.map +0 -1
- package/lib/node/utils/node/index.cjs +0 -4
- package/lib/node/utils/node/index.d.cts +0 -16
- package/lib/node/utils/node/index.d.mts +0 -16
- package/lib/node/utils/node/index.mjs +0 -3
- package/presets/browser/package.json +0 -5
- package/presets/node/package.json +0 -11
- package/src/BatchInterceptor.test.ts +0 -255
- package/src/BatchInterceptor.ts +0 -95
- package/src/Interceptor.test.ts +0 -205
- package/src/Interceptor.ts +0 -249
- package/src/getRawRequest.ts +0 -21
- package/src/interceptors/ClientRequest/MockHttpSocket.ts +0 -724
- package/src/interceptors/ClientRequest/agents.ts +0 -110
- package/src/interceptors/ClientRequest/utils/getIncomingMessageBody.test.ts +0 -54
- package/src/interceptors/ClientRequest/utils/getIncomingMessageBody.ts +0 -45
- package/src/interceptors/ClientRequest/utils/normalizeClientRequestArgs.test.ts +0 -427
- package/src/interceptors/ClientRequest/utils/normalizeClientRequestArgs.ts +0 -268
- package/src/interceptors/ClientRequest/utils/parserUtils.ts +0 -48
- package/src/interceptors/Socket/MockSocket.test.ts +0 -264
- package/src/interceptors/Socket/MockSocket.ts +0 -58
- package/src/interceptors/Socket/utils/baseUrlFromConnectionOptions.ts +0 -26
- package/src/interceptors/Socket/utils/normalizeSocketWriteArgs.test.ts +0 -52
- package/src/interceptors/Socket/utils/normalizeSocketWriteArgs.ts +0 -33
- package/src/interceptors/XMLHttpRequest/index.ts +0 -40
- package/src/interceptors/fetch/index.ts +0 -203
- package/src/utils/bufferUtils.ts +0 -22
- package/src/utils/canParseUrl.ts +0 -13
- package/src/utils/emitAsync.ts +0 -25
- package/src/utils/nextTick.ts +0 -11
- package/src/utils/node/index.ts +0 -39
- /package/src/{createRequestId.ts → create-request-id.ts} +0 -0
- /package/src/{InterceptorError.ts → interceptor-error.ts} +0 -0
- /package/src/interceptors/WebSocket/utils/{bindEvent.ts → bind-event.ts} +0 -0
- /package/src/interceptors/XMLHttpRequest/polyfills/{EventPolyfill.ts → event-polyfill.ts} +0 -0
- /package/src/interceptors/XMLHttpRequest/utils/{getBodyByteLength.ts → get-body-byte-length.ts} +0 -0
- /package/src/interceptors/XMLHttpRequest/utils/{isDomParserSupportedType.ts → is-dom-parser-supported-type.ts} +0 -0
- /package/src/interceptors/fetch/utils/{createNetworkError.ts → create-network-error.ts} +0 -0
- /package/src/utils/{findPropertySource.ts → find-property-source.ts} +0 -0
- /package/src/utils/{getCleanUrl.ts → get-clean-url.ts} +0 -0
- /package/src/utils/{getValueBySymbol.ts → get-value-by-symbol.ts} +0 -0
- /package/src/utils/{isNodeLikeError.ts → is-node-like-error.ts} +0 -0
- /package/src/utils/{isObject.ts → is-object.ts} +0 -0
- /package/src/utils/{isPropertyAccessible.ts → is-property-accessible.ts} +0 -0
- /package/src/utils/{parseJson.ts → parse-json.ts} +0 -0
- /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
|
+
}
|