Skip to content

fix(client): coerce ws scheme on forwarded upgrade target (fixes #1)#2

Merged
tlgimenes merged 1 commit into
mainfrom
deco/deep-orbit
May 22, 2026
Merged

fix(client): coerce ws scheme on forwarded upgrade target (fixes #1)#2
tlgimenes merged 1 commit into
mainfrom
deco/deep-orbit

Conversation

@tlgimenes

Copy link
Copy Markdown
Contributor

Summary

Fixes #1 — WebSocket upstream URL not coerced to ws://, HMR fails under Bun.

handleWebSocket in handlers.client.ts was passing an http(s):-scheme URL straight to new WebSocket(...). Node's built-in WebSocket (undici) silently rewrites the scheme to ws:, so it worked there — but Bun keeps the http: scheme and the handshake fails immediately, killing every WebSocket forwarded through the tunnel.

In practice this broke any dev-server feature that rides a WebSocket (Vite HMR, Next.js webpack-hmr / Turbopack HMR) when the warp client ran under Bun — including bunx decocms link.

Change

In handlers.client.ts, coerce the URL's protocol from http(s):ws(s): before constructing the WebSocket:

const target = new URL(message.url, state.localAddr);
target.protocol = target.protocol === "https:" ? "wss:" : "ws:";
const ws = new WebSocket(target);

Behavior under Node is unchanged (undici was already doing this conversion); Bun and any spec-strict runtime now work correctly.

Also includes a package-lock.json sync to match package.json (version + Node engines bump that was already in the lockfile-adjacent state).

Files

  • handlers.client.ts — scheme coercion + explanatory comment
  • package-lock.json — version/engines sync

Test plan

  • npm run typecheck — clean
  • npm test — 14/14 passing (vitest)
  • Manual: run bunx decocms link against a Next.js / Vite dev server and confirm HMR WebSockets connect through the tunnel (previously failed before handshake under Bun)
  • Confirm no regression under Node 22+ (undici path was already doing this conversion implicitly)

🤖 Generated with Claude Code

`new URL(message.url, state.localAddr)` yields an `http(s):` URL; Node's
undici silently rewrites the scheme but Bun's spec-strict WebSocket
rejects it, breaking every forwarded WebSocket (Vite/Next HMR) under
Bun. Coerce to `ws(s):` before constructing the WebSocket.

Also sync package-lock.json to match package.json (version + engines).

Fixes #1

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@tlgimenes
tlgimenes merged commit c726401 into main May 22, 2026
1 check passed
tlgimenes added a commit that referenced this pull request May 22, 2026
`new URL(message.url, state.localAddr)` yields an `http(s):` URL; Node's
undici silently rewrites the scheme but Bun's spec-strict WebSocket
rejects it, breaking every forwarded WebSocket (Vite/Next HMR) under
Bun. Coerce to `ws(s):` before constructing the WebSocket.

Also sync package-lock.json to match package.json (version + engines).

Fixes #1

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
tlgimenes added a commit to decocms/studio that referenced this pull request May 22, 2026
0.3.20 passes an `http:`-scheme URL to `new WebSocket(...)` when
forwarding upgrades in `handlers.client.ts`. Node's undici silently
rewrites it to `ws:`, but Bun keeps the scheme and the handshake
fails immediately — so every WebSocket through the link tunnel
(Vite HMR, Next.js webpack-hmr/Turbopack HMR) dies before connecting
when the link daemon runs under Bun, which it always does via
`bunx decocms link`.

Upstream fix: deco-cx/warp-node#2, released in 0.3.22/0.3.23.
Issue: deco-cx/warp-node#1.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

WebSocket upstream URL not coerced to ws:// — HMR fails under Bun

1 participant