/** * WebSocket transport abstraction. * * The default transport opens a real WS connection via the `ws` package; tests * inject a mock factory so unit tests don't reach the network. Two contracts * here: the `WSTransport` (write/close + isOpen) and the `WSTransportFactory` * (returns a `Promise` that resolves once the WS upgrade succeeds, * or rejects with `QodoAuthError` on 401/403 and `Error` on other upgrade * failures). */ export { validateCloseReason, CLOSE_FRAME_REASON_MAX_BYTES, } from './transport.shared.js'; /** * Live WebSocket the client owns after `connect()` returns. Outbound envelopes * are JSON-encoded strings written via `send`; `close` triggers a normal * close handshake. Read-side flows through the handlers passed to the factory. */ export interface WSTransport { /** Write a frame. Backpressure semantics live one layer up in `Connection`. */ send(data: string): void; /** Close the underlying socket. Idempotent. */ close(code?: number, reason?: string): void; /** Whether the socket is currently in the `OPEN` state. */ readonly isOpen: boolean; } /** Read-side callbacks plumbed into the transport at construction time. */ export interface WSEventHandlers { /** A complete text frame arrived. The transport decodes binary→utf8 itself. */ onMessage(data: string): void; /** Underlying socket error. Distinct from a clean close. */ onError(err: Error): void; /** Socket closed. After this, the transport is dead — make a new one to reconnect. */ onClose(code: number, reason: string): void; } /** * Resolved keepalive parameters handed to the transport factory. * * Concrete millisecond values (the public {@link ClientKeepaliveOptions} * defaults already applied) so a factory never has to know the defaults. * Present ⇒ keepalive is ON; the factory should send a protocol-level ping * every `pingIntervalMs` and proactively tear the socket down (firing * `onClose` so the reconnect loop runs) if no pong arrives within * `pongTimeoutMs`. Absent ⇒ keepalive disabled; the factory pings nothing. * * Keepalive lives in the transport, not the `Connection`, because a WS * `ping`/`pong` is a protocol frame below the JSON-envelope layer — only * the socket library can send one. A BYO transport that can't ping (e.g. * the browser WHATWG `WebSocket`, which exposes no app-level ping) may * ignore this field; it then loses fast half-open detection and idle-cutoff * defense but is otherwise unaffected. */ export interface ResolvedKeepalive { /** Interval between pings, in milliseconds. */ readonly pingIntervalMs: number; /** How long to wait for a pong before declaring the socket dead, in milliseconds. */ readonly pongTimeoutMs: number; } /** * Structural stand-in for a Node `http.Agent` — also satisfied by * `https.Agent` and the common proxy-agent packages. Keeps `node:http` out of * the published declarations so browser consumers need no Node typings. */ export interface WSUpgradeAgent { readonly maxSockets: number; createConnection(options: unknown, callback?: unknown): unknown; destroy(): void; } /** Construction args for a transport factory. */ export interface WSTransportFactoryArgs { readonly url: string; readonly headers: Readonly>; readonly handlers: WSEventHandlers; /** * Resolved keepalive config, or `undefined` to disable keepalive. * Threaded identically on the initial connect and on every reconnect. */ readonly keepalive?: ResolvedKeepalive; /** * Overrides automatic environment-proxy selection for Node upgrades. * `false` requests a fresh direct agent; omission uses proxy env / NO_PROXY. * Ignored by transports that cannot accept an agent. */ readonly agent?: WSUpgradeAgent | false; } /** Asynchronously open a WS connection. Resolves once the upgrade has succeeded. */ export type WSTransportFactory = (args: WSTransportFactoryArgs) => Promise; /** * Default transport — uses the `ws` package via dynamic import so consumers * who BYO a transport never need `ws` resolved. */ export declare const defaultTransportFactory: WSTransportFactory; //# sourceMappingURL=transport.d.ts.map