Portable core and Workers

For a Worker, import RPCPeer from @wsrpc/client/core and connect it to the host’s WebSocket API. Use @wsrpc/server for Node.js applications instead. Deno, Bun and native browser transports can use the same core interface.

Cloudflare Worker

This example accepts a WebSocketPair and feeds messages to the core. The host owns WebSocket upgrades, payload limits and authorization.

import { RPCPeer } from "@wsrpc/client/core";

export default {
  fetch(request: Request): Response {
    if (new URL(request.url).pathname !== "/ws/")
      return new Response("Not found", { status: 404 });
    if (request.headers.get("Upgrade")?.toLowerCase() !== "websocket")
      return new Response("Expected WebSocket", { status: 426 });
    const pair = new WebSocketPair();
    const client = pair[0],
      server = pair[1];
    server.binaryType = "arraybuffer";
    server.accept();
    const peer = new RPCPeer({
      send(data) {
        server.send(data);
      },
      close(code, reason) {
        server.close(code, reason);
      },
    });
    peer.addRoute("echo", (_socket, params: unknown) => params);
    peer.addRoute("callback", (socket, params: { value: number }) =>
      socket.call("double", params),
    );
    server.addEventListener("message", (event) => {
      const binary = typeof event.data !== "string";
      const data =
        typeof event.data === "string"
          ? event.data
          : new Uint8Array(event.data);
      void peer
        .receive(data, binary)
        .catch(() => peer.close(1011, "RPC dispatch failed"));
    });
    server.addEventListener("close", () => {
      void peer.close();
    });
    server.addEventListener("error", () => {
      void peer.close(1011, "WebSocket error");
    });
    return new Response(null, { status: 101, webSocket: client });
  },
};

No nodejs_compat flag is required. server.binaryType = "arraybuffer" selects synchronous byte access for binary messages. See Cloudflare’s WebSocket API for lifecycle and host settings.

Use the explicit socket argument or connection-bound Route classes. Implicit async-local context requires a host-provided context storage; the Node adapter installs that automatically.

Deno/Bun consumers supply a native Transport using the same send, close and receive interface; there is no separate adapter package for those hosts.