import { type NatsConnection } from "@nats-io/transport-node"; /** The structured outcome of an eviction attempt — every field a repair/flip gate reads to decide * "done" vs "blocked". `verifiedGone` is the ONLY success signal; it is true only when a COMPLETE * re-scan found zero live cids for the principal. */ export interface EvictionResult { principal: string; /** cids KICKed across all servers this attempt. */ kicked: number; /** cids still live for the principal after the verify deadline (0 with `verifiedGone` = success). */ remaining: number; /** True iff a COMPLETE re-scan proved the principal has no live connection. Partial/failed scans * are false — a caller must treat false as "not verified", never "probably fine". */ verifiedGone: boolean; /** False if any CONNZ round under-reported (no responder, pagination truncation) — the result is * UNKNOWN, not success, even if `kicked` > 0. */ scanComplete: boolean; /** Human-readable per-attempt note (scan errors, deadline hit) for the daemon log / doctor. */ note?: string; } /** Options bounding the scan→kick→re-scan loop. Defaults suit a local single-server broker; the * cluster case widens the settle window. */ export interface EvictOptions { /** How many verify re-scans to attempt before reporting `remaining` (default 3). */ maxVerifyRounds?: number; /** Per-CONNZ-round settle window in ms after the last reply (default 250). */ settleMs?: number; /** Hard per-round ceiling in ms (default 2000). */ maxWaitMs?: number; pageLimit?: number; } /** * Evict every live connection of one principal — the kill-live half of revocation, to be called * ONLY AFTER the deny-new is committed (ledger revoke / cred expiry / ACL removal). Scans, KICKs * each matching cid on its own server, then re-scans up to `maxVerifyRounds` to confirm the * principal is gone. Fail-closed: a partial scan is `verifiedGone:false, scanComplete:false`, and a * principal that was never live is an idempotent success no-op. * * The name carries the precondition: this is `evictDeniedPrincipal`-shaped — it does NOT deny new * connects; without a committed deny-new a kicked client reconnects with a fresh cid. */ export declare function evictDeniedPrincipal(observerConn: NatsConnection, evictorConn: NatsConnection, accountId: string, principal: string, options?: EvictOptions): Promise; /** One plane-owned connection's broker identity, captured at connect from the protocol INFO and * pinned in the auth plane's durable claim row. `serverId` is the broker RUN's ephemeral id (a * restart mints a new one), `cid` is that server's connection id, `userNkey` is the connection's * stable user public key (the self-minted authority identity). */ export interface PlaneConnTuple { serverId: string; cid: number; userNkey: string; } /** The closed plane-liveness query: exactly the TWO ownership-bearing sealed-scanner tuples out of * the plane claim row — never a generic CONNZ filter (the delivery daemon derives the allowed * connection labels from its own space; a caller cannot probe arbitrary connections). */ export interface PlaneLivenessQuery { ledger: PlaneConnTuple; records: PlaneConnTuple; } /** Per-role verdict. `live` = the claimed identity (or its user nkey anywhere) is connected NOW; * `gone` = a COMPLETE sweep conclusively proves it absent; `unknown` = the observation cannot * decide (incomplete sweep) — a caller MUST treat unknown as "may still be live" (refuse * takeover), never as gone. */ export type PlaneRoleLiveness = "live" | "gone" | "unknown"; /** The oracle's bound reply: each queried tuple echoed with its verdict (a reply that does not * echo the caller's exact query never authorizes), plus `sweepComplete` — CONNZ OBSERVATION * completeness (every round replied, no truncation), NEVER any statement about a sealed scan * having finished (the critic's mid-scan-crash wedge; reclaim gates on liveness alone). */ export interface PlaneLivenessResult { ledger: { tuple: PlaneConnTuple; state: PlaneRoleLiveness; }; records: { tuple: PlaneConnTuple; state: PlaneRoleLiveness; }; sweepComplete: boolean; note?: string; } /** Structural tuple validation (closed parse — the wire crosses a trust boundary in BOTH * directions: the daemon validates the query, the auth plane validates the echo). CLOSED schema: * an unknown field refuses (a v1 tuple is exactly these three keys). */ export declare function isPlaneConnTuple(v: unknown): v is PlaneConnTuple; /** Closed parse of a wire-crossing {@link PlaneLivenessResult} (the auth plane validates the * delivery-admin rail's reply BEFORE reasoning over it): exactly the v1 keys, both role objects * exactly `{ tuple, state }`, states in the enum, tuples closed. Undefined on ANY violation — the * caller maps that to `unknown` (a garbled oracle must block takeover, never authorize it). */ export declare function parsePlaneLivenessResult(v: unknown): PlaneLivenessResult | undefined; /** * Answer a plane-liveness query over the account's live connections (the delivery daemon's * read-only half of the #29 HIGH 3 reclaim protocol; observer cred only, no KICK). Verdict rules, * fail-safe by construction: * * - `live`: a connection carrying the claimed `userNkey` exists ANYWHERE (any server, any cid — * wider than the exact tuple on purpose: an identity that still holds ANY connection must block * takeover), or the exact `(serverId, cid)` pair is present. * - `gone`: the sweep is COMPLETE, the observation PROVES the single-server mode, and the claimed * `userNkey` appears nowhere. This includes the claimed `serverId` being absent from the * repliers entirely: `server_id` is per-broker-RUN, so after a broker restart the claimed * incarnation can never reply again while every connection it held is gone by definition — * requiring its reply forever would turn every whole-stack crash into a permanent reclaim * wedge (the inverted-lockout class). * * THE SINGLE-SERVER PROOF (SPEC 13.13): CONNZ absence alone cannot distinguish a RESTARTED * claimed server (genuinely gone) from a PARTITIONED one (live, unreachable) — both present as * "the claimed serverId did not reply". The discriminator is the responding server's OWN * topology declaration, never an inference from who replied: `gone` additionally requires that * EVERY reply carried a server envelope declaring NO cluster membership (`server.cluster` * absent — nats-server sets it, config-named or dynamically generated, whenever clustering is * configured) and that exactly ONE distinct server replied. A standalone process cannot have a * silent same-cluster peer holding the claimed connection, so its complete reply is the whole * truth; a partitioned cluster member still DECLARES its cluster and reads `unknown`. NAMED * RESIDUALS: a leafnode/gateway-extended account is outside the cluster self-report (such * topologies are out of contract for the auth account until a multi-server incarnation * authority exists), and a backup-restore onto a fresh broker can present a still-running * foreign predecessor's `serverId` as dead. * - `unknown`: the sweep under-reported (no replies, truncation, an unroutable row) OR the * single-server mode is unproven (a cluster self-report, multiple repliers, or a reply without * the server envelope) — the caller refuses takeover. * * Closed surface: the CONNZ request carries no caller-selected filter (account-wide sweep only) * and the reply exposes ONLY the two bound verdicts + sweep completeness — never a connection * listing. A row matching the claimed nkey under ANY connection name counts live (fail safe); * the residual "is this nkey connected" bit the verb leaks is strictly weaker than the kick * authority the same rail already carries. */ export declare function observePlaneLiveness(observerConn: NatsConnection, accountId: string, query: PlaneLivenessQuery, options?: EvictOptions): Promise; /** Creds-level wrapper for the delivery daemon's admin-rail plane-liveness verb: open the $SYS * observer PER CALL (the eviction seam's rule — never a standing $SYS connection), run * {@link observePlaneLiveness}, drain. Read-only: no evictor cred enters this path. */ export declare function observePlaneLivenessWithCreds(opts: { servers: string; observerCreds: string; accountId: string; query: PlaneLivenessQuery; options?: EvictOptions; }): Promise; /** A principal's liveness verdict. `live` = a connection attributed to it exists NOW; `gone` = a * COMPLETE, single-server-proven sweep proves none does; `unknown` = the observation cannot decide. * A caller MUST treat `unknown` as "may still be live" — never as gone. */ export type PrincipalLiveness = "live" | "gone" | "unknown"; /** The probe's bound reply: the principal ECHOED back with its verdict (a reply that does not echo * the exact principal asked about never authorizes), plus `sweepComplete` — CONNZ observation * completeness, kept as its own field and NEVER folded into the verdict. */ export interface PrincipalLivenessResult { principal: string; state: PrincipalLiveness; sweepComplete: boolean; note?: string; } /** Closed, ECHO-BOUND parse of a wire-crossing {@link PrincipalLivenessResult} — the caller * validates the delivery-admin rail's reply BEFORE reasoning over it. Exactly the v1 keys, the * state in the enum, and the echoed principal EQUAL to the one queried. Undefined on ANY * violation; the caller maps that to `unknown` (a garbled or foreign oracle must block the repair, * never authorize it). `expected` is required precisely so the echo cannot be forgotten. */ export declare function parsePrincipalLivenessResult(v: unknown, expected: string): PrincipalLivenessResult | undefined; /** * Answer whether ONE principal holds any live connection — the read-only half of principal * eviction, drawn from the SAME {@link livenessSweep} the plane oracle uses, so an observation good * enough to authorize a repair is validated identically wherever it is read. * * - `live`: a complete sweep attributed at least one connection to the principal. * - `gone`: the sweep is COMPLETE, the single-server mode is PROVEN (SPEC 13.13), and no connection * attributes to the principal. The single-server proof is required for the same reason the plane * reclaim requires it: in a clustered account, CONNZ absence cannot distinguish a genuinely dead * holder from a live one behind a partition, and reading the second as "gone" is exactly the * unsafe direction for a repair that revokes and evicts a credential family. * - `unknown`: the sweep under-reported, or the single-server mode is unproven. * * Refuses a non-principal loudly: CONNZ attribution only ever surfaces `local`/`u_…` owners, so a * syntactically-valid non-principal would sweep clean and return a HEALTHY `gone` — false * confidence for a typo'd target. Same boundary `executeEviction` applies to its filter. */ export declare function observePrincipalLiveness(observerConn: NatsConnection, accountId: string, principal: string, options?: EvictOptions): Promise; /** Creds-level wrapper for the delivery daemon's admin-rail principal-liveness verb: open the $SYS * observer PER CALL (the eviction seam's rule — never a standing $SYS connection), run * {@link observePrincipalLiveness}, drain. Read-only: no evictor cred enters this path. */ export declare function observePrincipalLivenessWithCreds(opts: { servers: string; observerCreds: string; accountId: string; principal: string; options?: EvictOptions; }): Promise; /** Creds-level wrapper for composition roots that hold the two $SYS creds as FILES/strings (the * delivery daemon's admin-rail executor): open the observer (under its granted inbox prefix) and * the kick-only evictor PER CALL, run {@link evictDeniedPrincipal}, and drain both — eviction is a * rare repair/flip step, never a standing $SYS connection. Core owns the connection lifecycle * (the same placement rule as the membership feed), so edge packages never import the transport. */ export declare function evictDeniedPrincipalWithCreds(opts: { servers: string; observerCreds: string; evictorCreds: string; accountId: string; principal: string; options?: EvictOptions; }): Promise; //# sourceMappingURL=evict.d.ts.map