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 +34 -0
- package/README.md +115 -0
- package/dist/download.d.ts +12 -0
- package/dist/download.d.ts.map +1 -0
- package/dist/download.js +122 -0
- package/dist/download.js.map +1 -0
- package/dist/fingerprint.d.ts +38 -0
- package/dist/fingerprint.d.ts.map +1 -0
- package/dist/fingerprint.js +54 -0
- package/dist/fingerprint.js.map +1 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +67 -0
- package/dist/index.js.map +1 -0
- package/dist/release.d.ts +20 -0
- package/dist/release.d.ts.map +1 -0
- package/dist/release.js +16 -0
- package/dist/release.js.map +1 -0
- package/package.json +57 -0
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"}
|
package/dist/download.js
ADDED
|
@@ -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"}
|
package/dist/index.d.ts
ADDED
|
@@ -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":"AAAA,kCAAkC;AAClC,EAAE;AACF,wCAAwC;AACxC,oFAAoF;AACpF,0CAA0C;AAC1C,iEAAiE;AACjE,EAAE;AACF,4FAA4F;AAC5F,gGAAgG;AAChG,gGAAgG;AAChG,sBAAsB;AAEtB,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAO3C,OAAO,EAAE,YAAY,EAAwB,MAAM,eAAe,CAAC;AACnE,OAAO,EAAE,eAAe,EAAE,uBAAuB,EAA2B,MAAM,kBAAkB,CAAC;AACrG,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAIvC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAWvC,SAAS,kBAAkB,CAAC,GAAW;IACrC,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CACb,aAAa,OAAO,CAAC,OAAO,2DAA2D,OAAO,CAAC,QAAQ,MAAM;YAC3G,kEAAkE;YAClE,8DAA8D,GAAG,GAAG,CACvE,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,UAAyD,EAAE;IAE3D,IAAI,OAAO,CAAC,cAAc;QAAE,OAAO,OAAO,CAAC,cAAc,CAAC;IAC1D,IAAI,OAAO,CAAC,GAAG,CAAC,gBAAgB;QAAE,OAAO,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;IACtE,OAAO,YAAY,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;AAC5E,CAAC;AAED,iGAAiG;AACjG,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,UAA2B,EAAE;IAC1D,OAAO,YAAY,CAAC,OAAO,CAAC,CAAC;AAC/B,CAAC;AAED,yEAAyE;AACzE,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,UAAyB,EAAE;IACtD,MAAM,EAAE,cAAc,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,IAAI,EAAE,GAAG,OAAO,CAAC;IAC7D,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,uBAAuB,CAAC,IAAI,CAAC,CAAC;IACvE,MAAM,GAAG,GAAG,MAAM,cAAc,CAAC,EAAE,cAAc,EAAE,SAAS,EAAE,CAAC,CAAC;IAChE,kBAAkB,CAAC,GAAG,CAAC,CAAC;IACxB,OAAO,QAAQ,CAAC,MAAM,CAAC;QACrB,GAAI,SAAqC;QACzC,cAAc,EAAE,GAAG;QACnB,IAAI,EAAE,CAAC,GAAG,eAAe,CAAC,WAAW,CAAC,EAAE,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;KACzD,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,WAAmB,EACnB,UAAoC,EAAE;IAEtC,MAAM,EAAE,cAAc,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,IAAI,EAAE,GAAG,OAAO,CAAC;IAC7D,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,uBAAuB,CAAC,IAAI,CAAC,CAAC;IACvE,MAAM,GAAG,GAAG,MAAM,cAAc,CAAC,EAAE,cAAc,EAAE,SAAS,EAAE,CAAC,CAAC;IAChE,kBAAkB,CAAC,GAAG,CAAC,CAAC;IACxB,OAAO,QAAQ,CAAC,uBAAuB,CAAC,WAAW,EAAE;QACnD,GAAI,SAA6D;QACjE,cAAc,EAAE,GAAG;QACnB,IAAI,EAAE,CAAC,GAAG,eAAe,CAAC,WAAW,CAAC,EAAE,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;KACzD,CAAC,CAAC;AACL,CAAC;AAED,eAAe,EAAE,MAAM,EAAE,uBAAuB,EAAE,cAAc,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC"}
|
|
@@ -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"}
|
package/dist/release.js
ADDED
|
@@ -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
|
+
}
|