/** * Delivery-daemon single-flight lease — a CAS-guarded key in the per-space `cotal_delivery_` KV * bucket. One key per shard ({@link leaseKey}); the holder is the live delivery daemon for that shard. * Acquire is an ATOMIC `kv.create` (fails if a live lease exists) — a loud refusal-to-bind, so two * daemons never split a durable's delivery. The bucket has a bucket-level TTL ({@link LEASE_TTL_MS}), * so a CRASHED holder's lease key auto-expires and a fresh daemon can re-acquire; the holder renews * (CAS `kv.update`) at ~half the TTL to stay alive. The same key is the daemon-readiness signal and * the non-gating `cotal_channels` delivery-health signal (READ-ONLY for an agent — Component 6). * * The acquire/renew/release/read operations live as methods on {@link CotalEndpoint} (they reuse its * connection + cred); this module is just the bucket-open helper + the record shape, mirroring * `openMembersRegistry` / `openAclRegistry`. */ import { type KV } from "@nats-io/kv"; /** The `holder` string a delivery daemon holding THIS credential will write into its lease row. * * EXISTS BECAUSE THE OBVIOUS ANSWER IS WRONG, and was wrong at three separate call sites. A caller * that launches a daemon knows the cred it handed over, so `idFromCreds` looks like the daemon's * identity - and it is, at the connection layer. But the endpoint rewrites `card.id` in its * constructor to the wire PRINCIPAL dot-form `${owner}.${actor}` (`local.U...` in the static mode * the daemon runs in), and THAT is what lands in the row. Comparing a bare nkey against the row can * only ever be false, which is a comparison that silently never fires rather than one that fails * loudly. Derived here, once, so no caller has to re-derive a rule that lives in the endpoint. */ export declare function deliveryLeaseHolderFor(creds: string): string; /** A delivery lease record: who holds the shard and since when (epoch ms; diagnostics + health surface), * plus `ready` — set true only AFTER the daemon has bound `ctl.delivery` + the fan-out/reader loops, so * "lease live" proves the RESPONDER is up, not merely that the single-flight slot was claimed. The lease * is CAS-created (`ready:false`) BEFORE binding (single-flight gate, prevents double-bind), then updated * to `ready:true` after `startPlane3` — and renews keep it true. */ export interface DeliveryLeaseInfo { holder: string; /** WHICH RUN of that holder, not merely which principal. `holder` is the endpoint's wire identity, * and it is NOT unique per process: the daemon's cred is a FILE on disk that every restart re-reads * (`delivery-proc.ts` mints it once and re-launches against it), so a replacement daemon in the same * space authenticates as the same nkey and presents the same principal as the process it replaced. * A daemon asking "is this row still mine?" therefore cannot get a truthful answer from `holder` * alone, it would recognise its own SUCCESSOR's row as its own, keep serving a shard it had lost, * and CAS-release the row out from under the live holder. Minted per endpoint instance, so it * changes on every restart even when the credential does not. * * Optional because rows written by daemons from before this field exist in live buckets; a row * without one cannot be proven ours (some other process wrote it), which is the safe reading. */ incarnation?: string; since: number; ready: boolean; } /** A manager per-instance LIVENESS-lease record: which logical instance is live + how it was launched. * `runtime`/`root` let `spawn -f` fail LOUD on a mismatch instead of silently reusing a wrong-runtime / * foreign-checkout manager (no fallbacks); `pid` is a diagnostics + targeted-stop hint. Keyed per * {@link ManagerLeaseInfo.instanceId} ({@link import("./subjects.js").managerLeaseKey}) — P2 item 3 * demoted the per-space singleton to per-instance liveness, so a second manager's create no longer * THROWS (distinct instance id ⇒ distinct key ⇒ both acquire). Losing the key stops THAT instance only. */ export interface ManagerLeaseInfo { /** The manager endpoint id — `principalKey(owner, actor).key` dot-form (the endpoint card's * id), so it is DIRECTLY comparable to a control subject's `.` attribution: * the auth service's retirement rail (#29 piece 3) leader-reads this row and requires * holder == the subject-attributed requester principal, fresh per request. On an auth mesh every * instance of one space shares this holder (same owner+actor principal); {@link instanceId} is what * distinguishes them. */ holder: string; /** The live LOGICAL manager instance id (persisted per workspace root, advanced-epoch on restart). * The KEY discriminator: two managers in one space share `holder` but have distinct `instanceId`. */ instanceId: string; runtime: string; root: string; pid: number; since: number; } /** Open the delivery lease/readiness bucket (pre-created with a bucket-level TTL at `cotal up`; the * daemon binds, never creates). Read-only for an agent (Component 6 health), write-lease for the daemon. */ export declare function openDeliveryRegistry(nc: import("@nats-io/transport-node").NatsConnection, space: string): Promise; /** Poll until the delivery daemon has acquired its shard-0 lease (i.e. is ready to serve `ctl.delivery`), * or the timeout elapses. Used by the CLI's `ensureDelivery` to wait for readiness before the manager * spawns agents (so their boot self-join finds the responder). Connects with the daemon's own scoped * creds (`id` sets the `_INBOX_` prefix the cred's `sub.allow` permits for the kv.get reply). * Returns false on timeout / unreachable — the caller treats it as non-fatal (boot self-join reconciles). * * `holder` is WHOSE readiness is being waited for, and it is NOT optional information (#837). * This used to accept ANY ready lease, which made it answer a question nobody asked: a daemon that * was SIGKILLed leaves its `ready:true` record behind for the rest of the bucket TTL, so a freshly * launched replacement that LOST the CAS and exited was reported ready off the corpse's lease — * `up` printed green with no daemon running at all. Pass the launched daemon's endpoint id * (`idFromCreds` of the cred it was given) to demand that daemon; pass `undefined` only when * ADOPTING a daemon that was already running, whose id is genuinely not knowable from here. */ export declare function waitForDeliveryLease(opts: { servers: string; space: string; creds: string; id: string; holder: string | undefined; timeoutMs?: number; }): Promise; //# sourceMappingURL=lease.d.ts.map