chrome-cdp-manager 1.1.0 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -73,6 +73,41 @@ chrome-cdp stop
73
73
  | `stop` | Ask the running ChromeCDP instance to quit |
74
74
  | `browsers` | List supported browsers and which are installed |
75
75
 
76
+ ## Programmatic API
77
+
78
+ Beyond the CLI, the package exposes a small ES-module API (Node ≥ 22).
79
+
80
+ ```js
81
+ import { launch, CdpClient } from "chrome-cdp-manager";
82
+
83
+ // Ensure ChromeCDP is running (launches it if needed) and get its endpoint.
84
+ const { endpoint, config, launched } = await launch({ headless: false });
85
+
86
+ // Drive it with the built-in zero-dependency raw-CDP client...
87
+ const cdp = await CdpClient.connect(config.cdpPort);
88
+ ```
89
+
90
+ Also exported: `loadConfig`, `getLauncher`, `ensureBrowserRunning`, `probeCdp`,
91
+ `waitForCdp`, `openUrl`, `getPageHtml`, `closeBrowser`.
92
+
93
+ ### Playwright bridge (optional)
94
+
95
+ If you want Playwright's high-level page API, opt into the separate entry point.
96
+ `playwright` is an **optional peer dependency** — the core stays dependency-free.
97
+
98
+ ```js
99
+ import { connect } from "chrome-cdp-manager/playwright";
100
+
101
+ await using session = await connect({ headless: false, match: u => u.includes("bing.com") });
102
+ await session.page.goto("https://www.bing.com");
103
+ // `await using` detaches the CDP channel on scope exit; the browser keeps running.
104
+ ```
105
+
106
+ `connect()` resolves config, ensures the launcher + a running browser, connects
107
+ Playwright over CDP, and returns `{ browser, context, page, config }`. In
108
+ zero-install (npx) setups where Playwright can't be resolved automatically,
109
+ inject it: `connect({ chromium })`.
110
+
76
111
  ## Common options
77
112
 
78
113
  | Option | Description |
package/package.json CHANGED
@@ -1,8 +1,14 @@
1
1
  {
2
2
  "name": "chrome-cdp-manager",
3
- "version": "1.1.0",
3
+ "version": "1.2.1",
4
4
  "description": "Set up and drive a Chrome DevTools Protocol (CDP) instance on macOS or Windows through a dedicated launcher (consistent Dock/taskbar icon). Works with any Chromium-based browser — Chrome, Edge, Brave, Chromium, Vivaldi, Opera, Arc.",
5
5
  "type": "module",
6
+ "main": "./src/index.js",
7
+ "exports": {
8
+ ".": "./src/index.js",
9
+ "./playwright": "./src/playwright.js",
10
+ "./package.json": "./package.json"
11
+ },
6
12
  "bin": {
7
13
  "chrome-cdp": "bin/cli.js",
8
14
  "chrome-cdp-manager": "bin/cli.js"
@@ -42,5 +48,13 @@
42
48
  "license": "MIT",
43
49
  "dependencies": {
44
50
  "commander": "^12.1.0"
51
+ },
52
+ "peerDependencies": {
53
+ "playwright": "*"
54
+ },
55
+ "peerDependenciesMeta": {
56
+ "playwright": {
57
+ "optional": true
58
+ }
45
59
  }
46
60
  }
package/src/index.js ADDED
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Public entry point for chrome-cdp-manager.
3
+ *
4
+ * Re-exports the stable building blocks and adds {@link launch} — a one-call
5
+ * helper that resolves config, ensures the launcher exists, and starts the
6
+ * browser if it isn't already running. Stays dependency-free; the optional
7
+ * Playwright integration lives in the separate "chrome-cdp-manager/playwright"
8
+ * entry point so the core keeps its zero-heavy-dependency promise.
9
+ */
10
+ import { loadConfig } from "./config.js";
11
+ import { getLauncher } from "./launcher.js";
12
+ import { ensureBrowserRunning } from "./browser.js";
13
+
14
+ export { CdpClient, openUrl, getPageHtml, closeBrowser } from "./cdp.js";
15
+ export { loadConfig, computeDefaults, DEFAULTS } from "./config.js";
16
+ export { getLauncher } from "./launcher.js";
17
+ export { ensureBrowserRunning, probeCdp, waitForCdp } from "./browser.js";
18
+
19
+ /**
20
+ * Ensure a ChromeCDP instance is running and return its connection details.
21
+ *
22
+ * @param {object} [opts]
23
+ * @param {boolean} [opts.headless=false]
24
+ * @param {number} [opts.timeoutMs=30000] startup timeout in milliseconds.
25
+ * @param {object} [opts.config] overrides merged over the persisted config
26
+ * (e.g. `{ cdpPort, profileDir, browserPath }`).
27
+ * @returns {Promise<{ config: object, endpoint: string, launched: boolean, version: object }>}
28
+ */
29
+ export async function launch({ headless = false, timeoutMs = 30_000, config: overrides } = {}) {
30
+ const config = { ...loadConfig(), ...overrides };
31
+ getLauncher().ensure(config, { force: false });
32
+ const { launched, version } = await ensureBrowserRunning(config, { headless, timeoutMs });
33
+ return {
34
+ config,
35
+ endpoint: `http://127.0.0.1:${config.cdpPort}`,
36
+ launched,
37
+ version,
38
+ };
39
+ }
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Optional Playwright bridge for chrome-cdp-manager.
3
+ *
4
+ * Loaded only when you opt in via "chrome-cdp-manager/playwright", so the core
5
+ * package stays free of heavy dependencies. `playwright` is an OPTIONAL peer
6
+ * dependency: install it yourself, or inject it through the `chromium` option
7
+ * (handy for zero-install / npx setups where this module can't resolve
8
+ * Playwright on its own).
9
+ */
10
+ import { launch } from "./index.js";
11
+
12
+ /**
13
+ * Launch (or attach to) ChromeCDP and return a ready-to-drive Playwright page.
14
+ *
15
+ * @param {object} [opts]
16
+ * @param {boolean} [opts.headless=false]
17
+ * @param {(url: string) => boolean} [opts.match] pick an existing tab by URL;
18
+ * falls back to the first tab, then a fresh one.
19
+ * @param {number} [opts.timeoutMs=30000]
20
+ * @param {object} [opts.config] config overrides (see {@link launch}).
21
+ * @param {object} [opts.chromium] a Playwright `chromium` object to use
22
+ * instead of `import("playwright")` — for injected/zero-install
23
+ * setups.
24
+ * @returns {Promise<{ browser, context, page, config } & AsyncDisposable>}
25
+ * Dispose (or `await using`) detaches the CDP channel; the
26
+ * launcher-managed browser keeps running.
27
+ */
28
+ export async function connect({ headless = false, match, timeoutMs = 30_000, config: overrides, chromium } = {}) {
29
+ const { config, endpoint } = await launch({ headless, timeoutMs, config: overrides });
30
+
31
+ const pwChromium = chromium ?? (await importPlaywright()).chromium;
32
+ const browser = await pwChromium.connectOverCDP(endpoint);
33
+ const context = browser.contexts()[0] ?? (await browser.newContext());
34
+ const page =
35
+ (match && context.pages().find((p) => match(p.url()))) ??
36
+ context.pages()[0] ??
37
+ (await context.newPage());
38
+
39
+ if (headless) await unmaskHeadlessUserAgent(context, page);
40
+
41
+ return {
42
+ browser,
43
+ context,
44
+ page,
45
+ config,
46
+ async [Symbol.asyncDispose]() {
47
+ await browser.close();
48
+ },
49
+ };
50
+ }
51
+
52
+ async function importPlaywright() {
53
+ try {
54
+ return await import("playwright");
55
+ } catch {
56
+ throw new Error(
57
+ "Playwright not found. Install it (`npm i playwright`) or pass `{ chromium }` to connect().",
58
+ );
59
+ }
60
+ }
61
+
62
+ /** Drop "HeadlessChrome" from the UA so sites don't treat the session as headless. */
63
+ async function unmaskHeadlessUserAgent(context, page) {
64
+ const userAgent = await page.evaluate(() => navigator.userAgent).catch(() => "");
65
+ const clean = userAgent.replace(/HeadlessChrome/g, "Chrome");
66
+ if (!clean || clean === userAgent) return;
67
+
68
+ await context.setExtraHTTPHeaders({ "user-agent": clean });
69
+ const session = await context.newCDPSession(page);
70
+ await session.send("Network.setUserAgentOverride", { userAgent: clean });
71
+ }