msw 2.9.0 → 2.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/lib/browser/index.js +8 -8
  2. package/lib/browser/index.js.map +1 -1
  3. package/lib/browser/index.mjs +8 -8
  4. package/lib/browser/index.mjs.map +1 -1
  5. package/lib/core/handlers/WebSocketHandler.d.mts +10 -7
  6. package/lib/core/handlers/WebSocketHandler.d.ts +10 -7
  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/WebSocketClientManager.d.mts +4 -2
  12. package/lib/core/ws/WebSocketClientManager.d.ts +4 -2
  13. package/lib/core/ws/WebSocketClientManager.js +10 -0
  14. package/lib/core/ws/WebSocketClientManager.js.map +1 -1
  15. package/lib/core/ws/WebSocketClientManager.mjs +10 -0
  16. package/lib/core/ws/WebSocketClientManager.mjs.map +1 -1
  17. package/lib/core/ws/handleWebSocketEvent.js +26 -39
  18. package/lib/core/ws/handleWebSocketEvent.js.map +1 -1
  19. package/lib/core/ws/handleWebSocketEvent.mjs +26 -39
  20. package/lib/core/ws/handleWebSocketEvent.mjs.map +1 -1
  21. package/lib/core/ws/utils/getMessageLength.js.map +1 -1
  22. package/lib/core/ws/utils/getMessageLength.mjs.map +1 -1
  23. package/lib/core/ws/utils/getPublicData.js.map +1 -1
  24. package/lib/core/ws/utils/getPublicData.mjs.map +1 -1
  25. package/lib/iife/index.js +57 -54
  26. package/lib/iife/index.js.map +1 -1
  27. package/lib/mockServiceWorker.js +1 -1
  28. package/package.json +3 -3
  29. package/src/core/handlers/WebSocketHandler.test.ts +12 -61
  30. package/src/core/handlers/WebSocketHandler.ts +27 -15
  31. package/src/core/ws/WebSocketClientManager.ts +33 -3
  32. package/src/core/ws/handleWebSocketEvent.ts +36 -55
  33. package/src/core/ws/utils/getMessageLength.ts +1 -1
  34. package/src/core/ws/utils/getPublicData.ts +1 -1
@@ -7,7 +7,7 @@
7
7
  * - Please do NOT modify this file.
8
8
  */
9
9
 
10
- const PACKAGE_VERSION = '2.9.0'
10
+ const PACKAGE_VERSION = '2.10.1'
11
11
  const INTEGRITY_CHECKSUM = 'f5825c521429caf22a4dd13b66e243af'
12
12
  const IS_MOCKED_RESPONSE = Symbol('isMockedResponse')
13
13
  const activeClientIds = new Set()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "msw",
3
- "version": "2.9.0",
3
+ "version": "2.10.1",
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",
@@ -218,7 +218,7 @@
218
218
  "@bundled-es-modules/statuses": "^1.0.1",
219
219
  "@bundled-es-modules/tough-cookie": "^0.1.6",
220
220
  "@inquirer/confirm": "^5.0.0",
221
- "@mswjs/interceptors": "^0.38.7",
221
+ "@mswjs/interceptors": "^0.39.1",
222
222
  "@open-draft/deferred-promise": "^2.2.0",
223
223
  "@open-draft/until": "^2.1.0",
224
224
  "@types/cookie": "^0.6.0",
@@ -280,7 +280,7 @@
280
280
  "vitest-environment-miniflare": "^2.14.4",
281
281
  "webpack": "^5.95.0",
282
282
  "webpack-http-server": "^0.5.0",
283
- "msw": "2.9.0"
283
+ "msw": "2.10.1"
284
284
  },
285
285
  "peerDependencies": {
286
286
  "typescript": ">= 4.8.x"
@@ -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: {
@@ -1,6 +1,10 @@
1
1
  import { Emitter } from 'strict-event-emitter'
2
2
  import { createRequestId } from '@mswjs/interceptors'
3
- import type { WebSocketConnectionData } from '@mswjs/interceptors/WebSocket'
3
+ import type {
4
+ WebSocketClientConnectionProtocol,
5
+ WebSocketConnectionData,
6
+ WebSocketServerConnectionProtocol,
7
+ } from '@mswjs/interceptors/WebSocket'
4
8
  import {
5
9
  type Match,
6
10
  type Path,
@@ -18,12 +22,14 @@ export type WebSocketHandlerEventMap = {
18
22
  connection: [args: WebSocketHandlerConnection]
19
23
  }
20
24
 
21
- export interface WebSocketHandlerConnection extends WebSocketConnectionData {
25
+ export interface WebSocketHandlerConnection {
26
+ client: WebSocketClientConnectionProtocol
27
+ server: WebSocketServerConnectionProtocol
28
+ info: WebSocketConnectionData['info']
22
29
  params: PathParams
23
30
  }
24
31
 
25
32
  export const kEmitter = Symbol('kEmitter')
26
- export const kDispatchEvent = Symbol('kDispatchEvent')
27
33
  export const kSender = Symbol('kSender')
28
34
  const kStopPropagationPatched = Symbol('kStopPropagationPatched')
29
35
  const KOnStopPropagation = Symbol('KOnStopPropagation')
@@ -44,11 +50,8 @@ export class WebSocketHandler {
44
50
  this.__kind = 'EventHandler'
45
51
  }
46
52
 
47
- public parse(args: {
48
- event: MessageEvent<WebSocketConnectionData>
49
- }): WebSocketHandlerParsedResult {
50
- const { data: connection } = args.event
51
- const { url: clientUrl } = connection.client
53
+ public parse(args: { url: URL }): WebSocketHandlerParsedResult {
54
+ const clientUrl = new URL(args.url)
52
55
 
53
56
  /**
54
57
  * @note Remove the Socket.IO path prefix from the WebSocket
@@ -65,23 +68,32 @@ export class WebSocketHandler {
65
68
  }
66
69
 
67
70
  public predicate(args: {
68
- event: MessageEvent<WebSocketConnectionData>
71
+ url: URL
69
72
  parsedResult: WebSocketHandlerParsedResult
70
73
  }): boolean {
71
74
  return args.parsedResult.match.matches
72
75
  }
73
76
 
74
- async [kDispatchEvent](
75
- event: MessageEvent<WebSocketConnectionData>,
76
- ): Promise<void> {
77
- const parsedResult = this.parse({ event })
78
- const connection = event.data
77
+ public async run(
78
+ connection: Omit<WebSocketHandlerConnection, 'params'>,
79
+ ): Promise<boolean> {
80
+ const parsedResult = this.parse({
81
+ url: connection.client.url,
82
+ })
83
+
84
+ if (!this.predicate({ url: connection.client.url, parsedResult })) {
85
+ return false
86
+ }
79
87
 
80
88
  const resolvedConnection: WebSocketHandlerConnection = {
81
89
  ...connection,
82
90
  params: parsedResult.match.params || {},
83
91
  }
84
92
 
93
+ return this.connect(resolvedConnection)
94
+ }
95
+
96
+ protected connect(connection: WebSocketHandlerConnection): boolean {
85
97
  // Support `event.stopPropagation()` for various client/server events.
86
98
  connection.client.addEventListener(
87
99
  'message',
@@ -111,7 +123,7 @@ export class WebSocketHandler {
111
123
 
112
124
  // Emit the connection event on the handler.
113
125
  // This is what the developer adds listeners for.
114
- this[kEmitter].emit('connection', resolvedConnection)
126
+ return this[kEmitter].emit('connection', connection)
115
127
  }
116
128
  }
117
129
 
@@ -1,7 +1,7 @@
1
1
  import type {
2
2
  WebSocketData,
3
- WebSocketClientConnection,
4
3
  WebSocketClientConnectionProtocol,
4
+ WebSocketClientEventMap,
5
5
  } from '@mswjs/interceptors/WebSocket'
6
6
  import { WebSocketClientStore } from './WebSocketClientStore'
7
7
  import { WebSocketMemoryClientStore } from './WebSocketMemoryClientStore'
@@ -105,7 +105,9 @@ export class WebSocketClientManager {
105
105
  this.channel.postMessage({ type: 'db:update' })
106
106
  }
107
107
 
108
- private async addClient(client: WebSocketClientConnection): Promise<void> {
108
+ private async addClient(
109
+ client: WebSocketClientConnectionProtocol,
110
+ ): Promise<void> {
109
111
  await this.store.add(client)
110
112
  // Sync the in-memory clients in this runtime with the
111
113
  // updated database. This pulls in all the stored clients.
@@ -119,7 +121,9 @@ export class WebSocketClientManager {
119
121
  * connection object because `addConnection()` is called only
120
122
  * for the opened connections in the same runtime.
121
123
  */
122
- public async addConnection(client: WebSocketClientConnection): Promise<void> {
124
+ public async addConnection(
125
+ client: WebSocketClientConnectionProtocol,
126
+ ): Promise<void> {
123
127
  // Store this client in the map of clients created in this runtime.
124
128
  // This way, the manager can distinguish between this runtime clients
125
129
  // and extraneous runtime clients when synchronizing clients storage.
@@ -208,4 +212,30 @@ export class WebSocketRemoteClientConnection
208
212
  },
209
213
  } as WebSocketBroadcastChannelMessage)
210
214
  }
215
+
216
+ addEventListener<EventType extends keyof WebSocketClientEventMap>(
217
+ _type: EventType,
218
+ _listener: (
219
+ this: WebSocket,
220
+ event: WebSocketClientEventMap[EventType],
221
+ ) => void,
222
+ _options?: AddEventListenerOptions | boolean,
223
+ ): void {
224
+ throw new Error(
225
+ 'WebSocketRemoteClientConnection.addEventListener is not supported',
226
+ )
227
+ }
228
+
229
+ removeEventListener<EventType extends keyof WebSocketClientEventMap>(
230
+ _event: EventType,
231
+ _listener: (
232
+ this: WebSocket,
233
+ event: WebSocketClientEventMap[EventType],
234
+ ) => void,
235
+ _options?: EventListenerOptions | boolean,
236
+ ): void {
237
+ throw new Error(
238
+ 'WebSocketRemoteClientConnection.removeEventListener is not supported',
239
+ )
240
+ }
211
241
  }
@@ -1,6 +1,6 @@
1
1
  import type { WebSocketConnectionData } from '@mswjs/interceptors/lib/browser/interceptors/WebSocket'
2
2
  import { RequestHandler } from '../handlers/RequestHandler'
3
- import { WebSocketHandler, kDispatchEvent } from '../handlers/WebSocketHandler'
3
+ import { WebSocketHandler } from '../handlers/WebSocketHandler'
4
4
  import { webSocketInterceptor } from './webSocketInterceptor'
5
5
  import {
6
6
  onUnhandledRequest,
@@ -17,67 +17,48 @@ interface HandleWebSocketEventOptions {
17
17
 
18
18
  export function handleWebSocketEvent(options: HandleWebSocketEventOptions) {
19
19
  webSocketInterceptor.on('connection', async (connection) => {
20
- const handlers = options.getHandlers()
20
+ const handlers = options.getHandlers().filter(isHandlerKind('EventHandler'))
21
21
 
22
- const connectionEvent = new MessageEvent('connection', {
23
- data: connection,
24
- })
22
+ // Ignore this connection if the user hasn't defined any handlers.
23
+ if (handlers.length > 0) {
24
+ options?.onMockedConnection(connection)
25
25
 
26
- // First, filter only those WebSocket handlers that
27
- // match the "ws.link()" endpoint predicate. Don't dispatch
28
- // anything yet so the logger can be attached to the connection
29
- // before it potentially sends events.
30
- const matchingHandlers: Array<WebSocketHandler> = []
26
+ await Promise.all(
27
+ handlers.map((handler) => {
28
+ // Iterate over the handlers and forward the connection
29
+ // event to WebSocket event handlers. This is equivalent
30
+ // to dispatching that event onto multiple listeners.
31
+ return handler.run(connection)
32
+ }),
33
+ )
31
34
 
32
- for (const handler of handlers) {
33
- if (
34
- isHandlerKind('EventHandler')(handler) &&
35
- handler.predicate({
36
- event: connectionEvent,
37
- parsedResult: handler.parse({
38
- event: connectionEvent,
39
- }),
40
- })
41
- ) {
42
- matchingHandlers.push(handler)
43
- }
35
+ return
44
36
  }
45
37
 
46
- if (matchingHandlers.length > 0) {
47
- options?.onMockedConnection(connection)
48
-
49
- // Iterate over the handlers and forward the connection
50
- // event to WebSocket event handlers. This is equivalent
51
- // to dispatching that event onto multiple listeners.
52
- for (const handler of matchingHandlers) {
53
- handler[kDispatchEvent](connectionEvent)
54
- }
55
- } else {
56
- // Construct a request representing this WebSocket connection.
57
- const request = new Request(connection.client.url, {
58
- headers: {
59
- upgrade: 'websocket',
60
- connection: 'upgrade',
61
- },
62
- })
63
- await onUnhandledRequest(
64
- request,
65
- options.getUnhandledRequestStrategy(),
66
- ).catch((error) => {
67
- const errorEvent = new Event('error')
68
- Object.defineProperty(errorEvent, 'cause', {
69
- enumerable: true,
70
- configurable: false,
71
- value: error,
72
- })
73
- connection.client.socket.dispatchEvent(errorEvent)
38
+ // Construct a request representing this WebSocket connection.
39
+ const request = new Request(connection.client.url, {
40
+ headers: {
41
+ upgrade: 'websocket',
42
+ connection: 'upgrade',
43
+ },
44
+ })
45
+ await onUnhandledRequest(
46
+ request,
47
+ options.getUnhandledRequestStrategy(),
48
+ ).catch((error) => {
49
+ const errorEvent = new Event('error')
50
+ Object.defineProperty(errorEvent, 'cause', {
51
+ enumerable: true,
52
+ configurable: false,
53
+ value: error,
74
54
  })
55
+ connection.client.socket.dispatchEvent(errorEvent)
56
+ })
75
57
 
76
- options?.onPassthroughConnection(connection)
58
+ options?.onPassthroughConnection(connection)
77
59
 
78
- // If none of the "ws" handlers matched,
79
- // establish the WebSocket connection as-is.
80
- connection.server.connect()
81
- }
60
+ // If none of the "ws" handlers matched,
61
+ // establish the WebSocket connection as-is.
62
+ connection.server.connect()
82
63
  })
83
64
  }
@@ -15,5 +15,5 @@ export function getMessageLength(data: WebSocketData): number {
15
15
  return data.byteLength
16
16
  }
17
17
 
18
- return new Blob([data]).size
18
+ return new Blob([data as any]).size
19
19
  }
@@ -9,7 +9,7 @@ export async function getPublicData(data: WebSocketData): Promise<string> {
9
9
 
10
10
  // Handle all ArrayBuffer-like objects.
11
11
  if (typeof data === 'object' && 'byteLength' in data) {
12
- const text = new TextDecoder().decode(data)
12
+ const text = new TextDecoder().decode(data as ArrayBuffer)
13
13
  return `ArrayBuffer(${truncateMessage(text)})`
14
14
  }
15
15