msw 2.8.7 → 2.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/lib/browser/index.js +13 -17
  2. package/lib/browser/index.js.map +1 -1
  3. package/lib/browser/index.mjs +13 -17
  4. package/lib/browser/index.mjs.map +1 -1
  5. package/lib/core/handlers/WebSocketHandler.d.mts +5 -5
  6. package/lib/core/handlers/WebSocketHandler.d.ts +5 -5
  7. package/lib/core/handlers/WebSocketHandler.js +12 -8
  8. package/lib/core/handlers/WebSocketHandler.js.map +1 -1
  9. package/lib/core/handlers/WebSocketHandler.mjs +12 -8
  10. package/lib/core/handlers/WebSocketHandler.mjs.map +1 -1
  11. package/lib/core/ws/handleWebSocketEvent.js +26 -39
  12. package/lib/core/ws/handleWebSocketEvent.js.map +1 -1
  13. package/lib/core/ws/handleWebSocketEvent.mjs +26 -39
  14. package/lib/core/ws/handleWebSocketEvent.mjs.map +1 -1
  15. package/lib/core/ws/utils/getMessageLength.js.map +1 -1
  16. package/lib/core/ws/utils/getMessageLength.mjs.map +1 -1
  17. package/lib/core/ws/utils/getPublicData.js.map +1 -1
  18. package/lib/core/ws/utils/getPublicData.mjs.map +1 -1
  19. package/lib/iife/index.js +51 -62
  20. package/lib/iife/index.js.map +1 -1
  21. package/lib/mockServiceWorker.js +91 -54
  22. package/package.json +3 -2
  23. package/src/browser/setupWorker/glossary.ts +7 -7
  24. package/src/browser/setupWorker/setupWorker.ts +0 -1
  25. package/src/browser/setupWorker/start/createRequestListener.ts +3 -4
  26. package/src/browser/setupWorker/start/createResponseListener.ts +8 -12
  27. package/src/browser/utils/{parseWorkerRequest.ts → deserializeRequest.ts} +5 -5
  28. package/src/core/handlers/WebSocketHandler.test.ts +12 -61
  29. package/src/core/handlers/WebSocketHandler.ts +16 -13
  30. package/src/core/ws/handleWebSocketEvent.ts +36 -55
  31. package/src/core/ws/utils/getMessageLength.ts +1 -1
  32. package/src/core/ws/utils/getPublicData.ts +1 -1
  33. package/src/mockServiceWorker.js +89 -52
  34. package/src/tsconfig.worker.json +13 -0
@@ -5,24 +5,23 @@
5
5
  * Mock Service Worker.
6
6
  * @see https://github.com/mswjs/msw
7
7
  * - Please do NOT modify this file.
8
- * - Please do NOT serve this file on production.
9
8
  */
10
9
 
11
- const PACKAGE_VERSION = '2.8.7'
12
- const INTEGRITY_CHECKSUM = '00729d72e3b82faf54ca8b9621dbb96f'
10
+ const PACKAGE_VERSION = '2.10.0'
11
+ const INTEGRITY_CHECKSUM = 'f5825c521429caf22a4dd13b66e243af'
13
12
  const IS_MOCKED_RESPONSE = Symbol('isMockedResponse')
14
13
  const activeClientIds = new Set()
15
14
 
16
- self.addEventListener('install', function () {
15
+ addEventListener('install', function () {
17
16
  self.skipWaiting()
18
17
  })
19
18
 
20
- self.addEventListener('activate', function (event) {
19
+ addEventListener('activate', function (event) {
21
20
  event.waitUntil(self.clients.claim())
22
21
  })
23
22
 
24
- self.addEventListener('message', async function (event) {
25
- const clientId = event.source.id
23
+ addEventListener('message', async function (event) {
24
+ const clientId = Reflect.get(event.source || {}, 'id')
26
25
 
27
26
  if (!clientId || !self.clients) {
28
27
  return
@@ -94,17 +93,18 @@ self.addEventListener('message', async function (event) {
94
93
  }
95
94
  })
96
95
 
97
- self.addEventListener('fetch', function (event) {
98
- const { request } = event
99
-
96
+ addEventListener('fetch', function (event) {
100
97
  // Bypass navigation requests.
101
- if (request.mode === 'navigate') {
98
+ if (event.request.mode === 'navigate') {
102
99
  return
103
100
  }
104
101
 
105
102
  // Opening the DevTools triggers the "only-if-cached" request
106
103
  // that cannot be handled by the worker. Bypass such requests.
107
- if (request.cache === 'only-if-cached' && request.mode !== 'same-origin') {
104
+ if (
105
+ event.request.cache === 'only-if-cached' &&
106
+ event.request.mode !== 'same-origin'
107
+ ) {
108
108
  return
109
109
  }
110
110
 
@@ -115,48 +115,62 @@ self.addEventListener('fetch', function (event) {
115
115
  return
116
116
  }
117
117
 
118
- // Generate unique request ID.
119
118
  const requestId = crypto.randomUUID()
120
119
  event.respondWith(handleRequest(event, requestId))
121
120
  })
122
121
 
122
+ /**
123
+ * @param {FetchEvent} event
124
+ * @param {string} requestId
125
+ */
123
126
  async function handleRequest(event, requestId) {
124
127
  const client = await resolveMainClient(event)
128
+ const requestCloneForEvents = event.request.clone()
125
129
  const response = await getResponse(event, client, requestId)
126
130
 
127
131
  // Send back the response clone for the "response:*" life-cycle events.
128
132
  // Ensure MSW is active and ready to handle the message, otherwise
129
133
  // this message will pend indefinitely.
130
134
  if (client && activeClientIds.has(client.id)) {
131
- ;(async function () {
132
- const responseClone = response.clone()
133
-
134
- sendToClient(
135
- client,
136
- {
137
- type: 'RESPONSE',
138
- payload: {
139
- requestId,
140
- isMockedResponse: IS_MOCKED_RESPONSE in response,
135
+ const serializedRequest = await serializeRequest(requestCloneForEvents)
136
+
137
+ // Clone the response so both the client and the library could consume it.
138
+ const responseClone = response.clone()
139
+
140
+ sendToClient(
141
+ client,
142
+ {
143
+ type: 'RESPONSE',
144
+ payload: {
145
+ isMockedResponse: IS_MOCKED_RESPONSE in response,
146
+ request: {
147
+ id: requestId,
148
+ ...serializedRequest,
149
+ },
150
+ response: {
141
151
  type: responseClone.type,
142
152
  status: responseClone.status,
143
153
  statusText: responseClone.statusText,
144
- body: responseClone.body,
145
154
  headers: Object.fromEntries(responseClone.headers.entries()),
155
+ body: responseClone.body,
146
156
  },
147
157
  },
148
- [responseClone.body],
149
- )
150
- })()
158
+ },
159
+ responseClone.body ? [serializedRequest.body, responseClone.body] : [],
160
+ )
151
161
  }
152
162
 
153
163
  return response
154
164
  }
155
165
 
156
- // Resolve the main client for the given event.
157
- // Client that issues a request doesn't necessarily equal the client
158
- // that registered the worker. It's with the latter the worker should
159
- // communicate with during the response resolving phase.
166
+ /**
167
+ * Resolve the main client for the given event.
168
+ * Client that issues a request doesn't necessarily equal the client
169
+ * that registered the worker. It's with the latter the worker should
170
+ * communicate with during the response resolving phase.
171
+ * @param {FetchEvent} event
172
+ * @returns {Promise<Client | undefined>}
173
+ */
160
174
  async function resolveMainClient(event) {
161
175
  const client = await self.clients.get(event.clientId)
162
176
 
@@ -184,12 +198,16 @@ async function resolveMainClient(event) {
184
198
  })
185
199
  }
186
200
 
201
+ /**
202
+ * @param {FetchEvent} event
203
+ * @param {Client | undefined} client
204
+ * @param {string} requestId
205
+ * @returns {Promise<Response>}
206
+ */
187
207
  async function getResponse(event, client, requestId) {
188
- const { request } = event
189
-
190
208
  // Clone the request because it might've been already used
191
209
  // (i.e. its body has been read and sent to the client).
192
- const requestClone = request.clone()
210
+ const requestClone = event.request.clone()
193
211
 
194
212
  function passthrough() {
195
213
  // Cast the request headers to a new Headers instance
@@ -230,29 +248,17 @@ async function getResponse(event, client, requestId) {
230
248
  }
231
249
 
232
250
  // Notify the client that a request has been intercepted.
233
- const requestBuffer = await request.arrayBuffer()
251
+ const serializedRequest = await serializeRequest(event.request)
234
252
  const clientMessage = await sendToClient(
235
253
  client,
236
254
  {
237
255
  type: 'REQUEST',
238
256
  payload: {
239
257
  id: requestId,
240
- url: request.url,
241
- mode: request.mode,
242
- method: request.method,
243
- headers: Object.fromEntries(request.headers.entries()),
244
- cache: request.cache,
245
- credentials: request.credentials,
246
- destination: request.destination,
247
- integrity: request.integrity,
248
- redirect: request.redirect,
249
- referrer: request.referrer,
250
- referrerPolicy: request.referrerPolicy,
251
- body: requestBuffer,
252
- keepalive: request.keepalive,
258
+ ...serializedRequest,
253
259
  },
254
260
  },
255
- [requestBuffer],
261
+ [serializedRequest.body],
256
262
  )
257
263
 
258
264
  switch (clientMessage.type) {
@@ -268,6 +274,12 @@ async function getResponse(event, client, requestId) {
268
274
  return passthrough()
269
275
  }
270
276
 
277
+ /**
278
+ * @param {Client} client
279
+ * @param {any} message
280
+ * @param {Array<Transferable>} transferrables
281
+ * @returns {Promise<any>}
282
+ */
271
283
  function sendToClient(client, message, transferrables = []) {
272
284
  return new Promise((resolve, reject) => {
273
285
  const channel = new MessageChannel()
@@ -280,14 +292,18 @@ function sendToClient(client, message, transferrables = []) {
280
292
  resolve(event.data)
281
293
  }
282
294
 
283
- client.postMessage(
284
- message,
285
- [channel.port2].concat(transferrables.filter(Boolean)),
286
- )
295
+ client.postMessage(message, [
296
+ channel.port2,
297
+ ...transferrables.filter(Boolean),
298
+ ])
287
299
  })
288
300
  }
289
301
 
290
- async function respondWithMock(response) {
302
+ /**
303
+ * @param {Response} response
304
+ * @returns {Response}
305
+ */
306
+ function respondWithMock(response) {
291
307
  // Setting response status code to 0 is a no-op.
292
308
  // However, when responding with a "Response.error()", the produced Response
293
309
  // instance will have status code set to 0. Since it's not possible to create
@@ -305,3 +321,24 @@ async function respondWithMock(response) {
305
321
 
306
322
  return mockedResponse
307
323
  }
324
+
325
+ /**
326
+ * @param {Request} request
327
+ */
328
+ async function serializeRequest(request) {
329
+ return {
330
+ url: request.url,
331
+ mode: request.mode,
332
+ method: request.method,
333
+ headers: Object.fromEntries(request.headers.entries()),
334
+ cache: request.cache,
335
+ credentials: request.credentials,
336
+ destination: request.destination,
337
+ integrity: request.integrity,
338
+ redirect: request.redirect,
339
+ referrer: request.referrer,
340
+ referrerPolicy: request.referrerPolicy,
341
+ body: await request.arrayBuffer(),
342
+ keepalive: request.keepalive,
343
+ }
344
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "msw",
3
- "version": "2.8.7",
3
+ "version": "2.10.0",
4
4
  "description": "Seamless REST/GraphQL API mocking library for browser and Node.js.",
5
5
  "type": "commonjs",
6
6
  "main": "./lib/core/index.js",
@@ -243,6 +243,7 @@
243
243
  "@types/express": "^4.17.21",
244
244
  "@types/json-bigint": "^1.0.4",
245
245
  "@types/node": "~18.19.28",
246
+ "@types/serviceworker": "^0.0.136",
246
247
  "@typescript-eslint/eslint-plugin": "^8.8.1",
247
248
  "@typescript-eslint/parser": "^8.8.1",
248
249
  "@web/dev-server": "^0.4.6",
@@ -279,7 +280,7 @@
279
280
  "vitest-environment-miniflare": "^2.14.4",
280
281
  "webpack": "^5.95.0",
281
282
  "webpack-http-server": "^0.5.0",
282
- "msw": "2.8.7"
283
+ "msw": "2.10.0"
283
284
  },
284
285
  "peerDependencies": {
285
286
  "typescript": ">= 4.8.x"
@@ -36,12 +36,13 @@ export interface ServiceWorkerIncomingRequest extends RequestWithoutMethods {
36
36
  body?: ArrayBuffer | null
37
37
  }
38
38
 
39
- type ServiceWorkerIncomingResponse = Pick<
40
- Response,
41
- 'type' | 'ok' | 'status' | 'statusText' | 'body' | 'headers' | 'redirected'
42
- > & {
43
- requestId: string
39
+ type ServiceWorkerIncomingResponse = {
44
40
  isMockedResponse: boolean
41
+ request: ServiceWorkerIncomingRequest
42
+ response: Pick<
43
+ Response,
44
+ 'type' | 'ok' | 'status' | 'statusText' | 'body' | 'headers' | 'redirected'
45
+ >
45
46
  }
46
47
 
47
48
  /**
@@ -87,8 +88,7 @@ export interface SetupWorkerInternalContext {
87
88
  startOptions: RequiredDeep<StartOptions>
88
89
  worker: ServiceWorker | null
89
90
  registration: ServiceWorkerRegistration | null
90
- getRequestHandlers(): Array<RequestHandler | WebSocketHandler>
91
- requests: Map<string, Request>
91
+ getRequestHandlers: () => Array<RequestHandler | WebSocketHandler>
92
92
  emitter: Emitter<LifeCycleEventsMap>
93
93
  keepAliveInterval?: number
94
94
  workerChannel: {
@@ -66,7 +66,6 @@ export class SetupWorkerApi
66
66
  return this.handlersController.currentHandlers()
67
67
  },
68
68
  registration: null,
69
- requests: new Map(),
70
69
  emitter: this.emitter,
71
70
  workerChannel: {
72
71
  on: (eventType, callback) => {
@@ -7,7 +7,7 @@ import {
7
7
  ServiceWorkerMessage,
8
8
  WorkerChannel,
9
9
  } from './utils/createMessageChannel'
10
- import { parseWorkerRequest } from '../../utils/parseWorkerRequest'
10
+ import { deserializeRequest } from '../../utils/deserializeRequest'
11
11
  import { RequestHandler } from '~/core/handlers/RequestHandler'
12
12
  import { handleRequest } from '~/core/utils/handleRequest'
13
13
  import { RequiredDeep } from '~/core/typeUtils'
@@ -29,16 +29,15 @@ export const createRequestListener = (
29
29
  const messageChannel = new WorkerChannel(event.ports[0])
30
30
 
31
31
  const requestId = message.payload.id
32
- const request = parseWorkerRequest(message.payload)
32
+ const request = deserializeRequest(message.payload)
33
33
  const requestCloneForLogs = request.clone()
34
34
 
35
- // Make this the first requets clone before the
35
+ // Make this the first request clone before the
36
36
  // request resolution pipeline even starts.
37
37
  // Store the clone in cache so the first matching
38
38
  // request handler would skip the cloning phase.
39
39
  const requestClone = request.clone()
40
40
  RequestHandler.cache.set(request, requestClone)
41
- context.requests.set(requestId, requestClone)
42
41
 
43
42
  try {
44
43
  await handleRequest(
@@ -4,6 +4,7 @@ import type {
4
4
  SetupWorkerInternalContext,
5
5
  } from '../glossary'
6
6
  import type { ServiceWorkerMessage } from './utils/createMessageChannel'
7
+ import { deserializeRequest } from '../../utils/deserializeRequest'
7
8
 
8
9
  export function createResponseListener(context: SetupWorkerInternalContext) {
9
10
  return (
@@ -14,12 +15,7 @@ export function createResponseListener(context: SetupWorkerInternalContext) {
14
15
  >,
15
16
  ) => {
16
17
  const { payload: responseJson } = message
17
-
18
- // Get the Request instance reference stored in the
19
- // request listener.
20
- const { requestId } = responseJson
21
- const request = context.requests.get(requestId)!
22
- context.requests.delete(requestId)
18
+ const request = deserializeRequest(responseJson.request)
23
19
 
24
20
  /**
25
21
  * CORS requests with `mode: "no-cors"` result in "opaque" responses.
@@ -28,12 +24,12 @@ export function createResponseListener(context: SetupWorkerInternalContext) {
28
24
  * @see https://fetch.spec.whatwg.org/#concept-filtered-response-opaque
29
25
  * @see https://github.com/mswjs/msw/issues/529
30
26
  */
31
- if (responseJson.type?.includes('opaque')) {
27
+ if (responseJson.response.type?.includes('opaque')) {
32
28
  return
33
29
  }
34
30
 
35
31
  const response =
36
- responseJson.status === 0
32
+ responseJson.response.status === 0
37
33
  ? Response.error()
38
34
  : new FetchResponse(
39
35
  /**
@@ -42,8 +38,8 @@ export function createResponseListener(context: SetupWorkerInternalContext) {
42
38
  * throw when passed a non-null body, so ensure it's null here
43
39
  * for those codes
44
40
  */
45
- FetchResponse.isResponseWithBody(responseJson.status)
46
- ? responseJson.body
41
+ FetchResponse.isResponseWithBody(responseJson.response.status)
42
+ ? responseJson.response.body
47
43
  : null,
48
44
  {
49
45
  ...responseJson,
@@ -59,9 +55,9 @@ export function createResponseListener(context: SetupWorkerInternalContext) {
59
55
  context.emitter.emit(
60
56
  responseJson.isMockedResponse ? 'response:mocked' : 'response:bypass',
61
57
  {
62
- response,
58
+ requestId: responseJson.request.id,
63
59
  request,
64
- requestId: responseJson.requestId,
60
+ response,
65
61
  },
66
62
  )
67
63
  }
@@ -5,11 +5,11 @@ import type { ServiceWorkerIncomingRequest } from '../setupWorker/glossary'
5
5
  * Converts a given request received from the Service Worker
6
6
  * into a Fetch `Request` instance.
7
7
  */
8
- export function parseWorkerRequest(
9
- incomingRequest: ServiceWorkerIncomingRequest,
8
+ export function deserializeRequest(
9
+ serializedRequest: ServiceWorkerIncomingRequest,
10
10
  ): Request {
11
- return new Request(incomingRequest.url, {
12
- ...incomingRequest,
13
- body: pruneGetRequestBody(incomingRequest),
11
+ return new Request(serializedRequest.url, {
12
+ ...serializedRequest,
13
+ body: pruneGetRequestBody(serializedRequest),
14
14
  })
15
15
  }
@@ -1,17 +1,10 @@
1
- import type { WebSocketConnectionData } from '@mswjs/interceptors/WebSocket'
2
1
  import { WebSocketHandler } from './WebSocketHandler'
3
2
 
4
3
  describe('parse', () => {
5
4
  it('matches an exact url', () => {
6
5
  expect(
7
6
  new WebSocketHandler('ws://localhost:3000').parse({
8
- event: new MessageEvent('connection', {
9
- data: {
10
- client: {
11
- url: new URL('ws://localhost:3000'),
12
- },
13
- } as WebSocketConnectionData,
14
- }),
7
+ url: new URL('ws://localhost:3000'),
15
8
  }),
16
9
  ).toEqual({
17
10
  match: {
@@ -24,13 +17,7 @@ describe('parse', () => {
24
17
  it('ignores trailing slash', () => {
25
18
  expect(
26
19
  new WebSocketHandler('ws://localhost:3000').parse({
27
- event: new MessageEvent('connection', {
28
- data: {
29
- client: {
30
- url: new URL('ws://localhost:3000/'),
31
- },
32
- } as WebSocketConnectionData,
33
- }),
20
+ url: new URL('ws://localhost:3000/'),
34
21
  }),
35
22
  ).toEqual({
36
23
  match: {
@@ -41,13 +28,7 @@ describe('parse', () => {
41
28
 
42
29
  expect(
43
30
  new WebSocketHandler('ws://localhost:3000/').parse({
44
- event: new MessageEvent('connection', {
45
- data: {
46
- client: {
47
- url: new URL('ws://localhost:3000'),
48
- },
49
- } as WebSocketConnectionData,
50
- }),
31
+ url: new URL('ws://localhost:3000/'),
51
32
  }),
52
33
  ).toEqual({
53
34
  match: {
@@ -60,13 +41,7 @@ describe('parse', () => {
60
41
  it('supports path parameters', () => {
61
42
  expect(
62
43
  new WebSocketHandler('ws://localhost:3000/:serviceName').parse({
63
- event: new MessageEvent('connection', {
64
- data: {
65
- client: {
66
- url: new URL('ws://localhost:3000/auth'),
67
- },
68
- } as WebSocketConnectionData,
69
- }),
44
+ url: new URL('ws://localhost:3000/auth'),
70
45
  }),
71
46
  ).toEqual({
72
47
  match: {
@@ -81,15 +56,9 @@ describe('parse', () => {
81
56
  it('ignores "/socket.io/" prefix in the client url', () => {
82
57
  expect(
83
58
  new WebSocketHandler('ws://localhost:3000').parse({
84
- event: new MessageEvent('connection', {
85
- data: {
86
- client: {
87
- url: new URL(
88
- 'ws://localhost:3000/socket.io/?EIO=4&transport=websocket',
89
- ),
90
- },
91
- } as WebSocketConnectionData,
92
- }),
59
+ url: new URL(
60
+ 'ws://localhost:3000/socket.io/?EIO=4&transport=websocket',
61
+ ),
93
62
  }),
94
63
  ).toEqual({
95
64
  match: {
@@ -100,15 +69,9 @@ describe('parse', () => {
100
69
 
101
70
  expect(
102
71
  new WebSocketHandler('ws://localhost:3000/non-matching').parse({
103
- event: new MessageEvent('connection', {
104
- data: {
105
- client: {
106
- url: new URL(
107
- 'ws://localhost:3000/socket.io/?EIO=4&transport=websocket',
108
- ),
109
- },
110
- } as WebSocketConnectionData,
111
- }),
72
+ url: new URL(
73
+ 'ws://localhost:3000/socket.io/?EIO=4&transport=websocket',
74
+ ),
112
75
  }),
113
76
  ).toEqual({
114
77
  match: {
@@ -125,13 +88,7 @@ describe('parse', () => {
125
88
  */
126
89
  expect(
127
90
  new WebSocketHandler('ws://localhost:3000/clients/socket.io/123').parse({
128
- event: new MessageEvent('connection', {
129
- data: {
130
- client: {
131
- url: new URL('ws://localhost:3000/clients/socket.io/123'),
132
- },
133
- } as WebSocketConnectionData,
134
- }),
91
+ url: new URL('ws://localhost:3000/clients/socket.io/123'),
135
92
  }),
136
93
  ).toEqual({
137
94
  match: {
@@ -142,13 +99,7 @@ describe('parse', () => {
142
99
 
143
100
  expect(
144
101
  new WebSocketHandler('ws://localhost:3000').parse({
145
- event: new MessageEvent('connection', {
146
- data: {
147
- client: {
148
- url: new URL('ws://localhost:3000/clients/socket.io/123'),
149
- },
150
- } as WebSocketConnectionData,
151
- }),
102
+ url: new URL('ws://localhost:3000/clients/socket.io/123'),
152
103
  }),
153
104
  ).toEqual({
154
105
  match: {
@@ -23,7 +23,6 @@ export interface WebSocketHandlerConnection extends WebSocketConnectionData {
23
23
  }
24
24
 
25
25
  export const kEmitter = Symbol('kEmitter')
26
- export const kDispatchEvent = Symbol('kDispatchEvent')
27
26
  export const kSender = Symbol('kSender')
28
27
  const kStopPropagationPatched = Symbol('kStopPropagationPatched')
29
28
  const KOnStopPropagation = Symbol('KOnStopPropagation')
@@ -44,11 +43,8 @@ export class WebSocketHandler {
44
43
  this.__kind = 'EventHandler'
45
44
  }
46
45
 
47
- public parse(args: {
48
- event: MessageEvent<WebSocketConnectionData>
49
- }): WebSocketHandlerParsedResult {
50
- const { data: connection } = args.event
51
- const { url: clientUrl } = connection.client
46
+ public parse(args: { url: URL }): WebSocketHandlerParsedResult {
47
+ const clientUrl = new URL(args.url)
52
48
 
53
49
  /**
54
50
  * @note Remove the Socket.IO path prefix from the WebSocket
@@ -65,23 +61,30 @@ export class WebSocketHandler {
65
61
  }
66
62
 
67
63
  public predicate(args: {
68
- event: MessageEvent<WebSocketConnectionData>
64
+ url: URL
69
65
  parsedResult: WebSocketHandlerParsedResult
70
66
  }): boolean {
71
67
  return args.parsedResult.match.matches
72
68
  }
73
69
 
74
- async [kDispatchEvent](
75
- event: MessageEvent<WebSocketConnectionData>,
76
- ): Promise<void> {
77
- const parsedResult = this.parse({ event })
78
- const connection = event.data
70
+ public async run(connection: WebSocketConnectionData): Promise<boolean> {
71
+ const parsedResult = this.parse({
72
+ url: connection.client.url,
73
+ })
74
+
75
+ if (!this.predicate({ url: connection.client.url, parsedResult })) {
76
+ return false
77
+ }
79
78
 
80
79
  const resolvedConnection: WebSocketHandlerConnection = {
81
80
  ...connection,
82
81
  params: parsedResult.match.params || {},
83
82
  }
84
83
 
84
+ return this.connect(resolvedConnection)
85
+ }
86
+
87
+ protected connect(connection: WebSocketHandlerConnection): boolean {
85
88
  // Support `event.stopPropagation()` for various client/server events.
86
89
  connection.client.addEventListener(
87
90
  'message',
@@ -111,7 +114,7 @@ export class WebSocketHandler {
111
114
 
112
115
  // Emit the connection event on the handler.
113
116
  // This is what the developer adds listeners for.
114
- this[kEmitter].emit('connection', resolvedConnection)
117
+ return this[kEmitter].emit('connection', connection)
115
118
  }
116
119
  }
117
120