Skip to content

feat: use the network source architecture (defineNetwork)#2650

Merged
kettanaito merged 116 commits into
mainfrom
fix/define-network
Apr 6, 2026
Merged

feat: use the network source architecture (defineNetwork)#2650
kettanaito merged 116 commits into
mainfrom
fix/define-network

Conversation

@kettanaito
Copy link
Copy Markdown
Member

@kettanaito kettanaito commented Jan 10, 2026

Changes

  • Rewrites the way the SetupApi behaves by introducing: network frames, sources, controllers, and defineNetwork.
  • Handlers are now stored in a kind-based map. This should improve the performance during handler lookup since it becomes O(1).
  • Fixes an issue where a WebSocket connection would be logged in the console even when there are no matching event handlers for it.
  • Handlers filtering no longer uses instanceof check. Instead, the kind property of the handler is used.

Usage

The introduces APIs are meant to be used from the explicit msw/future export path. The path itself isn't documented as the APIs are considered experimental until the next major release.

Roadmap

  • Ensure the changes are backward-compatible
    • I removed HandlersKind and just inlined them in the handler classes.
    • I removed __kind private field from handler classes and made kind public. This is a safe change as nobody should be using these fields.
  • Passing handlers as both handlers and the constructor argument for the handlers controller seems odd. Choose just one?
    • Merged two into a single handlers option. After all, handlers are only needed as the input to the controller.
  • Consider higher-level utilities to create things like custom setupServer. The defineNetwork API is rather low-level. Export NetowrkOptions to the user can just override some of them?
import { defineNetwork } from 'msw'
import { defaultNetwork } from 'msw/node'

// Create a custom "setup*" wrapper.
function setupCustomApi(...handlers) {
  return defineNetwork({
    ...defaultNetwork,
    ...customizations,
    handlers,
  })
}

// Use it as you normally would use "setup*" APIs.
const network = setupCustomApi(...handlers)
await network.enable()
  • Export createSetupServerCommonApi or its alternative. That's a crucial part of extending the default behaviors.
    • I'll hold on regarding this. Let the userland decide what utilities are missing. The common SetuApi isn't that difficult to implement by hand.
  • Fix the issue where onUnhandledFrame couldn't affect the request resolution because it's called after frame.resolve() is finished.
  • Add a test for onUnhandledRequest: 'error' to ensure that the request is errored (not bypassed). There's currently a bug since onUnhandledFrame is called after frame.resolve(), which always calls passthrough() before the unhandled frame callback.
  • Add a test for multiple WebSocket handlers that match the same URL. Make the first throw an error intentionally. Make sure that the next two still fire off. I suspect due to the algo change in WebSocketNetworkFrame, that won't happen (exception in one handler will short-circuit the entire loop).
    • ⚠️ The handler lookup must short-circuit. This is how HTTP behaves, this is how WebSocket should behave to remain predictable.
  • Unit tests for the introduced functionality.
  • Check if unhandled frame logic and exception try/catch in WebSocketInterceptor aren't fighting each other. I suspect since we catch exceptions, they never surface to the interceptor and it never properly translates them to socket error + closure.
  • Consider a new API to replace server.boundary() to establish ASL boundaries for Node.js tests. The NetworkApi must remain the same across environments. Environment-specific APIs must come from the environment entrypoints (msw/node) and applied explicitly.
    • Consider AsyncHandlersController.boundary() instead of the boundary() method in setup-server.ts.
  • (Potentially unneeded) Introduce readyState to NetworkApi so implementers don't have to introduce it themselves (e.g. remove isStarted from setup-worker.ts and use a network.readyState check).
  • ⚠️ Solve the optional asynchronicity in .enable() leaking from the network sources. Not awaiting network.disable() in server.stop() feels weird.
  • Write unit tests for colorless enable/disable in defineNetwork.
  • ⚠️ SetupWorkerApi was exported as a class before, now it's only a type. Re-implement that class similar to how we re-implement SetupServerApi for backwards compatibility.

@kettanaito kettanaito changed the title feat: add the defineNetwork API feat: migrate to the defineNetwork API Jan 11, 2026
@kettanaito kettanaito changed the title feat: migrate to the defineNetwork API feat: implement the defineNetwork API Jan 14, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
src/browser/sources/service-worker-source.ts (1)

400-428: ⚠️ Potential issue | 🟡 Minor

errorWith() silently ignores non-Error, non-Response throwables.

If reason is neither a Response nor an Error (e.g., a thrown string, number, or plain object), the method returns without resolving the request. This could leave the request hanging indefinitely.

🛡️ Proposed fix to handle arbitrary throwables
   public errorWith(reason?: unknown): void {
     if (reason instanceof Response) {
       return this.respondWith(reason)
     }

     if (reason instanceof Error) {
       devUtils.warn(
         `Uncaught exception in the request handler for "%s %s". This exception has been gracefully handled as a 500 response, however, it's strongly recommended to resolve this error, as it indicates a mistake in your code. If you wish to mock an error response, please see this guide: https://mswjs.io/docs/http/mocking-responses/error-responses`,
         this.data.request.method,
         this.data.request.url,
       )

       this.respondWith(
         HttpResponse.json(
           {
             name: reason.name,
             message: reason.message,
             stack: reason.stack,
           },
           {
             status: 500,
             statusText: 'Request Handler Error',
           },
         ),
       )
+      return
+    }
+
+    if (reason !== undefined) {
+      devUtils.warn(
+        `Uncaught non-Error value thrown in the request handler for "%s %s": %o. This has been gracefully handled as a 500 response.`,
+        this.data.request.method,
+        this.data.request.url,
+        reason,
+      )
+
+      this.respondWith(
+        HttpResponse.json(
+          {
+            name: 'UnknownError',
+            message: String(reason),
+          },
+          {
+            status: 500,
+            statusText: 'Request Handler Error',
+          },
+        ),
+      )
     }
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/browser/sources/service-worker-source.ts` around lines 400 - 428, The
errorWith method currently returns silently for throwables that are neither
Response nor Error, leaving requests unresolved; update errorWith (the method)
to handle arbitrary throwables by adding an else branch that logs a warning via
devUtils.warn (including this.data.request.method and this.data.request.url) and
calls this.respondWith(HttpResponse.json(...)) returning a 500 response;
construct the JSON body with a fallback name like "NonErrorThrown" (or use
typeof reason), a message created by String(reason) or JSON.stringify when safe,
and omit or set stack to undefined, so all thrown values resolve the request
instead of hanging.
🧹 Nitpick comments (1)
src/browser/setup-worker.ts (1)

107-109: Consider stronger typing for the WebSocketInterceptor cast.

The as any cast obscures type incompatibilities. If InterceptorSource expects a specific interceptor interface, consider updating the type definition or using a more precise cast to maintain type safety.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/browser/setup-worker.ts` around lines 107 - 109, The current use of "as
any" on new WebSocketInterceptor() hides type mismatches for
InterceptorSource.interceptors; replace the any cast with the concrete
interceptor interface expected by InterceptorSource (or make InterceptorSource
generic) so the compiler enforces compatibility—either update
WebSocketInterceptor to implement the required interface (methods/properties) or
update the InterceptorSource type signature to accept the WebSocketInterceptor
type, and then remove the "as any" cast from the interceptors array where new
WebSocketInterceptor() is passed.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@src/browser/sources/service-worker-source.ts`:
- Around line 400-428: The errorWith method currently returns silently for
throwables that are neither Response nor Error, leaving requests unresolved;
update errorWith (the method) to handle arbitrary throwables by adding an else
branch that logs a warning via devUtils.warn (including this.data.request.method
and this.data.request.url) and calls this.respondWith(HttpResponse.json(...))
returning a 500 response; construct the JSON body with a fallback name like
"NonErrorThrown" (or use typeof reason), a message created by String(reason) or
JSON.stringify when safe, and omit or set stack to undefined, so all thrown
values resolve the request instead of hanging.

---

Nitpick comments:
In `@src/browser/setup-worker.ts`:
- Around line 107-109: The current use of "as any" on new WebSocketInterceptor()
hides type mismatches for InterceptorSource.interceptors; replace the any cast
with the concrete interceptor interface expected by InterceptorSource (or make
InterceptorSource generic) so the compiler enforces compatibility—either update
WebSocketInterceptor to implement the required interface (methods/properties) or
update the InterceptorSource type signature to accept the WebSocketInterceptor
type, and then remove the "as any" cast from the interceptors array where new
WebSocketInterceptor() is passed.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: e56feca9-0dcd-4ef4-9fa9-0e963bc2ce5c

📥 Commits

Reviewing files that changed from the base of the PR and between a41926b and 8d34dc7.

📒 Files selected for processing (3)
  • src/browser/setup-worker.ts
  • src/browser/sources/service-worker-source.ts
  • test/browser/msw-api/setup-worker/life-cycle-events/on.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • test/browser/msw-api/setup-worker/life-cycle-events/on.test.ts

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/core/experimental/define-network.test.ts (1)

28-28: Floating promises in async assertions could cause test runner warnings.

The toBeInstanceOf(Promise) assertions verify the return type but leave the returned Promises unhandled. While these empty async functions won't reject, some test runners flag unhandled promises. Consider awaiting or explicitly ignoring them for cleaner test output.

💡 Example fix for one case
-    expect(network.enable()).toBeInstanceOf(Promise)
+    const result = network.enable()
+    expect(result).toBeInstanceOf(Promise)
+    await result

Also applies to: 40-40, 73-73, 87-87

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/core/experimental/define-network.test.ts` at line 28, Tests currently
assert return types with expect(network.enable()).toBeInstanceOf(Promise) (and
similarly for network.disable(), network.onRequest(), network.offRequest()),
leaving Promises unawaited and creating floating promises; change each assertion
to either await the call (e.g., await network.enable() then assert expected
side-effects) or use Jest's promise helpers (await
expect(network.enable()).resolves.toBeDefined() or similar) so the returned
Promise is handled and no unhandled/floating promise warnings occur.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/core/experimental/define-network.test.ts`:
- Line 16: Fix the typo in the test names in
src/core/experimental/define-network.test.ts: change the string "returns an
async enable if any the sources are async" to "returns an async enable if any of
the sources are async" (update both occurrences, including the one referenced
around the second occurrence) so the test descriptions read correctly; locate
the tests by the current description in the it(...) calls in the file.

---

Nitpick comments:
In `@src/core/experimental/define-network.test.ts`:
- Line 28: Tests currently assert return types with
expect(network.enable()).toBeInstanceOf(Promise) (and similarly for
network.disable(), network.onRequest(), network.offRequest()), leaving Promises
unawaited and creating floating promises; change each assertion to either await
the call (e.g., await network.enable() then assert expected side-effects) or use
Jest's promise helpers (await expect(network.enable()).resolves.toBeDefined() or
similar) so the returned Promise is handled and no unhandled/floating promise
warnings occur.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 6bf9d467-fa56-4297-b0e0-4816c7bb266a

📥 Commits

Reviewing files that changed from the base of the PR and between 8d34dc7 and 9b2a005.

📒 Files selected for processing (4)
  • src/browser/glossary.ts
  • src/browser/index.ts
  • src/browser/setup-worker.ts
  • src/core/experimental/define-network.test.ts
✅ Files skipped from review due to trivial changes (2)
  • src/browser/glossary.ts
  • src/browser/index.ts

Comment thread src/core/experimental/define-network.test.ts Outdated
@kettanaito kettanaito merged commit 2b73790 into main Apr 6, 2026
22 checks passed
@kettanaito kettanaito deleted the fix/define-network branch April 6, 2026 12:29
@kettanaito
Copy link
Copy Markdown
Member Author

Released: v2.13.0 🎉

This has been released in v2.13.0.

Get these changes by running the following command:

npm i msw@latest

Predictable release automation by Release.

Amund211 added a commit to Amund211/rainbow that referenced this pull request Apr 22, 2026
msw 2.13 introduced a service-worker lifecycle change that breaks our
vitest browser tests. Our per-test fixture calls worker.start()/stop()
around each test; on 2.13 the stop → next start cycle leaves a window
where requests bypass the worker and hit Vite directly, so the uuid
lookup fails with "Failed to fetch" and dependent tests time out at 20s.

This reproduces locally: upgrading to 2.13.3 fails ~13 tests; pinning
back to 2.12.14 makes all 196 tests pass (~21s, matching baseline).

Upstream bug: mswjs/msw#2706
Introduced by the 2.13.0 "network source architecture" refactor
(mswjs/msw#2650).

A follow-up PR will upgrade msw back to the latest and adjust the
worker fixture to only start() once per test file (the recommended
workaround: reset handlers between tests, never stop).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Amund211 added a commit to Amund211/rainbow that referenced this pull request Apr 22, 2026
msw 2.13 shipped a "network source architecture" refactor (mswjs/msw#2650)
that altered the worker lifecycle. Our fixture called worker.start() before
each test and worker.stop() after, which on 2.13 creates a race: the next
test's start() can't take over before requests are made, so they bypass the
worker and hit Vite directly — surfacing as "Failed to fetch" and 20s
timeouts on every test that makes a request.

The upstream fix is to simply not call worker.stop(). This matches the
official vitest-browser-mode recipe
(https://mswjs.io/docs/recipes/vitest-browser-mode).

Tracked upstream at mswjs/msw#2706.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Amund211 added a commit to Amund211/rainbow that referenced this pull request Apr 22, 2026
…updates (#225)

* chore(deps): Bump the minor-updates group across 1 directory with 21 updates

Bumps the minor-updates group with 21 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [@sentry/react](https://github.com/getsentry/sentry-javascript) | `10.46.0` | `10.48.0` |
| [@sentry/vite-plugin](https://github.com/getsentry/sentry-javascript-bundler-plugins) | `5.1.1` | `5.2.0` |
| [@tanstack/react-query](https://github.com/TanStack/query/tree/HEAD/packages/react-query) | `5.95.2` | `5.99.0` |
| [@tanstack/react-query-persist-client](https://github.com/TanStack/query/tree/HEAD/packages/react-query-persist-client) | `5.95.2` | `5.99.0` |
| [@tanstack/react-router](https://github.com/TanStack/router/tree/HEAD/packages/react-router) | `1.168.8` | `1.168.21` |
| [react](https://github.com/facebook/react/tree/HEAD/packages/react) | `19.2.4` | `19.2.5` |
| [react-dom](https://github.com/facebook/react/tree/HEAD/packages/react-dom) | `19.2.4` | `19.2.5` |
| [@rolldown/plugin-babel](https://github.com/rolldown/plugins/tree/HEAD/packages/babel) | `0.2.2` | `0.2.3` |
| [@tanstack/eslint-plugin-query](https://github.com/TanStack/query/tree/HEAD/packages/eslint-plugin-query) | `5.97.0` | `5.99.0` |
| [@tanstack/react-query-devtools](https://github.com/TanStack/query/tree/HEAD/packages/react-query-devtools) | `5.95.2` | `5.99.0` |
| [@tanstack/react-router-devtools](https://github.com/TanStack/router/tree/HEAD/packages/react-router-devtools) | `1.166.11` | `1.166.13` |
| [@tanstack/router-plugin](https://github.com/TanStack/router/tree/HEAD/packages/router-plugin) | `1.167.9` | `1.167.22` |
| [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) | `24.12.0` | `24.12.2` |
| [@vitest/browser-playwright](https://github.com/vitest-dev/vitest/tree/HEAD/packages/browser-playwright) | `4.1.2` | `4.1.4` |
| [@vitest/coverage-v8](https://github.com/vitest-dev/vitest/tree/HEAD/packages/coverage-v8) | `4.1.2` | `4.1.4` |
| [msw](https://github.com/mswjs/msw) | `2.12.14` | `2.13.3` |
| [oxfmt](https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt) | `0.42.0` | `0.45.0` |
| [oxlint-tsgolint](https://github.com/oxc-project/tsgolint) | `0.20.0` | `0.21.0` |
| [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) | `8.0.5` | `8.0.8` |
| [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest) | `4.1.2` | `4.1.4` |
| [vitest-browser-react](https://github.com/vitest-community/vitest-browser-react) | `2.1.0` | `2.2.0` |



Updates `@sentry/react` from 10.46.0 to 10.48.0
- [Release notes](https://github.com/getsentry/sentry-javascript/releases)
- [Changelog](https://github.com/getsentry/sentry-javascript/blob/develop/CHANGELOG.md)
- [Commits](getsentry/sentry-javascript@10.46.0...10.48.0)

Updates `@sentry/vite-plugin` from 5.1.1 to 5.2.0
- [Release notes](https://github.com/getsentry/sentry-javascript-bundler-plugins/releases)
- [Changelog](https://github.com/getsentry/sentry-javascript-bundler-plugins/blob/main/CHANGELOG.md)
- [Commits](getsentry/sentry-javascript-bundler-plugins@5.1.1...5.2.0)

Updates `@tanstack/react-query` from 5.95.2 to 5.99.0
- [Release notes](https://github.com/TanStack/query/releases)
- [Changelog](https://github.com/TanStack/query/blob/main/packages/react-query/CHANGELOG.md)
- [Commits](https://github.com/TanStack/query/commits/@tanstack/react-query@5.99.0/packages/react-query)

Updates `@tanstack/react-query-persist-client` from 5.95.2 to 5.99.0
- [Release notes](https://github.com/TanStack/query/releases)
- [Changelog](https://github.com/TanStack/query/blob/main/packages/react-query-persist-client/CHANGELOG.md)
- [Commits](https://github.com/TanStack/query/commits/@tanstack/react-query-persist-client@5.99.0/packages/react-query-persist-client)

Updates `@tanstack/react-router` from 1.168.8 to 1.168.21
- [Release notes](https://github.com/TanStack/router/releases)
- [Changelog](https://github.com/TanStack/router/blob/main/packages/react-router/CHANGELOG.md)
- [Commits](https://github.com/TanStack/router/commits/@tanstack/react-router@1.168.21/packages/react-router)

Updates `react` from 19.2.4 to 19.2.5
- [Release notes](https://github.com/facebook/react/releases)
- [Changelog](https://github.com/facebook/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/react/commits/v19.2.5/packages/react)

Updates `react-dom` from 19.2.4 to 19.2.5
- [Release notes](https://github.com/facebook/react/releases)
- [Changelog](https://github.com/facebook/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/react/commits/v19.2.5/packages/react-dom)

Updates `@rolldown/plugin-babel` from 0.2.2 to 0.2.3
- [Release notes](https://github.com/rolldown/plugins/releases)
- [Changelog](https://github.com/rolldown/plugins/blob/main/packages/babel/CHANGELOG.md)
- [Commits](https://github.com/rolldown/plugins/commits/plugin-babel@0.2.3/packages/babel)

Updates `@tanstack/eslint-plugin-query` from 5.97.0 to 5.99.0
- [Release notes](https://github.com/TanStack/query/releases)
- [Changelog](https://github.com/TanStack/query/blob/main/packages/eslint-plugin-query/CHANGELOG.md)
- [Commits](https://github.com/TanStack/query/commits/@tanstack/eslint-plugin-query@5.99.0/packages/eslint-plugin-query)

Updates `@tanstack/react-query-devtools` from 5.95.2 to 5.99.0
- [Release notes](https://github.com/TanStack/query/releases)
- [Changelog](https://github.com/TanStack/query/blob/main/packages/react-query-devtools/CHANGELOG.md)
- [Commits](https://github.com/TanStack/query/commits/@tanstack/react-query-devtools@5.99.0/packages/react-query-devtools)

Updates `@tanstack/react-router-devtools` from 1.166.11 to 1.166.13
- [Release notes](https://github.com/TanStack/router/releases)
- [Changelog](https://github.com/TanStack/router/blob/main/packages/react-router-devtools/CHANGELOG.md)
- [Commits](https://github.com/TanStack/router/commits/@tanstack/react-router-devtools@1.166.13/packages/react-router-devtools)

Updates `@tanstack/router-plugin` from 1.167.9 to 1.167.22
- [Release notes](https://github.com/TanStack/router/releases)
- [Changelog](https://github.com/TanStack/router/blob/main/packages/router-plugin/CHANGELOG.md)
- [Commits](https://github.com/TanStack/router/commits/@tanstack/router-plugin@1.167.22/packages/router-plugin)

Updates `@types/node` from 24.12.0 to 24.12.2
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Updates `@vitest/browser-playwright` from 4.1.2 to 4.1.4
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.1.4/packages/browser-playwright)

Updates `@vitest/coverage-v8` from 4.1.2 to 4.1.4
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.1.4/packages/coverage-v8)

Updates `msw` from 2.12.14 to 2.13.3
- [Release notes](https://github.com/mswjs/msw/releases)
- [Changelog](https://github.com/mswjs/msw/blob/main/CHANGELOG.md)
- [Commits](mswjs/msw@v2.12.14...v2.13.3)

Updates `oxfmt` from 0.42.0 to 0.45.0
- [Release notes](https://github.com/oxc-project/oxc/releases)
- [Changelog](https://github.com/oxc-project/oxc/blob/main/npm/oxfmt/CHANGELOG.md)
- [Commits](https://github.com/oxc-project/oxc/commits/oxfmt_v0.45.0/npm/oxfmt)

Updates `oxlint-tsgolint` from 0.20.0 to 0.21.0
- [Release notes](https://github.com/oxc-project/tsgolint/releases)
- [Commits](oxc-project/tsgolint@v0.20.0...v0.21.0)

Updates `vite` from 8.0.5 to 8.0.8
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v8.0.8/packages/vite)

Updates `vitest` from 4.1.2 to 4.1.4
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.1.4/packages/vitest)

Updates `vitest-browser-react` from 2.1.0 to 2.2.0
- [Release notes](https://github.com/vitest-community/vitest-browser-react/releases)
- [Commits](vitest-community/vitest-browser-react@v2.1.0...v2.2.0)

---
updated-dependencies:
- dependency-name: "@sentry/react"
  dependency-version: 10.48.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor-updates
- dependency-name: "@sentry/vite-plugin"
  dependency-version: 5.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor-updates
- dependency-name: "@tanstack/react-query"
  dependency-version: 5.99.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor-updates
- dependency-name: "@tanstack/react-query-persist-client"
  dependency-version: 5.99.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor-updates
- dependency-name: "@tanstack/react-router"
  dependency-version: 1.168.21
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: minor-updates
- dependency-name: react
  dependency-version: 19.2.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: minor-updates
- dependency-name: react-dom
  dependency-version: 19.2.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: minor-updates
- dependency-name: "@rolldown/plugin-babel"
  dependency-version: 0.2.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: minor-updates
- dependency-name: "@tanstack/eslint-plugin-query"
  dependency-version: 5.99.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor-updates
- dependency-name: "@tanstack/react-query-devtools"
  dependency-version: 5.99.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor-updates
- dependency-name: "@tanstack/react-router-devtools"
  dependency-version: 1.166.13
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: minor-updates
- dependency-name: "@tanstack/router-plugin"
  dependency-version: 1.167.22
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: minor-updates
- dependency-name: "@types/node"
  dependency-version: 24.12.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: minor-updates
- dependency-name: "@vitest/browser-playwright"
  dependency-version: 4.1.4
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: minor-updates
- dependency-name: "@vitest/coverage-v8"
  dependency-version: 4.1.4
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: minor-updates
- dependency-name: msw
  dependency-version: 2.13.3
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor-updates
- dependency-name: oxfmt
  dependency-version: 0.45.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor-updates
- dependency-name: oxlint-tsgolint
  dependency-version: 0.21.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor-updates
- dependency-name: vite
  dependency-version: 8.0.8
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: minor-updates
- dependency-name: vitest
  dependency-version: 4.1.4
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: minor-updates
- dependency-name: vitest-browser-react
  dependency-version: 2.2.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor-updates
...

Signed-off-by: dependabot[bot] <support@github.com>

* deps: pin msw to 2.12.14 to avoid 2.13 browser lifecycle regression

msw 2.13 introduced a service-worker lifecycle change that breaks our
vitest browser tests. Our per-test fixture calls worker.start()/stop()
around each test; on 2.13 the stop → next start cycle leaves a window
where requests bypass the worker and hit Vite directly, so the uuid
lookup fails with "Failed to fetch" and dependent tests time out at 20s.

This reproduces locally: upgrading to 2.13.3 fails ~13 tests; pinning
back to 2.12.14 makes all 196 tests pass (~21s, matching baseline).

Upstream bug: mswjs/msw#2706
Introduced by the 2.13.0 "network source architecture" refactor
(mswjs/msw#2650).

A follow-up PR will upgrade msw back to the latest and adjust the
worker fixture to only start() once per test file (the recommended
workaround: reset handlers between tests, never stop).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore: bump oxfmt pre-commit hook to v0.45.0

Align with the oxfmt bump in package.json so the pre-commit hook
uses the same formatter version as CI and local dev.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Amund Eggen Svandal <aesvandal@gmail.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Amund211 added a commit to Amund211/rainbow that referenced this pull request Apr 22, 2026
msw 2.13 shipped a "network source architecture" refactor (mswjs/msw#2650)
that altered the worker lifecycle. Our fixture called worker.start() before
each test and worker.stop() after, which on 2.13 creates a race: the next
test's start() can't take over before requests are made, so they bypass the
worker and hit Vite directly — surfacing as "Failed to fetch" and 20s
timeouts on every test that makes a request.

The upstream fix is to simply not call worker.stop(). This matches the
official vitest-browser-mode recipe
(https://mswjs.io/docs/recipes/vitest-browser-mode).

Tracked upstream at mswjs/msw#2706.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Amund211 added a commit to Amund211/rainbow that referenced this pull request Apr 22, 2026
msw 2.13 shipped a "network source architecture" refactor (mswjs/msw#2650)
that altered the worker lifecycle. Our fixture called worker.start() before
each test and worker.stop() after, which on 2.13 creates a race: the next
test's start() can't take over before requests are made, so they bypass the
worker and hit Vite directly — surfacing as "Failed to fetch" and 20s
timeouts on every test that makes a request.

The upstream fix is to simply not call worker.stop(). This matches the
official vitest-browser-mode recipe
(https://mswjs.io/docs/recipes/vitest-browser-mode).

Tracked upstream at mswjs/msw#2706.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants