Peer

Peer object allows easily interacting with connected clients.

When a new client connects to the server, crossws creates a peer instance that allows getting information from clients and sending messages to them.

Instance properties

peer.id

Unique random identifier (uuid v4) for the peer.

peer.request?

Access to the upgrade request info. You can use it to do authentication and access users headers and cookies.

This property is compatible with web Request interface, However interface is emulated for Node.js and sometimes unavailable. Refer to the compatibility table for more info.

peer.remoteAddress?

The IP address of the client.

Not all adapters provide this. Refer to the compatibility table for more info.

peer.websocket

Direct access to the WebSocket instance.

WebSocket properties vary across runtimes. When accessing peer.websocket, a lightweight proxy increases stability. Refer to the compatibility table for more info.

peer.context

The context is an object that contains arbitrary information about the request.

You can augment the PeerContext interface types to add your properties.

declare module "crossws" {
  interface PeerContext {
    customData?: string[];
  }
}
context data can be volatile in some runtimes.

peer.topics

All topics, this peer has been subscribed to.

peer.namespace

Peer's pubsub namespace.

peer.bufferedAmount

Number of bytes queued for transmission but not yet flushed to the client.

Use this to apply backpressure: pause sending while it grows past a high watermark and resume once it drops. This prevents a fast producer (for example a streaming async generator) from filling the adapter's send buffer faster than the client can drain it. The easiest way to wait is peer.waitForDrain().

Not all adapters expose a buffer signal; those return 0. Refer to the compatibility table for more info.

Instance methods

peer.send(message, { compress? })

Send a message to the connected client.

peer.waitForDrain({ threshold?, pollInterval?, signal? })

Returns a promise that resolves once peer.bufferedAmount drops to or below threshold bytes (default 0), letting you await backpressure relief in a send loop:

// Throttle a fast producer to the client's pace
for (const chunk of stream) {
  peer.send(chunk);
  if (peer.bufferedAmount > 1024 * 1024 /* 1MB */) {
    await peer.waitForDrain({ threshold: 256 * 1024 /* 256KB */ });
  }
}

It resolves immediately when there is no backpressure (or on adapters that do not report bufferedAmount). Otherwise it polls every pollInterval ms (default 100) until the buffer drains, and also resolves early if the connection is no longer open so a send loop never hangs on a dropped client. Pass a signal (e.g. AbortSignal.timeout(ms)) to abort the wait — the promise then rejects with the signal's reason.

For event-driven backpressure (instead of awaiting in a loop), use the drain hook together with peer.bufferedAmount.

peer.subscribe(channel)

Join a broadcast channel.

Read more in Guide > Pubsub.

peer.unsubscribe(channel)

Leave a broadcast channel.

Read more in Guide > Pubsub.

peer.publish(channel, message)

Broadcast a message to the channel. The peer that the publish is called on itself is excluded from the broadcast.

Read more in Guide > Pubsub.

peer.close(code?, number?)

Gracefully closes the connection.

Here is a list of close codes:

  • 1000 means "normal closure" (default)
  • 1009 means a message was too big and was rejected
  • 1011 means the server encountered an error
  • 1012 means the server is restarting
  • 1013 means the server is too busy or the client is rate-limited
  • 4000 through 4999 are reserved for applications (you can use it!)

To close the connection abruptly, use peer.terminate().

peer.terminate()

Abruptly close the connection.

To gracefully close the connection, use peer.close().

Compatibility

BunCloudflareCloudflare (durable)DenoNode (ws)Node (μWebSockets)SSE
send()
publish() / subscribe()1111
close()
terminate()22
bufferedAmount333
drain hook4444
request566
remoteAddress
websocket.url
websocket.extensions7777
websocket.protocol888888
websocket.readyState99
websocket.binaryType1010
websocket.bufferedAmount

Footnotes

  1. pubsub is not natively handled by runtime. peers are internally tracked. 2 3 4
  2. close() will be used for compatibility. 2
  3. The runtime exposes no send-buffer signal, so peer.bufferedAmount reports 0. (Cloudflare buffers and applies backpressure internally; SSE has no equivalent.) 2 3
  4. The runtime emits no drain signal. Poll peer.bufferedAmount instead where it is available. 2 3 4
  5. After durable object's hibernation, only request.url (and peer.id) remain available due to 2048 byte in-memory state limit.
  6. using a proxy for Request compatible interface (url, headers only) wrapping Node.js requests. 2
  7. websocket.extensions is polyfilled using sec-websocket-extensions request header. 2 3 4
  8. websocket.protocol is polyfilled using sec-websocket-protocol request header. 2 3 4 5 6
  9. websocket.readyState is polyfilled by tracking open/close events. 2
  10. Some runtimes have non standard values including "nodebuffer" and "uint8array". crossws auto converts them for message.data. 2