msw 2.13.5 → 2.13.6

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.
@@ -31,13 +31,16 @@ declare class WebSocketHandler {
31
31
  protected [kEmitter]: Emitter<WebSocketHandlerEventMap>;
32
32
  constructor(url: Path);
33
33
  parse(args: {
34
- url: URL;
34
+ url: string | URL;
35
35
  resolutionContext?: WebSocketResolutionContext;
36
36
  }): WebSocketHandlerParsedResult;
37
37
  predicate(args: {
38
- url: URL;
38
+ url: string | URL;
39
39
  parsedResult: WebSocketHandlerParsedResult;
40
40
  }): boolean;
41
+ test(url: string | URL, resolutionContext?: WebSocketResolutionContext & {
42
+ strict?: boolean;
43
+ }): boolean;
41
44
  run(connection: WebSocketConnectionData, resolutionContext?: WebSocketResolutionContext): Promise<WebSocketHandlerConnection | null>;
42
45
  protected [kConnect](connection: WebSocketHandlerConnection): boolean;
43
46
  log(connection: WebSocketConnectionData): () => void;
@@ -31,13 +31,16 @@ declare class WebSocketHandler {
31
31
  protected [kEmitter]: Emitter<WebSocketHandlerEventMap>;
32
32
  constructor(url: Path);
33
33
  parse(args: {
34
- url: URL;
34
+ url: string | URL;
35
35
  resolutionContext?: WebSocketResolutionContext;
36
36
  }): WebSocketHandlerParsedResult;
37
37
  predicate(args: {
38
- url: URL;
38
+ url: string | URL;
39
39
  parsedResult: WebSocketHandlerParsedResult;
40
40
  }): boolean;
41
+ test(url: string | URL, resolutionContext?: WebSocketResolutionContext & {
42
+ strict?: boolean;
43
+ }): boolean;
41
44
  run(connection: WebSocketConnectionData, resolutionContext?: WebSocketResolutionContext): Promise<WebSocketHandlerConnection | null>;
42
45
  protected [kConnect](connection: WebSocketHandlerConnection): boolean;
43
46
  log(connection: WebSocketConnectionData): () => void;
@@ -63,12 +63,12 @@ class WebSocketHandler {
63
63
  predicate(args) {
64
64
  return args.parsedResult.match.matches;
65
65
  }
66
+ test(url, resolutionContext) {
67
+ return this.#match(url, resolutionContext) != null;
68
+ }
66
69
  async run(connection, resolutionContext) {
67
- const parsedResult = this.parse({
68
- url: connection.client.url,
69
- resolutionContext
70
- });
71
- if (!this.predicate({ url: connection.client.url, parsedResult })) {
70
+ const parsedResult = this.#match(connection.client.url, resolutionContext);
71
+ if (parsedResult == null) {
72
72
  return null;
73
73
  }
74
74
  const resolvedConnection = {
@@ -83,6 +83,23 @@ class WebSocketHandler {
83
83
  }
84
84
  return resolvedConnection;
85
85
  }
86
+ #match(url, resolutionContext) {
87
+ const resolvedUrl = this.#resolveWebSocketUrl(
88
+ url.toString(),
89
+ resolutionContext?.baseUrl
90
+ );
91
+ const parsedResult = this.parse({
92
+ url: resolvedUrl,
93
+ resolutionContext
94
+ });
95
+ if (this.predicate({
96
+ url,
97
+ parsedResult
98
+ })) {
99
+ return parsedResult;
100
+ }
101
+ return null;
102
+ }
86
103
  [kConnect](connection) {
87
104
  connection.client.addEventListener(
88
105
  "message",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/core/handlers/WebSocketHandler.ts"],"sourcesContent":["import { Emitter } from 'strict-event-emitter'\nimport { createRequestId, resolveWebSocketUrl } from '@mswjs/interceptors'\nimport type {\n WebSocketClientConnectionProtocol,\n WebSocketConnectionData,\n WebSocketServerConnectionProtocol,\n} from '@mswjs/interceptors/WebSocket'\nimport {\n type Match,\n type Path,\n type PathParams,\n matchRequestUrl,\n} from '../utils/matching/matchRequestUrl'\nimport { getCallFrame } from '../utils/internal/getCallFrame'\nimport { attachWebSocketLogger } from '../ws/utils/attachWebSocketLogger'\n\ntype WebSocketHandlerParsedResult = {\n match: Match\n}\n\nexport type WebSocketHandlerEventMap = {\n connection: [args: WebSocketHandlerConnection]\n}\n\nexport interface WebSocketHandlerConnection {\n client: WebSocketClientConnectionProtocol\n server: WebSocketServerConnectionProtocol\n info: WebSocketConnectionData['info']\n params: PathParams\n}\n\nexport interface WebSocketResolutionContext {\n baseUrl?: string\n [kAutoConnect]?: boolean\n}\n\nexport const kEmitter = Symbol('kEmitter')\nexport const kSender = Symbol('kSender')\nexport const kConnect = Symbol('kConnect')\nexport const kAutoConnect = Symbol('kAutoConnect')\n\nconst kStopPropagationPatched = Symbol('kStopPropagationPatched')\nconst KOnStopPropagation = Symbol('KOnStopPropagation')\n\nexport class WebSocketHandler {\n public id: string\n public callFrame?: string\n public kind = 'websocket' as const\n\n protected [kEmitter]: Emitter<WebSocketHandlerEventMap>\n\n constructor(protected readonly url: Path) {\n this.id = createRequestId()\n\n this[kEmitter] = new Emitter()\n this.callFrame = getCallFrame(new Error())\n }\n\n public parse(args: {\n url: URL\n resolutionContext?: WebSocketResolutionContext\n }): WebSocketHandlerParsedResult {\n const clientUrl = new URL(args.url)\n\n // Resolve the WebSocket handler path:\n // - Plain string URLs resolved as per the specification (via Interceptors).\n // - String URLs starting with a wildcard are preserved (prepending a scheme there will break them).\n // - RegExp paths are preserved.\n const resolvedHandlerUrl =\n this.url instanceof RegExp || this.url.startsWith('*')\n ? this.url\n : this.#resolveWebSocketUrl(this.url, args.resolutionContext?.baseUrl)\n\n /**\n * @note Remove the Socket.IO path prefix from the WebSocket\n * client URL. This is an exception to keep the users from\n * including the implementation details in their handlers.\n */\n clientUrl.pathname = clientUrl.pathname.replace(/^\\/socket.io\\//, '/')\n\n const match = matchRequestUrl(\n clientUrl,\n resolvedHandlerUrl,\n args.resolutionContext?.baseUrl,\n )\n\n return {\n match,\n }\n }\n\n public predicate(args: {\n url: URL\n parsedResult: WebSocketHandlerParsedResult\n }): boolean {\n return args.parsedResult.match.matches\n }\n\n public async run(\n connection: WebSocketConnectionData,\n resolutionContext?: WebSocketResolutionContext,\n ): Promise<WebSocketHandlerConnection | null> {\n const parsedResult = this.parse({\n url: connection.client.url,\n resolutionContext,\n })\n\n if (!this.predicate({ url: connection.client.url, parsedResult })) {\n return null\n }\n\n const resolvedConnection: WebSocketHandlerConnection = {\n ...connection,\n params: parsedResult.match.params || {},\n }\n\n if (resolutionContext?.[kAutoConnect]) {\n if (this[kConnect](resolvedConnection)) {\n return resolvedConnection\n }\n\n return null\n }\n\n return resolvedConnection\n }\n\n protected [kConnect](connection: WebSocketHandlerConnection): boolean {\n // Support `event.stopPropagation()` for various client/server events.\n connection.client.addEventListener(\n 'message',\n createStopPropagationListener(this),\n )\n connection.client.addEventListener(\n 'close',\n createStopPropagationListener(this),\n )\n\n connection.server.addEventListener(\n 'open',\n createStopPropagationListener(this),\n )\n connection.server.addEventListener(\n 'message',\n createStopPropagationListener(this),\n )\n connection.server.addEventListener(\n 'error',\n createStopPropagationListener(this),\n )\n connection.server.addEventListener(\n 'close',\n createStopPropagationListener(this),\n )\n\n /**\n * @fixme Use \"rettime\" and await these events to have\n * exceptions propagate properly.\n */\n return this[kEmitter].emit('connection', connection)\n }\n\n public log(connection: WebSocketConnectionData): () => void {\n return attachWebSocketLogger(connection)\n }\n\n #resolveWebSocketUrl(url: string, baseUrl?: string): string {\n const resolvedUrl = resolveWebSocketUrl(\n baseUrl\n ? /**\n * @note Resolve against the base URL preemtively because `resolveWebSocketUrl` only\n * resolves against `location.href`, which is missing in Node.js. Base URL allows\n * the handler to accept a relative URL in Node.js.\n */\n new URL(url, baseUrl)\n : url,\n )\n\n /**\n * @note Omit the trailing slash.\n * While the browser always produces a trailing slash at the end of a WebSocket URL,\n * having it in as the handler's predicate would mean it is *required* in the actual URL.\n */\n return resolvedUrl.replace(/\\/$/, '')\n }\n}\n\nfunction createStopPropagationListener(handler: WebSocketHandler) {\n return function stopPropagationListener(event: Event) {\n const propagationStoppedAt = Reflect.get(event, 'kPropagationStoppedAt') as\n | string\n | undefined\n\n if (propagationStoppedAt && handler.id !== propagationStoppedAt) {\n event.stopImmediatePropagation()\n return\n }\n\n Object.defineProperty(event, KOnStopPropagation, {\n value(this: WebSocketHandler) {\n Object.defineProperty(event, 'kPropagationStoppedAt', {\n value: handler.id,\n })\n },\n configurable: true,\n })\n\n // Since the same event instance is shared between all client/server objects,\n // make sure to patch its `stopPropagation` method only once.\n if (!Reflect.get(event, kStopPropagationPatched)) {\n event.stopPropagation = new Proxy(event.stopPropagation, {\n apply: (target, thisArg, args) => {\n Reflect.get(event, KOnStopPropagation)?.call(handler)\n return Reflect.apply(target, thisArg, args)\n },\n })\n\n Object.defineProperty(event, kStopPropagationPatched, {\n value: true,\n // If something else attempts to redefine this, throw.\n configurable: false,\n })\n }\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/core/handlers/WebSocketHandler.ts"],"sourcesContent":["import { Emitter } from 'strict-event-emitter'\nimport { createRequestId, resolveWebSocketUrl } from '@mswjs/interceptors'\nimport type {\n WebSocketClientConnectionProtocol,\n WebSocketConnectionData,\n WebSocketServerConnectionProtocol,\n} from '@mswjs/interceptors/WebSocket'\nimport {\n type Match,\n type Path,\n type PathParams,\n matchRequestUrl,\n} from '../utils/matching/matchRequestUrl'\nimport { getCallFrame } from '../utils/internal/getCallFrame'\nimport { attachWebSocketLogger } from '../ws/utils/attachWebSocketLogger'\n\ntype WebSocketHandlerParsedResult = {\n match: Match\n}\n\nexport type WebSocketHandlerEventMap = {\n connection: [args: WebSocketHandlerConnection]\n}\n\nexport interface WebSocketHandlerConnection {\n client: WebSocketClientConnectionProtocol\n server: WebSocketServerConnectionProtocol\n info: WebSocketConnectionData['info']\n params: PathParams\n}\n\nexport interface WebSocketResolutionContext {\n baseUrl?: string\n [kAutoConnect]?: boolean\n}\n\nexport const kEmitter = Symbol('kEmitter')\nexport const kSender = Symbol('kSender')\nexport const kConnect = Symbol('kConnect')\nexport const kAutoConnect = Symbol('kAutoConnect')\n\nconst kStopPropagationPatched = Symbol('kStopPropagationPatched')\nconst KOnStopPropagation = Symbol('KOnStopPropagation')\n\nexport class WebSocketHandler {\n public id: string\n public callFrame?: string\n public kind = 'websocket' as const\n\n protected [kEmitter]: Emitter<WebSocketHandlerEventMap>\n\n constructor(protected readonly url: Path) {\n this.id = createRequestId()\n\n this[kEmitter] = new Emitter()\n this.callFrame = getCallFrame(new Error())\n }\n\n public parse(args: {\n url: string | URL\n resolutionContext?: WebSocketResolutionContext\n }): WebSocketHandlerParsedResult {\n const clientUrl = new URL(args.url)\n\n // Resolve the WebSocket handler path:\n // - Plain string URLs resolved as per the specification (via Interceptors).\n // - String URLs starting with a wildcard are preserved (prepending a scheme there will break them).\n // - RegExp paths are preserved.\n const resolvedHandlerUrl =\n this.url instanceof RegExp || this.url.startsWith('*')\n ? this.url\n : this.#resolveWebSocketUrl(this.url, args.resolutionContext?.baseUrl)\n\n /**\n * @note Remove the Socket.IO path prefix from the WebSocket\n * client URL. This is an exception to keep the users from\n * including the implementation details in their handlers.\n */\n clientUrl.pathname = clientUrl.pathname.replace(/^\\/socket.io\\//, '/')\n\n const match = matchRequestUrl(\n clientUrl,\n resolvedHandlerUrl,\n args.resolutionContext?.baseUrl,\n )\n\n return {\n match,\n }\n }\n\n public predicate(args: {\n url: string | URL\n parsedResult: WebSocketHandlerParsedResult\n }): boolean {\n return args.parsedResult.match.matches\n }\n\n public test(\n url: string | URL,\n resolutionContext?: WebSocketResolutionContext & { strict?: boolean },\n ): boolean {\n return this.#match(url, resolutionContext) != null\n }\n\n public async run(\n connection: WebSocketConnectionData,\n resolutionContext?: WebSocketResolutionContext,\n ): Promise<WebSocketHandlerConnection | null> {\n const parsedResult = this.#match(connection.client.url, resolutionContext)\n\n if (parsedResult == null) {\n return null\n }\n\n const resolvedConnection: WebSocketHandlerConnection = {\n ...connection,\n params: parsedResult.match.params || {},\n }\n\n if (resolutionContext?.[kAutoConnect]) {\n if (this[kConnect](resolvedConnection)) {\n return resolvedConnection\n }\n\n return null\n }\n\n return resolvedConnection\n }\n\n #match(\n url: string | URL,\n resolutionContext?: WebSocketResolutionContext & { strict?: boolean },\n ): WebSocketHandlerParsedResult | null {\n const resolvedUrl = this.#resolveWebSocketUrl(\n url.toString(),\n resolutionContext?.baseUrl,\n )\n const parsedResult = this.parse({\n url: resolvedUrl,\n resolutionContext,\n })\n\n if (\n this.predicate({\n url,\n parsedResult,\n })\n ) {\n return parsedResult\n }\n\n return null\n }\n\n protected [kConnect](connection: WebSocketHandlerConnection): boolean {\n // Support `event.stopPropagation()` for various client/server events.\n connection.client.addEventListener(\n 'message',\n createStopPropagationListener(this),\n )\n connection.client.addEventListener(\n 'close',\n createStopPropagationListener(this),\n )\n\n connection.server.addEventListener(\n 'open',\n createStopPropagationListener(this),\n )\n connection.server.addEventListener(\n 'message',\n createStopPropagationListener(this),\n )\n connection.server.addEventListener(\n 'error',\n createStopPropagationListener(this),\n )\n connection.server.addEventListener(\n 'close',\n createStopPropagationListener(this),\n )\n\n /**\n * @fixme Use \"rettime\" and await these events to have\n * exceptions propagate properly.\n */\n return this[kEmitter].emit('connection', connection)\n }\n\n public log(connection: WebSocketConnectionData): () => void {\n return attachWebSocketLogger(connection)\n }\n\n #resolveWebSocketUrl(url: string, baseUrl?: string): string {\n const resolvedUrl = resolveWebSocketUrl(\n baseUrl\n ? /**\n * @note Resolve against the base URL preemtively because `resolveWebSocketUrl` only\n * resolves against `location.href`, which is missing in Node.js. Base URL allows\n * the handler to accept a relative URL in Node.js.\n */\n new URL(url, baseUrl)\n : url,\n )\n\n /**\n * @note Omit the trailing slash.\n * While the browser always produces a trailing slash at the end of a WebSocket URL,\n * having it in as the handler's predicate would mean it is *required* in the actual URL.\n */\n return resolvedUrl.replace(/\\/$/, '')\n }\n}\n\nfunction createStopPropagationListener(handler: WebSocketHandler) {\n return function stopPropagationListener(event: Event) {\n const propagationStoppedAt = Reflect.get(event, 'kPropagationStoppedAt') as\n | string\n | undefined\n\n if (propagationStoppedAt && handler.id !== propagationStoppedAt) {\n event.stopImmediatePropagation()\n return\n }\n\n Object.defineProperty(event, KOnStopPropagation, {\n value(this: WebSocketHandler) {\n Object.defineProperty(event, 'kPropagationStoppedAt', {\n value: handler.id,\n })\n },\n configurable: true,\n })\n\n // Since the same event instance is shared between all client/server objects,\n // make sure to patch its `stopPropagation` method only once.\n if (!Reflect.get(event, kStopPropagationPatched)) {\n event.stopPropagation = new Proxy(event.stopPropagation, {\n apply: (target, thisArg, args) => {\n Reflect.get(event, KOnStopPropagation)?.call(handler)\n return Reflect.apply(target, thisArg, args)\n },\n })\n\n Object.defineProperty(event, kStopPropagationPatched, {\n value: true,\n // If something else attempts to redefine this, throw.\n configurable: false,\n })\n }\n }\n}\n"],"mappings":"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","names":[]}
@@ -38,12 +38,12 @@ class WebSocketHandler {
38
38
  predicate(args) {
39
39
  return args.parsedResult.match.matches;
40
40
  }
41
+ test(url, resolutionContext) {
42
+ return this.#match(url, resolutionContext) != null;
43
+ }
41
44
  async run(connection, resolutionContext) {
42
- const parsedResult = this.parse({
43
- url: connection.client.url,
44
- resolutionContext
45
- });
46
- if (!this.predicate({ url: connection.client.url, parsedResult })) {
45
+ const parsedResult = this.#match(connection.client.url, resolutionContext);
46
+ if (parsedResult == null) {
47
47
  return null;
48
48
  }
49
49
  const resolvedConnection = {
@@ -58,6 +58,23 @@ class WebSocketHandler {
58
58
  }
59
59
  return resolvedConnection;
60
60
  }
61
+ #match(url, resolutionContext) {
62
+ const resolvedUrl = this.#resolveWebSocketUrl(
63
+ url.toString(),
64
+ resolutionContext?.baseUrl
65
+ );
66
+ const parsedResult = this.parse({
67
+ url: resolvedUrl,
68
+ resolutionContext
69
+ });
70
+ if (this.predicate({
71
+ url,
72
+ parsedResult
73
+ })) {
74
+ return parsedResult;
75
+ }
76
+ return null;
77
+ }
61
78
  [kConnect](connection) {
62
79
  connection.client.addEventListener(
63
80
  "message",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/core/handlers/WebSocketHandler.ts"],"sourcesContent":["import { Emitter } from 'strict-event-emitter'\nimport { createRequestId, resolveWebSocketUrl } from '@mswjs/interceptors'\nimport type {\n WebSocketClientConnectionProtocol,\n WebSocketConnectionData,\n WebSocketServerConnectionProtocol,\n} from '@mswjs/interceptors/WebSocket'\nimport {\n type Match,\n type Path,\n type PathParams,\n matchRequestUrl,\n} from '../utils/matching/matchRequestUrl'\nimport { getCallFrame } from '../utils/internal/getCallFrame'\nimport { attachWebSocketLogger } from '../ws/utils/attachWebSocketLogger'\n\ntype WebSocketHandlerParsedResult = {\n match: Match\n}\n\nexport type WebSocketHandlerEventMap = {\n connection: [args: WebSocketHandlerConnection]\n}\n\nexport interface WebSocketHandlerConnection {\n client: WebSocketClientConnectionProtocol\n server: WebSocketServerConnectionProtocol\n info: WebSocketConnectionData['info']\n params: PathParams\n}\n\nexport interface WebSocketResolutionContext {\n baseUrl?: string\n [kAutoConnect]?: boolean\n}\n\nexport const kEmitter = Symbol('kEmitter')\nexport const kSender = Symbol('kSender')\nexport const kConnect = Symbol('kConnect')\nexport const kAutoConnect = Symbol('kAutoConnect')\n\nconst kStopPropagationPatched = Symbol('kStopPropagationPatched')\nconst KOnStopPropagation = Symbol('KOnStopPropagation')\n\nexport class WebSocketHandler {\n public id: string\n public callFrame?: string\n public kind = 'websocket' as const\n\n protected [kEmitter]: Emitter<WebSocketHandlerEventMap>\n\n constructor(protected readonly url: Path) {\n this.id = createRequestId()\n\n this[kEmitter] = new Emitter()\n this.callFrame = getCallFrame(new Error())\n }\n\n public parse(args: {\n url: URL\n resolutionContext?: WebSocketResolutionContext\n }): WebSocketHandlerParsedResult {\n const clientUrl = new URL(args.url)\n\n // Resolve the WebSocket handler path:\n // - Plain string URLs resolved as per the specification (via Interceptors).\n // - String URLs starting with a wildcard are preserved (prepending a scheme there will break them).\n // - RegExp paths are preserved.\n const resolvedHandlerUrl =\n this.url instanceof RegExp || this.url.startsWith('*')\n ? this.url\n : this.#resolveWebSocketUrl(this.url, args.resolutionContext?.baseUrl)\n\n /**\n * @note Remove the Socket.IO path prefix from the WebSocket\n * client URL. This is an exception to keep the users from\n * including the implementation details in their handlers.\n */\n clientUrl.pathname = clientUrl.pathname.replace(/^\\/socket.io\\//, '/')\n\n const match = matchRequestUrl(\n clientUrl,\n resolvedHandlerUrl,\n args.resolutionContext?.baseUrl,\n )\n\n return {\n match,\n }\n }\n\n public predicate(args: {\n url: URL\n parsedResult: WebSocketHandlerParsedResult\n }): boolean {\n return args.parsedResult.match.matches\n }\n\n public async run(\n connection: WebSocketConnectionData,\n resolutionContext?: WebSocketResolutionContext,\n ): Promise<WebSocketHandlerConnection | null> {\n const parsedResult = this.parse({\n url: connection.client.url,\n resolutionContext,\n })\n\n if (!this.predicate({ url: connection.client.url, parsedResult })) {\n return null\n }\n\n const resolvedConnection: WebSocketHandlerConnection = {\n ...connection,\n params: parsedResult.match.params || {},\n }\n\n if (resolutionContext?.[kAutoConnect]) {\n if (this[kConnect](resolvedConnection)) {\n return resolvedConnection\n }\n\n return null\n }\n\n return resolvedConnection\n }\n\n protected [kConnect](connection: WebSocketHandlerConnection): boolean {\n // Support `event.stopPropagation()` for various client/server events.\n connection.client.addEventListener(\n 'message',\n createStopPropagationListener(this),\n )\n connection.client.addEventListener(\n 'close',\n createStopPropagationListener(this),\n )\n\n connection.server.addEventListener(\n 'open',\n createStopPropagationListener(this),\n )\n connection.server.addEventListener(\n 'message',\n createStopPropagationListener(this),\n )\n connection.server.addEventListener(\n 'error',\n createStopPropagationListener(this),\n )\n connection.server.addEventListener(\n 'close',\n createStopPropagationListener(this),\n )\n\n /**\n * @fixme Use \"rettime\" and await these events to have\n * exceptions propagate properly.\n */\n return this[kEmitter].emit('connection', connection)\n }\n\n public log(connection: WebSocketConnectionData): () => void {\n return attachWebSocketLogger(connection)\n }\n\n #resolveWebSocketUrl(url: string, baseUrl?: string): string {\n const resolvedUrl = resolveWebSocketUrl(\n baseUrl\n ? /**\n * @note Resolve against the base URL preemtively because `resolveWebSocketUrl` only\n * resolves against `location.href`, which is missing in Node.js. Base URL allows\n * the handler to accept a relative URL in Node.js.\n */\n new URL(url, baseUrl)\n : url,\n )\n\n /**\n * @note Omit the trailing slash.\n * While the browser always produces a trailing slash at the end of a WebSocket URL,\n * having it in as the handler's predicate would mean it is *required* in the actual URL.\n */\n return resolvedUrl.replace(/\\/$/, '')\n }\n}\n\nfunction createStopPropagationListener(handler: WebSocketHandler) {\n return function stopPropagationListener(event: Event) {\n const propagationStoppedAt = Reflect.get(event, 'kPropagationStoppedAt') as\n | string\n | undefined\n\n if (propagationStoppedAt && handler.id !== propagationStoppedAt) {\n event.stopImmediatePropagation()\n return\n }\n\n Object.defineProperty(event, KOnStopPropagation, {\n value(this: WebSocketHandler) {\n Object.defineProperty(event, 'kPropagationStoppedAt', {\n value: handler.id,\n })\n },\n configurable: true,\n })\n\n // Since the same event instance is shared between all client/server objects,\n // make sure to patch its `stopPropagation` method only once.\n if (!Reflect.get(event, kStopPropagationPatched)) {\n event.stopPropagation = new Proxy(event.stopPropagation, {\n apply: (target, thisArg, args) => {\n Reflect.get(event, KOnStopPropagation)?.call(handler)\n return Reflect.apply(target, thisArg, args)\n },\n })\n\n Object.defineProperty(event, kStopPropagationPatched, {\n value: true,\n // If something else attempts to redefine this, throw.\n configurable: false,\n })\n }\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/core/handlers/WebSocketHandler.ts"],"sourcesContent":["import { Emitter } from 'strict-event-emitter'\nimport { createRequestId, resolveWebSocketUrl } from '@mswjs/interceptors'\nimport type {\n WebSocketClientConnectionProtocol,\n WebSocketConnectionData,\n WebSocketServerConnectionProtocol,\n} from '@mswjs/interceptors/WebSocket'\nimport {\n type Match,\n type Path,\n type PathParams,\n matchRequestUrl,\n} from '../utils/matching/matchRequestUrl'\nimport { getCallFrame } from '../utils/internal/getCallFrame'\nimport { attachWebSocketLogger } from '../ws/utils/attachWebSocketLogger'\n\ntype WebSocketHandlerParsedResult = {\n match: Match\n}\n\nexport type WebSocketHandlerEventMap = {\n connection: [args: WebSocketHandlerConnection]\n}\n\nexport interface WebSocketHandlerConnection {\n client: WebSocketClientConnectionProtocol\n server: WebSocketServerConnectionProtocol\n info: WebSocketConnectionData['info']\n params: PathParams\n}\n\nexport interface WebSocketResolutionContext {\n baseUrl?: string\n [kAutoConnect]?: boolean\n}\n\nexport const kEmitter = Symbol('kEmitter')\nexport const kSender = Symbol('kSender')\nexport const kConnect = Symbol('kConnect')\nexport const kAutoConnect = Symbol('kAutoConnect')\n\nconst kStopPropagationPatched = Symbol('kStopPropagationPatched')\nconst KOnStopPropagation = Symbol('KOnStopPropagation')\n\nexport class WebSocketHandler {\n public id: string\n public callFrame?: string\n public kind = 'websocket' as const\n\n protected [kEmitter]: Emitter<WebSocketHandlerEventMap>\n\n constructor(protected readonly url: Path) {\n this.id = createRequestId()\n\n this[kEmitter] = new Emitter()\n this.callFrame = getCallFrame(new Error())\n }\n\n public parse(args: {\n url: string | URL\n resolutionContext?: WebSocketResolutionContext\n }): WebSocketHandlerParsedResult {\n const clientUrl = new URL(args.url)\n\n // Resolve the WebSocket handler path:\n // - Plain string URLs resolved as per the specification (via Interceptors).\n // - String URLs starting with a wildcard are preserved (prepending a scheme there will break them).\n // - RegExp paths are preserved.\n const resolvedHandlerUrl =\n this.url instanceof RegExp || this.url.startsWith('*')\n ? this.url\n : this.#resolveWebSocketUrl(this.url, args.resolutionContext?.baseUrl)\n\n /**\n * @note Remove the Socket.IO path prefix from the WebSocket\n * client URL. This is an exception to keep the users from\n * including the implementation details in their handlers.\n */\n clientUrl.pathname = clientUrl.pathname.replace(/^\\/socket.io\\//, '/')\n\n const match = matchRequestUrl(\n clientUrl,\n resolvedHandlerUrl,\n args.resolutionContext?.baseUrl,\n )\n\n return {\n match,\n }\n }\n\n public predicate(args: {\n url: string | URL\n parsedResult: WebSocketHandlerParsedResult\n }): boolean {\n return args.parsedResult.match.matches\n }\n\n public test(\n url: string | URL,\n resolutionContext?: WebSocketResolutionContext & { strict?: boolean },\n ): boolean {\n return this.#match(url, resolutionContext) != null\n }\n\n public async run(\n connection: WebSocketConnectionData,\n resolutionContext?: WebSocketResolutionContext,\n ): Promise<WebSocketHandlerConnection | null> {\n const parsedResult = this.#match(connection.client.url, resolutionContext)\n\n if (parsedResult == null) {\n return null\n }\n\n const resolvedConnection: WebSocketHandlerConnection = {\n ...connection,\n params: parsedResult.match.params || {},\n }\n\n if (resolutionContext?.[kAutoConnect]) {\n if (this[kConnect](resolvedConnection)) {\n return resolvedConnection\n }\n\n return null\n }\n\n return resolvedConnection\n }\n\n #match(\n url: string | URL,\n resolutionContext?: WebSocketResolutionContext & { strict?: boolean },\n ): WebSocketHandlerParsedResult | null {\n const resolvedUrl = this.#resolveWebSocketUrl(\n url.toString(),\n resolutionContext?.baseUrl,\n )\n const parsedResult = this.parse({\n url: resolvedUrl,\n resolutionContext,\n })\n\n if (\n this.predicate({\n url,\n parsedResult,\n })\n ) {\n return parsedResult\n }\n\n return null\n }\n\n protected [kConnect](connection: WebSocketHandlerConnection): boolean {\n // Support `event.stopPropagation()` for various client/server events.\n connection.client.addEventListener(\n 'message',\n createStopPropagationListener(this),\n )\n connection.client.addEventListener(\n 'close',\n createStopPropagationListener(this),\n )\n\n connection.server.addEventListener(\n 'open',\n createStopPropagationListener(this),\n )\n connection.server.addEventListener(\n 'message',\n createStopPropagationListener(this),\n )\n connection.server.addEventListener(\n 'error',\n createStopPropagationListener(this),\n )\n connection.server.addEventListener(\n 'close',\n createStopPropagationListener(this),\n )\n\n /**\n * @fixme Use \"rettime\" and await these events to have\n * exceptions propagate properly.\n */\n return this[kEmitter].emit('connection', connection)\n }\n\n public log(connection: WebSocketConnectionData): () => void {\n return attachWebSocketLogger(connection)\n }\n\n #resolveWebSocketUrl(url: string, baseUrl?: string): string {\n const resolvedUrl = resolveWebSocketUrl(\n baseUrl\n ? /**\n * @note Resolve against the base URL preemtively because `resolveWebSocketUrl` only\n * resolves against `location.href`, which is missing in Node.js. Base URL allows\n * the handler to accept a relative URL in Node.js.\n */\n new URL(url, baseUrl)\n : url,\n )\n\n /**\n * @note Omit the trailing slash.\n * While the browser always produces a trailing slash at the end of a WebSocket URL,\n * having it in as the handler's predicate would mean it is *required* in the actual URL.\n */\n return resolvedUrl.replace(/\\/$/, '')\n }\n}\n\nfunction createStopPropagationListener(handler: WebSocketHandler) {\n return function stopPropagationListener(event: Event) {\n const propagationStoppedAt = Reflect.get(event, 'kPropagationStoppedAt') as\n | string\n | undefined\n\n if (propagationStoppedAt && handler.id !== propagationStoppedAt) {\n event.stopImmediatePropagation()\n return\n }\n\n Object.defineProperty(event, KOnStopPropagation, {\n value(this: WebSocketHandler) {\n Object.defineProperty(event, 'kPropagationStoppedAt', {\n value: handler.id,\n })\n },\n configurable: true,\n })\n\n // Since the same event instance is shared between all client/server objects,\n // make sure to patch its `stopPropagation` method only once.\n if (!Reflect.get(event, kStopPropagationPatched)) {\n event.stopPropagation = new Proxy(event.stopPropagation, {\n apply: (target, thisArg, args) => {\n Reflect.get(event, KOnStopPropagation)?.call(handler)\n return Reflect.apply(target, thisArg, args)\n },\n })\n\n Object.defineProperty(event, kStopPropagationPatched, {\n value: true,\n // If something else attempts to redefine this, throw.\n configurable: false,\n })\n }\n }\n}\n"],"mappings":"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","names":[]}
package/lib/iife/index.js CHANGED
@@ -16963,12 +16963,12 @@ ${operationTypes.join("\n")}
16963
16963
  predicate(args) {
16964
16964
  return args.parsedResult.match.matches;
16965
16965
  }
16966
+ test(url, resolutionContext) {
16967
+ return this.#match(url, resolutionContext) != null;
16968
+ }
16966
16969
  async run(connection, resolutionContext) {
16967
- const parsedResult = this.parse({
16968
- url: connection.client.url,
16969
- resolutionContext
16970
- });
16971
- if (!this.predicate({ url: connection.client.url, parsedResult })) {
16970
+ const parsedResult = this.#match(connection.client.url, resolutionContext);
16971
+ if (parsedResult == null) {
16972
16972
  return null;
16973
16973
  }
16974
16974
  const resolvedConnection = {
@@ -16983,6 +16983,23 @@ ${operationTypes.join("\n")}
16983
16983
  }
16984
16984
  return resolvedConnection;
16985
16985
  }
16986
+ #match(url, resolutionContext) {
16987
+ const resolvedUrl = this.#resolveWebSocketUrl(
16988
+ url.toString(),
16989
+ resolutionContext?.baseUrl
16990
+ );
16991
+ const parsedResult = this.parse({
16992
+ url: resolvedUrl,
16993
+ resolutionContext
16994
+ });
16995
+ if (this.predicate({
16996
+ url,
16997
+ parsedResult
16998
+ })) {
16999
+ return parsedResult;
17000
+ }
17001
+ return null;
17002
+ }
16986
17003
  [kConnect](connection) {
16987
17004
  connection.client.addEventListener(
16988
17005
  "message",