/** * CDP Connection Manager * Handles connection to Chrome DevTools Protocol (Chrome or Node.js) */ import type { BreakpointInfo, CallFrame, RuntimeType, ConsoleMessageCallback, DOMBreakpointInfo, DOMBreakpointType, EventListenerBreakpointInfo, XHRBreakpointInfo } from './types.js'; import type { SourceMapHandler } from './sourcemap-handler.js'; export declare class CDPManager { private client; private state; private scriptIdToUrl; private urlToScriptId; private pauseResolvers; private scriptWaitResolvers; private sourceMapHandler; private logpointLimitExceeded; private consoleMessageCallback; private domBreakpoints; private eventBreakpoints; private xhrBreakpoints; private advancedBpCounter; constructor(sourceMapHandler?: SourceMapHandler); /** * Set a callback to receive console messages from Runtime.consoleAPICalled * This is used for Node.js debugging where Puppeteer's page.on('console') isn't available */ setConsoleMessageCallback(callback: ConsoleMessageCallback | null): void; /** * Find script IDs by URL, with fallback matching strategies: * 1. Exact match * 2. Base URL match (strips query params) * 3. Filename/path suffix match (e.g., "click.js" matches "/controls/click.js") * * This allows breakpoints to work with partial URLs and across page reloads * Returns the most recently loaded script (highest scriptId) when multiple matches exist */ private findScriptIds; /** * Check if a script with the given URL (or matching suffix) is loaded * This is useful to detect Vite-style serving where .ts files are loaded directly */ isScriptLoaded(url: string): boolean; /** * Get the URL for a script by its ID */ getScriptUrl(scriptId: string): string | undefined; /** * Connect to a Chrome or Node.js debugger instance * @param host - The debugger host (default: localhost) * @param port - The debugger port (default: 9222) * @param targetId - Optional target ID to connect to a specific page/tab */ connect(host?: string, port?: number, targetId?: string): Promise; /** * Disconnect from the debugger */ disconnect(): Promise; /** * Check if connected */ isConnected(): boolean; /** * Check if currently paused at a breakpoint */ isPaused(): boolean; /** * Get the runtime type (chrome, node, or unknown) */ getRuntimeType(): RuntimeType; /** * Detect whether we're connected to Chrome/browser or Node.js * This detection happens by checking for browser-specific global objects */ private detectRuntimeType; /** * Set a breakpoint at a specific file and line */ setBreakpoint(url: string, lineNumber: number, columnNumber?: number, condition?: string): Promise; /** * Remove a breakpoint */ removeBreakpoint(breakpointId: string): Promise; /** * Get all active breakpoints */ getBreakpoints(): BreakpointInfo[]; /** * Get breakpoint counts (total, regular, logpoints) */ getBreakpointCounts(): { total: number; breakpoints: number; logpoints: number; }; /** * Wait for a script matching the given URL pattern to load * @param urlPattern - String (substring match) or RegExp to match against script URLs * @param timeout - Maximum time to wait in milliseconds (default: 10000) * @returns The URL of the matched script * @throws Error if timeout expires before script loads */ waitForScript(urlPattern: string | RegExp, timeout?: number): Promise; /** * Get list of all loaded scripts * @returns Array of script URLs */ getLoadedScripts(): string[]; /** * Check if a script matching the pattern is loaded * @param urlPattern - String (substring match) or RegExp * @returns The matched URL or null */ findLoadedScript(urlPattern: string | RegExp): string | null; /** * Synchronize breakpoint state with CDP's actual breakpoints * Use this to recover from state desynchronization */ syncBreakpoints(): Promise<{ synced: number; removed: number; }>; /** * Diagnose why a breakpoint failed to set (empty locations array) * Performs lazy validation to determine exact cause */ diagnoseBreakpointFailure(url: string, lineNumber: number): Promise<{ cause: 'script_not_found' | 'line_out_of_bounds' | 'line_not_executable'; message: string; scriptUrl: string; requestedLine: number; totalLines?: number; suggestion: string; }>; /** * Resume execution */ resume(): Promise; /** * Pause execution */ pause(): Promise; /** * Handle logpoint execution limit exceeded * This should be called by the LogpointExecutionTracker when a logpoint hits its limit */ handleLogpointLimitExceeded(metadata: { breakpointId: string; url: string; lineNumber: number; logMessage: string; executionCount: number; maxExecutions: number; logs: any[]; }): Promise; /** * Get information about the logpoint that exceeded its limit (if any) */ getLogpointLimitExceeded(): typeof this.logpointLimitExceeded; /** * Clear the logpoint limit exceeded state */ clearLogpointLimitExceeded(): void; /** * Step over (next line) */ stepOver(): Promise; /** * Step into function */ stepInto(): Promise; /** * Step out of function */ stepOut(): Promise; /** * Get current call stack */ getCallStack(): CallFrame[] | undefined; /** * Get variables for a specific call frame */ /** * Estimate token count for a value (rough approximation: ~4 chars per token) */ private estimateTokens; /** * Calculate effective token budget accounting for response overhead. * The final MCP response includes: * - Message template text (~100 tokens) * - JSON code block markers and wrapper (~50 tokens) * - JSON.stringify indentation adds ~30% to data size */ private calculateEffectiveBudget; getVariables(callFrameId: string, includeGlobal?: boolean, filter?: string, expandObjects?: boolean, maxDepth?: number, maxTokens?: number): Promise<{ data: any; totalCount: number; usedDepth: number; requestedDepth: number; responseType: 'full' | 'depth_reduced' | 'names_only' | 'counts_only'; filterInsufficient: boolean; }>; /** * Evaluate an expression in the current context */ evaluateExpression(expression: string, callFrameId?: string, expandObjects?: boolean, maxDepth?: number): Promise; /** * Get available variables at a specific source location * Useful for validating logpoint expressions */ getScopeVariablesAtLocation(url: string, lineNumber: number): Promise<{ variables: string[]; scopes: Array<{ type: string; variables: string[]; }>; } | null>; /** * Validate logpoint expressions at a specific location * Sets temp breakpoint, waits for execution, tests expressions * * @param url File URL (e.g., http://localhost:3000/app.js) * @param lineNumber Line number (1-based, will be converted to 0-based for CDP) * @param columnNumber Optional column number (1-based, will be converted to 0-based for CDP) * @param expressions Array of expressions to validate (e.g., ["user.name", "user.id"]) * @param timeout Max wait time for execution in milliseconds * @returns Validation results with pass/fail for each expression, plus available variables */ validateLogpointAtActualLocation(url: string, lineNumber: number, columnNumber: number | undefined, expressions: string[], timeout?: number): Promise<{ executed: boolean; allValid: boolean; results: Array<{ expression: string; valid: boolean; value?: any; error?: string; }>; availableVariables?: string[]; actualLocation?: { line: number; column: number; }; }>; /** * Search for the best location to set a logpoint by trying nearby lines/columns * Returns suggestions ranked by how many expressions are valid * * @param url File URL * @param lineNumber Desired line number (1-based) * @param columnNumber Desired column number (1-based, optional) * @param expressions Array of expressions to validate * @param searchRadius Number of lines to search in each direction (default: 2) * @param timeout Timeout per location test in milliseconds (default: 1000ms) * @returns Array of suggestions sorted by score (best first), max 3 results */ findBestLogpointLocation(url: string, lineNumber: number, columnNumber: number | undefined, expressions: string[], searchRadius?: number, timeout?: number): Promise>; /** * Get source code from a file at a specific line range */ getSourceCode(url: string, startLine?: number, endLine?: number): Promise<{ code: string; totalLines: number; hasSourceMap: boolean; }>; /** * Inject a clickable console link in the browser */ injectConsoleLink(url: string, lineNumber: number, message: string): Promise; /** * Get detailed information about current pause state */ getPausedInfo(): { paused: boolean; location?: any; callStack?: CallFrame[]; }; /** * Wait for debugger to pause (for race detection) * Returns a promise that resolves when debugger pauses, or rejects on timeout */ waitForPause(timeoutMs?: number): Promise; /** * Format a CDP RemoteObject value for display * @param value The CDP RemoteObject to format * @param expandObjects Whether to expand object/array contents (default: false for backward compatibility) * @param maxDepth Maximum depth for object expansion (default: 2) * @param currentDepth Current recursion depth (internal use) */ private formatValue; /** * Expand a CDP RemoteObject by its objectId * This is used to get full object details for console messages * @param objectId - The CDP object ID to expand * @param maxDepth - Maximum depth for nested object expansion (default: 2) */ expandObjectById(objectId: string, maxDepth?: number): Promise; /** * Get all loaded scripts */ getAllScripts(): Array<{ scriptId: string; url: string; }>; /** * Search within a specific script using regex */ searchInScript(scriptId: string, pattern: string, caseSensitive?: boolean, isRegex?: boolean): Promise>; /** * Get a specific line from a script by scriptId and line number * Returns the full line content (useful for getting full webpack eval lines) */ getScriptLine(scriptId: string, lineNumber: number): Promise; /** * Generate a unique ID for advanced breakpoints */ private generateAdvancedBpId; /** * Resolve a CSS selector to a CDP nodeId * @param selector - CSS selector to resolve * @returns nodeId for the element */ resolveSelector(selector: string): Promise; /** * Set a DOM breakpoint on a node * Pauses execution when the specified DOM mutation occurs * @param nodeId - The node ID from resolveSelector * @param type - Type of DOM change to break on * @param selector - Original CSS selector (for reference/display) */ setDOMBreakpoint(nodeId: number, type: DOMBreakpointType, selector: string): Promise; /** * Remove a DOM breakpoint by its ID */ removeDOMBreakpoint(breakpointId: string): Promise; /** * Get all DOM breakpoints */ getDOMBreakpoints(): DOMBreakpointInfo[]; /** * Set an event listener breakpoint * Pauses execution when the specified event fires * @param eventName - DOM event name (e.g., 'click', 'submit', 'input') * @param targetName - Optional EventTarget interface filter (e.g., 'HTMLInputElement') */ setEventListenerBreakpoint(eventName: string, targetName?: string): Promise; /** * Remove an event listener breakpoint by its ID */ removeEventListenerBreakpoint(breakpointId: string): Promise; /** * Get all event listener breakpoints */ getEventListenerBreakpoints(): EventListenerBreakpointInfo[]; /** * Set an XHR/Fetch breakpoint * Pauses execution when an XHR or Fetch request URL contains the pattern * @param urlPattern - URL substring to match */ setXHRBreakpoint(urlPattern: string): Promise; /** * Remove an XHR/Fetch breakpoint by its ID */ removeXHRBreakpoint(breakpointId: string): Promise; /** * Get all XHR/Fetch breakpoints */ getXHRBreakpoints(): XHRBreakpointInfo[]; } //# sourceMappingURL=cdp-manager.d.ts.map