@oya-ai/browser 1.0.57 โ 1.0.58
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +234 -54
- package/package.json +22 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Oya AI
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,104 +1,284 @@
|
|
|
1
1
|
# @oya-ai/browser
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
<p align="center">
|
|
4
|
+
<strong>Thousands of browsers behind one API: personas, residential proxies, measured stealth, CAPTCHA, and MFA.</strong>
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
<a href="https://www.npmjs.com/package/@oya-ai/browser"><img src="https://img.shields.io/npm/v/@oya-ai/browser?color=39ed35&label=@oya-ai/browser&logo=npm" alt="NPM Version"></a>
|
|
9
|
+
<a href="https://github.com/OyadotAI/oya-browser/blob/main/packages/sdk/LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg?color=39ed35" alt="License: MIT"></a>
|
|
10
|
+
<a href="https://www.typescriptlang.org"><img src="https://img.shields.io/badge/TypeScript-Ready-3178C6.svg?logo=typescript&logoColor=white" alt="TypeScript"></a>
|
|
11
|
+
<a href="https://nodejs.org"><img src="https://img.shields.io/badge/node-%3E%3D18.0.0-brightgreen.svg" alt="Node Version"></a>
|
|
12
|
+
<a href="https://bundlephobia.com/package/@oya-ai/browser"><img src="https://img.shields.io/bundlephobia/minzip/@oya-ai/browser?color=39ed35" alt="Bundle Size"></a>
|
|
13
|
+
</p>
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
Orchestrate browser instances running on **Oya Cloud sandboxes**, **Browserbase**, **Steel**, **Anchor**, **Browser Use**, or your own **private Chrome fleet**.
|
|
18
|
+
|
|
19
|
+
Oya does for browser vendors what OpenRouter does for LLM providers. The vendor behind a browser is a setting on your API key, or one `provider` parameter, so switching vendors never means rewriting your agent.
|
|
4
20
|
|
|
5
21
|
```bash
|
|
6
|
-
npm
|
|
22
|
+
npm install @oya-ai/browser
|
|
7
23
|
```
|
|
8
24
|
|
|
9
|
-
Get an API key at [browser.getoya.ai](https://browser.getoya.ai)
|
|
25
|
+
Get an API key at [browser.getoya.ai](https://browser.getoya.ai) or self-host your control plane, and set `OYA_API_KEY`.
|
|
10
26
|
|
|
11
|
-
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## โก Quickstart
|
|
30
|
+
|
|
31
|
+
### Natural Language Driving
|
|
12
32
|
|
|
13
33
|
```ts
|
|
14
|
-
import { Oya } from
|
|
34
|
+
import { Oya } from "@oya-ai/browser";
|
|
35
|
+
|
|
36
|
+
const oya = new Oya(); // Reads process.env.OYA_API_KEY
|
|
15
37
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
await browser.
|
|
19
|
-
|
|
38
|
+
// Explicit resource management (Node 24+ / TS 5.2+)
|
|
39
|
+
// Stops the browser automatically when the scope exits, even on error
|
|
40
|
+
await using browser = await oya.browser.start({ persona: "auto", captcha: "auto" });
|
|
41
|
+
|
|
42
|
+
await browser.goto("https://news.ycombinator.com");
|
|
43
|
+
const answer = await browser.ask("What are the top 3 stories and their points?");
|
|
44
|
+
console.log(answer);
|
|
20
45
|
```
|
|
21
46
|
|
|
22
|
-
|
|
47
|
+
> **Universal Lifecycle:** If you are not using `await using`, manage lifecycle with `try / finally`:
|
|
48
|
+
> ```ts
|
|
49
|
+
> const browser = await oya.browser.start();
|
|
50
|
+
> try {
|
|
51
|
+
> await browser.goto("https://example.com");
|
|
52
|
+
> } finally {
|
|
53
|
+
> await browser.stop();
|
|
54
|
+
> }
|
|
55
|
+
> ```
|
|
56
|
+
|
|
57
|
+
---
|
|
23
58
|
|
|
24
|
-
## Personas
|
|
59
|
+
## ๐ก๏ธ Deterministic Personas (Anti-Ban Identity)
|
|
25
60
|
|
|
26
|
-
A persona is
|
|
61
|
+
A persona is a permanent, mathematically seeded device identity: **fingerprint + cookie jar + residential proxy**, identical on every run to eliminate bot-farm and device-farm flags.
|
|
27
62
|
|
|
28
63
|
```ts
|
|
29
|
-
import { Oya } from
|
|
64
|
+
import { Oya } from "@oya-ai/browser";
|
|
30
65
|
|
|
31
66
|
const oya = new Oya();
|
|
67
|
+
|
|
68
|
+
// Create a persistent persona
|
|
32
69
|
const persona = await oya.personas.create({
|
|
33
|
-
name:
|
|
34
|
-
prefs: { platform:
|
|
35
|
-
proxy: { geo:
|
|
70
|
+
name: "us-shopper",
|
|
71
|
+
prefs: { platform: "MacIntel", timezone: "America/New_York", locale: "en-US" },
|
|
72
|
+
proxy: { geo: "US" },
|
|
73
|
+
maxConcurrent: 2, // Concurrency cap prevents device-farm detection
|
|
36
74
|
});
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
75
|
+
|
|
76
|
+
// Launch a browser with this persona (or persona: 'auto' for least-recently-used)
|
|
77
|
+
await using browser = await oya.browser.start({ persona: persona.id });
|
|
78
|
+
await browser.goto("https://www.amazon.com");
|
|
79
|
+
|
|
80
|
+
// Hardware attributes remain byte-identical on subsequent sessions
|
|
81
|
+
console.log(persona.fingerprint.platform, persona.fingerprint.timezone);
|
|
82
|
+
|
|
83
|
+
// Need another device of the same class? Clone it with an empty cookie jar:
|
|
84
|
+
// const altDevice = await oya.personas.clone(persona.id, { name: "us-shopper-02" });
|
|
40
85
|
```
|
|
41
86
|
|
|
42
|
-
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## ๐ง Structured Agent Analysis & Interaction
|
|
43
90
|
|
|
44
|
-
|
|
91
|
+
Skip messy DOM traversal. Get clean markdown and numbered interactive elements:
|
|
45
92
|
|
|
46
93
|
```ts
|
|
47
|
-
import { Oya } from
|
|
94
|
+
import { Oya } from "@oya-ai/browser";
|
|
48
95
|
|
|
49
96
|
const oya = new Oya();
|
|
50
|
-
await using browser = await oya.browser.start();
|
|
51
|
-
await browser.goto(
|
|
52
|
-
|
|
97
|
+
await using browser = await oya.browser.start();
|
|
98
|
+
await browser.goto("https://github.com/trending");
|
|
99
|
+
|
|
100
|
+
// Analyze page: returns markdown and visible numbered elements
|
|
101
|
+
const { markdown, elements } = await browser.analyze();
|
|
102
|
+
console.log(markdown.slice(0, 300));
|
|
103
|
+
|
|
104
|
+
// Interact using numbered element IDs:
|
|
105
|
+
const firstRepo = elements.find((el) => el.tag === "a" && el.href?.includes("/stargazers"));
|
|
106
|
+
if (firstRepo) {
|
|
107
|
+
await browser.click(firstRepo.id); // clicks [data-ac-id="firstRepo.id"]
|
|
108
|
+
}
|
|
53
109
|
```
|
|
54
110
|
|
|
55
|
-
|
|
111
|
+
---
|
|
56
112
|
|
|
57
|
-
|
|
113
|
+
## ๐งฉ Challenge Handling: Automated CAPTCHA & Sealed MFA
|
|
58
114
|
|
|
59
115
|
```ts
|
|
60
|
-
import { Oya } from
|
|
116
|
+
import { Oya } from "@oya-ai/browser";
|
|
61
117
|
|
|
62
118
|
const oya = new Oya();
|
|
63
|
-
|
|
64
|
-
|
|
119
|
+
|
|
120
|
+
// 1. Seal a TOTP secret on a persona (encrypted with AES-256-GCM at rest, never exposed over API)
|
|
121
|
+
const persona = await oya.personas.create({ name: "finance-admin" });
|
|
122
|
+
await oya.personas.setMfa(persona.id, {
|
|
123
|
+
type: "totp",
|
|
124
|
+
secret: process.env.TOTP_SECRET!,
|
|
125
|
+
});
|
|
65
126
|
|
|
66
127
|
await using browser = await oya.browser.start({ persona: persona.id });
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
128
|
+
|
|
129
|
+
// 2. Clear CAPTCHAs automatically (uses vendor solver or CapSolver/2Captcha fallback)
|
|
130
|
+
await browser.goto("https://www.google.com/recaptcha/api2/demo");
|
|
131
|
+
const captcha = await browser.solveCaptcha();
|
|
132
|
+
console.log("CAPTCHA Solved:", captcha.solved, "via", captcha.method);
|
|
133
|
+
|
|
134
|
+
// 3. Complete Two-Factor Authentication
|
|
135
|
+
await browser.goto(process.env.MFA_LOGIN_URL!);
|
|
136
|
+
const mfa = await browser.completeMfa();
|
|
137
|
+
|
|
138
|
+
if (!mfa.completed && mfa.liveViewUrl) {
|
|
139
|
+
// Hand off to human operator if interactive push notification or WebAuthn is needed
|
|
140
|
+
console.log("Interactive handoff required at:", mfa.liveViewUrl);
|
|
141
|
+
}
|
|
70
142
|
```
|
|
71
143
|
|
|
72
|
-
|
|
144
|
+
---
|
|
73
145
|
|
|
74
|
-
|
|
146
|
+
## ๐ Universal CDP Gateway (Playwright & Puppeteer)
|
|
147
|
+
|
|
148
|
+
Every browser exposes an authenticated `browser.cdpUrl` routed through Oya's gateway. Connect standard Playwright, Puppeteer, or Stagehand:
|
|
75
149
|
|
|
76
150
|
```ts
|
|
77
|
-
import { chromium } from
|
|
78
|
-
import { Oya } from
|
|
151
|
+
import { chromium } from "playwright-core";
|
|
152
|
+
import { Oya } from "@oya-ai/browser";
|
|
79
153
|
|
|
80
154
|
const oya = new Oya();
|
|
81
|
-
|
|
155
|
+
|
|
156
|
+
// Run on any underlying provider: browserbase, steel, anchor, browseruse, or oya-cloud
|
|
157
|
+
await using browser = await oya.browser.start({ provider: "browserbase" });
|
|
158
|
+
|
|
159
|
+
// Connect Playwright directly over Oya's gateway
|
|
82
160
|
const context = (await chromium.connectOverCDP(browser.cdpUrl!)).contexts()[0];
|
|
83
|
-
const page = context.pages()[0] ?? await context.newPage();
|
|
84
|
-
|
|
85
|
-
|
|
161
|
+
const page = context.pages()[0] ?? (await context.newPage());
|
|
162
|
+
|
|
163
|
+
await page.goto("https://news.ycombinator.com");
|
|
164
|
+
console.log("Page Title:", await page.title());
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## ๐ Complete API Reference
|
|
170
|
+
|
|
171
|
+
### Initialization
|
|
172
|
+
|
|
173
|
+
```ts
|
|
174
|
+
import { Oya } from "@oya-ai/browser";
|
|
175
|
+
|
|
176
|
+
const oya = new Oya({
|
|
177
|
+
apiKey: "oya_...", // default: process.env.OYA_API_KEY
|
|
178
|
+
baseUrl: "https://browser.getoya.ai", // default: OYA_BASE_URL, then the hosted service
|
|
179
|
+
timeoutMs: 60_000, // per request
|
|
180
|
+
// fetch: customFetch, // any fetch-compatible implementation
|
|
181
|
+
});
|
|
86
182
|
```
|
|
87
183
|
|
|
88
|
-
|
|
184
|
+
### Browser Operations (`oya.browser`)
|
|
185
|
+
|
|
186
|
+
| Method | Signature | Description |
|
|
187
|
+
|:---|:---|:---|
|
|
188
|
+
| `start(options)` | `(options?: StartOptions) => Promise<Browser>` | Start a browser and wait until it is ready for commands |
|
|
189
|
+
| `get(id)` | `(id: string) => Promise<Browser>` | Reattach to an existing running browser |
|
|
190
|
+
| `list()` | `() => Promise<BrowserInfo[]>` | List all active running browser sessions |
|
|
191
|
+
| `stop(ids \| 'all')` | `(ids: string[] \| 'all') => Promise<{ stopped: number; results: StopResult[] }>` | Stop target browsers or all browsers |
|
|
192
|
+
| `stopAll()` | `() => Promise<number>` | Terminate all active browser sessions |
|
|
193
|
+
|
|
194
|
+
#### `StartOptions`
|
|
195
|
+
|
|
196
|
+
- `persona?: 'default' | 'auto' | string` โ Assign persistent identity
|
|
197
|
+
- `provider?: 'oya-cloud' | 'oya-selfhosted' | 'browserbase' | 'steel' | 'anchor' | 'browseruse' | 'cdp'`
|
|
198
|
+
- `wsUrl?: string`: required only for the `'cdp'` provider
|
|
199
|
+
- `name?: string`: display name in the console and `oya ls`
|
|
200
|
+
- `captcha?: 'auto' | 'off'` โ Automatically solve CAPTCHAs on navigation
|
|
201
|
+
- `queueMs?: number` โ Wait duration for fleet capacity (ms)
|
|
202
|
+
- `budgetUsd?: number` โ Enforce budget limit for session
|
|
203
|
+
- `idempotencyKey?: string` โ Safe retry token
|
|
204
|
+
- `governed?: boolean` โ Enforce strict isolation policies
|
|
89
205
|
|
|
90
|
-
|
|
206
|
+
### Browser Instance Methods (`browser.*`)
|
|
207
|
+
|
|
208
|
+
| Method | Returns | Description |
|
|
209
|
+
|:---|:---|:---|
|
|
210
|
+
| `goto(url)` | `Promise<void>` | Navigate to URL (with optional auto-CAPTCHA) |
|
|
211
|
+
| `ask(prompt)` | `Promise<string>` | Natural-language AI driving using key's configured model |
|
|
212
|
+
| `analyze()` | `Promise<Analysis>` | Returns markdown representation and numbered elements |
|
|
213
|
+
| `elements()` | `Promise<Element[]>` | Returns only visible interactable elements |
|
|
214
|
+
| `click(elementId)` | `Promise<void>` | Click element by numeric ID from `analyze()` |
|
|
215
|
+
| `type(elementId, text)` | `Promise<{ suggestions_visible?: boolean }>` | Type text into specified element |
|
|
216
|
+
| `pressKey(key)` | `Promise<void>` | Dispatch keyboard key event (e.g. `'Enter'`) |
|
|
217
|
+
| `scroll(dir, amount?, at?)` | `Promise<void>` | Scroll `'up' \| 'down' \| 'top' \| 'bottom'` |
|
|
218
|
+
| `waitFor(selector, timeout?)`| `Promise<void>` | Wait for DOM selector |
|
|
219
|
+
| `screenshot()` | `Promise<string>` | Capture page as base64 image data URL |
|
|
220
|
+
| `url()` | `Promise<string>` | Current active tab URL |
|
|
221
|
+
| `tabs()` | `Promise<Tab[]>` | List open tabs |
|
|
222
|
+
| `openTab(url?)` | `Promise<string>` | Open a new tab |
|
|
223
|
+
| `switchTab(tabId)` | `Promise<void>` | Switch active tab |
|
|
224
|
+
| `closeTab(tabId)` | `Promise<void>` | Close target tab |
|
|
225
|
+
| `solveCaptcha()` | `Promise<CaptchaResult>` | Detect and solve on-screen CAPTCHA |
|
|
226
|
+
| `completeMfa()` | `Promise<MfaResult>` | Resolve TOTP/SMS MFA or return `liveViewUrl` |
|
|
227
|
+
| `liveViewUrl()` | `string` | SSE JPEG stream URL for sub-second human takeover |
|
|
228
|
+
| `status()` | `Promise<BrowserDetail>` | Instance metrics, health, and recent activity log |
|
|
229
|
+
| `stop()` | `Promise<StopResult>` | Tear down sandbox and release CDP session |
|
|
230
|
+
|
|
231
|
+
### Persona Management (`oya.personas`)
|
|
232
|
+
|
|
233
|
+
| Method | Description |
|
|
234
|
+
|:---|:---|
|
|
235
|
+
| `create({ name?, prefs?, proxy?, maxConcurrent? })` | Create new deterministic device identity |
|
|
236
|
+
| `list()` | List all saved personas and active concurrency |
|
|
237
|
+
| `get(id)` | Get persona profile details |
|
|
238
|
+
| `update(id, changes)` | Update name, concurrency limit, or proxy geo |
|
|
239
|
+
| `clone(id, options)` | Create fresh persona with same device traits but empty cookie jar |
|
|
240
|
+
| `preview(prefs)` | Preview generated hardware fingerprint before creating |
|
|
241
|
+
| `options()` | Available platforms, timezones, and valid locales |
|
|
242
|
+
| `pinProxy(id, proxyId)` | Bind persona permanently to a residential proxy exit node |
|
|
243
|
+
| `remove(id)` | Delete persona and associated cookie jar |
|
|
244
|
+
| `setMfa(id, config)` | Store TOTP secret (sealed at rest with AES-256-GCM) |
|
|
245
|
+
| `clearMfa(id)` | Remove MFA secret from persona |
|
|
246
|
+
|
|
247
|
+
### Durable Governance & Control (`oya.control`)
|
|
248
|
+
|
|
249
|
+
| Method | Description |
|
|
250
|
+
|:---|:---|
|
|
251
|
+
| `overview()` | Fleet overview, spend, sessions, and active rate cards |
|
|
252
|
+
| `sessions()` | List all durable sessions (including cleanup-pending) |
|
|
253
|
+
| `session(id)` | Get detailed session execution state |
|
|
254
|
+
| `takeover(id, 'acquire' \| 'release' \| 'resume')` | Manage human control leases |
|
|
255
|
+
| `ticket(id)` | Generate single-use connection ticket for secure handoff |
|
|
256
|
+
| `events(after?)` | Stream append-only audit event log |
|
|
257
|
+
| `createCredential(options)` | Mint scoped service credential (`viewer` / `operator` / `administrator`) |
|
|
258
|
+
| `createWebhook(url, types)` | Register HMAC-signed webhook for fleet lifecycle events |
|
|
259
|
+
|
|
260
|
+
---
|
|
261
|
+
|
|
262
|
+
## ๐จ Error Handling
|
|
263
|
+
|
|
264
|
+
All failed API and command operations throw an `OyaError`:
|
|
265
|
+
|
|
266
|
+
```ts
|
|
267
|
+
import { Oya, OyaError } from "@oya-ai/browser";
|
|
268
|
+
|
|
269
|
+
try {
|
|
270
|
+
const oya = new Oya();
|
|
271
|
+
await oya.browser.start({ persona: "invalid-id" });
|
|
272
|
+
} catch (err) {
|
|
273
|
+
if (err instanceof OyaError) {
|
|
274
|
+
console.error(`Oya API Error (${err.status}):`, err.message);
|
|
275
|
+
console.error("Payload:", err.body);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
```
|
|
91
279
|
|
|
92
|
-
|
|
93
|
-
|---|---|
|
|
94
|
-
| `new Oya({ apiKey?, baseUrl?, timeoutMs? })` | Defaults to `OYA_API_KEY` and `OYA_BASE_URL` |
|
|
95
|
-
| `oya.browser` | `start(options)`, `get(id)`, `list()`, `stop(ids \| 'all')`, `stopAll()` |
|
|
96
|
-
| `browser` | `goto`, `ask`, `analyze`, `elements`, `click`, `type`, `pressKey`, `scroll`, `waitFor`, `screenshot`, `url`, `tabs`, `openTab`, `switchTab`, `closeTab`, `solveCaptcha`, `completeMfa`, `liveViewUrl`, `status`, `stop`, `cdpUrl` |
|
|
97
|
-
| `oya.personas` | `list`, `get`, `create`, `update`, `clone`, `preview`, `options`, `pinProxy`, `remove`, `setMfa`, `clearMfa` |
|
|
98
|
-
| `oya.config` | `get()`, `set(values)`: model, provider and solver keys for this API key |
|
|
99
|
-
| `oya.control` | Sessions, human takeover, events, members, credentials and webhooks |
|
|
100
|
-
| `oya.usage()` | What this key has spent |
|
|
280
|
+
---
|
|
101
281
|
|
|
102
|
-
|
|
282
|
+
## ๐ License
|
|
103
283
|
|
|
104
|
-
|
|
284
|
+
MIT ยฉ [Oya](https://getoya.ai)
|
package/package.json
CHANGED
|
@@ -1,8 +1,29 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oya-ai/browser",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.58",
|
|
4
4
|
"description": "Rotate thousands of browsers behind one API โ personas, proxies, stealth, CAPTCHA and MFA.",
|
|
5
5
|
"license": "MIT",
|
|
6
|
+
"homepage": "https://browser.getoya.ai",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/OyadotAI/oya-browser.git",
|
|
10
|
+
"directory": "packages/sdk"
|
|
11
|
+
},
|
|
12
|
+
"bugs": "https://github.com/OyadotAI/oya-browser/issues",
|
|
13
|
+
"keywords": [
|
|
14
|
+
"browser",
|
|
15
|
+
"ai-agents",
|
|
16
|
+
"cdp",
|
|
17
|
+
"playwright",
|
|
18
|
+
"puppeteer",
|
|
19
|
+
"headless-chrome",
|
|
20
|
+
"browserbase",
|
|
21
|
+
"steel",
|
|
22
|
+
"browser-use",
|
|
23
|
+
"captcha",
|
|
24
|
+
"fingerprint",
|
|
25
|
+
"mcp"
|
|
26
|
+
],
|
|
6
27
|
"type": "module",
|
|
7
28
|
"main": "./dist/index.cjs",
|
|
8
29
|
"module": "./dist/index.js",
|