Skip to content

Add newWorkersWebSocketRpcSession for bidirectional server-side WebSockets + typescript fixes#8

Merged
jmorrell merged 5 commits intomainfrom
simplify-bidirectional-websocket-example
Feb 17, 2026
Merged

Add newWorkersWebSocketRpcSession for bidirectional server-side WebSockets + typescript fixes#8
jmorrell merged 5 commits intomainfrom
simplify-bidirectional-websocket-example

Conversation

@jmorrell
Copy link
Owner

  • Add newWorkersWebSocketRpcSession — new export for bidirectional WebSocket RPC in Workers. Returns { response, remote } so server-side code can call back to the client with a typed proxy. newWorkersWebSocketRpcResponse is now a thin wrapper that discards the remote.

  • Unify tsconfig — single tsconfig.json covers both library and test files so the editor/language server picks up Cloudflare Workers types. Add npm run typecheck script.

  • Eliminate as any from production code — replace with Record<string, unknown> casts in type guards. Reduce test as any from 20 to 5 justified instances.

    Before/after: bidirectional worker fixture

  // Before (20 lines, manual plumbing, untyped)
  if (request.headers.get("Upgrade") !== "websocket") {
    return new Response("Expected WebSocket upgrade", { status: 400 });
  }
  const pair = new WebSocketPair();
  const [client, server] = Object.values(pair);
  server.accept();
  const transport = createWebSocketTransport(server);
  const biService = {
    async addWithClientMultiplier(a: number, b: number): Promise<number> {
      const multiplier: number = await (session.remote as any).getMultiplier();
      return (a + b) * multiplier;
    },
  };
  const session = new RpcSession(transport, biService, { role: "acceptor" });
  return new Response(null, { status: 101, webSocket: client });

  // After (8 lines, fully typed)
  const biService = {
    async addWithClientMultiplier(a: number, b: number): Promise<number> {
      const multiplier = await remote.getMultiplier();
      return (a + b) * multiplier;
    },
  };
  const { response, remote } = newWorkersWebSocketRpcSession<ClientService>(request, biService);
  return response;

jmorrell and others added 5 commits February 16, 2026 15:46
…cket RPC

newWorkersWebSocketRpcResponse is fire-and-forget — it returns a Response but
no handle to the client. For bidirectional use (server calling back to client),
newWorkersWebSocketRpcSession returns { response, remote } where remote is a
typed proxy. On non-upgrade requests it returns a 400 Response with a dead
proxy (dispose/close are no-ops, any other access throws).

newWorkersWebSocketRpcResponse is now a thin wrapper that discards the remote.
Both it and newWebSocketRpcSession share an extracted createRemoteProxy helper,
removing the duplicated Proxy construction.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Unify into a single tsconfig.json that covers both library and test
files, so the editor/language server picks up Cloudflare Workers types
(cloudflare:test) and test type errors are caught by the build.

Add npm run typecheck (tsc --noEmit) for quick type checking without emit.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- worker.ts: add explicit TLocal type param to newWorkersWebSocketRpcSession
- session.test.ts: use double assertion for null-to-RpcProtocolError cast
- spec.test.ts: assert response.json() as any for property access
- workers.workers.test.ts: fix RpcError constructor args (needs code),
  use string RpcProtocolErrorCode, assert response.json() as any

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Production code (core.ts):
- Replace as-any with Record<string, unknown> casts in isJsonRpcResponse
  type guard and extractError helper

Test code:
- Use Object.assign for adding code/data to Error objects
- Use JsonRpcResponse[] instead of any[] for processRpc array results
- Use proper narrowing (!Array.isArray) instead of as-any in property tests
- Use Record<string, unknown> in property test type guard
- Add justification comments to remaining 5 as-any usages:
  3x Response.json() returns unknown, 1x deliberate type violation,
  1x bypassing typed proxy to test dead proxy behavior

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@jmorrell jmorrell merged commit 7b0602e into main Feb 17, 2026
1 check passed
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.

1 participant