@oya-ai/browser 1.0.96 → 1.0.99

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