Examples

Example 1

import { createApplication } from '@setu-ts/kernel';
import { RuntimePlugin } from '@setu-ts/runtime';
import { WebSocketPlugin } from '@setu-ts/websocket-plugin';
import { CAPABILITIES, type IWebSocketService } from '@setu-ts/common';

const app = createApplication({
  plugins: [RuntimePlugin(), WebSocketPlugin({ heartbeatMs: 30_000 })],
});

const ws = app.services.get<IWebSocketService>(CAPABILITIES.WEBSOCKET);
ws.route('/ws/chat', {
  onOpen: (conn, { query }) => {
    conn.data.set('room', query.room ?? 'lobby');
    ws.room(query.room ?? 'lobby').add(conn);
  },
  onMessage: (conn, data) => {
    ws.room(conn.data.get('room') as string).broadcast(data, { except: conn });
  },
});

await app.start({ port: 3000 });

Classes

c
HeartbeatSweeper(
runtime: IRuntimeServices,
options: HeartbeatOptions,
connections: () => Iterable<WebSocketConnection>
)

Sends heartbeats and closes idle connections on one shared interval.

  • isRunning(): boolean

    Whether the interval is currently running.

  • start(): void

    Starts the interval. A no-op when heartbeats are disabled, so a plugin left at its defaults never creates a timer.

  • stop(): void

    Stops the interval. Idempotent.

  • tick(): void

    Runs one sweep: closes connections that have been silent too long, then sends the heartbeat payload to the rest.

c
Room(
name: string,
listener?: RoomMembershipListener,
publish?: RoomPublisher
)

A named group of connections that can be addressed as one.

c
RoomRegistry(
publish?: RoomPublisher,
onMemberJoined?: () => void
)

Owns the set of live rooms, creating them on demand and dropping them once empty.

c
WebSocketConnection(
id: string,
path: string,
transport: IWebSocketTransport,
now: number,
heartbeat?: boolean
)

A live WebSocket connection.

c
WebSocketService(
runtime: IRuntimeServices,
options: ResolvedOptions,
available: boolean,
logger?: ILogger,
backplane?: IRealtimeBackplane,
behaviors?: readonly IIngressBehavior[]
)

The WebSocket hub.

c
WebSocketUnavailableError(message?: string)

Thrown when a WebSocket route is registered but the application's HTTP adapter provides no upgrade seam, so no handshake could ever succeed.

c
WsRouteTable

The registered WebSocket routes.

Functions

f
frameByteLength(data: string | Uint8Array): number

Measures an inbound frame in bytes.

f
parseRequestedProtocols(header: string | null): readonly string[]

Parses a Sec-WebSocket-Protocol header into its comma-separated tokens.

f
resolveOptions(options?: WebSocketPluginOptions): ResolvedOptions

Applies defaults and rejects a configuration that cannot work.

Interfaces

I
HeartbeatOptions

Configuration for the sweeper.

I
IWebSocketConnection

A live WebSocket connection, as seen by application code.

I
IWebSocketService

Service contract for the WebSocket hub — registered by the WebSocketPlugin under CAPABILITIES.WEBSOCKET.

I
IWebSocketTransport

The runtime-native socket, normalized to the two operations the framework needs. Implemented by each HTTP adapter's upgrader over its platform socket (Deno.upgradeWebSocket's WebSocket, a ws socket on Node, Bun's ServerWebSocket, the server half of a Workers WebSocketPair).

I
LocalBroadcastOptions

Options for Room.broadcastLocal.

I
RoomBroadcastOptions

Options for a room broadcast.

I
RoomMembershipListener

Notified whenever a connection joins or leaves a Room.

I
WebSocketCloseEvent

Payload of a WebSocket close, normalized across runtimes.

  • code: number

    The RFC 6455 close code (e.g. 1000 normal, 1001 going away).

  • reason: string

    The close reason; an empty string when the peer supplied none.

I
WebSocketConnectionContext

Details of the upgrade request that opened a connection, handed to WebSocketHandlers.onOpen.

  • headers: Headers

    The upgrade request headers — read these to authenticate the peer.

  • path: string

    The URL path component (no query string).

  • protocol: string

    The negotiated subprotocol, when one was selected.

  • query: Readonly<Record<string, string>>

    Query string parameters.

  • url: string

    The full upgrade request URL.

  • user: IPrincipal

    The authenticated principal, when one authenticated the upgrade. Populated by threading ctx.request.user through IWebSocketService.routeUpgrade; omitted when the upgrade was not authenticated. Read this in onOpen to identify the peer rather than re-deriving it from the headers.

I
WebSocketEventSink

The callbacks an HTTP adapter drives once it has completed a handshake. The WebSocket plugin builds one sink per accepted upgrade and hands it to the adapter inside the accept decision; the adapter binds its native socket events to these methods.

I
WebSocketHandlers

The lifecycle callbacks an application supplies per WebSocket route.

I
WebSocketPluginOptions

Configuration for WebSocketPlugin.

  • behaviors: readonly (IIngressBehavior | RegistryFactory<IIngressBehavior>)[]

    Plugin-level ingress behaviours wrapped around every route's onMessage — the WebSocket arm of the transport-neutral behaviour chain shared with the queue, scheduler, and messaging plugins (IIngressBehavior in @setu-ts/common).

  • heartbeatMs: number

    Interval in milliseconds at which WebSocketPluginOptions.heartbeatPayload is sent to every open connection. 0 (the default) disables the heartbeat entirely and creates no timer.

  • heartbeatPayload: string

    The text frame sent on each heartbeat tick. Defaults to 'ping'. Read only when WebSocketPluginOptions.heartbeatMs is above 0.

  • idleTimeoutMs: number

    Milliseconds of inbound silence after which a connection is closed with code 1001. 0 (the default) disables idle closing.

  • maxConnections: number

    Maximum number of simultaneously open connections across all routes. 0 (the default) means unlimited. At the limit, further upgrade requests are refused with HTTP 503 before any socket is created.

  • maxMessageBytes: number

    Maximum size in bytes of a single inbound frame. 0 (the default) means unlimited. A larger frame closes the connection with code 1009 (message too big) and is never delivered to onMessage.

  • routes: readonly WebSocketRouteEntry[]

    Routes registered declaratively, as an alternative to calling service.route(...) imperatively after start(). Each entry — instance or RegistryFactory — produces one route() call, so a route can be declared where the plugin is composed instead of after the application has started.

  • scalingNotice: boolean

    Whether to log one info line at registration when no realtime backplane is registered, stating that rooms broadcast in-process only. Defaults to true.

I
WebSocketRoom

A named broadcast group of connections — the bidirectional analogue of the SSE plugin's channels.

I
WebSocketRouteDefinition

The declarative form of one IWebSocketService.route() call — the entry an application writes instead of calling route() imperatively after start().

I
WebSocketRouteOptions

Per-route configuration supplied alongside the handlers.

  • guards: readonly WebSocketUpgradeGuard[]

    Guards evaluated before this route's WebSocket handshake is accepted.

  • heartbeat: boolean

    Whether this route participates in the shared heartbeat sweep.

  • protocols: readonly string[]

    Subprotocols this route accepts. When non-empty, the first client-requested protocol appearing in this list is echoed back and any request whose Sec-WebSocket-Protocol matches none of them is rejected with 400. When omitted, no protocol is negotiated and none is echoed.

I
WsRoute

One registered WebSocket route.

Type Aliases

T
T
WebSocketReadyState = "connecting" | "open" | "closing" | "closed"

Lifecycle state of a WebSocket, normalized across runtimes to names rather than the numeric codes the web API uses.

T
WebSocketRouteEntry =
WebSocketRouteDefinition
| RegistryFactory<WebSocketRouteDefinition>

One entry of WebSocketPluginOptions.routes: a route definition, or a RegistryFactory producing one when the handlers need a resolved capability.

T
WebSocketUpgradeRouter = (request: Request) => Promise<WebSocketUpgradeDecision | null>

Consulted by an HTTP adapter for every inbound WebSocket upgrade request.

Variables

v
CAPABILITIES: { RUNTIME: string; LOGGER: string; CONFIG: string; VALIDATION: string; DATABASE: string; CACHE: string; EVENTS: string; MESSAGING: string; AUTH: string; AUTHORIZATION: string; JWT: string; SCHEDULER: string; METRICS: string; HEALTH: string; OPENAPI: string; TELEMETRY: string; SECRETS: string; AUDIT: string; RESILIENCE: string; STORAGE: string; MAIL: string; NOTIFICATION: string; FEATURE_FLAGS: string; QUEUE: string; CQRS: string; COMMAND_BUS: string; QUERY_BUS: string; MULTI_TENANCY: string; WORKER_POOL: string; DI_CONTAINER: string; HTTP_ADAPTER: string; SSE: string; WEBSOCKET: string; REALTIME_BACKPLANE: string; SSR: string; SESSION: string; SERVICE_DISCOVERY: string; HEALTH_INDICATOR: string; METRIC_REGISTRATION: string; OPENAPI_SCHEMA: string; CLI_COMMAND: string; DECORATOR_HANDLER: string; METADATA_STORE: string; GRPC: string; CLOUDFLARE: string; GRAPHQL: string; STATIC_FILES: string; VIEW: string; }

Standard capability tokens provided by the first-party plugins.