feat: add TURN-TCP support with server-driven config#112
Merged
nagar-decart merged 7 commits intomainfrom Apr 7, 2026
Merged
Conversation
Add TURN-over-TCP ICE server alongside existing STUN for networks where UDP is blocked. ICE naturally prefers direct UDP and falls back to TURN-TCP relay via coturn. Includes Playwright E2E tests verifying both relay-only and dual-mode paths against local k8s slim-bit-invert. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Handle `turn_config` WebSocket message from server to receive TURN servers dynamically (for production server-side control) - Add `iceServers` option to connect() for manual/internal testing - Remove hardcoded TURN from ICE_SERVERS (now server-driven or explicit) - Skip relay-only E2E test until server-side aioice TURN allocation is verified Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When the server sends turn_config after the PeerConnection is already created (race: bouncer acks Phase 2 locally before upstream pump delivers turn_config), update the PC's ICE servers via setConfiguration() and trigger an ICE restart so TURN candidates are gathered. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When turn_config triggers an ICE restart, the answer to the original offer may arrive after the new offer resets signaling state to stable. Guard setRemoteDescription(answer) with a signalingState check to drop stale answers. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace ICE restart approach with a Phase 2.5 wait: after Phase 2 completes, wait up to 2s for turn_config to arrive before creating the PeerConnection. This ensures TURN servers are included from the start — one offer, one answer, no re-negotiation. Also reverts the stale answer guard (no longer needed without ICE restart). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 9348290. Configure here.
Forwards ice_transport_policy query param to the server, which filters
TURN URLs by transport (tcp/udp/all) and configures server-side ICE
accordingly.
Usage: client.realtime.connect(stream, { model, iceTransportPolicy: "tcp" })
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Only wait for turn_config in Phase 2.5 when iceTransportPolicy is set (server expected to send TURN config). Connections without TURN have zero added latency. - Clean up turnConfig event handler after Promise.race resolves, preventing leaked handlers on reconnection cycles. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
nagar-decart
added a commit
that referenced
this pull request
Apr 7, 2026
This reverts commit 39b9f09.
nagar-decart
added a commit
that referenced
this pull request
Apr 7, 2026
…115) Reverts #112. Merged by mistake — the SDK PR needs to land together with the API PR (DecartAI/api#971). <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Changes the realtime/WebRTC connection setup by removing TURN server configuration and related signaling handling, which can affect connectivity in restricted NAT/firewall environments. Also deletes associated E2E coverage, increasing the chance of regressions going unnoticed. > > **Overview** > Reverts the previously added TURN-TCP support in the realtime SDK by removing `iceServers`/`iceTransportPolicy` connect options and dropping the `turn_config` signaling message path. > > WebRTC peer connections now always use a fixed STUN-only `iceServers` list, and the websocket URL no longer includes the `ice_transport_policy` query param. The TURN-TCP E2E test/config and the `test:e2e:turn-tcp` script are removed. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 5f31ec2. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Summary
turn_configvia WebSocket signaling, giving full server-side control over TURN rollouticeServersoption toconnect()for manual/internal testing without server-side changesChanges
webrtc-connection.ts: Handleturn_configmessage, merge server-driven + explicit ICE servers into PC configwebrtc-manager.ts/client.ts: ThreadiceServersoption from connect API to connection layertypes.ts: AddTurnConfigMessagetypee2e-turn-tcp.test.ts: E2E tests for relay-only and dual-mode paths (relay test skipped pending server-side aioice fix)vitest.config.e2e-turn-tcp.ts: Vitest config for TURN-TCP testsTest plan
pnpm typecheckcleanpnpm buildsucceedspnpm test— 141 unit tests passpnpm test:e2e:turn-tcp— dual-mode test passes against local k8s🤖 Generated with Claude Code
Note
Medium Risk
Changes WebRTC connection setup by introducing server-provided TURN configuration and new ICE options, which can affect connectivity and handshake timing across environments. Added tests reduce risk but the new signaling path and timing waits could introduce regressions in connection establishment.
Overview
Adds TURN/TURN-TCP support to realtime connections by letting
connect()accept optionaliceServersand aniceTransportPolicyhint (forwarded as a query param) and by consuming a new WebSocketturn_configsignaling message.Updates the WebRTC connection flow to merge default/manual ICE servers with server-provided TURN servers, optionally wait briefly for TURN config before creating the peer connection, and reset TURN state on cleanup.
Introduces Playwright-based E2E coverage for TURN scenarios via a new
test:e2e:turn-tcpVitest config/script, and excludes the new E2E test from the default unit test run.Reviewed by Cursor Bugbot for commit 9bebe2d. Bugbot is set up for automated code reviews on this repo. Configure here.