// Attach-socket reconnect policy. Split out of attach.ts so it can be tested // without a DOM or an xterm instance. import type { Session, Uuid } from "./types.js"; /** First retry delay after an unexpected close, doubling up to the cap. */ export const INITIAL_RECONNECT_MS = 500; export const MAX_RECONNECT_MS = 10_000; /** Close codes at or above this are application-defined; the daemon uses * them to signal a rejection, which retrying would only loop on. */ const APPLICATION_CLOSE = 4000; /** Normal Closure — the peer ended the stream deliberately. */ const CLEAN_CLOSE = 1000; /** * Should a closed attach socket be retried? * * The catalog is the authority: a session still `Running` lost its link, so * retry; one that is `Dead` has had its PTY stream sealed and will never send * again, and one absent from the catalog is gone. Before this existed, any * dropped frame destroyed the pane permanently. */ export function shouldRetryClose( sessionId: Uuid, code: number, sessions: ReadonlyMap, /** Did this socket ever reach `open`? A handshake that never completed is * the daemon rejecting the attach (dormant/unknown) rather than a dropped * stream — retrying it spins in place until the catalog updates, which for * a dormant session it never will (#168 review). Defaults to `true` so * existing callers that only track drops of an established link are * unaffected. */ everOpened = true, ): boolean { if (code >= APPLICATION_CLOSE || code === CLEAN_CLOSE) return false; if (!everOpened) return false; return sessions.get(sessionId)?.status === "Running"; }