aboutsummaryrefslogtreecommitdiff
path: root/src/cdp/discovery.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/cdp/discovery.ts')
-rw-r--r--src/cdp/discovery.ts49
1 files changed, 27 insertions, 22 deletions
diff --git a/src/cdp/discovery.ts b/src/cdp/discovery.ts
index 41bcfe5..53d4ad2 100644
--- a/src/cdp/discovery.ts
+++ b/src/cdp/discovery.ts
@@ -6,6 +6,7 @@ import { type Result, err, ok } from "../util/result";
import { userDataDirCandidates } from "../profile/paths";
import { type CdpError, cdpError } from "./errors";
import { asString, errnoCode, isRecord } from "../util/guards";
+import { describeCdpTarget, resolveCdpTarget } from "./endpoint";
const PORT_PROBE_DEADLINE_MS = 30_000;
const PORT_PROBE_INTERVAL_MS = 1_000;
@@ -63,7 +64,7 @@ const waitForPort = async (port: number): Promise<Result<void, CdpError>> => {
const isPortLive = async (port: number): Promise<boolean> => (await probePort(port)).success;
// /json/version is authoritative: a stale DevToolsActivePort file may name a browser that has since exited while another now owns the port.
-const queryLiveWsUrl = (port: number, timeoutMs = 1_500, host = "127.0.0.1"): Promise<string | null> =>
+export const queryLiveWsUrl = (port: number, timeoutMs = 1_500, host = "127.0.0.1"): Promise<string | null> =>
new Promise<string | null>((resolve) => {
const req = httpRequest(
{ host, port, path: "/json/version", method: "GET", timeout: timeoutMs },
@@ -114,33 +115,37 @@ export const discoverEndpoint = async (): Promise<Result<CdpEndpoint, CdpError>>
const override = endpointFromEnv();
if (override) return ok(override);
- // LOCAL PATCH: direct remote browser support.
+ // FORK: drive a browser on another host. See src/cdp/endpoint.ts for the
+ // precedence rules and FORK.md for why this exists at all.
//
- // BU_CDP_HTTP="host:port" points at a CDP *HTTP* endpoint on another machine.
- // We ask it for its canonical webSocketDebuggerUrl on every discovery call,
- // so the browser UUID is re-read after the remote Chrome restarts. That is
- // the difference from the stock BU_CDP_WS (checked just above, so an explicit
- // WebSocket URL still wins), which pins a UUID that Chrome re-mints on every
- // launch.
+ // The remote is asked for its canonical webSocketDebuggerUrl on every
+ // discovery call, so the browser UUID is re-read after the remote browser
+ // restarts. That is the difference from upstream's BU_CDP_WS (checked just
+ // above, so an explicit WebSocket URL still wins), which pins a UUID that
+ // Chrome re-mints on every launch.
//
- // Returns no userDataDir: the profile registry lives on the remote host, so
- // profile enumeration correctly degrades to the pre-profile behaviour.
- const remote = process.env["BU_CDP_HTTP"]?.trim();
- if (remote) {
- const sep = remote.lastIndexOf(":");
- const host = sep === -1 ? remote : remote.slice(0, sep);
- const port = sep === -1 ? 9222 : Number(remote.slice(sep + 1));
- if (!host || !Number.isInteger(port) || port <= 0 || port >= 65536) {
- return err(cdpError("discovery_failed", `BU_CDP_HTTP is not a valid host:port — got "${remote}"`));
- }
- const ws = await queryLiveWsUrl(port, 5_000, host);
- if (!ws) {
+ // No userDataDir is returned: the profile registry lives on the remote host,
+ // so profile enumeration degrades to the pre-profile behaviour rather than
+ // reading the wrong machine's Local State.
+ const target = resolveCdpTarget();
+ if (target.kind === "invalid") {
+ return err(cdpError("discovery_failed", describeCdpTarget(target)));
+ }
+ if (target.kind === "remote") {
+ const ws = await queryLiveWsUrl(target.port, 5_000, target.host);
+ if (ws) return ok({ wsUrl: ws });
+
+ // An explicitly configured endpoint is an instruction: fail rather than
+ // quietly automate a different browser than the one that was asked for.
+ if (target.source === "env") {
return err(cdpError(
"discovery_failed",
- `No CDP endpoint answered at http://${host}:${port}/json/version (BU_CDP_HTTP). Is the remote browser running and reachable?`,
+ `No CDP endpoint answered at http://${target.host}:${target.port}/json/version (BU_CDP_HTTP). ` +
+ `Is the remote browser running and reachable? Set BU_CDP_HTTP=local to use this machine's browser instead.`,
));
}
- return ok({ wsUrl: ws });
+ // The built-in default is only a preference — off the wire network, fall
+ // through to the local browser the extension was originally written for.
}
const dirs = userDataDirCandidates();