diff options
Diffstat (limited to 'src/cdp/endpoint.ts')
| -rw-r--r-- | src/cdp/endpoint.ts | 60 |
1 files changed, 53 insertions, 7 deletions
diff --git a/src/cdp/endpoint.ts b/src/cdp/endpoint.ts index 96cf2ea..9cb21c6 100644 --- a/src/cdp/endpoint.ts +++ b/src/cdp/endpoint.ts @@ -16,10 +16,11 @@ export const DEFAULT_REMOTE_CDP = "10.88.0.25:9223"; const LOCAL_ALIASES = new Set(["local", "localhost", "off", "none", "0", "no"]); /** - * Where a target came from. "env" is BU_CDP_HTTP, "stored" is /browser-target, - * "default" is this fork's built-in. Only "default" is allowed to fall back. + * Where a target came from. "ws" is upstream's BU_CDP_WS, "env" is BU_CDP_HTTP, + * "stored" is /browser-target, "default" is this fork's built-in. Only + * "default" is allowed to fall back. */ -export type CdpTargetSource = "env" | "stored" | "default"; +export type CdpTargetSource = "ws" | "env" | "stored" | "default"; export type CdpTarget = | { @@ -28,12 +29,17 @@ export type CdpTarget = readonly port: number; readonly source: CdpTargetSource; } - | { readonly kind: "local"; readonly source: Exclude<CdpTargetSource, "default"> } + | { readonly kind: "local"; readonly source: Exclude<CdpTargetSource, "default" | "ws"> } | { readonly kind: "invalid"; readonly raw: string; readonly reason: string; readonly source: CdpTargetSource }; /** - * Precedence: BU_CDP_HTTP, then the /browser-target choice, then the built-in - * default. + * Precedence: BU_CDP_WS, then BU_CDP_HTTP, then the /browser-target choice, + * then the built-in default. + * + * BU_CDP_WS -> upstream's pinned WebSocket URL; discoverEndpoint() returns + * it before any of the rest is consulted, so it is reported + * here only so status, /browser-target and the prompt agree + * with what the daemon actually dials * * "host:port" -> that remote, and a failure to reach it is fatal * local|off|… -> upstream behaviour, this machine's own browser @@ -57,6 +63,16 @@ export const resolveCdpTarget = ( env: NodeJS.ProcessEnv = process.env, stored: string | null = null, ): CdpTarget => { + // FORK: mirror upstream's endpointFromEnv() in discovery.ts, which wins. + const pinnedWs = env["BU_CDP_WS"]?.trim(); + if (pinnedWs) { + const parsed = parseWsUrl(pinnedWs); + if (!parsed) { + return { kind: "invalid", raw: redactWsUrl(pinnedWs), source: "ws", reason: "expected a ws:// or wss:// URL" }; + } + return { kind: "remote", host: parsed.host, port: parsed.port, source: "ws" }; + } + const fromEnv = env["BU_CDP_HTTP"]?.trim(); const fromStore = stored?.trim(); @@ -104,8 +120,38 @@ const parseHostPort = (value: string): { host: string; port: number } | null => return { host, port }; }; +/** + * host:port of a BU_CDP_WS URL. Only that much is ever shown: the path carries + * the browser's id, and a proxied endpoint may carry a token or credentials. + */ +const parseWsUrl = (value: string): { host: string; port: number } | null => { + let url: URL; + try { + url = new URL(value); + } catch { + return null; + } + if (url.protocol !== "ws:" && url.protocol !== "wss:") return null; + const host = url.hostname.replace(/^\[(.*)\]$/, "$1"); + if (!host) return null; + const port = url.port === "" ? (url.protocol === "wss:" ? 443 : 80) : Number(url.port); + return { host, port }; +}; + +/** A BU_CDP_WS value safe to print: host:port when parseable, otherwise a placeholder. */ +export const redactWsUrl = (value: string): string => { + const parsed = parseWsUrl(value.trim()); + return parsed ? `${parsed.host}:${parsed.port}` : "<unparseable URL>"; +}; + const sourceLabel = (source: CdpTargetSource): string => - source === "env" ? "BU_CDP_HTTP" : source === "stored" ? "/browser-target" : "built-in default"; + source === "ws" + ? "BU_CDP_WS, pinned WebSocket" + : source === "env" + ? "BU_CDP_HTTP" + : source === "stored" + ? "/browser-target" + : "built-in default"; /** One-line description for /browser-status and error messages. */ export const describeCdpTarget = (target: CdpTarget): string => { |
