msw 2.12.13 → 2.13.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/lib/browser/index.d.mts +29 -19
- package/lib/browser/index.d.ts +29 -19
- package/lib/browser/index.js +1763 -1321
- package/lib/browser/index.js.map +1 -1
- package/lib/browser/index.mjs +1769 -1321
- package/lib/browser/index.mjs.map +1 -1
- package/lib/core/{HttpResponse-Dj6ibgFJ.d.ts → HttpResponse-CksOMVAa.d.ts} +5 -5
- package/lib/core/{HttpResponse-Be4eT3x6.d.mts → HttpResponse-DlRR1D-f.d.mts} +5 -5
- package/lib/core/HttpResponse.d.mts +1 -1
- package/lib/core/HttpResponse.d.ts +1 -1
- package/lib/core/experimental/compat.d.mts +17 -0
- package/lib/core/experimental/compat.d.ts +17 -0
- package/lib/core/experimental/compat.js +54 -0
- package/lib/core/experimental/compat.js.map +1 -0
- package/lib/core/experimental/compat.mjs +36 -0
- package/lib/core/experimental/compat.mjs.map +1 -0
- package/lib/core/experimental/define-network.d.mts +75 -0
- package/lib/core/experimental/define-network.d.ts +75 -0
- package/lib/core/experimental/define-network.js +124 -0
- package/lib/core/experimental/define-network.js.map +1 -0
- package/lib/core/experimental/define-network.mjs +107 -0
- package/lib/core/experimental/define-network.mjs.map +1 -0
- package/lib/core/experimental/frames/http-frame.d.mts +77 -0
- package/lib/core/experimental/frames/http-frame.d.ts +77 -0
- package/lib/core/experimental/frames/http-frame.js +194 -0
- package/lib/core/experimental/frames/http-frame.js.map +1 -0
- package/lib/core/experimental/frames/http-frame.mjs +176 -0
- package/lib/core/experimental/frames/http-frame.mjs.map +1 -0
- package/lib/core/experimental/frames/network-frame.d.mts +12 -0
- package/lib/core/experimental/frames/network-frame.d.ts +12 -0
- package/lib/core/{handlers/common.js → experimental/frames/network-frame.js} +19 -3
- package/lib/core/experimental/frames/network-frame.js.map +1 -0
- package/lib/core/experimental/frames/network-frame.mjs +13 -0
- package/lib/core/experimental/frames/network-frame.mjs.map +1 -0
- package/lib/core/experimental/frames/websocket-frame.d.mts +55 -0
- package/lib/core/experimental/frames/websocket-frame.d.ts +55 -0
- package/lib/core/experimental/frames/websocket-frame.js +129 -0
- package/lib/core/experimental/frames/websocket-frame.js.map +1 -0
- package/lib/core/experimental/frames/websocket-frame.mjs +116 -0
- package/lib/core/experimental/frames/websocket-frame.mjs.map +1 -0
- package/lib/core/experimental/handlers-controller.d.mts +35 -0
- package/lib/core/experimental/handlers-controller.d.ts +35 -0
- package/lib/core/experimental/handlers-controller.js +121 -0
- package/lib/core/experimental/handlers-controller.js.map +1 -0
- package/lib/core/experimental/handlers-controller.mjs +101 -0
- package/lib/core/experimental/handlers-controller.mjs.map +1 -0
- package/lib/core/experimental/index.d.mts +17 -0
- package/lib/core/experimental/index.d.ts +17 -0
- package/lib/core/experimental/index.js +36 -0
- package/lib/core/experimental/index.js.map +1 -0
- package/lib/core/experimental/index.mjs +20 -0
- package/lib/core/experimental/index.mjs.map +1 -0
- package/lib/core/experimental/on-unhandled-frame.d.mts +12 -0
- package/lib/core/experimental/on-unhandled-frame.d.ts +12 -0
- package/lib/core/experimental/on-unhandled-frame.js +90 -0
- package/lib/core/experimental/on-unhandled-frame.js.map +1 -0
- package/lib/core/experimental/on-unhandled-frame.mjs +70 -0
- package/lib/core/experimental/on-unhandled-frame.mjs.map +1 -0
- package/lib/core/experimental/request-utils.d.mts +12 -0
- package/lib/core/experimental/request-utils.d.ts +12 -0
- package/lib/core/experimental/request-utils.js +50 -0
- package/lib/core/experimental/request-utils.js.map +1 -0
- package/lib/core/experimental/request-utils.mjs +30 -0
- package/lib/core/experimental/request-utils.mjs.map +1 -0
- package/lib/core/experimental/setup-api.d.mts +33 -0
- package/lib/core/experimental/setup-api.d.ts +33 -0
- package/lib/core/experimental/setup-api.js +61 -0
- package/lib/core/experimental/setup-api.js.map +1 -0
- package/lib/core/experimental/setup-api.mjs +43 -0
- package/lib/core/experimental/setup-api.mjs.map +1 -0
- package/lib/core/experimental/sources/interceptor-source.d.mts +28 -0
- package/lib/core/experimental/sources/interceptor-source.d.ts +28 -0
- package/lib/core/experimental/sources/interceptor-source.js +142 -0
- package/lib/core/experimental/sources/interceptor-source.js.map +1 -0
- package/lib/core/experimental/sources/interceptor-source.mjs +124 -0
- package/lib/core/experimental/sources/interceptor-source.mjs.map +1 -0
- package/lib/core/experimental/sources/network-source.d.mts +31 -0
- package/lib/core/experimental/sources/network-source.d.ts +31 -0
- package/lib/core/experimental/sources/network-source.js +50 -0
- package/lib/core/experimental/sources/network-source.js.map +1 -0
- package/lib/core/experimental/sources/network-source.mjs +30 -0
- package/lib/core/experimental/sources/network-source.mjs.map +1 -0
- package/lib/core/getResponse.d.mts +1 -1
- package/lib/core/getResponse.d.ts +1 -1
- package/lib/core/graphql.d.mts +1 -1
- package/lib/core/graphql.d.ts +1 -1
- package/lib/core/handlers/GraphQLHandler.d.mts +1 -1
- package/lib/core/handlers/GraphQLHandler.d.ts +1 -1
- package/lib/core/handlers/HttpHandler.d.mts +1 -1
- package/lib/core/handlers/HttpHandler.d.ts +1 -1
- package/lib/core/handlers/RequestHandler.d.mts +1 -1
- package/lib/core/handlers/RequestHandler.d.ts +1 -1
- package/lib/core/handlers/RequestHandler.js +5 -6
- package/lib/core/handlers/RequestHandler.js.map +1 -1
- package/lib/core/handlers/RequestHandler.mjs +5 -6
- package/lib/core/handlers/RequestHandler.mjs.map +1 -1
- package/lib/core/handlers/WebSocketHandler.d.mts +8 -4
- package/lib/core/handlers/WebSocketHandler.d.ts +8 -4
- package/lib/core/handlers/WebSocketHandler.js +18 -5
- package/lib/core/handlers/WebSocketHandler.js.map +1 -1
- package/lib/core/handlers/WebSocketHandler.mjs +18 -5
- package/lib/core/handlers/WebSocketHandler.mjs.map +1 -1
- package/lib/core/http.d.mts +1 -1
- package/lib/core/http.d.ts +1 -1
- package/lib/core/index.d.mts +7 -12
- package/lib/core/index.d.ts +7 -12
- package/lib/core/index.js +2 -2
- package/lib/core/index.js.map +1 -1
- package/lib/core/index.mjs +1 -1
- package/lib/core/index.mjs.map +1 -1
- package/lib/core/network-frame-B7A0ggXE.d.mts +56 -0
- package/lib/core/network-frame-usYiHS0K.d.ts +56 -0
- package/lib/core/passthrough.d.mts +1 -1
- package/lib/core/passthrough.d.ts +1 -1
- package/lib/core/sharedOptions.d.mts +6 -2
- package/lib/core/sharedOptions.d.ts +6 -2
- package/lib/core/sharedOptions.js.map +1 -1
- package/lib/core/sse.d.mts +1 -1
- package/lib/core/sse.d.ts +1 -1
- package/lib/core/sse.js.map +1 -1
- package/lib/core/sse.mjs.map +1 -1
- package/lib/core/utils/HttpResponse/decorators.d.mts +1 -1
- package/lib/core/utils/HttpResponse/decorators.d.ts +1 -1
- package/lib/core/utils/cookieStore.js.map +1 -1
- package/lib/core/utils/cookieStore.mjs.map +1 -1
- package/lib/core/utils/executeHandlers.d.mts +1 -1
- package/lib/core/utils/executeHandlers.d.ts +1 -1
- package/lib/core/utils/handleRequest.d.mts +2 -1
- package/lib/core/utils/handleRequest.d.ts +2 -1
- package/lib/core/utils/internal/isHandlerKind.d.mts +3 -3
- package/lib/core/utils/internal/isHandlerKind.d.ts +3 -3
- package/lib/core/utils/internal/isHandlerKind.js +2 -1
- package/lib/core/utils/internal/isHandlerKind.js.map +1 -1
- package/lib/core/utils/internal/isHandlerKind.mjs +2 -1
- package/lib/core/utils/internal/isHandlerKind.mjs.map +1 -1
- package/lib/core/utils/internal/parseGraphQLRequest.d.mts +1 -1
- package/lib/core/utils/internal/parseGraphQLRequest.d.ts +1 -1
- package/lib/core/utils/internal/parseMultipartData.d.mts +1 -1
- package/lib/core/utils/internal/parseMultipartData.d.ts +1 -1
- package/lib/core/utils/internal/requestHandlerUtils.d.mts +1 -1
- package/lib/core/utils/internal/requestHandlerUtils.d.ts +1 -1
- package/lib/core/utils/matching/matchRequestUrl.js +1 -1
- package/lib/core/utils/matching/matchRequestUrl.js.map +1 -1
- package/lib/core/utils/matching/matchRequestUrl.mjs +1 -1
- package/lib/core/utils/matching/matchRequestUrl.mjs.map +1 -1
- package/lib/core/utils/request/onUnhandledRequest.d.mts +2 -2
- package/lib/core/utils/request/onUnhandledRequest.d.ts +2 -2
- package/lib/core/utils/request/onUnhandledRequest.js.map +1 -1
- package/lib/core/utils/request/onUnhandledRequest.mjs.map +1 -1
- package/lib/core/ws/handleWebSocketEvent.d.mts +1 -1
- package/lib/core/ws/handleWebSocketEvent.d.ts +1 -1
- package/lib/core/ws/handleWebSocketEvent.js +1 -1
- package/lib/core/ws/handleWebSocketEvent.js.map +1 -1
- package/lib/core/ws/handleWebSocketEvent.mjs +1 -1
- package/lib/core/ws/handleWebSocketEvent.mjs.map +1 -1
- package/lib/core/ws/utils/attachWebSocketLogger.d.mts +1 -1
- package/lib/core/ws/utils/attachWebSocketLogger.d.ts +1 -1
- package/lib/core/ws/utils/attachWebSocketLogger.js +39 -10
- package/lib/core/ws/utils/attachWebSocketLogger.js.map +1 -1
- package/lib/core/ws/utils/attachWebSocketLogger.mjs +39 -10
- package/lib/core/ws/utils/attachWebSocketLogger.mjs.map +1 -1
- package/lib/core/ws.d.mts +3 -3
- package/lib/core/ws.d.ts +3 -3
- package/lib/core/ws.js.map +1 -1
- package/lib/core/ws.mjs.map +1 -1
- package/lib/iife/index.js +2022 -1433
- package/lib/iife/index.js.map +1 -1
- package/lib/mockServiceWorker.js +1 -1
- package/lib/native/index.d.mts +21 -29
- package/lib/native/index.d.ts +21 -29
- package/lib/native/index.js +48 -116
- package/lib/native/index.js.map +1 -1
- package/lib/native/index.mjs +51 -118
- package/lib/native/index.mjs.map +1 -1
- package/lib/node/index.d.mts +55 -33
- package/lib/node/index.d.ts +55 -33
- package/lib/node/index.js +152 -154
- package/lib/node/index.js.map +1 -1
- package/lib/node/index.mjs +156 -156
- package/lib/node/index.mjs.map +1 -1
- package/package.json +10 -2
- package/src/browser/{setupWorker/glossary.ts → glossary.ts} +16 -33
- package/src/browser/index.ts +2 -3
- package/src/browser/{setupWorker/setupWorker.node.test.ts → setup-worker.node.test.ts} +2 -4
- package/src/browser/setup-worker.ts +148 -0
- package/src/browser/sources/fallback-http-source.ts +56 -0
- package/src/browser/sources/service-worker-source.ts +455 -0
- package/src/browser/tsconfig.browser.json +7 -2
- package/src/browser/utils/deserializeRequest.ts +1 -1
- package/src/browser/{setupWorker/start/utils/getWorkerByRegistration.ts → utils/get-worker-by-registration.ts} +3 -1
- package/src/browser/{setupWorker/start/utils/getWorkerInstance.ts → utils/get-worker-instance.ts} +4 -4
- package/src/browser/utils/pruneGetRequestBody.test.ts +1 -3
- package/src/browser/utils/pruneGetRequestBody.ts +1 -1
- package/src/browser/utils/validate-worker-scope.ts +19 -0
- package/src/browser/utils/workerChannel.ts +2 -2
- package/src/core/experimental/compat.ts +50 -0
- package/src/core/experimental/define-network.test.ts +124 -0
- package/src/core/experimental/define-network.ts +215 -0
- package/src/core/experimental/frames/http-frame.test.ts +360 -0
- package/src/core/experimental/frames/http-frame.ts +271 -0
- package/src/core/experimental/frames/network-frame.ts +64 -0
- package/src/core/experimental/frames/websocket-frame.test.ts +280 -0
- package/src/core/experimental/frames/websocket-frame.ts +188 -0
- package/src/core/experimental/handlers-controller.test.ts +198 -0
- package/src/core/experimental/handlers-controller.ts +145 -0
- package/src/core/experimental/index.ts +16 -0
- package/src/core/experimental/on-unhandled-frame.test.ts +360 -0
- package/src/core/experimental/on-unhandled-frame.ts +110 -0
- package/src/core/experimental/request-utils.test.ts +70 -0
- package/src/core/experimental/request-utils.ts +39 -0
- package/src/core/experimental/setup-api.ts +59 -0
- package/src/core/experimental/sources/interceptor-source.ts +185 -0
- package/src/core/experimental/sources/network-source.test.ts +74 -0
- package/src/core/experimental/sources/network-source.ts +56 -0
- package/src/core/handlers/RequestHandler.ts +9 -10
- package/src/core/handlers/WebSocketHandler.ts +27 -11
- package/src/core/index.ts +3 -7
- package/src/core/sharedOptions.ts +9 -4
- package/src/core/sse.ts +1 -1
- package/src/core/utils/cookieStore.ts +2 -1
- package/src/core/utils/internal/isHandlerKind.test.ts +20 -22
- package/src/core/utils/internal/isHandlerKind.ts +5 -9
- package/src/core/utils/matching/matchRequestUrl.test.ts +87 -3
- package/src/core/utils/matching/matchRequestUrl.ts +2 -2
- package/src/core/utils/request/onUnhandledRequest.ts +2 -2
- package/src/core/ws/WebSocketClientManager.test.ts +2 -10
- package/src/core/ws/handleWebSocketEvent.ts +5 -1
- package/src/core/ws/utils/attachWebSocketLogger.ts +43 -11
- package/src/core/ws.test.ts +1 -3
- package/src/core/ws.ts +6 -6
- package/src/iife/index.ts +1 -1
- package/src/native/index.ts +34 -11
- package/src/node/async-handlers-controller.test.ts +50 -0
- package/src/node/async-handlers-controller.ts +69 -0
- package/src/node/glossary.ts +19 -18
- package/src/node/index.ts +6 -2
- package/src/node/setup-server-common.ts +100 -0
- package/src/node/setup-server.ts +91 -0
- package/src/tsconfig.core.json +8 -0
- package/src/tsconfig.node.json +8 -3
- package/src/tsconfig.src.json +0 -2
- package/src/tsconfig.worker.json +2 -1
- package/lib/core/SetupApi.d.mts +0 -44
- package/lib/core/SetupApi.d.ts +0 -44
- package/lib/core/SetupApi.js +0 -112
- package/lib/core/SetupApi.js.map +0 -1
- package/lib/core/SetupApi.mjs +0 -92
- package/lib/core/SetupApi.mjs.map +0 -1
- package/lib/core/handlers/common.d.mts +0 -3
- package/lib/core/handlers/common.d.ts +0 -3
- package/lib/core/handlers/common.js.map +0 -1
- package/lib/core/handlers/common.mjs +0 -1
- package/lib/core/handlers/common.mjs.map +0 -1
- package/src/browser/setupWorker/setupWorker.ts +0 -184
- package/src/browser/setupWorker/start/createFallbackRequestListener.ts +0 -71
- package/src/browser/setupWorker/start/createRequestListener.ts +0 -138
- package/src/browser/setupWorker/start/createResponseListener.ts +0 -57
- package/src/browser/setupWorker/start/createStartHandler.ts +0 -137
- package/src/browser/setupWorker/start/utils/enableMocking.ts +0 -30
- package/src/browser/setupWorker/start/utils/prepareStartHandler.test.ts +0 -59
- package/src/browser/setupWorker/start/utils/prepareStartHandler.ts +0 -44
- package/src/browser/setupWorker/start/utils/printStartMessage.test.ts +0 -84
- package/src/browser/setupWorker/start/utils/printStartMessage.ts +0 -51
- package/src/browser/setupWorker/start/utils/validateWorkerScope.ts +0 -18
- package/src/browser/setupWorker/stop/utils/printStopMessage.test.ts +0 -26
- package/src/browser/setupWorker/stop/utils/printStopMessage.ts +0 -13
- package/src/browser/utils/checkWorkerIntegrity.ts +0 -42
- package/src/core/SetupApi.ts +0 -127
- package/src/core/handlers/common.ts +0 -1
- package/src/node/SetupServerApi.ts +0 -87
- package/src/node/SetupServerCommonApi.ts +0 -169
- package/src/node/setupServer.ts +0 -15
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
import { http } from '../../http'
|
|
2
|
+
import { graphql } from '../../graphql'
|
|
3
|
+
import { ws } from '../../ws'
|
|
4
|
+
import { bypass } from '../../bypass'
|
|
5
|
+
import { HttpNetworkFrame, HttpNetworkFrameEventMap } from './http-frame'
|
|
6
|
+
import { InMemoryHandlersController } from '#core/experimental/handlers-controller'
|
|
7
|
+
|
|
8
|
+
beforeAll(() => {
|
|
9
|
+
vi.spyOn(console, 'error').mockImplementation(() => {})
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
afterEach(() => {
|
|
13
|
+
vi.clearAllMocks()
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
afterAll(() => {
|
|
17
|
+
vi.restoreAllMocks()
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
function spyOnNetworkFrame(frame: HttpNetworkFrame) {
|
|
21
|
+
const events: Array<
|
|
22
|
+
HttpNetworkFrameEventMap[keyof HttpNetworkFrameEventMap]
|
|
23
|
+
> = []
|
|
24
|
+
|
|
25
|
+
frame.events.on('*', (event) => events.push(event))
|
|
26
|
+
|
|
27
|
+
return {
|
|
28
|
+
events,
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
it('filters only request type handlers', async () => {
|
|
33
|
+
class HttpFrame extends HttpNetworkFrame {
|
|
34
|
+
respondWith = vi.fn()
|
|
35
|
+
passthrough = vi.fn()
|
|
36
|
+
errorWith = vi.fn()
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const frame = new HttpFrame({
|
|
40
|
+
request: new Request('http://localhost/api'),
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
const httpHandlers = [http.post('http://localhost/api/user', () => {})]
|
|
44
|
+
const graphqlHandlers = [graphql.query('GetUser', () => {})]
|
|
45
|
+
const webSocketHandlers = [
|
|
46
|
+
ws.link('ws://localhost').addEventListener('connection', () => {}),
|
|
47
|
+
]
|
|
48
|
+
|
|
49
|
+
const controller = new InMemoryHandlersController([
|
|
50
|
+
...httpHandlers,
|
|
51
|
+
...webSocketHandlers,
|
|
52
|
+
...graphqlHandlers,
|
|
53
|
+
])
|
|
54
|
+
|
|
55
|
+
expect(frame.getHandlers(controller)).toEqual([
|
|
56
|
+
...httpHandlers,
|
|
57
|
+
...graphqlHandlers,
|
|
58
|
+
])
|
|
59
|
+
expect(frame.getHandlers(new InMemoryHandlersController([]))).toEqual([])
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
it('resolves a matching request', async () => {
|
|
63
|
+
class HttpFrame extends HttpNetworkFrame {
|
|
64
|
+
respondWith = vi.fn()
|
|
65
|
+
passthrough = vi.fn()
|
|
66
|
+
errorWith = vi.fn()
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const frame = new HttpFrame({
|
|
70
|
+
request: new Request('http://localhost/api'),
|
|
71
|
+
})
|
|
72
|
+
const { events } = spyOnNetworkFrame(frame)
|
|
73
|
+
const unhandledFrameCallback = vi.fn()
|
|
74
|
+
|
|
75
|
+
const matches = await frame.resolve(
|
|
76
|
+
[
|
|
77
|
+
http.get('http://localhost/api', () => {
|
|
78
|
+
return new Response(null, { status: 204 })
|
|
79
|
+
}),
|
|
80
|
+
],
|
|
81
|
+
unhandledFrameCallback,
|
|
82
|
+
{ quiet: true },
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
expect.soft(matches).toBe(true)
|
|
86
|
+
expect.soft(frame.respondWith).toHaveBeenCalledExactlyOnceWith(
|
|
87
|
+
expect.objectContaining({
|
|
88
|
+
status: 204,
|
|
89
|
+
}),
|
|
90
|
+
)
|
|
91
|
+
expect.soft(frame.passthrough).not.toHaveBeenCalled()
|
|
92
|
+
expect.soft(frame.errorWith).not.toHaveBeenCalled()
|
|
93
|
+
expect.soft(unhandledFrameCallback).not.toHaveBeenCalled()
|
|
94
|
+
expect.soft(events).toEqual([
|
|
95
|
+
expect.objectContaining({
|
|
96
|
+
type: 'request:start',
|
|
97
|
+
requestId: frame.data.id,
|
|
98
|
+
request: frame.data.request,
|
|
99
|
+
}),
|
|
100
|
+
expect.objectContaining({
|
|
101
|
+
type: 'request:match',
|
|
102
|
+
requestId: frame.data.id,
|
|
103
|
+
request: frame.data.request,
|
|
104
|
+
}),
|
|
105
|
+
expect.objectContaining({
|
|
106
|
+
type: 'request:end',
|
|
107
|
+
requestId: frame.data.id,
|
|
108
|
+
request: frame.data.request,
|
|
109
|
+
}),
|
|
110
|
+
])
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
it('resolves a non-matching request', async () => {
|
|
114
|
+
class HttpFrame extends HttpNetworkFrame {
|
|
115
|
+
respondWith = vi.fn()
|
|
116
|
+
passthrough = vi.fn()
|
|
117
|
+
errorWith = vi.fn()
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const frame = new HttpFrame({
|
|
121
|
+
request: new Request('http://localhost/api'),
|
|
122
|
+
})
|
|
123
|
+
const { events } = spyOnNetworkFrame(frame)
|
|
124
|
+
const unhandledFrameCallback = vi.fn()
|
|
125
|
+
|
|
126
|
+
const matches = await frame.resolve(
|
|
127
|
+
[
|
|
128
|
+
http.get('http://example.com/resource', () => {
|
|
129
|
+
return new Response(null, { status: 204 })
|
|
130
|
+
}),
|
|
131
|
+
],
|
|
132
|
+
unhandledFrameCallback,
|
|
133
|
+
{ quiet: true },
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
expect.soft(matches).toBe(false)
|
|
137
|
+
expect.soft(frame.passthrough).toHaveBeenCalledOnce()
|
|
138
|
+
expect.soft(frame.respondWith).not.toHaveBeenCalled()
|
|
139
|
+
expect.soft(frame.errorWith).not.toHaveBeenCalled()
|
|
140
|
+
expect.soft(unhandledFrameCallback).toHaveBeenCalledExactlyOnceWith(
|
|
141
|
+
expect.objectContaining({
|
|
142
|
+
frame,
|
|
143
|
+
}),
|
|
144
|
+
)
|
|
145
|
+
expect.soft(events).toEqual([
|
|
146
|
+
expect.objectContaining({
|
|
147
|
+
type: 'request:start',
|
|
148
|
+
requestId: frame.data.id,
|
|
149
|
+
request: frame.data.request,
|
|
150
|
+
}),
|
|
151
|
+
expect.objectContaining({
|
|
152
|
+
type: 'request:unhandled',
|
|
153
|
+
requestId: frame.data.id,
|
|
154
|
+
request: frame.data.request,
|
|
155
|
+
}),
|
|
156
|
+
expect.objectContaining({
|
|
157
|
+
type: 'request:end',
|
|
158
|
+
requestId: frame.data.id,
|
|
159
|
+
request: frame.data.request,
|
|
160
|
+
}),
|
|
161
|
+
])
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
it('resolves a matched passthrough', async () => {
|
|
165
|
+
class HttpFrame extends HttpNetworkFrame {
|
|
166
|
+
respondWith = vi.fn()
|
|
167
|
+
passthrough = vi.fn()
|
|
168
|
+
errorWith = vi.fn()
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const frame = new HttpFrame({
|
|
172
|
+
request: new Request('http://localhost/api'),
|
|
173
|
+
})
|
|
174
|
+
const { events } = spyOnNetworkFrame(frame)
|
|
175
|
+
const unhandledFrameCallback = vi.fn()
|
|
176
|
+
|
|
177
|
+
const matches = await frame.resolve(
|
|
178
|
+
[
|
|
179
|
+
http.get('http://localhost/api', () => {
|
|
180
|
+
// Intentionally do nothing to passthrough.
|
|
181
|
+
}),
|
|
182
|
+
],
|
|
183
|
+
unhandledFrameCallback,
|
|
184
|
+
{ quiet: true },
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
expect.soft(matches).toBeNull()
|
|
188
|
+
expect.soft(frame.passthrough).toHaveBeenCalledOnce()
|
|
189
|
+
expect.soft(frame.respondWith).not.toHaveBeenCalled()
|
|
190
|
+
expect.soft(frame.errorWith).not.toHaveBeenCalled()
|
|
191
|
+
expect.soft(unhandledFrameCallback).not.toHaveBeenCalled()
|
|
192
|
+
expect.soft(events).toEqual([
|
|
193
|
+
expect.objectContaining({
|
|
194
|
+
type: 'request:start',
|
|
195
|
+
requestId: frame.data.id,
|
|
196
|
+
request: frame.data.request,
|
|
197
|
+
}),
|
|
198
|
+
expect.objectContaining({
|
|
199
|
+
type: 'request:match',
|
|
200
|
+
requestId: frame.data.id,
|
|
201
|
+
request: frame.data.request,
|
|
202
|
+
}),
|
|
203
|
+
expect.objectContaining({
|
|
204
|
+
type: 'request:end',
|
|
205
|
+
requestId: frame.data.id,
|
|
206
|
+
request: frame.data.request,
|
|
207
|
+
}),
|
|
208
|
+
])
|
|
209
|
+
})
|
|
210
|
+
|
|
211
|
+
it('resolves a bypassed request', async () => {
|
|
212
|
+
class HttpFrame extends HttpNetworkFrame {
|
|
213
|
+
respondWith = vi.fn()
|
|
214
|
+
passthrough = vi.fn()
|
|
215
|
+
errorWith = vi.fn()
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const frame = new HttpFrame({
|
|
219
|
+
request: bypass(new Request('http://localhost/api')),
|
|
220
|
+
})
|
|
221
|
+
const { events } = spyOnNetworkFrame(frame)
|
|
222
|
+
const unhandledFrameCallback = vi.fn()
|
|
223
|
+
|
|
224
|
+
const matches = await frame.resolve(
|
|
225
|
+
[
|
|
226
|
+
http.get('http://localhost/api', () => {
|
|
227
|
+
return new Response(null, { status: 204 })
|
|
228
|
+
}),
|
|
229
|
+
],
|
|
230
|
+
unhandledFrameCallback,
|
|
231
|
+
{ quiet: true },
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
expect.soft(matches).toBeNull()
|
|
235
|
+
expect.soft(frame.passthrough).toHaveBeenCalledOnce()
|
|
236
|
+
expect.soft(frame.respondWith).not.toHaveBeenCalled()
|
|
237
|
+
expect.soft(frame.errorWith).not.toHaveBeenCalled()
|
|
238
|
+
expect.soft(unhandledFrameCallback).not.toHaveBeenCalled()
|
|
239
|
+
expect.soft(events).toEqual([
|
|
240
|
+
expect.objectContaining({
|
|
241
|
+
type: 'request:start',
|
|
242
|
+
requestId: frame.data.id,
|
|
243
|
+
request: frame.data.request,
|
|
244
|
+
}),
|
|
245
|
+
expect.objectContaining({
|
|
246
|
+
type: 'request:end',
|
|
247
|
+
requestId: frame.data.id,
|
|
248
|
+
request: frame.data.request,
|
|
249
|
+
}),
|
|
250
|
+
])
|
|
251
|
+
})
|
|
252
|
+
|
|
253
|
+
it('errors the request on unhandled exception', async () => {
|
|
254
|
+
class HttpFrame extends HttpNetworkFrame {
|
|
255
|
+
respondWith = vi.fn()
|
|
256
|
+
passthrough = vi.fn()
|
|
257
|
+
errorWith = vi.fn()
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const frame = new HttpFrame({
|
|
261
|
+
request: new Request('http://localhost/api'),
|
|
262
|
+
})
|
|
263
|
+
const { events } = spyOnNetworkFrame(frame)
|
|
264
|
+
const unhandledFrameCallback = vi.fn()
|
|
265
|
+
|
|
266
|
+
const exception = new Error('Unhandled exception')
|
|
267
|
+
const matches = await frame.resolve(
|
|
268
|
+
[
|
|
269
|
+
http.get('http://localhost/api', () => {
|
|
270
|
+
throw exception
|
|
271
|
+
}),
|
|
272
|
+
],
|
|
273
|
+
unhandledFrameCallback,
|
|
274
|
+
{ quiet: true },
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
expect.soft(matches).toBeNull()
|
|
278
|
+
expect.soft(frame.errorWith).toHaveBeenCalledExactlyOnceWith(exception)
|
|
279
|
+
expect.soft(frame.passthrough).not.toHaveBeenCalled()
|
|
280
|
+
expect.soft(frame.respondWith).not.toHaveBeenCalled()
|
|
281
|
+
expect.soft(unhandledFrameCallback).not.toHaveBeenCalled()
|
|
282
|
+
expect.soft(events).toEqual([
|
|
283
|
+
expect.objectContaining({
|
|
284
|
+
type: 'request:start',
|
|
285
|
+
requestId: frame.data.id,
|
|
286
|
+
request: frame.data.request,
|
|
287
|
+
}),
|
|
288
|
+
expect.objectContaining({
|
|
289
|
+
type: 'unhandledException',
|
|
290
|
+
error: exception,
|
|
291
|
+
requestId: frame.data.id,
|
|
292
|
+
request: frame.data.request,
|
|
293
|
+
}),
|
|
294
|
+
])
|
|
295
|
+
|
|
296
|
+
expect.soft(console.error).toHaveBeenCalledTimes(2)
|
|
297
|
+
expect.soft(console.error).toHaveBeenNthCalledWith(1, exception)
|
|
298
|
+
expect
|
|
299
|
+
.soft(console.error)
|
|
300
|
+
.toHaveBeenNthCalledWith(
|
|
301
|
+
2,
|
|
302
|
+
'[MSW] Encountered an unhandled exception during the handler lookup for "GET http://localhost/api". Please see the original error above.',
|
|
303
|
+
)
|
|
304
|
+
})
|
|
305
|
+
|
|
306
|
+
it('does not print an unhandled exception if the "unhandledException" listener is present', async () => {
|
|
307
|
+
class HttpFrame extends HttpNetworkFrame {
|
|
308
|
+
respondWith = vi.fn()
|
|
309
|
+
passthrough = vi.fn()
|
|
310
|
+
errorWith = vi.fn()
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
const frame = new HttpFrame({
|
|
314
|
+
request: new Request('http://localhost/api'),
|
|
315
|
+
})
|
|
316
|
+
const { events } = spyOnNetworkFrame(frame)
|
|
317
|
+
const unhandledFrameCallback = vi.fn()
|
|
318
|
+
|
|
319
|
+
const unhandledExceptionListener = vi.fn()
|
|
320
|
+
frame.events.on('unhandledException', unhandledExceptionListener)
|
|
321
|
+
|
|
322
|
+
const exception = new Error('Unhandled exception')
|
|
323
|
+
const matches = await frame.resolve(
|
|
324
|
+
[
|
|
325
|
+
http.get('http://localhost/api', () => {
|
|
326
|
+
throw exception
|
|
327
|
+
}),
|
|
328
|
+
],
|
|
329
|
+
unhandledFrameCallback,
|
|
330
|
+
{ quiet: true },
|
|
331
|
+
)
|
|
332
|
+
|
|
333
|
+
expect.soft(matches).toBeNull()
|
|
334
|
+
expect.soft(frame.errorWith).toHaveBeenCalledExactlyOnceWith(exception)
|
|
335
|
+
expect.soft(frame.passthrough).not.toHaveBeenCalled()
|
|
336
|
+
expect.soft(frame.respondWith).not.toHaveBeenCalled()
|
|
337
|
+
expect.soft(unhandledFrameCallback).not.toHaveBeenCalled()
|
|
338
|
+
expect.soft(events).toEqual([
|
|
339
|
+
expect.objectContaining({
|
|
340
|
+
type: 'request:start',
|
|
341
|
+
requestId: frame.data.id,
|
|
342
|
+
request: frame.data.request,
|
|
343
|
+
}),
|
|
344
|
+
expect.objectContaining({
|
|
345
|
+
type: 'unhandledException',
|
|
346
|
+
error: exception,
|
|
347
|
+
requestId: frame.data.id,
|
|
348
|
+
request: frame.data.request,
|
|
349
|
+
}),
|
|
350
|
+
])
|
|
351
|
+
|
|
352
|
+
expect.soft(console.error).not.toHaveBeenCalled()
|
|
353
|
+
expect.soft(unhandledExceptionListener).toHaveBeenCalledExactlyOnceWith(
|
|
354
|
+
expect.objectContaining({
|
|
355
|
+
error: exception,
|
|
356
|
+
requestId: frame.data.id,
|
|
357
|
+
request: frame.data.request,
|
|
358
|
+
}),
|
|
359
|
+
)
|
|
360
|
+
})
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
import { TypedEvent } from 'rettime'
|
|
2
|
+
import { until } from 'until-async'
|
|
3
|
+
import { createRequestId } from '@mswjs/interceptors'
|
|
4
|
+
import { NetworkFrame, NetworkFrameResolutionContext } from './network-frame'
|
|
5
|
+
import { toPublicUrl } from '../../utils/request/toPublicUrl'
|
|
6
|
+
import { executeHandlers } from '../../utils/executeHandlers'
|
|
7
|
+
import { storeResponseCookies } from '../../utils/request/storeResponseCookies'
|
|
8
|
+
import { isPassthroughResponse, shouldBypassRequest } from '../request-utils'
|
|
9
|
+
import { devUtils } from '../../utils/internal/devUtils'
|
|
10
|
+
import {
|
|
11
|
+
executeUnhandledFrameHandle,
|
|
12
|
+
type UnhandledFrameHandle,
|
|
13
|
+
} from '../on-unhandled-frame'
|
|
14
|
+
import { HandlersController, AnyHandler } from '../handlers-controller'
|
|
15
|
+
import { type RequestHandler } from '../../handlers/RequestHandler'
|
|
16
|
+
|
|
17
|
+
interface HttpNetworkFrameOptions {
|
|
18
|
+
id?: string
|
|
19
|
+
request: Request
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export class RequestEvent<
|
|
23
|
+
DataType extends { requestId: string; request: Request } = {
|
|
24
|
+
requestId: string
|
|
25
|
+
request: Request
|
|
26
|
+
},
|
|
27
|
+
ReturnType = void,
|
|
28
|
+
EventType extends string = string,
|
|
29
|
+
> extends TypedEvent<DataType, ReturnType, EventType> {
|
|
30
|
+
public readonly requestId: string
|
|
31
|
+
public readonly request: Request
|
|
32
|
+
|
|
33
|
+
constructor(type: EventType, data: DataType) {
|
|
34
|
+
super(...([type, {}] as any))
|
|
35
|
+
this.requestId = data.requestId
|
|
36
|
+
this.request = data.request
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export class ResponseEvent<
|
|
41
|
+
DataType extends {
|
|
42
|
+
requestId: string
|
|
43
|
+
request: Request
|
|
44
|
+
response: Response
|
|
45
|
+
} = {
|
|
46
|
+
requestId: string
|
|
47
|
+
request: Request
|
|
48
|
+
response: Response
|
|
49
|
+
},
|
|
50
|
+
ReturnType = void,
|
|
51
|
+
EventType extends string = string,
|
|
52
|
+
> extends TypedEvent<DataType, ReturnType, EventType> {
|
|
53
|
+
public readonly requestId: string
|
|
54
|
+
public readonly request: Request
|
|
55
|
+
public readonly response: Response
|
|
56
|
+
|
|
57
|
+
constructor(type: EventType, data: DataType) {
|
|
58
|
+
super(...([type, {}] as any))
|
|
59
|
+
this.requestId = data.requestId
|
|
60
|
+
this.request = data.request
|
|
61
|
+
this.response = data.response
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export class UnhandledExceptionEvent<
|
|
66
|
+
DataType extends {
|
|
67
|
+
error: Error
|
|
68
|
+
requestId: string
|
|
69
|
+
request: Request
|
|
70
|
+
} = {
|
|
71
|
+
error: Error
|
|
72
|
+
requestId: string
|
|
73
|
+
request: Request
|
|
74
|
+
},
|
|
75
|
+
ReturnType = void,
|
|
76
|
+
EventType extends string = string,
|
|
77
|
+
> extends TypedEvent<DataType, ReturnType, EventType> {
|
|
78
|
+
public readonly error: Error
|
|
79
|
+
public readonly requestId: string
|
|
80
|
+
public readonly request: Request
|
|
81
|
+
|
|
82
|
+
constructor(type: EventType, data: DataType) {
|
|
83
|
+
super(...([type, {}] as any))
|
|
84
|
+
this.error = data.error
|
|
85
|
+
this.requestId = data.requestId
|
|
86
|
+
this.request = data.request
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export type HttpNetworkFrameEventMap = {
|
|
91
|
+
'request:start': RequestEvent
|
|
92
|
+
'request:match': RequestEvent
|
|
93
|
+
'request:unhandled': RequestEvent
|
|
94
|
+
'request:end': RequestEvent
|
|
95
|
+
'response:mocked': ResponseEvent
|
|
96
|
+
'response:bypass': ResponseEvent
|
|
97
|
+
unhandledException: UnhandledExceptionEvent
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export abstract class HttpNetworkFrame extends NetworkFrame<
|
|
101
|
+
'http',
|
|
102
|
+
{
|
|
103
|
+
id: string
|
|
104
|
+
request: Request
|
|
105
|
+
},
|
|
106
|
+
HttpNetworkFrameEventMap
|
|
107
|
+
> {
|
|
108
|
+
constructor(options: HttpNetworkFrameOptions) {
|
|
109
|
+
const id = options.id || createRequestId()
|
|
110
|
+
super('http', { id, request: options.request })
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
public getHandlers(controller: HandlersController): Array<AnyHandler> {
|
|
114
|
+
return controller.getHandlersByKind('request')
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
public abstract respondWith(response?: Response): void
|
|
118
|
+
|
|
119
|
+
public async getUnhandledMessage(): Promise<string> {
|
|
120
|
+
const { request } = this.data
|
|
121
|
+
|
|
122
|
+
const url = new URL(request.url)
|
|
123
|
+
const publicUrl = toPublicUrl(url) + url.search
|
|
124
|
+
const requestBody =
|
|
125
|
+
request.body == null ? null : await request.clone().text()
|
|
126
|
+
|
|
127
|
+
const details = `\n\n \u2022 ${request.method} ${publicUrl}\n\n${requestBody ? ` \u2022 Request body: ${requestBody}\n\n` : ''}`
|
|
128
|
+
const message = `intercepted a request without a matching request handler:${details}If you still wish to intercept this unhandled request, please create a request handler for it.\nRead more: https://mswjs.io/docs/http/intercepting-requests`
|
|
129
|
+
|
|
130
|
+
return message
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
public async resolve(
|
|
134
|
+
handlers: Array<RequestHandler>,
|
|
135
|
+
onUnhandledFrame: UnhandledFrameHandle,
|
|
136
|
+
resolutionContext?: NetworkFrameResolutionContext,
|
|
137
|
+
): Promise<boolean | null> {
|
|
138
|
+
const { id: requestId, request } = this.data
|
|
139
|
+
const requestCloneForLogs = resolutionContext?.quiet
|
|
140
|
+
? null
|
|
141
|
+
: request.clone()
|
|
142
|
+
|
|
143
|
+
this.events.emit(new RequestEvent('request:start', { requestId, request }))
|
|
144
|
+
|
|
145
|
+
// Requests wrapped in explicit "bypass(request)".
|
|
146
|
+
if (shouldBypassRequest(request)) {
|
|
147
|
+
this.events.emit(new RequestEvent('request:end', { requestId, request }))
|
|
148
|
+
this.passthrough()
|
|
149
|
+
return null
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const [lookupError, lookupResult] = await until(() => {
|
|
153
|
+
return executeHandlers({
|
|
154
|
+
requestId,
|
|
155
|
+
request,
|
|
156
|
+
handlers,
|
|
157
|
+
resolutionContext: {
|
|
158
|
+
baseUrl: resolutionContext?.baseUrl?.toString(),
|
|
159
|
+
quiet: resolutionContext?.quiet,
|
|
160
|
+
},
|
|
161
|
+
})
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
if (lookupError != null) {
|
|
165
|
+
if (
|
|
166
|
+
!this.events.emit(
|
|
167
|
+
new UnhandledExceptionEvent('unhandledException', {
|
|
168
|
+
error: lookupError,
|
|
169
|
+
requestId,
|
|
170
|
+
request,
|
|
171
|
+
}),
|
|
172
|
+
)
|
|
173
|
+
) {
|
|
174
|
+
// Surface the error to the developer since they haven't handled it.
|
|
175
|
+
console.error(lookupError)
|
|
176
|
+
devUtils.error(
|
|
177
|
+
'Encountered an unhandled exception during the handler lookup for "%s %s". Please see the original error above.',
|
|
178
|
+
request.method,
|
|
179
|
+
request.url,
|
|
180
|
+
)
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
this.errorWith(lookupError)
|
|
184
|
+
return null
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// No matching handlers.
|
|
188
|
+
if (lookupResult == null) {
|
|
189
|
+
this.events.emit(
|
|
190
|
+
new RequestEvent('request:unhandled', {
|
|
191
|
+
requestId,
|
|
192
|
+
request,
|
|
193
|
+
}),
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* @note The unhandled frame handle must be executed during the request resolution
|
|
198
|
+
* since it can influence it (e.g. error the request if the "error" startegy was used).
|
|
199
|
+
*/
|
|
200
|
+
await executeUnhandledFrameHandle(this, onUnhandledFrame).then(
|
|
201
|
+
() => this.passthrough(),
|
|
202
|
+
(error) => this.errorWith(error),
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
this.events.emit(
|
|
206
|
+
new RequestEvent('request:end', {
|
|
207
|
+
requestId,
|
|
208
|
+
request,
|
|
209
|
+
}),
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
return false
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const { response, handler, parsedResult } = lookupResult
|
|
216
|
+
|
|
217
|
+
this.events.emit(
|
|
218
|
+
new RequestEvent('request:match', {
|
|
219
|
+
requestId,
|
|
220
|
+
request,
|
|
221
|
+
}),
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
// Handlers that returned no mocked response.
|
|
225
|
+
if (response == null) {
|
|
226
|
+
this.events.emit(
|
|
227
|
+
new RequestEvent('request:end', {
|
|
228
|
+
requestId,
|
|
229
|
+
request,
|
|
230
|
+
}),
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
this.passthrough()
|
|
234
|
+
return null
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Handlers that returned explicit `passthrough()`.
|
|
238
|
+
if (isPassthroughResponse(response)) {
|
|
239
|
+
this.events.emit(
|
|
240
|
+
new RequestEvent('request:end', {
|
|
241
|
+
requestId,
|
|
242
|
+
request,
|
|
243
|
+
}),
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
this.passthrough()
|
|
247
|
+
return null
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
await storeResponseCookies(request, response)
|
|
251
|
+
|
|
252
|
+
this.respondWith(response.clone())
|
|
253
|
+
|
|
254
|
+
this.events.emit(
|
|
255
|
+
new RequestEvent('request:end', {
|
|
256
|
+
requestId,
|
|
257
|
+
request,
|
|
258
|
+
}),
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
if (!resolutionContext?.quiet) {
|
|
262
|
+
handler.log({
|
|
263
|
+
request: requestCloneForLogs!,
|
|
264
|
+
response,
|
|
265
|
+
parsedResult,
|
|
266
|
+
})
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
return true
|
|
270
|
+
}
|
|
271
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { Emitter, type DefaultEventMap } from 'rettime'
|
|
2
|
+
import type { AnyHandler, HandlersController } from '../handlers-controller'
|
|
3
|
+
import type { UnhandledFrameHandle } from '../on-unhandled-frame'
|
|
4
|
+
|
|
5
|
+
export type AnyNetworkFrame = NetworkFrame<string, unknown, any>
|
|
6
|
+
|
|
7
|
+
export type ExtractFrameEvents<Frame> =
|
|
8
|
+
Frame extends NetworkFrame<any, any, infer Events> ? Events : never
|
|
9
|
+
|
|
10
|
+
export interface NetworkFrameResolutionContext {
|
|
11
|
+
baseUrl?: string | URL
|
|
12
|
+
quiet?: boolean
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* The base for the network frames. Extend this abstract class
|
|
17
|
+
* to implement custom network frames.
|
|
18
|
+
*/
|
|
19
|
+
export abstract class NetworkFrame<
|
|
20
|
+
Protocol extends string,
|
|
21
|
+
Data,
|
|
22
|
+
Events extends DefaultEventMap,
|
|
23
|
+
> {
|
|
24
|
+
public events: Emitter<Events>
|
|
25
|
+
|
|
26
|
+
constructor(
|
|
27
|
+
public readonly protocol: Protocol,
|
|
28
|
+
public readonly data: Data,
|
|
29
|
+
) {
|
|
30
|
+
this.events = new Emitter()
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
public abstract getHandlers(controller: HandlersController): Array<AnyHandler>
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Resolve the current frame against the given list of handlers.
|
|
37
|
+
* Optionally, use a custom resolution context to control behaviors
|
|
38
|
+
* like `baseUrl`.
|
|
39
|
+
*
|
|
40
|
+
* Returns `true` if the frame was handled, `false` if it wasn't, and `null`
|
|
41
|
+
* if its handling was skipped (e.g. the frame was bypassed).
|
|
42
|
+
*/
|
|
43
|
+
public abstract resolve(
|
|
44
|
+
handlers: Array<AnyHandler>,
|
|
45
|
+
onUnhandledFrame: UnhandledFrameHandle,
|
|
46
|
+
resolutionContext?: NetworkFrameResolutionContext,
|
|
47
|
+
): Promise<boolean | null>
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Perform this network frame as-is.
|
|
51
|
+
*/
|
|
52
|
+
public abstract passthrough(): void
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Error the underling network frame.
|
|
56
|
+
* @param reason The reason for the error.
|
|
57
|
+
*/
|
|
58
|
+
public abstract errorWith(reason?: unknown): void
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Get a message to be used when this frame is unhandled.
|
|
62
|
+
*/
|
|
63
|
+
public abstract getUnhandledMessage(): Promise<string>
|
|
64
|
+
}
|