# 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 ```ts import { connectClient, disconnectClient } from "@suaveplan/websocket-gateway"; connectClient(deps, "alice"); disconnectClient(deps, "alice", "normal"); ``` ## Usage: Advanced Example ```ts 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.