export type SdkErrorCode = "invalid_input" | "unknown_operation" | "not_found" | "unavailable" | "timeout" | "connection_closed" | "uncertain_after_send" | "endpoint_credential_forbidden" | (string & {}); export declare class SdkClientError extends Error { readonly code: SdkErrorCode; readonly details: unknown; /** * Reconnect-cycle diagnostics, separate from `details` because `details` is an * established contract: callers read the terminating transport error straight off * it (`session-cli.ts` matches `details.code` against `ENOENT`/`ECONNREFUSED`, and * lifecycle callers cast it to a sent record). Wrapping that value would silently * break every such reader, so the new attribution rides alongside it instead. */ readonly reconnect?: SdkReconnectExhaustedDetails; constructor(code: SdkErrorCode, message: string, details?: unknown, reconnect?: SdkReconnectExhaustedDetails); } export type SdkReconnectTerminationReason = "attempts_exhausted" | "deadline" | "cancelled"; /** * Reconnect-cycle termination diagnostics. `attemptsConsumed` counts retry slots, * not socket opens: the initial open is free, so the loop can open one more socket * than `attemptBudget`. Both values are therefore directly comparable. * * `reason` is authoritative. `attemptsConsumed < attemptBudget` is corroborating * evidence of truncation, not a classifier: a zero-attempt client that trips its * deadline immediately reports `0 === 0` and is still deadline-terminated. */ export interface SdkReconnectExhaustedDetails { readonly attemptsConsumed: number; readonly attemptBudget: number; readonly elapsedMs: number; readonly reason: SdkReconnectTerminationReason; } /** * Deadline a one-shot request client waits for a reply. Long-lived session * clients override it per request; see `SESSION_REQUEST_TIMEOUT_MS`. */ export declare const DEFAULT_SDK_REQUEST_TIMEOUT_MS = 10000; export interface SdkClientOptions { timeoutMs?: number; /** Absolute wall-clock deadline shared by connect, hello, retry, and request work. */ deadline?: number; reconnectAttempts?: number; reconnectBackoffMs?: number; /** * Per-attempt ceiling for the exponential reconnect backoff. A long reconnect * budget must keep probing frequently instead of sleeping for tens of seconds * on its last attempts. Defaults to 2s. */ reconnectMaxBackoffMs?: number; } export interface SdkRequestOptions { timeoutMs?: number; idempotencyKey?: string; confirm?: boolean; /** * Synchronous pre-send observer for one request. Called after the * connection is live and validated, immediately before the frame is written * to the socket. Throwing aborts the dispatch: nothing is written, no sent * record is retained, and the request rejects with the thrown error, so the * caller may safely retry (pre-send semantics). */ beforeDispatch?: SdkBeforeDispatchHandler; /** * Synchronous dispatch-boundary observer for one request. Called immediately * after the frame was handed to the socket — never before — and before any * other client work. From this point a transport close before the response * settles the request as `uncertain_after_send`; observer exceptions cannot * alter that settlement. */ onDispatch?: SdkDispatchHandler; } export type SdkFrame = Record; /** * Synchronous by contract. Returning a thenable (e.g. an `async` function) is a * contract violation: pre-send the dispatch aborts retryably and the eventual * rejection is sunk, never escaping to the process unhandled-rejection channel. */ export type SdkBeforeDispatchHandler = (request: SdkDispatchContext) => void; /** * Synchronous by contract. A returned thenable's rejection is sunk; it can * neither displace request settlement nor escape to the process * unhandled-rejection channel. */ export type SdkDispatchHandler = (request: SdkDispatchContext) => void; /** * Facts about one request at its dispatch boundary. `frame.id` is the exact * correlated identity a response frame must carry to settle this request. */ export interface SdkDispatchContext { readonly frame: SdkFrame; /** Transport generation this request was written to. */ readonly connectionId: string | undefined; readonly generation: number; } /** Request identity retained after an uncertain send for lifecycle reconciliation. */ export interface SdkSentRecord { readonly id: string; readonly operation?: string; readonly idempotencyKey?: string; readonly fingerprint: string; } export type SdkFrameHandler = (frame: SdkFrame) => void; export type SdkReconnectHandler = () => void; export type SdkReconnectFailedHandler = (error: SdkClientError) => void; /** * Transport facts attached to a request timeout before an outcome is known. * A timeout after send is surfaced as `uncertain_after_send` with an * {@link SdkSentRecord} in its details. */ export interface SdkRequestTimeoutDetails { requestId: string; requestSent: boolean; } /** A transport-only v3 SDK WebSocket client with no host or session authority. */ export declare class SdkClient { #private; connectionId?: string; constructor(url: string, token: string, options?: SdkClientOptions); static connect(url: string, token: string, options?: SdkClientOptions): Promise; connect(): Promise; /** Resolves once the current WebSocket has received its server hello frame. */ awaitHello(): Promise; onFrame(handler: SdkFrameHandler): () => void; onReconnect(handler: SdkReconnectHandler): () => void; onReconnectFailed(handler: SdkReconnectFailedHandler): () => void; send(frame: SdkFrame): void; request(frame: SdkFrame, options?: number | SdkRequestOptions): Promise; close(): Promise; control(operation: string, input?: Record, options?: SdkRequestOptions): Promise; query(query: string, input?: Record, cursor?: string, options?: SdkRequestOptions): Promise; global(operation: string, input?: Record, options?: SdkRequestOptions): Promise; getSentRecord(id: string): SdkSentRecord | undefined; lookupLifecycle(record: SdkSentRecord, timeoutMs?: number): Promise; }