mockServiceWorker.js 8.9 KB

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