@vectoral-labs/sdk 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 +215 -0
- package/README.md +46 -0
- package/dist/index.cjs +895 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +572 -0
- package/dist/index.d.ts +572 -0
- package/dist/index.js +855 -0
- package/dist/index.js.map +1 -0
- package/package.json +44 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/http.ts","../src/salt.ts","../src/resources/registrations.ts","../src/fingerprint/encoding.ts","../src/fingerprint/xxhash64.ts","../src/fingerprint/normalize.ts","../src/fingerprint/minhash_constants.json","../src/fingerprint/similarity.ts","../src/fingerprint/index.ts","../src/resources/inference.ts","../src/resources/identity.ts","../src/resources/labels.ts","../src/client.ts"],"sourcesContent":["// @vectoral-labs/sdk — server-side SDK for the Vectoral fraud-scoring API.\n//\n// vectoral.registrations.score() screen a signup before the account exists\n// vectoral.inference.score() score an inference request before the call\n// vectoral.inference.postCall() report what the call actually cost\n// vectoral.identity.record() signup/login events, and registration links\n// vectoral.labels.submit() ground truth\n//\n// SERVER-SIDE ONLY. It carries a secret API key, and the client IP it sends is\n// only meaningful when your server observed it. Browser-side collection lives\n// in @vectoral-labs/browser, whose output you forward through here.\n\nexport { Vectoral, createClient } from \"./client.js\";\nexport type { VectoralOptions } from \"./client.js\";\n\nexport { VectoralError, VectoralConfigError } from \"./errors.js\";\nexport type { VectoralErrorCode } from \"./errors.js\";\nexport type { FetchLike } from \"./http.js\";\n\nexport { Registrations, RegistrationTier } from \"./resources/registrations.js\";\nexport type {\n RegistrationRequest,\n RegistrationVerdict,\n RegistrationClientBlock,\n RegistrationFormBlock,\n RegistrationFormField,\n} from \"./resources/registrations.js\";\n\nexport { Inference } from \"./resources/inference.js\";\nexport type {\n ScoreRequest,\n ScoreResponse,\n PostCallEvent,\n OkResponse,\n AccountBlock,\n RequestBlock,\n SessionSignals,\n PromptFingerprintBlock,\n ReasonCode,\n Tier,\n} from \"./resources/inference.js\";\n\nexport { Identity } from \"./resources/identity.js\";\nexport type { IdentityEvent, IdentityEventType } from \"./resources/identity.js\";\n\nexport { Labels } from \"./resources/labels.js\";\nexport type { Label, LabelRequest } from \"./resources/labels.js\";\n\nexport { generateSalt, suggestSaltId, MIN_SALT_LENGTH } from \"./salt.js\";\nexport type { FingerprintOptions } from \"./salt.js\";\n\nexport { computeFingerprint, conversationKey } from \"./fingerprint/index.js\";\nexport type { ComputedFingerprint } from \"./fingerprint/index.js\";\n","/** Categorizes why a call failed, so callers can branch without string-matching. */\nexport type VectoralErrorCode =\n | \"http_error\"\n | \"network_error\"\n | \"timeout\"\n | \"invalid_response\";\n\n/** Thrown for any non-2xx response, network failure, or timeout. */\nexport class VectoralError extends Error {\n /** HTTP status code, or 0 for network/timeout errors. */\n readonly status: number;\n readonly code: VectoralErrorCode;\n /** Raw response body, when there was one. */\n readonly responseBody: string | undefined;\n\n constructor(\n message: string,\n opts: {\n code: VectoralErrorCode;\n status: number;\n responseBody?: string;\n cause?: unknown;\n },\n ) {\n super(message, opts.cause !== undefined ? { cause: opts.cause } : undefined);\n this.name = \"VectoralError\";\n this.code = opts.code;\n this.status = opts.status;\n this.responseBody = opts.responseBody;\n }\n\n /**\n * True for failures where the request provably did not reach a decision:\n * network errors, timeouts, and 5xx. A retry is safe only if the call also\n * carried an `event_id` — see `docs/concepts/reliability.md`.\n */\n get transient(): boolean {\n return (\n this.code === \"network_error\" ||\n this.code === \"timeout\" ||\n (this.code === \"http_error\" && this.status >= 500)\n );\n }\n}\n\n/**\n * Invoke a caller-supplied error callback, swallowing anything it throws.\n *\n * `onError` runs on the fail-open path, so a logging or metrics handler that\n * blows up would otherwise convert the degraded verdict into a rejection —\n * taking down the very flow `failOpen` exists to protect. The failure is not\n * lost: the verdict still carries `degraded: true` and the underlying `error`.\n */\nexport function notifyError(\n cb: ((err: VectoralError, context: string) => void) | undefined,\n err: VectoralError,\n context: string,\n): void {\n try {\n cb?.(err, context);\n } catch {\n // Deliberately empty — see above.\n }\n}\n\n/** Thrown at construction time for a misconfigured client. Never at call time. */\nexport class VectoralConfigError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"VectoralConfigError\";\n }\n}\n","import { VectoralError } from \"./errors.js\";\n\n/** Minimal fetch signature so this runs on Node 18+, Deno, Bun, and edge runtimes. */\nexport type FetchLike = (input: string, init?: RequestInit) => Promise<Response>;\n\nexport interface TransportOptions {\n baseUrl: string;\n authHeader: Record<string, string>;\n headers: Record<string, string>;\n timeoutMs: number;\n fetch: FetchLike;\n /**\n * Attempts after the first, for transient failures. Only applied to requests\n * the caller marked idempotent — see `post()`.\n */\n retries: number;\n}\n\n/**\n * Assert that a 2xx body is the acknowledgement these write endpoints promise.\n *\n * They never fail open, so an unvalidated pass-through is a silently dropped\n * write: a captive portal or version-skewed gateway answering `200 {\"message\":\n * \"ok\"}` would look exactly like delivered telemetry. Telemetry you silently\n * drop is telemetry you never notice missing.\n */\nexport function assertAck<T>(body: T): T {\n // Strictly `true`. `{ ok: false }` is not a success, and callers treat\n // fulfilment as delivery — they only retry on rejection — so resolving a\n // negative acknowledgement drops the write just as silently as accepting a\n // body with no `ok` at all.\n if ((body as { ok?: unknown })?.ok !== true) {\n throw new VectoralError(\n \"vectoral: write was not acknowledged (expected `ok: true`)\",\n { code: \"invalid_response\", status: 200, responseBody: JSON.stringify(body) },\n );\n }\n return body;\n}\n\nexport interface PostOptions {\n /**\n * Whether a retry is safe. Every Vectoral write endpoint mints a new row per\n * call unless the body carries an `event_id`, so the transport refuses to\n * retry anything without one: a blind retry after a response lost in transit\n * would double-write.\n */\n idempotent: boolean;\n /**\n * A per-call timeout FLOOR, used by `deadline_ms`. It can only raise the\n * effective timeout, never lower it: a caller who configured `timeoutMs`\n * explicitly must not have it silently reduced by asking the server for a\n * tight budget, or a slow link turns every good verdict into a fail-open\n * zero — the failure mode `httpTimeoutFor` exists to prevent.\n */\n timeoutMs?: number;\n}\n\nconst delay = (ms: number): Promise<void> =>\n new Promise((resolve) => setTimeout(resolve, ms));\n\n/** Exponential backoff with a 5s cap. */\nconst backoffMs = (attempt: number): number => Math.min(200 * 2 ** attempt, 5000);\n\nexport class Transport {\n constructor(private readonly opts: TransportOptions) {}\n\n async post<T>(path: string, body: unknown, po: PostOptions): Promise<T> {\n const url = `${this.opts.baseUrl}${path}`;\n const maxAttempts = po.idempotent ? this.opts.retries : 0;\n let attempt = 0;\n for (;;) {\n try {\n return await this.doPost<T>(\n url,\n body,\n Math.max(po.timeoutMs ?? 0, this.opts.timeoutMs),\n );\n } catch (err) {\n const retryable = err instanceof VectoralError && err.transient;\n if (retryable && attempt < maxAttempts) {\n attempt += 1;\n await delay(backoffMs(attempt));\n continue;\n }\n throw err;\n }\n }\n }\n\n private async doPost<T>(url: string, body: unknown, timeoutMs: number): Promise<T> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n // The timer must stay armed until the BODY is consumed, not just until the\n // headers land. A server or proxy that sends headers and then stalls\n // mid-body would otherwise hang this call forever: no timeout, no retry,\n // and no fail-open verdict for a flow that is waiting on one.\n try {\n return await this.send<T>(url, body, controller, timeoutMs);\n } finally {\n clearTimeout(timer);\n }\n }\n\n private async send<T>(\n url: string,\n body: unknown,\n controller: AbortController,\n timeoutMs: number,\n ): Promise<T> {\n const failed = (err: unknown): VectoralError =>\n controller.signal.aborted\n ? new VectoralError(`request timed out after ${timeoutMs}ms`, {\n code: \"timeout\",\n status: 0,\n cause: err,\n })\n : new VectoralError(\n `network error: ${err instanceof Error ? err.message : String(err)}`,\n { code: \"network_error\", status: 0, cause: err },\n );\n\n let res: Response;\n try {\n res = await this.opts.fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n ...this.opts.authHeader,\n ...this.opts.headers,\n },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n } catch (err) {\n throw failed(err);\n }\n\n let text: string;\n try {\n text = await res.text();\n } catch (err) {\n // Headers arrived, then the body stalled or the stream broke.\n throw failed(err);\n }\n\n if (!res.ok) {\n let message = res.statusText;\n try {\n const parsed = JSON.parse(text) as { error?: unknown };\n if (typeof parsed.error === \"string\") message = parsed.error;\n } catch {\n // non-JSON error body (e.g. a load balancer HTML page); keep statusText\n }\n throw new VectoralError(`vectoral ${res.status}: ${message}`, {\n code: \"http_error\",\n status: res.status,\n responseBody: text,\n });\n }\n\n try {\n return JSON.parse(text) as T;\n } catch (err) {\n throw new VectoralError(\"vectoral: invalid JSON in response body\", {\n code: \"invalid_response\",\n status: res.status,\n responseBody: text,\n cause: err,\n });\n }\n }\n}\n","// Salt policy for prompt fingerprinting.\n//\n// A prompt fingerprint is a one-way digest of normalized prompt text. The salt\n// decides WHO can compare two fingerprints:\n//\n// secret tenant salt -> only you. Nobody without the salt can correlate your\n// fingerprints, including against a dictionary of\n// guessed prompts.\n// no salt (\"global\") -> every Vectoral customer who opted in. Catches a farm\n// that reuses the same prompts across victims, at the\n// cost of that comparability.\n//\n// The salt is a secret and must never reach a browser. The browser-side\n// analogue — device fingerprints — is salted with the PUBLISHABLE site key\n// instead, which scopes values to your tenant without pretending to be secret.\n// See docs/concepts/salts.md.\n\nimport { VectoralConfigError } from \"./errors.js\";\n\n/** Minimum salt length we will accept. 32 hex chars = 128 bits. */\nexport const MIN_SALT_LENGTH = 32;\n\nexport interface FingerprintOptions {\n /**\n * Master switch. When false or absent, prompt text is never read and never\n * hashed — the SDK does not touch it.\n */\n enabled: boolean;\n /**\n * Secret tenant salt. Defaults to `process.env.VECTORAL_FINGERPRINT_SALT`.\n * Treat it like a signing key: 128+ bits, out of source control, rotated\n * deliberately.\n */\n salt?: string;\n /**\n * Generation id for `salt`, e.g. `s_2026_09`. Sent alongside every\n * fingerprint so the server knows which generation a value belongs to and\n * never compares across a rotation. Defaults to\n * `process.env.VECTORAL_FINGERPRINT_SALT_ID`.\n */\n saltId?: string;\n /**\n * Additionally compute an UNSALTED fingerprint, comparable across all\n * Vectoral customers who opted in. Requires `enabled`. Opting in\n * acknowledges the reduced confidentiality of that tier.\n */\n shareGlobal?: boolean;\n}\n\n/** Resolved config. `null` means fingerprinting is inert for this client. */\nexport interface ResolvedFingerprintConfig {\n salt: string;\n saltId: string;\n shareGlobal: boolean;\n}\n\nexport interface ResolveResult {\n config: ResolvedFingerprintConfig | null;\n /** Non-fatal problems. The caller surfaces these; it never throws on them. */\n warnings: string[];\n}\n\nconst env = (name: string): string | undefined => {\n const p = (globalThis as { process?: { env?: Record<string, string | undefined> } })\n .process;\n return p?.env?.[name];\n};\n\n/** Salts that show up in copy-pasted examples and must never reach production. */\nconst PLACEHOLDER_SALTS = new Set([\n \"changeme\",\n \"your-salt-here\",\n \"test\",\n \"secret\",\n \"vectoral\",\n]);\n\n/**\n * Resolve fingerprinting config from explicit options and the environment.\n *\n * Fails OPEN by design: a missing or unusable salt disables fingerprinting with\n * a warning rather than throwing. Customer traffic must never block on\n * fingerprint configuration — a score request without a fingerprint is merely\n * less informed, while a constructor that throws in production is an outage.\n *\n * The one exception is `shareGlobal` without `enabled`, which is a\n * contradiction in the caller's intent rather than a missing value, so it\n * throws at construction time.\n */\nexport function resolveFingerprintConfig(\n opts: FingerprintOptions | undefined,\n): ResolveResult {\n const warnings: string[] = [];\n if (!opts?.enabled) {\n if (opts?.shareGlobal) {\n throw new VectoralConfigError(\n \"fingerprint.shareGlobal requires fingerprint.enabled: true\",\n );\n }\n return { config: null, warnings };\n }\n\n const salt = opts.salt ?? env(\"VECTORAL_FINGERPRINT_SALT\");\n const saltId = opts.saltId ?? env(\"VECTORAL_FINGERPRINT_SALT_ID\");\n\n if (!salt || !saltId) {\n warnings.push(\n \"fingerprint.enabled is set but salt/saltId are missing (pass them, or set \" +\n \"VECTORAL_FINGERPRINT_SALT and VECTORAL_FINGERPRINT_SALT_ID) — \" +\n \"prompt fingerprinting is disabled\",\n );\n return { config: null, warnings };\n }\n if (PLACEHOLDER_SALTS.has(salt.toLowerCase())) {\n warnings.push(\n \"fingerprint.salt is a well-known placeholder value — prompt fingerprinting \" +\n \"is disabled. Generate one with generateSalt().\",\n );\n return { config: null, warnings };\n }\n if (salt.length < MIN_SALT_LENGTH) {\n warnings.push(\n `fingerprint.salt is only ${salt.length} characters; at least ` +\n `${MIN_SALT_LENGTH} are required for a meaningful search space — ` +\n \"prompt fingerprinting is disabled\",\n );\n return { config: null, warnings };\n }\n\n return {\n config: { salt, saltId, shareGlobal: opts.shareGlobal ?? false },\n warnings,\n };\n}\n\n/**\n * Generate a fresh tenant salt: 32 random bytes, hex-encoded.\n *\n * For bootstrapping and rotation. Store the output in your secret manager and\n * pair it with a new `saltId`; do not call this at process start, which would\n * mint a new salt per deploy and make every stored fingerprint incomparable.\n */\nexport function generateSalt(): string {\n const bytes = new Uint8Array(32);\n crypto.getRandomValues(bytes);\n return Array.from(bytes, (b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n}\n\n/**\n * A conventional salt id for the current month, e.g. `s_2026_09`. Any stable\n * string works; the convention just makes rotations self-documenting in logs.\n */\nexport function suggestSaltId(now: Date = new Date()): string {\n const yyyy = now.getUTCFullYear();\n const mm = String(now.getUTCMonth() + 1).padStart(2, \"0\");\n return `s_${yyyy}_${mm}`;\n}\n","// POST /v1/registrations/score — screen a signup BEFORE the account exists.\n\nimport type { Transport } from \"../http.js\";\nimport { VectoralError, notifyError } from \"../errors.js\";\n\n/** Browser-environment tells, as collected by `@vectoral-labs/browser`. */\nexport interface RegistrationClientBlock {\n /** `navigator.webdriver`. Cheap, and a strong tell when true. */\n webdriver?: boolean;\n /** Your own [0,1] canvas/WebGL/capability-consistency score. */\n fingerprint_anomaly?: number;\n /** Milliseconds from page load to submit. */\n load_to_submit_ms?: number;\n /** IANA zone, compared against the observed origin. */\n timezone?: string;\n}\n\n/** Per-field fill behaviour. `pasted` is the highest-value bit. */\nexport interface RegistrationFormField {\n pasted?: boolean;\n keystrokes?: number;\n corrections?: number;\n focus_ms?: number;\n}\n\nexport interface RegistrationFormBlock {\n load_to_submit_ms?: number;\n fields?: Record<string, RegistrationFormField>;\n}\n\n/**\n * Body of POST /v1/registrations/score.\n *\n * Every optional field you omit produces an **absent** signal, never a\n * favourable one: no `device_fingerprint` does not mean \"no device reuse\", and\n * no `form` does not mean \"a human typed it\".\n */\nexport interface RegistrationRequest {\n /** The submitted address. The only required field. */\n email: string;\n /**\n * Idempotency key. A repeat of the same `(customer, event_id)` returns the\n * original verdict with `duplicate: true` and writes nothing.\n *\n * Strongly recommended, and the SDK only retries transient failures when it\n * is present. Derive it from your own pending-signup record, not from a\n * transport message id.\n */\n event_id?: string;\n /** The user's browser IP at submit — the one your server observed. */\n ip?: string;\n /** Your own keyed token instead of `ip`. Disables per-subnet velocity. */\n ip_hash?: string;\n asn?: number;\n ip_country?: string;\n /** The country the user claimed, if your form collects one. */\n declared_country?: string;\n user_agent?: string;\n /**\n * Client-side device identifier. **The single highest-value optional field** —\n * one device across many registrations is the strongest farm signal there is.\n * `@vectoral-labs/browser`'s `deviceFingerprint()` produces one.\n */\n device_fingerprint?: string;\n /** A token from the browser sensor, if deployed. */\n sensor_token?: string;\n client?: RegistrationClientBlock;\n form?: RegistrationFormBlock;\n phone?: string;\n username?: string;\n referrer?: string;\n /**\n * Whole-call budget in ms for the server's external lookups. Defaults to 400\n * server-side and is clamped to [250, 2000] rather than rejected. The SDK\n * raises its own HTTP timeout to sit above whatever you set here.\n */\n deadline_ms?: number;\n}\n\n/**\n * What to do with the signup. An **open, ordered scale** — higher means more\n * friction. Compare (`tier >= Tier.StepUp`); never switch exhaustively, because\n * new tiers can be added without a new API version.\n */\nexport const RegistrationTier = {\n Allow: 0,\n Challenge: 1,\n StepUp: 2,\n} as const;\n\nexport interface RegistrationVerdict {\n /**\n * Opaque handle to pass back on `identity.record()` when the account is\n * created. `null` only when the call failed open — there is nothing to link.\n */\n registration_id: string | null;\n /** See `RegistrationTier`. Compare, do not switch. */\n tier: number;\n /** The underlying risk score in [0,1], for your own tuning. */\n score: number;\n /** Up to three contributing facts, most significant first. Do not branch on these. */\n reasons: string[];\n /** True on an idempotent replay of a previous `event_id`. */\n duplicate?: boolean;\n /** True during the warm-up window, when `tier` is pinned to 0. */\n shadow_mode?: boolean;\n /**\n * True when this verdict is the SDK's fail-open default rather than a real\n * answer — the call errored and `failOpen` was on. Log it: a flow silently\n * running at `tier: 0` because Vectoral is unreachable looks identical to one\n * where every signup is clean.\n */\n degraded: boolean;\n /** The underlying failure, when `degraded`. */\n error?: VectoralError;\n}\n\n/** Wire shape, before the SDK adds `degraded`. */\ninterface RegistrationResponseBody {\n registration_id: string;\n tier: number;\n score: number;\n reasons: string[] | null;\n duplicate?: boolean;\n shadow_mode?: boolean;\n}\n\nconst DEADLINE_MIN_MS = 250;\nconst DEADLINE_MAX_MS = 2000;\n/** Headroom over the server-side deadline for TLS, queueing, and the response. */\nconst DEADLINE_OVERHEAD_MS = 300;\n\nexport interface RegistrationsOptions {\n failOpen: boolean;\n onError: ((err: VectoralError, context: string) => void) | undefined;\n}\n\nexport class Registrations {\n constructor(\n private readonly transport: Transport,\n private readonly opts: RegistrationsOptions,\n ) {}\n\n /**\n * Score a registration at form submit.\n *\n * With `failOpen` (the default) this never throws: any network failure,\n * timeout, or HTTP error yields `tier: 0, degraded: true`. A screening check\n * that can take your signup page down is worse than no screening check.\n */\n async score(req: RegistrationRequest): Promise<RegistrationVerdict> {\n try {\n const body = await this.transport.post<RegistrationResponseBody>(\n \"/v1/registrations/score\",\n req,\n {\n idempotent: req.event_id !== undefined,\n ...(req.deadline_ms !== undefined\n ? { timeoutMs: httpTimeoutFor(req.deadline_ms) }\n : {}),\n },\n );\n // A 2xx body is not automatically a verdict: a proxy or a version-skewed\n // service can return well-formed JSON with no `tier` at all. Left\n // unchecked, `undefined >= RegistrationTier.StepUp` is false and the call\n // reads as a clean allow with `degraded` unset — the one failure the\n // reliability contract promises is always visible.\n if (typeof body?.tier !== \"number\" || typeof body?.score !== \"number\") {\n throw new VectoralError(\n \"vectoral: response is not a registration verdict (missing numeric `tier`/`score`)\",\n { code: \"invalid_response\", status: 200, responseBody: JSON.stringify(body) },\n );\n }\n return {\n registration_id: body.registration_id,\n tier: body.tier,\n score: body.score,\n reasons: body.reasons ?? [],\n ...(body.duplicate !== undefined ? { duplicate: body.duplicate } : {}),\n ...(body.shadow_mode !== undefined ? { shadow_mode: body.shadow_mode } : {}),\n degraded: false,\n };\n } catch (err) {\n if (!this.opts.failOpen || !(err instanceof VectoralError)) throw err;\n notifyError(this.opts.onError, err, \"registrations.score\");\n return {\n registration_id: null,\n tier: RegistrationTier.Allow,\n score: 0,\n reasons: [],\n degraded: true,\n error: err,\n };\n }\n }\n}\n\n/**\n * The HTTP timeout must sit ABOVE the server's own deadline, or we abort a\n * request the server was about to answer and turn a usable verdict into a\n * fail-open 0.\n */\nexport function httpTimeoutFor(deadlineMs: number): number {\n const clamped = Math.min(Math.max(deadlineMs, DEADLINE_MIN_MS), DEADLINE_MAX_MS);\n return clamped + DEADLINE_OVERHEAD_MS;\n}\n","// Encoding helpers for the fingerprint wire format. No Buffer dependency —\n// the SDK must run in any Node ≥18 (and stay bundler-friendly).\n\nconst encoder = new TextEncoder();\n\n/** UTF-8 bytes of a string. */\nexport const utf8 = (s: string): Uint8Array => encoder.encode(s);\n\n/** 16 lowercase zero-padded hex digits of an unsigned 64-bit bigint. */\nexport const hex64 = (v: bigint): string => v.toString(16).padStart(16, \"0\");\n\nconst B64 = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\";\n\n/** Standard base64 (with padding) of raw bytes. */\nexport function bytesToBase64(b: Uint8Array): string {\n let out = \"\";\n let i = 0;\n for (; i + 3 <= b.length; i += 3) {\n const n = (b[i]! << 16) | (b[i + 1]! << 8) | b[i + 2]!;\n out += B64[(n >> 18) & 63]! + B64[(n >> 12) & 63]! + B64[(n >> 6) & 63]! + B64[n & 63]!;\n }\n const rem = b.length - i;\n if (rem === 1) {\n const n = b[i]! << 16;\n out += B64[(n >> 18) & 63]! + B64[(n >> 12) & 63]! + \"==\";\n } else if (rem === 2) {\n const n = (b[i]! << 16) | (b[i + 1]! << 8);\n out += B64[(n >> 18) & 63]! + B64[(n >> 12) & 63]! + B64[(n >> 6) & 63]! + \"=\";\n }\n return out;\n}\n","// Seeded xxHash64 in BigInt — a direct port of the normative Go\n// implementation. Bit-exactness with Go and\n// Python is enforced by the golden-vector test; any change here that alters\n// output is a breaking algo_version bump.\n\nconst MASK64 = (1n << 64n) - 1n;\n\nconst PRIME64_1 = 0x9e3779b185ebca87n;\nconst PRIME64_2 = 0xc2b2ae3d27d4eb4fn;\nconst PRIME64_3 = 0x165667b19e3779f9n;\nconst PRIME64_4 = 0x85ebca77c2b2ae63n;\nconst PRIME64_5 = 0x27d4eb2f165667c5n;\n\nconst rotl = (v: bigint, r: bigint): bigint =>\n ((v << r) | (v >> (64n - r))) & MASK64;\n\nconst round = (acc: bigint, input: bigint): bigint =>\n (rotl((acc + input * PRIME64_2) & MASK64, 31n) * PRIME64_1) & MASK64;\n\nconst mergeRound = (acc: bigint, val: bigint): bigint =>\n ((acc ^ round(0n, val)) * PRIME64_1 + PRIME64_4) & MASK64;\n\nconst le64 = (b: Uint8Array, i: number): bigint =>\n BigInt(b[i]!) |\n (BigInt(b[i + 1]!) << 8n) |\n (BigInt(b[i + 2]!) << 16n) |\n (BigInt(b[i + 3]!) << 24n) |\n (BigInt(b[i + 4]!) << 32n) |\n (BigInt(b[i + 5]!) << 40n) |\n (BigInt(b[i + 6]!) << 48n) |\n (BigInt(b[i + 7]!) << 56n);\n\nconst le32 = (b: Uint8Array, i: number): bigint =>\n BigInt(b[i]! | (b[i + 1]! << 8) | (b[i + 2]! << 16)) |\n (BigInt(b[i + 3]!) << 24n);\n\n/** Seeded xxHash64. Returns the unsigned 64-bit value as a bigint. */\nexport function xxh64(data: Uint8Array, seed: bigint): bigint {\n const n = data.length;\n let i = 0;\n let h: bigint;\n if (n >= 32) {\n let v1 = (seed + PRIME64_1 + PRIME64_2) & MASK64;\n let v2 = (seed + PRIME64_2) & MASK64;\n let v3 = seed & MASK64;\n let v4 = (seed - PRIME64_1) & MASK64;\n for (; i + 32 <= n; i += 32) {\n v1 = round(v1, le64(data, i));\n v2 = round(v2, le64(data, i + 8));\n v3 = round(v3, le64(data, i + 16));\n v4 = round(v4, le64(data, i + 24));\n }\n h = (rotl(v1, 1n) + rotl(v2, 7n) + rotl(v3, 12n) + rotl(v4, 18n)) & MASK64;\n h = mergeRound(h, v1);\n h = mergeRound(h, v2);\n h = mergeRound(h, v3);\n h = mergeRound(h, v4);\n } else {\n h = (seed + PRIME64_5) & MASK64;\n }\n h = (h + BigInt(n)) & MASK64;\n for (; i + 8 <= n; i += 8) {\n h = (rotl(h ^ round(0n, le64(data, i)), 27n) * PRIME64_1 + PRIME64_4) & MASK64;\n }\n if (i + 4 <= n) {\n h = (rotl(h ^ ((le32(data, i) * PRIME64_1) & MASK64), 23n) * PRIME64_2 + PRIME64_3) & MASK64;\n i += 4;\n }\n for (; i < n; i++) {\n h = (rotl(h ^ ((BigInt(data[i]!) * PRIME64_5) & MASK64), 11n) * PRIME64_1) & MASK64;\n }\n h ^= h >> 33n;\n h = (h * PRIME64_2) & MASK64;\n h ^= h >> 29n;\n h = (h * PRIME64_3) & MASK64;\n h ^= h >> 32n;\n return h;\n}\n","// Normative normalization pipeline — a port of the Go implementation.\n// Order is binding: NFKC → full lowercase → digit bucketing → whitespace split\n// → head-kept cap. Bit-exactness is enforced by the golden-vector test.\n\n/** Cap on fingerprint input: UTF-8 bytes of the space-joined token stream. */\nexport const MAX_NORMALIZED_BYTES = 32 * 1024;\n/** Token floor below which no fingerprint is produced. */\nexport const MIN_TOKENS = 8;\n\n// Unicode White_Space property, pinned explicitly. JS \\s is NOT conformant:\n// it matches U+FEFF (BOM, not White_Space) and misses U+0085 (NEL).\nconst WHITESPACE_RE =\n /[\\t\\n\\v\\f\\r \\u0085\\u00a0\\u1680\\u2000-\\u200a\\u2028\\u2029\\u202f\\u205f\\u3000]+/gu;\n\n// Each maximal run of ASCII digits becomes a length bucket:\n// 1 → \"0\", 2–3 → \"00\", ≥4 → \"000\". ASCII [0-9] only (post-NFKC), pinned.\nconst bucket = (run: string): string =>\n run.length === 1 ? \"0\" : run.length <= 3 ? \"00\" : \"000\";\n\n/**\n * Run the normative pipeline. collapseDigits=false is used only for the\n * exact-form hash.\n */\nexport function normalizeTokens(text: string, collapseDigits: boolean): string[] {\n let s = text.normalize(\"NFKC\").toLowerCase();\n if (collapseDigits) s = s.replace(/[0-9]+/g, bucket);\n const tokens = s.split(WHITESPACE_RE).filter((t) => t.length > 0);\n return capTokens(tokens, MAX_NORMALIZED_BYTES);\n}\n\nconst encoder = new TextEncoder();\n\n// Keep the head of the stream up to maxBytes of UTF-8 counting single\n// joining spaces, never splitting a token.\nfunction capTokens(tokens: string[], maxBytes: number): string[] {\n let total = 0;\n for (let i = 0; i < tokens.length; i++) {\n const n = encoder.encode(tokens[i]!).length + (i > 0 ? 1 : 0);\n if (total + n > maxBytes) return tokens.slice(0, i);\n total += n;\n }\n return tokens;\n}\n","{\n \"a\": [\n \"2021813335835409049\",\n \"35211633415242073\",\n \"1032286529175131953\",\n \"2069131852558007211\",\n \"1978694875717179127\",\n \"92632024908598310\",\n \"2227348836476178120\",\n \"1241523794948756209\",\n \"1281414715180458463\",\n \"68168729981692814\",\n \"1590120462813979606\",\n \"1854116879905405569\",\n \"1727992762099619348\",\n \"2119624372221496183\",\n \"1134157368671934749\",\n \"1889971077583265806\",\n \"1331960984677369123\",\n \"424766757415873078\",\n \"248769665290609414\",\n \"379392552670680551\",\n \"1071663163969004878\",\n \"1088771757875541551\",\n \"525798032415552240\",\n \"1801279986719471057\",\n \"2160440382124210661\",\n \"542330089998054146\",\n \"34780299756627497\",\n \"864036708820350785\",\n \"751227794015040822\",\n \"1831265118418158537\",\n \"204218925239092992\",\n \"1011056663065980301\",\n \"128115764264397803\",\n \"1505159286259654375\",\n \"1191262882168263883\",\n \"740932194332428643\",\n \"1593133303768919397\",\n \"1618445643131025398\",\n \"509860659052195117\",\n \"1297874447217707170\",\n \"1085228754310083322\",\n \"119203851975622499\",\n \"746088216632479645\",\n \"259900005950983532\",\n \"66551348091461166\",\n \"1059503232844960577\",\n \"255114382916886367\",\n \"235744748558065614\",\n \"2028861987517208555\",\n \"360011178275786621\",\n \"1854044834799956775\",\n \"1374770026548661332\",\n \"343207213113865673\",\n \"679958157873282646\",\n \"37240336268295500\",\n \"1548562591492889568\",\n \"1361800152292289303\",\n \"1932288454007280877\",\n \"1076765584066084170\",\n \"177822684145201725\",\n \"456689636495482067\",\n \"486814351553121932\",\n \"794790680498008333\",\n \"1316082831976020478\"\n ],\n \"b\": [\n \"1610806161966735655\",\n \"2047677487906336758\",\n \"1275918690921527573\",\n \"1189635637049945452\",\n \"1281403506175249200\",\n \"2081287680319054019\",\n \"192492701049451181\",\n \"1425310758080347673\",\n \"2039895406543135671\",\n \"1501410306195161698\",\n \"1375342227526167841\",\n \"308564847782375531\",\n \"1049081053798665627\",\n \"1584374554533213180\",\n \"29377296984809279\",\n \"455684791224639069\",\n \"1701487829648668302\",\n \"2052418598727637090\",\n \"1782181777482596496\",\n \"1405174944115920234\",\n \"142697458214177465\",\n \"2230201305625643893\",\n \"1274214892560249329\",\n \"108256409252165718\",\n \"202993594240856655\",\n \"1113572638037699701\",\n \"293926112313331388\",\n \"1266928255254575415\",\n \"1378430457629976093\",\n \"2279739612382497097\",\n \"253506377110122931\",\n \"2121229711337812063\",\n \"1051445940000326502\",\n \"1585510647031081366\",\n \"513071450608671516\",\n \"1692342139284161390\",\n \"2099966457055163223\",\n \"80748089313457135\",\n \"915320896732073477\",\n \"206016695116487206\",\n \"313255738298670383\",\n \"350087690804126655\",\n \"566597602277147588\",\n \"2286505508950253560\",\n \"59749117790775024\",\n \"1254224403872925255\",\n \"62443264473934934\",\n \"879402817051146288\",\n \"579168338468101788\",\n \"109843255863370304\",\n \"2262200584042665321\",\n \"2222280625931509317\",\n \"1738258800373110427\",\n \"208491563184516265\",\n \"1409983652033055411\",\n \"1950247065602176885\",\n \"975504388282036391\",\n \"804721776541171833\",\n \"1241808411053857370\",\n \"2092916582302830364\",\n \"1783854280345651430\",\n \"1299024548425035192\",\n \"125336755862468958\",\n \"646127779493447141\"\n ],\n \"comment\": \"Canonical MinHash permutation constants. Decimal strings. p = 2^61 - 1. DO NOT REGENERATE (breaking algo_version change).\",\n \"p\": \"2305843009213693951\"\n}\n","// SimHash / MinHash / band-key primitives — a port of the normative Go\n// implementation.\n// The permutation constants are the canonical minhash_constants.json; a\n// parity test guards against drift from the repo-root copy.\n\nimport { xxh64 } from \"./xxhash64.js\";\nimport { utf8 } from \"./encoding.js\";\nimport { normalizeTokens } from \"./normalize.js\";\nimport constants from \"./minhash_constants.json\";\n\n/** Tenant hash seed: XXH64(UTF-8(salt), 0). Normative. */\nexport const saltSeed = (salt: string): bigint => xxh64(utf8(salt), 0n);\n\n/** Seed for the unsalted global fingerprint. Normative. */\nexport const GLOBAL_SEED = 0n;\n\nconst P61 = (1n << 61n) - 1n;\n\nconst A: readonly bigint[] = (constants.a as string[]).map(BigInt);\nconst B: readonly bigint[] = (constants.b as string[]).map(BigInt);\nif (A.length !== 64 || B.length !== 64) {\n throw new Error(\"fingerprint: minhash_constants.json must have 64 a and 64 b values\");\n}\n\n/**\n * Deduplicated word 3-gram shingle hashes in first-occurrence order.\n * Callers gate on MIN_TOKENS first; <3 tokens yields an empty set.\n */\nexport function shingleSet(tokens: string[], seed: bigint): bigint[] {\n const seen = new Set<string>();\n const hashes: bigint[] = [];\n for (let i = 0; i + 3 <= tokens.length; i++) {\n const sh = `${tokens[i]} ${tokens[i + 1]} ${tokens[i + 2]}`;\n if (seen.has(sh)) continue;\n seen.add(sh);\n hashes.push(xxh64(utf8(sh), seed));\n }\n return hashes;\n}\n\n/**\n * 64-bit SimHash. Normative tie rule: bit i = 1 iff the +1/−1 column sum is\n * strictly positive. Bit tests run in Number space (two 32-bit halves) —\n * 64 BigInt ops per shingle would dominate the runtime.\n */\nexport function simHash64(hashes: bigint[]): bigint {\n const sums = new Int32Array(64);\n for (const h of hashes) {\n const lo = Number(h & 0xffffffffn);\n const hi = Number(h >> 32n);\n for (let i = 0; i < 32; i++) {\n sums[i]! += (lo >>> i) & 1 ? 1 : -1;\n sums[i + 32]! += (hi >>> i) & 1 ? 1 : -1;\n }\n }\n let out = 0n;\n for (let i = 0; i < 64; i++) {\n if (sums[i]! > 0) out |= 1n << BigInt(i);\n }\n return out;\n}\n\n// ((a·h' + b) mod p), h' = h mod p — BigInt is exact by construction, which\n// is the whole point (a uint64-wrapping implementation silently produces\n// incompatible signatures; forbidden by the spec).\nconst permute = (a: bigint, b: bigint, hp: bigint): bigint => (a * hp + b) % P61;\n\n/** 64-permutation MinHash signature: min over full values, low 16 bits. */\nexport function minHash64x16(hashes: bigint[]): Uint16Array {\n const sig = new Uint16Array(64);\n const reduced = hashes.map((h) => h % P61);\n for (let i = 0; i < 64; i++) {\n let min = P61;\n const a = A[i]!;\n const b = B[i]!;\n for (const hp of reduced) {\n const v = permute(a, b, hp);\n if (v < min) min = v;\n }\n sig[i] = Number(min & 0xffffn);\n }\n return sig;\n}\n\n/** 128 bytes: 64 rows, each little-endian uint16. Storage/wire form. */\nexport function signatureBytes(sig: Uint16Array): Uint8Array {\n const out = new Uint8Array(128);\n for (let i = 0; i < 64; i++) {\n out[2 * i] = sig[i]! & 0xff;\n out[2 * i + 1] = sig[i]! >> 8;\n }\n return out;\n}\n\n/**\n * 16 LSH band keys: band b = rows 4b..4b+3 (8 bytes LE) hashed with the\n * tenant seed, reinterpreted as signed int64 (BIGINT[] storage form).\n */\nexport function bandKeys(sig: Uint16Array, seed: bigint): bigint[] {\n const keys: bigint[] = [];\n const buf = new Uint8Array(8);\n for (let band = 0; band < 16; band++) {\n for (let r = 0; r < 4; r++) {\n const v = sig[band * 4 + r]!;\n buf[2 * r] = v & 0xff;\n buf[2 * r + 1] = v >> 8;\n }\n keys.push(BigInt.asIntN(64, xxh64(buf, seed)));\n }\n return keys;\n}\n\n/**\n * Exact-form hash: normalized text with digit collapse SKIPPED — separates\n * verbatim repetition from template reuse.\n */\nexport function exactHash(text: string, seed: bigint): bigint {\n return xxh64(utf8(normalizeTokens(text, false).join(\" \")), seed);\n}\n","// Public fingerprint API — a port of the normative Go implementation\n// (Compute + ConversationKey). Output fields are already in wire encoding\n// (hex / base64 / decimal strings) so the client attaches them directly.\n\nimport { hex64, utf8, bytesToBase64 } from \"./encoding.js\";\nimport { xxh64 } from \"./xxhash64.js\";\nimport { normalizeTokens, MIN_TOKENS } from \"./normalize.js\";\nimport {\n saltSeed,\n GLOBAL_SEED,\n shingleSet,\n simHash64,\n minHash64x16,\n signatureBytes,\n bandKeys,\n exactHash,\n} from \"./similarity.js\";\n\nexport interface FingerprintOptions {\n /** Also compute the MinHash signature + band keys. */\n minHash: boolean;\n /** Also compute the unsalted global SimHash (cross-customer opt-in). */\n global: boolean;\n}\n\nexport interface ComputedFingerprint {\n /** True when the prompt is under the 8-token floor; no other field is set. */\n tooShort: boolean;\n simhash?: string; // 16 hex digits\n exactHash?: string; // 16 hex digits\n minhashB64?: string; // base64 of 128 bytes\n bandKeys?: string[]; // 16 decimal signed int64 strings\n simhashGlobal?: string; // 16 hex digits\n}\n\n/** Run the full normative pipeline over text with the tenant salt. */\nexport function computeFingerprint(\n text: string,\n salt: string,\n opts: FingerprintOptions,\n): ComputedFingerprint {\n const seed = saltSeed(salt);\n const tokens = normalizeTokens(text, true);\n if (tokens.length < MIN_TOKENS) return { tooShort: true };\n const hashes = shingleSet(tokens, seed);\n const fp: ComputedFingerprint = {\n tooShort: false,\n simhash: hex64(simHash64(hashes)),\n exactHash: hex64(exactHash(text, seed)),\n };\n if (opts.minHash) {\n const sig = minHash64x16(hashes);\n fp.minhashB64 = bytesToBase64(signatureBytes(sig));\n fp.bandKeys = bandKeys(sig, seed).map((k) => k.toString(10));\n }\n if (opts.global) {\n fp.simhashGlobal = hex64(simHash64(shingleSet(tokens, GLOBAL_SEED)));\n }\n return fp;\n}\n\n/**\n * Fallback conversation key derived from the first user message:\n * \"c_\" + hex64(XXH64(normalized text, tenant seed)).\n */\nexport function conversationKey(firstUserMessage: string, salt: string): string {\n const tokens = normalizeTokens(firstUserMessage, true);\n return \"c_\" + hex64(xxh64(utf8(tokens.join(\" \")), saltSeed(salt)));\n}\n","// POST /v1/score and POST /v1/events/post-call — the per-inference pair.\n\nimport type { Transport } from \"../http.js\";\nimport { VectoralError, notifyError } from \"../errors.js\";\nimport { assertAck } from \"../http.js\";\nimport type { ResolvedFingerprintConfig } from \"../salt.js\";\nimport { computeFingerprint, conversationKey } from \"../fingerprint/index.js\";\n\n/** Risk banding returned alongside the numeric score. */\nexport type Tier = \"low\" | \"medium\" | \"high\";\n\n/**\n * Reason codes that can appear in a score response, as a hint for autocomplete.\n *\n * **This list is not exhaustive and cannot be made exhaustive.** Reasons are\n * produced by the scoring algorithm running server-side, which ships\n * independently of this package — a new one can appear in a response without an\n * SDK release. The `(string & {})` member is what makes that safe: an unlisted\n * code type-checks. It is also why you must not write an exhaustive `switch`\n * over this type, and why `reasons` is for your logs and support conversations\n * rather than for branching. `tier` is the field to act on.\n *\n * The server returns at most three, ordered by contribution.\n *\n * Listed below by where the code comes from, because the three groups behave\n * differently — an operational code means the verdict was overridden and the\n * algorithm's opinion is not what you are looking at. See\n * `docs/concepts/inference-scoring.md` for what each one means.\n */\nexport type ReasonCode =\n // Account behaviour — the scoring algorithm's own findings. These are the\n // ordinary case, and the group that grows.\n | \"machine_paced\"\n | \"hidden_telemetry\"\n | \"birth_cohort\"\n | \"probing\"\n | \"resource_shape\"\n | \"value_extraction\"\n | \"resource_extraction\"\n | \"datacenter_origin\"\n | \"account_risk\"\n | \"synthetic_noop\"\n // Operational — these do not come from the algorithm. They are prepended when\n // something overrode or replaced the verdict, so they lead the list when they\n // appear, and the codes after them may be from a score that was not acted on.\n | \"account_blocked\"\n | \"spend_cap_exceeded:account\"\n | \"spend_cap_exceeded:org\"\n | \"scoring_unavailable\"\n | \"reputation_discount\"\n // Browser signals — present only when a verified sensor token was fused into\n // this score. Absent entirely if you have not deployed `@vectoral-labs/browser`.\n | \"webdriver_present\"\n | \"automation_signature\"\n | \"headless_browser\"\n | \"no_accept_languages\"\n | \"missing_chrome_object\"\n | \"no_human_interaction\"\n | \"no_pointer_activity\"\n | \"cursor_teleport\"\n | \"thin_fingerprint\"\n | (string & {});\n\n/**\n * Account-context block. All fields optional but recommended.\n *\n * Both fields are sent verbatim in the request body — this block is context you\n * supply, not something derived from the prompt. Worth knowing if anything on\n * your egress path inspects outgoing bodies: a label you chose will appear in\n * them as plain text. See `docs/concepts/inference-scoring.md`.\n */\nexport interface AccountBlock {\n /** RFC 3339 timestamp of when the account first existed in your system. */\n first_seen?: string;\n /**\n * Free-form tier label, e.g. \"free\" | \"pro\" | \"enterprise\". Sent as given;\n * use a stable internal label rather than anything user-supplied.\n */\n subscription_tier?: string;\n}\n\n/**\n * Per-session behavioral signals.\n *\n * Semantics matter: OMITTING this block entirely differs from sending it with\n * zero values. If absent, session-derived signals are skipped. If present (even\n * as `{}`), they participate — and `interaction_events_count: 0` is a\n * meaningful \"scripted-shaped\" signal.\n */\nexport interface SessionSignals {\n ms_since_last_request?: number;\n ms_since_page_load?: number;\n interaction_events_count?: number;\n is_first_request_in_session?: boolean;\n ms_since_signup?: number;\n}\n\n/**\n * Wire form of the prompt fingerprint. 64-bit values are strings (hex for\n * hashes, decimal for band keys) because JSON cannot carry 64-bit integers\n * safely through every runtime.\n */\nexport interface PromptFingerprintBlock {\n v: 1;\n salt_id: string;\n simhash: string;\n exact_hash: string;\n conversation_key?: string;\n minhash?: string;\n band_keys?: string[];\n simhash_global?: string;\n}\n\n/** Per-request context. */\nexport interface RequestBlock {\n /**\n * End-user IP. Drives datacenter / IP-rotation / sybil signals. Use the IP\n * your SERVER observed, not one reported by the browser.\n */\n ip?: string;\n ip_hash?: string;\n user_agent?: string;\n /** The model you're about to invoke, e.g. \"claude-opus-5\". */\n model_requested?: string;\n estimated_prompt_tokens?: number;\n /** Pass `null` or omit to skip session signals entirely. */\n session_signals?: SessionSignals | null;\n /** Only used by Deep Mode. Never leaves the customer VPC. */\n prompt_text?: string;\n /** Customer-precomputed embedding (alternative to `prompt_text`). */\n prompt_embedding?: number[];\n /**\n * LOCAL-ONLY input for prompt fingerprinting. When fingerprinting is\n * configured, the SDK hashes this in-process and attaches\n * `prompt_fingerprint`. **This field is always stripped before the request\n * leaves the process** — enabled or not — and is independent of\n * `prompt_text`/Deep Mode.\n */\n prompt_text_to_fingerprint?: string;\n /** Normally set by the SDK; pass it yourself only if you precompute. */\n prompt_fingerprint?: PromptFingerprintBlock;\n}\n\n/** Body of POST /v1/score. */\nexport interface ScoreRequest {\n /** Stable end-user identifier; the primary join key for scoring history. */\n account_id: string;\n /** Your own session token; stored for forensic correlation. */\n session_id?: string;\n account?: AccountBlock;\n request: RequestBlock;\n}\n\nexport interface ScoreResponse {\n /** Calibrated [0,1] score. 0 = clean, 1 = certain fraud. */\n score: number;\n /** low (<0.4) | medium (<0.7) | high (>=0.7). */\n tier: Tier;\n /** Up to 3 reason codes. */\n reasons: ReasonCode[];\n deep_mode_active: boolean;\n /**\n * False while the per-account baseline is still forming: the score is\n * provisional — advisory, not enforcement-grade.\n */\n baseline_ready: boolean;\n /** True during the customer's warm-up window. The score is still real. */\n shadow_mode: boolean;\n /** Diagnostic only; treat as an opaque string. */\n algorithm?: string;\n algorithm_version?: string;\n /** The Vectoral release that answered, e.g. `0.1.7`. */\n service_version?: string;\n /**\n * True when this is the SDK's fail-open default rather than a real verdict.\n * See `RegistrationVerdict.degraded`.\n */\n degraded?: boolean;\n /** The underlying failure, when `degraded`. */\n error?: VectoralError;\n}\n\n/** Body of POST /v1/events/post-call. */\nexport interface PostCallEvent {\n /** Must match the `account_id` from the preceding score call. */\n account_id: string;\n session_id?: string;\n /** Recommended; omitting it loses model-mix features. */\n model?: string;\n /** Required if `inference_cost_usd` is not supplied. */\n prompt_tokens?: number;\n /** Required if `inference_cost_usd` is not supplied. */\n completion_tokens?: number;\n latency_ms?: number;\n /** If omitted, the server computes cost from its bundled rate table. */\n inference_cost_usd?: number;\n /** Idempotency key. Also what makes an SDK-level retry safe. */\n event_id?: string;\n}\n\nexport interface OkResponse {\n ok: boolean;\n duplicate?: boolean;\n}\n\nexport interface InferenceOptions {\n failOpen: boolean;\n fingerprint: ResolvedFingerprintConfig | null;\n onError: ((err: VectoralError, context: string) => void) | undefined;\n onWarning: ((message: string) => void) | undefined;\n}\n\n/** The verdict returned when a score call fails open. */\nconst FAIL_OPEN_SCORE: Omit<ScoreResponse, \"error\"> = {\n score: 0,\n tier: \"low\",\n reasons: [],\n deep_mode_active: false,\n baseline_ready: false,\n shadow_mode: false,\n degraded: true,\n};\n\nexport class Inference {\n private warnedMissingFingerprintInput = false;\n\n constructor(\n private readonly transport: Transport,\n private readonly opts: InferenceOptions,\n ) {}\n\n /** Pre-call risk score. Call before invoking the LLM. */\n async score(req: ScoreRequest): Promise<ScoreResponse> {\n try {\n const body = await this.transport.post<ScoreResponse>(\n \"/v1/score\",\n this.prepare(req),\n { idempotent: false },\n );\n // See the matching check in registrations.score(): syntactically valid\n // JSON is not proof of a verdict, and a silent pass-through would hand\n // the caller a score of `undefined` with `degraded` unset.\n //\n // Every field below is unconditional server-side, and callers branch on\n // all of them — the documented enforcement guard reads `baseline_ready`,\n // so a response missing it would read as \"not enforcement-grade\" and\n // permit the request while claiming to be healthy.\n //\n // `tier` is checked for being a non-empty string and NOT against a list\n // of known values. Bands are an open scale server-side; an allowlist\n // would fail-open every call the day a new one ships, which is the very\n // bug this check exists to prevent.\n //\n // Validated through an untrusted view: `body` is typed as ScoreResponse,\n // so TypeScript would reject a check for a shape that type cannot hold —\n // which is exactly the shape a misbehaving server can send.\n const raw = body as unknown as Record<string, unknown>;\n if (\n typeof raw?.score !== \"number\" ||\n typeof raw?.tier !== \"string\" ||\n raw.tier === \"\" ||\n typeof raw?.deep_mode_active !== \"boolean\" ||\n typeof raw?.baseline_ready !== \"boolean\" ||\n typeof raw?.shadow_mode !== \"boolean\" ||\n !(Array.isArray(raw?.reasons) || raw?.reasons === null)\n ) {\n throw new VectoralError(\n \"vectoral: response is not a score verdict (missing or malformed required fields)\",\n { code: \"invalid_response\", status: 200, responseBody: JSON.stringify(body) },\n );\n }\n // Go marshals a nil slice as `null`; that is the server's own shape for\n // \"no reasons\", so normalise rather than hand the caller a null array.\n return raw.reasons === null ? { ...body, reasons: [] } : body;\n } catch (err) {\n if (!this.opts.failOpen || !(err instanceof VectoralError)) throw err;\n notifyError(this.opts.onError, err, \"inference.score\");\n return { ...FAIL_OPEN_SCORE, error: err };\n }\n }\n\n /**\n * Post-call token/cost telemetry. Call after the LLM responds.\n *\n * This is the feedback that makes every later score meaningful — it is where\n * token velocity and cost signals come from. It never fails open: telemetry\n * you silently drop is telemetry you never notice missing.\n */\n postCall(event: PostCallEvent): Promise<OkResponse> {\n return this.transport\n .post<OkResponse>(\"/v1/events/post-call\", event, {\n idempotent: event.event_id !== undefined,\n })\n .then(assertAck);\n }\n\n /**\n * Consume `prompt_text_to_fingerprint` (always stripped from the wire,\n * enabled or not) and attach the computed block when fingerprinting is\n * active. The caller's object is never mutated.\n */\n private prepare(req: ScoreRequest): ScoreRequest {\n const { prompt_text_to_fingerprint: text, ...rest } = req.request;\n const out: ScoreRequest = { ...req, request: rest };\n const cfg = this.opts.fingerprint;\n if (!cfg) {\n if (text !== undefined && text !== \"\" && !this.warnedMissingFingerprintInput) {\n this.warnedMissingFingerprintInput = true;\n this.opts.onWarning?.(\n \"request.prompt_text_to_fingerprint was supplied but prompt \" +\n \"fingerprinting is not configured — the text was stripped and no \" +\n \"fingerprint was sent. Set `fingerprint: { enabled: true, salt, saltId }`\",\n );\n }\n return out;\n }\n // A caller who precomputed their own block (a proxy, a batch importer)\n // asked for exactly that. Recomputing over it would silently discard work\n // the docs tell them to do.\n if (rest.prompt_fingerprint !== undefined) return out;\n if (text === undefined || text === \"\") {\n if (!this.warnedMissingFingerprintInput) {\n this.warnedMissingFingerprintInput = true;\n this.opts.onWarning?.(\n \"prompt fingerprinting is configured but this score() call has no \" +\n \"request.prompt_text_to_fingerprint — no fingerprint sent\",\n );\n }\n return out;\n }\n const fp = computeFingerprint(text, cfg.salt, {\n minHash: true,\n global: cfg.shareGlobal,\n });\n // Under the 8-token floor there is not enough text for a stable\n // fingerprint; send nothing rather than something noisy.\n if (fp.tooShort) return out;\n const block: PromptFingerprintBlock = {\n v: 1,\n salt_id: cfg.saltId,\n simhash: fp.simhash!,\n exact_hash: fp.exactHash!,\n conversation_key: req.session_id ?? conversationKey(text, cfg.salt),\n minhash: fp.minhashB64!,\n band_keys: fp.bandKeys!,\n };\n if (cfg.shareGlobal) block.simhash_global = fp.simhashGlobal!;\n out.request = { ...rest, prompt_fingerprint: block };\n return out;\n }\n}\n","// POST /v1/identity — low-volume, high-signal authentication events, and the\n// place a registration gets linked to the account it became.\n\nimport type { Transport } from \"../http.js\";\nimport { assertAck } from \"../http.js\";\nimport type { OkResponse } from \"./inference.js\";\n\nexport type IdentityEventType = \"signup\" | \"login\" | \"dashboard\";\n\nexport interface IdentityEvent {\n /** Created if not already present, so identity-only accounts still surface. */\n account_id: string;\n /** Defaults to `login` server-side. */\n event_type?: IdentityEventType;\n /** The user's real browser IP at that moment. */\n ip?: string;\n /** Your own keyed token instead of `ip`. */\n ip_hash?: string;\n asn?: number;\n ip_country?: string;\n user_agent?: string;\n /** Idempotency key. Also what makes an SDK-level retry safe. */\n event_id?: string;\n /**\n * The handle from `registrations.score()`. Send it once, on the `signup`\n * event, and the fraud labels you later report reach back to the registration\n * that produced the account. That is the feedback loop.\n *\n * It can arrive late — if you gate account creation on email verification,\n * store the id with your pending-signup record and send it whenever the\n * account is finally created. An unknown or already-linked id is ignored,\n * never rejected.\n */\n registration_id?: string;\n}\n\nexport class Identity {\n constructor(private readonly transport: Transport) {}\n\n /**\n * Record an authentication event.\n *\n * Use the same IP shape here as on `inference.score()`: the accounts-per-IP\n * query unions both sources, so mixing raw addresses on one and tokens on the\n * other splits your own sybil graph.\n */\n record(event: IdentityEvent): Promise<OkResponse> {\n return this.transport\n .post<OkResponse>(\"/v1/identity\", event, {\n idempotent: event.event_id !== undefined,\n })\n .then(assertAck);\n }\n\n /**\n * Convenience for the common signup case: record the event and link the\n * registration in one call.\n */\n linkRegistration(\n accountId: string,\n registrationId: string,\n extra: Omit<IdentityEvent, \"account_id\" | \"registration_id\" | \"event_type\"> = {},\n ): Promise<OkResponse> {\n return this.record({\n ...extra,\n account_id: accountId,\n event_type: \"signup\",\n registration_id: registrationId,\n });\n }\n}\n","// POST /v1/labels — ground truth. This is what the models train on.\n\nimport type { Transport } from \"../http.js\";\nimport { assertAck } from \"../http.js\";\nimport type { OkResponse } from \"./inference.js\";\n\nexport type Label = \"fraud\" | \"legitimate\";\n\nexport interface LabelRequest {\n account_id: string;\n label: Label;\n notes?: string;\n}\n\nexport class Labels {\n constructor(private readonly transport: Transport) {}\n\n /**\n * Report a verdict you reached yourself — a chargeback, a ban, a support\n * resolution. Label legitimate accounts too: a corpus of only-fraud labels\n * teaches a model nothing about the boundary.\n */\n submit(req: LabelRequest): Promise<OkResponse> {\n return this.transport\n .post<OkResponse>(\"/v1/labels\", req, { idempotent: false })\n .then(assertAck);\n }\n\n fraud(accountId: string, notes?: string): Promise<OkResponse> {\n return this.submit({\n account_id: accountId,\n label: \"fraud\",\n ...(notes !== undefined ? { notes } : {}),\n });\n }\n\n legitimate(accountId: string, notes?: string): Promise<OkResponse> {\n return this.submit({\n account_id: accountId,\n label: \"legitimate\",\n ...(notes !== undefined ? { notes } : {}),\n });\n }\n}\n","import { VectoralConfigError, VectoralError } from \"./errors.js\";\nimport { Transport, type FetchLike } from \"./http.js\";\nimport { resolveFingerprintConfig, type FingerprintOptions } from \"./salt.js\";\nimport { Registrations } from \"./resources/registrations.js\";\nimport { Inference } from \"./resources/inference.js\";\nimport { Identity } from \"./resources/identity.js\";\nimport { Labels } from \"./resources/labels.js\";\n\nconst DEFAULT_BASE_URL = \"https://api.vectoral.cloud\";\nconst DEFAULT_TIMEOUT_MS = 5000;\nconst DEFAULT_RETRIES = 2;\n\nexport interface VectoralOptions {\n /**\n * API key (`vg_live_…`), sent as `Authorization: Bearer`. Defaults to\n * `process.env.VECTORAL_API_KEY`. Provide exactly one of `apiKey` or\n * `customerId`.\n */\n apiKey?: string;\n /**\n * Customer identifier, sent as `X-Customer-ID`. Only for a self-hosted or\n * in-VPC deployment running in header auth mode.\n */\n customerId?: string;\n /** API base URL. Defaults to `VECTORAL_BASE_URL`, then the hosted endpoint. */\n baseUrl?: string;\n /** Per-request timeout in ms. Default 5000. */\n timeoutMs?: number;\n /** Custom fetch implementation. Defaults to global fetch. */\n fetch?: FetchLike;\n /** Extra headers merged into every request. */\n headers?: Record<string, string>;\n /**\n * Retry attempts for transient failures. Default 2.\n *\n * **Only applied to calls that carry an `event_id`.** Every write endpoint\n * mints a new row per call, so retrying a request without an idempotency key\n * would double-write after a response lost in transit. Supplying `event_id`\n * is what buys you retries.\n */\n retries?: number;\n /**\n * Return a safe default instead of throwing when a scoring call fails.\n * Default true. Applies to `registrations.score()` and `inference.score()`;\n * results carry `degraded: true`. Telemetry and label calls always throw —\n * you want to know when those are being dropped.\n */\n failOpen?: boolean;\n /** Privacy-preserving prompt fingerprinting. Off unless `enabled`. */\n fingerprint?: FingerprintOptions;\n /** Called for every fail-open failure. Default: none (silent). Wire this up. */\n onError?: (err: VectoralError, context: string) => void;\n /** Called for non-fatal configuration problems. Defaults to `console.warn`. */\n onWarning?: (message: string) => void;\n}\n\nconst env = (name: string): string | undefined => {\n const p = (globalThis as { process?: { env?: Record<string, string | undefined> } })\n .process;\n return p?.env?.[name];\n};\n\n/**\n * Server-side Vectoral client.\n *\n * Use this on your backend only. It holds a secret API key, and the signals it\n * sends — above all the client IP — are only trustworthy when your own server\n * observed them.\n */\nexport class Vectoral {\n readonly registrations: Registrations;\n readonly inference: Inference;\n readonly identity: Identity;\n readonly labels: Labels;\n /** True when prompt fingerprinting resolved to a usable salt. */\n readonly fingerprintingActive: boolean;\n\n constructor(opts: VectoralOptions = {}) {\n const customerId = opts.customerId;\n // The env fallback applies only when no credential was passed at all. A\n // stray VECTORAL_API_KEY in a shared .env or on a CI runner must not make\n // header auth unconstructable — the caller supplied exactly one credential.\n const apiKey = opts.apiKey ?? (customerId ? undefined : env(\"VECTORAL_API_KEY\"));\n if (apiKey && customerId) {\n throw new VectoralConfigError(\n \"provide either `apiKey` or `customerId`, not both\",\n );\n }\n let authHeader: Record<string, string>;\n if (apiKey) {\n authHeader = { Authorization: `Bearer ${apiKey}` };\n } else if (customerId) {\n authHeader = { \"X-Customer-ID\": customerId };\n } else {\n throw new VectoralConfigError(\n \"`apiKey` is required (pass it, or set VECTORAL_API_KEY)\",\n );\n }\n\n const fetchImpl = opts.fetch ?? globalThis.fetch;\n if (!fetchImpl) {\n throw new VectoralConfigError(\n \"no global fetch available — pass `fetch` (Node >=18 has it built in)\",\n );\n }\n\n const onWarning =\n opts.onWarning ?? ((m: string) => console.warn(`[vectoral] ${m}`));\n const resolved = resolveFingerprintConfig(opts.fingerprint);\n for (const w of resolved.warnings) onWarning(w);\n this.fingerprintingActive = resolved.config !== null;\n\n const transport = new Transport({\n baseUrl: (opts.baseUrl ?? env(\"VECTORAL_BASE_URL\") ?? DEFAULT_BASE_URL).replace(\n /\\/+$/,\n \"\",\n ),\n authHeader,\n headers: opts.headers ?? {},\n timeoutMs: opts.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n fetch: fetchImpl,\n retries: opts.retries ?? DEFAULT_RETRIES,\n });\n\n const failOpen = opts.failOpen ?? true;\n this.registrations = new Registrations(transport, {\n failOpen,\n onError: opts.onError,\n });\n this.inference = new Inference(transport, {\n failOpen,\n fingerprint: resolved.config,\n onError: opts.onError,\n onWarning,\n });\n this.identity = new Identity(transport);\n this.labels = new Labels(transport);\n }\n}\n\n/** Convenience factory equivalent to `new Vectoral(opts)`. */\nexport const createClient = (opts: VectoralOptions = {}): Vectoral =>\n new Vectoral(opts);\n"],"mappings":"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","names":["encoder","env"]}
|