/**
 * # adapters/broker/ibkr/requests — the per-reqId REQUEST-ERROR CHANNEL (kestrel-7o2.7)
 *
 * The gap this closes — a known kestrel-7o2.16 follow-up. IB multiplexes REQUEST-scoped and
 * CONNECTION-scoped errors onto ONE `error` event, telling them apart by `reqId` (`-1` ⇒ "about the
 * CONNECTION"). 7o2.16 correctly stopped a request-scoped error from felling the SHARED session: one
 * bad contract query (IB 200) no longer STANDs DOWN the whole live socket. But it routed that error
 * to a **diagnostic log sink that DEFAULTS TO A NO-OP** — so the error reached *nobody*. For a
 * request/response lookup that was survivable (the contract layer registers its own `error` listener
 * and rejects its own promise). For a **streaming market-data subscription** it is not: `reqMktData`
 * has no reply-then-end shape, so a refused subscription would simply never tick, and a caller
 * waiting on its first quote would **hang forever** on a silent failure. A dead line rendering as a
 * merely-quiet one is precisely the bug class this runtime treats as first-class.
 *
 * So a request-scoped error needs a real, CALLER-VISIBLE channel — not a log. {@link IbRequestRouter}
 * is it: ONE `error` listener over the shared socket, dispatching by `reqId` to the OWNER of that
 * request. An owned reqId gets a typed {@link IbkrRequestError}; an unowned one (another face's
 * request, or a connection-level message) is left alone — it is not this router's to judge, and the
 * transport still owns the connection-level walls (a router must never quietly re-classify a session
 * the transport declared dead).
 *
 * Fail-closed and LOUD: every routed error carries the IB code + the reqId + the human label of what
 * was being asked for, and the owner is told exactly once. Non-fatal IB info codes (2100–2999 — the
 * market-data-farm chatter every real gateway emits constantly) are NOT failures and are passed to
 * the optional log, exactly as the transport and the contract layer treat them.
 *
 * Determinism at the edge: no clock, no RNG, no timer here — the router is a pure dispatcher over an
 * injected client. The subscription/deadline machinery lives in `./feed.ts`, which injects both.
 */
import { EventName } from "@stoqey/ib";
/** A listener over the IB event bus (the transport's convention — concrete closures are wrapped at
 * the registration site, so the `never[]` never escapes into a handler body). */
type IbListener = (...args: never[]) => void;
/** IB's own marker for "this message is about the CONNECTION, not a request" (`ErrorCode.NO_VALID_ID`). */
export declare const IB_CONNECTION_REQ_ID = -1;
/**
 * The NARROW surface the router needs of the shared IB client: the event bus, nothing else. It
 * declares no request method at all — the router only *listens*; the caller issues its own requests.
 */
export interface IbErrorBus {
    on(event: EventName, listener: IbListener): unknown;
    removeListener(event: EventName, listener: IbListener): unknown;
}
/**
 * A REQUEST-scoped IB error, delivered to the caller that OWNS the request (kestrel-7o2.7) — the
 * typed, fail-closed refusal that replaces the old silent no-op log. It is deliberately DISTINCT from
 * `IbkrConnectionError` (the session is fine) and from `IbkrContractError` (no identity was being
 * resolved): it says "the gateway refused THIS request", so the caller can drop THAT subscription and
 * carry on, or STAND_DOWN, without ever mistaking it for a dead socket.
 *
 * Carries the IB `code` (200 no-security-definition, 321 invalid request, 10197 no market data …),
 * the owning `reqId`, and the secret-free `label` naming what was being asked for.
 */
export declare class IbkrRequestError extends Error {
    readonly name = "IbkrRequestError";
    /** The IB request id the gateway refused — the key the router dispatched on. */
    readonly reqId: number;
    /** The IB error code, when the venue named one; `undefined` for a locally-raised deadline lapse. */
    readonly code: number | undefined;
    /** A secret-free description of what was being asked for (e.g. `market data for SPY 445C`). */
    readonly label: string;
    constructor(reqId: number, label: string, reason: string, options?: {
        code?: number | undefined;
        cause?: unknown;
    });
}
/** What the router hands the owner of a reqId when the gateway refuses that request. */
export type RequestErrorSink = (err: IbkrRequestError) => void;
/**
 * The per-reqId error router over ONE shared IB socket (kestrel-7o2.7).
 *
 * Registers a SINGLE `error` listener and dispatches by `reqId`:
 *
 *  - a **non-fatal** info code (2100–2999) ⇒ logged, never a failure (the farm chatter a real gateway
 *    emits constantly is not a refusal);
 *  - an **owned** reqId ⇒ a typed {@link IbkrRequestError} handed to that owner's sink — the channel
 *    that did not exist before, and the reason a failed subscription can no longer hang;
 *  - an **unowned** reqId (another face's request) or a **connection-level** message (`reqId === -1`)
 *    ⇒ left strictly alone. The router never degrades, re-opens, or re-classifies the shared session:
 *    connection-level walls belong to the transport (kestrel-7o2.5/7o2.16), and this router's whole
 *    purpose is that a request-scoped error must NOT become a session-scoped one.
 *
 * Pure dispatch — no clock, no RNG, no timer.
 */
export declare class IbRequestRouter {
    #private;
    constructor(bus: IbErrorBus, opts?: {
        log?: ((line: string) => void) | undefined;
    });
    /** Claim a reqId: from now until {@link close}, an IB error on it reaches `onError`. Claiming a
     * reqId twice is a programming error, not a runtime guess — the LAST owner wins and the collision
     * is logged loudly (a shared request-id space with two owners is never silently tolerated). */
    open(reqId: number, label: string, onError: RequestErrorSink): void;
    /** Release a reqId. A later error on it becomes an unowned message (logged, never a failure of
     * something that already finished — and never a session kill). Idempotent. */
    close(reqId: number): void;
    /** Is this reqId currently owned? (Used by the feed to tell its own lines from another face's.) */
    owns(reqId: number): boolean;
    /** Detach the single `error` listener from the shared socket and forget every owner. A leaked
     * listener on a shared socket is a cross-request bug; teardown is therefore total and idempotent. */
    dispose(): void;
    private dispatch;
}
/** A human, secret-free gloss on the IB error codes a market-data request actually meets. An
 * unrecognised code still FAILS the request (fail-closed — an unknown refusal is never shrugged off);
 * it is simply named honestly as unrecognised rather than mislabelled as something the adapter cannot
 * actually vouch for. */
export declare function describeIbErrorCode(code: number): string;
export {};
//# sourceMappingURL=requests.d.ts.map