/** * Browser Automation Client for ZCLAW * Provides TypeScript API for Fantoccini-based browser automation */ import { invoke } from '@tauri-apps/api/core'; // ============================================================================ // Types // ============================================================================ export interface BrowserSessionResult { session_id: string; } export interface BrowserSessionInfo { id: string; name: string; current_url: string | null; title: string | null; status: string; created_at: string; last_activity: string; } export interface BrowserNavigationResult { url: string | null; title: string | null; } export interface BrowserElementInfo { selector: string; tag_name: string | null; text: string | null; is_displayed: boolean; is_enabled: boolean; is_selected: boolean; location: BrowserElementLocation | null; size: BrowserElementSize | null; } export interface BrowserElementLocation { x: number; y: number; } export interface BrowserElementSize { width: number; height: number; } export interface BrowserScreenshotResult { base64: string; format: string; } export interface FormFieldData { selector: string; value: string; } // ============================================================================ // Session Management // ============================================================================ /** * Create a new browser session */ export async function createSession(options?: { webdriverUrl?: string; headless?: boolean; browserType?: 'chrome' | 'firefox' | 'edge' | 'safari'; windowWidth?: number; windowHeight?: number; }): Promise { return invoke('browser_create_session', { webdriverUrl: options?.webdriverUrl, headless: options?.headless, browserType: options?.browserType, windowWidth: options?.windowWidth, windowHeight: options?.windowHeight, }); } /** * Close a browser session */ export async function closeSession(sessionId: string): Promise { return invoke('browser_close_session', { sessionId }); } /** * List all browser sessions */ export async function listSessions(): Promise { return invoke('browser_list_sessions'); } /** * Get session info */ export async function getSession(sessionId: string): Promise { return invoke('browser_get_session', { sessionId }); } // ============================================================================ // Navigation // ============================================================================ /** * Navigate to URL */ export async function navigate( sessionId: string, url: string ): Promise { return invoke('browser_navigate', { sessionId, url }); } /** * Go back */ export async function back(sessionId: string): Promise { return invoke('browser_back', { sessionId }); } /** * Go forward */ export async function forward(sessionId: string): Promise { return invoke('browser_forward', { sessionId }); } /** * Refresh page */ export async function refresh(sessionId: string): Promise { return invoke('browser_refresh', { sessionId }); } /** * Get current URL */ export async function getCurrentUrl(sessionId: string): Promise { return invoke('browser_get_url', { sessionId }); } /** * Get page title */ export async function getTitle(sessionId: string): Promise { return invoke('browser_get_title', { sessionId }); } // ============================================================================ // Element Interaction // ============================================================================ /** * Find element by CSS selector */ export async function findElement( sessionId: string, selector: string ): Promise { return invoke('browser_find_element', { sessionId, selector }); } /** * Find multiple elements */ export async function findElements( sessionId: string, selector: string ): Promise { return invoke('browser_find_elements', { sessionId, selector }); } /** * Click element */ export async function click(sessionId: string, selector: string): Promise { return invoke('browser_click', { sessionId, selector }); } /** * Type text into element */ export async function typeText( sessionId: string, selector: string, text: string, clearFirst?: boolean ): Promise { return invoke('browser_type', { sessionId, selector, text, clearFirst }); } /** * Get element text */ export async function getText(sessionId: string, selector: string): Promise { return invoke('browser_get_text', { sessionId, selector }); } /** * Get element attribute */ export async function getAttribute( sessionId: string, selector: string, attribute: string ): Promise { return invoke('browser_get_attribute', { sessionId, selector, attribute }); } /** * Wait for element */ export async function waitForElement( sessionId: string, selector: string, timeoutMs?: number ): Promise { return invoke('browser_wait_for_element', { sessionId, selector, timeoutMs: timeoutMs ?? 10000, }); } // ============================================================================ // Advanced Operations // ============================================================================ /** * Execute JavaScript */ export async function executeScript( sessionId: string, script: string, args?: unknown[] ): Promise { return invoke('browser_execute_script', { sessionId, script, args }); } /** * Take screenshot */ export async function screenshot(sessionId: string): Promise { return invoke('browser_screenshot', { sessionId }); } /** * Take element screenshot */ export async function elementScreenshot( sessionId: string, selector: string ): Promise { return invoke('browser_element_screenshot', { sessionId, selector }); } /** * Get page source */ export async function getSource(sessionId: string): Promise { return invoke('browser_get_source', { sessionId }); } // ============================================================================ // High-Level Tasks // ============================================================================ /** * Scrape page content */ export async function scrapePage( sessionId: string, selectors: string[], waitFor?: string, timeoutMs?: number ): Promise> { return invoke('browser_scrape_page', { sessionId, selectors, waitFor, timeoutMs, }); } /** * Fill form */ export async function fillForm( sessionId: string, fields: FormFieldData[], submitSelector?: string ): Promise { return invoke('browser_fill_form', { sessionId, fields, submitSelector }); } // ============================================================================ // Browser Client Class (Convenience Wrapper) // ============================================================================ /** * High-level browser client for easier usage */ export class Browser { private sessionId: string | null = null; /** * Start a new browser session */ async start(options?: { webdriverUrl?: string; headless?: boolean; browserType?: 'chrome' | 'firefox' | 'edge' | 'safari'; windowWidth?: number; windowHeight?: number; }): Promise { const result = await createSession(options); this.sessionId = result.session_id; return this.sessionId; } /** * Close browser session */ async close(): Promise { if (this.sessionId) { await closeSession(this.sessionId); this.sessionId = null; } } /** * Get current session ID */ getSessionId(): string | null { return this.sessionId; } /** * Navigate to URL */ async goto(url: string): Promise { this.ensureSession(); return navigate(this.sessionId!, url); } /** * Find element */ async $(selector: string): Promise { this.ensureSession(); return findElement(this.sessionId!, selector); } /** * Find multiple elements */ async $$(selector: string): Promise { this.ensureSession(); return findElements(this.sessionId!, selector); } /** * Click element */ async click(selector: string): Promise { this.ensureSession(); return click(this.sessionId!, selector); } /** * Type text */ async type(selector: string, text: string, clearFirst = false): Promise { this.ensureSession(); return typeText(this.sessionId!, selector, text, clearFirst); } /** * Wait for element */ async wait(selector: string, timeoutMs = 10000): Promise { this.ensureSession(); return waitForElement(this.sessionId!, selector, timeoutMs); } /** * Take screenshot */ async screenshot(): Promise { this.ensureSession(); return screenshot(this.sessionId!); } /** * Execute JavaScript */ async eval(script: string, args?: unknown[]): Promise { this.ensureSession(); return executeScript(this.sessionId!, script, args); } /** * Get page source */ async source(): Promise { this.ensureSession(); return getSource(this.sessionId!); } /** * Get current URL */ async url(): Promise { this.ensureSession(); return getCurrentUrl(this.sessionId!); } /** * Get page title */ async title(): Promise { this.ensureSession(); return getTitle(this.sessionId!); } /** * Scrape page content */ async scrape( selectors: string[], waitFor?: string, timeoutMs?: number ): Promise> { this.ensureSession(); return scrapePage(this.sessionId!, selectors, waitFor, timeoutMs); } /** * Fill form */ async fillForm(fields: FormFieldData[], submitSelector?: string): Promise { this.ensureSession(); return fillForm(this.sessionId!, fields, submitSelector); } private ensureSession(): void { if (!this.sessionId) { throw new Error('Browser session not started. Call start() first.'); } } } // Default export export default Browser;