Skip to content

feat: network transport fallback for isolated server runtimes#384

Open
AlemTuzlak wants to merge 15 commits intomainfrom
worktree-polished-cuddling-lark
Open

feat: network transport fallback for isolated server runtimes#384
AlemTuzlak wants to merge 15 commits intomainfrom
worktree-polished-cuddling-lark

Conversation

@AlemTuzlak
Copy link
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

…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
Copy link

changeset-bot bot commented Mar 12, 2026

⚠️ No Changeset found

Latest commit: ac41406

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
Copy link

nx-cloud bot commented Mar 12, 2026

🤖 Nx Cloud AI Fix Eligible

An automatically generated fix could have helped fix failing tasks for this run, but Self-healing CI is disabled for this workspace. Visit workspace settings to enable it and get automatic fixes in future runs.

To disable these notifications, a workspace admin can disable them in workspace settings.


View your CI Pipeline Execution ↗ for commit 64ae1bb

Command Status Duration Result
nx affected --targets=test:eslint,test:sherif,t... ❌ Failed 2m 17s View ↗
nx run-many --targets=build --exclude=examples/** ✅ Succeeded 22s View ↗

☁️ Nx Cloud last updated this comment at 2026-03-12 14:38:15 UTC

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.
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