/** * attachments.ts, who is watching a hosted session, and for how long. * * An attachment is a claim about a LIVE process, and the only way it used to * end was a client calling `sessions.hosted.detach`. A client that crashed, was * killed, or simply had its tab closed makes no such call: its attachment stood * for as long as the daemon ran, and a `kill`-policy session, the default, * waited for a departure that was never going to arrive. The session that was * supposed to end when the last person left instead outlived everyone watching * it, holding a workspace floor and a model connection. * * So an attachment carries a LEASE, exactly as the conversation-rewind host * registration does (platform/rewind/conversation-host-broker.ts): a claim * bounded by time rather than by anyone remembering to clean up. Two things * renew it, and between them no client has to learn a new call: * * 1. Attaching again. `sessions.hosted.attach` is idempotent and always was, * the same client id re-attaching now also renews, which is the same * "polling renews the lease" shape the rewind host uses. * 2. The client's control-plane connection still being open. A client that * attached under the same id it opened its event stream with is renewed by * the daemon's own observation that it is still there, so an attached client * watching a long turn in silence is never reaped for being quiet. * * The lease is `hostedSessions.attachmentTtlMs`, ten minutes by default, which * is far longer than any disconnect a client recovers from on its own and far * shorter than "until the daemon restarts". */ /** Floor and ceiling for a lease, whoever asks for it. */ export declare const HOSTED_ATTACHMENT_MIN_LEASE_MS = 30000; export declare const HOSTED_ATTACHMENT_MAX_LEASE_MS: number; export declare const HOSTED_ATTACHMENT_DEFAULT_LEASE_MS: number; /** * How often lapsed attachments are swept, for a given lease. * * A quarter of the lease, bounded to [15s, 60s], often enough that a * kill-policy session ends promptly after its last watcher vanishes, rarely * enough to be invisible on an idle daemon. */ export declare function attachmentSweepIntervalFor(leaseMs: number): number; /** A requested lease, clamped. A non-number or a non-positive one takes the default. */ export declare function clampAttachmentLease(requestedMs: number | undefined, fallbackMs: number): number; /** One hosted session's attachments, each with the moment its lease runs out. */ export declare class HostedSessionAttachments { private readonly leases; /** Attach or renew. Returns when the lease now runs out. */ renew(clientId: string, at: number, leaseMs: number): number; delete(clientId: string): boolean; clear(): void; get size(): number; clientIds(): string[]; /** When this attachment's lease runs out, or null when there is no such attachment. */ expiresAt(clientId: string): number | null; /** * Drop and return every attachment whose lease has run out. * * `isConnected` is the second renewal signal: a client the control plane can * still see is renewed in place rather than reaped, so a client that attached * under its stream's own id never has to heartbeat at all. A probe that * throws is treated as "cannot tell", which renews, refusing to answer must * not become a reason to end someone's session. */ expire(at: number, leaseMs: number, isConnected?: (clientId: string) => boolean): string[]; } //# sourceMappingURL=attachments.d.ts.map