device-passport 1.0.0 → 1.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.
Files changed (42) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/README.md +69 -2
  3. package/dist/adapters/index.cjs +19 -0
  4. package/dist/adapters/index.d.cts +156 -0
  5. package/dist/adapters/index.d.mts +156 -0
  6. package/dist/adapters/index.d.ts +156 -0
  7. package/dist/adapters/index.mjs +3 -0
  8. package/dist/evaluator/index.cjs +702 -0
  9. package/dist/evaluator/index.d.cts +204 -0
  10. package/dist/evaluator/index.d.mts +204 -0
  11. package/dist/evaluator/index.d.ts +204 -0
  12. package/dist/evaluator/index.mjs +680 -0
  13. package/dist/geo/index.cjs +50 -0
  14. package/dist/geo/index.d.cts +209 -0
  15. package/dist/geo/index.d.mts +209 -0
  16. package/dist/geo/index.d.ts +209 -0
  17. package/dist/geo/index.mjs +18 -0
  18. package/dist/index.cjs +113 -3543
  19. package/dist/index.d.cts +45 -903
  20. package/dist/index.d.mts +45 -903
  21. package/dist/index.d.ts +45 -903
  22. package/dist/index.mjs +11 -3438
  23. package/dist/shared/device-passport.BBf9OKap.mjs +1237 -0
  24. package/dist/shared/device-passport.BPd2-w8e.cjs +1265 -0
  25. package/dist/shared/device-passport.CLaBZWUV.cjs +1569 -0
  26. package/dist/shared/device-passport.C_F1vBE8.d.cts +79 -0
  27. package/dist/shared/device-passport.C_F1vBE8.d.mts +79 -0
  28. package/dist/shared/device-passport.C_F1vBE8.d.ts +79 -0
  29. package/dist/shared/device-passport.Cjxlv8xI.cjs +245 -0
  30. package/dist/shared/device-passport.CyQtcZeD.mjs +237 -0
  31. package/dist/shared/device-passport.NHw_f6HT.mjs +1535 -0
  32. package/dist/storage/index.cjs +10 -0
  33. package/dist/storage/index.d.cts +128 -0
  34. package/dist/storage/index.d.mts +128 -0
  35. package/dist/storage/index.d.ts +128 -0
  36. package/dist/storage/index.mjs +3 -0
  37. package/dist/types/index.cjs +2 -0
  38. package/dist/types/index.d.cts +215 -0
  39. package/dist/types/index.d.mts +215 -0
  40. package/dist/types/index.d.ts +215 -0
  41. package/dist/types/index.mjs +1 -0
  42. package/package.json +27 -2
package/CHANGELOG.md CHANGED
@@ -5,6 +5,36 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.1.0] - 2026-11-04
9
+
10
+ > ⚠️ 发布受阻说明:本版本代码已合并并打好 tag,但 **npm 发布尚未完成** ——
11
+ > `device-passport` 在 npmjs.com 上没有配置 Trusted Publisher 信任关系。
12
+ > 证据:`device-passport@1.0.0` 没有 OIDC attestation(对比 `im-notify-kit@0.4.1` 有),
13
+ > 说明该包从未成功走通 OIDC 通道;workflow 里的 `id-token: write` 只是必要条件,
14
+ > 不是充分条件。需要在 npmjs.com → Packages → device-passport → Settings →
15
+ > Trusted Publisher 里登记:GitHub Actions / 组织 `webkubor` / 仓库 `device-passport` /
16
+ > 工作流 `publish.yml`,并允许 `npm publish`。登记后 2 天内需完成首次发布,否则配置过期。
17
+
18
+ ### Added
19
+ - **Pixel-level protection**: `getStealthScript()` now appends a deterministic noise layer that patches `canvas.toDataURL()`, `getImageData()`, `gl.readPixels()` and the audio analyser, so read-back no longer exposes the host GPU or a shared hash across personas. The noise is derived from the passport seed — stable per account, distinct per account — and uses discrete quantization levels rather than per-pixel dithering, because a smooth ±1 RGB jitter is itself a fingerprint.
20
+ - **Raw CDP adapter**: `getCdpPlan()` and `applyCdpPassport()` emit an ordered, transport-agnostic Chrome DevTools Protocol command plan for tools that speak bare CDP (e.g. `lite-browser`'s `cdp` channel). Covers headers, `Emulation.setUserAgentOverride` with Client-Hints metadata, timezone, locale, device metrics, touch emulation and init-script installation.
21
+
22
+ ### Fixed
23
+ - **Canvas serialization recursion**: the temporary canvas used for re-serialization shares the patched prototype, so calling its `toDataURL` recursed until the stack limit. Serialization now uses the captured original method (verified with 25 repeated calls in real Chromium).
24
+ - **WebGL canvases leaked the real framebuffer through `toDataURL()`**: a canvas with a WebGL context returns `null` from `getContext('2d')`, so that path silently skipped protection. Pixel perturbation now runs through `gl.readPixels` for such canvases.
25
+ - **Alpha bytes were perturbed**: RGBA alpha now stays untouched, so transparent and opaque pixels keep their semantics (masks and hit-testing unaffected).
26
+ - **Audio perturbation was seed-independent**: a fixed `1e-7` step was identical for every persona and rounded away in Float32 at typical dB values. The step is now seed-derived and representable.
27
+ - **Injected stealth script was invalid JavaScript**: the runtime script embedded TypeScript-only syntax (`navigator as any`), which raised a `SyntaxError` in the page and silently disabled the **entire** stealth layer — `navigator.webdriver` stayed `true` and every spoofed API reverted to the real values. The script is now valid browser JavaScript, and a regression test parses it to prevent this from returning.
28
+ - **CDP init scripts never executed**: `Page.addScriptToEvaluateOnNewDocument` was issued without `Page.enable`. Chrome accepted the script, returned an identifier and then never ran it, so a CDP-driven persona looked like a plain automation session. `Page.enable` is now emitted first, with a regression test covering the ordering.
29
+
30
+ ## [1.0.1] - 2026-10-17
31
+
32
+ ### Added
33
+ - **Standard ESM subpath exports**: `device-passport/geo`, `device-passport/storage`, `device-passport/adapters` are now importable as separate entry points, each shipping its own `types` / `import` / `require` conditions. Consumers can tree-shake by pulling only the module they need instead of the whole bundle.
34
+
35
+ ### Fixed
36
+ - **npm publish path**: the release workflow now runs on Node 24 with pure OIDC Trusted Publishing (the previous `NODE_AUTH_TOKEN` pointed at a secret that was never configured, which forced npm down the token-auth path and made Trusted Publishing ineffective).
37
+
8
38
  ## [1.0.0] - 2026-10-17
9
39
 
10
40
  ### Added
package/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  <p align="center">
2
- <img src="assets/banner.svg" alt="device-passport banner" width="800"/>
2
+ <img src="https://cdn.jsdelivr.net/gh/webkubor/free-imgbed@main/device-passport/banner.svg" alt="device-passport banner" width="800"/>
3
3
  </p>
4
4
 
5
5
  <h1 align="center">🛂 device-passport</h1>
@@ -59,7 +59,7 @@ Modern anti-bot classifiers (Cloudflare Turnstile, DataDome, Akamai, GitHub Anti
59
59
  Under-parameterized headers ($H(X) < 4.6$ bits/char) scream "naive scraper"; chaotic randomized noise ($H(X) > 5.6$ bits/char) screams "evasion bot". `device-passport` operates strictly within the natural human entropy equilibrium ($5.24$ bits/char).
60
60
 
61
61
  <p align="center">
62
- <img src="assets/architecture.svg" alt="device-passport formal state-space architecture" width="100%"/>
62
+ <img src="https://cdn.jsdelivr.net/gh/webkubor/free-imgbed@main/device-passport/architecture.svg" alt="device-passport formal state-space architecture" width="100%"/>
63
63
  </p>
64
64
 
65
65
  ---
@@ -292,6 +292,60 @@ await passport.injectToPuppeteer(page);
292
292
  await page.goto('https://bot.sannysoft.com');
293
293
  ```
294
294
 
295
+ ### Raw CDP Integration (lite-browser, custom transports)
296
+
297
+ Tools that drive Chrome over a bare DevTools Protocol socket cannot use the Playwright or
298
+ Puppeteer adapters, because those return framework-shaped options. `getCdpPlan()` returns
299
+ an ordered, transport-agnostic command plan instead:
300
+
301
+ ```typescript
302
+ import { createPassport, applyCdpPassport } from 'device-passport';
303
+
304
+ const passport = createPassport({ seed: 'worker_de_19', geo: 'DE', os: 'windows' });
305
+
306
+ // `send` is yours: a WebSocket, stdio, or an in-process socket.
307
+ await applyCdpPassport(passport, (cmd) => transport.send(cmd.method, cmd.params));
308
+ ```
309
+
310
+ The plan covers `Page.enable`, extra HTTP headers, `Emulation.setUserAgentOverride`
311
+ (with Client-Hints metadata), timezone, locale, device metrics and touch emulation, and
312
+ installs the stealth script through `Page.addScriptToEvaluateOnNewDocument`.
313
+
314
+ > **`Page.enable` is mandatory.** Without it Chrome accepts the init script, returns an
315
+ > identifier, and then never runs it — the persona stays a plain automation session.
316
+ > `applyCdpPassport` emits it first for that reason.
317
+
318
+ ---
319
+
320
+ ## Pixel-Level Protection
321
+
322
+ API-level spoofing is not sufficient on its own. `canvas.toDataURL()` and
323
+ `gl.readPixels()` hand back the **real** framebuffer, so a headless browser exposes
324
+ SwiftShader while its User-Agent claims a discrete GPU — and every persona rendered on
325
+ the same machine produces a **byte-identical** canvas hash, which makes a fleet easy to
326
+ cluster.
327
+
328
+ `getStealthScript()` now appends a deterministic pixel-protection layer that patches
329
+ `toDataURL`, `getImageData`, `readPixels` and the audio analyser:
330
+
331
+ ```typescript
332
+ import { createPassport, getStealthScript } from 'device-passport';
333
+
334
+ const passport = createPassport('alice');
335
+ const script = getStealthScript(passport);
336
+ // Use with Playwright addInitScript, Puppeteer evaluateOnNewDocument, or CDP.
337
+ ```
338
+
339
+ Properties:
340
+
341
+ - **Deterministic per seed** — the same account reads back identical pixels forever,
342
+ which is what makes "sticky hardware" true beyond the API layer.
343
+ - **Distinct per account** — different seeds produce different noise tables.
344
+ - **Plausible** — a discrete quantization of a few levels, not per-pixel dithering. Real
345
+ GPUs quantize; a smooth ±1 RGB jitter on every pixel is itself a fingerprint.
346
+ - **Self-contained** — dependency-free IIFE, safe to inject repeatedly (re-injection is
347
+ a no-op).
348
+
295
349
  ---
296
350
 
297
351
  ## Multi-Account Fleet Management (`PassportManager`)
@@ -411,6 +465,19 @@ npx device-passport inspect --seed production_user_102
411
465
  │ Native Fetch │ │ Playwright │ │ Puppeteer │
412
466
  │ Headers │ │Context Options│ │ Emulation Hook│
413
467
  └──────────────┘ └──────────────┘ └──────────────┘
468
+ │ │
469
+ └───────────────┬───────────────┘
470
+ ▼
471
+ ┌───────────────────────────┐
472
+ │ Pixel-Level Protection │
473
+ │ canvas / WebGL / audio │
474
+ │ deterministic per seed │
475
+ └───────────┬───────────────┘
476
+ ▼
477
+ ┌───────────────────────────┐
478
+ │ Raw CDP Command Plan │
479
+ │ (lite-browser, custom) │
480
+ └───────────────────────────┘
414
481
  ```
415
482
 
416
483
  ---
@@ -0,0 +1,19 @@
1
+ 'use strict';
2
+
3
+ const cdp = require('../shared/device-passport.CLaBZWUV.cjs');
4
+ require('node:crypto');
5
+ require('../shared/device-passport.BPd2-w8e.cjs');
6
+
7
+
8
+
9
+ exports.CANONICAL_HEADER_ORDER = cdp.CANONICAL_HEADER_ORDER;
10
+ exports.applyCdpPassport = cdp.applyCdpPassport;
11
+ exports.applyToPlaywrightContext = cdp.applyToPlaywrightContext;
12
+ exports.applyToPuppeteerPage = cdp.applyToPuppeteerPage;
13
+ exports.formatCanonicalHeaders = cdp.formatCanonicalHeaders;
14
+ exports.getCdpPlan = cdp.getCdpPlan;
15
+ exports.getPlaywrightContext = cdp.getPlaywrightContext;
16
+ exports.getPuppeteerArgs = cdp.getPuppeteerArgs;
17
+ exports.getStealthScript = cdp.getStealthScript;
18
+ exports.toCurl = cdp.toCurl;
19
+ exports.withPassport = cdp.withPassport;
@@ -0,0 +1,156 @@
1
+ import { DevicePassport } from '../types/index.cjs';
2
+ import '../shared/device-passport.C_F1vBE8.cjs';
3
+
4
+ /**
5
+ * Standard Chromium browser header ordering.
6
+ * Anti-bot systems (Cloudflare, Akamai, DataDome, Kasada) strictly inspect
7
+ * the sequence of HTTP request headers. A mismatch in header order triggers
8
+ * immediate bot heuristics.
9
+ */
10
+ declare const CANONICAL_HEADER_ORDER: readonly string[];
11
+ /**
12
+ * Sorts and formats HTTP headers according to canonical browser ordering.
13
+ * Merges base headers with optional overrides.
14
+ */
15
+ declare function formatCanonicalHeaders(baseHeaders: Record<string, string>, overrides?: Record<string, string>): Record<string, string>;
16
+ interface PassportLike {
17
+ headers: Record<string, string>;
18
+ getHeaders?: (overrides?: Record<string, string>) => Record<string, string>;
19
+ }
20
+ /**
21
+ * Higher-order fetch function wrapping standard fetch with canonical DevicePassport headers.
22
+ * Ensures consistent TLS/HTTP persona across API calls, scraping requests, and webhooks.
23
+ *
24
+ * @param passport DevicePassport instance or object
25
+ * @param customFetch Optional fetch implementation (e.g. node-fetch, undici, or global fetch)
26
+ */
27
+ declare function withPassport(passport: PassportLike | DevicePassport, customFetch?: typeof fetch): typeof fetch;
28
+ /**
29
+ * Generates an executable cURL command with correct browser headers.
30
+ */
31
+ declare function toCurl(passport: PassportLike | DevicePassport, url: string, options?: {
32
+ method?: string;
33
+ data?: any;
34
+ headers?: Record<string, string>;
35
+ }): string;
36
+
37
+ interface PlaywrightContextOptions {
38
+ userAgent: string;
39
+ viewport: {
40
+ width: number;
41
+ height: number;
42
+ };
43
+ deviceScaleFactor: number;
44
+ locale: string;
45
+ timezoneId: string;
46
+ geolocation?: {
47
+ latitude: number;
48
+ longitude: number;
49
+ accuracy?: number;
50
+ };
51
+ permissions?: string[];
52
+ extraHTTPHeaders: Record<string, string>;
53
+ hasTouch: boolean;
54
+ isMobile: boolean;
55
+ colorScheme?: 'light' | 'dark' | 'no-preference';
56
+ }
57
+ /**
58
+ * Builds Playwright BrowserContext options directly from a DevicePassport.
59
+ * Ready for `browser.newContext(getPlaywrightContext(passport))`.
60
+ */
61
+ declare function getPlaywrightContext(passport: DevicePassport): PlaywrightContextOptions;
62
+ /**
63
+ * Generates an in-page stealth script to patch runtime JavaScript APIs
64
+ * (navigator.webdriver, hardwareConcurrency, deviceMemory, WebGL unmasked vendor/renderer,
65
+ * navigator.userAgentData Client Hints, and Screen dimensions).
66
+ *
67
+ * 🔴 API-level spoofing is not enough on its own: `canvas.toDataURL()` and `gl.readPixels()`
68
+ * still return the **real** framebuffer, so a headless browser exposes SwiftShader while
69
+ * its UA claims a discrete GPU — and every persona on one machine hashes identically.
70
+ * The pixel-protection script is therefore appended here, so existing users get
71
+ * read-back-safe personas without changing their call sites.
72
+ *
73
+ * The noise is seeded from the passport seed: stable per account, different per account.
74
+ */
75
+ declare function getStealthScript(passport: DevicePassport): string;
76
+ /**
77
+ * Applies stealth injections and extra headers to a Playwright BrowserContext.
78
+ *
79
+ * @param context Playwright BrowserContext instance
80
+ * @param passport DevicePassport instance
81
+ */
82
+ declare function applyToPlaywrightContext(context: any, passport: DevicePassport): Promise<void>;
83
+
84
+ interface PuppeteerEmulationOptions {
85
+ launchArgs: string[];
86
+ defaultViewport: {
87
+ width: number;
88
+ height: number;
89
+ deviceScaleFactor: number;
90
+ isMobile: boolean;
91
+ hasTouch: boolean;
92
+ };
93
+ userAgent: string;
94
+ locale: string;
95
+ timezoneId: string;
96
+ extraHTTPHeaders: Record<string, string>;
97
+ }
98
+ /**
99
+ * Returns Puppeteer launch args and page emulation parameters matching the DevicePassport.
100
+ */
101
+ declare function getPuppeteerArgs(passport: DevicePassport): PuppeteerEmulationOptions;
102
+ /**
103
+ * Applies stealth injections, headers, viewport, and timezone emulation to a Puppeteer Page.
104
+ *
105
+ * @param page Puppeteer Page instance
106
+ * @param passport DevicePassport instance
107
+ */
108
+ declare function applyToPuppeteerPage(page: any, passport: DevicePassport): Promise<void>;
109
+
110
+ /**
111
+ * Raw Chrome DevTools Protocol adapter.
112
+ *
113
+ * 🔴 Why this exists (2026-11-04):
114
+ * Tools that drive Chrome over a bare CDP socket — `lite-browser`'s `cdp <method> [json]`
115
+ * channel, for example — cannot use the Playwright/Puppeteer adapters, because those
116
+ * hand back framework-shaped options. This adapter speaks plain CDP so any CDP client
117
+ * can apply a passport.
118
+ *
119
+ * The returned plan is deliberately **declarative**: a `send(method, params)` function
120
+ * applies every command in order. The caller owns the transport, so this module has no
121
+ * dependency and works over WebSocket, stdio, or an in-process socket.
122
+ */
123
+ interface CdpCommand {
124
+ method: string;
125
+ params?: Record<string, unknown>;
126
+ /** `sessionId` is required for page-scoped domains when using flattened sessions. */
127
+ sessionId?: string;
128
+ }
129
+ interface CdpPassportPlan {
130
+ /** Ordered commands to apply the passport to a target. */
131
+ commands: CdpCommand[];
132
+ /** Init scripts to install on every new document. */
133
+ initScripts: {
134
+ source: string;
135
+ }[];
136
+ /** Extra HTTP headers to set on the session. */
137
+ headers: Record<string, string>;
138
+ /** The raw stealth + pixel-protection script, for callers that prefer their own path. */
139
+ stealthScript: string;
140
+ }
141
+ /**
142
+ * Builds the ordered CDP command plan for a passport.
143
+ *
144
+ * Order matters: the UA override must precede navigation, and the init script has to be
145
+ * installed before the first document is created.
146
+ */
147
+ declare function getCdpPlan(passport: DevicePassport, sessionId?: string): CdpPassportPlan;
148
+ /**
149
+ * Applies a passport through a raw CDP transport.
150
+ *
151
+ * @param send Function that sends one CDP command and resolves with its result.
152
+ */
153
+ declare function applyCdpPassport(passport: DevicePassport, send: (command: CdpCommand) => Promise<unknown>, sessionId?: string): Promise<void>;
154
+
155
+ export { CANONICAL_HEADER_ORDER, applyCdpPassport, applyToPlaywrightContext, applyToPuppeteerPage, formatCanonicalHeaders, getCdpPlan, getPlaywrightContext, getPuppeteerArgs, getStealthScript, toCurl, withPassport };
156
+ export type { CdpCommand, CdpPassportPlan, PassportLike, PlaywrightContextOptions, PuppeteerEmulationOptions };
@@ -0,0 +1,156 @@
1
+ import { DevicePassport } from '../types/index.mjs';
2
+ import '../shared/device-passport.C_F1vBE8.mjs';
3
+
4
+ /**
5
+ * Standard Chromium browser header ordering.
6
+ * Anti-bot systems (Cloudflare, Akamai, DataDome, Kasada) strictly inspect
7
+ * the sequence of HTTP request headers. A mismatch in header order triggers
8
+ * immediate bot heuristics.
9
+ */
10
+ declare const CANONICAL_HEADER_ORDER: readonly string[];
11
+ /**
12
+ * Sorts and formats HTTP headers according to canonical browser ordering.
13
+ * Merges base headers with optional overrides.
14
+ */
15
+ declare function formatCanonicalHeaders(baseHeaders: Record<string, string>, overrides?: Record<string, string>): Record<string, string>;
16
+ interface PassportLike {
17
+ headers: Record<string, string>;
18
+ getHeaders?: (overrides?: Record<string, string>) => Record<string, string>;
19
+ }
20
+ /**
21
+ * Higher-order fetch function wrapping standard fetch with canonical DevicePassport headers.
22
+ * Ensures consistent TLS/HTTP persona across API calls, scraping requests, and webhooks.
23
+ *
24
+ * @param passport DevicePassport instance or object
25
+ * @param customFetch Optional fetch implementation (e.g. node-fetch, undici, or global fetch)
26
+ */
27
+ declare function withPassport(passport: PassportLike | DevicePassport, customFetch?: typeof fetch): typeof fetch;
28
+ /**
29
+ * Generates an executable cURL command with correct browser headers.
30
+ */
31
+ declare function toCurl(passport: PassportLike | DevicePassport, url: string, options?: {
32
+ method?: string;
33
+ data?: any;
34
+ headers?: Record<string, string>;
35
+ }): string;
36
+
37
+ interface PlaywrightContextOptions {
38
+ userAgent: string;
39
+ viewport: {
40
+ width: number;
41
+ height: number;
42
+ };
43
+ deviceScaleFactor: number;
44
+ locale: string;
45
+ timezoneId: string;
46
+ geolocation?: {
47
+ latitude: number;
48
+ longitude: number;
49
+ accuracy?: number;
50
+ };
51
+ permissions?: string[];
52
+ extraHTTPHeaders: Record<string, string>;
53
+ hasTouch: boolean;
54
+ isMobile: boolean;
55
+ colorScheme?: 'light' | 'dark' | 'no-preference';
56
+ }
57
+ /**
58
+ * Builds Playwright BrowserContext options directly from a DevicePassport.
59
+ * Ready for `browser.newContext(getPlaywrightContext(passport))`.
60
+ */
61
+ declare function getPlaywrightContext(passport: DevicePassport): PlaywrightContextOptions;
62
+ /**
63
+ * Generates an in-page stealth script to patch runtime JavaScript APIs
64
+ * (navigator.webdriver, hardwareConcurrency, deviceMemory, WebGL unmasked vendor/renderer,
65
+ * navigator.userAgentData Client Hints, and Screen dimensions).
66
+ *
67
+ * 🔴 API-level spoofing is not enough on its own: `canvas.toDataURL()` and `gl.readPixels()`
68
+ * still return the **real** framebuffer, so a headless browser exposes SwiftShader while
69
+ * its UA claims a discrete GPU — and every persona on one machine hashes identically.
70
+ * The pixel-protection script is therefore appended here, so existing users get
71
+ * read-back-safe personas without changing their call sites.
72
+ *
73
+ * The noise is seeded from the passport seed: stable per account, different per account.
74
+ */
75
+ declare function getStealthScript(passport: DevicePassport): string;
76
+ /**
77
+ * Applies stealth injections and extra headers to a Playwright BrowserContext.
78
+ *
79
+ * @param context Playwright BrowserContext instance
80
+ * @param passport DevicePassport instance
81
+ */
82
+ declare function applyToPlaywrightContext(context: any, passport: DevicePassport): Promise<void>;
83
+
84
+ interface PuppeteerEmulationOptions {
85
+ launchArgs: string[];
86
+ defaultViewport: {
87
+ width: number;
88
+ height: number;
89
+ deviceScaleFactor: number;
90
+ isMobile: boolean;
91
+ hasTouch: boolean;
92
+ };
93
+ userAgent: string;
94
+ locale: string;
95
+ timezoneId: string;
96
+ extraHTTPHeaders: Record<string, string>;
97
+ }
98
+ /**
99
+ * Returns Puppeteer launch args and page emulation parameters matching the DevicePassport.
100
+ */
101
+ declare function getPuppeteerArgs(passport: DevicePassport): PuppeteerEmulationOptions;
102
+ /**
103
+ * Applies stealth injections, headers, viewport, and timezone emulation to a Puppeteer Page.
104
+ *
105
+ * @param page Puppeteer Page instance
106
+ * @param passport DevicePassport instance
107
+ */
108
+ declare function applyToPuppeteerPage(page: any, passport: DevicePassport): Promise<void>;
109
+
110
+ /**
111
+ * Raw Chrome DevTools Protocol adapter.
112
+ *
113
+ * 🔴 Why this exists (2026-11-04):
114
+ * Tools that drive Chrome over a bare CDP socket — `lite-browser`'s `cdp <method> [json]`
115
+ * channel, for example — cannot use the Playwright/Puppeteer adapters, because those
116
+ * hand back framework-shaped options. This adapter speaks plain CDP so any CDP client
117
+ * can apply a passport.
118
+ *
119
+ * The returned plan is deliberately **declarative**: a `send(method, params)` function
120
+ * applies every command in order. The caller owns the transport, so this module has no
121
+ * dependency and works over WebSocket, stdio, or an in-process socket.
122
+ */
123
+ interface CdpCommand {
124
+ method: string;
125
+ params?: Record<string, unknown>;
126
+ /** `sessionId` is required for page-scoped domains when using flattened sessions. */
127
+ sessionId?: string;
128
+ }
129
+ interface CdpPassportPlan {
130
+ /** Ordered commands to apply the passport to a target. */
131
+ commands: CdpCommand[];
132
+ /** Init scripts to install on every new document. */
133
+ initScripts: {
134
+ source: string;
135
+ }[];
136
+ /** Extra HTTP headers to set on the session. */
137
+ headers: Record<string, string>;
138
+ /** The raw stealth + pixel-protection script, for callers that prefer their own path. */
139
+ stealthScript: string;
140
+ }
141
+ /**
142
+ * Builds the ordered CDP command plan for a passport.
143
+ *
144
+ * Order matters: the UA override must precede navigation, and the init script has to be
145
+ * installed before the first document is created.
146
+ */
147
+ declare function getCdpPlan(passport: DevicePassport, sessionId?: string): CdpPassportPlan;
148
+ /**
149
+ * Applies a passport through a raw CDP transport.
150
+ *
151
+ * @param send Function that sends one CDP command and resolves with its result.
152
+ */
153
+ declare function applyCdpPassport(passport: DevicePassport, send: (command: CdpCommand) => Promise<unknown>, sessionId?: string): Promise<void>;
154
+
155
+ export { CANONICAL_HEADER_ORDER, applyCdpPassport, applyToPlaywrightContext, applyToPuppeteerPage, formatCanonicalHeaders, getCdpPlan, getPlaywrightContext, getPuppeteerArgs, getStealthScript, toCurl, withPassport };
156
+ export type { CdpCommand, CdpPassportPlan, PassportLike, PlaywrightContextOptions, PuppeteerEmulationOptions };
@@ -0,0 +1,156 @@
1
+ import { DevicePassport } from '../types/index.js';
2
+ import '../shared/device-passport.C_F1vBE8.js';
3
+
4
+ /**
5
+ * Standard Chromium browser header ordering.
6
+ * Anti-bot systems (Cloudflare, Akamai, DataDome, Kasada) strictly inspect
7
+ * the sequence of HTTP request headers. A mismatch in header order triggers
8
+ * immediate bot heuristics.
9
+ */
10
+ declare const CANONICAL_HEADER_ORDER: readonly string[];
11
+ /**
12
+ * Sorts and formats HTTP headers according to canonical browser ordering.
13
+ * Merges base headers with optional overrides.
14
+ */
15
+ declare function formatCanonicalHeaders(baseHeaders: Record<string, string>, overrides?: Record<string, string>): Record<string, string>;
16
+ interface PassportLike {
17
+ headers: Record<string, string>;
18
+ getHeaders?: (overrides?: Record<string, string>) => Record<string, string>;
19
+ }
20
+ /**
21
+ * Higher-order fetch function wrapping standard fetch with canonical DevicePassport headers.
22
+ * Ensures consistent TLS/HTTP persona across API calls, scraping requests, and webhooks.
23
+ *
24
+ * @param passport DevicePassport instance or object
25
+ * @param customFetch Optional fetch implementation (e.g. node-fetch, undici, or global fetch)
26
+ */
27
+ declare function withPassport(passport: PassportLike | DevicePassport, customFetch?: typeof fetch): typeof fetch;
28
+ /**
29
+ * Generates an executable cURL command with correct browser headers.
30
+ */
31
+ declare function toCurl(passport: PassportLike | DevicePassport, url: string, options?: {
32
+ method?: string;
33
+ data?: any;
34
+ headers?: Record<string, string>;
35
+ }): string;
36
+
37
+ interface PlaywrightContextOptions {
38
+ userAgent: string;
39
+ viewport: {
40
+ width: number;
41
+ height: number;
42
+ };
43
+ deviceScaleFactor: number;
44
+ locale: string;
45
+ timezoneId: string;
46
+ geolocation?: {
47
+ latitude: number;
48
+ longitude: number;
49
+ accuracy?: number;
50
+ };
51
+ permissions?: string[];
52
+ extraHTTPHeaders: Record<string, string>;
53
+ hasTouch: boolean;
54
+ isMobile: boolean;
55
+ colorScheme?: 'light' | 'dark' | 'no-preference';
56
+ }
57
+ /**
58
+ * Builds Playwright BrowserContext options directly from a DevicePassport.
59
+ * Ready for `browser.newContext(getPlaywrightContext(passport))`.
60
+ */
61
+ declare function getPlaywrightContext(passport: DevicePassport): PlaywrightContextOptions;
62
+ /**
63
+ * Generates an in-page stealth script to patch runtime JavaScript APIs
64
+ * (navigator.webdriver, hardwareConcurrency, deviceMemory, WebGL unmasked vendor/renderer,
65
+ * navigator.userAgentData Client Hints, and Screen dimensions).
66
+ *
67
+ * 🔴 API-level spoofing is not enough on its own: `canvas.toDataURL()` and `gl.readPixels()`
68
+ * still return the **real** framebuffer, so a headless browser exposes SwiftShader while
69
+ * its UA claims a discrete GPU — and every persona on one machine hashes identically.
70
+ * The pixel-protection script is therefore appended here, so existing users get
71
+ * read-back-safe personas without changing their call sites.
72
+ *
73
+ * The noise is seeded from the passport seed: stable per account, different per account.
74
+ */
75
+ declare function getStealthScript(passport: DevicePassport): string;
76
+ /**
77
+ * Applies stealth injections and extra headers to a Playwright BrowserContext.
78
+ *
79
+ * @param context Playwright BrowserContext instance
80
+ * @param passport DevicePassport instance
81
+ */
82
+ declare function applyToPlaywrightContext(context: any, passport: DevicePassport): Promise<void>;
83
+
84
+ interface PuppeteerEmulationOptions {
85
+ launchArgs: string[];
86
+ defaultViewport: {
87
+ width: number;
88
+ height: number;
89
+ deviceScaleFactor: number;
90
+ isMobile: boolean;
91
+ hasTouch: boolean;
92
+ };
93
+ userAgent: string;
94
+ locale: string;
95
+ timezoneId: string;
96
+ extraHTTPHeaders: Record<string, string>;
97
+ }
98
+ /**
99
+ * Returns Puppeteer launch args and page emulation parameters matching the DevicePassport.
100
+ */
101
+ declare function getPuppeteerArgs(passport: DevicePassport): PuppeteerEmulationOptions;
102
+ /**
103
+ * Applies stealth injections, headers, viewport, and timezone emulation to a Puppeteer Page.
104
+ *
105
+ * @param page Puppeteer Page instance
106
+ * @param passport DevicePassport instance
107
+ */
108
+ declare function applyToPuppeteerPage(page: any, passport: DevicePassport): Promise<void>;
109
+
110
+ /**
111
+ * Raw Chrome DevTools Protocol adapter.
112
+ *
113
+ * 🔴 Why this exists (2026-11-04):
114
+ * Tools that drive Chrome over a bare CDP socket — `lite-browser`'s `cdp <method> [json]`
115
+ * channel, for example — cannot use the Playwright/Puppeteer adapters, because those
116
+ * hand back framework-shaped options. This adapter speaks plain CDP so any CDP client
117
+ * can apply a passport.
118
+ *
119
+ * The returned plan is deliberately **declarative**: a `send(method, params)` function
120
+ * applies every command in order. The caller owns the transport, so this module has no
121
+ * dependency and works over WebSocket, stdio, or an in-process socket.
122
+ */
123
+ interface CdpCommand {
124
+ method: string;
125
+ params?: Record<string, unknown>;
126
+ /** `sessionId` is required for page-scoped domains when using flattened sessions. */
127
+ sessionId?: string;
128
+ }
129
+ interface CdpPassportPlan {
130
+ /** Ordered commands to apply the passport to a target. */
131
+ commands: CdpCommand[];
132
+ /** Init scripts to install on every new document. */
133
+ initScripts: {
134
+ source: string;
135
+ }[];
136
+ /** Extra HTTP headers to set on the session. */
137
+ headers: Record<string, string>;
138
+ /** The raw stealth + pixel-protection script, for callers that prefer their own path. */
139
+ stealthScript: string;
140
+ }
141
+ /**
142
+ * Builds the ordered CDP command plan for a passport.
143
+ *
144
+ * Order matters: the UA override must precede navigation, and the init script has to be
145
+ * installed before the first document is created.
146
+ */
147
+ declare function getCdpPlan(passport: DevicePassport, sessionId?: string): CdpPassportPlan;
148
+ /**
149
+ * Applies a passport through a raw CDP transport.
150
+ *
151
+ * @param send Function that sends one CDP command and resolves with its result.
152
+ */
153
+ declare function applyCdpPassport(passport: DevicePassport, send: (command: CdpCommand) => Promise<unknown>, sessionId?: string): Promise<void>;
154
+
155
+ export { CANONICAL_HEADER_ORDER, applyCdpPassport, applyToPlaywrightContext, applyToPuppeteerPage, formatCanonicalHeaders, getCdpPlan, getPlaywrightContext, getPuppeteerArgs, getStealthScript, toCurl, withPassport };
156
+ export type { CdpCommand, CdpPassportPlan, PassportLike, PlaywrightContextOptions, PuppeteerEmulationOptions };
@@ -0,0 +1,3 @@
1
+ export { C as CANONICAL_HEADER_ORDER, a as applyCdpPassport, b as applyToPlaywrightContext, c as applyToPuppeteerPage, f as formatCanonicalHeaders, g as getCdpPlan, d as getPlaywrightContext, e as getPuppeteerArgs, h as getStealthScript, t as toCurl, w as withPassport } from '../shared/device-passport.NHw_f6HT.mjs';
2
+ import 'node:crypto';
3
+ import '../shared/device-passport.BBf9OKap.mjs';