import type { HexisMcpConfig } from './config.js'; /** * The ONE renewal mechanism for an OAuth-mode bearer. Three problems, one * design, because they are the same problem — "who may run the refresh, and * who learns its result": * * 1. SINGLE-FLIGHT. The refresh token ROTATES on every grant, so two * concurrent renewals are not merely wasteful — the loser presents a * refresh token the winner just retired and gets `invalid_grant`, killing * a perfectly healthy sign-in. Startup does exactly this (`Promise.all` * over two REST reads, both 401ing at once), and mid-run tool calls can * race the same way. So there is ONE in-flight renewal per config; every * caller awaits the same promise and shares its outcome, failure included. * * 2. PROACTIVE. The REST reads recover from an expired bearer reactively * (401 → renew → retry), but the remote manual's MCP transport does NOT * go through that path — its session captured the bearer as a header at * registration, and when the token expires every remote tool dies until * restart. So each successful exchange schedules the next renewal at * ~80% of the granted lifetime, on an `unref()`d timer that never holds * the process open. * * 3. NOTIFICATION. A fresh bearer is useless to the remote manual unless * someone re-registers it. `config.onConnectionKeyRenewed` (set by the * server once it exists) is called on EVERY successful renewal — timer- or * 401-triggered alike — so the transport swap has exactly one trigger. * * Key mode never arrives here: `config.renewConnectionKey` is unset, the * schedule call refuses to arm, and `renewConnectionKeyNow` is never consulted * (deployment.ts's `renewer` returns undefined first). */ /** Renew when this fraction of the granted lifetime has elapsed. */ export declare const RENEWAL_FRACTION = 0.8; /** * A failed proactive renewal retries on this cadence. Deliberately short of * any plausible token lifetime: the reactive 401 path also keeps trying, but * only REST reads travel that path — the remote manual's transport depends on * this timer alone. */ export declare const RETRY_AFTER_FAILURE_MS = 60000; /** * Run one renewal — or join the one already running. On success the config's * `connectionKey` is swapped, the next proactive renewal is armed from the * grant's own lifetime, and the credential listener is notified. On failure * every joined caller sees the same rejection, and a retry is armed so the * remote manual is not left to die quietly. */ export declare function renewConnectionKeyNow(config: HexisMcpConfig): Promise; /** * Arm (or re-arm) the proactive renewal at ~80% of the granted lifetime. * Called with the initial exchange's `expiresInMs` at startup and with each * renewal's thereafter. No lifetime reported = no timer: the deployment is too * old to say, and reactive renewal still covers the REST surface. */ export declare function scheduleProactiveRenewal(config: HexisMcpConfig, expiresInMs?: number): void; /** * Disarm the timer — re-arm hygiene (every `scheduleProactiveRenewal` cancels * first); it is unref()d and never holds the process anyway. Also revokes any * IN-FLIGHT attempt's right to re-arm or notify (see the generation note * above): a renewal racing shutdown must not schedule a retry, or apply a * credential swap, into a world that is closing. NOT final — a later renewal * may start and re-arm; teardown wants `closeRenewal`. */ export declare function cancelProactiveRenewal(config: HexisMcpConfig): void; /** * The FINAL cancel — teardown's entry. Everything `cancelProactiveRenewal` * does, plus the config is marked closed for good: a renewal that STARTS after * this point (a straggling REST call's 401-retry racing shutdown) is refused * outright instead of renewing and re-arming the timer into a torn-down world. * Irreversible by design — a config is one process lifecycle, and nothing * legitimately renews for a server that shut down. */ export declare function closeRenewal(config: HexisMcpConfig): void; //# sourceMappingURL=renewal.d.ts.map