/** * BasePage — shared IPage method implementations for DOM helpers. * * Both Page (daemon-backed) and CDPPage (direct CDP) execute JS the same way * for DOM operations. This base class deduplicates ~200 lines of identical * click/type/scroll/wait/snapshot/interceptor methods. * * Subclasses implement the transport-specific methods: goto, evaluate, * getCookies, screenshot, tabs, etc. */ import type { BrowserCookie, BrowserEvaluateFunction, FetchJsonOptions, IPage, ScreenshotOptions, SnapshotOptions, WaitOptions } from '../types.js'; import { type ResolveOptions, type TargetMatchLevel } from './target-resolver.js'; export interface ResolveSuccess { matches_n: number; /** * Cascading stale-ref tier the resolver traversed. Callers surface this to * agents so `stable` / `reidentified` hits are visibly distinct from a * clean `exact` match — the page changed, the action still succeeded. */ match_level: TargetMatchLevel; } export interface FillTextResult extends ResolveSuccess { filled: boolean; verified: boolean; expected: string; actual: string; length: number; mode?: 'input' | 'textarea' | 'contenteditable'; } export interface SetCheckedResult extends ResolveSuccess { checked: boolean; changed: boolean; kind?: string; } export interface UploadFilesResult extends ResolveSuccess { uploaded: boolean; files: number; file_names: string[]; target: string; multiple?: boolean; accept?: string; } export interface DragResult { dragged: boolean; source: string; target: string; source_matches_n: number; target_matches_n: number; source_match_level: TargetMatchLevel; target_match_level: TargetMatchLevel; } export declare abstract class BasePage implements IPage { protected _lastUrl: string | null; /** Cached previous snapshot hashes for incremental diff marking */ private _prevSnapshotHashes; private _cdpTargetMarkerSeq; private _axRefs; abstract goto(url: string, options?: { waitUntil?: 'load' | 'none'; settleMs?: number; allowBoundNavigation?: boolean; }): Promise; abstract evaluate(js: string): Promise; abstract evaluate(fn: BrowserEvaluateFunction, ...args: Args): Promise>; /** * Safely evaluate JS with pre-serialized arguments. * Each key in `args` becomes a `const` declaration with JSON-serialized value, * prepended to the JS code. Prevents injection by design. * * Usage: * page.evaluateWithArgs(`(async () => { return sym; })()`, { sym: userInput }) */ evaluateWithArgs(js: string, args: Record): Promise; fetchJson(url: string, opts?: FetchJsonOptions): Promise; abstract getCookies(opts?: { domain?: string; url?: string; }): Promise; abstract screenshot(options?: ScreenshotOptions): Promise; annotatedScreenshot(options?: ScreenshotOptions): Promise; abstract tabs(): Promise; abstract selectTab(target: number | string): Promise; click(ref: string, opts?: ResolveOptions): Promise; /** Uses native CDP click support when the concrete page exposes it. */ protected tryNativeClick(x: number, y: number): Promise; protected tryNativeMouseMove(x: number, y: number): Promise; protected tryNativeDoubleClick(x: number, y: number): Promise; protected tryNativeDrag(from: { x: number; y: number; }, to: { x: number; y: number; }): Promise; protected tryClickAxRef(ref: string): Promise; private resolveAxRefPoint; private axBoxCenter; /** Uses native CDP text insertion when the concrete page exposes it. */ protected tryNativeType(text: string): Promise; /** Uses native CDP key events when the concrete page exposes them. */ protected tryNativeKeyPress(key: string, modifiers: string[]): Promise; protected isResolvedFocused(): Promise; /** * Run a DOM-domain CDP command against `window.__resolved`. * * CDP DOM.focus / DOM.scrollIntoViewIfNeeded need a nodeId, while our * resolver stores the live Element in page JS. Bridge the two worlds with a * short-lived marker attribute, then query it through CDP. */ protected tryCdpOnResolvedElement(method: 'DOM.focus' | 'DOM.scrollIntoViewIfNeeded'): Promise; typeText(ref: string, text: string, opts?: ResolveOptions): Promise; hover(ref: string, opts?: ResolveOptions): Promise; focus(ref: string, opts?: ResolveOptions): Promise; dblClick(ref: string, opts?: ResolveOptions): Promise; private readCheckableState; setChecked(ref: string, checked: boolean, opts?: ResolveOptions): Promise; private setFileInputBySelector; uploadFiles(ref: string, files: string[], opts?: ResolveOptions): Promise; drag(source: string, target: string, opts?: { from?: ResolveOptions; to?: ResolveOptions; }): Promise; fillText(ref: string, text: string, opts?: ResolveOptions): Promise; pressKey(key: string): Promise; scrollTo(ref: string, opts?: ResolveOptions): Promise; getFormState(): Promise>; scroll(direction?: string, amount?: number): Promise; autoScroll(options?: { times?: number; delayMs?: number; }): Promise; networkRequests(includeStatic?: boolean): Promise; consoleMessages(_level?: string): Promise; wait(options: number | WaitOptions): Promise; snapshot(opts?: SnapshotOptions): Promise; private collectAxSnapshotTrees; getCurrentUrl(): Promise; installInterceptor(pattern: string): Promise; getInterceptedRequests(): Promise; waitForCapture(timeout?: number): Promise; /** Fallback basic snapshot */ protected _basicSnapshot(opts?: Pick): Promise; }