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
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,1223 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
/** Browser types supported by spider's backend. */
|
|
4
|
+
type BrowserType = 'chrome' | 'chrome-new' | 'chrome-h' | 'firefox' | 'servo' | 'lightpanda' | 'auto';
|
|
5
|
+
/** All events emitted by SpiderBrowser. */
|
|
6
|
+
interface SpiderEvents {
|
|
7
|
+
/** WebSocket connection opened. */
|
|
8
|
+
'ws.open': {};
|
|
9
|
+
/** WebSocket connection closed. */
|
|
10
|
+
'ws.close': {
|
|
11
|
+
code: number;
|
|
12
|
+
reason: string;
|
|
13
|
+
};
|
|
14
|
+
/** WebSocket error. */
|
|
15
|
+
'ws.error': {
|
|
16
|
+
error: Error;
|
|
17
|
+
};
|
|
18
|
+
/** Captcha was detected on the page. */
|
|
19
|
+
'captcha.detected': {
|
|
20
|
+
types: string[];
|
|
21
|
+
url: string;
|
|
22
|
+
};
|
|
23
|
+
/** Captcha solver is running. */
|
|
24
|
+
'captcha.solving': {
|
|
25
|
+
types: string[];
|
|
26
|
+
url: string;
|
|
27
|
+
round: number;
|
|
28
|
+
};
|
|
29
|
+
/** Captcha was solved. */
|
|
30
|
+
'captcha.solved': {
|
|
31
|
+
url: string;
|
|
32
|
+
};
|
|
33
|
+
/** Captcha solving failed. */
|
|
34
|
+
'captcha.failed': {
|
|
35
|
+
url: string;
|
|
36
|
+
reason: string;
|
|
37
|
+
};
|
|
38
|
+
/** Smart retry is switching browsers. */
|
|
39
|
+
'browser.switching': {
|
|
40
|
+
from: BrowserType;
|
|
41
|
+
to: BrowserType;
|
|
42
|
+
reason: string;
|
|
43
|
+
};
|
|
44
|
+
/** Browser switched successfully. */
|
|
45
|
+
'browser.switched': {
|
|
46
|
+
browser: BrowserType;
|
|
47
|
+
};
|
|
48
|
+
/** Retry attempt. */
|
|
49
|
+
'retry.attempt': {
|
|
50
|
+
attempt: number;
|
|
51
|
+
maxRetries: number;
|
|
52
|
+
error: string;
|
|
53
|
+
};
|
|
54
|
+
/** Stealth level escalated (proxy tier upgraded). */
|
|
55
|
+
'stealth.escalated': {
|
|
56
|
+
from: number;
|
|
57
|
+
to: number;
|
|
58
|
+
reason: string;
|
|
59
|
+
};
|
|
60
|
+
/** Metering data from server (credits remaining, cost rate, session cost). */
|
|
61
|
+
'metering': {
|
|
62
|
+
credits: number;
|
|
63
|
+
rate: number;
|
|
64
|
+
session_credits_used?: number;
|
|
65
|
+
};
|
|
66
|
+
/** Page navigation completed. */
|
|
67
|
+
'page.navigated': {
|
|
68
|
+
url: string;
|
|
69
|
+
};
|
|
70
|
+
/** Page loaded (DOMContentLoaded or load). */
|
|
71
|
+
'page.loaded': {
|
|
72
|
+
url: string;
|
|
73
|
+
};
|
|
74
|
+
/** Agent step executed. */
|
|
75
|
+
'agent.step': {
|
|
76
|
+
round: number;
|
|
77
|
+
label: string;
|
|
78
|
+
stepsCount: number;
|
|
79
|
+
};
|
|
80
|
+
/** Agent completed. */
|
|
81
|
+
'agent.done': {
|
|
82
|
+
rounds: number;
|
|
83
|
+
result?: unknown;
|
|
84
|
+
};
|
|
85
|
+
/** Agent failed. */
|
|
86
|
+
'agent.error': {
|
|
87
|
+
error: string;
|
|
88
|
+
round: number;
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
type SpiderEventName = keyof SpiderEvents;
|
|
92
|
+
|
|
93
|
+
type Handler<T> = (data: T) => void;
|
|
94
|
+
/** Type-safe event emitter for SpiderBrowser events. */
|
|
95
|
+
declare class SpiderEventEmitter {
|
|
96
|
+
private handlers;
|
|
97
|
+
on<K extends SpiderEventName>(event: K, handler: Handler<SpiderEvents[K]>): this;
|
|
98
|
+
off<K extends SpiderEventName>(event: K, handler: Handler<SpiderEvents[K]>): this;
|
|
99
|
+
once<K extends SpiderEventName>(event: K, handler: Handler<SpiderEvents[K]>): this;
|
|
100
|
+
emit<K extends SpiderEventName>(event: K, data: SpiderEvents[K]): void;
|
|
101
|
+
removeAllListeners(event?: SpiderEventName): void;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
interface TransportOptions {
|
|
105
|
+
apiKey: string;
|
|
106
|
+
serverUrl: string;
|
|
107
|
+
browser: BrowserType;
|
|
108
|
+
url?: string;
|
|
109
|
+
captcha?: 'off' | 'detect' | 'solve';
|
|
110
|
+
/** Stealth level (1-3). 0 or undefined = auto. Controls proxy quality tier on server. */
|
|
111
|
+
stealthLevel?: number;
|
|
112
|
+
/** WebSocket connect timeout in ms (default: 30000). */
|
|
113
|
+
connectTimeoutMs?: number;
|
|
114
|
+
/** CDP/BiDi command timeout in ms (default: 30000). Passed through to sessions. */
|
|
115
|
+
commandTimeoutMs?: number;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* WebSocket transport to Spider's browser_server.
|
|
119
|
+
*
|
|
120
|
+
* Connects to `wss://browser.spider.cloud/v1/browser?token=TOKEN&browser=TYPE`,
|
|
121
|
+
* handles reconnection on browser switch, and dispatches raw messages.
|
|
122
|
+
*/
|
|
123
|
+
declare class Transport {
|
|
124
|
+
private ws;
|
|
125
|
+
private messageHandler;
|
|
126
|
+
private currentBrowser;
|
|
127
|
+
private opts;
|
|
128
|
+
private emitter;
|
|
129
|
+
private _stealthLevel;
|
|
130
|
+
/** Generation counter — incremented on each connect. Prevents stale WS messages from being processed. */
|
|
131
|
+
private generation;
|
|
132
|
+
/** Credits remaining from last upgrade response (x-sc header). */
|
|
133
|
+
private _upgradeCredits;
|
|
134
|
+
/** Stealth tier from last upgrade response (x-sr header). */
|
|
135
|
+
private _upgradeStealthTier;
|
|
136
|
+
/** Credits consumed during this session (from Spider.metering event). */
|
|
137
|
+
private _sessionCreditsUsed;
|
|
138
|
+
constructor(opts: TransportOptions, emitter: SpiderEventEmitter);
|
|
139
|
+
get browser(): BrowserType;
|
|
140
|
+
get connected(): boolean;
|
|
141
|
+
get stealthLevel(): number;
|
|
142
|
+
set stealthLevel(level: number);
|
|
143
|
+
/** Credits remaining from the WebSocket upgrade response. */
|
|
144
|
+
get upgradeCredits(): number | undefined;
|
|
145
|
+
/** Active stealth tier from the WebSocket upgrade response. */
|
|
146
|
+
get upgradeStealthTier(): number | undefined;
|
|
147
|
+
/** Credits consumed during this session (from server Spider.metering event). */
|
|
148
|
+
get sessionCreditsUsed(): number | undefined;
|
|
149
|
+
/**
|
|
150
|
+
* Request the current session cost from the server via Spider.getMetering.
|
|
151
|
+
* This is a synchronous CDP-style request/response — no event-loop timing issues.
|
|
152
|
+
* Returns the credits used so far, or the last known value if the request fails.
|
|
153
|
+
*/
|
|
154
|
+
requestMetering(timeoutMs?: number): Promise<number>;
|
|
155
|
+
/** Set the handler that receives raw JSON messages from the WebSocket. */
|
|
156
|
+
onMessage(handler: (data: string) => void): void;
|
|
157
|
+
/** Connect to the browser_server WebSocket with retry. */
|
|
158
|
+
connect(maxAttempts?: number): Promise<void>;
|
|
159
|
+
/** Reconnect with a different browser type (used by retry engine). */
|
|
160
|
+
reconnect(browser: BrowserType): Promise<void>;
|
|
161
|
+
/** Send a raw JSON string through the WebSocket. */
|
|
162
|
+
send(data: string): void;
|
|
163
|
+
/** Close the WebSocket connection, removing event listeners to prevent data mixing. */
|
|
164
|
+
close(): void;
|
|
165
|
+
private buildUrl;
|
|
166
|
+
private connectInternal;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Unified protocol interface that wraps either CDPSession or BiDiSession
|
|
171
|
+
* based on the browser type.
|
|
172
|
+
*
|
|
173
|
+
* - chrome, chrome-new, chrome-h, servo, lightpanda → CDP
|
|
174
|
+
* - firefox → BiDi
|
|
175
|
+
*/
|
|
176
|
+
interface ProtocolAdapterOptions {
|
|
177
|
+
commandTimeoutMs?: number;
|
|
178
|
+
}
|
|
179
|
+
declare class ProtocolAdapter {
|
|
180
|
+
private cdp;
|
|
181
|
+
private bidi;
|
|
182
|
+
private transport;
|
|
183
|
+
private emitter;
|
|
184
|
+
private protocol;
|
|
185
|
+
private adapterOpts;
|
|
186
|
+
constructor(transport: Transport, emitter: SpiderEventEmitter, browser: BrowserType, opts?: ProtocolAdapterOptions);
|
|
187
|
+
/** Whether this adapter uses CDP or BiDi (or 'auto' before init). */
|
|
188
|
+
get protocolType(): 'cdp' | 'bidi' | 'auto';
|
|
189
|
+
/** Route incoming WebSocket messages to the right session + spider events. */
|
|
190
|
+
private routeMessage;
|
|
191
|
+
/** Handle Spider.* custom events from the browser_server. */
|
|
192
|
+
private handleSpiderEvent;
|
|
193
|
+
/**
|
|
194
|
+
* Initialize the protocol session.
|
|
195
|
+
*
|
|
196
|
+
* For CDP (Chrome/Servo/LightPanda): discovers page targets, attaches to one
|
|
197
|
+
* with flatten:true to get a sessionId, then enables Page + Runtime domains
|
|
198
|
+
* on that target. This is required because browser_server proxies to Chrome's
|
|
199
|
+
* browser-level CDP endpoint.
|
|
200
|
+
*
|
|
201
|
+
* For BiDi (Firefox): gets or creates a browsing context.
|
|
202
|
+
*
|
|
203
|
+
* For "auto" mode: tries CDP first (Target.setDiscoverTargets). If it fails
|
|
204
|
+
* (e.g. we actually got a BiDi session), falls back to BiDi.
|
|
205
|
+
*/
|
|
206
|
+
init(): Promise<void>;
|
|
207
|
+
/**
|
|
208
|
+
* Auto-detect protocol by trying CDP first, falling back to BiDi.
|
|
209
|
+
* Used when browser type is "auto" and we don't know what the server gave us.
|
|
210
|
+
*/
|
|
211
|
+
private autoDetectAndInit;
|
|
212
|
+
/** Navigate to URL. */
|
|
213
|
+
navigate(url: string): Promise<void>;
|
|
214
|
+
/** Get page HTML. */
|
|
215
|
+
getHTML(): Promise<string>;
|
|
216
|
+
/** Evaluate JavaScript expression. */
|
|
217
|
+
evaluate(expression: string): Promise<unknown>;
|
|
218
|
+
/** Capture screenshot as base64 PNG. */
|
|
219
|
+
captureScreenshot(): Promise<string>;
|
|
220
|
+
/** Click at viewport coordinates. */
|
|
221
|
+
clickPoint(x: number, y: number): Promise<void>;
|
|
222
|
+
/** Right-click at coordinates. */
|
|
223
|
+
rightClickPoint(x: number, y: number): Promise<void>;
|
|
224
|
+
/** Double-click at coordinates. */
|
|
225
|
+
doubleClickPoint(x: number, y: number): Promise<void>;
|
|
226
|
+
/** Click and hold at coordinates. */
|
|
227
|
+
clickHoldPoint(x: number, y: number, holdMs: number): Promise<void>;
|
|
228
|
+
/** Hover at coordinates. */
|
|
229
|
+
hoverPoint(x: number, y: number): Promise<void>;
|
|
230
|
+
/** Smooth drag from point to point. */
|
|
231
|
+
dragPoint(fromX: number, fromY: number, toX: number, toY: number): Promise<void>;
|
|
232
|
+
/** Insert text. */
|
|
233
|
+
insertText(text: string): Promise<void>;
|
|
234
|
+
/** Press a named key (e.g. "Enter", "Tab"). */
|
|
235
|
+
pressKey(keyName: string): Promise<void>;
|
|
236
|
+
/** Send keyDown. */
|
|
237
|
+
keyDown(keyName: string): Promise<void>;
|
|
238
|
+
/** Send keyUp. */
|
|
239
|
+
keyUp(keyName: string): Promise<void>;
|
|
240
|
+
/** Set viewport dimensions. */
|
|
241
|
+
setViewport(width: number, height: number, deviceScaleFactor?: number, mobile?: boolean): Promise<void>;
|
|
242
|
+
/** Subscribe to a CDP domain event (only relevant for CDP). */
|
|
243
|
+
onProtocolEvent(method: string, handler: (params: Record<string, unknown>) => void): void;
|
|
244
|
+
/** Clean up resources. Nulls references first to prevent stale message routing. */
|
|
245
|
+
destroy(): void;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* SpiderPage — deterministic browser tab abstraction.
|
|
250
|
+
*
|
|
251
|
+
* All standard browser automation methods (no LLM required).
|
|
252
|
+
* Works over both CDP (Chrome/Servo/LightPanda) and BiDi (Firefox)
|
|
253
|
+
* through the ProtocolAdapter.
|
|
254
|
+
*/
|
|
255
|
+
declare class SpiderPage {
|
|
256
|
+
private adapter;
|
|
257
|
+
/** @internal */
|
|
258
|
+
constructor(adapter: ProtocolAdapter);
|
|
259
|
+
/** Navigate to a URL and wait for load. */
|
|
260
|
+
goto(url: string): Promise<void>;
|
|
261
|
+
/** Go back in browser history. */
|
|
262
|
+
goBack(): Promise<void>;
|
|
263
|
+
/** Go forward in browser history. */
|
|
264
|
+
goForward(): Promise<void>;
|
|
265
|
+
/** Reload the page. */
|
|
266
|
+
reload(): Promise<void>;
|
|
267
|
+
/**
|
|
268
|
+
* Get the full page HTML, ensuring the page is ready first.
|
|
269
|
+
*
|
|
270
|
+
* Waits for network idle + DOM stability, then checks content quality.
|
|
271
|
+
* If the content seems incomplete (too short or looks like a loading state),
|
|
272
|
+
* does incremental waits with exponential backoff before returning.
|
|
273
|
+
*
|
|
274
|
+
* @param waitMs Max time to wait for readiness (default: 8000ms).
|
|
275
|
+
* Pass 0 to skip readiness checks and return immediately.
|
|
276
|
+
* @param minLength Minimum content length to consider "good" (default: 1000).
|
|
277
|
+
*/
|
|
278
|
+
content(waitMs?: number, minLength?: number): Promise<string>;
|
|
279
|
+
/**
|
|
280
|
+
* Get the raw page HTML without any readiness waiting.
|
|
281
|
+
* Use this when you need immediate access or have already waited.
|
|
282
|
+
*/
|
|
283
|
+
rawContent(): Promise<string>;
|
|
284
|
+
/** Get the page title. */
|
|
285
|
+
title(): Promise<string>;
|
|
286
|
+
/** Get the current page URL. */
|
|
287
|
+
url(): Promise<string>;
|
|
288
|
+
/** Capture a screenshot as base64 PNG. */
|
|
289
|
+
screenshot(): Promise<string>;
|
|
290
|
+
/** Evaluate arbitrary JavaScript and return the result. */
|
|
291
|
+
evaluate(expression: string): Promise<unknown>;
|
|
292
|
+
/** Click an element by CSS selector. */
|
|
293
|
+
click(selector: string): Promise<void>;
|
|
294
|
+
/** Click at specific viewport coordinates. */
|
|
295
|
+
clickAt(x: number, y: number): Promise<void>;
|
|
296
|
+
/** Double-click an element by CSS selector. */
|
|
297
|
+
dblclick(selector: string): Promise<void>;
|
|
298
|
+
/** Right-click an element by CSS selector. */
|
|
299
|
+
rightClick(selector: string): Promise<void>;
|
|
300
|
+
/** Click all elements matching a selector. */
|
|
301
|
+
clickAll(selector: string): Promise<void>;
|
|
302
|
+
/** Fill a form field — focus, clear existing value, type new value. */
|
|
303
|
+
fill(selector: string, value: string): Promise<void>;
|
|
304
|
+
/** Type text into the currently focused element. */
|
|
305
|
+
type(value: string): Promise<void>;
|
|
306
|
+
/** Press a named key (e.g. "Enter", "Tab", "Escape"). */
|
|
307
|
+
press(key: string): Promise<void>;
|
|
308
|
+
/** Clear an input field. */
|
|
309
|
+
clear(selector: string): Promise<void>;
|
|
310
|
+
/** Select an option in a <select> element. */
|
|
311
|
+
select(selector: string, value: string): Promise<void>;
|
|
312
|
+
/** Focus an element. */
|
|
313
|
+
focus(selector: string): Promise<void>;
|
|
314
|
+
/** Blur (unfocus) an element. */
|
|
315
|
+
blur(selector: string): Promise<void>;
|
|
316
|
+
/** Hover over an element. */
|
|
317
|
+
hover(selector: string): Promise<void>;
|
|
318
|
+
/** Drag from one element to another. */
|
|
319
|
+
drag(fromSelector: string, toSelector: string): Promise<void>;
|
|
320
|
+
/** Scroll vertically by pixels (positive = down). */
|
|
321
|
+
scrollY(pixels: number): Promise<void>;
|
|
322
|
+
/** Scroll horizontally by pixels (positive = right). */
|
|
323
|
+
scrollX(pixels: number): Promise<void>;
|
|
324
|
+
/** Scroll an element into view. */
|
|
325
|
+
scrollTo(selector: string): Promise<void>;
|
|
326
|
+
/** Scroll to absolute page coordinates. */
|
|
327
|
+
scrollToPoint(x: number, y: number): Promise<void>;
|
|
328
|
+
/** Wait for a CSS selector to appear in the DOM. */
|
|
329
|
+
waitForSelector(selector: string, timeoutMs?: number): Promise<void>;
|
|
330
|
+
/** Wait for navigation/page load (simple delay). */
|
|
331
|
+
waitForNavigation(timeoutMs?: number): Promise<void>;
|
|
332
|
+
/**
|
|
333
|
+
* Wait until the page is fully loaded and DOM is stable.
|
|
334
|
+
*
|
|
335
|
+
* Checks:
|
|
336
|
+
* 1. document.readyState === 'complete'
|
|
337
|
+
* 2. DOM content length stabilizes (no changes for 500ms)
|
|
338
|
+
*
|
|
339
|
+
* Use after goto() for SPAs and dynamic pages to ensure all
|
|
340
|
+
* content is rendered before extracting HTML.
|
|
341
|
+
*/
|
|
342
|
+
waitForReady(timeoutMs?: number): Promise<void>;
|
|
343
|
+
/**
|
|
344
|
+
* Wait until page content exceeds a minimum length.
|
|
345
|
+
* Useful for SPAs where content loads asynchronously.
|
|
346
|
+
*/
|
|
347
|
+
waitForContent(minLength?: number, timeoutMs?: number): Promise<void>;
|
|
348
|
+
/**
|
|
349
|
+
* Wait for network idle + DOM stability (cross-platform).
|
|
350
|
+
*
|
|
351
|
+
* Uses the Performance/Resource Timing API and MutationObserver
|
|
352
|
+
* (works in both Chrome/CDP and Firefox/BiDi) to detect when:
|
|
353
|
+
* 1. document.readyState === 'complete'
|
|
354
|
+
* 2. No new network resources loading (PerformanceObserver)
|
|
355
|
+
* 3. DOM mutations have settled
|
|
356
|
+
*
|
|
357
|
+
* This is more comprehensive than waitForReady() — it also
|
|
358
|
+
* catches lazy-loaded images, XHR/fetch requests, and script-injected content.
|
|
359
|
+
*/
|
|
360
|
+
waitForNetworkIdle(timeoutMs?: number): Promise<void>;
|
|
361
|
+
/** Set the viewport dimensions. */
|
|
362
|
+
setViewport(width: number, height: number, deviceScaleFactor?: number, mobile?: boolean): Promise<void>;
|
|
363
|
+
/** Query a single element and return its outer HTML. */
|
|
364
|
+
querySelector(selector: string): Promise<string | null>;
|
|
365
|
+
/** Query all matching elements and return their outer HTML. */
|
|
366
|
+
querySelectorAll(selector: string): Promise<string[]>;
|
|
367
|
+
/** Get text content of an element. */
|
|
368
|
+
textContent(selector: string): Promise<string | null>;
|
|
369
|
+
/** Get the center coordinates of a DOM element (scrolls into view first). */
|
|
370
|
+
private getElementCenter;
|
|
371
|
+
/** @internal Replace the adapter (used during browser switching). */
|
|
372
|
+
_setAdapter(adapter: ProtocolAdapter): void;
|
|
373
|
+
/**
|
|
374
|
+
* Detect challenge interstitials that may auto-resolve (e.g. Cloudflare "Just a moment...").
|
|
375
|
+
* These pages show briefly before redirecting to the real content.
|
|
376
|
+
*/
|
|
377
|
+
private isInterstitialContent;
|
|
378
|
+
/**
|
|
379
|
+
* Detect site-level rate limiting in page content.
|
|
380
|
+
* Browser rotation gives a new profile which bypasses per-session rate limits.
|
|
381
|
+
*/
|
|
382
|
+
private isRateLimitContent;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
/** LLM configuration for AI methods. */
|
|
386
|
+
interface LLMConfig {
|
|
387
|
+
/** Provider: 'openai', 'anthropic', or 'openrouter'. */
|
|
388
|
+
provider: 'openai' | 'anthropic' | 'openrouter';
|
|
389
|
+
/** Model name (e.g. 'gpt-4o', 'claude-sonnet-4-5-20250929'). */
|
|
390
|
+
model: string;
|
|
391
|
+
/** API key for the provider. */
|
|
392
|
+
apiKey: string;
|
|
393
|
+
/** Base URL override (e.g. for OpenRouter or local vLLM). */
|
|
394
|
+
baseUrl?: string;
|
|
395
|
+
/** Max tokens (default: 4096). */
|
|
396
|
+
maxTokens?: number;
|
|
397
|
+
/** Temperature (default: 0.1). */
|
|
398
|
+
temperature?: number;
|
|
399
|
+
}
|
|
400
|
+
/** Message format for LLM calls. */
|
|
401
|
+
interface LLMMessage {
|
|
402
|
+
role: 'system' | 'user' | 'assistant';
|
|
403
|
+
content: string | LLMContentPart[];
|
|
404
|
+
}
|
|
405
|
+
type LLMContentPart = {
|
|
406
|
+
type: 'text';
|
|
407
|
+
text: string;
|
|
408
|
+
} | {
|
|
409
|
+
type: 'image_url';
|
|
410
|
+
image_url: {
|
|
411
|
+
url: string;
|
|
412
|
+
};
|
|
413
|
+
};
|
|
414
|
+
/** Pluggable LLM provider interface. */
|
|
415
|
+
interface LLMProvider {
|
|
416
|
+
/** Call the LLM with messages and get a text response. */
|
|
417
|
+
chat(messages: LLMMessage[], options?: {
|
|
418
|
+
jsonMode?: boolean;
|
|
419
|
+
}): Promise<string>;
|
|
420
|
+
/** Call the LLM with messages and get a parsed JSON response. */
|
|
421
|
+
chatJSON<T = unknown>(messages: LLMMessage[]): Promise<T>;
|
|
422
|
+
}
|
|
423
|
+
/** Create an LLM provider from config. */
|
|
424
|
+
declare function createProvider(config: LLMConfig): LLMProvider;
|
|
425
|
+
|
|
426
|
+
/** An observed interactive element on the page. */
|
|
427
|
+
interface ObserveResult {
|
|
428
|
+
/** CSS selector that can target this element. */
|
|
429
|
+
selector: string;
|
|
430
|
+
/** HTML tag name. */
|
|
431
|
+
tag: string;
|
|
432
|
+
/** Input type (for input elements). */
|
|
433
|
+
type: string;
|
|
434
|
+
/** Visible text content (truncated). */
|
|
435
|
+
text: string;
|
|
436
|
+
/** aria-label attribute. */
|
|
437
|
+
ariaLabel: string;
|
|
438
|
+
/** Placeholder text. */
|
|
439
|
+
placeholder: string;
|
|
440
|
+
/** href attribute (for links). */
|
|
441
|
+
href: string;
|
|
442
|
+
/** Current input value (for inputs/textareas). */
|
|
443
|
+
value: string;
|
|
444
|
+
/** Bounding rectangle in viewport coordinates. */
|
|
445
|
+
rect: {
|
|
446
|
+
x: number;
|
|
447
|
+
y: number;
|
|
448
|
+
width: number;
|
|
449
|
+
height: number;
|
|
450
|
+
};
|
|
451
|
+
/** Relevance score (0-1) when LLM ranking is used. */
|
|
452
|
+
score?: number;
|
|
453
|
+
}
|
|
454
|
+
/**
|
|
455
|
+
* Discover interactive elements on the page.
|
|
456
|
+
*
|
|
457
|
+
* Works WITHOUT an LLM — injects a DOM traversal script to collect
|
|
458
|
+
* interactive elements (buttons, links, inputs) with selectors, text,
|
|
459
|
+
* and bounding rects.
|
|
460
|
+
*
|
|
461
|
+
* When instruction is provided + LLM is available, adds ranking/filtering.
|
|
462
|
+
*/
|
|
463
|
+
declare function observe(adapter: ProtocolAdapter, instruction?: string, llm?: LLMProvider): Promise<ObserveResult[]>;
|
|
464
|
+
|
|
465
|
+
/** All possible agent actions — mirrors browser_server/src/ai/actions.rs. */
|
|
466
|
+
type AgentAction = {
|
|
467
|
+
Click: string;
|
|
468
|
+
} | {
|
|
469
|
+
ClickAll: string;
|
|
470
|
+
} | {
|
|
471
|
+
ClickPoint: {
|
|
472
|
+
x: number;
|
|
473
|
+
y: number;
|
|
474
|
+
};
|
|
475
|
+
} | {
|
|
476
|
+
ClickHold: {
|
|
477
|
+
selector: string;
|
|
478
|
+
hold_ms: number;
|
|
479
|
+
};
|
|
480
|
+
} | {
|
|
481
|
+
ClickHoldPoint: {
|
|
482
|
+
x: number;
|
|
483
|
+
y: number;
|
|
484
|
+
hold_ms: number;
|
|
485
|
+
};
|
|
486
|
+
} | {
|
|
487
|
+
DoubleClick: string;
|
|
488
|
+
} | {
|
|
489
|
+
DoubleClickPoint: {
|
|
490
|
+
x: number;
|
|
491
|
+
y: number;
|
|
492
|
+
};
|
|
493
|
+
} | {
|
|
494
|
+
RightClick: string;
|
|
495
|
+
} | {
|
|
496
|
+
RightClickPoint: {
|
|
497
|
+
x: number;
|
|
498
|
+
y: number;
|
|
499
|
+
};
|
|
500
|
+
} | {
|
|
501
|
+
WaitForAndClick: string;
|
|
502
|
+
} | {
|
|
503
|
+
ClickDrag: {
|
|
504
|
+
from: string;
|
|
505
|
+
to: string;
|
|
506
|
+
modifier?: number;
|
|
507
|
+
};
|
|
508
|
+
} | {
|
|
509
|
+
ClickDragPoint: {
|
|
510
|
+
from_x: number;
|
|
511
|
+
from_y: number;
|
|
512
|
+
to_x: number;
|
|
513
|
+
to_y: number;
|
|
514
|
+
modifier?: number;
|
|
515
|
+
};
|
|
516
|
+
} | {
|
|
517
|
+
Type: {
|
|
518
|
+
value: string;
|
|
519
|
+
};
|
|
520
|
+
} | {
|
|
521
|
+
Fill: {
|
|
522
|
+
selector: string;
|
|
523
|
+
value: string;
|
|
524
|
+
};
|
|
525
|
+
} | {
|
|
526
|
+
Clear: string;
|
|
527
|
+
} | {
|
|
528
|
+
Press: string;
|
|
529
|
+
} | {
|
|
530
|
+
KeyDown: string;
|
|
531
|
+
} | {
|
|
532
|
+
KeyUp: string;
|
|
533
|
+
} | {
|
|
534
|
+
Select: {
|
|
535
|
+
selector: string;
|
|
536
|
+
value: string;
|
|
537
|
+
};
|
|
538
|
+
} | {
|
|
539
|
+
Focus: string;
|
|
540
|
+
} | {
|
|
541
|
+
Blur: string;
|
|
542
|
+
} | {
|
|
543
|
+
Hover: string;
|
|
544
|
+
} | {
|
|
545
|
+
HoverPoint: {
|
|
546
|
+
x: number;
|
|
547
|
+
y: number;
|
|
548
|
+
};
|
|
549
|
+
} | {
|
|
550
|
+
ScrollY: number;
|
|
551
|
+
} | {
|
|
552
|
+
ScrollX: number;
|
|
553
|
+
} | {
|
|
554
|
+
ScrollTo: {
|
|
555
|
+
selector: string;
|
|
556
|
+
};
|
|
557
|
+
} | {
|
|
558
|
+
ScrollToPoint: {
|
|
559
|
+
x: number;
|
|
560
|
+
y: number;
|
|
561
|
+
};
|
|
562
|
+
} | {
|
|
563
|
+
InfiniteScroll: number;
|
|
564
|
+
} | {
|
|
565
|
+
Wait: number;
|
|
566
|
+
} | {
|
|
567
|
+
WaitFor: string;
|
|
568
|
+
} | {
|
|
569
|
+
WaitForWithTimeout: {
|
|
570
|
+
selector: string;
|
|
571
|
+
timeout: number;
|
|
572
|
+
};
|
|
573
|
+
} | {
|
|
574
|
+
WaitForNavigation: null;
|
|
575
|
+
} | {
|
|
576
|
+
WaitForDom: {
|
|
577
|
+
selector?: string;
|
|
578
|
+
timeout: number;
|
|
579
|
+
};
|
|
580
|
+
} | {
|
|
581
|
+
Navigate: string;
|
|
582
|
+
} | {
|
|
583
|
+
GoBack: null;
|
|
584
|
+
} | {
|
|
585
|
+
GoForward: null;
|
|
586
|
+
} | {
|
|
587
|
+
Reload: null;
|
|
588
|
+
} | {
|
|
589
|
+
SetViewport: {
|
|
590
|
+
width: number;
|
|
591
|
+
height: number;
|
|
592
|
+
device_scale_factor?: number;
|
|
593
|
+
mobile?: boolean;
|
|
594
|
+
};
|
|
595
|
+
} | {
|
|
596
|
+
Evaluate: string;
|
|
597
|
+
} | {
|
|
598
|
+
Screenshot: null;
|
|
599
|
+
};
|
|
600
|
+
/** Parsed LLM response — mirrors actions.rs AgentPlan. */
|
|
601
|
+
interface AgentPlan {
|
|
602
|
+
label: string;
|
|
603
|
+
done: boolean;
|
|
604
|
+
steps: AgentAction[];
|
|
605
|
+
extracted?: unknown;
|
|
606
|
+
memory_ops?: unknown[];
|
|
607
|
+
}
|
|
608
|
+
interface AgentOptions {
|
|
609
|
+
/** Max automation rounds (default: 30). */
|
|
610
|
+
maxRounds: number;
|
|
611
|
+
/** Delay in ms after actions for page settle (default: 1500). */
|
|
612
|
+
stepDelayMs: number;
|
|
613
|
+
/** Extra context/instruction for each round. */
|
|
614
|
+
instruction?: string;
|
|
615
|
+
}
|
|
616
|
+
interface AgentResult {
|
|
617
|
+
/** Whether the agent completed the task. */
|
|
618
|
+
done: boolean;
|
|
619
|
+
/** Number of rounds executed. */
|
|
620
|
+
rounds: number;
|
|
621
|
+
/** Extracted data (accumulated across rounds). */
|
|
622
|
+
extracted?: unknown;
|
|
623
|
+
/** Final label from the agent. */
|
|
624
|
+
label: string;
|
|
625
|
+
}
|
|
626
|
+
/**
|
|
627
|
+
* Autonomous multi-step agent.
|
|
628
|
+
*
|
|
629
|
+
* Uses the same action vocabulary and system prompt as Spider's
|
|
630
|
+
* server-side captcha solver (browser_server/src/ai/agent.rs).
|
|
631
|
+
*
|
|
632
|
+
* Loop: screenshot → HTML → LLM → parse plan → execute actions → repeat.
|
|
633
|
+
*/
|
|
634
|
+
declare class Agent {
|
|
635
|
+
private adapter;
|
|
636
|
+
private llm;
|
|
637
|
+
private emitter;
|
|
638
|
+
private opts;
|
|
639
|
+
constructor(adapter: ProtocolAdapter, llm: LLMProvider, emitter: SpiderEventEmitter, options?: Partial<AgentOptions>);
|
|
640
|
+
/**
|
|
641
|
+
* Execute the agent loop until the task is done or max rounds reached.
|
|
642
|
+
*/
|
|
643
|
+
execute(instruction: string): Promise<AgentResult>;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'silent';
|
|
647
|
+
declare class Logger {
|
|
648
|
+
private level;
|
|
649
|
+
constructor(level?: LogLevel);
|
|
650
|
+
setLevel(level: LogLevel): void;
|
|
651
|
+
debug(msg: string, data?: Record<string, unknown>): void;
|
|
652
|
+
info(msg: string, data?: Record<string, unknown>): void;
|
|
653
|
+
warn(msg: string, data?: Record<string, unknown>): void;
|
|
654
|
+
error(msg: string, data?: Record<string, unknown>): void;
|
|
655
|
+
private log;
|
|
656
|
+
}
|
|
657
|
+
/** Shared default logger instance. */
|
|
658
|
+
declare const logger: Logger;
|
|
659
|
+
|
|
660
|
+
interface SpiderBrowserOptions {
|
|
661
|
+
/** Spider API key (required). */
|
|
662
|
+
apiKey: string;
|
|
663
|
+
/** WebSocket server URL (default: wss://browser.spider.cloud). */
|
|
664
|
+
serverUrl?: string;
|
|
665
|
+
/** Browser to use (default: auto). */
|
|
666
|
+
browser?: BrowserType;
|
|
667
|
+
/** Target URL hint for server browser+proxy selection. */
|
|
668
|
+
url?: string;
|
|
669
|
+
/** Captcha handling (default: solve). */
|
|
670
|
+
captcha?: 'off' | 'detect' | 'solve';
|
|
671
|
+
/** Enable smart retry with browser switching (default: true). */
|
|
672
|
+
smartRetry?: boolean;
|
|
673
|
+
/** Max retry attempts across all browsers (default: 3). */
|
|
674
|
+
maxRetries?: number;
|
|
675
|
+
/** Stealth level (1-3). Controls proxy quality tier. 0 or undefined = auto-escalate on failure. */
|
|
676
|
+
stealth?: number;
|
|
677
|
+
/** Maximum stealth level to auto-escalate to (1-3, default: 3). */
|
|
678
|
+
maxStealthLevels?: number;
|
|
679
|
+
/** LLM configuration for AI methods (optional). */
|
|
680
|
+
llm?: LLMConfig;
|
|
681
|
+
/** Log level (default: info). */
|
|
682
|
+
logLevel?: LogLevel;
|
|
683
|
+
/** WebSocket connect timeout in ms (default: 30000). */
|
|
684
|
+
connectTimeoutMs?: number;
|
|
685
|
+
/** CDP/BiDi command timeout in ms (default: 30000). */
|
|
686
|
+
commandTimeoutMs?: number;
|
|
687
|
+
/** Timeout for retry attempts — shorter than first try (default: 15000). */
|
|
688
|
+
retryTimeoutMs?: number;
|
|
689
|
+
}
|
|
690
|
+
/**
|
|
691
|
+
* SpiderBrowser — main entry point for spider-browser.
|
|
692
|
+
*
|
|
693
|
+
* Connects to Spider's pre-warmed browser fleet via WebSocket.
|
|
694
|
+
* Provides deterministic page control (via SpiderPage) and
|
|
695
|
+
* AI-powered automation (act, observe, extract, agent).
|
|
696
|
+
*
|
|
697
|
+
* Key features:
|
|
698
|
+
* - Pre-warmed browsers (no cold start)
|
|
699
|
+
* - Full stealth Chrome & Firefox
|
|
700
|
+
* - Smart retry with automatic browser switching
|
|
701
|
+
* - CDP (Chrome/Servo/LightPanda) + BiDi (Firefox) protocol support
|
|
702
|
+
*/
|
|
703
|
+
declare class SpiderBrowser {
|
|
704
|
+
private opts;
|
|
705
|
+
private transport;
|
|
706
|
+
private adapter;
|
|
707
|
+
private retryEngine;
|
|
708
|
+
private emitter;
|
|
709
|
+
private _page;
|
|
710
|
+
private llmProvider;
|
|
711
|
+
private currentUrl;
|
|
712
|
+
constructor(options: SpiderBrowserOptions);
|
|
713
|
+
/** The active page instance for deterministic browser control. */
|
|
714
|
+
get page(): SpiderPage;
|
|
715
|
+
/** Current browser type. */
|
|
716
|
+
get browser(): BrowserType;
|
|
717
|
+
/** Whether the WebSocket is connected. */
|
|
718
|
+
get connected(): boolean;
|
|
719
|
+
/** Active stealth level (0=auto, 1-3=explicit tiers). */
|
|
720
|
+
get stealthLevel(): number;
|
|
721
|
+
/** Credits remaining from last upgrade response. */
|
|
722
|
+
get credits(): number | undefined;
|
|
723
|
+
/** Credits consumed during this session (from server Spider.metering event). */
|
|
724
|
+
get sessionCreditsUsed(): number | undefined;
|
|
725
|
+
/**
|
|
726
|
+
* Request the exact session cost from the server.
|
|
727
|
+
* Unlike `sessionCreditsUsed` (which relies on async event delivery),
|
|
728
|
+
* this sends a Spider.getMetering command and waits for the response.
|
|
729
|
+
* Call this before close() for accurate per-session metering.
|
|
730
|
+
*/
|
|
731
|
+
getSessionCredits(): Promise<number>;
|
|
732
|
+
/** Subscribe to events. */
|
|
733
|
+
on<K extends SpiderEventName>(event: K, handler: (data: SpiderEvents[K]) => void): this;
|
|
734
|
+
/** Unsubscribe from events. */
|
|
735
|
+
off<K extends SpiderEventName>(event: K, handler: (data: SpiderEvents[K]) => void): this;
|
|
736
|
+
/** Subscribe to an event once. */
|
|
737
|
+
once<K extends SpiderEventName>(event: K, handler: (data: SpiderEvents[K]) => void): this;
|
|
738
|
+
/**
|
|
739
|
+
* Connect to the browser server WebSocket and initialize the protocol.
|
|
740
|
+
*/
|
|
741
|
+
init(): Promise<void>;
|
|
742
|
+
/**
|
|
743
|
+
* Execute an action with smart retry. On failure, classifies the error and
|
|
744
|
+
* may switch browsers, reconnect, re-navigate, and retry.
|
|
745
|
+
*/
|
|
746
|
+
withRetry<T>(fn: () => Promise<T>): Promise<T>;
|
|
747
|
+
/**
|
|
748
|
+
* Navigate to a URL with smart retry.
|
|
749
|
+
*
|
|
750
|
+
* On ERR_ABORTED: closes the WebSocket, reconnects, and retries.
|
|
751
|
+
* On bot detection: switches to a different browser and retries.
|
|
752
|
+
*
|
|
753
|
+
* Also updates `currentUrl` for subsequent retries on other operations.
|
|
754
|
+
*/
|
|
755
|
+
goto(url: string): Promise<void>;
|
|
756
|
+
/**
|
|
757
|
+
* Execute a single action from natural language.
|
|
758
|
+
*
|
|
759
|
+
* Example: `await browser.act('Click the login button')`
|
|
760
|
+
*/
|
|
761
|
+
act(instruction: string): Promise<void>;
|
|
762
|
+
/**
|
|
763
|
+
* Discover interactive elements on the page.
|
|
764
|
+
*
|
|
765
|
+
* Works WITHOUT an LLM — injects DOM traversal to collect elements.
|
|
766
|
+
* When instruction is provided + LLM is configured, adds ranking/filtering.
|
|
767
|
+
*/
|
|
768
|
+
observe(instruction?: string): Promise<ObserveResult[]>;
|
|
769
|
+
/**
|
|
770
|
+
* Extract structured data from the page.
|
|
771
|
+
*
|
|
772
|
+
* Example: `await browser.extract('Product name and price', { schema: z.object({...}) })`
|
|
773
|
+
*/
|
|
774
|
+
extract<T>(instruction: string, options?: {
|
|
775
|
+
schema?: z.ZodType<T>;
|
|
776
|
+
}): Promise<T>;
|
|
777
|
+
/**
|
|
778
|
+
* Create an autonomous agent that executes multi-step tasks.
|
|
779
|
+
*
|
|
780
|
+
* Uses the same action vocabulary and system prompt as Spider's
|
|
781
|
+
* server-side captcha solver for consistent behavior.
|
|
782
|
+
*/
|
|
783
|
+
agent(options?: Partial<AgentOptions>): Agent;
|
|
784
|
+
/**
|
|
785
|
+
* Close the connection and clean up resources.
|
|
786
|
+
*/
|
|
787
|
+
close(): Promise<void>;
|
|
788
|
+
private requireLLM;
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
/** CDP JSON-RPC response. */
|
|
792
|
+
interface CDPResponse {
|
|
793
|
+
id: number;
|
|
794
|
+
result?: Record<string, unknown>;
|
|
795
|
+
error?: {
|
|
796
|
+
code: number;
|
|
797
|
+
message: string;
|
|
798
|
+
data?: string;
|
|
799
|
+
};
|
|
800
|
+
sessionId?: string;
|
|
801
|
+
}
|
|
802
|
+
/** BiDi response. */
|
|
803
|
+
interface BiDiResponse {
|
|
804
|
+
id: number;
|
|
805
|
+
type: 'success' | 'error';
|
|
806
|
+
result?: Record<string, unknown>;
|
|
807
|
+
error?: string;
|
|
808
|
+
message?: string;
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
type EventHandler$1 = (params: Record<string, unknown>) => void;
|
|
812
|
+
/**
|
|
813
|
+
* CDP JSON-RPC session over the Spider WebSocket transport.
|
|
814
|
+
*
|
|
815
|
+
* The browser_server proxies to Chrome's BROWSER-LEVEL CDP target
|
|
816
|
+
* (/devtools/browser/{id}). This means we must:
|
|
817
|
+
* 1. Discover/create a page target
|
|
818
|
+
* 2. Attach to it with flatten: true to get a sessionId
|
|
819
|
+
* 3. Send all Page/Runtime/Input commands with that sessionId
|
|
820
|
+
*
|
|
821
|
+
* Used for Chrome, Chrome-H, Servo, and LightPanda browsers.
|
|
822
|
+
*/
|
|
823
|
+
declare class CDPSession {
|
|
824
|
+
private nextId;
|
|
825
|
+
private pending;
|
|
826
|
+
private eventHandlers;
|
|
827
|
+
private transport;
|
|
828
|
+
/** CDP session ID from Target.attachToTarget (required for page-level commands). */
|
|
829
|
+
private targetSessionId;
|
|
830
|
+
private commandTimeoutMs;
|
|
831
|
+
constructor(transport: Transport, opts?: {
|
|
832
|
+
commandTimeoutMs?: number;
|
|
833
|
+
});
|
|
834
|
+
/** Get the attached target session ID. */
|
|
835
|
+
get sessionId(): string | undefined;
|
|
836
|
+
/** Process a raw message from the transport. Returns true if handled. */
|
|
837
|
+
handleMessage(data: string): boolean;
|
|
838
|
+
/** Send a CDP command and wait for the response. */
|
|
839
|
+
send(method: string, params?: Record<string, unknown>): Promise<CDPResponse>;
|
|
840
|
+
/**
|
|
841
|
+
* Send a CDP command scoped to the attached page session.
|
|
842
|
+
* This is what you use for Page.*, Runtime.*, Input.* commands.
|
|
843
|
+
*/
|
|
844
|
+
sendToTarget(method: string, params?: Record<string, unknown>): Promise<CDPResponse>;
|
|
845
|
+
/** Subscribe to a CDP event. */
|
|
846
|
+
on(method: string, handler: EventHandler$1): void;
|
|
847
|
+
/** Unsubscribe from a CDP event. */
|
|
848
|
+
off(method: string, handler: EventHandler$1): void;
|
|
849
|
+
/**
|
|
850
|
+
* Discover page targets, find or create one, attach to it, and enable
|
|
851
|
+
* the required CDP domains (Page, Runtime).
|
|
852
|
+
*
|
|
853
|
+
* This is the key initialization step — without this, Page.navigate and
|
|
854
|
+
* Runtime.evaluate won't work because we're connected at browser level.
|
|
855
|
+
*/
|
|
856
|
+
attachToPage(): Promise<string>;
|
|
857
|
+
/** Capture a screenshot as base64 PNG (10s timeout to avoid blocking on heavy pages). */
|
|
858
|
+
captureScreenshot(): Promise<string>;
|
|
859
|
+
/** Get full page HTML. */
|
|
860
|
+
getHTML(): Promise<string>;
|
|
861
|
+
/** Evaluate a JavaScript expression and return the value. */
|
|
862
|
+
evaluate(expression: string): Promise<unknown>;
|
|
863
|
+
/** Wait for a CDP event to fire, with timeout. Returns true if event fired, false on timeout. */
|
|
864
|
+
private waitForEvent;
|
|
865
|
+
/** Navigate to a URL and wait for the page to load. */
|
|
866
|
+
navigate(url: string): Promise<void>;
|
|
867
|
+
/** Dispatch a mouse event. */
|
|
868
|
+
dispatchMouseEvent(type: string, x: number, y: number, button?: string, clickCount?: number): Promise<void>;
|
|
869
|
+
/** Click at coordinates (mouseMoved -> mousePressed -> mouseReleased). */
|
|
870
|
+
clickPoint(x: number, y: number): Promise<void>;
|
|
871
|
+
/** Right-click at coordinates. */
|
|
872
|
+
rightClickPoint(x: number, y: number): Promise<void>;
|
|
873
|
+
/** Double-click at coordinates. */
|
|
874
|
+
doubleClickPoint(x: number, y: number): Promise<void>;
|
|
875
|
+
/** Click and hold at coordinates for a duration. */
|
|
876
|
+
clickHoldPoint(x: number, y: number, holdMs: number): Promise<void>;
|
|
877
|
+
/** Hover (mouseMoved only). */
|
|
878
|
+
hoverPoint(x: number, y: number): Promise<void>;
|
|
879
|
+
/** Smooth drag from point to point (10-step interpolation). */
|
|
880
|
+
dragPoint(fromX: number, fromY: number, toX: number, toY: number): Promise<void>;
|
|
881
|
+
/** Insert text via Input.insertText. */
|
|
882
|
+
insertText(text: string): Promise<void>;
|
|
883
|
+
/** Press a key (keyDown + keyUp). */
|
|
884
|
+
pressKey(key: string, code: string, keyCode: number): Promise<void>;
|
|
885
|
+
/** Send keyDown event. */
|
|
886
|
+
keyDown(key: string, code: string, keyCode: number): Promise<void>;
|
|
887
|
+
/** Send keyUp event. */
|
|
888
|
+
keyUp(key: string, code: string, keyCode: number): Promise<void>;
|
|
889
|
+
/** Set viewport via Emulation.setDeviceMetricsOverride. */
|
|
890
|
+
setViewport(width: number, height: number, deviceScaleFactor?: number, mobile?: boolean): Promise<void>;
|
|
891
|
+
/** Clean up all pending commands and event handlers. Rejects in-flight commands. */
|
|
892
|
+
destroy(): void;
|
|
893
|
+
private extractEvalValue;
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
type EventHandler = (params: Record<string, unknown>) => void;
|
|
897
|
+
/**
|
|
898
|
+
* WebDriver BiDi session over the Spider WebSocket transport.
|
|
899
|
+
*
|
|
900
|
+
* Used for Firefox browser connections. Mirrors CDPSession's interface
|
|
901
|
+
* but speaks the BiDi protocol.
|
|
902
|
+
*/
|
|
903
|
+
declare class BiDiSession {
|
|
904
|
+
private nextId;
|
|
905
|
+
private pending;
|
|
906
|
+
private eventHandlers;
|
|
907
|
+
private transport;
|
|
908
|
+
private browsingContext;
|
|
909
|
+
private commandTimeoutMs;
|
|
910
|
+
constructor(transport: Transport, opts?: {
|
|
911
|
+
commandTimeoutMs?: number;
|
|
912
|
+
});
|
|
913
|
+
get context(): string | undefined;
|
|
914
|
+
/** Process a raw message from the transport. Returns true if handled. */
|
|
915
|
+
handleMessage(data: string): boolean;
|
|
916
|
+
/** Send a BiDi command and wait for the response. */
|
|
917
|
+
send(method: string, params: Record<string, unknown>): Promise<BiDiResponse>;
|
|
918
|
+
/** Subscribe to a BiDi event. */
|
|
919
|
+
on(method: string, handler: EventHandler): void;
|
|
920
|
+
/** Unsubscribe from a BiDi event. */
|
|
921
|
+
off(method: string, handler: EventHandler): void;
|
|
922
|
+
/**
|
|
923
|
+
* Get or create a browsing context.
|
|
924
|
+
*
|
|
925
|
+
* The browser_server's Firefox relay proxies to geckodriver which already has
|
|
926
|
+
* a session with a browsing context. We try multiple strategies:
|
|
927
|
+
* 1. browsingContext.getTree (standard BiDi)
|
|
928
|
+
* 2. session.status (to get session info, then extract context)
|
|
929
|
+
* 3. browsingContext.create as last resort
|
|
930
|
+
*
|
|
931
|
+
* If all discovery fails, we set a placeholder context that gets replaced
|
|
932
|
+
* on the first successful navigate response.
|
|
933
|
+
*/
|
|
934
|
+
getOrCreateContext(): Promise<string>;
|
|
935
|
+
/** Set the browsing context (called when we discover it from a response). */
|
|
936
|
+
setContext(contextId: string): void;
|
|
937
|
+
/** Navigate to a URL. */
|
|
938
|
+
navigate(url: string): Promise<void>;
|
|
939
|
+
/** Capture a screenshot as base64 PNG. */
|
|
940
|
+
captureScreenshot(): Promise<string>;
|
|
941
|
+
/**
|
|
942
|
+
* Evaluate JavaScript and return the value.
|
|
943
|
+
*
|
|
944
|
+
* BiDi script.evaluate returns results in this format:
|
|
945
|
+
* { result: { type: "string", value: "..." } }
|
|
946
|
+
* { result: { type: "number", value: 42 } }
|
|
947
|
+
* { result: { type: "boolean", value: true } }
|
|
948
|
+
* { result: { type: "object", value: [...entries...] } }
|
|
949
|
+
* { result: { type: "null" } }
|
|
950
|
+
* { result: { type: "undefined" } }
|
|
951
|
+
* { result: { type: "array", value: [...] } }
|
|
952
|
+
*/
|
|
953
|
+
evaluate(expression: string): Promise<unknown>;
|
|
954
|
+
/** Extract a JS value from a BiDi remote value object. */
|
|
955
|
+
private extractBiDiValue;
|
|
956
|
+
/** Get full page HTML. */
|
|
957
|
+
getHTML(): Promise<string>;
|
|
958
|
+
/**
|
|
959
|
+
* Perform actions (BiDi input.performActions).
|
|
960
|
+
* This is the BiDi way to do mouse/keyboard events.
|
|
961
|
+
*/
|
|
962
|
+
performActions(actions: unknown[]): Promise<void>;
|
|
963
|
+
/** Click at coordinates via BiDi input actions. */
|
|
964
|
+
clickPoint(x: number, y: number): Promise<void>;
|
|
965
|
+
/** Insert text via BiDi input actions. */
|
|
966
|
+
insertText(text: string): Promise<void>;
|
|
967
|
+
/** Clean up all pending commands and event handlers. Rejects in-flight commands. */
|
|
968
|
+
destroy(): void;
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
interface RetryOptions {
|
|
972
|
+
maxRetries: number;
|
|
973
|
+
transportOpts: TransportOptions;
|
|
974
|
+
emitter: SpiderEventEmitter;
|
|
975
|
+
/** Maximum stealth level to escalate to (1-3, default 3). */
|
|
976
|
+
maxStealthLevel?: number;
|
|
977
|
+
/** Timeout for retry attempts — shorter than first try (default: 15000ms). */
|
|
978
|
+
retryTimeoutMs?: number;
|
|
979
|
+
/** CDP/BiDi command timeout in ms, passed through to new adapters (default: 30000). */
|
|
980
|
+
commandTimeoutMs?: number;
|
|
981
|
+
}
|
|
982
|
+
interface RetryContext {
|
|
983
|
+
transport: Transport;
|
|
984
|
+
adapter: ProtocolAdapter;
|
|
985
|
+
page: SpiderPage;
|
|
986
|
+
currentUrl: string | undefined;
|
|
987
|
+
onAdapterChanged: (adapter: ProtocolAdapter) => void;
|
|
988
|
+
}
|
|
989
|
+
/**
|
|
990
|
+
* Smart retry engine with stealth-first escalation.
|
|
991
|
+
*
|
|
992
|
+
* **Strategy: escalate proxy quality (stealth) FAST, try alternative engines LAST.**
|
|
993
|
+
*
|
|
994
|
+
* - **Phase 1 (Stealth escalation)**: For each stealth level [0 → max],
|
|
995
|
+
* try PRIMARY browsers [chrome, chrome-new] with transient retries.
|
|
996
|
+
* If blocked → skip remaining primary browsers, escalate stealth immediately.
|
|
997
|
+
*
|
|
998
|
+
* - **Phase 2 (Extended rotation)**: Only at max stealth, if still blocked,
|
|
999
|
+
* try EXTENDED browsers [firefox, lightpanda, servo] for different engine
|
|
1000
|
+
* fingerprints + best proxies.
|
|
1001
|
+
*
|
|
1002
|
+
* **Retry flow:**
|
|
1003
|
+
* ```
|
|
1004
|
+
* Phase 1 — stealth escalation across primary browsers:
|
|
1005
|
+
* for each stealth level (initial → maxStealthLevel):
|
|
1006
|
+
* for each PRIMARY browser [chrome, chrome-new]:
|
|
1007
|
+
* attempt action
|
|
1008
|
+
* if transient → reconnect same browser, retry up to 2x
|
|
1009
|
+
* if blocked → skip remaining primary, escalate stealth immediately
|
|
1010
|
+
* if backend_down → mark down, next browser
|
|
1011
|
+
* if auth → throw immediately
|
|
1012
|
+
* if rate_limit → wait, retry same browser
|
|
1013
|
+
*
|
|
1014
|
+
* Phase 2 — extended rotation at max stealth only (if blocked):
|
|
1015
|
+
* for each EXTENDED browser [firefox, lightpanda, servo]:
|
|
1016
|
+
* single attempt (no transient retries)
|
|
1017
|
+
* ```
|
|
1018
|
+
*
|
|
1019
|
+
* Error classification (mirrors server hints.rs):
|
|
1020
|
+
*
|
|
1021
|
+
* | Error Pattern | Classification | Action |
|
|
1022
|
+
* |----------------------------|-----------------|-------------------------------------------|
|
|
1023
|
+
* | ERR_ABORTED (nav) | Transient+Disco | Reconnect (new session), retry up to 2x |
|
|
1024
|
+
* | WS close 1006/1011 | Transient+Disco | Reconnect same browser, retry up to 2x |
|
|
1025
|
+
* | Timeout | Transient | Retry same browser up to 2x, then switch |
|
|
1026
|
+
* | blocked / 403 / captcha | Blocked | Skip remaining primary, escalate stealth |
|
|
1027
|
+
* | bot detection | Blocked | Skip remaining primary, escalate stealth |
|
|
1028
|
+
* | 401 / 402 | Auth | Throw immediately (no retry) |
|
|
1029
|
+
* | 429 | Rate limit | Wait + retry same browser |
|
|
1030
|
+
* | 503 / backend unavailable | Backend down | Mark down, switch browser |
|
|
1031
|
+
*/
|
|
1032
|
+
declare class RetryEngine {
|
|
1033
|
+
private opts;
|
|
1034
|
+
private selector;
|
|
1035
|
+
private currentStealthLevel;
|
|
1036
|
+
private maxStealthLevel;
|
|
1037
|
+
private retryTimeoutMs;
|
|
1038
|
+
private commandTimeoutMs;
|
|
1039
|
+
/** Browser backends that returned 503/unavailable — persists across stealth levels. */
|
|
1040
|
+
private downBackends;
|
|
1041
|
+
constructor(opts: RetryOptions);
|
|
1042
|
+
/** Current stealth level (0=auto, 1-3=explicit tiers). */
|
|
1043
|
+
get stealthLevel(): number;
|
|
1044
|
+
/**
|
|
1045
|
+
* Execute an action with stealth-first retry across browsers and stealth levels.
|
|
1046
|
+
*
|
|
1047
|
+
* Phase 1: Escalate stealth across primary browsers (chrome, chrome-new).
|
|
1048
|
+
* Blocked errors skip remaining primary browsers and immediately escalate stealth.
|
|
1049
|
+
*
|
|
1050
|
+
* Phase 2: At max stealth only, try extended browsers (firefox, lightpanda, servo)
|
|
1051
|
+
* for a different engine fingerprint with the best proxy quality.
|
|
1052
|
+
*/
|
|
1053
|
+
execute<T>(fn: () => Promise<T>, ctx: RetryContext): Promise<T>;
|
|
1054
|
+
/**
|
|
1055
|
+
* Attempt an action on a specific browser, with optional transient retries.
|
|
1056
|
+
*
|
|
1057
|
+
* @param allowTransientRetries If true, retries up to 2x for transient errors
|
|
1058
|
+
* (reconnect + retry). If false, a single attempt only (for extended browsers).
|
|
1059
|
+
*/
|
|
1060
|
+
private tryBrowser;
|
|
1061
|
+
/** Check if an error indicates the WebSocket/session is dead and needs reconnection. */
|
|
1062
|
+
private isDisconnectionError;
|
|
1063
|
+
/**
|
|
1064
|
+
* Classify an error to determine retry strategy.
|
|
1065
|
+
*
|
|
1066
|
+
* Fast path: typed error instances (instanceof check, no string scan).
|
|
1067
|
+
* Slow path: Aho-Corasick O(n) single-pass keyword matching on error message.
|
|
1068
|
+
*/
|
|
1069
|
+
private classifyError;
|
|
1070
|
+
/** Reconnect with a (possibly different) browser, re-navigate to the same URL. */
|
|
1071
|
+
private switchBrowser;
|
|
1072
|
+
/**
|
|
1073
|
+
* Get stealth progression: from current level up to maxStealthLevel.
|
|
1074
|
+
* e.g. start=0, max=3 → [0, 1, 2, 3]
|
|
1075
|
+
* e.g. start=2, max=3 → [2, 3]
|
|
1076
|
+
*/
|
|
1077
|
+
private getStealthProgression;
|
|
1078
|
+
/**
|
|
1079
|
+
* Order PRIMARY browsers starting from `start`, then the rest in primary rotation order.
|
|
1080
|
+
* If `start` is not in PRIMARY_ROTATION, returns primary rotation as-is.
|
|
1081
|
+
*/
|
|
1082
|
+
private orderedPrimaryBrowsers;
|
|
1083
|
+
private extractDomain;
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
/**
|
|
1087
|
+
* Per-domain failure tracking (mirrors server hints.rs FailureTracker).
|
|
1088
|
+
*
|
|
1089
|
+
* Tracks (domain, browser_type) failure counts with 10-minute TTL.
|
|
1090
|
+
* Used by BrowserSelector to decide when to rotate browsers.
|
|
1091
|
+
*/
|
|
1092
|
+
declare class FailureTracker {
|
|
1093
|
+
private failures;
|
|
1094
|
+
private key;
|
|
1095
|
+
/** Record a failure for a domain + browser. */
|
|
1096
|
+
recordFailure(domain: string, browser: BrowserType): void;
|
|
1097
|
+
/** Record a success — clears the failure counter. */
|
|
1098
|
+
recordSuccess(domain: string, browser: BrowserType): void;
|
|
1099
|
+
/** Get failure count (0 if expired or not found). */
|
|
1100
|
+
failureCount(domain: string, browser: BrowserType): number;
|
|
1101
|
+
/** Get total failures across all browsers for a domain. */
|
|
1102
|
+
totalFailureCount(domain: string): number;
|
|
1103
|
+
/** Clear all failure records for a domain (used on stealth escalation). */
|
|
1104
|
+
clear(domain: string): void;
|
|
1105
|
+
/** Clean expired entries. */
|
|
1106
|
+
cleanup(): void;
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
/**
|
|
1110
|
+
* Full browser rotation order for retry/failover.
|
|
1111
|
+
* Primary (Chrome) browsers are tried first, then extended if blocked.
|
|
1112
|
+
*/
|
|
1113
|
+
declare const BROWSER_ROTATION: BrowserType[];
|
|
1114
|
+
/**
|
|
1115
|
+
* BrowserSelector — picks the next browser in rotation based on failures.
|
|
1116
|
+
*
|
|
1117
|
+
* Follows the server's hints.rs logic:
|
|
1118
|
+
* 1. Try current browser until ROTATE_AFTER_FAILURES consecutive failures
|
|
1119
|
+
* 2. Then move to the next browser in BROWSER_ROTATION order
|
|
1120
|
+
* 3. Skip browsers that have also exceeded the failure threshold
|
|
1121
|
+
*/
|
|
1122
|
+
declare class BrowserSelector {
|
|
1123
|
+
private tracker;
|
|
1124
|
+
private rotationIndex;
|
|
1125
|
+
constructor(tracker: FailureTracker);
|
|
1126
|
+
/** Get the current failure tracker. */
|
|
1127
|
+
get failureTracker(): FailureTracker;
|
|
1128
|
+
/**
|
|
1129
|
+
* Check if the current browser should be rotated for a domain.
|
|
1130
|
+
*/
|
|
1131
|
+
shouldRotate(domain: string, currentBrowser: BrowserType): boolean;
|
|
1132
|
+
/**
|
|
1133
|
+
* Pick the next browser to try, given the current one has failed.
|
|
1134
|
+
* Returns the next browser in rotation that hasn't exceeded the failure threshold.
|
|
1135
|
+
* Returns null if all browsers have been exhausted.
|
|
1136
|
+
*/
|
|
1137
|
+
nextBrowser(domain: string, currentBrowser: BrowserType): BrowserType | null;
|
|
1138
|
+
/**
|
|
1139
|
+
* Choose the best browser for a domain (mirrors hints.rs choose_browser_for_domain).
|
|
1140
|
+
* Uses failure history to skip browsers that have been failing.
|
|
1141
|
+
*/
|
|
1142
|
+
chooseBrowser(domain: string, fallback: BrowserType): BrowserType;
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
/**
|
|
1146
|
+
* Execute a single action from natural language.
|
|
1147
|
+
*
|
|
1148
|
+
* Takes a screenshot + HTML, sends to LLM with the instruction,
|
|
1149
|
+
* then executes the returned action steps.
|
|
1150
|
+
*
|
|
1151
|
+
* Example: `await act(adapter, llm, 'Click the login button')`
|
|
1152
|
+
*/
|
|
1153
|
+
declare function act(adapter: ProtocolAdapter, llm: LLMProvider, instruction: string): Promise<void>;
|
|
1154
|
+
|
|
1155
|
+
/**
|
|
1156
|
+
* Extract structured data from the page.
|
|
1157
|
+
*
|
|
1158
|
+
* Takes a screenshot + HTML, sends to LLM with the instruction and optional
|
|
1159
|
+
* Zod schema, returns parsed and validated data.
|
|
1160
|
+
*/
|
|
1161
|
+
declare function extract<T>(adapter: ProtocolAdapter, llm: LLMProvider, instruction: string, schema?: z.ZodType<T>): Promise<T>;
|
|
1162
|
+
|
|
1163
|
+
/**
|
|
1164
|
+
* System prompt for the web automation agent.
|
|
1165
|
+
*
|
|
1166
|
+
* Ported VERBATIM from browser_server/src/ai/llm.rs SYSTEM_PROMPT (lines 30-135)
|
|
1167
|
+
* to ensure identical agent behavior between server-side captcha solver
|
|
1168
|
+
* and client-side agent.
|
|
1169
|
+
*/
|
|
1170
|
+
declare const SYSTEM_PROMPT = "You 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 \u2014 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";
|
|
1171
|
+
|
|
1172
|
+
/**
|
|
1173
|
+
* Truncate HTML to roughly maxChars, trying to break at a tag boundary.
|
|
1174
|
+
* Mirrors server's truncate_html in llm.rs.
|
|
1175
|
+
*/
|
|
1176
|
+
declare function truncateHtml(html: string, maxChars?: number): string;
|
|
1177
|
+
|
|
1178
|
+
/** Base error for all spider-browser errors. */
|
|
1179
|
+
declare class SpiderError extends Error {
|
|
1180
|
+
readonly code: string;
|
|
1181
|
+
readonly retryable: boolean;
|
|
1182
|
+
constructor(message: string, code: string, retryable?: boolean);
|
|
1183
|
+
}
|
|
1184
|
+
/** WebSocket connection or transport error. */
|
|
1185
|
+
declare class ConnectionError extends SpiderError {
|
|
1186
|
+
readonly wsCode?: number | undefined;
|
|
1187
|
+
constructor(message: string, wsCode?: number | undefined);
|
|
1188
|
+
}
|
|
1189
|
+
/** Authentication failure (401/402). Never retried. */
|
|
1190
|
+
declare class AuthError extends SpiderError {
|
|
1191
|
+
constructor(message: string);
|
|
1192
|
+
}
|
|
1193
|
+
/** Rate limit (429). Retried with delay. */
|
|
1194
|
+
declare class RateLimitError extends SpiderError {
|
|
1195
|
+
readonly retryAfterMs?: number | undefined;
|
|
1196
|
+
constructor(message: string, retryAfterMs?: number | undefined);
|
|
1197
|
+
}
|
|
1198
|
+
/** The browser was blocked by the target site (403, captcha stuck). */
|
|
1199
|
+
declare class BlockedError extends SpiderError {
|
|
1200
|
+
constructor(message: string);
|
|
1201
|
+
}
|
|
1202
|
+
/** The requested backend browser is unavailable. */
|
|
1203
|
+
declare class BackendUnavailableError extends SpiderError {
|
|
1204
|
+
constructor(message: string);
|
|
1205
|
+
}
|
|
1206
|
+
/** Timeout waiting for a response or navigation. */
|
|
1207
|
+
declare class TimeoutError extends SpiderError {
|
|
1208
|
+
constructor(message: string);
|
|
1209
|
+
}
|
|
1210
|
+
/** Protocol-level error (invalid CDP/BiDi response). */
|
|
1211
|
+
declare class ProtocolError extends SpiderError {
|
|
1212
|
+
constructor(message: string);
|
|
1213
|
+
}
|
|
1214
|
+
/** Navigation error that can be retried (ERR_ABORTED, ERR_CONNECTION_RESET, etc.). */
|
|
1215
|
+
declare class NavigationError extends SpiderError {
|
|
1216
|
+
constructor(message: string);
|
|
1217
|
+
}
|
|
1218
|
+
/** LLM call failed or returned unparseable response. */
|
|
1219
|
+
declare class LLMError extends SpiderError {
|
|
1220
|
+
constructor(message: string);
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
export { Agent, type AgentAction, type AgentOptions, type AgentPlan, type AgentResult, AuthError, BROWSER_ROTATION, BackendUnavailableError, BiDiSession, BlockedError, BrowserSelector, type BrowserType, CDPSession, ConnectionError, FailureTracker, type LLMConfig, LLMError, type LLMMessage, type LLMProvider, Logger, NavigationError, type ObserveResult, ProtocolAdapter, ProtocolError, RateLimitError, RetryEngine, type RetryOptions, SYSTEM_PROMPT, SpiderBrowser, type SpiderBrowserOptions, SpiderError, SpiderEventEmitter, type SpiderEventName, type SpiderEvents, SpiderPage, TimeoutError, Transport, type TransportOptions, act, createProvider, extract, logger, observe, truncateHtml };
|