From 83d63ddf307418da44f86e42e2c01a3177dd1f3d Mon Sep 17 00:00:00 2001 From: Ruskin Constant <6400000+jonnyparris@users.noreply.github.com> Date: Tue, 30 Jun 2026 14:40:48 +0100 Subject: [PATCH 1/2] feat(cloudflare): add typed Cloudflare.* CDP command definitions Declares the request/response types for Cloudflare's custom CDP domain (handoff, handoffComplete, getHandoffState, getSessionId, getLiveView) and merges them into Protocol.CommandParameters / CommandReturnValues so calls like cdpSession.send('Cloudflare.handoff', {...}) type-check with full param and return-type inference. The augmentation lives outside the build-generated types/ directory so it survives copy_types.js rebuilds, mirroring the existing Browser.sessionId() augmentation in index.d.ts. The shared interface block is the canonical definition, vendored identically into the puppeteer and playwright forks; it is intended to be promoted to a shared package once the cloudflare/browser-run monorepo lands. Only the Protocol augmentation is fork-specific. BRAPI-1194, BRAPI-1218 --- .../playwright-cloudflare/cloudflare-cdp.d.ts | 230 ++++++++++++++++++ packages/playwright-cloudflare/index.d.ts | 5 + 2 files changed, 235 insertions(+) create mode 100644 packages/playwright-cloudflare/cloudflare-cdp.d.ts diff --git a/packages/playwright-cloudflare/cloudflare-cdp.d.ts b/packages/playwright-cloudflare/cloudflare-cdp.d.ts new file mode 100644 index 000000000..6e2c04750 --- /dev/null +++ b/packages/playwright-cloudflare/cloudflare-cdp.d.ts @@ -0,0 +1,230 @@ +/** + * Type definitions for Cloudflare's custom CDP commands. + * + * Cloudflare's Browser Run platform exposes a non-standard `Cloudflare.*` CDP + * domain that is not part of the upstream DevTools protocol, so it is absent + * from Playwright's generated protocol types. This module declares the request + * and response shapes for those commands and merges them into + * `Protocol.CommandParameters` / `Protocol.CommandReturnValues`, which makes + * calls such as `cdpSession.send('Cloudflare.handoff', {...})` type-check with + * full parameter and return-type inference. + * + * SHARED SOURCE OF TRUTH. The interface block below is intended to be the + * canonical definition of the `Cloudflare.*` CDP types and is vendored + * identically into the puppeteer and playwright forks. When the + * `cloudflare/browser-run` monorepo lands, this block should be promoted to a + * shared package that both ports import, replacing the vendored copies. Keep + * the two copies in sync until then. Only the `declare module` augmentation at + * the bottom is fork-specific. + * + * This file lives outside the build-generated `types/` directory (which is + * overwritten by utils/copy_types.js) so the augmentation survives rebuilds. + * + * @see https://jira.cfdata.org/browse/BRAPI-1194 + * @see https://jira.cfdata.org/browse/BRAPI-1218 + */ + +// ============================================================================ +// Shared Cloudflare.* CDP types (canonical — keep in sync across forks) +// ============================================================================ + +/** + * Live view mode options. + * + * @public + */ +export type LiveViewMode = 'devtools' | 'tab' | 'full'; + +// ---------------- Cloudflare.handoff ---------------- + +/** + * @public + */ +export interface HandoffRequest { + /** + * Target page ID requiring intervention. + */ + targetId?: string; + /** + * Human-readable instructions (max 4096 chars). + */ + instructions?: string; + /** + * Timeout in milliseconds (max 30 minutes). + */ + timeout?: number; +} + +/** + * @public + */ +export interface HandoffResponse { + /** + * The target page ID. + */ + targetId: string; + /** + * Unique identifier for this handoff. + */ + handoffId: string; +} + +// ---------------- Cloudflare.handoffComplete ---------------- + +/** + * @public + */ +export interface HandoffCompleteRequest { + /** + * Target page ID. + */ + targetId?: string; + /** + * Whether intervention was successful. Defaults to true. + */ + success?: boolean; + /** + * Reason for the result (max 1024 chars). + */ + reason?: string; +} + +/** + * @public + */ +export interface HandoffCompleteResponse { + /** + * Target page ID. + */ + targetId: string; + /** + * Unique identifier for the handoff. + */ + handoffId?: string; + /** + * Original instructions for the handoff. + */ + instructions?: string; + /** + * Whether intervention was successful. + */ + success: boolean; + /** + * Reason for the result. + */ + reason?: string; +} + +// ---------------- Cloudflare.getHandoffState ---------------- + +/** + * @public + */ +export interface GetHandoffStateRequest { + /** + * Target page ID. + */ + targetId?: string; +} + +/** + * @public + */ +export interface GetHandoffStateResponse { + /** + * Whether a handoff is active. + */ + active: boolean; + /** + * Unique identifier for the handoff. + */ + handoffId?: string; + /** + * Active handoff instructions. + */ + instructions?: string; + /** + * Active handoff timeout in milliseconds. + */ + timeout?: number; + /** + * Elapsed time since handoff started in milliseconds. + */ + durationMs?: number; +} + +// ---------------- Cloudflare.getSessionId ---------------- + +/** + * @public + */ +export interface GetSessionIdRequest {} + +/** + * @public + */ +export interface GetSessionIdResponse { + sessionId: string; +} + +// ---------------- Cloudflare.getLiveView ---------------- + +/** + * @public + */ +export interface GetLiveViewRequest { + /** + * Target ID to get live view for. Optional - auto-resolved if omitted. + */ + targetId?: string; + /** + * Live view mode: devtools, tab, or full. Defaults to "devtools". + */ + mode?: LiveViewMode; +} + +/** + * @public + */ +export interface GetLiveViewResponse { + /** + * WebSocket URL for the live view. + */ + webSocketDebuggerUrl: string; + /** + * DevTools frontend URL for the live view. + */ + devtoolsFrontendUrl: string; + /** + * The target ID. + */ + id: string; + /** + * Live view options. + */ + options: Record; +} + +// ============================================================================ +// Fork-specific augmentation (playwright: merge into the generated Protocol +// CommandParameters / CommandReturnValues maps that CDPSession.send is keyed on) +// ============================================================================ + +declare module './types/protocol' { + export namespace Protocol { + interface CommandParameters { + 'Cloudflare.handoff': HandoffRequest; + 'Cloudflare.handoffComplete': HandoffCompleteRequest; + 'Cloudflare.getHandoffState': GetHandoffStateRequest; + 'Cloudflare.getSessionId': GetSessionIdRequest; + 'Cloudflare.getLiveView': GetLiveViewRequest; + } + interface CommandReturnValues { + 'Cloudflare.handoff': HandoffResponse; + 'Cloudflare.handoffComplete': HandoffCompleteResponse; + 'Cloudflare.getHandoffState': GetHandoffStateResponse; + 'Cloudflare.getSessionId': GetSessionIdResponse; + 'Cloudflare.getLiveView': GetLiveViewResponse; + } + } +} diff --git a/packages/playwright-cloudflare/index.d.ts b/packages/playwright-cloudflare/index.d.ts index 9a14b2fb4..c883eba1d 100644 --- a/packages/playwright-cloudflare/index.d.ts +++ b/packages/playwright-cloudflare/index.d.ts @@ -5,6 +5,11 @@ import { env } from 'cloudflare:workers'; export * from './types/types'; +// Re-export the Cloudflare.* CDP command types and pull in their augmentation +// of Protocol.CommandParameters / CommandReturnValues so that +// cdpSession.send('Cloudflare.*', ...) is typed. +export * from './cloudflare-cdp'; + declare module './types/types' { interface Browser { /** From a3fd9780f7cf42a002d6b4c3c451915269aeb621 Mon Sep 17 00:00:00 2001 From: Ruskin Constant <6400000+jonnyparris@users.noreply.github.com> Date: Tue, 30 Jun 2026 21:28:01 +0100 Subject: [PATCH 2/2] fix(cloudflare): keep canonical block in sync (Record) - GetSessionIdRequest: use Record instead of an empty interface, matching the puppeteer fork's lint-clean canonical block - scope an eslint-disable for no-namespace on the Protocol augmentation --- packages/playwright-cloudflare/cloudflare-cdp.d.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/playwright-cloudflare/cloudflare-cdp.d.ts b/packages/playwright-cloudflare/cloudflare-cdp.d.ts index 6e2c04750..cbd172618 100644 --- a/packages/playwright-cloudflare/cloudflare-cdp.d.ts +++ b/packages/playwright-cloudflare/cloudflare-cdp.d.ts @@ -158,7 +158,7 @@ export interface GetHandoffStateResponse { /** * @public */ -export interface GetSessionIdRequest {} +export type GetSessionIdRequest = Record; /** * @public @@ -211,6 +211,9 @@ export interface GetLiveViewResponse { // ============================================================================ declare module './types/protocol' { + // Augmenting the generated Protocol namespace requires a namespace to match + // its own declaration, so the no-namespace rule does not apply here. + // eslint-disable-next-line @typescript-eslint/no-namespace export namespace Protocol { interface CommandParameters { 'Cloudflare.handoff': HandoffRequest;