@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
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { Agent } from 'http'
|
|
2
|
-
import { RequestOptions, Agent as HttpsAgent } from 'https'
|
|
3
|
-
import {
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
112
|
+
logger.verbose('request options %o', options)
|
|
113
113
|
|
|
114
114
|
if (options.uri) {
|
|
115
|
-
logger.
|
|
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.
|
|
122
|
+
logger.verbose('figuring out URL from request options')
|
|
123
123
|
|
|
124
124
|
const protocol = getProtocolByRequestOptions(options)
|
|
125
|
-
logger.
|
|
125
|
+
logger.verbose('protocol: %s', protocol)
|
|
126
126
|
|
|
127
127
|
const port = getPortByRequestOptions(options)
|
|
128
|
-
logger.
|
|
128
|
+
logger.verbose('port: %s', port)
|
|
129
129
|
|
|
130
130
|
const hostname = getHostname(options)
|
|
131
|
-
logger.
|
|
131
|
+
logger.verbose('hostname: %s', hostname)
|
|
132
132
|
|
|
133
133
|
const path = options.path || DEFAULT_PATH
|
|
134
|
-
logger.
|
|
134
|
+
logger.verbose('path: %s', path)
|
|
135
135
|
|
|
136
136
|
const credentials = getAuthByRequestOptions(options)
|
|
137
|
-
logger.
|
|
137
|
+
logger.verbose('credentials %o', credentials)
|
|
138
138
|
|
|
139
139
|
const authString = credentials
|
|
140
140
|
? `${credentials.username}:${credentials.password}@`
|
|
141
141
|
: ''
|
|
142
|
-
logger.
|
|
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.
|
|
149
|
+
logger.verbose('created URL: %s', url.href)
|
|
150
150
|
|
|
151
151
|
return url
|
|
152
152
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
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 '
|
|
2
|
-
import { DeferredPromise } from '@open-draft/deferred-promise'
|
|
1
|
+
import type { Emitter } from 'rettime'
|
|
3
2
|
import { until } from '@open-draft/until'
|
|
4
|
-
import
|
|
5
|
-
|
|
6
|
-
|
|
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 './
|
|
12
|
-
import { InterceptorError } from '../
|
|
13
|
-
import { isNodeLikeError } from './
|
|
14
|
-
import { isObject } from './
|
|
15
|
-
|
|
16
|
-
|
|
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
|
|
75
|
+
throw resultError
|
|
64
76
|
}
|
|
65
77
|
|
|
66
78
|
// Support mocking Node.js-like errors.
|
|
@@ -77,19 +89,14 @@ export async function handleRequest(
|
|
|
77
89
|
return false
|
|
78
90
|
}
|
|
79
91
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
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
|
|
95
|
+
const onAbort = () => {
|
|
96
|
+
isRequestAborted = true
|
|
97
|
+
requestAbortReason = options.request.signal?.reason
|
|
98
|
+
requestAbortPromise.reject(requestAbortReason)
|
|
99
|
+
}
|
|
93
100
|
|
|
94
101
|
/**
|
|
95
102
|
* @note `signal` is not always defined in React Native.
|
|
@@ -100,44 +107,53 @@ export async function handleRequest(
|
|
|
100
107
|
return
|
|
101
108
|
}
|
|
102
109
|
|
|
103
|
-
options.request.signal.addEventListener(
|
|
104
|
-
'abort',
|
|
105
|
-
() => {
|
|
106
|
-
requestAbortPromise.reject(options.request.signal.reason)
|
|
107
|
-
},
|
|
108
|
-
{ once: true }
|
|
109
|
-
)
|
|
110
|
+
options.request.signal.addEventListener('abort', onAbort, { once: true })
|
|
110
111
|
}
|
|
111
112
|
|
|
112
|
-
const
|
|
113
|
+
const [resultError] = await until(async () => {
|
|
113
114
|
// Emit the "request" event and wait until all the listeners
|
|
114
115
|
// for that event are finished (e.g. async listeners awaited).
|
|
115
116
|
// By the end of this promise, the developer cannot affect the
|
|
116
117
|
// request anymore.
|
|
117
|
-
const
|
|
118
|
+
const requestEventData: HttpRequestEventData = {
|
|
119
|
+
initiator: options.initiator,
|
|
118
120
|
requestId: options.requestId,
|
|
119
121
|
request: options.request,
|
|
120
122
|
controller: options.controller,
|
|
121
|
-
}
|
|
123
|
+
}
|
|
124
|
+
const requestEvent = new HttpRequestEvent(requestEventData)
|
|
125
|
+
const requestListenersPromise = options.emitter.emitAsPromise(requestEvent)
|
|
122
126
|
|
|
123
127
|
await Promise.race([
|
|
124
128
|
// Short-circuit the request handling promise if the request gets aborted.
|
|
125
|
-
requestAbortPromise,
|
|
129
|
+
requestAbortPromise.promise,
|
|
126
130
|
requestListenersPromise,
|
|
127
131
|
options.controller.handled,
|
|
128
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
|
+
}
|
|
129
143
|
})
|
|
130
144
|
|
|
145
|
+
options.request.signal?.removeEventListener('abort', onAbort)
|
|
146
|
+
|
|
131
147
|
// Handle the request being aborted while waiting for the request listeners.
|
|
132
|
-
if (
|
|
133
|
-
await options.controller.errorWith(
|
|
148
|
+
if (isRequestAborted) {
|
|
149
|
+
await options.controller.errorWith(requestAbortReason)
|
|
134
150
|
return
|
|
135
151
|
}
|
|
136
152
|
|
|
137
|
-
if (
|
|
153
|
+
if (resultError) {
|
|
138
154
|
// Handle the error during the request listener execution.
|
|
139
155
|
// These can be thrown responses or request errors.
|
|
140
|
-
if (await handleResponseError(
|
|
156
|
+
if (await handleResponseError(resultError)) {
|
|
141
157
|
return
|
|
142
158
|
}
|
|
143
159
|
|
|
@@ -173,12 +189,15 @@ export async function handleRequest(
|
|
|
173
189
|
}
|
|
174
190
|
)
|
|
175
191
|
|
|
176
|
-
await
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
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
|
+
)
|
|
182
201
|
|
|
183
202
|
// If all the "unhandledException" listeners have finished
|
|
184
203
|
// but have not handled the request in any way, passthrough.
|
|
@@ -191,7 +210,7 @@ export async function handleRequest(
|
|
|
191
210
|
|
|
192
211
|
// Otherwise, coerce unhandled exceptions to a 500 Internal Server Error response.
|
|
193
212
|
await options.controller.respondWith(
|
|
194
|
-
createServerErrorResponse(
|
|
213
|
+
createServerErrorResponse(resultError)
|
|
195
214
|
)
|
|
196
215
|
return
|
|
197
216
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
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 './
|
|
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.
|
|
@@ -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
|
+
}
|
|
@@ -114,7 +114,7 @@ interface DeepDescriptorMatch {
|
|
|
114
114
|
*/
|
|
115
115
|
export function getDeepPropertyDescriptor<Owner extends object>(
|
|
116
116
|
owner: Owner,
|
|
117
|
-
key:
|
|
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 './
|
|
2
|
-
import { isPropertyAccessible } from './
|
|
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
|
*
|