### Install devtools-protocol with npm Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/getting-started.md Install the package using npm. This is the standard way to add Node.js dependencies. ```bash npm install devtools-protocol ``` -------------------------------- ### Complete Debugger Client Example Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/getting-started.md A comprehensive example demonstrating a simple debugger client. It includes setting up listeners for script parsing, pause, and resume events, enabling the debugger, and setting breakpoints. ```typescript import { Protocol } from 'devtools-protocol'; import { ProtocolProxyApi } from 'devtools-protocol/types/protocol-proxy-api'; class SimpleDebugger { private breakpoints = new Map(); constructor(private api: ProtocolProxyApi.DebuggerApi) { this.setupListeners(); } private setupListeners(): void { this.api.on('scriptParsed', this.onScriptParsed.bind(this)); this.api.on('paused', this.onPaused.bind(this)); this.api.on('resumed', this.onResumed.bind(this)); } async start(): Promise { // Enable debugger const response = await this.api.enable(); console.log('Debugger enabled:', response.debuggerId); // Set pause on all exceptions await this.api.setPauseOnExceptions({ state: Protocol.Debugger.SetPauseOnExceptionsRequestState.All, }); } async setBreakpoint( scriptId: string, lineNumber: number, condition?: string ): Promise { const response = await this.api.setBreakpoint({ location: { scriptId, lineNumber }, condition, }); const key = `${scriptId}:${lineNumber}`; this.breakpoints.set(key, response.breakpointId); console.log(`Breakpoint set at ${key}: ${response.breakpointId}`); return response.breakpointId; } async removeBreakpoint(breakpointId: Protocol.Debugger.BreakpointId): Promise { await this.api.removeBreakpoint({ breakpointId }); console.log(`Breakpoint removed: ${breakpointId}`); } private onScriptParsed(event: Protocol.Debugger.ScriptParsedEvent): void { console.log(`πŸ“œ Script parsed: ${event.url}`); } private onPaused(event: Protocol.Debugger.PausedEvent): void { console.log(` ⏸️ Paused: ${event.reason}`); console.log('Call stack:'); event.callFrames.forEach((frame, i) => { const loc = `${frame.location.lineNumber}:${frame.location.columnNumber}`; console.log(` ${i}. ${frame.functionName} at ${loc}`); }); } private onResumed(): void { console.log('▢️ Resumed\n'); } } // Usage with a protocol transport async function runDebugger(protocolApi: ProtocolProxyApi.DebuggerApi): Promise { const debugger = new SimpleDebugger(protocolApi); await debugger.start(); // Set breakpoint on first script debugger.api.on('scriptParsed', async (event) => { if (event.url.includes('app.js')) { await debugger.setBreakpoint(event.scriptId, 10); } }); } ``` -------------------------------- ### Start Screencast Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/api-reference/page-domain.md Initiates the capture of screenshots from the page. Allows configuration of format, quality, and dimensions. ```typescript startScreencast(params?: StartScreencastRequest): Promise; ``` ```typescript export interface StartScreencastRequest { format?: ScreencastFormat; quality?: integer; maxWidth?: integer; maxHeight?: integer; everyNthFrame?: integer; } ``` -------------------------------- ### Install devtools-protocol with yarn Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/README.md Use this command to install the devtools-protocol package using yarn. This package provides only types and requires a separate transport layer. ```bash yarn add devtools-protocol ``` -------------------------------- ### Install devtools-protocol with npm Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/README.md Use this command to install the devtools-protocol package using npm. This package provides only types and requires a separate transport layer. ```bash npm install devtools-protocol ``` -------------------------------- ### Protocol Command Mapping Examples Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/api-reference/protocol-mapping.md Shows the pattern for mapping protocol command names to their request and response types. ```typescript 'Debugger.enable': [Protocol.Debugger.EnableRequest, Protocol.Debugger.EnableResponse]; 'Debugger.setBreakpoint': [Protocol.Debugger.SetBreakpointRequest, Protocol.Debugger.SetBreakpointResponse]; 'Runtime.evaluate': [Protocol.Runtime.EvaluateRequest, Protocol.Runtime.EvaluateResponse]; 'Network.setRequestInterception': [Protocol.Network.SetRequestInterceptionRequest, void]; 'DOM.getDocument': [Protocol.DOM.GetDocumentRequest, Protocol.DOM.GetDocumentResponse]; ``` -------------------------------- ### Get Document Root Node Usage Example Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/api-reference/dom-domain.md Example of how to call getDocument and access properties of the returned root node, such as its URL and child count. ```typescript const response = await api.DOM.getDocument(); const documentNode = response.root; console.log(`Document URL: ${documentNode.documentURL}`); console.log(`Children: ${documentNode.childNodeIds?.length || 0}`); ``` -------------------------------- ### Resource Timing Usage Example Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/types.md Demonstrates how to access and log network timing metrics like DNS, TCP, TLS, and TTFB from a response. ```typescript api.Network.on('responseReceived', (event) => { if (event.response.timing) { const timing = event.response.timing; const dns = timing.dnsEnd - timing.dnsStart; const tcp = timing.connectEnd - timing.connectStart; const tls = timing.sslEnd - timing.sslStart; const ttfb = timing.receiveHeadersStart - timing.sendStart; console.log(`DNS: ${dns}ms, TCP: ${tcp}ms, TLS: ${tls}ms, TTFB: ${ttfb}ms`); } }); ``` -------------------------------- ### DOM Inspector Usage Example Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/api-reference/dom-domain.md An example demonstrating how to use the DOM API to inspect and interact with the Document Object Model, including enabling the domain, retrieving the page structure, and highlighting elements. ```APIDOC ## Usage Example: DOM Inspector ```typescript import { Protocol } from 'devtools-protocol'; import { ProtocolProxyApi } from 'devtools-protocol/types/protocol-proxy-api'; class DOMInspector { constructor(private api: ProtocolProxyApi.DOMApi) { this.setupEventHandlers(); } private setupEventHandlers(): void { this.api.on('childNodeInserted', this.onChildNodeInserted.bind(this)); this.api.on('childNodeRemoved', this.onChildNodeRemoved.bind(this)); this.api.on('attributeModified', this.onAttributeModified.bind(this)); } async start(): Promise { await this.api.enable(); } async getPageStructure(): Promise { const response = await this.api.getDocument(); this.printNode(response.root, 0); } private printNode(node: Protocol.DOM.Node, depth: number): void { const indent = ' '.repeat(depth); if (node.nodeType === 1) { // Element let tag = `<${node.nodeName}`; if (node.attributes) { for (let i = 0; i < node.attributes.length; i += 2) { tag += ` ${node.attributes[i]} ="${node.attributes[i + 1]}"`; } } tag += '>'; console.log(`${indent}${tag}`); } else if (node.nodeType === 3) { // Text node const text = node.nodeValue?.trim(); if (text) { console.log(`${indent}#text: "${text}"`); } } else if (node.nodeType === 9) { // Document console.log(`${indent}#document`); } if (node.childNodeIds) { node.childNodeIds.forEach((childId) => { // Note: need to fetch child nodes separately }); } } async findElementByText(text: string): Promise { const doc = (await this.api.getDocument()).root; return this.searchForText(doc, text); } private async searchForText( node: Protocol.DOM.Node, text: string ): Promise { if (node.nodeType === 3 && node.nodeValue?.includes(text)) { if (node.parentNodeId) { return node.parentNodeId; } } if (node.childNodeIds) { for (const childId of node.childNodeIds) { const response = await this.api.describeNode({ nodeId: childId, }); const result = await this.searchForText(response.node, text); if (result) { return result; } } } return null; } async highlightElement(selector: string): Promise { const doc = (await this.api.getDocument()).root; const response = await this.api.querySelectorAll({ nodeId: doc.nodeId, selector, }); if (response.nodeIds.length > 0) { await this.api.highlightNode({ nodeId: response.nodeIds[0], highlightConfig: { showInfo: true, contentColor: { r: 255, g: 165, b: 0, a: 0.5 }, }, }); console.log(`Highlighted element matching: ${selector}`); } else { console.log(`No element found matching: ${selector}`); } } private onChildNodeInserted(event: Protocol.DOM.ChildNodeInsertedEvent): void { console.log(`Element inserted: ${event.node.nodeName}`); } private onChildNodeRemoved(event: Protocol.DOM.ChildNodeRemovedEvent): void { console.log(`Element removed: ${event.nodeId}`); } private onAttributeModified(event: Protocol.DOM.AttributeModifiedEvent): void { console.log(`Attribute modified: ${event.name}="${event.value}"`); } } // Usage // Assuming 'protocolApi' is an instance of ProtocolProxyApi // const inspector = new DOMInspector(protocolApi.DOM); // await inspector.start(); // await inspector.getPageStructure(); // await inspector.highlightElement('.main-content > p'); ``` ``` -------------------------------- ### Protocol Event Mapping Examples Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/api-reference/protocol-mapping.md Illustrates the pattern for mapping specific protocol event names to their corresponding event types. ```typescript 'Console.messageAdded': [Protocol.Console.MessageAddedEvent]; 'Debugger.paused': [Protocol.Debugger.PausedEvent]; 'Debugger.resumed': []; // No parameters 'Network.requestWillBeSent': [Protocol.Network.RequestWillBeSentEvent]; 'Page.frameNavigated': [Protocol.Page.FrameNavigatedEvent]; 'Runtime.consoleAPICalled': [Protocol.Runtime.ConsoleAPICalledEvent]; ``` -------------------------------- ### Debugger Paused Event Listener Example Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/api-reference/debugger-domain.md Example of how to listen for the 'paused' event and log details about the pause reason and call stack. ```typescript api.Debugger.on('paused', (event) => { console.log(`Paused due to: ${event.reason}`); event.callFrames.forEach((frame, i) => { console.log(`Frame ${i}: ${frame.functionName} at line ${frame.location.lineNumber}`); }); }); ``` -------------------------------- ### Optional Fields Example: PropertyDescriptor Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/overview.md Demonstrates the use of optional fields marked with '?' in an interface, such as 'value', 'get', and 'set' in PropertyDescriptor. ```typescript interface PropertyDescriptor { name: string; value?: RemoteObject; // optional get?: RemoteObject; // optional set?: RemoteObject; // optional } ``` -------------------------------- ### Request/Response Pair Example: Set Breakpoint Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/overview.md Illustrates the Request and Response interfaces for the 'setBreakpoint' command, showing parameters and return values. ```typescript // Request with parameters interface SetBreakpointRequest { location: Location; condition?: string; logMessage?: string; } // Response with result fields interface SetBreakpointResponse { breakpointId: BreakpointId; actualLocation: Location; } ``` -------------------------------- ### Complete Debugger Session Example Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/README.md Demonstrates a full debugger session, including enabling domains, navigating, setting breakpoints, listening for pauses, evaluating expressions, and resuming execution. Requires the devtools-protocol package and a transport layer. ```typescript import { Protocol } from 'devtools-protocol'; import { ProtocolProxyApi } from 'devtools-protocol/types/protocol-proxy-api'; class DebugSession { constructor(private api: ProtocolProxyApi.ProtocolApi) {} async start() { // Enable domains await this.api.Page.enable(); await this.api.Debugger.enable(); await this.api.Runtime.enable(); // Navigate await this.api.Page.navigate({ url: 'https://example.com' }); // Wait for script const scriptParsed = await new Promise((resolve) => { this.api.Debugger.on('scriptParsed', resolve); }); // Set breakpoint const bp = await this.api.Debugger.setBreakpoint({ location: { scriptId: scriptParsed.scriptId, lineNumber: 10, }, }); // Listen for pause this.api.Debugger.on('paused', this.onPaused.bind(this)); } private async onPaused(event: Protocol.Debugger.PausedEvent) { console.log(`Paused: ${event.reason}`); event.callFrames.forEach((frame) => { console.log(` ${frame.functionName} at ${frame.location.lineNumber}`); }); // Evaluate expression const result = await this.api.Debugger.evaluateOnCallFrame({ callFrameId: event.callFrames[0].callFrameId, expression: 'Math.max(1, 2, 3)', returnByValue: true, }); console.log('Expression result:', result.result.value); // Resume await this.api.Debugger.resume({}); } } ``` -------------------------------- ### Using Protocol Mapping for Event Handlers Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/overview.md Example of using ProtocolMapping.Events to define a type for a generic event handler. ```typescript import { ProtocolMapping } from 'devtools-protocol/types/protocol-mapping'; type EventMap = ProtocolMapping.Events; const event: EventMap['Debugger.paused'] = [pausedEvent]; ``` -------------------------------- ### DOM Inspector Class Example Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/api-reference/dom-domain.md A comprehensive TypeScript example demonstrating how to use the DOM domain API to inspect and interact with the Document Object Model. This class sets up event handlers for DOM changes and provides methods to retrieve page structure, find elements by text, and highlight elements. ```typescript import { Protocol } from 'devtools-protocol'; import { ProtocolProxyApi } from 'devtools-protocol/types/protocol-proxy-api'; class DOMInspector { constructor(private api: ProtocolProxyApi.DOMApi) { this.setupEventHandlers(); } private setupEventHandlers(): void { this.api.on('childNodeInserted', this.onChildNodeInserted.bind(this)); this.api.on('childNodeRemoved', this.onChildNodeRemoved.bind(this)); this.api.on('attributeModified', this.onAttributeModified.bind(this)); } async start(): Promise { await this.api.enable(); } async getPageStructure(): Promise { const response = await this.api.getDocument(); this.printNode(response.root, 0); } private printNode(node: Protocol.DOM.Node, depth: number): void { const indent = ' '.repeat(depth); if (node.nodeType === 1) { // Element let tag = `<${node.nodeName}`; if (node.attributes) { for (let i = 0; i < node.attributes.length; i += 2) { tag += ` ${node.attributes[i]}="${node.attributes[i + 1]}"`; } } tag += '>'; console.log(`${indent}${tag}`); } else if (node.nodeType === 3) { // Text node const text = node.nodeValue?.trim(); if (text) { console.log(`${indent}#text: "${text}"`); } } else if (node.nodeType === 9) { // Document console.log(`${indent}#document`); } if (node.childNodeIds) { node.childNodeIds.forEach((childId) => { // Note: need to fetch child nodes separately }); } } async findElementByText(text: string): Promise { const doc = (await this.api.getDocument()).root; return this.searchForText(doc, text); } private async searchForText( node: Protocol.DOM.Node, text: string ): Promise { if (node.nodeType === 3 && node.nodeValue?.includes(text)) { if (node.parentNodeId) { return node.parentNodeId; } } if (node.childNodeIds) { for (const childId of node.childNodeIds) { const response = await this.api.describeNode({ nodeId: childId, }); const result = await this.searchForText(response.node, text); if (result) { return result; } } } return null; } async highlightElement(selector: string): Promise { const doc = (await this.api.getDocument()).root; const response = await this.api.querySelectorAll({ nodeId: doc.nodeId, selector, }); if (response.nodeIds.length > 0) { await this.api.highlightNode({ nodeId: response.nodeIds[0], highlightConfig: { showInfo: true, contentColor: { r: 255, g: 165, b: 0, a: 0.5 }, }, }); console.log(`Highlighted element matching: ${selector}`); } else { console.log(`No element found matching: ${selector}`); } } private onChildNodeInserted(event: Protocol.DOM.ChildNodeInsertedEvent): void { console.log(`Element inserted: ${event.node.nodeName}`); } private onChildNodeRemoved(event: Protocol.DOM.ChildNodeRemovedEvent): void { console.log(`Element removed: ${event.nodeId}`); } private onAttributeModified(event: Protocol.DOM.AttributeModifiedEvent): void { console.log(`Attribute modified: ${event.name}="${event.value}"`); } } // Usage const inspector = new DOMInspector(protocolApi.DOM); await inspector.start(); await inspector.getPageStructure(); await inspector.highlightElement('.main-content > p'); ``` -------------------------------- ### Protocol Namespace Structure Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/api-reference/protocol-namespace.md The Protocol namespace uses nested namespaces to organize different domains. This example shows the basic structure with examples of Debugger, Runtime, and DOM domains. ```typescript export namespace Protocol { export type integer = number; export namespace Debugger { ... } export namespace Runtime { ... } export namespace DOM { ... } // ... 53 more domains } ``` -------------------------------- ### Protocol Namespace Example Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/README.md Use the Protocol Namespace for type checking, documentation, and creating protocol objects. It provides direct type references for protocol commands and events. ```typescript import { Protocol } from 'devtools-protocol'; const location: Protocol.Debugger.Location = { scriptId: 'script-1', lineNumber: 42, }; ``` -------------------------------- ### Network Monitor Class with Event Handlers Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/api-reference/network-domain.md A comprehensive example demonstrating a NetworkMonitor class that sets up event handlers for various network events like request initiation, response, loading completion, and failures. It also includes functionality to intercept XHR requests. ```typescript import { Protocol } from 'devtools-protocol'; import { ProtocolProxyApi } from 'devtools-protocol/types/protocol-proxy-api'; class NetworkMonitor { private requestMap = new Map(); constructor(private api: ProtocolProxyApi.NetworkApi) { this.setupEventHandlers(); } private setupEventHandlers(): void { this.api.on('requestWillBeSent', this.onRequestWillBeSent.bind(this)); this.api.on('responseReceived', this.onResponseReceived.bind(this)); this.api.on('loadingFinished', this.onLoadingFinished.bind(this)); this.api.on('loadingFailed', this.onLoadingFailed.bind(this)); } async start(): Promise { await this.api.enable(); await this.api.setCacheDisabled({ cacheDisabled: true }); } async interceptXHR(): Promise { await this.api.setRequestInterception({ patterns: [{ urlPattern: '*/api/*' }], }); this.api.on('requestIntercepted', this.onRequestIntercepted.bind(this)); } private onRequestWillBeSent(event: Protocol.Network.RequestWillBeSentEvent): void { this.requestMap.set(event.requestId, event.request); console.log(`β†’ ${event.request.method} ${event.request.url}`); } private onResponseReceived(event: Protocol.Network.ResponseReceivedEvent): void { console.log(`← ${event.response.status} ${event.response.mimeType}`); } private async onLoadingFinished(event: Protocol.Network.LoadingFinishedEvent): Promise { console.log(`βœ“ Finished (${event.encodedDataLength} bytes)`); const body = await this.api.getResponseBody({ requestId: event.requestId }); console.log('Response:', body.body.substring(0, 100)); } private onLoadingFailed(event: Protocol.Network.LoadingFailedEvent): void { console.error(`βœ— Failed: ${event.errorText}`); } private async onRequestIntercepted(event: Protocol.Network.RequestInterceptedEvent): Promise { console.log(`πŸ›‘ Intercepted: ${event.request.method} ${event.request.url}`); // Modify headers const newHeaders = { ...event.request.headers, 'X-Intercepted': 'true', }; await this.api.continueInterceptedRequest({ interceptionId: event.interceptionId, headers: newHeaders, }); } } // Usage const monitor = new NetworkMonitor(protocolApi.Network); await monitor.start(); await monitor.interceptXHR(); ``` -------------------------------- ### Implementing a CDP Client with DebuggerApi Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/api-reference/protocol-proxy-api.md This snippet shows how to create a client for the Debugger API. It includes setting up event listeners for 'paused' and 'resumed' events, and a method to set breakpoints. Ensure you have 'devtools-protocol' installed. ```typescript import { ProtocolProxyApi } from 'devtools-protocol/types/protocol-proxy-api'; import { Protocol } from 'devtools-protocol'; class DebuggerClient { constructor(private api: ProtocolProxyApi.DebuggerApi) { this.api.on('paused', this.handlePause.bind(this)); this.api.on('resumed', this.handleResume.bind(this)); } async setBreakpoint(location: Protocol.Debugger.Location): Promise { const response = await this.api.setBreakpoint({ location }); return response.breakpointId; } private handlePause(event: Protocol.Debugger.PausedEvent): void { console.log('Debugger paused:', event.reason); event.callFrames.forEach((frame, index) => { console.log(`Frame ${index}: ${frame.functionName} at ${frame.location.lineNumber}:${frame.location.columnNumber}`); }); } private handleResume(): void { console.log('Debugger resumed'); } } ``` -------------------------------- ### RemoteObject Usage Example Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/api-reference/runtime-domain.md Illustrates how to construct a RemoteObject, typically used for representing remote JavaScript objects like arrays. ```typescript const remoteObj: Protocol.Runtime.RemoteObject = { type: 'object', className: 'Array', objectId: 'obj-123', preview: { ... }, }; ``` -------------------------------- ### Using Proxy API for Debugger Client Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/overview.md Example of a DebuggerClient class that uses the ProtocolProxyApi.DebuggerApi to set breakpoints. ```typescript import { ProtocolProxyApi } from 'devtools-protocol/types/protocol-proxy-api'; import { Protocol } from 'devtools-protocol'; class DebuggerClient { constructor(private api: ProtocolProxyApi.DebuggerApi) {} async setBreakpoint(location: Protocol.Debugger.Location) { return this.api.setBreakpoint({ location }); } } ``` -------------------------------- ### Working with Protocol Types: Breakpoint Location Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/overview.md Example of defining a breakpoint location using the Protocol.Debugger.Location type. ```typescript import { Protocol } from 'devtools-protocol'; // Use a breakpoint location const location: Protocol.Debugger.Location = { scriptId: 'script-1', lineNumber: 42, }; ``` -------------------------------- ### Control Execution Flow with Debugger Commands Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/getting-started.md Provides examples for stepping through code execution using stepInto, stepOver, and stepOut commands. These commands allow fine-grained control over the debugger's progression. ```typescript // Step through code await api.Debugger.stepInto({}); await api.Debugger.stepOver({}); await api.Debugger.stepOut(); ``` -------------------------------- ### Frame Started Loading Event Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/api-reference/page-domain.md Fired when a specific frame within the page begins its loading process. ```typescript on(event: 'frameStartedLoading', listener: (params: FrameStartedLoadingEvent) => void): void; ``` ```typescript export interface FrameStartedLoadingEvent { frameId: FrameId; } ``` -------------------------------- ### Working with Protocol Types: Remote Object Inspection Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/overview.md Example of defining a remote object for inspection using the Protocol.Runtime.RemoteObject type. ```typescript import { Protocol } from 'devtools-protocol'; // Inspect a remote object const obj: Protocol.Runtime.RemoteObject = { type: 'object', className: 'MyClass', objectId: 'obj-123', }; ``` -------------------------------- ### Enable Network Domain Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/api-reference/network-domain.md Enables the Network domain to start receiving network-related events. Optional parameters can configure buffer sizes. ```typescript enable(params?: EnableRequest): Promise; ``` -------------------------------- ### Listening to frameNavigated Event Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/api-reference/page-domain.md Example of how to listen for the 'frameNavigated' event and log the navigated frame's ID and URL. This is useful for tracking frame changes during page interactions. ```typescript api.Page.on('frameNavigated', (event) => { console.log(`Frame navigated: ${event.frame.id} to ${event.frame.url}`); }); ``` -------------------------------- ### TypeScript Event Serialization Example Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/api-reference/protocol-mapping.md Demonstrates how to serialize DevTools Protocol events using ProtocolMapping for type safety. This is useful for logging or routing events generically. ```typescript import { ProtocolMapping } from 'devtools-protocol/types/protocol-mapping'; class EventLogger { log( eventName: EventName, params: ProtocolMapping.Events[EventName][0] ): void { const json = JSON.stringify({ event: eventName, timestamp: Date.now(), params, }); console.log(json); } } const logger = new EventLogger(); logger.log('Debugger.paused', { callFrames: [], reason: 'other', }); ``` -------------------------------- ### Get Document by URL Request Interface Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/api-reference/dom-domain.md Defines the request parameters for retrieving a document by its URL. Requires a URL string. ```typescript export interface GetDocumentByUrlRequest { url: string; } ``` -------------------------------- ### Proxy API Example Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/README.md The Proxy API is ideal for implementing CDP clients and organizing domain-specific code. It offers a domain-based interface for accessing API methods and events. ```typescript import { ProtocolProxyApi } from 'devtools-protocol/types/protocol-proxy-api'; interface DebuggerClient { api: ProtocolProxyApi.DebuggerApi; } ``` -------------------------------- ### Get Document by URL Response Interface Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/api-reference/dom-domain.md Defines the response structure for retrieving a document by URL. Includes the root node of the document. ```typescript export interface GetDocumentByUrlResponse { root: Node; } ``` -------------------------------- ### Event Mapping Example Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/README.md Event Mapping is suitable for generic handlers, command dispatch, and protocol introspection. It allows for dynamic routing of protocol events. ```typescript import { ProtocolMapping } from 'devtools-protocol/types/protocol-mapping'; type Events = ProtocolMapping.Events; const event: Events['Debugger.paused'] = [pausedEvent]; ``` -------------------------------- ### Debugger Event Listener Signature Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/api-reference/protocol-proxy-api.md Example of how to register event listeners for protocol events. The `on` method takes an event name and a callback function that receives event parameters. ```typescript on(event: 'paused', listener: (params: Protocol.Debugger.PausedEvent) => void): void; on(event: 'resumed', listener: () => void): void; ``` -------------------------------- ### Create and Use a Full Protocol Session Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/api-reference/protocol-proxy-api.md Demonstrates how to create a ProtocolSession class that enables various domains, navigates to a URL, and sets breakpoints. It also shows how to handle debugger paused, frame navigated, and network request events. ```typescript import { ProtocolProxyApi } from 'devtools-protocol/types/protocol-proxy-api'; import { Protocol } from 'devtools-protocol'; class ProtocolSession { constructor(private api: ProtocolProxyApi.ProtocolApi) { this.setupListeners(); } private setupListeners(): void { this.api.Debugger.on('paused', (params) => this.onDebuggerPaused(params)); this.api.Page.on('frameNavigated', (params) => this.onFrameNavigated(params)); this.api.Network.on('requestWillBeSent', (params) => this.onNetworkRequest(params)); } async navigateAndDebug(url: string): Promise { // Enable domains await this.api.Page.enable(); await this.api.Debugger.enable(); await this.api.Network.enable({ recordType: 'all' }); // Navigate const response = await this.api.Page.navigate({ url }); console.log('Navigation started:', response); // Set breakpoint const script = await this.waitForScript(); const breakpoint = await this.api.Debugger.setBreakpoint({ location: { scriptId: script, lineNumber: 10, }, }); console.log('Breakpoint set:', breakpoint.breakpointId); } private onDebuggerPaused(event: Protocol.Debugger.PausedEvent): void { console.log('Paused:', event.reason); } private onFrameNavigated(event: Protocol.Page.FrameNavigatedEvent): void { console.log('Frame navigated:', event.frame.url); } private onNetworkRequest(event: Protocol.Network.RequestWillBeSentEvent): void { console.log('Network request:', event.request.url); } private async waitForScript(): Promise { return new Promise((resolve) => { this.api.Debugger.on('scriptParsed', (event) => { resolve(event.scriptId); }); }); } } ``` -------------------------------- ### StackTrace interface and exception handling Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/types.md Defines the structure for a StackTrace, including call frames and asynchronous parent information. Shows an example of how to access and log stack trace details when an exception is thrown. ```typescript export interface StackTrace { description?: string; // Stack trace description callFrames: CallFrame[]; // Stack frames from innermost to outermost parent?: StackTrace; // Async parent stack parentId?: StackTraceId; // Async parent stack ID } export type StackTraceId = { id: string; debuggerId?: Runtime.UniqueDebuggerId; }; ``` ```typescript // Exception with stack trace api.Runtime.on('exceptionThrown', (event) => { const details = event.exceptionDetails; console.log('Exception:', details.text); if (details.stackTrace) { details.stackTrace.callFrames.forEach((frame) => { console.log(` at ${frame.functionName} (${frame.location.lineNumber})`); }); } }); ``` -------------------------------- ### Get object properties Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/api-reference/runtime-domain.md Use to retrieve the properties of a given object. Set `ownProperties` to true to only get the object's own properties. ```typescript const response = await api.Runtime.getProperties({ objectId: myObjectId, ownProperties: true, }); response.result.forEach((prop) => { console.log(`${prop.name}: ${prop.value?.value}`); }); ``` -------------------------------- ### Generic Command Execution with ProtocolMapping Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/api-reference/protocol-mapping.md Illustrates type-safe command dispatch using ProtocolMapping.Commands for generic command execution. ```typescript import { ProtocolMapping } from 'devtools-protocol/types/protocol-mapping'; class CommandDispatcher { async dispatch( commandName: CommandName, params: ProtocolMapping.Commands[CommandName][0] ): Promise { // Send command to protocol handler const result = await this.send(commandName, params); return result; } private send(commandName: string, params: any): Promise { // Implementation return Promise.resolve({}); } } // Type-safe command dispatch const dispatcher = new CommandDispatcher(); const response = await dispatcher.dispatch('Debugger.setBreakpoint', { location: { scriptId: 'script-1', lineNumber: 10, }, }); // response type is inferred as Protocol.Debugger.SetBreakpointResponse ``` -------------------------------- ### startScreencast Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/api-reference/page-domain.md Initiates the capture of screenshots from the page, with options to specify format, quality, dimensions, and frame interval. ```APIDOC ## startScreencast ### Description Start capturing screenshots. ### Method POST ### Endpoint /Page/startScreencast ### Parameters #### Request Body - **format** (string) - Optional - Image format (jpeg, png) - **quality** (integer) - Optional - JPEG quality (0-100) - **maxWidth** (integer) - Optional - Max width - **maxHeight** (integer) - Optional - Max height - **everyNthFrame** (integer) - Optional - Capture every Nth frame ### Request Example { "format": "jpeg", "quality": 80 } ``` -------------------------------- ### enable Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/api-reference/network-domain.md Enables the Network domain, allowing for network activity monitoring and interception. Optional parameters can be provided to limit buffer sizes. ```APIDOC ## enable ### Description Enable the Network domain. ### Method POST ### Endpoint /Network.enable ### Parameters #### Request Body - **maxTotalBufferSize** (integer) - Optional - Max total buffer size - **maxResourceBufferSize** (integer) - Optional - Max per-resource buffer size - **maxPostDataSize** (integer) - Optional - Max POST data size ``` -------------------------------- ### Get Response Body Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/api-reference/network-domain.md Retrieves the body of a network response. The body is base64 encoded if it's binary data. ```typescript getResponseBody(params: GetResponseBodyRequest): Promise; ``` ```typescript export interface GetResponseBodyRequest { requestId: RequestId; } ``` ```typescript export interface GetResponseBodyResponse { body: string; base64Encoded: boolean; } ``` ```typescript const response = await api.Network.getResponseBody({ requestId: 'request-123', }); const body = response.base64Encoded ? Buffer.from(response.body, 'base64').toString() : response.body; console.log('Response body:', body); ``` -------------------------------- ### navigate Method Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/api-reference/page-domain.md Navigates the current page to a new URL. This method initiates the navigation process and returns a response indicating success or failure. ```APIDOC ## navigate ### Description Navigates the page to a new URL. ### Method `navigate` ### Parameters #### Request Body - **url** (string) - Required - The URL to navigate to. ### Response #### Success Response - **frameId** (FrameId) - The frame ID of the main frame that navigated. - **loaderId** (LoaderId) - The loader ID for this page. - **baseUrl** (string) - Optional: The URL of the page's base URL. #### Error Response - **errorText** (string) - Description of the error if navigation failed. ### Usage Example ```typescript const response = await api.Page.navigate({ url: 'https://example.com' }); if (response.errorText) { console.error(`Navigation failed: ${response.errorText}`); } ``` ``` -------------------------------- ### Enable Runtime Domain Command Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/api-reference/runtime-domain.md Enables the Runtime domain, allowing the client to interact with the JavaScript runtime. This command returns a promise that resolves when the domain is enabled. ```typescript enable(): Promise; ``` -------------------------------- ### Get Document Root Node Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/api-reference/dom-domain.md Retrieves the root node of the DOM document. The response includes the root node object. ```typescript getDocument(): Promise; ``` -------------------------------- ### Accessing and Using DevTools Protocol Types Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/api-reference/protocol-namespace.md Demonstrates how to import and use types from the DevTools Protocol namespace, including accessing specific domains, using cross-domain types, creating command requests, and utilizing enums. ```typescript import { Protocol } from 'devtools-protocol'; // Access a domain type DebuggerDomain = typeof Protocol.Debugger; // Use types from a domain const location: Protocol.Debugger.Location = { scriptId: 'script-123', lineNumber: 10, columnNumber: 5, }; // Use cross-domain types const remoteObject: Protocol.Runtime.RemoteObject = { type: 'object', className: 'MyClass', }; // Create a command request const request: Protocol.Debugger.SetBreakpointRequest = { location, }; // Use enums const scope: Protocol.Debugger.Scope = { type: Protocol.Debugger.ScopeType.Local, object: { type: 'object', }, }; ``` -------------------------------- ### Get Frame Tree Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/api-reference/page-domain.md Retrieves the hierarchical structure of frames within the page. Useful for understanding nested iframes and their content. ```typescript getFrameTree(): Promise; ``` ```typescript export interface GetFrameTreeResponse { frameTree: FrameResourceTree; } ``` ```typescript const response = await api.Page.getFrameTree(); const printFrames = (tree: Protocol.Page.FrameResourceTree, depth = 0) => { const indent = ' '.repeat(depth); console.log(`${indent}Frame: ${tree.frame.url}`); console.log(`${indent} Resources: ${tree.resources.length}`); tree.resources.forEach((res) => { console.log(`${indent} - ${res.url} (${res.type})`); }); tree.childFrames?.forEach((child) => printFrames(child, depth + 1)); }; printFrames(response.frameTree); ``` -------------------------------- ### ObjectGroup usage for bulk object management Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/types.md Illustrates how to organize objects into groups for bulk lifecycle management. Objects can be created within a specified group, and later, all objects in that group can be released simultaneously. ```typescript // Create objects in a group const response = await api.Runtime.evaluate({ expression: '[1,2,3]', objectGroup: 'myGroup', }); // Later, release all objects in group at once await api.Runtime.releaseObjectGroup({ objectGroup: 'myGroup' }); ``` -------------------------------- ### Importing devtools-protocol types Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/getting-started.md Import the main Protocol namespace, the proxy API, and event/command mappings from the devtools-protocol package. ```typescript // Import the main Protocol namespace import { Protocol } from 'devtools-protocol'; // Import proxy API (domain-based interface) import { ProtocolProxyApi } from 'devtools-protocol/types/protocol-proxy-api'; // Import event/command mappings import { ProtocolMapping } from 'devtools-protocol/types/protocol-mapping'; ``` -------------------------------- ### enable Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/api-reference/dom-domain.md Enables the DOM domain, allowing for DOM inspection and manipulation. This command should be called before any other DOM-related commands. ```APIDOC ## enable ### Description Enable the DOM domain. ### Method POST ### Endpoint Protocol.DOM.enable ### Parameters None ### Response #### Success Response (200) None ### Request Example ```json { "method": "DOM.enable" } ``` ### Response Example ```json { "id": 1, "result": {} } ``` ``` -------------------------------- ### Get Page Navigation History Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/api-reference/page-domain.md Retrieves the navigation history of the current page. Useful for understanding the user's browsing path. ```typescript getNavigationHistory(): Promise; ``` ```typescript export interface GetNavigationHistoryResponse { currentIndex: integer; entries: NavigationEntry[]; } ``` ```typescript const history = await api.Page.getNavigationHistory(); console.log('Current entry:', history.entries[history.currentIndex]); console.log('History length:', history.entries.length); ``` -------------------------------- ### Initiator Interface Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/types.md Represents information about what initiated a network request, including the type and optional stack trace or URL. ```typescript export interface Initiator { type: InitiatorType; stack?: StackTrace; url?: string; lineNumber?: number; columnNumber?: number; requestId?: RequestId; } ``` -------------------------------- ### Using Event/Command Mapping for Dynamic Routing Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/getting-started.md Employ ProtocolMapping for generic event handling and dynamic command dispatch. This is suitable for generic event handlers, command dispatch routers, and protocol introspection. ```typescript import { ProtocolMapping } from 'devtools-protocol/types/protocol-mapping'; type AllEvents = ProtocolMapping.Events; type AllCommands = ProtocolMapping.Commands; class EventRouter { route( eventName: EventName, params: AllEvents[EventName][0] ): void { console.log(`Received ${eventName}:`, params); } } // Type-safe usage const router = new EventRouter(); router.route('Debugger.paused', { callFrames: [], reason: 'other', }); // This would be a type error: // router.route('Debugger.paused', { invalid: 'data' }); ``` -------------------------------- ### Enable Runtime Domain and Evaluate JavaScript Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/getting-started.md Enables the Runtime domain and demonstrates evaluating a JavaScript expression. The `returnByValue` option ensures the result is returned directly, not as a remote object. ```typescript // Enable runtime domain await api.Runtime.enable(); // Evaluate JavaScript const result = await api.Runtime.evaluate({ expression: 'Math.max(1, 2, 3)', returnByValue: true, }); console.log('Result:', result.result.value); // 3 ``` -------------------------------- ### Get Child Nodes Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/api-reference/dom-domain.md Requests child nodes for a given DOM node. Supports fetching up to a specified depth and piercing shadow roots. ```typescript await api.DOM.requestChildNodes({ nodeId: someNodeId, depth: 5, pierce: true, }); ``` -------------------------------- ### Importing and Using DevTools Protocol Types Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/types.md Demonstrates how to import and use base and domain-specific types from the DevTools Protocol library in TypeScript, including using them in function signatures. ```typescript import { Protocol } from 'devtools-protocol'; // Access base types type MonotonicTime = Protocol.MonotonicTime; type RemoteObjectId = Protocol.RemoteObjectId; // Access domain-specific types type Location = Protocol.Debugger.Location; type RemoteObject = Protocol.Runtime.RemoteObject; type Request = Protocol.Network.Request; type Frame = Protocol.Page.Frame; // Use in function signatures async function inspectObject( api: ProtocolProxyApi.RuntimeApi, objectId: Protocol.RemoteObjectId ): Promise { const response = await api.getProperties({ objectId }); return response.result; } ``` -------------------------------- ### Get Element Attributes Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/api-reference/dom-domain.md Retrieve the attributes of an HTML element. The attributes are returned as a flat array of name-value pairs, which needs to be parsed into an object. ```typescript export interface GetAttributesRequest { nodeId: NodeId; } export interface GetAttributesResponse { attributes: string[]; } ``` ```typescript const response = await api.DOM.getAttributes({ nodeId }); const attrs: { [key: string]: string } = {}; // Parse flat array into object for (let i = 0; i < response.attributes.length; i += 2) { attrs[response.attributes[i]] = response.attributes[i + 1]; } console.log('Class:', attrs.class); console.log('ID:', attrs.id); ``` -------------------------------- ### Enable Domain Command Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/api-reference/protocol-proxy-api.md Enables a specific domain, allowing it to send notifications. This command takes no parameters and returns a Promise resolving to void. ```APIDOC ## enable ### Description Enables a specific domain to start receiving notifications. ### Method `enable` ### Parameters This command does not accept any parameters. ### Response #### Success Response (200) This command returns `void` upon successful execution. ### Error Handling Rejects with protocol errors if the domain cannot be enabled. ``` -------------------------------- ### Importing DevTools Protocol Types Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/api-reference/protocol-namespace.md Shows how to import specific types from the DevTools Protocol namespace to optimize module resolution and tree-shaking. ```typescript // Access types through the Protocol namespace import type { Protocol } from 'devtools-protocol'; ``` -------------------------------- ### Get Box Model Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/api-reference/dom-domain.md Retrieve the box model dimensions (content, padding, border, margin) for a given DOM node. This provides layout information. ```typescript export interface GetBoxModelRequest { nodeId: NodeId; } export interface GetBoxModelResponse { model: BoxModel; } export interface BoxModel { content: Quad; padding: Quad; border: Quad; margin: Quad; width: integer; height: integer; } export type Quad = number[]; // [x1, y1, x2, y2, x3, y3, x4, y4] ``` ```typescript const response = await api.DOM.getBoxModel({ nodeId }); const model = response.model; console.log(`Width: ${model.width}, Height: ${model.height}`); console.log(`Content: ${model.content.join(',')}`); ``` -------------------------------- ### Get Node For Location Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/api-reference/dom-domain.md Find the DOM node located at specific viewport coordinates. Useful for identifying elements under a mouse click or touch event. ```typescript export interface GetNodeForLocationRequest { x: integer; y: integer; includeUserAgentShadowDOM?: boolean; ignorePointerEventsNone?: boolean; } export interface GetNodeForLocationResponse { backendNodeId: BackendNodeId; frameId?: Page.FrameId; nodeId?: NodeId; } ``` ```typescript // Find element under mouse click const response = await api.DOM.getNodeForLocation({ x: event.clientX, y: event.clientY, }); console.log('Element at click:', response.backendNodeId); ``` -------------------------------- ### Evaluate an expression Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/api-reference/runtime-domain.md Use to evaluate a JavaScript expression in the global context. Set `returnByValue` to true to get the result as a primitive value instead of a RemoteObject. ```typescript const response = await api.Runtime.evaluate({ expression: 'Math.max(1, 2, 3)', returnByValue: true, }); console.log('Result:', response.result.value); // 3 ``` -------------------------------- ### Logging Full Exception Details Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/errors.md Implement a helper function to log comprehensive details about runtime exceptions, including type, location, and stack trace. ```typescript function logException(details: Protocol.Runtime.ExceptionDetails): void { console.group(`Exception: ${details.text}`); console.log(`Type: ${details.exception?.className || 'unknown'}`); console.log(`Location: ${details.url}:${details.lineNumber}:${details.columnNumber}`); if (details.stackTrace) { console.log('Stack:'); details.stackTrace.callFrames.forEach((frame) => { console.log(` ${frame.functionName} @ ${frame.location.lineNumber}`); }); } console.groupEnd(); } ``` -------------------------------- ### Avoid `any` Types in TypeScript Source: https://github.com/chromedevtools/devtools-protocol/blob/master/_autodocs/getting-started.md Demonstrates the difference between using `any` types and specific Protocol types for better type safety and autocompletion in TypeScript. ```typescript // ❌ Bad async function evaluateCode(api: any, code: string): Promise { return await api.Runtime.evaluate({ expression: code }); } // βœ… Good async function evaluateCode( api: ProtocolProxyApi.RuntimeApi, code: string ): Promise { return await api.Runtime.evaluate({ expression: code }); } ```