diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a31b8cff10c..d979abbf29e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3412,9 +3412,6 @@ importers: jsdom: specifier: ^29.1.1 version: 29.1.1(@noble/hashes@2.4.0) - msw: - specifier: ^2.15.0 - version: 2.15.0(@types/node@26.6.3)(typescript@6.0.3) playwright: specifier: ^1.62.1 version: 1.63.0 @@ -5350,9 +5347,6 @@ importers: '@vitejs/plugin-react': specifier: ^6.0.5 version: 6.0.5(vite@8.3.5(@types/node@26.6.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15(patch_hash=4d1d35da1809be2a945519cb26890e48107810b9b66c6913a6a89abb5ad6a1e6))(yaml@2.9.1)) - msw: - specifier: ^2.15.0 - version: 2.15.0(@types/node@26.6.3)(typescript@6.0.3) typescript: specifier: ^6.0.3 version: 6.0.3 @@ -5493,9 +5487,6 @@ importers: '@vitejs/plugin-react': specifier: ^6.0.5 version: 6.0.5(vite@8.3.5(@types/node@26.6.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15(patch_hash=4d1d35da1809be2a945519cb26890e48107810b9b66c6913a6a89abb5ad6a1e6))(yaml@2.9.1)) - msw: - specifier: ^2.15.0 - version: 2.15.0(@types/node@26.6.3)(typescript@6.0.3) postcss: specifier: ^8.5.10 version: 8.5.31 @@ -16358,7 +16349,8 @@ snapshots: '@img/sharp-win32-x64@0.35.5': optional: true - '@inquirer/ansi@2.0.7': {} + '@inquirer/ansi@2.0.7': + optional: true '@inquirer/confirm@6.1.1(@types/node@26.6.3)': dependencies: @@ -16366,6 +16358,7 @@ snapshots: '@inquirer/type': 4.0.7(@types/node@26.6.3) optionalDependencies: '@types/node': 26.6.3 + optional: true '@inquirer/core@11.2.1(@types/node@26.6.3)': dependencies: @@ -16378,12 +16371,15 @@ snapshots: signal-exit: 4.1.0 optionalDependencies: '@types/node': 26.6.3 + optional: true - '@inquirer/figures@2.0.7': {} + '@inquirer/figures@2.0.7': + optional: true '@inquirer/type@4.0.7(@types/node@26.6.3)': optionalDependencies: '@types/node': 26.6.3 + optional: true '@ioredis/as-callback@3.0.0': {} @@ -16683,6 +16679,7 @@ snapshots: is-node-process: 1.2.0 outvariant: 1.4.3 strict-event-emitter: 0.5.1 + optional: true '@neon-rs/load@0.0.4': {} @@ -16751,16 +16748,20 @@ snapshots: wrap-ansi: 7.0.0 wsl-utils: 0.4.0 - '@open-draft/deferred-promise@2.2.0': {} + '@open-draft/deferred-promise@2.2.0': + optional: true - '@open-draft/deferred-promise@3.0.0': {} + '@open-draft/deferred-promise@3.0.0': + optional: true '@open-draft/logger@0.3.0': dependencies: is-node-process: 1.2.0 outvariant: 1.4.3 + optional: true - '@open-draft/until@2.1.0': {} + '@open-draft/until@2.1.0': + optional: true '@opentelemetry/api@1.9.1': optional: true @@ -18410,13 +18411,15 @@ snapshots: '@types/set-cookie-parser@2.4.10': dependencies: '@types/node': 26.6.3 + optional: true '@types/sql.js@1.4.11': dependencies: '@types/emscripten': 1.41.5 '@types/node': 26.6.3 - '@types/statuses@2.0.6': {} + '@types/statuses@2.0.6': + optional: true '@types/trusted-types@2.0.7': optional: true @@ -19366,7 +19369,8 @@ snapshots: cli-spinners@2.9.2: {} - cli-width@4.1.0: {} + cli-width@4.1.0: + optional: true client-only@0.0.1: {} @@ -19381,6 +19385,7 @@ snapshots: string-width: 4.2.3 strip-ansi: 6.0.1 wrap-ansi: 7.0.0 + optional: true cliui@9.0.1: dependencies: @@ -20818,7 +20823,8 @@ snapshots: graceful-fs@4.2.11: {} - graphql@16.14.2: {} + graphql@16.14.2: + optional: true hachure-fill@0.5.2: {} @@ -20988,6 +20994,7 @@ snapshots: dependencies: '@types/set-cookie-parser': 2.4.10 set-cookie-parser: 3.1.2 + optional: true hermes-estree@0.25.1: {} @@ -21199,7 +21206,8 @@ snapshots: is-interactive@2.0.0: {} - is-node-process@1.2.0: {} + is-node-process@1.2.0: + optional: true is-number@7.0.0: {} @@ -22425,12 +22433,14 @@ snapshots: typescript: 6.0.3 transitivePeerDependencies: - '@types/node' + optional: true murmurhash-js@1.0.0: {} mute-stream@0.0.8: {} - mute-stream@3.0.0: {} + mute-stream@3.0.0: + optional: true mysql2@3.24.4(@types/node@26.6.3): dependencies: @@ -22631,7 +22641,8 @@ snapshots: string-width: 7.2.0 strip-ansi: 7.2.0 - outvariant@1.4.3: {} + outvariant@1.4.3: + optional: true p-limit@2.3.0: dependencies: @@ -22727,7 +22738,8 @@ snapshots: path-to-regexp@0.1.13: {} - path-to-regexp@6.3.0: {} + path-to-regexp@6.3.0: + optional: true path-to-regexp@8.4.2: {} @@ -23415,7 +23427,8 @@ snapshots: onetime: 7.0.0 signal-exit: 4.1.0 - rettime@0.11.11: {} + rettime@0.11.11: + optional: true reusify@1.1.0: {} @@ -23916,7 +23929,8 @@ snapshots: - bare-abort-controller - react-native-b4a - strict-event-emitter@0.5.1: {} + strict-event-emitter@0.5.1: + optional: true strictdom@1.0.1: {} @@ -24071,7 +24085,8 @@ snapshots: string-width: 4.2.3 strip-ansi: 6.0.1 - tagged-tag@1.0.0: {} + tagged-tag@1.0.0: + optional: true tailwind-merge@3.6.0: {} @@ -24307,6 +24322,7 @@ snapshots: type-fest@5.8.0: dependencies: tagged-tag: 1.0.0 + optional: true type-is@1.6.18: dependencies: @@ -24461,7 +24477,8 @@ snapshots: picomatch: 4.0.7 webpack-virtual-modules: 0.6.2 - until-async@3.0.2: {} + until-async@3.0.2: + optional: true unzipper@0.10.14: dependencies: @@ -24845,7 +24862,8 @@ snapshots: camelcase: 5.3.1 decamelize: 1.2.0 - yargs-parser@21.1.1: {} + yargs-parser@21.1.1: + optional: true yargs-parser@22.0.0: {} @@ -24872,6 +24890,7 @@ snapshots: string-width: 4.2.3 y18n: 5.0.8 yargs-parser: 21.1.1 + optional: true yargs@18.0.0: dependencies: diff --git a/ui/apps/console/.gitignore b/ui/apps/console/.gitignore index 866ed01c9bb..18fc4bad42a 100644 --- a/ui/apps/console/.gitignore +++ b/ui/apps/console/.gitignore @@ -27,5 +27,3 @@ plugin.d.ts *.sln *.sw? -# MSW -public/mockServiceWorker.js diff --git a/ui/e2e/console-rendering.spec.ts b/ui/e2e/console-rendering.spec.ts index 9a744987f65..a810c601add 100644 --- a/ui/e2e/console-rendering.spec.ts +++ b/ui/e2e/console-rendering.spec.ts @@ -67,22 +67,4 @@ test.describe('Console Rendering', () => { const childCount = await root.evaluate((el) => el.children.length); expect(childCount, 'React did not mount on deep route').toBeGreaterThan(0); }); - - test('should include the MSW service worker in the build output', async ({ page }) => { - // The mock server requires mockServiceWorker.js to be served from /public. - // If it's missing, the app may hang during bootstrap. - const response = await page.request.get(`${CONSOLE_BASE}/mockServiceWorker.js`); - - // In production builds without MSW, the asset may be absent. The static - // server returns the SPA fallback (index.html) for unknown paths, which - // is a 200 with `text/html`. Treat that as "MSW not bundled" and skip. - if (response.ok()) { - const contentType = response.headers()['content-type'] || ''; - if (contentType.includes('text/html')) { - // SPA fallback — mockServiceWorker.js is not bundled in this build. - return; - } - expect(contentType).toContain('javascript'); - } - }); }); diff --git a/ui/package.json b/ui/package.json index 206648cfd0c..db991bb3161 100644 --- a/ui/package.json +++ b/ui/package.json @@ -155,7 +155,6 @@ "globals": "^17.11.0", "happy-dom": "^20.11.2", "jsdom": "^29.1.1", - "msw": "^2.15.0", "playwright": "^1.62.1", "react": "19.3.0", "react-dom": "19.3.0", @@ -177,10 +176,5 @@ "vitest-axe": "^0.1.0", "wait-on": "^9.5.1", "yaml": "^2.9.0" - }, - "msw": { - "workerDirectory": [ - "public" - ] } } diff --git a/ui/packages/plugin-form/package.json b/ui/packages/plugin-form/package.json index f4a912165d4..a18155bb841 100644 --- a/ui/packages/plugin-form/package.json +++ b/ui/packages/plugin-form/package.json @@ -44,7 +44,6 @@ "@object-ui/data-objectstack": "workspace:*", "@object-ui/test-support": "workspace:*", "@vitejs/plugin-react": "^6.0.5", - "msw": "^2.15.0", "typescript": "^6.0.3", "vite": "^8.2.1", "vite-plugin-dts": "^5.0.3" diff --git a/ui/packages/plugin-grid/package.json b/ui/packages/plugin-grid/package.json index aaf00208850..23fc0d758f7 100644 --- a/ui/packages/plugin-grid/package.json +++ b/ui/packages/plugin-grid/package.json @@ -48,7 +48,6 @@ "@objectstack/spec": "workspace:^", "@tailwindcss/postcss": "^4.3.3", "@vitejs/plugin-react": "^6.0.5", - "msw": "^2.15.0", "postcss": "^8.5.26", "tailwindcss": "^4.3.3", "typescript": "^6.0.3", diff --git a/ui/public/mockServiceWorker.js b/ui/public/mockServiceWorker.js deleted file mode 100644 index 33dde9e7700..00000000000 --- a/ui/public/mockServiceWorker.js +++ /dev/null @@ -1,349 +0,0 @@ -/* eslint-disable */ -/* tslint:disable */ - -/** - * Mock Service Worker. - * @see https://github.com/mswjs/msw - * - Please do NOT modify this file. - */ - -const PACKAGE_VERSION = '2.14.6' -const INTEGRITY_CHECKSUM = '4db4a41e972cec1b64cc569c66952d82' -const IS_MOCKED_RESPONSE = Symbol('isMockedResponse') -const activeClientIds = new Set() - -addEventListener('install', function () { - self.skipWaiting() -}) - -addEventListener('activate', function (event) { - event.waitUntil(self.clients.claim()) -}) - -addEventListener('message', async function (event) { - const clientId = Reflect.get(event.source || {}, 'id') - - if (!clientId || !self.clients) { - return - } - - const client = await self.clients.get(clientId) - - if (!client) { - return - } - - const allClients = await self.clients.matchAll({ - type: 'window', - }) - - switch (event.data) { - case 'KEEPALIVE_REQUEST': { - sendToClient(client, { - type: 'KEEPALIVE_RESPONSE', - }) - break - } - - case 'INTEGRITY_CHECK_REQUEST': { - sendToClient(client, { - type: 'INTEGRITY_CHECK_RESPONSE', - payload: { - packageVersion: PACKAGE_VERSION, - checksum: INTEGRITY_CHECKSUM, - }, - }) - break - } - - case 'MOCK_ACTIVATE': { - activeClientIds.add(clientId) - - sendToClient(client, { - type: 'MOCKING_ENABLED', - payload: { - client: { - id: client.id, - frameType: client.frameType, - }, - }, - }) - break - } - - case 'CLIENT_CLOSED': { - activeClientIds.delete(clientId) - - const remainingClients = allClients.filter((client) => { - return client.id !== clientId - }) - - // Unregister itself when there are no more clients - if (remainingClients.length === 0) { - self.registration.unregister() - } - - break - } - } -}) - -addEventListener('fetch', function (event) { - const requestInterceptedAt = Date.now() - - // Bypass navigation requests. - 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 ( - event.request.cache === 'only-if-cached' && - event.request.mode !== 'same-origin' - ) { - return - } - - // Bypass all requests when there are no active clients. - // Prevents the self-unregistered worked from handling requests - // after it's been terminated (still remains active until the next reload). - if (activeClientIds.size === 0) { - return - } - - const requestId = crypto.randomUUID() - event.respondWith(handleRequest(event, requestId, requestInterceptedAt)) -}) - -/** - * @param {FetchEvent} event - * @param {string} requestId - * @param {number} requestInterceptedAt - */ -async function handleRequest(event, requestId, requestInterceptedAt) { - const client = await resolveMainClient(event) - const requestCloneForEvents = event.request.clone() - const response = await getResponse( - event, - client, - requestId, - requestInterceptedAt, - ) - - // 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)) { - const serializedRequest = await serializeRequest(requestCloneForEvents) - - // 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, - headers: Object.fromEntries(responseClone.headers.entries()), - 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. - * @param {FetchEvent} event - * @returns {Promise} - */ -async function resolveMainClient(event) { - const client = await self.clients.get(event.clientId) - - if (activeClientIds.has(event.clientId)) { - return client - } - - if (client?.frameType === 'top-level') { - return client - } - - const allClients = await self.clients.matchAll({ - type: 'window', - }) - - return allClients - .filter((client) => { - // Get only those clients that are currently visible. - return client.visibilityState === 'visible' - }) - .find((client) => { - // Find the client ID that's recorded in the - // set of clients that have registered the worker. - return activeClientIds.has(client.id) - }) -} - -/** - * @param {FetchEvent} event - * @param {Client | undefined} client - * @param {string} requestId - * @param {number} requestInterceptedAt - * @returns {Promise} - */ -async function getResponse(event, client, requestId, requestInterceptedAt) { - // Clone the request because it might've been already used - // (i.e. its body has been read and sent to the client). - const requestClone = event.request.clone() - - function passthrough() { - // Cast the request headers to a new Headers instance - // so the headers can be manipulated with. - const headers = new Headers(requestClone.headers) - - // Remove the "accept" header value that marked this request as passthrough. - // This prevents request alteration and also keeps it compliant with the - // user-defined CORS policies. - const acceptHeader = headers.get('accept') - if (acceptHeader) { - const values = acceptHeader.split(',').map((value) => value.trim()) - const filteredValues = values.filter( - (value) => value !== 'msw/passthrough', - ) - - if (filteredValues.length > 0) { - headers.set('accept', filteredValues.join(', ')) - } else { - headers.delete('accept') - } - } - - return fetch(requestClone, { headers }) - } - - // Bypass mocking when the client is not active. - if (!client) { - return passthrough() - } - - // Bypass initial page load requests (i.e. static assets). - // The absence of the immediate/parent client in the map of the active clients - // means that MSW hasn't dispatched the "MOCK_ACTIVATE" event yet - // and is not ready to handle requests. - if (!activeClientIds.has(client.id)) { - return passthrough() - } - - // Notify the client that a request has been intercepted. - const serializedRequest = await serializeRequest(event.request) - const clientMessage = await sendToClient( - client, - { - type: 'REQUEST', - payload: { - id: requestId, - interceptedAt: requestInterceptedAt, - ...serializedRequest, - }, - }, - [serializedRequest.body], - ) - - switch (clientMessage.type) { - case 'MOCK_RESPONSE': { - return respondWithMock(clientMessage.data) - } - - case 'PASSTHROUGH': { - return passthrough() - } - } - - 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() - - channel.port1.onmessage = (event) => { - if (event.data && event.data.error) { - return reject(event.data.error) - } - - resolve(event.data) - } - - client.postMessage(message, [ - channel.port2, - ...transferrables.filter(Boolean), - ]) - }) -} - -/** - * @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 - // a Response instance with status code 0, handle that use-case separately. - if (response.status === 0) { - return Response.error() - } - - const mockedResponse = new Response(response.body, response) - - Reflect.defineProperty(mockedResponse, IS_MOCKED_RESPONSE, { - value: true, - enumerable: true, - }) - - 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, - } -}