mockServiceWorker.js 7.6 KB

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