npm package: @mack1ch/fingerprint-js
Description: Browser-only fingerprinting library for antifraud and risk scoring.
Latest version: 0.2.0

# @1payment/fingerprint

TypeScript SDK для device/browser fingerprinting в антифрод-сценариях.

Пакет помогает:

- собирать браузерные сигналы,
- вычислять устойчивые идентификаторы среды,
- сравнивать fingerprint-снимки,
- строить вероятностный matching-контур (vNext),
- безопасно раскатывать решения через shadow/compare/assist/enforcement.

---

## 1. Установка

```bash
npm i @1payment/fingerprint
```

Требования:

- Node.js `>= 18`
- для браузерной части нужен реальный browser context

---

## 2. Быстрый старт (Browser)

```ts
import { createFingerprint } from "@1payment/fingerprint";

const fp = await createFingerprint({
  mode: "balanced",
  includeRaw: false,
  includeDebug: false
});

console.log(fp);
```

Вы получаете:

- `fingerprintId` — полный fingerprint,
- `stableId` — более устойчивый идентификатор,
- `environmentId` — идентификатор среды,
- `confidenceScore` — качество сигналов,
- `riskScore` — эвристический риск,
- `flags` — признаки нестабильности/анома

---

## 3. Основной публичный API

### Базовые функции

- `createFingerprint(options?) => Promise<FingerprintResult>`
- `getFingerprint(options?) => Promise<FingerprintResult>` (алиас)
- `hashComponents(components, salt?) => string`
- `compareFingerprints(a, b, options?) => FingerprintComparison`
- `toFingerprintPayload(result, requestId?) => FingerprintPayload`

### Стратегии сравнения

- `strict` — более жесткое сравнение
- `resilient` — устойчивое сравнение при частичных изменениях сигналов

Пример:

```ts
import { compareFingerprints } from "@1payment/fingerprint";

const result = compareFingerprints(fpA, fpB, { strategy: "resilient" });
console.log(result.similarity, result.confidenceLabel);
```

---

## 4. Опции createFingerprint

Ключевые опции:

- `mode`: `fast | balanced | strict`
- `timeoutMs`: таймаут на коллектор
- `includeRaw`: включать сырые компоненты
- `includeDebug`: отладочная информация по коллекторам
- `includePerformance`: тайминги коллекторов
- `collectPermissions`, `collectCanvas`, `collectWebGL`, `collectAudio`, `collectFonts`, `collectStorageSignals`
- `salt`: соль для хэширования
- `componentWeights`: веса компонент
- `customComponents`: свои асинхронные коллекторы

Рекомендация по режимам:

- `fast` — для раннего этапа страницы,
- `balanced` — рабочий дефолт,
- `strict` — для high-risk сценариев.

---

## 5. Namespace v2 (browser + server flow)

В пакете есть namespace `v2`:

- `v2.BrowserFingerprintSession`
- `v2.FingerprintServerSDK`
- `v2.migrateV1PayloadToV2`
- `v2.validateEnvelopeV2`
- `v2.hashPII`
- `v2.similarityScore`

### Browser (v2)

```ts
import { v2 } from "@1payment/fingerprint";

const session = new v2.BrowserFingerprintSession();
const envelope = await session.collectStage({
  requestId: "req-1",
  stage: "pre_submit",
  mode: "balanced"
});
```

### Server (v2)

```ts
import { v2 } from "@1payment/fingerprint";

const sdk = new v2.FingerprintServerSDK({ shadowMode: true });
const ingest = await sdk.ingestEnvelope(envelope, { country: "RU", asn: "AS12345" });
const match = await sdk.matchProfiles(ingest.eventId);
const risk = await sdk.calculateRisk(ingest.eventId);
```

---

## 6. Namespace vNext (matching platform)

`vNext` — это production-контур для candidate retrieval + pairwise matching.

Что доступно:

- versioned contracts и compatibility validation,
- retrieval и `recall@K`,
- pairwise feature builder,
- baseline/prod модели,
- calibration layer,
- decision output (`same_device | likely_same | review | different`),
- rollout runtime (`shadow | compare | assist | enforcement`),
- logging/storage/labeling helpers,
- мониторинг (cohorts, drift).

### Пример vNext runtime

```ts
import { vNext } from "@1payment/fingerprint";

const versions = vNext.buildVersionSet({
  collectorVersion: "collector-v1",
  featureSchemaVersion: "feature-v1",
  modelVersion: "model-v1",
  calibrationVersion: "cal-v1",
  thresholdPolicyVersion: "thr-v1"
});
```

Подробности:

- `docs/VNEXT_PHASE2.md`
- `docs/threshold-policy.md`
- `docs/rollout-checklist.md`

---

## 7. Offline ML (опционально)

Если вы используете оффлайн обучение:

- скрипты в `offline_ml/`
- baseline: Logistic Regression
- production candidate: HistGradientBoosting/XGBoost
- калибровка: sigmoid/isotonic
- экспорт model/calibration/threshold artifacts

Запуск:

```bash
python -m venv .venv
source .venv/bin/activate
pip install -r offline_ml/requirements.txt
python offline_ml/train.py --input "/path/to/pairwise.jsonl" --output-dir offline_ml/out --model-kind both --calibration sigmoid
```

Подробный процесс:

- `offline_ml/README.md`
- `offline_ml/runbook.md`

---

## 8. Демо для ручного тестирования

```bash
npm run demo:serve
```

Откройте:

- `http://localhost:4173/demo/`

В demo есть русскоязычный test harness:

- сценарные прогоны (`Balanced x5`, `Strict x5`, `Mixed x6`),
- быстрый compare последних результатов,
- ручное сравнение JSON A/B,
- экспорт истории прогонов.

---

## 9. Проверка качества перед релизом

```bash
npm run typecheck
npm run lint
npm test
npm run build
```

---

## 10. Ограничения и важные замечания

- Fingerprinting — вероятностный сигнал, не абсолютная идентификация.
- Не принимайте финальные антифрод-решения только по одному hash/id.
- Для прод-решений используйте:
  - candidate retrieval,
  - pairwise scoring,
  - calibration,
  - threshold policy,
  - мониторинг cohort/drift.
- Synthetic-only данные подходят для bootstrap/sanity, но не для финальных порогов production.

---

## 11. Документация

- `docs/API.md`
- `docs/ARCHITECTURE.md`
- `docs/SECURITY_PRIVACY.md`
- `docs/TESTING.md`
- `docs/UPGRADE_V2.md`
- `docs/BROWSER_SDK_V2.md`
- `docs/SERVER_SDK_V2.md`
- `docs/PAYMENT_FLOW_MAPPING_V2.md`
- `docs/VNEXT_PHASE2.md`
- `docs/threshold-policy.md`
- `docs/rollout-checklist.md`

---

## 12. Лицензия

MIT
# @1payment/fingerprint

TypeScript SDK для device/browser fingerprinting в платежных сценариях 1PAYMENT.

SDK ориентирован на antifraud/risk scoring и состоит из browser + server контуров:
- сбор клиентских сигналов,
- probabilistic matching,
- profile linking (device/payer/instrument),
- explainable risk.

## Важные ограничения

- Библиотека **не обещает** 100% идентификацию пользователя и идеальную склейку между браузерами.
- Результат нужно использовать как вероятностный сигнал для antifraud/risk систем.
- По умолчанию библиотека **не делает сетевых запросов**.
- Библиотека **не вызывает permission prompts**.

## Установка

```bash
npm i @1payment/fingerprint
```

## Быстрый старт (Browser)

```html
<script type="module">
  import { createFingerprint } from "https://esm.sh/@1payment/fingerprint";

  const fp = await createFingerprint({
    mode: "fast",
    includeRaw: false,
    includeDebug: false
  });

  console.log(fp);
</script>
```

## Что SDK возвращает

- `fingerprintId` — полный session/browser fingerprint.
- `stableId` — более устойчивый fingerprint (device-centric subset).
- `environmentId` — fingerprint среды (браузер/платформа/рендер).
- `confidenceScore` — качество доступных сигналов.
- `riskScore` — риск по клиентским эвристикам.
- `flags` — tamper/anomaly/privacy-индикаторы.

---

## Публичный API

### v1/v2 base API

- `createFingerprint(options?) => Promise<FingerprintResult>`
- `getFingerprint(options?) => Promise<FingerprintResult>`
- `hashComponents(components, salt?) => string`
- `compareFingerprints(a, b, options?) => FingerprintComparison`
- `toFingerprintPayload(result, requestId?) => FingerprintPayload`

## V2 APIs

В `@1payment/fingerprint` доступен namespace `v2`:

- `v2.BrowserFingerprintSession`
- `v2.FingerprintServerSDK`
- `v2.migrateV1PayloadToV2`
- `v2.validateEnvelopeV2`
- `v2.hashPII`
- `v2.similarityScore`

## vNext APIs

В `@1payment/fingerprint` доступен namespace `vNext`:

- retrieval + pairwise feature builder
- baseline/production model interfaces
- calibration layer
- rollout runtime (`shadow/compare/assist/enforcement`)
- versioned artifact compatibility validation
- labeling and monitoring helpers

Production contracts описаны в `docs/VNEXT_PHASE2.md`.

---

## Как теперь работает vNext (Phase 2)

`vNext` теперь разделен на runtime matching-контур и offline ML lifecycle.

### 1) Browser snapshot (сбор сигналов)

Browser SDK собирает multi-signal fingerprint (navigator/locale/screen/canvas/webgl/audio/fonts/storage/permissions), а также:

- `fingerprintId`, `stableId`, `environmentId`
- component quality metadata (present/missing/unstable/privacy_reduced/error)
- top-level flags (webdriver/automation/incognito/spoofing hints)

Важно: `fingerprintId/stableId/environmentId` больше не трактуются как финальное решение, а используются как retrieval/diagnostic keys.

### 2) Runtime matching pipeline (server-side)

`vNext` runtime работает как двухстадийный matching:

1. candidate retrieval / blocking
2. pairwise scoring + calibration + threshold decision

Пайплайн:

- retrieval находит кандидатов (stable/environment/buckets/context);
- pairwise feature builder строит comparison vector;
- model выдает `rawScore`;
- calibration превращает его в `calibratedProbability`;
- threshold policy выдает решение:
  - `same_device`
  - `likely_same`
  - `review`
  - `different`

Decision содержит:

- `rawScore`
- `calibratedProbability`
- `decision`
- `reasons`
- `candidateSnapshotId`
- `modelVersion`
- `calibrationVersion`
- `thresholdPolicyVersion`

### 3) Versioned contracts и артефакты

Контракты versioned и валидируются до инференса:

- `collector_version`
- `feature_schema_version`
- `model_version`
- `calibration_version`
- `threshold_policy_version`

Артефакты загружаются независимо:

- model artifact
- calibration artifact
- threshold artifact

Если версии несовместимы — runtime отклоняет запуск инференса.

### 4) Logging и storage для обучения

Runtime логирует:

- snapshot-level события
- retrieval-level события
- pairwise-level события

Логи содержат versions + business anchors и используются для offline dataset/label enrichment.

Минимальный storage-модуль хранит:

- snapshots
- retrieval logs
- pairwise logs
- match decisions
- device profile history

### 5) Labeling pipeline

Pair labels строятся offline job’ом из production-like логов и anchors:

- positives: confirmed/verified same-entity anchors
- negatives: easy/medium/hard
- hard negatives: near-miss/high-score label=0 и конфликтные сценарии

### 6) Offline training lifecycle

Offline stack находится в `offline_ml/` и не зависит от runtime:

- baseline: Logistic Regression
- production candidate: XGBoost (или HistGradientBoosting fallback)
- calibration: sigmoid/isotonic
- leak-safe split policy
- evaluation reports + artifact export

### 7) Rollout modes

Поддерживаются безопасные режимы:

- `shadow` — считается, но не влияет на финальный action
- `compare` — сравнение с предыдущим контуром
- `assist` — сигнал для review/admin
- `enforcement` — участие в финальном decisioning

### 8) Monitoring и drift

Доступны helpers для:

- PR/ROC/LogLoss/Brier
- cohort breakdown
- retrieval recall@K
- distribution drift (PSI-like)

---

## Как потестировать vNext

### Полная проверка (рекомендуется)

```bash
npm run typecheck
npm test
```

### Только vNext тесты

```bash
npm run test -- test/vnext.pipeline.test.ts test/vnext.retrieval.test.ts test/vnext.phase2.test.ts
```

### Browser smoke (демо)

```bash
npm run demo:serve
```

Откройте `http://localhost:4173/demo/` и сравните несколько сборов/режимов.

Быстрый ручной чеклист в demo:

1. Нажмите `Run Balanced x5`:
   - проверьте `stable transitions` (должен быть высоким);
   - посмотрите `last similarity` между соседними запусками.
2. Нажмите `Run Mixed x6`:
   - оцените, как меняется similarity между `fast/balanced/strict`;
   - сравните `Compare Last Two`.
3. Используйте `Use Last as A/B` + `Compare JSONs` и `Compare Strict`:
   - `resilient` обычно устойчивее при частичных изменениях;
   - `strict` полезен для same-browser проверки.
4. Нажмите `Download History`:
   - сохраните историю прогона в JSON для последующего анализа/репортов.
5. Нажмите `Clear History` и повторите сценарий в incognito/private режиме.

### Offline trainer

```bash
python -m venv .venv
source .venv/bin/activate
pip install -r offline_ml/requirements.txt
python offline_ml/train.py --input pairwise_training_rows.jsonl --output-dir offline_ml/out --model-kind both --calibration sigmoid
```

Проверьте в `offline_ml/out`:

- `model-*.json`
- `calibration-*.json`
- `threshold-*.json`
- `evaluation-report.json`
- `evaluation-report.md`

---

## Режимы сбора (Browser)

- `fast` — минимальная задержка для initial render.
- `balanced` — режим по умолчанию для pre-submit.
- `strict` — максимальный сбор для high-risk сценариев.

Рекомендуемый lifecycle:
- `page_open` -> `fast`
- `pre_submit` -> `balanced`
- `post_init`/подозрительные кейсы -> `strict`

---

## Сравнение отпечатков

`compareFingerprints()` поддерживает стратегии:
- `strict` — жесткое сравнение (подходит для same-browser проверок).
- `resilient` — устойчивое сравнение (лучше для cross-browser и частичных изменений).

Пример:

```ts
import { compareFingerprints } from "@1payment/fingerprint";

const cmp = compareFingerprints(a, b, { strategy: "resilient" });
console.log(cmp.similarity, cmp.confidenceLabel, cmp.matchedComponents);
```

---

## Browser SDK v2 (multi-stage)

```ts
import { v2 } from "@1payment/fingerprint";

const session = new v2.BrowserFingerprintSession();

const pageOpen = await session.collectStage({
  requestId: "req-1",
  stage: "page_open",
  mode: "fast",
  paymentContext: {
    partnerId: "partner-1",
    projectId: "project-1",
    flowType: "card_form",
    paymentType: "card",
    userId: "u-123",
    userData: "crm-42",
    shopUrl: "https://merchant.example",
    lang: "ru"
  }
});

session.registerSubmitAttempt();

const preSubmit = await session.collectStage({
  requestId: "req-1",
  stage: "pre_submit",
  mode: "balanced"
});
```

---

## Server SDK v2 (ingestion/enrichment/scoring)

```ts
import { v2 } from "@1payment/fingerprint";

const server = new v2.FingerprintServerSDK({ shadowMode: true });

const ingest = await server.ingestEnvelope(preSubmit, {
  ip: "203.0.113.10",
  asn: "AS12345",
  country: "RU",
  origin: "https://merchant.example"
});

await server.enrichWithPaymentInit({
  requestId: "req-1",
  orderId: "order-1001",
  status: "init",
  paymentType: "card"
});

await server.enrichWithCallback({
  orderId: "order-1001",
  status: "success",
  token: "tok_abc",
  accountMask: "4111****1111"
});

const match = await server.matchProfiles(ingest.eventId);
const risk = await server.calculateRisk(ingest.eventId);
const admin = await server.buildAdminView(ingest.eventId);
```

Что возвращает server-контур:
- match probabilities (`sameDeviceProbability`, `samePayerProbability`, `sameInstrumentProbability`)
- `profileDecision`
- explainability (`topRiskReasons`, `topTrustReasons`)
- admin-ready view model

---

## Какие данные прокидывать для максимальной точности

Чтобы повысить качество идентификации, передавайте:
- `partnerId`, `projectId`, `flowType`, `paymentType`
- `userId`, `userData`
- `orderId` (когда появляется)
- `tokenHash`/`token` (для recurring/card linkage)
- `phoneHash`, `emailHash`, `nameHash` (где применимо)
- request metadata на сервере: `ip`, `asn`, `country`, `origin/referrer`

Важно: точность повышается не за счет одного “супер-хэша”, а за счет **мультисигнального match + server enrichment**.

---

## Как считается fingerprint (формула)

Browser SDK собирает набор компонент:

`components = { navigator, locale, screen, canvas, webgl, audio, fonts, storage, permissions?, ...customComponents }`

Дальше применяется канонизация (стабильный порядок ключей/значений):

`C = canonicalize(components)`

Если веса не заданы, базовый идентификатор считается как:

`fingerprintId = SHA-256(salt + ":" + JSON.stringify(C))`

Если заданы `componentWeights`, используется взвешенное хэширование:

`fingerprintId = SHA-256(salt + ":" + join("|", repeat(path=value, weight(path))))`

где:
- `path=value` — leaf-пара компоненты (например, `navigator.userAgent="..."`);
- `weight(path)` — вес для пути (`navigator.userAgent`) или его top-level ключа (`navigator`);
- веса нормализуются в диапазон `1..10`;
- вес `<= 0` исключает параметр из финального хэша.

Дополнительно считаются:
- `stableId = hash(weightedStableSubset(C))`
- `environmentId = hash(weightedEnvironmentSubset(C))`
- `confidenceScore`, `riskScore`, `flags` — на основе качества/аномалий сигналов.

---

## Что можно менять самостоятельно

Через `createFingerprint(options)` можно гибко управлять расчетом:

- включать/выключать коллекторы:
  - `collectCanvas`, `collectWebGL`, `collectAudio`, `collectFonts`, `collectStorageSignals`, `collectPermissions`;
- задавать `mode` (`fast | balanced | strict`) и `timeoutMs`;
- добавлять свои сигналы через `customComponents`;
- менять вклад каждого сигнала через `componentWeights`;
- задавать `salt` для изоляции хэш-пространства.

Пример:

```ts
const fp = await createFingerprint({
  mode: "balanced",
  salt: "merchant-v1",
  collectPermissions: true,
  componentWeights: {
    navigator: 2,
    "navigator.userAgent": 4,
    screen: 1,
    "fonts.availableCount": 3,
    "audio.baseLatency": 0
  },
  customComponents: {
    appBuild: () => "web-2026.03.20"
  }
});
```

Важно: изменение весов и состава компонент изменяет распределение `fingerprintId/stableId/environmentId`. Для production рекомендуем фиксировать конфиг по версии (`signalsVersion`/ваша версия профиля).

---

## Совместимость с v1

- Принимается старый payload через migration layer:
  - `v2.migrateV1PayloadToV2(...)`
- В `ingestEnvelope` доступен флаг `migratedFromV1` и `missingFields`.

---

## Demo

Запуск:

```bash
npm run demo:serve
```

Откройте:
- `http://localhost:4173/demo/`

В demo доступны:
- `Collect Fast/Balanced/Strict`
- сравнение двух JSON (Safari ↔ Chrome)
- `Compare JSONs` (resilient)
- `Compare Strict`
- `Copy Last JSON`, `Use Last as A/B`

---

## Скрипты

- `npm run lint`
- `npm run typecheck`
- `npm run test`
- `npm run test:browser`
- `npm run build`
- `npm run size`

---

## Документация

- `docs/API.md`
- `docs/ARCHITECTURE.md`
- `docs/SECURITY_PRIVACY.md`
- `docs/TESTING.md`
- `docs/UPGRADE_V2.md`
- `docs/BROWSER_SDK_V2.md`
- `docs/SERVER_SDK_V2.md`
- `docs/PAYMENT_FLOW_MAPPING_V2.md`
- `docs/VNEXT_PHASE2.md`
- `docs/threshold-policy.md`
- `docs/rollout-checklist.md`
- `offline_ml/runbook.md`