import WebSocket from 'ws'; import type { DevToolsTarget } from './electron-connection'; /** * Result payload of a `Runtime.evaluate` call returned by CDP. * See https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#method-evaluate */ export interface RuntimeEvaluateResultPayload { result: { type: 'string' | 'number' | 'boolean' | 'undefined' | 'object' | 'function' | 'symbol' | 'bigint'; value?: unknown; description?: string; className?: string; objectId?: string; subtype?: string; }; exceptionDetails?: { text: string; exception?: { description?: string; value?: unknown; }; }; } /** A pending CDP request waiting for its matching response. */ interface PendingMessage { resolve: (value: unknown) => void; reject: (error: Error) => void; timeoutHandle: NodeJS.Timeout; method: string; } /** A single multiplexed CDP connection managed by the pool. */ interface PooledConnection { ws: WebSocket; target: DevToolsTarget; pendingMessages: Map; nextMessageId: number; enabledDomains: Set; isClosing: boolean; } /** Options passed to `CdpConnectionPool.send`. */ export interface CdpSendOptions { /** Override the default request timeout (ms). */ timeoutMs?: number; } /** Options passed to `CdpConnectionPool.evaluate`. */ export interface CdpEvaluateOptions extends CdpSendOptions { /** Block until any returned Promise resolves (CDP `awaitPromise`). */ awaitPromise?: boolean; /** Serialize result by value (CDP `returnByValue`). Default true. */ returnByValue?: boolean; /** Optional userGesture flag for trusted UI events. */ userGesture?: boolean; } /** * Singleton pool of long-lived CDP WebSocket connections. * * Why this exists: * - The previous `electron-connection.ts` opened a fresh WebSocket per call * (~50 connections / 5 seconds for `wait_*` polling). That is unsustainable * and incompatible with `MutationObserver` based primitives that need a * long-lived connection for streaming events. * - This pool keeps one WebSocket per CDP target, multiplexes requests using * monotonic message IDs, caches `Runtime.enable` per connection, and routes * responses back to the right caller through a pendingMessages map. * * Reconnection policy: callers retry on failure. The pool removes a broken * connection from its cache so the *next* `getConnection` opens a new socket. */ export declare class CdpConnectionPool { private static instance; /** * Storing `Promise` (not `PooledConnection`) prevents the * race where two concurrent callers both see the cache miss and each open a * WebSocket. The first caller writes the in-flight Promise; the second * caller awaits the same Promise. */ private connections; static getInstance(): CdpConnectionPool; /** * Reset the singleton. ONLY used by tests — production code never calls this. * @internal */ static resetForTesting(): void; /** * Get (or create) the pooled connection for a target. * Concurrent calls for the same target share the same in-flight Promise. */ getConnection(target: DevToolsTarget): Promise; /** * Send any CDP method on the pooled connection. * @returns The CDP `result` payload (caller decides shape). * @example * pool.send(target, 'Input.dispatchMouseEvent', { type: 'mousePressed', x, y }) */ send(target: DevToolsTarget, method: string, params?: Record, options?: CdpSendOptions): Promise; /** * Convenience wrapper around `Runtime.evaluate` with sensible defaults * (`returnByValue: true`, `awaitPromise: false`). */ evaluate(target: DevToolsTarget, expression: string, options?: CdpEvaluateOptions): Promise; /** * Ensure a CDP domain (`Runtime`, `Console`, `Page`, ...) is enabled on the * connection. Idempotent: subsequent calls for the same domain are no-ops. */ ensureDomainEnabled(conn: PooledConnection, domain: string): Promise; /** Close a single connection (e.g. after the underlying target disappears). */ close(targetId: string): Promise; /** Close every pooled connection. Used on shutdown / test teardown. */ closeAll(): Promise; private openConnection; private sendOnConnection; private dispatchMessage; private handleConnectionClosed; private terminateConnection; } export {};