/** * The connection registry with liveness. * * S1 tracks every authenticated connection and its last-seen time; a connection * not seen within the liveness TTL ages out on {@link ConnectionRegistry.sweep}. * Presence detail (the instances a connection carries and each one's declared * capability / host / family) is left blank by S1 and filled in by the S2 * register/heartbeat/deregister family module through * {@link ConnectionRegistry.addInstance} / {@link ConnectionRegistry.removeInstance} * — S1 owns liveness, S2 owns presence. */ import type { Capability } from "../protocol/index.ts"; import type { Clock } from "./clock.ts"; /** * Presence attributes a family module (S2) attaches to a live connection. * * A single connection may carry MANY worker instances — a per-host supervisor * multiplexes N workers over one socket — so instances are held as a set with * each instance's enrolment capability. Job ownership and relay attribution read * the instance carried EXPLICITLY in a frame's payload, resolved against this * set, never inferred 1:1 from the connection id. */ export interface Presence { /** The worker instances registered on this connection, keyed by instance id. */ readonly instances: Map; } /** A tracked, authenticated connection. */ export interface RegisteredConnection { /** The connection id (matches {@link ChannelConnection.id}). */ readonly id: string; /** The authenticated principal (ADR 0028 identity) from the handshake. */ readonly identity: string; /** When the connection was accepted, in epoch ms. */ readonly connectedAt: number; /** Last time any inbound frame or keepalive pong was seen, in epoch ms. */ lastSeen: number; /** Presence detail, populated by the S2 family module (blank until then). */ presence: Presence; } export interface ConnectionRegistryOptions { /** Liveness TTL in ms; a connection unseen for longer ages out. Default 30000. */ ttlMs?: number; /** Injectable clock (deterministic tests). Default {@link systemClock}. */ clock?: Clock; } export declare class ConnectionRegistry { #private; constructor(options?: ConnectionRegistryOptions); /** The liveness TTL in ms. */ get ttlMs(): number; /** Number of tracked connections. */ get size(): number; /** * Start tracking a newly authenticated connection. `connectedAt` and * `lastSeen` are set to now; presence starts blank. */ add(id: string, identity: string): RegisteredConnection; /** Update a connection's liveness to now. No-op if unknown. */ touch(id: string): void; /** * Bind an instance to a tracked connection (used by S2 on `register`), storing * its enrolment capability. Re-adding an already-bound instance refreshes its * capability. No-op if the connection is unknown. */ addInstance(id: string, instance: string, capability?: Capability): void; /** * Unbind a single instance from a tracked connection (used by S2 on * `deregister`). Returns `true` if the instance was bound. No-op (returns * `false`) if the connection or instance is unknown. */ removeInstance(id: string, instance: string): boolean; /** * The set of instances bound to a connection — the resolver the relay/claim * path uses to attribute a frame's EXPLICIT `instance` to its connection * (never inferring it 1:1 from the connection id). Empty for an unknown or * not-yet-registered connection. */ instancesForConnection(id: string): ReadonlySet; /** * The enrolment capability an instance registered with on a connection, or * `undefined` if that instance is not bound to it. */ capabilityForInstance(id: string, instance: string): Capability | undefined; /** Look up a tracked connection. */ get(id: string): RegisteredConnection | undefined; /** Whether a connection is tracked. */ has(id: string): boolean; /** Stop tracking a connection, returning the removed entry if present. */ remove(id: string): RegisteredConnection | undefined; /** All tracked connections, in insertion order. */ list(): RegisteredConnection[]; /** * Age out every connection whose last-seen time is older than the TTL and * return the removed entries, so the hub can close their sockets. `now` * defaults to the clock; pass an explicit value for deterministic tests. */ sweep(now?: number): RegisteredConnection[]; }