@vigilkids/device-fingerprint 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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024-present VigilKids
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,99 @@
1
+ # @vigilkids/device-fingerprint
2
+
3
+ Browser device fingerprint and platform standard client headers for VigilKids / Visiva frontend applications. Built on [FingerprintJS v4](https://github.com/nicknisi/fingerprintjs) (MIT, open-source).
4
+
5
+ ## Features
6
+
7
+ - **Deterministic fingerprint** — same hash in normal and incognito mode (canvas/webgl/audio signals)
8
+ - **Memory-only cache** — no cookie/localStorage dependency, recomputes on page load (~50ms)
9
+ - **Platform headers** — generates `X-Device-ID`, `X-Client-Type`, `X-Client-Platform`, `X-Product-Code` headers
10
+ - **Multi-product** — works with any VigilKids product (`vigilkids`, `visiva`, etc.)
11
+
12
+ ## Install
13
+
14
+ ```bash
15
+ pnpm add @vigilkids/device-fingerprint
16
+ ```
17
+
18
+ ## Usage
19
+
20
+ ### Client Headers (recommended)
21
+
22
+ Most use cases only need `getClientHeaders` — it computes the fingerprint internally and returns all standard headers:
23
+
24
+ ```typescript
25
+ import { getClientHeaders } from '@vigilkids/device-fingerprint'
26
+
27
+ const headers = await getClientHeaders({
28
+ productCode: 'visiva',
29
+ appVersion: '1.0.0', // optional
30
+ })
31
+ // {
32
+ // 'X-Device-ID': 'a1b2c3d4e5f6...',
33
+ // 'X-Client-Type': 'web',
34
+ // 'X-Client-Platform': 'web',
35
+ // 'X-Product-Code': 'visiva',
36
+ // 'X-Client-Version': '1.0.0',
37
+ // }
38
+ ```
39
+
40
+ ### Raw Fingerprint
41
+
42
+ For direct access to the fingerprint result:
43
+
44
+ ```typescript
45
+ import { getDeviceFingerprint } from '@vigilkids/device-fingerprint'
46
+
47
+ const { visitorId, confidence } = await getDeviceFingerprint()
48
+ // visitorId: hex string (FingerprintJS hash)
49
+ // confidence: 0-1 (higher = more reliable)
50
+ ```
51
+
52
+ ### Reset Cache
53
+
54
+ Force recomputation on next call (typically not needed):
55
+
56
+ ```typescript
57
+ import { resetFingerprint } from '@vigilkids/device-fingerprint'
58
+
59
+ resetFingerprint()
60
+ ```
61
+
62
+ ## Exports
63
+
64
+ | Entry Point | Import | Content |
65
+ |-------------|--------|---------|
66
+ | Main | `@vigilkids/device-fingerprint` | `getDeviceFingerprint`, `getClientHeaders`, `resetFingerprint` |
67
+ | Types | `@vigilkids/device-fingerprint/types` | `DeviceFingerprintResult`, `ClientHeaderOptions` |
68
+
69
+ ## How It Works
70
+
71
+ ```
72
+ getClientHeaders()
73
+ └─ getDeviceFingerprint()
74
+ └─ FingerprintJS.load() → agent (singleton, cached)
75
+ └─ agent.get() → { visitorId, confidence }
76
+ ↓ (memory cache)
77
+ └─ return cached result
78
+ └─ build headers map with X-Device-ID = visitorId
79
+ ```
80
+
81
+ The fingerprint is computed from browser hardware signals (canvas rendering, WebGL renderer, audio context, etc.). These signals are consistent across normal and incognito sessions on the same device/browser combination.
82
+
83
+ ## Backend Integration
84
+
85
+ The generated headers are consumed by the OneX backend middleware chain:
86
+
87
+ 1. `ClientContextMiddleware` extracts `X-Device-ID` → `ClientContext.DeviceID`
88
+ 2. `SessionService.Create()` stores `DeviceID` in `p_identity_sessions.device_id`
89
+ 3. Audit and promotion modules use the device ID for logging and fraud analysis
90
+
91
+ ## Compatibility
92
+
93
+ - Browser only (requires `window`, `document`, `canvas`)
94
+ - ESM only
95
+ - TypeScript >= 5.0
96
+
97
+ ## License
98
+
99
+ [MIT](./LICENSE)
@@ -0,0 +1,41 @@
1
+ import { DeviceFingerprintResult, ClientHeaderOptions } from './types.mjs';
2
+
3
+ /**
4
+ * 获取当前设备的指纹
5
+ *
6
+ * 首次调用会计算指纹(~50ms),后续调用返回内存缓存。
7
+ * 无痕模式下产生相同 hash(基于 canvas/webgl/audio 等硬件信号,不依赖 cookie/storage)。
8
+ *
9
+ * @throws 当浏览器环境不支持指纹计算时抛出错误(不使用随机 fallback)
10
+ */
11
+ declare function getDeviceFingerprint(): Promise<DeviceFingerprintResult>;
12
+ /**
13
+ * 清除内存缓存,强制下次调用重新计算
14
+ *
15
+ * 一般不需要调用。仅用于测试或特殊场景(如检测到硬件变更)。
16
+ */
17
+ declare function resetFingerprint(): void;
18
+
19
+ /**
20
+ * 生成平台标准客户端请求头
21
+ *
22
+ * 所有前端站点的 API 请求应携带这些 header,供后端:
23
+ * - Identity 模块:记录设备信息到 session
24
+ * - Audit 模块:记录访问日志
25
+ * - Promotion 模块:防欺诈分析
26
+ *
27
+ * @example
28
+ * ```ts
29
+ * const headers = await getClientHeaders({ productCode: 'visiva' })
30
+ * // 结果:
31
+ * // {
32
+ * // 'X-Device-ID': 'a1b2c3d4e5f6...',
33
+ * // 'X-Client-Type': 'web',
34
+ * // 'X-Client-Platform': 'web',
35
+ * // 'X-Product-Code': 'visiva',
36
+ * // }
37
+ * ```
38
+ */
39
+ declare function getClientHeaders(options: ClientHeaderOptions): Promise<Record<string, string>>;
40
+
41
+ export { ClientHeaderOptions, DeviceFingerprintResult, getClientHeaders, getDeviceFingerprint, resetFingerprint };
@@ -0,0 +1,41 @@
1
+ import { DeviceFingerprintResult, ClientHeaderOptions } from './types.js';
2
+
3
+ /**
4
+ * 获取当前设备的指纹
5
+ *
6
+ * 首次调用会计算指纹(~50ms),后续调用返回内存缓存。
7
+ * 无痕模式下产生相同 hash(基于 canvas/webgl/audio 等硬件信号,不依赖 cookie/storage)。
8
+ *
9
+ * @throws 当浏览器环境不支持指纹计算时抛出错误(不使用随机 fallback)
10
+ */
11
+ declare function getDeviceFingerprint(): Promise<DeviceFingerprintResult>;
12
+ /**
13
+ * 清除内存缓存,强制下次调用重新计算
14
+ *
15
+ * 一般不需要调用。仅用于测试或特殊场景(如检测到硬件变更)。
16
+ */
17
+ declare function resetFingerprint(): void;
18
+
19
+ /**
20
+ * 生成平台标准客户端请求头
21
+ *
22
+ * 所有前端站点的 API 请求应携带这些 header,供后端:
23
+ * - Identity 模块:记录设备信息到 session
24
+ * - Audit 模块:记录访问日志
25
+ * - Promotion 模块:防欺诈分析
26
+ *
27
+ * @example
28
+ * ```ts
29
+ * const headers = await getClientHeaders({ productCode: 'visiva' })
30
+ * // 结果:
31
+ * // {
32
+ * // 'X-Device-ID': 'a1b2c3d4e5f6...',
33
+ * // 'X-Client-Type': 'web',
34
+ * // 'X-Client-Platform': 'web',
35
+ * // 'X-Product-Code': 'visiva',
36
+ * // }
37
+ * ```
38
+ */
39
+ declare function getClientHeaders(options: ClientHeaderOptions): Promise<Record<string, string>>;
40
+
41
+ export { ClientHeaderOptions, DeviceFingerprintResult, getClientHeaders, getDeviceFingerprint, resetFingerprint };
package/dist/index.mjs ADDED
@@ -0,0 +1,41 @@
1
+ import FingerprintJS from '@fingerprintjs/fingerprintjs';
2
+
3
+ let agentPromise = null;
4
+ let cachedResult = null;
5
+ function getAgent() {
6
+ if (!agentPromise) {
7
+ agentPromise = FingerprintJS.load();
8
+ }
9
+ return agentPromise;
10
+ }
11
+ async function getDeviceFingerprint() {
12
+ if (cachedResult) {
13
+ return cachedResult;
14
+ }
15
+ const agent = await getAgent();
16
+ const result = await agent.get();
17
+ cachedResult = {
18
+ visitorId: result.visitorId,
19
+ confidence: result.confidence.score
20
+ };
21
+ return cachedResult;
22
+ }
23
+ function resetFingerprint() {
24
+ cachedResult = null;
25
+ }
26
+
27
+ async function getClientHeaders(options) {
28
+ const fp = await getDeviceFingerprint();
29
+ const headers = {
30
+ "X-Device-ID": fp.visitorId,
31
+ "X-Client-Type": "web",
32
+ "X-Client-Platform": "web",
33
+ "X-Product-Code": options.productCode
34
+ };
35
+ if (options.appVersion) {
36
+ headers["X-Client-Version"] = options.appVersion;
37
+ }
38
+ return headers;
39
+ }
40
+
41
+ export { getClientHeaders, getDeviceFingerprint, resetFingerprint };
@@ -0,0 +1,21 @@
1
+ /**
2
+ * 设备指纹计算结果
3
+ *
4
+ * visitorId 基于浏览器硬件信号(canvas/webgl/audio)计算,
5
+ * 同一浏览器+硬件在正常和无痕模式下产生相同 hash。
6
+ */
7
+ interface DeviceFingerprintResult {
8
+ /** 设备指纹 hash(十六进制字符串,由 FingerprintJS 生成) */
9
+ visitorId: string;
10
+ /** 指纹置信度 0-1(越高越可靠) */
11
+ confidence: number;
12
+ }
13
+ /** 平台标准请求头(所有 API 请求携带) */
14
+ interface ClientHeaderOptions {
15
+ /** 产品标识(如 'visiva', 'vigilkids') */
16
+ productCode: string;
17
+ /** 客户端版本号 */
18
+ appVersion?: string;
19
+ }
20
+
21
+ export type { ClientHeaderOptions, DeviceFingerprintResult };
@@ -0,0 +1,21 @@
1
+ /**
2
+ * 设备指纹计算结果
3
+ *
4
+ * visitorId 基于浏览器硬件信号(canvas/webgl/audio)计算,
5
+ * 同一浏览器+硬件在正常和无痕模式下产生相同 hash。
6
+ */
7
+ interface DeviceFingerprintResult {
8
+ /** 设备指纹 hash(十六进制字符串,由 FingerprintJS 生成) */
9
+ visitorId: string;
10
+ /** 指纹置信度 0-1(越高越可靠) */
11
+ confidence: number;
12
+ }
13
+ /** 平台标准请求头(所有 API 请求携带) */
14
+ interface ClientHeaderOptions {
15
+ /** 产品标识(如 'visiva', 'vigilkids') */
16
+ productCode: string;
17
+ /** 客户端版本号 */
18
+ appVersion?: string;
19
+ }
20
+
21
+ export type { ClientHeaderOptions, DeviceFingerprintResult };
package/dist/types.mjs ADDED
@@ -0,0 +1 @@
1
+
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@vigilkids/device-fingerprint",
3
+ "version": "0.1.0",
4
+ "description": "Browser device fingerprint and platform standard client headers for VigilKids frontend applications",
5
+ "type": "module",
6
+ "main": "./dist/index.mjs",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.mjs"
12
+ },
13
+ "./types": {
14
+ "types": "./dist/types.d.ts",
15
+ "import": "./dist/types.mjs"
16
+ }
17
+ },
18
+ "files": [
19
+ "dist"
20
+ ],
21
+ "sideEffects": false,
22
+ "scripts": {
23
+ "build": "unbuild"
24
+ },
25
+ "publishConfig": {
26
+ "access": "public"
27
+ },
28
+ "repository": {
29
+ "type": "git",
30
+ "url": "https://github.com/1yhy/onex.git",
31
+ "directory": "packages/device-fingerprint"
32
+ },
33
+ "keywords": [
34
+ "device-fingerprint",
35
+ "fingerprintjs",
36
+ "browser-fingerprint",
37
+ "client-headers",
38
+ "vigilkids"
39
+ ],
40
+ "license": "MIT",
41
+ "dependencies": {
42
+ "@fingerprintjs/fingerprintjs": "^4.6.1"
43
+ },
44
+ "devDependencies": {
45
+ "unbuild": "^3.5.0"
46
+ }
47
+ }