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.
- package/lib/core/handlers/WebSocketHandler.d.mts +5 -2
- package/lib/core/handlers/WebSocketHandler.d.ts +5 -2
- package/lib/core/handlers/WebSocketHandler.js +22 -5
- package/lib/core/handlers/WebSocketHandler.js.map +1 -1
- package/lib/core/handlers/WebSocketHandler.mjs +22 -5
- package/lib/core/handlers/WebSocketHandler.mjs.map +1 -1
- package/lib/iife/index.js +22 -5
- package/lib/iife/index.js.map +1 -1
- package/lib/mockServiceWorker.js +1 -1
- package/package.json +2 -2
- package/src/core/handlers/WebSocketHandler.test.ts +58 -0
- package/src/core/handlers/WebSocketHandler.ts +36 -7
|
@@ -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.
|
|
68
|
-
|
|
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.
|
|
43
|
-
|
|
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.
|
|
16968
|
-
|
|
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",
|