@oya-ai/browser 1.0.97 → 1.0.101

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/dist/index.d.ts CHANGED
@@ -1,14 +1,262 @@
1
- /** The one HTTP path. Everything else in this package is a wrapper over it. */
2
- declare class Http {
3
- readonly baseUrl: string;
4
- readonly apiKey: string;
5
- private readonly timeoutMs;
6
- private readonly fetchImpl;
7
- constructor(baseUrl: string, apiKey: string, timeoutMs: number, fetchImpl: typeof globalThis.fetch);
8
- request<T>(method: string, path: string, body?: unknown, timeoutMs?: number, headers?: Record<string, string>): Promise<T>;
1
+ /**
2
+ * Types for browsers themselves: starting one, what a page looks like to the
3
+ * SDK, the results of CAPTCHA and MFA handling, and the fleet listing.
4
+ */
5
+ /** Where a browser comes from. Configuration, not something a caller must know. */
6
+ type Provider = 'oya-cloud' | 'oya-selfhosted' | 'browseruse' | 'browserbase' | 'steel' | 'anchor' | 'cdp';
7
+ /** How `oya.browser.start()` should start a browser. Every field is optional. */
8
+ interface StartOptions {
9
+ /** Reuse this value when retrying the same logical creation. */
10
+ idempotencyKey?: string;
11
+ /** Wait for capacity for up to five minutes; zero rejects immediately. */
12
+ queueMs?: number;
13
+ /** Spend ceiling for this browser, in US dollars. */
14
+ budgetUsd?: number;
15
+ /** Run under the project's governance: policies, budgets and recordings. */
16
+ governed?: boolean;
17
+ /** Egress and recording rules for a governed browser. */
18
+ policy?: {
19
+ /** Hosts the browser may reach; everything else is blocked. */
20
+ allowedHosts?: string[];
21
+ /** Hosts where a person, not the agent, must act. */
22
+ humanHosts?: string[];
23
+ /** Where the browser must run. */
24
+ region?: string;
25
+ /** Blur typed values out of the session recording. */
26
+ redactRecording?: boolean;
27
+ };
28
+ /** Place in the queue when capacity is short. */
29
+ priority?: 'low' | 'normal' | 'high';
30
+ /** Saved login profile. Defaults to the desktop's default profile. */
31
+ profile?: string;
32
+ /**
33
+ * Which identity to run as. A persona is one device: fingerprint, cookie jar
34
+ * and proxy bound together and stable for its life.
35
+ * 'default' — this key's own persona (the default)
36
+ * 'auto' — the least recently used persona under its concurrency cap
37
+ * <id> — a specific persona
38
+ */
39
+ persona?: 'default' | 'auto' | (string & {});
40
+ /** Solve CAPTCHAs as they appear rather than waiting to be asked. */
41
+ captcha?: 'auto' | 'off';
42
+ /** Override the key's configured provider for this browser only. */
43
+ provider?: Provider;
44
+ /** Required only for the 'cdp' provider. */
45
+ wsUrl?: string;
46
+ /** A label for the fleet listing. */
47
+ name?: string;
48
+ /** How long to wait for a cloud browser to dial in. Default 120s. */
49
+ readyTimeoutMs?: number;
50
+ }
51
+ /** What the server answers when a browser starts. */
52
+ interface StartResult {
53
+ /** The browser's id, for every later call. */
54
+ id: string;
55
+ /** Which provider runs it. */
56
+ provider: string;
57
+ /** Which persona it runs as. */
58
+ persona: string;
59
+ /** 'starting' while a cloud browser has yet to dial in. */
60
+ status: 'ready' | 'starting';
61
+ /** Point Playwright, Puppeteer or browser-use at this. */
62
+ cdpUrl?: string;
63
+ /** Anything the server wants the caller to know about this start. */
64
+ note?: string;
65
+ }
66
+ /** One element on the page, numbered by `analyze()`. */
67
+ interface Element {
68
+ /** The number to pass to `click()` and `type()`. Valid until the page changes. */
69
+ id: number;
70
+ /** What kind of control it is: link, button, input and so on. */
71
+ type: string;
72
+ /** Visible label, capped at 80 characters by the analyzer. */
73
+ text?: string;
74
+ /** Where a link goes. */
75
+ href?: string;
76
+ /** The current value of a field. */
77
+ value?: string;
78
+ /** Whether a checkbox or radio is ticked. */
79
+ checked?: boolean;
80
+ /** Whether it refuses input. */
81
+ disabled?: boolean;
82
+ /** Whether it is on screen. */
83
+ visible: boolean;
84
+ /** The HTML tag name. */
85
+ tag?: string;
86
+ /** The element's DOM `id`. Usually the most stable handle a site offers. */
87
+ domId?: string;
88
+ /** Its `aria-label`. */
89
+ ariaLabel?: string;
90
+ /** `data-testid`, when the site ships one. */
91
+ testId?: string;
92
+ /** Its `name` attribute. */
93
+ name?: string;
94
+ /** A field's placeholder text. */
95
+ placeholder?: string;
96
+ /** Action of the enclosing form. */
97
+ formName?: string;
98
+ }
99
+ /** How `analyze()` writes the page: markdown (the default) or toon (toonformat.dev). */
100
+ type PageFormat = 'markdown' | 'toon' | 'jsonl';
101
+ /** What `analyze()` accepts. */
102
+ interface AnalyzeOptions {
103
+ /** How the page is written: markdown (the default) or toon. */
104
+ format?: PageFormat;
105
+ }
106
+ /** One block of a page, in reading order: a heading, paragraph, list item, table row, image or element. */
107
+ interface Block {
108
+ /** The element's id, for interactive elements; act on it with click and type. */
109
+ id?: number;
110
+ /** The part of the page it is in: nav, main, form/…, dialog, or empty. */
111
+ region: string;
112
+ /** What it is: h1-h6, text, item, row, header, quote, code, image, or an element kind (link, button, input:email…). */
113
+ kind: string;
114
+ /** Its text, or an element's name. */
115
+ text?: string;
116
+ /** Where a link goes, or what a field holds now. */
117
+ target?: string;
118
+ /** An element's state: checked, disabled, required, off-screen, hint… */
119
+ state?: string;
120
+ }
121
+ /** The page as `analyze()` sees it. */
122
+ interface Analysis {
123
+ /** The format `page` is written in. */
124
+ format?: PageFormat;
125
+ /** The page, written in `format`. */
126
+ page?: string;
127
+ /** The page as markdown; present when the format is markdown (the default). */
128
+ markdown?: string;
129
+ /** The page's facts: url, title, scroll, and when they apply panelScroll, modal, covered, truncated. */
130
+ facts?: Record<string, string | number>;
131
+ /** The page as data: every block in reading order, whatever the format. */
132
+ blocks?: Block[];
133
+ /** Every numbered element, visible or not. */
134
+ elements: Element[];
135
+ /** The window size, in CSS pixels. */
136
+ viewport?: {
137
+ /** Width in CSS pixels. */
138
+ width: number;
139
+ /** Height in CSS pixels. */
140
+ height: number;
141
+ };
142
+ /** How far the page is scrolled. */
143
+ scroll?: {
144
+ /** Horizontal offset in CSS pixels. */
145
+ x: number;
146
+ /** Vertical offset in CSS pixels. */
147
+ y: number;
148
+ };
149
+ /** True when the page was too long to send in full. */
150
+ truncated?: boolean;
151
+ }
152
+ /** What `solveCaptcha()` found and did. */
153
+ interface CaptchaResult {
154
+ /** Whether a CAPTCHA was on the page. */
155
+ present: boolean;
156
+ /** Whether it was cleared. */
157
+ solved: boolean;
158
+ /** 'provider' when the vendor solved it, 'solver' when we did, 'none' otherwise. */
159
+ method: 'provider' | 'solver' | 'none';
160
+ /** Which kind of CAPTCHA it was. */
161
+ type?: string;
162
+ /** Invisible reCAPTCHA v3 scores the visit passively; there is nothing on screen to clear. */
163
+ invisible?: boolean;
164
+ /** The site key the solver was given. */
165
+ sitekey?: string | null;
166
+ /** Why it was not solved. */
167
+ error?: string;
168
+ }
169
+ /** What `completeMfa()` found and did. */
170
+ interface MfaResult {
171
+ /** Whether an MFA prompt was on the page. */
172
+ present: boolean;
173
+ /** Whether it was answered and accepted. */
174
+ completed: boolean;
175
+ /** Which factor answered it, or 'handoff' when a person must. */
176
+ method?: 'totp' | 'email' | 'sms' | 'handoff' | 'none';
177
+ /** Whether the code was typed in. */
178
+ filled?: boolean;
179
+ /** Whether the form was submitted. */
180
+ submitted?: boolean;
181
+ /** Open this to finish by hand when nothing automated can. */
182
+ liveViewUrl?: string | null;
183
+ /** Why it could not be completed. */
184
+ error?: string;
185
+ }
186
+ /** How a browser is doing, judged from its recent commands and heartbeats. */
187
+ type Health = 'ok' | 'stale' | 'errors' | 'dead';
188
+ /** One thing a browser did. */
189
+ interface Activity {
190
+ /** When, as an ISO timestamp. */
191
+ ts: string;
192
+ /** The command's name. */
193
+ action: string;
194
+ /** A one-line account of it. */
195
+ summary: string;
196
+ /** Whether it succeeded. */
197
+ ok: boolean;
198
+ /** How long it took. */
199
+ ms: number;
200
+ /** Why it failed. */
201
+ error?: string;
202
+ }
203
+ /** The outcome of stopping one browser. */
204
+ interface StopResult {
205
+ /** The browser. */
206
+ id: string;
207
+ /** Whether it stopped. */
208
+ ok: boolean;
209
+ /** Which provider ran it. */
210
+ provider?: string | null;
211
+ /** For a cloud browser, whether its sandbox was destroyed (and billing ended). */
212
+ sandboxRemoved?: boolean | null;
213
+ /** Why it did not stop. */
214
+ error?: string;
215
+ }
216
+ /** One browser in the fleet listing. */
217
+ interface BrowserInfo {
218
+ /** The browser's id. */
219
+ id: string;
220
+ /** Its label. */
221
+ name: string;
222
+ /** An Oya Browser on the control socket, or a third-party browser over CDP. */
223
+ clientType: 'oya' | 'cdp';
224
+ /** Which provider runs it. */
225
+ provider: string | null;
226
+ /** The persona id it runs as. */
227
+ persona: string | null;
228
+ /** That persona's name. */
229
+ personaName: string | null;
230
+ /** How it is doing. */
231
+ health: Health;
232
+ /** When it connected. */
233
+ connectedAt: string;
234
+ /** When it was last heard from. */
235
+ lastSeen: string;
236
+ /** The page it is on. */
237
+ currentUrl: string;
238
+ /** Commands run so far. */
239
+ commands: number;
240
+ /** Commands that failed. */
241
+ errors: number;
242
+ /** Commands in flight. */
243
+ pending: number;
244
+ /** When it last ran a command. */
245
+ lastCommandAt: string | null;
246
+ /** The last failure's message. */
247
+ lastError: string | null;
248
+ }
249
+ /** A browser plus what it has been doing, from `browser.status()`. */
250
+ interface BrowserDetail extends BrowserInfo {
251
+ /** Its most recent commands, newest first. */
252
+ activity: Activity[];
9
253
  }
10
254
 
11
- /** Everything the API returns or accepts, in one place. */
255
+ /**
256
+ * Types for a key's settings: the LLM behind `ask()`, the browser provider and
257
+ * the CAPTCHA solver, as `config.set()` accepts them and `config.get()` returns them.
258
+ */
259
+
12
260
  /** Which model drives `ask()` and the chat API. */
13
261
  type LlmProvider = 'openai' | 'anthropic'
14
262
  /** Gemini via AI Studio. */
@@ -24,6 +272,7 @@ type CaptchaSolver = 'capsolver' | '2captcha' | '';
24
272
  * `null` clears a field and falls back to the deployment default.
25
273
  */
26
274
  interface ConfigUpdate {
275
+ /** Which LLM vendor `ask()` and the chat API call. */
27
276
  llm_provider?: LlmProvider | null;
28
277
  /** The credential for whichever `llm_provider` is set — the field name is shared. */
29
278
  openai_api_key?: string | null;
@@ -31,111 +280,119 @@ interface ConfigUpdate {
31
280
  openai_base_url?: string | null;
32
281
  /** Overrides the provider's default model. */
33
282
  chat_model?: string | null;
283
+ /** Where this key's browsers run unless `start()` names a provider. */
34
284
  browser_provider?: Provider | null;
285
+ /** Anchor's API key, for the 'anchor' provider. */
35
286
  anchor_api_key?: string | null;
287
+ /** Browserbase's API key, for the 'browserbase' provider. */
36
288
  browserbase_api_key?: string | null;
289
+ /** The Browserbase project browsers are created in. */
37
290
  browserbase_project_id?: string | null;
291
+ /** Steel's API key, for the 'steel' provider. */
38
292
  steel_api_key?: string | null;
293
+ /** Browser Use Cloud's API key, for the 'browseruse' provider. */
39
294
  browseruse_api_key?: string | null;
295
+ /** The DevTools WebSocket URL of your own Chrome, for the 'cdp' provider. */
40
296
  cdp_ws_url?: string | null;
297
+ /** Which CAPTCHA solving service to call. */
41
298
  captcha_solver?: CaptchaSolver | null;
299
+ /** The solving service's API key. */
42
300
  captcha_api_key?: string | null;
301
+ /** Set once onboarding has been completed, so the console stops offering it. */
43
302
  onboarded?: string | null;
44
303
  }
45
304
  /** What `config.get()` returns. Secrets read back masked, never in full. */
46
305
  interface Config extends Omit<ConfigUpdate, 'llm_provider' | 'browser_provider' | 'captcha_solver'> {
306
+ /** The configured LLM vendor, or empty for the deployment default. */
47
307
  llm_provider?: LlmProvider | '';
308
+ /** The configured browser provider, or empty for the deployment default. */
48
309
  browser_provider?: Provider | '';
310
+ /** The configured CAPTCHA solver; empty when solving is off. */
49
311
  captcha_solver?: CaptchaSolver;
50
312
  /** What this key would actually use right now, deployment defaults included. */
51
313
  effective: {
314
+ /** The LLM endpoint in use. */
52
315
  baseUrl: string;
316
+ /** The model in use. */
53
317
  model: string;
318
+ /** Whether any LLM credential is available. */
54
319
  hasLlmKey: boolean;
55
320
  };
56
321
  /** True when the LLM key in play belongs to the deployment, not this key. */
57
322
  inherited: boolean;
323
+ /** Whether this key has its own LLM credential stored. */
58
324
  has_openai_key: boolean;
325
+ /** Every browser provider, what it needs configured, and whether it is. */
59
326
  providers: Array<{
327
+ /** The provider. */
60
328
  id: Provider;
329
+ /** Its display name. */
61
330
  label: string;
331
+ /** The config fields it requires. */
62
332
  needs: string[];
333
+ /** Whether those fields are set. */
63
334
  configured: boolean;
64
335
  }>;
65
336
  }
66
- /** Where a browser comes from. Configuration, not something a caller must know. */
67
- type Provider = 'oya-cloud' | 'oya-selfhosted' | 'browseruse' | 'browserbase' | 'steel' | 'anchor' | 'cdp';
68
- interface StartOptions {
69
- /** Reuse this value when retrying the same logical creation. */
70
- idempotencyKey?: string;
71
- /** Wait for capacity for up to five minutes; zero rejects immediately. */
72
- queueMs?: number;
73
- budgetUsd?: number;
74
- governed?: boolean;
75
- policy?: {
76
- allowedHosts?: string[];
77
- humanHosts?: string[];
78
- region?: string;
79
- redactRecording?: boolean;
80
- };
81
- priority?: 'low' | 'normal' | 'high';
82
- /** Saved login profile. Defaults to the desktop's default profile. */
83
- profile?: string;
84
- /**
85
- * Which identity to run as. A persona is one device: fingerprint, cookie jar
86
- * and proxy bound together and stable for its life.
87
- * 'default' — this key's own persona (the default)
88
- * 'auto' — the least recently used persona under its concurrency cap
89
- * <id> — a specific persona
90
- */
91
- persona?: 'default' | 'auto' | (string & {});
92
- /** Solve CAPTCHAs as they appear rather than waiting to be asked. */
93
- captcha?: 'auto' | 'off';
94
- /** Override the key's configured provider for this browser only. */
95
- provider?: Provider;
96
- /** Required only for the 'cdp' provider. */
97
- wsUrl?: string;
98
- name?: string;
99
- /** How long to wait for a cloud browser to dial in. Default 120s. */
100
- readyTimeoutMs?: number;
101
- }
102
- interface StartResult {
103
- id: string;
104
- provider: string;
105
- persona: string;
106
- status: 'ready' | 'starting';
107
- /** Point Playwright, Puppeteer or browser-use at this. */
108
- cdpUrl?: string;
109
- note?: string;
337
+
338
+ /**
339
+ * OyaError: the one error type the SDK throws for a failed call, carrying the
340
+ * HTTP status and the server's answer so a caller can branch on either.
341
+ */
342
+ /** A failed API call or browser command. */
343
+ declare class OyaError extends Error {
344
+ /** The HTTP status, or the SDK's own status for errors it raises itself. */
345
+ readonly status: number;
346
+ /** The server's response body, parsed when it was JSON. */
347
+ readonly body: unknown;
348
+ /** Records the message, status and body. */
349
+ constructor(message: string, status: number, body: unknown);
110
350
  }
351
+
352
+ /**
353
+ * Types for agent work: task values and files, playbooks and their replays,
354
+ * and background runs with their attention requests.
355
+ */
356
+
357
+ /** A saved flow, replayable without an LLM. */
111
358
  interface Playbook {
359
+ /** The name it is played by. */
112
360
  name: string;
113
361
  /** Inputs `play()` accepts; any left out reuse the recorded value. */
114
362
  variables: string[];
115
363
  /** What each variable was recorded with. A secret has none — it never left the page. */
116
364
  defaults: Record<string, string>;
365
+ /** How many steps it replays. */
117
366
  steps: number;
118
367
  /** The same flow as a Playwright module: `export default async function run(page, vars)`. */
119
368
  code: string;
120
369
  }
370
+ /** What a `play()` did. */
121
371
  interface PlayResult {
122
372
  /** Steps replayed before finishing or handing over to the agent. */
123
373
  steps: number;
374
+ /** Steps in the playbook. */
124
375
  total: number;
125
376
  /** A step no longer fit the page and the agent finished the task. */
126
377
  fellBack: boolean;
127
378
  /** The agent's fix was saved as `draft`; promote it with `oya.playbooks.promote(name)`. */
128
379
  healed?: boolean;
380
+ /** The draft's name, when one was saved. */
129
381
  draft?: string;
130
382
  /** The agent's summary, when it fell back. */
131
383
  text?: string;
132
384
  }
385
+ /** A playbook in the listing, with its history and any pending fix. */
133
386
  interface PlaybookSummary extends Playbook {
387
+ /** When it was saved. */
134
388
  createdAt: string | null;
389
+ /** When a draft last replaced it. */
135
390
  promotedAt: string | null;
136
391
  /** A healed replay's fix, waiting for `promote()` or `remove('<name>:draft')`. */
137
392
  draft: (Playbook & {
393
+ /** When the replay was healed. */
138
394
  healedAt: string;
395
+ /** The step the replay broke at. */
139
396
  healedFrom: number;
140
397
  }) | null;
141
398
  }
@@ -161,29 +418,46 @@ interface FileValue {
161
418
  * upload tool rather than typing it.
162
419
  */
163
420
  type RunData = Record<string, string | number | FileValue>;
421
+ /** A run is waiting on a person. */
164
422
  interface AttentionRequest {
423
+ /** Identifies this request; a new one means a new problem. */
165
424
  id: string;
166
425
  /** captcha / login / mfa: finish it in the live view. agent: the agent's question. heal_failed: replay and the agent both gave up. */
167
426
  reason: 'captcha' | 'login' | 'mfa' | 'agent' | 'heal_failed';
427
+ /** What is needed, in words. */
168
428
  message: string;
429
+ /** Where to finish it by hand. */
169
430
  liveViewUrl?: string;
431
+ /** When it was raised, in epoch milliseconds. */
170
432
  at: number;
171
433
  }
434
+ /** What a finished run produced: a replay's result, an agent's answer, or both. */
172
435
  type RunResult = Partial<PlayResult> & {
436
+ /** The agent's answer. */
173
437
  text?: string;
174
438
  };
439
+ /** A background run's state. */
175
440
  interface RunInfo {
441
+ /** The run's id. */
176
442
  id: string;
443
+ /** The browser it runs on. */
177
444
  browserId: string;
445
+ /** Where it is. */
178
446
  status: 'running' | 'needs_attention' | 'succeeded' | 'failed';
447
+ /** When it started, in epoch milliseconds. */
179
448
  createdAt: number;
449
+ /** When it ended. */
180
450
  endedAt?: number;
451
+ /** The open request for a person, if any. */
181
452
  attention: AttentionRequest | null;
453
+ /** What it produced, once it succeeded. */
182
454
  result?: RunResult;
455
+ /** Why it failed. */
183
456
  error?: string;
184
457
  /** HTTP-style status of a failure: 429 when a quota stopped the run. */
185
458
  errorStatus?: number;
186
459
  }
460
+ /** The inputs and callbacks for `browser.submit()`. */
187
461
  interface SubmitOptions {
188
462
  /** Task values the agent can read; for a playbook, its variables (secret ones included). */
189
463
  data?: RunData;
@@ -191,7 +465,9 @@ interface SubmitOptions {
191
465
  secrets?: RunData;
192
466
  /** Playbooks only: let the agent finish a broken replay and save its fix as a draft. Default true. */
193
467
  autoHeal?: boolean;
468
+ /** Fires once with the result when the run succeeds. */
194
469
  onSuccess?: (result: RunResult) => unknown;
470
+ /** Fires once when the run fails, or when it can no longer be polled. */
195
471
  onFailure?: (error: OyaError) => unknown;
196
472
  /** Call `respond()` once it is handled: `'done'` after finishing by hand, or your answer to the agent. */
197
473
  onHumanAttention?: (request: AttentionRequest & {
@@ -202,165 +478,151 @@ interface SubmitOptions {
202
478
  /** How often to check on the run. Default 2000. */
203
479
  pollMs?: number;
204
480
  }
205
- interface Element {
206
- id: number;
207
- type: string;
208
- /** Visible label, capped at 80 characters by the analyzer. */
209
- text?: string;
210
- href?: string;
211
- value?: string;
212
- checked?: boolean;
213
- disabled?: boolean;
214
- visible: boolean;
215
- tag?: string;
216
- /** The element's DOM `id`. Usually the most stable handle a site offers. */
217
- domId?: string;
218
- ariaLabel?: string;
219
- /** `data-testid`, when the site ships one. */
220
- testId?: string;
221
- name?: string;
222
- placeholder?: string;
223
- /** Action of the enclosing form. */
224
- formName?: string;
225
- }
226
- interface Analysis {
227
- /** The page as markdown. */
228
- markdown: string;
229
- elements: Element[];
230
- viewport?: {
231
- width: number;
232
- height: number;
233
- };
234
- scroll?: {
235
- x: number;
236
- y: number;
237
- };
238
- truncated?: boolean;
239
- }
240
- interface CaptchaResult {
241
- present: boolean;
242
- solved: boolean;
243
- /** 'provider' when the vendor solved it, 'solver' when we did, 'none' otherwise. */
244
- method: 'provider' | 'solver' | 'none';
245
- type?: string;
246
- /** Invisible reCAPTCHA v3 scores the visit passively; there is nothing on screen to clear. */
247
- invisible?: boolean;
248
- sitekey?: string | null;
249
- error?: string;
250
- }
251
- interface MfaResult {
252
- present: boolean;
253
- completed: boolean;
254
- method?: 'totp' | 'email' | 'sms' | 'handoff' | 'none';
255
- filled?: boolean;
256
- submitted?: boolean;
257
- /** Open this to finish by hand when nothing automated can. */
258
- liveViewUrl?: string | null;
259
- error?: string;
260
- }
481
+
482
+ /**
483
+ * Types for identities: a persona's device and fingerprint, the proxies it
484
+ * exits through, and the second factors and site logins stored for it.
485
+ */
486
+ /** The device a persona presents. Fixed for its life. */
261
487
  interface Fingerprint {
488
+ /** `navigator.platform`. */
262
489
  platform: string;
490
+ /** IANA timezone. */
263
491
  timezone: string;
492
+ /** BCP 47 locale. */
264
493
  locale: string;
494
+ /** Screen size, as `WIDTHxHEIGHT`. */
265
495
  screen: string;
496
+ /** The GPU the WebGL renderer reports. */
266
497
  webgl: string;
498
+ /** Logical CPU cores reported. */
267
499
  hardwareConcurrency: number;
500
+ /** Device memory reported, in GB. */
268
501
  deviceMemory: number;
502
+ /** Seed for the persona's stable canvas noise. */
269
503
  canvasSeed: number;
270
504
  }
271
505
  /** Device choices made at creation. Fixed for the persona's life. */
272
506
  interface PersonaPrefs {
507
+ /** Which operating system to present. */
273
508
  platform?: 'Win32' | 'MacIntel' | 'Linux x86_64';
509
+ /** IANA timezone; must be one the platform can coherently claim. */
274
510
  timezone?: string;
511
+ /** BCP 47 locale; must be one the platform can coherently claim. */
275
512
  locale?: string;
276
513
  }
277
514
  /** A proxy exit. Credentials go in on create and never come back out. */
278
515
  interface ProxyInfo {
516
+ /** The proxy's id. */
279
517
  id: string;
518
+ /** Its display name. */
280
519
  label: string;
520
+ /** Residential IPs look like homes; datacenter ones are cheaper and easier to flag. */
281
521
  kind: 'residential' | 'datacenter';
282
522
  /** Two-letter country, optionally a region: "US", "US-CA". */
283
523
  geo: string | null;
284
524
  /** Provided by the host rather than this key. Cannot be removed. */
285
525
  shared: boolean;
526
+ /** Whether its last check passed. */
286
527
  healthy: boolean;
287
528
  /** Healthy and not cooling down after a failure. */
288
529
  available: boolean;
289
530
  /** Where traffic actually leaves, as of the last check. */
290
531
  exitIp: string | null;
532
+ /** When it was last checked. */
291
533
  lastCheckedAt: string | null;
292
534
  /** Personas on it now, out of `maxPersonas`. */
293
535
  assigned: number;
536
+ /** How many personas may share it. */
294
537
  maxPersonas: number;
538
+ /** How long until a failed proxy is tried again. */
295
539
  cooldownMsRemaining: number;
296
540
  }
541
+ /** A proxy to add. */
297
542
  interface ProxyCreate {
298
543
  /** http(s)://user:pass@host:port from your vendor. Chromium cannot use SOCKS5 with a password. */
299
544
  url: string;
545
+ /** A display name. */
300
546
  label?: string;
547
+ /** Two-letter country, optionally a region, used to match personas' geo hints. */
301
548
  geo?: string;
549
+ /** Residential or datacenter. */
302
550
  kind?: 'residential' | 'datacenter';
303
551
  /** Personas that may share it. Keep 1 for a sticky-session URL so each keeps its own IP. */
304
552
  maxPersonas?: number;
305
553
  }
554
+ /** A persona: one device, its cookie jar and its proxy. */
306
555
  interface PersonaInfo {
556
+ /** The persona's id. */
307
557
  id: string;
558
+ /** Its display name. */
308
559
  name: string;
560
+ /** Whether it is this key's own default persona. */
309
561
  isDefault: boolean;
562
+ /** Browsers running as it now. */
310
563
  activeBrowsers: number;
564
+ /** How many may run as it at once; null for no cap. */
311
565
  maxConcurrent: number | null;
566
+ /** Where its proxy should be, before one is assigned. */
312
567
  proxy: {
568
+ /** Two-letter country, optionally a region. */
313
569
  geo: string | null;
314
570
  } | null;
315
571
  /** The proxy it is actually on, once assigned or pinned. */
316
572
  exit: {
573
+ /** The proxy's id. */
317
574
  id: string;
575
+ /** Its display name. */
318
576
  label: string;
577
+ /** Its country and region. */
319
578
  geo: string | null;
579
+ /** Whether its last check passed. */
320
580
  healthy: boolean;
321
581
  } | null;
582
+ /** The device choices it was created with. */
322
583
  prefs: PersonaPrefs | null;
584
+ /** The device it presents. */
323
585
  fingerprint: Fingerprint;
586
+ /** Its persona-wide second factor. */
324
587
  mfa: {
588
+ /** Whether a factor is stored. */
325
589
  configured: boolean;
590
+ /** Which kind of factor. */
326
591
  type?: string;
592
+ /** The site it is filed against, if any. */
327
593
  domain?: string;
328
594
  };
329
595
  /** Per-site factors and stored logins. Usernames and types only, never secrets. */
330
596
  sites: {
597
+ /** Second factors filed against one site. */
331
598
  mfa: {
599
+ /** The site. */
332
600
  domain: string;
601
+ /** Which kind of factor. */
333
602
  type: string;
334
603
  }[];
604
+ /** Stored site logins. */
335
605
  credentials: {
606
+ /** The site. */
336
607
  domain: string;
608
+ /** The account name. */
337
609
  username: string;
338
610
  }[];
339
611
  };
612
+ /** What its cookie jar holds. */
340
613
  login: {
614
+ /** Cookies in the jar. */
341
615
  cookies: number;
616
+ /** Sites it holds a session for. */
342
617
  sites: string[];
618
+ /** When the jar last changed. */
343
619
  updatedAt: string | null;
344
620
  };
621
+ /** When it was created. */
345
622
  createdAt: string;
623
+ /** When a browser last ran as it. */
346
624
  lastUsedAt: string | null;
347
625
  }
348
- type Health = 'ok' | 'stale' | 'errors' | 'dead';
349
- interface Activity {
350
- ts: string;
351
- action: string;
352
- summary: string;
353
- ok: boolean;
354
- ms: number;
355
- error?: string;
356
- }
357
- interface StopResult {
358
- id: string;
359
- ok: boolean;
360
- provider?: string | null;
361
- sandboxRemoved?: boolean | null;
362
- error?: string;
363
- }
364
626
  /**
365
627
  * A second factor. `domain` files it against one site, because a persona driving
366
628
  * several portals meets several kinds of factor; without it the record is the
@@ -375,122 +637,452 @@ interface StopResult {
375
637
  * `pattern` is only the fallback for when no LLM key is set or the call fails.
376
638
  */
377
639
  type MfaConfig = {
640
+ /** The site this factor answers for; without it, the persona-wide default. */
378
641
  domain?: string;
379
642
  } & ({
643
+ /** An authenticator app's time-based codes. */
380
644
  type: 'totp';
645
+ /** The base32 seed. */
381
646
  secret: string;
382
647
  } | {
648
+ /** Codes delivered to an endpoint you host. */
383
649
  type: 'email' | 'sms';
650
+ /** The endpoint polled for the latest message. */
384
651
  url: string;
652
+ /** Headers sent with each poll. */
385
653
  headers?: Record<string, string>;
654
+ /** Fallback regex for the code, used when no LLM is available. */
386
655
  pattern?: string;
656
+ /** How long to wait for a code. */
387
657
  timeoutMs?: number;
388
658
  } | {
659
+ /** Codes read from a Gmail or Microsoft 365 mailbox. */
389
660
  type: 'gmail' | 'graph';
661
+ /** The mailbox's OAuth refresh token. */
390
662
  refreshToken: string;
663
+ /** The OAuth client the token was issued to. */
391
664
  clientId: string;
665
+ /** That client's secret, when it has one. */
392
666
  clientSecret?: string;
667
+ /** The Microsoft tenant, for `graph`. */
393
668
  tenant?: string;
669
+ /** A mailbox search narrowing which messages are read. */
394
670
  query?: string;
671
+ /** Fallback regex for the code, used when no LLM is available. */
395
672
  pattern?: string;
673
+ /** How long to wait for a code. */
396
674
  timeoutMs?: number;
397
675
  });
398
676
  /** A site login. The password is write-only: no API ever reads it back. */
399
677
  interface SiteCredentials {
678
+ /** The site it signs in to. */
400
679
  domain: string;
680
+ /** The account name. */
401
681
  username: string;
682
+ /** The password; stored sealed and never returned. */
402
683
  password: string;
403
684
  }
404
- interface BrowserInfo {
405
- id: string;
406
- name: string;
407
- clientType: 'oya' | 'cdp';
408
- provider: string | null;
409
- persona: string | null;
410
- personaName: string | null;
411
- health: Health;
412
- connectedAt: string;
413
- lastSeen: string;
414
- currentUrl: string;
415
- commands: number;
416
- errors: number;
417
- pending: number;
418
- lastCommandAt: string | null;
419
- lastError: string | null;
420
- }
421
- interface BrowserDetail extends BrowserInfo {
422
- activity: Activity[];
423
- }
424
- interface OyaOptions {
425
- /** Defaults to OYA_API_KEY. */
426
- apiKey?: string;
427
- /** Defaults to OYA_BASE_URL, then https://browser.getoya.ai. */
428
- baseUrl?: string;
429
- /** Per-request timeout. Navigation gets its own, longer budget. */
430
- timeoutMs?: number;
431
- fetch?: typeof globalThis.fetch;
432
- }
433
- declare class OyaError extends Error {
434
- readonly status: number;
435
- readonly body: unknown;
436
- constructor(message: string, status: number, body: unknown);
437
- }
685
+
686
+ /**
687
+ * Types for the durable control plane: sessions and their lifecycle, human
688
+ * takeover, project settings, lifecycle events and service credentials.
689
+ */
690
+ /** What a member or credential may do: read, operate browsers, or also administer the project. */
438
691
  type ControlRole = 'viewer' | 'operator' | 'administrator';
439
692
  /** What a human holding the control lease may send. Mirrors the server's allowlist. */
440
693
  type HumanInputAction = 'click' | 'type' | 'press_key' | 'scroll' | 'click_coordinates' | 'double_click' | 'drag' | 'mouse_move' | 'scroll_at' | 'type_text' | 'keyboard_type' | 'navigate' | 'back' | 'forward' | 'reload' | 'screenshot' | 'analyze' | 'read_page';
694
+ /** A browser session as the control plane records it, including ones no longer connected. */
441
695
  interface ControlSession {
696
+ /** The session's id, which is also the browser's. */
442
697
  id: string;
698
+ /** The project it belongs to. */
443
699
  project: string;
700
+ /** Which provider runs it. */
444
701
  provider: string;
702
+ /** The persona it runs as. */
445
703
  persona: string | null;
704
+ /** Where it is in its lifecycle. */
446
705
  state: 'queued' | 'provisioning' | 'ready' | 'disconnected' | 'stopping' | 'cleanup_pending' | 'stopped' | 'failed' | 'unknown_outcome';
706
+ /** Whether the control plane provisioned it (and so must clean it up). */
447
707
  managed: boolean;
708
+ /** When it was created, in epoch milliseconds. */
448
709
  createdAt: number;
710
+ /** When its state last changed. */
449
711
  updatedAt: number;
712
+ /** Estimated spend so far, in US dollars. */
450
713
  costUsd: number;
714
+ /** Who is driving it. */
451
715
  control: {
716
+ /** The agent, a person, or nobody while paused. */
452
717
  mode: 'agent' | 'human' | 'paused';
718
+ /** When a human lease runs out. */
453
719
  expiresAt?: number;
454
720
  };
721
+ /** Why cleanup has not finished. */
455
722
  cleanupError?: string;
456
723
  }
724
+ /** A project's limits, retention and rate cards. */
457
725
  interface ProjectSettings {
726
+ /** Days recordings are kept. */
458
727
  recordingDays: number;
728
+ /** Days audit events are kept. */
459
729
  auditDays: number;
730
+ /** Spend ceiling in US dollars; null for none. */
460
731
  budgetUsd: number | null;
732
+ /** Browsers that may run at once; null for no cap. */
461
733
  maxConcurrent: number | null;
734
+ /** Price per unit, by what is metered. */
462
735
  rates: Record<string, number>;
736
+ /** The default policy for governed browsers. */
463
737
  policy: Record<string, unknown>;
464
738
  }
739
+ /** One durable lifecycle event. */
465
740
  interface ControlEvent {
741
+ /** Increasing id, used as the read cursor. */
466
742
  id: number;
743
+ /** The project it belongs to. */
467
744
  project: string;
745
+ /** What happened. */
468
746
  type: string;
747
+ /** The session it concerns, if any. */
469
748
  sessionId: string | null;
749
+ /** When, in epoch milliseconds. */
470
750
  at: number;
751
+ /** Event-specific fields. */
471
752
  detail: Record<string, unknown>;
472
753
  }
754
+ /** A service credential. Its token is shown once, at creation. */
473
755
  interface ControlCredential {
756
+ /** The credential's id, for revoking it. */
474
757
  id: string;
758
+ /** What it is for. */
475
759
  label: string;
760
+ /** What it may do. */
476
761
  role: ControlRole;
762
+ /** When it stops working; null for never. */
477
763
  expiresAt: number | null;
764
+ /** When it was revoked, if it was. */
478
765
  revokedAt: number | null;
479
766
  }
767
+ /** The project at a glance: settings, sessions, recent events. */
480
768
  interface ControlOverview {
481
769
  /** costUsd: estimated lifetime spend, metered from rate cards. */
482
770
  project: {
771
+ /** The project's id. */
483
772
  id: string;
773
+ /** Its name. */
484
774
  name: string;
775
+ /** Its limits and retention. */
485
776
  settings: ProjectSettings;
777
+ /** Estimated lifetime spend, in US dollars. */
486
778
  costUsd?: number;
487
779
  };
780
+ /** Every session the control plane knows about. */
488
781
  sessions: ControlSession[];
782
+ /** Recent lifecycle events. */
489
783
  events: ControlEvent[];
784
+ /** True while the server is draining for a restart. */
490
785
  draining: boolean;
786
+ /** Service credentials, for administrators. */
491
787
  credentials?: ControlCredential[];
492
788
  }
493
789
 
790
+ /**
791
+ * The options the `Oya` client is constructed with.
792
+ */
793
+ /** How to reach the control plane, and as whom. */
794
+ interface OyaOptions {
795
+ /** Defaults to OYA_API_KEY. */
796
+ apiKey?: string;
797
+ /** Defaults to OYA_BASE_URL, then https://browser.getoya.ai. */
798
+ baseUrl?: string;
799
+ /** Per-request timeout. Navigation gets its own, longer budget. */
800
+ timeoutMs?: number;
801
+ /** A fetch to use instead of the global one, for tests, proxies or old runtimes. */
802
+ fetch?: typeof globalThis.fetch;
803
+ }
804
+
805
+ /** The one HTTP path. Everything else in this package is a wrapper over it. */
806
+ declare class Http {
807
+ readonly baseUrl: string;
808
+ readonly apiKey: string;
809
+ private readonly timeoutMs;
810
+ private readonly fetchImpl;
811
+ /** Stores where to call, with which key, how long to wait and which fetch to use. */
812
+ constructor(baseUrl: string, apiKey: string, timeoutMs: number, fetchImpl: typeof globalThis.fetch);
813
+ /** Sends one request and returns the parsed answer, or throws an OyaError when it failed. */
814
+ request<T>(method: string, path: string, body?: unknown, timeoutMs?: number, headers?: Record<string, string>): Promise<T>;
815
+ }
816
+
817
+ /**
818
+ * The shapes the client's namespaces (`oya.browser`, `oya.control`,
819
+ * `oya.personas` …) take and return that are not part of the exported types,
820
+ * named so each field can say what it is.
821
+ */
822
+
823
+ /** What stopping several browsers did. */
824
+ interface StopManyResult {
825
+ /** How many stopped. */
826
+ stopped: number;
827
+ /** Each browser's outcome. */
828
+ results: StopResult[];
829
+ }
830
+ /** A plain acknowledgement. */
831
+ interface Ack {
832
+ /** Whether it was done. */
833
+ ok: boolean;
834
+ }
835
+ /** A single-use live-stream ticket. */
836
+ interface Ticket {
837
+ /** The ticket. */
838
+ ticket: string;
839
+ /** Seconds until it expires. */
840
+ expiresIn: number;
841
+ }
842
+ /** A page of lifecycle events. */
843
+ interface EventPage {
844
+ /** Events after the cursor asked for. */
845
+ events: ControlEvent[];
846
+ /** Pass this as `after` to read on. */
847
+ cursor: number;
848
+ }
849
+ /** A service credential to mint. */
850
+ interface CredentialRequest {
851
+ /** What it may do. */
852
+ role: ControlRole;
853
+ /** What it is for. */
854
+ label?: string;
855
+ /** When it stops working, in epoch milliseconds. */
856
+ expiresAt?: number;
857
+ }
858
+ /** A new service credential, with its token: shown this once. */
859
+ interface NewCredential extends ControlCredential {
860
+ /** The secret to authenticate with. */
861
+ token: string;
862
+ }
863
+ /** One project member. */
864
+ interface Member {
865
+ /** The member's user id. */
866
+ userId: string;
867
+ /** What they may do. */
868
+ role: ControlRole;
869
+ }
870
+ /** The project's owner and members. */
871
+ interface MemberList {
872
+ /** The owner's user id. */
873
+ owner: string | null;
874
+ /** Everyone else. */
875
+ members: Member[];
876
+ }
877
+ /** An invitation code. */
878
+ interface Invite {
879
+ /** The code to hand to the invitee. */
880
+ code: string;
881
+ /** Seconds until it expires. */
882
+ expiresIn: number;
883
+ }
884
+ /** A registered webhook. */
885
+ interface Webhook {
886
+ /** Its id, for removing it. */
887
+ id: string;
888
+ /** The key its deliveries are signed with. */
889
+ secret: string;
890
+ }
891
+ /** One proxy's check. */
892
+ interface ProxyCheck {
893
+ /** The proxy. */
894
+ id: string;
895
+ /** Whether it answered. */
896
+ ok: boolean;
897
+ /** Where its traffic actually leaves. */
898
+ exitIp?: string | null;
899
+ /** Why it failed. */
900
+ error?: string;
901
+ }
902
+ /** Where a persona's proxy should be. */
903
+ interface GeoHint {
904
+ /** Two-letter country, optionally a region. */
905
+ geo?: string;
906
+ }
907
+ /** A persona to create. */
908
+ interface PersonaCreate {
909
+ /** Its display name. */
910
+ name?: string;
911
+ /** Device choices, fixed for its life. */
912
+ prefs?: PersonaPrefs;
913
+ /** Where its proxy should be. */
914
+ proxy?: GeoHint;
915
+ /** How many browsers may run as it at once; null for no cap. */
916
+ maxConcurrent?: number | null;
917
+ }
918
+ /** What may change on a persona. Never the device. */
919
+ interface PersonaUpdate {
920
+ /** Its display name. */
921
+ name?: string;
922
+ /** How many browsers may run as it at once; null for no cap. */
923
+ maxConcurrent?: number | null;
924
+ /** Where its proxy should be; null clears the hint. */
925
+ proxy?: GeoHint | null;
926
+ }
927
+ /** Options for a clone. */
928
+ interface CloneOptions {
929
+ /** The new persona's name. */
930
+ name?: string;
931
+ }
932
+ /** What a persona may claim, per platform. */
933
+ interface PersonaOptions {
934
+ /** The platforms on offer. */
935
+ platforms: string[];
936
+ /** Timezones each platform may coherently claim. */
937
+ timezones: Record<string, string[]>;
938
+ /** Locales each platform may coherently claim. */
939
+ locales: Record<string, string[]>;
940
+ }
941
+ /** The proxy a persona is pinned to. */
942
+ interface PinnedProxy {
943
+ /** The proxy's id. */
944
+ id: string;
945
+ /** Its display name. */
946
+ label: string;
947
+ }
948
+ /** The outcome of pinning a proxy. */
949
+ interface ProxyPin {
950
+ /** Whether it was saved. */
951
+ ok: boolean;
952
+ /** The proxy now pinned, or null when assignment is left to connect time. */
953
+ proxy: PinnedProxy | null;
954
+ }
955
+ /** A stored second factor, as confirmed. */
956
+ interface MfaSaved {
957
+ /** Whether it is stored. */
958
+ configured: boolean;
959
+ /** Which kind of factor. */
960
+ type: string;
961
+ }
962
+ /** A site login the persona can use. Never the password. */
963
+ interface SiteLogin {
964
+ /** The site. */
965
+ domain: string;
966
+ /** The account name. */
967
+ username: string;
968
+ }
969
+ /** A stored site login, as confirmed. */
970
+ interface CredentialsSaved extends SiteLogin {
971
+ /** Whether it is stored. */
972
+ configured: boolean;
973
+ }
974
+ /** The sites a persona can sign in to. */
975
+ interface SiteLogins {
976
+ /** Usernames only. */
977
+ credentials: SiteLogin[];
978
+ }
979
+
980
+ /**
981
+ * The shapes Browser's methods take and return that are not part of the
982
+ * exported types: tab listings, dialog answers, share links and the like.
983
+ * Named here so each field can say what it is.
984
+ */
985
+
986
+ /** What `type()` reports back. */
987
+ interface TypeResult {
988
+ /** An autocomplete list opened under the field; pick from it before moving on. */
989
+ suggestions_visible?: boolean;
990
+ }
991
+ /** The dialog `handleDialog()` answered. */
992
+ interface DialogResult {
993
+ /** alert, confirm, prompt or beforeunload. */
994
+ type: string;
995
+ /** The dialog's text. */
996
+ message: string;
997
+ /** Whether it was accepted. */
998
+ accepted: boolean;
999
+ }
1000
+ /** A point on the page, in CSS pixels. */
1001
+ interface Point {
1002
+ /** From the left edge. */
1003
+ x: number;
1004
+ /** From the top edge. */
1005
+ y: number;
1006
+ }
1007
+ /** One open tab. */
1008
+ interface Tab {
1009
+ /** The tab's id, for `switchTab()` and `closeTab()`. */
1010
+ id: string;
1011
+ /** The page it shows. */
1012
+ url: string;
1013
+ /** The page's title. */
1014
+ title: string;
1015
+ /** Whether it is the tab commands act on. */
1016
+ active: boolean;
1017
+ }
1018
+ /** Task values for `ask()`. */
1019
+ interface AskValues {
1020
+ /** Values the agent can read. */
1021
+ data?: RunData;
1022
+ /** Values the agent never sees. */
1023
+ secrets?: RunData;
1024
+ }
1025
+ /** How `play()` handles a step that no longer fits. */
1026
+ interface PlayOptions {
1027
+ /** Let the agent finish the task and save its fix as a draft. Default true. */
1028
+ autoHeal?: boolean;
1029
+ }
1030
+ /** What `submit()` runs: a prompt for the agent, or a saved playbook. */
1031
+ type Task = {
1032
+ /** A natural-language task for the agent. */
1033
+ prompt: string;
1034
+ } | {
1035
+ /** The name of a saved playbook. */
1036
+ playbook: string;
1037
+ };
1038
+ /** How a `shareUrl()` link works. */
1039
+ interface ShareOptions {
1040
+ /** Let whoever opens it act in the browser. Default view-only. */
1041
+ control?: boolean;
1042
+ /** How long it lasts. Default one hour. */
1043
+ expiresInSeconds?: number;
1044
+ }
1045
+ /** A link from `shareUrl()`. */
1046
+ interface ShareLink {
1047
+ /** The link to hand out. */
1048
+ url: string;
1049
+ /** Its credential's id, for `revokeShare()`. */
1050
+ id: string;
1051
+ /** When it stops working, in epoch milliseconds; null for never. */
1052
+ expiresAt: number | null;
1053
+ }
1054
+
1055
+ /** The callbacks a run can fire. */
1056
+ type RunCallbacks = Pick<SubmitOptions, 'onSuccess' | 'onFailure' | 'onHumanAttention' | 'onHealed'>;
1057
+
1058
+ /**
1059
+ * Run: a task submitted with `browser.submit()`, running in the background.
1060
+ * The polling itself lives in run-watch.ts.
1061
+ */
1062
+
1063
+ /** A submitted task. Callbacks fire as it changes; `done` settles when it ends. */
1064
+ declare class Run {
1065
+ private readonly http;
1066
+ readonly id: string;
1067
+ /** Settles with the result when the run succeeds, or rejects when it fails. */
1068
+ readonly done: Promise<RunResult>;
1069
+ /** Starts watching the run straight away. */
1070
+ constructor(http: Http, id: string, callbacks: RunCallbacks, pollMs?: number);
1071
+ /** The run's current state. */
1072
+ status(): Promise<RunInfo>;
1073
+ /** Answer the open attention request: `'done'` after handling it by hand, or your reply to the agent. */
1074
+ respond(response?: string): Promise<void>;
1075
+ /** Polls until the run ends, firing callbacks on the way. */
1076
+ private watch;
1077
+ }
1078
+
1079
+ /**
1080
+ * Browser: one running browser, driven through the API. Page actions go
1081
+ * through the command endpoint; CAPTCHA, MFA, agent runs, playbooks and live
1082
+ * view links have their own endpoints. The small rules the methods share
1083
+ * (element ids, aimed scrolls, agent errors) are the functions below the class.
1084
+ */
1085
+
494
1086
  /**
495
1087
  * One running browser.
496
1088
  *
@@ -501,54 +1093,59 @@ interface ControlOverview {
501
1093
  declare class Browser {
502
1094
  private readonly http;
503
1095
  private readonly autoCaptcha;
1096
+ /** The browser's id. */
504
1097
  readonly id: string;
1098
+ /** Which provider runs it. */
505
1099
  readonly provider: string;
1100
+ /** Which persona it runs as. */
506
1101
  readonly persona: string;
507
1102
  /** Point Playwright, Puppeteer or browser-use here. */
508
1103
  readonly cdpUrl?: string;
1104
+ /** Wraps a started browser; `autoCaptcha` solves CAPTCHAs after every `goto()`. */
509
1105
  constructor(http: Http, info: StartResult, autoCaptcha: boolean);
1106
+ /** Runs one browser command; a command that ran and failed throws. */
510
1107
  private command;
1108
+ /** Navigates, then clears any CAPTCHA when `captcha: 'auto'` was asked for. */
511
1109
  goto(url: string): Promise<void>;
512
- /** The page as markdown plus numbered elements to act on. */
513
- analyze(): Promise<Analysis>;
1110
+ /**
1111
+ * The page, written as markdown (the default), TOON or JSONL, plus its blocks and
1112
+ * the numbered elements to act on.
1113
+ */
1114
+ analyze(options?: AnalyzeOptions): Promise<Analysis>;
514
1115
  /** Only the visible elements, which is what an agent almost always wants. */
515
1116
  elements(): Promise<Element[]>;
1117
+ /** Clicks an element by its id from `analyze()`. */
516
1118
  click(elementId: number | string): Promise<void>;
517
- type(elementId: number | string, text: string): Promise<{
518
- suggestions_visible?: boolean;
519
- }>;
1119
+ /** Types into an element by its id from `analyze()`. */
1120
+ type(elementId: number | string, text: string): Promise<TypeResult>;
1121
+ /** A valid element id, or an OyaError saying where ids come from. */
520
1122
  private elementId;
1123
+ /** Presses one key, such as Enter or Escape. */
521
1124
  pressKey(key: string): Promise<void>;
522
1125
  /**
523
1126
  * Answer a native dialog holding the page. alert() and beforeunload are
524
1127
  * answered for you; a confirm() or prompt() waits for this, and every other
525
1128
  * command fails fast with the dialog's text until it is answered.
526
1129
  */
527
- handleDialog(accept: boolean, promptText?: string): Promise<{
528
- type: string;
529
- message: string;
530
- accepted: boolean;
531
- }>;
1130
+ handleDialog(accept: boolean, promptText?: string): Promise<DialogResult>;
532
1131
  /** `at` aims the wheel at an inner scroller (a results panel, a chat pane) instead of the page. */
533
- scroll(direction: 'up' | 'down' | 'top' | 'bottom', amount?: number, at?: {
534
- x: number;
535
- y: number;
536
- }): Promise<void>;
1132
+ scroll(direction: 'up' | 'down' | 'top' | 'bottom', amount?: number, at?: Point): Promise<void>;
1133
+ /** Waits until `selector` matches, up to `timeout` milliseconds. */
537
1134
  waitFor(selector: string, timeout?: number): Promise<void>;
538
1135
  /** A `data:image/…;base64,` URL. PNG or JPEG depending on the driver. */
539
1136
  screenshot(): Promise<string>;
1137
+ /** The active tab's URL, or empty when there is none. */
540
1138
  url(): Promise<string>;
541
- tabs(): Promise<Array<{
542
- id: string;
543
- url: string;
544
- title: string;
545
- active: boolean;
546
- }>>;
1139
+ /** Every open tab. */
1140
+ tabs(): Promise<Array<Tab>>;
1141
+ /** Opens a tab, optionally at `url`, and returns its id. */
547
1142
  openTab(url?: string): Promise<string>;
1143
+ /** Makes a tab the one commands act on. */
548
1144
  switchTab(tabId: string): Promise<void>;
1145
+ /** Closes a tab. */
549
1146
  closeTab(tabId: string): Promise<void>;
550
1147
  /**
551
- x * Detect and clear a CAPTCHA. Providers that solve natively are left to do
1148
+ * Detect and clear a CAPTCHA. Providers that solve natively are left to do
552
1149
  * it; everything else goes to the configured solver.
553
1150
  */
554
1151
  solveCaptcha(): Promise<CaptchaResult>;
@@ -563,10 +1160,7 @@ declare class Browser {
563
1160
  * the matching option; `secrets` it never sees. It types both through placeholders,
564
1161
  * with filters like `{{name|first}}`, so a playbook saved from the run stores no values.
565
1162
  */
566
- ask(prompt: string, { data, secrets }?: {
567
- data?: RunData;
568
- secrets?: RunData;
569
- }): Promise<string>;
1163
+ ask(prompt: string, { data, secrets }?: AskValues): Promise<string>;
570
1164
  /**
571
1165
  * Save the last `ask()` on this browser as a named playbook. Every value that was
572
1166
  * typed, picked or clicked becomes a variable, with what the run used kept in
@@ -581,31 +1175,17 @@ declare class Browser {
581
1175
  * saved as a draft (`healed`, `draft`); off, the step's error is thrown.
582
1176
  * Play `'<name>:draft'` to try a draft before promoting it.
583
1177
  */
584
- play(name: string, data?: RunData, { autoHeal }?: {
585
- autoHeal?: boolean;
586
- }): Promise<PlayResult>;
1178
+ play(name: string, data?: RunData, { autoHeal }?: PlayOptions): Promise<PlayResult>;
587
1179
  /**
588
1180
  * Start a prompt or playbook in the background and hear back through callbacks.
589
1181
  * `onHumanAttention` fires for an unsolved CAPTCHA, an unfinished MFA, the agent
590
1182
  * asking for help, or a replay the agent could not heal; the run waits (up to 30
591
1183
  * minutes) until you call `respond()`.
592
1184
  */
593
- submit(task: {
594
- prompt: string;
595
- } | {
596
- playbook: string;
597
- }, options?: SubmitOptions): Promise<Run>;
1185
+ submit(task: Task, options?: SubmitOptions): Promise<Run>;
598
1186
  /**
599
- * Watch it work: the console, opened on this browser.
600
- *
601
- * This used to return the raw frame stream with the project's API key in the
602
- * query string — a permanent credential in browser history, Referer headers
603
- * and every proxy log on the way, and a URL that renders as a wall of
604
- * text/event-stream if a person actually opens it. It is the console deep
605
- * link now, the same one the server hands back from `completeMfa()`, and it
606
- * carries no credential at all.
607
- *
608
- * For the frames themselves, use `liveStreamUrl()`.
1187
+ * Watch it work: the console, opened on this browser. It carries no
1188
+ * credential. For the frames themselves, use `liveStreamUrl()`.
609
1189
  */
610
1190
  liveViewUrl(): string;
611
1191
  /**
@@ -625,14 +1205,7 @@ declare class Browser {
625
1205
  * rest of your project. Anyone holding the link has that access until it
626
1206
  * expires or you revoke it, so treat it like a password.
627
1207
  */
628
- shareUrl({ control, expiresInSeconds }?: {
629
- control?: boolean;
630
- expiresInSeconds?: number;
631
- }): Promise<{
632
- url: string;
633
- id: string;
634
- expiresAt: number | null;
635
- }>;
1208
+ shareUrl({ control, expiresInSeconds }?: ShareOptions): Promise<ShareLink>;
636
1209
  /** Revoke a link from `shareUrl()` before it expires, by the id it returned. */
637
1210
  revokeShare(id: string): Promise<void>;
638
1211
  /** Counters, health and the last 50 things this browser did. */
@@ -647,18 +1220,6 @@ declare class Browser {
647
1220
  /** @deprecated use stop() — close() only dropped the socket, and a cloud browser redialled. */
648
1221
  close(): Promise<void>;
649
1222
  }
650
- type RunCallbacks = Pick<SubmitOptions, 'onSuccess' | 'onFailure' | 'onHumanAttention' | 'onHealed'>;
651
- /** A submitted task. Callbacks fire as it changes; `done` settles when it ends. */
652
- declare class Run {
653
- private readonly http;
654
- readonly id: string;
655
- readonly done: Promise<RunResult>;
656
- constructor(http: Http, id: string, callbacks: RunCallbacks, pollMs?: number);
657
- status(): Promise<RunInfo>;
658
- /** Answer the open attention request: `'done'` after handling it by hand, or your reply to the agent. */
659
- respond(response?: string): Promise<void>;
660
- private watch;
661
- }
662
1223
 
663
1224
  /**
664
1225
  * Files as task values.
@@ -678,100 +1239,52 @@ declare const MAX_FILE_BYTES: number;
678
1239
  * from the extension.
679
1240
  */
680
1241
  declare function file(source: string | Uint8Array | Blob, options?: {
1242
+ /** The filename the site sees. */
681
1243
  name?: string;
1244
+ /** The MIME type, instead of the one guessed from the extension. */
682
1245
  type?: string;
683
1246
  }): Promise<FileValue>;
684
1247
 
685
- /**
686
- * @oya-ai/browser — thousands of browsers, one API.
687
- *
688
- * import { Oya } from '@oya-ai/browser';
689
- *
690
- * const oya = new Oya(); // OYA_API_KEY
691
- * const browser = await oya.browser.start({ persona: 'auto', captcha: 'auto' });
692
- * await browser.goto('https://example.com');
693
- *
694
- * Which provider actually runs the browser — Oya Cloud, your own machines,
695
- * Browser Use, Browserbase, Steel, Anchor, or a CDP URL you hand us — is
696
- * configuration on your API key, not something this code has to know.
697
- */
698
-
1248
+ /** The client: one API key, every browser behind it. */
699
1249
  declare class Oya {
1250
+ /** The one HTTP path every call goes through. */
700
1251
  private readonly http;
1252
+ /** Reads the key and URL from `options`, then OYA_API_KEY and OYA_BASE_URL. Throws without a key. */
701
1253
  constructor(options?: OyaOptions);
1254
+ /** Start, reattach to, list and stop browsers. */
702
1255
  readonly browser: {
703
- /** Start a browser and wait until it can take commands. */
704
1256
  start: (options?: StartOptions) => Promise<Browser>;
705
- /** Reattach to a browser that is already running. */
706
1257
  get: (id: string) => Promise<Browser>;
707
1258
  list: () => Promise<BrowserInfo[]>;
708
- /** Stop some (`ids`) or every browser on this key. Each reports separately. */
709
- stop: (ids: string[] | "all") => Promise<{
710
- stopped: number;
711
- results: StopResult[];
712
- }>;
1259
+ stop: (ids: string[] | "all") => Promise<StopManyResult>;
713
1260
  stopAll: () => Promise<number>;
714
1261
  };
715
1262
  /** Durable operational controls, including disconnected and cleanup-pending sessions. */
716
1263
  readonly control: {
717
- overview: () => Promise<ControlOverview>;
718
- sessions: () => Promise<ControlSession[]>;
719
- session: (id: string) => Promise<ControlSession>;
720
- settings: (changes: Partial<ProjectSettings>) => Promise<ControlOverview["project"]>;
1264
+ createWebhook: (url: string, types?: string[]) => Promise<Webhook>;
1265
+ removeWebhook: (id: string) => Promise<Ack>;
1266
+ replayDelivery: (id: string) => Promise<Ack>;
1267
+ members: () => Promise<MemberList>;
1268
+ inviteMember: (role?: ControlRole) => Promise<Invite>;
1269
+ removeMember: (userId: string) => Promise<Ack>;
1270
+ createCredential: (options: CredentialRequest) => Promise<NewCredential>;
1271
+ revokeCredential: (id: string) => Promise<Ack>;
1272
+ recover: (id: string, replace?: boolean) => Promise<unknown>;
1273
+ ticket: (id: string) => Promise<Ticket>;
1274
+ events: (after?: number) => Promise<EventPage>;
721
1275
  cancel: (id: string) => Promise<ControlSession>;
722
1276
  stop: (id: string, force?: boolean) => Promise<StopResult>;
723
1277
  takeover: (id: string, action: "acquire" | "release" | "resume") => Promise<ControlSession["control"]>;
724
1278
  input: (id: string, action: HumanInputAction, params: Record<string, unknown>) => Promise<unknown>;
725
- recover: (id: string, replace?: boolean) => Promise<unknown>;
726
- ticket: (id: string) => Promise<{
727
- ticket: string;
728
- expiresIn: number;
729
- }>;
730
- events: (after?: number) => Promise<{
731
- events: ControlEvent[];
732
- cursor: number;
733
- }>;
734
- createCredential: (options: {
735
- role: ControlRole;
736
- label?: string;
737
- expiresAt?: number;
738
- }) => Promise<ControlCredential & {
739
- token: string;
740
- }>;
741
- revokeCredential: (id: string) => Promise<{
742
- ok: boolean;
743
- }>;
744
- members: () => Promise<{
745
- owner: string | null;
746
- members: {
747
- userId: string;
748
- role: ControlRole;
749
- }[];
750
- }>;
751
- inviteMember: (role?: ControlRole) => Promise<{
752
- code: string;
753
- expiresIn: number;
754
- }>;
755
- removeMember: (userId: string) => Promise<{
756
- ok: boolean;
757
- }>;
758
- createWebhook: (url: string, types?: string[]) => Promise<{
759
- id: string;
760
- secret: string;
761
- }>;
762
- removeWebhook: (id: string) => Promise<{
763
- ok: boolean;
764
- }>;
765
- replayDelivery: (id: string) => Promise<{
766
- ok: boolean;
767
- }>;
1279
+ overview: () => Promise<ControlOverview>;
1280
+ sessions: () => Promise<ControlSession[]>;
1281
+ session: (id: string) => Promise<ControlSession>;
1282
+ settings: (changes: Partial<ProjectSettings>) => Promise<ControlOverview["project"]>;
768
1283
  };
769
1284
  /** Playbooks saved with `browser.toPlaybook()`. */
770
1285
  readonly playbooks: {
771
1286
  list: () => Promise<PlaybookSummary[]>;
772
- /** Delete a playbook and its draft, or only the draft with `'<name>:draft'`. */
773
1287
  remove: (name: string) => Promise<void>;
774
- /** Replace a playbook with the draft a healed replay saved. Try it first with `browser.play('<name>:draft')`. */
775
1288
  promote: (name: string) => Promise<Playbook>;
776
1289
  };
777
1290
  /**
@@ -782,84 +1295,24 @@ declare class Oya {
782
1295
  list: () => Promise<ProxyInfo[]>;
783
1296
  create: (proxy: ProxyCreate) => Promise<ProxyInfo>;
784
1297
  remove: (id: string) => Promise<void>;
785
- /** Dial each proxy and learn its real exit IP. Failing ones cool down and are skipped. */
786
- check: () => Promise<Array<{
787
- id: string;
788
- ok: boolean;
789
- exitIp?: string | null;
790
- error?: string;
791
- }>>;
1298
+ check: () => Promise<Array<ProxyCheck>>;
792
1299
  };
1300
+ /** Identities: fingerprint, cookie jar and proxy bound together, plus their stored factors and logins. */
793
1301
  readonly personas: {
794
- list: () => Promise<PersonaInfo[]>;
795
- get: (id: string) => Promise<PersonaInfo>;
796
- /**
797
- * Create an identity. The device — platform, timezone, locale — is chosen
798
- * here and fixed for its life; `preview()` shows what a choice produces.
799
- */
800
- create: (options?: {
801
- name?: string;
802
- prefs?: PersonaPrefs;
803
- proxy?: {
804
- geo?: string;
805
- };
806
- maxConcurrent?: number | null;
807
- }) => Promise<PersonaInfo>;
808
- /** Name, concurrency cap and proxy hint. Never the device — clone for that. */
809
- update: (id: string, changes: {
810
- name?: string;
811
- maxConcurrent?: number | null;
812
- proxy?: {
813
- geo?: string;
814
- } | null;
815
- }) => Promise<PersonaInfo>;
816
- /** A new persona of the same kind of device: same choices, fresh identity, empty jar. */
817
- clone: (id: string, options?: {
818
- name?: string;
819
- }) => Promise<PersonaInfo>;
820
- /** The fingerprint these choices would produce. Persists nothing. */
1302
+ setCredentials: (id: string, config: SiteCredentials) => Promise<CredentialsSaved>;
1303
+ credentials: (id: string) => Promise<SiteLogins>;
1304
+ clearCredentials: (id: string, domain: string) => Promise<void>;
1305
+ setMfa: (id: string, config: MfaConfig) => Promise<MfaSaved>;
1306
+ clearMfa: (id: string, domain?: string) => Promise<void>;
821
1307
  preview: (prefs?: PersonaPrefs) => Promise<Fingerprint>;
822
- /** Platforms, and the timezones and locales each may coherently claim. */
823
- options: () => Promise<{
824
- platforms: string[];
825
- timezones: Record<string, string[]>;
826
- locales: Record<string, string[]>;
827
- }>;
828
- /** Pin the persona to one of your proxies, or `null` to let assignment happen at connect. */
829
- pinProxy: (id: string, proxyId: string | null) => Promise<{
830
- ok: boolean;
831
- proxy: {
832
- id: string;
833
- label: string;
834
- } | null;
835
- }>;
1308
+ options: () => Promise<PersonaOptions>;
1309
+ pinProxy: (id: string, proxyId: string | null) => Promise<ProxyPin>;
836
1310
  remove: (id: string) => Promise<void>;
837
- /** Store the second factor for this identity. Sealed at rest, never read back. */
838
- setMfa: (id: string, config: MfaConfig) => Promise<{
839
- configured: boolean;
840
- type: string;
841
- }>;
842
- clearMfa: (id: string, domain?: string) => Promise<void>;
843
- /**
844
- * Store a site login for this identity. Sealed at rest, never read back.
845
- *
846
- * Signing in once on the desktop and inheriting the cookies is still the
847
- * better path. This is for portals that expire a session server-side
848
- * between runs, where an unattended run has nothing else to recover with.
849
- */
850
- setCredentials: (id: string, config: SiteCredentials) => Promise<{
851
- configured: boolean;
852
- domain: string;
853
- username: string;
854
- }>;
855
- /** Which sites this identity can sign in to. Usernames only. */
856
- credentials: (id: string) => Promise<{
857
- credentials: {
858
- domain: string;
859
- username: string;
860
- }[];
861
- }>;
862
- clearCredentials: (id: string, domain: string) => Promise<void>;
1311
+ list: () => Promise<PersonaInfo[]>;
1312
+ get: (id: string) => Promise<PersonaInfo>;
1313
+ create: (options?: PersonaCreate) => Promise<PersonaInfo>;
1314
+ update: (id: string, changes: PersonaUpdate) => Promise<PersonaInfo>;
1315
+ clone: (id: string, options?: CloneOptions) => Promise<PersonaInfo>;
863
1316
  };
864
1317
  /**
865
1318
  * This key's settings: LLM credentials, browser provider, solver.
@@ -878,78 +1331,25 @@ declare class Oya {
878
1331
  };
879
1332
  /** Saved profiles. `personas` is retained as an alias for existing clients. */
880
1333
  readonly profiles: {
881
- list: () => Promise<PersonaInfo[]>;
882
- get: (id: string) => Promise<PersonaInfo>;
883
- /**
884
- * Create an identity. The device — platform, timezone, locale — is chosen
885
- * here and fixed for its life; `preview()` shows what a choice produces.
886
- */
887
- create: (options?: {
888
- name?: string;
889
- prefs?: PersonaPrefs;
890
- proxy?: {
891
- geo?: string;
892
- };
893
- maxConcurrent?: number | null;
894
- }) => Promise<PersonaInfo>;
895
- /** Name, concurrency cap and proxy hint. Never the device — clone for that. */
896
- update: (id: string, changes: {
897
- name?: string;
898
- maxConcurrent?: number | null;
899
- proxy?: {
900
- geo?: string;
901
- } | null;
902
- }) => Promise<PersonaInfo>;
903
- /** A new persona of the same kind of device: same choices, fresh identity, empty jar. */
904
- clone: (id: string, options?: {
905
- name?: string;
906
- }) => Promise<PersonaInfo>;
907
- /** The fingerprint these choices would produce. Persists nothing. */
1334
+ setCredentials: (id: string, config: SiteCredentials) => Promise<CredentialsSaved>;
1335
+ credentials: (id: string) => Promise<SiteLogins>;
1336
+ clearCredentials: (id: string, domain: string) => Promise<void>;
1337
+ setMfa: (id: string, config: MfaConfig) => Promise<MfaSaved>;
1338
+ clearMfa: (id: string, domain?: string) => Promise<void>;
908
1339
  preview: (prefs?: PersonaPrefs) => Promise<Fingerprint>;
909
- /** Platforms, and the timezones and locales each may coherently claim. */
910
- options: () => Promise<{
911
- platforms: string[];
912
- timezones: Record<string, string[]>;
913
- locales: Record<string, string[]>;
914
- }>;
915
- /** Pin the persona to one of your proxies, or `null` to let assignment happen at connect. */
916
- pinProxy: (id: string, proxyId: string | null) => Promise<{
917
- ok: boolean;
918
- proxy: {
919
- id: string;
920
- label: string;
921
- } | null;
922
- }>;
1340
+ options: () => Promise<PersonaOptions>;
1341
+ pinProxy: (id: string, proxyId: string | null) => Promise<ProxyPin>;
923
1342
  remove: (id: string) => Promise<void>;
924
- /** Store the second factor for this identity. Sealed at rest, never read back. */
925
- setMfa: (id: string, config: MfaConfig) => Promise<{
926
- configured: boolean;
927
- type: string;
928
- }>;
929
- clearMfa: (id: string, domain?: string) => Promise<void>;
930
- /**
931
- * Store a site login for this identity. Sealed at rest, never read back.
932
- *
933
- * Signing in once on the desktop and inheriting the cookies is still the
934
- * better path. This is for portals that expire a session server-side
935
- * between runs, where an unattended run has nothing else to recover with.
936
- */
937
- setCredentials: (id: string, config: SiteCredentials) => Promise<{
938
- configured: boolean;
939
- domain: string;
940
- username: string;
941
- }>;
942
- /** Which sites this identity can sign in to. Usernames only. */
943
- credentials: (id: string) => Promise<{
944
- credentials: {
945
- domain: string;
946
- username: string;
947
- }[];
948
- }>;
949
- clearCredentials: (id: string, domain: string) => Promise<void>;
1343
+ list: () => Promise<PersonaInfo[]>;
1344
+ get: (id: string) => Promise<PersonaInfo>;
1345
+ create: (options?: PersonaCreate) => Promise<PersonaInfo>;
1346
+ update: (id: string, changes: PersonaUpdate) => Promise<PersonaInfo>;
1347
+ clone: (id: string, options?: CloneOptions) => Promise<PersonaInfo>;
950
1348
  };
1349
+ /** What this key has spent. */
951
1350
  usage(): Promise<unknown>;
1351
+ /** Waits for a starting browser to dial in, through this client's own list and session calls. */
952
1352
  private waitUntilConnected;
953
1353
  }
954
1354
 
955
- export { type Activity, type Analysis, type AttentionRequest, Browser, type BrowserDetail, type BrowserInfo, type CaptchaResult, type CaptchaSolver, type Config, type ConfigUpdate, type ControlCredential, type ControlEvent, type ControlOverview, type ControlRole, type ControlSession, type Element, type FileValue, type Fingerprint, type Health, type HumanInputAction, type LlmProvider, MAX_FILE_BYTES, type MfaConfig, type MfaResult, Oya, OyaError, type OyaOptions, type PersonaInfo, type PersonaPrefs, type PlayResult, type Playbook, type PlaybookSummary, type ProjectSettings, type Provider, type ProxyCreate, type ProxyInfo, Run, type RunData, type RunInfo, type RunResult, type SiteCredentials, type StartOptions, type StartResult, type StopResult, type SubmitOptions, Oya as default, file };
1355
+ export { type Activity, type Analysis, type AnalyzeOptions, type AttentionRequest, type Block, Browser, type BrowserDetail, type BrowserInfo, type CaptchaResult, type CaptchaSolver, type Config, type ConfigUpdate, type ControlCredential, type ControlEvent, type ControlOverview, type ControlRole, type ControlSession, type Element, type FileValue, type Fingerprint, type Health, type HumanInputAction, type LlmProvider, MAX_FILE_BYTES, type MfaConfig, type MfaResult, Oya, OyaError, type OyaOptions, type PageFormat, type PersonaInfo, type PersonaPrefs, type PlayResult, type Playbook, type PlaybookSummary, type ProjectSettings, type Provider, type ProxyCreate, type ProxyInfo, Run, type RunData, type RunInfo, type RunResult, type SiteCredentials, type StartOptions, type StartResult, type StopResult, type SubmitOptions, Oya as default, file };