Docs · WhiskerJS 0.1.0 · signalsVersion 5 · idVersion 2

API reference

Every export, option, type and default.

In plain words

There are two calls: load() makes an agent and agent.collect() makes one result. Everything else is constants and types that describe the result. collect() never throws.

Everything below is exported from whiskerjs (the package’s only entry point, ES modules). Version 0.1.0, signalsVersion 5, idVersion 2.

Functions

load(options?: LoadOptions): Promise<Agent>

Creates an agent. Does no collection work and keeps no state between collect() calls. Never rejects: if options.env cannot be used, the default environment is used.

agent.collect(options?: CollectOptions): Promise<CollectResult>

Runs one collection. Never throws and never rejects. Each call is independent.

bindingInput(result): string

Returns the exact text the binding digest is computed over (see Anti-replay binding). Takes a result with its binding; binding.digest is not part of the text. Pure: usable on a server.

Options

LoadOptions

Option Type Default Meaning
env Partial<Environment> the real browser globals override what the library touches; mainly for tests
onResult (result: CollectResult) => void | Promise<void> none (off) called once per collect() with a deep copy of the result; errors are swallowed, not awaited. See Integration

Environment

Field Type Default
window WindowLike (any Window-like object) globalThis
now() () => number (milliseconds) window.performance.now(), else Date.now()
setTimeout(fn, ms) timer globalThis.setTimeout
clearTimeout(handle) timer globalThis.clearTimeout
subtle DigestLike or undefined window.crypto.subtle, else globalThis.crypto.subtle

Passing subtle: undefined explicitly simulates a browser without Web Crypto.

CollectOptions

Option Type Default Meaning
timeoutMs number 5000 overall budget; clamped to 0 to 60000; not a finite number means 5000
signal AbortSignal none aborting resolves every pending component as timed_out / aborted and skips the iframe checks
exclude string[] [] component names not to collect; they report excluded / caller_excluded; unknown names and non-strings are ignored
binding { nonce: string; timestamp: number } none anti-replay input from your server; see Anti-replay binding

Types

CollectResult

Field Type Meaning
visitorId string | null 32 lowercase hex characters; null without a digest
version string library version, '0.1.0'
signalsVersion string '5'
idVersion string '2'
components Record<string, Component> all 46, always present
structuredId string | null '2_' then seven 12-hex parts joined by _; null without a digest
integrityFlags string[] sorted names of the checks that fired
durationMs number whole milliseconds the collection took
binding Binding | null null unless binding was passed

The result is plain JSON: no functions, no undefined values, no cycles.

Component

Field Type Present
status ComponentStatus always
value string only when status is 'ok'; at most 128 printable ASCII characters
hashed boolean only when status is 'ok'; true when value is a digest
ruleId string only when status is not 'ok'; matches ^[a-z0-9_]{1,32}$

ComponentStatus

'ok' | 'unavailable' | 'blocked' | 'noisy' | 'excluded' | 'timed_out'. Meanings and every ruleId: How it works.

Binding

Field Type Meaning
nonce string | null your nonce; null when the input was invalid
timestamp number | null your timestamp; null when the input was invalid
digest string | null 32 hex characters; null when invalid or without a digest
ruleId string (optional) why digest is null: invalid_binding, invalid_nonce, invalid_timestamp or no_digest

Other types

  • Agent: { collect(options?): Promise<CollectResult> }.
  • DigestLike: { digest(algorithm: string, data: ArrayBuffer): Promise<ArrayBuffer> }, the part of SubtleCrypto the library uses.
  • WindowLike: any; collectors read the browser only through it.
  • BrowserClass: 'brave' | 'firefox_rfp' | 'firefox' | 'safari' | 'chromium' | 'other'.

Constants

Export Value
VERSION '0.1.0'
SIGNALS_VERSION '5'
ID_VERSION '2'
DEFAULT_TIMEOUT_MS 5000
COMPONENT_NAMES the 46 component names, sorted (frozen array)
INTEGRITY_FLAG_NAMES the 14 flag names, sorted (frozen array)
EXCLUSION_TABLE Record<BrowserClass, Record<componentName, ruleId>> (frozen)
ID_GROUPS Record<group, componentName[]>, seven groups (frozen)
ID_GROUP_ORDER ['gpu', 'audio', 'fonts', 'device', 'browser', 'locale', 'prefs']
ID_PART_LENGTH 12 (hex characters per structuredId part)

Not exported but fixed: the maximum timeoutMs (60000), the inner timeout per collector (1000 ms), the value length limit (128 characters).

Testing with a fake environment

import { load } from 'whiskerjs';

const agent = await load({
  env: {
    window: myFakeWindow,          // anything Window-like
    now: () => fakeClock.now(),
    subtle: globalThis.crypto.subtle,
  },
});
const result = await agent.collect();

The project’s own tests do this with test/fake-browser.ts.