device-passport 1.1.0 → 1.2.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/CHANGELOG.md +10 -7
- package/README.md +41 -0
- package/assets/ego-profile-manager.png +0 -0
- package/dist/adapters/index.cjs +2 -2
- package/dist/adapters/index.d.cts +4 -94
- package/dist/adapters/index.d.mts +4 -94
- package/dist/adapters/index.d.ts +4 -94
- package/dist/adapters/index.mjs +2 -2
- package/dist/ego/index.cjs +22 -0
- package/dist/ego/index.d.cts +5 -0
- package/dist/ego/index.d.mts +5 -0
- package/dist/ego/index.d.ts +5 -0
- package/dist/ego/index.mjs +8 -0
- package/dist/evaluator/index.cjs +22 -584
- package/dist/evaluator/index.mjs +3 -564
- package/dist/geo/index.cjs +1 -1
- package/dist/geo/index.d.cts +4 -0
- package/dist/geo/index.d.mts +4 -0
- package/dist/geo/index.d.ts +4 -0
- package/dist/geo/index.mjs +2 -2
- package/dist/index.cjs +41 -441
- package/dist/index.d.cts +10 -198
- package/dist/index.d.mts +10 -198
- package/dist/index.d.ts +10 -198
- package/dist/index.mjs +7 -418
- package/dist/shared/device-passport.BGfRcQNh.mjs +565 -0
- package/dist/shared/{device-passport.BPd2-w8e.cjs → device-passport.BKtmLzPt.cjs} +4 -3
- package/dist/shared/{device-passport.BBf9OKap.mjs → device-passport.BPQj0qdT.mjs} +4 -3
- package/dist/shared/device-passport.CDS7xrj8.d.ts +469 -0
- package/dist/shared/device-passport.CfLes-lq.d.cts +469 -0
- package/dist/shared/device-passport.CsOWqPIr.d.cts +77 -0
- package/dist/shared/device-passport.D7pEnyp2.d.ts +77 -0
- package/dist/shared/{device-passport.CLaBZWUV.cjs → device-passport.D9xW6R0B.cjs} +4 -2
- package/dist/shared/device-passport.DirQmSd4.d.cts +47 -0
- package/dist/shared/device-passport.DirQmSd4.d.mts +47 -0
- package/dist/shared/device-passport.DirQmSd4.d.ts +47 -0
- package/dist/shared/device-passport.EK4RX7Xd.cjs +584 -0
- package/dist/shared/device-passport.ZBspe4ZW.d.mts +77 -0
- package/dist/shared/device-passport.dVEqzSEb.d.mts +469 -0
- package/dist/shared/{device-passport.NHw_f6HT.mjs → device-passport.gNo82fQ5.mjs} +5 -3
- package/dist/shared/device-passport.kekU28UM.mjs +705 -0
- package/dist/shared/device-passport.qL4tjwc0.cjs +718 -0
- package/dist/storage/index.d.cts +3 -34
- package/dist/storage/index.d.mts +3 -34
- package/dist/storage/index.d.ts +3 -34
- package/dist/types/index.d.cts +183 -1
- package/dist/types/index.d.mts +183 -1
- package/dist/types/index.d.ts +183 -1
- package/package.json +6 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,201 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
export { CANONICAL_HEADER_ORDER, CdpCommand, CdpPassportPlan, PassportLike, applyCdpPassport, applyToPlaywrightContext, applyToPuppeteerPage, formatCanonicalHeaders, getCdpPlan, getPlaywrightContext, getPuppeteerArgs, getStealthScript, toCurl, withPassport } from './adapters/index.js';
|
|
5
|
-
import { StorageAdapter } from './storage/index.js';
|
|
6
|
-
export { JSONFileStorage, JSONFileStorageOptions, MemoryStorage, MemoryStorageOptions } from './storage/index.js';
|
|
7
|
-
import { L as LocaleProfile } from './shared/device-passport.C_F1vBE8.js';
|
|
8
|
-
export { C as CountryGeoDefinition, G as GeoContext, a as GeoCoordinates, b as GeoLocation, c as GeoOptions, d as LanguageWeight } from './shared/device-passport.C_F1vBE8.js';
|
|
1
|
+
export { A as AccountProfileManager, a as AccountProfileManagerOptions, B as BindProfileOptions, b as BuildEgoSessionPlanOptions, C as CreatePassportInputOptions, c as CreateSessionPlanOptions, D as DevicePassportInstance, E as EgoNativeBridge, P as PROXY_MISSING_NOTE, d as PROXY_RESOLUTION_NOTE, e as PassportManager, f as PassportManagerOptions, g as buildEgoSessionPlan, h as buildProxyDeclaration, i as createEgoBridge, j as createPassport, k as defaultTaskSpaceName, l as getEgoNativeBridge, m as getProfileReadiness } from './shared/device-passport.CDS7xrj8.js';
|
|
2
|
+
import { OperatingSystemProfile, HardwareProfile, SupportedPlatform, SupportedArchitecture, SupportedBrowserName, BrandVersion, UserAgentClientHints, PassportGeneratorOptions, DevicePassport } from './types/index.js';
|
|
3
|
+
export { BenchmarkMetrics, BrowserProfile, CdpCommand, CdpInitScript, CdpPassportPlan, ClientHintsHeaders, ConsistencyCategory, ConsistencyCheck, CpuProfile, DevicePassportContext, DeviceProfile, EgoAccountProfile, EgoLiteBridge, EgoProfile, EgoProfileReadiness, EgoProxyBinding, EgoProxyDeclaration, EgoSessionPlan, EntropyAnalysis, EvaluationGrade, EvaluationStatus, GpuProfile, MemoryProfile, PassportEvaluation, ScreenProfile } from './types/index.js';
|
|
9
4
|
export { ALPHA3_TO_ALPHA2, COUNTRY_LOCALES, COUNTRY_NAME_TO_CODE, CountryLocaleConfig, DEFAULT_ACCEPT_LANGUAGE, DEFAULT_COUNTRY, DEFAULT_LOCALE, DEFAULT_TIMEZONE, GEO_LOCALES, GeoDetectOptions, TIMEZONE_MATRIX, TIMEZONE_TO_COUNTRY, alignGeoContext, detectCountry, detectGeoFromUrl, extractCountryFromProxyUrl, formatAcceptLanguage, getAllSupportedCountries, getCountryConfig, getCountryForTimezone, getDefaultTimezoneForCountry, getLocaleProfile, getTimezoneOffsetMinutes, getTimezonesForCountry, hasCountryConfig, isGeoAligned, isTimezoneAlignedWithCountry, isValidCountryCode, isValidTimezone, listAllTimezones, normalizeCountryCode, parseAcceptLanguage, toGeoLocation, toLocaleProfile } from './geo/index.js';
|
|
5
|
+
export { CANONICAL_HEADER_ORDER, PassportLike, applyCdpPassport, formatCanonicalHeaders, getCdpPlan, toCurl, withPassport } from './adapters/index.js';
|
|
6
|
+
export { P as PlaywrightContextOptions, a as PuppeteerEmulationOptions, b as applyToPlaywrightContext, c as applyToPuppeteerPage, g as getPlaywrightContext, d as getPuppeteerArgs, e as getStealthScript } from './shared/device-passport.D7pEnyp2.js';
|
|
7
|
+
export { S as StorageAdapter } from './shared/device-passport.DirQmSd4.js';
|
|
8
|
+
export { JSONFileStorage, JSONFileStorageOptions, MemoryStorage, MemoryStorageOptions } from './storage/index.js';
|
|
10
9
|
export { BASELINE_OPTIMAL_ENTROPY, BROWSER_BASELINE_FREQUENCIES, COUNTRY_PRIMARY_LANGUAGES, COUNTRY_TIMEZONE_MAP, CoherenceEvaluationResult, Contradiction, ContradictionCategory, ContradictionSeverity, EntropyAnalysisResult, HeaderEntropyProfile, MIN_STRUCTURAL_ENTROPY, MathematicalModelFormalism, OPTIMAL_CHAR_ENTROPY_MAX, OPTIMAL_CHAR_ENTROPY_MIN, OPTIMAL_ENTROPY_MAX, OPTIMAL_ENTROPY_MIN, SubspaceEvaluation, analyzeHeaderEntropy, calculateKLDivergence, calculateShannonEntropy, calculateStructuralEntropy, detectAllContradictions, detectClientHintsContradictions, detectGeoChronoContradictions, detectHardwareContradictions, detectOSBrowserContradictions, evaluateCoherence, evaluateGeoAlignment, evaluatePassport } from './evaluator/index.js';
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* DevicePassportInstance encapsulates a single concrete, zero-contradiction digital identity persona.
|
|
14
|
-
*
|
|
15
|
-
* Provides runtime adapters for:
|
|
16
|
-
* 1. Lightweight HTTP mode (Fetch, Axios, Undici, Got, cURL) with strict canonical header ordering.
|
|
17
|
-
* 2. Heavyweight browser automation (Playwright, Puppeteer, ego-lite) with deep fingerprint masking.
|
|
18
|
-
* 3. Self-evaluating consistency diagnostics based on empirical telemetry models.
|
|
19
|
-
*/
|
|
20
|
-
declare class DevicePassportInstance {
|
|
21
|
-
readonly profile: DevicePassport;
|
|
22
|
-
constructor(profile: DevicePassport);
|
|
23
|
-
/**
|
|
24
|
-
* Factory method to create an instance from a plain DevicePassport object.
|
|
25
|
-
*/
|
|
26
|
-
static from(profile: DevicePassport): DevicePassportInstance;
|
|
27
|
-
get id(): string;
|
|
28
|
-
get seed(): string;
|
|
29
|
-
get createdAt(): string;
|
|
30
|
-
get browser(): BrowserProfile;
|
|
31
|
-
get os(): OperatingSystemProfile;
|
|
32
|
-
get hardware(): HardwareProfile;
|
|
33
|
-
get locale(): LocaleProfile;
|
|
34
|
-
get headers(): Record<string, string>;
|
|
35
|
-
get clientHints(): UserAgentClientHints;
|
|
36
|
-
get context(): DevicePassportContext;
|
|
37
|
-
get userAgent(): string;
|
|
38
|
-
get timezone(): string;
|
|
39
|
-
get playwrightContext(): PlaywrightContextOptions;
|
|
40
|
-
get puppeteerArgs(): PuppeteerEmulationOptions;
|
|
41
|
-
get evaluation(): PassportEvaluation | undefined;
|
|
42
|
-
/**
|
|
43
|
-
* Returns HTTP headers formatted in strict canonical browser sequence.
|
|
44
|
-
* Essential for anti-bot evasion against Cloudflare, Akamai, and DataDome.
|
|
45
|
-
*/
|
|
46
|
-
getHeaders(overrides?: Record<string, string>): Record<string, string>;
|
|
47
|
-
/**
|
|
48
|
-
* Returns a higher-order fetch function wrapping standard fetch with this passport's canonical persona.
|
|
49
|
-
*/
|
|
50
|
-
wrapFetch(customFetch?: typeof fetch): typeof fetch;
|
|
51
|
-
/**
|
|
52
|
-
* Alias for wrapFetch.
|
|
53
|
-
*/
|
|
54
|
-
withPassport(customFetch?: typeof fetch): typeof fetch;
|
|
55
|
-
/**
|
|
56
|
-
* Generates a copy-pasteable cURL command with correct browser headers and User-Agent.
|
|
57
|
-
*/
|
|
58
|
-
toCurl(url: string, options?: {
|
|
59
|
-
method?: string;
|
|
60
|
-
data?: any;
|
|
61
|
-
headers?: Record<string, string>;
|
|
62
|
-
}): string;
|
|
63
|
-
/**
|
|
64
|
-
* Generates Playwright BrowserContext options.
|
|
65
|
-
* Usage:
|
|
66
|
-
* ```ts
|
|
67
|
-
* const context = await browser.newContext(passport.getPlaywrightContext());
|
|
68
|
-
* ```
|
|
69
|
-
*/
|
|
70
|
-
getPlaywrightContext(): PlaywrightContextOptions;
|
|
71
|
-
/**
|
|
72
|
-
* Returns Puppeteer launch args and page emulation parameters.
|
|
73
|
-
*/
|
|
74
|
-
getPuppeteerArgs(): PuppeteerEmulationOptions;
|
|
75
|
-
/**
|
|
76
|
-
* Generates an in-page stealth script to patch runtime JavaScript APIs
|
|
77
|
-
* (navigator.webdriver, hardwareConcurrency, deviceMemory, WebGL, Client Hints).
|
|
78
|
-
*/
|
|
79
|
-
getStealthScript(): string;
|
|
80
|
-
/**
|
|
81
|
-
* Injects stealth scripts and extra HTTP headers into a Playwright BrowserContext.
|
|
82
|
-
*/
|
|
83
|
-
applyToPlaywright(context: any): Promise<void>;
|
|
84
|
-
/**
|
|
85
|
-
* Injects stealth scripts and emulation parameters into a Puppeteer Page.
|
|
86
|
-
*/
|
|
87
|
-
applyToPuppeteer(page: any): Promise<void>;
|
|
88
|
-
/**
|
|
89
|
-
* Evaluates cross-layer consistency and Shannon entropy.
|
|
90
|
-
* Caches the result on `this.profile.evaluation`.
|
|
91
|
-
*/
|
|
92
|
-
evaluate(forceRecompute?: boolean): PassportEvaluation;
|
|
93
|
-
/**
|
|
94
|
-
* Returns the underlying raw DevicePassport data object.
|
|
95
|
-
*/
|
|
96
|
-
toJSON(): DevicePassport;
|
|
97
|
-
toString(): string;
|
|
98
|
-
}
|
|
99
|
-
interface CreatePassportInputOptions extends PassportGeneratorOptions {
|
|
100
|
-
/** Optional file path or storage adapter to persist this passport deterministically */
|
|
101
|
-
store?: string | StorageAdapter<DevicePassport>;
|
|
102
|
-
}
|
|
103
|
-
/**
|
|
104
|
-
* Universal polymorphic factory for creating a DevicePassportInstance.
|
|
105
|
-
*
|
|
106
|
-
* Supports:
|
|
107
|
-
* - One-line string seed: `createPassport('alice', { geo: 'US' })`
|
|
108
|
-
* - Full options object: `createPassport({ seed: 'bot1', store: './passports.json' })`
|
|
109
|
-
* - Existing raw profile: `createPassport(rawProfile)`
|
|
110
|
-
* - Zero-config ephemeral persona: `createPassport()`
|
|
111
|
-
*/
|
|
112
|
-
declare function createPassport(seedOrOptionsOrProfile?: string | CreatePassportInputOptions | DevicePassport, extraOptions?: CreatePassportInputOptions): DevicePassportInstance;
|
|
113
|
-
|
|
114
|
-
interface PassportManagerOptions {
|
|
115
|
-
/**
|
|
116
|
-
* Storage backend for persisting passports:
|
|
117
|
-
* - String path (e.g. './passports.json') -> creates JSONFileStorage automatically.
|
|
118
|
-
* - StorageAdapter instance -> custom pluggable storage (Memory, File, Redis, DB).
|
|
119
|
-
* - Omitted or 'memory' -> uses MemoryStorage.
|
|
120
|
-
*/
|
|
121
|
-
store?: string | StorageAdapter<DevicePassport>;
|
|
122
|
-
/**
|
|
123
|
-
* Default geographic country code for newly generated personas (e.g. 'US', 'GB', 'DE', 'JP').
|
|
124
|
-
* Defaults to 'US'.
|
|
125
|
-
*/
|
|
126
|
-
defaultGeo?: string;
|
|
127
|
-
/**
|
|
128
|
-
* Default operating system preference ('macOS' | 'Windows').
|
|
129
|
-
*/
|
|
130
|
-
defaultOS?: SupportedPlatform;
|
|
131
|
-
/**
|
|
132
|
-
* Default browser preference ('Chrome' | 'Edge').
|
|
133
|
-
*/
|
|
134
|
-
defaultBrowser?: SupportedBrowserName;
|
|
135
|
-
/**
|
|
136
|
-
* Generator function. Defaults to engine's generatePassport.
|
|
137
|
-
*/
|
|
138
|
-
generator?: (options?: PassportGeneratorOptions) => DevicePassport;
|
|
139
|
-
}
|
|
140
|
-
/**
|
|
141
|
-
* PassportManager manages fleet-scale digital device identities.
|
|
142
|
-
*
|
|
143
|
-
* Guarantees true sticky identity across runs:
|
|
144
|
-
* Calling `getPassport(seed)` with the same seed (e.g. account ID, proxy IP, username)
|
|
145
|
-
* will consistently return the exact same device passport across restarts and cron jobs.
|
|
146
|
-
*/
|
|
147
|
-
declare class PassportManager {
|
|
148
|
-
readonly storage: StorageAdapter<DevicePassport>;
|
|
149
|
-
readonly defaultGeo: string;
|
|
150
|
-
readonly defaultOS?: SupportedPlatform;
|
|
151
|
-
readonly defaultBrowser?: SupportedBrowserName;
|
|
152
|
-
private readonly generator;
|
|
153
|
-
constructor(options?: PassportManagerOptions);
|
|
154
|
-
/**
|
|
155
|
-
* Retrieves an existing sticky passport by seed or deterministically generates
|
|
156
|
-
* and persists a new one if it does not already exist.
|
|
157
|
-
*
|
|
158
|
-
* @param seed Deterministic seed (user ID, account handle, proxy IP, worker slot)
|
|
159
|
-
* @param options Generator options to use if persona needs to be created
|
|
160
|
-
*/
|
|
161
|
-
getPassport(seed: string | number, options?: PassportGeneratorOptions): Promise<DevicePassportInstance>;
|
|
162
|
-
/**
|
|
163
|
-
* Synchronous passport retrieval for environments backed by MemoryStorage or JSONFileStorage.
|
|
164
|
-
*/
|
|
165
|
-
getPassportSync(seed: string | number, options?: PassportGeneratorOptions): DevicePassportInstance;
|
|
166
|
-
/**
|
|
167
|
-
* Forces re-generation and overwrite of a passport for the given seed.
|
|
168
|
-
*/
|
|
169
|
-
renewPassport(seed: string | number, options?: PassportGeneratorOptions): Promise<DevicePassportInstance>;
|
|
170
|
-
/**
|
|
171
|
-
* Check if a passport exists in storage for the given seed.
|
|
172
|
-
*/
|
|
173
|
-
hasPassport(seed: string | number): Promise<boolean>;
|
|
174
|
-
/**
|
|
175
|
-
* Delete a passport from storage.
|
|
176
|
-
*/
|
|
177
|
-
deletePassport(seed: string | number): Promise<boolean>;
|
|
178
|
-
/**
|
|
179
|
-
* Import an existing passport into storage.
|
|
180
|
-
*/
|
|
181
|
-
importPassport(passport: DevicePassport | DevicePassportInstance): Promise<DevicePassportInstance>;
|
|
182
|
-
/**
|
|
183
|
-
* List all stored seeds.
|
|
184
|
-
*/
|
|
185
|
-
listSeeds(): Promise<string[]>;
|
|
186
|
-
/**
|
|
187
|
-
* List all stored passports as DevicePassportInstance objects.
|
|
188
|
-
*/
|
|
189
|
-
listPassports(): Promise<DevicePassportInstance[]>;
|
|
190
|
-
/**
|
|
191
|
-
* Clear all stored passports.
|
|
192
|
-
*/
|
|
193
|
-
clear(): Promise<void>;
|
|
194
|
-
/**
|
|
195
|
-
* Return number of stored personas.
|
|
196
|
-
*/
|
|
197
|
-
count(): Promise<number>;
|
|
198
|
-
}
|
|
10
|
+
export { C as CountryGeoDefinition, G as GeoContext, a as GeoCoordinates, b as GeoLocation, c as GeoOptions, d as LanguageWeight, L as LocaleProfile } from './shared/device-passport.C_F1vBE8.js';
|
|
199
11
|
|
|
200
12
|
/**
|
|
201
13
|
* Zero-Contradiction Hardware Matrix for Device Passport.
|
|
@@ -472,5 +284,5 @@ declare function formatComparativeMatrixJSON(): string;
|
|
|
472
284
|
*/
|
|
473
285
|
declare const VERSION = "1.0.0";
|
|
474
286
|
|
|
475
|
-
export { ALL_PRESETS, BENCHMARK_METRICS_METADATA, BrandVersion,
|
|
476
|
-
export type { BenchmarkReportSummary, CanvasNoiseConfig, ClientHintsGenerateOptions,
|
|
287
|
+
export { ALL_PRESETS, BENCHMARK_METRICS_METADATA, BrandVersion, CHROME_VERSIONS, COMPARATIVE_DATASET, DevicePassport, EDGE_VERSIONS, HardwareProfile, MACOS_PRESETS, OperatingSystemProfile, PassportGeneratorOptions, SupportedArchitecture, SupportedBrowserName, SupportedPlatform, UserAgentClientHints, VERSION, WINDOWS_PRESETS, buildUserAgent, createDeterministicPRNG, createMulberry32, fnv1a, formatComparativeMatrixJSON, formatComparativeMatrixLaTeX, formatComparativeMatrixMarkdown, formatStructuredBrandList, generateBrandVersions, generateDevicePassport, generatePassport, generateUserAgentClientHints, getApifyHeadersIfAvailable, getHardwarePresets, getPixelProtectionConfig, getPixelProtectionScript, getStaticFallbackHeaders, murmur3, parseStructuredBrandList, runComparativeBenchmark, validateHardwareContradictions };
|
|
288
|
+
export type { BenchmarkReportSummary, CanvasNoiseConfig, ClientHintsGenerateOptions, DeviceMatrixPreset, LibraryBenchmarkProfile, MetricMetadata, MetricScore };
|
package/dist/index.mjs
CHANGED
|
@@ -1,425 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
export { A as ALL_PRESETS, C as CANONICAL_HEADER_ORDER,
|
|
3
|
-
import { detectAllContradictions, analyzeHeaderEntropy } from './evaluator/index.mjs';
|
|
4
|
-
export { BASELINE_OPTIMAL_ENTROPY, BROWSER_BASELINE_FREQUENCIES, COUNTRY_PRIMARY_LANGUAGES, COUNTRY_TIMEZONE_MAP, MIN_STRUCTURAL_ENTROPY, OPTIMAL_CHAR_ENTROPY_MAX, OPTIMAL_CHAR_ENTROPY_MIN, OPTIMAL_ENTROPY_MAX, OPTIMAL_ENTROPY_MIN, calculateKLDivergence, calculateShannonEntropy, calculateStructuralEntropy, detectClientHintsContradictions, detectGeoChronoContradictions, detectHardwareContradictions, detectOSBrowserContradictions, evaluateCoherence, evaluateGeoAlignment, evaluatePassport } from './evaluator/index.mjs';
|
|
5
|
-
import { J as JSONFileStorage, M as MemoryStorage } from './shared/device-passport.CyQtcZeD.mjs';
|
|
1
|
+
export { A as AccountProfileManager, D as DevicePassportInstance, P as PROXY_MISSING_NOTE, a as PROXY_RESOLUTION_NOTE, h as PassportManager, b as buildEgoSessionPlan, c as buildProxyDeclaration, d as createEgoBridge, i as createPassport, e as defaultTaskSpaceName, g as getEgoNativeBridge, f as getProfileReadiness } from './shared/device-passport.kekU28UM.mjs';
|
|
2
|
+
export { A as ALL_PRESETS, C as CANONICAL_HEADER_ORDER, i as CHROME_VERSIONS, E as EDGE_VERSIONS, M as MACOS_PRESETS, W as WINDOWS_PRESETS, a as applyCdpPassport, b as applyToPlaywrightContext, c as applyToPuppeteerPage, j as buildUserAgent, k as createDeterministicPRNG, l as createMulberry32, m as fnv1a, f as formatCanonicalHeaders, n as formatStructuredBrandList, o as generateBrandVersions, p as generateDevicePassport, q as generatePassport, r as generateUserAgentClientHints, s as getApifyHeadersIfAvailable, g as getCdpPlan, u as getHardwarePresets, v as getPixelProtectionConfig, x as getPixelProtectionScript, d as getPlaywrightContext, e as getPuppeteerArgs, y as getStaticFallbackHeaders, h as getStealthScript, z as murmur3, B as parseStructuredBrandList, t as toCurl, D as validateHardwareContradictions, w as withPassport } from './shared/device-passport.gNo82fQ5.mjs';
|
|
6
3
|
export { GEO_LOCALES, TIMEZONE_MATRIX, detectGeoFromUrl, getLocaleProfile, isValidCountryCode } from './geo/index.mjs';
|
|
7
|
-
export {
|
|
4
|
+
export { J as JSONFileStorage, M as MemoryStorage } from './shared/device-passport.CyQtcZeD.mjs';
|
|
5
|
+
export { evaluateCoherence, evaluateGeoAlignment, evaluatePassport } from './evaluator/index.mjs';
|
|
6
|
+
export { A as ALPHA3_TO_ALPHA2, C as COUNTRY_LOCALES, b as COUNTRY_NAME_TO_CODE, D as DEFAULT_ACCEPT_LANGUAGE, c as DEFAULT_COUNTRY, d as DEFAULT_LOCALE, f as DEFAULT_TIMEZONE, T as TIMEZONE_TO_COUNTRY, a as alignGeoContext, g as detectCountry, e as extractCountryFromProxyUrl, i as formatAcceptLanguage, j as getAllSupportedCountries, k as getCountryConfig, l as getCountryForTimezone, m as getDefaultTimezoneForCountry, n as getTimezoneOffsetMinutes, o as getTimezonesForCountry, h as hasCountryConfig, p as isGeoAligned, q as isTimezoneAlignedWithCountry, r as isValidTimezone, s as listAllTimezones, u as normalizeCountryCode, v as parseAcceptLanguage, w as toGeoLocation, t as toLocaleProfile } from './shared/device-passport.BPQj0qdT.mjs';
|
|
7
|
+
export { B as BASELINE_OPTIMAL_ENTROPY, c as BROWSER_BASELINE_FREQUENCIES, C as COUNTRY_PRIMARY_LANGUAGES, e as COUNTRY_TIMEZONE_MAP, M as MIN_STRUCTURAL_ENTROPY, O as OPTIMAL_CHAR_ENTROPY_MAX, f as OPTIMAL_CHAR_ENTROPY_MIN, g as OPTIMAL_ENTROPY_MAX, h as OPTIMAL_ENTROPY_MIN, a as analyzeHeaderEntropy, i as calculateKLDivergence, j as calculateShannonEntropy, k as calculateStructuralEntropy, d as detectAllContradictions, l as detectClientHintsContradictions, b as detectGeoChronoContradictions, m as detectHardwareContradictions, n as detectOSBrowserContradictions } from './shared/device-passport.BGfRcQNh.mjs';
|
|
8
8
|
import 'node:crypto';
|
|
9
9
|
import 'node:fs';
|
|
10
10
|
import 'node:path';
|
|
11
11
|
|
|
12
|
-
class DevicePassportInstance {
|
|
13
|
-
profile;
|
|
14
|
-
constructor(profile) {
|
|
15
|
-
if (!profile) {
|
|
16
|
-
throw new Error("[DevicePassportInstance] Profile cannot be null or undefined");
|
|
17
|
-
}
|
|
18
|
-
this.profile = profile;
|
|
19
|
-
}
|
|
20
|
-
/**
|
|
21
|
-
* Factory method to create an instance from a plain DevicePassport object.
|
|
22
|
-
*/
|
|
23
|
-
static from(profile) {
|
|
24
|
-
return new DevicePassportInstance(profile);
|
|
25
|
-
}
|
|
26
|
-
// ==========================================
|
|
27
|
-
// Getters for core profile facets
|
|
28
|
-
// ==========================================
|
|
29
|
-
get id() {
|
|
30
|
-
return this.profile.id;
|
|
31
|
-
}
|
|
32
|
-
get seed() {
|
|
33
|
-
return this.profile.seed;
|
|
34
|
-
}
|
|
35
|
-
get createdAt() {
|
|
36
|
-
return this.profile.createdAt;
|
|
37
|
-
}
|
|
38
|
-
get browser() {
|
|
39
|
-
return this.profile.browser;
|
|
40
|
-
}
|
|
41
|
-
get os() {
|
|
42
|
-
return this.profile.os;
|
|
43
|
-
}
|
|
44
|
-
get hardware() {
|
|
45
|
-
return this.profile.hardware;
|
|
46
|
-
}
|
|
47
|
-
get locale() {
|
|
48
|
-
return this.profile.locale;
|
|
49
|
-
}
|
|
50
|
-
get headers() {
|
|
51
|
-
return this.profile.headers;
|
|
52
|
-
}
|
|
53
|
-
get clientHints() {
|
|
54
|
-
return this.profile.clientHints;
|
|
55
|
-
}
|
|
56
|
-
get context() {
|
|
57
|
-
return this.profile.context;
|
|
58
|
-
}
|
|
59
|
-
get userAgent() {
|
|
60
|
-
return this.profile.headers["user-agent"] || this.profile.browser.userAgent;
|
|
61
|
-
}
|
|
62
|
-
get timezone() {
|
|
63
|
-
return this.profile.locale.timezone;
|
|
64
|
-
}
|
|
65
|
-
get playwrightContext() {
|
|
66
|
-
return this.getPlaywrightContext();
|
|
67
|
-
}
|
|
68
|
-
get puppeteerArgs() {
|
|
69
|
-
return this.getPuppeteerArgs();
|
|
70
|
-
}
|
|
71
|
-
get evaluation() {
|
|
72
|
-
return this.profile.evaluation;
|
|
73
|
-
}
|
|
74
|
-
// ==========================================
|
|
75
|
-
// Lightweight HTTP Mode Adapters
|
|
76
|
-
// ==========================================
|
|
77
|
-
/**
|
|
78
|
-
* Returns HTTP headers formatted in strict canonical browser sequence.
|
|
79
|
-
* Essential for anti-bot evasion against Cloudflare, Akamai, and DataDome.
|
|
80
|
-
*/
|
|
81
|
-
getHeaders(overrides) {
|
|
82
|
-
return formatCanonicalHeaders(this.profile.headers, overrides);
|
|
83
|
-
}
|
|
84
|
-
/**
|
|
85
|
-
* Returns a higher-order fetch function wrapping standard fetch with this passport's canonical persona.
|
|
86
|
-
*/
|
|
87
|
-
wrapFetch(customFetch) {
|
|
88
|
-
return withPassport(this, customFetch);
|
|
89
|
-
}
|
|
90
|
-
/**
|
|
91
|
-
* Alias for wrapFetch.
|
|
92
|
-
*/
|
|
93
|
-
withPassport(customFetch) {
|
|
94
|
-
return withPassport(this, customFetch);
|
|
95
|
-
}
|
|
96
|
-
/**
|
|
97
|
-
* Generates a copy-pasteable cURL command with correct browser headers and User-Agent.
|
|
98
|
-
*/
|
|
99
|
-
toCurl(url, options) {
|
|
100
|
-
return toCurl(this, url, options);
|
|
101
|
-
}
|
|
102
|
-
// ==========================================
|
|
103
|
-
// Heavyweight Browser Automation Adapters
|
|
104
|
-
// ==========================================
|
|
105
|
-
/**
|
|
106
|
-
* Generates Playwright BrowserContext options.
|
|
107
|
-
* Usage:
|
|
108
|
-
* ```ts
|
|
109
|
-
* const context = await browser.newContext(passport.getPlaywrightContext());
|
|
110
|
-
* ```
|
|
111
|
-
*/
|
|
112
|
-
getPlaywrightContext() {
|
|
113
|
-
return getPlaywrightContext(this.profile);
|
|
114
|
-
}
|
|
115
|
-
/**
|
|
116
|
-
* Returns Puppeteer launch args and page emulation parameters.
|
|
117
|
-
*/
|
|
118
|
-
getPuppeteerArgs() {
|
|
119
|
-
return getPuppeteerArgs(this.profile);
|
|
120
|
-
}
|
|
121
|
-
/**
|
|
122
|
-
* Generates an in-page stealth script to patch runtime JavaScript APIs
|
|
123
|
-
* (navigator.webdriver, hardwareConcurrency, deviceMemory, WebGL, Client Hints).
|
|
124
|
-
*/
|
|
125
|
-
getStealthScript() {
|
|
126
|
-
return getStealthScript(this.profile);
|
|
127
|
-
}
|
|
128
|
-
/**
|
|
129
|
-
* Injects stealth scripts and extra HTTP headers into a Playwright BrowserContext.
|
|
130
|
-
*/
|
|
131
|
-
async applyToPlaywright(context) {
|
|
132
|
-
await applyToPlaywrightContext(context, this.profile);
|
|
133
|
-
}
|
|
134
|
-
/**
|
|
135
|
-
* Injects stealth scripts and emulation parameters into a Puppeteer Page.
|
|
136
|
-
*/
|
|
137
|
-
async applyToPuppeteer(page) {
|
|
138
|
-
await applyToPuppeteerPage(page, this.profile);
|
|
139
|
-
}
|
|
140
|
-
// ==========================================
|
|
141
|
-
// Consistency & Diagnostics
|
|
142
|
-
// ==========================================
|
|
143
|
-
/**
|
|
144
|
-
* Evaluates cross-layer consistency and Shannon entropy.
|
|
145
|
-
* Caches the result on `this.profile.evaluation`.
|
|
146
|
-
*/
|
|
147
|
-
evaluate(forceRecompute = false) {
|
|
148
|
-
if (this.profile.evaluation && !forceRecompute) {
|
|
149
|
-
return this.profile.evaluation;
|
|
150
|
-
}
|
|
151
|
-
try {
|
|
152
|
-
const contradictions = detectAllContradictions(this.profile);
|
|
153
|
-
let estimatedBits = 48;
|
|
154
|
-
let collisionRisk = "very_low";
|
|
155
|
-
try {
|
|
156
|
-
const entropy = analyzeHeaderEntropy(this.profile.headers);
|
|
157
|
-
if (entropy) {
|
|
158
|
-
estimatedBits = entropy.estimatedBits;
|
|
159
|
-
collisionRisk = entropy.collisionRisk;
|
|
160
|
-
}
|
|
161
|
-
} catch {
|
|
162
|
-
}
|
|
163
|
-
const totalPenalty = contradictions.reduce((sum, c) => sum + c.impactPenalty, 0);
|
|
164
|
-
const overallScore = Math.max(0, Math.min(100, Math.round(100 - totalPenalty)));
|
|
165
|
-
const status = overallScore >= 90 ? "PASS" : overallScore >= 70 ? "WARN" : "FAIL";
|
|
166
|
-
const grade = overallScore >= 95 ? "A+" : overallScore >= 85 ? "A" : overallScore >= 70 ? "B" : overallScore >= 50 ? "C" : "F";
|
|
167
|
-
const checks = [
|
|
168
|
-
{
|
|
169
|
-
id: "chk_os_ua_alignment",
|
|
170
|
-
name: "OS and User-Agent Alignment",
|
|
171
|
-
category: "os_ua_alignment",
|
|
172
|
-
passed: !contradictions.some((c) => c.category === "os_browser"),
|
|
173
|
-
score: contradictions.some((c) => c.category === "os_browser") ? 0 : 100,
|
|
174
|
-
weight: 1.5,
|
|
175
|
-
message: contradictions.find((c) => c.category === "os_browser")?.description ?? "User-Agent and Operating System are fully coherent"
|
|
176
|
-
},
|
|
177
|
-
{
|
|
178
|
-
id: "chk_hardware_plausibility",
|
|
179
|
-
name: "Hardware and GPU Plausibility",
|
|
180
|
-
category: "hardware_plausibility",
|
|
181
|
-
passed: !contradictions.some((c) => c.category === "hardware_system"),
|
|
182
|
-
score: contradictions.some((c) => c.category === "hardware_system") ? 0 : 100,
|
|
183
|
-
weight: 2,
|
|
184
|
-
message: contradictions.find((c) => c.category === "hardware_system")?.description ?? "GPU renderer, CPU architecture and RAM are physically plausible"
|
|
185
|
-
},
|
|
186
|
-
{
|
|
187
|
-
id: "chk_geo_locale_coherence",
|
|
188
|
-
name: "Geo and Locale Coherence",
|
|
189
|
-
category: "geo_locale_coherence",
|
|
190
|
-
passed: !contradictions.some((c) => c.category === "geo_chrono"),
|
|
191
|
-
score: contradictions.some((c) => c.category === "geo_chrono") ? 0 : 100,
|
|
192
|
-
weight: 1.5,
|
|
193
|
-
message: contradictions.find((c) => c.category === "geo_chrono")?.description ?? "Timezone, country, and Accept-Language are geographically locked"
|
|
194
|
-
},
|
|
195
|
-
{
|
|
196
|
-
id: "chk_client_hints_entropy",
|
|
197
|
-
name: "Client Hints RFC 8942 Compliance",
|
|
198
|
-
category: "client_hints_entropy",
|
|
199
|
-
passed: !contradictions.some((c) => c.category === "client_hints"),
|
|
200
|
-
score: contradictions.some((c) => c.category === "client_hints") ? 0 : 100,
|
|
201
|
-
weight: 1.5,
|
|
202
|
-
message: contradictions.find((c) => c.category === "client_hints")?.description ?? "User-Agent Client Hints headers strictly match W3C and Chromium freeze specifications"
|
|
203
|
-
}
|
|
204
|
-
];
|
|
205
|
-
const evaluation = {
|
|
206
|
-
overallScore,
|
|
207
|
-
status,
|
|
208
|
-
grade,
|
|
209
|
-
checks,
|
|
210
|
-
entropyAnalysis: {
|
|
211
|
-
estimatedBits,
|
|
212
|
-
collisionRisk
|
|
213
|
-
},
|
|
214
|
-
evaluatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
215
|
-
};
|
|
216
|
-
this.profile.evaluation = evaluation;
|
|
217
|
-
return evaluation;
|
|
218
|
-
} catch {
|
|
219
|
-
if (this.profile.evaluation) {
|
|
220
|
-
return this.profile.evaluation;
|
|
221
|
-
}
|
|
222
|
-
const baseline = {
|
|
223
|
-
overallScore: 100,
|
|
224
|
-
status: "PASS",
|
|
225
|
-
grade: "A+",
|
|
226
|
-
checks: [],
|
|
227
|
-
evaluatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
228
|
-
};
|
|
229
|
-
this.profile.evaluation = baseline;
|
|
230
|
-
return baseline;
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
// ==========================================
|
|
234
|
-
// Serialization
|
|
235
|
-
// ==========================================
|
|
236
|
-
/**
|
|
237
|
-
* Returns the underlying raw DevicePassport data object.
|
|
238
|
-
*/
|
|
239
|
-
toJSON() {
|
|
240
|
-
return this.profile;
|
|
241
|
-
}
|
|
242
|
-
toString() {
|
|
243
|
-
const { id, browser, os, locale } = this.profile;
|
|
244
|
-
return `[DevicePassport ${id} | ${browser?.name ?? "Browser"} ${browser?.version ?? ""} on ${os?.platform ?? "OS"} | ${locale?.language ?? "Locale"}]`;
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
function createPassport(seedOrOptionsOrProfile, extraOptions) {
|
|
248
|
-
if (seedOrOptionsOrProfile instanceof DevicePassportInstance) {
|
|
249
|
-
return seedOrOptionsOrProfile;
|
|
250
|
-
}
|
|
251
|
-
if (seedOrOptionsOrProfile && typeof seedOrOptionsOrProfile === "object" && "id" in seedOrOptionsOrProfile && "clientHints" in seedOrOptionsOrProfile && "headers" in seedOrOptionsOrProfile) {
|
|
252
|
-
return new DevicePassportInstance(seedOrOptionsOrProfile);
|
|
253
|
-
}
|
|
254
|
-
let options = {};
|
|
255
|
-
if (typeof seedOrOptionsOrProfile === "string") {
|
|
256
|
-
options = { ...extraOptions, seed: seedOrOptionsOrProfile };
|
|
257
|
-
} else if (seedOrOptionsOrProfile && typeof seedOrOptionsOrProfile === "object") {
|
|
258
|
-
options = { ...seedOrOptionsOrProfile };
|
|
259
|
-
} else if (extraOptions) {
|
|
260
|
-
options = { ...extraOptions };
|
|
261
|
-
}
|
|
262
|
-
if (options.store && options.seed) {
|
|
263
|
-
const storage = typeof options.store === "string" ? new JSONFileStorage({ filePath: options.store }) : options.store;
|
|
264
|
-
if (storage.hasSync && storage.hasSync(options.seed)) {
|
|
265
|
-
const existing = storage.getSync(options.seed);
|
|
266
|
-
if (existing) return new DevicePassportInstance(existing);
|
|
267
|
-
}
|
|
268
|
-
const generated2 = generatePassport(options);
|
|
269
|
-
if (storage.setSync) {
|
|
270
|
-
storage.setSync(options.seed, generated2);
|
|
271
|
-
} else {
|
|
272
|
-
storage.set(options.seed, generated2).catch(() => {
|
|
273
|
-
});
|
|
274
|
-
}
|
|
275
|
-
return new DevicePassportInstance(generated2);
|
|
276
|
-
}
|
|
277
|
-
const generated = generatePassport(options);
|
|
278
|
-
return new DevicePassportInstance(generated);
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
class PassportManager {
|
|
282
|
-
storage;
|
|
283
|
-
defaultGeo;
|
|
284
|
-
defaultOS;
|
|
285
|
-
defaultBrowser;
|
|
286
|
-
generator;
|
|
287
|
-
constructor(options) {
|
|
288
|
-
if (typeof options?.store === "string") {
|
|
289
|
-
this.storage = new JSONFileStorage(options.store);
|
|
290
|
-
} else if (options?.store && typeof options.store.get === "function") {
|
|
291
|
-
this.storage = options.store;
|
|
292
|
-
} else {
|
|
293
|
-
this.storage = new MemoryStorage();
|
|
294
|
-
}
|
|
295
|
-
this.defaultGeo = options?.defaultGeo ?? "US";
|
|
296
|
-
this.defaultOS = options?.defaultOS;
|
|
297
|
-
this.defaultBrowser = options?.defaultBrowser;
|
|
298
|
-
this.generator = options?.generator ?? generatePassport;
|
|
299
|
-
}
|
|
300
|
-
/**
|
|
301
|
-
* Retrieves an existing sticky passport by seed or deterministically generates
|
|
302
|
-
* and persists a new one if it does not already exist.
|
|
303
|
-
*
|
|
304
|
-
* @param seed Deterministic seed (user ID, account handle, proxy IP, worker slot)
|
|
305
|
-
* @param options Generator options to use if persona needs to be created
|
|
306
|
-
*/
|
|
307
|
-
async getPassport(seed, options) {
|
|
308
|
-
const seedStr = String(seed);
|
|
309
|
-
const existing = await this.storage.get(seedStr);
|
|
310
|
-
if (existing) {
|
|
311
|
-
return new DevicePassportInstance(existing);
|
|
312
|
-
}
|
|
313
|
-
const mergedOptions = {
|
|
314
|
-
seed: seedStr,
|
|
315
|
-
country: options?.country ?? this.defaultGeo,
|
|
316
|
-
os: options?.os ?? this.defaultOS,
|
|
317
|
-
browser: options?.browser ?? this.defaultBrowser,
|
|
318
|
-
...options
|
|
319
|
-
};
|
|
320
|
-
const profile = this.generator(mergedOptions);
|
|
321
|
-
await this.storage.set(seedStr, profile);
|
|
322
|
-
return new DevicePassportInstance(profile);
|
|
323
|
-
}
|
|
324
|
-
/**
|
|
325
|
-
* Synchronous passport retrieval for environments backed by MemoryStorage or JSONFileStorage.
|
|
326
|
-
*/
|
|
327
|
-
getPassportSync(seed, options) {
|
|
328
|
-
const seedStr = String(seed);
|
|
329
|
-
const syncStore = this.storage;
|
|
330
|
-
if (typeof syncStore.getSync === "function") {
|
|
331
|
-
const existing = syncStore.getSync(seedStr);
|
|
332
|
-
if (existing) {
|
|
333
|
-
return new DevicePassportInstance(existing);
|
|
334
|
-
}
|
|
335
|
-
const mergedOptions = {
|
|
336
|
-
seed: seedStr,
|
|
337
|
-
country: options?.country ?? this.defaultGeo,
|
|
338
|
-
os: options?.os ?? this.defaultOS,
|
|
339
|
-
browser: options?.browser ?? this.defaultBrowser,
|
|
340
|
-
...options
|
|
341
|
-
};
|
|
342
|
-
const profile = this.generator(mergedOptions);
|
|
343
|
-
if (typeof syncStore.setSync === "function") {
|
|
344
|
-
syncStore.setSync(seedStr, profile);
|
|
345
|
-
}
|
|
346
|
-
return new DevicePassportInstance(profile);
|
|
347
|
-
}
|
|
348
|
-
throw new Error(
|
|
349
|
-
"[PassportManager] Current storage adapter does not support synchronous operations. Use await manager.getPassport(seed) instead."
|
|
350
|
-
);
|
|
351
|
-
}
|
|
352
|
-
/**
|
|
353
|
-
* Forces re-generation and overwrite of a passport for the given seed.
|
|
354
|
-
*/
|
|
355
|
-
async renewPassport(seed, options) {
|
|
356
|
-
const seedStr = String(seed);
|
|
357
|
-
const mergedOptions = {
|
|
358
|
-
seed: seedStr,
|
|
359
|
-
country: options?.country ?? this.defaultGeo,
|
|
360
|
-
os: options?.os ?? this.defaultOS,
|
|
361
|
-
browser: options?.browser ?? this.defaultBrowser,
|
|
362
|
-
...options
|
|
363
|
-
};
|
|
364
|
-
const profile = this.generator(mergedOptions);
|
|
365
|
-
await this.storage.set(seedStr, profile);
|
|
366
|
-
return new DevicePassportInstance(profile);
|
|
367
|
-
}
|
|
368
|
-
/**
|
|
369
|
-
* Check if a passport exists in storage for the given seed.
|
|
370
|
-
*/
|
|
371
|
-
async hasPassport(seed) {
|
|
372
|
-
return this.storage.has(String(seed));
|
|
373
|
-
}
|
|
374
|
-
/**
|
|
375
|
-
* Delete a passport from storage.
|
|
376
|
-
*/
|
|
377
|
-
async deletePassport(seed) {
|
|
378
|
-
return this.storage.delete(String(seed));
|
|
379
|
-
}
|
|
380
|
-
/**
|
|
381
|
-
* Import an existing passport into storage.
|
|
382
|
-
*/
|
|
383
|
-
async importPassport(passport) {
|
|
384
|
-
const raw = passport instanceof DevicePassportInstance ? passport.toJSON() : passport;
|
|
385
|
-
await this.storage.set(raw.seed, raw);
|
|
386
|
-
return new DevicePassportInstance(raw);
|
|
387
|
-
}
|
|
388
|
-
/**
|
|
389
|
-
* List all stored seeds.
|
|
390
|
-
*/
|
|
391
|
-
async listSeeds() {
|
|
392
|
-
return this.storage.keys();
|
|
393
|
-
}
|
|
394
|
-
/**
|
|
395
|
-
* List all stored passports as DevicePassportInstance objects.
|
|
396
|
-
*/
|
|
397
|
-
async listPassports() {
|
|
398
|
-
const keys = await this.storage.keys();
|
|
399
|
-
const instances = [];
|
|
400
|
-
for (const key of keys) {
|
|
401
|
-
const item = await this.storage.get(key);
|
|
402
|
-
if (item) {
|
|
403
|
-
instances.push(new DevicePassportInstance(item));
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
return instances;
|
|
407
|
-
}
|
|
408
|
-
/**
|
|
409
|
-
* Clear all stored passports.
|
|
410
|
-
*/
|
|
411
|
-
async clear() {
|
|
412
|
-
await this.storage.clear();
|
|
413
|
-
}
|
|
414
|
-
/**
|
|
415
|
-
* Return number of stored personas.
|
|
416
|
-
*/
|
|
417
|
-
async count() {
|
|
418
|
-
const keys = await this.storage.keys();
|
|
419
|
-
return keys.length;
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
|
|
423
12
|
const BENCHMARK_METRICS_METADATA = {
|
|
424
13
|
clientHintsSupport: {
|
|
425
14
|
id: "clientHintsSupport",
|
|
@@ -792,4 +381,4 @@ function formatComparativeMatrixJSON() {
|
|
|
792
381
|
|
|
793
382
|
const VERSION = "1.0.0";
|
|
794
383
|
|
|
795
|
-
export { BENCHMARK_METRICS_METADATA, COMPARATIVE_DATASET,
|
|
384
|
+
export { BENCHMARK_METRICS_METADATA, COMPARATIVE_DATASET, VERSION, formatComparativeMatrixJSON, formatComparativeMatrixLaTeX, formatComparativeMatrixMarkdown, runComparativeBenchmark };
|