From dd778ee37e97ad19d774c0c92ea0abba5a2705f9 Mon Sep 17 00:00:00 2001 From: sergei-aronsen Date: Sun, 17 May 2026 08:55:09 +0200 Subject: [PATCH] fix(cdp-client): type-only emitter cast for Page.loadEventFired race MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `navigateWithRetry` subscribes to `Page.loadEventFired` via `client.once` and removes the listener via `client.removeListener` if the timeout branch wins. The CRI Client is an EventEmitter at runtime so both methods exist, but @types/chrome-remote-interface@^0.34.x only declares `on(...)`. tsc therefore rejected this file with: src/cdp-client.ts(1394,22): error TS2339: Property 'removeListener' does not exist on type 'Client'. src/cdp-client.ts(1397,20): error TS2339: Property 'once' does not exist on type 'Client'. The error is real — it broke the build on main itself, blocking every in-flight PR from passing CI. Fix: a minimal locally-scoped EventEmitter-shaped interface and a single `as unknown as ...` cast. No runtime change. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/cdp-client.ts | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/cdp-client.ts b/src/cdp-client.ts index 0a2d227..2563c5a 100644 --- a/src/cdp-client.ts +++ b/src/cdp-client.ts @@ -1383,9 +1383,19 @@ export class CometCDPClient { // leaves the underlying listener registered if the timeout // branch of Promise.race wins. After many timeouts in one // session the listener list grows unbounded. Subscribe via - // `client.once` (which auto-unsubscribes after one event) and + // `once` (which auto-unsubscribes after one event) and // explicitly remove the listener when the timeout wins. - const client = this.client!; + // + // The CRI Client is an EventEmitter at runtime, but the type + // declaration in @types/chrome-remote-interface only exposes + // `on(...)` — not `once`/`removeListener`. Cast to a minimal + // EventEmitter-shaped surface so this compiles without + // pulling in `events` as a value import for a type-only need. + interface CdpEmitter { + once(event: string, listener: (...args: unknown[]) => void): void; + removeListener(event: string, listener: (...args: unknown[]) => void): void; + } + const client = this.client! as unknown as CdpEmitter; await new Promise((resolve, reject) => { const onLoad = () => { clearTimeout(timer);