@windrun-huaiin/third-ui 7.1.2 → 7.2.1
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/dist/clerk/clerk-page-generator-client.d.ts +10 -0
- package/dist/clerk/clerk-page-generator-client.js +28 -0
- package/dist/clerk/clerk-page-generator-client.mjs +25 -0
- package/dist/clerk/clerk-page-generator.js +1 -0
- package/dist/clerk/clerk-page-generator.mjs +1 -0
- package/dist/clerk/client-page-generator.d.ts +10 -0
- package/dist/clerk/client-page-generator.js +28 -0
- package/dist/clerk/client-page-generator.mjs +25 -0
- package/dist/clerk/context/FingerprintProvider.d.ts +25 -0
- package/dist/clerk/context/FingerprintProvider.js +71 -0
- package/dist/clerk/context/FingerprintProvider.mjs +65 -0
- package/dist/clerk/fingerprint/fingerprint-client.d.ts +47 -0
- package/dist/clerk/fingerprint/fingerprint-client.js +177 -0
- package/dist/clerk/fingerprint/fingerprint-client.mjs +168 -0
- package/dist/clerk/fingerprint/fingerprint-provider.d.ts +25 -0
- package/dist/clerk/fingerprint/fingerprint-provider.js +71 -0
- package/dist/clerk/fingerprint/fingerprint-provider.mjs +65 -0
- package/dist/clerk/fingerprint/fingerprint-server.d.ts +22 -0
- package/dist/clerk/fingerprint/fingerprint-server.js +75 -0
- package/dist/clerk/fingerprint/fingerprint-server.mjs +71 -0
- package/dist/clerk/fingerprint/fingerprint-shared.d.ts +17 -0
- package/dist/clerk/fingerprint/fingerprint-shared.js +35 -0
- package/dist/clerk/fingerprint/fingerprint-shared.mjs +29 -0
- package/dist/clerk/fingerprint/fingerprint.d.ts +55 -0
- package/dist/clerk/fingerprint/fingerprint.js +17 -0
- package/dist/clerk/fingerprint/fingerprint.mjs +15 -0
- package/dist/clerk/fingerprint/index.d.ts +5 -0
- package/dist/clerk/fingerprint/index.js +29 -0
- package/dist/clerk/fingerprint/index.mjs +5 -0
- package/dist/clerk/fingerprint/server.d.ts +3 -0
- package/dist/clerk/fingerprint/server.js +15 -0
- package/dist/clerk/fingerprint/server.mjs +2 -0
- package/dist/clerk/fingerprint/types.d.ts +44 -0
- package/dist/clerk/fingerprint/use-fingerprint.d.ts +6 -0
- package/dist/clerk/fingerprint/use-fingerprint.js +176 -0
- package/dist/clerk/fingerprint/use-fingerprint.mjs +174 -0
- package/dist/clerk/fingerprint.d.ts +55 -0
- package/dist/clerk/fingerprint.js +237 -0
- package/dist/clerk/fingerprint.mjs +225 -0
- package/dist/clerk/hooks/useFingerprint.d.ts +6 -0
- package/dist/clerk/hooks/useFingerprint.js +182 -0
- package/dist/clerk/hooks/useFingerprint.mjs +180 -0
- package/dist/clerk/index.d.ts +3 -0
- package/dist/clerk/index.js +7 -0
- package/dist/clerk/index.mjs +3 -0
- package/dist/clerk/signin-with-fingerprint-client.d.ts +7 -0
- package/dist/clerk/signin-with-fingerprint-client.js +52 -0
- package/dist/clerk/signin-with-fingerprint-client.mjs +47 -0
- package/dist/clerk/signup-with-fingerprint-client.d.ts +7 -0
- package/dist/clerk/signup-with-fingerprint-client.js +52 -0
- package/dist/clerk/signup-with-fingerprint-client.mjs +47 -0
- package/dist/clerk/types.d.ts +42 -0
- package/dist/fuma/mdx/toc-base.js +1 -1
- package/dist/fuma/mdx/toc-base.mjs +1 -1
- package/dist/node_modules/.pnpm/@fingerprintjs_fingerprintjs@4.6.2/node_modules/@fingerprintjs/fingerprintjs/dist/fp.esm.js +3212 -0
- package/dist/node_modules/.pnpm/@fingerprintjs_fingerprintjs@4.6.2/node_modules/@fingerprintjs/fingerprintjs/dist/fp.esm.mjs +3187 -0
- package/dist/node_modules/.pnpm/@rollup_plugin-typescript@12.1.4_rollup@4.46.2_tslib@2.8.1_typescript@5.9.2/node_modules/tslib/tslib.es6.js +51 -0
- package/dist/node_modules/.pnpm/@rollup_plugin-typescript@12.1.4_rollup@4.46.2_tslib@2.8.1_typescript@5.9.2/node_modules/tslib/tslib.es6.mjs +50 -1
- package/dist/node_modules/.pnpm/cose-base@1.0.3/node_modules/cose-base/cose-base.js +1 -1
- package/dist/node_modules/.pnpm/cose-base@2.2.0/node_modules/cose-base/cose-base.js +1 -1
- package/dist/node_modules/.pnpm/layout-base@1.0.2/node_modules/layout-base/layout-base.js +1 -1
- package/dist/node_modules/.pnpm/layout-base@2.0.1/node_modules/layout-base/layout-base.js +1 -1
- package/package.json +14 -3
- package/src/clerk/clerk-page-generator-client.tsx +37 -0
- package/src/clerk/clerk-page-generator.tsx +5 -1
- package/src/clerk/fingerprint/fingerprint-client.ts +194 -0
- package/src/clerk/fingerprint/fingerprint-provider.tsx +114 -0
- package/src/clerk/fingerprint/fingerprint-server.ts +88 -0
- package/src/clerk/fingerprint/fingerprint-shared.ts +29 -0
- package/src/clerk/fingerprint/index.ts +15 -0
- package/src/clerk/fingerprint/server.ts +9 -0
- package/src/clerk/fingerprint/types.ts +50 -0
- package/src/clerk/fingerprint/use-fingerprint.ts +200 -0
- package/src/clerk/index.ts +9 -2
- package/src/clerk/server.ts +1 -0
- package/src/clerk/signin-with-fingerprint-client.tsx +57 -0
- package/src/clerk/signup-with-fingerprint-client.tsx +57 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var fingerprintShared = require('./fingerprint-shared.js');
|
|
5
|
+
var fingerprintClient = require('./fingerprint-client.js');
|
|
6
|
+
var useFingerprint = require('./use-fingerprint.js');
|
|
7
|
+
var fingerprintProvider = require('./fingerprint-provider.js');
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
exports.FINGERPRINT_CONSTANTS = fingerprintShared.FINGERPRINT_CONSTANTS;
|
|
12
|
+
exports.FINGERPRINT_COOKIE_NAME = fingerprintShared.FINGERPRINT_COOKIE_NAME;
|
|
13
|
+
exports.FINGERPRINT_HEADER_NAME = fingerprintShared.FINGERPRINT_HEADER_NAME;
|
|
14
|
+
exports.FINGERPRINT_STORAGE_KEY = fingerprintShared.FINGERPRINT_STORAGE_KEY;
|
|
15
|
+
exports.isValidFingerprintId = fingerprintShared.isValidFingerprintId;
|
|
16
|
+
exports.clearFingerprintId = fingerprintClient.clearFingerprintId;
|
|
17
|
+
exports.createFingerprintFetch = fingerprintClient.createFingerprintFetch;
|
|
18
|
+
exports.createFingerprintHeaders = fingerprintClient.createFingerprintHeaders;
|
|
19
|
+
exports.generateFingerprintId = fingerprintClient.generateFingerprintId;
|
|
20
|
+
exports.getFingerprintId = fingerprintClient.getFingerprintId;
|
|
21
|
+
exports.getOrGenerateFingerprintId = fingerprintClient.getOrGenerateFingerprintId;
|
|
22
|
+
exports.setFingerprintId = fingerprintClient.setFingerprintId;
|
|
23
|
+
exports.useFingerprintHeaders = fingerprintClient.useFingerprintHeaders;
|
|
24
|
+
exports.useFingerprint = useFingerprint.useFingerprint;
|
|
25
|
+
exports.FingerprintDebugInfo = fingerprintProvider.FingerprintDebugInfo;
|
|
26
|
+
exports.FingerprintProvider = fingerprintProvider.FingerprintProvider;
|
|
27
|
+
exports.useFingerprintContext = fingerprintProvider.useFingerprintContext;
|
|
28
|
+
exports.useFingerprintContextSafe = fingerprintProvider.useFingerprintContextSafe;
|
|
29
|
+
exports.withFingerprint = fingerprintProvider.withFingerprint;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
export { FINGERPRINT_CONSTANTS, FINGERPRINT_COOKIE_NAME, FINGERPRINT_HEADER_NAME, FINGERPRINT_STORAGE_KEY, isValidFingerprintId } from './fingerprint-shared.mjs';
|
|
3
|
+
export { clearFingerprintId, createFingerprintFetch, createFingerprintHeaders, generateFingerprintId, getFingerprintId, getOrGenerateFingerprintId, setFingerprintId, useFingerprintHeaders } from './fingerprint-client.mjs';
|
|
4
|
+
export { useFingerprint } from './use-fingerprint.mjs';
|
|
5
|
+
export { FingerprintDebugInfo, FingerprintProvider, useFingerprintContext, useFingerprintContextSafe, withFingerprint } from './fingerprint-provider.mjs';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var fingerprintShared = require('./fingerprint-shared.js');
|
|
4
|
+
var fingerprintServer = require('./fingerprint-server.js');
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
exports.FINGERPRINT_CONSTANTS = fingerprintShared.FINGERPRINT_CONSTANTS;
|
|
9
|
+
exports.FINGERPRINT_COOKIE_NAME = fingerprintShared.FINGERPRINT_COOKIE_NAME;
|
|
10
|
+
exports.FINGERPRINT_HEADER_NAME = fingerprintShared.FINGERPRINT_HEADER_NAME;
|
|
11
|
+
exports.FINGERPRINT_STORAGE_KEY = fingerprintShared.FINGERPRINT_STORAGE_KEY;
|
|
12
|
+
exports.isValidFingerprintId = fingerprintShared.isValidFingerprintId;
|
|
13
|
+
exports.extractFingerprintFromNextRequest = fingerprintServer.extractFingerprintFromNextRequest;
|
|
14
|
+
exports.extractFingerprintId = fingerprintServer.extractFingerprintId;
|
|
15
|
+
exports.generateServerFingerprintId = fingerprintServer.generateServerFingerprintId;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export { FINGERPRINT_CONSTANTS, FINGERPRINT_COOKIE_NAME, FINGERPRINT_HEADER_NAME, FINGERPRINT_STORAGE_KEY, isValidFingerprintId } from './fingerprint-shared.mjs';
|
|
2
|
+
export { extractFingerprintFromNextRequest, extractFingerprintId, generateServerFingerprintId } from './fingerprint-server.mjs';
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fingerprint System Types
|
|
3
|
+
* 指纹识别系统的类型定义
|
|
4
|
+
*/
|
|
5
|
+
export interface AnonymousUser {
|
|
6
|
+
userId: string;
|
|
7
|
+
fingerprintId: string;
|
|
8
|
+
clerkUserId: string;
|
|
9
|
+
email: string;
|
|
10
|
+
status: string;
|
|
11
|
+
createdAt: string;
|
|
12
|
+
}
|
|
13
|
+
export interface Credits {
|
|
14
|
+
balanceFree: number;
|
|
15
|
+
balancePaid: number;
|
|
16
|
+
totalBalance: number;
|
|
17
|
+
}
|
|
18
|
+
export interface FingerprintConfig {
|
|
19
|
+
/** API endpoint for anonymous user initialization */
|
|
20
|
+
apiEndpoint: string;
|
|
21
|
+
/** Whether to automatically initialize the user on load */
|
|
22
|
+
autoInitialize?: boolean;
|
|
23
|
+
/** Initial credits for new users */
|
|
24
|
+
initialCredits?: number;
|
|
25
|
+
}
|
|
26
|
+
export interface UseFingerprintResult {
|
|
27
|
+
fingerprintId: string | null;
|
|
28
|
+
anonymousUser: AnonymousUser | null;
|
|
29
|
+
credits: Credits | null;
|
|
30
|
+
isLoading: boolean;
|
|
31
|
+
isInitialized: boolean;
|
|
32
|
+
error: string | null;
|
|
33
|
+
initializeAnonymousUser: () => Promise<void>;
|
|
34
|
+
refreshUserData: () => Promise<void>;
|
|
35
|
+
}
|
|
36
|
+
export interface FingerprintContextType extends UseFingerprintResult {
|
|
37
|
+
}
|
|
38
|
+
export interface FingerprintProviderProps {
|
|
39
|
+
children: React.ReactNode;
|
|
40
|
+
config: FingerprintConfig;
|
|
41
|
+
}
|
|
42
|
+
export interface FingerprintFetch {
|
|
43
|
+
(url: string | URL | Request, init?: RequestInit): Promise<Response>;
|
|
44
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { UseFingerprintResult, FingerprintConfig } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Hook for managing fingerprint ID and anonymous user data
|
|
4
|
+
* Accepts configuration to customize API endpoint and behavior
|
|
5
|
+
*/
|
|
6
|
+
export declare function useFingerprint(config: FingerprintConfig): UseFingerprintResult;
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var tslib_es6 = require('../../node_modules/.pnpm/@rollup_plugin-typescript@12.1.4_rollup@4.46.2_tslib@2.8.1_typescript@5.9.2/node_modules/tslib/tslib.es6.js');
|
|
5
|
+
var React = require('react');
|
|
6
|
+
var fingerprintClient = require('./fingerprint-client.js');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Hook for managing fingerprint ID and anonymous user data
|
|
10
|
+
* Accepts configuration to customize API endpoint and behavior
|
|
11
|
+
*/
|
|
12
|
+
function useFingerprint(config) {
|
|
13
|
+
const [fingerprintId, setFingerprintIdState] = React.useState(null);
|
|
14
|
+
const [anonymousUser, setAnonymousUser] = React.useState(null);
|
|
15
|
+
const [credits, setCredits] = React.useState(null);
|
|
16
|
+
const [isLoading, setIsLoading] = React.useState(true);
|
|
17
|
+
const [isInitialized, setIsInitialized] = React.useState(false);
|
|
18
|
+
const [error, setError] = React.useState(null);
|
|
19
|
+
/**
|
|
20
|
+
* 第一阶段:初始化fingerprint ID
|
|
21
|
+
*/
|
|
22
|
+
const initializeFingerprintId = React.useCallback(() => tslib_es6.__awaiter(this, void 0, void 0, function* () {
|
|
23
|
+
if (typeof window === 'undefined')
|
|
24
|
+
return null;
|
|
25
|
+
try {
|
|
26
|
+
// 优先检查现有ID, 没有就生成新的fingerprint ID
|
|
27
|
+
const currentFingerprintId = yield fingerprintClient.getOrGenerateFingerprintId();
|
|
28
|
+
setFingerprintIdState(currentFingerprintId);
|
|
29
|
+
return currentFingerprintId;
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
console.error('Failed to initialize fingerprint ID:', error);
|
|
33
|
+
setError('Failed to generate fingerprint ID');
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
}), []);
|
|
37
|
+
/**
|
|
38
|
+
* 第二阶段:初始化匿名用户
|
|
39
|
+
*/
|
|
40
|
+
const initializeAnonymousUser = React.useCallback(() => tslib_es6.__awaiter(this, void 0, void 0, function* () {
|
|
41
|
+
if (!fingerprintId) {
|
|
42
|
+
console.warn('Cannot initialize user without fingerprint ID');
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
try {
|
|
46
|
+
setIsLoading(true);
|
|
47
|
+
setError(null);
|
|
48
|
+
const fingerprintHeaders = yield fingerprintClient.createFingerprintHeaders();
|
|
49
|
+
const response = yield fetch(config.apiEndpoint, {
|
|
50
|
+
method: 'POST',
|
|
51
|
+
headers: Object.assign({ 'Content-Type': 'application/json' }, fingerprintHeaders),
|
|
52
|
+
body: JSON.stringify({
|
|
53
|
+
fingerprintId: fingerprintId,
|
|
54
|
+
}),
|
|
55
|
+
});
|
|
56
|
+
if (!response.ok) {
|
|
57
|
+
const errorData = yield response.json().catch(() => ({}));
|
|
58
|
+
throw new Error(errorData.error || 'Failed to initialize anonymous user');
|
|
59
|
+
}
|
|
60
|
+
const data = yield response.json();
|
|
61
|
+
if (data.success) {
|
|
62
|
+
setAnonymousUser(data.user);
|
|
63
|
+
setCredits(data.credits);
|
|
64
|
+
setIsInitialized(true);
|
|
65
|
+
// 确保fingerprint ID同步
|
|
66
|
+
if (data.user.fingerprintId !== fingerprintId) {
|
|
67
|
+
fingerprintClient.setFingerprintId(data.user.fingerprintId);
|
|
68
|
+
setFingerprintIdState(data.user.fingerprintId);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
throw new Error(data.error || 'Unknown error occurred');
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
catch (err) {
|
|
76
|
+
console.error('Failed to initialize anonymous user:', err);
|
|
77
|
+
setError(err instanceof Error ? err.message : 'Unknown error');
|
|
78
|
+
}
|
|
79
|
+
finally {
|
|
80
|
+
setIsLoading(false);
|
|
81
|
+
}
|
|
82
|
+
}), [fingerprintId]);
|
|
83
|
+
/**
|
|
84
|
+
* 刷新用户数据
|
|
85
|
+
*/
|
|
86
|
+
const refreshUserData = React.useCallback(() => tslib_es6.__awaiter(this, void 0, void 0, function* () {
|
|
87
|
+
if (!fingerprintId)
|
|
88
|
+
return;
|
|
89
|
+
try {
|
|
90
|
+
setError(null);
|
|
91
|
+
const fingerprintHeaders = yield fingerprintClient.createFingerprintHeaders();
|
|
92
|
+
const response = yield fetch(`${config.apiEndpoint}?fingerprintId=${fingerprintId}`, {
|
|
93
|
+
method: 'GET',
|
|
94
|
+
headers: fingerprintHeaders,
|
|
95
|
+
});
|
|
96
|
+
if (!response.ok) {
|
|
97
|
+
if (response.status === 404) {
|
|
98
|
+
// 用户不存在,需要重新初始化
|
|
99
|
+
yield initializeAnonymousUser();
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
throw new Error('Failed to fetch user data');
|
|
103
|
+
}
|
|
104
|
+
const data = yield response.json();
|
|
105
|
+
if (data.success) {
|
|
106
|
+
setAnonymousUser(data.user);
|
|
107
|
+
setCredits(data.credits);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
catch (err) {
|
|
111
|
+
console.error('Failed to refresh user data:', err);
|
|
112
|
+
setError(err instanceof Error ? err.message : 'Unknown error');
|
|
113
|
+
}
|
|
114
|
+
}), [fingerprintId, initializeAnonymousUser, config.apiEndpoint]);
|
|
115
|
+
/**
|
|
116
|
+
* 检查现有用户数据(仅在有fingerprint ID时执行)
|
|
117
|
+
*/
|
|
118
|
+
const checkExistingUser = React.useCallback(() => tslib_es6.__awaiter(this, void 0, void 0, function* () {
|
|
119
|
+
if (!fingerprintId)
|
|
120
|
+
return;
|
|
121
|
+
try {
|
|
122
|
+
const fingerprintHeaders = yield fingerprintClient.createFingerprintHeaders();
|
|
123
|
+
const response = yield fetch(`${config.apiEndpoint}?fingerprintId=${fingerprintId}`, {
|
|
124
|
+
method: 'GET',
|
|
125
|
+
headers: fingerprintHeaders,
|
|
126
|
+
});
|
|
127
|
+
if (response.ok) {
|
|
128
|
+
const data = yield response.json();
|
|
129
|
+
if (data.success) {
|
|
130
|
+
setAnonymousUser(data.user);
|
|
131
|
+
setCredits(data.credits);
|
|
132
|
+
setIsInitialized(true);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
catch (err) {
|
|
137
|
+
console.error('Failed to check existing user:', err);
|
|
138
|
+
}
|
|
139
|
+
}), [fingerprintId, config.apiEndpoint]);
|
|
140
|
+
// 第一阶段:页面加载完成后生成指纹ID
|
|
141
|
+
React.useEffect(() => {
|
|
142
|
+
if (typeof window === 'undefined')
|
|
143
|
+
return;
|
|
144
|
+
const initFingerprint = () => tslib_es6.__awaiter(this, void 0, void 0, function* () {
|
|
145
|
+
yield initializeFingerprintId();
|
|
146
|
+
setIsLoading(false); // 第一阶段完成,结束加载状态
|
|
147
|
+
});
|
|
148
|
+
initFingerprint();
|
|
149
|
+
}, [initializeFingerprintId]);
|
|
150
|
+
// 第二阶段:有指纹ID后检查现有用户
|
|
151
|
+
React.useEffect(() => {
|
|
152
|
+
if (!fingerprintId || isInitialized)
|
|
153
|
+
return;
|
|
154
|
+
checkExistingUser();
|
|
155
|
+
}, [fingerprintId, isInitialized, checkExistingUser]);
|
|
156
|
+
// 第三阶段:如果没有现有用户且自动初始化开启,则创建新用户
|
|
157
|
+
React.useEffect(() => {
|
|
158
|
+
if (!fingerprintId || isInitialized || isLoading || error)
|
|
159
|
+
return;
|
|
160
|
+
if (config.autoInitialize === false)
|
|
161
|
+
return;
|
|
162
|
+
initializeAnonymousUser();
|
|
163
|
+
}, [fingerprintId, isInitialized, isLoading, error, initializeAnonymousUser, config.autoInitialize]);
|
|
164
|
+
return {
|
|
165
|
+
fingerprintId,
|
|
166
|
+
anonymousUser,
|
|
167
|
+
credits,
|
|
168
|
+
isLoading,
|
|
169
|
+
isInitialized,
|
|
170
|
+
error,
|
|
171
|
+
initializeAnonymousUser,
|
|
172
|
+
refreshUserData,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
exports.useFingerprint = useFingerprint;
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { __awaiter } from '../../node_modules/.pnpm/@rollup_plugin-typescript@12.1.4_rollup@4.46.2_tslib@2.8.1_typescript@5.9.2/node_modules/tslib/tslib.es6.mjs';
|
|
3
|
+
import { useState, useCallback, useEffect } from 'react';
|
|
4
|
+
import { createFingerprintHeaders, setFingerprintId, getOrGenerateFingerprintId } from './fingerprint-client.mjs';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Hook for managing fingerprint ID and anonymous user data
|
|
8
|
+
* Accepts configuration to customize API endpoint and behavior
|
|
9
|
+
*/
|
|
10
|
+
function useFingerprint(config) {
|
|
11
|
+
const [fingerprintId, setFingerprintIdState] = useState(null);
|
|
12
|
+
const [anonymousUser, setAnonymousUser] = useState(null);
|
|
13
|
+
const [credits, setCredits] = useState(null);
|
|
14
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
15
|
+
const [isInitialized, setIsInitialized] = useState(false);
|
|
16
|
+
const [error, setError] = useState(null);
|
|
17
|
+
/**
|
|
18
|
+
* 第一阶段:初始化fingerprint ID
|
|
19
|
+
*/
|
|
20
|
+
const initializeFingerprintId = useCallback(() => __awaiter(this, void 0, void 0, function* () {
|
|
21
|
+
if (typeof window === 'undefined')
|
|
22
|
+
return null;
|
|
23
|
+
try {
|
|
24
|
+
// 优先检查现有ID, 没有就生成新的fingerprint ID
|
|
25
|
+
const currentFingerprintId = yield getOrGenerateFingerprintId();
|
|
26
|
+
setFingerprintIdState(currentFingerprintId);
|
|
27
|
+
return currentFingerprintId;
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
console.error('Failed to initialize fingerprint ID:', error);
|
|
31
|
+
setError('Failed to generate fingerprint ID');
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
}), []);
|
|
35
|
+
/**
|
|
36
|
+
* 第二阶段:初始化匿名用户
|
|
37
|
+
*/
|
|
38
|
+
const initializeAnonymousUser = useCallback(() => __awaiter(this, void 0, void 0, function* () {
|
|
39
|
+
if (!fingerprintId) {
|
|
40
|
+
console.warn('Cannot initialize user without fingerprint ID');
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
try {
|
|
44
|
+
setIsLoading(true);
|
|
45
|
+
setError(null);
|
|
46
|
+
const fingerprintHeaders = yield createFingerprintHeaders();
|
|
47
|
+
const response = yield fetch(config.apiEndpoint, {
|
|
48
|
+
method: 'POST',
|
|
49
|
+
headers: Object.assign({ 'Content-Type': 'application/json' }, fingerprintHeaders),
|
|
50
|
+
body: JSON.stringify({
|
|
51
|
+
fingerprintId: fingerprintId,
|
|
52
|
+
}),
|
|
53
|
+
});
|
|
54
|
+
if (!response.ok) {
|
|
55
|
+
const errorData = yield response.json().catch(() => ({}));
|
|
56
|
+
throw new Error(errorData.error || 'Failed to initialize anonymous user');
|
|
57
|
+
}
|
|
58
|
+
const data = yield response.json();
|
|
59
|
+
if (data.success) {
|
|
60
|
+
setAnonymousUser(data.user);
|
|
61
|
+
setCredits(data.credits);
|
|
62
|
+
setIsInitialized(true);
|
|
63
|
+
// 确保fingerprint ID同步
|
|
64
|
+
if (data.user.fingerprintId !== fingerprintId) {
|
|
65
|
+
setFingerprintId(data.user.fingerprintId);
|
|
66
|
+
setFingerprintIdState(data.user.fingerprintId);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
throw new Error(data.error || 'Unknown error occurred');
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
catch (err) {
|
|
74
|
+
console.error('Failed to initialize anonymous user:', err);
|
|
75
|
+
setError(err instanceof Error ? err.message : 'Unknown error');
|
|
76
|
+
}
|
|
77
|
+
finally {
|
|
78
|
+
setIsLoading(false);
|
|
79
|
+
}
|
|
80
|
+
}), [fingerprintId]);
|
|
81
|
+
/**
|
|
82
|
+
* 刷新用户数据
|
|
83
|
+
*/
|
|
84
|
+
const refreshUserData = useCallback(() => __awaiter(this, void 0, void 0, function* () {
|
|
85
|
+
if (!fingerprintId)
|
|
86
|
+
return;
|
|
87
|
+
try {
|
|
88
|
+
setError(null);
|
|
89
|
+
const fingerprintHeaders = yield createFingerprintHeaders();
|
|
90
|
+
const response = yield fetch(`${config.apiEndpoint}?fingerprintId=${fingerprintId}`, {
|
|
91
|
+
method: 'GET',
|
|
92
|
+
headers: fingerprintHeaders,
|
|
93
|
+
});
|
|
94
|
+
if (!response.ok) {
|
|
95
|
+
if (response.status === 404) {
|
|
96
|
+
// 用户不存在,需要重新初始化
|
|
97
|
+
yield initializeAnonymousUser();
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
throw new Error('Failed to fetch user data');
|
|
101
|
+
}
|
|
102
|
+
const data = yield response.json();
|
|
103
|
+
if (data.success) {
|
|
104
|
+
setAnonymousUser(data.user);
|
|
105
|
+
setCredits(data.credits);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
catch (err) {
|
|
109
|
+
console.error('Failed to refresh user data:', err);
|
|
110
|
+
setError(err instanceof Error ? err.message : 'Unknown error');
|
|
111
|
+
}
|
|
112
|
+
}), [fingerprintId, initializeAnonymousUser, config.apiEndpoint]);
|
|
113
|
+
/**
|
|
114
|
+
* 检查现有用户数据(仅在有fingerprint ID时执行)
|
|
115
|
+
*/
|
|
116
|
+
const checkExistingUser = useCallback(() => __awaiter(this, void 0, void 0, function* () {
|
|
117
|
+
if (!fingerprintId)
|
|
118
|
+
return;
|
|
119
|
+
try {
|
|
120
|
+
const fingerprintHeaders = yield createFingerprintHeaders();
|
|
121
|
+
const response = yield fetch(`${config.apiEndpoint}?fingerprintId=${fingerprintId}`, {
|
|
122
|
+
method: 'GET',
|
|
123
|
+
headers: fingerprintHeaders,
|
|
124
|
+
});
|
|
125
|
+
if (response.ok) {
|
|
126
|
+
const data = yield response.json();
|
|
127
|
+
if (data.success) {
|
|
128
|
+
setAnonymousUser(data.user);
|
|
129
|
+
setCredits(data.credits);
|
|
130
|
+
setIsInitialized(true);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
catch (err) {
|
|
135
|
+
console.error('Failed to check existing user:', err);
|
|
136
|
+
}
|
|
137
|
+
}), [fingerprintId, config.apiEndpoint]);
|
|
138
|
+
// 第一阶段:页面加载完成后生成指纹ID
|
|
139
|
+
useEffect(() => {
|
|
140
|
+
if (typeof window === 'undefined')
|
|
141
|
+
return;
|
|
142
|
+
const initFingerprint = () => __awaiter(this, void 0, void 0, function* () {
|
|
143
|
+
yield initializeFingerprintId();
|
|
144
|
+
setIsLoading(false); // 第一阶段完成,结束加载状态
|
|
145
|
+
});
|
|
146
|
+
initFingerprint();
|
|
147
|
+
}, [initializeFingerprintId]);
|
|
148
|
+
// 第二阶段:有指纹ID后检查现有用户
|
|
149
|
+
useEffect(() => {
|
|
150
|
+
if (!fingerprintId || isInitialized)
|
|
151
|
+
return;
|
|
152
|
+
checkExistingUser();
|
|
153
|
+
}, [fingerprintId, isInitialized, checkExistingUser]);
|
|
154
|
+
// 第三阶段:如果没有现有用户且自动初始化开启,则创建新用户
|
|
155
|
+
useEffect(() => {
|
|
156
|
+
if (!fingerprintId || isInitialized || isLoading || error)
|
|
157
|
+
return;
|
|
158
|
+
if (config.autoInitialize === false)
|
|
159
|
+
return;
|
|
160
|
+
initializeAnonymousUser();
|
|
161
|
+
}, [fingerprintId, isInitialized, isLoading, error, initializeAnonymousUser, config.autoInitialize]);
|
|
162
|
+
return {
|
|
163
|
+
fingerprintId,
|
|
164
|
+
anonymousUser,
|
|
165
|
+
credits,
|
|
166
|
+
isLoading,
|
|
167
|
+
isInitialized,
|
|
168
|
+
error,
|
|
169
|
+
initializeAnonymousUser,
|
|
170
|
+
refreshUserData,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export { useFingerprint };
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fingerprint Core Utilities
|
|
3
|
+
* 基于浏览器特征生成唯一的设备指纹ID,用于匿名用户识别
|
|
4
|
+
* Core fingerprint generation logic - completely generic
|
|
5
|
+
*
|
|
6
|
+
* NOTE: This module should only be used on the client-side
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* 生成基于真实浏览器特征的fingerprint ID
|
|
10
|
+
* 使用FingerprintJS收集浏览器特征并生成唯一标识
|
|
11
|
+
*/
|
|
12
|
+
export declare function generateFingerprintId(): Promise<string>;
|
|
13
|
+
/**
|
|
14
|
+
* 获取当前的fingerprint ID
|
|
15
|
+
*/
|
|
16
|
+
export declare function getFingerprintId(): string | null;
|
|
17
|
+
/**
|
|
18
|
+
* 设置fingerprint ID到存储
|
|
19
|
+
*/
|
|
20
|
+
export declare function setFingerprintId(fingerprintId: string): void;
|
|
21
|
+
/**
|
|
22
|
+
* 清除fingerprint ID
|
|
23
|
+
*/
|
|
24
|
+
export declare function clearFingerprintId(): void;
|
|
25
|
+
/**
|
|
26
|
+
* 获取或生成fingerprint ID
|
|
27
|
+
* 如果不存在则自动生成新的
|
|
28
|
+
*/
|
|
29
|
+
export declare function getOrGenerateFingerprintId(): Promise<string>;
|
|
30
|
+
/**
|
|
31
|
+
* 验证fingerprint ID格式
|
|
32
|
+
*/
|
|
33
|
+
export declare function isValidFingerprintId(fingerprintId: string): boolean;
|
|
34
|
+
/**
|
|
35
|
+
* 创建包含fingerprint ID的fetch headers
|
|
36
|
+
*/
|
|
37
|
+
export declare function createFingerprintHeaders(): Promise<Record<string, string>>;
|
|
38
|
+
/**
|
|
39
|
+
* Hook for generating fingerprint headers
|
|
40
|
+
*/
|
|
41
|
+
export declare function useFingerprintHeaders(): () => Promise<Record<string, string>>;
|
|
42
|
+
/**
|
|
43
|
+
* Create a fetch wrapper that automatically includes fingerprint headers
|
|
44
|
+
*/
|
|
45
|
+
export declare function createFingerprintFetch(): (url: string | URL | Request, init?: RequestInit) => Promise<Response>;
|
|
46
|
+
/**
|
|
47
|
+
* 从请求中提取fingerprint ID
|
|
48
|
+
* 优先级:header > cookie > query参数
|
|
49
|
+
*/
|
|
50
|
+
export declare function extractFingerprintId(headers: Headers | Record<string, string>, cookies?: Record<string, string>, query?: Record<string, string | undefined>): string | null;
|
|
51
|
+
export declare const FINGERPRINT_CONSTANTS: {
|
|
52
|
+
readonly STORAGE_KEY: "diaomao_fingerprint_id";
|
|
53
|
+
readonly HEADER_NAME: "x-fingerprint-id";
|
|
54
|
+
readonly COOKIE_NAME: "fingerprint_id";
|
|
55
|
+
};
|