CDP Client
src/cdp/client.ts exports CDPClient, the only thing in the extension that
talks to chrome.debugger. One instance exists per attached tab.
const client = new CDPClient(tabId);
await client.attach();
await client.navigate('https://example.com');
await client.detach();
Every method returns the same shape, so callers never have to guess whether something worked:
interface CDPResult<T = unknown> {
success: boolean;
data?: T;
error?: string;
}
Methods
| Method | CDP used | Notes |
|---|---|---|
attach() |
chrome.debugger.attach (v1.3) then DOM.enable, Page.enable, Runtime.enable, Log.enable |
Log.enable is what makes Log.entryAdded fire for the Console Logs tool |
detach() |
chrome.debugger.detach |
Safe to call when not attached |
send(method, params) |
chrome.debugger.sendCommand |
Returns an error result if not attached |
navigate(url) |
Page.navigate |
The caller validates and normalises the URL. Fails if the response carries an errorText (e.g. net::ERR_NAME_NOT_RESOLVED), then waits for document.readyState === 'complete' (10 s cap) before returning |
captureScreenshot(format) |
Page.captureScreenshot |
PNG, captureBeyondViewport: false |
click(x, y) |
Input.dispatchMouseEvent ×2 |
Raw press/release at viewport coordinates |
clickElement(selector) |
mixed | Bounding-box click, then element.click(), then focus + Enter |
type(text) |
Input.insertText |
Single insert, so no double-typing |
typeInElement(selector, text) |
mixed | Click to focus, clear, verify empty, insert, then verify the text landed |
scroll(dx, dy) |
Input.dispatchMouseEvent (mouseWheel) |
Returns the command's real result |
evaluate(expression) |
Runtime.evaluate |
returnByValue: true, awaitPromise: true; surfaces exceptionDetails.exception.description as the error, falling back to exceptionDetails.text |
isAttached() |
— | Local flag |
Design notes
- Failures are values, not exceptions. Nothing here throws past the caller,
and nothing returns
success: truefor a command that did not run. The background worker forwards the error text straight to the panel. clickElementdegrades in the open. If all three strategies fail it returnsAll click methods failed for: <selector>rather than reporting a click that never happened.typeInElementverifies the clear, and then the write. After clearing it re-reads.valueand forces it empty if content survived, so text is not appended to whatever was there. After inserting, it re-reads the element again and fails with an explanatory error if the text is not there —Input.insertTextreturns success at the protocol level even when the focused node accepts no text, so without this check the panel would report a write that never happened.navigatedoes not trustPage.navigate. The command resolves successfully for a failed load and reports the reason inerrorText, so that field is checked and turned into a failure. It then waits for the document to reachreadyState === 'complete'.evaluatesurfaces the useful message. For a thrown errorexceptionDetails.textis the literal string"Uncaught"; the real message and stack live onexceptionDetails.exception.description, which is what the panel is given.- Only four domains are enabled, matching the shipped tools exactly.
What it does not do
CDPClient has no methods for downloading, recording, network interception,
cookie access or any form of persistent monitoring. It sends commands, one at a
time, in response to a click in the panel.