import { type ClientFrame, type ServerFrame } from './protocol/index.js'; export interface SocketLike { binaryType: string; send(data: Uint8Array): void; close(): void; onopen: (() => void) | null; onclose: (() => void) | null; onerror: (() => void) | null; onmessage: ((ev: { data: ArrayBuffer; }) => void) | null; } export type SocketFactory = (url: string) => SocketLike; export interface ConnectionOptions { url: string; token: string; /** Authenticated embeds: called when the server rejects the token * (typically an expired signed JWT). Return a freshly minted token to * resume seamlessly, or null to give up (shows the fatal error). */ refreshToken?: () => Promise; open: ClientFrame; onFrame: (frame: ServerFrame) => void; getCursor: () => number; onStatusChange?: (status: 'connecting' | 'open' | 'reconnecting' | 'error', message?: string) => void; socketFactory?: SocketFactory; backoffBaseMs?: number; backoffMaxMs?: number; maxOutbox?: number; } export declare class ConnectionManager { private readonly opts; private socket; private state; private authed; private everAuthed; private attempt; private outbox; private stopped; private timer; constructor(opts: ConnectionOptions); connect(): void; /** Queue a frame; sent immediately if open, else flushed on (re)connect. * The outbox is bounded so a prolonged outage can't grow memory without limit * — oldest queued frames are dropped past the cap. */ send(frame: ClientFrame): void; /** How many frames are waiting to go out. Useful for a host that wants to * show "message pending" state, and for asserting the outbox stays bounded. */ pendingCount(): number; close(): void; private handle; private refreshing; private fatal; /** Release queued frames. When called from 'opened' we know the canonical * conversation id the server just resolved us to, and queued `send` frames * are retargeted to it. A manager only ever opens ONE conversation (its * `opts.open`), so every queued send belongs to that thread by * construction — but the id it was queued with can be STALE (queued against * the previous session's conversation before a reconnect). Retargeting is a * no-op in the normal case and rescues the message in the stale one. */ private flush; /** Bounded enqueue — the cap lives here so EVERY path that queues respects * it (a failed `raw` used to push straight onto the array, bypassing it). */ private queue; private raw; private onClosed; }