Adapters

crossws allows integrating your WebSocket hooks with different runtimes and platforms using built-in adapters. Each runtime has a specific method of integrating WebSocket. Once integrated, will work consistently even if you change the runtime.

See Adapters section to learn more about all available built-in adapters.

Shared options

Every adapter accepts these options in addition to its runtime-specific ones.

idleTimeout

Close a connection that has stayed idle — no incoming messages and no pong replies — for roughly this many seconds. This reclaims peers whose transport died silently ("half-open" sockets: laptop sleep, NAT/mobile idle timeout, power loss, a cut cable) without the TCP stack ever delivering a FIN/RST, which would otherwise leak forever (the peer, and anything it owns such as a proxied upstream connection).

It maps to each runtime's liveness mechanism behind one consistent knob:

  • Node — the ws library has no built-in liveness, so crossws pings each peer on this interval and terminates any that miss the pong.
  • Bun / Deno / uWebSockets / Bunny — mapped to the runtime's native WebSocket idle timeout, which also auto-sends keepalive pings.

Terminated peers surface through the normal close hook (Node reports code 1006), so close/error teardown runs unchanged.

Defaults to 30 (seconds) on every runtime. 30s stays under the common ~60s reverse-proxy / load-balancer idle timeout (so idle-but-alive connections aren't dropped) while reclaiming dead sockets promptly; pings are a few bytes and standards clients auto-pong, so a live connection is never disconnected. Set to 0 to disable.

handleProtocols

Select the WebSocket subprotocol to accept during the handshake. Browsers that open new WebSocket(url, protocols) send their offer in the Sec-WebSocket-Protocol request header and reject the connection unless the server echoes one of the offered values back. By default crossws accepts none, so supply this to negotiate one:

crossws({
  handleProtocols: (protocols /* Set<string> */, request) =>
    protocols.has("graphql-transport-ws") ? "graphql-transport-ws" : false,
});

It is called only when the client offered at least one subprotocol, and receives the set of offered values plus the upgrade request. Return the single subprotocol to accept (one of the offered values), or false/undefined for none. It may be async.

This is the global default; the upgrade hook can return { protocol } to override it per connection. Consistent across the Node, Bun and Deno adapters.