WebSocket · In depth

SocketRoute

Defines a WebSocket endpoint and owns its handlers, services, clients, and opt-in multiplayer policies. Routes can add bounded admission, transport limits, ordered work, heartbeat, rooms, resumable sessions, distribution, draining, metrics, and protocol negotiation without changing legacy routes.

Explain it like I’m five

The simple mental model

A SocketRoute is a room with its own door and rules. The URL chooses the room; message.type chooses which handler inside the room receives the message.

When it fits

When should I use it?

Create one whenever a WebSocket path represents a distinct protocol, trust boundary, workload, or group of multiplayer resources.

A practical API pattern

Follow the example

This pattern explains the named API. Application classes, credentials, and assets may need to be supplied; use a complete recipe for a runnable starting point.

Read this article as Markdown

JavaScript
const { SocketRoute } = require('redweb')
const { ChatHandler } = require('./handlers/ChatHandler')
const { ClockService } = require('./services/ClockService')

class ChatRoute extends SocketRoute {
  constructor() {
    super({
      path: '/chat',
      handlers: [ChatHandler],
      services: [ClockService],
      allowDuplicateConnections: true,
      websocketOptions: {
        maxPayload: 1024 * 1024,
        perMessageDeflate: false,
      },
    })
  }
}
  1. 1

    The /match path selects the route during the WebSocket upgrade.

  2. 2

    Admission and capacity checks run before the connection becomes an active client.

  3. 3

    Messages are dispatched by type to BaseHandler instances while route services and registries share the same lifecycle.

Configuration

Choices you can make

  • path: WebSocket path (required)
  • handlers: array of handler classes (required)
  • services: array of SocketService subclasses (optional)
  • allowDuplicateConnections: allow multiple clients from the same IP
  • websocketOptions: options passed to ws WebSocketServer, such as maxPayload or perMessageDeflate
  • admission: authenticate, validate origins, and optionally place a client before upgrade
  • maxPendingUpgrades: finite concurrent admission/negotiation work (default 64)
  • limits: connection, message-rate, pending-message, and outbound-buffer ceilings
  • orderedMessages: serialize each connection through a bounded queue
  • heartbeat: one route-level half-open connection monitor
  • rooms and sessions: bounded grouping and expiring application-issued ownership
  • distribution: optional bounded broker adapter; no broker is bundled or required
  • drainHandlers: track handler work and expose a cooperative shutdown signal
  • protocol: version negotiation, stable envelopes/error codes, and optional binary codecs
Surface area

Methods and members

constructor({ path, handlers, services, allowDuplicateConnections, websocketOptions })

Validates input, instantiates handlers/services, sets up a `ws` server for the path with any websocketOptions, and registers connection listeners.

addHandler(HandlerClass)

Adds another handler class unless a handler with the same name already exists.

handleConnection(socket, req)

Stores the client (deduping by IP unless allowed), decorates the socket with `sendJson`/`broadcast`, and wires close/error/message listeners.

handleMessage(socket, data)

Parses JSON text frames, finds the handler matching `data.type`; on success delegates to handler.handleMessage, otherwise replies with an error and closes the socket.

handleBinaryMessage(socket, buffer)

Handles binary frames separately from JSON text frames and delegates to a handler selected by acceptsBinary(socket, buffer).

handleClose(socket, ip)

Removes the client from the registry and triggers an optional `connectionCloseCallback`.

shutdown()

Marks the route draining, stops services, bounds handler/adapter cleanup, closes clients, and releases every route-owned resource.

beginDrain()

Flips readiness and rejects new upgrades before shutdown work begins.

isReady()

Reports whether the route is accepting upgrades and any required distribution adapter is healthy.

publish(type, payload)

Publishes through the optional bounded distribution adapter and resolves to a success boolean.

handleError(socket, error, ip)

Logs socket errors; override for custom reporting.