@oya-ai/browser 1.0.70 → 1.0.73

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/README.md CHANGED
@@ -244,6 +244,23 @@ const oya = new Oya({
244
244
  | `setMfa(id, config)` | Store TOTP secret (sealed at rest with AES-256-GCM) |
245
245
  | `clearMfa(id)` | Remove MFA secret from persona |
246
246
 
247
+ ### Proxies (`oya.proxies`)
248
+
249
+ | Method | Description |
250
+ |:---|:---|
251
+ | `create({ url, label?, geo?, kind?, maxPersonas? })` | Add a proxy from your vendor. Credentials are encrypted and never returned |
252
+ | `list()` | Your proxies and shared ones, with exit IP, health and how many personas use each |
253
+ | `check()` | Dial every proxy and record its real exit IP |
254
+ | `remove(id)` | Delete a proxy and unpin the personas on it |
255
+
256
+ ```ts
257
+ const proxy = await oya.proxies.create({
258
+ url: "http://user:pass_session-shopper1@gate.vendor.com:7000", // one sticky session per persona
259
+ label: "us-shopper-1", geo: "US", kind: "residential", maxPersonas: 1,
260
+ });
261
+ await oya.personas.pinProxy(persona.id, proxy.id);
262
+ ```
263
+
247
264
  ### Durable Governance & Control (`oya.control`)
248
265
 
249
266
  | Method | Description |
package/dist/index.cjs CHANGED
@@ -223,6 +223,29 @@ var Browser = class {
223
223
  );
224
224
  return `${this.http.baseUrl}/api/live/${this.id}?ticket=${encodeURIComponent(ticket)}`;
225
225
  }
226
+ /**
227
+ * A shareable link to this browser's live view, for handing to a person or
228
+ * embedding in your own app. The token rides in the URL fragment, so it never
229
+ * reaches a server log or Referer header. `control: true` lets whoever opens
230
+ * it take over and act in the browser; otherwise it is view-only. The link
231
+ * expires (default one hour) and is revocable with `revokeShare(id)`.
232
+ *
233
+ * The credential is scoped to this one browser: it cannot see or touch the
234
+ * rest of your project. Anyone holding the link has that access until it
235
+ * expires or you revoke it, so treat it like a password.
236
+ */
237
+ async shareUrl({ control = false, expiresInSeconds = 3600 } = {}) {
238
+ const c = await this.http.request(
239
+ "POST",
240
+ `/api/control/sessions/${encodeURIComponent(this.id)}/share`,
241
+ { control, expiresIn: expiresInSeconds }
242
+ );
243
+ return { url: `${this.http.baseUrl}/live/${encodeURIComponent(this.id)}#t=${encodeURIComponent(c.token)}`, id: c.id, expiresAt: c.expiresAt };
244
+ }
245
+ /** Revoke a link from `shareUrl()` before it expires, by the id it returned. */
246
+ async revokeShare(id) {
247
+ await this.http.request("DELETE", `/api/control/credentials/${encodeURIComponent(id)}`);
248
+ }
226
249
  /** Counters, health and the last 50 things this browser did. */
227
250
  status() {
228
251
  return this.http.request("GET", `/api/browsers/${this.id}`);
@@ -319,6 +342,19 @@ var Oya = class {
319
342
  removeWebhook: (id) => this.http.request("DELETE", `/api/control/webhooks/${encodeURIComponent(id)}`),
320
343
  replayDelivery: (id) => this.http.request("POST", `/api/control/deliveries/${encodeURIComponent(id)}/replay`, {})
321
344
  };
345
+ /**
346
+ * Proxy exits for your personas. A persona takes one at first connect (by its
347
+ * geo hint) or by `personas.pinProxy`, and keeps it.
348
+ */
349
+ proxies = {
350
+ list: async () => (await this.http.request("GET", "/api/proxies")).proxies,
351
+ create: (proxy) => this.http.request("POST", "/api/proxies", proxy),
352
+ remove: async (id) => {
353
+ await this.http.request("DELETE", `/api/proxies/${encodeURIComponent(id)}`);
354
+ },
355
+ /** Dial each proxy and learn its real exit IP. Failing ones cool down and are skipped. */
356
+ check: async () => (await this.http.request("POST", "/api/proxies/check", {})).results
357
+ };
322
358
  personas = {
323
359
  list: async () => (await this.http.request("GET", "/api/personas")).personas,
324
360
  get: (id) => this.http.request("GET", `/api/personas/${id}`),
package/dist/index.d.cts CHANGED
@@ -126,6 +126,35 @@ interface PersonaPrefs {
126
126
  timezone?: string;
127
127
  locale?: string;
128
128
  }
129
+ /** A proxy exit. Credentials go in on create and never come back out. */
130
+ interface ProxyInfo {
131
+ id: string;
132
+ label: string;
133
+ kind: 'residential' | 'datacenter';
134
+ /** Two-letter country, optionally a region: "US", "US-CA". */
135
+ geo: string | null;
136
+ /** Provided by the host rather than this key. Cannot be removed. */
137
+ shared: boolean;
138
+ healthy: boolean;
139
+ /** Healthy and not cooling down after a failure. */
140
+ available: boolean;
141
+ /** Where traffic actually leaves, as of the last check. */
142
+ exitIp: string | null;
143
+ lastCheckedAt: string | null;
144
+ /** Personas on it now, out of `maxPersonas`. */
145
+ assigned: number;
146
+ maxPersonas: number;
147
+ cooldownMsRemaining: number;
148
+ }
149
+ interface ProxyCreate {
150
+ /** http(s)://user:pass@host:port from your vendor. Chromium cannot use SOCKS5 with a password. */
151
+ url: string;
152
+ label?: string;
153
+ geo?: string;
154
+ kind?: 'residential' | 'datacenter';
155
+ /** Personas that may share it. Keep 1 for a sticky-session URL so each keeps its own IP. */
156
+ maxPersonas?: number;
157
+ }
129
158
  interface PersonaInfo {
130
159
  id: string;
131
160
  name: string;
@@ -349,6 +378,27 @@ declare class Browser {
349
378
  * 60 seconds. Mint one per viewer — the first connection spends it.
350
379
  */
351
380
  liveStreamUrl(): Promise<string>;
381
+ /**
382
+ * A shareable link to this browser's live view, for handing to a person or
383
+ * embedding in your own app. The token rides in the URL fragment, so it never
384
+ * reaches a server log or Referer header. `control: true` lets whoever opens
385
+ * it take over and act in the browser; otherwise it is view-only. The link
386
+ * expires (default one hour) and is revocable with `revokeShare(id)`.
387
+ *
388
+ * The credential is scoped to this one browser: it cannot see or touch the
389
+ * rest of your project. Anyone holding the link has that access until it
390
+ * expires or you revoke it, so treat it like a password.
391
+ */
392
+ shareUrl({ control, expiresInSeconds }?: {
393
+ control?: boolean;
394
+ expiresInSeconds?: number;
395
+ }): Promise<{
396
+ url: string;
397
+ id: string;
398
+ expiresAt: number | null;
399
+ }>;
400
+ /** Revoke a link from `shareUrl()` before it expires, by the id it returned. */
401
+ revokeShare(id: string): Promise<void>;
352
402
  /** Counters, health and the last 50 things this browser did. */
353
403
  status(): Promise<BrowserDetail>;
354
404
  /**
@@ -446,6 +496,22 @@ declare class Oya {
446
496
  ok: boolean;
447
497
  }>;
448
498
  };
499
+ /**
500
+ * Proxy exits for your personas. A persona takes one at first connect (by its
501
+ * geo hint) or by `personas.pinProxy`, and keeps it.
502
+ */
503
+ readonly proxies: {
504
+ list: () => Promise<ProxyInfo[]>;
505
+ create: (proxy: ProxyCreate) => Promise<ProxyInfo>;
506
+ remove: (id: string) => Promise<void>;
507
+ /** Dial each proxy and learn its real exit IP. Failing ones cool down and are skipped. */
508
+ check: () => Promise<Array<{
509
+ id: string;
510
+ ok: boolean;
511
+ exitIp?: string | null;
512
+ error?: string;
513
+ }>>;
514
+ };
449
515
  readonly personas: {
450
516
  list: () => Promise<PersonaInfo[]>;
451
517
  get: (id: string) => Promise<PersonaInfo>;
@@ -558,4 +624,4 @@ declare class Oya {
558
624
  private waitUntilConnected;
559
625
  }
560
626
 
561
- export { type Activity, type Analysis, Browser, type BrowserDetail, type BrowserInfo, type CaptchaResult, type ControlCredential, type ControlEvent, type ControlOverview, type ControlRole, type ControlSession, type Element, type Fingerprint, type Health, type HumanInputAction, type MfaConfig, type MfaResult, Oya, OyaError, type OyaOptions, type PersonaInfo, type PersonaPrefs, type ProjectSettings, type Provider, type StartOptions, type StartResult, type StopResult, Oya as default };
627
+ export { type Activity, type Analysis, Browser, type BrowserDetail, type BrowserInfo, type CaptchaResult, type ControlCredential, type ControlEvent, type ControlOverview, type ControlRole, type ControlSession, type Element, type Fingerprint, type Health, type HumanInputAction, type MfaConfig, type MfaResult, Oya, OyaError, type OyaOptions, type PersonaInfo, type PersonaPrefs, type ProjectSettings, type Provider, type ProxyCreate, type ProxyInfo, type StartOptions, type StartResult, type StopResult, Oya as default };
package/dist/index.d.ts CHANGED
@@ -126,6 +126,35 @@ interface PersonaPrefs {
126
126
  timezone?: string;
127
127
  locale?: string;
128
128
  }
129
+ /** A proxy exit. Credentials go in on create and never come back out. */
130
+ interface ProxyInfo {
131
+ id: string;
132
+ label: string;
133
+ kind: 'residential' | 'datacenter';
134
+ /** Two-letter country, optionally a region: "US", "US-CA". */
135
+ geo: string | null;
136
+ /** Provided by the host rather than this key. Cannot be removed. */
137
+ shared: boolean;
138
+ healthy: boolean;
139
+ /** Healthy and not cooling down after a failure. */
140
+ available: boolean;
141
+ /** Where traffic actually leaves, as of the last check. */
142
+ exitIp: string | null;
143
+ lastCheckedAt: string | null;
144
+ /** Personas on it now, out of `maxPersonas`. */
145
+ assigned: number;
146
+ maxPersonas: number;
147
+ cooldownMsRemaining: number;
148
+ }
149
+ interface ProxyCreate {
150
+ /** http(s)://user:pass@host:port from your vendor. Chromium cannot use SOCKS5 with a password. */
151
+ url: string;
152
+ label?: string;
153
+ geo?: string;
154
+ kind?: 'residential' | 'datacenter';
155
+ /** Personas that may share it. Keep 1 for a sticky-session URL so each keeps its own IP. */
156
+ maxPersonas?: number;
157
+ }
129
158
  interface PersonaInfo {
130
159
  id: string;
131
160
  name: string;
@@ -349,6 +378,27 @@ declare class Browser {
349
378
  * 60 seconds. Mint one per viewer — the first connection spends it.
350
379
  */
351
380
  liveStreamUrl(): Promise<string>;
381
+ /**
382
+ * A shareable link to this browser's live view, for handing to a person or
383
+ * embedding in your own app. The token rides in the URL fragment, so it never
384
+ * reaches a server log or Referer header. `control: true` lets whoever opens
385
+ * it take over and act in the browser; otherwise it is view-only. The link
386
+ * expires (default one hour) and is revocable with `revokeShare(id)`.
387
+ *
388
+ * The credential is scoped to this one browser: it cannot see or touch the
389
+ * rest of your project. Anyone holding the link has that access until it
390
+ * expires or you revoke it, so treat it like a password.
391
+ */
392
+ shareUrl({ control, expiresInSeconds }?: {
393
+ control?: boolean;
394
+ expiresInSeconds?: number;
395
+ }): Promise<{
396
+ url: string;
397
+ id: string;
398
+ expiresAt: number | null;
399
+ }>;
400
+ /** Revoke a link from `shareUrl()` before it expires, by the id it returned. */
401
+ revokeShare(id: string): Promise<void>;
352
402
  /** Counters, health and the last 50 things this browser did. */
353
403
  status(): Promise<BrowserDetail>;
354
404
  /**
@@ -446,6 +496,22 @@ declare class Oya {
446
496
  ok: boolean;
447
497
  }>;
448
498
  };
499
+ /**
500
+ * Proxy exits for your personas. A persona takes one at first connect (by its
501
+ * geo hint) or by `personas.pinProxy`, and keeps it.
502
+ */
503
+ readonly proxies: {
504
+ list: () => Promise<ProxyInfo[]>;
505
+ create: (proxy: ProxyCreate) => Promise<ProxyInfo>;
506
+ remove: (id: string) => Promise<void>;
507
+ /** Dial each proxy and learn its real exit IP. Failing ones cool down and are skipped. */
508
+ check: () => Promise<Array<{
509
+ id: string;
510
+ ok: boolean;
511
+ exitIp?: string | null;
512
+ error?: string;
513
+ }>>;
514
+ };
449
515
  readonly personas: {
450
516
  list: () => Promise<PersonaInfo[]>;
451
517
  get: (id: string) => Promise<PersonaInfo>;
@@ -558,4 +624,4 @@ declare class Oya {
558
624
  private waitUntilConnected;
559
625
  }
560
626
 
561
- export { type Activity, type Analysis, Browser, type BrowserDetail, type BrowserInfo, type CaptchaResult, type ControlCredential, type ControlEvent, type ControlOverview, type ControlRole, type ControlSession, type Element, type Fingerprint, type Health, type HumanInputAction, type MfaConfig, type MfaResult, Oya, OyaError, type OyaOptions, type PersonaInfo, type PersonaPrefs, type ProjectSettings, type Provider, type StartOptions, type StartResult, type StopResult, Oya as default };
627
+ export { type Activity, type Analysis, Browser, type BrowserDetail, type BrowserInfo, type CaptchaResult, type ControlCredential, type ControlEvent, type ControlOverview, type ControlRole, type ControlSession, type Element, type Fingerprint, type Health, type HumanInputAction, type MfaConfig, type MfaResult, Oya, OyaError, type OyaOptions, type PersonaInfo, type PersonaPrefs, type ProjectSettings, type Provider, type ProxyCreate, type ProxyInfo, type StartOptions, type StartResult, type StopResult, Oya as default };
package/dist/index.js CHANGED
@@ -194,6 +194,29 @@ var Browser = class {
194
194
  );
195
195
  return `${this.http.baseUrl}/api/live/${this.id}?ticket=${encodeURIComponent(ticket)}`;
196
196
  }
197
+ /**
198
+ * A shareable link to this browser's live view, for handing to a person or
199
+ * embedding in your own app. The token rides in the URL fragment, so it never
200
+ * reaches a server log or Referer header. `control: true` lets whoever opens
201
+ * it take over and act in the browser; otherwise it is view-only. The link
202
+ * expires (default one hour) and is revocable with `revokeShare(id)`.
203
+ *
204
+ * The credential is scoped to this one browser: it cannot see or touch the
205
+ * rest of your project. Anyone holding the link has that access until it
206
+ * expires or you revoke it, so treat it like a password.
207
+ */
208
+ async shareUrl({ control = false, expiresInSeconds = 3600 } = {}) {
209
+ const c = await this.http.request(
210
+ "POST",
211
+ `/api/control/sessions/${encodeURIComponent(this.id)}/share`,
212
+ { control, expiresIn: expiresInSeconds }
213
+ );
214
+ return { url: `${this.http.baseUrl}/live/${encodeURIComponent(this.id)}#t=${encodeURIComponent(c.token)}`, id: c.id, expiresAt: c.expiresAt };
215
+ }
216
+ /** Revoke a link from `shareUrl()` before it expires, by the id it returned. */
217
+ async revokeShare(id) {
218
+ await this.http.request("DELETE", `/api/control/credentials/${encodeURIComponent(id)}`);
219
+ }
197
220
  /** Counters, health and the last 50 things this browser did. */
198
221
  status() {
199
222
  return this.http.request("GET", `/api/browsers/${this.id}`);
@@ -290,6 +313,19 @@ var Oya = class {
290
313
  removeWebhook: (id) => this.http.request("DELETE", `/api/control/webhooks/${encodeURIComponent(id)}`),
291
314
  replayDelivery: (id) => this.http.request("POST", `/api/control/deliveries/${encodeURIComponent(id)}/replay`, {})
292
315
  };
316
+ /**
317
+ * Proxy exits for your personas. A persona takes one at first connect (by its
318
+ * geo hint) or by `personas.pinProxy`, and keeps it.
319
+ */
320
+ proxies = {
321
+ list: async () => (await this.http.request("GET", "/api/proxies")).proxies,
322
+ create: (proxy) => this.http.request("POST", "/api/proxies", proxy),
323
+ remove: async (id) => {
324
+ await this.http.request("DELETE", `/api/proxies/${encodeURIComponent(id)}`);
325
+ },
326
+ /** Dial each proxy and learn its real exit IP. Failing ones cool down and are skipped. */
327
+ check: async () => (await this.http.request("POST", "/api/proxies/check", {})).results
328
+ };
293
329
  personas = {
294
330
  list: async () => (await this.http.request("GET", "/api/personas")).personas,
295
331
  get: (id) => this.http.request("GET", `/api/personas/${id}`),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oya-ai/browser",
3
- "version": "1.0.70",
3
+ "version": "1.0.73",
4
4
  "description": "Rotate thousands of browsers behind one API — personas, proxies, stealth, CAPTCHA and MFA.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://browser.getoya.ai",