Files
suaveplan/packages/networking/network/websocket-gateway/src/gateway/client-lifecycle.md
2026-05-27 23:47:53 +01:00

2.1 KiB

Gateway client-lifecycle helpers

Purpose

Free-function module containing connectClient and disconnectClient — every state mutation that happens when a client attaches or detaches from the daemon. Extracted from gateway.ts so the daemon file stays under the 300-line cap.

Features

  • connectClient registers the client in the client map, presence tracker (when enabled), and bumps the OTel presence_updates_total{kind: "join"} counter.
  • disconnectClient is the cleanup orchestrator: leaves every room, removes the client from every channel, untracks presence (with counter bump), drops the auth context, emits the typed bus event, and fires the presence:leave side effects.
  • Returns false from disconnectClient when the client was never connected so the daemon's error-path handler is idempotent.

Usage: Basic Example

import { connectClient, disconnectClient } from "@suaveplan/websocket-gateway";

connectClient(deps, "alice");
disconnectClient(deps, "alice", "normal");

Usage: Advanced Example

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

const client = connectClient(deps, "alice", {
    userAgent: "Chrome/123",
    region: "us-east-1",
});
// client.metadata is a defensive copy of the input

API Reference

  • connectClient(deps, id, metadata?): ClientInfo — registers a client with lastHeartbeat = clock().
  • disconnectClient(deps, clientId, reason = "normal"): boolean — full cleanup; idempotent.
  • ClientLifecycleDeps — structurally-typed dependency bundle.

Implementation Notes

connectClient clones metadata so the daemon cannot leak mutations back to the caller. disconnectClient calls room.leave on every registered room rather than maintaining a per-client room index because the room set is bounded by maxRooms and the linear sweep keeps disconnect O(rooms) without paying the index-maintenance cost on every join/leave. The OTel counter increments fire next to the actual map mutations so the counter reflects true client lifecycle, not best-effort presence webhook fan-out.