@windrun-huaiin/third-ui 7.3.5 → 7.3.7
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/fingerprint/fingerprint-client.d.ts +1 -9
- package/dist/clerk/fingerprint/fingerprint-client.js +40 -41
- package/dist/clerk/fingerprint/fingerprint-client.mjs +40 -41
- package/dist/clerk/fingerprint/use-fingerprint.js +47 -15
- package/dist/clerk/fingerprint/use-fingerprint.mjs +47 -15
- package/dist/main/money-price/money-price-button.js +0 -1
- package/dist/main/money-price/money-price-button.mjs +0 -1
- package/dist/main/money-price/money-price-interactive.js +1 -1
- package/dist/main/money-price/money-price-interactive.mjs +1 -1
- package/dist/main/money-price/money-price.js +2 -1
- package/dist/main/money-price/money-price.mjs +2 -1
- package/dist/node_modules/.pnpm/cose-base@1.0.3/node_modules/cose-base/cose-base.mjs +1 -1
- package/dist/node_modules/.pnpm/cose-base@2.2.0/node_modules/cose-base/cose-base.mjs +1 -1
- package/dist/node_modules/.pnpm/layout-base@1.0.2/node_modules/layout-base/layout-base.mjs +1 -1
- package/dist/node_modules/.pnpm/layout-base@2.0.1/node_modules/layout-base/layout-base.mjs +1 -1
- package/package.json +3 -3
- package/src/clerk/fingerprint/fingerprint-client.ts +46 -50
- package/src/clerk/fingerprint/use-fingerprint.ts +50 -17
- package/src/main/money-price/money-price-button.tsx +0 -1
- package/src/main/money-price/money-price-interactive.tsx +1 -1
- package/src/main/money-price/money-price.tsx +1 -1
|
@@ -5,43 +5,35 @@
|
|
|
5
5
|
*/
|
|
6
6
|
/**
|
|
7
7
|
* 生成基于真实浏览器特征的fingerprint ID
|
|
8
|
-
* 使用FingerprintJS收集浏览器特征并生成唯一标识
|
|
9
|
-
* 只能在客户端使用
|
|
8
|
+
* 使用 FingerprintJS 收集浏览器特征并生成唯一标识
|
|
10
9
|
*/
|
|
11
10
|
export declare function generateFingerprintId(): Promise<string>;
|
|
12
11
|
/**
|
|
13
12
|
* 获取当前的fingerprint ID
|
|
14
|
-
* 只能在客户端使用
|
|
15
13
|
*/
|
|
16
14
|
export declare function getFingerprintId(): string | null;
|
|
17
15
|
/**
|
|
18
16
|
* 设置fingerprint ID到存储
|
|
19
|
-
* 只能在客户端使用
|
|
20
17
|
*/
|
|
21
18
|
export declare function setFingerprintId(fingerprintId: string): void;
|
|
22
19
|
/**
|
|
23
20
|
* 清除fingerprint ID
|
|
24
|
-
* 只能在客户端使用
|
|
25
21
|
*/
|
|
26
22
|
export declare function clearFingerprintId(): void;
|
|
27
23
|
/**
|
|
28
24
|
* 获取或生成fingerprint ID
|
|
29
25
|
* 如果不存在则自动生成新的
|
|
30
|
-
* 只能在客户端使用
|
|
31
26
|
*/
|
|
32
27
|
export declare function getOrGenerateFingerprintId(): Promise<string>;
|
|
33
28
|
/**
|
|
34
29
|
* 创建包含fingerprint ID的fetch headers
|
|
35
|
-
* 只能在客户端使用
|
|
36
30
|
*/
|
|
37
31
|
export declare function createFingerprintHeaders(): Promise<Record<string, string>>;
|
|
38
32
|
/**
|
|
39
33
|
* Hook for generating fingerprint headers
|
|
40
|
-
* 只能在客户端使用
|
|
41
34
|
*/
|
|
42
35
|
export declare function useFingerprintHeaders(): () => Promise<Record<string, string>>;
|
|
43
36
|
/**
|
|
44
37
|
* Create a fetch wrapper that automatically includes fingerprint headers
|
|
45
|
-
* 只能在客户端使用
|
|
46
38
|
*/
|
|
47
39
|
export declare function createFingerprintFetch(): (url: string | URL | Request, init?: RequestInit) => Promise<Response>;
|
|
@@ -1,92 +1,94 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
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');
|
|
4
|
-
var fingerprintShared = require('./fingerprint-shared.js');
|
|
5
4
|
var fp_esm = require('../../node_modules/.pnpm/@fingerprintjs_fingerprintjs@4.6.2/node_modules/@fingerprintjs/fingerprintjs/dist/fp.esm.js');
|
|
5
|
+
var fingerprintShared = require('./fingerprint-shared.js');
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Fingerprint Client Utilities
|
|
9
9
|
* 客户端专用的指纹生成和管理逻辑
|
|
10
10
|
* 只能在浏览器环境中使用
|
|
11
11
|
*/
|
|
12
|
+
/**
|
|
13
|
+
* 检查浏览器存储(localStorage 和 cookie)中的指纹 ID
|
|
14
|
+
* 返回有效的 ID 或 null
|
|
15
|
+
*/
|
|
16
|
+
function checkStoredFingerprintId() {
|
|
17
|
+
if (typeof window === 'undefined') {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
// 优先检查 localStorage
|
|
21
|
+
const localStorageId = localStorage.getItem(fingerprintShared.FINGERPRINT_STORAGE_KEY);
|
|
22
|
+
if (localStorageId && fingerprintShared.isValidFingerprintId(localStorageId)) {
|
|
23
|
+
return localStorageId;
|
|
24
|
+
}
|
|
25
|
+
// 检查 cookie
|
|
26
|
+
const cookieId = getCookieValue(fingerprintShared.FINGERPRINT_COOKIE_NAME);
|
|
27
|
+
if (cookieId && fingerprintShared.isValidFingerprintId(cookieId)) {
|
|
28
|
+
// 同步到 localStorage
|
|
29
|
+
localStorage.setItem(fingerprintShared.FINGERPRINT_STORAGE_KEY, cookieId);
|
|
30
|
+
return cookieId;
|
|
31
|
+
}
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
12
34
|
/**
|
|
13
35
|
* 生成基于真实浏览器特征的fingerprint ID
|
|
14
|
-
* 使用FingerprintJS收集浏览器特征并生成唯一标识
|
|
15
|
-
* 只能在客户端使用
|
|
36
|
+
* 使用 FingerprintJS 收集浏览器特征并生成唯一标识
|
|
16
37
|
*/
|
|
17
38
|
function generateFingerprintId() {
|
|
18
39
|
return tslib_es6.__awaiter(this, void 0, void 0, function* () {
|
|
19
40
|
if (typeof window === 'undefined') {
|
|
20
41
|
throw new Error('generateFingerprintId can only be used in browser environment');
|
|
21
42
|
}
|
|
22
|
-
//
|
|
23
|
-
const existingId =
|
|
24
|
-
if (existingId
|
|
43
|
+
// 检查现有 ID
|
|
44
|
+
const existingId = checkStoredFingerprintId();
|
|
45
|
+
if (existingId) {
|
|
46
|
+
console.log('Using existing fingerprint ID:', existingId);
|
|
25
47
|
return existingId;
|
|
26
48
|
}
|
|
27
|
-
// 检查cookie
|
|
28
|
-
const cookieId = getCookieValue(fingerprintShared.FINGERPRINT_COOKIE_NAME);
|
|
29
|
-
if (cookieId && fingerprintShared.isValidFingerprintId(cookieId)) {
|
|
30
|
-
// 同步到localStorage
|
|
31
|
-
localStorage.setItem(fingerprintShared.FINGERPRINT_STORAGE_KEY, cookieId);
|
|
32
|
-
return cookieId;
|
|
33
|
-
}
|
|
34
49
|
try {
|
|
35
|
-
// 使用FingerprintJS
|
|
50
|
+
// 使用 FingerprintJS 生成指纹
|
|
36
51
|
const fp = yield fp_esm.default.load();
|
|
37
52
|
const result = yield fp.get();
|
|
38
53
|
const fingerprintId = `fp_${result.visitorId}`;
|
|
39
|
-
// 存储到localStorage和cookie
|
|
54
|
+
// 存储到 localStorage 和 cookie
|
|
40
55
|
localStorage.setItem(fingerprintShared.FINGERPRINT_STORAGE_KEY, fingerprintId);
|
|
41
|
-
setCookie(fingerprintShared.FINGERPRINT_COOKIE_NAME, fingerprintId, 365);
|
|
56
|
+
setCookie(fingerprintShared.FINGERPRINT_COOKIE_NAME, fingerprintId, 365);
|
|
57
|
+
console.log('Generated new fingerprint ID:', fingerprintId);
|
|
42
58
|
return fingerprintId;
|
|
43
59
|
}
|
|
44
60
|
catch (error) {
|
|
45
61
|
console.warn('Failed to generate fingerprint with FingerprintJS:', error);
|
|
46
|
-
//
|
|
62
|
+
// 降级方案:生成基于时间戳和随机数的 ID
|
|
47
63
|
const fallbackId = `fp_fallback_${Date.now()}_${Math.random().toString(36).slice(2, 11)}`;
|
|
48
64
|
localStorage.setItem(fingerprintShared.FINGERPRINT_STORAGE_KEY, fallbackId);
|
|
49
65
|
setCookie(fingerprintShared.FINGERPRINT_COOKIE_NAME, fallbackId, 365);
|
|
66
|
+
console.log('Generated fallback fingerprint ID:', fallbackId);
|
|
50
67
|
return fallbackId;
|
|
51
68
|
}
|
|
52
69
|
});
|
|
53
70
|
}
|
|
54
71
|
/**
|
|
55
72
|
* 获取当前的fingerprint ID
|
|
56
|
-
* 只能在客户端使用
|
|
57
73
|
*/
|
|
58
74
|
function getFingerprintId() {
|
|
59
|
-
|
|
60
|
-
return null;
|
|
61
|
-
}
|
|
62
|
-
// 首先检查localStorage
|
|
63
|
-
const localStorageId = localStorage.getItem(fingerprintShared.FINGERPRINT_STORAGE_KEY);
|
|
64
|
-
if (localStorageId) {
|
|
65
|
-
return localStorageId;
|
|
66
|
-
}
|
|
67
|
-
// 检查cookie
|
|
68
|
-
const cookieId = getCookieValue(fingerprintShared.FINGERPRINT_COOKIE_NAME);
|
|
69
|
-
if (cookieId) {
|
|
70
|
-
// 同步到localStorage
|
|
71
|
-
localStorage.setItem(fingerprintShared.FINGERPRINT_STORAGE_KEY, cookieId);
|
|
72
|
-
return cookieId;
|
|
73
|
-
}
|
|
74
|
-
return null;
|
|
75
|
+
return checkStoredFingerprintId();
|
|
75
76
|
}
|
|
76
77
|
/**
|
|
77
78
|
* 设置fingerprint ID到存储
|
|
78
|
-
* 只能在客户端使用
|
|
79
79
|
*/
|
|
80
80
|
function setFingerprintId(fingerprintId) {
|
|
81
81
|
if (typeof window === 'undefined') {
|
|
82
82
|
throw new Error('setFingerprintId can only be used in browser environment');
|
|
83
83
|
}
|
|
84
|
+
if (!fingerprintShared.isValidFingerprintId(fingerprintId)) {
|
|
85
|
+
throw new Error('Invalid fingerprint ID');
|
|
86
|
+
}
|
|
84
87
|
localStorage.setItem(fingerprintShared.FINGERPRINT_STORAGE_KEY, fingerprintId);
|
|
85
88
|
setCookie(fingerprintShared.FINGERPRINT_COOKIE_NAME, fingerprintId, 365);
|
|
86
89
|
}
|
|
87
90
|
/**
|
|
88
91
|
* 清除fingerprint ID
|
|
89
|
-
* 只能在客户端使用
|
|
90
92
|
*/
|
|
91
93
|
function clearFingerprintId() {
|
|
92
94
|
if (typeof window === 'undefined') {
|
|
@@ -98,12 +100,12 @@ function clearFingerprintId() {
|
|
|
98
100
|
/**
|
|
99
101
|
* 获取或生成fingerprint ID
|
|
100
102
|
* 如果不存在则自动生成新的
|
|
101
|
-
* 只能在客户端使用
|
|
102
103
|
*/
|
|
103
104
|
function getOrGenerateFingerprintId() {
|
|
104
105
|
return tslib_es6.__awaiter(this, void 0, void 0, function* () {
|
|
105
|
-
const existingId =
|
|
106
|
+
const existingId = checkStoredFingerprintId();
|
|
106
107
|
if (existingId) {
|
|
108
|
+
console.log('Retrieved existing fingerprint ID:', existingId);
|
|
107
109
|
return existingId;
|
|
108
110
|
}
|
|
109
111
|
return yield generateFingerprintId();
|
|
@@ -111,7 +113,6 @@ function getOrGenerateFingerprintId() {
|
|
|
111
113
|
}
|
|
112
114
|
/**
|
|
113
115
|
* 创建包含fingerprint ID的fetch headers
|
|
114
|
-
* 只能在客户端使用
|
|
115
116
|
*/
|
|
116
117
|
function createFingerprintHeaders() {
|
|
117
118
|
return tslib_es6.__awaiter(this, void 0, void 0, function* () {
|
|
@@ -123,14 +124,12 @@ function createFingerprintHeaders() {
|
|
|
123
124
|
}
|
|
124
125
|
/**
|
|
125
126
|
* Hook for generating fingerprint headers
|
|
126
|
-
* 只能在客户端使用
|
|
127
127
|
*/
|
|
128
128
|
function useFingerprintHeaders() {
|
|
129
129
|
return createFingerprintHeaders;
|
|
130
130
|
}
|
|
131
131
|
/**
|
|
132
132
|
* Create a fetch wrapper that automatically includes fingerprint headers
|
|
133
|
-
* 只能在客户端使用
|
|
134
133
|
*/
|
|
135
134
|
function createFingerprintFetch() {
|
|
136
135
|
return (url, init) => tslib_es6.__awaiter(this, void 0, void 0, function* () {
|
|
@@ -1,90 +1,92 @@
|
|
|
1
1
|
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';
|
|
2
|
-
import { FINGERPRINT_STORAGE_KEY, isValidFingerprintId, FINGERPRINT_COOKIE_NAME } from './fingerprint-shared.mjs';
|
|
3
2
|
import index from '../../node_modules/.pnpm/@fingerprintjs_fingerprintjs@4.6.2/node_modules/@fingerprintjs/fingerprintjs/dist/fp.esm.mjs';
|
|
3
|
+
import { isValidFingerprintId, FINGERPRINT_STORAGE_KEY, FINGERPRINT_COOKIE_NAME } from './fingerprint-shared.mjs';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Fingerprint Client Utilities
|
|
7
7
|
* 客户端专用的指纹生成和管理逻辑
|
|
8
8
|
* 只能在浏览器环境中使用
|
|
9
9
|
*/
|
|
10
|
+
/**
|
|
11
|
+
* 检查浏览器存储(localStorage 和 cookie)中的指纹 ID
|
|
12
|
+
* 返回有效的 ID 或 null
|
|
13
|
+
*/
|
|
14
|
+
function checkStoredFingerprintId() {
|
|
15
|
+
if (typeof window === 'undefined') {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
// 优先检查 localStorage
|
|
19
|
+
const localStorageId = localStorage.getItem(FINGERPRINT_STORAGE_KEY);
|
|
20
|
+
if (localStorageId && isValidFingerprintId(localStorageId)) {
|
|
21
|
+
return localStorageId;
|
|
22
|
+
}
|
|
23
|
+
// 检查 cookie
|
|
24
|
+
const cookieId = getCookieValue(FINGERPRINT_COOKIE_NAME);
|
|
25
|
+
if (cookieId && isValidFingerprintId(cookieId)) {
|
|
26
|
+
// 同步到 localStorage
|
|
27
|
+
localStorage.setItem(FINGERPRINT_STORAGE_KEY, cookieId);
|
|
28
|
+
return cookieId;
|
|
29
|
+
}
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
10
32
|
/**
|
|
11
33
|
* 生成基于真实浏览器特征的fingerprint ID
|
|
12
|
-
* 使用FingerprintJS收集浏览器特征并生成唯一标识
|
|
13
|
-
* 只能在客户端使用
|
|
34
|
+
* 使用 FingerprintJS 收集浏览器特征并生成唯一标识
|
|
14
35
|
*/
|
|
15
36
|
function generateFingerprintId() {
|
|
16
37
|
return __awaiter(this, void 0, void 0, function* () {
|
|
17
38
|
if (typeof window === 'undefined') {
|
|
18
39
|
throw new Error('generateFingerprintId can only be used in browser environment');
|
|
19
40
|
}
|
|
20
|
-
//
|
|
21
|
-
const existingId =
|
|
22
|
-
if (existingId
|
|
41
|
+
// 检查现有 ID
|
|
42
|
+
const existingId = checkStoredFingerprintId();
|
|
43
|
+
if (existingId) {
|
|
44
|
+
console.log('Using existing fingerprint ID:', existingId);
|
|
23
45
|
return existingId;
|
|
24
46
|
}
|
|
25
|
-
// 检查cookie
|
|
26
|
-
const cookieId = getCookieValue(FINGERPRINT_COOKIE_NAME);
|
|
27
|
-
if (cookieId && isValidFingerprintId(cookieId)) {
|
|
28
|
-
// 同步到localStorage
|
|
29
|
-
localStorage.setItem(FINGERPRINT_STORAGE_KEY, cookieId);
|
|
30
|
-
return cookieId;
|
|
31
|
-
}
|
|
32
47
|
try {
|
|
33
|
-
// 使用FingerprintJS
|
|
48
|
+
// 使用 FingerprintJS 生成指纹
|
|
34
49
|
const fp = yield index.load();
|
|
35
50
|
const result = yield fp.get();
|
|
36
51
|
const fingerprintId = `fp_${result.visitorId}`;
|
|
37
|
-
// 存储到localStorage和cookie
|
|
52
|
+
// 存储到 localStorage 和 cookie
|
|
38
53
|
localStorage.setItem(FINGERPRINT_STORAGE_KEY, fingerprintId);
|
|
39
|
-
setCookie(FINGERPRINT_COOKIE_NAME, fingerprintId, 365);
|
|
54
|
+
setCookie(FINGERPRINT_COOKIE_NAME, fingerprintId, 365);
|
|
55
|
+
console.log('Generated new fingerprint ID:', fingerprintId);
|
|
40
56
|
return fingerprintId;
|
|
41
57
|
}
|
|
42
58
|
catch (error) {
|
|
43
59
|
console.warn('Failed to generate fingerprint with FingerprintJS:', error);
|
|
44
|
-
//
|
|
60
|
+
// 降级方案:生成基于时间戳和随机数的 ID
|
|
45
61
|
const fallbackId = `fp_fallback_${Date.now()}_${Math.random().toString(36).slice(2, 11)}`;
|
|
46
62
|
localStorage.setItem(FINGERPRINT_STORAGE_KEY, fallbackId);
|
|
47
63
|
setCookie(FINGERPRINT_COOKIE_NAME, fallbackId, 365);
|
|
64
|
+
console.log('Generated fallback fingerprint ID:', fallbackId);
|
|
48
65
|
return fallbackId;
|
|
49
66
|
}
|
|
50
67
|
});
|
|
51
68
|
}
|
|
52
69
|
/**
|
|
53
70
|
* 获取当前的fingerprint ID
|
|
54
|
-
* 只能在客户端使用
|
|
55
71
|
*/
|
|
56
72
|
function getFingerprintId() {
|
|
57
|
-
|
|
58
|
-
return null;
|
|
59
|
-
}
|
|
60
|
-
// 首先检查localStorage
|
|
61
|
-
const localStorageId = localStorage.getItem(FINGERPRINT_STORAGE_KEY);
|
|
62
|
-
if (localStorageId) {
|
|
63
|
-
return localStorageId;
|
|
64
|
-
}
|
|
65
|
-
// 检查cookie
|
|
66
|
-
const cookieId = getCookieValue(FINGERPRINT_COOKIE_NAME);
|
|
67
|
-
if (cookieId) {
|
|
68
|
-
// 同步到localStorage
|
|
69
|
-
localStorage.setItem(FINGERPRINT_STORAGE_KEY, cookieId);
|
|
70
|
-
return cookieId;
|
|
71
|
-
}
|
|
72
|
-
return null;
|
|
73
|
+
return checkStoredFingerprintId();
|
|
73
74
|
}
|
|
74
75
|
/**
|
|
75
76
|
* 设置fingerprint ID到存储
|
|
76
|
-
* 只能在客户端使用
|
|
77
77
|
*/
|
|
78
78
|
function setFingerprintId(fingerprintId) {
|
|
79
79
|
if (typeof window === 'undefined') {
|
|
80
80
|
throw new Error('setFingerprintId can only be used in browser environment');
|
|
81
81
|
}
|
|
82
|
+
if (!isValidFingerprintId(fingerprintId)) {
|
|
83
|
+
throw new Error('Invalid fingerprint ID');
|
|
84
|
+
}
|
|
82
85
|
localStorage.setItem(FINGERPRINT_STORAGE_KEY, fingerprintId);
|
|
83
86
|
setCookie(FINGERPRINT_COOKIE_NAME, fingerprintId, 365);
|
|
84
87
|
}
|
|
85
88
|
/**
|
|
86
89
|
* 清除fingerprint ID
|
|
87
|
-
* 只能在客户端使用
|
|
88
90
|
*/
|
|
89
91
|
function clearFingerprintId() {
|
|
90
92
|
if (typeof window === 'undefined') {
|
|
@@ -96,12 +98,12 @@ function clearFingerprintId() {
|
|
|
96
98
|
/**
|
|
97
99
|
* 获取或生成fingerprint ID
|
|
98
100
|
* 如果不存在则自动生成新的
|
|
99
|
-
* 只能在客户端使用
|
|
100
101
|
*/
|
|
101
102
|
function getOrGenerateFingerprintId() {
|
|
102
103
|
return __awaiter(this, void 0, void 0, function* () {
|
|
103
|
-
const existingId =
|
|
104
|
+
const existingId = checkStoredFingerprintId();
|
|
104
105
|
if (existingId) {
|
|
106
|
+
console.log('Retrieved existing fingerprint ID:', existingId);
|
|
105
107
|
return existingId;
|
|
106
108
|
}
|
|
107
109
|
return yield generateFingerprintId();
|
|
@@ -109,7 +111,6 @@ function getOrGenerateFingerprintId() {
|
|
|
109
111
|
}
|
|
110
112
|
/**
|
|
111
113
|
* 创建包含fingerprint ID的fetch headers
|
|
112
|
-
* 只能在客户端使用
|
|
113
114
|
*/
|
|
114
115
|
function createFingerprintHeaders() {
|
|
115
116
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -121,14 +122,12 @@ function createFingerprintHeaders() {
|
|
|
121
122
|
}
|
|
122
123
|
/**
|
|
123
124
|
* Hook for generating fingerprint headers
|
|
124
|
-
* 只能在客户端使用
|
|
125
125
|
*/
|
|
126
126
|
function useFingerprintHeaders() {
|
|
127
127
|
return createFingerprintHeaders;
|
|
128
128
|
}
|
|
129
129
|
/**
|
|
130
130
|
* Create a fetch wrapper that automatically includes fingerprint headers
|
|
131
|
-
* 只能在客户端使用
|
|
132
131
|
*/
|
|
133
132
|
function createFingerprintFetch() {
|
|
134
133
|
return (url, init) => __awaiter(this, void 0, void 0, function* () {
|
|
@@ -10,6 +10,20 @@ var fingerprintClient = require('./fingerprint-client.js');
|
|
|
10
10
|
* Accepts configuration to customize API endpoint and behavior
|
|
11
11
|
*/
|
|
12
12
|
function useFingerprint(config) {
|
|
13
|
+
// 服务端渲染检查
|
|
14
|
+
if (typeof window === 'undefined') {
|
|
15
|
+
return {
|
|
16
|
+
fingerprintId: null,
|
|
17
|
+
xUser: null,
|
|
18
|
+
xCredit: null,
|
|
19
|
+
xSubscription: null,
|
|
20
|
+
isLoading: false,
|
|
21
|
+
isInitialized: false,
|
|
22
|
+
error: 'Server-side rendering is not supported',
|
|
23
|
+
initializeAnonymousUser: () => tslib_es6.__awaiter(this, void 0, void 0, function* () { }),
|
|
24
|
+
refreshUserData: () => tslib_es6.__awaiter(this, void 0, void 0, function* () { }),
|
|
25
|
+
};
|
|
26
|
+
}
|
|
13
27
|
const [fingerprintId, setFingerprintIdState] = React.useState(null);
|
|
14
28
|
const [xUser, setXUser] = React.useState(null);
|
|
15
29
|
const [xCredit, setXCredit] = React.useState(null);
|
|
@@ -21,11 +35,9 @@ function useFingerprint(config) {
|
|
|
21
35
|
* 第一阶段:初始化fingerprint ID
|
|
22
36
|
*/
|
|
23
37
|
const initializeFingerprintId = React.useCallback(() => tslib_es6.__awaiter(this, void 0, void 0, function* () {
|
|
24
|
-
if (typeof window === 'undefined')
|
|
25
|
-
return null;
|
|
26
38
|
try {
|
|
27
|
-
// 优先检查现有ID, 没有就生成新的fingerprint ID
|
|
28
39
|
const currentFingerprintId = yield fingerprintClient.getOrGenerateFingerprintId();
|
|
40
|
+
console.log('Initialized fingerprintId:', currentFingerprintId);
|
|
29
41
|
setFingerprintIdState(currentFingerprintId);
|
|
30
42
|
return currentFingerprintId;
|
|
31
43
|
}
|
|
@@ -40,7 +52,12 @@ function useFingerprint(config) {
|
|
|
40
52
|
*/
|
|
41
53
|
const initializeAnonymousUser = React.useCallback(() => tslib_es6.__awaiter(this, void 0, void 0, function* () {
|
|
42
54
|
if (!fingerprintId) {
|
|
43
|
-
console.warn('Cannot initialize user
|
|
55
|
+
console.warn('Cannot initialize user: Fingerprint ID is missing', {
|
|
56
|
+
fingerprintId,
|
|
57
|
+
isLoading,
|
|
58
|
+
isInitialized,
|
|
59
|
+
});
|
|
60
|
+
setError('Cannot initialize user: Missing fingerprint ID');
|
|
44
61
|
return;
|
|
45
62
|
}
|
|
46
63
|
try {
|
|
@@ -86,8 +103,15 @@ function useFingerprint(config) {
|
|
|
86
103
|
* 刷新用户数据
|
|
87
104
|
*/
|
|
88
105
|
const refreshUserData = React.useCallback(() => tslib_es6.__awaiter(this, void 0, void 0, function* () {
|
|
89
|
-
if (!fingerprintId)
|
|
106
|
+
if (!fingerprintId) {
|
|
107
|
+
console.warn('Cannot refresh user data: Fingerprint ID is missing', {
|
|
108
|
+
fingerprintId,
|
|
109
|
+
isLoading,
|
|
110
|
+
isInitialized,
|
|
111
|
+
});
|
|
112
|
+
setError('Cannot refresh user data: Missing fingerprint ID');
|
|
90
113
|
return;
|
|
114
|
+
}
|
|
91
115
|
try {
|
|
92
116
|
setError(null);
|
|
93
117
|
const fingerprintHeaders = yield fingerprintClient.createFingerprintHeaders();
|
|
@@ -119,8 +143,14 @@ function useFingerprint(config) {
|
|
|
119
143
|
* 检查现有用户数据(仅在有fingerprint ID时执行)
|
|
120
144
|
*/
|
|
121
145
|
const checkExistingUser = React.useCallback(() => tslib_es6.__awaiter(this, void 0, void 0, function* () {
|
|
122
|
-
if (!fingerprintId)
|
|
146
|
+
if (!fingerprintId) {
|
|
147
|
+
console.warn('Cannot check existing user: Fingerprint ID is missing', {
|
|
148
|
+
fingerprintId,
|
|
149
|
+
isLoading,
|
|
150
|
+
isInitialized,
|
|
151
|
+
});
|
|
123
152
|
return;
|
|
153
|
+
}
|
|
124
154
|
try {
|
|
125
155
|
const fingerprintHeaders = yield fingerprintClient.createFingerprintHeaders();
|
|
126
156
|
const response = yield fetch(`${config.apiEndpoint}?fingerprintId=${fingerprintId}`, {
|
|
@@ -143,25 +173,27 @@ function useFingerprint(config) {
|
|
|
143
173
|
}), [fingerprintId, config.apiEndpoint]);
|
|
144
174
|
// 第一阶段:页面加载完成后生成指纹ID
|
|
145
175
|
React.useEffect(() => {
|
|
146
|
-
if (typeof window === 'undefined')
|
|
147
|
-
return;
|
|
148
176
|
const initFingerprint = () => tslib_es6.__awaiter(this, void 0, void 0, function* () {
|
|
149
|
-
|
|
150
|
-
|
|
177
|
+
setIsLoading(true);
|
|
178
|
+
const currentFingerprintId = yield initializeFingerprintId();
|
|
179
|
+
if (currentFingerprintId) {
|
|
180
|
+
setIsLoading(false);
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
setIsLoading(false);
|
|
184
|
+
}
|
|
151
185
|
});
|
|
152
186
|
initFingerprint();
|
|
153
187
|
}, [initializeFingerprintId]);
|
|
154
188
|
// 第二阶段:有指纹ID后检查现有用户
|
|
155
189
|
React.useEffect(() => {
|
|
156
|
-
if (!fingerprintId || isInitialized)
|
|
190
|
+
if (!fingerprintId || isInitialized || isLoading)
|
|
157
191
|
return;
|
|
158
192
|
checkExistingUser();
|
|
159
|
-
}, [fingerprintId, isInitialized, checkExistingUser]);
|
|
193
|
+
}, [fingerprintId, isInitialized, isLoading, checkExistingUser]);
|
|
160
194
|
// 第三阶段:如果没有现有用户且自动初始化开启,则创建新用户
|
|
161
195
|
React.useEffect(() => {
|
|
162
|
-
if (!fingerprintId || isInitialized || isLoading || error)
|
|
163
|
-
return;
|
|
164
|
-
if (config.autoInitialize === false)
|
|
196
|
+
if (!fingerprintId || isInitialized || isLoading || error || config.autoInitialize === false)
|
|
165
197
|
return;
|
|
166
198
|
initializeAnonymousUser();
|
|
167
199
|
}, [fingerprintId, isInitialized, isLoading, error, initializeAnonymousUser, config.autoInitialize]);
|
|
@@ -8,6 +8,20 @@ import { createFingerprintHeaders, setFingerprintId, getOrGenerateFingerprintId
|
|
|
8
8
|
* Accepts configuration to customize API endpoint and behavior
|
|
9
9
|
*/
|
|
10
10
|
function useFingerprint(config) {
|
|
11
|
+
// 服务端渲染检查
|
|
12
|
+
if (typeof window === 'undefined') {
|
|
13
|
+
return {
|
|
14
|
+
fingerprintId: null,
|
|
15
|
+
xUser: null,
|
|
16
|
+
xCredit: null,
|
|
17
|
+
xSubscription: null,
|
|
18
|
+
isLoading: false,
|
|
19
|
+
isInitialized: false,
|
|
20
|
+
error: 'Server-side rendering is not supported',
|
|
21
|
+
initializeAnonymousUser: () => __awaiter(this, void 0, void 0, function* () { }),
|
|
22
|
+
refreshUserData: () => __awaiter(this, void 0, void 0, function* () { }),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
11
25
|
const [fingerprintId, setFingerprintIdState] = useState(null);
|
|
12
26
|
const [xUser, setXUser] = useState(null);
|
|
13
27
|
const [xCredit, setXCredit] = useState(null);
|
|
@@ -19,11 +33,9 @@ function useFingerprint(config) {
|
|
|
19
33
|
* 第一阶段:初始化fingerprint ID
|
|
20
34
|
*/
|
|
21
35
|
const initializeFingerprintId = useCallback(() => __awaiter(this, void 0, void 0, function* () {
|
|
22
|
-
if (typeof window === 'undefined')
|
|
23
|
-
return null;
|
|
24
36
|
try {
|
|
25
|
-
// 优先检查现有ID, 没有就生成新的fingerprint ID
|
|
26
37
|
const currentFingerprintId = yield getOrGenerateFingerprintId();
|
|
38
|
+
console.log('Initialized fingerprintId:', currentFingerprintId);
|
|
27
39
|
setFingerprintIdState(currentFingerprintId);
|
|
28
40
|
return currentFingerprintId;
|
|
29
41
|
}
|
|
@@ -38,7 +50,12 @@ function useFingerprint(config) {
|
|
|
38
50
|
*/
|
|
39
51
|
const initializeAnonymousUser = useCallback(() => __awaiter(this, void 0, void 0, function* () {
|
|
40
52
|
if (!fingerprintId) {
|
|
41
|
-
console.warn('Cannot initialize user
|
|
53
|
+
console.warn('Cannot initialize user: Fingerprint ID is missing', {
|
|
54
|
+
fingerprintId,
|
|
55
|
+
isLoading,
|
|
56
|
+
isInitialized,
|
|
57
|
+
});
|
|
58
|
+
setError('Cannot initialize user: Missing fingerprint ID');
|
|
42
59
|
return;
|
|
43
60
|
}
|
|
44
61
|
try {
|
|
@@ -84,8 +101,15 @@ function useFingerprint(config) {
|
|
|
84
101
|
* 刷新用户数据
|
|
85
102
|
*/
|
|
86
103
|
const refreshUserData = useCallback(() => __awaiter(this, void 0, void 0, function* () {
|
|
87
|
-
if (!fingerprintId)
|
|
104
|
+
if (!fingerprintId) {
|
|
105
|
+
console.warn('Cannot refresh user data: Fingerprint ID is missing', {
|
|
106
|
+
fingerprintId,
|
|
107
|
+
isLoading,
|
|
108
|
+
isInitialized,
|
|
109
|
+
});
|
|
110
|
+
setError('Cannot refresh user data: Missing fingerprint ID');
|
|
88
111
|
return;
|
|
112
|
+
}
|
|
89
113
|
try {
|
|
90
114
|
setError(null);
|
|
91
115
|
const fingerprintHeaders = yield createFingerprintHeaders();
|
|
@@ -117,8 +141,14 @@ function useFingerprint(config) {
|
|
|
117
141
|
* 检查现有用户数据(仅在有fingerprint ID时执行)
|
|
118
142
|
*/
|
|
119
143
|
const checkExistingUser = useCallback(() => __awaiter(this, void 0, void 0, function* () {
|
|
120
|
-
if (!fingerprintId)
|
|
144
|
+
if (!fingerprintId) {
|
|
145
|
+
console.warn('Cannot check existing user: Fingerprint ID is missing', {
|
|
146
|
+
fingerprintId,
|
|
147
|
+
isLoading,
|
|
148
|
+
isInitialized,
|
|
149
|
+
});
|
|
121
150
|
return;
|
|
151
|
+
}
|
|
122
152
|
try {
|
|
123
153
|
const fingerprintHeaders = yield createFingerprintHeaders();
|
|
124
154
|
const response = yield fetch(`${config.apiEndpoint}?fingerprintId=${fingerprintId}`, {
|
|
@@ -141,25 +171,27 @@ function useFingerprint(config) {
|
|
|
141
171
|
}), [fingerprintId, config.apiEndpoint]);
|
|
142
172
|
// 第一阶段:页面加载完成后生成指纹ID
|
|
143
173
|
useEffect(() => {
|
|
144
|
-
if (typeof window === 'undefined')
|
|
145
|
-
return;
|
|
146
174
|
const initFingerprint = () => __awaiter(this, void 0, void 0, function* () {
|
|
147
|
-
|
|
148
|
-
|
|
175
|
+
setIsLoading(true);
|
|
176
|
+
const currentFingerprintId = yield initializeFingerprintId();
|
|
177
|
+
if (currentFingerprintId) {
|
|
178
|
+
setIsLoading(false);
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
setIsLoading(false);
|
|
182
|
+
}
|
|
149
183
|
});
|
|
150
184
|
initFingerprint();
|
|
151
185
|
}, [initializeFingerprintId]);
|
|
152
186
|
// 第二阶段:有指纹ID后检查现有用户
|
|
153
187
|
useEffect(() => {
|
|
154
|
-
if (!fingerprintId || isInitialized)
|
|
188
|
+
if (!fingerprintId || isInitialized || isLoading)
|
|
155
189
|
return;
|
|
156
190
|
checkExistingUser();
|
|
157
|
-
}, [fingerprintId, isInitialized, checkExistingUser]);
|
|
191
|
+
}, [fingerprintId, isInitialized, isLoading, checkExistingUser]);
|
|
158
192
|
// 第三阶段:如果没有现有用户且自动初始化开启,则创建新用户
|
|
159
193
|
useEffect(() => {
|
|
160
|
-
if (!fingerprintId || isInitialized || isLoading || error)
|
|
161
|
-
return;
|
|
162
|
-
if (config.autoInitialize === false)
|
|
194
|
+
if (!fingerprintId || isInitialized || isLoading || error || config.autoInitialize === false)
|
|
163
195
|
return;
|
|
164
196
|
initializeAnonymousUser();
|
|
165
197
|
}, [fingerprintId, isInitialized, isLoading, error, initializeAnonymousUser, config.autoInitialize]);
|
|
@@ -89,7 +89,6 @@ function MoneyPriceButton({ planKey, userContext, billingType, onLogin, onUpgrad
|
|
|
89
89
|
const config = getButtonConfig();
|
|
90
90
|
if (config.hidden)
|
|
91
91
|
return null;
|
|
92
|
-
// 使用 GradientButton 组件
|
|
93
92
|
return (jsxRuntime.jsx(gradientButton.GradientButton, { title: config.text, icon: config.icon, onClick: config.onClick, disabled: config.disabled || isProcessing, align: "center", className: "w-full", preventDoubleClick: true, loadingText: "Processing..." }));
|
|
94
93
|
}
|
|
95
94
|
|
|
@@ -87,7 +87,6 @@ function MoneyPriceButton({ planKey, userContext, billingType, onLogin, onUpgrad
|
|
|
87
87
|
const config = getButtonConfig();
|
|
88
88
|
if (config.hidden)
|
|
89
89
|
return null;
|
|
90
|
-
// 使用 GradientButton 组件
|
|
91
90
|
return (jsx(GradientButton, { title: config.text, icon: config.icon, onClick: config.onClick, disabled: config.disabled || isProcessing, align: "center", className: "w-full", preventDoubleClick: true, loadingText: "Processing..." }));
|
|
92
91
|
}
|
|
93
92
|
|
|
@@ -265,7 +265,7 @@ function MoneyPriceInteractive({ data, config, upgradeApiEndpoint, signInPath })
|
|
|
265
265
|
};
|
|
266
266
|
return (jsxRuntime.jsx("div", { style: style, className: "bg-gray-700 dark:bg-gray-200 text-gray-100 dark:text-gray-800 text-xs leading-relaxed px-3 py-2 rounded-lg shadow-lg border border-gray-300 dark:border-gray-600 backdrop-blur-sm", children: content }));
|
|
267
267
|
};
|
|
268
|
-
//
|
|
268
|
+
// 直接渲染按钮
|
|
269
269
|
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [data.plans.map((plan) => (jsxRuntime.jsx("div", { "data-button-placeholder": plan.key, children: jsxRuntime.jsx(moneyPriceButton.MoneyPriceButton, { planKey: plan.key, userContext: userContext, billingType: billingType, onLogin: handleLogin, onUpgrade: handleUpgrade, texts: data.buttonTexts, isProcessing: isProcessing }) }, plan.key))), jsxRuntime.jsx(Tooltip, Object.assign({}, tooltip))] }));
|
|
270
270
|
}
|
|
271
271
|
|
|
@@ -263,7 +263,7 @@ function MoneyPriceInteractive({ data, config, upgradeApiEndpoint, signInPath })
|
|
|
263
263
|
};
|
|
264
264
|
return (jsx("div", { style: style, className: "bg-gray-700 dark:bg-gray-200 text-gray-100 dark:text-gray-800 text-xs leading-relaxed px-3 py-2 rounded-lg shadow-lg border border-gray-300 dark:border-gray-600 backdrop-blur-sm", children: content }));
|
|
265
265
|
};
|
|
266
|
-
//
|
|
266
|
+
// 直接渲染按钮
|
|
267
267
|
return (jsxs(Fragment, { children: [data.plans.map((plan) => (jsx("div", { "data-button-placeholder": plan.key, children: jsx(MoneyPriceButton, { planKey: plan.key, userContext: userContext, billingType: billingType, onLogin: handleLogin, onUpgrade: handleUpgrade, texts: data.buttonTexts, isProcessing: isProcessing }) }, plan.key))), jsx(Tooltip, Object.assign({}, tooltip))] }));
|
|
268
268
|
}
|
|
269
269
|
|
|
@@ -66,7 +66,8 @@ function MoneyPrice(_a) {
|
|
|
66
66
|
if (!(opt && hasDiscount && opt.discountText))
|
|
67
67
|
return null;
|
|
68
68
|
return (jsxRuntime.jsx("span", { className: "px-2 py-1 text-xs rounded bg-yellow-100 text-yellow-800 font-semibold align-middle text-center inline-flex items-center justify-center whitespace-nowrap", children: opt.discountText.replace('{percent}', String(discountPercent)) }));
|
|
69
|
-
})() })] }), jsxRuntime.jsx("div", { className: "grid grid-cols-1 md:grid-cols-3 gap-8", children: data.plans.map((plan, _idx) => (jsxRuntime.jsxs("div", { "data-price-plan": plan.key, className: utils.cn('flex flex-col bg-white dark:bg-gray-800/60 rounded-2xl border border-gray-300 dark:border-[#7c3aed40] transition p-8
|
|
69
|
+
})() })] }), jsxRuntime.jsx("div", { className: "grid grid-cols-1 md:grid-cols-3 gap-8", children: data.plans.map((plan, _idx) => (jsxRuntime.jsxs("div", { "data-price-plan": plan.key, className: utils.cn('flex flex-col bg-white dark:bg-gray-800/60 rounded-2xl border border-gray-300 dark:border-[#7c3aed40] transition p-8 w-full h-full shadow-sm dark:shadow-none', // 添加 w-full
|
|
70
|
+
'hover:border-2 hover:border-purple-500', 'focus-within:border-2 focus-within:border-purple-500'), style: { minHeight: maxFeaturesCount * 100 }, children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-2 mb-2", children: [jsxRuntime.jsx("span", { className: "text-xl font-bold text-gray-900 dark:text-gray-100", children: plan.title }), plan.titleTags && plan.titleTags.map((tag, i) => (jsxRuntime.jsx("span", { className: "px-2 py-0.5 text-xs rounded bg-orange-100 text-orange-800 dark:bg-orange-900 dark:text-orange-200 font-semibold align-middle", children: tag }, i)))] }), renderPrice(plan), jsxRuntime.jsx("ul", { className: "flex-1 mb-6 mt-4", children: getFeatureRows(plan).map((feature, i) => (jsxRuntime.jsxs("li", { className: "flex items-center gap-2 mb-2 min-h-[28px]", "data-feature-item": `${plan.key}-${i}`, children: [feature ? (jsxRuntime.jsx("span", { className: "inline-flex items-center justify-center w-5 h-5 rounded-full bg-green-100 text-green-700 dark:bg-green-900 dark:text-green-200 mr-1", children: feature.icon ? jsxRuntime.jsx("span", { children: feature.icon }) : jsxRuntime.jsx("span", { className: "font-bold", children: "\u2713" }) })) : (jsxRuntime.jsx("span", { className: "inline-flex items-center justify-center w-5 h-5 rounded-full mr-1", children: "\u00A0" })), feature && feature.tag && (jsxRuntime.jsx("span", { className: "px-1 py-0.5 text-[6px] rounded bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200 font-semibold align-middle", children: feature.tag })), feature ? (jsxRuntime.jsxs("span", { className: "relative group cursor-pointer text-sm text-gray-800 dark:text-gray-200", children: [feature.description, feature.tooltip && (jsxRuntime.jsx("span", { className: "ml-1 align-middle inline-flex", "data-tooltip-trigger": `${plan.key}-${i}`, "data-tooltip-content": feature.tooltip, children: jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M8.228 9c.549-1.165 2.03-2 3.772-2 2.21 0 4 1.343 4 3 0 1.4-1.278 2.575-3.006 2.907-.542.104-.994.54-.994 1.093m0 3h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" }) }) }))] })) : (jsxRuntime.jsx("span", { children: "\u00A0" }))] }, i))) }), jsxRuntime.jsx("div", { className: "flex-1" }), jsxRuntime.jsx("div", { "data-button-placeholder": plan.key, className: "w-full" })] }, plan.key))) }), jsxRuntime.jsx(moneyPriceInteractive.MoneyPriceInteractive, { data: data, config: config, upgradeApiEndpoint: upgradeApiEndpoint, signInPath: signInPath })] }));
|
|
70
71
|
});
|
|
71
72
|
}
|
|
72
73
|
|
|
@@ -64,7 +64,8 @@ function MoneyPrice(_a) {
|
|
|
64
64
|
if (!(opt && hasDiscount && opt.discountText))
|
|
65
65
|
return null;
|
|
66
66
|
return (jsx("span", { className: "px-2 py-1 text-xs rounded bg-yellow-100 text-yellow-800 font-semibold align-middle text-center inline-flex items-center justify-center whitespace-nowrap", children: opt.discountText.replace('{percent}', String(discountPercent)) }));
|
|
67
|
-
})() })] }), jsx("div", { className: "grid grid-cols-1 md:grid-cols-3 gap-8", children: data.plans.map((plan, _idx) => (jsxs("div", { "data-price-plan": plan.key, className: cn('flex flex-col bg-white dark:bg-gray-800/60 rounded-2xl border border-gray-300 dark:border-[#7c3aed40] transition p-8
|
|
67
|
+
})() })] }), jsx("div", { className: "grid grid-cols-1 md:grid-cols-3 gap-8", children: data.plans.map((plan, _idx) => (jsxs("div", { "data-price-plan": plan.key, className: cn('flex flex-col bg-white dark:bg-gray-800/60 rounded-2xl border border-gray-300 dark:border-[#7c3aed40] transition p-8 w-full h-full shadow-sm dark:shadow-none', // 添加 w-full
|
|
68
|
+
'hover:border-2 hover:border-purple-500', 'focus-within:border-2 focus-within:border-purple-500'), style: { minHeight: maxFeaturesCount * 100 }, children: [jsxs("div", { className: "flex items-center gap-2 mb-2", children: [jsx("span", { className: "text-xl font-bold text-gray-900 dark:text-gray-100", children: plan.title }), plan.titleTags && plan.titleTags.map((tag, i) => (jsx("span", { className: "px-2 py-0.5 text-xs rounded bg-orange-100 text-orange-800 dark:bg-orange-900 dark:text-orange-200 font-semibold align-middle", children: tag }, i)))] }), renderPrice(plan), jsx("ul", { className: "flex-1 mb-6 mt-4", children: getFeatureRows(plan).map((feature, i) => (jsxs("li", { className: "flex items-center gap-2 mb-2 min-h-[28px]", "data-feature-item": `${plan.key}-${i}`, children: [feature ? (jsx("span", { className: "inline-flex items-center justify-center w-5 h-5 rounded-full bg-green-100 text-green-700 dark:bg-green-900 dark:text-green-200 mr-1", children: feature.icon ? jsx("span", { children: feature.icon }) : jsx("span", { className: "font-bold", children: "\u2713" }) })) : (jsx("span", { className: "inline-flex items-center justify-center w-5 h-5 rounded-full mr-1", children: "\u00A0" })), feature && feature.tag && (jsx("span", { className: "px-1 py-0.5 text-[6px] rounded bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200 font-semibold align-middle", children: feature.tag })), feature ? (jsxs("span", { className: "relative group cursor-pointer text-sm text-gray-800 dark:text-gray-200", children: [feature.description, feature.tooltip && (jsx("span", { className: "ml-1 align-middle inline-flex", "data-tooltip-trigger": `${plan.key}-${i}`, "data-tooltip-content": feature.tooltip, children: jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M8.228 9c.549-1.165 2.03-2 3.772-2 2.21 0 4 1.343 4 3 0 1.4-1.278 2.575-3.006 2.907-.542.104-.994.54-.994 1.093m0 3h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" }) }) }))] })) : (jsx("span", { children: "\u00A0" }))] }, i))) }), jsx("div", { className: "flex-1" }), jsx("div", { "data-button-placeholder": plan.key, className: "w-full" })] }, plan.key))) }), jsx(MoneyPriceInteractive, { data: data, config: config, upgradeApiEndpoint: upgradeApiEndpoint, signInPath: signInPath })] }));
|
|
68
69
|
});
|
|
69
70
|
}
|
|
70
71
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { __module as coseBase$1 } from '../../../../../_virtual/cose-
|
|
1
|
+
import { __module as coseBase$1 } from '../../../../../_virtual/cose-base2.mjs';
|
|
2
2
|
import { __require as requireLayoutBase } from '../../../layout-base@1.0.2/node_modules/layout-base/layout-base.mjs';
|
|
3
3
|
|
|
4
4
|
var coseBase = coseBase$1.exports;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { __module as coseBase$1 } from '../../../../../_virtual/cose-
|
|
1
|
+
import { __module as coseBase$1 } from '../../../../../_virtual/cose-base.mjs';
|
|
2
2
|
import { __require as requireLayoutBase } from '../../../layout-base@2.0.1/node_modules/layout-base/layout-base.mjs';
|
|
3
3
|
|
|
4
4
|
var coseBase = coseBase$1.exports;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@windrun-huaiin/third-ui",
|
|
3
|
-
"version": "7.3.
|
|
3
|
+
"version": "7.3.7",
|
|
4
4
|
"description": "Third-party integrated UI components for windrun-huaiin projects",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -75,8 +75,8 @@
|
|
|
75
75
|
"mermaid": "^11.6.0",
|
|
76
76
|
"react-medium-image-zoom": "^5.2.14",
|
|
77
77
|
"zod": "^3.22.4",
|
|
78
|
-
"@windrun-huaiin/
|
|
79
|
-
"@windrun-huaiin/
|
|
78
|
+
"@windrun-huaiin/base-ui": "^8.1.2",
|
|
79
|
+
"@windrun-huaiin/lib": "^7.1.2"
|
|
80
80
|
},
|
|
81
81
|
"peerDependencies": {
|
|
82
82
|
"react": "19.1.0",
|
|
@@ -4,102 +4,100 @@
|
|
|
4
4
|
* 只能在浏览器环境中使用
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import {
|
|
8
|
-
FINGERPRINT_STORAGE_KEY,
|
|
9
|
-
FINGERPRINT_COOKIE_NAME,
|
|
10
|
-
isValidFingerprintId
|
|
11
|
-
} from './fingerprint-shared';
|
|
12
7
|
import FingerprintJS from '@fingerprintjs/fingerprintjs';
|
|
8
|
+
import { FINGERPRINT_STORAGE_KEY, FINGERPRINT_COOKIE_NAME, isValidFingerprintId } from './fingerprint-shared';
|
|
13
9
|
|
|
14
10
|
/**
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* 只能在客户端使用
|
|
11
|
+
* 检查浏览器存储(localStorage 和 cookie)中的指纹 ID
|
|
12
|
+
* 返回有效的 ID 或 null
|
|
18
13
|
*/
|
|
19
|
-
|
|
14
|
+
function checkStoredFingerprintId(): string | null {
|
|
20
15
|
if (typeof window === 'undefined') {
|
|
21
|
-
|
|
16
|
+
return null;
|
|
22
17
|
}
|
|
23
18
|
|
|
24
|
-
//
|
|
25
|
-
const
|
|
26
|
-
if (
|
|
27
|
-
return
|
|
19
|
+
// 优先检查 localStorage
|
|
20
|
+
const localStorageId = localStorage.getItem(FINGERPRINT_STORAGE_KEY);
|
|
21
|
+
if (localStorageId && isValidFingerprintId(localStorageId)) {
|
|
22
|
+
return localStorageId;
|
|
28
23
|
}
|
|
29
24
|
|
|
30
|
-
// 检查cookie
|
|
25
|
+
// 检查 cookie
|
|
31
26
|
const cookieId = getCookieValue(FINGERPRINT_COOKIE_NAME);
|
|
32
27
|
if (cookieId && isValidFingerprintId(cookieId)) {
|
|
33
|
-
// 同步到localStorage
|
|
28
|
+
// 同步到 localStorage
|
|
34
29
|
localStorage.setItem(FINGERPRINT_STORAGE_KEY, cookieId);
|
|
35
30
|
return cookieId;
|
|
36
31
|
}
|
|
37
32
|
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* 生成基于真实浏览器特征的fingerprint ID
|
|
38
|
+
* 使用 FingerprintJS 收集浏览器特征并生成唯一标识
|
|
39
|
+
*/
|
|
40
|
+
export async function generateFingerprintId(): Promise<string> {
|
|
41
|
+
if (typeof window === 'undefined') {
|
|
42
|
+
throw new Error('generateFingerprintId can only be used in browser environment');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// 检查现有 ID
|
|
46
|
+
const existingId = checkStoredFingerprintId();
|
|
47
|
+
if (existingId) {
|
|
48
|
+
console.log('Using existing fingerprint ID:', existingId);
|
|
49
|
+
return existingId;
|
|
50
|
+
}
|
|
51
|
+
|
|
38
52
|
try {
|
|
39
|
-
// 使用FingerprintJS
|
|
53
|
+
// 使用 FingerprintJS 生成指纹
|
|
40
54
|
const fp = await FingerprintJS.load();
|
|
41
55
|
const result = await fp.get();
|
|
42
56
|
const fingerprintId = `fp_${result.visitorId}`;
|
|
43
57
|
|
|
44
|
-
// 存储到localStorage和cookie
|
|
58
|
+
// 存储到 localStorage 和 cookie
|
|
45
59
|
localStorage.setItem(FINGERPRINT_STORAGE_KEY, fingerprintId);
|
|
46
|
-
setCookie(FINGERPRINT_COOKIE_NAME, fingerprintId, 365);
|
|
60
|
+
setCookie(FINGERPRINT_COOKIE_NAME, fingerprintId, 365);
|
|
47
61
|
|
|
62
|
+
console.log('Generated new fingerprint ID:', fingerprintId);
|
|
48
63
|
return fingerprintId;
|
|
49
64
|
} catch (error) {
|
|
50
65
|
console.warn('Failed to generate fingerprint with FingerprintJS:', error);
|
|
51
|
-
//
|
|
66
|
+
// 降级方案:生成基于时间戳和随机数的 ID
|
|
52
67
|
const fallbackId = `fp_fallback_${Date.now()}_${Math.random().toString(36).slice(2, 11)}`;
|
|
53
|
-
|
|
54
68
|
localStorage.setItem(FINGERPRINT_STORAGE_KEY, fallbackId);
|
|
55
69
|
setCookie(FINGERPRINT_COOKIE_NAME, fallbackId, 365);
|
|
56
|
-
|
|
70
|
+
|
|
71
|
+
console.log('Generated fallback fingerprint ID:', fallbackId);
|
|
57
72
|
return fallbackId;
|
|
58
73
|
}
|
|
59
74
|
}
|
|
60
75
|
|
|
61
76
|
/**
|
|
62
77
|
* 获取当前的fingerprint ID
|
|
63
|
-
* 只能在客户端使用
|
|
64
78
|
*/
|
|
65
79
|
export function getFingerprintId(): string | null {
|
|
66
|
-
|
|
67
|
-
return null;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// 首先检查localStorage
|
|
71
|
-
const localStorageId = localStorage.getItem(FINGERPRINT_STORAGE_KEY);
|
|
72
|
-
if (localStorageId) {
|
|
73
|
-
return localStorageId;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// 检查cookie
|
|
77
|
-
const cookieId = getCookieValue(FINGERPRINT_COOKIE_NAME);
|
|
78
|
-
if (cookieId) {
|
|
79
|
-
// 同步到localStorage
|
|
80
|
-
localStorage.setItem(FINGERPRINT_STORAGE_KEY, cookieId);
|
|
81
|
-
return cookieId;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
return null;
|
|
80
|
+
return checkStoredFingerprintId();
|
|
85
81
|
}
|
|
86
82
|
|
|
87
83
|
/**
|
|
88
84
|
* 设置fingerprint ID到存储
|
|
89
|
-
* 只能在客户端使用
|
|
90
85
|
*/
|
|
91
86
|
export function setFingerprintId(fingerprintId: string): void {
|
|
92
87
|
if (typeof window === 'undefined') {
|
|
93
88
|
throw new Error('setFingerprintId can only be used in browser environment');
|
|
94
89
|
}
|
|
95
90
|
|
|
91
|
+
if (!isValidFingerprintId(fingerprintId)) {
|
|
92
|
+
throw new Error('Invalid fingerprint ID');
|
|
93
|
+
}
|
|
94
|
+
|
|
96
95
|
localStorage.setItem(FINGERPRINT_STORAGE_KEY, fingerprintId);
|
|
97
96
|
setCookie(FINGERPRINT_COOKIE_NAME, fingerprintId, 365);
|
|
98
97
|
}
|
|
99
98
|
|
|
100
99
|
/**
|
|
101
100
|
* 清除fingerprint ID
|
|
102
|
-
* 只能在客户端使用
|
|
103
101
|
*/
|
|
104
102
|
export function clearFingerprintId(): void {
|
|
105
103
|
if (typeof window === 'undefined') {
|
|
@@ -113,30 +111,29 @@ export function clearFingerprintId(): void {
|
|
|
113
111
|
/**
|
|
114
112
|
* 获取或生成fingerprint ID
|
|
115
113
|
* 如果不存在则自动生成新的
|
|
116
|
-
* 只能在客户端使用
|
|
117
114
|
*/
|
|
118
115
|
export async function getOrGenerateFingerprintId(): Promise<string> {
|
|
119
|
-
const existingId =
|
|
116
|
+
const existingId = checkStoredFingerprintId();
|
|
120
117
|
if (existingId) {
|
|
118
|
+
console.log('Retrieved existing fingerprint ID:', existingId);
|
|
121
119
|
return existingId;
|
|
122
120
|
}
|
|
121
|
+
|
|
123
122
|
return await generateFingerprintId();
|
|
124
123
|
}
|
|
125
124
|
|
|
126
125
|
/**
|
|
127
126
|
* 创建包含fingerprint ID的fetch headers
|
|
128
|
-
* 只能在客户端使用
|
|
129
127
|
*/
|
|
130
128
|
export async function createFingerprintHeaders(): Promise<Record<string, string>> {
|
|
131
129
|
const fingerprintId = await getOrGenerateFingerprintId();
|
|
132
130
|
return {
|
|
133
|
-
FINGERPRINT_HEADER_NAME
|
|
131
|
+
FINGERPRINT_HEADER_NAME: fingerprintId,
|
|
134
132
|
};
|
|
135
133
|
}
|
|
136
134
|
|
|
137
135
|
/**
|
|
138
136
|
* Hook for generating fingerprint headers
|
|
139
|
-
* 只能在客户端使用
|
|
140
137
|
*/
|
|
141
138
|
export function useFingerprintHeaders(): () => Promise<Record<string, string>> {
|
|
142
139
|
return createFingerprintHeaders;
|
|
@@ -144,7 +141,6 @@ export function useFingerprintHeaders(): () => Promise<Record<string, string>> {
|
|
|
144
141
|
|
|
145
142
|
/**
|
|
146
143
|
* Create a fetch wrapper that automatically includes fingerprint headers
|
|
147
|
-
* 只能在客户端使用
|
|
148
144
|
*/
|
|
149
145
|
export function createFingerprintFetch() {
|
|
150
146
|
return async (url: string | URL | Request, init?: RequestInit) => {
|
|
@@ -19,6 +19,21 @@ import type {
|
|
|
19
19
|
* Accepts configuration to customize API endpoint and behavior
|
|
20
20
|
*/
|
|
21
21
|
export function useFingerprint(config: FingerprintConfig): UseFingerprintResult {
|
|
22
|
+
// 服务端渲染检查
|
|
23
|
+
if (typeof window === 'undefined') {
|
|
24
|
+
return {
|
|
25
|
+
fingerprintId: null,
|
|
26
|
+
xUser: null,
|
|
27
|
+
xCredit: null,
|
|
28
|
+
xSubscription: null,
|
|
29
|
+
isLoading: false,
|
|
30
|
+
isInitialized: false,
|
|
31
|
+
error: 'Server-side rendering is not supported',
|
|
32
|
+
initializeAnonymousUser: async () => {},
|
|
33
|
+
refreshUserData: async () => {},
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
22
37
|
const [fingerprintId, setFingerprintIdState] = useState<string | null>(null);
|
|
23
38
|
const [xUser, setXUser] = useState<XUser | null>(null);
|
|
24
39
|
const [xCredit, setXCredit] = useState<XCredit | null>(null);
|
|
@@ -31,11 +46,9 @@ export function useFingerprint(config: FingerprintConfig): UseFingerprintResult
|
|
|
31
46
|
* 第一阶段:初始化fingerprint ID
|
|
32
47
|
*/
|
|
33
48
|
const initializeFingerprintId = useCallback(async () => {
|
|
34
|
-
if (typeof window === 'undefined') return null;
|
|
35
|
-
|
|
36
49
|
try {
|
|
37
|
-
// 优先检查现有ID, 没有就生成新的fingerprint ID
|
|
38
50
|
const currentFingerprintId = await getOrGenerateFingerprintId();
|
|
51
|
+
console.log('Initialized fingerprintId:', currentFingerprintId);
|
|
39
52
|
setFingerprintIdState(currentFingerprintId);
|
|
40
53
|
return currentFingerprintId;
|
|
41
54
|
} catch (error) {
|
|
@@ -50,7 +63,12 @@ export function useFingerprint(config: FingerprintConfig): UseFingerprintResult
|
|
|
50
63
|
*/
|
|
51
64
|
const initializeAnonymousUser = useCallback(async () => {
|
|
52
65
|
if (!fingerprintId) {
|
|
53
|
-
console.warn('Cannot initialize user
|
|
66
|
+
console.warn('Cannot initialize user: Fingerprint ID is missing', {
|
|
67
|
+
fingerprintId,
|
|
68
|
+
isLoading,
|
|
69
|
+
isInitialized,
|
|
70
|
+
});
|
|
71
|
+
setError('Cannot initialize user: Missing fingerprint ID');
|
|
54
72
|
return;
|
|
55
73
|
}
|
|
56
74
|
|
|
@@ -103,7 +121,15 @@ export function useFingerprint(config: FingerprintConfig): UseFingerprintResult
|
|
|
103
121
|
* 刷新用户数据
|
|
104
122
|
*/
|
|
105
123
|
const refreshUserData = useCallback(async () => {
|
|
106
|
-
if (!fingerprintId)
|
|
124
|
+
if (!fingerprintId) {
|
|
125
|
+
console.warn('Cannot refresh user data: Fingerprint ID is missing', {
|
|
126
|
+
fingerprintId,
|
|
127
|
+
isLoading,
|
|
128
|
+
isInitialized,
|
|
129
|
+
});
|
|
130
|
+
setError('Cannot refresh user data: Missing fingerprint ID');
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
107
133
|
|
|
108
134
|
try {
|
|
109
135
|
setError(null);
|
|
@@ -140,7 +166,14 @@ export function useFingerprint(config: FingerprintConfig): UseFingerprintResult
|
|
|
140
166
|
* 检查现有用户数据(仅在有fingerprint ID时执行)
|
|
141
167
|
*/
|
|
142
168
|
const checkExistingUser = useCallback(async () => {
|
|
143
|
-
if (!fingerprintId)
|
|
169
|
+
if (!fingerprintId) {
|
|
170
|
+
console.warn('Cannot check existing user: Fingerprint ID is missing', {
|
|
171
|
+
fingerprintId,
|
|
172
|
+
isLoading,
|
|
173
|
+
isInitialized,
|
|
174
|
+
});
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
144
177
|
|
|
145
178
|
try {
|
|
146
179
|
const fingerprintHeaders = await createFingerprintHeaders();
|
|
@@ -165,11 +198,14 @@ export function useFingerprint(config: FingerprintConfig): UseFingerprintResult
|
|
|
165
198
|
|
|
166
199
|
// 第一阶段:页面加载完成后生成指纹ID
|
|
167
200
|
useEffect(() => {
|
|
168
|
-
if (typeof window === 'undefined') return;
|
|
169
|
-
|
|
170
201
|
const initFingerprint = async () => {
|
|
171
|
-
|
|
172
|
-
|
|
202
|
+
setIsLoading(true);
|
|
203
|
+
const currentFingerprintId = await initializeFingerprintId();
|
|
204
|
+
if (currentFingerprintId) {
|
|
205
|
+
setIsLoading(false);
|
|
206
|
+
} else {
|
|
207
|
+
setIsLoading(false);
|
|
208
|
+
}
|
|
173
209
|
};
|
|
174
210
|
|
|
175
211
|
initFingerprint();
|
|
@@ -177,15 +213,14 @@ export function useFingerprint(config: FingerprintConfig): UseFingerprintResult
|
|
|
177
213
|
|
|
178
214
|
// 第二阶段:有指纹ID后检查现有用户
|
|
179
215
|
useEffect(() => {
|
|
180
|
-
if (!fingerprintId || isInitialized) return;
|
|
216
|
+
if (!fingerprintId || isInitialized || isLoading) return;
|
|
181
217
|
|
|
182
218
|
checkExistingUser();
|
|
183
|
-
}, [fingerprintId, isInitialized, checkExistingUser]);
|
|
219
|
+
}, [fingerprintId, isInitialized, isLoading, checkExistingUser]);
|
|
184
220
|
|
|
185
221
|
// 第三阶段:如果没有现有用户且自动初始化开启,则创建新用户
|
|
186
222
|
useEffect(() => {
|
|
187
|
-
if (!fingerprintId || isInitialized || isLoading || error) return;
|
|
188
|
-
if (config.autoInitialize === false) return;
|
|
223
|
+
if (!fingerprintId || isInitialized || isLoading || error || config.autoInitialize === false) return;
|
|
189
224
|
|
|
190
225
|
initializeAnonymousUser();
|
|
191
226
|
}, [fingerprintId, isInitialized, isLoading, error, initializeAnonymousUser, config.autoInitialize]);
|
|
@@ -201,6 +236,4 @@ export function useFingerprint(config: FingerprintConfig): UseFingerprintResult
|
|
|
201
236
|
initializeAnonymousUser,
|
|
202
237
|
refreshUserData,
|
|
203
238
|
};
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
// createFingerprintFetch moved to fingerprint.ts
|
|
239
|
+
}
|
|
@@ -205,7 +205,7 @@ export async function MoneyPrice({
|
|
|
205
205
|
key={plan.key}
|
|
206
206
|
data-price-plan={plan.key}
|
|
207
207
|
className={cn(
|
|
208
|
-
'flex flex-col bg-white dark:bg-gray-800/60 rounded-2xl border border-gray-300 dark:border-[#7c3aed40] transition p-8 h-full shadow-sm dark:shadow-none',
|
|
208
|
+
'flex flex-col bg-white dark:bg-gray-800/60 rounded-2xl border border-gray-300 dark:border-[#7c3aed40] transition p-8 w-full h-full shadow-sm dark:shadow-none', // 添加 w-full
|
|
209
209
|
'hover:border-2 hover:border-purple-500',
|
|
210
210
|
'focus-within:border-2 focus-within:border-purple-500'
|
|
211
211
|
)}
|