capiumbrowser 0.1.0

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 ADDED
@@ -0,0 +1,38 @@
1
+ Capzy capiumbrowser SDK License
2
+
3
+ Copyright (c) Capzy. All rights reserved.
4
+
5
+ 1. Definitions.
6
+ "SDK" means this Python package ("capiumbrowser"), its source, and its
7
+ documentation. "Browser Binary" means the Capium stealth Chromium build that
8
+ the SDK downloads and launches. "License Key" means a key issued by Capzy that
9
+ entitles you to run the Browser Binary.
10
+
11
+ 2. The SDK.
12
+ Capzy grants you a non-exclusive, non-transferable, royalty-free license to
13
+ install and use the SDK to launch the Browser Binary, and to modify the SDK for
14
+ your own internal use. You may not remove or alter this notice.
15
+
16
+ 3. The Browser Binary is licensed separately.
17
+ Use of the Browser Binary requires a valid License Key and is governed by the
18
+ Capzy Terms of Service. The Browser Binary is enforced per concurrent session;
19
+ see the documentation. Nothing in this SDK license grants any right to use the
20
+ Browser Binary without a valid License Key.
21
+
22
+ 4. Restrictions.
23
+ You may not sublicense, resell, or redistribute the Browser Binary. You may not
24
+ use the SDK or the Browser Binary to violate any applicable law or the rights of
25
+ any third party. You are responsible for using the software only where you are
26
+ authorized to do so.
27
+
28
+ 5. No warranty.
29
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
31
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
32
+
33
+ 6. Limitation of liability.
34
+ IN NO EVENT SHALL CAPZY BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY,
35
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
36
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
37
+
38
+ For licensing inquiries, visit https://capzy.ai.
package/README.md ADDED
@@ -0,0 +1,174 @@
1
+ <h3 align="center">Capium — a stealth Chromium built to withstand bot detection, for Node.js.</h3>
2
+
3
+ <p align="center">
4
+ <a href="https://capiumbrowser.com">capiumbrowser.com</a> ·
5
+ <a href="https://docs.capiumbrowser.com">Documentation</a> ·
6
+ <a href="https://capiumbrowser.com/#pricing">Pricing</a> ·
7
+ <a href="https://github.com/capzy-ai/capiumbrowser">Product overview</a> ·
8
+ <a href="https://pypi.org/project/capiumbrowser/">Python SDK</a>
9
+ </p>
10
+
11
+ ---
12
+
13
+ Not a patched config. Not a JavaScript injection. A real Chromium binary whose fingerprints are
14
+ rewritten at the **C++ source level** and compiled in. Page scripts that hunt for injected hooks
15
+ find nothing to catch — the values a site reads *are* the persona's values, produced by the
16
+ engine. Drive it with the **Playwright** or **Puppeteer** API you already know.
17
+
18
+ ## Install
19
+
20
+ ```bash
21
+ # With Playwright
22
+ npm install capiumbrowser playwright-core
23
+
24
+ # With Puppeteer
25
+ npm install capiumbrowser puppeteer-core
26
+ ```
27
+
28
+ The driver is a normal peer dependency, so you update the engine independently
29
+ (`npm install -U playwright-core`). You do **not** run `npx playwright install chromium` —
30
+ Capium ships its own binary. On first launch the SDK fetches the per-platform build from the
31
+ license service (authenticated, checksum-verified) and caches it under `~/.capium`
32
+ (`CAPIUM_HOME` overrides).
33
+
34
+ ## Quick start
35
+
36
+ ```js
37
+ // Auto-detects the installed driver (Playwright preferred when both are present):
38
+ const { launchContext } = require('capiumbrowser');
39
+
40
+ // ...or pick one explicitly:
41
+ // const { launchContext } = require('capiumbrowser/playwright');
42
+ // const { launchContext } = require('capiumbrowser/puppeteer');
43
+
44
+ const { browser, page } = await launchContext({
45
+ seed: 200123, // a coherent, repeatable device
46
+ platform: 'windows', // the spoofed OS persona
47
+ proxy: 'http://user:pass@host:port',
48
+ geoip: true, // exit IP + matching tz/geo/WebRTC
49
+ humanize: true, // human-like clicks/typing/scrolls
50
+ url: 'https://fingerprint.com/demo/',
51
+ });
52
+
53
+ await page.humanType('#email', 'alex@example.com');
54
+ await page.humanClick('#submit');
55
+ await browser.close();
56
+ ```
57
+
58
+ The returned objects are standard Playwright / Puppeteer objects — the rest of your code is
59
+ unchanged.
60
+
61
+ ```js
62
+ // Playwright: launch() -> Browser, launchPersistentContext(dir) -> BrowserContext
63
+ const { launch, launchPersistentContext } = require('capiumbrowser/playwright');
64
+ const browser = await launch({ seed: 42 });
65
+ const page = await (await browser.newContext({ viewport: null })).newPage();
66
+
67
+ // Puppeteer: launch() -> Browser (persistent profile via userDataDir)
68
+ const pptr = require('capiumbrowser/puppeteer');
69
+ const browser2 = await pptr.launch({ seed: 42, userDataDir: './profile' });
70
+ ```
71
+
72
+ ## Highlights
73
+
74
+ - **Source-level C++ stealth** — User-Agent & UA-CH, WebGL/GPU, canvas, audio, screen,
75
+ hardware, fonts, voices, WebRTC, `navigator.webdriver`, DevTools, pointer, client-rects —
76
+ all rewritten **in the browser's own source**, below the JavaScript layer.
77
+ - **Coherent per-seed identities** — one integer **seed** derives a complete, self-consistent
78
+ device (OS, GPU, cores, memory, screen, fonts, UA). Same seed ⇒ same machine, every run.
79
+ - **`humanize: true`** — attaches `page.humanMove/humanClick/humanType/humanScroll`: curved,
80
+ human-timed mouse, keyboard, and scroll.
81
+ - **`geoip: true`** — the binary resolves its own exit IP through your proxy and pins timezone,
82
+ WebRTC IP, geolocation, and `navigator.languages` to match.
83
+ - **Plain drivers over CDP** — no patched driver, no init-script signature, no
84
+ `Object.defineProperty` shim to detect.
85
+ - **Always the latest binary** — one license key fetches the newest checksum-verified build for
86
+ your platform and reuses it thereafter.
87
+
88
+ ## Options (both drivers)
89
+
90
+ | Option | Default | Meaning |
91
+ | --- | --- | --- |
92
+ | `seed` | random | Identity seed; a stable, coherent device per seed |
93
+ | `platform` | `"windows"` | Spoofed OS persona: `windows` \| `macos` \| `linux` |
94
+ | `headless` | `false` | Windowed is the coherent persona default |
95
+ | `proxy` | none | `"http://user:pass@host:port"`, `"socks5://host:port"`, or `{server, username, password, bypass}` |
96
+ | `geoip` | off | `true` = pin tz/geo/WebRTC/language to the egress; `false` = explicit opt-out |
97
+ | `timezone` / `locale` | — | Explicit overrides (IANA tz, BCP-47 locale; in-binary spoof) |
98
+ | `stealthArgs` | `true` | `false` drops the default fingerprint flags |
99
+ | `licenseKey` / `licenseServer` | env / `~/.capium/license` | Handed to the self-licensing binary via the environment, never argv |
100
+
101
+ Remaining options are forwarded to the driver's own `launch()`.
102
+
103
+ ### Framework integrations
104
+
105
+ `buildLaunchOptions()` (on both subpaths) returns the ready-made options object for the
106
+ driver's own `launch()`, for frameworks that must hold the launch themselves (Crawlee,
107
+ custom pools):
108
+
109
+ ```js
110
+ const { chromium } = require('playwright-core');
111
+ const { buildLaunchOptions } = require('capiumbrowser/playwright');
112
+ const browser = await chromium.launch(await buildLaunchOptions({ seed: 42 }));
113
+ ```
114
+
115
+ ## License & binary
116
+
117
+ The `capiumbrowser` npm package is open; the **Capium browser binary is licensed** per
118
+ concurrent session (free tier: 1 concurrent session). Configure the key once:
119
+
120
+ ```bash
121
+ export CAPIUM_LICENSE_KEY=cap_... # or ~/.capium/license with a KEY= line
122
+ ```
123
+
124
+ Enforcement lives **in the browser binary** (activate → session → heartbeat); the SDK only
125
+ passes the key along and translates the binary's fail-closed exit into typed errors:
126
+ `CapiumConfigError` (no key), `CapiumSeatLimitError`, `CapiumExpiredError`,
127
+ `CapiumServerDownError`.
128
+
129
+ ## CLI
130
+
131
+ ```bash
132
+ npx capiumbrowser # environment check: license + binary + drivers
133
+ npx capiumbrowser status # license entitlements from the server
134
+ npx capiumbrowser install # download the capium browser binary
135
+ npx capiumbrowser run [URL] # demo launch (SEED/PLATFORM/PROXY/HEADLESS=1/PROFILE env)
136
+ ```
137
+
138
+ ## Environment variables
139
+
140
+ | Variable | Meaning |
141
+ | --- | --- |
142
+ | `CAPIUM_LICENSE_KEY` / `CAPIUM_LICENSE_SERVER` | License credentials (or `~/.capium/license`) |
143
+ | `CAPIUM_HOME` | Install/search root for the browser binary (default `~/.capium`) |
144
+ | `CAPIUM_BINARY` | Exact launch target; skips discovery and download |
145
+ | `CAPIUM_VERSION` | Pin a specific binary build |
146
+ | `CAPIUM_DOWNLOAD_URL` | Direct `.tar.gz` URL escape hatch (may contain `{platform}`/`{version}`) |
147
+ | `CAPIUM_INLINE_PROXY_AUTH=0` | Legacy CDP proxy-auth path for old binaries |
148
+
149
+ ## Fonts (cross-OS personas)
150
+
151
+ A persona reads cleanest on a **matching-OS host** (Windows persona on Windows, …) — the OS
152
+ fonts back the claim and there's nothing to install. For a **Windows persona on Linux/macOS**,
153
+ copy the fonts from a real Windows machine you own:
154
+
155
+ ```bash
156
+ # Linux: copy C:\Windows\Fonts\* into a font dir, then refresh
157
+ mkdir -p ~/.local/share/fonts/windows
158
+ scp C:\Windows\Fonts\* user@linuxbox:~/.local/share/fonts/windows/ # from the Windows box
159
+ fc-cache -f
160
+ # macOS: drop the .ttf/.ttc files into ~/Library/Fonts/ (picked up immediately)
161
+ ```
162
+
163
+ Once Segoe UI/Calibri/Consolas & co. resolve, the wrapper auto-enables
164
+ `--fingerprint-windows-font-metrics`. `CAPIUM_FONTS_DIR=/path` points at a custom dir. Copy
165
+ proprietary fonts only between machines you hold licenses for. Full guide: the
166
+ [product README](https://github.com/capzy-ai/capiumbrowser#fonts).
167
+
168
+ ## Platforms
169
+
170
+ `linux-x64` · `linux-arm64` · `windows-x64` · `macos-arm64` (Apple Silicon).
171
+
172
+ > **Responsible use.** Capium is a stealth browser for legitimate automation, testing, QA, and
173
+ > research. Capium doesn't solve CAPTCHAs, and no stealth tool can promise you'll never see
174
+ > one. Respect the terms of service of the sites you automate.
@@ -0,0 +1,305 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * capiumbrowser CLI -- npx capiumbrowser <command>
4
+ *
5
+ * info environment check: license + binary + drivers (i.e. "what do I
6
+ * still need installed?"). Exit 0 if ready, 1 if not.
7
+ * status license entitlements from the server (plan, seats, live sessions)
8
+ * version SDK version + the Chromium/Capium build it targets
9
+ * install download the capium browser binary
10
+ * run [URL] launch a stealth browser to URL (demo; Ctrl-C to exit)
11
+ *
12
+ * info/status flags: --json --quick (skip the license-server call)
13
+ * run env: SEED, PLATFORM (windows|macos|linux), HEADLESS=1, PROXY, GEOIP=1,
14
+ * PROFILE=<dir> (persistent), HUMANIZE=1
15
+ */
16
+ 'use strict';
17
+
18
+ const { execFileSync } = require('child_process');
19
+ const fs = require('fs');
20
+ const os = require('os');
21
+
22
+ const config = require('../lib/config');
23
+ const download = require('../lib/download');
24
+ const license = require('../lib/license');
25
+ const { CapiumError } = require('../lib/errors');
26
+ const { SDK_VERSION, CAPIUM_BINARY_VERSION } = require('../lib/version');
27
+
28
+ // ---- diagnostics helpers -----------------------------------------------------
29
+
30
+ function driverVersion(name) {
31
+ try {
32
+ return require(`${name}/package.json`).version;
33
+ } catch {
34
+ return null;
35
+ }
36
+ }
37
+
38
+ function binaryVersionOf(binPath) {
39
+ // Ask the binary its version. `--version` prints and exits BEFORE the license gate,
40
+ // so this works without a configured license. Returns null if it can't be read.
41
+ try {
42
+ const out = execFileSync(binPath, ['--version'],
43
+ { encoding: 'utf8', timeout: 15000, stdio: ['ignore', 'pipe', 'pipe'] });
44
+ return out.trim() || null;
45
+ } catch (e) {
46
+ const out = ((e.stdout || '') + (e.stderr || '')).trim();
47
+ return out || null;
48
+ }
49
+ }
50
+
51
+ function licenseSource() {
52
+ // Where the key is configured (env / file), with NO server call. null if unset.
53
+ if (process.env.CAPIUM_LICENSE_KEY) return 'env CAPIUM_LICENSE_KEY';
54
+ const { key } = license._fromFile(); // ~/.capium/license
55
+ return key ? '~/.capium/license' : null;
56
+ }
57
+
58
+ async function gather(quick) {
59
+ const info = { issues: [] };
60
+ info.sdk = { version: SDK_VERSION, targets_chromium: CAPIUM_BINARY_VERSION };
61
+ info.node = { version: process.version, os: process.platform, arch: os.arch() };
62
+
63
+ const pwv = driverVersion('playwright-core') || driverVersion('playwright');
64
+ const ppv = driverVersion('puppeteer-core') || driverVersion('puppeteer');
65
+ info.drivers = {
66
+ 'playwright-core': pwv,
67
+ 'puppeteer-core': ppv,
68
+ };
69
+ if (!pwv && !ppv) {
70
+ info.issues.push('No driver installed -> npm install playwright-core (or puppeteer-core)');
71
+ }
72
+
73
+ const binary = { found: false, path: null, version: null, installed_version: null,
74
+ target_version: CAPIUM_BINARY_VERSION, up_to_date: null, platform_tag: null };
75
+ try {
76
+ binary.platform_tag = download.downloadTag();
77
+ } catch (e) { // unsupported platform (macOS Intel, Windows ARM)
78
+ binary.platform_error = e.message;
79
+ info.issues.push(e.message);
80
+ }
81
+ try {
82
+ const binPath = config.findBinary();
83
+ const vstr = binaryVersionOf(binPath); // e.g. "Capium 152.0.7977.65"
84
+ const m = /\d+\.\d+\.\d+\.\d+/.exec(vstr || '');
85
+ const iv = m ? m[0] : download.installedVersion(binPath); // marker fallback
86
+ binary.found = true;
87
+ binary.path = binPath;
88
+ binary.version = vstr;
89
+ binary.installed_version = iv;
90
+ binary.up_to_date = iv ? iv === CAPIUM_BINARY_VERSION : null;
91
+ if (iv && iv !== CAPIUM_BINARY_VERSION) {
92
+ info.issues.push(
93
+ `Browser binary is ${iv} but the SDK targets ${CAPIUM_BINARY_VERSION} -> it ` +
94
+ 'auto-updates on the next launch (or run: npx capiumbrowser install)');
95
+ }
96
+ } catch {
97
+ info.issues.push('Browser binary not installed -> npx capiumbrowser install');
98
+ }
99
+ info.binary = binary;
100
+
101
+ const src = licenseSource();
102
+ const lic = { configured: src !== null, source: src, server_checked: false,
103
+ plan: null, sessions_cap: null, live_sessions: null, period_end: null };
104
+ if (src === null) {
105
+ info.issues.push('No license key -> set CAPIUM_LICENSE_KEY or ~/.capium/license (KEY=...)');
106
+ } else if (!quick) {
107
+ try {
108
+ const st = await license.status();
109
+ Object.assign(lic, { server_checked: true, plan: st.plan,
110
+ sessions_cap: st.sessions_cap, live_sessions: st.live_sessions,
111
+ period_end: st.period_end });
112
+ } catch (e) {
113
+ lic.server_error = e.message;
114
+ info.issues.push(`License check failed -> ${e.message}`);
115
+ }
116
+ }
117
+ info.license = lic;
118
+ return info;
119
+ }
120
+
121
+ function printHuman(info) {
122
+ const row = (label, val, status) => {
123
+ const tag = status === undefined ? '' : ` [${status}]`;
124
+ console.log(` ${label.padEnd(13)} ${val}${tag}`);
125
+ };
126
+
127
+ console.log('\nCapium browser -- environment check\n');
128
+ row('SDK', `capiumbrowser ${info.sdk.version} (targets Chromium ${info.sdk.targets_chromium})`);
129
+ row('Node', `${info.node.version} on ${info.node.os}/${info.node.arch}`);
130
+ const d = info.drivers;
131
+ row('Playwright', d['playwright-core'] || 'not installed',
132
+ d['playwright-core'] ? 'OK' : 'missing');
133
+ row('Puppeteer', d['puppeteer-core'] || 'not installed',
134
+ d['puppeteer-core'] ? 'OK' : 'missing');
135
+
136
+ const b = info.binary;
137
+ console.log();
138
+ if (b.platform_tag) row('Platform', `${b.platform_tag} (${info.node.os}/${info.node.arch})`);
139
+ else if (b.platform_error) {
140
+ row('Platform', `unsupported: ${info.node.os}/${info.node.arch}`, 'UNSUPPORTED');
141
+ }
142
+ if (b.found) {
143
+ const iv = b.installed_version;
144
+ if (iv && b.up_to_date) row('Binary', `installed v${iv} (up to date)`, 'OK');
145
+ else if (iv) {
146
+ row('Binary',
147
+ `installed v${iv} -> SDK targets v${b.target_version} (auto-updates next launch)`,
148
+ 'UPDATE');
149
+ } else row('Binary', 'installed', 'OK');
150
+ row('', b.path);
151
+ } else {
152
+ row('Binary', 'NOT INSTALLED', 'MISSING');
153
+ row('', `target v${b.target_version} -> npx capiumbrowser install`);
154
+ }
155
+
156
+ const lic = info.license;
157
+ console.log();
158
+ if (lic.configured) {
159
+ row('License', `key from ${lic.source}`, 'OK');
160
+ if (lic.server_checked) {
161
+ row('', `plan=${lic.plan} seats=${lic.sessions_cap} (${lic.live_sessions} live) ` +
162
+ `renews=${lic.period_end}`);
163
+ } else if (lic.server_error) row('', `server check: ${lic.server_error}`, 'WARN');
164
+ } else {
165
+ row('License', 'not configured', 'MISSING');
166
+ }
167
+
168
+ console.log();
169
+ if (info.issues.length) {
170
+ console.log(`${info.issues.length} thing(s) to fix:`);
171
+ for (const i of info.issues) console.log(` - ${i}`);
172
+ } else {
173
+ console.log('Ready: everything needed is installed and configured.');
174
+ }
175
+ console.log();
176
+ }
177
+
178
+ // ---- subcommands -------------------------------------------------------------
179
+
180
+ async function cmdInfo(flags) {
181
+ const info = await gather(flags.includes('--quick'));
182
+ if (flags.includes('--json')) console.log(JSON.stringify(info, null, 2));
183
+ else printHuman(info);
184
+ return info.issues.length ? 1 : 0;
185
+ }
186
+
187
+ async function cmdStatus(flags) {
188
+ let st;
189
+ try {
190
+ st = await license.status();
191
+ } catch (e) {
192
+ console.error(`capiumbrowser status: ${e.message}`);
193
+ return 1;
194
+ }
195
+ if (flags.includes('--json')) console.log(JSON.stringify(st, null, 2));
196
+ else for (const [k, v] of Object.entries(st)) console.log(` ${k.padEnd(14)} ${v}`);
197
+ return 0;
198
+ }
199
+
200
+ function cmdVersion() {
201
+ console.log(`capiumbrowser ${SDK_VERSION} (targets Chromium ${CAPIUM_BINARY_VERSION})`);
202
+ try {
203
+ const binPath = config.findBinary();
204
+ const vstr = binaryVersionOf(binPath) || '';
205
+ const m = /\d+\.\d+\.\d+\.\d+/.exec(vstr);
206
+ const iv = m ? m[0] : (download.installedVersion(binPath) || 'unknown');
207
+ if (iv === CAPIUM_BINARY_VERSION) {
208
+ console.log(`installed binary: v${iv} (up to date) at ${binPath}`);
209
+ } else {
210
+ console.log(
211
+ `installed binary: v${iv} -> updates to v${CAPIUM_BINARY_VERSION} on next launch, ` +
212
+ `at ${binPath}`);
213
+ }
214
+ } catch {
215
+ console.log('installed binary: NOT INSTALLED -> npx capiumbrowser install');
216
+ }
217
+ return 0;
218
+ }
219
+
220
+ async function cmdInstall() {
221
+ const { key } = license.effective();
222
+ console.log('downloading the capium browser binary ...');
223
+ console.log('installed:', await download.ensureBinary({ licenseKey: key }));
224
+ return 0;
225
+ }
226
+
227
+ async function cmdRun(url) {
228
+ const seed = process.env.SEED;
229
+ const geoipEnv = process.env.GEOIP; // 1 = force on, 0 = force off, unset = auto (null)
230
+ const opts = {
231
+ seed: seed ? Number(seed) : null,
232
+ platform: process.env.PLATFORM || 'windows',
233
+ headless: process.env.HEADLESS === '1',
234
+ proxy: process.env.PROXY || null,
235
+ geoip: geoipEnv === '1' ? true : geoipEnv === '0' ? false : null,
236
+ };
237
+ const driver = require('../index').detectDriver();
238
+ const target = url || 'https://fingerprint.com/demo/';
239
+ let page;
240
+ let closer;
241
+ const profile = process.env.PROFILE;
242
+ if (profile) {
243
+ const ctx = await driver.launchPersistentContext(profile, opts);
244
+ closer = ctx;
245
+ const pages = typeof ctx.pages === 'function' ? await ctx.pages() : [];
246
+ page = pages[0] || (await ctx.newPage());
247
+ await page.goto(target, { waitUntil: 'domcontentloaded', timeout: 60000 });
248
+ } else {
249
+ const res = await driver.launchContext({
250
+ url: target, humanize: process.env.HUMANIZE === '1', ...opts,
251
+ });
252
+ page = res.page;
253
+ closer = res.browser;
254
+ }
255
+ console.log('== Capium ==');
256
+ console.log(' platform :', await page.evaluate(() => navigator.platform));
257
+ console.log(' userAgent:', await page.evaluate(() => navigator.userAgent));
258
+ console.log(' url :', target);
259
+ console.log('Browser open. Ctrl-C to exit.');
260
+ await new Promise((resolve) => {
261
+ process.on('SIGINT', resolve);
262
+ process.on('SIGTERM', resolve);
263
+ });
264
+ await closer.close();
265
+ return 0;
266
+ }
267
+
268
+ async function main() {
269
+ const [cmd, ...restArgs] = process.argv.slice(2);
270
+ const flags = restArgs.filter((a) => a.startsWith('--'));
271
+ const positional = restArgs.filter((a) => !a.startsWith('--'));
272
+ try {
273
+ switch (cmd) {
274
+ case undefined:
275
+ case 'info':
276
+ // No subcommand -> the diagnostic, so a bare `npx capiumbrowser` is useful.
277
+ return await cmdInfo(flags);
278
+ case 'status':
279
+ return await cmdStatus(flags);
280
+ case 'version':
281
+ return cmdVersion();
282
+ case 'install':
283
+ return await cmdInstall();
284
+ case 'run':
285
+ return await cmdRun(positional[0]);
286
+ case '--help':
287
+ case '-h':
288
+ case 'help':
289
+ console.log(fs.readFileSync(__filename, 'utf8')
290
+ .split('\n').slice(1, 15).map((l) => l.replace(/^ \* ?/, '')).join('\n'));
291
+ return 0;
292
+ default:
293
+ console.error(`unknown command: ${cmd} (try: info, status, version, install, run)`);
294
+ return 2;
295
+ }
296
+ } catch (e) {
297
+ if (e instanceof CapiumError) {
298
+ console.error(`capiumbrowser: ${e.message}`);
299
+ return 1;
300
+ }
301
+ throw e;
302
+ }
303
+ }
304
+
305
+ main().then((code) => process.exit(code));
package/index.d.ts ADDED
@@ -0,0 +1,131 @@
1
+ /**
2
+ * Type declarations for capiumbrowser.
3
+ *
4
+ * Driver return types are intentionally structural (`any`-compatible) so the package works
5
+ * with playwright-core OR puppeteer-core without depending on either's types. Cast the
6
+ * results to your driver's types at the call site if you want full IntelliSense:
7
+ *
8
+ * import type { Browser } from 'playwright-core';
9
+ * const browser = (await launch({ seed: 42 })) as unknown as Browser;
10
+ */
11
+
12
+ export type Platform = 'windows' | 'macos' | 'linux';
13
+
14
+ export interface ProxySpec {
15
+ /** "scheme://host:port" (http, https, socks5). */
16
+ server: string;
17
+ username?: string;
18
+ password?: string;
19
+ /** Comma-separated hosts/patterns that connect DIRECT, skipping the proxy. */
20
+ bypass?: string;
21
+ }
22
+
23
+ export interface LaunchOptions {
24
+ /** Identity seed (a stable, coherent device per seed). Random if omitted. */
25
+ seed?: number | null;
26
+ /** The spoofed OS persona. Default "windows". */
27
+ platform?: Platform;
28
+ /** Default false (a windowed browser is the coherent persona default). */
29
+ headless?: boolean;
30
+ /** "http://user:pass@host:port" | "socks5://host:port" | ProxySpec. */
31
+ proxy?: string | ProxySpec | null;
32
+ /**
33
+ * Geo coherence, resolved inside the binary. null/undefined (default) = OFF: no lookup
34
+ * runs, even with a proxy. true = pin timezone/geo/WebRTC/language to the egress.
35
+ * false = explicit opt-out.
36
+ */
37
+ geoip?: boolean | null;
38
+ /** Extra Chromium args appended after the stealth flags. */
39
+ args?: string[] | null;
40
+ /** false drops the default fingerprint flags. Default true. */
41
+ stealthArgs?: boolean;
42
+ /** IANA timezone override (in-binary spoof), e.g. "Europe/Berlin". */
43
+ timezone?: string | null;
44
+ /** BCP-47 locale override, e.g. "de-DE". */
45
+ locale?: string | null;
46
+ /** Unpacked extension dir(s) to load. */
47
+ extensionPaths?: string | string[] | null;
48
+ /** Explicit path to the capium launch target (skips discovery + download). */
49
+ binary?: string | null;
50
+ /** License key (else CAPIUM_LICENSE_KEY / ~/.capium/license). Never lands on argv. */
51
+ licenseKey?: string | null;
52
+ licenseServer?: string | null;
53
+ /** Route the binary's license traffic through the configured proxy. */
54
+ licenseThroughProxy?: boolean;
55
+ /** Fail fast (offline) with CapiumConfigError when no key is set. Default true. */
56
+ licensePreflight?: boolean;
57
+ /** Any remaining options are forwarded to the driver's launch(). */
58
+ [driverOption: string]: unknown;
59
+ }
60
+
61
+ export interface LaunchContextOptions extends LaunchOptions {
62
+ /** Navigate the first page here (domcontentloaded). */
63
+ url?: string | null;
64
+ /** Attach page.humanMove/humanClick/humanType/humanScroll helpers. */
65
+ humanize?: boolean;
66
+ humanPreset?: 'default' | 'careful';
67
+ }
68
+
69
+ export class CapiumError extends Error {}
70
+ export class CapiumLicenseError extends CapiumError {}
71
+ export class CapiumConfigError extends CapiumLicenseError {}
72
+ export class CapiumSeatLimitError extends CapiumLicenseError {}
73
+ export class CapiumExpiredError extends CapiumLicenseError {}
74
+ export class CapiumServerDownError extends CapiumLicenseError {}
75
+
76
+ export const VERSION: string;
77
+ export const CAPIUM_BINARY_VERSION: string;
78
+ export const CAPIUM_BINARY_VERSIONS: Record<string, string>;
79
+
80
+ /**
81
+ * Escape hatch (on the capiumbrowser/playwright and capiumbrowser/puppeteer subpaths):
82
+ * the ready-made options object for the driver's own launch(), for framework
83
+ * integrations that must hold the launch themselves.
84
+ */
85
+ export function buildLaunchOptions(options?: LaunchOptions): Promise<Record<string, unknown>>;
86
+
87
+ /** Launch a Capium Browser via the installed driver (Playwright preferred when both are). */
88
+ export function launch(options?: LaunchOptions): Promise<any>;
89
+ export function launchContext(options?: LaunchContextOptions):
90
+ Promise<{ browser: any; context?: any; page: any }>;
91
+ export function launchPersistentContext(userDataDir: string, options?: LaunchOptions):
92
+ Promise<any>;
93
+ export function detectDriver(): {
94
+ launch: typeof launch;
95
+ launchContext: typeof launchContext;
96
+ launchPersistentContext: typeof launchPersistentContext;
97
+ };
98
+
99
+ export function status(licenseKey?: string | null, licenseServer?: string | null):
100
+ Promise<{ plan: string | null; sessions_cap: number | null; live_sessions: number | null;
101
+ period_end: string | null; heartbeat_every: number | null }>;
102
+
103
+ export namespace config {
104
+ function getDefaultStealthArgs(seed?: number | null, platform?: Platform,
105
+ screen?: [number, number] | null): string[];
106
+ function newSeed(): number;
107
+ function findBinary(binary?: string | null): string;
108
+ }
109
+
110
+ export namespace proxy {
111
+ function buildProxyArg(spec: string | ProxySpec | null | false): string | null;
112
+ function resolveProxyConfig(spec: string | ProxySpec | null | false,
113
+ inlineAuth?: boolean | null): { launchOptions: object; args: string[] };
114
+ }
115
+
116
+ export namespace download {
117
+ function downloadTag(system?: string | null, machine?: string | null): string;
118
+ function distroPath(version: string, tag: string): string;
119
+ function ensureBinary(opts?: { version?: string | null; licenseKey?: string | null;
120
+ server?: string | null }): Promise<string>;
121
+ function installedVersion(binPath?: string | null): string | null;
122
+ }
123
+
124
+ export namespace human {
125
+ function humanize<T>(target: T, preset?: 'default' | 'careful'): T;
126
+ function move(page: any, x: number, y: number, preset?: string): Promise<void>;
127
+ function click(page: any, selector: string, preset?: string): Promise<void>;
128
+ function typeText(page: any, selector: string, text: string, preset?: string): Promise<void>;
129
+ function scroll(page: any, dy: number, preset?: string): Promise<void>;
130
+ function dwell(loSec?: number, hiSec?: number): Promise<void>;
131
+ }