import type { Connector } from '@lynx-js/devtool-connector'; /** * A stateless CDP (Chrome DevTools Protocol) channel for sending commands * to a specific Lynx session. * * Each `send()` call is a short-lived request/response via the `Connector`. * Channels are cached per session ID using `WeakRef` to allow reuse. */ export declare class CDPChannel { private _connector; private _clientId; private _sessionId; /** * Retrieves or instantiates a stateless `CDPChannel` for a specific Lynx session. * * **Design pattern (For Agents):** * This testing library uses a **stateless** CDP architecture to avoid hanging Websocket connections * over unstable ADB links. Channels are cached per `sessionId` via `WeakRef` to reduce allocations. * * @param sessionId - The numeric Lynx devtool session ID assigned by the Lynx runtime. * @param clientId - The unique device-port identifier for the client app (e.g., `"emulator-5554:40121"`). * @param connector - The active `Connector` instance powering the ADB transport. * @returns A `CDPChannel` reference bound to the requested session. */ static from(sessionId: number, clientId: string, connector: Connector): CDPChannel; /** * Constructs a new CDP Channel strictly bound to a single Lynx session. * * **Note for Agents:** * Favor using `CDPChannel.from()` over manually newing up a channel, as `from()` handles * WeakRef caching to minimize memory footprint. * * @param _connector - Low-level ADB transport controller. * @param _clientId - Bound devtool target identification string. * @param _sessionId - Narrowly scoped Lynx view session ID. */ constructor(_connector: Connector, _clientId: string, _sessionId: number); /** * Dispatches a strongly-typed Chrome DevTools Protocol (CDP) method command and awaits its return block. * * **Agent Usage:** * This is the beating heart of all interactions in `kitten-lynx`. Instead of maintaining a socket, * every `send(...)` call constructs a self-contained ADB request and awaits the isolated response. * * **Typings:** * Notice that the generics strictly bind to the `Protocol` interface defined at the top of this file. * If you need to invoke a CDP command that TypeScript rejects, you must update the `Protocol` interface first! * * @typeParam T - The literal string name of the CDP method (e.g., `'DOM.getDocument'`, `'Page.navigate'`). * @param method - The command to send to the Lynx devtool server. * @param params - A strongly-typed payload object required by the CDP method. * @returns A promise resolving to a strongly-typed response object matching the expected return structure of the `method`. */ send(method: T, params: Protocol[T]['params']): Promise; } /** * Options for configuring the connection to a Lynx device. */ declare interface ConnectOptions { /** * ADB device serial to target (e.g. `"localhost:5555"`, `"emulator-5554"`). * When multiple ADB devices are connected, use this to select the correct one. * If omitted, uses the first available device. */ deviceId?: string; /** * App package name to launch on the device. * @default "com.lynx.explorer" */ appPackage?: string; } /** * Represents a DOM element in a Lynx page. * * Wraps a CDP `nodeId` and provides methods for inspecting attributes, * computed styles, and simulating user interactions like taps. */ export declare class ElementNode { readonly nodeId: number; private _lynxView; /** * Retrieves or creates an `ElementNode` instance corresponding to a specific Lynx DOM node ID. * * **Agent Caching Strategy:** * Nodes are aggressively cached per `KittenLynxView` instance using `WeakRef`. * This means if an Agent queries the same DOM node twice before garbage collection, * it returns the same `ElementNode` reference, reducing memory overhead during extensive DOM crawling. * * @param id - The numeric CDP node ID to wrap. * @param lynxView - The `KittenLynxView` instance this node belongs to. * @returns An `ElementNode` bound to the provided node ID and view. */ static fromId(id: number, lynxView: KittenLynxView): ElementNode; /** * Initializes a new `ElementNode` instance to represent a Lynx Component or Tag. * * **Note for Agents:** * Similar to `KittenLynxView`, you should rarely call this directly. * Rely on `KittenLynxView.locator()` or `ElementNode.fromId()` for instantiations. * * @param nodeId - The unique CDP numeric ID denoting this element in the Lynx renderer. * @param _lynxView - The parent `KittenLynxView` instance used to dispatch subsequent CDP queries. */ constructor(nodeId: number, _lynxView: KittenLynxView); /** * Simulates a native user tap (touch press followed by touch release) directly on the center of this element. * * **Internal Mechanics (For Agents):** * This is not a simulated DOM event (like `element.click()` in Web). It is a highly accurate native-layer * gesture dispatch: * 1. Fetches the exact boundary coordinates via `DOM.getBoxModel`. * 2. Calculates the absolute center `(x, y)` of the content box. * 3. Dispatches an `Input.emulateTouchFromMouseEvent` (`'mousePressed'`) over the ADB bridge. * 4. Waits 50ms, then dispatches the corresponding `'mouseReleased'`. * * **Crucial:** Ensure the element is visible on the screen before calling this, or the coordinate calculation might fail or hit nothing. * * @throws Error if the layout box model cannot be computed natively. */ tap(): Promise; /** * Retrieves the string value of a specified attribute on this element. * * **Agent Quirk / Gotcha:** * In Lynx, standard web `id="foo"` attributes are actually stored as `idSelector="foo"` internally. * This library provides a seamless shim: if you query `getAttribute('id')`, it automatically * queries `idSelector` instead. No manual handling of `idSelector` is required on your part. * * @param name - The name of the attribute to fetch. * @returns A promise resolving to the string value of the attribute, or `null` if the attribute does not exist. */ getAttribute(name: string): Promise; /** * Fetches all actively computed CSS properties for this specific element. * * **Agent Usage:** * This relies on `CSS.getComputedStyleForNode`. It returns the fully resolved style values * post-layout calculation (e.g., resolving `100%` into absolute `px` values). * It is highly recommended to use this for visual assertions (e.g., verifying a box is indeed `display: none` * or has a specific `background-color`). * * @returns A promise resolving to a native JS `Map`, where keys are CSS property names and values are their computed string expressions. */ computedStyleMap(): Promise>; } /** * Represents a Lynx page instance, similar to Puppeteer's `Page`. * * Provides methods for navigating to Lynx bundle URLs, querying the DOM, * and reading page content. Created via {@link Lynx.newPage}. */ export declare class KittenLynxView { #private; private _connector; private _clientId; private _client?; private static incId; private _root?; private _url; _channel: CDPChannel; readonly id: number; /** * Retrieves a previously created `KittenLynxView` instance using its stringified numeric ID. * * **Why this is useful for Agents:** * This is primarily used for cross-referencing or finding an existing view without passing the object reference around. * * @param id - The string representation of the LynxView's numeric ID (e.g., `'1'`, `'2'`). * @returns The `KittenLynxView` instance if it is still alive in memory, or `undefined` if it has been garbage-collected. */ static getKittenLynxViewById(id: string): KittenLynxView | undefined; /** * Initializes a new `KittenLynxView` instance. * * **Note for Agents:** * You generally should avoid calling this constructor directly. Instead, use `Lynx.newPage()` to properly * initialize a `KittenLynxView` instance bound to the active ADB connection and client. * * @param _connector - The low-level `Connector` instance used to dispatch CDP messages over ADB/USB. * @param _clientId - The unique client identifier (typically `:`). * @param _client - Optional client metadata object containing internal app states. */ constructor(_connector: Connector, _clientId: string, _client?: any); /** * Navigates the Lynx App to a specific Lynx bundle URL and attaches to the corresponding CDP session. * * **How it works (Crucial for Agents to understand):** * Unlike standard web browsers, calling `Page.navigate` in Lynx creates a **new** debugging session * instead of reusing the current one. This method abstracts away that complexity by: * 1. Waiting for the devtool server to boot. * 2. Sending an `App.openPage` (or a fallback message) to trigger the navigation. * 3. **Polling the session list** over ADB to find a new session whose URL matches the target bundle URL. * 4. Automatically re-attaching to the matched session and fetching the initial DOM tree (`DOM.getDocument`). * * @param url - The absolute URL of the Lynx bundle to navigate to (e.g., `'http://localhost:8080/dist/main.lynx.bundle'`). * @param _options - Currently unused. Reserved for future navigation options. * @throws An error if it times out waiting for the devtool server to boot (60s limit). * @throws An error if the specific session for the URL cannot be found (30s limit) or cannot be attached. */ goto(url: string, options?: { timeout?: number; }): Promise; /** * Returns the last URL successfully loaded by {@link goto}. */ url(): string; /** * Locates the first DOM element matching the provided CSS selector in the current page. * * **Agent Usage:** * This operates identically to `document.querySelector` or Playwright's `page.locator()`. * It relies on the `DOM` CDP domain. Always ensure that `goto()` has completed successfully before calling this, * otherwise the DOM tree will not exist. * * @param selector - A valid CSS selector string targeting the desired element (e.g., `'view'`, `'#submit-btn'`, `'.container > text'`). * @returns A promise resolving to an `ElementNode` containing methods to interact with the element, or `undefined` if no node matched. * @throws Error if the method is called before a page is loaded via `goto()`. */ locator(selector: string): Promise; /** * Attaches the LynxView to a specific Lynx devtool session and initializes the CDP channel. * * **Internal Mechanics:** * This method creates a `CDPChannel` for the specific `sessionId` and immediately fires * a `DOM.getDocument` request to cache the root document node. This must succeed for the page to be interactable. * * **Note for Agents:** * This is generally marked as internal, but it is not `private`. You normally do not need to call this manually, * as `goto()` handles session attachment automatically. * * @param sessionId - The numeric Lynx devtool session ID to attach to, discovered via `sendListSessionMessage`. */ onAttachedToTarget(sessionId: number): Promise; /** * Serializes the current page's entire DOM tree into an HTML-like string format. * * **Agent Usage:** * This is highly useful for debugging and logging the current state of the Lynx App DOM. * It forces a fresh `DOM.getDocument` snapshot from the CDP server and recursively walks the tree * to build a string containing tags and attributes (e.g., `...`). * * @returns A promise resolving to a string representing the serialized DOM content of the page. */ content(): Promise; /** * Captures a screenshot of the page. * * @param options - Screenshot options, such as path, format, and quality. * @returns A Buffer with the image data. */ screenshot(options?: { path?: string; format?: 'jpeg' | 'png' | 'webp'; quality?: number; }): Promise; } /** * Main entry point for the kitten-lynx testing framework. * * Provides Puppeteer-like APIs for connecting to a Lynx app running on an * Android device (physical or emulator) via ADB and the Chrome DevTools Protocol. * * @example * ```typescript * const lynx = await Lynx.connect({ deviceId: 'localhost:5555' }); * const page = await lynx.newPage(); * await page.goto('http://example.com/bundle.lynx.bundle'); * const content = await page.content(); * await lynx.close(); * ``` */ export declare class Lynx { private _connector; private _transport; private _currentClient; private _currentClientId; /** * Main setup method. Connects to the Lynx app devtool server over ADB. * * **Agent Guide on the Connection Flow:** * 1. Discovers the target ADB device (physical Android or emulator). * 2. Force-stops the target app to ensure a clean state (`adb shell am force-stop`). * 3. Launches the application (usually Lynx Explorer) on the device. * 4. Queries the `Connector` for available clients and matches by device ID and package name. * 5. Enables the master devtool switch (`enable_devtool`). * * **When to use:** * This should be the first method invoked in any test script or interaction flow. * * @param options - Configure connection variables, such as `appPackage` and `deviceId` (useful if multiple devices are attached). * @returns A Promise resolving to a connected `Lynx` instance ready to spawn new pages. * @throws Errors if devices aren't found, the app is missing, or the target client fails to initialize. */ static connect(options?: ConnectOptions): Promise; /** * Spawns a new page representation for the connected Lynx environment. * * **Agent Usage:** * Similar to Puppeteer's `browser.newPage()`. Once you have a `Lynx` connection instance safely created * via `Lynx.connect()`, call this method to obtain a `KittenLynxView`. You can then call `post.goto(url)` * on the view to navigate to a Lynx Bundle. * * @returns A Promise resolving to a new `KittenLynxView` instance bound to the active ADB client. * @throws Error if the Lynx connection isn't properly initialized first. */ newPage(): Promise; /** * Closes the active ADB/CDP connection and releases associated resources. * * **Agent Usage:** * Ensure this is called in your test's teardown block (e.g., in `afterAll()`) to prevent * floating Node.js processes or hanging ADB connections that can ruin subsequent test runs. * * @returns A Promise resolving when the cleanup operation is fully processed. */ close(): Promise; } /** * Represents a node in the DOM tree returned by `DOM.getDocument`. */ declare interface NodeInfoInGetDocument { /** Unique DOM node identifier. */ nodeId: number; /** Child nodes of this node. */ children: NodeInfoInGetDocument[]; /** Flat array of alternating attribute name/value pairs. */ attributes: string[]; /** The node's tag name (e.g. `'view'`, `'text'`). */ nodeName: string; } declare interface Protocol { 'DOM.getDocument': { params: { depth: number; pierce?: boolean; }; return: { root: NodeInfoInGetDocument; }; }; 'DOM.querySelector': { params: { nodeId: number; selector: string; }; return: { nodeId: number; }; }; 'DOM.getAttributes': { params: { nodeId: number; }; return: { attributes: string[]; }; }; 'DOM.getBoxModel': { params: { nodeId: number; }; return: { model: { content: Quad; padding: Quad; border: Quad; margin: Quad; width: number; height: number; }; }; }; 'CSS.getComputedStyleForNode': { params: { nodeId: number; }; return: { computedStyle: { name: string; value: string; }[]; }; }; 'Page.navigate': { params: { url: string; }; return: unknown; }; 'Input.emulateTouchFromMouseEvent': { params: { type: 'mousePressed' | 'mouseReleased' | 'mouseMoved'; x: number; y: number; timestamp?: number; button: 'left' | 'middle' | 'right'; deltaX?: number; deltaY?: number; }; return: unknown; }; } declare type Quad = [number, number, number, number, number, number, number, number]; export { }