diff --git a/packages/redux-devtools-rtk-query-monitor/demo/package.json b/packages/redux-devtools-rtk-query-monitor/demo/package.json index 0255660f..c4fdf42a 100644 --- a/packages/redux-devtools-rtk-query-monitor/demo/package.json +++ b/packages/redux-devtools-rtk-query-monitor/demo/package.json @@ -19,7 +19,7 @@ "@redux-devtools/dock-monitor": "workspace:^", "@redux-devtools/rtk-query-monitor": "workspace:^", "@reduxjs/toolkit": "^2.8.2", - "msw": "^2.8.7", + "msw": "^2.10.2", "react": "^19.1.0", "react-dom": "^19.1.0", "react-icons": "^5.5.0", diff --git a/packages/redux-devtools-rtk-query-monitor/demo/public/mockServiceWorker.js b/packages/redux-devtools-rtk-query-monitor/demo/public/mockServiceWorker.js index 84491eb3..de7bc0f2 100644 --- a/packages/redux-devtools-rtk-query-monitor/demo/public/mockServiceWorker.js +++ b/packages/redux-devtools-rtk-query-monitor/demo/public/mockServiceWorker.js @@ -5,24 +5,23 @@ * Mock Service Worker. * @see https://github.com/mswjs/msw * - Please do NOT modify this file. - * - Please do NOT serve this file on production. */ -const PACKAGE_VERSION = '2.8.7' -const INTEGRITY_CHECKSUM = '00729d72e3b82faf54ca8b9621dbb96f' +const PACKAGE_VERSION = '2.10.2' +const INTEGRITY_CHECKSUM = 'f5825c521429caf22a4dd13b66e243af' const IS_MOCKED_RESPONSE = Symbol('isMockedResponse') const activeClientIds = new Set() -self.addEventListener('install', function () { +addEventListener('install', function () { self.skipWaiting() }) -self.addEventListener('activate', function (event) { +addEventListener('activate', function (event) { event.waitUntil(self.clients.claim()) }) -self.addEventListener('message', async function (event) { - const clientId = event.source.id +addEventListener('message', async function (event) { + const clientId = Reflect.get(event.source || {}, 'id') if (!clientId || !self.clients) { return @@ -94,17 +93,18 @@ self.addEventListener('message', async function (event) { } }) -self.addEventListener('fetch', function (event) { - const { request } = event - +addEventListener('fetch', function (event) { // Bypass navigation requests. - if (request.mode === 'navigate') { + if (event.request.mode === 'navigate') { return } // Opening the DevTools triggers the "only-if-cached" request // that cannot be handled by the worker. Bypass such requests. - if (request.cache === 'only-if-cached' && request.mode !== 'same-origin') { + if ( + event.request.cache === 'only-if-cached' && + event.request.mode !== 'same-origin' + ) { return } @@ -115,48 +115,62 @@ self.addEventListener('fetch', function (event) { return } - // Generate unique request ID. const requestId = crypto.randomUUID() event.respondWith(handleRequest(event, requestId)) }) +/** + * @param {FetchEvent} event + * @param {string} requestId + */ async function handleRequest(event, requestId) { const client = await resolveMainClient(event) + const requestCloneForEvents = event.request.clone() const response = await getResponse(event, client, requestId) // Send back the response clone for the "response:*" life-cycle events. // Ensure MSW is active and ready to handle the message, otherwise // this message will pend indefinitely. if (client && activeClientIds.has(client.id)) { - ;(async function () { - const responseClone = response.clone() + const serializedRequest = await serializeRequest(requestCloneForEvents) - sendToClient( - client, - { - type: 'RESPONSE', - payload: { - requestId, - isMockedResponse: IS_MOCKED_RESPONSE in response, + // Clone the response so both the client and the library could consume it. + const responseClone = response.clone() + + sendToClient( + client, + { + type: 'RESPONSE', + payload: { + isMockedResponse: IS_MOCKED_RESPONSE in response, + request: { + id: requestId, + ...serializedRequest, + }, + response: { type: responseClone.type, status: responseClone.status, statusText: responseClone.statusText, - body: responseClone.body, headers: Object.fromEntries(responseClone.headers.entries()), + body: responseClone.body, }, }, - [responseClone.body], - ) - })() + }, + responseClone.body ? [serializedRequest.body, responseClone.body] : [], + ) } return response } -// Resolve the main client for the given event. -// Client that issues a request doesn't necessarily equal the client -// that registered the worker. It's with the latter the worker should -// communicate with during the response resolving phase. +/** + * Resolve the main client for the given event. + * Client that issues a request doesn't necessarily equal the client + * that registered the worker. It's with the latter the worker should + * communicate with during the response resolving phase. + * @param {FetchEvent} event + * @returns {Promise} + */ async function resolveMainClient(event) { const client = await self.clients.get(event.clientId) @@ -184,12 +198,16 @@ async function resolveMainClient(event) { }) } +/** + * @param {FetchEvent} event + * @param {Client | undefined} client + * @param {string} requestId + * @returns {Promise} + */ async function getResponse(event, client, requestId) { - const { request } = event - // Clone the request because it might've been already used // (i.e. its body has been read and sent to the client). - const requestClone = request.clone() + const requestClone = event.request.clone() function passthrough() { // Cast the request headers to a new Headers instance @@ -230,29 +248,17 @@ async function getResponse(event, client, requestId) { } // Notify the client that a request has been intercepted. - const requestBuffer = await request.arrayBuffer() + const serializedRequest = await serializeRequest(event.request) const clientMessage = await sendToClient( client, { type: 'REQUEST', payload: { id: requestId, - url: request.url, - mode: request.mode, - method: request.method, - headers: Object.fromEntries(request.headers.entries()), - cache: request.cache, - credentials: request.credentials, - destination: request.destination, - integrity: request.integrity, - redirect: request.redirect, - referrer: request.referrer, - referrerPolicy: request.referrerPolicy, - body: requestBuffer, - keepalive: request.keepalive, + ...serializedRequest, }, }, - [requestBuffer], + [serializedRequest.body], ) switch (clientMessage.type) { @@ -268,6 +274,12 @@ async function getResponse(event, client, requestId) { return passthrough() } +/** + * @param {Client} client + * @param {any} message + * @param {Array} transferrables + * @returns {Promise} + */ function sendToClient(client, message, transferrables = []) { return new Promise((resolve, reject) => { const channel = new MessageChannel() @@ -280,14 +292,18 @@ function sendToClient(client, message, transferrables = []) { resolve(event.data) } - client.postMessage( - message, - [channel.port2].concat(transferrables.filter(Boolean)), - ) + client.postMessage(message, [ + channel.port2, + ...transferrables.filter(Boolean), + ]) }) } -async function respondWithMock(response) { +/** + * @param {Response} response + * @returns {Response} + */ +function respondWithMock(response) { // Setting response status code to 0 is a no-op. // However, when responding with a "Response.error()", the produced Response // instance will have status code set to 0. Since it's not possible to create @@ -305,3 +321,24 @@ async function respondWithMock(response) { return mockedResponse } + +/** + * @param {Request} request + */ +async function serializeRequest(request) { + return { + url: request.url, + mode: request.mode, + method: request.method, + headers: Object.fromEntries(request.headers.entries()), + cache: request.cache, + credentials: request.credentials, + destination: request.destination, + integrity: request.integrity, + redirect: request.redirect, + referrer: request.referrer, + referrerPolicy: request.referrerPolicy, + body: await request.arrayBuffer(), + keepalive: request.keepalive, + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 44849e18..9e12c51d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2063,8 +2063,8 @@ importers: specifier: ^2.8.2 version: 2.8.2(react-redux@9.2.0(@types/react@19.1.6)(react@19.1.0)(redux@5.0.1))(react@19.1.0) msw: - specifier: ^2.8.7 - version: 2.8.7(@types/node@22.15.21)(typescript@5.8.3) + specifier: ^2.10.2 + version: 2.10.2(@types/node@22.15.21)(typescript@5.8.3) react: specifier: ^19.1.0 version: 19.1.0 @@ -4074,8 +4074,8 @@ packages: '@mswjs/data@0.16.2': resolution: {integrity: sha512-/C0d/PBcJyQJokUhcjO4HiZPc67hzllKlRtD1XELygl2t991/ATAAQJVcStn4YtVALsNodruzOHT0JIvgr0hnA==} - '@mswjs/interceptors@0.38.7': - resolution: {integrity: sha512-Jkb27iSn7JPdkqlTqKfhncFfnEZsIJVYxsFbUSWEkxdIPdsyngrhoDBk0/BGD2FQcRH99vlRrkHpNTyKqI+0/w==} + '@mswjs/interceptors@0.39.2': + resolution: {integrity: sha512-RuzCup9Ct91Y7V79xwCb146RaBRHZ7NBbrIUySumd1rpKqHL5OonaqrGIbug5hNwP/fRyxFMA6ISgw4FTtYFYg==} engines: {node: '>=18'} '@nicolo-ribaudo/chokidar-2@2.1.8-no-fsevents.3': @@ -8157,8 +8157,8 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - msw@2.8.7: - resolution: {integrity: sha512-0TGfV4oQiKpa3pDsQBDf0xvFP+sRrqEOnh2n1JWpHVKHJHLv6ZmY1HCZpCi7uDiJTeIHJMBpmBiRmBJN+ETPSQ==} + msw@2.10.2: + resolution: {integrity: sha512-RCKM6IZseZQCWcSWlutdf590M8nVfRHG1ImwzOtwz8IYxgT4zhUO0rfTcTvDGiaFE0Rhcc+h43lcF3Jc9gFtwQ==} engines: {node: '>=18'} hasBin: true peerDependencies: @@ -11876,13 +11876,13 @@ snapshots: strict-event-emitter: 0.5.1 uuid: 8.3.2 optionalDependencies: - msw: 2.8.7(@types/node@22.15.21)(typescript@5.8.3) + msw: 2.10.2(@types/node@22.15.21)(typescript@5.8.3) transitivePeerDependencies: - '@types/node' - supports-color - typescript - '@mswjs/interceptors@0.38.7': + '@mswjs/interceptors@0.39.2': dependencies: '@open-draft/deferred-promise': 2.2.0 '@open-draft/logger': 0.3.0 @@ -16826,13 +16826,13 @@ snapshots: ms@2.1.3: {} - msw@2.8.7(@types/node@22.15.21)(typescript@5.8.3): + msw@2.10.2(@types/node@22.15.21)(typescript@5.8.3): dependencies: '@bundled-es-modules/cookie': 2.0.1 '@bundled-es-modules/statuses': 1.0.1 '@bundled-es-modules/tough-cookie': 0.1.6 '@inquirer/confirm': 5.1.10(@types/node@22.15.21) - '@mswjs/interceptors': 0.38.7 + '@mswjs/interceptors': 0.39.2 '@open-draft/deferred-promise': 2.2.0 '@open-draft/until': 2.1.0 '@types/cookie': 0.6.0