{"id":13804359,"url":"https://github.com/TracerBench/chrome-debugging-client","last_synced_at":"2025-05-13T17:32:05.920Z","repository":{"id":38291077,"uuid":"50677750","full_name":"TracerBench/chrome-debugging-client","owner":"TracerBench","description":"An async / await friendly debugging client for chrome","archived":false,"fork":false,"pushed_at":"2023-07-18T20:41:28.000Z","size":2907,"stargazers_count":134,"open_issues_count":16,"forks_count":19,"subscribers_count":10,"default_branch":"master","last_synced_at":"2024-10-28T21:04:57.217Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-2-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/TracerBench.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2016-01-29T17:11:11.000Z","updated_at":"2024-07-11T13:15:46.000Z","dependencies_parsed_at":"2024-01-07T09:39:33.745Z","dependency_job_id":"fb129756-f268-40d8-beb8-ded349cd79b1","html_url":"https://github.com/TracerBench/chrome-debugging-client","commit_stats":null,"previous_names":["krisselden/chrome-debugging-client"],"tags_count":33,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TracerBench%2Fchrome-debugging-client","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TracerBench%2Fchrome-debugging-client/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TracerBench%2Fchrome-debugging-client/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TracerBench%2Fchrome-debugging-client/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/TracerBench","download_url":"https://codeload.github.com/TracerBench/chrome-debugging-client/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225247858,"owners_count":17444127,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-04T01:00:46.402Z","updated_at":"2024-11-18T20:31:51.316Z","avatar_url":"https://github.com/TracerBench.png","language":"TypeScript","funding_links":[],"categories":["Chrome DevTools Protocol"],"sub_categories":["Libraries for driving the protocol (or a layer above)"],"readme":"# chrome-debugging-client\n\n[![Build Status](https://travis-ci.org/tracerbench/chrome-debugging-client.svg?branch=master)](https://travis-ci.org/tracerbench/chrome-debugging-client)\n[![npm](https://img.shields.io/npm/v/chrome-debugging-client.svg)](https://www.npmjs.com/package/chrome-debugging-client)\n[![install size](https://packagephobia.now.sh/badge?p=chrome-debugging-client)](https://packagephobia.now.sh/result?p=chrome-debugging-client)\n\nAn async/await friendly Chrome debugging client with TypeScript support,\ndesigned with automation in mind.\n\n## Table of Contents\n\n*   [Features](#features)\n\n*   [Examples](#examples)\n\n    *   [Print URL as PDF](#print-url-as-pdf)\n    *   [Node Debugging](#node-debugging)\n\n## Features\n\n*   Promise API for async/await (most debugger commands are meant to be sequential).\n*   TypeScript support and uses \"devtools-protocol\" types, allowing you to pick a protocol version.\n*   Launches Chrome with a new temp user data folder so Chrome launches an isolated instance.\n    (regardless if you already have Chrome open).\n*   Opens Chrome with a pipe message transport to the browser connection and supports\n    attaching flattened session connections to targets.\n*   Supports cancellation in a way that avoids unhandled rejections, and allows you to add combine\n    additional cancellation concerns.\n*   Supports seeing protocol debug messages with `DEBUG=chrome-debugging-client:*`\n*   Use with race-cancellation library to add timeouts or other cancellation concerns to tasks\n    using the connection.\n*   The library was designed to be careful about not floating promises (promises are\n    chained immediately after being created, combining concurrent promises with all\n    or race), this avoids unhandled rejections.\n\n## Examples\n\n### Print URL as PDF\n\n```js file=examples/printToPDF.js\n#!/usr/bin/env node\nconst { writeFileSync } = require(\"fs\");\nconst { spawnChrome } = require(\"chrome-debugging-client\");\n\n/**\n * Print a url to a PDF file.\n * @param url {string}\n * @param file {string}\n */\nasync function printToPDF(url, file) {\n  const chrome = spawnChrome({ headless: true });\n  try {\n    const browser = chrome.connection;\n\n    // we create with a target of about:blank so that we can\n    // setup Page events before navigating to url\n    const { targetId } = await browser.send(\"Target.createTarget\", {\n      url: \"about:blank\",\n    });\n\n    const page = await browser.attachToTarget(targetId);\n    // enable events for Page domain\n    await page.send(\"Page.enable\");\n\n    // concurrently wait until load and navigate\n    await Promise.all([\n      page.until(\"Page.loadEventFired\"),\n      page.send(\"Page.navigate\", { url }),\n    ]);\n\n    const { data } = await page.send(\"Page.printToPDF\");\n\n    writeFileSync(file, data, \"base64\");\n\n    // attempt graceful close\n    await chrome.close();\n  } finally {\n    // kill process if hasn't exited\n    await chrome.dispose();\n  }\n\n  console.log(`${url} written to ${file}`);\n}\n\nif (process.argv.length \u003c 4) {\n  console.log(`usage: printToPDF.js url file`);\n  console.log(\n    `example: printToPDF.js https://en.wikipedia.org/wiki/Binomial_coefficient Binomial_coefficient.pdf`,\n  );\n  process.exit(1);\n}\n\nprintToPDF(process.argv[2], process.argv[3]).catch((err) =\u003e {\n  console.log(\"print failed %o\", err);\n});\n\n```\n\n### Node Debugging\n\n```js file=examples/nodeDebug.js\n#!/usr/bin/env node\nconst { spawnWithWebSocket } = require(\"chrome-debugging-client\");\n\nasync function main() {\n  const script = `const obj = {\n    hello: \"world\",\n  };\n  console.log(\"end\");\n  `;\n\n  // start node requesting it break on start at debug port that\n  // is available\n  const node = await spawnWithWebSocket(process.execPath, [\n    // node will pick an available port and wait for debugger\n    \"--inspect-brk=0\",\n    \"-e\",\n    script,\n  ]);\n\n  async function doDebugging() {\n    const { connection } = node;\n\n    // Setup console api handler\n    connection.on(\"Runtime.consoleAPICalled\", ({ type, args }) =\u003e {\n      console.log(`console.${type}: ${JSON.stringify(args)}`);\n    });\n\n    // We requested Node to break on start, so we runIfWaitingForDebugger\n    // and wait for it to break at the start of our script.\n    // These commands must be sent concurrently with\n    // the pause event setup.\n    const [\n      {\n        callFrames: [\n          {\n            location: { scriptId },\n          },\n        ],\n        reason,\n      },\n    ] = await Promise.all([\n      connection.until(\"Debugger.paused\"),\n      connection.send(\"Debugger.enable\"),\n      connection.send(\"Runtime.enable\"),\n      connection.send(\"Runtime.runIfWaitingForDebugger\"),\n    ]);\n    // Right now we are paused at the start of the script\n    console.log(`paused reason: ${reason}`); //= paused: Break on start\n    console.log(`set breakpoint on line 3`);\n    await connection.send(\"Debugger.setBreakpoint\", {\n      location: {\n        lineNumber: 3,\n        scriptId,\n      },\n    });\n\n    console.log(\"resume and wait for next paused event\");\n    const [breakpoint] = await Promise.all([\n      connection.until(\"Debugger.paused\"),\n      connection.send(\"Debugger.resume\"),\n    ]);\n    const {\n      callFrames: [{ location, callFrameId }],\n    } = breakpoint;\n    console.log(`paused at line ${location.lineNumber}`);\n\n    console.log(\"evaluate `obj`\");\n    const { result } = await connection.send(\"Debugger.evaluateOnCallFrame\", {\n      callFrameId,\n      expression: \"obj\",\n      returnByValue: true,\n    });\n    console.log(JSON.stringify(result.value)); //= {\"hello\":\"world\"}\n\n    console.log(\"resume and wait for execution context to be destroyed\");\n    await Promise.all([\n      connection.until(\"Runtime.executionContextDestroyed\"),\n      connection.send(\"Debugger.resume\"),\n    ]);\n  }\n\n  try {\n    await doDebugging();\n\n    // Node is still alive here and waiting for the debugger to disconnect\n    console.log(\"close websocket\");\n    node.close();\n\n    // Node should exit on its own after the websocket closes\n    console.log(\"wait for exit\");\n    await node.waitForExit();\n\n    console.log(\"node exited\");\n  } finally {\n    // kill process if still alive\n    await node.dispose();\n  }\n}\n\nmain().catch((err) =\u003e {\n  console.log(\"print failed %o\", err);\n});\n\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FTracerBench%2Fchrome-debugging-client","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FTracerBench%2Fchrome-debugging-client","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FTracerBench%2Fchrome-debugging-client/lists"}