spider-browser 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +354 -0
- package/dist/index.d.ts +1223 -0
- package/dist/index.js +3609 -0
- package/dist/index.js.map +1 -0
- package/package.json +48 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../utils/errors.ts","../ai/providers/openai.ts","../ai/providers/anthropic.ts","../protocol/transport.ts","../utils/logger.ts","../protocol/cdp-session.ts","../protocol/bidi-session.ts","../protocol/types.ts","../protocol/protocol-adapter.ts","../events/emitter.ts","../page.ts","../retry/failure-tracker.ts","../retry/browser-selector.ts","../retry/retry-engine.ts","../retry/keyword-classifier.ts","../ai/llm-provider.ts","../ai/prompts.ts","../ai/agent.ts","../ai/act.ts","../utils/dom.ts","../ai/observe.ts","../utils/html.ts","../ai/extract.ts","../spider-browser.ts","../index.ts"],"sourcesContent":["/** Base error for all spider-browser errors. */\nexport class SpiderError extends Error {\n constructor(\n message: string,\n public readonly code: string,\n public readonly retryable: boolean = false,\n ) {\n super(message);\n this.name = 'SpiderError';\n }\n}\n\n/** WebSocket connection or transport error. */\nexport class ConnectionError extends SpiderError {\n constructor(message: string, public readonly wsCode?: number) {\n super(message, 'CONNECTION_ERROR', true);\n this.name = 'ConnectionError';\n }\n}\n\n/** Authentication failure (401/402). Never retried. */\nexport class AuthError extends SpiderError {\n constructor(message: string) {\n super(message, 'AUTH_ERROR', false);\n this.name = 'AuthError';\n }\n}\n\n/** Rate limit (429). Retried with delay. */\nexport class RateLimitError extends SpiderError {\n constructor(\n message: string,\n public readonly retryAfterMs?: number,\n ) {\n super(message, 'RATE_LIMIT', true);\n this.name = 'RateLimitError';\n }\n}\n\n/** The browser was blocked by the target site (403, captcha stuck). */\nexport class BlockedError extends SpiderError {\n constructor(message: string) {\n super(message, 'BLOCKED', true);\n this.name = 'BlockedError';\n }\n}\n\n/** The requested backend browser is unavailable. */\nexport class BackendUnavailableError extends SpiderError {\n constructor(message: string) {\n super(message, 'BACKEND_UNAVAILABLE', true);\n this.name = 'BackendUnavailableError';\n }\n}\n\n/** Timeout waiting for a response or navigation. */\nexport class TimeoutError extends SpiderError {\n constructor(message: string) {\n super(message, 'TIMEOUT', true);\n this.name = 'TimeoutError';\n }\n}\n\n/** Protocol-level error (invalid CDP/BiDi response). */\nexport class ProtocolError extends SpiderError {\n constructor(message: string) {\n super(message, 'PROTOCOL_ERROR', false);\n this.name = 'ProtocolError';\n }\n}\n\n/** Navigation error that can be retried (ERR_ABORTED, ERR_CONNECTION_RESET, etc.). */\nexport class NavigationError extends SpiderError {\n constructor(message: string) {\n super(message, 'NAVIGATION_ERROR', true);\n this.name = 'NavigationError';\n }\n}\n\n/** LLM call failed or returned unparseable response. */\nexport class LLMError extends SpiderError {\n constructor(message: string) {\n super(message, 'LLM_ERROR', true);\n this.name = 'LLMError';\n }\n}\n","import type { LLMConfig, LLMMessage, LLMProvider } from '../llm-provider.js';\nimport { LLMError } from '../../utils/errors.js';\n\nconst DEFAULT_URLS: Record<string, string> = {\n openai: 'https://api.openai.com/v1/chat/completions',\n openrouter: 'https://openrouter.ai/api/v1/chat/completions',\n};\n\n/**\n * OpenAI-compatible LLM provider.\n *\n * Works with OpenAI, OpenRouter, Qwen/vLLM, or any /v1/chat/completions endpoint.\n */\nexport class OpenAICompatibleProvider implements LLMProvider {\n private url: string;\n private apiKey: string;\n private model: string;\n private maxTokens: number;\n private temperature: number;\n\n constructor(config: LLMConfig) {\n this.url = config.baseUrl ?? DEFAULT_URLS[config.provider] ?? DEFAULT_URLS.openai!;\n this.apiKey = config.apiKey;\n this.model = config.model;\n this.maxTokens = config.maxTokens ?? 4096;\n this.temperature = config.temperature ?? 0.1;\n }\n\n async chat(messages: LLMMessage[], options?: { jsonMode?: boolean }): Promise<string> {\n const body: Record<string, unknown> = {\n model: this.model,\n messages,\n max_tokens: this.maxTokens,\n temperature: this.temperature,\n };\n\n if (options?.jsonMode) {\n body.response_format = { type: 'json_object' };\n }\n\n const resp = await fetch(this.url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.apiKey}`,\n },\n body: JSON.stringify(body),\n });\n\n if (!resp.ok) {\n const text = await resp.text().catch(() => '');\n throw new LLMError(`OpenAI API error ${resp.status}: ${text}`);\n }\n\n const json = (await resp.json()) as any;\n const content = json?.choices?.[0]?.message?.content;\n if (typeof content !== 'string') {\n throw new LLMError('OpenAI response missing choices[0].message.content');\n }\n return content;\n }\n\n async chatJSON<T = unknown>(messages: LLMMessage[]): Promise<T> {\n const text = await this.chat(messages, { jsonMode: true });\n try {\n return JSON.parse(text) as T;\n } catch {\n // Try extracting JSON from markdown code blocks\n const match = text.match(/```(?:json)?\\s*([\\s\\S]*?)```/);\n if (match) {\n return JSON.parse(match[1]!) as T;\n }\n throw new LLMError(`LLM response is not valid JSON: ${text.slice(0, 200)}`);\n }\n }\n}\n","import type { LLMConfig, LLMMessage, LLMProvider, LLMContentPart } from '../llm-provider.js';\nimport { LLMError } from '../../utils/errors.js';\n\n/**\n * Anthropic native API provider.\n *\n * Converts OpenAI-style messages to Anthropic's format.\n */\nexport class AnthropicProvider implements LLMProvider {\n private url: string;\n private apiKey: string;\n private model: string;\n private maxTokens: number;\n private temperature: number;\n\n constructor(config: LLMConfig) {\n this.url = config.baseUrl ?? 'https://api.anthropic.com/v1/messages';\n this.apiKey = config.apiKey;\n this.model = config.model;\n this.maxTokens = config.maxTokens ?? 4096;\n this.temperature = config.temperature ?? 0.1;\n }\n\n async chat(messages: LLMMessage[], _options?: { jsonMode?: boolean }): Promise<string> {\n // Extract system message\n const systemMsg = messages.find((m) => m.role === 'system');\n const userMessages = messages.filter((m) => m.role !== 'system');\n\n // Convert to Anthropic format\n const anthropicMessages = userMessages.map((m) => {\n if (typeof m.content === 'string') {\n return { role: m.role, content: m.content };\n }\n // Convert content parts\n const parts = (m.content as LLMContentPart[]).map((part) => {\n if (part.type === 'text') {\n return { type: 'text' as const, text: part.text };\n }\n // Convert image_url to Anthropic's image format\n const dataUrl = part.image_url.url;\n const match = dataUrl.match(/^data:(image\\/\\w+);base64,(.+)$/);\n if (match) {\n return {\n type: 'image' as const,\n source: {\n type: 'base64' as const,\n media_type: match[1]!,\n data: match[2]!,\n },\n };\n }\n // URL-based image\n return {\n type: 'image' as const,\n source: { type: 'url' as const, url: dataUrl },\n };\n });\n return { role: m.role, content: parts };\n });\n\n const body: Record<string, unknown> = {\n model: this.model,\n max_tokens: this.maxTokens,\n temperature: this.temperature,\n messages: anthropicMessages,\n };\n\n if (systemMsg) {\n body.system = typeof systemMsg.content === 'string'\n ? systemMsg.content\n : (systemMsg.content as LLMContentPart[]).map((p) => (p as any).text).join('\\n');\n }\n\n const resp = await fetch(this.url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': this.apiKey,\n 'anthropic-version': '2023-06-01',\n },\n body: JSON.stringify(body),\n });\n\n if (!resp.ok) {\n const text = await resp.text().catch(() => '');\n throw new LLMError(`Anthropic API error ${resp.status}: ${text}`);\n }\n\n const json = (await resp.json()) as any;\n const content = json?.content?.[0]?.text;\n if (typeof content !== 'string') {\n throw new LLMError('Anthropic response missing content[0].text');\n }\n return content;\n }\n\n async chatJSON<T = unknown>(messages: LLMMessage[]): Promise<T> {\n const text = await this.chat(messages);\n try {\n return JSON.parse(text) as T;\n } catch {\n const match = text.match(/```(?:json)?\\s*([\\s\\S]*?)```/);\n if (match) {\n return JSON.parse(match[1]!) as T;\n }\n throw new LLMError(`LLM response is not valid JSON: ${text.slice(0, 200)}`);\n }\n }\n}\n","import WebSocket from 'ws';\nimport type { BrowserType } from '../events/types.js';\nimport { SpiderEventEmitter } from '../events/emitter.js';\nimport { ConnectionError, AuthError, BackendUnavailableError, TimeoutError } from '../utils/errors.js';\nimport { logger } from '../utils/logger.js';\n\nexport interface TransportOptions {\n apiKey: string;\n serverUrl: string;\n browser: BrowserType;\n url?: string;\n captcha?: 'off' | 'detect' | 'solve';\n /** Stealth level (1-3). 0 or undefined = auto. Controls proxy quality tier on server. */\n stealthLevel?: number;\n /** WebSocket connect timeout in ms (default: 30000). */\n connectTimeoutMs?: number;\n /** CDP/BiDi command timeout in ms (default: 30000). Passed through to sessions. */\n commandTimeoutMs?: number;\n}\n\n/**\n * WebSocket transport to Spider's browser_server.\n *\n * Connects to `wss://browser.spider.cloud/v1/browser?token=TOKEN&browser=TYPE`,\n * handles reconnection on browser switch, and dispatches raw messages.\n */\nexport class Transport {\n private ws: WebSocket | null = null;\n private messageHandler: ((data: string) => void) | null = null;\n private currentBrowser: BrowserType;\n private opts: TransportOptions;\n private emitter: SpiderEventEmitter;\n private _stealthLevel: number;\n /** Generation counter — incremented on each connect. Prevents stale WS messages from being processed. */\n private generation = 0;\n /** Credits remaining from last upgrade response (x-sc header). */\n private _upgradeCredits: number | undefined;\n /** Stealth tier from last upgrade response (x-sr header). */\n private _upgradeStealthTier: number | undefined;\n /** Credits consumed during this session (from Spider.metering event). */\n private _sessionCreditsUsed: number | undefined;\n\n constructor(opts: TransportOptions, emitter: SpiderEventEmitter) {\n this.opts = opts;\n this.currentBrowser = opts.browser === 'auto' ? 'chrome' : opts.browser;\n this.emitter = emitter;\n this._stealthLevel = opts.stealthLevel ?? 0;\n }\n\n get browser(): BrowserType {\n return this.currentBrowser;\n }\n\n get connected(): boolean {\n return this.ws?.readyState === WebSocket.OPEN;\n }\n\n get stealthLevel(): number {\n return this._stealthLevel;\n }\n\n set stealthLevel(level: number) {\n this._stealthLevel = Math.max(0, Math.min(3, level));\n }\n\n /** Credits remaining from the WebSocket upgrade response. */\n get upgradeCredits(): number | undefined {\n return this._upgradeCredits;\n }\n\n /** Active stealth tier from the WebSocket upgrade response. */\n get upgradeStealthTier(): number | undefined {\n return this._upgradeStealthTier;\n }\n\n /** Credits consumed during this session (from server Spider.metering event). */\n get sessionCreditsUsed(): number | undefined {\n return this._sessionCreditsUsed;\n }\n\n /**\n * Request the current session cost from the server via Spider.getMetering.\n * This is a synchronous CDP-style request/response — no event-loop timing issues.\n * Returns the credits used so far, or the last known value if the request fails.\n */\n async requestMetering(timeoutMs = 3000): Promise<number> {\n if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {\n return this._sessionCreditsUsed ?? 0;\n }\n\n const meteringId = 2147483640; // High ID to avoid collisions with client CDP IDs\n\n return new Promise<number>((resolve) => {\n const timer = setTimeout(() => {\n resolve(this._sessionCreditsUsed ?? 0);\n }, timeoutMs);\n\n // Temporarily intercept the response by wrapping the message handler\n const origHandler = this.messageHandler;\n this.messageHandler = (data: string) => {\n // Check if this is our Spider.getMetering response\n if (data.includes(`\"id\":${meteringId}`)) {\n try {\n const msg = JSON.parse(data);\n if (msg.id === meteringId && msg.result?.credits_used !== undefined) {\n clearTimeout(timer);\n this._sessionCreditsUsed = msg.result.credits_used;\n this.messageHandler = origHandler;\n resolve(msg.result.credits_used);\n return;\n }\n } catch { /* not valid JSON, pass through */ }\n }\n // Forward all other messages to the original handler\n if (origHandler) origHandler(data);\n };\n\n try {\n this.send(JSON.stringify({ id: meteringId, method: 'Spider.getMetering' }));\n } catch {\n clearTimeout(timer);\n this.messageHandler = origHandler;\n resolve(this._sessionCreditsUsed ?? 0);\n }\n });\n }\n\n /** Set the handler that receives raw JSON messages from the WebSocket. */\n onMessage(handler: (data: string) => void): void {\n this.messageHandler = handler;\n }\n\n /** Connect to the browser_server WebSocket with retry. */\n async connect(maxAttempts = 3): Promise<void> {\n if (this.ws && this.ws.readyState === WebSocket.OPEN) {\n return;\n }\n\n let lastError: Error | undefined;\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n try {\n return await this.connectInternal();\n } catch (err) {\n lastError = err instanceof Error ? err : new Error(String(err));\n // Don't retry auth errors\n if (lastError instanceof AuthError) throw lastError;\n if (attempt < maxAttempts) {\n const backoff = 500 * attempt;\n logger.warn(`connect attempt ${attempt}/${maxAttempts} failed, retrying in ${backoff}ms`, {\n error: lastError.message,\n });\n await new Promise((r) => setTimeout(r, backoff));\n }\n }\n }\n throw lastError!;\n }\n\n /** Reconnect with a different browser type (used by retry engine). */\n async reconnect(browser: BrowserType): Promise<void> {\n const prev = this.currentBrowser;\n this.currentBrowser = browser;\n this.close();\n logger.info(`switching browser: ${prev} -> ${browser}`);\n return this.connectInternal();\n }\n\n /** Send a raw JSON string through the WebSocket. */\n send(data: string): void {\n if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {\n throw new ConnectionError('WebSocket is not connected');\n }\n this.ws.send(data);\n }\n\n /** Close the WebSocket connection, removing event listeners to prevent data mixing. */\n close(): void {\n if (this.ws) {\n const ws = this.ws;\n this.ws = null;\n\n // Remove non-error listeners first to prevent stale messages from being\n // routed to the new adapter after reconnect().\n ws.removeAllListeners('message');\n ws.removeAllListeners('open');\n ws.removeAllListeners('close');\n ws.removeAllListeners('upgrade');\n\n // Replace the error handler with a no-op. Doing removeAllListeners('error')\n // followed by on('error') is safer than removeAllListeners() which strips\n // ALL handlers — the ws library's Receiver can emit errors during terminate()\n // teardown, and any micro-gap without an error handler crashes the process.\n ws.removeAllListeners('error');\n ws.on('error', () => {});\n\n try {\n // terminate() immediately destroys the socket — no close handshake.\n // This prevents the old WS from processing any more incoming data.\n ws.terminate();\n } catch {\n // ignore\n }\n }\n }\n\n private buildUrl(): string {\n const base = this.opts.serverUrl.replace(/\\/$/, '');\n const params = new URLSearchParams();\n params.set('token', this.opts.apiKey);\n if (this.currentBrowser !== 'auto') {\n params.set('browser', this.currentBrowser);\n }\n if (this.opts.url) {\n params.set('url', this.opts.url);\n }\n if (this.opts.captcha && this.opts.captcha !== 'off') {\n params.set('ai_captcha', this.opts.captcha);\n }\n if (this._stealthLevel > 0) {\n params.set('s', String(this._stealthLevel));\n }\n return `${base}/v1/browser?${params.toString()}`;\n }\n\n private connectInternal(): Promise<void> {\n // Bump generation — any messages from previous WS instances with a stale\n // generation will be silently dropped (belt-and-suspenders with removeAllListeners).\n const gen = ++this.generation;\n\n return new Promise<void>((resolve, reject) => {\n const url = this.buildUrl();\n logger.debug(`connecting to ${url.replace(/token=[^&]+/, 'token=***')}`);\n\n const ws = new WebSocket(url);\n let resolved = false;\n\n const connectMs = this.opts.connectTimeoutMs ?? 30_000;\n const timeout = setTimeout(() => {\n if (!resolved) {\n resolved = true;\n ws.removeAllListeners();\n ws.on('error', () => {}); // Prevent unhandled error crash\n ws.terminate();\n reject(new TimeoutError(`WebSocket connection timeout (${connectMs}ms)`));\n }\n }, connectMs);\n\n ws.on('upgrade', (response: import('http').IncomingMessage) => {\n // Capture credit/stealth headers from the WebSocket upgrade response\n const sc = response.headers['x-sc'];\n const sr = response.headers['x-sr'];\n if (sc) {\n this._upgradeCredits = parseFloat(String(sc));\n }\n if (sr) {\n this._upgradeStealthTier = parseInt(String(sr), 10);\n }\n if (this._upgradeCredits !== undefined) {\n this.emitter.emit('metering', {\n credits: this._upgradeCredits,\n rate: this._upgradeStealthTier ?? 0,\n });\n }\n });\n\n ws.on('open', () => {\n if (!resolved) {\n resolved = true;\n clearTimeout(timeout);\n this.ws = ws;\n this.emitter.emit('ws.open', {});\n logger.info(`connected (browser=${this.currentBrowser}, stealth=${this._stealthLevel})`);\n resolve();\n }\n });\n\n ws.on('message', (raw: WebSocket.RawData) => {\n // Guard: ignore messages from stale WebSocket instances\n if (gen !== this.generation) return;\n const str = raw.toString();\n\n // Intercept Spider.metering events from the server.\n // Sent right before close with the exact session credits cost.\n if (str.includes('\"Spider.metering\"')) {\n try {\n const msg = JSON.parse(str);\n if (msg.method === 'Spider.metering' && msg.params?.credits_used !== undefined) {\n this._sessionCreditsUsed = msg.params.credits_used;\n this.emitter.emit('metering', {\n credits: this._upgradeCredits ?? 0,\n rate: this._upgradeStealthTier ?? 0,\n session_credits_used: msg.params.credits_used,\n });\n return; // Don't forward to CDP handler\n }\n } catch { /* not valid JSON, pass through */ }\n }\n\n if (this.messageHandler) {\n this.messageHandler(str);\n }\n });\n\n ws.on('close', (code: number, reason: Buffer) => {\n const reasonStr = reason.toString();\n // Only emit events for the current generation\n if (gen === this.generation) {\n this.emitter.emit('ws.close', { code, reason: reasonStr });\n }\n\n if (!resolved) {\n resolved = true;\n clearTimeout(timeout);\n if (code === 4001 || code === 4002) {\n reject(new AuthError(`Authentication failed (code ${code}): ${reasonStr}`));\n } else if (code === 4003) {\n reject(new BackendUnavailableError(`Backend unavailable: ${reasonStr}`));\n } else {\n reject(new ConnectionError(`WebSocket closed during connect: ${code} ${reasonStr}`, code));\n }\n }\n });\n\n ws.on('error', (err: Error) => {\n if (gen === this.generation) {\n this.emitter.emit('ws.error', { error: err });\n }\n if (!resolved) {\n resolved = true;\n clearTimeout(timeout);\n reject(new ConnectionError(`WebSocket error: ${err.message}`));\n }\n });\n });\n }\n}\n","export type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'silent';\n\nconst LEVELS: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n silent: 4,\n};\n\nexport class Logger {\n private level: number;\n\n constructor(level: LogLevel = 'info') {\n this.level = LEVELS[level];\n }\n\n setLevel(level: LogLevel): void {\n this.level = LEVELS[level];\n }\n\n debug(msg: string, data?: Record<string, unknown>): void {\n if (this.level <= LEVELS.debug) this.log('DEBUG', msg, data);\n }\n\n info(msg: string, data?: Record<string, unknown>): void {\n if (this.level <= LEVELS.info) this.log('INFO', msg, data);\n }\n\n warn(msg: string, data?: Record<string, unknown>): void {\n if (this.level <= LEVELS.warn) this.log('WARN', msg, data);\n }\n\n error(msg: string, data?: Record<string, unknown>): void {\n if (this.level <= LEVELS.error) this.log('ERROR', msg, data);\n }\n\n private log(level: string, msg: string, data?: Record<string, unknown>): void {\n const ts = new Date().toISOString();\n const extra = data ? ' ' + JSON.stringify(data) : '';\n const line = `[${ts}] ${level} spider-browser: ${msg}${extra}`;\n if (level === 'ERROR') {\n console.error(line);\n } else if (level === 'WARN') {\n console.warn(line);\n } else {\n console.log(line);\n }\n }\n}\n\n/** Shared default logger instance. */\nexport const logger = new Logger('info');\n","import type { Transport } from './transport.js';\nimport type { CDPResponse, CDPEvent } from './types.js';\nimport { NavigationError, ProtocolError, TimeoutError } from '../utils/errors.js';\nimport { logger } from '../utils/logger.js';\n\ntype PendingResolver = {\n resolve: (value: CDPResponse) => void;\n reject: (err: Error) => void;\n timer: ReturnType<typeof setTimeout>;\n};\n\ntype EventHandler = (params: Record<string, unknown>) => void;\n\n/**\n * CDP JSON-RPC session over the Spider WebSocket transport.\n *\n * The browser_server proxies to Chrome's BROWSER-LEVEL CDP target\n * (/devtools/browser/{id}). This means we must:\n * 1. Discover/create a page target\n * 2. Attach to it with flatten: true to get a sessionId\n * 3. Send all Page/Runtime/Input commands with that sessionId\n *\n * Used for Chrome, Chrome-H, Servo, and LightPanda browsers.\n */\nexport class CDPSession {\n private nextId = 1;\n private pending = new Map<number, PendingResolver>();\n private eventHandlers = new Map<string, Set<EventHandler>>();\n private transport: Transport;\n /** CDP session ID from Target.attachToTarget (required for page-level commands). */\n private targetSessionId: string | undefined;\n private commandTimeoutMs: number;\n\n constructor(transport: Transport, opts?: { commandTimeoutMs?: number }) {\n this.transport = transport;\n this.commandTimeoutMs = opts?.commandTimeoutMs ?? 30_000;\n }\n\n /** Get the attached target session ID. */\n get sessionId(): string | undefined {\n return this.targetSessionId;\n }\n\n /** Process a raw message from the transport. Returns true if handled. */\n handleMessage(data: string): boolean {\n let msg: any;\n try {\n msg = JSON.parse(data);\n } catch {\n return false;\n }\n\n // Response to a command (has \"id\")\n if (typeof msg.id === 'number') {\n const pending = this.pending.get(msg.id);\n if (pending) {\n this.pending.delete(msg.id);\n clearTimeout(pending.timer);\n pending.resolve(msg as CDPResponse);\n return true;\n }\n return false;\n }\n\n // Event (has \"method\", no \"id\")\n if (typeof msg.method === 'string') {\n const handlers = this.eventHandlers.get(msg.method);\n if (handlers) {\n const params = msg.params ?? {};\n for (const h of handlers) {\n try {\n h(params);\n } catch {\n // ignore handler errors\n }\n }\n }\n // Also fire wildcard handlers (for target discovery)\n const wildcardHandlers = this.eventHandlers.get('*');\n if (wildcardHandlers) {\n for (const h of wildcardHandlers) {\n try {\n h({ method: msg.method, ...(msg.params ?? {}) });\n } catch {\n // ignore\n }\n }\n }\n return true;\n }\n\n return false;\n }\n\n /** Send a CDP command and wait for the response. */\n async send(method: string, params?: Record<string, unknown>): Promise<CDPResponse> {\n const id = this.nextId++;\n const cmd: any = { id, method, params: params ?? {} };\n\n return new Promise<CDPResponse>((resolve, reject) => {\n const timer = setTimeout(() => {\n this.pending.delete(id);\n reject(new TimeoutError(`CDP command timeout: ${method} (${this.commandTimeoutMs}ms)`));\n }, this.commandTimeoutMs);\n\n this.pending.set(id, { resolve, reject, timer });\n try {\n this.transport.send(JSON.stringify(cmd));\n } catch (err) {\n this.pending.delete(id);\n clearTimeout(timer);\n reject(err);\n }\n });\n }\n\n /**\n * Send a CDP command scoped to the attached page session.\n * This is what you use for Page.*, Runtime.*, Input.* commands.\n */\n async sendToTarget(method: string, params?: Record<string, unknown>): Promise<CDPResponse> {\n if (!this.targetSessionId) {\n throw new ProtocolError('No target session — call attachToPage() first');\n }\n const id = this.nextId++;\n const cmd: any = {\n id,\n method,\n params: params ?? {},\n sessionId: this.targetSessionId,\n };\n\n return new Promise<CDPResponse>((resolve, reject) => {\n const timer = setTimeout(() => {\n this.pending.delete(id);\n reject(new TimeoutError(`CDP command timeout: ${method} (${this.commandTimeoutMs}ms)`));\n }, this.commandTimeoutMs);\n\n this.pending.set(id, { resolve, reject, timer });\n try {\n this.transport.send(JSON.stringify(cmd));\n } catch (err) {\n this.pending.delete(id);\n clearTimeout(timer);\n reject(err);\n }\n });\n }\n\n /** Subscribe to a CDP event. */\n on(method: string, handler: EventHandler): void {\n let set = this.eventHandlers.get(method);\n if (!set) {\n set = new Set();\n this.eventHandlers.set(method, set);\n }\n set.add(handler);\n }\n\n /** Unsubscribe from a CDP event. */\n off(method: string, handler: EventHandler): void {\n this.eventHandlers.get(method)?.delete(handler);\n }\n\n // -------------------------------------------------------------------\n // Browser-level target management\n // -------------------------------------------------------------------\n\n /**\n * Discover page targets, find or create one, attach to it, and enable\n * the required CDP domains (Page, Runtime).\n *\n * This is the key initialization step — without this, Page.navigate and\n * Runtime.evaluate won't work because we're connected at browser level.\n */\n async attachToPage(): Promise<string> {\n // Step 1: Enable target discovery\n await this.send('Target.setDiscoverTargets', { discover: true });\n\n // Step 2: Always create a fresh page target.\n // When multiple sessions share a Chrome instance, reusing existing page targets\n // causes content contamination (wrong cookies, storage, cached content).\n // The server injects browserContextId into Target.createTarget to isolate\n // each session's pages in their own browser context.\n let pageTargetId: string | undefined;\n logger.debug('creating fresh page target for session isolation');\n const createResp = await this.send('Target.createTarget', { url: 'about:blank' });\n pageTargetId = (createResp.result as any)?.targetId;\n if (!pageTargetId) {\n throw new ProtocolError('Failed to create page target');\n }\n logger.debug(`created page target: ${pageTargetId}`);\n\n // Step 4: Attach to the target with flatten: true\n // flatten: true gives us a flat session — commands with sessionId go directly to the target\n const attachResp = await this.send('Target.attachToTarget', {\n targetId: pageTargetId,\n flatten: true,\n });\n\n // The sessionId comes either from the response or from a Target.attachedToTarget event\n let sessionId = (attachResp.result as any)?.sessionId;\n\n if (!sessionId) {\n // Some Chrome versions send the sessionId via an event instead\n // Wait briefly for the event\n sessionId = await new Promise<string>((resolve, reject) => {\n const timeout = setTimeout(() => {\n this.off('Target.attachedToTarget', handler);\n reject(new TimeoutError('Timeout waiting for Target.attachedToTarget event'));\n }, 5000);\n\n const handler = (params: Record<string, unknown>) => {\n const sid = (params as any).sessionId;\n if (sid) {\n clearTimeout(timeout);\n this.off('Target.attachedToTarget', handler);\n resolve(sid);\n }\n };\n this.on('Target.attachedToTarget', handler);\n });\n }\n\n this.targetSessionId = sessionId;\n logger.info(`attached to page target`, { targetId: pageTargetId, sessionId });\n\n // Step 5: Enable domains on the target session\n await this.sendToTarget('Page.enable');\n await this.sendToTarget('Runtime.enable');\n\n return sessionId;\n }\n\n // -------------------------------------------------------------------\n // High-level CDP commands (all use sendToTarget for page-scoped ops)\n // -------------------------------------------------------------------\n\n /** Capture a screenshot as base64 PNG (10s timeout to avoid blocking on heavy pages). */\n async captureScreenshot(): Promise<string> {\n const screenshotTimeout = Math.min(this.commandTimeoutMs, 10_000);\n const id = this.nextId++;\n const cmd: any = {\n id,\n method: 'Page.captureScreenshot',\n params: { format: 'png' },\n sessionId: this.targetSessionId,\n };\n\n const resp = await new Promise<CDPResponse>((resolve, reject) => {\n const timer = setTimeout(() => {\n this.pending.delete(id);\n reject(new TimeoutError(`CDP command timeout: Page.captureScreenshot (${screenshotTimeout}ms)`));\n }, screenshotTimeout);\n\n this.pending.set(id, { resolve, reject, timer });\n try {\n this.transport.send(JSON.stringify(cmd));\n } catch (err) {\n this.pending.delete(id);\n clearTimeout(timer);\n reject(err);\n }\n });\n\n const data = resp.result?.['data'];\n if (typeof data !== 'string') {\n throw new ProtocolError('captureScreenshot: missing result.data');\n }\n return data;\n }\n\n /** Get full page HTML. */\n async getHTML(): Promise<string> {\n const resp = await this.sendToTarget('Runtime.evaluate', {\n expression: 'document.documentElement.outerHTML',\n returnByValue: true,\n });\n return this.extractEvalValue(resp) as string;\n }\n\n /** Evaluate a JavaScript expression and return the value. */\n async evaluate(expression: string): Promise<unknown> {\n const resp = await this.sendToTarget('Runtime.evaluate', {\n expression,\n returnByValue: true,\n });\n return this.extractEvalValue(resp);\n }\n\n /** Wait for a CDP event to fire, with timeout. Returns true if event fired, false on timeout. */\n private waitForEvent(method: string, timeoutMs: number): Promise<boolean> {\n return new Promise<boolean>((resolve) => {\n const timer = setTimeout(() => {\n this.off(method, handler);\n resolve(false);\n }, timeoutMs);\n\n const handler = () => {\n clearTimeout(timer);\n this.off(method, handler);\n resolve(true);\n };\n this.on(method, handler);\n });\n }\n\n /** Navigate to a URL and wait for the page to load. */\n async navigate(url: string): Promise<void> {\n // Start listening for load events BEFORE sending navigate\n const loadPromise = this.waitForEvent('Page.loadEventFired', 30_000);\n const stopPromise = this.waitForEvent('Page.frameStoppedLoading', 35_000);\n\n const resp = await this.sendToTarget('Page.navigate', { url });\n\n // Check for navigation errors (e.g. net::ERR_NAME_NOT_RESOLVED)\n const errorText = (resp.result as any)?.errorText;\n if (errorText) {\n // Clean up event listeners\n loadPromise.catch(() => {});\n stopPromise.catch(() => {});\n // Retryable nav errors: close connection and try fresh\n if (isRetryableNavError(errorText)) {\n throw new NavigationError(`Navigation failed: ${errorText}`);\n }\n throw new ProtocolError(`Navigation failed: ${errorText}`);\n }\n\n // Wait for load event; if it times out, fall back to frameStoppedLoading\n const loaded = await loadPromise;\n if (!loaded) {\n // loadEventFired timed out — wait briefly for frameStoppedLoading\n await stopPromise;\n // Proceed silently even if both timed out (some pages never fire load events)\n }\n }\n\n /** Dispatch a mouse event. */\n async dispatchMouseEvent(\n type: string,\n x: number,\n y: number,\n button: string = 'none',\n clickCount: number = 0,\n ): Promise<void> {\n await this.sendToTarget('Input.dispatchMouseEvent', { type, x, y, button, clickCount });\n }\n\n /** Click at coordinates (mouseMoved -> mousePressed -> mouseReleased). */\n async clickPoint(x: number, y: number): Promise<void> {\n await this.dispatchMouseEvent('mouseMoved', x, y, 'none', 0);\n await this.dispatchMouseEvent('mousePressed', x, y, 'left', 1);\n await this.dispatchMouseEvent('mouseReleased', x, y, 'left', 1);\n }\n\n /** Right-click at coordinates. */\n async rightClickPoint(x: number, y: number): Promise<void> {\n await this.dispatchMouseEvent('mouseMoved', x, y, 'none', 0);\n await this.dispatchMouseEvent('mousePressed', x, y, 'right', 1);\n await this.dispatchMouseEvent('mouseReleased', x, y, 'right', 1);\n }\n\n /** Double-click at coordinates. */\n async doubleClickPoint(x: number, y: number): Promise<void> {\n await this.dispatchMouseEvent('mouseMoved', x, y, 'none', 0);\n await this.dispatchMouseEvent('mousePressed', x, y, 'left', 1);\n await this.dispatchMouseEvent('mouseReleased', x, y, 'left', 1);\n await this.dispatchMouseEvent('mousePressed', x, y, 'left', 2);\n await this.dispatchMouseEvent('mouseReleased', x, y, 'left', 2);\n }\n\n /** Click and hold at coordinates for a duration. */\n async clickHoldPoint(x: number, y: number, holdMs: number): Promise<void> {\n await this.dispatchMouseEvent('mouseMoved', x, y, 'none', 0);\n await this.dispatchMouseEvent('mousePressed', x, y, 'left', 1);\n await sleep(holdMs);\n await this.dispatchMouseEvent('mouseReleased', x, y, 'left', 1);\n }\n\n /** Hover (mouseMoved only). */\n async hoverPoint(x: number, y: number): Promise<void> {\n await this.dispatchMouseEvent('mouseMoved', x, y, 'none', 0);\n }\n\n /** Smooth drag from point to point (10-step interpolation). */\n async dragPoint(fromX: number, fromY: number, toX: number, toY: number): Promise<void> {\n const steps = 10;\n await this.dispatchMouseEvent('mouseMoved', fromX, fromY, 'none', 0);\n await this.dispatchMouseEvent('mousePressed', fromX, fromY, 'left', 1);\n for (let i = 1; i <= steps; i++) {\n const t = i / steps;\n const x = fromX + (toX - fromX) * t;\n const y = fromY + (toY - fromY) * t;\n await this.dispatchMouseEvent('mouseMoved', x, y, 'left', 0);\n await sleep(16);\n }\n await this.dispatchMouseEvent('mouseReleased', toX, toY, 'left', 1);\n }\n\n /** Insert text via Input.insertText. */\n async insertText(text: string): Promise<void> {\n await this.sendToTarget('Input.insertText', { text });\n }\n\n /** Press a key (keyDown + keyUp). */\n async pressKey(key: string, code: string, keyCode: number): Promise<void> {\n await this.sendToTarget('Input.dispatchKeyEvent', {\n type: 'keyDown',\n key,\n code,\n windowsVirtualKeyCode: keyCode,\n text: key,\n });\n await this.sendToTarget('Input.dispatchKeyEvent', {\n type: 'keyUp',\n key,\n code,\n windowsVirtualKeyCode: keyCode,\n });\n }\n\n /** Send keyDown event. */\n async keyDown(key: string, code: string, keyCode: number): Promise<void> {\n await this.sendToTarget('Input.dispatchKeyEvent', {\n type: 'keyDown',\n key,\n code,\n windowsVirtualKeyCode: keyCode,\n text: key,\n });\n }\n\n /** Send keyUp event. */\n async keyUp(key: string, code: string, keyCode: number): Promise<void> {\n await this.sendToTarget('Input.dispatchKeyEvent', {\n type: 'keyUp',\n key,\n code,\n windowsVirtualKeyCode: keyCode,\n });\n }\n\n /** Set viewport via Emulation.setDeviceMetricsOverride. */\n async setViewport(\n width: number,\n height: number,\n deviceScaleFactor: number = 2,\n mobile: boolean = false,\n ): Promise<void> {\n await this.sendToTarget('Emulation.setDeviceMetricsOverride', {\n width,\n height,\n deviceScaleFactor,\n mobile,\n });\n }\n\n /** Clean up all pending commands and event handlers. Rejects in-flight commands. */\n destroy(): void {\n // Snapshot and clear first to prevent re-entrant issues from reject callbacks\n const pendingSnapshot = [...this.pending.values()];\n this.pending.clear();\n this.eventHandlers.clear();\n this.targetSessionId = undefined;\n\n for (const pending of pendingSnapshot) {\n clearTimeout(pending.timer);\n pending.reject(new Error('session destroyed'));\n }\n }\n\n private extractEvalValue(resp: CDPResponse): unknown {\n if (resp.error) {\n throw new ProtocolError(`CDP error: ${resp.error.message}`);\n }\n const result = resp.result as any;\n return result?.result?.value;\n }\n}\n\n/** Navigation errors that are retryable by closing the connection and reconnecting. */\nconst RETRYABLE_NAV_ERRORS = [\n 'net::ERR_ABORTED',\n 'net::ERR_CONNECTION_RESET',\n 'net::ERR_CONNECTION_CLOSED',\n 'net::ERR_CONNECTION_REFUSED',\n 'net::ERR_CONNECTION_TIMED_OUT',\n 'net::ERR_TIMED_OUT',\n 'net::ERR_EMPTY_RESPONSE',\n 'net::ERR_SOCKET_NOT_CONNECTED',\n 'net::ERR_NETWORK_CHANGED',\n];\n\nfunction isRetryableNavError(errorText: string): boolean {\n return RETRYABLE_NAV_ERRORS.some((e) => errorText.includes(e));\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((r) => setTimeout(r, ms));\n}\n","import type { Transport } from './transport.js';\nimport type { BiDiResponse } from './types.js';\nimport { ProtocolError, TimeoutError } from '../utils/errors.js';\n\ntype PendingResolver = {\n resolve: (value: BiDiResponse) => void;\n reject: (err: Error) => void;\n timer: ReturnType<typeof setTimeout>;\n};\n\ntype EventHandler = (params: Record<string, unknown>) => void;\n\n/**\n * WebDriver BiDi session over the Spider WebSocket transport.\n *\n * Used for Firefox browser connections. Mirrors CDPSession's interface\n * but speaks the BiDi protocol.\n */\nexport class BiDiSession {\n private nextId = 1;\n private pending = new Map<number, PendingResolver>();\n private eventHandlers = new Map<string, Set<EventHandler>>();\n private transport: Transport;\n private browsingContext: string | undefined;\n private commandTimeoutMs: number;\n\n constructor(transport: Transport, opts?: { commandTimeoutMs?: number }) {\n this.transport = transport;\n this.commandTimeoutMs = opts?.commandTimeoutMs ?? 30_000;\n }\n\n get context(): string | undefined {\n return this.browsingContext;\n }\n\n /** Process a raw message from the transport. Returns true if handled. */\n handleMessage(data: string): boolean {\n let msg: any;\n try {\n msg = JSON.parse(data);\n } catch {\n return false;\n }\n\n // Response (has \"id\" and \"type\")\n if (typeof msg.id === 'number' && typeof msg.type === 'string') {\n const pending = this.pending.get(msg.id);\n if (pending) {\n this.pending.delete(msg.id);\n clearTimeout(pending.timer);\n pending.resolve(msg as BiDiResponse);\n return true;\n }\n return false;\n }\n\n // Event (has \"type\": \"event\" and \"method\")\n if (msg.type === 'event' && typeof msg.method === 'string') {\n const handlers = this.eventHandlers.get(msg.method);\n if (handlers) {\n const params = msg.params ?? {};\n for (const h of handlers) {\n try {\n h(params);\n } catch {\n // ignore\n }\n }\n }\n return true;\n }\n\n return false;\n }\n\n /** Send a BiDi command and wait for the response. */\n async send(method: string, params: Record<string, unknown>): Promise<BiDiResponse> {\n const id = this.nextId++;\n const cmd = { id, method, params };\n\n return new Promise<BiDiResponse>((resolve, reject) => {\n const timer = setTimeout(() => {\n this.pending.delete(id);\n reject(new TimeoutError(`BiDi command timeout: ${method} (${this.commandTimeoutMs}ms)`));\n }, this.commandTimeoutMs);\n\n this.pending.set(id, { resolve, reject, timer });\n try {\n this.transport.send(JSON.stringify(cmd));\n } catch (err) {\n this.pending.delete(id);\n clearTimeout(timer);\n reject(err);\n }\n });\n }\n\n /** Subscribe to a BiDi event. */\n on(method: string, handler: EventHandler): void {\n let set = this.eventHandlers.get(method);\n if (!set) {\n set = new Set();\n this.eventHandlers.set(method, set);\n }\n set.add(handler);\n }\n\n /** Unsubscribe from a BiDi event. */\n off(method: string, handler: EventHandler): void {\n this.eventHandlers.get(method)?.delete(handler);\n }\n\n // -------------------------------------------------------------------\n // High-level BiDi commands\n // -------------------------------------------------------------------\n\n /**\n * Get or create a browsing context.\n *\n * The browser_server's Firefox relay proxies to geckodriver which already has\n * a session with a browsing context. We try multiple strategies:\n * 1. browsingContext.getTree (standard BiDi)\n * 2. session.status (to get session info, then extract context)\n * 3. browsingContext.create as last resort\n *\n * If all discovery fails, we set a placeholder context that gets replaced\n * on the first successful navigate response.\n */\n async getOrCreateContext(): Promise<string> {\n if (this.browsingContext) return this.browsingContext;\n\n // Strategy 1: Try browsingContext.getTree with a short timeout\n try {\n const savedTimeout = this.commandTimeoutMs;\n try {\n this.commandTimeoutMs = 5000;\n const resp = await this.send('browsingContext.getTree', {});\n const contexts = (resp.result as any)?.contexts;\n if (Array.isArray(contexts) && contexts.length > 0) {\n this.browsingContext = contexts[0].context;\n return this.browsingContext!;\n }\n } finally {\n this.commandTimeoutMs = savedTimeout;\n }\n } catch {\n // getTree not supported or timed out — try other strategies\n }\n\n // Strategy 2: Try creating a new context\n try {\n const savedTimeout = this.commandTimeoutMs;\n try {\n this.commandTimeoutMs = 5000;\n const createResp = await this.send('browsingContext.create', { type: 'tab' });\n const ctx = (createResp.result as any)?.context;\n if (ctx) {\n this.browsingContext = ctx;\n return this.browsingContext!;\n }\n } finally {\n this.commandTimeoutMs = savedTimeout;\n }\n } catch {\n // create not supported either\n }\n\n // Strategy 3: Use a placeholder — the geckodriver session already has a context,\n // and browsingContext.navigate/script.evaluate commands will use it implicitly.\n // We'll extract the real context ID from the first navigation response.\n this.browsingContext = '__default__';\n return this.browsingContext;\n }\n\n /** Set the browsing context (called when we discover it from a response). */\n setContext(contextId: string): void {\n this.browsingContext = contextId;\n }\n\n /** Navigate to a URL. */\n async navigate(url: string): Promise<void> {\n const ctx = await this.getOrCreateContext();\n const resp = await this.send('browsingContext.navigate', {\n context: ctx,\n url,\n wait: 'complete',\n });\n // Extract real context from response if we used a placeholder\n if (this.browsingContext === '__default__') {\n const realCtx = (resp.result as any)?.navigation\n ? (resp as any)?.params?.context\n : undefined;\n if (realCtx) {\n this.browsingContext = realCtx;\n }\n }\n }\n\n /** Capture a screenshot as base64 PNG. */\n async captureScreenshot(): Promise<string> {\n const ctx = await this.getOrCreateContext();\n const resp = await this.send('browsingContext.captureScreenshot', { context: ctx });\n const data = (resp.result as any)?.data;\n if (typeof data !== 'string') {\n throw new ProtocolError('captureScreenshot: missing result.data');\n }\n return data;\n }\n\n /**\n * Evaluate JavaScript and return the value.\n *\n * BiDi script.evaluate returns results in this format:\n * { result: { type: \"string\", value: \"...\" } }\n * { result: { type: \"number\", value: 42 } }\n * { result: { type: \"boolean\", value: true } }\n * { result: { type: \"object\", value: [...entries...] } }\n * { result: { type: \"null\" } }\n * { result: { type: \"undefined\" } }\n * { result: { type: \"array\", value: [...] } }\n */\n async evaluate(expression: string): Promise<unknown> {\n const ctx = await this.getOrCreateContext();\n const resp = await this.send('script.evaluate', {\n expression,\n target: { context: ctx },\n awaitPromise: false,\n resultOwnership: 'none',\n });\n if (resp.type === 'error') {\n throw new ProtocolError(`BiDi script error: ${resp.message ?? resp.error}`);\n }\n // BiDi result is nested: result.result.value or result.value depending on spec version\n const resultObj = (resp.result as any)?.result ?? resp.result;\n return this.extractBiDiValue(resultObj);\n }\n\n /** Extract a JS value from a BiDi remote value object. */\n private extractBiDiValue(remoteValue: any): unknown {\n if (!remoteValue) return undefined;\n const type = remoteValue.type;\n switch (type) {\n case 'undefined':\n return undefined;\n case 'null':\n return null;\n case 'string':\n case 'number':\n case 'boolean':\n case 'bigint':\n return remoteValue.value;\n case 'array':\n if (Array.isArray(remoteValue.value)) {\n return remoteValue.value.map((v: any) => this.extractBiDiValue(v));\n }\n return remoteValue.value;\n case 'object':\n if (Array.isArray(remoteValue.value)) {\n // BiDi objects come as [[key, valueObj], ...] pairs\n const obj: Record<string, unknown> = {};\n for (const entry of remoteValue.value) {\n if (Array.isArray(entry) && entry.length === 2) {\n const key = typeof entry[0] === 'string' ? entry[0] : entry[0]?.value ?? String(entry[0]);\n obj[key] = this.extractBiDiValue(entry[1]);\n }\n }\n return obj;\n }\n return remoteValue.value;\n default:\n // Fallback — return value directly if present\n return remoteValue.value ?? remoteValue;\n }\n }\n\n /** Get full page HTML. */\n async getHTML(): Promise<string> {\n return (await this.evaluate('document.documentElement.outerHTML')) as string;\n }\n\n /**\n * Perform actions (BiDi input.performActions).\n * This is the BiDi way to do mouse/keyboard events.\n */\n async performActions(actions: unknown[]): Promise<void> {\n const ctx = await this.getOrCreateContext();\n await this.send('input.performActions', {\n context: ctx,\n actions,\n });\n }\n\n /** Click at coordinates via BiDi input actions. */\n async clickPoint(x: number, y: number): Promise<void> {\n await this.performActions([\n {\n type: 'pointer',\n id: 'mouse',\n actions: [\n { type: 'pointerMove', x: Math.round(x), y: Math.round(y) },\n { type: 'pointerDown', button: 0 },\n { type: 'pointerUp', button: 0 },\n ],\n },\n ]);\n }\n\n /** Insert text via BiDi input actions. */\n async insertText(text: string): Promise<void> {\n const actions = text.split('').map((ch) => [\n { type: 'keyDown', value: ch },\n { type: 'keyUp', value: ch },\n ]).flat();\n await this.performActions([{ type: 'key', id: 'keyboard', actions }]);\n }\n\n /** Clean up all pending commands and event handlers. Rejects in-flight commands. */\n destroy(): void {\n // Snapshot and clear first to prevent re-entrant issues from reject callbacks\n const pendingSnapshot = [...this.pending.values()];\n this.pending.clear();\n this.eventHandlers.clear();\n this.browsingContext = undefined;\n\n for (const pending of pendingSnapshot) {\n clearTimeout(pending.timer);\n pending.reject(new Error('session destroyed'));\n }\n }\n}\n","/** CDP JSON-RPC request. */\nexport interface CDPCommand {\n id: number;\n method: string;\n params?: Record<string, unknown>;\n sessionId?: string;\n}\n\n/** CDP JSON-RPC response. */\nexport interface CDPResponse {\n id: number;\n result?: Record<string, unknown>;\n error?: { code: number; message: string; data?: string };\n sessionId?: string;\n}\n\n/** CDP event (no id). */\nexport interface CDPEvent {\n method: string;\n params?: Record<string, unknown>;\n sessionId?: string;\n}\n\n/** BiDi command. */\nexport interface BiDiCommand {\n id: number;\n method: string;\n params: Record<string, unknown>;\n}\n\n/** BiDi response. */\nexport interface BiDiResponse {\n id: number;\n type: 'success' | 'error';\n result?: Record<string, unknown>;\n error?: string;\n message?: string;\n}\n\n/** BiDi event. */\nexport interface BiDiEvent {\n type: 'event';\n method: string;\n params: Record<string, unknown>;\n}\n\n/** Spider-specific event sent by browser_server through the WebSocket. */\nexport interface SpiderProtocolEvent {\n method: string;\n params: Record<string, unknown>;\n}\n\n/** A message arriving from the WebSocket — either protocol or Spider event. */\nexport type IncomingMessage =\n | { kind: 'cdp-response'; data: CDPResponse }\n | { kind: 'cdp-event'; data: CDPEvent }\n | { kind: 'bidi-response'; data: BiDiResponse }\n | { kind: 'bidi-event'; data: BiDiEvent }\n | { kind: 'spider-event'; data: SpiderProtocolEvent };\n\n/** Key mapping for Input.dispatchKeyEvent (mirrors inject.rs key_params). */\nexport const KEY_MAP: Record<string, { key: string; code: string; keyCode: number }> = {\n Enter: { key: 'Enter', code: 'Enter', keyCode: 13 },\n Tab: { key: 'Tab', code: 'Tab', keyCode: 9 },\n Escape: { key: 'Escape', code: 'Escape', keyCode: 27 },\n Backspace: { key: 'Backspace', code: 'Backspace', keyCode: 8 },\n Delete: { key: 'Delete', code: 'Delete', keyCode: 46 },\n Space: { key: ' ', code: 'Space', keyCode: 32 },\n ' ': { key: ' ', code: 'Space', keyCode: 32 },\n ArrowLeft: { key: 'ArrowLeft', code: 'ArrowLeft', keyCode: 37 },\n ArrowUp: { key: 'ArrowUp', code: 'ArrowUp', keyCode: 38 },\n ArrowRight: { key: 'ArrowRight', code: 'ArrowRight', keyCode: 39 },\n ArrowDown: { key: 'ArrowDown', code: 'ArrowDown', keyCode: 40 },\n Home: { key: 'Home', code: 'Home', keyCode: 36 },\n End: { key: 'End', code: 'End', keyCode: 35 },\n PageUp: { key: 'PageUp', code: 'PageUp', keyCode: 33 },\n PageDown: { key: 'PageDown', code: 'PageDown', keyCode: 34 },\n};\n\nexport function getKeyParams(keyName: string): { key: string; code: string; keyCode: number } {\n return KEY_MAP[keyName] ?? { key: keyName, code: keyName, keyCode: 0 };\n}\n","import type { Transport } from './transport.js';\nimport { CDPSession } from './cdp-session.js';\nimport { BiDiSession } from './bidi-session.js';\nimport { SpiderEventEmitter } from '../events/emitter.js';\nimport type { BrowserType } from '../events/types.js';\nimport { getKeyParams } from './types.js';\nimport { logger } from '../utils/logger.js';\n\n/**\n * Unified protocol interface that wraps either CDPSession or BiDiSession\n * based on the browser type.\n *\n * - chrome, chrome-new, chrome-h, servo, lightpanda → CDP\n * - firefox → BiDi\n */\nexport interface ProtocolAdapterOptions {\n commandTimeoutMs?: number;\n}\n\nexport class ProtocolAdapter {\n private cdp: CDPSession | null = null;\n private bidi: BiDiSession | null = null;\n private transport: Transport;\n private emitter: SpiderEventEmitter;\n private protocol: 'cdp' | 'bidi' | 'auto';\n private adapterOpts: ProtocolAdapterOptions;\n\n constructor(transport: Transport, emitter: SpiderEventEmitter, browser: BrowserType, opts?: ProtocolAdapterOptions) {\n this.transport = transport;\n this.emitter = emitter;\n this.adapterOpts = opts ?? {};\n\n const sessionOpts = opts?.commandTimeoutMs ? { commandTimeoutMs: opts.commandTimeoutMs } : undefined;\n\n // Determine protocol from browser type\n if (browser === 'auto') {\n this.protocol = 'auto';\n // Don't create sessions yet — auto-detect in init()\n } else if (browser === 'firefox') {\n this.protocol = 'bidi';\n this.bidi = new BiDiSession(transport, sessionOpts);\n } else {\n this.protocol = 'cdp';\n this.cdp = new CDPSession(transport, sessionOpts);\n }\n\n // Wire up message routing\n transport.onMessage((data: string) => this.routeMessage(data));\n }\n\n /** Whether this adapter uses CDP or BiDi (or 'auto' before init). */\n get protocolType(): 'cdp' | 'bidi' | 'auto' {\n return this.protocol;\n }\n\n /** Route incoming WebSocket messages to the right session + spider events. */\n private routeMessage(data: string): void {\n // Check for Spider.* events first\n try {\n const msg = JSON.parse(data);\n if (typeof msg.method === 'string' && msg.method.startsWith('Spider.')) {\n this.handleSpiderEvent(msg.method, msg.params ?? {});\n return;\n }\n } catch {\n // ignore parse errors for spider event check\n }\n\n // Route to protocol session\n if (this.cdp) {\n this.cdp.handleMessage(data);\n } else if (this.bidi) {\n this.bidi.handleMessage(data);\n }\n }\n\n /** Handle Spider.* custom events from the browser_server. */\n private handleSpiderEvent(method: string, params: Record<string, unknown>): void {\n switch (method) {\n case 'Spider.captchaDetected':\n this.emitter.emit('captcha.detected', {\n types: (params.types as string[]) ?? [],\n url: (params.url as string) ?? '',\n });\n break;\n case 'Spider.captchaSolving':\n this.emitter.emit('captcha.solving', {\n types: (params.types as string[]) ?? [],\n url: (params.url as string) ?? '',\n round: (params.round as number) ?? 0,\n });\n break;\n case 'Spider.captchaSolved':\n this.emitter.emit('captcha.solved', { url: (params.url as string) ?? '' });\n break;\n case 'Spider.captchaFailed':\n this.emitter.emit('captcha.failed', {\n url: (params.url as string) ?? '',\n reason: (params.reason as string) ?? '',\n });\n break;\n default:\n logger.debug(`unhandled Spider event: ${method}`, params);\n }\n }\n\n // -------------------------------------------------------------------\n // Unified interface — all methods work for both CDP and BiDi\n // -------------------------------------------------------------------\n\n /**\n * Initialize the protocol session.\n *\n * For CDP (Chrome/Servo/LightPanda): discovers page targets, attaches to one\n * with flatten:true to get a sessionId, then enables Page + Runtime domains\n * on that target. This is required because browser_server proxies to Chrome's\n * browser-level CDP endpoint.\n *\n * For BiDi (Firefox): gets or creates a browsing context.\n *\n * For \"auto\" mode: tries CDP first (Target.setDiscoverTargets). If it fails\n * (e.g. we actually got a BiDi session), falls back to BiDi.\n */\n async init(): Promise<void> {\n if (this.protocol === 'auto') {\n await this.autoDetectAndInit();\n return;\n }\n\n if (this.cdp) {\n await this.cdp.attachToPage();\n } else if (this.bidi) {\n await this.bidi.getOrCreateContext();\n }\n }\n\n /**\n * Auto-detect protocol by trying CDP first, falling back to BiDi.\n * Used when browser type is \"auto\" and we don't know what the server gave us.\n */\n private async autoDetectAndInit(): Promise<void> {\n const sessionOpts = this.adapterOpts.commandTimeoutMs\n ? { commandTimeoutMs: this.adapterOpts.commandTimeoutMs }\n : undefined;\n\n // Try CDP first (most common — Chrome is the default)\n try {\n this.cdp = new CDPSession(this.transport, sessionOpts);\n // Re-wire message routing to include CDP\n this.transport.onMessage((data: string) => this.routeMessage(data));\n await this.cdp.attachToPage();\n this.protocol = 'cdp';\n logger.info('auto-detected CDP protocol');\n return;\n } catch {\n // CDP failed — likely a BiDi session\n this.cdp?.destroy();\n this.cdp = null;\n }\n\n // Try BiDi\n this.bidi = new BiDiSession(this.transport, sessionOpts);\n this.transport.onMessage((data: string) => this.routeMessage(data));\n await this.bidi.getOrCreateContext();\n this.protocol = 'bidi';\n logger.info('auto-detected BiDi protocol');\n }\n\n /** Navigate to URL. */\n async navigate(url: string): Promise<void> {\n if (this.cdp) {\n await this.cdp.navigate(url);\n } else {\n await this.bidi!.navigate(url);\n }\n }\n\n /** Get page HTML. */\n async getHTML(): Promise<string> {\n if (this.cdp) {\n return this.cdp.getHTML();\n }\n return this.bidi!.getHTML();\n }\n\n /** Evaluate JavaScript expression. */\n async evaluate(expression: string): Promise<unknown> {\n if (this.cdp) {\n return this.cdp.evaluate(expression);\n }\n return this.bidi!.evaluate(expression);\n }\n\n /** Capture screenshot as base64 PNG. */\n async captureScreenshot(): Promise<string> {\n if (this.cdp) {\n return this.cdp.captureScreenshot();\n }\n return this.bidi!.captureScreenshot();\n }\n\n /** Click at viewport coordinates. */\n async clickPoint(x: number, y: number): Promise<void> {\n if (this.cdp) {\n await this.cdp.clickPoint(x, y);\n } else {\n await this.bidi!.clickPoint(x, y);\n }\n }\n\n /** Right-click at coordinates. */\n async rightClickPoint(x: number, y: number): Promise<void> {\n if (this.cdp) {\n await this.cdp.rightClickPoint(x, y);\n } else {\n // BiDi right-click via pointer actions\n await this.bidi!.performActions([\n {\n type: 'pointer',\n id: 'mouse',\n actions: [\n { type: 'pointerMove', x: Math.round(x), y: Math.round(y) },\n { type: 'pointerDown', button: 2 },\n { type: 'pointerUp', button: 2 },\n ],\n },\n ]);\n }\n }\n\n /** Double-click at coordinates. */\n async doubleClickPoint(x: number, y: number): Promise<void> {\n if (this.cdp) {\n await this.cdp.doubleClickPoint(x, y);\n } else {\n await this.bidi!.performActions([\n {\n type: 'pointer',\n id: 'mouse',\n actions: [\n { type: 'pointerMove', x: Math.round(x), y: Math.round(y) },\n { type: 'pointerDown', button: 0 },\n { type: 'pointerUp', button: 0 },\n { type: 'pointerDown', button: 0 },\n { type: 'pointerUp', button: 0 },\n ],\n },\n ]);\n }\n }\n\n /** Click and hold at coordinates. */\n async clickHoldPoint(x: number, y: number, holdMs: number): Promise<void> {\n if (this.cdp) {\n await this.cdp.clickHoldPoint(x, y, holdMs);\n } else {\n await this.bidi!.performActions([\n {\n type: 'pointer',\n id: 'mouse',\n actions: [\n { type: 'pointerMove', x: Math.round(x), y: Math.round(y) },\n { type: 'pointerDown', button: 0 },\n { type: 'pause', duration: holdMs },\n { type: 'pointerUp', button: 0 },\n ],\n },\n ]);\n }\n }\n\n /** Hover at coordinates. */\n async hoverPoint(x: number, y: number): Promise<void> {\n if (this.cdp) {\n await this.cdp.hoverPoint(x, y);\n } else {\n await this.bidi!.performActions([\n {\n type: 'pointer',\n id: 'mouse',\n actions: [{ type: 'pointerMove', x: Math.round(x), y: Math.round(y) }],\n },\n ]);\n }\n }\n\n /** Smooth drag from point to point. */\n async dragPoint(fromX: number, fromY: number, toX: number, toY: number): Promise<void> {\n if (this.cdp) {\n await this.cdp.dragPoint(fromX, fromY, toX, toY);\n } else {\n const steps = 10;\n const actions: any[] = [\n { type: 'pointerMove', x: Math.round(fromX), y: Math.round(fromY) },\n { type: 'pointerDown', button: 0 },\n ];\n for (let i = 1; i <= steps; i++) {\n const t = i / steps;\n actions.push({\n type: 'pointerMove',\n x: Math.round(fromX + (toX - fromX) * t),\n y: Math.round(fromY + (toY - fromY) * t),\n duration: 16,\n });\n }\n actions.push({ type: 'pointerUp', button: 0 });\n await this.bidi!.performActions([{ type: 'pointer', id: 'mouse', actions }]);\n }\n }\n\n /** Insert text. */\n async insertText(text: string): Promise<void> {\n if (this.cdp) {\n await this.cdp.insertText(text);\n } else {\n await this.bidi!.insertText(text);\n }\n }\n\n /** Press a named key (e.g. \"Enter\", \"Tab\"). */\n async pressKey(keyName: string): Promise<void> {\n const { key, code, keyCode } = getKeyParams(keyName);\n if (this.cdp) {\n await this.cdp.pressKey(key, code, keyCode);\n } else {\n await this.bidi!.performActions([\n {\n type: 'key',\n id: 'keyboard',\n actions: [\n { type: 'keyDown', value: key },\n { type: 'keyUp', value: key },\n ],\n },\n ]);\n }\n }\n\n /** Send keyDown. */\n async keyDown(keyName: string): Promise<void> {\n const { key, code, keyCode } = getKeyParams(keyName);\n if (this.cdp) {\n await this.cdp.keyDown(key, code, keyCode);\n } else {\n await this.bidi!.performActions([\n { type: 'key', id: 'keyboard', actions: [{ type: 'keyDown', value: key }] },\n ]);\n }\n }\n\n /** Send keyUp. */\n async keyUp(keyName: string): Promise<void> {\n const { key, code, keyCode } = getKeyParams(keyName);\n if (this.cdp) {\n await this.cdp.keyUp(key, code, keyCode);\n } else {\n await this.bidi!.performActions([\n { type: 'key', id: 'keyboard', actions: [{ type: 'keyUp', value: key }] },\n ]);\n }\n }\n\n /** Set viewport dimensions. */\n async setViewport(\n width: number,\n height: number,\n deviceScaleFactor: number = 2,\n mobile: boolean = false,\n ): Promise<void> {\n if (this.cdp) {\n await this.cdp.setViewport(width, height, deviceScaleFactor, mobile);\n } else {\n // BiDi doesn't have a direct viewport override — use script\n await this.bidi!.evaluate(\n `window.resizeTo(${width}, ${height})`,\n );\n }\n }\n\n /** Subscribe to a CDP domain event (only relevant for CDP). */\n onProtocolEvent(method: string, handler: (params: Record<string, unknown>) => void): void {\n if (this.cdp) {\n this.cdp.on(method, handler);\n } else if (this.bidi) {\n this.bidi.on(method, handler);\n }\n }\n\n /** Clean up resources. Nulls references first to prevent stale message routing. */\n destroy(): void {\n const cdp = this.cdp;\n const bidi = this.bidi;\n // Null out first so routeMessage() drops any in-flight messages during destroy\n this.cdp = null;\n this.bidi = null;\n cdp?.destroy();\n bidi?.destroy();\n }\n}\n","import type { SpiderEvents, SpiderEventName } from './types.js';\n\ntype Handler<T> = (data: T) => void;\n\n/** Type-safe event emitter for SpiderBrowser events. */\nexport class SpiderEventEmitter {\n private handlers = new Map<string, Set<Handler<any>>>();\n\n on<K extends SpiderEventName>(event: K, handler: Handler<SpiderEvents[K]>): this {\n let set = this.handlers.get(event);\n if (!set) {\n set = new Set();\n this.handlers.set(event, set);\n }\n set.add(handler);\n return this;\n }\n\n off<K extends SpiderEventName>(event: K, handler: Handler<SpiderEvents[K]>): this {\n this.handlers.get(event)?.delete(handler);\n return this;\n }\n\n once<K extends SpiderEventName>(event: K, handler: Handler<SpiderEvents[K]>): this {\n const wrapped: Handler<SpiderEvents[K]> = (data) => {\n this.off(event, wrapped);\n handler(data);\n };\n return this.on(event, wrapped);\n }\n\n emit<K extends SpiderEventName>(event: K, data: SpiderEvents[K]): void {\n const set = this.handlers.get(event);\n if (set) {\n for (const handler of set) {\n try {\n handler(data);\n } catch {\n // Don't let user handlers crash the library\n }\n }\n }\n }\n\n removeAllListeners(event?: SpiderEventName): void {\n if (event) {\n this.handlers.delete(event);\n } else {\n this.handlers.clear();\n }\n }\n}\n","import type { ProtocolAdapter } from './protocol/protocol-adapter.js';\nimport { BlockedError, TimeoutError } from './utils/errors.js';\n\n/**\n * SpiderPage — deterministic browser tab abstraction.\n *\n * All standard browser automation methods (no LLM required).\n * Works over both CDP (Chrome/Servo/LightPanda) and BiDi (Firefox)\n * through the ProtocolAdapter.\n */\nexport class SpiderPage {\n /** @internal */\n constructor(private adapter: ProtocolAdapter) {}\n\n // -------------------------------------------------------------------\n // Navigation\n // -------------------------------------------------------------------\n\n /** Navigate to a URL and wait for load. */\n async goto(url: string): Promise<void> {\n await this.adapter.navigate(url);\n }\n\n /** Go back in browser history. */\n async goBack(): Promise<void> {\n await this.adapter.evaluate('window.history.back()');\n }\n\n /** Go forward in browser history. */\n async goForward(): Promise<void> {\n await this.adapter.evaluate('window.history.forward()');\n }\n\n /** Reload the page. */\n async reload(): Promise<void> {\n await this.adapter.evaluate('window.location.reload()');\n }\n\n // -------------------------------------------------------------------\n // Content\n // -------------------------------------------------------------------\n\n /**\n * Get the full page HTML, ensuring the page is ready first.\n *\n * Waits for network idle + DOM stability, then checks content quality.\n * If the content seems incomplete (too short or looks like a loading state),\n * does incremental waits with exponential backoff before returning.\n *\n * @param waitMs Max time to wait for readiness (default: 8000ms).\n * Pass 0 to skip readiness checks and return immediately.\n * @param minLength Minimum content length to consider \"good\" (default: 1000).\n */\n async content(waitMs: number = 8000, minLength: number = 1000): Promise<string> {\n if (waitMs > 0) {\n await this.waitForNetworkIdle(waitMs);\n }\n\n let html = (await this.adapter.getHTML()) ?? '';\n\n // Interstitial detection — wait for challenge pages to resolve before failing.\n // Cloudflare \"Just a moment...\" and similar interstitials auto-resolve after a few seconds.\n // Use graduated waits: some challenges take up to 10s to resolve.\n if (waitMs > 0 && this.isInterstitialContent(html)) {\n const interstitialWaits = [4000, 4000, 4000]; // 4s + 4s + 4s = 12s max\n for (const wait of interstitialWaits) {\n await sleep(wait);\n html = (await this.adapter.getHTML()) ?? '';\n if (!this.isInterstitialContent(html)) break;\n }\n // If still an interstitial after all waits, throw BlockedError so retry engine rotates browser\n if (this.isInterstitialContent(html)) {\n throw new BlockedError('Page stuck on interstitial challenge');\n }\n }\n\n // Site-level rate limiting — throw BlockedError so retry engine rotates browser (new profile)\n if (waitMs > 0 && this.isRateLimitContent(html)) {\n throw new BlockedError('Rate limit exceeded (site-level)');\n }\n\n // Incremental quality check — if content seems incomplete, wait progressively\n if (waitMs > 0 && html.length < minLength) {\n const increments = [300, 500, 800, 1200];\n for (const extra of increments) {\n await sleep(extra);\n const updated = await this.adapter.getHTML();\n if (updated.length > html.length) {\n html = updated;\n }\n if (html.length >= minLength) break;\n }\n }\n\n return html;\n }\n\n /**\n * Get the raw page HTML without any readiness waiting.\n * Use this when you need immediate access or have already waited.\n */\n async rawContent(): Promise<string> {\n return this.adapter.getHTML();\n }\n\n /** Get the page title. */\n async title(): Promise<string> {\n return (await this.adapter.evaluate('document.title')) as string;\n }\n\n /** Get the current page URL. */\n async url(): Promise<string> {\n return (await this.adapter.evaluate('window.location.href')) as string;\n }\n\n /** Capture a screenshot as base64 PNG. */\n async screenshot(): Promise<string> {\n return this.adapter.captureScreenshot();\n }\n\n /** Evaluate arbitrary JavaScript and return the result. */\n async evaluate(expression: string): Promise<unknown> {\n return this.adapter.evaluate(expression);\n }\n\n // -------------------------------------------------------------------\n // Click Actions\n // -------------------------------------------------------------------\n\n /** Click an element by CSS selector. */\n async click(selector: string): Promise<void> {\n const { x, y } = await this.getElementCenter(selector);\n await this.adapter.clickPoint(x, y);\n }\n\n /** Click at specific viewport coordinates. */\n async clickAt(x: number, y: number): Promise<void> {\n await this.adapter.clickPoint(x, y);\n }\n\n /** Double-click an element by CSS selector. */\n async dblclick(selector: string): Promise<void> {\n const { x, y } = await this.getElementCenter(selector);\n await this.adapter.doubleClickPoint(x, y);\n }\n\n /** Right-click an element by CSS selector. */\n async rightClick(selector: string): Promise<void> {\n const { x, y } = await this.getElementCenter(selector);\n await this.adapter.rightClickPoint(x, y);\n }\n\n /** Click all elements matching a selector. */\n async clickAll(selector: string): Promise<void> {\n const points = (await this.adapter.evaluate(`\n (function() {\n const els = document.querySelectorAll(${JSON.stringify(selector)});\n return Array.from(els).map(el => {\n const r = el.getBoundingClientRect();\n return { x: r.x + r.width / 2, y: r.y + r.height / 2 };\n });\n })()\n `)) as Array<{ x: number; y: number }>;\n if (Array.isArray(points)) {\n for (const pt of points) {\n await this.adapter.clickPoint(pt.x, pt.y);\n await sleep(100);\n }\n }\n }\n\n // -------------------------------------------------------------------\n // Input Actions\n // -------------------------------------------------------------------\n\n /** Fill a form field — focus, clear existing value, type new value. */\n async fill(selector: string, value: string): Promise<void> {\n // Clear via JS\n await this.adapter.evaluate(`\n (function() {\n const el = document.querySelector(${JSON.stringify(selector)});\n if (el) { el.focus(); el.value = ''; }\n })()\n `);\n // Click to ensure focus with real browser event\n try {\n const { x, y } = await this.getElementCenter(selector);\n await this.adapter.clickPoint(x, y);\n } catch {\n // element may not be clickable, continue anyway\n }\n // Insert text\n await this.adapter.insertText(value);\n // Dispatch input + change events\n await this.adapter.evaluate(`\n (function() {\n const el = document.querySelector(${JSON.stringify(selector)});\n if (el) {\n el.dispatchEvent(new Event('input', { bubbles: true }));\n el.dispatchEvent(new Event('change', { bubbles: true }));\n }\n })()\n `);\n }\n\n /** Type text into the currently focused element. */\n async type(value: string): Promise<void> {\n await this.adapter.insertText(value);\n }\n\n /** Press a named key (e.g. \"Enter\", \"Tab\", \"Escape\"). */\n async press(key: string): Promise<void> {\n await this.adapter.pressKey(key);\n }\n\n /** Clear an input field. */\n async clear(selector: string): Promise<void> {\n await this.adapter.evaluate(\n `document.querySelector(${JSON.stringify(selector)}).value = ''`,\n );\n }\n\n /** Select an option in a <select> element. */\n async select(selector: string, value: string): Promise<void> {\n await this.adapter.evaluate(`\n (function() {\n const el = document.querySelector(${JSON.stringify(selector)});\n if (el) {\n el.value = ${JSON.stringify(value)};\n el.dispatchEvent(new Event('change', { bubbles: true }));\n }\n })()\n `);\n }\n\n // -------------------------------------------------------------------\n // Focus & Hover\n // -------------------------------------------------------------------\n\n /** Focus an element. */\n async focus(selector: string): Promise<void> {\n await this.adapter.evaluate(\n `document.querySelector(${JSON.stringify(selector)})?.focus()`,\n );\n }\n\n /** Blur (unfocus) an element. */\n async blur(selector: string): Promise<void> {\n await this.adapter.evaluate(\n `document.querySelector(${JSON.stringify(selector)})?.blur()`,\n );\n }\n\n /** Hover over an element. */\n async hover(selector: string): Promise<void> {\n const { x, y } = await this.getElementCenter(selector);\n await this.adapter.hoverPoint(x, y);\n }\n\n // -------------------------------------------------------------------\n // Drag\n // -------------------------------------------------------------------\n\n /** Drag from one element to another. */\n async drag(fromSelector: string, toSelector: string): Promise<void> {\n const from = await this.getElementCenter(fromSelector);\n const to = await this.getElementCenter(toSelector);\n await this.adapter.dragPoint(from.x, from.y, to.x, to.y);\n }\n\n // -------------------------------------------------------------------\n // Scroll\n // -------------------------------------------------------------------\n\n /** Scroll vertically by pixels (positive = down). */\n async scrollY(pixels: number): Promise<void> {\n await this.adapter.evaluate(`window.scrollBy(0, ${pixels})`);\n }\n\n /** Scroll horizontally by pixels (positive = right). */\n async scrollX(pixels: number): Promise<void> {\n await this.adapter.evaluate(`window.scrollBy(${pixels}, 0)`);\n }\n\n /** Scroll an element into view. */\n async scrollTo(selector: string): Promise<void> {\n await this.adapter.evaluate(\n `document.querySelector(${JSON.stringify(selector)})?.scrollIntoView({ behavior: 'smooth', block: 'center' })`,\n );\n }\n\n /** Scroll to absolute page coordinates. */\n async scrollToPoint(x: number, y: number): Promise<void> {\n await this.adapter.evaluate(`window.scrollTo(${x}, ${y})`);\n }\n\n // -------------------------------------------------------------------\n // Wait\n // -------------------------------------------------------------------\n\n /** Wait for a CSS selector to appear in the DOM. */\n async waitForSelector(selector: string, timeoutMs: number = 5000): Promise<void> {\n const interval = 100;\n const maxIter = Math.ceil(timeoutMs / interval);\n const checkJs = `!!document.querySelector(${JSON.stringify(selector)})`;\n for (let i = 0; i < maxIter; i++) {\n const found = await this.adapter.evaluate(checkJs);\n if (found) return;\n await sleep(interval);\n }\n throw new TimeoutError(`Timeout waiting for selector: ${selector}`);\n }\n\n /** Wait for navigation/page load (simple delay). */\n async waitForNavigation(timeoutMs: number = 5000): Promise<void> {\n await sleep(Math.min(timeoutMs, 1000));\n }\n\n /**\n * Wait until the page is fully loaded and DOM is stable.\n *\n * Checks:\n * 1. document.readyState === 'complete'\n * 2. DOM content length stabilizes (no changes for 500ms)\n *\n * Use after goto() for SPAs and dynamic pages to ensure all\n * content is rendered before extracting HTML.\n */\n async waitForReady(timeoutMs: number = 10000): Promise<void> {\n const start = Date.now();\n const pollInterval = 200;\n const stableThreshold = 500; // content must be stable for this long\n\n // Phase 1: wait for document.readyState === 'complete'\n while (Date.now() - start < timeoutMs) {\n const state = await this.adapter.evaluate('document.readyState') as string;\n if (state === 'complete') break;\n await sleep(pollInterval);\n }\n\n // Phase 2: wait for DOM content length to stabilize\n let lastLength = 0;\n let stableSince = Date.now();\n\n while (Date.now() - start < timeoutMs) {\n const length = await this.adapter.evaluate(\n 'document.documentElement.innerHTML.length',\n ) as number;\n\n if (length !== lastLength) {\n lastLength = length;\n stableSince = Date.now();\n } else if (Date.now() - stableSince >= stableThreshold) {\n return; // Stable\n }\n\n await sleep(pollInterval);\n }\n }\n\n /**\n * Wait until page content exceeds a minimum length.\n * Useful for SPAs where content loads asynchronously.\n */\n async waitForContent(minLength: number = 500, timeoutMs: number = 8000): Promise<void> {\n const start = Date.now();\n while (Date.now() - start < timeoutMs) {\n const length = await this.adapter.evaluate(\n 'document.documentElement.innerHTML.length',\n ) as number;\n if (length >= minLength) return;\n await sleep(200);\n }\n }\n\n /**\n * Wait for network idle + DOM stability (cross-platform).\n *\n * Uses the Performance/Resource Timing API and MutationObserver\n * (works in both Chrome/CDP and Firefox/BiDi) to detect when:\n * 1. document.readyState === 'complete'\n * 2. No new network resources loading (PerformanceObserver)\n * 3. DOM mutations have settled\n *\n * This is more comprehensive than waitForReady() — it also\n * catches lazy-loaded images, XHR/fetch requests, and script-injected content.\n */\n async waitForNetworkIdle(timeoutMs: number = 8000): Promise<void> {\n const start = Date.now();\n const pollInterval = 250;\n\n // Phase 1: wait for document.readyState === 'complete'\n while (Date.now() - start < timeoutMs) {\n const state = await this.adapter.evaluate('document.readyState') as string;\n if (state === 'complete') break;\n await sleep(pollInterval);\n }\n\n // Phase 2: inject a combined network + DOM stability checker\n // Uses PerformanceObserver for resource timing + MutationObserver for DOM changes.\n // Returns a promise that resolves when both are quiet for `idleMs`.\n const idleMs = 400;\n const remaining = Math.max(1000, timeoutMs - (Date.now() - start));\n try {\n await this.adapter.evaluate(`\n new Promise((resolve) => {\n let lastActivity = Date.now();\n const idleThreshold = ${idleMs};\n const deadline = Date.now() + ${remaining};\n\n // Track resource loads\n const perfObs = new PerformanceObserver(() => { lastActivity = Date.now(); });\n try { perfObs.observe({ entryTypes: ['resource'] }); } catch(e) {}\n\n // Track DOM mutations\n const mutObs = new MutationObserver(() => { lastActivity = Date.now(); });\n mutObs.observe(document.documentElement, {\n childList: true, subtree: true, attributes: true\n });\n\n const check = () => {\n const now = Date.now();\n if (now >= deadline || (now - lastActivity >= idleThreshold)) {\n perfObs.disconnect();\n mutObs.disconnect();\n resolve(true);\n return;\n }\n setTimeout(check, 100);\n };\n setTimeout(check, idleThreshold);\n })\n `);\n } catch {\n // If the evaluate fails (e.g. page navigated away), just continue\n await sleep(500);\n }\n }\n\n // -------------------------------------------------------------------\n // Viewport\n // -------------------------------------------------------------------\n\n /** Set the viewport dimensions. */\n async setViewport(\n width: number,\n height: number,\n deviceScaleFactor: number = 2,\n mobile: boolean = false,\n ): Promise<void> {\n await this.adapter.setViewport(width, height, deviceScaleFactor, mobile);\n }\n\n // -------------------------------------------------------------------\n // DOM Queries\n // -------------------------------------------------------------------\n\n /** Query a single element and return its outer HTML. */\n async querySelector(selector: string): Promise<string | null> {\n return (await this.adapter.evaluate(\n `document.querySelector(${JSON.stringify(selector)})?.outerHTML ?? null`,\n )) as string | null;\n }\n\n /** Query all matching elements and return their outer HTML. */\n async querySelectorAll(selector: string): Promise<string[]> {\n return (await this.adapter.evaluate(`\n Array.from(document.querySelectorAll(${JSON.stringify(selector)})).map(el => el.outerHTML)\n `)) as string[];\n }\n\n /** Get text content of an element. */\n async textContent(selector: string): Promise<string | null> {\n return (await this.adapter.evaluate(\n `document.querySelector(${JSON.stringify(selector)})?.textContent ?? null`,\n )) as string | null;\n }\n\n // -------------------------------------------------------------------\n // Internals\n // -------------------------------------------------------------------\n\n /** Get the center coordinates of a DOM element (scrolls into view first). */\n private async getElementCenter(selector: string): Promise<{ x: number; y: number }> {\n const result = (await this.adapter.evaluate(`\n (function() {\n const el = document.querySelector(${JSON.stringify(selector)});\n if (!el) return null;\n el.scrollIntoView({ block: 'center', behavior: 'instant' });\n const r = el.getBoundingClientRect();\n return { x: r.x + r.width / 2, y: r.y + r.height / 2 };\n })()\n `)) as { x: number; y: number } | null;\n\n if (!result) {\n throw new Error(`Element not found: ${selector}`);\n }\n return result;\n }\n\n /** @internal Replace the adapter (used during browser switching). */\n _setAdapter(adapter: ProtocolAdapter): void {\n this.adapter = adapter;\n }\n\n /**\n * Detect challenge interstitials that may auto-resolve (e.g. Cloudflare \"Just a moment...\").\n * These pages show briefly before redirecting to the real content.\n */\n private isInterstitialContent(html: string): boolean {\n if (html.length > 15_000) return false; // Real pages are larger\n const lower = html.toLowerCase();\n return (\n lower.includes('just a moment') ||\n lower.includes('checking your browser') ||\n lower.includes('please wait while we verify') ||\n lower.includes('ddos-guard') ||\n lower.includes('challenge-platform')\n );\n }\n\n /**\n * Detect site-level rate limiting in page content.\n * Browser rotation gives a new profile which bypasses per-session rate limits.\n */\n private isRateLimitContent(html: string): boolean {\n if (html.length > 20_000) return false; // Real pages won't be just a rate limit message\n const lower = html.toLowerCase();\n return (\n lower.includes('rate limit exceeded') ||\n lower.includes('too many requests') ||\n (lower.includes('rate limit') && lower.includes('please try again'))\n );\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((r) => setTimeout(r, ms));\n}\n","import type { BrowserType } from '../events/types.js';\n\n/** Mirrors hints.rs FAILURE_TTL (10 minutes). */\nconst FAILURE_TTL_MS = 10 * 60 * 1000;\n\n/** Mirrors hints.rs ROTATE_AFTER_FAILURES. */\nexport const ROTATE_AFTER_FAILURES = 2;\n\ninterface FailureRecord {\n count: number;\n lastFailure: number;\n}\n\n/**\n * Per-domain failure tracking (mirrors server hints.rs FailureTracker).\n *\n * Tracks (domain, browser_type) failure counts with 10-minute TTL.\n * Used by BrowserSelector to decide when to rotate browsers.\n */\nexport class FailureTracker {\n private failures = new Map<string, FailureRecord>();\n\n private key(domain: string, browser: BrowserType): string {\n return `${domain}::${browser}`;\n }\n\n /** Record a failure for a domain + browser. */\n recordFailure(domain: string, browser: BrowserType): void {\n const k = this.key(domain, browser);\n const existing = this.failures.get(k);\n if (existing) {\n existing.count++;\n existing.lastFailure = Date.now();\n } else {\n this.failures.set(k, { count: 1, lastFailure: Date.now() });\n }\n }\n\n /** Record a success — clears the failure counter. */\n recordSuccess(domain: string, browser: BrowserType): void {\n this.failures.delete(this.key(domain, browser));\n }\n\n /** Get failure count (0 if expired or not found). */\n failureCount(domain: string, browser: BrowserType): number {\n const record = this.failures.get(this.key(domain, browser));\n if (!record) return 0;\n if (Date.now() - record.lastFailure > FAILURE_TTL_MS) {\n this.failures.delete(this.key(domain, browser));\n return 0;\n }\n return record.count;\n }\n\n /** Get total failures across all browsers for a domain. */\n totalFailureCount(domain: string): number {\n let total = 0;\n for (const [key, record] of this.failures) {\n if (key.startsWith(`${domain}::`)) {\n if (Date.now() - record.lastFailure < FAILURE_TTL_MS) {\n total += record.count;\n }\n }\n }\n return total;\n }\n\n /** Clear all failure records for a domain (used on stealth escalation). */\n clear(domain: string): void {\n for (const key of this.failures.keys()) {\n if (key.startsWith(`${domain}::`)) {\n this.failures.delete(key);\n }\n }\n }\n\n /** Clean expired entries. */\n cleanup(): void {\n const now = Date.now();\n for (const [key, record] of this.failures) {\n if (now - record.lastFailure > FAILURE_TTL_MS) {\n this.failures.delete(key);\n }\n }\n }\n}\n","import type { BrowserType } from '../events/types.js';\nimport { FailureTracker, ROTATE_AFTER_FAILURES } from './failure-tracker.js';\n\n/**\n * Primary browser rotation — most stable Chrome backends.\n * Used for all error types with transient retries.\n * chrome-h (Xvfb shared process) is excluded — less stable under load.\n */\nexport const PRIMARY_ROTATION: BrowserType[] = [\n 'chrome',\n 'chrome-new',\n];\n\n/**\n * Extended browser rotation — non-Chrome engines tried at max stealth only.\n * These offer different engine fingerprints for bypassing bot detection.\n *\n * Excluded backends (based on stealth test data):\n * - chrome-h: same Chrome engine (no fingerprint benefit), 36% success rate\n * - servo: 0% success (\"Failed to create page target\" on all attempts)\n * - lightpanda: 0% success (503s + CDP timeouts when backend overloaded)\n * - firefox: 0% success (BiDi browsingContext.navigate timeouts on all attempts)\n *\n * If a backend returns 503/\"unexpected server response\", it's marked as\n * backend_down and skipped for all remaining attempts automatically.\n */\nexport const EXTENDED_ROTATION: BrowserType[] = [];\n\n/**\n * Full browser rotation order for retry/failover.\n * Primary (Chrome) browsers are tried first, then extended if blocked.\n */\nexport const BROWSER_ROTATION: BrowserType[] = [\n ...PRIMARY_ROTATION,\n ...EXTENDED_ROTATION,\n];\n\n/**\n * BrowserSelector — picks the next browser in rotation based on failures.\n *\n * Follows the server's hints.rs logic:\n * 1. Try current browser until ROTATE_AFTER_FAILURES consecutive failures\n * 2. Then move to the next browser in BROWSER_ROTATION order\n * 3. Skip browsers that have also exceeded the failure threshold\n */\nexport class BrowserSelector {\n private tracker: FailureTracker;\n private rotationIndex = 0;\n\n constructor(tracker: FailureTracker) {\n this.tracker = tracker;\n }\n\n /** Get the current failure tracker. */\n get failureTracker(): FailureTracker {\n return this.tracker;\n }\n\n /**\n * Check if the current browser should be rotated for a domain.\n */\n shouldRotate(domain: string, currentBrowser: BrowserType): boolean {\n return this.tracker.failureCount(domain, currentBrowser) >= ROTATE_AFTER_FAILURES;\n }\n\n /**\n * Pick the next browser to try, given the current one has failed.\n * Returns the next browser in rotation that hasn't exceeded the failure threshold.\n * Returns null if all browsers have been exhausted.\n */\n nextBrowser(domain: string, currentBrowser: BrowserType): BrowserType | null {\n // Find current position in rotation\n const currentIdx = BROWSER_ROTATION.indexOf(currentBrowser);\n\n // Try each browser after the current one\n for (let offset = 1; offset < BROWSER_ROTATION.length; offset++) {\n const idx = (currentIdx + offset) % BROWSER_ROTATION.length;\n const candidate = BROWSER_ROTATION[idx]!;\n if (this.tracker.failureCount(domain, candidate) < ROTATE_AFTER_FAILURES) {\n return candidate;\n }\n }\n\n return null;\n }\n\n /**\n * Choose the best browser for a domain (mirrors hints.rs choose_browser_for_domain).\n * Uses failure history to skip browsers that have been failing.\n */\n chooseBrowser(domain: string, fallback: BrowserType): BrowserType {\n for (const browser of BROWSER_ROTATION) {\n if (this.tracker.failureCount(domain, browser) < ROTATE_AFTER_FAILURES) {\n return browser;\n }\n }\n return fallback;\n }\n}\n","import type { Transport, TransportOptions } from '../protocol/transport.js';\nimport { ProtocolAdapter } from '../protocol/protocol-adapter.js';\nimport type { SpiderEventEmitter } from '../events/emitter.js';\nimport type { BrowserType } from '../events/types.js';\nimport type { SpiderPage } from '../page.js';\nimport { BrowserSelector, BROWSER_ROTATION, PRIMARY_ROTATION, EXTENDED_ROTATION } from './browser-selector.js';\nimport { FailureTracker } from './failure-tracker.js';\nimport {\n ConnectionError,\n AuthError,\n RateLimitError,\n BlockedError,\n BackendUnavailableError,\n TimeoutError,\n NavigationError,\n} from '../utils/errors.js';\nimport { logger } from '../utils/logger.js';\n\nimport { KeywordClassifier } from './keyword-classifier.js';\n\n/**\n * Error classification via Aho-Corasick multi-pattern matching.\n *\n * Scans the error message ONCE in O(n) regardless of keyword count.\n * Rules are priority-ordered — first match wins.\n *\n * To add a new keyword: add it to the appropriate array below.\n */\nconst errorClassifier = new KeywordClassifier<ErrorClass>([\n // Blocked — checked first (most common heuristic case)\n // NOTE: err_aborted is NOT here — it's handled specially in classifyError().\n // Server already retries ERR_ABORTED internally; when it reaches the client,\n // it's usually session interference (shared Chrome) not actual blocking.\n // Reconnecting (new session) is the right fix, not stealth escalation.\n [[\n 'bot detect', 'are you a robot', 'blocked', '403', 'captcha',\n 'network security', 'human verification', 'verify you are human',\n 'checking your browser', 'bot protection', 'automated access',\n 'pardon our interruption', 'powered and protected by',\n 'request could not be processed', 'access to this page has been denied',\n 'access denied', 'please complete the security check',\n 'enable cookies', 'browser check', 'just a moment',\n 'rate limit exceeded', 'too many requests',\n 'err_blocked_by_client',\n ], 'blocked'],\n // Auth\n [['401', '402', 'unauthorized'], 'auth'],\n // Backend down\n [['backend unavailable', 'no backend', 'service unavailable', '503', 'failed to create page target', 'unexpected server response'], 'backend_down'],\n // Transient (connection)\n [['err_connection_reset', 'err_connection_closed', 'err_empty_response', 'err_ssl_protocol_error', 'err_ssl_version_or_cipher_mismatch', 'err_cert', 'timeout'], 'transient'],\n // Transient (WebSocket / session)\n [['websocket is not connected', 'websocket closed', 'session with given id not found', 'content contamination', 'insufficient content'], 'transient'],\n]);\n\n/** Disconnection detection — single O(n) scan. */\nconst disconnectionClassifier = new KeywordClassifier<boolean>([\n // NOT disconnections (page-level) — checked first\n // NOTE: err_aborted is intentionally NOT here — at high concurrency it's\n // usually session interference (shared Chrome process), so reconnecting\n // (new session) is the correct fix. For NavigationError, undefined → true.\n [['err_blocked_by_client'], false],\n // Actual disconnections (socket hang up = server killed the connection)\n // Content contamination = shared Chrome leaked another session's content → new session fixes it\n [[\n 'websocket is not connected', 'websocket closed', 'session destroyed',\n 'session with given id not found', 'err_connection_reset',\n 'err_connection_closed', 'err_empty_response', 'socket hang up',\n 'err_aborted', 'content contamination', 'insufficient content',\n 'err_ssl_protocol_error', 'err_ssl_version_or_cipher_mismatch',\n ], true],\n]);\n\nexport interface RetryOptions {\n maxRetries: number;\n transportOpts: TransportOptions;\n emitter: SpiderEventEmitter;\n /** Maximum stealth level to escalate to (1-3, default 3). */\n maxStealthLevel?: number;\n /** Timeout for retry attempts — shorter than first try (default: 15000ms). */\n retryTimeoutMs?: number;\n /** CDP/BiDi command timeout in ms, passed through to new adapters (default: 30000). */\n commandTimeoutMs?: number;\n}\n\nexport interface RetryContext {\n transport: Transport;\n adapter: ProtocolAdapter;\n page: SpiderPage;\n currentUrl: string | undefined;\n onAdapterChanged: (adapter: ProtocolAdapter) => void;\n}\n\n/** Error classification for retry decisions. */\ntype ErrorClass = 'transient' | 'blocked' | 'backend_down' | 'auth' | 'rate_limit';\n\n/**\n * Smart retry engine with stealth-first escalation.\n *\n * **Strategy: escalate proxy quality (stealth) FAST, try alternative engines LAST.**\n *\n * - **Phase 1 (Stealth escalation)**: For each stealth level [0 → max],\n * try PRIMARY browsers [chrome, chrome-new] with transient retries.\n * If blocked → skip remaining primary browsers, escalate stealth immediately.\n *\n * - **Phase 2 (Extended rotation)**: Only at max stealth, if still blocked,\n * try EXTENDED browsers [firefox, lightpanda, servo] for different engine\n * fingerprints + best proxies.\n *\n * **Retry flow:**\n * ```\n * Phase 1 — stealth escalation across primary browsers:\n * for each stealth level (initial → maxStealthLevel):\n * for each PRIMARY browser [chrome, chrome-new]:\n * attempt action\n * if transient → reconnect same browser, retry up to 2x\n * if blocked → skip remaining primary, escalate stealth immediately\n * if backend_down → mark down, next browser\n * if auth → throw immediately\n * if rate_limit → wait, retry same browser\n *\n * Phase 2 — extended rotation at max stealth only (if blocked):\n * for each EXTENDED browser [firefox, lightpanda, servo]:\n * single attempt (no transient retries)\n * ```\n *\n * Error classification (mirrors server hints.rs):\n *\n * | Error Pattern | Classification | Action |\n * |----------------------------|-----------------|-------------------------------------------|\n * | ERR_ABORTED (nav) | Transient+Disco | Reconnect (new session), retry up to 2x |\n * | WS close 1006/1011 | Transient+Disco | Reconnect same browser, retry up to 2x |\n * | Timeout | Transient | Retry same browser up to 2x, then switch |\n * | blocked / 403 / captcha | Blocked | Skip remaining primary, escalate stealth |\n * | bot detection | Blocked | Skip remaining primary, escalate stealth |\n * | 401 / 402 | Auth | Throw immediately (no retry) |\n * | 429 | Rate limit | Wait + retry same browser |\n * | 503 / backend unavailable | Backend down | Mark down, switch browser |\n */\nexport class RetryEngine {\n private opts: RetryOptions;\n private selector: BrowserSelector;\n private currentStealthLevel: number;\n private maxStealthLevel: number;\n private retryTimeoutMs: number;\n private commandTimeoutMs: number;\n /** Browser backends that returned 503/unavailable — persists across stealth levels. */\n private downBackends = new Set<BrowserType>();\n\n constructor(opts: RetryOptions) {\n this.opts = opts;\n this.selector = new BrowserSelector(new FailureTracker());\n this.currentStealthLevel = opts.transportOpts.stealthLevel ?? 0;\n this.maxStealthLevel = opts.maxStealthLevel ?? 3;\n this.retryTimeoutMs = opts.retryTimeoutMs ?? 15_000;\n this.commandTimeoutMs = opts.commandTimeoutMs ?? 30_000;\n }\n\n /** Current stealth level (0=auto, 1-3=explicit tiers). */\n get stealthLevel(): number {\n return this.currentStealthLevel;\n }\n\n /**\n * Execute an action with stealth-first retry across browsers and stealth levels.\n *\n * Phase 1: Escalate stealth across primary browsers (chrome, chrome-new).\n * Blocked errors skip remaining primary browsers and immediately escalate stealth.\n *\n * Phase 2: At max stealth only, try extended browsers (firefox, lightpanda, servo)\n * for a different engine fingerprint with the best proxy quality.\n */\n async execute<T>(fn: () => Promise<T>, ctx: RetryContext): Promise<T> {\n let lastError: Error | undefined;\n let totalAttempts = 0;\n const budget = this.opts.maxRetries + 1; // total attempts allowed\n this.downBackends.clear();\n\n const stealthLevels = this.getStealthProgression();\n const initialBrowser = ctx.transport.browser;\n /** Consecutive WS disconnect errors — when 3+ in a row, server is overloaded. */\n let consecutiveDisconnects = 0;\n /** Whether the last error was a blocked error (for extended rotation decision). */\n let wasBlocked = false;\n\n // Phase 1: Stealth escalation across primary browsers\n for (let si = 0; si < stealthLevels.length; si++) {\n if (totalAttempts >= budget) break;\n\n const stealth = stealthLevels[si]!;\n\n // Stealth escalation (skip for first level)\n if (si > 0) {\n const prev = stealthLevels[si - 1]!;\n this.currentStealthLevel = stealth;\n ctx.transport.stealthLevel = stealth;\n\n logger.info(`retry: escalating stealth ${prev} -> ${stealth}`);\n this.opts.emitter.emit('stealth.escalated', {\n from: prev,\n to: stealth,\n reason: lastError ? this.classifyError(lastError) : 'exhausted',\n });\n\n // Clear domain failure tracking so all browsers are available again\n const domain = this.extractDomain(ctx.currentUrl);\n if (domain) this.selector.failureTracker.clear(domain);\n }\n\n const primaryBrowsers = si === 0\n ? this.orderedPrimaryBrowsers(initialBrowser)\n : [...PRIMARY_ROTATION];\n\n let triedAny = false;\n\n for (const browser of primaryBrowsers) {\n if (totalAttempts >= budget) break;\n if (this.downBackends.has(browser)) continue;\n\n // If 6+ consecutive WS disconnects across browsers, server is overloaded — stop\n if (consecutiveDisconnects >= 6) {\n logger.warn('retry: 6+ consecutive disconnects, server overloaded — aborting');\n break;\n }\n\n const result = await this.tryBrowser(fn, ctx, browser, stealth, totalAttempts, budget, true);\n totalAttempts = result.totalAttempts;\n if (result.success) {\n consecutiveDisconnects = 0;\n return result.value!;\n }\n if (result.triedAction) triedAny = true;\n if (result.lastError) {\n lastError = result.lastError;\n const errorClass = this.classifyError(lastError);\n wasBlocked = errorClass === 'blocked';\n if (errorClass === 'auth') throw lastError;\n // Track consecutive disconnects\n if (this.isDisconnectionError(lastError)) {\n consecutiveDisconnects++;\n } else {\n consecutiveDisconnects = 0;\n }\n // Blocked → skip remaining primary browsers, escalate stealth immediately\n if (wasBlocked) break;\n }\n }\n\n // If no browser could be tried (all backends down), stop entirely\n if (!triedAny) {\n logger.warn('retry: all browser backends unavailable, stopping');\n break;\n }\n }\n\n // Phase 2: Extended rotation at max stealth only (if last error was blocked)\n if (wasBlocked && totalAttempts < budget) {\n for (const browser of EXTENDED_ROTATION) {\n if (totalAttempts >= budget) break;\n if (this.downBackends.has(browser)) continue;\n\n // Extended browsers get a single attempt — no transient retries\n const maxStealth = stealthLevels[stealthLevels.length - 1] ?? this.maxStealthLevel;\n const result = await this.tryBrowser(fn, ctx, browser, maxStealth, totalAttempts, budget, false);\n totalAttempts = result.totalAttempts;\n if (result.success) return result.value!;\n if (result.lastError) {\n lastError = result.lastError;\n if (this.classifyError(lastError) === 'auth') throw lastError;\n }\n }\n }\n\n throw lastError ?? new Error('All browsers and stealth levels exhausted');\n }\n\n /**\n * Attempt an action on a specific browser, with optional transient retries.\n *\n * @param allowTransientRetries If true, retries up to 2x for transient errors\n * (reconnect + retry). If false, a single attempt only (for extended browsers).\n */\n private async tryBrowser<T>(\n fn: () => Promise<T>,\n ctx: RetryContext,\n browser: BrowserType,\n stealth: number,\n totalAttempts: number,\n budget: number,\n allowTransientRetries: boolean,\n ): Promise<{ success: boolean; value?: T; totalAttempts: number; triedAction: boolean; lastError?: Error }> {\n let lastError: Error | undefined;\n\n // Switch to this browser (skip on very first attempt — already connected)\n if (totalAttempts > 0) {\n try {\n const prevBrowser = ctx.transport.browser;\n logger.info(`retry: switching ${prevBrowser} -> ${browser} (stealth=${stealth})`);\n this.opts.emitter.emit('browser.switching', {\n from: prevBrowser,\n to: browser,\n reason: lastError ? this.classifyError(lastError) : 'rotation',\n });\n\n const prevTimeout = this.opts.transportOpts.connectTimeoutMs;\n this.opts.transportOpts.connectTimeoutMs = this.retryTimeoutMs;\n await this.switchBrowser(ctx, browser);\n this.opts.transportOpts.connectTimeoutMs = prevTimeout;\n\n this.opts.emitter.emit('browser.switched', { browser });\n } catch (switchErr) {\n logger.warn(`retry: switch to ${browser} failed, skipping`, {\n error: switchErr instanceof Error ? switchErr.message : String(switchErr),\n });\n if (switchErr instanceof BackendUnavailableError) {\n this.downBackends.add(browser);\n }\n return { success: false, totalAttempts, triedAction: false, lastError: switchErr instanceof Error ? switchErr : undefined };\n }\n }\n\n const MAX_TRANSIENT_RETRIES = allowTransientRetries ? 2 : 0;\n const MAX_DISCONNECT_RETRIES = allowTransientRetries ? 2 : 0;\n let transientRetries = 0;\n let disconnectRetries = 0;\n\n while (totalAttempts < budget) {\n totalAttempts++;\n\n try {\n const result = await fn();\n const domain = this.extractDomain(ctx.currentUrl);\n if (domain) this.selector.failureTracker.recordSuccess(domain, browser);\n return { success: true, value: result, totalAttempts, triedAction: true };\n } catch (err) {\n lastError = err instanceof Error ? err : new Error(String(err));\n const errorClass = this.classifyError(lastError);\n\n logger.warn(`retry: attempt ${totalAttempts}/${budget} failed`, {\n error: lastError.message,\n class: errorClass,\n browser,\n stealth,\n });\n\n this.opts.emitter.emit('retry.attempt', {\n attempt: totalAttempts,\n maxRetries: this.opts.maxRetries,\n error: lastError.message,\n });\n\n // Auth → bubble up immediately (caller will throw)\n if (errorClass === 'auth') {\n return { success: false, totalAttempts, triedAction: true, lastError };\n }\n\n // Rate limit → wait and retry same browser\n if (errorClass === 'rate_limit') {\n const waitMs = lastError instanceof RateLimitError && lastError.retryAfterMs\n ? lastError.retryAfterMs\n : 2000;\n await sleep(waitMs);\n continue;\n }\n\n // Backend down → mark this browser type as down\n if (errorClass === 'backend_down') {\n this.downBackends.add(browser);\n return { success: false, totalAttempts, triedAction: true, lastError };\n }\n\n // Blocked → record failure, move to next browser\n if (errorClass === 'blocked') {\n const domain = this.extractDomain(ctx.currentUrl);\n if (domain) this.selector.failureTracker.recordFailure(domain, browser);\n return { success: false, totalAttempts, triedAction: true, lastError };\n }\n\n // WS disconnection → allow 1 reconnect retry with delay (server may free capacity).\n // If second attempt also disconnects, rotate to next browser.\n if (errorClass === 'transient' && this.isDisconnectionError(lastError)) {\n if (disconnectRetries < MAX_DISCONNECT_RETRIES) {\n disconnectRetries++;\n await sleep(500); // Quick reconnect — just need a fresh session\n try {\n await this.switchBrowser(ctx, browser);\n } catch {\n const domain = this.extractDomain(ctx.currentUrl);\n if (domain) this.selector.failureTracker.recordFailure(domain, browser);\n return { success: false, totalAttempts, triedAction: true, lastError };\n }\n continue; // Retry the action on the same browser\n }\n const domain = this.extractDomain(ctx.currentUrl);\n if (domain) this.selector.failureTracker.recordFailure(domain, browser);\n return { success: false, totalAttempts, triedAction: true, lastError };\n }\n\n // Non-disconnect transient → retry same browser up to MAX_TRANSIENT_RETRIES\n if (errorClass === 'transient' && transientRetries < MAX_TRANSIENT_RETRIES) {\n transientRetries++;\n await sleep(100);\n continue; // Retry same browser\n }\n\n // Transient retry exhausted → move to next browser\n const domain = this.extractDomain(ctx.currentUrl);\n if (domain) this.selector.failureTracker.recordFailure(domain, browser);\n return { success: false, totalAttempts, triedAction: true, lastError };\n }\n }\n\n return { success: false, totalAttempts, triedAction: true, lastError };\n }\n\n /** Check if an error indicates the WebSocket/session is dead and needs reconnection. */\n private isDisconnectionError(err: Error): boolean {\n // NavigationError with connection-level errors (but NOT page-level) → reconnect\n if (err instanceof NavigationError) {\n const result = disconnectionClassifier.classify(err.message);\n return result !== false; // false = page-level, true = disconnection, undefined = generic nav error → true\n }\n return disconnectionClassifier.classify(err.message) === true;\n }\n\n /**\n * Classify an error to determine retry strategy.\n *\n * Fast path: typed error instances (instanceof check, no string scan).\n * Slow path: Aho-Corasick O(n) single-pass keyword matching on error message.\n */\n private classifyError(err: Error): ErrorClass {\n // Fast path: typed error instances (no string matching needed)\n if (err instanceof AuthError) return 'auth';\n if (err instanceof RateLimitError) return 'rate_limit';\n if (err instanceof BlockedError) return 'blocked';\n if (err instanceof BackendUnavailableError) return 'backend_down';\n if (err instanceof TimeoutError) return 'transient';\n if (err instanceof ConnectionError) {\n const code = err.wsCode;\n if (code === 1006 || code === 1011) return 'transient';\n if (code === 4001 || code === 4002) return 'auth';\n return 'transient';\n }\n\n // NavigationError subtypes — ERR_ABORTED/ERR_BLOCKED_BY_CLIENT are page-level.\n // Server already retries ERR_ABORTED internally (MAX_NAV_RETRIES); if the client\n // still sees it, adding more connections makes overload worse. Classify as blocked\n // so the client rotates browser/stealth without piling on reconnects.\n if (err instanceof NavigationError) {\n const cls = errorClassifier.classify(err.message);\n return cls === 'blocked' ? 'blocked' : 'transient';\n }\n\n // Heuristic: single O(n) scan via Aho-Corasick trie\n // Note: \"rate limit exceeded\" / \"too many requests\" → blocked (browser rotation).\n // Only transport-level \"429\" without those phrases → rate_limit.\n const cls = errorClassifier.classify(err.message);\n if (cls) return cls;\n\n // Transport-level 429 fallback (not caught by keyword classifier which has \"rate limit exceeded\" → blocked)\n if (err.message.includes('429')) return 'rate_limit';\n\n return 'transient';\n }\n\n /** Reconnect with a (possibly different) browser, re-navigate to the same URL. */\n private async switchBrowser(ctx: RetryContext, newBrowser: BrowserType): Promise<void> {\n ctx.adapter.destroy();\n\n await ctx.transport.reconnect(newBrowser);\n\n const adapterOpts = this.commandTimeoutMs !== 30_000\n ? { commandTimeoutMs: this.commandTimeoutMs }\n : undefined;\n const newAdapter = new ProtocolAdapter(\n ctx.transport,\n this.opts.emitter,\n newBrowser,\n adapterOpts,\n );\n await newAdapter.init();\n\n ctx.adapter = newAdapter;\n ctx.onAdapterChanged(newAdapter);\n\n if (ctx.currentUrl) {\n await newAdapter.navigate(ctx.currentUrl);\n await sleep(200);\n }\n }\n\n /**\n * Get stealth progression: from current level up to maxStealthLevel.\n * e.g. start=0, max=3 → [0, 1, 2, 3]\n * e.g. start=2, max=3 → [2, 3]\n */\n private getStealthProgression(): number[] {\n const start = this.currentStealthLevel;\n const levels: number[] = [start];\n let next = start < 1 ? 1 : start + 1;\n while (next <= this.maxStealthLevel) {\n levels.push(next);\n next++;\n }\n return levels;\n }\n\n /**\n * Order PRIMARY browsers starting from `start`, then the rest in primary rotation order.\n * If `start` is not in PRIMARY_ROTATION, returns primary rotation as-is.\n */\n private orderedPrimaryBrowsers(start: BrowserType): BrowserType[] {\n const idx = PRIMARY_ROTATION.indexOf(start);\n if (idx <= 0) return [...PRIMARY_ROTATION];\n return [\n ...PRIMARY_ROTATION.slice(idx),\n ...PRIMARY_ROTATION.slice(0, idx),\n ];\n }\n\n private extractDomain(url: string | undefined): string | undefined {\n if (!url) return undefined;\n try {\n return new URL(url).hostname;\n } catch {\n return undefined;\n }\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((r) => setTimeout(r, ms));\n}\n","/**\n * Aho-Corasick keyword classifier — O(n) multi-pattern substring matching.\n *\n * Scans the input string exactly ONCE regardless of how many keywords exist.\n * Returns the classification of the first matched keyword (priority-ordered).\n *\n * Built at module load time — zero per-call allocation or compilation.\n */\n\ninterface TrieNode<T> {\n children: Map<number, TrieNode<T>>; // char code → child\n output: T | undefined; // classification if this node ends a keyword\n fail: TrieNode<T> | undefined; // failure link (longest proper suffix in trie)\n dict: TrieNode<T> | undefined; // dictionary suffix link (nearest ancestor with output)\n}\n\nexport class KeywordClassifier<T> {\n private root: TrieNode<T>;\n\n constructor(rules: [string[], T][]) {\n this.root = { children: new Map(), output: undefined, fail: undefined, dict: undefined };\n\n // Insert keywords — rules are in priority order (first match wins)\n for (const [keywords, cls] of rules) {\n for (const kw of keywords) {\n this.insert(kw.toLowerCase(), cls);\n }\n }\n\n this.buildFailureLinks();\n }\n\n /**\n * Classify a string by scanning it once for all keywords.\n * Returns the classification of the highest-priority matching keyword, or undefined.\n */\n classify(text: string): T | undefined {\n let node = this.root;\n for (let i = 0; i < text.length; i++) {\n // lowercase inline (avoids allocating a new string)\n let ch = text.charCodeAt(i);\n if (ch >= 65 && ch <= 90) ch += 32; // A-Z → a-z\n\n // Follow failure links until we find a matching transition or reach root\n while (node !== this.root && !node.children.has(ch)) {\n node = node.fail!;\n }\n node = node.children.get(ch) ?? this.root;\n\n // Check output chain for matches\n if (node.output !== undefined) return node.output;\n if (node.dict !== undefined && node.dict.output !== undefined) {\n return node.dict.output;\n }\n }\n return undefined;\n }\n\n private insert(word: string, cls: T): void {\n let node = this.root;\n for (let i = 0; i < word.length; i++) {\n const ch = word.charCodeAt(i);\n let child = node.children.get(ch);\n if (!child) {\n child = { children: new Map(), output: undefined, fail: undefined, dict: undefined };\n node.children.set(ch, child);\n }\n node = child;\n }\n // First rule wins — don't overwrite higher-priority classification\n if (node.output === undefined) {\n node.output = cls;\n }\n }\n\n private buildFailureLinks(): void {\n const queue: TrieNode<T>[] = [];\n\n // Root's children have fail → root\n for (const child of this.root.children.values()) {\n child.fail = this.root;\n child.dict = this.root;\n queue.push(child);\n }\n\n // BFS to build failure and dictionary links\n let head = 0;\n while (head < queue.length) {\n const node = queue[head++]!;\n\n for (const [ch, child] of node.children) {\n // Find failure link for child\n let fail = node.fail!;\n while (fail !== this.root && !fail.children.has(ch)) {\n fail = fail.fail!;\n }\n child.fail = fail.children.get(ch) ?? this.root;\n if (child.fail === child) child.fail = this.root; // avoid self-loop\n\n // Dictionary suffix link — nearest ancestor node with output\n child.dict = child.fail.output !== undefined\n ? child.fail\n : (child.fail.dict ?? undefined);\n\n queue.push(child);\n }\n }\n }\n}\n","/** LLM configuration for AI methods. */\nexport interface LLMConfig {\n /** Provider: 'openai', 'anthropic', or 'openrouter'. */\n provider: 'openai' | 'anthropic' | 'openrouter';\n /** Model name (e.g. 'gpt-4o', 'claude-sonnet-4-5-20250929'). */\n model: string;\n /** API key for the provider. */\n apiKey: string;\n /** Base URL override (e.g. for OpenRouter or local vLLM). */\n baseUrl?: string;\n /** Max tokens (default: 4096). */\n maxTokens?: number;\n /** Temperature (default: 0.1). */\n temperature?: number;\n}\n\n/** Message format for LLM calls. */\nexport interface LLMMessage {\n role: 'system' | 'user' | 'assistant';\n content: string | LLMContentPart[];\n}\n\nexport type LLMContentPart =\n | { type: 'text'; text: string }\n | { type: 'image_url'; image_url: { url: string } };\n\n/** Pluggable LLM provider interface. */\nexport interface LLMProvider {\n /** Call the LLM with messages and get a text response. */\n chat(messages: LLMMessage[], options?: { jsonMode?: boolean }): Promise<string>;\n /** Call the LLM with messages and get a parsed JSON response. */\n chatJSON<T = unknown>(messages: LLMMessage[]): Promise<T>;\n}\n\n/** Create an LLM provider from config. */\nexport function createProvider(config: LLMConfig): LLMProvider {\n switch (config.provider) {\n case 'openai':\n case 'openrouter': {\n // Dynamic import to keep this module sync\n const { OpenAICompatibleProvider } = require('./providers/openai.js') as typeof import('./providers/openai.js');\n return new OpenAICompatibleProvider(config);\n }\n case 'anthropic': {\n const { AnthropicProvider } = require('./providers/anthropic.js') as typeof import('./providers/anthropic.js');\n return new AnthropicProvider(config);\n }\n default:\n throw new Error(`Unknown LLM provider: ${config.provider}`);\n }\n}\n","import type { LLMContentPart } from './llm-provider.js';\n\n/**\n * System prompt for the web automation agent.\n *\n * Ported VERBATIM from browser_server/src/ai/llm.rs SYSTEM_PROMPT (lines 30-135)\n * to ensure identical agent behavior between server-side captcha solver\n * and client-side agent.\n */\nexport const SYSTEM_PROMPT = `\\\nYou are an expert web automation agent. You interact with any webpage to solve challenges, fill forms, navigate sites, extract data, and complete complex multi-step tasks.\n\n## Input\nEach round you receive:\n- Screenshot of current page state\n- URL, title, HTML context\n- Round number and detected challenge types\n\n## Output\nReturn a single JSON object (no prose):\n{\n \"label\": \"brief action description\",\n \"done\": true|false,\n \"steps\": [...]\n}\nSet \"done\": true when the task is fully complete. Set \"done\": false to continue.\n\n## Coordinate System\n**ClickPoint coordinates use CSS pixels** (same as getBoundingClientRect()).\n- Screenshot pixels = viewport x DPR. Divide screenshot coordinates by DPR for CSS pixels.\n- Example: viewport 1280x960 at DPR 2 = screenshot 2560x1920. Visual point (500,400) in screenshot = (250,200) CSS.\n\n## Actions\n\n### Click\n- { \"Click\": \"selector\" } - CSS selector click\n- { \"ClickPoint\": { \"x\": 100, \"y\": 200 } } - CSS pixel coordinates\n- { \"ClickAll\": \"selector\" } - Click all matches\n- { \"DoubleClick\": \"selector\" } / { \"DoubleClickPoint\": { \"x\": 0, \"y\": 0 } }\n- { \"RightClick\": \"selector\" } / { \"RightClickPoint\": { \"x\": 0, \"y\": 0 } }\n- { \"ClickHold\": { \"selector\": \"sel\", \"hold_ms\": 500 } } / { \"ClickHoldPoint\": { \"x\": 0, \"y\": 0, \"hold_ms\": 500 } }\n- { \"WaitForAndClick\": \"selector\" }\n\n### Drag\n- { \"ClickDrag\": { \"from\": \"sel1\", \"to\": \"sel2\" } }\n- { \"ClickDragPoint\": { \"from_x\": 0, \"from_y\": 0, \"to_x\": 100, \"to_y\": 100 } }\n\n### Type & Input\n- { \"Fill\": { \"selector\": \"input\", \"value\": \"text\" } } - Clear and type\n- { \"Type\": { \"value\": \"text\" } } - Type into focused element\n- { \"Clear\": \"selector\" } - Clear input\n- { \"Press\": \"Enter\" } - Press key (Enter, Tab, Escape, ArrowDown, Space, etc.)\n- { \"KeyDown\": \"Shift\" } / { \"KeyUp\": \"Shift\" }\n\n### Select & Focus\n- { \"Select\": { \"selector\": \"select\", \"value\": \"option\" } }\n- { \"Focus\": \"selector\" } / { \"Blur\": \"selector\" }\n- { \"Hover\": \"selector\" } / { \"HoverPoint\": { \"x\": 0, \"y\": 0 } }\n\n### Scroll\n- { \"ScrollY\": 300 } - Scroll down (negative = up)\n- { \"ScrollX\": 200 } - Scroll right (negative = left)\n- { \"ScrollTo\": { \"selector\": \"element\" } } - Scroll element into view\n- { \"ScrollToPoint\": { \"x\": 0, \"y\": 500 } }\n- { \"InfiniteScroll\": 5 } - Scroll to bottom repeatedly\n\n### Wait\n- { \"Wait\": 1000 } - Wait milliseconds\n- { \"WaitFor\": \"selector\" } - Wait for element\n- { \"WaitForWithTimeout\": { \"selector\": \"sel\", \"timeout\": 5000 } }\n- { \"WaitForNavigation\": null } - Wait for page load\n- { \"WaitForDom\": { \"selector\": \"sel\", \"timeout\": 5000 } }\n\n### Navigate\n- { \"Navigate\": \"https://url\" } - Go to URL\n- { \"GoBack\": null } / { \"GoForward\": null } / { \"Reload\": null }\n\n### Viewport\n- { \"SetViewport\": { \"width\": 1920, \"height\": 1080, \"device_scale_factor\": 2.0 } } - Change viewport/DPR at runtime. Follow with { \"Wait\": 500 }.\n\n### JavaScript\n- { \"Evaluate\": \"javascript code\" } - Execute JS on the page\n\n**Evaluate notes:**\n- Return values are NOT sent back. To see results, inject into the page:\n - Title: document.title = JSON.stringify(data) (visible in PAGE TITLE next round)\n - DOM: inject a visible overlay div with the info (visible in screenshot)\n- **Do NOT use element.click() in Evaluate** - it does not trigger real browser events (mousedown/pointerdown). Always use real Click/ClickPoint actions for interactions.\n- **Always pair Evaluate with action steps** in the same round. Never submit a round with ONLY Evaluate.\n\n## Core Strategy\n\n1. **Be efficient**: Solve challenges in the fewest rounds possible. Combine Evaluate (read state) + action (click/fill) in the SAME round. Never spend a round only gathering data.\n2. **Batch operations**: When you need to click/select multiple elements, include multiple Click actions in a single step list rather than spreading across multiple rounds.\n3. **Evaluate = READ ONLY**: Use Evaluate to read DOM state, computed styles, coordinates. Set results in document.title. NEVER use el.click() inside Evaluate - it does NOT trigger real browser events. Use real Click/ClickPoint for all interactions.\n4. **Prefer selectors over coordinates**: Use CSS selectors when elements exist in DOM. Reserve ClickPoint for canvas/SVG or when selectors fail.\n5. **Handle stagnation**: If your last actions had no visible effect, try a different approach - different selector, different interaction method, or use Evaluate to understand why.\n6. **Never repeat failures**: If something fails twice, change strategy entirely. If verify/submit doesn't advance, your answer is likely wrong - re-examine.\n7. **Commit and iterate**: Submit your best answer rather than endlessly adjusting. Learn from the result.\n\n## Captcha & Challenge Strategies\n\n- **reCAPTCHA checkbox**: Click the iframe first, then the checkbox inside it.\n- **Cloudflare Turnstile**: The challenge is in an iframe. Look for \\`iframe[src*=\"challenges.cloudflare.com\"]\\` and click inside it.\n- **Image selection (reCAPTCHA v2)**: Identify matching images and click them one at a time. After selecting, click the verify button. If incorrect, the grid refreshes - try again.\n- **Slider/puzzle captchas**: Use ClickDragPoint to drag the slider from start to end position.\n- **Text captchas**: Read the distorted text carefully, then Fill the answer input and Press Enter.\n- **Visual puzzles**: Describe what you see, reason about the solution, then act precisely.\n- **PerimeterX (px-captcha)**: This is a press-and-hold captcha. Find the button element inside the #px-captcha container or iframe with [role=\"button\"]. Use ClickHold with hold_ms: 15000 (15 seconds). Wait for the captcha wrapper to disappear after release.\n- **DataDome**: Often shows an iframe from geo.captcha-delivery.com. Click inside the iframe to interact with the challenge. May include slider or image selection.\n- **Arkose Labs / FunCaptcha**: Interactive challenge in an iframe from arkoselabs.com. Follow on-screen instructions — typically image rotation, matching, or selection puzzles.\n- **Cookie/consent banners**: Click accept/dismiss buttons to clear overlays before solving the actual captcha.\n- **Multiple challenge steps**: Some captchas have multiple rounds (e.g., reCAPTCHA may ask to solve 3 image grids). Keep going until done.\n\n## Output Rules\n- JSON only, no markdown or prose\n- Always include \"label\", \"done\", and \"steps\"\n- \"steps\" array can have multiple actions per round`;\n\n/**\n * Build the user message for an agent round.\n * Mirrors llm.rs call_vision() user content format.\n */\nexport function buildUserMessage(\n url: string,\n html: string,\n screenshotB64: string,\n extraContext?: string,\n): LLMContentPart[] {\n const truncatedHtml = truncateHtml(html, 12000);\n const userText = `URL: ${url}\\nHTML (truncated):\\n${truncatedHtml}\\n\\n${extraContext ?? 'Complete the task on this page.'}`;\n\n return [\n { type: 'text' as const, text: userText },\n {\n type: 'image_url' as const,\n image_url: { url: `data:image/png;base64,${screenshotB64}` },\n },\n ];\n}\n\n/**\n * Truncate HTML to roughly maxChars, breaking at a tag boundary.\n * Mirrors llm.rs truncate_html().\n */\nexport function truncateHtml(html: string, maxChars: number): string {\n if (html.length <= maxChars) return html;\n const slice = html.slice(0, maxChars);\n const lastClose = slice.lastIndexOf('>');\n return lastClose > 0 ? html.slice(0, lastClose + 1) : slice;\n}\n","import type { ProtocolAdapter } from '../protocol/protocol-adapter.js';\nimport type { LLMProvider } from './llm-provider.js';\nimport type { SpiderEventEmitter } from '../events/emitter.js';\nimport { SYSTEM_PROMPT, buildUserMessage } from './prompts.js';\nimport { getKeyParams } from '../protocol/types.js';\nimport { logger } from '../utils/logger.js';\nimport { TimeoutError } from '../utils/errors.js';\n\n// -------------------------------------------------------------------\n// Action types (mirrors actions.rs AgentAction enum)\n// -------------------------------------------------------------------\n\n/** All possible agent actions — mirrors browser_server/src/ai/actions.rs. */\nexport type AgentAction =\n | { Click: string }\n | { ClickAll: string }\n | { ClickPoint: { x: number; y: number } }\n | { ClickHold: { selector: string; hold_ms: number } }\n | { ClickHoldPoint: { x: number; y: number; hold_ms: number } }\n | { DoubleClick: string }\n | { DoubleClickPoint: { x: number; y: number } }\n | { RightClick: string }\n | { RightClickPoint: { x: number; y: number } }\n | { WaitForAndClick: string }\n | { ClickDrag: { from: string; to: string; modifier?: number } }\n | { ClickDragPoint: { from_x: number; from_y: number; to_x: number; to_y: number; modifier?: number } }\n | { Type: { value: string } }\n | { Fill: { selector: string; value: string } }\n | { Clear: string }\n | { Press: string }\n | { KeyDown: string }\n | { KeyUp: string }\n | { Select: { selector: string; value: string } }\n | { Focus: string }\n | { Blur: string }\n | { Hover: string }\n | { HoverPoint: { x: number; y: number } }\n | { ScrollY: number }\n | { ScrollX: number }\n | { ScrollTo: { selector: string } }\n | { ScrollToPoint: { x: number; y: number } }\n | { InfiniteScroll: number }\n | { Wait: number }\n | { WaitFor: string }\n | { WaitForWithTimeout: { selector: string; timeout: number } }\n | { WaitForNavigation: null }\n | { WaitForDom: { selector?: string; timeout: number } }\n | { Navigate: string }\n | { GoBack: null }\n | { GoForward: null }\n | { Reload: null }\n | { SetViewport: { width: number; height: number; device_scale_factor?: number; mobile?: boolean } }\n | { Evaluate: string }\n | { Screenshot: null };\n\n/** Parsed LLM response — mirrors actions.rs AgentPlan. */\nexport interface AgentPlan {\n label: string;\n done: boolean;\n steps: AgentAction[];\n extracted?: unknown;\n memory_ops?: unknown[];\n}\n\nexport interface AgentOptions {\n /** Max automation rounds (default: 30). */\n maxRounds: number;\n /** Delay in ms after actions for page settle (default: 1500). */\n stepDelayMs: number;\n /** Extra context/instruction for each round. */\n instruction?: string;\n}\n\nexport interface AgentResult {\n /** Whether the agent completed the task. */\n done: boolean;\n /** Number of rounds executed. */\n rounds: number;\n /** Extracted data (accumulated across rounds). */\n extracted?: unknown;\n /** Final label from the agent. */\n label: string;\n}\n\n/**\n * Autonomous multi-step agent.\n *\n * Uses the same action vocabulary and system prompt as Spider's\n * server-side captcha solver (browser_server/src/ai/agent.rs).\n *\n * Loop: screenshot → HTML → LLM → parse plan → execute actions → repeat.\n */\nexport class Agent {\n private adapter: ProtocolAdapter;\n private llm: LLMProvider;\n private emitter: SpiderEventEmitter;\n private opts: Required<Pick<AgentOptions, 'maxRounds' | 'stepDelayMs'>> & Pick<AgentOptions, 'instruction'>;\n\n constructor(\n adapter: ProtocolAdapter,\n llm: LLMProvider,\n emitter: SpiderEventEmitter,\n options?: Partial<AgentOptions>,\n ) {\n this.adapter = adapter;\n this.llm = llm;\n this.emitter = emitter;\n this.opts = {\n maxRounds: options?.maxRounds ?? 30,\n stepDelayMs: options?.stepDelayMs ?? 1500,\n instruction: options?.instruction,\n };\n }\n\n /**\n * Execute the agent loop until the task is done or max rounds reached.\n */\n async execute(instruction: string): Promise<AgentResult> {\n let extracted: unknown = undefined;\n let lastLabel = '';\n\n // Small initial delay for page to render\n await sleep(500);\n\n for (let round = 0; round < this.opts.maxRounds; round++) {\n // 1. Capture screenshot\n let screenshot: string;\n try {\n screenshot = await this.adapter.captureScreenshot();\n } catch (err) {\n logger.warn(`agent: screenshot failed round ${round}`, {\n error: err instanceof Error ? err.message : String(err),\n });\n break;\n }\n\n // 2. Get page HTML\n let html: string;\n try {\n html = await this.adapter.getHTML();\n } catch (err) {\n logger.warn(`agent: get HTML failed round ${round}`, {\n error: err instanceof Error ? err.message : String(err),\n });\n break;\n }\n\n // 3. Get URL and title\n const [url, title] = await Promise.all([\n this.adapter.evaluate('window.location.href').catch(() => 'unknown') as Promise<string>,\n this.adapter.evaluate('document.title').catch(() => '') as Promise<string>,\n ]);\n\n // 4. Call LLM\n const context = `Round ${round + 1}/${this.opts.maxRounds}. Task: ${instruction}\\nPAGE TITLE: ${title}`;\n\n let plan: AgentPlan;\n try {\n plan = await this.llm.chatJSON<AgentPlan>([\n { role: 'system', content: SYSTEM_PROMPT },\n {\n role: 'user',\n content: buildUserMessage(url, html, screenshot, context),\n },\n ]);\n } catch (err) {\n logger.warn(`agent: LLM call failed round ${round}`, {\n error: err instanceof Error ? err.message : String(err),\n });\n await sleep(2000);\n continue;\n }\n\n lastLabel = plan.label ?? '';\n if (plan.extracted !== undefined) {\n extracted = plan.extracted;\n }\n\n logger.info(`agent: round ${round + 1}`, {\n label: plan.label,\n done: plan.done,\n steps: plan.steps?.length ?? 0,\n });\n\n this.emitter.emit('agent.step', {\n round: round + 1,\n label: plan.label,\n stepsCount: plan.steps?.length ?? 0,\n });\n\n // 5. Check if done\n if (plan.done) {\n this.emitter.emit('agent.done', { rounds: round + 1, result: extracted });\n return { done: true, rounds: round + 1, extracted, label: lastLabel };\n }\n\n if (!plan.steps || plan.steps.length === 0) {\n logger.info('agent: no steps, retrying');\n await sleep(this.opts.stepDelayMs);\n continue;\n }\n\n // 6. Execute each step\n for (let i = 0; i < plan.steps.length; i++) {\n const action = plan.steps[i]!;\n try {\n await executeAction(this.adapter, action);\n } catch (err) {\n logger.warn(`agent: action failed round ${round} step ${i}`, {\n action: JSON.stringify(action).slice(0, 100),\n error: err instanceof Error ? err.message : String(err),\n });\n break;\n }\n await sleep(200);\n }\n\n // 7. Wait for page to settle\n await sleep(this.opts.stepDelayMs);\n }\n\n // Max rounds exceeded\n logger.warn('agent: max rounds exceeded');\n this.emitter.emit('agent.error', {\n error: 'max rounds exceeded',\n round: this.opts.maxRounds,\n });\n return { done: false, rounds: this.opts.maxRounds, extracted, label: lastLabel };\n }\n}\n\n// -------------------------------------------------------------------\n// Action executor — mirrors agent.rs execute_action()\n// -------------------------------------------------------------------\n\n/**\n * Execute a single agent action via the protocol adapter.\n * Handles all 40+ action types from the AgentAction union.\n */\nexport async function executeAction(\n adapter: ProtocolAdapter,\n action: AgentAction,\n): Promise<void> {\n // Click actions\n if ('Click' in action) {\n const { x, y } = await getElementCenter(adapter, (action as any).Click);\n await adapter.clickPoint(x, y);\n return;\n }\n if ('ClickAll' in action) {\n const selector = (action as any).ClickAll as string;\n const points = (await adapter.evaluate(`\n (function() {\n const els = document.querySelectorAll(${JSON.stringify(selector)});\n return Array.from(els).map(el => {\n const r = el.getBoundingClientRect();\n return { x: r.x + r.width / 2, y: r.y + r.height / 2 };\n });\n })()\n `)) as Array<{ x: number; y: number }>;\n if (Array.isArray(points)) {\n for (const pt of points) {\n await adapter.clickPoint(pt.x, pt.y);\n await sleep(100);\n }\n }\n return;\n }\n if ('ClickPoint' in action) {\n const { x, y } = (action as any).ClickPoint;\n await adapter.clickPoint(x, y);\n return;\n }\n if ('ClickHold' in action) {\n const { selector, hold_ms } = (action as any).ClickHold;\n const { x, y } = await getElementCenter(adapter, selector);\n await adapter.clickHoldPoint(x, y, hold_ms);\n return;\n }\n if ('ClickHoldPoint' in action) {\n const { x, y, hold_ms } = (action as any).ClickHoldPoint;\n await adapter.clickHoldPoint(x, y, hold_ms);\n return;\n }\n if ('DoubleClick' in action) {\n const { x, y } = await getElementCenter(adapter, (action as any).DoubleClick);\n await adapter.doubleClickPoint(x, y);\n return;\n }\n if ('DoubleClickPoint' in action) {\n const { x, y } = (action as any).DoubleClickPoint;\n await adapter.doubleClickPoint(x, y);\n return;\n }\n if ('RightClick' in action) {\n const { x, y } = await getElementCenter(adapter, (action as any).RightClick);\n await adapter.rightClickPoint(x, y);\n return;\n }\n if ('RightClickPoint' in action) {\n const { x, y } = (action as any).RightClickPoint;\n await adapter.rightClickPoint(x, y);\n return;\n }\n if ('WaitForAndClick' in action) {\n const selector = (action as any).WaitForAndClick as string;\n await waitForElement(adapter, selector, 5000);\n const { x, y } = await getElementCenter(adapter, selector);\n await adapter.clickPoint(x, y);\n return;\n }\n\n // Drag actions\n if ('ClickDrag' in action) {\n const { from, to } = (action as any).ClickDrag;\n const f = await getElementCenter(adapter, from);\n const t = await getElementCenter(adapter, to);\n await adapter.dragPoint(f.x, f.y, t.x, t.y);\n return;\n }\n if ('ClickDragPoint' in action) {\n const { from_x, from_y, to_x, to_y } = (action as any).ClickDragPoint;\n await adapter.dragPoint(from_x, from_y, to_x, to_y);\n return;\n }\n\n // Input actions\n if ('Type' in action) {\n await adapter.insertText((action as any).Type.value);\n return;\n }\n if ('Fill' in action) {\n const { selector, value } = (action as any).Fill;\n // Clear via JS\n await adapter.evaluate(`\n (function() {\n const el = document.querySelector(${JSON.stringify(selector)});\n if (el) { el.focus(); el.value = ''; }\n })()\n `);\n // Click for real focus\n try {\n const { x, y } = await getElementCenter(adapter, selector);\n await adapter.clickPoint(x, y);\n } catch {\n // element may not be clickable\n }\n // Insert text\n await adapter.insertText(value);\n // Dispatch events\n await adapter.evaluate(`\n (function() {\n const el = document.querySelector(${JSON.stringify(selector)});\n if (el) {\n el.dispatchEvent(new Event('input', { bubbles: true }));\n el.dispatchEvent(new Event('change', { bubbles: true }));\n }\n })()\n `);\n return;\n }\n if ('Clear' in action) {\n const selector = (action as any).Clear as string;\n await adapter.evaluate(`document.querySelector(${JSON.stringify(selector)}).value = ''`);\n return;\n }\n if ('Press' in action) {\n await adapter.pressKey((action as any).Press);\n return;\n }\n if ('KeyDown' in action) {\n await adapter.keyDown((action as any).KeyDown);\n return;\n }\n if ('KeyUp' in action) {\n await adapter.keyUp((action as any).KeyUp);\n return;\n }\n\n // Select & Focus\n if ('Select' in action) {\n const { selector, value } = (action as any).Select;\n await adapter.evaluate(`\n (function() {\n const el = document.querySelector(${JSON.stringify(selector)});\n if (el) {\n el.value = ${JSON.stringify(value)};\n el.dispatchEvent(new Event('change', { bubbles: true }));\n }\n })()\n `);\n return;\n }\n if ('Focus' in action) {\n await adapter.evaluate(`document.querySelector(${JSON.stringify((action as any).Focus)})?.focus()`);\n return;\n }\n if ('Blur' in action) {\n await adapter.evaluate(`document.querySelector(${JSON.stringify((action as any).Blur)})?.blur()`);\n return;\n }\n if ('Hover' in action) {\n const { x, y } = await getElementCenter(adapter, (action as any).Hover);\n await adapter.hoverPoint(x, y);\n return;\n }\n if ('HoverPoint' in action) {\n const { x, y } = (action as any).HoverPoint;\n await adapter.hoverPoint(x, y);\n return;\n }\n\n // Scroll actions\n if ('ScrollY' in action) {\n await adapter.evaluate(`window.scrollBy(0, ${(action as any).ScrollY})`);\n return;\n }\n if ('ScrollX' in action) {\n await adapter.evaluate(`window.scrollBy(${(action as any).ScrollX}, 0)`);\n return;\n }\n if ('ScrollTo' in action) {\n const selector = (action as any).ScrollTo.selector;\n await adapter.evaluate(\n `document.querySelector(${JSON.stringify(selector)})?.scrollIntoView({ behavior: 'smooth', block: 'center' })`,\n );\n return;\n }\n if ('ScrollToPoint' in action) {\n const { x, y } = (action as any).ScrollToPoint;\n await adapter.evaluate(`window.scrollTo(${x}, ${y})`);\n return;\n }\n if ('InfiniteScroll' in action) {\n const max = (action as any).InfiniteScroll as number;\n for (let i = 0; i < max; i++) {\n await adapter.evaluate('window.scrollTo(0, document.body.scrollHeight)');\n await sleep(500);\n }\n return;\n }\n\n // Wait actions\n if ('Wait' in action) {\n await sleep((action as any).Wait as number);\n return;\n }\n if ('WaitFor' in action) {\n await waitForElement(adapter, (action as any).WaitFor, 5000);\n return;\n }\n if ('WaitForWithTimeout' in action) {\n const { selector, timeout } = (action as any).WaitForWithTimeout;\n await waitForElement(adapter, selector, timeout);\n return;\n }\n if ('WaitForNavigation' in action) {\n await sleep(1000);\n return;\n }\n if ('WaitForDom' in action) {\n const timeout = (action as any).WaitForDom.timeout ?? 5000;\n await sleep(timeout);\n return;\n }\n\n // Navigation actions\n if ('Navigate' in action) {\n await adapter.navigate((action as any).Navigate);\n return;\n }\n if ('GoBack' in action) {\n await adapter.evaluate('window.history.back()');\n return;\n }\n if ('GoForward' in action) {\n await adapter.evaluate('window.history.forward()');\n return;\n }\n if ('Reload' in action) {\n await adapter.evaluate('window.location.reload()');\n return;\n }\n\n // Viewport\n if ('SetViewport' in action) {\n const { width, height, device_scale_factor, mobile } = (action as any).SetViewport;\n await adapter.setViewport(width, height, device_scale_factor ?? 2, mobile ?? false);\n return;\n }\n\n // JavaScript\n if ('Evaluate' in action) {\n await adapter.evaluate((action as any).Evaluate);\n return;\n }\n\n // Screenshot (no-op in client — handled by agent loop)\n if ('Screenshot' in action) {\n return;\n }\n\n logger.warn('agent: unknown action', { action: JSON.stringify(action).slice(0, 100) });\n}\n\n// -------------------------------------------------------------------\n// Helpers (mirrors agent.rs get_element_center / wait_for_element)\n// -------------------------------------------------------------------\n\nasync function getElementCenter(\n adapter: ProtocolAdapter,\n selector: string,\n): Promise<{ x: number; y: number }> {\n const result = (await adapter.evaluate(`\n (function() {\n const el = document.querySelector(${JSON.stringify(selector)});\n if (!el) return null;\n el.scrollIntoView({ block: 'center', behavior: 'instant' });\n const r = el.getBoundingClientRect();\n return { x: r.x + r.width / 2, y: r.y + r.height / 2 };\n })()\n `)) as { x: number; y: number } | null;\n\n if (!result) {\n throw new Error(`Element not found: ${selector}`);\n }\n return result;\n}\n\nasync function waitForElement(\n adapter: ProtocolAdapter,\n selector: string,\n timeoutMs: number,\n): Promise<void> {\n const interval = 100;\n const maxIter = Math.ceil(timeoutMs / interval);\n const checkJs = `!!document.querySelector(${JSON.stringify(selector)})`;\n for (let i = 0; i < maxIter; i++) {\n const found = await adapter.evaluate(checkJs);\n if (found) return;\n await sleep(interval);\n }\n throw new TimeoutError(`Timeout waiting for element: ${selector}`);\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((r) => setTimeout(r, ms));\n}\n","import type { ProtocolAdapter } from '../protocol/protocol-adapter.js';\nimport type { LLMProvider } from './llm-provider.js';\nimport { SYSTEM_PROMPT, buildUserMessage } from './prompts.js';\nimport { executeAction, type AgentAction, type AgentPlan } from './agent.js';\n\n/**\n * Execute a single action from natural language.\n *\n * Takes a screenshot + HTML, sends to LLM with the instruction,\n * then executes the returned action steps.\n *\n * Example: `await act(adapter, llm, 'Click the login button')`\n */\nexport async function act(\n adapter: ProtocolAdapter,\n llm: LLMProvider,\n instruction: string,\n): Promise<void> {\n // Capture current page state\n const [screenshot, html, url, title] = await Promise.all([\n adapter.captureScreenshot(),\n adapter.getHTML(),\n adapter.evaluate('window.location.href') as Promise<string>,\n adapter.evaluate('document.title') as Promise<string>,\n ]);\n\n const context = `Task: ${instruction}\\nPAGE TITLE: ${title}`;\n\n // Call LLM\n const plan = await llm.chatJSON<AgentPlan>([\n { role: 'system', content: SYSTEM_PROMPT },\n {\n role: 'user',\n content: buildUserMessage(url, html, screenshot, context),\n },\n ]);\n\n // Execute steps\n if (plan.steps && Array.isArray(plan.steps)) {\n for (const step of plan.steps) {\n await executeAction(adapter, step);\n await sleep(200);\n }\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((r) => setTimeout(r, ms));\n}\n","/**\n * JavaScript snippets for evaluate() — element interaction, accessibility tree, etc.\n * Injected into the browser page via protocol evaluate.\n */\n\n/** Get the center coordinates of an element (scrolls into view). */\nexport const GET_ELEMENT_CENTER = (selector: string) => `\n(function() {\n const el = document.querySelector(${JSON.stringify(selector)});\n if (!el) return null;\n el.scrollIntoView({ block: 'center', behavior: 'instant' });\n const r = el.getBoundingClientRect();\n return { x: r.x + r.width / 2, y: r.y + r.height / 2 };\n})()\n`;\n\n/** Get all interactive elements on the page with selectors and bounding rects. */\nexport const GET_INTERACTIVE_ELEMENTS = `\n(function() {\n const interactiveSelectors = [\n 'a[href]',\n 'button',\n 'input',\n 'select',\n 'textarea',\n '[role=\"button\"]',\n '[role=\"link\"]',\n '[role=\"tab\"]',\n '[role=\"menuitem\"]',\n '[role=\"checkbox\"]',\n '[role=\"radio\"]',\n '[role=\"switch\"]',\n '[role=\"combobox\"]',\n '[onclick]',\n '[tabindex]',\n 'summary',\n 'details',\n 'label',\n ];\n const seen = new Set();\n const results = [];\n for (const sel of interactiveSelectors) {\n for (const el of document.querySelectorAll(sel)) {\n if (seen.has(el)) continue;\n seen.add(el);\n const r = el.getBoundingClientRect();\n if (r.width === 0 && r.height === 0) continue;\n if (r.bottom < 0 || r.right < 0) continue;\n\n const tag = el.tagName.toLowerCase();\n const type = el.getAttribute('type') || '';\n const text = (el.textContent || '').trim().slice(0, 100);\n const ariaLabel = el.getAttribute('aria-label') || '';\n const placeholder = el.getAttribute('placeholder') || '';\n const href = el.getAttribute('href') || '';\n const value = (el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement)\n ? el.value.slice(0, 50) : '';\n\n // Build a unique-ish selector\n let cssSelector = tag;\n const id = el.getAttribute('id');\n if (id) {\n cssSelector = '#' + CSS.escape(id);\n } else {\n const cls = el.getAttribute('class');\n if (cls) {\n const classes = cls.trim().split(/\\\\s+/).slice(0, 2);\n cssSelector = tag + classes.map(c => '.' + CSS.escape(c)).join('');\n }\n const name = el.getAttribute('name');\n if (name) {\n cssSelector = tag + '[name=\"' + CSS.escape(name) + '\"]';\n }\n }\n\n results.push({\n selector: cssSelector,\n tag,\n type,\n text,\n ariaLabel,\n placeholder,\n href,\n value,\n rect: {\n x: Math.round(r.x),\n y: Math.round(r.y),\n width: Math.round(r.width),\n height: Math.round(r.height),\n },\n });\n }\n }\n return results;\n})()\n`;\n","import type { ProtocolAdapter } from '../protocol/protocol-adapter.js';\nimport type { LLMProvider } from './llm-provider.js';\nimport { GET_INTERACTIVE_ELEMENTS } from '../utils/dom.js';\nimport { truncateHtml } from '../utils/html.js';\n\n/** An observed interactive element on the page. */\nexport interface ObserveResult {\n /** CSS selector that can target this element. */\n selector: string;\n /** HTML tag name. */\n tag: string;\n /** Input type (for input elements). */\n type: string;\n /** Visible text content (truncated). */\n text: string;\n /** aria-label attribute. */\n ariaLabel: string;\n /** Placeholder text. */\n placeholder: string;\n /** href attribute (for links). */\n href: string;\n /** Current input value (for inputs/textareas). */\n value: string;\n /** Bounding rectangle in viewport coordinates. */\n rect: { x: number; y: number; width: number; height: number };\n /** Relevance score (0-1) when LLM ranking is used. */\n score?: number;\n}\n\n/**\n * Discover interactive elements on the page.\n *\n * Works WITHOUT an LLM — injects a DOM traversal script to collect\n * interactive elements (buttons, links, inputs) with selectors, text,\n * and bounding rects.\n *\n * When instruction is provided + LLM is available, adds ranking/filtering.\n */\nexport async function observe(\n adapter: ProtocolAdapter,\n instruction?: string,\n llm?: LLMProvider,\n): Promise<ObserveResult[]> {\n // Collect all interactive elements via DOM traversal\n const elements = (await adapter.evaluate(GET_INTERACTIVE_ELEMENTS)) as ObserveResult[];\n\n if (!Array.isArray(elements) || elements.length === 0) {\n return [];\n }\n\n // If no instruction or no LLM, return all elements\n if (!instruction || !llm) {\n return elements;\n }\n\n // Use LLM to rank/filter elements by relevance to the instruction\n const elementSummary = elements\n .map((el, i) => {\n const parts = [`[${i}] <${el.tag}>`];\n if (el.text) parts.push(`text=\"${el.text}\"`);\n if (el.ariaLabel) parts.push(`aria=\"${el.ariaLabel}\"`);\n if (el.placeholder) parts.push(`placeholder=\"${el.placeholder}\"`);\n if (el.href) parts.push(`href=\"${el.href}\"`);\n if (el.type) parts.push(`type=\"${el.type}\"`);\n return parts.join(' ');\n })\n .join('\\n');\n\n const response = await llm.chatJSON<{ indices: number[] }>([\n {\n role: 'system',\n content:\n 'You are an element selector. Given a list of page elements and an instruction, return a JSON object with an \"indices\" array of element indices that match the instruction. Order by relevance (most relevant first). Return {\"indices\": []} if none match.',\n },\n {\n role: 'user',\n content: `Instruction: ${instruction}\\n\\nElements:\\n${elementSummary}`,\n },\n ]);\n\n const indices = response.indices ?? [];\n return indices\n .filter((i) => i >= 0 && i < elements.length)\n .map((i, rank) => ({\n ...elements[i]!,\n score: 1 - rank / Math.max(indices.length, 1),\n }));\n}\n","/**\n * Truncate HTML to roughly maxChars, trying to break at a tag boundary.\n * Mirrors server's truncate_html in llm.rs.\n */\nexport function truncateHtml(html: string, maxChars: number = 12000): string {\n if (html.length <= maxChars) return html;\n const slice = html.slice(0, maxChars);\n const lastClose = slice.lastIndexOf('>');\n return lastClose > 0 ? html.slice(0, lastClose + 1) : slice;\n}\n","import type { ProtocolAdapter } from '../protocol/protocol-adapter.js';\nimport type { LLMProvider } from './llm-provider.js';\nimport { truncateHtml } from '../utils/html.js';\nimport type { z } from 'zod';\n\n/**\n * Extract structured data from the page.\n *\n * Takes a screenshot + HTML, sends to LLM with the instruction and optional\n * Zod schema, returns parsed and validated data.\n */\nexport async function extract<T>(\n adapter: ProtocolAdapter,\n llm: LLMProvider,\n instruction: string,\n schema?: z.ZodType<T>,\n): Promise<T> {\n // Capture page state\n const [screenshot, html, url, title] = await Promise.all([\n adapter.captureScreenshot(),\n adapter.getHTML(),\n adapter.evaluate('window.location.href') as Promise<string>,\n adapter.evaluate('document.title') as Promise<string>,\n ]);\n\n const truncatedHtml = truncateHtml(html, 12000);\n\n // Build schema description if provided\n let schemaDesc = '';\n if (schema) {\n // Zod schemas have a ._def property we can inspect\n try {\n schemaDesc = `\\n\\nReturn data matching this JSON schema:\\n${JSON.stringify((schema as any)._def, null, 2)}`;\n } catch {\n schemaDesc = '\\n\\nReturn a JSON object matching the expected structure.';\n }\n }\n\n const systemPrompt = `You are a data extraction agent. Given a webpage screenshot and HTML, extract the requested information as JSON.${schemaDesc}\n\nReturn ONLY a valid JSON object. No prose, no markdown.`;\n\n const userText = `URL: ${url}\\nTitle: ${title}\\nInstruction: ${instruction}\\n\\nHTML (truncated):\\n${truncatedHtml}`;\n\n const result = await llm.chatJSON<T>([\n { role: 'system', content: systemPrompt },\n {\n role: 'user',\n content: [\n { type: 'text', text: userText },\n {\n type: 'image_url',\n image_url: { url: `data:image/png;base64,${screenshot}` },\n },\n ],\n },\n ]);\n\n // Validate with Zod if schema provided\n if (schema) {\n return schema.parse(result);\n }\n\n return result;\n}\n","import { Transport, type TransportOptions } from './protocol/transport.js';\nimport { ProtocolAdapter } from './protocol/protocol-adapter.js';\nimport { SpiderEventEmitter } from './events/emitter.js';\nimport type { BrowserType, SpiderEvents, SpiderEventName } from './events/types.js';\nimport { SpiderPage } from './page.js';\nimport { RetryEngine, type RetryOptions } from './retry/retry-engine.js';\nimport type { LLMConfig } from './ai/llm-provider.js';\nimport { createProvider, type LLMProvider } from './ai/llm-provider.js';\nimport { act } from './ai/act.js';\nimport { observe, type ObserveResult } from './ai/observe.js';\nimport { extract } from './ai/extract.js';\nimport { Agent, type AgentOptions, type AgentResult } from './ai/agent.js';\nimport { logger, type LogLevel } from './utils/logger.js';\nimport type { z } from 'zod';\n\nexport interface SpiderBrowserOptions {\n /** Spider API key (required). */\n apiKey: string;\n /** WebSocket server URL (default: wss://browser.spider.cloud). */\n serverUrl?: string;\n /** Browser to use (default: auto). */\n browser?: BrowserType;\n /** Target URL hint for server browser+proxy selection. */\n url?: string;\n /** Captcha handling (default: solve). */\n captcha?: 'off' | 'detect' | 'solve';\n /** Enable smart retry with browser switching (default: true). */\n smartRetry?: boolean;\n /** Max retry attempts across all browsers (default: 3). */\n maxRetries?: number;\n /** Stealth level (1-3). Controls proxy quality tier. 0 or undefined = auto-escalate on failure. */\n stealth?: number;\n /** Maximum stealth level to auto-escalate to (1-3, default: 3). */\n maxStealthLevels?: number;\n /** LLM configuration for AI methods (optional). */\n llm?: LLMConfig;\n /** Log level (default: info). */\n logLevel?: LogLevel;\n /** WebSocket connect timeout in ms (default: 30000). */\n connectTimeoutMs?: number;\n /** CDP/BiDi command timeout in ms (default: 30000). */\n commandTimeoutMs?: number;\n /** Timeout for retry attempts — shorter than first try (default: 15000). */\n retryTimeoutMs?: number;\n}\n\n/**\n * SpiderBrowser — main entry point for spider-browser.\n *\n * Connects to Spider's pre-warmed browser fleet via WebSocket.\n * Provides deterministic page control (via SpiderPage) and\n * AI-powered automation (act, observe, extract, agent).\n *\n * Key features:\n * - Pre-warmed browsers (no cold start)\n * - Full stealth Chrome & Firefox\n * - Smart retry with automatic browser switching\n * - CDP (Chrome/Servo/LightPanda) + BiDi (Firefox) protocol support\n */\nexport class SpiderBrowser {\n private opts: Required<\n Pick<SpiderBrowserOptions, 'apiKey' | 'serverUrl' | 'browser' | 'captcha' | 'smartRetry' | 'maxRetries' | 'stealth' | 'maxStealthLevels' | 'connectTimeoutMs' | 'commandTimeoutMs' | 'retryTimeoutMs'>\n > & Pick<SpiderBrowserOptions, 'url' | 'llm'>;\n private transport: Transport | null = null;\n private adapter: ProtocolAdapter | null = null;\n private retryEngine: RetryEngine | null = null;\n private emitter = new SpiderEventEmitter();\n private _page: SpiderPage | null = null;\n private llmProvider: LLMProvider | null = null;\n private currentUrl: string | undefined;\n\n constructor(options: SpiderBrowserOptions) {\n this.opts = {\n apiKey: options.apiKey,\n serverUrl: options.serverUrl ?? 'wss://browser.spider.cloud',\n browser: options.browser ?? 'auto',\n captcha: options.captcha ?? 'solve',\n smartRetry: options.smartRetry ?? true,\n maxRetries: options.maxRetries ?? 12,\n stealth: options.stealth ?? 0,\n maxStealthLevels: options.maxStealthLevels ?? 3,\n connectTimeoutMs: options.connectTimeoutMs ?? 30_000,\n commandTimeoutMs: options.commandTimeoutMs ?? 30_000,\n retryTimeoutMs: options.retryTimeoutMs ?? 15_000,\n url: options.url,\n llm: options.llm,\n };\n\n if (options.logLevel) {\n logger.setLevel(options.logLevel);\n }\n\n if (this.opts.llm) {\n this.llmProvider = createProvider(this.opts.llm);\n }\n }\n\n /** The active page instance for deterministic browser control. */\n get page(): SpiderPage {\n if (!this._page) {\n throw new Error('SpiderBrowser not initialized. Call init() first.');\n }\n return this._page;\n }\n\n /** Current browser type. */\n get browser(): BrowserType {\n return this.transport?.browser ?? this.opts.browser;\n }\n\n /** Whether the WebSocket is connected. */\n get connected(): boolean {\n return this.transport?.connected ?? false;\n }\n\n /** Active stealth level (0=auto, 1-3=explicit tiers). */\n get stealthLevel(): number {\n return this.retryEngine?.stealthLevel ?? this.transport?.stealthLevel ?? this.opts.stealth;\n }\n\n /** Credits remaining from last upgrade response. */\n get credits(): number | undefined {\n return this.transport?.upgradeCredits;\n }\n\n /** Credits consumed during this session (from server Spider.metering event). */\n get sessionCreditsUsed(): number | undefined {\n return this.transport?.sessionCreditsUsed;\n }\n\n /**\n * Request the exact session cost from the server.\n * Unlike `sessionCreditsUsed` (which relies on async event delivery),\n * this sends a Spider.getMetering command and waits for the response.\n * Call this before close() for accurate per-session metering.\n */\n async getSessionCredits(): Promise<number> {\n if (!this.transport) return 0;\n return this.transport.requestMetering();\n }\n\n /** Subscribe to events. */\n on<K extends SpiderEventName>(event: K, handler: (data: SpiderEvents[K]) => void): this {\n this.emitter.on(event, handler);\n return this;\n }\n\n /** Unsubscribe from events. */\n off<K extends SpiderEventName>(event: K, handler: (data: SpiderEvents[K]) => void): this {\n this.emitter.off(event, handler);\n return this;\n }\n\n /** Subscribe to an event once. */\n once<K extends SpiderEventName>(event: K, handler: (data: SpiderEvents[K]) => void): this {\n this.emitter.once(event, handler);\n return this;\n }\n\n /**\n * Connect to the browser server WebSocket and initialize the protocol.\n */\n async init(): Promise<void> {\n const transportOpts: TransportOptions = {\n apiKey: this.opts.apiKey,\n serverUrl: this.opts.serverUrl,\n browser: this.opts.browser,\n url: this.opts.url,\n captcha: this.opts.captcha,\n stealthLevel: this.opts.stealth,\n connectTimeoutMs: this.opts.connectTimeoutMs,\n commandTimeoutMs: this.opts.commandTimeoutMs,\n };\n\n this.transport = new Transport(transportOpts, this.emitter);\n await this.transport.connect();\n\n const activeBrowser = this.transport.browser;\n this.adapter = new ProtocolAdapter(this.transport, this.emitter, activeBrowser, {\n commandTimeoutMs: this.opts.commandTimeoutMs,\n });\n await this.adapter.init();\n\n this._page = new SpiderPage(this.adapter);\n\n if (this.opts.smartRetry) {\n const retryOpts: RetryOptions = {\n maxRetries: this.opts.maxRetries,\n transportOpts,\n emitter: this.emitter,\n maxStealthLevel: this.opts.maxStealthLevels,\n retryTimeoutMs: this.opts.retryTimeoutMs,\n commandTimeoutMs: this.opts.commandTimeoutMs,\n };\n this.retryEngine = new RetryEngine(retryOpts);\n }\n\n this.currentUrl = this.opts.url;\n logger.info('SpiderBrowser initialized', { browser: activeBrowser });\n }\n\n /**\n * Execute an action with smart retry. On failure, classifies the error and\n * may switch browsers, reconnect, re-navigate, and retry.\n */\n async withRetry<T>(fn: () => Promise<T>): Promise<T> {\n if (!this.retryEngine || !this.transport || !this.adapter) {\n return fn();\n }\n\n return this.retryEngine.execute(fn, {\n transport: this.transport,\n adapter: this.adapter,\n page: this._page!,\n currentUrl: this.currentUrl,\n onAdapterChanged: (newAdapter) => {\n this.adapter = newAdapter;\n this._page!._setAdapter(newAdapter);\n },\n });\n }\n\n // -------------------------------------------------------------------\n // Navigation (with retry)\n // -------------------------------------------------------------------\n\n /**\n * Navigate to a URL with smart retry.\n *\n * On ERR_ABORTED: closes the WebSocket, reconnects, and retries.\n * On bot detection: switches to a different browser and retries.\n *\n * Also updates `currentUrl` for subsequent retries on other operations.\n */\n async goto(url: string): Promise<void> {\n this.currentUrl = url;\n await this.withRetry(async () => {\n await this._page!.goto(url);\n });\n }\n\n // -------------------------------------------------------------------\n // AI Methods (require LLM config)\n // -------------------------------------------------------------------\n\n /**\n * Execute a single action from natural language.\n *\n * Example: `await browser.act('Click the login button')`\n */\n async act(instruction: string): Promise<void> {\n this.requireLLM();\n await this.withRetry(() => act(this.adapter!, this.llmProvider!, instruction));\n }\n\n /**\n * Discover interactive elements on the page.\n *\n * Works WITHOUT an LLM — injects DOM traversal to collect elements.\n * When instruction is provided + LLM is configured, adds ranking/filtering.\n */\n async observe(instruction?: string): Promise<ObserveResult[]> {\n return this.withRetry(() =>\n observe(this.adapter!, instruction, this.llmProvider ?? undefined),\n );\n }\n\n /**\n * Extract structured data from the page.\n *\n * Example: `await browser.extract('Product name and price', { schema: z.object({...}) })`\n */\n async extract<T>(\n instruction: string,\n options?: { schema?: z.ZodType<T> },\n ): Promise<T> {\n this.requireLLM();\n return this.withRetry(() =>\n extract(this.adapter!, this.llmProvider!, instruction, options?.schema),\n );\n }\n\n /**\n * Create an autonomous agent that executes multi-step tasks.\n *\n * Uses the same action vocabulary and system prompt as Spider's\n * server-side captcha solver for consistent behavior.\n */\n agent(options?: Partial<AgentOptions>): Agent {\n this.requireLLM();\n return new Agent(this.adapter!, this.llmProvider!, this.emitter, options);\n }\n\n /**\n * Close the connection and clean up resources.\n */\n async close(): Promise<void> {\n this.adapter?.destroy();\n this.transport?.close();\n this.emitter.removeAllListeners();\n this._page = null;\n this.adapter = null;\n this.transport = null;\n logger.info('SpiderBrowser closed');\n }\n\n private requireLLM(): void {\n if (!this.llmProvider) {\n throw new Error(\n 'LLM not configured. Pass `llm` option to SpiderBrowser constructor for AI methods.',\n );\n }\n }\n}\n","// spider-browser — OSS Browser Automation Client for Spider\n// https://spider.cloud\n\nexport { SpiderBrowser, type SpiderBrowserOptions } from './spider-browser.js';\nexport { SpiderPage } from './page.js';\n\n// Events\nexport { SpiderEventEmitter } from './events/emitter.js';\nexport type { SpiderEvents, SpiderEventName, BrowserType } from './events/types.js';\n\n// Protocol (advanced usage)\nexport { Transport, type TransportOptions } from './protocol/transport.js';\nexport { ProtocolAdapter } from './protocol/protocol-adapter.js';\nexport { CDPSession } from './protocol/cdp-session.js';\nexport { BiDiSession } from './protocol/bidi-session.js';\n\n// Retry\nexport { RetryEngine, type RetryOptions } from './retry/retry-engine.js';\nexport { FailureTracker } from './retry/failure-tracker.js';\nexport { BrowserSelector, BROWSER_ROTATION } from './retry/browser-selector.js';\n\n// AI\nexport { createProvider, type LLMConfig, type LLMProvider, type LLMMessage } from './ai/llm-provider.js';\nexport { act } from './ai/act.js';\nexport { observe, type ObserveResult } from './ai/observe.js';\nexport { extract } from './ai/extract.js';\nexport { Agent, type AgentOptions, type AgentResult, type AgentAction, type AgentPlan } from './ai/agent.js';\nexport { SYSTEM_PROMPT } from './ai/prompts.js';\n\n// Utils\nexport { truncateHtml } from './utils/html.js';\nexport * from './utils/errors.js';\nexport { Logger, logger } from './utils/logger.js';\n"],"mappings":"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","names":["sleep","sleep","domain","cls","OpenAICompatibleProvider","AnthropicProvider","sleep","sleep","truncateHtml","truncateHtml"]}
|