clearcote 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,34 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2026, Clearcote Labs and the Clearcote contributors
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright notice, this
9
+ list of conditions and the following disclaimer.
10
+
11
+ 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ this list of conditions and the following disclaimer in the documentation
13
+ and/or other materials provided with the distribution.
14
+
15
+ 3. Neither the name of the copyright holder nor the names of its
16
+ contributors may be used to endorse or promote products derived from
17
+ this software without specific prior written permission.
18
+
19
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
+
30
+ ---
31
+
32
+ This license applies to Clearcote's own source code and patches. Upstream
33
+ components (Chromium, ungoogled-chromium, and others) are distributed under
34
+ their respective licenses; see CREDITS.md.
package/README.md ADDED
@@ -0,0 +1,115 @@
1
+ # clearcote (Node / TypeScript SDK)
2
+
3
+ A **Playwright drop-in** for [Clearcote](https://github.com/clearcotelabs/clearcote-browser) — the
4
+ open, reproducible, anti-fingerprint Chromium build. `launch()` returns a standard Playwright
5
+ `Browser`, so migrating is a one-line import change.
6
+
7
+ The verified Clearcote binary is **auto-downloaded and SHA-256 checked** on first use, then cached —
8
+ you don't manage zips or paths.
9
+
10
+ > **Platform:** Clearcote currently ships a **Windows x64** binary, so `launch()` runs on Windows.
11
+ > (The SDK will download + verify the binary on any OS — useful for packaging — but only launches it
12
+ > on Windows. Linux/macOS builds are on the [roadmap](../../ROADMAP.md).)
13
+
14
+ ## Install
15
+
16
+ ```bash
17
+ npm install clearcote
18
+ ```
19
+
20
+ `playwright-core` comes as a dependency — you do **not** need to install Playwright separately or
21
+ run `playwright install` (Clearcote uses its own browser binary).
22
+
23
+ ## Usage
24
+
25
+ ```ts
26
+ import { launch } from "clearcote";
27
+
28
+ const browser = await launch({
29
+ fingerprint: "user-7423", // per-eTLD+1 seed: same seed => same identity, different => unlinkable
30
+ platform: "windows",
31
+ timezone: "America/New_York",
32
+ headless: false,
33
+ });
34
+
35
+ const page = await browser.newPage();
36
+ await page.goto("https://abrahamjuliot.github.io/creepjs/");
37
+ // ... standard Playwright from here ...
38
+ await browser.close();
39
+ ```
40
+
41
+ Already using Playwright? Swap `chromium.launch(...)` for `launch(...)` from `clearcote` — the
42
+ returned object is a normal Playwright `Browser`.
43
+
44
+ ### Through a proxy (report the proxy's IP, not your host's)
45
+
46
+ ```ts
47
+ const browser = await launch({
48
+ fingerprint: "user-7423",
49
+ proxy: { server: "http://host:8080", username: "u", password: "p" }, // standard Playwright option
50
+ timezone: "America/New_York",
51
+ webrtcIp: "203.0.113.10", // make WebRTC report the proxy egress IP
52
+ });
53
+ ```
54
+
55
+ ### Persistent profile
56
+
57
+ ```ts
58
+ import { launchPersistentContext } from "clearcote";
59
+
60
+ const context = await launchPersistentContext("./profile-7423", {
61
+ fingerprint: "user-7423",
62
+ platform: "windows",
63
+ });
64
+ ```
65
+
66
+ ## Fingerprint options
67
+
68
+ All optional. Anything not listed here is passed straight through to Playwright
69
+ (`headless`, `proxy`, `args`, `timeout`, `slowMo`, …).
70
+
71
+ | Option | Switch | Meaning |
72
+ |---|---|---|
73
+ | `fingerprint` | `--fingerprint` | Master seed (per-eTLD+1 farbling root). String or number. |
74
+ | `platform` | `--fingerprint-platform` | `windows` \| `linux` \| `macos`. |
75
+ | `platformVersion` | `--fingerprint-platform-version` | UA-CH platform version. |
76
+ | `brand` | `--fingerprint-brand` | `Chrome` \| `Edge` \| `Opera` \| `Vivaldi`. |
77
+ | `brandVersion` | `--fingerprint-brand-version` | Brand version. |
78
+ | `gpuVendor` | `--fingerprint-gpu-vendor` | WebGL UNMASKED vendor. |
79
+ | `gpuRenderer` | `--fingerprint-gpu-renderer` | WebGL UNMASKED renderer. |
80
+ | `hardwareConcurrency` | `--fingerprint-hardware-concurrency` | `navigator.hardwareConcurrency`. |
81
+ | `location` | `--fingerprint-location` | `"lat,lng"` (only when geo permission is granted). |
82
+ | `timezone` | `--timezone` | IANA timezone, e.g. `America/New_York`. |
83
+ | `webrtcIp` | `--webrtc-ip` | WebRTC egress IP to report (your proxy IP). |
84
+ | `disableGpuFingerprint` | `--disable-gpu-fingerprint` | Turn off GPU/WebGL spoofing. |
85
+
86
+ ## API
87
+
88
+ - `launch(options?)` → `Promise<Browser>` — launch and get a Playwright `Browser`.
89
+ - `launchPersistentContext(userDataDir, options?)` → `Promise<BrowserContext>`.
90
+ - `executablePath(options?)` → `Promise<string>` — resolve (download/verify if needed) the chrome.exe path, e.g. for raw `chromium.launch({ executablePath })`.
91
+ - `download(options?)` → `Promise<string>` — pre-fetch + verify the binary without launching.
92
+ - `RELEASE` — the pinned release metadata (tag, version, sha256).
93
+
94
+ ## Binary resolution & verification
95
+
96
+ `launch()` resolves the browser in this order:
97
+
98
+ 1. `executablePath` option, if given;
99
+ 2. `CLEARCOTE_BINARY` environment variable, if set;
100
+ 3. otherwise **download** the pinned release, **verify its SHA-256** (the hash is baked into this
101
+ package — it's the trust anchor), extract to a per-version cache, and verify the extracted
102
+ `chrome.exe` hash too.
103
+
104
+ Cache location (override with `CLEARCOTE_CACHE`):
105
+ - Windows: `%LOCALAPPDATA%\clearcote\Cache\<tag>`
106
+ - macOS: `~/Library/Caches/clearcote/<tag>`
107
+ - Linux: `${XDG_CACHE_HOME:-~/.cache}/clearcote/<tag>`
108
+
109
+ A SHA-256 mismatch is a hard error — the SDK refuses to run an unverified binary. You can
110
+ independently confirm the published checksums and GPG signatures on the
111
+ [release page](https://github.com/clearcotelabs/clearcote-browser/releases).
112
+
113
+ ## License
114
+
115
+ BSD-3-Clause. See [LICENSE](../../LICENSE).
@@ -0,0 +1,12 @@
1
+ export interface DownloadOptions {
2
+ /** Override the cache directory (default: per-OS user cache dir). */
3
+ cacheDir?: string;
4
+ /** Suppress progress logging. */
5
+ quiet?: boolean;
6
+ }
7
+ /**
8
+ * Ensure the Clearcote binary is present and verified; return the path to chrome.exe.
9
+ * Cached per release tag, so subsequent calls are instant.
10
+ */
11
+ export declare function ensureBinary(opts?: DownloadOptions): Promise<string>;
12
+ //# sourceMappingURL=download.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"download.d.ts","sourceRoot":"","sources":["../src/download.ts"],"names":[],"mappings":"AAeA,MAAM,WAAW,eAAe;IAC9B,qEAAqE;IACrE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iCAAiC;IACjC,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAqED;;;GAGG;AACH,wBAAsB,YAAY,CAAC,IAAI,GAAE,eAAoB,GAAG,OAAO,CAAC,MAAM,CAAC,CA6C9E"}
@@ -0,0 +1,122 @@
1
+ // Resolve the Clearcote browser binary: use an explicit path / env override if given, otherwise
2
+ // download the pinned release, verify its SHA-256 against the value baked into the SDK, extract
3
+ // it to a per-version cache, and return the path to chrome.exe. The hash check is mandatory —
4
+ // a mismatch throws and the partial download is deleted.
5
+ import { createHash } from "node:crypto";
6
+ import { createReadStream, createWriteStream, existsSync, mkdirSync, readdirSync, writeFileSync } from "node:fs";
7
+ import { rm } from "node:fs/promises";
8
+ import os from "node:os";
9
+ import path from "node:path";
10
+ import { Readable } from "node:stream";
11
+ import { pipeline } from "node:stream/promises";
12
+ import extract from "extract-zip";
13
+ import { RELEASE } from "./release.js";
14
+ function log(quiet, msg) {
15
+ if (!quiet)
16
+ process.stderr.write(`[clearcote] ${msg}\n`);
17
+ }
18
+ function defaultCacheRoot() {
19
+ if (process.env.CLEARCOTE_CACHE)
20
+ return process.env.CLEARCOTE_CACHE;
21
+ if (process.platform === "win32") {
22
+ return path.join(process.env.LOCALAPPDATA || path.join(os.homedir(), "AppData", "Local"), "clearcote", "Cache");
23
+ }
24
+ if (process.platform === "darwin") {
25
+ return path.join(os.homedir(), "Library", "Caches", "clearcote");
26
+ }
27
+ return path.join(process.env.XDG_CACHE_HOME || path.join(os.homedir(), ".cache"), "clearcote");
28
+ }
29
+ function findFile(dir, name) {
30
+ const stack = [dir];
31
+ while (stack.length) {
32
+ const cur = stack.pop();
33
+ let entries;
34
+ try {
35
+ entries = readdirSync(cur, { withFileTypes: true });
36
+ }
37
+ catch {
38
+ continue;
39
+ }
40
+ for (const e of entries) {
41
+ const full = path.join(cur, e.name);
42
+ if (e.isDirectory())
43
+ stack.push(full);
44
+ else if (e.name.toLowerCase() === name.toLowerCase())
45
+ return full;
46
+ }
47
+ }
48
+ return null;
49
+ }
50
+ function sha256File(file) {
51
+ return new Promise((resolve, reject) => {
52
+ const hash = createHash("sha256");
53
+ createReadStream(file)
54
+ .on("error", reject)
55
+ .on("data", (d) => hash.update(d))
56
+ .on("end", () => resolve(hash.digest("hex")));
57
+ });
58
+ }
59
+ async function downloadTo(url, dest, quiet) {
60
+ const res = await fetch(url, { redirect: "follow" });
61
+ if (!res.ok || !res.body) {
62
+ throw new Error(`Clearcote download failed: HTTP ${res.status} ${res.statusText} for ${url}`);
63
+ }
64
+ const total = Number(res.headers.get("content-length")) || RELEASE.size;
65
+ let seen = 0;
66
+ let lastPct = -1;
67
+ const progress = new TransformStream({
68
+ transform(chunk, controller) {
69
+ seen += chunk.byteLength;
70
+ const pct = Math.floor((seen / total) * 100);
71
+ if (!quiet && pct !== lastPct && pct % 5 === 0) {
72
+ lastPct = pct;
73
+ process.stderr.write(`\r[clearcote] downloading ${pct}% (${(seen / 1e6).toFixed(0)}/${(total / 1e6).toFixed(0)} MB)`);
74
+ }
75
+ controller.enqueue(chunk);
76
+ },
77
+ });
78
+ await pipeline(Readable.fromWeb(res.body.pipeThrough(progress)), createWriteStream(dest));
79
+ if (!quiet)
80
+ process.stderr.write("\n");
81
+ }
82
+ /**
83
+ * Ensure the Clearcote binary is present and verified; return the path to chrome.exe.
84
+ * Cached per release tag, so subsequent calls are instant.
85
+ */
86
+ export async function ensureBinary(opts = {}) {
87
+ const base = path.join(opts.cacheDir || defaultCacheRoot(), RELEASE.tag);
88
+ const browserDir = path.join(base, "browser");
89
+ const marker = path.join(base, ".verified");
90
+ if (existsSync(marker)) {
91
+ const cached = findFile(browserDir, "chrome.exe");
92
+ if (cached)
93
+ return cached;
94
+ }
95
+ mkdirSync(base, { recursive: true });
96
+ const zipPath = path.join(base, RELEASE.asset);
97
+ log(opts.quiet, `fetching Clearcote ${RELEASE.version} (${RELEASE.tag}, ~${(RELEASE.size / 1e6).toFixed(0)} MB)`);
98
+ await downloadTo(RELEASE.url, zipPath, opts.quiet);
99
+ log(opts.quiet, "verifying SHA-256");
100
+ const got = await sha256File(zipPath);
101
+ if (got.toLowerCase() !== RELEASE.sha256.toLowerCase()) {
102
+ await rm(zipPath, { force: true });
103
+ throw new Error(`Clearcote archive SHA-256 mismatch — refusing to use it.\n expected ${RELEASE.sha256}\n got ${got}`);
104
+ }
105
+ log(opts.quiet, "extracting");
106
+ await rm(browserDir, { recursive: true, force: true });
107
+ await extract(zipPath, { dir: browserDir });
108
+ const exe = findFile(browserDir, "chrome.exe");
109
+ if (!exe) {
110
+ throw new Error("Clearcote archive verified but chrome.exe was not found inside it.");
111
+ }
112
+ // defense in depth: verify the extracted exe too
113
+ const exeHash = await sha256File(exe);
114
+ if (exeHash.toLowerCase() !== RELEASE.exeSha256.toLowerCase()) {
115
+ throw new Error(`Clearcote chrome.exe SHA-256 mismatch — refusing to use it.\n expected ${RELEASE.exeSha256}\n got ${exeHash}`);
116
+ }
117
+ writeFileSync(marker, `${RELEASE.sha256}\n`);
118
+ await rm(zipPath, { force: true }); // reclaim ~250 MB; keep only the extracted tree
119
+ log(opts.quiet, `ready: ${exe}`);
120
+ return exe;
121
+ }
122
+ //# sourceMappingURL=download.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"download.js","sourceRoot":"","sources":["../src/download.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ export interface FingerprintOptions {
2
+ /**
3
+ * Master fingerprint seed (the per-eTLD+1 farbling root). Same seed => the same stable
4
+ * identity across launches; different seeds => unlinkable identities. Any string or number
5
+ * is accepted (non-numeric seeds are hashed engine-side — they will not crash the renderer).
6
+ */
7
+ fingerprint?: string | number;
8
+ /** Spoofed OS family for UA / UA-CH / navigator.platform. */
9
+ platform?: "windows" | "linux" | "macos";
10
+ /** Spoofed platform version (UA-CH high-entropy). */
11
+ platformVersion?: string;
12
+ /** Browser brand for UA / UA-CH. */
13
+ brand?: "Chrome" | "Edge" | "Opera" | "Vivaldi" | (string & {});
14
+ /** Brand version. */
15
+ brandVersion?: string;
16
+ /** WebGL UNMASKED_VENDOR string. */
17
+ gpuVendor?: string;
18
+ /** WebGL UNMASKED_RENDERER string. */
19
+ gpuRenderer?: string;
20
+ /** navigator.hardwareConcurrency. */
21
+ hardwareConcurrency?: number;
22
+ /** Geolocation as "lat,lng" (only returned when the page is granted permission). */
23
+ location?: string;
24
+ /** IANA timezone, e.g. "America/New_York". */
25
+ timezone?: string;
26
+ /** WebRTC egress IP to report (typically your proxy's public IP). */
27
+ webrtcIp?: string;
28
+ /** Turn OFF GPU/WebGL fingerprint spoofing (advertise the real backend). */
29
+ disableGpuFingerprint?: boolean;
30
+ }
31
+ /** Split an options object into its fingerprint half and the remaining (Playwright) half. */
32
+ export declare function splitFingerprintOptions<T extends FingerprintOptions>(options: T): {
33
+ fingerprint: FingerprintOptions;
34
+ rest: Omit<T, keyof FingerprintOptions>;
35
+ };
36
+ /** Build the Chromium switches for a set of fingerprint options. */
37
+ export declare function fingerprintArgs(o: FingerprintOptions): string[];
38
+ //# sourceMappingURL=fingerprint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fingerprint.d.ts","sourceRoot":"","sources":["../src/fingerprint.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,kBAAkB;IACjC;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC9B,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,OAAO,CAAC;IACzC,qDAAqD;IACrD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,oCAAoC;IACpC,KAAK,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;IAChE,qBAAqB;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oCAAoC;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sCAAsC;IACtC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,qCAAqC;IACrC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,oFAAoF;IACpF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,qEAAqE;IACrE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,4EAA4E;IAC5E,qBAAqB,CAAC,EAAE,OAAO,CAAC;CACjC;AAiBD,6FAA6F;AAC7F,wBAAgB,uBAAuB,CAAC,CAAC,SAAS,kBAAkB,EAClE,OAAO,EAAE,CAAC,GACT;IAAE,WAAW,EAAE,kBAAkB,CAAC;IAAC,IAAI,EAAE,IAAI,CAAC,CAAC,EAAE,MAAM,kBAAkB,CAAC,CAAA;CAAE,CAW9E;AAED,oEAAoE;AACpE,wBAAgB,eAAe,CAAC,CAAC,EAAE,kBAAkB,GAAG,MAAM,EAAE,CAoB/D"}
@@ -0,0 +1,54 @@
1
+ // Maps the SDK's fingerprint options to the Clearcote Chromium command-line switches.
2
+ // Switch names mirror components/ungoogled/ungoogled_switches.cc (see patches/000-fingerprint-switches.patch).
3
+ const FINGERPRINT_KEYS = [
4
+ "fingerprint",
5
+ "platform",
6
+ "platformVersion",
7
+ "brand",
8
+ "brandVersion",
9
+ "gpuVendor",
10
+ "gpuRenderer",
11
+ "hardwareConcurrency",
12
+ "location",
13
+ "timezone",
14
+ "webrtcIp",
15
+ "disableGpuFingerprint",
16
+ ];
17
+ /** Split an options object into its fingerprint half and the remaining (Playwright) half. */
18
+ export function splitFingerprintOptions(options) {
19
+ const fingerprint = {};
20
+ const rest = {};
21
+ for (const [k, v] of Object.entries(options)) {
22
+ if (FINGERPRINT_KEYS.includes(k)) {
23
+ fingerprint[k] = v;
24
+ }
25
+ else {
26
+ rest[k] = v;
27
+ }
28
+ }
29
+ return { fingerprint, rest: rest };
30
+ }
31
+ /** Build the Chromium switches for a set of fingerprint options. */
32
+ export function fingerprintArgs(o) {
33
+ const args = [];
34
+ const set = (flag, value) => {
35
+ if (value !== undefined && value !== null && value !== "") {
36
+ args.push(`--${flag}=${value}`);
37
+ }
38
+ };
39
+ set("fingerprint", o.fingerprint);
40
+ set("fingerprint-platform", o.platform);
41
+ set("fingerprint-platform-version", o.platformVersion);
42
+ set("fingerprint-brand", o.brand);
43
+ set("fingerprint-brand-version", o.brandVersion);
44
+ set("fingerprint-gpu-vendor", o.gpuVendor);
45
+ set("fingerprint-gpu-renderer", o.gpuRenderer);
46
+ set("fingerprint-hardware-concurrency", o.hardwareConcurrency);
47
+ set("fingerprint-location", o.location);
48
+ set("timezone", o.timezone);
49
+ set("webrtc-ip", o.webrtcIp);
50
+ if (o.disableGpuFingerprint)
51
+ args.push("--disable-gpu-fingerprint");
52
+ return args;
53
+ }
54
+ //# sourceMappingURL=fingerprint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fingerprint.js","sourceRoot":"","sources":["../src/fingerprint.ts"],"names":[],"mappings":"AAAA,sFAAsF;AACtF,+GAA+G;AAiC/G,MAAM,gBAAgB,GAAiC;IACrD,aAAa;IACb,UAAU;IACV,iBAAiB;IACjB,OAAO;IACP,cAAc;IACd,WAAW;IACX,aAAa;IACb,qBAAqB;IACrB,UAAU;IACV,UAAU;IACV,UAAU;IACV,uBAAuB;CACxB,CAAC;AAEF,6FAA6F;AAC7F,MAAM,UAAU,uBAAuB,CACrC,OAAU;IAEV,MAAM,WAAW,GAAuB,EAAE,CAAC;IAC3C,MAAM,IAAI,GAA4B,EAAE,CAAC;IACzC,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QAC7C,IAAK,gBAA6B,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;YAC9C,WAAuC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QAClD,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACd,CAAC;IACH,CAAC;IACD,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,IAAyC,EAAE,CAAC;AAC1E,CAAC;AAED,oEAAoE;AACpE,MAAM,UAAU,eAAe,CAAC,CAAqB;IACnD,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,MAAM,GAAG,GAAG,CAAC,IAAY,EAAE,KAAc,EAAE,EAAE;QAC3C,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,EAAE,EAAE,CAAC;YAC1D,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,IAAI,KAAK,EAAE,CAAC,CAAC;QAClC,CAAC;IACH,CAAC,CAAC;IACF,GAAG,CAAC,aAAa,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC;IAClC,GAAG,CAAC,sBAAsB,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC;IACxC,GAAG,CAAC,8BAA8B,EAAE,CAAC,CAAC,eAAe,CAAC,CAAC;IACvD,GAAG,CAAC,mBAAmB,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC;IAClC,GAAG,CAAC,2BAA2B,EAAE,CAAC,CAAC,YAAY,CAAC,CAAC;IACjD,GAAG,CAAC,wBAAwB,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC;IAC3C,GAAG,CAAC,0BAA0B,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC;IAC/C,GAAG,CAAC,kCAAkC,EAAE,CAAC,CAAC,mBAAmB,CAAC,CAAC;IAC/D,GAAG,CAAC,sBAAsB,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC;IACxC,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC;IAC5B,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC;IAC7B,IAAI,CAAC,CAAC,qBAAqB;QAAE,IAAI,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;IACpE,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,37 @@
1
+ import type { Browser, BrowserContext, BrowserContextOptions, LaunchOptions as PlaywrightLaunchOptions } from "playwright-core";
2
+ import { type DownloadOptions } from "./download.js";
3
+ import { type FingerprintOptions } from "./fingerprint.js";
4
+ export type { FingerprintOptions } from "./fingerprint.js";
5
+ export type { DownloadOptions } from "./download.js";
6
+ export { RELEASE } from "./release.js";
7
+ /** Options for {@link launch}: Playwright launch options + Clearcote fingerprint options. */
8
+ export interface LaunchOptions extends PlaywrightLaunchOptions, FingerprintOptions {
9
+ }
10
+ /** Options for {@link launchPersistentContext}. */
11
+ export interface PersistentContextOptions extends PlaywrightLaunchOptions, BrowserContextOptions, FingerprintOptions {
12
+ }
13
+ /**
14
+ * Resolve the Clearcote chrome.exe path, downloading + verifying it if needed.
15
+ * Order: explicit `executablePath` > `CLEARCOTE_BINARY` env > auto-download.
16
+ */
17
+ export declare function executablePath(options?: {
18
+ executablePath?: string;
19
+ } & DownloadOptions): Promise<string>;
20
+ /** Pre-fetch + verify the Clearcote binary without launching it. Returns the chrome.exe path. */
21
+ export declare function download(options?: DownloadOptions): Promise<string>;
22
+ /** Launch Clearcote and return a standard Playwright {@link Browser}. */
23
+ export declare function launch(options?: LaunchOptions): Promise<Browser>;
24
+ /**
25
+ * Launch Clearcote with a persistent profile directory and return a Playwright
26
+ * {@link BrowserContext} (cookies, storage, etc. persist in `userDataDir`).
27
+ */
28
+ export declare function launchPersistentContext(userDataDir: string, options?: PersistentContextOptions): Promise<BrowserContext>;
29
+ declare const _default: {
30
+ launch: typeof launch;
31
+ launchPersistentContext: typeof launchPersistentContext;
32
+ executablePath: typeof executablePath;
33
+ download: typeof download;
34
+ RELEASE: import("./release.js").ReleaseInfo;
35
+ };
36
+ export default _default;
37
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EACV,OAAO,EACP,cAAc,EACd,qBAAqB,EACrB,aAAa,IAAI,uBAAuB,EACzC,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAgB,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC;AACnE,OAAO,EAA4C,KAAK,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAGrG,YAAY,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAC3D,YAAY,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,6FAA6F;AAC7F,MAAM,WAAW,aAAc,SAAQ,uBAAuB,EAAE,kBAAkB;CAAG;AAErF,mDAAmD;AACnD,MAAM,WAAW,wBACf,SAAQ,uBAAuB,EAC7B,qBAAqB,EACrB,kBAAkB;CAAG;AAYzB;;;GAGG;AACH,wBAAsB,cAAc,CAClC,OAAO,GAAE;IAAE,cAAc,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,eAAoB,GAC1D,OAAO,CAAC,MAAM,CAAC,CAIjB;AAED,iGAAiG;AACjG,wBAAsB,QAAQ,CAAC,OAAO,GAAE,eAAoB,GAAG,OAAO,CAAC,MAAM,CAAC,CAE7E;AAED,yEAAyE;AACzE,wBAAsB,MAAM,CAAC,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,OAAO,CAAC,CAU1E;AAED;;;GAGG;AACH,wBAAsB,uBAAuB,CAC3C,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE,wBAA6B,GACrC,OAAO,CAAC,cAAc,CAAC,CAUzB;;;;;;;;AAED,wBAAsF"}
package/dist/index.js ADDED
@@ -0,0 +1,67 @@
1
+ // Clearcote — Playwright drop-in.
2
+ //
3
+ // import { launch } from "clearcote";
4
+ // const browser = await launch({ fingerprint: "seed-123", platform: "windows" });
5
+ // const page = await browser.newPage();
6
+ // await page.goto("https://abrahamjuliot.github.io/creepjs/");
7
+ //
8
+ // launch() returns a standard Playwright `Browser`, backed by the verified Clearcote binary
9
+ // (auto-downloaded + SHA-256 checked on first use, then cached). Every Playwright launch option
10
+ // (headless, proxy, args, timeout, ...) passes through; the fingerprint options below are added
11
+ // as engine switches.
12
+ import { chromium } from "playwright-core";
13
+ import { ensureBinary } from "./download.js";
14
+ import { fingerprintArgs, splitFingerprintOptions } from "./fingerprint.js";
15
+ import { RELEASE } from "./release.js";
16
+ export { RELEASE } from "./release.js";
17
+ function ensureRunnableHere(exe) {
18
+ if (process.platform !== "win32") {
19
+ throw new Error(`Clearcote ${RELEASE.version} ships a Windows x64 binary only — it cannot launch on '${process.platform}'.\n` +
20
+ `Run on Windows, or pass executablePath to a compatible binary.\n` +
21
+ `(The binary downloaded and verified fine; it is cached at: ${exe})`);
22
+ }
23
+ }
24
+ /**
25
+ * Resolve the Clearcote chrome.exe path, downloading + verifying it if needed.
26
+ * Order: explicit `executablePath` > `CLEARCOTE_BINARY` env > auto-download.
27
+ */
28
+ export async function executablePath(options = {}) {
29
+ if (options.executablePath)
30
+ return options.executablePath;
31
+ if (process.env.CLEARCOTE_BINARY)
32
+ return process.env.CLEARCOTE_BINARY;
33
+ return ensureBinary({ cacheDir: options.cacheDir, quiet: options.quiet });
34
+ }
35
+ /** Pre-fetch + verify the Clearcote binary without launching it. Returns the chrome.exe path. */
36
+ export async function download(options = {}) {
37
+ return ensureBinary(options);
38
+ }
39
+ /** Launch Clearcote and return a standard Playwright {@link Browser}. */
40
+ export async function launch(options = {}) {
41
+ const { executablePath: exeOption, args, ...rest } = options;
42
+ const { fingerprint, rest: pwOptions } = splitFingerprintOptions(rest);
43
+ const exe = await executablePath({ executablePath: exeOption });
44
+ ensureRunnableHere(exe);
45
+ return chromium.launch({
46
+ ...pwOptions,
47
+ executablePath: exe,
48
+ args: [...fingerprintArgs(fingerprint), ...(args ?? [])],
49
+ });
50
+ }
51
+ /**
52
+ * Launch Clearcote with a persistent profile directory and return a Playwright
53
+ * {@link BrowserContext} (cookies, storage, etc. persist in `userDataDir`).
54
+ */
55
+ export async function launchPersistentContext(userDataDir, options = {}) {
56
+ const { executablePath: exeOption, args, ...rest } = options;
57
+ const { fingerprint, rest: pwOptions } = splitFingerprintOptions(rest);
58
+ const exe = await executablePath({ executablePath: exeOption });
59
+ ensureRunnableHere(exe);
60
+ return chromium.launchPersistentContext(userDataDir, {
61
+ ...pwOptions,
62
+ executablePath: exe,
63
+ args: [...fingerprintArgs(fingerprint), ...(args ?? [])],
64
+ });
65
+ }
66
+ export default { launch, launchPersistentContext, executablePath, download, RELEASE };
67
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ export interface ReleaseInfo {
2
+ /** Git tag / release the binary comes from. */
3
+ tag: string;
4
+ /** Chromium version the build is based on. */
5
+ version: string;
6
+ /** Release asset (zip) file name. */
7
+ asset: string;
8
+ /** Direct download URL for the asset. */
9
+ url: string;
10
+ /** SHA-256 of the zip — verified after download; mismatch is a hard failure. */
11
+ sha256: string;
12
+ /** SHA-256 of chrome.exe inside the zip — verified after extraction (defense in depth). */
13
+ exeSha256: string;
14
+ /** Expected zip size in bytes (for progress display only). */
15
+ size: number;
16
+ /** Platform the binary runs on. */
17
+ os: NodeJS.Platform;
18
+ }
19
+ export declare const RELEASE: ReleaseInfo;
20
+ //# sourceMappingURL=release.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"release.d.ts","sourceRoot":"","sources":["../src/release.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,WAAW;IAC1B,+CAA+C;IAC/C,GAAG,EAAE,MAAM,CAAC;IACZ,8CAA8C;IAC9C,OAAO,EAAE,MAAM,CAAC;IAChB,qCAAqC;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,yCAAyC;IACzC,GAAG,EAAE,MAAM,CAAC;IACZ,gFAAgF;IAChF,MAAM,EAAE,MAAM,CAAC;IACf,2FAA2F;IAC3F,SAAS,EAAE,MAAM,CAAC;IAClB,8DAA8D;IAC9D,IAAI,EAAE,MAAM,CAAC;IACb,mCAAmC;IACnC,EAAE,EAAE,MAAM,CAAC,QAAQ,CAAC;CACrB;AAED,eAAO,MAAM,OAAO,EAAE,WASrB,CAAC"}
@@ -0,0 +1,16 @@
1
+ // Pinned Clearcote release the SDK downloads and verifies.
2
+ // Bumping the SDK to a new browser build = updating these constants (and the version in
3
+ // package.json). The sha256 is the SINGLE trust anchor for the auto-download: if you trust
4
+ // this package, the hash check guarantees you run exactly the published, signed binary.
5
+ // Published checksums + GPG signatures live on the release page.
6
+ export const RELEASE = {
7
+ tag: "v0.1.0-pre.2",
8
+ version: "149.0.7827.114",
9
+ asset: "clearcote-149.0.7827.114-windows-x64.zip",
10
+ url: "https://github.com/clearcotelabs/clearcote-browser/releases/download/v0.1.0-pre.2/clearcote-149.0.7827.114-windows-x64.zip",
11
+ sha256: "4071aa06add252caa274c4f52dfe2e8eaede4eb37cf55be6fb6f8e3c28bcf256",
12
+ exeSha256: "5743595256c89c6874804bf3315acce592fc7f1883760c8d380c010151a73b23",
13
+ size: 253015969,
14
+ os: "win32",
15
+ };
16
+ //# sourceMappingURL=release.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"release.js","sourceRoot":"","sources":["../src/release.ts"],"names":[],"mappings":"AAAA,2DAA2D;AAC3D,wFAAwF;AACxF,2FAA2F;AAC3F,wFAAwF;AACxF,iEAAiE;AAqBjE,MAAM,CAAC,MAAM,OAAO,GAAgB;IAClC,GAAG,EAAE,cAAc;IACnB,OAAO,EAAE,gBAAgB;IACzB,KAAK,EAAE,0CAA0C;IACjD,GAAG,EAAE,4HAA4H;IACjI,MAAM,EAAE,kEAAkE;IAC1E,SAAS,EAAE,kEAAkE;IAC7E,IAAI,EAAE,SAAS;IACf,EAAE,EAAE,OAAO;CACZ,CAAC"}
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "clearcote",
3
+ "version": "0.1.0",
4
+ "description": "Playwright drop-in for the Clearcote anti-fingerprint Chromium build. launch() returns a standard Playwright Browser backed by the verified Clearcote binary, which is auto-downloaded and SHA-256 checked.",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist",
16
+ "README.md"
17
+ ],
18
+ "engines": {
19
+ "node": ">=18"
20
+ },
21
+ "scripts": {
22
+ "build": "tsc -p tsconfig.json",
23
+ "clean": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\"",
24
+ "prepublishOnly": "npm run clean && npm run build"
25
+ },
26
+ "dependencies": {
27
+ "extract-zip": "^2.0.1",
28
+ "playwright-core": "^1.49.0"
29
+ },
30
+ "devDependencies": {
31
+ "@types/node": "^22.0.0",
32
+ "typescript": "^5.6.0"
33
+ },
34
+ "keywords": [
35
+ "clearcote",
36
+ "playwright",
37
+ "puppeteer",
38
+ "chromium",
39
+ "anti-detect",
40
+ "anti-fingerprint",
41
+ "fingerprint",
42
+ "farbling",
43
+ "automation",
44
+ "stealth",
45
+ "ungoogled"
46
+ ],
47
+ "license": "BSD-3-Clause",
48
+ "homepage": "https://github.com/clearcotelabs/clearcote-browser",
49
+ "repository": {
50
+ "type": "git",
51
+ "url": "git+https://github.com/clearcotelabs/clearcote-browser.git",
52
+ "directory": "sdk/node"
53
+ },
54
+ "bugs": {
55
+ "url": "https://github.com/clearcotelabs/clearcote-browser/issues"
56
+ }
57
+ }