@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 +17 -0
- package/dist/index.cjs +36 -0
- package/dist/index.d.cts +67 -1
- package/dist/index.d.ts +67 -1
- package/dist/index.js +36 -0
- package/package.json +1 -1
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