mockServiceWorker.js 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. /* eslint-disable */
  2. /* tslint:disable */
  3. /**
  4. * Mock Service Worker.
  5. * @see https://github.com/mswjs/msw
  6. * - Please do NOT modify this file.
  7. */
  8. const PACKAGE_VERSION = '2.10.3'
  9. const INTEGRITY_CHECKSUM = 'f5825c521429caf22a4dd13b66e243af'
  10. const IS_MOCKED_RESPONSE = Symbol('isMockedResponse')
  11. const activeClientIds = new Set()
  12. addEventListener('install', function () {
  13. self.skipWaiting()
  14. })
  15. addEventListener('activate', function (event) {
  16. event.waitUntil(self.clients.claim())
  17. })
  18. addEventListener('message', async function (event) {
  19. const clientId = Reflect.get(event.source || {}, 'id')
  20. if (!clientId || !self.clients) {
  21. return
  22. }
  23. const client = await self.clients.get(clientId)
  24. if (!client) {
  25. return
  26. }
  27. const allClients = await self.clients.matchAll({
  28. type: 'window',
  29. })
  30. switch (event.data) {
  31. case 'KEEPALIVE_REQUEST': {
  32. sendToClient(client, {
  33. type: 'KEEPALIVE_RESPONSE',
  34. })
  35. break
  36. }
  37. case 'INTEGRITY_CHECK_REQUEST': {
  38. sendToClient(client, {
  39. type: 'INTEGRITY_CHECK_RESPONSE',
  40. payload: {
  41. packageVersion: PACKAGE_VERSION,
  42. checksum: INTEGRITY_CHECKSUM,
  43. },
  44. })
  45. break
  46. }
  47. case 'MOCK_ACTIVATE': {
  48. activeClientIds.add(clientId)
  49. sendToClient(client, {
  50. type: 'MOCKING_ENABLED',
  51. payload: {
  52. client: {
  53. id: client.id,
  54. frameType: client.frameType,
  55. },
  56. },
  57. })
  58. break
  59. }
  60. case 'MOCK_DEACTIVATE': {
  61. activeClientIds.delete(clientId)
  62. break
  63. }
  64. case 'CLIENT_CLOSED': {
  65. activeClientIds.delete(clientId)
  66. const remainingClients = allClients.filter((client) => {
  67. return client.id !== clientId
  68. })
  69. // Unregister itself when there are no more clients
  70. if (remainingClients.length === 0) {
  71. self.registration.unregister()
  72. }
  73. break
  74. }
  75. }
  76. })
  77. addEventListener('fetch', function (event) {
  78. // Bypass navigation requests.
  79. if (event.request.mode === 'navigate') {
  80. return
  81. }
  82. // Opening the DevTools triggers the "only-if-cached" request
  83. // that cannot be handled by the worker. Bypass such requests.
  84. if (
  85. event.request.cache === 'only-if-cached' &&
  86. event.request.mode !== 'same-origin'
  87. ) {
  88. return
  89. }
  90. // Bypass all requests when there are no active clients.
  91. // Prevents the self-unregistered worked from handling requests
  92. // after it's been deleted (still remains active until the next reload).
  93. if (activeClientIds.size === 0) {
  94. return
  95. }
  96. const requestId = crypto.randomUUID()
  97. event.respondWith(handleRequest(event, requestId))
  98. })
  99. /**
  100. * @param {FetchEvent} event
  101. * @param {string} requestId
  102. */
  103. async function handleRequest(event, requestId) {
  104. const client = await resolveMainClient(event)
  105. const requestCloneForEvents = event.request.clone()
  106. const response = await getResponse(event, client, requestId)
  107. // Send back the response clone for the "response:*" life-cycle events.
  108. // Ensure MSW is active and ready to handle the message, otherwise
  109. // this message will pend indefinitely.
  110. if (client && activeClientIds.has(client.id)) {
  111. const serializedRequest = await serializeRequest(requestCloneForEvents)
  112. // Clone the response so both the client and the library could consume it.
  113. const responseClone = response.clone()
  114. sendToClient(
  115. client,
  116. {
  117. type: 'RESPONSE',
  118. payload: {
  119. isMockedResponse: IS_MOCKED_RESPONSE in response,
  120. request: {
  121. id: requestId,
  122. ...serializedRequest,
  123. },
  124. response: {
  125. type: responseClone.type,
  126. status: responseClone.status,
  127. statusText: responseClone.statusText,
  128. headers: Object.fromEntries(responseClone.headers.entries()),
  129. body: responseClone.body,
  130. },
  131. },
  132. },
  133. responseClone.body ? [serializedRequest.body, responseClone.body] : [],
  134. )
  135. }
  136. return response
  137. }
  138. /**
  139. * Resolve the main client for the given event.
  140. * Client that issues a request doesn't necessarily equal the client
  141. * that registered the worker. It's with the latter the worker should
  142. * communicate with during the response resolving phase.
  143. * @param {FetchEvent} event
  144. * @returns {Promise<Client | undefined>}
  145. */
  146. async function resolveMainClient(event) {
  147. const client = await self.clients.get(event.clientId)
  148. if (activeClientIds.has(event.clientId)) {
  149. return client
  150. }
  151. if (client?.frameType === 'top-level') {
  152. return client
  153. }
  154. const allClients = await self.clients.matchAll({
  155. type: 'window',
  156. })
  157. return allClients
  158. .filter((client) => {
  159. // Get only those clients that are currently visible.
  160. return client.visibilityState === 'visible'
  161. })
  162. .find((client) => {
  163. // Find the client ID that's recorded in the
  164. // set of clients that have registered the worker.
  165. return activeClientIds.has(client.id)
  166. })
  167. }
  168. /**
  169. * @param {FetchEvent} event
  170. * @param {Client | undefined} client
  171. * @param {string} requestId
  172. * @returns {Promise<Response>}
  173. */
  174. async function getResponse(event, client, requestId) {
  175. // Clone the request because it might've been already used
  176. // (i.e. its body has been read and sent to the client).
  177. const requestClone = event.request.clone()
  178. function passthrough() {
  179. // Cast the request headers to a new Headers instance
  180. // so the headers can be manipulated with.
  181. const headers = new Headers(requestClone.headers)
  182. // Remove the "accept" header value that marked this request as passthrough.
  183. // This prevents request alteration and also keeps it compliant with the
  184. // user-defined CORS policies.
  185. const acceptHeader = headers.get('accept')
  186. if (acceptHeader) {
  187. const values = acceptHeader.split(',').map((value) => value.trim())
  188. const filteredValues = values.filter(
  189. (value) => value !== 'msw/passthrough',
  190. )
  191. if (filteredValues.length > 0) {
  192. headers.set('accept', filteredValues.join(', '))
  193. } else {
  194. headers.delete('accept')
  195. }
  196. }
  197. return fetch(requestClone, { headers })
  198. }
  199. // Bypass mocking when the client is not active.
  200. if (!client) {
  201. return passthrough()
  202. }
  203. // Bypass initial page load requests (i.e. static assets).
  204. // The absence of the immediate/parent client in the map of the active clients
  205. // means that MSW hasn't dispatched the "MOCK_ACTIVATE" event yet
  206. // and is not ready to handle requests.
  207. if (!activeClientIds.has(client.id)) {
  208. return passthrough()
  209. }
  210. // Notify the client that a request has been intercepted.
  211. const serializedRequest = await serializeRequest(event.request)
  212. const clientMessage = await sendToClient(
  213. client,
  214. {
  215. type: 'REQUEST',
  216. payload: {
  217. id: requestId,
  218. ...serializedRequest,
  219. },
  220. },
  221. [serializedRequest.body],
  222. )
  223. switch (clientMessage.type) {
  224. case 'MOCK_RESPONSE': {
  225. return respondWithMock(clientMessage.data)
  226. }
  227. case 'PASSTHROUGH': {
  228. return passthrough()
  229. }
  230. }
  231. return passthrough()
  232. }
  233. /**
  234. * @param {Client} client
  235. * @param {any} message
  236. * @param {Array<Transferable>} transferrables
  237. * @returns {Promise<any>}
  238. */
  239. function sendToClient(client, message, transferrables = []) {
  240. return new Promise((resolve, reject) => {
  241. const channel = new MessageChannel()
  242. channel.port1.onmessage = (event) => {
  243. if (event.data && event.data.error) {
  244. return reject(event.data.error)
  245. }
  246. resolve(event.data)
  247. }
  248. client.postMessage(message, [
  249. channel.port2,
  250. ...transferrables.filter(Boolean),
  251. ])
  252. })
  253. }
  254. /**
  255. * @param {Response} response
  256. * @returns {Response}
  257. */
  258. function respondWithMock(response) {
  259. // Setting response status code to 0 is a no-op.
  260. // However, when responding with a "Response.error()", the produced Response
  261. // instance will have status code set to 0. Since it's not possible to create
  262. // a Response instance with status code 0, handle that use-case separately.
  263. if (response.status === 0) {
  264. return Response.error()
  265. }
  266. const mockedResponse = new Response(response.body, response)
  267. Reflect.defineProperty(mockedResponse, IS_MOCKED_RESPONSE, {
  268. value: true,
  269. enumerable: true,
  270. })
  271. return mockedResponse
  272. }
  273. /**
  274. * @param {Request} request
  275. */
  276. async function serializeRequest(request) {
  277. return {
  278. url: request.url,
  279. mode: request.mode,
  280. method: request.method,
  281. headers: Object.fromEntries(request.headers.entries()),
  282. cache: request.cache,
  283. credentials: request.credentials,
  284. destination: request.destination,
  285. integrity: request.integrity,
  286. redirect: request.redirect,
  287. referrer: request.referrer,
  288. referrerPolicy: request.referrerPolicy,
  289. body: await request.arrayBuffer(),
  290. keepalive: request.keepalive,
  291. }
  292. }