@depup/msw 2.13.2-depup.0 → 2.15.0-depup.7

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
@@ -4,7 +4,7 @@ import {
4
4
  Cookie,
5
5
  CookieJar,
6
6
  MemoryCookieStore,
7
- SerializedCookie,
7
+ type SerializedCookie,
8
8
  type MemoryCookieStoreIndex,
9
9
  } from 'tough-cookie'
10
10
  import { jsonParse } from './internal/jsonParse'
@@ -1,7 +1,5 @@
1
- import {
2
- RequestHandler,
3
- type RequestHandlerExecutionResult,
4
- } from '../handlers/RequestHandler'
1
+ import type { RequestHandler } from '../handlers/RequestHandler'
2
+ import { type RequestHandlerExecutionResult } from '../handlers/RequestHandler'
5
3
 
6
4
  export interface HandlersExecutionResult {
7
5
  handler: RequestHandler
@@ -1,11 +1,12 @@
1
1
  // @vitest-environment jsdom
2
2
  import { Emitter } from 'strict-event-emitter'
3
3
  import { createRequestId } from '@mswjs/interceptors'
4
- import { LifeCycleEventsMap, SharedOptions } from '../sharedOptions'
5
- import { RequestHandler } from '../handlers/RequestHandler'
4
+ import type { LifeCycleEventsMap, SharedOptions } from '../sharedOptions'
5
+ import type { RequestHandler } from '../handlers/RequestHandler'
6
6
  import { http } from '../http'
7
- import { handleRequest, HandleRequestOptions } from './handleRequest'
8
- import { RequiredDeep } from '../typeUtils'
7
+ import type { HandleRequestOptions } from './handleRequest'
8
+ import { handleRequest } from './handleRequest'
9
+ import type { RequiredDeep } from '../typeUtils'
9
10
  import { HttpResponse } from '../HttpResponse'
10
11
  import { passthrough } from '../passthrough'
11
12
 
@@ -1,7 +1,7 @@
1
1
  import { until } from 'until-async'
2
- import { Emitter } from 'strict-event-emitter'
3
- import { LifeCycleEventsMap, SharedOptions } from '../sharedOptions'
4
- import { RequiredDeep } from '../typeUtils'
2
+ import type { Emitter } from 'strict-event-emitter'
3
+ import type { LifeCycleEventsMap, SharedOptions } from '../sharedOptions'
4
+ import type { RequiredDeep } from '../typeUtils'
5
5
  import type { RequestHandler } from '../handlers/RequestHandler'
6
6
  import {
7
7
  type HandlersExecutionResult,
@@ -1,3 +1,5 @@
1
+ import { devUtils } from './devUtils'
2
+
1
3
  export type DisposableSubscription = () => void
2
4
 
3
5
  export class Disposable {
@@ -5,8 +7,27 @@ export class Disposable {
5
7
 
6
8
  public dispose() {
7
9
  let subscription: DisposableSubscription | undefined
10
+ const errors: Array<Error> = []
11
+
8
12
  while ((subscription = this.subscriptions.shift())) {
9
- subscription()
13
+ try {
14
+ subscription()
15
+ } catch (error) {
16
+ if (error instanceof Error) {
17
+ errors.push(error)
18
+ }
19
+ }
20
+ }
21
+
22
+ if (errors.length > 0) {
23
+ console.error(
24
+ new AggregateError(
25
+ errors,
26
+ devUtils.formatMessage(
27
+ 'Failed to dispose of some side effects. This is likely an issue with MSW, please report it on GitHub: https://github.com/mswjs/msw/issues',
28
+ ),
29
+ ),
30
+ )
10
31
  }
11
32
  }
12
33
  }
@@ -0,0 +1,28 @@
1
+ import { invariant } from 'outvariant'
2
+ import type { AnyHandler } from '../../experimental/handlers-controller'
3
+
4
+ const kSiblingHandlers = Symbol('kSiblingHandlers')
5
+
6
+ export function attachSiblingHandlers<T extends AnyHandler>(
7
+ owner: T,
8
+ siblings: Array<AnyHandler>,
9
+ ): T {
10
+ invariant(
11
+ getSiblingHandlers(owner).length === 0,
12
+ 'Failed to merge handlers: the owner "%s" handler is already merged',
13
+ owner.kind,
14
+ )
15
+
16
+ Object.defineProperty(owner, kSiblingHandlers, {
17
+ value: siblings,
18
+ enumerable: false,
19
+ writable: false,
20
+ configurable: false,
21
+ })
22
+
23
+ return owner
24
+ }
25
+
26
+ export function getSiblingHandlers(owner: AnyHandler): Array<AnyHandler> {
27
+ return Reflect.get(owner, kSiblingHandlers) || []
28
+ }
@@ -0,0 +1,64 @@
1
+ import { observeResponseBodyStream } from './observe-response-body-stream'
2
+
3
+ it('returns null for a response without a body', () => {
4
+ expect(observeResponseBodyStream(new Response(null))).toBeNull()
5
+ })
6
+
7
+ it('returns null for a response whose body is already used', async () => {
8
+ const response = new Response('hello')
9
+ await response.text()
10
+
11
+ expect(observeResponseBodyStream(response)).toBeNull()
12
+ })
13
+
14
+ it('returns null for a response whose body is locked', () => {
15
+ const response = new Response('hello')
16
+ response.body?.getReader()
17
+
18
+ expect(observeResponseBodyStream(response)).toBeNull()
19
+ })
20
+
21
+ it('resolves "settled" when the response body is read to completion', async () => {
22
+ const observed = observeResponseBodyStream(new Response('hello'))
23
+ expect(observed).not.toBeNull()
24
+
25
+ await expect(observed?.response.text()).resolves.toBe('hello')
26
+ await expect(observed?.settled).resolves.toBeUndefined()
27
+ })
28
+
29
+ it('resolves "settled" when the response body errors', async () => {
30
+ const stream = new ReadableStream({
31
+ start(controller) {
32
+ controller.error(new Error('stream error'))
33
+ },
34
+ })
35
+ const observed = observeResponseBodyStream(new Response(stream))
36
+ expect(observed).not.toBeNull()
37
+
38
+ await expect(observed?.response.text()).rejects.toThrow('stream error')
39
+ await expect(observed?.settled).resolves.toBeUndefined()
40
+ })
41
+
42
+ it('resolves "settled" when the response body is canceled', async () => {
43
+ const stream = new ReadableStream({
44
+ pull(controller) {
45
+ controller.enqueue(new TextEncoder().encode('ping'))
46
+ },
47
+ })
48
+ const observed = observeResponseBodyStream(new Response(stream))
49
+ const reader = observed?.response.body?.getReader()
50
+ expect(reader).toBeDefined()
51
+
52
+ await reader?.read()
53
+ await reader?.cancel(new Error('client disconnected'))
54
+
55
+ await expect(observed?.settled).resolves.toBeUndefined()
56
+ })
57
+
58
+ it('resolves "settled" when the response body is consumed via piping', async () => {
59
+ const observed = observeResponseBodyStream(new Response('hello'))
60
+ expect(observed).not.toBeNull()
61
+
62
+ await observed?.response.body?.pipeTo(new WritableStream())
63
+ await expect(observed?.settled).resolves.toBeUndefined()
64
+ })
@@ -0,0 +1,77 @@
1
+ import { DeferredPromise } from '@open-draft/deferred-promise'
2
+ import { FetchResponse } from '@mswjs/interceptors'
3
+ import { copyResponseOwnProperties } from '../HttpResponse/decorators'
4
+
5
+ export interface ObservedResponse {
6
+ response: Response
7
+ /**
8
+ * A promise that resolves once the response body stream has settled:
9
+ * it was closed, errored, or canceled, and will not be used anymore.
10
+ */
11
+ settled: Promise<void>
12
+ }
13
+
14
+ /**
15
+ * Observe the `ReadableStream` body of the given response.
16
+ * Returns a copy of that response whose body reports when it has
17
+ * settled (was read to completion, errored, or canceled by the consumer).
18
+ * Returns `null` for responses whose body cannot be observed
19
+ * (no body, already used, or locked).
20
+ */
21
+ export function observeResponseBodyStream(
22
+ response: Response,
23
+ ): ObservedResponse | null {
24
+ if (response.body == null || response.bodyUsed || response.body.locked) {
25
+ return null
26
+ }
27
+
28
+ const settled = new DeferredPromise<void>()
29
+ const reader = response.body.getReader()
30
+
31
+ /**
32
+ * @note Relay the body through a manual underlying source instead of
33
+ * `.pipeThrough(new TransformStream({ flush, cancel }))`. The `cancel`
34
+ * transformer callback is not implemented in Chromium, which loses
35
+ * the stream error/cancelation signals there entirely.
36
+ */
37
+ const observedStream = new ReadableStream<Uint8Array>({
38
+ async pull(controller) {
39
+ try {
40
+ const readResult = await reader.read()
41
+
42
+ if (readResult.done) {
43
+ settled.resolve()
44
+ controller.close()
45
+ return
46
+ }
47
+
48
+ controller.enqueue(readResult.value)
49
+ } catch (error) {
50
+ settled.resolve()
51
+ throw error
52
+ }
53
+ },
54
+ async cancel(reason) {
55
+ settled.resolve()
56
+ await reader.cancel(reason)
57
+ },
58
+ })
59
+
60
+ /**
61
+ * @note Reconstruct the response because the body of an existing
62
+ * response cannot be replaced. Use `FetchResponse` to support
63
+ * non-standard response status codes (e.g. 101).
64
+ */
65
+ const observedResponse = new FetchResponse(observedStream, {
66
+ status: response.status,
67
+ statusText: response.statusText,
68
+ headers: response.headers,
69
+ })
70
+
71
+ copyResponseOwnProperties(response, observedResponse)
72
+
73
+ return {
74
+ response: observedResponse,
75
+ settled,
76
+ }
77
+ }
@@ -3,10 +3,8 @@
3
3
  */
4
4
  import { encodeBuffer } from '@mswjs/interceptors'
5
5
  import { OperationTypeNode } from 'graphql'
6
- import {
7
- ParsedGraphQLRequest,
8
- parseGraphQLRequest,
9
- } from './parseGraphQLRequest'
6
+ import type { ParsedGraphQLRequest } from './parseGraphQLRequest'
7
+ import { parseGraphQLRequest } from './parseGraphQLRequest'
10
8
 
11
9
  test('returns true given a GraphQL-compatible request', async () => {
12
10
  const getRequest = new Request(
@@ -1,5 +1,5 @@
1
1
  import { stringToHeaders } from 'headers-polyfill'
2
- import { DefaultRequestMultipartBody } from '../../handlers/RequestHandler'
2
+ import { type DefaultRequestMultipartBody } from '../../handlers/RequestHandler'
3
3
 
4
4
  interface ParsedContentHeaders {
5
5
  name: string
@@ -1,4 +1,5 @@
1
- import { Emitter, EventMap } from 'strict-event-emitter'
1
+ import type { Emitter } from 'strict-event-emitter'
2
+ import { type EventMap } from 'strict-event-emitter'
2
3
 
3
4
  /**
4
5
  * Pipes all emitted events from one emitter to another.
@@ -1,8 +1,6 @@
1
1
  // @vitest-environment jsdom
2
- import {
3
- onUnhandledRequest,
4
- UnhandledRequestCallback,
5
- } from './onUnhandledRequest'
2
+ import type { UnhandledRequestCallback } from './onUnhandledRequest'
3
+ import { onUnhandledRequest } from './onUnhandledRequest'
6
4
 
7
5
  const fixtures = {
8
6
  warningWithoutSuggestions: (url = `/api`) => `\
@@ -1,5 +1,5 @@
1
1
  import { cookieStore } from '../cookieStore'
2
- import { kSetCookie } from '../HttpResponse/decorators'
2
+ import { getRawSetCookie } from '../HttpResponse/decorators'
3
3
 
4
4
  export async function storeResponseCookies(
5
5
  request: Request,
@@ -7,9 +7,7 @@ export async function storeResponseCookies(
7
7
  ): Promise<void> {
8
8
  // Grab the raw "Set-Cookie" response header provided
9
9
  // in the HeadersInit for this mocked response.
10
- const responseCookies = Reflect.get(response, kSetCookie) as
11
- | string
12
- | undefined
10
+ const responseCookies = getRawSetCookie(response)
13
11
 
14
12
  if (responseCookies) {
15
13
  await cookieStore.setCookie(responseCookies, request.url)
@@ -1,10 +1,8 @@
1
1
  // @vitest-environment node-websocket
2
2
  import { setMaxListeners } from 'node:events'
3
3
  import { WebSocketClientConnection } from '@mswjs/interceptors/WebSocket'
4
- import {
5
- WebSocketClientManager,
6
- WebSocketBroadcastChannelMessage,
7
- } from './WebSocketClientManager'
4
+ import type { WebSocketBroadcastChannelMessage } from './WebSocketClientManager'
5
+ import { WebSocketClientManager } from './WebSocketClientManager'
8
6
  import { TestWebSocketTransport } from '../../../test/support/ws-test-utils'
9
7
 
10
8
  const channel = new BroadcastChannel('test:channel')
@@ -3,7 +3,7 @@ import type {
3
3
  WebSocketClientConnectionProtocol,
4
4
  WebSocketClientEventMap,
5
5
  } from '@mswjs/interceptors/WebSocket'
6
- import { WebSocketClientStore } from './WebSocketClientStore'
6
+ import type { WebSocketClientStore } from './WebSocketClientStore'
7
7
  import { WebSocketMemoryClientStore } from './WebSocketMemoryClientStore'
8
8
  import { WebSocketIndexedDBClientStore } from './WebSocketIndexedDBClientStore'
9
9
 
@@ -1,9 +1,7 @@
1
1
  import { DeferredPromise } from '@open-draft/deferred-promise'
2
- import { WebSocketClientConnectionProtocol } from '@mswjs/interceptors/WebSocket'
3
- import {
4
- type SerializedWebSocketClient,
5
- WebSocketClientStore,
6
- } from './WebSocketClientStore'
2
+ import type { WebSocketClientConnectionProtocol } from '@mswjs/interceptors/WebSocket'
3
+ import type { WebSocketClientStore } from './WebSocketClientStore'
4
+ import { type SerializedWebSocketClient } from './WebSocketClientStore'
7
5
 
8
6
  const DB_NAME = 'msw-websocket-clients'
9
7
  const DB_STORE_NAME = 'clients'
@@ -1,8 +1,6 @@
1
- import { WebSocketClientConnectionProtocol } from '@mswjs/interceptors/WebSocket'
2
- import {
3
- SerializedWebSocketClient,
4
- WebSocketClientStore,
5
- } from './WebSocketClientStore'
1
+ import type { WebSocketClientConnectionProtocol } from '@mswjs/interceptors/WebSocket'
2
+ import type { WebSocketClientStore } from './WebSocketClientStore'
3
+ import { type SerializedWebSocketClient } from './WebSocketClientStore'
6
4
 
7
5
  export class WebSocketMemoryClientStore implements WebSocketClientStore {
8
6
  private store: Map<string, SerializedWebSocketClient>
@@ -1,10 +1,10 @@
1
1
  import type { WebSocketConnectionData } from '@mswjs/interceptors/WebSocket'
2
- import { RequestHandler } from '../handlers/RequestHandler'
3
- import { WebSocketHandler } from '../handlers/WebSocketHandler'
2
+ import type { RequestHandler } from '../handlers/RequestHandler'
3
+ import type { WebSocketHandler } from '../handlers/WebSocketHandler'
4
4
  import { webSocketInterceptor } from './webSocketInterceptor'
5
5
  import {
6
6
  onUnhandledRequest,
7
- UnhandledRequestStrategy,
7
+ type UnhandledRequestStrategy,
8
8
  } from '../utils/request/onUnhandledRequest'
9
9
  import { isHandlerKind } from '../utils/internal/isHandlerKind'
10
10
 
package/src/core/ws.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { invariant } from 'outvariant'
2
+ import { FetchResponse, resolveWebSocketUrl } from '@mswjs/interceptors'
2
3
  import type {
3
4
  WebSocketData,
4
5
  WebSocketClientConnectionProtocol,
@@ -9,8 +10,15 @@ import {
9
10
  type WebSocketHandlerEventMap,
10
11
  } from './handlers/WebSocketHandler'
11
12
  import { hasRefCounted } from './utils/internal/hasRefCounted'
12
- import { type Path, isPath } from './utils/matching/matchRequestUrl'
13
+ import {
14
+ type Path,
15
+ type PathParams,
16
+ isPath,
17
+ matchRequestUrl,
18
+ } from './utils/matching/matchRequestUrl'
13
19
  import { WebSocketClientManager } from './ws/WebSocketClientManager'
20
+ import { http } from './http'
21
+ import { attachSiblingHandlers } from './utils/internal/attachSiblingHandlers'
14
22
 
15
23
  const webSocketChannel = new BroadcastChannel('msw:websocket-client-manager')
16
24
 
@@ -100,18 +108,29 @@ function createWebSocketLinkHandler(url: Path): WebSocketLink {
100
108
 
101
109
  const clientManager = new WebSocketClientManager(webSocketChannel)
102
110
 
111
+ // The same upgrade handler instance is attached as a sibling to every
112
+ // WebSocketHandler returned by this link. `groupHandlersByKind` dedupes
113
+ // by reference, so it lands in the `request` bucket exactly once regardless
114
+ // of which subset of WS handlers the user ends up registering.
115
+ const upgradeHandler = http.get(({ request }) => {
116
+ return (
117
+ request.headers.get('upgrade')?.toLowerCase() === 'websocket' &&
118
+ matchRequestUrl(new URL(resolveWebSocketUrl(request.url)), url).matches
119
+ )
120
+ }, ws.onUpgrade)
121
+
103
122
  return {
104
123
  get clients() {
105
124
  return clientManager.clients
106
125
  },
107
126
  addEventListener(event, listener) {
108
- const handler = new WebSocketHandler(url)
127
+ const webSocketHandler = new WebSocketHandler(url)
109
128
 
110
129
  // Add the connection event listener for when the
111
130
  // handler matches and emits a connection event.
112
131
  // When that happens, store that connection in the
113
132
  // set of all connections for reference.
114
- handler[kEmitter].on('connection', async ({ client }) => {
133
+ webSocketHandler[kEmitter].on('connection', async ({ client }) => {
115
134
  await clientManager.addConnection(client)
116
135
  })
117
136
 
@@ -119,9 +138,9 @@ function createWebSocketLinkHandler(url: Path): WebSocketLink {
119
138
  // the "run()" method on the WebSocketHandler.
120
139
  // If the handler matches, it will emit the "connection"
121
140
  // event. Attach the user-defined listener to that event.
122
- handler[kEmitter].on(event, listener)
141
+ webSocketHandler[kEmitter].on(event, listener)
123
142
 
124
- return handler
143
+ return attachSiblingHandlers(webSocketHandler, [upgradeHandler])
125
144
  },
126
145
 
127
146
  broadcast(data) {
@@ -145,6 +164,24 @@ function createWebSocketLinkHandler(url: Path): WebSocketLink {
145
164
  }
146
165
  }
147
166
 
167
+ const WEBSOCKET_GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
168
+
169
+ interface WebSocketNamespace {
170
+ link: typeof createWebSocketLinkHandler
171
+ /**
172
+ * Request handler for the `upgrade` requests to the WebSocket protocol.
173
+ * This requires a WebSocket handler to be present to fire.
174
+ * @note This only affects Node.js as the `upgrade` request header is
175
+ * forbidden and cannot be read in the browser. Consider using the
176
+ * `WebSocket` API for establishing WebSocket connections in the browser.
177
+ */
178
+ onUpgrade: (info: {
179
+ requestId: string
180
+ request: Request
181
+ params: PathParams
182
+ }) => Promise<Response | undefined> | Response | undefined
183
+ }
184
+
148
185
  /**
149
186
  * A namespace to intercept and mock WebSocket connections.
150
187
  *
@@ -154,8 +191,30 @@ function createWebSocketLinkHandler(url: Path): WebSocketLink {
154
191
  * @see {@link https://mswjs.io/docs/api/ws `ws` API reference}
155
192
  * @see {@link https://mswjs.io/docs/basics/handling-websocket-events Handling WebSocket events}
156
193
  */
157
- export const ws = {
194
+ export const ws: WebSocketNamespace = {
158
195
  link: createWebSocketLinkHandler,
196
+ async onUpgrade({ request }) {
197
+ const key = request.headers.get('sec-websocket-key')
198
+
199
+ if (!key) {
200
+ return
201
+ }
202
+
203
+ const keyBytes = new TextEncoder().encode(key + WEBSOCKET_GUID)
204
+ const digest = await crypto.subtle.digest('SHA-1', keyBytes)
205
+ const acceptValue = btoa(String.fromCharCode(...new Uint8Array(digest)))
206
+
207
+ new WebSocket(resolveWebSocketUrl(request.url))
208
+
209
+ return new FetchResponse(null, {
210
+ status: 101,
211
+ headers: {
212
+ upgrade: 'websocket',
213
+ connection: 'upgrade',
214
+ 'sec-websocket-accept': acceptValue,
215
+ },
216
+ })
217
+ },
159
218
  }
160
219
 
161
- export { WebSocketData }
220
+ export { type WebSocketData }
@@ -137,8 +137,18 @@ async function handleRequest(event, requestId, requestInterceptedAt) {
137
137
  if (client && activeClientIds.has(client.id)) {
138
138
  const serializedRequest = await serializeRequest(requestCloneForEvents)
139
139
 
140
+ // Omit the body of server-sent event stream responses.
141
+ // Cloning such responses would prevent client-side stream cancelations
142
+ // from reaching the original stream (a teed stream only cancels its
143
+ // source once both of its branches cancel) and would buffer the
144
+ // entire stream into the unconsumed clone indefinitely.
145
+ const isEventStreamResponse = response.headers
146
+ .get('content-type')
147
+ ?.toLowerCase()
148
+ .startsWith('text/event-stream')
149
+
140
150
  // Clone the response so both the client and the library could consume it.
141
- const responseClone = response.clone()
151
+ const responseClone = isEventStreamResponse ? null : response.clone()
142
152
 
143
153
  sendToClient(
144
154
  client,
@@ -151,15 +161,17 @@ async function handleRequest(event, requestId, requestInterceptedAt) {
151
161
  ...serializedRequest,
152
162
  },
153
163
  response: {
154
- type: responseClone.type,
155
- status: responseClone.status,
156
- statusText: responseClone.statusText,
157
- headers: Object.fromEntries(responseClone.headers.entries()),
158
- body: responseClone.body,
164
+ type: response.type,
165
+ status: response.status,
166
+ statusText: response.statusText,
167
+ headers: Object.fromEntries(response.headers.entries()),
168
+ body: responseClone ? responseClone.body : null,
159
169
  },
160
170
  },
161
171
  },
162
- responseClone.body ? [serializedRequest.body, responseClone.body] : [],
172
+ responseClone && responseClone.body
173
+ ? [serializedRequest.body, responseClone.body]
174
+ : [],
163
175
  )
164
176
  }
165
177
 
@@ -1,10 +1,10 @@
1
1
  import type { Interceptor } from '@mswjs/interceptors'
2
2
  import { FetchInterceptor } from '@mswjs/interceptors/fetch'
3
3
  import { XMLHttpRequestInterceptor } from '@mswjs/interceptors/XMLHttpRequest'
4
- import { type AnyHandler } from '#core/experimental/handlers-controller'
4
+ import type { AnyHandler } from '#core/experimental/handlers-controller'
5
5
  import {
6
6
  defineNetwork,
7
- DefineNetworkOptions,
7
+ type DefineNetworkOptions,
8
8
  } from '#core/experimental/define-network'
9
9
  import { InterceptorSource } from '#core/experimental/sources/interceptor-source'
10
10
  import { type SetupServerCommon } from '../node/glossary'
@@ -1,9 +1,9 @@
1
1
  import { AsyncLocalStorage } from 'node:async_hooks'
2
2
  import {
3
+ HandlersController,
3
4
  type AnyHandler,
4
5
  type HandlersMap,
5
- HandlersController,
6
- HandlersControllerState,
6
+ type HandlersControllerState,
7
7
  } from '#core/experimental/handlers-controller'
8
8
 
9
9
  export interface AsyncHandlersControllerContext {
package/src/node/index.ts CHANGED
@@ -5,3 +5,4 @@ export {
5
5
  defaultNetworkOptions,
6
6
  } from './setup-server'
7
7
  export { SetupServerCommonApi } from './setup-server-common'
8
+ export { AsyncHandlersController } from './async-handlers-controller'
@@ -1,12 +1,12 @@
1
1
  import type { PartialDeep } from 'type-fest'
2
- import { Interceptor } from '@mswjs/interceptors'
2
+ import type { Interceptor } from '@mswjs/interceptors'
3
3
  import {
4
- type NetworkApi,
5
4
  NetworkReadyState,
6
5
  defineNetwork,
6
+ type NetworkApi,
7
7
  } from '#core/experimental/define-network'
8
- import { type AnyHandler } from '#core/experimental/handlers-controller'
9
- import { type HandlersController } from '#core/experimental/handlers-controller'
8
+ import type { AnyHandler } from '#core/experimental/handlers-controller'
9
+ import type { HandlersController } from '#core/experimental/handlers-controller'
10
10
  import { InterceptorSource } from '#core/experimental/sources/interceptor-source'
11
11
  import { fromLegacyOnUnhandledRequest } from '#core/experimental/compat'
12
12
  import type { ListenOptions, SetupServerCommon } from './glossary'
@@ -7,9 +7,9 @@ import {
7
7
  defineNetwork,
8
8
  type DefineNetworkOptions,
9
9
  } from '#core/experimental/define-network'
10
- import { type AnyHandler } from '#core/experimental/handlers-controller'
10
+ import type { AnyHandler } from '#core/experimental/handlers-controller'
11
11
  import { InterceptorSource } from '#core/experimental/sources/interceptor-source'
12
- import { SetupServer } from './glossary'
12
+ import type { SetupServer } from './glossary'
13
13
  import { AsyncHandlersController } from './async-handlers-controller'
14
14
  import {
15
15
  defineSetupServerApi,
@@ -1,12 +0,0 @@
1
- import { R as RequestHandler, r as RequestHandlerDefaultInfo, c as RequestHandlerOptions } from '../../HttpResponse-DlRR1D-f.mjs';
2
- import '@mswjs/interceptors';
3
- import './isIterable.mjs';
4
- import '../../typeUtils.mjs';
5
- import 'graphql';
6
- import '../matching/matchRequestUrl.mjs';
7
-
8
- declare function use(currentHandlers: Array<RequestHandler>, ...handlers: Array<RequestHandler>): void;
9
- declare function restoreHandlers(handlers: Array<RequestHandler>): void;
10
- declare function resetHandlers(initialHandlers: Array<RequestHandler>, ...nextHandlers: Array<RequestHandler>): RequestHandler<RequestHandlerDefaultInfo, any, any, RequestHandlerOptions>[];
11
-
12
- export { resetHandlers, restoreHandlers, use };
@@ -1,12 +0,0 @@
1
- import { R as RequestHandler, r as RequestHandlerDefaultInfo, c as RequestHandlerOptions } from '../../HttpResponse-CksOMVAa.js';
2
- import '@mswjs/interceptors';
3
- import './isIterable.js';
4
- import '../../typeUtils.js';
5
- import 'graphql';
6
- import '../matching/matchRequestUrl.js';
7
-
8
- declare function use(currentHandlers: Array<RequestHandler>, ...handlers: Array<RequestHandler>): void;
9
- declare function restoreHandlers(handlers: Array<RequestHandler>): void;
10
- declare function resetHandlers(initialHandlers: Array<RequestHandler>, ...nextHandlers: Array<RequestHandler>): RequestHandler<RequestHandlerDefaultInfo, any, any, RequestHandlerOptions>[];
11
-
12
- export { resetHandlers, restoreHandlers, use };