Skip to content

feat: deliver devtools events from isolated server runtimes via Vite HotChannel#384

Merged
AlemTuzlak merged 30 commits into
mainfrom
worktree-polished-cuddling-lark
Jun 19, 2026
Merged

feat: deliver devtools events from isolated server runtimes via Vite HotChannel#384
AlemTuzlak merged 30 commits into
mainfrom
worktree-polished-cuddling-lark

Conversation

@AlemTuzlak

@AlemTuzlak AlemTuzlak commented Mar 12, 2026

Copy link
Copy Markdown
Collaborator

Summary

Fixes TanStack/ai#339

When TanStack Start uses Nitro v3's nitro() Vite plugin (or any runtime that isolates server code in a separate thread/process), devtools events break because globalThis.__TANSTACK_EVENT_TARGET__ is not shared across isolation boundaries.

This PR adds automatic network transport fallback:

  • EventClient detects isolated server environments (no shared EventTarget, no window) and automatically connects to ServerEventBus via WebSocket
  • ServerEventBus distinguishes "server bridge" connections (?bridge=server) from browser clients and routes bridge messages through both emitEventToClients() (browser devtools) and emitToServer() (in-process EventTarget)
  • Echo prevention via 200-entry ring buffer of event IDs
  • Reconnection with exponential backoff (100ms → 5s, max 10 attempts) then HTTP POST fallback
  • Zero API changes — existing consumers work unchanged
  • Zero configuration — detection and fallback are automatic
  • Dev-only — network transport only activates when Vite plugin replaces compile-time placeholders

Changes

  • packages/event-bus/src/server/server.ts — bridge WebSocket support, POST source-based routing
  • packages/event-bus/src/client/client.ts — interface update (eventId, source fields)
  • packages/event-bus-client/src/plugin.ts — network transport detection, WebSocket connection, emit/receive, reconnect, HTTP fallback
  • packages/event-bus-client/src/ring-buffer.ts — new RingBuffer utility for dedup
  • packages/event-bus-client/src/index.ts — export createNetworkTransportClient

Test plan

  • 60 event-bus tests pass (26 server tests including 5 new bridge/POST tests)
  • 28 event-bus-client tests pass (including 4 network transport + 2 integration + 3 ring buffer)
  • Bidirectional events: client→server and server→client via WebSocket
  • Echo deduplication: client does not receive its own events back
  • Event queuing: events queue during connection and flush on connect
  • Multiple isolated clients work simultaneously
  • Manual test with Nitro v3 nitro() plugin in examples/react/start

Summary by CodeRabbit

  • New Features
    • Added a DevTools runtime bridge that carries dev-only server events from isolated server runtimes back into the Vite dev process for display.
    • Added two React example projects (Cloudflare Workers and Nitro) featuring an on-page server events panel and interactive server calls.
  • Bug Fixes
    • Improved dev-only event delivery/teardown behavior for the runtime bridge.
  • Tests
    • Added comprehensive test coverage for runtime bridge code generation, injection, channel wiring, and DevTools plugin transform behavior.

…er runtimes

Addresses the issue where devtools events are lost when server code runs in
isolated environments (Nitro v3 worker threads, Cloudflare Workers, etc.)
that don't share globalThis with the Vite main thread.
Fix problem description precision, URL matching and handleNewConnection
signature issues, POST handler routing, placeholder convention, triplicate
interface sync, queue preservation, and multi-worker echo safety.
Disambiguate that both standalone and external server POST/upgrade
handlers need updates, and that only WebSocket URL matching needs
prefix change (not SSE/POST URLs).
7-task plan covering: interface updates, ServerEventBus bridge support,
POST handler routing, RingBuffer utility, EventClient network transport
detection, WebSocket connection/emit/receive, and integration tests.
- Accept WebSocket connections with ?bridge=server query parameter
- Track bridge clients separately for proper routing
- Bridge messages route through emit() (broadcast to WS clients + EventTarget)
- Regular browser messages route through emitToServer() (EventTarget only)
- Clean up bridge client tracking on disconnect and stop()
When EventClient detects it is in an isolated server environment
(no shared globalThis.__TANSTACK_EVENT_TARGET__, no window), it
automatically connects to ServerEventBus via WebSocket. Bidirectional:
events emitted in the worker reach the devtools panel, and events
from the devtools panel reach listeners in the worker.

Includes echo prevention via 200-entry ring buffer, exponential
backoff reconnection, HTTP POST fallback, and event queuing.
- Add scheduleReconnect() call in error handler for non-browser runtimes
  where 'close' may not follow 'error'
- Reset wsGaveUp, wsReconnectAttempts, wsReconnectDelay in
  ___destroyNetworkTransport for safe reuse
@changeset-bot

changeset-bot Bot commented Mar 12, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 3f82eeb

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@nx-cloud

nx-cloud Bot commented Mar 12, 2026

Copy link
Copy Markdown

View your CI Pipeline Execution ↗ for commit 8c973f6

Command Status Duration Result
nx affected --targets=test:eslint,test:sherif,t... ✅ Succeeded 43s View ↗
nx run-many --targets=build --exclude=examples/** ✅ Succeeded 4s View ↗

☁️ Nx Cloud last updated this comment at 2026-06-19 17:46:26 UTC

AlemTuzlak and others added 2 commits March 12, 2026 16:59
Two minimal examples for manually testing the network transport fallback:

- examples/react/start-nitro — TanStack Start + Nitro v3 (worker threads)
- examples/react/start-cloudflare — TanStack Start + Cloudflare Workers

Both emit devtools events from server functions and display them in a
custom "Server Events" devtools panel. If events appear in the panel,
the network transport fallback is working correctly.
@coderabbitai

coderabbitai Bot commented Mar 13, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@AlemTuzlak, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 14 minutes and 5 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1a5683ea-dd87-4cd2-9468-7196dbade03d

📥 Commits

Reviewing files that changed from the base of the PR and between f8579d1 and eb46dc4.

📒 Files selected for processing (1)
  • packages/devtools-vite/src/runtime-bridge.test.ts
📝 Walkthrough

Walkthrough

Adds a dev-only Vite HotChannel bridge (runtime-bridge.ts) that injects code into the EventClient module in isolated server runtimes (Cloudflare Workers, Nitro), forwarding devtools events to the Vite process via import.meta.hot. The bridge is wired into the existing Vite plugin and validated with unit tests. Two new example projects demonstrate the feature end-to-end.

Changes

Runtime Bridge Core and Example Apps

Layer / File(s) Summary
Runtime bridge implementation
packages/devtools-vite/src/runtime-bridge.ts
Defines BridgeHotChannel/BridgeServerLike types, isEventClientModule detection, generateRuntimeBridgeCode (IIFE injected into workers), injectRuntimeBridge (injection gate for non-client envs), and wireRuntimeBridgeChannels (bidirectional HotChannel↔EventTarget wiring with teardown).
Plugin wiring and transform
packages/devtools-vite/src/plugin.ts
Imports injectRuntimeBridge and wireRuntimeBridgeChannels, wires channels per non-client environment in configureServer with teardown on httpServer close, and registers the new @tanstack/devtools:runtime-bridge serve-mode transform plugin.
Runtime bridge and plugin tests
packages/devtools-vite/src/runtime-bridge.test.ts, packages/devtools-vite/tests/index.test.ts
Tests generateRuntimeBridgeCode (guards, handshake, forwarding), injectRuntimeBridge (SSR injection, skip conditions), wireRuntimeBridgeChannels (bidirectionality, teardown, handler removal), and the transform plugin for ssr vs client environments.
Cloudflare Workers example app
examples/react/start-cloudflare/src/routes/__root.tsx, examples/react/start-cloudflare/src/routes/index.tsx, examples/react/start-cloudflare/wrangler.jsonc, examples/react/start-cloudflare/package.json
Root route mounts TanStackDevtools with a server-events plugin rendering ServerEventsPanel; index route defines three server functions calling emitServerEvent plus a loader and App component; wrangler.jsonc sets the @tanstack/react-start/server-entry main entry; package.json declares React/Vite/Wrangler dependencies.
Nitro example app
examples/react/start-nitro/src/routes/__root.tsx, examples/react/start-nitro/src/routes/index.tsx, examples/react/start-nitro/package.json
Mirrors the Cloudflare example structure with Nitro-isolated server handlers (greet, generateNumber, fetchData with POST input validation), each emitting devtools events, an App component with a live server responses log, and a package.json declaring Nitro, React/Vite, and build tooling dependencies.
Minor release changeset
.changeset/devtools-vite-runtime-bridge.md
Declares a minor bump for @tanstack/devtools-vite documenting the HotChannel bridge, dev-only injection, production tree-shaking, and zero new runtime dependencies.

Sequence Diagram

sequenceDiagram
  participant ServerFn as Server Function (Worker/Nitro)
  participant EventClient as EventClient (injected bridge)
  participant HotChannel as Vite HotChannel (import.meta.hot)
  participant Plugin as devtools-vite plugin
  participant ServerEventBus as ServerEventBus (Vite process)
  participant DevtoolsUI as TanStackDevtools UI

  ServerFn->>EventClient: emitServerEvent("server-fn-called", data)
  EventClient->>EventClient: dispatches tanstack-dispatch-event on globalThis.__TANSTACK_EVENT_TARGET__
  EventClient->>HotChannel: import.meta.hot.send("tsd:to-server", payload)
  HotChannel->>Plugin: wireRuntimeBridgeChannels tsd:to-server handler
  Plugin->>ServerEventBus: dispatches tanstack-dispatch-event on EventTarget
  ServerEventBus->>HotChannel: EventTarget dispatches tanstack-devtools-global
  HotChannel->>EventClient: import.meta.hot.on("tsd:to-client") re-dispatches CustomEvent
  ServerEventBus->>DevtoolsUI: ServerEventsPanel receives server-fn-called event
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐇 Hoppity-hop through the worker divide,
Events once lost now have somewhere to ride!
A bridge built of hot channels, injected with care,
Dispatching from workerd through thin Vite-lit air.
Cloudflare and Nitro both join in the fun—
No devtools event left behind, not one! 🌉

🚥 Pre-merge checks | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Title check ⚠️ Warning PR title describes devtools-vite runtime bridge feature, but 90% of changes are devtools examples (React Cloudflare/Nitro integration, 600+ LOC) unrelated to the titled feature. Retitle to reflect all substantive work (e.g., 'feat: add devtools runtime bridge and React examples for Cloudflare/Nitro') or split example additions into a separate PR.
Docstring Coverage ⚠️ Warning Docstring coverage is 18.75% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch worktree-polished-cuddling-lark

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Nitpick comments (8)
examples/react/start-cloudflare/.gitignore (1)

6-11: Consider adding env variant ignores to reduce secret leak risk.

You already ignore .env; adding .env.* and Cloudflare local secret files (for example .dev.vars / .dev.vars.*) would provide better protection against accidental commits in local/dev workflows.

Proposed update
 .env
+.env.*
+.dev.vars
+.dev.vars.*
 .nitro
 .tanstack
 .wrangler
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/react/start-cloudflare/.gitignore` around lines 6 - 11, Update the
.gitignore entry that currently lists ".env" to also ignore environment file
variants and common Cloudflare local secret files: add patterns like ".env.*",
"*.env.local", ".dev.vars" and ".dev.vars.*" (or other local secret naming used
in this project) so accidental commits of local/dev secrets are prevented;
ensure these patterns are added alongside existing entries (".env", ".nitro",
".tanstack", ".wrangler", ".output", ".vinxi") in the
examples/react/start-cloudflare/.gitignore file.
examples/react/start-cloudflare/package.json (1)

12-20: Consider moving build-time Vite plugins to devDependencies.

The following packages are Vite plugins used only during development/build and do not run at runtime in Cloudflare Workers:

  • @cloudflare/vite-plugin (line 12)
  • @tanstack/router-plugin (line 17)
  • vite-tsconfig-paths (line 20)

Moving them to devDependencies more accurately reflects their purpose and can reduce confusion about what runs in the deployed worker.

♻️ Proposed fix
   "dependencies": {
-    "@cloudflare/vite-plugin": "^1.13.8",
     "@tanstack/devtools-event-client": "workspace:*",
     "@tanstack/react-devtools": "workspace:*",
     "@tanstack/react-router": "^1.132.0",
     "@tanstack/react-start": "^1.132.0",
-    "@tanstack/router-plugin": "^1.132.0",
     "react": "^19.2.0",
-    "react-dom": "^19.2.0",
-    "vite-tsconfig-paths": "^6.0.2"
+    "react-dom": "^19.2.0"
   },
   "devDependencies": {
+    "@cloudflare/vite-plugin": "^1.13.8",
     "@tanstack/devtools-vite": "workspace:*",
+    "@tanstack/router-plugin": "^1.132.0",
     "@types/node": "^22.15.2",
     "@types/react": "^19.2.0",
     "@types/react-dom": "^19.2.0",
     "@vitejs/plugin-react": "^5.0.4",
     "typescript": "~5.9.2",
     "vite": "^7.1.7",
+    "vite-tsconfig-paths": "^6.0.2",
     "wrangler": "^4.40.3"
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/react/start-cloudflare/package.json` around lines 12 - 20, The
package.json currently lists build-time Vite plugins as runtime dependencies;
remove "@cloudflare/vite-plugin", "@tanstack/router-plugin", and
"vite-tsconfig-paths" from the "dependencies" section and add them to
"devDependencies" with the same version strings so they are only installed for
build/dev. Ensure you update the package.json keys accordingly (keep other
packages untouched) and run your package manager to refresh lockfiles so the
change is reflected in installs.
examples/react/start-nitro/package.json (1)

16-16: Pin nitro to a specific version instead of using latest.

At Line 16, "nitro": "latest" is inconsistent with the rest of the dependencies and makes this example non-reproducible. The lockfile resolves to nitro@3.0.1-alpha.2; pin the dependency to this version or a specific stable release:

-    "nitro": "latest",
+    "nitro": "^3.0.1-alpha.2",
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/react/start-nitro/package.json` at line 16, The dependency entry
"nitro": "latest" in package.json makes the example non-reproducible; update the
"nitro" dependency (the "nitro" property in package.json) to a specific version
(e.g., "3.0.1-alpha.2" or a chosen stable release) so the example and lockfile
remain deterministic, then run npm/yarn install to refresh the lockfile.
examples/react/start-cloudflare/src/routes/index.tsx (1)

60-63: Consider adding error handling for server function calls.

The async button handlers call server functions without try/catch. If a server function fails (network error, worker crash), the promise rejection will be unhandled.

💡 Example error handling
         onClick={async () => {
+          try {
             const msg = await greet()
             addResult(msg)
+          } catch (e) {
+            addResult(`Error: ${e instanceof Error ? e.message : 'Unknown error'}`)
+          }
         }}

Also applies to: 78-81, 96-99

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

In `@examples/react/start-cloudflare/src/routes/index.tsx` around lines 60 - 63,
Wrap each async server-call handler (the onClick callbacks that call greet(),
and similar handlers at the other spots) in a try/catch: call the server
function inside try, await the result, and then call addResult(msg) on success;
in catch, log the error and surface a user-friendly message (e.g., via addResult
or an error state) so promise rejections from greet() (or other server
functions) are handled and do not stay unhandled. Ensure you update all three
handlers (the one invoking greet() and the other handlers at the 78-81 and 96-99
locations) and reference the existing functions greet() and addResult when
implementing the try/catch handling.
examples/react/start-cloudflare/src/devtools/ServerEventsPanel.tsx (1)

105-107: Consider a more unique key for event list items.

Using ${ev.timestamp}-${index} as the key could cause React reconciliation issues if events arrive with identical timestamps (possible with rapid emission). Since events are prepended, the index of existing items shifts on each new event, which combined with timestamp collisions could lead to incorrect DOM updates.

💡 Consider adding a unique identifier

If events gain an eventId field from the transport layer (as mentioned in the PR objectives), use that instead:

-            <div
-              key={`${ev.timestamp}-${index}`}
+            <div
+              key={ev.eventId ?? `${ev.timestamp}-${index}`}

Alternatively, generate a client-side ID when storing events.

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

In `@examples/react/start-cloudflare/src/devtools/ServerEventsPanel.tsx` around
lines 105 - 107, The list key for events in ServerEventsPanel (events.map ->
key={`${ev.timestamp}-${index}`}) is unstable; change it to use a stable unique
id: prefer using ev.eventId (if provided by the transport) or a client-generated
id assigned when the event is created/added (e.g., set ev.id or event.id inside
the event insertion logic). Update the mapping to use that stable id
(key={ev.eventId || ev.id}) so prepending new events won't shift keys and break
React reconciliation.
packages/event-bus/src/server/server.ts (1)

156-167: Extract the POST bridge routing into one helper.

Both server modes now duplicate the same source === 'server-bridge' branch. Pulling that into a shared helper will keep standalone and piggyback mode from drifting the next time the bridge protocol changes.

Also applies to: 274-288

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

In `@packages/event-bus/src/server/server.ts` around lines 156 - 167, Extract the
duplicated POST bridge routing into a single helper (e.g.
handleDevtoolsSendRequest) that performs the body collection, calls
parseWithBigInt, logs via this.debugLog('Received event from client', msg) and
then calls either this.emit(msg) or this.emitToServer(msg) based on msg.source
=== 'server-bridge'; replace the duplicated blocks currently handling req.url
=== '/__devtools/send' in both server modes (the block around the
parseWithBigInt/this.debugLog/this.emit/this.emitToServer sequence and the
similar block at the other location) with calls to this new helper so both modes
share the same logic.
packages/event-bus-client/src/plugin.ts (1)

581-595: Use plain comments for these private helpers.

@internal JSDoc on private methods will still flow into generated docs, which makes the website output noisy for implementation details. A normal // comment here is a better fit.

As per coding guidelines, **/*.{js,ts,jsx,tsx}: JSDoc should read like documentation as it gets converted to markdown docs for the website.

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

In `@packages/event-bus-client/src/plugin.ts` around lines 581 - 595, The JSDoc
`@internal` on private helper methods is leaking into generated docs; replace the
/** `@internal` */ JSDoc blocks on the private helpers (specifically
___enableNetworkTransport and ___destroyNetworkTransport) with plain single-line
comments (e.g., // internal — only for testing) so they are treated as
implementation comments rather than documentation and won’t be emitted into the
site output.
examples/react/start-nitro/src/devtools/ServerEventsPanel.tsx (1)

20-28: Consider hydration safety for time formatting.

toLocaleTimeString can produce different output on server vs client due to locale/timezone differences, potentially causing hydration mismatches. Since this is a devtools panel (client-only rendering context), this is likely fine, but worth noting.

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

In `@examples/react/start-nitro/src/devtools/ServerEventsPanel.tsx` around lines
20 - 28, formatTime currently uses toLocaleTimeString which can differ between
server and client and cause hydration mismatches; make the output deterministic
by specifying an explicit timeZone (e.g., add timeZone: 'UTC' to the options) or
move formatting to run only on the client (compute inside a useEffect or when
rendering client-only components) so timezone/locale differences won't cause
hydration errors — update the formatTime function to use Intl.DateTimeFormat or
toLocaleTimeString with a fixed timeZone option, or ensure calls to formatTime
occur only on the client side.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@examples/react/start-nitro/package.json`:
- Line 19: Move the "vite-tsconfig-paths" dependency from runtime dependencies
into devDependencies: remove the "vite-tsconfig-paths": "^6.0.2" entry under
dependencies in package.json and add the same entry under devDependencies (so
build-time only tools used by vite.config.ts are not bundled at runtime); ensure
package-lock/yarn lock is updated by reinstalling or running the package manager
after the change.

In `@packages/event-bus-client/src/plugin.ts`:
- Around line 50-54: The event ID generation (generateEventId using
globalEventIdCounter) is only unique per module instance and can collide across
workers; create a process-scoped random/unique prefix (e.g., instancePrefix
generated once at module init using crypto.randomBytes or a high-entropy
Math.random hex) and prepend it to the existing
`${++globalEventIdCounter}-${Date.now()}` scheme so generateEventId returns
`${instancePrefix}-${++globalEventIdCounter}-${Date.now()}`, ensuring
instance-scoped entropy and avoiding cross-worker collisions; ensure
instancePrefix is initialized once (top-level) and referenced in
generateEventId.
- Around line 475-483: The branch inside the this.#useNetworkTransport path
incorrectly queues events when the client has given up on WebSocket; update the
logic in the block that calls createEventPayload so that if this.#wsGaveUp is
true you bypass queuing and connectWebSocket(), and immediately call
sendViaNetwork (or sendViaHttp for non-network transport) instead; specifically,
in the code handling this.#useNetworkTransport, check this.#wsGaveUp before
pushing to this.#queuedEvents and short-circuit to sendViaNetwork/sendViaHttp,
leaving connectWebSocket() only for cases where a reconnect attempt should
actually be made.
- Around line 304-308: The bridge currently uses JSON.parse/JSON.stringify which
drops BigInt values; change the ws message handler in
ws.addEventListener('message') to call parseWithBigInt(data) instead of
JSON.parse(data), and update the bridge send methods (the functions around the
send calls at the locations corresponding to lines 408 and 428) to use
stringifyWithBigInt(payload) instead of JSON.stringify(payload). Ensure
parseWithBigInt and stringifyWithBigInt are imported from the event-bus
utilities and replace all plain JSON.parse/JSON.stringify usages in those
handlers/sendters to maintain BigInt-safe wire format compatibility.

In `@packages/event-bus-client/src/ring-buffer.ts`:
- Around line 7-11: The RingBuffer constructor must validate the incoming
capacity and fail fast for non-positive or non-integer values: in the
constructor (class RingBuffer) add a guard that checks capacity is a positive
integer (capacity > 0 && Number.isInteger(capacity)) and throw a clear
RangeError or TypeError if not, so fields like `#capacity`, `#buffer` and `#index`
remain valid and add() cannot enter a broken state; update the constructor that
currently sets this.#capacity, this.#buffer and this.#set to perform this
validation before initializing those fields.

---

Nitpick comments:
In `@examples/react/start-cloudflare/.gitignore`:
- Around line 6-11: Update the .gitignore entry that currently lists ".env" to
also ignore environment file variants and common Cloudflare local secret files:
add patterns like ".env.*", "*.env.local", ".dev.vars" and ".dev.vars.*" (or
other local secret naming used in this project) so accidental commits of
local/dev secrets are prevented; ensure these patterns are added alongside
existing entries (".env", ".nitro", ".tanstack", ".wrangler", ".output",
".vinxi") in the examples/react/start-cloudflare/.gitignore file.

In `@examples/react/start-cloudflare/package.json`:
- Around line 12-20: The package.json currently lists build-time Vite plugins as
runtime dependencies; remove "@cloudflare/vite-plugin",
"@tanstack/router-plugin", and "vite-tsconfig-paths" from the "dependencies"
section and add them to "devDependencies" with the same version strings so they
are only installed for build/dev. Ensure you update the package.json keys
accordingly (keep other packages untouched) and run your package manager to
refresh lockfiles so the change is reflected in installs.

In `@examples/react/start-cloudflare/src/devtools/ServerEventsPanel.tsx`:
- Around line 105-107: The list key for events in ServerEventsPanel (events.map
-> key={`${ev.timestamp}-${index}`}) is unstable; change it to use a stable
unique id: prefer using ev.eventId (if provided by the transport) or a
client-generated id assigned when the event is created/added (e.g., set ev.id or
event.id inside the event insertion logic). Update the mapping to use that
stable id (key={ev.eventId || ev.id}) so prepending new events won't shift keys
and break React reconciliation.

In `@examples/react/start-cloudflare/src/routes/index.tsx`:
- Around line 60-63: Wrap each async server-call handler (the onClick callbacks
that call greet(), and similar handlers at the other spots) in a try/catch: call
the server function inside try, await the result, and then call addResult(msg)
on success; in catch, log the error and surface a user-friendly message (e.g.,
via addResult or an error state) so promise rejections from greet() (or other
server functions) are handled and do not stay unhandled. Ensure you update all
three handlers (the one invoking greet() and the other handlers at the 78-81 and
96-99 locations) and reference the existing functions greet() and addResult when
implementing the try/catch handling.

In `@examples/react/start-nitro/package.json`:
- Line 16: The dependency entry "nitro": "latest" in package.json makes the
example non-reproducible; update the "nitro" dependency (the "nitro" property in
package.json) to a specific version (e.g., "3.0.1-alpha.2" or a chosen stable
release) so the example and lockfile remain deterministic, then run npm/yarn
install to refresh the lockfile.

In `@examples/react/start-nitro/src/devtools/ServerEventsPanel.tsx`:
- Around line 20-28: formatTime currently uses toLocaleTimeString which can
differ between server and client and cause hydration mismatches; make the output
deterministic by specifying an explicit timeZone (e.g., add timeZone: 'UTC' to
the options) or move formatting to run only on the client (compute inside a
useEffect or when rendering client-only components) so timezone/locale
differences won't cause hydration errors — update the formatTime function to use
Intl.DateTimeFormat or toLocaleTimeString with a fixed timeZone option, or
ensure calls to formatTime occur only on the client side.

In `@packages/event-bus-client/src/plugin.ts`:
- Around line 581-595: The JSDoc `@internal` on private helper methods is leaking
into generated docs; replace the /** `@internal` */ JSDoc blocks on the private
helpers (specifically ___enableNetworkTransport and ___destroyNetworkTransport)
with plain single-line comments (e.g., // internal — only for testing) so they
are treated as implementation comments rather than documentation and won’t be
emitted into the site output.

In `@packages/event-bus/src/server/server.ts`:
- Around line 156-167: Extract the duplicated POST bridge routing into a single
helper (e.g. handleDevtoolsSendRequest) that performs the body collection, calls
parseWithBigInt, logs via this.debugLog('Received event from client', msg) and
then calls either this.emit(msg) or this.emitToServer(msg) based on msg.source
=== 'server-bridge'; replace the duplicated blocks currently handling req.url
=== '/__devtools/send' in both server modes (the block around the
parseWithBigInt/this.debugLog/this.emit/this.emitToServer sequence and the
similar block at the other location) with calls to this new helper so both modes
share the same logic.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 23c57afd-2ae3-40ad-89fd-677242f015bd

📥 Commits

Reviewing files that changed from the base of the PR and between 1fc0afa and 3f82eeb.

📒 Files selected for processing (32)
  • docs/superpowers/plans/2026-03-12-network-transport-fallback.md
  • docs/superpowers/specs/2026-03-12-network-transport-fallback-design.md
  • examples/react/start-cloudflare/.gitignore
  • examples/react/start-cloudflare/package.json
  • examples/react/start-cloudflare/src/devtools/ServerEventsPanel.tsx
  • examples/react/start-cloudflare/src/devtools/index.ts
  • examples/react/start-cloudflare/src/devtools/server-event-client.ts
  • examples/react/start-cloudflare/src/router.tsx
  • examples/react/start-cloudflare/src/routes/__root.tsx
  • examples/react/start-cloudflare/src/routes/index.tsx
  • examples/react/start-cloudflare/tsconfig.json
  • examples/react/start-cloudflare/vite.config.ts
  • examples/react/start-cloudflare/wrangler.jsonc
  • examples/react/start-nitro/.gitignore
  • examples/react/start-nitro/package.json
  • examples/react/start-nitro/src/devtools/ServerEventsPanel.tsx
  • examples/react/start-nitro/src/devtools/index.ts
  • examples/react/start-nitro/src/devtools/server-event-client.ts
  • examples/react/start-nitro/src/router.tsx
  • examples/react/start-nitro/src/routes/__root.tsx
  • examples/react/start-nitro/src/routes/index.tsx
  • examples/react/start-nitro/tsconfig.json
  • examples/react/start-nitro/vite.config.ts
  • packages/event-bus-client/src/index.ts
  • packages/event-bus-client/src/plugin.ts
  • packages/event-bus-client/src/ring-buffer.ts
  • packages/event-bus-client/tests/integration.test.ts
  • packages/event-bus-client/tests/network-transport.test.ts
  • packages/event-bus-client/tests/ring-buffer.test.ts
  • packages/event-bus/src/client/client.ts
  • packages/event-bus/src/server/server.ts
  • packages/event-bus/tests/server.test.ts

"nitro": "latest",
"react": "^19.2.0",
"react-dom": "^19.2.0",
"vite-tsconfig-paths": "^6.0.2"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Search for vite-tsconfig-paths usage:"
rg -n 'vite-tsconfig-paths|tsconfigPaths\s*\(' --glob '**/*.{ts,tsx,js,jsx,mjs,cjs,mts,cts}'

Repository: TanStack/devtools

Length of output: 484


🏁 Script executed:

cat examples/react/start-nitro/package.json

Repository: TanStack/devtools

Length of output: 860


Move vite-tsconfig-paths to devDependencies.

This package is imported only in vite.config.ts (build-time configuration). It should not be in dependencies since it's not used at runtime.

Proposed change
   "dependencies": {
     "@tanstack/devtools-event-client": "workspace:*",
     "@tanstack/react-devtools": "workspace:*",
     "@tanstack/react-router": "^1.132.0",
     "@tanstack/react-start": "^1.132.0",
     "@tanstack/router-plugin": "^1.132.0",
     "nitro": "latest",
     "react": "^19.2.0",
     "react-dom": "^19.2.0",
-    "vite-tsconfig-paths": "^6.0.2"
   },
   "devDependencies": {
     "@tanstack/devtools-vite": "workspace:*",
     "@types/node": "^22.15.2",
     "@types/react": "^19.2.0",
     "@types/react-dom": "^19.2.0",
     "@vitejs/plugin-react": "^5.0.4",
+    "vite-tsconfig-paths": "^6.0.2",
     "typescript": "~5.9.2",
     "vite": "^7.1.7"
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"vite-tsconfig-paths": "^6.0.2"
"dependencies": {
"@tanstack/devtools-event-client": "workspace:*",
"@tanstack/react-devtools": "workspace:*",
"@tanstack/react-router": "^1.132.0",
"@tanstack/react-start": "^1.132.0",
"@tanstack/router-plugin": "^1.132.0",
"nitro": "latest",
"react": "^19.2.0",
"react-dom": "^19.2.0"
},
"devDependencies": {
"@tanstack/devtools-vite": "workspace:*",
"@types/node": "^22.15.2",
"@types/react": "^19.2.0",
"@types/react-dom": "^19.2.0",
"@vitejs/plugin-react": "^5.0.4",
"vite-tsconfig-paths": "^6.0.2",
"typescript": "~5.9.2",
"vite": "^7.1.7"
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/react/start-nitro/package.json` at line 19, Move the
"vite-tsconfig-paths" dependency from runtime dependencies into devDependencies:
remove the "vite-tsconfig-paths": "^6.0.2" entry under dependencies in
package.json and add the same entry under devDependencies (so build-time only
tools used by vite.config.ts are not bundled at runtime); ensure
package-lock/yarn lock is updated by reinstalling or running the package manager
after the change.

Comment thread packages/event-bus-client/src/plugin.ts Outdated
Comment thread packages/event-bus-client/src/plugin.ts Outdated
Comment thread packages/event-bus-client/src/plugin.ts Outdated
Comment on lines +7 to +11
constructor(capacity: number) {
this.#capacity = capacity
this.#buffer = new Array(capacity).fill('')
this.#set = new Set()
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Reject invalid capacities in the constructor.

capacity <= 0 leaves add() in a broken state (#index becomes NaN) and negative values surface a generic Array() error. Since RingBuffer is exported, fail fast with a clear positive-integer check.

🛡️ Proposed guard
  constructor(capacity: number) {
+   if (!Number.isInteger(capacity) || capacity <= 0) {
+     throw new RangeError('RingBuffer capacity must be a positive integer')
+   }
    this.#capacity = capacity
    this.#buffer = new Array(capacity).fill('')
    this.#set = new Set()
  }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
constructor(capacity: number) {
this.#capacity = capacity
this.#buffer = new Array(capacity).fill('')
this.#set = new Set()
}
constructor(capacity: number) {
if (!Number.isInteger(capacity) || capacity <= 0) {
throw new RangeError('RingBuffer capacity must be a positive integer')
}
this.#capacity = capacity
this.#buffer = new Array(capacity).fill('')
this.#set = new Set()
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/event-bus-client/src/ring-buffer.ts` around lines 7 - 11, The
RingBuffer constructor must validate the incoming capacity and fail fast for
non-positive or non-integer values: in the constructor (class RingBuffer) add a
guard that checks capacity is a positive integer (capacity > 0 &&
Number.isInteger(capacity)) and throw a clear RangeError or TypeError if not, so
fields like `#capacity`, `#buffer` and `#index` remain valid and add() cannot enter a
broken state; update the constructor that currently sets this.#capacity,
this.#buffer and this.#set to perform this validation before initializing those
fields.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
examples/react/start-nitro/src/routes/__root.tsx (1)

24-37: Gate devtools mounting to development mode.

connectToServerBus: true triggers network connection attempts when mounted; wrapping this in a dev-only guard avoids unnecessary production runtime overhead in this example.

Suggested change
-        <TanStackDevtools
-        eventBusConfig={{
-          connectToServerBus: true
-        }}
-          config={{ position: 'bottom-right' }}
-          plugins={[
-            {
-              id: 'server-events',
-              name: 'Server Events',
-              render: <ServerEventsPanel />,
-            },
-          ]}
-        />
+        {import.meta.env.DEV ? (
+          <TanStackDevtools
+            eventBusConfig={{
+              connectToServerBus: true,
+            }}
+            config={{ position: 'bottom-right' }}
+            plugins={[
+              {
+                id: 'server-events',
+                name: 'Server Events',
+                render: <ServerEventsPanel />,
+              },
+            ]}
+          />
+        ) : null}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/react/start-nitro/src/routes/__root.tsx` around lines 24 - 37, The
TanStackDevtools block mounts a network-connected event bus because
eventBusConfig.connectToServerBus is true; guard its mounting to development
only by conditionally rendering TanStackDevtools (or setting connectToServerBus:
false in production) — wrap the TanStackDevtools usage that includes
eventBusConfig and the ServerEventsPanel plugin in a dev-only check (e.g.,
process.env.NODE_ENV === 'development' or import.meta.env.DEV) so that
ServerEventsPanel and connectToServerBus are not active in production.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@examples/react/start-nitro/src/routes/__root.tsx`:
- Around line 24-37: The TanStackDevtools block mounts a network-connected event
bus because eventBusConfig.connectToServerBus is true; guard its mounting to
development only by conditionally rendering TanStackDevtools (or setting
connectToServerBus: false in production) — wrap the TanStackDevtools usage that
includes eventBusConfig and the ServerEventsPanel plugin in a dev-only check
(e.g., process.env.NODE_ENV === 'development' or import.meta.env.DEV) so that
ServerEventsPanel and connectToServerBus are not active in production.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9b89ae07-b4c2-4ac3-b75f-0273477dc2f3

📥 Commits

Reviewing files that changed from the base of the PR and between 3f82eeb and 939ac70.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (4)
  • .gitignore
  • examples/react/start-cloudflare/src/routes/__root.tsx
  • examples/react/start-nitro/src/routes/__root.tsx
  • package.json
✅ Files skipped from review due to trivial changes (2)
  • .gitignore
  • package.json
🚧 Files skipped from review as they are similar to previous changes (1)
  • examples/react/start-cloudflare/src/routes/__root.tsx

@socket-security

socket-security Bot commented Jun 19, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addednitro@​3.0.260610-beta981008292100

View full report

@socket-security

socket-security Bot commented Jun 19, 2026

Copy link
Copy Markdown

Warning

Review the following alerts detected in dependencies.

According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.

Action Severity Alert  (click "▶" to expand/collapse)
Warn High
Obfuscated code: npm env-runner is 90.0% likely obfuscated

Confidence: 0.90

Location: Package overview

From: pnpm-lock.yamlnpm/nitro@3.0.260610-betanpm/env-runner@0.1.14

ℹ Read more on: This package | This alert | What is obfuscated code?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Packages should not obfuscate their code. Consider not using packages with obfuscated code.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/env-runner@0.1.14. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

View full report

@AlemTuzlak AlemTuzlak changed the title feat: network transport fallback for isolated server runtimes feat: deliver devtools events from isolated server runtimes via Vite HotChannel Jun 19, 2026
@pkg-pr-new

pkg-pr-new Bot commented Jun 19, 2026

Copy link
Copy Markdown
More templates

@tanstack/angular-devtools

npm i https://pkg.pr.new/@tanstack/angular-devtools@384

@tanstack/devtools

npm i https://pkg.pr.new/@tanstack/devtools@384

@tanstack/devtools-a11y

npm i https://pkg.pr.new/@tanstack/devtools-a11y@384

@tanstack/devtools-client

npm i https://pkg.pr.new/@tanstack/devtools-client@384

@tanstack/devtools-ui

npm i https://pkg.pr.new/@tanstack/devtools-ui@384

@tanstack/devtools-utils

npm i https://pkg.pr.new/@tanstack/devtools-utils@384

@tanstack/devtools-vite

npm i https://pkg.pr.new/@tanstack/devtools-vite@384

@tanstack/devtools-event-bus

npm i https://pkg.pr.new/@tanstack/devtools-event-bus@384

@tanstack/devtools-event-client

npm i https://pkg.pr.new/@tanstack/devtools-event-client@384

@tanstack/preact-devtools

npm i https://pkg.pr.new/@tanstack/preact-devtools@384

@tanstack/react-devtools

npm i https://pkg.pr.new/@tanstack/react-devtools@384

@tanstack/solid-devtools

npm i https://pkg.pr.new/@tanstack/solid-devtools@384

@tanstack/vue-devtools

npm i https://pkg.pr.new/@tanstack/vue-devtools@384

commit: eb46dc4

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/devtools-vite/src/plugin.ts`:
- Around line 240-243: The originalConsole object created at line 240 only
includes console methods from consolePipingLevels, but the fallback logic at
line 272 assumes originalConsole.log always exists. If users configure
consolePipingLevels without including 'log', the fallback will fail when
entry.level is unknown or malformed. Ensure that console.log is always available
as a fallback by adding it to originalConsole even if it is not in
consolePipingLevels, either by appending it to the map entries after
construction or by guaranteeing it is included in the initial mapping.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1d73483d-b5c2-4172-aed6-823fbd9a7479

📥 Commits

Reviewing files that changed from the base of the PR and between 939ac70 and 8c973f6.

📒 Files selected for processing (10)
  • .changeset/devtools-vite-runtime-bridge.md
  • examples/react/start-cloudflare/src/routes/__root.tsx
  • examples/react/start-cloudflare/src/routes/index.tsx
  • examples/react/start-cloudflare/wrangler.jsonc
  • examples/react/start-nitro/src/routes/__root.tsx
  • examples/react/start-nitro/src/routes/index.tsx
  • packages/devtools-vite/src/plugin.ts
  • packages/devtools-vite/src/runtime-bridge.test.ts
  • packages/devtools-vite/src/runtime-bridge.ts
  • packages/devtools-vite/tests/index.test.ts
✅ Files skipped from review due to trivial changes (2)
  • .changeset/devtools-vite-runtime-bridge.md
  • examples/react/start-cloudflare/wrangler.jsonc
🚧 Files skipped from review as they are similar to previous changes (4)
  • examples/react/start-nitro/src/routes/__root.tsx
  • examples/react/start-cloudflare/src/routes/__root.tsx
  • examples/react/start-cloudflare/src/routes/index.tsx
  • examples/react/start-nitro/src/routes/index.tsx

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/devtools-vite/src/plugin.ts`:
- Around line 240-243: The originalConsole object created at line 240 only
includes console methods from consolePipingLevels, but the fallback logic at
line 272 assumes originalConsole.log always exists. If users configure
consolePipingLevels without including 'log', the fallback will fail when
entry.level is unknown or malformed. Ensure that console.log is always available
as a fallback by adding it to originalConsole even if it is not in
consolePipingLevels, either by appending it to the map entries after
construction or by guaranteeing it is included in the initial mapping.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1d73483d-b5c2-4172-aed6-823fbd9a7479

📥 Commits

Reviewing files that changed from the base of the PR and between 939ac70 and 8c973f6.

📒 Files selected for processing (10)
  • .changeset/devtools-vite-runtime-bridge.md
  • examples/react/start-cloudflare/src/routes/__root.tsx
  • examples/react/start-cloudflare/src/routes/index.tsx
  • examples/react/start-cloudflare/wrangler.jsonc
  • examples/react/start-nitro/src/routes/__root.tsx
  • examples/react/start-nitro/src/routes/index.tsx
  • packages/devtools-vite/src/plugin.ts
  • packages/devtools-vite/src/runtime-bridge.test.ts
  • packages/devtools-vite/src/runtime-bridge.ts
  • packages/devtools-vite/tests/index.test.ts
✅ Files skipped from review due to trivial changes (2)
  • .changeset/devtools-vite-runtime-bridge.md
  • examples/react/start-cloudflare/wrangler.jsonc
🚧 Files skipped from review as they are similar to previous changes (4)
  • examples/react/start-nitro/src/routes/__root.tsx
  • examples/react/start-cloudflare/src/routes/__root.tsx
  • examples/react/start-cloudflare/src/routes/index.tsx
  • examples/react/start-nitro/src/routes/index.tsx
🛑 Comments failed to post (1)
packages/devtools-vite/src/plugin.ts (1)

240-243: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Ensure fallback logging is always callable when custom levels omit log.

At Line 240, originalConsole is built only from consolePipingLevels; at Line 272, fallback assumes originalConsole.log always exists. If users configure levels without 'log', unknown/malformed entry.level can make logMethod undefined and throw at Line 278.

Suggested fix
-        const originalConsole = Object.fromEntries(
-          consolePipingLevels.map((l) => [l, console[l].bind(console)]),
-        ) as Partial<Record<ConsoleLevel, typeof console.log>>
+        const originalConsole = {
+          log: console.log.bind(console),
+          ...Object.fromEntries(
+            consolePipingLevels
+              .map((l) => [l, console[l]] as const)
+              .filter(([, fn]) => typeof fn === 'function')
+              .map(([l, fn]) => [l, fn.bind(console)]),
+          ),
+        } as Partial<Record<ConsoleLevel, typeof console.log>> & {
+          log: typeof console.log
+        }

Also applies to: 269-273

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/devtools-vite/src/plugin.ts` around lines 240 - 243, The
originalConsole object created at line 240 only includes console methods from
consolePipingLevels, but the fallback logic at line 272 assumes
originalConsole.log always exists. If users configure consolePipingLevels
without including 'log', the fallback will fail when entry.level is unknown or
malformed. Ensure that console.log is always available as a fallback by adding
it to originalConsole even if it is not in consolePipingLevels, either by
appending it to the map entries after construction or by guaranteeing it is
included in the initial mapping.

@AlemTuzlak AlemTuzlak merged commit 958c683 into main Jun 19, 2026
10 checks passed
@AlemTuzlak AlemTuzlak deleted the worktree-polished-cuddling-lark branch June 19, 2026 17:47
@github-actions github-actions Bot mentioned this pull request Jun 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: AI Devtools ignores client-sourced assistant messages and streaming chunks

1 participant