msw 2.12.13 → 2.13.0

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 (272) hide show
  1. package/lib/browser/index.d.mts +29 -19
  2. package/lib/browser/index.d.ts +29 -19
  3. package/lib/browser/index.js +1763 -1321
  4. package/lib/browser/index.js.map +1 -1
  5. package/lib/browser/index.mjs +1769 -1321
  6. package/lib/browser/index.mjs.map +1 -1
  7. package/lib/core/{HttpResponse-Dj6ibgFJ.d.ts → HttpResponse-CksOMVAa.d.ts} +5 -5
  8. package/lib/core/{HttpResponse-Be4eT3x6.d.mts → HttpResponse-DlRR1D-f.d.mts} +5 -5
  9. package/lib/core/HttpResponse.d.mts +1 -1
  10. package/lib/core/HttpResponse.d.ts +1 -1
  11. package/lib/core/experimental/compat.d.mts +17 -0
  12. package/lib/core/experimental/compat.d.ts +17 -0
  13. package/lib/core/experimental/compat.js +54 -0
  14. package/lib/core/experimental/compat.js.map +1 -0
  15. package/lib/core/experimental/compat.mjs +36 -0
  16. package/lib/core/experimental/compat.mjs.map +1 -0
  17. package/lib/core/experimental/define-network.d.mts +75 -0
  18. package/lib/core/experimental/define-network.d.ts +75 -0
  19. package/lib/core/experimental/define-network.js +124 -0
  20. package/lib/core/experimental/define-network.js.map +1 -0
  21. package/lib/core/experimental/define-network.mjs +107 -0
  22. package/lib/core/experimental/define-network.mjs.map +1 -0
  23. package/lib/core/experimental/frames/http-frame.d.mts +77 -0
  24. package/lib/core/experimental/frames/http-frame.d.ts +77 -0
  25. package/lib/core/experimental/frames/http-frame.js +194 -0
  26. package/lib/core/experimental/frames/http-frame.js.map +1 -0
  27. package/lib/core/experimental/frames/http-frame.mjs +176 -0
  28. package/lib/core/experimental/frames/http-frame.mjs.map +1 -0
  29. package/lib/core/experimental/frames/network-frame.d.mts +12 -0
  30. package/lib/core/experimental/frames/network-frame.d.ts +12 -0
  31. package/lib/core/{handlers/common.js → experimental/frames/network-frame.js} +19 -3
  32. package/lib/core/experimental/frames/network-frame.js.map +1 -0
  33. package/lib/core/experimental/frames/network-frame.mjs +13 -0
  34. package/lib/core/experimental/frames/network-frame.mjs.map +1 -0
  35. package/lib/core/experimental/frames/websocket-frame.d.mts +55 -0
  36. package/lib/core/experimental/frames/websocket-frame.d.ts +55 -0
  37. package/lib/core/experimental/frames/websocket-frame.js +129 -0
  38. package/lib/core/experimental/frames/websocket-frame.js.map +1 -0
  39. package/lib/core/experimental/frames/websocket-frame.mjs +116 -0
  40. package/lib/core/experimental/frames/websocket-frame.mjs.map +1 -0
  41. package/lib/core/experimental/handlers-controller.d.mts +35 -0
  42. package/lib/core/experimental/handlers-controller.d.ts +35 -0
  43. package/lib/core/experimental/handlers-controller.js +121 -0
  44. package/lib/core/experimental/handlers-controller.js.map +1 -0
  45. package/lib/core/experimental/handlers-controller.mjs +101 -0
  46. package/lib/core/experimental/handlers-controller.mjs.map +1 -0
  47. package/lib/core/experimental/index.d.mts +17 -0
  48. package/lib/core/experimental/index.d.ts +17 -0
  49. package/lib/core/experimental/index.js +36 -0
  50. package/lib/core/experimental/index.js.map +1 -0
  51. package/lib/core/experimental/index.mjs +20 -0
  52. package/lib/core/experimental/index.mjs.map +1 -0
  53. package/lib/core/experimental/on-unhandled-frame.d.mts +12 -0
  54. package/lib/core/experimental/on-unhandled-frame.d.ts +12 -0
  55. package/lib/core/experimental/on-unhandled-frame.js +90 -0
  56. package/lib/core/experimental/on-unhandled-frame.js.map +1 -0
  57. package/lib/core/experimental/on-unhandled-frame.mjs +70 -0
  58. package/lib/core/experimental/on-unhandled-frame.mjs.map +1 -0
  59. package/lib/core/experimental/request-utils.d.mts +12 -0
  60. package/lib/core/experimental/request-utils.d.ts +12 -0
  61. package/lib/core/experimental/request-utils.js +50 -0
  62. package/lib/core/experimental/request-utils.js.map +1 -0
  63. package/lib/core/experimental/request-utils.mjs +30 -0
  64. package/lib/core/experimental/request-utils.mjs.map +1 -0
  65. package/lib/core/experimental/setup-api.d.mts +33 -0
  66. package/lib/core/experimental/setup-api.d.ts +33 -0
  67. package/lib/core/experimental/setup-api.js +61 -0
  68. package/lib/core/experimental/setup-api.js.map +1 -0
  69. package/lib/core/experimental/setup-api.mjs +43 -0
  70. package/lib/core/experimental/setup-api.mjs.map +1 -0
  71. package/lib/core/experimental/sources/interceptor-source.d.mts +28 -0
  72. package/lib/core/experimental/sources/interceptor-source.d.ts +28 -0
  73. package/lib/core/experimental/sources/interceptor-source.js +142 -0
  74. package/lib/core/experimental/sources/interceptor-source.js.map +1 -0
  75. package/lib/core/experimental/sources/interceptor-source.mjs +124 -0
  76. package/lib/core/experimental/sources/interceptor-source.mjs.map +1 -0
  77. package/lib/core/experimental/sources/network-source.d.mts +31 -0
  78. package/lib/core/experimental/sources/network-source.d.ts +31 -0
  79. package/lib/core/experimental/sources/network-source.js +50 -0
  80. package/lib/core/experimental/sources/network-source.js.map +1 -0
  81. package/lib/core/experimental/sources/network-source.mjs +30 -0
  82. package/lib/core/experimental/sources/network-source.mjs.map +1 -0
  83. package/lib/core/getResponse.d.mts +1 -1
  84. package/lib/core/getResponse.d.ts +1 -1
  85. package/lib/core/graphql.d.mts +1 -1
  86. package/lib/core/graphql.d.ts +1 -1
  87. package/lib/core/handlers/GraphQLHandler.d.mts +1 -1
  88. package/lib/core/handlers/GraphQLHandler.d.ts +1 -1
  89. package/lib/core/handlers/HttpHandler.d.mts +1 -1
  90. package/lib/core/handlers/HttpHandler.d.ts +1 -1
  91. package/lib/core/handlers/RequestHandler.d.mts +1 -1
  92. package/lib/core/handlers/RequestHandler.d.ts +1 -1
  93. package/lib/core/handlers/RequestHandler.js +5 -6
  94. package/lib/core/handlers/RequestHandler.js.map +1 -1
  95. package/lib/core/handlers/RequestHandler.mjs +5 -6
  96. package/lib/core/handlers/RequestHandler.mjs.map +1 -1
  97. package/lib/core/handlers/WebSocketHandler.d.mts +8 -4
  98. package/lib/core/handlers/WebSocketHandler.d.ts +8 -4
  99. package/lib/core/handlers/WebSocketHandler.js +18 -5
  100. package/lib/core/handlers/WebSocketHandler.js.map +1 -1
  101. package/lib/core/handlers/WebSocketHandler.mjs +18 -5
  102. package/lib/core/handlers/WebSocketHandler.mjs.map +1 -1
  103. package/lib/core/http.d.mts +1 -1
  104. package/lib/core/http.d.ts +1 -1
  105. package/lib/core/index.d.mts +7 -12
  106. package/lib/core/index.d.ts +7 -12
  107. package/lib/core/index.js +2 -2
  108. package/lib/core/index.js.map +1 -1
  109. package/lib/core/index.mjs +1 -1
  110. package/lib/core/index.mjs.map +1 -1
  111. package/lib/core/network-frame-B7A0ggXE.d.mts +56 -0
  112. package/lib/core/network-frame-usYiHS0K.d.ts +56 -0
  113. package/lib/core/passthrough.d.mts +1 -1
  114. package/lib/core/passthrough.d.ts +1 -1
  115. package/lib/core/sharedOptions.d.mts +6 -2
  116. package/lib/core/sharedOptions.d.ts +6 -2
  117. package/lib/core/sharedOptions.js.map +1 -1
  118. package/lib/core/sse.d.mts +1 -1
  119. package/lib/core/sse.d.ts +1 -1
  120. package/lib/core/sse.js.map +1 -1
  121. package/lib/core/sse.mjs.map +1 -1
  122. package/lib/core/utils/HttpResponse/decorators.d.mts +1 -1
  123. package/lib/core/utils/HttpResponse/decorators.d.ts +1 -1
  124. package/lib/core/utils/cookieStore.js.map +1 -1
  125. package/lib/core/utils/cookieStore.mjs.map +1 -1
  126. package/lib/core/utils/executeHandlers.d.mts +1 -1
  127. package/lib/core/utils/executeHandlers.d.ts +1 -1
  128. package/lib/core/utils/handleRequest.d.mts +2 -1
  129. package/lib/core/utils/handleRequest.d.ts +2 -1
  130. package/lib/core/utils/internal/isHandlerKind.d.mts +3 -3
  131. package/lib/core/utils/internal/isHandlerKind.d.ts +3 -3
  132. package/lib/core/utils/internal/isHandlerKind.js +2 -1
  133. package/lib/core/utils/internal/isHandlerKind.js.map +1 -1
  134. package/lib/core/utils/internal/isHandlerKind.mjs +2 -1
  135. package/lib/core/utils/internal/isHandlerKind.mjs.map +1 -1
  136. package/lib/core/utils/internal/parseGraphQLRequest.d.mts +1 -1
  137. package/lib/core/utils/internal/parseGraphQLRequest.d.ts +1 -1
  138. package/lib/core/utils/internal/parseMultipartData.d.mts +1 -1
  139. package/lib/core/utils/internal/parseMultipartData.d.ts +1 -1
  140. package/lib/core/utils/internal/requestHandlerUtils.d.mts +1 -1
  141. package/lib/core/utils/internal/requestHandlerUtils.d.ts +1 -1
  142. package/lib/core/utils/matching/matchRequestUrl.js +1 -1
  143. package/lib/core/utils/matching/matchRequestUrl.js.map +1 -1
  144. package/lib/core/utils/matching/matchRequestUrl.mjs +1 -1
  145. package/lib/core/utils/matching/matchRequestUrl.mjs.map +1 -1
  146. package/lib/core/utils/request/onUnhandledRequest.d.mts +2 -2
  147. package/lib/core/utils/request/onUnhandledRequest.d.ts +2 -2
  148. package/lib/core/utils/request/onUnhandledRequest.js.map +1 -1
  149. package/lib/core/utils/request/onUnhandledRequest.mjs.map +1 -1
  150. package/lib/core/ws/handleWebSocketEvent.d.mts +1 -1
  151. package/lib/core/ws/handleWebSocketEvent.d.ts +1 -1
  152. package/lib/core/ws/handleWebSocketEvent.js +1 -1
  153. package/lib/core/ws/handleWebSocketEvent.js.map +1 -1
  154. package/lib/core/ws/handleWebSocketEvent.mjs +1 -1
  155. package/lib/core/ws/handleWebSocketEvent.mjs.map +1 -1
  156. package/lib/core/ws/utils/attachWebSocketLogger.d.mts +1 -1
  157. package/lib/core/ws/utils/attachWebSocketLogger.d.ts +1 -1
  158. package/lib/core/ws/utils/attachWebSocketLogger.js +39 -10
  159. package/lib/core/ws/utils/attachWebSocketLogger.js.map +1 -1
  160. package/lib/core/ws/utils/attachWebSocketLogger.mjs +39 -10
  161. package/lib/core/ws/utils/attachWebSocketLogger.mjs.map +1 -1
  162. package/lib/core/ws.d.mts +3 -3
  163. package/lib/core/ws.d.ts +3 -3
  164. package/lib/core/ws.js.map +1 -1
  165. package/lib/core/ws.mjs.map +1 -1
  166. package/lib/iife/index.js +2022 -1433
  167. package/lib/iife/index.js.map +1 -1
  168. package/lib/mockServiceWorker.js +1 -1
  169. package/lib/native/index.d.mts +21 -29
  170. package/lib/native/index.d.ts +21 -29
  171. package/lib/native/index.js +48 -116
  172. package/lib/native/index.js.map +1 -1
  173. package/lib/native/index.mjs +51 -118
  174. package/lib/native/index.mjs.map +1 -1
  175. package/lib/node/index.d.mts +55 -33
  176. package/lib/node/index.d.ts +55 -33
  177. package/lib/node/index.js +152 -154
  178. package/lib/node/index.js.map +1 -1
  179. package/lib/node/index.mjs +156 -156
  180. package/lib/node/index.mjs.map +1 -1
  181. package/package.json +10 -2
  182. package/src/browser/{setupWorker/glossary.ts → glossary.ts} +16 -33
  183. package/src/browser/index.ts +2 -3
  184. package/src/browser/{setupWorker/setupWorker.node.test.ts → setup-worker.node.test.ts} +2 -4
  185. package/src/browser/setup-worker.ts +148 -0
  186. package/src/browser/sources/fallback-http-source.ts +56 -0
  187. package/src/browser/sources/service-worker-source.ts +455 -0
  188. package/src/browser/tsconfig.browser.json +7 -2
  189. package/src/browser/utils/deserializeRequest.ts +1 -1
  190. package/src/browser/{setupWorker/start/utils/getWorkerByRegistration.ts → utils/get-worker-by-registration.ts} +3 -1
  191. package/src/browser/{setupWorker/start/utils/getWorkerInstance.ts → utils/get-worker-instance.ts} +4 -4
  192. package/src/browser/utils/pruneGetRequestBody.test.ts +1 -3
  193. package/src/browser/utils/pruneGetRequestBody.ts +1 -1
  194. package/src/browser/utils/validate-worker-scope.ts +19 -0
  195. package/src/browser/utils/workerChannel.ts +2 -2
  196. package/src/core/experimental/compat.ts +50 -0
  197. package/src/core/experimental/define-network.test.ts +124 -0
  198. package/src/core/experimental/define-network.ts +215 -0
  199. package/src/core/experimental/frames/http-frame.test.ts +360 -0
  200. package/src/core/experimental/frames/http-frame.ts +271 -0
  201. package/src/core/experimental/frames/network-frame.ts +64 -0
  202. package/src/core/experimental/frames/websocket-frame.test.ts +280 -0
  203. package/src/core/experimental/frames/websocket-frame.ts +188 -0
  204. package/src/core/experimental/handlers-controller.test.ts +198 -0
  205. package/src/core/experimental/handlers-controller.ts +145 -0
  206. package/src/core/experimental/index.ts +16 -0
  207. package/src/core/experimental/on-unhandled-frame.test.ts +360 -0
  208. package/src/core/experimental/on-unhandled-frame.ts +110 -0
  209. package/src/core/experimental/request-utils.test.ts +70 -0
  210. package/src/core/experimental/request-utils.ts +39 -0
  211. package/src/core/experimental/setup-api.ts +59 -0
  212. package/src/core/experimental/sources/interceptor-source.ts +185 -0
  213. package/src/core/experimental/sources/network-source.test.ts +74 -0
  214. package/src/core/experimental/sources/network-source.ts +56 -0
  215. package/src/core/handlers/RequestHandler.ts +9 -10
  216. package/src/core/handlers/WebSocketHandler.ts +27 -11
  217. package/src/core/index.ts +3 -7
  218. package/src/core/sharedOptions.ts +9 -4
  219. package/src/core/sse.ts +1 -1
  220. package/src/core/utils/cookieStore.ts +2 -1
  221. package/src/core/utils/internal/isHandlerKind.test.ts +20 -22
  222. package/src/core/utils/internal/isHandlerKind.ts +5 -9
  223. package/src/core/utils/matching/matchRequestUrl.test.ts +87 -3
  224. package/src/core/utils/matching/matchRequestUrl.ts +2 -2
  225. package/src/core/utils/request/onUnhandledRequest.ts +2 -2
  226. package/src/core/ws/WebSocketClientManager.test.ts +2 -10
  227. package/src/core/ws/handleWebSocketEvent.ts +5 -1
  228. package/src/core/ws/utils/attachWebSocketLogger.ts +43 -11
  229. package/src/core/ws.test.ts +1 -3
  230. package/src/core/ws.ts +6 -6
  231. package/src/iife/index.ts +1 -1
  232. package/src/native/index.ts +34 -11
  233. package/src/node/async-handlers-controller.test.ts +50 -0
  234. package/src/node/async-handlers-controller.ts +69 -0
  235. package/src/node/glossary.ts +19 -18
  236. package/src/node/index.ts +6 -2
  237. package/src/node/setup-server-common.ts +100 -0
  238. package/src/node/setup-server.ts +91 -0
  239. package/src/tsconfig.core.json +8 -0
  240. package/src/tsconfig.node.json +8 -3
  241. package/src/tsconfig.src.json +0 -2
  242. package/src/tsconfig.worker.json +2 -1
  243. package/lib/core/SetupApi.d.mts +0 -44
  244. package/lib/core/SetupApi.d.ts +0 -44
  245. package/lib/core/SetupApi.js +0 -112
  246. package/lib/core/SetupApi.js.map +0 -1
  247. package/lib/core/SetupApi.mjs +0 -92
  248. package/lib/core/SetupApi.mjs.map +0 -1
  249. package/lib/core/handlers/common.d.mts +0 -3
  250. package/lib/core/handlers/common.d.ts +0 -3
  251. package/lib/core/handlers/common.js.map +0 -1
  252. package/lib/core/handlers/common.mjs +0 -1
  253. package/lib/core/handlers/common.mjs.map +0 -1
  254. package/src/browser/setupWorker/setupWorker.ts +0 -184
  255. package/src/browser/setupWorker/start/createFallbackRequestListener.ts +0 -71
  256. package/src/browser/setupWorker/start/createRequestListener.ts +0 -138
  257. package/src/browser/setupWorker/start/createResponseListener.ts +0 -57
  258. package/src/browser/setupWorker/start/createStartHandler.ts +0 -137
  259. package/src/browser/setupWorker/start/utils/enableMocking.ts +0 -30
  260. package/src/browser/setupWorker/start/utils/prepareStartHandler.test.ts +0 -59
  261. package/src/browser/setupWorker/start/utils/prepareStartHandler.ts +0 -44
  262. package/src/browser/setupWorker/start/utils/printStartMessage.test.ts +0 -84
  263. package/src/browser/setupWorker/start/utils/printStartMessage.ts +0 -51
  264. package/src/browser/setupWorker/start/utils/validateWorkerScope.ts +0 -18
  265. package/src/browser/setupWorker/stop/utils/printStopMessage.test.ts +0 -26
  266. package/src/browser/setupWorker/stop/utils/printStopMessage.ts +0 -13
  267. package/src/browser/utils/checkWorkerIntegrity.ts +0 -42
  268. package/src/core/SetupApi.ts +0 -127
  269. package/src/core/handlers/common.ts +0 -1
  270. package/src/node/SetupServerApi.ts +0 -87
  271. package/src/node/SetupServerCommonApi.ts +0 -169
  272. package/src/node/setupServer.ts +0 -15
@@ -0,0 +1,148 @@
1
+ import { invariant } from 'outvariant'
2
+ import { isNodeProcess } from 'is-node-process'
3
+ import { WebSocketInterceptor } from '@mswjs/interceptors/WebSocket'
4
+ import {
5
+ defineNetwork,
6
+ NetworkReadyState,
7
+ } from '#core/experimental/define-network'
8
+ import { type AnyHandler } from '#core/experimental/handlers-controller'
9
+ import { InterceptorSource } from '#core/experimental/sources/interceptor-source'
10
+ import { fromLegacyOnUnhandledRequest } from '#core/experimental/compat'
11
+ import type { LifeCycleEventEmitter } from '#core/sharedOptions'
12
+ import type { HttpNetworkFrameEventMap } from '#core/experimental/frames/http-frame'
13
+ import type { WebSocketNetworkFrameEventMap } from '#core/experimental/frames/websocket-frame'
14
+ import { devUtils } from '#core/utils/internal/devUtils'
15
+ import { supportsServiceWorker } from './utils/supports'
16
+ import { ServiceWorkerSource } from './sources/service-worker-source'
17
+ import { FallbackHttpSource } from './sources/fallback-http-source'
18
+ import type {
19
+ SetupWorker,
20
+ StartOptions,
21
+ StartReturnType,
22
+ StopHandler,
23
+ } from './glossary'
24
+
25
+ const DEFAULT_WORKER_URL = '/mockServiceWorker.js'
26
+
27
+ /**
28
+ * Sets up a requests interception in the browser with the given request handlers.
29
+ * @param {Array<AnyHandler>} handlers List of request handlers.
30
+ *
31
+ * @see {@link https://mswjs.io/docs/api/setup-worker `setupWorker()` API reference}
32
+ */
33
+ export function setupWorker(...handlers: Array<AnyHandler>): SetupWorker {
34
+ invariant(
35
+ !isNodeProcess(),
36
+ devUtils.formatMessage(
37
+ 'Failed to execute `setupWorker` in a non-browser environment',
38
+ ),
39
+ )
40
+
41
+ const network = defineNetwork<
42
+ Array<ServiceWorkerSource | FallbackHttpSource | InterceptorSource>
43
+ >({
44
+ sources: [],
45
+ handlers,
46
+ })
47
+
48
+ return {
49
+ async start(options) {
50
+ if (options?.waitUntilReady != null) {
51
+ devUtils.warn(
52
+ `The "waitUntilReady" option has been deprecated. Please remove it from this "worker.start()" call. Follow the recommended Browser integration (https://mswjs.io/docs/integrations/browser) to eliminate any race conditions between the Service Worker registration and any requests made by your application on initial render.`,
53
+ )
54
+ }
55
+
56
+ /**
57
+ * @todo @fixme
58
+ * This is kept for backward-compatibility reasons. We don't really need this check anymore.
59
+ */
60
+ if (network.readyState === NetworkReadyState.ENABLED) {
61
+ devUtils.warn(
62
+ 'Found a redundant "worker.start()" call. Note that starting the worker while mocking is already enabled will have no effect. Consider removing this "worker.start()" call.',
63
+ )
64
+ return
65
+ }
66
+
67
+ const httpSource = supportsServiceWorker()
68
+ ? new ServiceWorkerSource({
69
+ serviceWorker: {
70
+ url:
71
+ options?.serviceWorker?.url?.toString() || DEFAULT_WORKER_URL,
72
+ options: options?.serviceWorker?.options,
73
+ },
74
+ findWorker: options?.findWorker,
75
+ quiet: options?.quiet,
76
+ })
77
+ : new FallbackHttpSource({
78
+ quiet: options?.quiet,
79
+ })
80
+
81
+ network.configure({
82
+ sources: [
83
+ httpSource,
84
+ new InterceptorSource({
85
+ interceptors: [new WebSocketInterceptor() as any],
86
+ }),
87
+ ],
88
+ onUnhandledFrame: fromLegacyOnUnhandledRequest(() => {
89
+ return options?.onUnhandledRequest || 'warn'
90
+ }),
91
+ context: {
92
+ quiet: options?.quiet,
93
+ },
94
+ })
95
+
96
+ await network.enable()
97
+
98
+ if (httpSource instanceof ServiceWorkerSource) {
99
+ const [, registration] = await httpSource.workerPromise
100
+ return registration
101
+ }
102
+ },
103
+ stop() {
104
+ if (network.readyState === NetworkReadyState.DISABLED) {
105
+ devUtils.warn(
106
+ `Found a redundant "worker.stop()" call. Notice that stopping the worker after it has already been stopped has no effect. Consider removing this "worker.stop()" call.`,
107
+ )
108
+ return
109
+ }
110
+
111
+ network.disable()
112
+ window.postMessage({ type: 'msw/worker:stop' })
113
+ },
114
+ events: network.events,
115
+ use: network.use.bind(network),
116
+ resetHandlers: network.resetHandlers.bind(network),
117
+ restoreHandlers: network.restoreHandlers.bind(network),
118
+ listHandlers: network.listHandlers.bind(network),
119
+ }
120
+ }
121
+
122
+ /**
123
+ * @deprecated
124
+ * Please use the `defineNetwork` API instead.
125
+ */
126
+ export class SetupWorkerApi implements SetupWorker {
127
+ start: (options?: StartOptions) => StartReturnType
128
+ stop: StopHandler
129
+ use: (...handlers: Array<AnyHandler>) => void
130
+ resetHandlers: (...nextHandlers: Array<AnyHandler>) => void
131
+ restoreHandlers: () => void
132
+ listHandlers: () => ReadonlyArray<AnyHandler>
133
+ events: LifeCycleEventEmitter<
134
+ HttpNetworkFrameEventMap | WebSocketNetworkFrameEventMap
135
+ >
136
+
137
+ constructor() {
138
+ const worker = setupWorker()
139
+
140
+ this.start = worker.start.bind(worker)
141
+ this.stop = worker.stop.bind(worker)
142
+ this.use = worker.use.bind(worker)
143
+ this.resetHandlers = worker.resetHandlers.bind(worker)
144
+ this.restoreHandlers = worker.restoreHandlers.bind(worker)
145
+ this.listHandlers = worker.listHandlers.bind(worker)
146
+ this.events = worker.events
147
+ }
148
+ }
@@ -0,0 +1,56 @@
1
+ import { FetchInterceptor } from '@mswjs/interceptors/fetch'
2
+ import { XMLHttpRequestInterceptor } from '@mswjs/interceptors/XMLHttpRequest'
3
+ import { InterceptorSource } from '#core/experimental/sources/interceptor-source'
4
+ import { devUtils } from '#core/utils/internal/devUtils'
5
+
6
+ interface FallbackHttpSourceOptions {
7
+ quiet?: boolean
8
+ }
9
+
10
+ export class FallbackHttpSource extends InterceptorSource {
11
+ constructor(private readonly options: FallbackHttpSourceOptions) {
12
+ super({
13
+ interceptors: [new XMLHttpRequestInterceptor(), new FetchInterceptor()],
14
+ })
15
+ }
16
+
17
+ public enable(): void {
18
+ super.enable()
19
+
20
+ if (!this.options.quiet) {
21
+ this.#printStartMessage()
22
+ }
23
+ }
24
+
25
+ public disable(): void {
26
+ super.disable()
27
+
28
+ if (!this.options.quiet) {
29
+ this.#printStopMessage()
30
+ }
31
+ }
32
+
33
+ #printStartMessage(): void {
34
+ console.groupCollapsed(
35
+ `%c${devUtils.formatMessage('Mocking enabled (fallback mode).')}`,
36
+ 'color:orangered;font-weight:bold;',
37
+ )
38
+ // eslint-disable-next-line no-console
39
+ console.log(
40
+ '%cDocumentation: %chttps://mswjs.io/docs',
41
+ 'font-weight:bold',
42
+ 'font-weight:normal',
43
+ )
44
+ // eslint-disable-next-line no-console
45
+ console.log('Found an issue? https://github.com/mswjs/msw/issues')
46
+ console.groupEnd()
47
+ }
48
+
49
+ #printStopMessage(): void {
50
+ // eslint-disable-next-line no-console
51
+ console.log(
52
+ `%c${devUtils.formatMessage('Mocking disabled.')}`,
53
+ 'color:orangered;font-weight:bold;',
54
+ )
55
+ }
56
+ }
@@ -0,0 +1,455 @@
1
+ import { invariant } from 'outvariant'
2
+ import { Emitter } from 'rettime'
3
+ import { DeferredPromise } from '@open-draft/deferred-promise'
4
+ import { FetchResponse } from '@mswjs/interceptors'
5
+ import { NetworkSource } from '#core/experimental/sources/network-source'
6
+ import { RequestHandler } from '#core/handlers/RequestHandler'
7
+ import {
8
+ HttpNetworkFrame,
9
+ ResponseEvent,
10
+ } from '#core/experimental/frames/http-frame'
11
+ import { HttpResponse } from '#core/HttpResponse'
12
+ import { toResponseInit } from '#core/utils/toResponseInit'
13
+ import { devUtils } from '#core/utils/internal/devUtils'
14
+ import {
15
+ supportsReadableStreamTransfer,
16
+ supportsServiceWorker,
17
+ } from '../utils/supports'
18
+ import { getWorkerInstance } from '../utils/get-worker-instance'
19
+ import { WorkerChannel, WorkerChannelEventMap } from '../utils/workerChannel'
20
+ import { FindWorker } from '../glossary'
21
+ import { deserializeRequest } from '../utils/deserializeRequest'
22
+ import { validateWorkerScope } from '../utils/validate-worker-scope'
23
+
24
+ export interface ServiceWorkerSourceOptions {
25
+ quiet?: boolean
26
+ serviceWorker: {
27
+ url: string
28
+ options?: RegistrationOptions
29
+ }
30
+ findWorker?: FindWorker
31
+ }
32
+
33
+ type WorkerChannelRequestEvent = Emitter.EventType<
34
+ WorkerChannel,
35
+ 'REQUEST',
36
+ WorkerChannelEventMap
37
+ >
38
+
39
+ type WorkerChannelResponseEvent = Emitter.EventType<
40
+ WorkerChannel,
41
+ 'RESPONSE',
42
+ WorkerChannelEventMap
43
+ >
44
+
45
+ type WorkerChannelClient =
46
+ WorkerChannelEventMap['MOCKING_ENABLED']['data']['client']
47
+
48
+ export class ServiceWorkerSource extends NetworkSource<ServiceWorkerHttpNetworkFrame> {
49
+ #frames: Map<string, ServiceWorkerHttpNetworkFrame>
50
+ #channel: WorkerChannel
51
+ #clientPromise?: Promise<WorkerChannelClient>
52
+ #keepAliveInterval?: number
53
+ #stoppedAt?: number
54
+
55
+ public workerPromise: DeferredPromise<
56
+ [ServiceWorker, ServiceWorkerRegistration]
57
+ >
58
+
59
+ constructor(private readonly options: ServiceWorkerSourceOptions) {
60
+ super()
61
+
62
+ invariant(
63
+ supportsServiceWorker(),
64
+ 'Failed to use Service Worker as the network source: the Service Worker API is not supported in this environment',
65
+ )
66
+
67
+ this.#frames = new Map()
68
+ this.workerPromise = new DeferredPromise()
69
+ this.#channel = new WorkerChannel({
70
+ worker: this.workerPromise.then(([worker]) => worker),
71
+ })
72
+ }
73
+
74
+ public async enable(): Promise<ServiceWorkerRegistration> {
75
+ this.#stoppedAt = undefined
76
+
77
+ if (this.workerPromise.state !== 'pending') {
78
+ devUtils.warn(
79
+ 'Found a redundant "worker.start()" call. Note that starting the worker while mocking is already enabled will have no effect. Consider removing this "worker.start()" call.',
80
+ )
81
+
82
+ return this.workerPromise.then(([, registration]) => registration)
83
+ }
84
+
85
+ this.#channel.removeAllListeners()
86
+ const [worker, registration] = await this.#startWorker()
87
+
88
+ if (worker.state !== 'activated') {
89
+ const controller = new AbortController()
90
+ const activationPromise = new DeferredPromise<void>()
91
+ activationPromise.then(() => controller.abort())
92
+
93
+ worker.addEventListener(
94
+ 'statechange',
95
+ () => {
96
+ if (worker.state === 'activated') {
97
+ activationPromise.resolve()
98
+ }
99
+ },
100
+ { signal: controller.signal },
101
+ )
102
+
103
+ await activationPromise
104
+ }
105
+
106
+ this.#channel.postMessage('MOCK_ACTIVATE')
107
+
108
+ const clientConfirmationPromise = new DeferredPromise<WorkerChannelClient>()
109
+ this.#clientPromise = clientConfirmationPromise
110
+
111
+ this.#channel.once('MOCKING_ENABLED', (event) => {
112
+ clientConfirmationPromise.resolve(event.data.client)
113
+ })
114
+ await clientConfirmationPromise
115
+
116
+ if (!this.options.quiet) {
117
+ this.#printStartMessage()
118
+ }
119
+
120
+ return registration
121
+ }
122
+
123
+ public disable(): void {
124
+ /**
125
+ * @note Do NOT call `super.disable()` because it removes any "frame" listeners
126
+ * from this network source, effectively turning it off. The Service Worker source
127
+ * is a bit special since it might process in-flight requests that have been performed
128
+ * after it's been disabled.
129
+ */
130
+
131
+ if (typeof this.#stoppedAt !== 'undefined') {
132
+ devUtils.warn(
133
+ `Found a redundant "worker.stop()" call. Notice that stopping the worker after it has already been stopped has no effect. Consider removing this "worker.stop()" call.`,
134
+ )
135
+
136
+ return
137
+ }
138
+
139
+ this.#stoppedAt = Date.now()
140
+ this.#frames.clear()
141
+ this.workerPromise = new DeferredPromise()
142
+
143
+ if (!this.options.quiet) {
144
+ this.#printStopMessage()
145
+ }
146
+ }
147
+
148
+ async #startWorker() {
149
+ if (this.#keepAliveInterval) {
150
+ clearInterval(this.#keepAliveInterval)
151
+ }
152
+
153
+ const workerUrl = this.options.serviceWorker.url
154
+
155
+ const [worker, registration] = await getWorkerInstance(
156
+ workerUrl,
157
+ this.options.serviceWorker.options,
158
+ this.options.findWorker || this.#defaultFindWorker,
159
+ )
160
+
161
+ if (worker == null) {
162
+ const missingWorkerMessage = this.options?.findWorker
163
+ ? devUtils.formatMessage(
164
+ `Failed to locate the Service Worker registration using a custom "findWorker" predicate.
165
+
166
+ Please ensure that the custom predicate properly locates the Service Worker registration at "%s".
167
+ More details: https://mswjs.io/docs/api/setup-worker/start#findworker
168
+ `,
169
+ workerUrl,
170
+ )
171
+ : devUtils.formatMessage(
172
+ `Failed to locate the Service Worker registration.
173
+
174
+ This most likely means that the worker script URL "%s" cannot resolve against the actual public hostname (%s). This may happen if your application runs behind a proxy, or has a dynamic hostname.
175
+
176
+ Please consider using a custom "serviceWorker.url" option to point to the actual worker script location, or a custom "findWorker" option to resolve the Service Worker registration manually. More details: https://mswjs.io/docs/api/setup-worker/start`,
177
+ workerUrl,
178
+ location.host,
179
+ )
180
+
181
+ throw new Error(missingWorkerMessage)
182
+ }
183
+
184
+ this.workerPromise.resolve([worker, registration])
185
+
186
+ this.#channel.on('REQUEST', this.#handleRequest.bind(this))
187
+ this.#channel.on('RESPONSE', this.#handleResponse.bind(this))
188
+
189
+ window.addEventListener('beforeunload', () => {
190
+ if (worker.state !== 'redundant') {
191
+ this.#channel.postMessage('CLIENT_CLOSED')
192
+ }
193
+
194
+ clearInterval(this.#keepAliveInterval)
195
+
196
+ window.postMessage({ type: 'msw/worker:stop' })
197
+ })
198
+
199
+ await this.#checkWorkerIntegrity().catch((error) => {
200
+ devUtils.error(
201
+ 'Error while checking the worker script integrity. Please report this on GitHub (https://github.com/mswjs/msw/issues) and include the original error below.',
202
+ )
203
+ console.error(error)
204
+ })
205
+
206
+ this.#keepAliveInterval = window.setInterval(() => {
207
+ this.#channel.postMessage('KEEPALIVE_REQUEST')
208
+ }, 5000)
209
+
210
+ if (!this.options.quiet) {
211
+ validateWorkerScope(registration)
212
+ }
213
+
214
+ return [worker, registration] as const
215
+ }
216
+
217
+ async #handleRequest(event: WorkerChannelRequestEvent): Promise<void> {
218
+ if (this.#stoppedAt && event.data.interceptedAt > this.#stoppedAt) {
219
+ return event.postMessage('PASSTHROUGH')
220
+ }
221
+
222
+ const request = deserializeRequest(event.data)
223
+ RequestHandler.cache.set(request, request.clone())
224
+
225
+ const frame = new ServiceWorkerHttpNetworkFrame({
226
+ event,
227
+ request,
228
+ })
229
+ this.#frames.set(event.data.id, frame)
230
+
231
+ await this.queue(frame)
232
+ }
233
+
234
+ async #handleResponse(event: WorkerChannelResponseEvent): Promise<void> {
235
+ const { request, response, isMockedResponse } = event.data
236
+
237
+ /**
238
+ * CORS requests with `mode: "no-cors"` result in "opaque" responses.
239
+ * That kind of responses cannot be manipulated in JavaScript due
240
+ * to the security considerations.
241
+ * @see https://fetch.spec.whatwg.org/#concept-filtered-response-opaque
242
+ * @see https://github.com/mswjs/msw/issues/529
243
+ */
244
+ if (response.type?.includes('opaque')) {
245
+ this.#frames.delete(request.id)
246
+ return
247
+ }
248
+
249
+ const frame = this.#frames.get(request.id)
250
+ this.#frames.delete(request.id)
251
+
252
+ /**
253
+ * @note A request frame will be missing in case of passthrough after the worker is stopped.
254
+ * Creating a frame is costly so it's better to handle it as an edge case here.
255
+ */
256
+ if (frame == null) {
257
+ return
258
+ }
259
+
260
+ const fetchRequest = deserializeRequest(request)
261
+ const fetchResponse =
262
+ response.status === 0
263
+ ? Response.error()
264
+ : new FetchResponse(
265
+ /**
266
+ * Responses may be streams here, but when we create a response object
267
+ * with null-body status codes, like 204, 205, 304 Response will
268
+ * throw when passed a non-null body, so ensure it's null here
269
+ * for those codes
270
+ */
271
+ FetchResponse.isResponseWithBody(response.status)
272
+ ? response.body
273
+ : null,
274
+ {
275
+ ...response,
276
+ /**
277
+ * Set response URL if it's not set already.
278
+ * @see https://github.com/mswjs/msw/issues/2030
279
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/Response/url
280
+ */
281
+ url: request.url,
282
+ },
283
+ )
284
+
285
+ frame.events.emit(
286
+ new ResponseEvent(
287
+ isMockedResponse ? 'response:mocked' : 'response:bypass',
288
+ {
289
+ requestId: frame.data.id,
290
+ request: fetchRequest,
291
+ response: fetchResponse,
292
+ isMockedResponse,
293
+ },
294
+ ),
295
+ )
296
+ }
297
+
298
+ #defaultFindWorker: FindWorker = (workerUrl, mockServiceWorkerUrl) => {
299
+ return workerUrl === mockServiceWorkerUrl
300
+ }
301
+
302
+ async #checkWorkerIntegrity(): Promise<void> {
303
+ const integrityCheckPromise = new DeferredPromise<void>()
304
+
305
+ this.#channel.postMessage('INTEGRITY_CHECK_REQUEST')
306
+ this.#channel.once('INTEGRITY_CHECK_RESPONSE', (event) => {
307
+ const { checksum, packageVersion } = event.data
308
+
309
+ // Compare the response from the Service Worker and the
310
+ // global variable set during the build.
311
+
312
+ // The integrity is validated based on the worker script's checksum
313
+ // that's derived from its minified content during the build.
314
+ // The "SERVICE_WORKER_CHECKSUM" global variable is injected by the build.
315
+ if (checksum !== SERVICE_WORKER_CHECKSUM) {
316
+ devUtils.warn(
317
+ `The currently registered Service Worker has been generated by a different version of MSW (${packageVersion}) and may not be fully compatible with the installed version.
318
+
319
+ It's recommended you update your worker script by running this command:
320
+
321
+ \u2022 npx msw init <PUBLIC_DIR>
322
+
323
+ You can also automate this process and make the worker script update automatically upon the library installations. Read more: https://mswjs.io/docs/cli/init.`,
324
+ )
325
+ }
326
+
327
+ integrityCheckPromise.resolve()
328
+ })
329
+
330
+ return integrityCheckPromise
331
+ }
332
+
333
+ async #printStartMessage() {
334
+ if (this.workerPromise.state === 'rejected') {
335
+ return
336
+ }
337
+
338
+ invariant(
339
+ this.#clientPromise != null,
340
+ '[ServiceWorkerSource] Failed to print a start message: client confirmation not received',
341
+ )
342
+
343
+ const client = await this.#clientPromise
344
+ const [worker, registration] = await this.workerPromise
345
+
346
+ console.groupCollapsed(
347
+ `%c${devUtils.formatMessage('Mocking enabled.')}`,
348
+ 'color:orangered;font-weight:bold;',
349
+ )
350
+ // eslint-disable-next-line no-console
351
+ console.log(
352
+ '%cDocumentation: %chttps://mswjs.io/docs',
353
+ 'font-weight:bold',
354
+ 'font-weight:normal',
355
+ )
356
+ // eslint-disable-next-line no-console
357
+ console.log('Found an issue? https://github.com/mswjs/msw/issues')
358
+
359
+ // eslint-disable-next-line no-console
360
+ console.log('Worker script URL:', worker.scriptURL)
361
+
362
+ // eslint-disable-next-line no-console
363
+ console.log('Worker scope:', registration.scope)
364
+
365
+ if (client) {
366
+ // eslint-disable-next-line no-console
367
+ console.log('Client ID: %s (%s)', client.id, client.frameType)
368
+ }
369
+
370
+ console.groupEnd()
371
+ }
372
+
373
+ #printStopMessage(): void {
374
+ // eslint-disable-next-line no-console
375
+ console.log(
376
+ `%c${devUtils.formatMessage('Mocking disabled.')}`,
377
+ 'color:orangered;font-weight:bold;',
378
+ )
379
+ }
380
+ }
381
+
382
+ class ServiceWorkerHttpNetworkFrame extends HttpNetworkFrame {
383
+ #event: WorkerChannelRequestEvent
384
+
385
+ constructor(options: { event: WorkerChannelRequestEvent; request: Request }) {
386
+ super({ request: options.request })
387
+ this.#event = options.event
388
+ }
389
+
390
+ public passthrough(): void {
391
+ this.#event.postMessage('PASSTHROUGH')
392
+ }
393
+
394
+ public respondWith(response?: Response): void {
395
+ if (response) {
396
+ this.#respondWith(response)
397
+ }
398
+ }
399
+
400
+ public errorWith(reason?: unknown): void {
401
+ if (reason instanceof Response) {
402
+ return this.respondWith(reason)
403
+ }
404
+
405
+ devUtils.warn(
406
+ `Uncaught exception in the request handler for "%s %s". This exception has been gracefully handled as a 500 response, however, it's strongly recommended to resolve this error, as it indicates a mistake in your code. If you wish to mock an error response, please see this guide: https://mswjs.io/docs/http/mocking-responses/error-responses`,
407
+ this.data.request.method,
408
+ this.data.request.url,
409
+ )
410
+
411
+ const error =
412
+ reason instanceof Error
413
+ ? reason
414
+ : new Error(reason?.toString() || 'Request failure')
415
+
416
+ // Treat exceptions during the request handling as 500 responses.
417
+ // This should alert the developer that there's a problem.
418
+ this.respondWith(
419
+ HttpResponse.json(
420
+ {
421
+ name: error.name,
422
+ message: error.message,
423
+ stack: error.stack,
424
+ },
425
+ {
426
+ status: 500,
427
+ statusText: 'Request Handler Error',
428
+ },
429
+ ),
430
+ )
431
+ }
432
+
433
+ async #respondWith(response: Response): Promise<void> {
434
+ let responseBody: ReadableStream<Uint8Array> | ArrayBuffer | null
435
+ let transfer: [ReadableStream<Uint8Array>] | undefined
436
+ const responseInit = toResponseInit(response)
437
+
438
+ if (supportsReadableStreamTransfer()) {
439
+ responseBody = response.body
440
+ transfer = response.body == null ? undefined : [response.body]
441
+ } else {
442
+ responseBody =
443
+ response.body == null ? null : await response.clone().arrayBuffer()
444
+ }
445
+
446
+ this.#event.postMessage(
447
+ 'MOCK_RESPONSE',
448
+ {
449
+ ...responseInit,
450
+ body: responseBody,
451
+ },
452
+ transfer,
453
+ )
454
+ }
455
+ }
@@ -1,9 +1,14 @@
1
1
  {
2
2
  "extends": "../tsconfig.src.json",
3
+ "include": ["../../global.d.ts", "./global.browser.d.ts", "./**/*.ts"],
4
+ "references": [
5
+ {
6
+ "path": "../tsconfig.core.json"
7
+ }
8
+ ],
3
9
  "compilerOptions": {
4
10
  // Expose browser-specific libraries only for the
5
11
  // source code under the "src/browser" directory.
6
12
  "lib": ["DOM", "WebWorker", "DOM.Iterable"]
7
- },
8
- "include": ["../../global.d.ts", "./global.browser.d.ts", "./**/*.ts"]
13
+ }
9
14
  }
@@ -1,5 +1,5 @@
1
1
  import { pruneGetRequestBody } from './pruneGetRequestBody'
2
- import type { ServiceWorkerIncomingRequest } from '../setupWorker/glossary'
2
+ import type { ServiceWorkerIncomingRequest } from '../glossary'
3
3
 
4
4
  /**
5
5
  * Converts a given request received from the Service Worker
@@ -1,4 +1,4 @@
1
- import { FindWorker } from '../../glossary'
1
+ import type { FindWorker } from '../glossary'
2
2
 
3
3
  /**
4
4
  * Attempts to resolve a Service Worker instance from a given registration,
@@ -14,9 +14,11 @@ export function getWorkerByRegistration(
14
14
  registration.installing,
15
15
  registration.waiting,
16
16
  ]
17
+
17
18
  const relevantStates = allStates.filter((state): state is ServiceWorker => {
18
19
  return state != null
19
20
  })
21
+
20
22
  const worker = relevantStates.find((worker) => {
21
23
  return findWorker(worker.scriptURL, absoluteWorkerUrl)
22
24
  })