@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.
Files changed (77) hide show
  1. package/dist/clerk/clerk-page-generator-client.d.ts +10 -0
  2. package/dist/clerk/clerk-page-generator-client.js +28 -0
  3. package/dist/clerk/clerk-page-generator-client.mjs +25 -0
  4. package/dist/clerk/clerk-page-generator.js +1 -0
  5. package/dist/clerk/clerk-page-generator.mjs +1 -0
  6. package/dist/clerk/client-page-generator.d.ts +10 -0
  7. package/dist/clerk/client-page-generator.js +28 -0
  8. package/dist/clerk/client-page-generator.mjs +25 -0
  9. package/dist/clerk/context/FingerprintProvider.d.ts +25 -0
  10. package/dist/clerk/context/FingerprintProvider.js +71 -0
  11. package/dist/clerk/context/FingerprintProvider.mjs +65 -0
  12. package/dist/clerk/fingerprint/fingerprint-client.d.ts +47 -0
  13. package/dist/clerk/fingerprint/fingerprint-client.js +177 -0
  14. package/dist/clerk/fingerprint/fingerprint-client.mjs +168 -0
  15. package/dist/clerk/fingerprint/fingerprint-provider.d.ts +25 -0
  16. package/dist/clerk/fingerprint/fingerprint-provider.js +71 -0
  17. package/dist/clerk/fingerprint/fingerprint-provider.mjs +65 -0
  18. package/dist/clerk/fingerprint/fingerprint-server.d.ts +22 -0
  19. package/dist/clerk/fingerprint/fingerprint-server.js +75 -0
  20. package/dist/clerk/fingerprint/fingerprint-server.mjs +71 -0
  21. package/dist/clerk/fingerprint/fingerprint-shared.d.ts +17 -0
  22. package/dist/clerk/fingerprint/fingerprint-shared.js +35 -0
  23. package/dist/clerk/fingerprint/fingerprint-shared.mjs +29 -0
  24. package/dist/clerk/fingerprint/fingerprint.d.ts +55 -0
  25. package/dist/clerk/fingerprint/fingerprint.js +17 -0
  26. package/dist/clerk/fingerprint/fingerprint.mjs +15 -0
  27. package/dist/clerk/fingerprint/index.d.ts +5 -0
  28. package/dist/clerk/fingerprint/index.js +29 -0
  29. package/dist/clerk/fingerprint/index.mjs +5 -0
  30. package/dist/clerk/fingerprint/server.d.ts +3 -0
  31. package/dist/clerk/fingerprint/server.js +15 -0
  32. package/dist/clerk/fingerprint/server.mjs +2 -0
  33. package/dist/clerk/fingerprint/types.d.ts +44 -0
  34. package/dist/clerk/fingerprint/use-fingerprint.d.ts +6 -0
  35. package/dist/clerk/fingerprint/use-fingerprint.js +176 -0
  36. package/dist/clerk/fingerprint/use-fingerprint.mjs +174 -0
  37. package/dist/clerk/fingerprint.d.ts +55 -0
  38. package/dist/clerk/fingerprint.js +237 -0
  39. package/dist/clerk/fingerprint.mjs +225 -0
  40. package/dist/clerk/hooks/useFingerprint.d.ts +6 -0
  41. package/dist/clerk/hooks/useFingerprint.js +182 -0
  42. package/dist/clerk/hooks/useFingerprint.mjs +180 -0
  43. package/dist/clerk/index.d.ts +3 -0
  44. package/dist/clerk/index.js +7 -0
  45. package/dist/clerk/index.mjs +3 -0
  46. package/dist/clerk/signin-with-fingerprint-client.d.ts +7 -0
  47. package/dist/clerk/signin-with-fingerprint-client.js +52 -0
  48. package/dist/clerk/signin-with-fingerprint-client.mjs +47 -0
  49. package/dist/clerk/signup-with-fingerprint-client.d.ts +7 -0
  50. package/dist/clerk/signup-with-fingerprint-client.js +52 -0
  51. package/dist/clerk/signup-with-fingerprint-client.mjs +47 -0
  52. package/dist/clerk/types.d.ts +42 -0
  53. package/dist/fuma/mdx/toc-base.js +1 -1
  54. package/dist/fuma/mdx/toc-base.mjs +1 -1
  55. package/dist/node_modules/.pnpm/@fingerprintjs_fingerprintjs@4.6.2/node_modules/@fingerprintjs/fingerprintjs/dist/fp.esm.js +3212 -0
  56. package/dist/node_modules/.pnpm/@fingerprintjs_fingerprintjs@4.6.2/node_modules/@fingerprintjs/fingerprintjs/dist/fp.esm.mjs +3187 -0
  57. 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
  58. 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
  59. package/dist/node_modules/.pnpm/cose-base@1.0.3/node_modules/cose-base/cose-base.js +1 -1
  60. package/dist/node_modules/.pnpm/cose-base@2.2.0/node_modules/cose-base/cose-base.js +1 -1
  61. package/dist/node_modules/.pnpm/layout-base@1.0.2/node_modules/layout-base/layout-base.js +1 -1
  62. package/dist/node_modules/.pnpm/layout-base@2.0.1/node_modules/layout-base/layout-base.js +1 -1
  63. package/package.json +14 -3
  64. package/src/clerk/clerk-page-generator-client.tsx +37 -0
  65. package/src/clerk/clerk-page-generator.tsx +5 -1
  66. package/src/clerk/fingerprint/fingerprint-client.ts +194 -0
  67. package/src/clerk/fingerprint/fingerprint-provider.tsx +114 -0
  68. package/src/clerk/fingerprint/fingerprint-server.ts +88 -0
  69. package/src/clerk/fingerprint/fingerprint-shared.ts +29 -0
  70. package/src/clerk/fingerprint/index.ts +15 -0
  71. package/src/clerk/fingerprint/server.ts +9 -0
  72. package/src/clerk/fingerprint/types.ts +50 -0
  73. package/src/clerk/fingerprint/use-fingerprint.ts +200 -0
  74. package/src/clerk/index.ts +9 -2
  75. package/src/clerk/server.ts +1 -0
  76. package/src/clerk/signin-with-fingerprint-client.tsx +57 -0
  77. package/src/clerk/signup-with-fingerprint-client.tsx +57 -0
@@ -17,6 +17,17 @@ PERFORMANCE OF THIS SOFTWARE.
17
17
  /* global Reflect, Promise, SuppressedError, Symbol, Iterator */
18
18
 
19
19
 
20
+ exports.__assign = function() {
21
+ exports.__assign = Object.assign || function __assign(t) {
22
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
23
+ s = arguments[i];
24
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
25
+ }
26
+ return t;
27
+ };
28
+ return exports.__assign.apply(this, arguments);
29
+ };
30
+
20
31
  function __rest(s, e) {
21
32
  var t = {};
22
33
  for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
@@ -39,10 +50,50 @@ function __awaiter(thisArg, _arguments, P, generator) {
39
50
  });
40
51
  }
41
52
 
53
+ function __generator(thisArg, body) {
54
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
55
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
56
+ function verb(n) { return function (v) { return step([n, v]); }; }
57
+ function step(op) {
58
+ if (f) throw new TypeError("Generator is already executing.");
59
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
60
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
61
+ if (y = 0, t) op = [op[0] & 2, t.value];
62
+ switch (op[0]) {
63
+ case 0: case 1: t = op; break;
64
+ case 4: _.label++; return { value: op[1], done: false };
65
+ case 5: _.label++; y = op[1]; op = [0]; continue;
66
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
67
+ default:
68
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
69
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
70
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
71
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
72
+ if (t[2]) _.ops.pop();
73
+ _.trys.pop(); continue;
74
+ }
75
+ op = body.call(thisArg, _);
76
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
77
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
78
+ }
79
+ }
80
+
81
+ function __spreadArray(to, from, pack) {
82
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
83
+ if (ar || !(i in from)) {
84
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
85
+ ar[i] = from[i];
86
+ }
87
+ }
88
+ return to.concat(ar || Array.prototype.slice.call(from));
89
+ }
90
+
42
91
  typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
43
92
  var e = new Error(message);
44
93
  return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
45
94
  };
46
95
 
47
96
  exports.__awaiter = __awaiter;
97
+ exports.__generator = __generator;
48
98
  exports.__rest = __rest;
99
+ exports.__spreadArray = __spreadArray;
@@ -15,6 +15,17 @@ PERFORMANCE OF THIS SOFTWARE.
15
15
  /* global Reflect, Promise, SuppressedError, Symbol, Iterator */
16
16
 
17
17
 
18
+ var __assign = function() {
19
+ __assign = Object.assign || function __assign(t) {
20
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
21
+ s = arguments[i];
22
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
23
+ }
24
+ return t;
25
+ };
26
+ return __assign.apply(this, arguments);
27
+ };
28
+
18
29
  function __rest(s, e) {
19
30
  var t = {};
20
31
  for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
@@ -37,9 +48,47 @@ function __awaiter(thisArg, _arguments, P, generator) {
37
48
  });
38
49
  }
39
50
 
51
+ function __generator(thisArg, body) {
52
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
53
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
54
+ function verb(n) { return function (v) { return step([n, v]); }; }
55
+ function step(op) {
56
+ if (f) throw new TypeError("Generator is already executing.");
57
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
58
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
59
+ if (y = 0, t) op = [op[0] & 2, t.value];
60
+ switch (op[0]) {
61
+ case 0: case 1: t = op; break;
62
+ case 4: _.label++; return { value: op[1], done: false };
63
+ case 5: _.label++; y = op[1]; op = [0]; continue;
64
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
65
+ default:
66
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
67
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
68
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
69
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
70
+ if (t[2]) _.ops.pop();
71
+ _.trys.pop(); continue;
72
+ }
73
+ op = body.call(thisArg, _);
74
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
75
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
76
+ }
77
+ }
78
+
79
+ function __spreadArray(to, from, pack) {
80
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
81
+ if (ar || !(i in from)) {
82
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
83
+ ar[i] = from[i];
84
+ }
85
+ }
86
+ return to.concat(ar || Array.prototype.slice.call(from));
87
+ }
88
+
40
89
  typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
41
90
  var e = new Error(message);
42
91
  return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
43
92
  };
44
93
 
45
- export { __awaiter, __rest };
94
+ export { __assign, __awaiter, __generator, __rest, __spreadArray };
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var coseBase$1 = require('../../../../../_virtual/cose-base2.js');
3
+ var coseBase$1 = require('../../../../../_virtual/cose-base.js');
4
4
  var layoutBase = require('../../../layout-base@1.0.2/node_modules/layout-base/layout-base.js');
5
5
 
6
6
  var coseBase = coseBase$1.__module.exports;
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var coseBase$1 = require('../../../../../_virtual/cose-base.js');
3
+ var coseBase$1 = require('../../../../../_virtual/cose-base2.js');
4
4
  var layoutBase = require('../../../layout-base@2.0.1/node_modules/layout-base/layout-base.js');
5
5
 
6
6
  var coseBase = coseBase$1.__module.exports;
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var layoutBase$1 = require('../../../../../_virtual/layout-base2.js');
3
+ var layoutBase$1 = require('../../../../../_virtual/layout-base.js');
4
4
 
5
5
  var layoutBase = layoutBase$1.__module.exports;
6
6
 
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var layoutBase$1 = require('../../../../../_virtual/layout-base.js');
3
+ var layoutBase$1 = require('../../../../../_virtual/layout-base2.js');
4
4
 
5
5
  var layoutBase = layoutBase$1.__module.exports;
6
6
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@windrun-huaiin/third-ui",
3
- "version": "7.1.2",
3
+ "version": "7.2.1",
4
4
  "description": "Third-party integrated UI components for windrun-huaiin projects",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -16,6 +16,16 @@
16
16
  "import": "./dist/clerk/server.mjs",
17
17
  "require": "./dist/clerk/server.js"
18
18
  },
19
+ "./fingerprint": {
20
+ "types": "./dist/clerk/fingerprint/index.d.ts",
21
+ "import": "./dist/clerk/fingerprint/index.mjs",
22
+ "require": "./dist/clerk/fingerprint/index.js"
23
+ },
24
+ "./fingerprint/server": {
25
+ "types": "./dist/clerk/fingerprint/server.d.ts",
26
+ "import": "./dist/clerk/fingerprint/server.mjs",
27
+ "require": "./dist/clerk/fingerprint/server.js"
28
+ },
19
29
  "./main": {
20
30
  "types": "./dist/main/index.d.ts",
21
31
  "import": "./dist/main/index.mjs",
@@ -55,6 +65,7 @@
55
65
  "@clerk/localizations": "^3.16.0",
56
66
  "@clerk/types": "^4.59.0",
57
67
  "@clerk/nextjs": "^6.19.4",
68
+ "@fingerprintjs/fingerprintjs": "^4.5.1",
58
69
  "fumadocs-core": "15.3.3",
59
70
  "fumadocs-mdx": "11.6.3",
60
71
  "fumadocs-typescript": "4.0.4",
@@ -64,8 +75,8 @@
64
75
  "mermaid": "^11.6.0",
65
76
  "react-medium-image-zoom": "^5.2.14",
66
77
  "zod": "^3.22.4",
67
- "@windrun-huaiin/base-ui": "^8.1.1",
68
- "@windrun-huaiin/lib": "^7.1.1"
78
+ "@windrun-huaiin/lib": "^7.1.1",
79
+ "@windrun-huaiin/base-ui": "^8.1.1"
69
80
  },
70
81
  "peerDependencies": {
71
82
  "react": "19.1.0",
@@ -0,0 +1,37 @@
1
+ 'use client';
2
+
3
+ /**
4
+ * Client-side page generators with fingerprint support
5
+ * These should only be used in client-side code
6
+ */
7
+
8
+ import { SignUpWithFingerprint } from './signup-with-fingerprint-client';
9
+ import { SignInWithFingerprint } from './signin-with-fingerprint-client';
10
+
11
+ /**
12
+ * Create a SignUp page with fingerprint support
13
+ * Note: This must be used within a FingerprintProvider
14
+ */
15
+ export function createSignUpPageWithFingerprint() {
16
+ return function SignUpPage() {
17
+ return (
18
+ <div className="flex-1 flex justify-center mt-0 mb-32">
19
+ <SignUpWithFingerprint />
20
+ </div>
21
+ );
22
+ };
23
+ }
24
+
25
+ /**
26
+ * Create a SignIn page with fingerprint support
27
+ * Note: This must be used within a FingerprintProvider
28
+ */
29
+ export function createSignInPageWithFingerprint() {
30
+ return function SignInPage() {
31
+ return (
32
+ <div className="flex-1 flex justify-center mb-64">
33
+ <SignInWithFingerprint />
34
+ </div>
35
+ );
36
+ };
37
+ }
@@ -9,6 +9,7 @@
9
9
 
10
10
  import { SignIn, SignUp, Waitlist } from '@clerk/nextjs';
11
11
 
12
+ // Legacy page generators (for backward compatibility)
12
13
  export function createSignInPage() {
13
14
  return function SignInPage() {
14
15
  return (
@@ -37,4 +38,7 @@ export function createWaitlistPage() {
37
38
  </div>
38
39
  );
39
40
  };
40
- }
41
+ }
42
+
43
+ // Note: Fingerprint-aware page generators moved to client-side only
44
+ // Use the fingerprint components directly in your client-side code
@@ -0,0 +1,194 @@
1
+ /**
2
+ * Fingerprint Client Utilities
3
+ * 客户端专用的指纹生成和管理逻辑
4
+ * 只能在浏览器环境中使用
5
+ */
6
+
7
+ import {
8
+ FINGERPRINT_STORAGE_KEY,
9
+ FINGERPRINT_COOKIE_NAME,
10
+ isValidFingerprintId
11
+ } from './fingerprint-shared';
12
+ import FingerprintJS from '@fingerprintjs/fingerprintjs';
13
+
14
+ /**
15
+ * 生成基于真实浏览器特征的fingerprint ID
16
+ * 使用FingerprintJS收集浏览器特征并生成唯一标识
17
+ * 只能在客户端使用
18
+ */
19
+ export async function generateFingerprintId(): Promise<string> {
20
+ if (typeof window === 'undefined') {
21
+ throw new Error('generateFingerprintId can only be used in browser environment');
22
+ }
23
+
24
+ // 首先检查现有ID
25
+ const existingId = getFingerprintId();
26
+ if (existingId && isValidFingerprintId(existingId)) {
27
+ return existingId;
28
+ }
29
+
30
+ // 检查cookie
31
+ const cookieId = getCookieValue(FINGERPRINT_COOKIE_NAME);
32
+ if (cookieId && isValidFingerprintId(cookieId)) {
33
+ // 同步到localStorage
34
+ localStorage.setItem(FINGERPRINT_STORAGE_KEY, cookieId);
35
+ return cookieId;
36
+ }
37
+
38
+ try {
39
+ // 使用FingerprintJS生成基于浏览器特征的指纹
40
+ const fp = await FingerprintJS.load();
41
+ const result = await fp.get();
42
+ const fingerprintId = `fp_${result.visitorId}`;
43
+
44
+ // 存储到localStorage和cookie
45
+ localStorage.setItem(FINGERPRINT_STORAGE_KEY, fingerprintId);
46
+ setCookie(FINGERPRINT_COOKIE_NAME, fingerprintId, 365); // 365天过期
47
+
48
+ return fingerprintId;
49
+ } catch (error) {
50
+ console.warn('Failed to generate fingerprint with FingerprintJS:', error);
51
+ // 降级方案:生成时间戳+随机数
52
+ const fallbackId = `fp_fallback_${Date.now()}_${Math.random().toString(36).slice(2, 11)}`;
53
+
54
+ localStorage.setItem(FINGERPRINT_STORAGE_KEY, fallbackId);
55
+ setCookie(FINGERPRINT_COOKIE_NAME, fallbackId, 365);
56
+
57
+ return fallbackId;
58
+ }
59
+ }
60
+
61
+ /**
62
+ * 获取当前的fingerprint ID
63
+ * 只能在客户端使用
64
+ */
65
+ export function getFingerprintId(): string | null {
66
+ if (typeof window === 'undefined') {
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;
85
+ }
86
+
87
+ /**
88
+ * 设置fingerprint ID到存储
89
+ * 只能在客户端使用
90
+ */
91
+ export function setFingerprintId(fingerprintId: string): void {
92
+ if (typeof window === 'undefined') {
93
+ throw new Error('setFingerprintId can only be used in browser environment');
94
+ }
95
+
96
+ localStorage.setItem(FINGERPRINT_STORAGE_KEY, fingerprintId);
97
+ setCookie(FINGERPRINT_COOKIE_NAME, fingerprintId, 365);
98
+ }
99
+
100
+ /**
101
+ * 清除fingerprint ID
102
+ * 只能在客户端使用
103
+ */
104
+ export function clearFingerprintId(): void {
105
+ if (typeof window === 'undefined') {
106
+ throw new Error('clearFingerprintId can only be used in browser environment');
107
+ }
108
+
109
+ localStorage.removeItem(FINGERPRINT_STORAGE_KEY);
110
+ deleteCookie(FINGERPRINT_COOKIE_NAME);
111
+ }
112
+
113
+ /**
114
+ * 获取或生成fingerprint ID
115
+ * 如果不存在则自动生成新的
116
+ * 只能在客户端使用
117
+ */
118
+ export async function getOrGenerateFingerprintId(): Promise<string> {
119
+ const existingId = getFingerprintId();
120
+ if (existingId) {
121
+ return existingId;
122
+ }
123
+ return await generateFingerprintId();
124
+ }
125
+
126
+ /**
127
+ * 创建包含fingerprint ID的fetch headers
128
+ * 只能在客户端使用
129
+ */
130
+ export async function createFingerprintHeaders(): Promise<Record<string, string>> {
131
+ const fingerprintId = await getOrGenerateFingerprintId();
132
+ return {
133
+ FINGERPRINT_HEADER_NAME : fingerprintId,
134
+ };
135
+ }
136
+
137
+ /**
138
+ * Hook for generating fingerprint headers
139
+ * 只能在客户端使用
140
+ */
141
+ export function useFingerprintHeaders(): () => Promise<Record<string, string>> {
142
+ return createFingerprintHeaders;
143
+ }
144
+
145
+ /**
146
+ * Create a fetch wrapper that automatically includes fingerprint headers
147
+ * 只能在客户端使用
148
+ */
149
+ export function createFingerprintFetch() {
150
+ return async (url: string | URL | Request, init?: RequestInit) => {
151
+ const fingerprintHeaders = await createFingerprintHeaders();
152
+ const headers = {
153
+ ...fingerprintHeaders,
154
+ ...(init?.headers || {}),
155
+ };
156
+
157
+ return fetch(url, {
158
+ ...init,
159
+ headers,
160
+ });
161
+ };
162
+ }
163
+
164
+ // Cookie 辅助函数 (私有)
165
+ function getCookieValue(name: string): string | null {
166
+ if (typeof document === 'undefined') {
167
+ return null;
168
+ }
169
+
170
+ const value = `; ${document.cookie}`;
171
+ const parts = value.split(`; ${name}=`);
172
+ if (parts.length === 2) {
173
+ return parts.pop()?.split(';').shift() || null;
174
+ }
175
+ return null;
176
+ }
177
+
178
+ function setCookie(name: string, value: string, days: number): void {
179
+ if (typeof document === 'undefined') {
180
+ return;
181
+ }
182
+
183
+ const expires = new Date();
184
+ expires.setTime(expires.getTime() + days * 24 * 60 * 60 * 1000);
185
+ document.cookie = `${name}=${value};expires=${expires.toUTCString()};path=/;SameSite=Lax`;
186
+ }
187
+
188
+ function deleteCookie(name: string): void {
189
+ if (typeof document === 'undefined') {
190
+ return;
191
+ }
192
+
193
+ document.cookie = `${name}=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/`;
194
+ }
@@ -0,0 +1,114 @@
1
+ 'use client';
2
+
3
+ import React, { createContext, useContext } from 'react';
4
+ import { useFingerprint } from './use-fingerprint';
5
+ import type {
6
+ FingerprintContextType,
7
+ FingerprintProviderProps
8
+ } from './types';
9
+
10
+ const FingerprintContext = createContext<FingerprintContextType | undefined>(undefined);
11
+
12
+ /**
13
+ * Fingerprint Provider Component
14
+ * 为应用提供fingerprint和匿名用户管理功能
15
+ */
16
+ export function FingerprintProvider({
17
+ children,
18
+ config
19
+ }: FingerprintProviderProps) {
20
+ const fingerprintData = useFingerprint(config);
21
+
22
+ return (
23
+ <FingerprintContext.Provider value={fingerprintData}>
24
+ {children}
25
+ </FingerprintContext.Provider>
26
+ );
27
+ }
28
+
29
+ /**
30
+ * Hook to use fingerprint context
31
+ */
32
+ export function useFingerprintContext(): FingerprintContextType {
33
+ const context = useContext(FingerprintContext);
34
+ if (context === undefined) {
35
+ throw new Error('useFingerprintContext must be used within a FingerprintProvider');
36
+ }
37
+ return context;
38
+ }
39
+
40
+ /**
41
+ * Safe hook to use fingerprint context - returns null if no provider
42
+ * 安全版本的fingerprint context hook - 如果没有Provider则返回null
43
+ */
44
+ export function useFingerprintContextSafe(): FingerprintContextType | null {
45
+ const context = useContext(FingerprintContext);
46
+ return context || null;
47
+ }
48
+
49
+ /**
50
+ * HOC for components that need fingerprint functionality
51
+ * Note: This HOC now requires config to be passed externally
52
+ */
53
+ export function withFingerprint<P extends object>(
54
+ Component: React.ComponentType<P>,
55
+ config: FingerprintProviderProps['config']
56
+ ) {
57
+ return function FingerprintWrappedComponent(props: P) {
58
+ return (
59
+ <FingerprintProvider config={config}>
60
+ <Component {...props} />
61
+ </FingerprintProvider>
62
+ );
63
+ };
64
+ }
65
+
66
+ /**
67
+ * 组件:显示用户状态和积分信息(用于调试)
68
+ */
69
+ export function FingerprintDebugInfo() {
70
+ const {
71
+ fingerprintId,
72
+ anonymousUser,
73
+ credits,
74
+ isLoading,
75
+ isInitialized,
76
+ error
77
+ } = useFingerprintContext();
78
+
79
+ if (!process.env.NODE_ENV || process.env.NODE_ENV === 'production') {
80
+ return null;
81
+ }
82
+
83
+ return (
84
+ <div style={{
85
+ position: 'fixed',
86
+ bottom: '10px',
87
+ right: '10px',
88
+ background: '#f0f0f0',
89
+ padding: '10px',
90
+ borderRadius: '5px',
91
+ fontSize: '12px',
92
+ fontFamily: 'monospace',
93
+ maxWidth: '300px',
94
+ zIndex: 9999,
95
+ border: '1px solid #ccc'
96
+ }}>
97
+ <h4 style={{ margin: '0 0 5px 0' }}>Fingerprint Debug</h4>
98
+ <div><strong>FP ID:</strong> {fingerprintId || 'None'}</div>
99
+ <div><strong>Loading:</strong> {isLoading ? 'Yes' : 'No'}</div>
100
+ <div><strong>Initialized:</strong> {isInitialized ? 'Yes' : 'No'}</div>
101
+ {error && <div style={{ color: 'red' }}><strong>Error:</strong> {error}</div>}
102
+ {anonymousUser && (
103
+ <div>
104
+ <strong>User ID:</strong> {anonymousUser.userId.slice(0, 8)}...
105
+ </div>
106
+ )}
107
+ {credits && (
108
+ <div>
109
+ <strong>Credits:</strong> {credits.balanceFree}F + {credits.balancePaid}P = {credits.totalBalance}
110
+ </div>
111
+ )}
112
+ </div>
113
+ );
114
+ }
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Fingerprint Server Utilities
3
+ * 服务端专用的指纹ID提取和验证逻辑
4
+ * 可以安全地在服务端使用,不依赖浏览器API或FingerprintJS
5
+ */
6
+
7
+ import {
8
+ FINGERPRINT_HEADER_NAME,
9
+ FINGERPRINT_COOKIE_NAME,
10
+ isValidFingerprintId
11
+ } from './fingerprint-shared';
12
+
13
+ /**
14
+ * 从请求中提取fingerprint ID
15
+ * 优先级:header > cookie > query参数
16
+ * 可以安全地在服务端使用
17
+ */
18
+ export function extractFingerprintId(
19
+ headers: Headers | Record<string, string>,
20
+ cookies?: Record<string, string>,
21
+ query?: Record<string, string | undefined>
22
+ ): string | null {
23
+ // 1. 从header中获取
24
+ const headerValue = headers instanceof Headers
25
+ ? headers.get(FINGERPRINT_HEADER_NAME)
26
+ : headers[FINGERPRINT_HEADER_NAME];
27
+
28
+ if (headerValue && isValidFingerprintId(headerValue)) {
29
+ return headerValue;
30
+ }
31
+
32
+ // 2. 从cookie中获取
33
+ if (cookies) {
34
+ const cookieValue = cookies[FINGERPRINT_COOKIE_NAME];
35
+ if (cookieValue && isValidFingerprintId(cookieValue)) {
36
+ return cookieValue;
37
+ }
38
+ }
39
+
40
+ // 3. 从query参数中获取
41
+ if (query) {
42
+ const queryValue = query.fingerprint_id || query.fp_id;
43
+ if (queryValue && isValidFingerprintId(queryValue)) {
44
+ return queryValue;
45
+ }
46
+ }
47
+
48
+ return null;
49
+ }
50
+
51
+ /**
52
+ * 生成服务端降级fingerprint ID
53
+ * 当客户端无法生成fingerprint时使用
54
+ * 可以安全地在服务端使用
55
+ */
56
+ export function generateServerFingerprintId(): string {
57
+ return `fp_server_${Date.now()}_${Math.random().toString(36).slice(2, 11)}`;
58
+ }
59
+
60
+ /**
61
+ * 从Next.js Request对象中提取fingerprint ID
62
+ * 便捷方法,适用于Next.js API路由
63
+ */
64
+ export function extractFingerprintFromNextRequest(request: Request): string | null {
65
+ const headers = request.headers;
66
+
67
+ // 尝试从cookies获取(需要解析cookie header)
68
+ const cookieHeader = headers.get('cookie');
69
+ const cookies: Record<string, string> = {};
70
+
71
+ if (cookieHeader) {
72
+ cookieHeader.split(';').forEach(cookie => {
73
+ const [name, value] = cookie.trim().split('=');
74
+ if (name && value) {
75
+ cookies[name] = value;
76
+ }
77
+ });
78
+ }
79
+
80
+ // 尝试从URL query参数获取
81
+ const url = new URL(request.url);
82
+ const query: Record<string, string> = {};
83
+ url.searchParams.forEach((value, key) => {
84
+ query[key] = value;
85
+ });
86
+
87
+ return extractFingerprintId(headers, cookies, query);
88
+ }