@depup/msw 2.13.2-depup.0 → 2.15.0-depup.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.
Files changed (282) hide show
  1. package/README.md +9 -12
  2. package/changes.json +14 -26
  3. package/cli/init.js +1 -1
  4. package/lib/browser/index.js +547 -177
  5. package/lib/browser/index.js.map +1 -1
  6. package/lib/browser/index.mjs +547 -177
  7. package/lib/browser/index.mjs.map +1 -1
  8. package/lib/core/{HttpResponse-DlRR1D-f.d.mts → HttpResponse-BE_Y2Ak9.d.mts} +52 -1
  9. package/lib/core/{HttpResponse-CksOMVAa.d.ts → HttpResponse-DL-P1EeG.d.ts} +52 -1
  10. package/lib/core/HttpResponse.d.mts +1 -1
  11. package/lib/core/HttpResponse.d.ts +1 -1
  12. package/lib/core/HttpResponse.js +2 -2
  13. package/lib/core/HttpResponse.js.map +1 -1
  14. package/lib/core/HttpResponse.mjs +2 -2
  15. package/lib/core/HttpResponse.mjs.map +1 -1
  16. package/lib/core/experimental/compat.d.mts +2 -2
  17. package/lib/core/experimental/compat.d.ts +2 -2
  18. package/lib/core/experimental/compat.js +1 -0
  19. package/lib/core/experimental/compat.js.map +1 -1
  20. package/lib/core/experimental/compat.mjs +1 -0
  21. package/lib/core/experimental/compat.mjs.map +1 -1
  22. package/lib/core/experimental/define-network.d.mts +2 -2
  23. package/lib/core/experimental/define-network.d.ts +2 -2
  24. package/lib/core/experimental/define-network.js +21 -11
  25. package/lib/core/experimental/define-network.js.map +1 -1
  26. package/lib/core/experimental/define-network.mjs +23 -11
  27. package/lib/core/experimental/define-network.mjs.map +1 -1
  28. package/lib/core/experimental/frames/http-frame.d.mts +2 -2
  29. package/lib/core/experimental/frames/http-frame.d.ts +2 -2
  30. package/lib/core/experimental/frames/http-frame.js +5 -2
  31. package/lib/core/experimental/frames/http-frame.js.map +1 -1
  32. package/lib/core/experimental/frames/http-frame.mjs +8 -3
  33. package/lib/core/experimental/frames/http-frame.mjs.map +1 -1
  34. package/lib/core/experimental/frames/network-frame.d.mts +2 -2
  35. package/lib/core/experimental/frames/network-frame.d.ts +2 -2
  36. package/lib/core/experimental/frames/network-frame.js +2 -0
  37. package/lib/core/experimental/frames/network-frame.js.map +1 -1
  38. package/lib/core/experimental/frames/network-frame.mjs +2 -0
  39. package/lib/core/experimental/frames/network-frame.mjs.map +1 -1
  40. package/lib/core/experimental/frames/websocket-frame.d.mts +2 -2
  41. package/lib/core/experimental/frames/websocket-frame.d.ts +2 -2
  42. package/lib/core/experimental/frames/websocket-frame.js +2 -0
  43. package/lib/core/experimental/frames/websocket-frame.js.map +1 -1
  44. package/lib/core/experimental/frames/websocket-frame.mjs +2 -0
  45. package/lib/core/experimental/frames/websocket-frame.mjs.map +1 -1
  46. package/lib/core/experimental/handlers-controller.d.mts +2 -1
  47. package/lib/core/experimental/handlers-controller.d.ts +2 -1
  48. package/lib/core/experimental/handlers-controller.js +31 -6
  49. package/lib/core/experimental/handlers-controller.js.map +1 -1
  50. package/lib/core/experimental/handlers-controller.mjs +31 -6
  51. package/lib/core/experimental/handlers-controller.mjs.map +1 -1
  52. package/lib/core/experimental/index.d.mts +5 -5
  53. package/lib/core/experimental/index.d.ts +5 -5
  54. package/lib/core/experimental/index.js +3 -1
  55. package/lib/core/experimental/index.js.map +1 -1
  56. package/lib/core/experimental/index.mjs +9 -2
  57. package/lib/core/experimental/index.mjs.map +1 -1
  58. package/lib/core/experimental/on-unhandled-frame.d.mts +2 -2
  59. package/lib/core/experimental/on-unhandled-frame.d.ts +2 -2
  60. package/lib/core/experimental/on-unhandled-frame.js +1 -0
  61. package/lib/core/experimental/on-unhandled-frame.js.map +1 -1
  62. package/lib/core/experimental/on-unhandled-frame.mjs +1 -0
  63. package/lib/core/experimental/on-unhandled-frame.mjs.map +1 -1
  64. package/lib/core/experimental/setup-api.d.mts +1 -1
  65. package/lib/core/experimental/setup-api.d.ts +1 -1
  66. package/lib/core/experimental/setup-api.js +2 -5
  67. package/lib/core/experimental/setup-api.js.map +1 -1
  68. package/lib/core/experimental/setup-api.mjs +2 -5
  69. package/lib/core/experimental/setup-api.mjs.map +1 -1
  70. package/lib/core/experimental/sources/interceptor-source.d.mts +2 -2
  71. package/lib/core/experimental/sources/interceptor-source.d.ts +2 -2
  72. package/lib/core/experimental/sources/interceptor-source.js +23 -10
  73. package/lib/core/experimental/sources/interceptor-source.js.map +1 -1
  74. package/lib/core/experimental/sources/interceptor-source.mjs +24 -13
  75. package/lib/core/experimental/sources/interceptor-source.mjs.map +1 -1
  76. package/lib/core/experimental/sources/network-source.d.mts +3 -3
  77. package/lib/core/experimental/sources/network-source.d.ts +3 -3
  78. package/lib/core/experimental/sources/network-source.js +1 -0
  79. package/lib/core/experimental/sources/network-source.js.map +1 -1
  80. package/lib/core/experimental/sources/network-source.mjs +2 -0
  81. package/lib/core/experimental/sources/network-source.mjs.map +1 -1
  82. package/lib/core/getResponse.d.mts +1 -1
  83. package/lib/core/getResponse.d.ts +1 -1
  84. package/lib/core/graphql.d.mts +1 -1
  85. package/lib/core/graphql.d.ts +1 -1
  86. package/lib/core/graphql.js +1 -0
  87. package/lib/core/graphql.js.map +1 -1
  88. package/lib/core/graphql.mjs +2 -0
  89. package/lib/core/graphql.mjs.map +1 -1
  90. package/lib/core/handlers/GraphQLHandler.d.mts +1 -1
  91. package/lib/core/handlers/GraphQLHandler.d.ts +1 -1
  92. package/lib/core/handlers/GraphQLHandler.js +1 -0
  93. package/lib/core/handlers/GraphQLHandler.js.map +1 -1
  94. package/lib/core/handlers/GraphQLHandler.mjs +4 -1
  95. package/lib/core/handlers/GraphQLHandler.mjs.map +1 -1
  96. package/lib/core/handlers/HttpHandler.d.mts +1 -1
  97. package/lib/core/handlers/HttpHandler.d.ts +1 -1
  98. package/lib/core/handlers/HttpHandler.js +1 -0
  99. package/lib/core/handlers/HttpHandler.js.map +1 -1
  100. package/lib/core/handlers/HttpHandler.mjs +1 -0
  101. package/lib/core/handlers/HttpHandler.mjs.map +1 -1
  102. package/lib/core/handlers/RequestHandler.d.mts +1 -1
  103. package/lib/core/handlers/RequestHandler.d.ts +1 -1
  104. package/lib/core/handlers/RequestHandler.js +197 -4
  105. package/lib/core/handlers/RequestHandler.js.map +1 -1
  106. package/lib/core/handlers/RequestHandler.mjs +198 -4
  107. package/lib/core/handlers/RequestHandler.mjs.map +1 -1
  108. package/lib/core/handlers/WebSocketHandler.d.mts +5 -2
  109. package/lib/core/handlers/WebSocketHandler.d.ts +5 -2
  110. package/lib/core/handlers/WebSocketHandler.js +30 -12
  111. package/lib/core/handlers/WebSocketHandler.js.map +1 -1
  112. package/lib/core/handlers/WebSocketHandler.mjs +30 -12
  113. package/lib/core/handlers/WebSocketHandler.mjs.map +1 -1
  114. package/lib/core/http.d.mts +1 -1
  115. package/lib/core/http.d.ts +1 -1
  116. package/lib/core/http.js +1 -0
  117. package/lib/core/http.js.map +1 -1
  118. package/lib/core/http.mjs +2 -0
  119. package/lib/core/http.mjs.map +1 -1
  120. package/lib/core/index.d.mts +1 -1
  121. package/lib/core/index.d.ts +1 -1
  122. package/lib/core/{network-frame-usYiHS0K.d.ts → on-unhandled-frame-0KmwUmeV.d.ts} +13 -13
  123. package/lib/core/{network-frame-B7A0ggXE.d.mts → on-unhandled-frame-gkokW4Rr.d.mts} +13 -13
  124. package/lib/core/passthrough.d.mts +1 -1
  125. package/lib/core/passthrough.d.ts +1 -1
  126. package/lib/core/sse.d.mts +4 -18
  127. package/lib/core/sse.d.ts +4 -18
  128. package/lib/core/sse.js +149 -66
  129. package/lib/core/sse.js.map +1 -1
  130. package/lib/core/sse.mjs +149 -66
  131. package/lib/core/sse.mjs.map +1 -1
  132. package/lib/core/utils/HttpResponse/decorators.d.mts +9 -4
  133. package/lib/core/utils/HttpResponse/decorators.d.ts +9 -4
  134. package/lib/core/utils/HttpResponse/decorators.js +18 -11
  135. package/lib/core/utils/HttpResponse/decorators.js.map +1 -1
  136. package/lib/core/utils/HttpResponse/decorators.mjs +18 -11
  137. package/lib/core/utils/HttpResponse/decorators.mjs.map +1 -1
  138. package/lib/core/utils/cookieStore.js.map +1 -1
  139. package/lib/core/utils/cookieStore.mjs.map +1 -1
  140. package/lib/core/utils/executeHandlers.d.mts +1 -1
  141. package/lib/core/utils/executeHandlers.d.ts +1 -1
  142. package/lib/core/utils/executeHandlers.js +1 -0
  143. package/lib/core/utils/executeHandlers.js.map +1 -1
  144. package/lib/core/utils/executeHandlers.mjs +1 -0
  145. package/lib/core/utils/executeHandlers.mjs.map +1 -1
  146. package/lib/core/utils/handleRequest.d.mts +1 -1
  147. package/lib/core/utils/handleRequest.d.ts +1 -1
  148. package/lib/core/utils/handleRequest.js.map +1 -1
  149. package/lib/core/utils/handleRequest.mjs.map +1 -1
  150. package/lib/core/utils/internal/Disposable.js +19 -1
  151. package/lib/core/utils/internal/Disposable.js.map +1 -1
  152. package/lib/core/utils/internal/Disposable.mjs +19 -1
  153. package/lib/core/utils/internal/Disposable.mjs.map +1 -1
  154. package/lib/core/utils/internal/attachSiblingHandlers.d.mts +15 -0
  155. package/lib/core/utils/internal/attachSiblingHandlers.d.ts +15 -0
  156. package/lib/core/utils/internal/attachSiblingHandlers.js +44 -0
  157. package/lib/core/utils/internal/attachSiblingHandlers.js.map +1 -0
  158. package/lib/core/utils/internal/attachSiblingHandlers.mjs +24 -0
  159. package/lib/core/utils/internal/attachSiblingHandlers.mjs.map +1 -0
  160. package/lib/core/utils/internal/isHandlerKind.d.mts +1 -1
  161. package/lib/core/utils/internal/isHandlerKind.d.ts +1 -1
  162. package/lib/core/utils/internal/observe-response-body-stream.d.mts +18 -0
  163. package/lib/core/utils/internal/observe-response-body-stream.d.ts +18 -0
  164. package/lib/core/utils/internal/observe-response-body-stream.js +64 -0
  165. package/lib/core/utils/internal/observe-response-body-stream.js.map +1 -0
  166. package/lib/core/utils/internal/observe-response-body-stream.mjs +44 -0
  167. package/lib/core/utils/internal/observe-response-body-stream.mjs.map +1 -0
  168. package/lib/core/utils/internal/parseGraphQLRequest.d.mts +1 -1
  169. package/lib/core/utils/internal/parseGraphQLRequest.d.ts +1 -1
  170. package/lib/core/utils/internal/parseMultipartData.d.mts +1 -1
  171. package/lib/core/utils/internal/parseMultipartData.d.ts +1 -1
  172. package/lib/core/utils/internal/parseMultipartData.js +1 -0
  173. package/lib/core/utils/internal/parseMultipartData.js.map +1 -1
  174. package/lib/core/utils/internal/parseMultipartData.mjs +1 -0
  175. package/lib/core/utils/internal/parseMultipartData.mjs.map +1 -1
  176. package/lib/core/utils/internal/pipeEvents.js +1 -0
  177. package/lib/core/utils/internal/pipeEvents.js.map +1 -1
  178. package/lib/core/utils/internal/pipeEvents.mjs +1 -0
  179. package/lib/core/utils/internal/pipeEvents.mjs.map +1 -1
  180. package/lib/core/utils/request/storeResponseCookies.js +1 -1
  181. package/lib/core/utils/request/storeResponseCookies.js.map +1 -1
  182. package/lib/core/utils/request/storeResponseCookies.mjs +2 -2
  183. package/lib/core/utils/request/storeResponseCookies.mjs.map +1 -1
  184. package/lib/core/ws/WebSocketClientManager.js +4 -0
  185. package/lib/core/ws/WebSocketClientManager.js.map +1 -1
  186. package/lib/core/ws/WebSocketClientManager.mjs +4 -0
  187. package/lib/core/ws/WebSocketClientManager.mjs.map +1 -1
  188. package/lib/core/ws/WebSocketIndexedDBClientStore.js +1 -0
  189. package/lib/core/ws/WebSocketIndexedDBClientStore.js.map +1 -1
  190. package/lib/core/ws/WebSocketIndexedDBClientStore.mjs +1 -0
  191. package/lib/core/ws/WebSocketIndexedDBClientStore.mjs.map +1 -1
  192. package/lib/core/ws/WebSocketMemoryClientStore.js +1 -0
  193. package/lib/core/ws/WebSocketMemoryClientStore.js.map +1 -1
  194. package/lib/core/ws/WebSocketMemoryClientStore.mjs +1 -0
  195. package/lib/core/ws/WebSocketMemoryClientStore.mjs.map +1 -1
  196. package/lib/core/ws/handleWebSocketEvent.d.mts +1 -1
  197. package/lib/core/ws/handleWebSocketEvent.d.ts +1 -1
  198. package/lib/core/ws/handleWebSocketEvent.js.map +1 -1
  199. package/lib/core/ws/handleWebSocketEvent.mjs.map +1 -1
  200. package/lib/core/ws.d.mts +17 -4
  201. package/lib/core/ws.d.ts +17 -4
  202. package/lib/core/ws.js +30 -5
  203. package/lib/core/ws.js.map +1 -1
  204. package/lib/core/ws.mjs +34 -6
  205. package/lib/core/ws.mjs.map +1 -1
  206. package/lib/iife/index.js +10138 -6034
  207. package/lib/iife/index.js.map +1 -1
  208. package/lib/mockServiceWorker.js +21 -9
  209. package/lib/native/index.js.map +1 -1
  210. package/lib/native/index.mjs.map +1 -1
  211. package/lib/node/index.d.mts +1 -1
  212. package/lib/node/index.d.ts +1 -1
  213. package/lib/node/index.js +2 -0
  214. package/lib/node/index.js.map +1 -1
  215. package/lib/node/index.mjs +1 -0
  216. package/lib/node/index.mjs.map +1 -1
  217. package/lib/shims/cookie.js +152 -62
  218. package/lib/shims/cookie.mjs +152 -62
  219. package/package.json +50 -69
  220. package/src/browser/glossary.ts +1 -1
  221. package/src/browser/setup-worker.ts +2 -2
  222. package/src/browser/sources/service-worker-source.ts +142 -40
  223. package/src/browser/utils/deserializeRequest.ts +2 -2
  224. package/src/browser/utils/pruneGetRequestBody.ts +3 -3
  225. package/src/browser/utils/should-invalidate-worker.test.ts +122 -0
  226. package/src/browser/utils/should-invalidate-worker.ts +13 -0
  227. package/src/browser/utils/workerChannel.ts +43 -21
  228. package/src/core/experimental/define-network.ts +44 -15
  229. package/src/core/experimental/frames/http-frame.test.ts +8 -2
  230. package/src/core/experimental/frames/http-frame.ts +12 -4
  231. package/src/core/experimental/frames/websocket-frame.test.ts +2 -4
  232. package/src/core/experimental/frames/websocket-frame.ts +3 -2
  233. package/src/core/experimental/handlers-controller.test.ts +139 -5
  234. package/src/core/experimental/handlers-controller.ts +39 -10
  235. package/src/core/experimental/index.ts +11 -1
  236. package/src/core/experimental/on-unhandled-frame.test.ts +2 -4
  237. package/src/core/experimental/setup-api.ts +4 -8
  238. package/src/core/experimental/sources/interceptor-source.ts +36 -16
  239. package/src/core/experimental/sources/network-source.ts +1 -1
  240. package/src/core/graphql.ts +8 -8
  241. package/src/core/handlers/GraphQLHandler.test.ts +3 -4
  242. package/src/core/handlers/GraphQLHandler.ts +15 -11
  243. package/src/core/handlers/HttpHandler.test.ts +92 -2
  244. package/src/core/handlers/HttpHandler.ts +7 -7
  245. package/src/core/handlers/RequestHandler.ts +329 -22
  246. package/src/core/handlers/WebSocketHandler.test.ts +58 -0
  247. package/src/core/handlers/WebSocketHandler.ts +37 -8
  248. package/src/core/http.ts +5 -5
  249. package/src/core/sse.ts +217 -73
  250. package/src/core/utils/HttpResponse/decorators.ts +28 -22
  251. package/src/core/utils/cookieStore.ts +1 -1
  252. package/src/core/utils/executeHandlers.ts +2 -4
  253. package/src/core/utils/handleRequest.test.ts +5 -4
  254. package/src/core/utils/handleRequest.ts +3 -3
  255. package/src/core/utils/internal/Disposable.ts +22 -1
  256. package/src/core/utils/internal/attachSiblingHandlers.ts +28 -0
  257. package/src/core/utils/internal/observe-response-body-stream.test.ts +64 -0
  258. package/src/core/utils/internal/observe-response-body-stream.ts +77 -0
  259. package/src/core/utils/internal/parseGraphQLRequest.test.ts +2 -4
  260. package/src/core/utils/internal/parseMultipartData.ts +1 -1
  261. package/src/core/utils/internal/pipeEvents.ts +2 -1
  262. package/src/core/utils/request/onUnhandledRequest.test.ts +2 -4
  263. package/src/core/utils/request/storeResponseCookies.ts +2 -4
  264. package/src/core/ws/WebSocketClientManager.test.ts +2 -4
  265. package/src/core/ws/WebSocketClientManager.ts +1 -1
  266. package/src/core/ws/WebSocketIndexedDBClientStore.ts +3 -5
  267. package/src/core/ws/WebSocketMemoryClientStore.ts +3 -5
  268. package/src/core/ws/handleWebSocketEvent.ts +3 -3
  269. package/src/core/ws.ts +66 -7
  270. package/src/mockServiceWorker.js +19 -7
  271. package/src/native/index.ts +2 -2
  272. package/src/node/async-handlers-controller.ts +2 -2
  273. package/src/node/index.ts +1 -0
  274. package/src/node/setup-server-common.ts +4 -4
  275. package/src/node/setup-server.ts +2 -2
  276. package/lib/core/utils/internal/requestHandlerUtils.d.mts +0 -12
  277. package/lib/core/utils/internal/requestHandlerUtils.d.ts +0 -12
  278. package/lib/core/utils/internal/requestHandlerUtils.js +0 -37
  279. package/lib/core/utils/internal/requestHandlerUtils.js.map +0 -1
  280. package/lib/core/utils/internal/requestHandlerUtils.mjs +0 -17
  281. package/lib/core/utils/internal/requestHandlerUtils.mjs.map +0 -1
  282. package/src/core/utils/internal/requestHandlerUtils.ts +0 -21
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/core/ws/handleWebSocketEvent.ts"],"sourcesContent":["import type { WebSocketConnectionData } from '@mswjs/interceptors/WebSocket'\nimport { RequestHandler } from '../handlers/RequestHandler'\nimport { WebSocketHandler } from '../handlers/WebSocketHandler'\nimport { webSocketInterceptor } from './webSocketInterceptor'\nimport {\n onUnhandledRequest,\n UnhandledRequestStrategy,\n} from '../utils/request/onUnhandledRequest'\nimport { isHandlerKind } from '../utils/internal/isHandlerKind'\n\ninterface HandleWebSocketEventOptions {\n getUnhandledRequestStrategy: () => UnhandledRequestStrategy\n getHandlers: () => Array<RequestHandler | WebSocketHandler>\n onMockedConnection: (connection: WebSocketConnectionData) => void\n onPassthroughConnection: (onnection: WebSocketConnectionData) => void\n}\n\nexport function handleWebSocketEvent(options: HandleWebSocketEventOptions) {\n webSocketInterceptor.on('connection', async (connection) => {\n /**\n * @todo @fixme Reference the handlers controller here and use `.getHandlersByKind`.\n * That one relies on the pre-grouped handlers map and will be more performant.\n */\n const handlers = options.getHandlers().filter(isHandlerKind('websocket'))\n\n // Ignore this connection if the user hasn't defined any handlers.\n if (handlers.length > 0) {\n options?.onMockedConnection(connection)\n\n await Promise.all(\n handlers.map((handler) => {\n // Iterate over the handlers and forward the connection\n // event to WebSocket event handlers. This is equivalent\n // to dispatching that event onto multiple listeners.\n return handler.run(connection)\n }),\n )\n\n return\n }\n\n // Construct a request representing this WebSocket connection.\n const request = new Request(connection.client.url, {\n headers: {\n upgrade: 'websocket',\n connection: 'upgrade',\n },\n })\n await onUnhandledRequest(\n request,\n options.getUnhandledRequestStrategy(),\n ).catch((error) => {\n const errorEvent = new Event('error')\n Object.defineProperty(errorEvent, 'cause', {\n enumerable: true,\n configurable: false,\n value: error,\n })\n connection.client.socket.dispatchEvent(errorEvent)\n })\n\n options?.onPassthroughConnection(connection)\n\n // If none of the \"ws\" handlers matched,\n // establish the WebSocket connection as-is.\n connection.server.connect()\n })\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,kCAAqC;AACrC,gCAGO;AACP,2BAA8B;AASvB,SAAS,qBAAqB,SAAsC;AACzE,mDAAqB,GAAG,cAAc,OAAO,eAAe;AAK1D,UAAM,WAAW,QAAQ,YAAY,EAAE,WAAO,oCAAc,WAAW,CAAC;AAGxE,QAAI,SAAS,SAAS,GAAG;AACvB,eAAS,mBAAmB,UAAU;AAEtC,YAAM,QAAQ;AAAA,QACZ,SAAS,IAAI,CAAC,YAAY;AAIxB,iBAAO,QAAQ,IAAI,UAAU;AAAA,QAC/B,CAAC;AAAA,MACH;AAEA;AAAA,IACF;AAGA,UAAM,UAAU,IAAI,QAAQ,WAAW,OAAO,KAAK;AAAA,MACjD,SAAS;AAAA,QACP,SAAS;AAAA,QACT,YAAY;AAAA,MACd;AAAA,IACF,CAAC;AACD,cAAM;AAAA,MACJ;AAAA,MACA,QAAQ,4BAA4B;AAAA,IACtC,EAAE,MAAM,CAAC,UAAU;AACjB,YAAM,aAAa,IAAI,MAAM,OAAO;AACpC,aAAO,eAAe,YAAY,SAAS;AAAA,QACzC,YAAY;AAAA,QACZ,cAAc;AAAA,QACd,OAAO;AAAA,MACT,CAAC;AACD,iBAAW,OAAO,OAAO,cAAc,UAAU;AAAA,IACnD,CAAC;AAED,aAAS,wBAAwB,UAAU;AAI3C,eAAW,OAAO,QAAQ;AAAA,EAC5B,CAAC;AACH;","names":[]}
1
+ {"version":3,"sources":["../../../src/core/ws/handleWebSocketEvent.ts"],"sourcesContent":["import type { WebSocketConnectionData } from '@mswjs/interceptors/WebSocket'\nimport type { RequestHandler } from '../handlers/RequestHandler'\nimport type { WebSocketHandler } from '../handlers/WebSocketHandler'\nimport { webSocketInterceptor } from './webSocketInterceptor'\nimport {\n onUnhandledRequest,\n type UnhandledRequestStrategy,\n} from '../utils/request/onUnhandledRequest'\nimport { isHandlerKind } from '../utils/internal/isHandlerKind'\n\ninterface HandleWebSocketEventOptions {\n getUnhandledRequestStrategy: () => UnhandledRequestStrategy\n getHandlers: () => Array<RequestHandler | WebSocketHandler>\n onMockedConnection: (connection: WebSocketConnectionData) => void\n onPassthroughConnection: (onnection: WebSocketConnectionData) => void\n}\n\nexport function handleWebSocketEvent(options: HandleWebSocketEventOptions) {\n webSocketInterceptor.on('connection', async (connection) => {\n /**\n * @todo @fixme Reference the handlers controller here and use `.getHandlersByKind`.\n * That one relies on the pre-grouped handlers map and will be more performant.\n */\n const handlers = options.getHandlers().filter(isHandlerKind('websocket'))\n\n // Ignore this connection if the user hasn't defined any handlers.\n if (handlers.length > 0) {\n options?.onMockedConnection(connection)\n\n await Promise.all(\n handlers.map((handler) => {\n // Iterate over the handlers and forward the connection\n // event to WebSocket event handlers. This is equivalent\n // to dispatching that event onto multiple listeners.\n return handler.run(connection)\n }),\n )\n\n return\n }\n\n // Construct a request representing this WebSocket connection.\n const request = new Request(connection.client.url, {\n headers: {\n upgrade: 'websocket',\n connection: 'upgrade',\n },\n })\n await onUnhandledRequest(\n request,\n options.getUnhandledRequestStrategy(),\n ).catch((error) => {\n const errorEvent = new Event('error')\n Object.defineProperty(errorEvent, 'cause', {\n enumerable: true,\n configurable: false,\n value: error,\n })\n connection.client.socket.dispatchEvent(errorEvent)\n })\n\n options?.onPassthroughConnection(connection)\n\n // If none of the \"ws\" handlers matched,\n // establish the WebSocket connection as-is.\n connection.server.connect()\n })\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,kCAAqC;AACrC,gCAGO;AACP,2BAA8B;AASvB,SAAS,qBAAqB,SAAsC;AACzE,mDAAqB,GAAG,cAAc,OAAO,eAAe;AAK1D,UAAM,WAAW,QAAQ,YAAY,EAAE,WAAO,oCAAc,WAAW,CAAC;AAGxE,QAAI,SAAS,SAAS,GAAG;AACvB,eAAS,mBAAmB,UAAU;AAEtC,YAAM,QAAQ;AAAA,QACZ,SAAS,IAAI,CAAC,YAAY;AAIxB,iBAAO,QAAQ,IAAI,UAAU;AAAA,QAC/B,CAAC;AAAA,MACH;AAEA;AAAA,IACF;AAGA,UAAM,UAAU,IAAI,QAAQ,WAAW,OAAO,KAAK;AAAA,MACjD,SAAS;AAAA,QACP,SAAS;AAAA,QACT,YAAY;AAAA,MACd;AAAA,IACF,CAAC;AACD,cAAM;AAAA,MACJ;AAAA,MACA,QAAQ,4BAA4B;AAAA,IACtC,EAAE,MAAM,CAAC,UAAU;AACjB,YAAM,aAAa,IAAI,MAAM,OAAO;AACpC,aAAO,eAAe,YAAY,SAAS;AAAA,QACzC,YAAY;AAAA,QACZ,cAAc;AAAA,QACd,OAAO;AAAA,MACT,CAAC;AACD,iBAAW,OAAO,OAAO,cAAc,UAAU;AAAA,IACnD,CAAC;AAED,aAAS,wBAAwB,UAAU;AAI3C,eAAW,OAAO,QAAQ;AAAA,EAC5B,CAAC;AACH;","names":[]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/core/ws/handleWebSocketEvent.ts"],"sourcesContent":["import type { WebSocketConnectionData } from '@mswjs/interceptors/WebSocket'\nimport { RequestHandler } from '../handlers/RequestHandler'\nimport { WebSocketHandler } from '../handlers/WebSocketHandler'\nimport { webSocketInterceptor } from './webSocketInterceptor'\nimport {\n onUnhandledRequest,\n UnhandledRequestStrategy,\n} from '../utils/request/onUnhandledRequest'\nimport { isHandlerKind } from '../utils/internal/isHandlerKind'\n\ninterface HandleWebSocketEventOptions {\n getUnhandledRequestStrategy: () => UnhandledRequestStrategy\n getHandlers: () => Array<RequestHandler | WebSocketHandler>\n onMockedConnection: (connection: WebSocketConnectionData) => void\n onPassthroughConnection: (onnection: WebSocketConnectionData) => void\n}\n\nexport function handleWebSocketEvent(options: HandleWebSocketEventOptions) {\n webSocketInterceptor.on('connection', async (connection) => {\n /**\n * @todo @fixme Reference the handlers controller here and use `.getHandlersByKind`.\n * That one relies on the pre-grouped handlers map and will be more performant.\n */\n const handlers = options.getHandlers().filter(isHandlerKind('websocket'))\n\n // Ignore this connection if the user hasn't defined any handlers.\n if (handlers.length > 0) {\n options?.onMockedConnection(connection)\n\n await Promise.all(\n handlers.map((handler) => {\n // Iterate over the handlers and forward the connection\n // event to WebSocket event handlers. This is equivalent\n // to dispatching that event onto multiple listeners.\n return handler.run(connection)\n }),\n )\n\n return\n }\n\n // Construct a request representing this WebSocket connection.\n const request = new Request(connection.client.url, {\n headers: {\n upgrade: 'websocket',\n connection: 'upgrade',\n },\n })\n await onUnhandledRequest(\n request,\n options.getUnhandledRequestStrategy(),\n ).catch((error) => {\n const errorEvent = new Event('error')\n Object.defineProperty(errorEvent, 'cause', {\n enumerable: true,\n configurable: false,\n value: error,\n })\n connection.client.socket.dispatchEvent(errorEvent)\n })\n\n options?.onPassthroughConnection(connection)\n\n // If none of the \"ws\" handlers matched,\n // establish the WebSocket connection as-is.\n connection.server.connect()\n })\n}\n"],"mappings":"AAGA,SAAS,4BAA4B;AACrC;AAAA,EACE;AAAA,OAEK;AACP,SAAS,qBAAqB;AASvB,SAAS,qBAAqB,SAAsC;AACzE,uBAAqB,GAAG,cAAc,OAAO,eAAe;AAK1D,UAAM,WAAW,QAAQ,YAAY,EAAE,OAAO,cAAc,WAAW,CAAC;AAGxE,QAAI,SAAS,SAAS,GAAG;AACvB,eAAS,mBAAmB,UAAU;AAEtC,YAAM,QAAQ;AAAA,QACZ,SAAS,IAAI,CAAC,YAAY;AAIxB,iBAAO,QAAQ,IAAI,UAAU;AAAA,QAC/B,CAAC;AAAA,MACH;AAEA;AAAA,IACF;AAGA,UAAM,UAAU,IAAI,QAAQ,WAAW,OAAO,KAAK;AAAA,MACjD,SAAS;AAAA,QACP,SAAS;AAAA,QACT,YAAY;AAAA,MACd;AAAA,IACF,CAAC;AACD,UAAM;AAAA,MACJ;AAAA,MACA,QAAQ,4BAA4B;AAAA,IACtC,EAAE,MAAM,CAAC,UAAU;AACjB,YAAM,aAAa,IAAI,MAAM,OAAO;AACpC,aAAO,eAAe,YAAY,SAAS;AAAA,QACzC,YAAY;AAAA,QACZ,cAAc;AAAA,QACd,OAAO;AAAA,MACT,CAAC;AACD,iBAAW,OAAO,OAAO,cAAc,UAAU;AAAA,IACnD,CAAC;AAED,aAAS,wBAAwB,UAAU;AAI3C,eAAW,OAAO,QAAQ;AAAA,EAC5B,CAAC;AACH;","names":[]}
1
+ {"version":3,"sources":["../../../src/core/ws/handleWebSocketEvent.ts"],"sourcesContent":["import type { WebSocketConnectionData } from '@mswjs/interceptors/WebSocket'\nimport type { RequestHandler } from '../handlers/RequestHandler'\nimport type { WebSocketHandler } from '../handlers/WebSocketHandler'\nimport { webSocketInterceptor } from './webSocketInterceptor'\nimport {\n onUnhandledRequest,\n type UnhandledRequestStrategy,\n} from '../utils/request/onUnhandledRequest'\nimport { isHandlerKind } from '../utils/internal/isHandlerKind'\n\ninterface HandleWebSocketEventOptions {\n getUnhandledRequestStrategy: () => UnhandledRequestStrategy\n getHandlers: () => Array<RequestHandler | WebSocketHandler>\n onMockedConnection: (connection: WebSocketConnectionData) => void\n onPassthroughConnection: (onnection: WebSocketConnectionData) => void\n}\n\nexport function handleWebSocketEvent(options: HandleWebSocketEventOptions) {\n webSocketInterceptor.on('connection', async (connection) => {\n /**\n * @todo @fixme Reference the handlers controller here and use `.getHandlersByKind`.\n * That one relies on the pre-grouped handlers map and will be more performant.\n */\n const handlers = options.getHandlers().filter(isHandlerKind('websocket'))\n\n // Ignore this connection if the user hasn't defined any handlers.\n if (handlers.length > 0) {\n options?.onMockedConnection(connection)\n\n await Promise.all(\n handlers.map((handler) => {\n // Iterate over the handlers and forward the connection\n // event to WebSocket event handlers. This is equivalent\n // to dispatching that event onto multiple listeners.\n return handler.run(connection)\n }),\n )\n\n return\n }\n\n // Construct a request representing this WebSocket connection.\n const request = new Request(connection.client.url, {\n headers: {\n upgrade: 'websocket',\n connection: 'upgrade',\n },\n })\n await onUnhandledRequest(\n request,\n options.getUnhandledRequestStrategy(),\n ).catch((error) => {\n const errorEvent = new Event('error')\n Object.defineProperty(errorEvent, 'cause', {\n enumerable: true,\n configurable: false,\n value: error,\n })\n connection.client.socket.dispatchEvent(errorEvent)\n })\n\n options?.onPassthroughConnection(connection)\n\n // If none of the \"ws\" handlers matched,\n // establish the WebSocket connection as-is.\n connection.server.connect()\n })\n}\n"],"mappings":"AAGA,SAAS,4BAA4B;AACrC;AAAA,EACE;AAAA,OAEK;AACP,SAAS,qBAAqB;AASvB,SAAS,qBAAqB,SAAsC;AACzE,uBAAqB,GAAG,cAAc,OAAO,eAAe;AAK1D,UAAM,WAAW,QAAQ,YAAY,EAAE,OAAO,cAAc,WAAW,CAAC;AAGxE,QAAI,SAAS,SAAS,GAAG;AACvB,eAAS,mBAAmB,UAAU;AAEtC,YAAM,QAAQ;AAAA,QACZ,SAAS,IAAI,CAAC,YAAY;AAIxB,iBAAO,QAAQ,IAAI,UAAU;AAAA,QAC/B,CAAC;AAAA,MACH;AAEA;AAAA,IACF;AAGA,UAAM,UAAU,IAAI,QAAQ,WAAW,OAAO,KAAK;AAAA,MACjD,SAAS;AAAA,QACP,SAAS;AAAA,QACT,YAAY;AAAA,MACd;AAAA,IACF,CAAC;AACD,UAAM;AAAA,MACJ;AAAA,MACA,QAAQ,4BAA4B;AAAA,IACtC,EAAE,MAAM,CAAC,UAAU;AACjB,YAAM,aAAa,IAAI,MAAM,OAAO;AACpC,aAAO,eAAe,YAAY,SAAS;AAAA,QACzC,YAAY;AAAA,QACZ,cAAc;AAAA,QACd,OAAO;AAAA,MACT,CAAC;AACD,iBAAW,OAAO,OAAO,cAAc,UAAU;AAAA,IACnD,CAAC;AAED,aAAS,wBAAwB,UAAU;AAI3C,eAAW,OAAO,QAAQ;AAAA,EAC5B,CAAC;AACH;","names":[]}
package/lib/core/ws.d.mts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { WebSocketClientConnectionProtocol, WebSocketData } from '@mswjs/interceptors/WebSocket';
2
2
  export { WebSocketData } from '@mswjs/interceptors/WebSocket';
3
3
  import { WebSocketHandlerEventMap, WebSocketHandler } from './handlers/WebSocketHandler.mjs';
4
- import { Path } from './utils/matching/matchRequestUrl.mjs';
4
+ import { Path, PathParams } from './utils/matching/matchRequestUrl.mjs';
5
5
  import 'strict-event-emitter';
6
6
 
7
7
  type WebSocketEventListener<EventType extends keyof WebSocketHandlerEventMap> = (...args: WebSocketHandlerEventMap[EventType]) => void;
@@ -59,6 +59,21 @@ type WebSocketLink = {
59
59
  * })
60
60
  */
61
61
  declare function createWebSocketLinkHandler(url: Path): WebSocketLink;
62
+ interface WebSocketNamespace {
63
+ link: typeof createWebSocketLinkHandler;
64
+ /**
65
+ * Request handler for the `upgrade` requests to the WebSocket protocol.
66
+ * This requires a WebSocket handler to be present to fire.
67
+ * @note This only affects Node.js as the `upgrade` request header is
68
+ * forbidden and cannot be read in the browser. Consider using the
69
+ * `WebSocket` API for establishing WebSocket connections in the browser.
70
+ */
71
+ onUpgrade: (info: {
72
+ requestId: string;
73
+ request: Request;
74
+ params: PathParams;
75
+ }) => Promise<Response | undefined> | Response | undefined;
76
+ }
62
77
  /**
63
78
  * A namespace to intercept and mock WebSocket connections.
64
79
  *
@@ -68,8 +83,6 @@ declare function createWebSocketLinkHandler(url: Path): WebSocketLink;
68
83
  * @see {@link https://mswjs.io/docs/api/ws `ws` API reference}
69
84
  * @see {@link https://mswjs.io/docs/basics/handling-websocket-events Handling WebSocket events}
70
85
  */
71
- declare const ws: {
72
- link: typeof createWebSocketLinkHandler;
73
- };
86
+ declare const ws: WebSocketNamespace;
74
87
 
75
88
  export { type WebSocketEventListener, type WebSocketLink, ws };
package/lib/core/ws.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { WebSocketClientConnectionProtocol, WebSocketData } from '@mswjs/interceptors/WebSocket';
2
2
  export { WebSocketData } from '@mswjs/interceptors/WebSocket';
3
3
  import { WebSocketHandlerEventMap, WebSocketHandler } from './handlers/WebSocketHandler.js';
4
- import { Path } from './utils/matching/matchRequestUrl.js';
4
+ import { Path, PathParams } from './utils/matching/matchRequestUrl.js';
5
5
  import 'strict-event-emitter';
6
6
 
7
7
  type WebSocketEventListener<EventType extends keyof WebSocketHandlerEventMap> = (...args: WebSocketHandlerEventMap[EventType]) => void;
@@ -59,6 +59,21 @@ type WebSocketLink = {
59
59
  * })
60
60
  */
61
61
  declare function createWebSocketLinkHandler(url: Path): WebSocketLink;
62
+ interface WebSocketNamespace {
63
+ link: typeof createWebSocketLinkHandler;
64
+ /**
65
+ * Request handler for the `upgrade` requests to the WebSocket protocol.
66
+ * This requires a WebSocket handler to be present to fire.
67
+ * @note This only affects Node.js as the `upgrade` request header is
68
+ * forbidden and cannot be read in the browser. Consider using the
69
+ * `WebSocket` API for establishing WebSocket connections in the browser.
70
+ */
71
+ onUpgrade: (info: {
72
+ requestId: string;
73
+ request: Request;
74
+ params: PathParams;
75
+ }) => Promise<Response | undefined> | Response | undefined;
76
+ }
62
77
  /**
63
78
  * A namespace to intercept and mock WebSocket connections.
64
79
  *
@@ -68,8 +83,6 @@ declare function createWebSocketLinkHandler(url: Path): WebSocketLink;
68
83
  * @see {@link https://mswjs.io/docs/api/ws `ws` API reference}
69
84
  * @see {@link https://mswjs.io/docs/basics/handling-websocket-events Handling WebSocket events}
70
85
  */
71
- declare const ws: {
72
- link: typeof createWebSocketLinkHandler;
73
- };
86
+ declare const ws: WebSocketNamespace;
74
87
 
75
88
  export { type WebSocketEventListener, type WebSocketLink, ws };
package/lib/core/ws.js CHANGED
@@ -22,10 +22,13 @@ __export(ws_exports, {
22
22
  });
23
23
  module.exports = __toCommonJS(ws_exports);
24
24
  var import_outvariant = require("outvariant");
25
+ var import_interceptors = require("@mswjs/interceptors");
25
26
  var import_WebSocketHandler = require("./handlers/WebSocketHandler");
26
27
  var import_hasRefCounted = require("./utils/internal/hasRefCounted");
27
28
  var import_matchRequestUrl = require("./utils/matching/matchRequestUrl");
28
29
  var import_WebSocketClientManager = require("./ws/WebSocketClientManager");
30
+ var import_http = require("./http");
31
+ var import_attachSiblingHandlers = require("./utils/internal/attachSiblingHandlers");
29
32
  const webSocketChannel = new BroadcastChannel("msw:websocket-client-manager");
30
33
  if ((0, import_hasRefCounted.hasRefCounted)(webSocketChannel)) {
31
34
  webSocketChannel.unref();
@@ -38,17 +41,20 @@ function createWebSocketLinkHandler(url) {
38
41
  typeof url
39
42
  );
40
43
  const clientManager = new import_WebSocketClientManager.WebSocketClientManager(webSocketChannel);
44
+ const upgradeHandler = import_http.http.get(({ request }) => {
45
+ return request.headers.get("upgrade")?.toLowerCase() === "websocket" && (0, import_matchRequestUrl.matchRequestUrl)(new URL((0, import_interceptors.resolveWebSocketUrl)(request.url)), url).matches;
46
+ }, ws.onUpgrade);
41
47
  return {
42
48
  get clients() {
43
49
  return clientManager.clients;
44
50
  },
45
51
  addEventListener(event, listener) {
46
- const handler = new import_WebSocketHandler.WebSocketHandler(url);
47
- handler[import_WebSocketHandler.kEmitter].on("connection", async ({ client }) => {
52
+ const webSocketHandler = new import_WebSocketHandler.WebSocketHandler(url);
53
+ webSocketHandler[import_WebSocketHandler.kEmitter].on("connection", async ({ client }) => {
48
54
  await clientManager.addConnection(client);
49
55
  });
50
- handler[import_WebSocketHandler.kEmitter].on(event, listener);
51
- return handler;
56
+ webSocketHandler[import_WebSocketHandler.kEmitter].on(event, listener);
57
+ return (0, import_attachSiblingHandlers.attachSiblingHandlers)(webSocketHandler, [upgradeHandler]);
52
58
  },
53
59
  broadcast(data) {
54
60
  this.broadcastExcept([], data);
@@ -63,7 +69,26 @@ function createWebSocketLinkHandler(url) {
63
69
  }
64
70
  };
65
71
  }
72
+ const WEBSOCKET_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
66
73
  const ws = {
67
- link: createWebSocketLinkHandler
74
+ link: createWebSocketLinkHandler,
75
+ async onUpgrade({ request }) {
76
+ const key = request.headers.get("sec-websocket-key");
77
+ if (!key) {
78
+ return;
79
+ }
80
+ const keyBytes = new TextEncoder().encode(key + WEBSOCKET_GUID);
81
+ const digest = await crypto.subtle.digest("SHA-1", keyBytes);
82
+ const acceptValue = btoa(String.fromCharCode(...new Uint8Array(digest)));
83
+ new WebSocket((0, import_interceptors.resolveWebSocketUrl)(request.url));
84
+ return new import_interceptors.FetchResponse(null, {
85
+ status: 101,
86
+ headers: {
87
+ upgrade: "websocket",
88
+ connection: "upgrade",
89
+ "sec-websocket-accept": acceptValue
90
+ }
91
+ });
92
+ }
68
93
  };
69
94
  //# sourceMappingURL=ws.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/core/ws.ts"],"sourcesContent":["import { invariant } from 'outvariant'\nimport type {\n WebSocketData,\n WebSocketClientConnectionProtocol,\n} from '@mswjs/interceptors/WebSocket'\nimport {\n WebSocketHandler,\n kEmitter,\n type WebSocketHandlerEventMap,\n} from './handlers/WebSocketHandler'\nimport { hasRefCounted } from './utils/internal/hasRefCounted'\nimport { type Path, isPath } from './utils/matching/matchRequestUrl'\nimport { WebSocketClientManager } from './ws/WebSocketClientManager'\n\nconst webSocketChannel = new BroadcastChannel('msw:websocket-client-manager')\n\nif (hasRefCounted(webSocketChannel)) {\n // Allows the Node.js thread to exit if it is the only active handle in the event system.\n // https://nodejs.org/api/worker_threads.html#broadcastchannelunref\n webSocketChannel.unref()\n}\n\nexport type WebSocketEventListener<\n EventType extends keyof WebSocketHandlerEventMap,\n> = (...args: WebSocketHandlerEventMap[EventType]) => void\n\nexport type WebSocketLink = {\n /**\n * A set of all WebSocket clients connected\n * to this link.\n *\n * @see {@link https://mswjs.io/docs/api/ws#clients `clients` API reference}\n */\n clients: Set<WebSocketClientConnectionProtocol>\n\n /**\n * Adds an event listener to this WebSocket link.\n *\n * @example\n * const chat = ws.link('wss://chat.example.com')\n * chat.addEventListener('connection', listener)\n *\n * @see {@link https://mswjs.io/docs/api/ws#onevent-listener `on()` API reference}\n */\n addEventListener: <EventType extends keyof WebSocketHandlerEventMap>(\n event: EventType,\n listener: WebSocketEventListener<EventType>,\n ) => WebSocketHandler\n\n /**\n * Broadcasts the given data to all WebSocket clients.\n *\n * @example\n * const service = ws.link('wss://example.com')\n * service.addEventListener('connection', () => {\n * service.broadcast('hello, everyone!')\n * })\n *\n * @see {@link https://mswjs.io/docs/api/ws#broadcastdata `broadcast()` API reference}\n */\n broadcast: (data: WebSocketData) => void\n\n /**\n * Broadcasts the given data to all WebSocket clients\n * except the ones provided in the `clients` argument.\n *\n * @example\n * const service = ws.link('wss://example.com')\n * service.addEventListener('connection', ({ client }) => {\n * service.broadcastExcept(client, 'hi, the rest of you!')\n * })\n *\n * @see {@link https://mswjs.io/docs/api/ws#broadcastexceptclients-data `broadcast()` API reference}\n */\n broadcastExcept: (\n clients:\n | WebSocketClientConnectionProtocol\n | Array<WebSocketClientConnectionProtocol>,\n data: WebSocketData,\n ) => void\n}\n\n/**\n * Intercepts outgoing WebSocket connections to the given URL.\n *\n * @example\n * const chat = ws.link('wss://chat.example.com')\n * chat.addEventListener('connection', ({ client }) => {\n * client.send('hello from server!')\n * })\n */\nfunction createWebSocketLinkHandler(url: Path): WebSocketLink {\n invariant(url, 'Expected a WebSocket server URL but got undefined')\n\n invariant(\n isPath(url),\n 'Expected a WebSocket server URL to be a valid path but got %s',\n typeof url,\n )\n\n const clientManager = new WebSocketClientManager(webSocketChannel)\n\n return {\n get clients() {\n return clientManager.clients\n },\n addEventListener(event, listener) {\n const handler = new WebSocketHandler(url)\n\n // Add the connection event listener for when the\n // handler matches and emits a connection event.\n // When that happens, store that connection in the\n // set of all connections for reference.\n handler[kEmitter].on('connection', async ({ client }) => {\n await clientManager.addConnection(client)\n })\n\n // The \"handleWebSocketEvent\" function will invoke\n // the \"run()\" method on the WebSocketHandler.\n // If the handler matches, it will emit the \"connection\"\n // event. Attach the user-defined listener to that event.\n handler[kEmitter].on(event, listener)\n\n return handler\n },\n\n broadcast(data) {\n // This will invoke \"send()\" on the immediate clients\n // in this runtime and post a message to the broadcast channel\n // to trigger send for the clients in other runtimes.\n this.broadcastExcept([], data)\n },\n\n broadcastExcept(clients, data) {\n const ignoreClients = Array.prototype\n .concat(clients)\n .map((client) => client.id)\n\n clientManager.clients.forEach((otherClient) => {\n if (!ignoreClients.includes(otherClient.id)) {\n otherClient.send(data)\n }\n })\n },\n }\n}\n\n/**\n * A namespace to intercept and mock WebSocket connections.\n *\n * @example\n * const chat = ws.link('wss://chat.example.com')\n *\n * @see {@link https://mswjs.io/docs/api/ws `ws` API reference}\n * @see {@link https://mswjs.io/docs/basics/handling-websocket-events Handling WebSocket events}\n */\nexport const ws = {\n link: createWebSocketLinkHandler,\n}\n\nexport { WebSocketData }\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAA0B;AAK1B,8BAIO;AACP,2BAA8B;AAC9B,6BAAkC;AAClC,oCAAuC;AAEvC,MAAM,mBAAmB,IAAI,iBAAiB,8BAA8B;AAE5E,QAAI,oCAAc,gBAAgB,GAAG;AAGnC,mBAAiB,MAAM;AACzB;AAuEA,SAAS,2BAA2B,KAA0B;AAC5D,mCAAU,KAAK,mDAAmD;AAElE;AAAA,QACE,+BAAO,GAAG;AAAA,IACV;AAAA,IACA,OAAO;AAAA,EACT;AAEA,QAAM,gBAAgB,IAAI,qDAAuB,gBAAgB;AAEjE,SAAO;AAAA,IACL,IAAI,UAAU;AACZ,aAAO,cAAc;AAAA,IACvB;AAAA,IACA,iBAAiB,OAAO,UAAU;AAChC,YAAM,UAAU,IAAI,yCAAiB,GAAG;AAMxC,cAAQ,gCAAQ,EAAE,GAAG,cAAc,OAAO,EAAE,OAAO,MAAM;AACvD,cAAM,cAAc,cAAc,MAAM;AAAA,MAC1C,CAAC;AAMD,cAAQ,gCAAQ,EAAE,GAAG,OAAO,QAAQ;AAEpC,aAAO;AAAA,IACT;AAAA,IAEA,UAAU,MAAM;AAId,WAAK,gBAAgB,CAAC,GAAG,IAAI;AAAA,IAC/B;AAAA,IAEA,gBAAgB,SAAS,MAAM;AAC7B,YAAM,gBAAgB,MAAM,UACzB,OAAO,OAAO,EACd,IAAI,CAAC,WAAW,OAAO,EAAE;AAE5B,oBAAc,QAAQ,QAAQ,CAAC,gBAAgB;AAC7C,YAAI,CAAC,cAAc,SAAS,YAAY,EAAE,GAAG;AAC3C,sBAAY,KAAK,IAAI;AAAA,QACvB;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAWO,MAAM,KAAK;AAAA,EAChB,MAAM;AACR;","names":[]}
1
+ {"version":3,"sources":["../../src/core/ws.ts"],"sourcesContent":["import { invariant } from 'outvariant'\nimport { FetchResponse, resolveWebSocketUrl } from '@mswjs/interceptors'\nimport type {\n WebSocketData,\n WebSocketClientConnectionProtocol,\n} from '@mswjs/interceptors/WebSocket'\nimport {\n WebSocketHandler,\n kEmitter,\n type WebSocketHandlerEventMap,\n} from './handlers/WebSocketHandler'\nimport { hasRefCounted } from './utils/internal/hasRefCounted'\nimport {\n type Path,\n type PathParams,\n isPath,\n matchRequestUrl,\n} from './utils/matching/matchRequestUrl'\nimport { WebSocketClientManager } from './ws/WebSocketClientManager'\nimport { http } from './http'\nimport { attachSiblingHandlers } from './utils/internal/attachSiblingHandlers'\n\nconst webSocketChannel = new BroadcastChannel('msw:websocket-client-manager')\n\nif (hasRefCounted(webSocketChannel)) {\n // Allows the Node.js thread to exit if it is the only active handle in the event system.\n // https://nodejs.org/api/worker_threads.html#broadcastchannelunref\n webSocketChannel.unref()\n}\n\nexport type WebSocketEventListener<\n EventType extends keyof WebSocketHandlerEventMap,\n> = (...args: WebSocketHandlerEventMap[EventType]) => void\n\nexport type WebSocketLink = {\n /**\n * A set of all WebSocket clients connected\n * to this link.\n *\n * @see {@link https://mswjs.io/docs/api/ws#clients `clients` API reference}\n */\n clients: Set<WebSocketClientConnectionProtocol>\n\n /**\n * Adds an event listener to this WebSocket link.\n *\n * @example\n * const chat = ws.link('wss://chat.example.com')\n * chat.addEventListener('connection', listener)\n *\n * @see {@link https://mswjs.io/docs/api/ws#onevent-listener `on()` API reference}\n */\n addEventListener: <EventType extends keyof WebSocketHandlerEventMap>(\n event: EventType,\n listener: WebSocketEventListener<EventType>,\n ) => WebSocketHandler\n\n /**\n * Broadcasts the given data to all WebSocket clients.\n *\n * @example\n * const service = ws.link('wss://example.com')\n * service.addEventListener('connection', () => {\n * service.broadcast('hello, everyone!')\n * })\n *\n * @see {@link https://mswjs.io/docs/api/ws#broadcastdata `broadcast()` API reference}\n */\n broadcast: (data: WebSocketData) => void\n\n /**\n * Broadcasts the given data to all WebSocket clients\n * except the ones provided in the `clients` argument.\n *\n * @example\n * const service = ws.link('wss://example.com')\n * service.addEventListener('connection', ({ client }) => {\n * service.broadcastExcept(client, 'hi, the rest of you!')\n * })\n *\n * @see {@link https://mswjs.io/docs/api/ws#broadcastexceptclients-data `broadcast()` API reference}\n */\n broadcastExcept: (\n clients:\n | WebSocketClientConnectionProtocol\n | Array<WebSocketClientConnectionProtocol>,\n data: WebSocketData,\n ) => void\n}\n\n/**\n * Intercepts outgoing WebSocket connections to the given URL.\n *\n * @example\n * const chat = ws.link('wss://chat.example.com')\n * chat.addEventListener('connection', ({ client }) => {\n * client.send('hello from server!')\n * })\n */\nfunction createWebSocketLinkHandler(url: Path): WebSocketLink {\n invariant(url, 'Expected a WebSocket server URL but got undefined')\n\n invariant(\n isPath(url),\n 'Expected a WebSocket server URL to be a valid path but got %s',\n typeof url,\n )\n\n const clientManager = new WebSocketClientManager(webSocketChannel)\n\n // The same upgrade handler instance is attached as a sibling to every\n // WebSocketHandler returned by this link. `groupHandlersByKind` dedupes\n // by reference, so it lands in the `request` bucket exactly once regardless\n // of which subset of WS handlers the user ends up registering.\n const upgradeHandler = http.get(({ request }) => {\n return (\n request.headers.get('upgrade')?.toLowerCase() === 'websocket' &&\n matchRequestUrl(new URL(resolveWebSocketUrl(request.url)), url).matches\n )\n }, ws.onUpgrade)\n\n return {\n get clients() {\n return clientManager.clients\n },\n addEventListener(event, listener) {\n const webSocketHandler = new WebSocketHandler(url)\n\n // Add the connection event listener for when the\n // handler matches and emits a connection event.\n // When that happens, store that connection in the\n // set of all connections for reference.\n webSocketHandler[kEmitter].on('connection', async ({ client }) => {\n await clientManager.addConnection(client)\n })\n\n // The \"handleWebSocketEvent\" function will invoke\n // the \"run()\" method on the WebSocketHandler.\n // If the handler matches, it will emit the \"connection\"\n // event. Attach the user-defined listener to that event.\n webSocketHandler[kEmitter].on(event, listener)\n\n return attachSiblingHandlers(webSocketHandler, [upgradeHandler])\n },\n\n broadcast(data) {\n // This will invoke \"send()\" on the immediate clients\n // in this runtime and post a message to the broadcast channel\n // to trigger send for the clients in other runtimes.\n this.broadcastExcept([], data)\n },\n\n broadcastExcept(clients, data) {\n const ignoreClients = Array.prototype\n .concat(clients)\n .map((client) => client.id)\n\n clientManager.clients.forEach((otherClient) => {\n if (!ignoreClients.includes(otherClient.id)) {\n otherClient.send(data)\n }\n })\n },\n }\n}\n\nconst WEBSOCKET_GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'\n\ninterface WebSocketNamespace {\n link: typeof createWebSocketLinkHandler\n /**\n * Request handler for the `upgrade` requests to the WebSocket protocol.\n * This requires a WebSocket handler to be present to fire.\n * @note This only affects Node.js as the `upgrade` request header is\n * forbidden and cannot be read in the browser. Consider using the\n * `WebSocket` API for establishing WebSocket connections in the browser.\n */\n onUpgrade: (info: {\n requestId: string\n request: Request\n params: PathParams\n }) => Promise<Response | undefined> | Response | undefined\n}\n\n/**\n * A namespace to intercept and mock WebSocket connections.\n *\n * @example\n * const chat = ws.link('wss://chat.example.com')\n *\n * @see {@link https://mswjs.io/docs/api/ws `ws` API reference}\n * @see {@link https://mswjs.io/docs/basics/handling-websocket-events Handling WebSocket events}\n */\nexport const ws: WebSocketNamespace = {\n link: createWebSocketLinkHandler,\n async onUpgrade({ request }) {\n const key = request.headers.get('sec-websocket-key')\n\n if (!key) {\n return\n }\n\n const keyBytes = new TextEncoder().encode(key + WEBSOCKET_GUID)\n const digest = await crypto.subtle.digest('SHA-1', keyBytes)\n const acceptValue = btoa(String.fromCharCode(...new Uint8Array(digest)))\n\n new WebSocket(resolveWebSocketUrl(request.url))\n\n return new FetchResponse(null, {\n status: 101,\n headers: {\n upgrade: 'websocket',\n connection: 'upgrade',\n 'sec-websocket-accept': acceptValue,\n },\n })\n },\n}\n\nexport { type WebSocketData }\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAA0B;AAC1B,0BAAmD;AAKnD,8BAIO;AACP,2BAA8B;AAC9B,6BAKO;AACP,oCAAuC;AACvC,kBAAqB;AACrB,mCAAsC;AAEtC,MAAM,mBAAmB,IAAI,iBAAiB,8BAA8B;AAE5E,QAAI,oCAAc,gBAAgB,GAAG;AAGnC,mBAAiB,MAAM;AACzB;AAuEA,SAAS,2BAA2B,KAA0B;AAC5D,mCAAU,KAAK,mDAAmD;AAElE;AAAA,QACE,+BAAO,GAAG;AAAA,IACV;AAAA,IACA,OAAO;AAAA,EACT;AAEA,QAAM,gBAAgB,IAAI,qDAAuB,gBAAgB;AAMjE,QAAM,iBAAiB,iBAAK,IAAI,CAAC,EAAE,QAAQ,MAAM;AAC/C,WACE,QAAQ,QAAQ,IAAI,SAAS,GAAG,YAAY,MAAM,mBAClD,wCAAgB,IAAI,QAAI,yCAAoB,QAAQ,GAAG,CAAC,GAAG,GAAG,EAAE;AAAA,EAEpE,GAAG,GAAG,SAAS;AAEf,SAAO;AAAA,IACL,IAAI,UAAU;AACZ,aAAO,cAAc;AAAA,IACvB;AAAA,IACA,iBAAiB,OAAO,UAAU;AAChC,YAAM,mBAAmB,IAAI,yCAAiB,GAAG;AAMjD,uBAAiB,gCAAQ,EAAE,GAAG,cAAc,OAAO,EAAE,OAAO,MAAM;AAChE,cAAM,cAAc,cAAc,MAAM;AAAA,MAC1C,CAAC;AAMD,uBAAiB,gCAAQ,EAAE,GAAG,OAAO,QAAQ;AAE7C,iBAAO,oDAAsB,kBAAkB,CAAC,cAAc,CAAC;AAAA,IACjE;AAAA,IAEA,UAAU,MAAM;AAId,WAAK,gBAAgB,CAAC,GAAG,IAAI;AAAA,IAC/B;AAAA,IAEA,gBAAgB,SAAS,MAAM;AAC7B,YAAM,gBAAgB,MAAM,UACzB,OAAO,OAAO,EACd,IAAI,CAAC,WAAW,OAAO,EAAE;AAE5B,oBAAc,QAAQ,QAAQ,CAAC,gBAAgB;AAC7C,YAAI,CAAC,cAAc,SAAS,YAAY,EAAE,GAAG;AAC3C,sBAAY,KAAK,IAAI;AAAA,QACvB;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAEA,MAAM,iBAAiB;AA2BhB,MAAM,KAAyB;AAAA,EACpC,MAAM;AAAA,EACN,MAAM,UAAU,EAAE,QAAQ,GAAG;AAC3B,UAAM,MAAM,QAAQ,QAAQ,IAAI,mBAAmB;AAEnD,QAAI,CAAC,KAAK;AACR;AAAA,IACF;AAEA,UAAM,WAAW,IAAI,YAAY,EAAE,OAAO,MAAM,cAAc;AAC9D,UAAM,SAAS,MAAM,OAAO,OAAO,OAAO,SAAS,QAAQ;AAC3D,UAAM,cAAc,KAAK,OAAO,aAAa,GAAG,IAAI,WAAW,MAAM,CAAC,CAAC;AAEvE,QAAI,cAAU,yCAAoB,QAAQ,GAAG,CAAC;AAE9C,WAAO,IAAI,kCAAc,MAAM;AAAA,MAC7B,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,SAAS;AAAA,QACT,YAAY;AAAA,QACZ,wBAAwB;AAAA,MAC1B;AAAA,IACF,CAAC;AAAA,EACH;AACF;","names":[]}
package/lib/core/ws.mjs CHANGED
@@ -1,11 +1,17 @@
1
1
  import { invariant } from "outvariant";
2
+ import { FetchResponse, resolveWebSocketUrl } from "@mswjs/interceptors";
2
3
  import {
3
4
  WebSocketHandler,
4
5
  kEmitter
5
6
  } from './handlers/WebSocketHandler.mjs';
6
7
  import { hasRefCounted } from './utils/internal/hasRefCounted.mjs';
7
- import { isPath } from './utils/matching/matchRequestUrl.mjs';
8
+ import {
9
+ isPath,
10
+ matchRequestUrl
11
+ } from './utils/matching/matchRequestUrl.mjs';
8
12
  import { WebSocketClientManager } from './ws/WebSocketClientManager.mjs';
13
+ import { http } from './http.mjs';
14
+ import { attachSiblingHandlers } from './utils/internal/attachSiblingHandlers.mjs';
9
15
  const webSocketChannel = new BroadcastChannel("msw:websocket-client-manager");
10
16
  if (hasRefCounted(webSocketChannel)) {
11
17
  webSocketChannel.unref();
@@ -18,17 +24,20 @@ function createWebSocketLinkHandler(url) {
18
24
  typeof url
19
25
  );
20
26
  const clientManager = new WebSocketClientManager(webSocketChannel);
27
+ const upgradeHandler = http.get(({ request }) => {
28
+ return request.headers.get("upgrade")?.toLowerCase() === "websocket" && matchRequestUrl(new URL(resolveWebSocketUrl(request.url)), url).matches;
29
+ }, ws.onUpgrade);
21
30
  return {
22
31
  get clients() {
23
32
  return clientManager.clients;
24
33
  },
25
34
  addEventListener(event, listener) {
26
- const handler = new WebSocketHandler(url);
27
- handler[kEmitter].on("connection", async ({ client }) => {
35
+ const webSocketHandler = new WebSocketHandler(url);
36
+ webSocketHandler[kEmitter].on("connection", async ({ client }) => {
28
37
  await clientManager.addConnection(client);
29
38
  });
30
- handler[kEmitter].on(event, listener);
31
- return handler;
39
+ webSocketHandler[kEmitter].on(event, listener);
40
+ return attachSiblingHandlers(webSocketHandler, [upgradeHandler]);
32
41
  },
33
42
  broadcast(data) {
34
43
  this.broadcastExcept([], data);
@@ -43,8 +52,27 @@ function createWebSocketLinkHandler(url) {
43
52
  }
44
53
  };
45
54
  }
55
+ const WEBSOCKET_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
46
56
  const ws = {
47
- link: createWebSocketLinkHandler
57
+ link: createWebSocketLinkHandler,
58
+ async onUpgrade({ request }) {
59
+ const key = request.headers.get("sec-websocket-key");
60
+ if (!key) {
61
+ return;
62
+ }
63
+ const keyBytes = new TextEncoder().encode(key + WEBSOCKET_GUID);
64
+ const digest = await crypto.subtle.digest("SHA-1", keyBytes);
65
+ const acceptValue = btoa(String.fromCharCode(...new Uint8Array(digest)));
66
+ new WebSocket(resolveWebSocketUrl(request.url));
67
+ return new FetchResponse(null, {
68
+ status: 101,
69
+ headers: {
70
+ upgrade: "websocket",
71
+ connection: "upgrade",
72
+ "sec-websocket-accept": acceptValue
73
+ }
74
+ });
75
+ }
48
76
  };
49
77
  export {
50
78
  ws
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/core/ws.ts"],"sourcesContent":["import { invariant } from 'outvariant'\nimport type {\n WebSocketData,\n WebSocketClientConnectionProtocol,\n} from '@mswjs/interceptors/WebSocket'\nimport {\n WebSocketHandler,\n kEmitter,\n type WebSocketHandlerEventMap,\n} from './handlers/WebSocketHandler'\nimport { hasRefCounted } from './utils/internal/hasRefCounted'\nimport { type Path, isPath } from './utils/matching/matchRequestUrl'\nimport { WebSocketClientManager } from './ws/WebSocketClientManager'\n\nconst webSocketChannel = new BroadcastChannel('msw:websocket-client-manager')\n\nif (hasRefCounted(webSocketChannel)) {\n // Allows the Node.js thread to exit if it is the only active handle in the event system.\n // https://nodejs.org/api/worker_threads.html#broadcastchannelunref\n webSocketChannel.unref()\n}\n\nexport type WebSocketEventListener<\n EventType extends keyof WebSocketHandlerEventMap,\n> = (...args: WebSocketHandlerEventMap[EventType]) => void\n\nexport type WebSocketLink = {\n /**\n * A set of all WebSocket clients connected\n * to this link.\n *\n * @see {@link https://mswjs.io/docs/api/ws#clients `clients` API reference}\n */\n clients: Set<WebSocketClientConnectionProtocol>\n\n /**\n * Adds an event listener to this WebSocket link.\n *\n * @example\n * const chat = ws.link('wss://chat.example.com')\n * chat.addEventListener('connection', listener)\n *\n * @see {@link https://mswjs.io/docs/api/ws#onevent-listener `on()` API reference}\n */\n addEventListener: <EventType extends keyof WebSocketHandlerEventMap>(\n event: EventType,\n listener: WebSocketEventListener<EventType>,\n ) => WebSocketHandler\n\n /**\n * Broadcasts the given data to all WebSocket clients.\n *\n * @example\n * const service = ws.link('wss://example.com')\n * service.addEventListener('connection', () => {\n * service.broadcast('hello, everyone!')\n * })\n *\n * @see {@link https://mswjs.io/docs/api/ws#broadcastdata `broadcast()` API reference}\n */\n broadcast: (data: WebSocketData) => void\n\n /**\n * Broadcasts the given data to all WebSocket clients\n * except the ones provided in the `clients` argument.\n *\n * @example\n * const service = ws.link('wss://example.com')\n * service.addEventListener('connection', ({ client }) => {\n * service.broadcastExcept(client, 'hi, the rest of you!')\n * })\n *\n * @see {@link https://mswjs.io/docs/api/ws#broadcastexceptclients-data `broadcast()` API reference}\n */\n broadcastExcept: (\n clients:\n | WebSocketClientConnectionProtocol\n | Array<WebSocketClientConnectionProtocol>,\n data: WebSocketData,\n ) => void\n}\n\n/**\n * Intercepts outgoing WebSocket connections to the given URL.\n *\n * @example\n * const chat = ws.link('wss://chat.example.com')\n * chat.addEventListener('connection', ({ client }) => {\n * client.send('hello from server!')\n * })\n */\nfunction createWebSocketLinkHandler(url: Path): WebSocketLink {\n invariant(url, 'Expected a WebSocket server URL but got undefined')\n\n invariant(\n isPath(url),\n 'Expected a WebSocket server URL to be a valid path but got %s',\n typeof url,\n )\n\n const clientManager = new WebSocketClientManager(webSocketChannel)\n\n return {\n get clients() {\n return clientManager.clients\n },\n addEventListener(event, listener) {\n const handler = new WebSocketHandler(url)\n\n // Add the connection event listener for when the\n // handler matches and emits a connection event.\n // When that happens, store that connection in the\n // set of all connections for reference.\n handler[kEmitter].on('connection', async ({ client }) => {\n await clientManager.addConnection(client)\n })\n\n // The \"handleWebSocketEvent\" function will invoke\n // the \"run()\" method on the WebSocketHandler.\n // If the handler matches, it will emit the \"connection\"\n // event. Attach the user-defined listener to that event.\n handler[kEmitter].on(event, listener)\n\n return handler\n },\n\n broadcast(data) {\n // This will invoke \"send()\" on the immediate clients\n // in this runtime and post a message to the broadcast channel\n // to trigger send for the clients in other runtimes.\n this.broadcastExcept([], data)\n },\n\n broadcastExcept(clients, data) {\n const ignoreClients = Array.prototype\n .concat(clients)\n .map((client) => client.id)\n\n clientManager.clients.forEach((otherClient) => {\n if (!ignoreClients.includes(otherClient.id)) {\n otherClient.send(data)\n }\n })\n },\n }\n}\n\n/**\n * A namespace to intercept and mock WebSocket connections.\n *\n * @example\n * const chat = ws.link('wss://chat.example.com')\n *\n * @see {@link https://mswjs.io/docs/api/ws `ws` API reference}\n * @see {@link https://mswjs.io/docs/basics/handling-websocket-events Handling WebSocket events}\n */\nexport const ws = {\n link: createWebSocketLinkHandler,\n}\n\nexport { WebSocketData }\n"],"mappings":"AAAA,SAAS,iBAAiB;AAK1B;AAAA,EACE;AAAA,EACA;AAAA,OAEK;AACP,SAAS,qBAAqB;AAC9B,SAAoB,cAAc;AAClC,SAAS,8BAA8B;AAEvC,MAAM,mBAAmB,IAAI,iBAAiB,8BAA8B;AAE5E,IAAI,cAAc,gBAAgB,GAAG;AAGnC,mBAAiB,MAAM;AACzB;AAuEA,SAAS,2BAA2B,KAA0B;AAC5D,YAAU,KAAK,mDAAmD;AAElE;AAAA,IACE,OAAO,GAAG;AAAA,IACV;AAAA,IACA,OAAO;AAAA,EACT;AAEA,QAAM,gBAAgB,IAAI,uBAAuB,gBAAgB;AAEjE,SAAO;AAAA,IACL,IAAI,UAAU;AACZ,aAAO,cAAc;AAAA,IACvB;AAAA,IACA,iBAAiB,OAAO,UAAU;AAChC,YAAM,UAAU,IAAI,iBAAiB,GAAG;AAMxC,cAAQ,QAAQ,EAAE,GAAG,cAAc,OAAO,EAAE,OAAO,MAAM;AACvD,cAAM,cAAc,cAAc,MAAM;AAAA,MAC1C,CAAC;AAMD,cAAQ,QAAQ,EAAE,GAAG,OAAO,QAAQ;AAEpC,aAAO;AAAA,IACT;AAAA,IAEA,UAAU,MAAM;AAId,WAAK,gBAAgB,CAAC,GAAG,IAAI;AAAA,IAC/B;AAAA,IAEA,gBAAgB,SAAS,MAAM;AAC7B,YAAM,gBAAgB,MAAM,UACzB,OAAO,OAAO,EACd,IAAI,CAAC,WAAW,OAAO,EAAE;AAE5B,oBAAc,QAAQ,QAAQ,CAAC,gBAAgB;AAC7C,YAAI,CAAC,cAAc,SAAS,YAAY,EAAE,GAAG;AAC3C,sBAAY,KAAK,IAAI;AAAA,QACvB;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAWO,MAAM,KAAK;AAAA,EAChB,MAAM;AACR;","names":[]}
1
+ {"version":3,"sources":["../../src/core/ws.ts"],"sourcesContent":["import { invariant } from 'outvariant'\nimport { FetchResponse, resolveWebSocketUrl } from '@mswjs/interceptors'\nimport type {\n WebSocketData,\n WebSocketClientConnectionProtocol,\n} from '@mswjs/interceptors/WebSocket'\nimport {\n WebSocketHandler,\n kEmitter,\n type WebSocketHandlerEventMap,\n} from './handlers/WebSocketHandler'\nimport { hasRefCounted } from './utils/internal/hasRefCounted'\nimport {\n type Path,\n type PathParams,\n isPath,\n matchRequestUrl,\n} from './utils/matching/matchRequestUrl'\nimport { WebSocketClientManager } from './ws/WebSocketClientManager'\nimport { http } from './http'\nimport { attachSiblingHandlers } from './utils/internal/attachSiblingHandlers'\n\nconst webSocketChannel = new BroadcastChannel('msw:websocket-client-manager')\n\nif (hasRefCounted(webSocketChannel)) {\n // Allows the Node.js thread to exit if it is the only active handle in the event system.\n // https://nodejs.org/api/worker_threads.html#broadcastchannelunref\n webSocketChannel.unref()\n}\n\nexport type WebSocketEventListener<\n EventType extends keyof WebSocketHandlerEventMap,\n> = (...args: WebSocketHandlerEventMap[EventType]) => void\n\nexport type WebSocketLink = {\n /**\n * A set of all WebSocket clients connected\n * to this link.\n *\n * @see {@link https://mswjs.io/docs/api/ws#clients `clients` API reference}\n */\n clients: Set<WebSocketClientConnectionProtocol>\n\n /**\n * Adds an event listener to this WebSocket link.\n *\n * @example\n * const chat = ws.link('wss://chat.example.com')\n * chat.addEventListener('connection', listener)\n *\n * @see {@link https://mswjs.io/docs/api/ws#onevent-listener `on()` API reference}\n */\n addEventListener: <EventType extends keyof WebSocketHandlerEventMap>(\n event: EventType,\n listener: WebSocketEventListener<EventType>,\n ) => WebSocketHandler\n\n /**\n * Broadcasts the given data to all WebSocket clients.\n *\n * @example\n * const service = ws.link('wss://example.com')\n * service.addEventListener('connection', () => {\n * service.broadcast('hello, everyone!')\n * })\n *\n * @see {@link https://mswjs.io/docs/api/ws#broadcastdata `broadcast()` API reference}\n */\n broadcast: (data: WebSocketData) => void\n\n /**\n * Broadcasts the given data to all WebSocket clients\n * except the ones provided in the `clients` argument.\n *\n * @example\n * const service = ws.link('wss://example.com')\n * service.addEventListener('connection', ({ client }) => {\n * service.broadcastExcept(client, 'hi, the rest of you!')\n * })\n *\n * @see {@link https://mswjs.io/docs/api/ws#broadcastexceptclients-data `broadcast()` API reference}\n */\n broadcastExcept: (\n clients:\n | WebSocketClientConnectionProtocol\n | Array<WebSocketClientConnectionProtocol>,\n data: WebSocketData,\n ) => void\n}\n\n/**\n * Intercepts outgoing WebSocket connections to the given URL.\n *\n * @example\n * const chat = ws.link('wss://chat.example.com')\n * chat.addEventListener('connection', ({ client }) => {\n * client.send('hello from server!')\n * })\n */\nfunction createWebSocketLinkHandler(url: Path): WebSocketLink {\n invariant(url, 'Expected a WebSocket server URL but got undefined')\n\n invariant(\n isPath(url),\n 'Expected a WebSocket server URL to be a valid path but got %s',\n typeof url,\n )\n\n const clientManager = new WebSocketClientManager(webSocketChannel)\n\n // The same upgrade handler instance is attached as a sibling to every\n // WebSocketHandler returned by this link. `groupHandlersByKind` dedupes\n // by reference, so it lands in the `request` bucket exactly once regardless\n // of which subset of WS handlers the user ends up registering.\n const upgradeHandler = http.get(({ request }) => {\n return (\n request.headers.get('upgrade')?.toLowerCase() === 'websocket' &&\n matchRequestUrl(new URL(resolveWebSocketUrl(request.url)), url).matches\n )\n }, ws.onUpgrade)\n\n return {\n get clients() {\n return clientManager.clients\n },\n addEventListener(event, listener) {\n const webSocketHandler = new WebSocketHandler(url)\n\n // Add the connection event listener for when the\n // handler matches and emits a connection event.\n // When that happens, store that connection in the\n // set of all connections for reference.\n webSocketHandler[kEmitter].on('connection', async ({ client }) => {\n await clientManager.addConnection(client)\n })\n\n // The \"handleWebSocketEvent\" function will invoke\n // the \"run()\" method on the WebSocketHandler.\n // If the handler matches, it will emit the \"connection\"\n // event. Attach the user-defined listener to that event.\n webSocketHandler[kEmitter].on(event, listener)\n\n return attachSiblingHandlers(webSocketHandler, [upgradeHandler])\n },\n\n broadcast(data) {\n // This will invoke \"send()\" on the immediate clients\n // in this runtime and post a message to the broadcast channel\n // to trigger send for the clients in other runtimes.\n this.broadcastExcept([], data)\n },\n\n broadcastExcept(clients, data) {\n const ignoreClients = Array.prototype\n .concat(clients)\n .map((client) => client.id)\n\n clientManager.clients.forEach((otherClient) => {\n if (!ignoreClients.includes(otherClient.id)) {\n otherClient.send(data)\n }\n })\n },\n }\n}\n\nconst WEBSOCKET_GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'\n\ninterface WebSocketNamespace {\n link: typeof createWebSocketLinkHandler\n /**\n * Request handler for the `upgrade` requests to the WebSocket protocol.\n * This requires a WebSocket handler to be present to fire.\n * @note This only affects Node.js as the `upgrade` request header is\n * forbidden and cannot be read in the browser. Consider using the\n * `WebSocket` API for establishing WebSocket connections in the browser.\n */\n onUpgrade: (info: {\n requestId: string\n request: Request\n params: PathParams\n }) => Promise<Response | undefined> | Response | undefined\n}\n\n/**\n * A namespace to intercept and mock WebSocket connections.\n *\n * @example\n * const chat = ws.link('wss://chat.example.com')\n *\n * @see {@link https://mswjs.io/docs/api/ws `ws` API reference}\n * @see {@link https://mswjs.io/docs/basics/handling-websocket-events Handling WebSocket events}\n */\nexport const ws: WebSocketNamespace = {\n link: createWebSocketLinkHandler,\n async onUpgrade({ request }) {\n const key = request.headers.get('sec-websocket-key')\n\n if (!key) {\n return\n }\n\n const keyBytes = new TextEncoder().encode(key + WEBSOCKET_GUID)\n const digest = await crypto.subtle.digest('SHA-1', keyBytes)\n const acceptValue = btoa(String.fromCharCode(...new Uint8Array(digest)))\n\n new WebSocket(resolveWebSocketUrl(request.url))\n\n return new FetchResponse(null, {\n status: 101,\n headers: {\n upgrade: 'websocket',\n connection: 'upgrade',\n 'sec-websocket-accept': acceptValue,\n },\n })\n },\n}\n\nexport { type WebSocketData }\n"],"mappings":"AAAA,SAAS,iBAAiB;AAC1B,SAAS,eAAe,2BAA2B;AAKnD;AAAA,EACE;AAAA,EACA;AAAA,OAEK;AACP,SAAS,qBAAqB;AAC9B;AAAA,EAGE;AAAA,EACA;AAAA,OACK;AACP,SAAS,8BAA8B;AACvC,SAAS,YAAY;AACrB,SAAS,6BAA6B;AAEtC,MAAM,mBAAmB,IAAI,iBAAiB,8BAA8B;AAE5E,IAAI,cAAc,gBAAgB,GAAG;AAGnC,mBAAiB,MAAM;AACzB;AAuEA,SAAS,2BAA2B,KAA0B;AAC5D,YAAU,KAAK,mDAAmD;AAElE;AAAA,IACE,OAAO,GAAG;AAAA,IACV;AAAA,IACA,OAAO;AAAA,EACT;AAEA,QAAM,gBAAgB,IAAI,uBAAuB,gBAAgB;AAMjE,QAAM,iBAAiB,KAAK,IAAI,CAAC,EAAE,QAAQ,MAAM;AAC/C,WACE,QAAQ,QAAQ,IAAI,SAAS,GAAG,YAAY,MAAM,eAClD,gBAAgB,IAAI,IAAI,oBAAoB,QAAQ,GAAG,CAAC,GAAG,GAAG,EAAE;AAAA,EAEpE,GAAG,GAAG,SAAS;AAEf,SAAO;AAAA,IACL,IAAI,UAAU;AACZ,aAAO,cAAc;AAAA,IACvB;AAAA,IACA,iBAAiB,OAAO,UAAU;AAChC,YAAM,mBAAmB,IAAI,iBAAiB,GAAG;AAMjD,uBAAiB,QAAQ,EAAE,GAAG,cAAc,OAAO,EAAE,OAAO,MAAM;AAChE,cAAM,cAAc,cAAc,MAAM;AAAA,MAC1C,CAAC;AAMD,uBAAiB,QAAQ,EAAE,GAAG,OAAO,QAAQ;AAE7C,aAAO,sBAAsB,kBAAkB,CAAC,cAAc,CAAC;AAAA,IACjE;AAAA,IAEA,UAAU,MAAM;AAId,WAAK,gBAAgB,CAAC,GAAG,IAAI;AAAA,IAC/B;AAAA,IAEA,gBAAgB,SAAS,MAAM;AAC7B,YAAM,gBAAgB,MAAM,UACzB,OAAO,OAAO,EACd,IAAI,CAAC,WAAW,OAAO,EAAE;AAE5B,oBAAc,QAAQ,QAAQ,CAAC,gBAAgB;AAC7C,YAAI,CAAC,cAAc,SAAS,YAAY,EAAE,GAAG;AAC3C,sBAAY,KAAK,IAAI;AAAA,QACvB;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAEA,MAAM,iBAAiB;AA2BhB,MAAM,KAAyB;AAAA,EACpC,MAAM;AAAA,EACN,MAAM,UAAU,EAAE,QAAQ,GAAG;AAC3B,UAAM,MAAM,QAAQ,QAAQ,IAAI,mBAAmB;AAEnD,QAAI,CAAC,KAAK;AACR;AAAA,IACF;AAEA,UAAM,WAAW,IAAI,YAAY,EAAE,OAAO,MAAM,cAAc;AAC9D,UAAM,SAAS,MAAM,OAAO,OAAO,OAAO,SAAS,QAAQ;AAC3D,UAAM,cAAc,KAAK,OAAO,aAAa,GAAG,IAAI,WAAW,MAAM,CAAC,CAAC;AAEvE,QAAI,UAAU,oBAAoB,QAAQ,GAAG,CAAC;AAE9C,WAAO,IAAI,cAAc,MAAM;AAAA,MAC7B,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,SAAS;AAAA,QACT,YAAY;AAAA,QACZ,wBAAwB;AAAA,MAC1B;AAAA,IACF,CAAC;AAAA,EACH;AACF;","names":[]}