@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
@@ -125,3 +125,61 @@ describe('parse', () => {
125
125
  })
126
126
  })
127
127
  })
128
+
129
+ describe('test', () => {
130
+ it('returns true for a matching string', () => {
131
+ expect(
132
+ new WebSocketHandler('ws://localhost/ws').test('ws://localhost/ws'),
133
+ ).toBe(true)
134
+ })
135
+
136
+ it('returns false for a non-matching string', () => {
137
+ expect(
138
+ new WebSocketHandler('ws://localhost/ws').test('ws://localhost/other'),
139
+ ).toBe(false)
140
+ })
141
+
142
+ it('returns true for a relative matching string', () => {
143
+ expect(
144
+ new WebSocketHandler('ws://localhost/ws').test('/ws', {
145
+ baseUrl: 'ws://localhost',
146
+ }),
147
+ ).toBe(true)
148
+ })
149
+
150
+ it('returns false for a relative non-matching string', () => {
151
+ expect(
152
+ new WebSocketHandler('ws://localhost/ws').test('/other', {
153
+ baseUrl: 'ws://localhost',
154
+ }),
155
+ ).toBe(false)
156
+ })
157
+
158
+ it('returns true for a matching URL', () => {
159
+ expect(
160
+ new WebSocketHandler('ws://localhost/ws').test(
161
+ new URL('ws://localhost/ws'),
162
+ ),
163
+ ).toBe(true)
164
+ })
165
+
166
+ it('returns false for a non-matching URL', () => {
167
+ expect(
168
+ new WebSocketHandler('ws://localhost/ws').test(
169
+ new URL('ws://localhost/other'),
170
+ ),
171
+ ).toBe(false)
172
+ })
173
+
174
+ it('returns true for a matching HTTP url string', () => {
175
+ expect(
176
+ new WebSocketHandler('ws://localhost/ws').test('http://localhost/ws'),
177
+ ).toBe(true)
178
+ })
179
+
180
+ it('returns false for a non-matching HTTP url string', () => {
181
+ expect(
182
+ new WebSocketHandler('ws://localhost/ws').test('http://localhost/other'),
183
+ ).toBe(false)
184
+ })
185
+ })
@@ -57,7 +57,7 @@ export class WebSocketHandler {
57
57
  }
58
58
 
59
59
  public parse(args: {
60
- url: URL
60
+ url: string | URL
61
61
  resolutionContext?: WebSocketResolutionContext
62
62
  }): WebSocketHandlerParsedResult {
63
63
  const clientUrl = new URL(args.url)
@@ -90,22 +90,26 @@ export class WebSocketHandler {
90
90
  }
91
91
 
92
92
  public predicate(args: {
93
- url: URL
93
+ url: string | URL
94
94
  parsedResult: WebSocketHandlerParsedResult
95
95
  }): boolean {
96
96
  return args.parsedResult.match.matches
97
97
  }
98
98
 
99
+ public test(
100
+ url: string | URL,
101
+ resolutionContext?: WebSocketResolutionContext & { strict?: boolean },
102
+ ): boolean {
103
+ return this.#match(url, resolutionContext) != null
104
+ }
105
+
99
106
  public async run(
100
107
  connection: WebSocketConnectionData,
101
108
  resolutionContext?: WebSocketResolutionContext,
102
109
  ): Promise<WebSocketHandlerConnection | null> {
103
- const parsedResult = this.parse({
104
- url: connection.client.url,
105
- resolutionContext,
106
- })
110
+ const parsedResult = this.#match(connection.client.url, resolutionContext)
107
111
 
108
- if (!this.predicate({ url: connection.client.url, parsedResult })) {
112
+ if (parsedResult == null) {
109
113
  return null
110
114
  }
111
115
 
@@ -114,7 +118,7 @@ export class WebSocketHandler {
114
118
  params: parsedResult.match.params || {},
115
119
  }
116
120
 
117
- if (resolutionContext?.[kAutoConnect]) {
121
+ if (resolutionContext?.[kAutoConnect] ?? true) {
118
122
  if (this[kConnect](resolvedConnection)) {
119
123
  return resolvedConnection
120
124
  }
@@ -125,6 +129,31 @@ export class WebSocketHandler {
125
129
  return resolvedConnection
126
130
  }
127
131
 
132
+ #match(
133
+ url: string | URL,
134
+ resolutionContext?: WebSocketResolutionContext & { strict?: boolean },
135
+ ): WebSocketHandlerParsedResult | null {
136
+ const resolvedUrl = this.#resolveWebSocketUrl(
137
+ url.toString(),
138
+ resolutionContext?.baseUrl,
139
+ )
140
+ const parsedResult = this.parse({
141
+ url: resolvedUrl,
142
+ resolutionContext,
143
+ })
144
+
145
+ if (
146
+ this.predicate({
147
+ url,
148
+ parsedResult,
149
+ })
150
+ ) {
151
+ return parsedResult
152
+ }
153
+
154
+ return null
155
+ }
156
+
128
157
  protected [kConnect](connection: WebSocketHandlerConnection): boolean {
129
158
  // Support `event.stopPropagation()` for various client/server events.
130
159
  connection.client.addEventListener(
package/src/core/http.ts CHANGED
@@ -1,13 +1,13 @@
1
1
  import {
2
- DefaultBodyType,
3
- RequestHandlerOptions,
4
- ResponseResolver,
2
+ type DefaultBodyType,
3
+ type RequestHandlerOptions,
4
+ type ResponseResolver,
5
5
  } from './handlers/RequestHandler'
6
6
  import {
7
7
  HttpMethods,
8
8
  HttpHandler,
9
- HttpRequestResolverExtras,
10
- HttpRequestPredicate,
9
+ type HttpRequestResolverExtras,
10
+ type HttpRequestPredicate,
11
11
  } from './handlers/HttpHandler'
12
12
  import type { PathParams } from './utils/matching/matchRequestUrl'
13
13
 
package/src/core/sse.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { invariant } from 'outvariant'
2
- import { Emitter } from 'strict-event-emitter'
2
+ import { DeferredPromise } from '@open-draft/deferred-promise'
3
+ import { Emitter, TypedEvent } from 'rettime'
3
4
  import type { ResponseResolver } from './handlers/RequestHandler'
4
5
  import {
5
6
  HttpHandler,
@@ -79,7 +80,7 @@ const SSE_RESPONSE_INIT: ResponseInit = {
79
80
  class ServerSentEventHandler<
80
81
  EventMap extends EventMapConstraint,
81
82
  > extends HttpHandler {
82
- #emitter: Emitter<ServerSentEventClientEventMap>
83
+ #loggableRequests: WeakSet<Request>
83
84
 
84
85
  constructor(path: Path, resolver: ServerSentEventResolver<EventMap, any>) {
85
86
  invariant(
@@ -89,29 +90,37 @@ class ServerSentEventHandler<
89
90
  )
90
91
 
91
92
  super('GET', path, async (info) => {
92
- const stream = new ReadableStream({
93
- start: async (controller) => {
94
- const client = new ServerSentEventClient<EventMap>({
95
- controller,
96
- emitter: this.#emitter,
97
- })
98
- const server = new ServerSentEventServer({
99
- request: info.request,
100
- client,
101
- })
102
-
103
- await resolver({
104
- ...info,
105
- client,
106
- server,
107
- })
108
- },
109
- })
93
+ const { client, server, response } = createEventStream<EventMap>(
94
+ info.request,
95
+ )
96
+
97
+ /**
98
+ * @note Scope the emitter to this connection so its logging
99
+ * listeners don't accumulate on the handler across connections.
100
+ */
101
+ const emitter = new Emitter<ServerSentEventClientEventMap>()
102
+ client[kClientEmitter] = emitter
103
+
104
+ if (this.#loggableRequests.has(info.request)) {
105
+ this.#attachClientLogger(info.request, emitter)
106
+ }
107
+
108
+ /**
109
+ * @note Extend the resolver info via assignment instead of a spread.
110
+ * Spreading the info would invoke its lazy `finalize` getter,
111
+ * initializing the finalize machinery for resolvers that never use it.
112
+ */
113
+ await resolver(
114
+ Object.assign(info, {
115
+ client,
116
+ server,
117
+ }),
118
+ )
110
119
 
111
- return new Response(stream, SSE_RESPONSE_INIT)
120
+ return response
112
121
  })
113
122
 
114
- this.#emitter = new Emitter<ServerSentEventClientEventMap>()
123
+ this.#loggableRequests = new WeakSet()
115
124
  }
116
125
 
117
126
  async predicate(args: {
@@ -140,13 +149,22 @@ class ServerSentEventHandler<
140
149
  response: new Response('[streaming]', SSE_RESPONSE_INIT),
141
150
  })
142
151
 
143
- this.#attachClientLogger(args.request, this.#emitter)
152
+ // Defer attaching the client logger until the resolver runs
153
+ // and creates a connection-scoped emitter for this request.
154
+ this.#loggableRequests.add(args.request)
144
155
  }
145
156
 
146
157
  return matches
147
158
  }
148
159
 
149
- async log(_args: { request: Request; response: Response }): Promise<void> {
160
+ async log(args: { request: Request; response: Response }): Promise<void> {
161
+ /**
162
+ * @note Cancel the response stream because it's not needed for logging.
163
+ * Otherwise, this cloned response remains unconsumed and its original
164
+ * doesn't propagate stream cancelations at all.
165
+ */
166
+ args.response.body?.cancel()
167
+
150
168
  /**
151
169
  * @note Skip the default `this.log()` logic so that when this handler is logged
152
170
  * upon handling the request, nothing is printed (we log SSE requests early).
@@ -161,16 +179,14 @@ class ServerSentEventHandler<
161
179
  const publicUrl = toPublicUrl(request.url)
162
180
 
163
181
  /* eslint-disable no-console */
164
- emitter.on('message', (payload) => {
182
+ emitter.on('message', ({ data }) => {
165
183
  console.groupCollapsed(
166
- devUtils.formatMessage(
167
- `${getTimestamp()} SSE %s %c⇣%c ${payload.event}`,
168
- ),
184
+ devUtils.formatMessage(`${getTimestamp()} SSE %s %c⇣%c ${data.event}`),
169
185
  publicUrl,
170
186
  `color:${colors.mocked}`,
171
187
  'color:inherit',
172
188
  )
173
- console.log(payload.frames)
189
+ console.log(data.frames)
174
190
  console.groupEnd()
175
191
  })
176
192
 
@@ -222,32 +238,26 @@ type ToEventDiscriminatedUnion<T> = Values<{
222
238
  }>
223
239
 
224
240
  type ServerSentEventClientEventMap = {
225
- message: [
226
- payload: {
227
- id?: string
228
- event: string
229
- data?: unknown
230
- frames: Array<string>
231
- },
232
- ]
233
- error: []
234
- close: []
241
+ message: TypedEvent<EventStreamMessage>
242
+ error: TypedEvent
243
+ close: TypedEvent
235
244
  }
236
245
 
246
+ const kClientEmitter = Symbol.for('kClientEmitter')
247
+
237
248
  class ServerSentEventClient<
238
249
  EventMap extends EventMapConstraint = { message: unknown },
239
250
  > {
251
+ private [kClientEmitter]?: Emitter<ServerSentEventClientEventMap>
252
+
240
253
  #encoder: TextEncoder
241
- #controller: ReadableStreamDefaultController
242
- #emitter: Emitter<ServerSentEventClientEventMap>
254
+ #controller: ReadableStreamDefaultController<Uint8Array>
255
+ #closed: DeferredPromise<void>
243
256
 
244
- constructor(args: {
245
- controller: ReadableStreamDefaultController
246
- emitter: Emitter<ServerSentEventClientEventMap>
247
- }) {
257
+ constructor(controller: ReadableStreamDefaultController<Uint8Array>) {
248
258
  this.#encoder = new TextEncoder()
249
- this.#controller = args.controller
250
- this.#emitter = args.emitter
259
+ this.#controller = controller
260
+ this.#closed = new DeferredPromise()
251
261
  }
252
262
 
253
263
  /**
@@ -303,24 +313,52 @@ class ServerSentEventClient<
303
313
  * error.
304
314
  */
305
315
  public error(): void {
316
+ if (this.#closed.state !== 'pending') {
317
+ return
318
+ }
319
+
306
320
  this.#controller.error()
307
- this.#emitter.emit('error')
321
+ this.#closed.resolve()
322
+ this[kClientEmitter]?.emit(new TypedEvent('error'))
308
323
  }
309
324
 
310
325
  /**
311
326
  * Closes the underlying `EventSource`, closing the connection.
312
327
  */
313
328
  public close(): void {
314
- this.#controller.close()
315
- this.#emitter.emit('close')
329
+ if (this.#closed.state !== 'pending') {
330
+ return
331
+ }
332
+
333
+ try {
334
+ this.#controller.close()
335
+ this.#closed.resolve()
336
+ } catch {
337
+ //
338
+ }
339
+
340
+ this[kClientEmitter]?.emit(new TypedEvent('close'))
316
341
  }
317
342
 
318
- #sendRetry(retry: number): void {
319
- if (typeof retry === 'number') {
320
- this.#controller.enqueue(this.#encoder.encode(`retry:${retry}\n\n`))
343
+ #enqueue(chunk: Uint8Array): void {
344
+ if (this.#closed.state !== 'pending') {
345
+ return
346
+ }
347
+
348
+ try {
349
+ this.#controller.enqueue(chunk)
350
+ } catch (error) {
351
+ console.error(error)
352
+ devUtils.error(
353
+ 'Failed to write to server-side EventSource. Please see the original error above.',
354
+ )
321
355
  }
322
356
  }
323
357
 
358
+ #sendRetry(retry: number): void {
359
+ this.#enqueue(this.#encoder.encode(`retry:${retry}\n\n`))
360
+ }
361
+
324
362
  #sendMessage(message: {
325
363
  id?: string
326
364
  event?: unknown
@@ -349,14 +387,18 @@ class ServerSentEventClient<
349
387
 
350
388
  frames.push('', '')
351
389
 
352
- this.#controller.enqueue(this.#encoder.encode(frames.join('\n')))
390
+ this.#enqueue(this.#encoder.encode(frames.join('\n')))
353
391
 
354
- this.#emitter.emit('message', {
355
- id: message.id,
356
- event: message.event?.toString() || 'message',
357
- data: message.data,
358
- frames,
359
- })
392
+ this[kClientEmitter]?.emit(
393
+ new TypedEvent('message', {
394
+ data: {
395
+ id: message.id,
396
+ event: message.event?.toString() || 'message',
397
+ data: message.data,
398
+ frames,
399
+ },
400
+ }),
401
+ )
360
402
  }
361
403
  }
362
404
 
@@ -383,6 +425,7 @@ class ServerSentEventServer {
383
425
  */
384
426
  accept: 'msw/passthrough',
385
427
  },
428
+ signal: this.#request.signal,
386
429
  })
387
430
 
388
431
  source[kOnAnyMessage] = (event) => {
@@ -429,6 +472,7 @@ class ServerSentEventServer {
429
472
 
430
473
  interface ObservableEventSourceInit extends EventSourceInit {
431
474
  headers?: HeadersInit
475
+ signal?: AbortSignal
432
476
  }
433
477
 
434
478
  type EventHandler<EventType extends Event> = (
@@ -489,6 +533,18 @@ class ObservableEventSource extends EventTarget implements EventSource {
489
533
  signal: this[kAbortController].signal,
490
534
  })
491
535
 
536
+ if (init?.signal) {
537
+ if (init.signal.aborted) {
538
+ this.close()
539
+ return
540
+ }
541
+
542
+ init.signal.addEventListener('abort', () => this.close(), {
543
+ once: true,
544
+ signal: this[kAbortController].signal,
545
+ })
546
+ }
547
+
492
548
  this.connect()
493
549
  }
494
550
 
@@ -518,7 +574,7 @@ class ObservableEventSource extends EventTarget implements EventSource {
518
574
  get onerror(): EventHandler<Event> | null {
519
575
  return this[kOnError]
520
576
  }
521
- set oneerror(handler: EventHandler<Event>) {
577
+ set onerror(handler: EventHandler<Event>) {
522
578
  if (this[kOnError]) {
523
579
  this.removeEventListener('error', { handleEvent: this[kOnError] })
524
580
  }
@@ -642,10 +698,6 @@ class ObservableEventSource extends EventTarget implements EventSource {
642
698
  this[kLastEventId] = message.id
643
699
  }
644
700
 
645
- if (message.retry) {
646
- this[kReconnectionTime] = message.retry
647
- }
648
-
649
701
  const messageEvent = new MessageEvent(
650
702
  message.event ? message.event : 'message',
651
703
  {
@@ -659,6 +711,9 @@ class ObservableEventSource extends EventTarget implements EventSource {
659
711
  this[kOnAnyMessage]?.(messageEvent)
660
712
  this.dispatchEvent(messageEvent)
661
713
  },
714
+ retry: (reconnectionTime) => {
715
+ this[kReconnectionTime] = reconnectionTime
716
+ },
662
717
  abort: () => {
663
718
  throw new Error('Stream abort is not implemented')
664
719
  },
@@ -693,7 +748,25 @@ class ObservableEventSource extends EventTarget implements EventSource {
693
748
  this.dispatchEvent(new Event('error'))
694
749
  })
695
750
 
696
- await delay(this[kReconnectionTime])
751
+ const signal = this[kAbortController].signal
752
+
753
+ if (signal.aborted) {
754
+ return
755
+ }
756
+
757
+ const aborted = new DeferredPromise<void>()
758
+ const onAbort = () => aborted.resolve()
759
+ signal.addEventListener('abort', onAbort, { once: true })
760
+
761
+ await Promise.race([delay(this[kReconnectionTime]), aborted]).finally(
762
+ () => {
763
+ signal.removeEventListener('abort', onAbort)
764
+ },
765
+ )
766
+
767
+ if (signal.aborted) {
768
+ return
769
+ }
697
770
 
698
771
  queueMicrotask(async () => {
699
772
  if (this.readyState !== this.CONNECTING) {
@@ -743,7 +816,6 @@ interface EventSourceMessage {
743
816
  id?: string
744
817
  event?: string
745
818
  data?: string
746
- retry?: number
747
819
  }
748
820
 
749
821
  class EventSourceParsingStream extends WritableStream {
@@ -758,12 +830,12 @@ class EventSourceParsingStream extends WritableStream {
758
830
  id: undefined,
759
831
  event: undefined,
760
832
  data: undefined,
761
- retry: undefined,
762
833
  }
763
834
 
764
835
  constructor(
765
836
  private underlyingSink: {
766
837
  message: (message: EventSourceMessage) => void
838
+ retry?: (reconnectionTime: number) => void
767
839
  abort?: (reason: any) => void
768
840
  close?: () => void
769
841
  },
@@ -789,7 +861,6 @@ class EventSourceParsingStream extends WritableStream {
789
861
  id: undefined,
790
862
  event: undefined,
791
863
  data: undefined,
792
- retry: undefined,
793
864
  }
794
865
  }
795
866
 
@@ -903,10 +974,12 @@ class EventSourceParsingStream extends WritableStream {
903
974
  }
904
975
 
905
976
  case 'retry': {
906
- const retry = parseInt(value, 10)
907
-
908
- if (!isNaN(retry)) {
909
- this.message.retry = retry
977
+ /**
978
+ * Apply the retry immediately. Don't buffer onto the current message.
979
+ * @see https://html.spec.whatwg.org/multipage/server-sent-events.html#event-stream-interpretation
980
+ */
981
+ if (/^\d+$/.test(value)) {
982
+ this.underlyingSink.retry?.(parseInt(value, 10))
910
983
  }
911
984
  break
912
985
  }
@@ -914,3 +987,74 @@ class EventSourceParsingStream extends WritableStream {
914
987
  }
915
988
  }
916
989
  }
990
+
991
+ interface EventStreamMessage {
992
+ id?: string
993
+ event: string
994
+ data?: unknown
995
+ frames: Array<string>
996
+ }
997
+
998
+ interface EventStream<EventMap extends EventMapConstraint> {
999
+ client: ServerSentEventClient<EventMap>
1000
+ server: ServerSentEventServer
1001
+ response: Response
1002
+ }
1003
+
1004
+ /**
1005
+ * Create an event stream out of the given Fetch API `Request`.
1006
+ * Returns the following properties:
1007
+ * - `client`, to operate on the intercepted request;
1008
+ * - `server`, to establish and manage the actual server connection;
1009
+ * - `response`, a `Response` to use as the mock response's body.
1010
+ *
1011
+ * @example
1012
+ * http.post('/resource', ({ request }) => {
1013
+ * const { client, server, response } = createEventStream(request)
1014
+ * client.send({ data: 'hello world' })
1015
+ * return response
1016
+ * })
1017
+ */
1018
+ function createEventStream<EventMap extends EventMapConstraint>(
1019
+ request: Request,
1020
+ ): EventStream<EventMap> {
1021
+ invariant(
1022
+ !request.signal.aborted,
1023
+ 'Failed to call "createEventStream" on the "%s %s" request: request aborted',
1024
+ request.method,
1025
+ request.url,
1026
+ )
1027
+
1028
+ let controller!: ReadableStreamDefaultController<Uint8Array>
1029
+
1030
+ const readable = new ReadableStream<Uint8Array>({
1031
+ start(defaultController) {
1032
+ controller = defaultController
1033
+ },
1034
+ cancel() {
1035
+ client.close()
1036
+ },
1037
+ })
1038
+
1039
+ const client = new ServerSentEventClient<EventMap>(controller)
1040
+ const server = new ServerSentEventServer({
1041
+ request,
1042
+ client,
1043
+ })
1044
+
1045
+ const response = new Response(readable, SSE_RESPONSE_INIT)
1046
+
1047
+ request.signal.addEventListener(
1048
+ 'abort',
1049
+ () => {
1050
+ client.close()
1051
+ },
1052
+ { once: true },
1053
+ )
1054
+
1055
+ return {
1056
+ client,
1057
+ server,
1058
+ response,
1059
+ }
1060
+ }
@@ -1,10 +1,9 @@
1
1
  import statuses from '../../../shims/statuses'
2
- import { Headers as HeadersPolyfill } from 'headers-polyfill'
3
- import type { HttpResponseInit } from '../../HttpResponse'
2
+ import type { HttpResponse, HttpResponseInit } from '../../HttpResponse'
4
3
 
5
4
  const { message } = statuses
6
5
 
7
- export const kSetCookie = Symbol('kSetCookie')
6
+ const kSetCookie = Symbol('kSetCookie')
8
7
 
9
8
  export interface HttpResponseDecoratedInit extends HttpResponseInit {
10
9
  status: number
@@ -28,10 +27,10 @@ export function normalizeResponseInit(
28
27
  }
29
28
 
30
29
  export function decorateResponse(
31
- response: Response,
30
+ response: HttpResponse<any>,
32
31
  init: HttpResponseDecoratedInit,
33
32
  ): Response {
34
- // Allow to mock the response type.
33
+ // Allow mocking the response type.
35
34
  if (init.type) {
36
35
  Object.defineProperty(response, 'type', {
37
36
  value: init.type,
@@ -52,25 +51,32 @@ export function decorateResponse(
52
51
  enumerable: false,
53
52
  writable: false,
54
53
  })
54
+ }
55
+
56
+ return response
57
+ }
55
58
 
56
- // Cookie forwarding is only relevant in the browser.
57
- if (typeof document !== 'undefined') {
58
- // Write the mocked response cookies to the document.
59
- // Use `headers-polyfill` to get the Set-Cookie header value correctly.
60
- // This is an alternative until TypeScript 5.2
61
- // and Node.js v20 become the minimum supported version
62
- // and getSetCookie in Headers can be used directly.
63
- const responseCookiePairs = HeadersPolyfill.prototype.getSetCookie.call(
64
- init.headers,
65
- )
59
+ export function getRawSetCookie(response: Response): string | undefined {
60
+ return Reflect.get(response, kSetCookie)
61
+ }
62
+
63
+ /**
64
+ * Copy the given response own properties, like internal symbols,
65
+ * onto another response. Used for faithful internal copying of responses.
66
+ */
67
+ export function copyResponseOwnProperties(
68
+ source: Response,
69
+ target: Response,
70
+ ): void {
71
+ for (const propertyName of Reflect.ownKeys(source)) {
72
+ const descriptor = Object.getOwnPropertyDescriptor(source, propertyName)
73
+ const existingDescriptor = Object.getOwnPropertyDescriptor(
74
+ target,
75
+ propertyName,
76
+ )
66
77
 
67
- for (const cookieString of responseCookiePairs) {
68
- // No need to parse the cookie headers because it's defined
69
- // as the valid cookie string to begin with.
70
- document.cookie = cookieString
71
- }
78
+ if (descriptor && existingDescriptor == null) {
79
+ Object.defineProperty(target, propertyName, descriptor)
72
80
  }
73
81
  }
74
-
75
- return response
76
82
  }