/**
 * requestLedger — which dispatched tool call an MCP request belongs to, so the
 * retry series that sends it files its attempts into THAT call's run; when the
 * MCP SDK cancels a request, so the series sending it stops; and whether the
 * request's JSON-RPC answer arrived.
 *
 * Pattern: a per-connection ledger + the SDK transport's `send`, watched in place.
 * Role:    The middle of the evidence seam (`tools/requestEvidence.ts` is its
 *          door). The retry series runs inside the transport's `fetch`, which
 *          the MCP SDK calls with a serialized body and nothing else — no tool
 *          call, no run. Three hops carry the call down to it:
 *
 *   1. call → marker    `issue`: the MCP tool gets a library-private marker and
 *                       puts it in its request's `_meta` (`callMarker.ts`). It
 *                       survives an SDK that copies the params.
 *   2. marker → id      the watched `send` takes the marker out of the message
 *                       — the server receives the bytes it always did — and
 *                       keys the call by the JSON-RPC `id` the SDK assigned.
 *   3. id → series      `claim`: the series reads the `id` back out of the body
 *                       it is about to send.
 *
 * CANCELLATION DOES NOT WAIT ON ATTRIBUTION. Every `tools/call` in flight gets
 * an entry, matched or not, and the SDK says when it gives a request up: it
 * sends `notifications/cancelled` naming the request's id — on its own
 * timeout, or when the call's signal fires — through this same `send`. The
 * ledger aborts that request's series there and then, so a request nobody waits
 * for is never asked again, even when it could not be matched to a call.
 *
 * Under `'app-authorized'` (`strict`), two more things hold:
 *   - A `tools/call` that reaches `send` without a marker this ledger issued
 *     and has not used is REFUSED there (`replayUnavailable.ts`,
 *     `'request-unmatched'`): its answer could not be tied to any call, so it
 *     is never sent rather than guessed at.
 *   - Each matched request's answer is AWAITED, by its id: the connection's
 *     incoming messages are observed for the JSON-RPC response to it. A 202, or
 *     a stream, is not that answer. The watch ends when the answer arrives,
 *     when the SDK cancels the request, when the call settles (found by its
 *     marker, never by its params object) or when the connection closes —
 *     never when only the HTTP send finished, since a 202 or a stream can still
 *     carry the answer later.
 *
 * Whether the answers are observed at all is established once, at
 * initialization: the `initialize` answer must pass the observer
 * (`answersObserved`). An SDK whose `connect` replaces the transport's
 * `onmessage` instead of keeping it leaves the observer out, and a call under
 * `'app-authorized'` is then refused before it is sent (`replayUnavailable.ts`).
 *
 * Ids are the client's, one ledger per connection, so concurrent calls — and
 * concurrent runs sharing one client — can never claim each other's request. A
 * request that is not a `tools/call` (a `tools/list`, a notification, a
 * response) claims nothing.
 *
 * `send` is installed as an OWN property of the transport instance — the same
 * object, its own `send` bound to it, so a transport class with `#private`
 * fields works as it always did. Assigning `send` again afterwards THROWS: a
 * send that bypassed the ledger would quietly lose every call's attempts.
 *
 * Each matched `tools/call` also gets ONE `RequestReplay` (`replay.ts`), the
 * facts its series, this ledger and its call share: the series' claim hands it
 * over by the request's id, the call reads it from the entry it was issued
 * (`IssuedCall`), which outlives the connection's close. The
 * series writes what HTTP showed; this ledger writes whether the JSON-RPC
 * answer arrived; the call writes how it settled.
 *
 * What it does NOT do: retry, wait, or decide anything. The series is the one
 * retry owner; this only tells it whose attempts it is making, and when the SDK
 * has stopped waiting for them.
 */
import type { RequestEvidenceSink } from '../tools/requestEvidence.js';
import type { RequestGuard } from './requestGuard.js';
import { RequestReplay } from './replay.js';
/** One call's claim on the request it sends. */
export interface RequestTicket {
    /** Where the request's attempts are filed. */
    readonly sink: RequestEvidenceSink;
    /** What cancels the call's series — the call's own signal, the client's, the call settling. */
    readonly signal?: AbortSignal;
}
/** What a series claims for the `tools/call` request it sends. */
export interface ClaimedRequest {
    /** The ticket a dispatched call issued for this request — absent when none was matched. */
    readonly ticket?: RequestTicket;
    /** Fires when the MCP SDK cancels this request (`notifications/cancelled`). */
    readonly cancelled: AbortSignal;
    /** What this request's series and its call share (`replay.ts` · `RequestReplay`). */
    readonly replay: RequestReplay;
    /**
     * The send gate of the pooled call this request belongs to (`requestGuard.ts`)
     * — absent for a call no pool made.
     */
    readonly guard?: RequestGuard;
}
/** How a connection's ledger is set up. */
export interface RequestLedgerOptions {
    /** The client's name, which a refusal names. */
    readonly server: string;
    /** The `'app-authorized'` policy is in force: see the module note. */
    readonly strict: boolean;
    /**
     * A pooled client's guard for every message that does not carry its own — its
     * open, its listing, its ending (`mcp/pool/`) — and for a `tools/call` that
     * reached `send` without a call carrying a guard: the pool answers that one
     * with a guard that refuses it, so a pooled request is never sent unchecked,
     * under either replay policy. A request it guards is checked before it is
     * sent, and every message's send is counted under it. Absent for a client no
     * pool built.
     */
    readonly guardFor?: (message: unknown) => RequestGuard | undefined;
}
type JsonRpcId = string | number;
/** The request a call's marker was matched to. */
export interface MatchedRequest {
    readonly id: JsonRpcId;
    readonly replay: RequestReplay;
}
/**
 * One call, from `issue` until it settles: the marker it sends, and the
 * request matched to it once one was. The call holds this entry itself, so
 * what it reads does not depend on the ledger still holding it.
 */
export interface IssuedCall {
    readonly marker: string;
    readonly ticket?: RequestTicket;
    /** The pooled call's send gate, when a pool made the call (`requestGuard.ts`). */
    readonly guard?: RequestGuard;
    /** Set once, by the watched `send`: a marker matches ONE request. */
    readonly request?: MatchedRequest;
}
/** Per connection: the calls issued and not yet settled, the requests being sent, the answers awaited. */
export declare class RequestLedger {
    private readonly options;
    /** Every call issued and not yet settled — keyed by its marker. */
    private readonly issued;
    /** Every `tools/call` sent and not yet settled — keyed by its JSON-RPC id. */
    private readonly sending;
    /** Matched requests whose JSON-RPC answer is awaited (`strict` only) — by id. */
    private readonly awaiting;
    /**
     * A pooled call's guard by its request's id, until the call settles: the SDK's
     * `notifications/cancelled` for that request is work started for the call, and
     * is counted under it (`requestGuard.ts`).
     */
    private readonly guards;
    private initializeId;
    private initializeAnswered;
    private markers;
    private calls;
    private unboundNamed;
    constructor(options?: RequestLedgerOptions);
    /**
     * A call is about to send its request: its entry, whose `marker` the call
     * puts in the request's `_meta` (`callMarker.ts` · `markParams`). `ticket`
     * is where its attempts are filed, when the call carries the run's evidence
     * port.
     */
    issue(ticket?: RequestTicket, guard?: RequestGuard): IssuedCall;
    /** `call` settled: forget it, and stop awaiting its request's answer. */
    settle(call: IssuedCall): void;
    /** The connection closed: nothing it sent is awaited, and no call is pending, any more. */
    close(): void;
    /**
     * Whether this connection's answers pass the observer: the `initialize`
     * answer did. Read once the connection is initialized.
     */
    get answersObserved(): boolean;
    /** How many `tools/call` requests the watched transport has sent — matched to a call or not. */
    get toolCallsSent(): number;
    /**
     * @internal How many entries the ledger holds: calls issued and not settled,
     * requests being sent, answers awaited. Zero once every call settled.
     */
    get retained(): number;
    /** `true` the first time it is asked, then never again: an unmatched request is named once per connection. */
    firstUnbound(): boolean;
    /**
     * Watch `transport`'s `send`: install a wrapped `send` as its OWN property, the
     * original bound to the instance itself. Returns the SAME object — or
     * `undefined` when it has no `send` to watch or refuses the property, and
     * then nothing is watched and no call should expect its attempts filed.
     *
     * Its incoming messages are watched too: an `onmessage` set before the
     * client connects, which the current MCP SDK's `Protocol.connect` keeps and
     * calls before its own dispatch. Whether it was kept is known once the
     * `initialize` answer has, or has not, passed it (`answersObserved`).
     */
    watch<T extends object>(transport: T): T | undefined;
    /** Observe incoming messages before whatever handled them already — never instead of it. */
    private watchMessages;
    /** One incoming message: the `initialize` answer, or the answer to an awaited request. */
    private observe;
    /**
     * The `tools/call` request `body` carries, while its send runs — its ticket
     * when a call issued one, and the signal its cancellation fires. `undefined`
     * for any other body. Parses only while some request is being sent.
     */
    claim(body: unknown): ClaimedRequest | undefined;
    /** One message through the watched transport. */
    private send;
    /**
     * Any message but a `tools/call`: sent as it always was — unless a pool
     * guards it (`guardFor`), and then a REQUEST is checked first and refused
     * unsent, and every message's send is counted under the guard.
     * Notifications are never refused: a `notifications/cancelled` is the
     * courtesy that tells the server to stop.
     */
    private sendOther;
    /** The guard of the pooled call a `notifications/cancelled` names, if any. */
    private cancelledGuard;
    /** The `initialize` request: its answer is the one that proves the observer is in place. */
    private noteInitialize;
    /** The SDK gave a request up: stop the series still sending it, and stop awaiting its answer. */
    private cancelIfAsked;
}
export {};
//# sourceMappingURL=requestLedger.d.ts.map