Files
skills/docs/networking/network/websocket-gateway/src/gateway/room-ops.md
2026-05-29 08:20:56 +01:00

2.6 KiB

Gateway room operations

Purpose

Free-function module containing every room-level mutation the gateway exposes — create / delete / join / leave / broadcast / unicast — extracted from gateway.ts so the daemon file stays under the 300-line cap. The functions consume a structurally-typed RoomOpsDeps and have no class dependency, which makes them straightforward to unit-test with hand-rolled fakes.

Features

  • createRoom(deps, config) — capacity check + idempotent registration; throws ROOM_FULL once the daemon hits maxRooms.
  • deleteRoom(rooms, id) — clears members, drops the entry, decrements the OTel rooms-active gauge.
  • joinRoom(deps, roomId, clientId, idempotencyKey?) — gates through rate-limit + authz, wraps the join in IdempotencyGuard.execute, fires the presence:update.
  • leaveRoom(deps, roomId, clientId) — symmetric leave + presence fire.
  • broadcastToRoom(deps, roomId, senderId, payload, idempotencyKey?) — gated + idempotent message dispatch returning {message, recipients}.
  • unicast(deps, senderId, targetId, payload) — gated unicast.

Usage: Basic Example

import { createRoom, joinRoom } from "@suaveplan/websocket-gateway";

createRoom(deps, { id: "general" });
await joinRoom(deps, "general", "alice");

Usage: Advanced Example

import { broadcastToRoom } from "@suaveplan/websocket-gateway";

const result = await broadcastToRoom(
    deps,
    "general",
    "alice",
    { text: "hi" },
    "client-supplied-idempotency-key"
);
// result.recipients excludes alice; result.message is the dispatched envelope.

API Reference

  • createRoom(deps, config): Room
  • deleteRoom(rooms, roomId): boolean
  • joinRoom(deps, roomId, clientId, idempotencyKey?): Promise<boolean>
  • leaveRoom(deps, roomId, clientId): Promise<boolean>
  • broadcastToRoom(deps, roomId, senderId, payload, idempotencyKey?): Promise<{message, recipients} | null>
  • unicast(deps, senderId, targetId, payload): Promise<Message | null>
  • RoomOpsDeps — structurally-typed dependency bundle.

Implementation Notes

The dependency bundle uses Pick<> / Omit<> per function so tests can construct minimal fakes — createRoom and deleteRoom deliberately avoid pulling in the gate/idempotency/presence-fire dependencies that aren't relevant to their pure path. Idempotency keys default to a deterministic <verb>:<roomId>:<clientId> shape; per-broadcast they incorporate the daemon's clock so two broadcastToRoom calls in the same logical operation are NOT deduplicated unless the caller passes an explicit key (the upstream behaviour).