@windrun-huaiin/third-ui 20.0.0 → 21.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/LICENSE +1 -1
  2. package/dist/clerk/clerk-page-generator.d.ts +0 -8
  3. package/dist/clerk/fingerprint/fingerprint-provider.js +58 -49
  4. package/dist/clerk/fingerprint/fingerprint-provider.mjs +58 -49
  5. package/dist/fuma/fuma-page-genarator.d.ts +2 -2
  6. package/dist/fuma/fuma-page-genarator.js +21 -8
  7. package/dist/fuma/fuma-page-genarator.mjs +21 -8
  8. package/dist/fuma/llm-copy-handler.js +3 -2
  9. package/dist/fuma/llm-copy-handler.mjs +3 -2
  10. package/dist/fuma/mdx/index.d.ts +1 -0
  11. package/dist/fuma/mdx/index.js +3 -0
  12. package/dist/fuma/mdx/index.mjs +1 -0
  13. package/dist/fuma/mdx/math.d.ts +17 -0
  14. package/dist/fuma/mdx/math.js +60 -0
  15. package/dist/fuma/mdx/math.mjs +57 -0
  16. package/dist/fuma/mdx/zia-card.js +1 -1
  17. package/dist/fuma/mdx/zia-card.mjs +1 -1
  18. package/dist/main/{ads-alert-dialog.d.ts → alert-dialog/ads-alert-dialog.d.ts} +1 -1
  19. package/dist/main/alert-dialog/ads-alert-dialog.js +24 -0
  20. package/dist/main/alert-dialog/ads-alert-dialog.mjs +22 -0
  21. package/dist/main/alert-dialog/confirm-dialog.d.ts +15 -0
  22. package/dist/main/alert-dialog/confirm-dialog.js +40 -0
  23. package/dist/main/alert-dialog/confirm-dialog.mjs +38 -0
  24. package/dist/main/alert-dialog/dialog-styles.d.ts +14 -0
  25. package/dist/main/alert-dialog/dialog-styles.js +35 -0
  26. package/dist/main/alert-dialog/dialog-styles.mjs +20 -0
  27. package/dist/main/alert-dialog/high-priority-confirm-dialog.d.ts +12 -0
  28. package/dist/main/alert-dialog/high-priority-confirm-dialog.js +23 -0
  29. package/dist/main/alert-dialog/high-priority-confirm-dialog.mjs +21 -0
  30. package/dist/main/alert-dialog/index.d.ts +4 -0
  31. package/dist/main/alert-dialog/info-dialog.d.ts +13 -0
  32. package/dist/main/alert-dialog/info-dialog.js +50 -0
  33. package/dist/main/alert-dialog/info-dialog.mjs +48 -0
  34. package/dist/main/index.d.ts +1 -1
  35. package/dist/main/index.js +7 -1
  36. package/dist/main/index.mjs +4 -1
  37. package/package.json +4 -4
  38. package/src/clerk/clerk-page-generator.tsx +0 -9
  39. package/src/clerk/fingerprint/fingerprint-provider.tsx +155 -62
  40. package/src/fuma/fuma-page-genarator.tsx +26 -9
  41. package/src/fuma/llm-copy-handler.ts +3 -3
  42. package/src/fuma/mdx/index.ts +1 -0
  43. package/src/fuma/mdx/math.tsx +130 -0
  44. package/src/fuma/mdx/zia-card.tsx +1 -0
  45. package/src/main/{ads-alert-dialog.tsx → alert-dialog/ads-alert-dialog.tsx} +46 -29
  46. package/src/main/alert-dialog/confirm-dialog.tsx +131 -0
  47. package/src/main/alert-dialog/dialog-styles.ts +73 -0
  48. package/src/main/alert-dialog/high-priority-confirm-dialog.tsx +94 -0
  49. package/src/main/alert-dialog/index.ts +7 -0
  50. package/src/main/alert-dialog/info-dialog.tsx +139 -0
  51. package/src/main/index.ts +1 -1
  52. package/src/main/language-detector.tsx +0 -8
  53. package/dist/main/ads-alert-dialog.js +0 -21
  54. package/dist/main/ads-alert-dialog.mjs +0 -19
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2026 D8ger
3
+ Copyright (c) 2025 D8ger
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -1,11 +1,3 @@
1
- /**
2
- * @license
3
- * MIT License
4
- * Copyright (c) 2026 D8ger
5
- *
6
- * This source code is licensed under the MIT license found in the
7
- * LICENSE file in the root directory of this source tree.
8
- */
9
1
  export declare function createSignInPage(): () => import("react/jsx-runtime").JSX.Element;
10
2
  export declare function createSignUpPage(): () => import("react/jsx-runtime").JSX.Element;
11
3
  export declare function createWaitlistPage(): () => import("react/jsx-runtime").JSX.Element;
@@ -6,6 +6,7 @@ var jsxRuntime = require('react/jsx-runtime');
6
6
  var icons = require('@windrun-huaiin/base-ui/icons');
7
7
  var lib = require('@windrun-huaiin/base-ui/lib');
8
8
  var utils = require('@windrun-huaiin/lib/utils');
9
+ var nextIntl = require('next-intl');
9
10
  var React = require('react');
10
11
  var useFingerprint = require('./use-fingerprint.js');
11
12
  var ui = require('@windrun-huaiin/base-ui/ui');
@@ -14,6 +15,10 @@ var fingerprintDebug = require('./fingerprint-debug.js');
14
15
  var fingerprintShared = require('./fingerprint-shared.js');
15
16
 
16
17
  const FingerprintContext = React.createContext(undefined);
18
+ function useFingerprintStatusTranslations() {
19
+ const messages = nextIntl.useMessages();
20
+ return messages.fingerprint;
21
+ }
17
22
  /**
18
23
  * Fingerprint Provider Component
19
24
  * 为应用提供fingerprint和匿名用户管理功能
@@ -53,6 +58,7 @@ function withFingerprint(Component, config) {
53
58
  * 组件:显示用户状态和积分信息(用于调试)
54
59
  */
55
60
  function FingerprintStatus() {
61
+ const translations = useFingerprintStatusTranslations();
56
62
  const { fingerprintId, xUser, xCredit, xSubscription, error, clearError, } = useFingerprintContext();
57
63
  const [isOpen, setIsOpen] = React.useState(false);
58
64
  const [panelMode, setPanelMode] = React.useState('info');
@@ -92,7 +98,7 @@ function FingerprintStatus() {
92
98
  return [
93
99
  {
94
100
  key: 'paid',
95
- label: 'Paid',
101
+ label: translations.creditBuckets.paid,
96
102
  icon: jsxRuntime.jsx(icons.Settings2Icon, { className: "size-4 text-green-500 dark:text-green-300" }),
97
103
  balance: xCredit.balancePaid,
98
104
  total: xCredit.totalPaidLimit,
@@ -101,7 +107,7 @@ function FingerprintStatus() {
101
107
  },
102
108
  {
103
109
  key: 'oneTimePaid',
104
- label: 'OneTimePaid',
110
+ label: translations.creditBuckets.oneTimePaid,
105
111
  icon: jsxRuntime.jsx(icons.CoinsIcon, { className: "size-4 text-amber-500 dark:text-amber-300" }),
106
112
  balance: xCredit.balanceOneTimePaid,
107
113
  total: xCredit.totalOneTimePaidLimit,
@@ -110,7 +116,7 @@ function FingerprintStatus() {
110
116
  },
111
117
  {
112
118
  key: 'free',
113
- label: 'Free',
119
+ label: translations.creditBuckets.free,
114
120
  icon: jsxRuntime.jsx(icons.GiftIcon, { className: "size-4 text-purple-500 dark:text-purple-300" }),
115
121
  balance: xCredit.balanceFree,
116
122
  total: xCredit.totalFreeLimit,
@@ -118,15 +124,15 @@ function FingerprintStatus() {
118
124
  end: xCredit.freeEnd,
119
125
  },
120
126
  ];
121
- }, [xCredit]);
127
+ }, [translations.creditBuckets.free, translations.creditBuckets.oneTimePaid, translations.creditBuckets.paid, xCredit]);
122
128
  const subscriptionStatus = React.useMemo(() => {
123
129
  var _a, _b;
124
130
  if (!xSubscription) {
125
131
  return {
126
- status: 'Never',
132
+ status: translations.placeholders.subscriptionStatusNever,
127
133
  priceName: '--',
128
134
  creditsAllocated: '--',
129
- period: 'Unavailable',
135
+ period: translations.placeholders.subscriptionPeriodUnavailable,
130
136
  };
131
137
  }
132
138
  return {
@@ -135,9 +141,9 @@ function FingerprintStatus() {
135
141
  creditsAllocated: typeof xSubscription.creditsAllocated === 'number'
136
142
  ? formatNumber(xSubscription.creditsAllocated)
137
143
  : '--',
138
- period: formatRangeText(xSubscription.subPeriodStart, xSubscription.subPeriodEnd),
144
+ period: formatRangeText(xSubscription.subPeriodStart, xSubscription.subPeriodEnd, translations),
139
145
  };
140
- }, [xSubscription]);
146
+ }, [translations.placeholders.subscriptionPeriodUnavailable, translations.placeholders.subscriptionStatusNever, xSubscription]);
141
147
  const userStatus = (xUser === null || xUser === void 0 ? void 0 : xUser.status) || '--';
142
148
  const totalCredits = formatNumber(xCredit === null || xCredit === void 0 ? void 0 : xCredit.totalBalance);
143
149
  const subStatus = subscriptionStatus.status;
@@ -145,22 +151,22 @@ function FingerprintStatus() {
145
151
  const runContextParallelInitTest = () => tslib.__awaiter(this, void 0, void 0, function* () {
146
152
  const debugFingerprintId = activeDebugFingerprintId !== null && activeDebugFingerprintId !== void 0 ? activeDebugFingerprintId : fingerprintDebug.getOrCreateDebugFingerprintOverride();
147
153
  if (!debugFingerprintId) {
148
- setTestResult('Test fingerprint override is not ready yet.');
154
+ setTestResult(translations.messages.testFingerprintNotReady);
149
155
  return;
150
156
  }
151
157
  setActiveDebugFingerprintId(debugFingerprintId);
152
158
  setIsRunningTest(true);
153
- setTestResult(`Running Frontend Prevention Test with fingerprint: ${debugFingerprintId}`);
159
+ setTestResult(tpl(translations.messages.runningFrontendPreventionTest, { fingerprintId: debugFingerprintId }));
154
160
  try {
155
161
  yield Promise.all([
156
162
  initializeDebugAnonymousUser(debugFingerprintId),
157
163
  initializeDebugAnonymousUser(debugFingerprintId),
158
164
  initializeDebugAnonymousUser(debugFingerprintId),
159
165
  ]);
160
- setTestResult(`Frontend Prevention Test finished. Active test fingerprint: ${debugFingerprintId}`);
166
+ setTestResult(tpl(translations.messages.frontendPreventionTestFinished, { fingerprintId: debugFingerprintId }));
161
167
  }
162
168
  catch (testError) {
163
- setTestResult(`Frontend Prevention Test failed: ${formatErrorMessage(testError)}`);
169
+ setTestResult(tpl(translations.messages.frontendPreventionTestFailed, { error: formatErrorMessage(testError, translations) }));
164
170
  }
165
171
  finally {
166
172
  setIsRunningTest(false);
@@ -180,7 +186,7 @@ function FingerprintStatus() {
180
186
  });
181
187
  if (!response.ok) {
182
188
  const errorData = yield response.json().catch(() => ({}));
183
- throw new Error(errorData.error || 'Failed to initialize anonymous user');
189
+ throw new Error(errorData.error || translations.messages.failedToInitializeAnonymousUser);
184
190
  }
185
191
  yield response.json().catch(() => ({}));
186
192
  }
@@ -191,12 +197,12 @@ function FingerprintStatus() {
191
197
  const runRawParallelPostTest = () => tslib.__awaiter(this, void 0, void 0, function* () {
192
198
  const normalizedFingerprintId = activeDebugFingerprintId !== null && activeDebugFingerprintId !== void 0 ? activeDebugFingerprintId : fingerprintDebug.getOrCreateDebugFingerprintOverride();
193
199
  if (!normalizedFingerprintId) {
194
- setTestResult('Test fingerprint override is not ready yet.');
200
+ setTestResult(translations.messages.testFingerprintNotReady);
195
201
  return;
196
202
  }
197
203
  setActiveDebugFingerprintId(normalizedFingerprintId);
198
204
  setIsRunningTest(true);
199
- setTestResult(`Running Backend Idempotency Test with fingerprint: ${normalizedFingerprintId}`);
205
+ setTestResult(tpl(translations.messages.runningBackendIdempotencyTest, { fingerprintId: normalizedFingerprintId }));
200
206
  try {
201
207
  const fingerprintHeaders = yield fingerprintClient.createFingerprintHeaders();
202
208
  const requests = Array.from({ length: 3 }, () => fetch('/api/user/anonymous/init', {
@@ -227,16 +233,16 @@ function FingerprintStatus() {
227
233
  .filter((payload) => !payload.ok)
228
234
  .map((payload) => `${payload.status}${payload.error ? `:${payload.error}` : ''}`);
229
235
  setTestResult([
230
- `Backend Idempotency Test done.`,
231
- `created=${createdUserIds.length}`,
232
- `reused=${reusedUserIds.length}`,
233
- `failed=${failedStatuses.length}`,
234
- `createdUserIds=[${createdUserIds.join(', ')}]`,
235
- failedStatuses.length > 0 ? `failedStatuses=[${failedStatuses.join(', ')}]` : null,
236
+ translations.messages.backendIdempotencyTestDone,
237
+ tpl(translations.messages.createdCount, { count: createdUserIds.length }),
238
+ tpl(translations.messages.reusedCount, { count: reusedUserIds.length }),
239
+ tpl(translations.messages.failedCount, { count: failedStatuses.length }),
240
+ tpl(translations.messages.createdUserIds, { value: createdUserIds.join(', ') }),
241
+ failedStatuses.length > 0 ? tpl(translations.messages.failedStatuses, { value: failedStatuses.join(', ') }) : null,
236
242
  ].filter(Boolean).join('\n'));
237
243
  }
238
244
  catch (testError) {
239
- setTestResult(`Backend Idempotency Test failed: ${formatErrorMessage(testError)}`);
245
+ setTestResult(tpl(translations.messages.backendIdempotencyTestFailed, { error: formatErrorMessage(testError, translations) }));
240
246
  }
241
247
  finally {
242
248
  setIsRunningTest(false);
@@ -245,31 +251,31 @@ function FingerprintStatus() {
245
251
  const regenerateTestFingerprint = () => {
246
252
  const nextFingerprintId = fingerprintDebug.regenerateDebugFingerprintOverride();
247
253
  setActiveDebugFingerprintId(nextFingerprintId);
248
- setTestResult(`Generated test fingerprint override: ${nextFingerprintId}`);
254
+ setTestResult(tpl(translations.messages.generatedTestFingerprintOverride, { fingerprintId: nextFingerprintId }));
249
255
  };
250
- return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [!isOpen && (jsxRuntime.jsx("button", { onClick: handleToggle, type: "button", "aria-label": "Fingerprint debug panel", className: utils.cn('fixed left-2 top-2 md:left-2 md:top-3 z-10000 inline-flex size-8 md:size-11 items-center justify-center rounded-full', lib.themeButtonGradientClass, lib.themeButtonGradientHoverClass, 'text-white rounded-full shadow-lg hover:shadow-xl transition-all duration-300'), children: jsxRuntime.jsx(icons.LightbulbIcon, { className: "size-6 text-white" }) })), isOpen && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { onClick: handleBackdropClick, className: "fixed inset-0 z-9998 bg-black/60 backdrop-blur-sm" }), jsxRuntime.jsxs("div", { ref: modalRef, className: utils.cn('fixed inset-3 z-9999 mx-auto w-[min(95vw,520px)] overflow-y-auto rounded-2xl border', 'border-slate-200/70 bg-white/95 p-4 shadow-2xl backdrop-blur-sm', 'font-sans text-sm text-slate-700 dark:border-white/12 dark:bg-slate-950/95 dark:text-slate-200', 'sm:inset-auto md:left-2 sm:top-1 md:right-auto sm:w-[min(520px,95vw)] sm:p-5'), children: [jsxRuntime.jsx("header", { className: "mb-4", children: jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-3", children: [jsxRuntime.jsxs("div", { className: utils.cn("flex items-center gap-2 text-base font-bold tracking-wider", lib.themeIconColor), children: [jsxRuntime.jsx(icons.ShieldUserIcon, { className: "size-4" }), "Fingerprint Debug Panel"] }), jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [jsxRuntime.jsxs("button", { type: "button", onClick: () => setPanelMode((prev) => prev === 'info' ? 'test' : 'info'), className: utils.cn('inline-flex items-center gap-2 rounded-full border px-2 py-1 text-[11px] font-semibold shadow-sm transition-all duration-200', panelMode === 'test'
256
+ return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [!isOpen && (jsxRuntime.jsx("button", { onClick: handleToggle, type: "button", "aria-label": translations.panel.toggleAriaLabel, className: utils.cn('fixed left-2 top-2 md:left-2 md:top-3 z-10000 inline-flex size-8 md:size-11 items-center justify-center rounded-full', lib.themeButtonGradientClass, lib.themeButtonGradientHoverClass, 'text-white rounded-full shadow-lg hover:shadow-xl transition-all duration-300'), children: jsxRuntime.jsx(icons.LightbulbIcon, { className: "size-6 text-white" }) })), isOpen && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { onClick: handleBackdropClick, className: "fixed inset-0 z-9998 bg-black/60 backdrop-blur-sm" }), jsxRuntime.jsxs("div", { ref: modalRef, className: utils.cn('fixed inset-3 z-9999 mx-auto w-[min(95vw,520px)] overflow-y-auto rounded-2xl border', 'border-slate-200/70 bg-white/95 p-4 shadow-2xl backdrop-blur-sm', 'font-sans text-sm text-slate-700 dark:border-white/12 dark:bg-slate-950/95 dark:text-slate-200', 'sm:inset-auto md:left-2 sm:top-1 md:right-auto sm:w-[min(520px,95vw)] sm:p-5'), children: [jsxRuntime.jsx("header", { className: "mb-4", children: jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-3", children: [jsxRuntime.jsxs("div", { className: utils.cn("flex items-center gap-2 text-base font-bold tracking-wider", lib.themeIconColor), children: [jsxRuntime.jsx(icons.ShieldUserIcon, { className: "size-4" }), translations.panel.title] }), jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [jsxRuntime.jsxs("button", { type: "button", onClick: () => setPanelMode((prev) => prev === 'info' ? 'test' : 'info'), className: utils.cn('inline-flex items-center gap-2 rounded-full border px-2 py-1 text-[11px] font-semibold shadow-sm transition-all duration-200', panelMode === 'test'
251
257
  ? utils.cn('border-transparent text-white', lib.themeButtonGradientClass, lib.themeButtonGradientHoverClass)
252
- : themedGhostButtonClass), "aria-pressed": panelMode === 'test', children: [jsxRuntime.jsx("span", { children: "Concurrent Test" }), jsxRuntime.jsx("span", { className: utils.cn('relative inline-flex h-5 w-9 items-center rounded-full transition-colors', panelMode === 'test'
258
+ : themedGhostButtonClass), "aria-pressed": panelMode === 'test', children: [jsxRuntime.jsx("span", { children: translations.panel.testModeLabel }), jsxRuntime.jsx("span", { className: utils.cn('relative inline-flex h-5 w-9 items-center rounded-full transition-colors', panelMode === 'test'
253
259
  ? 'bg-white/25'
254
- : 'bg-slate-300 dark:bg-slate-700'), children: jsxRuntime.jsx("span", { className: utils.cn('inline-block size-4 rounded-full shadow-sm transition-transform', panelMode === 'test' ? 'bg-white' : 'bg-white dark:bg-slate-100', panelMode === 'test' ? 'translate-x-4' : 'translate-x-0.5') }) })] }), jsxRuntime.jsx("button", { type: "button", "aria-label": "Close fingerprint panel", className: "rounded-full p-2 text-slate-500 transition hover:bg-slate-100 hover:text-slate-700 dark:text-slate-300 dark:hover:bg-white/10 dark:hover:text-white", onClick: () => setIsOpen(false), children: jsxRuntime.jsx(icons.XIcon, { className: "size-4" }) })] })] }) }), jsxRuntime.jsxs("section", { className: "space-y-1", children: [panelMode === 'info' ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(PanelSection, { icon: jsxRuntime.jsx(icons.FingerprintIcon, { className: "size-4" }), title: "User", rightInfo: jsxRuntime.jsx(StatusTag, { value: userStatus }), items: [
255
- { label: 'UserID', value: jsxRuntime.jsx(ui.CopyableText, { text: (xUser === null || xUser === void 0 ? void 0 : xUser.userId) || '' }) },
256
- { label: 'NickName', value: jsxRuntime.jsx(ui.CopyableText, { text: (xUser === null || xUser === void 0 ? void 0 : xUser.userName) || '' }) },
257
- { label: 'FingerprintID', value: jsxRuntime.jsx(ui.CopyableText, { text: (xUser === null || xUser === void 0 ? void 0 : xUser.fingerprintId) || fingerprintId || '' }) },
258
- { label: 'ClerkUserID', value: jsxRuntime.jsx(ui.CopyableText, { text: (xUser === null || xUser === void 0 ? void 0 : xUser.clerkUserId) || '' }) },
259
- { label: 'Email', value: jsxRuntime.jsx(ui.CopyableText, { text: (xUser === null || xUser === void 0 ? void 0 : xUser.email) || '' }) },
260
- { label: 'StripeCusID', value: jsxRuntime.jsx(ui.CopyableText, { text: (xUser === null || xUser === void 0 ? void 0 : xUser.stripeCusId) || '' }) },
261
- { label: 'CreatedAt', value: (xUser === null || xUser === void 0 ? void 0 : xUser.createdAt) || '--' },
262
- ] }), jsxRuntime.jsxs("div", { className: "space-y-2 rounded-xl border border-slate-200/70 bg-white/80 p-4 shadow-sm dark:border-white/12 dark:bg-slate-900/50", children: [jsxRuntime.jsx(PanelHeader, { icon: jsxRuntime.jsx(icons.GemIcon, { className: "size-4" }), title: "Credits Info", rightInfo: jsxRuntime.jsx("span", { className: utils.cn("font-semibold", lib.themeIconColor), children: totalCredits }) }), jsxRuntime.jsx("div", { className: "space-y-3", children: creditBuckets.length > 0 ? (creditBuckets.map((bucket) => {
260
+ : 'bg-slate-300 dark:bg-slate-700'), children: jsxRuntime.jsx("span", { className: utils.cn('inline-block size-4 rounded-full shadow-sm transition-transform', panelMode === 'test' ? 'bg-white' : 'bg-white dark:bg-slate-100', panelMode === 'test' ? 'translate-x-4' : 'translate-x-0.5') }) })] }), jsxRuntime.jsx("button", { type: "button", "aria-label": translations.panel.closeAriaLabel, className: "rounded-full p-2 text-slate-500 transition hover:bg-slate-100 hover:text-slate-700 dark:text-slate-300 dark:hover:bg-white/10 dark:hover:text-white", onClick: () => setIsOpen(false), children: jsxRuntime.jsx(icons.XIcon, { className: "size-4" }) })] })] }) }), jsxRuntime.jsxs("section", { className: "space-y-1", children: [panelMode === 'info' ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(PanelSection, { icon: jsxRuntime.jsx(icons.FingerprintIcon, { className: "size-4" }), title: translations.sections.user, rightInfo: jsxRuntime.jsx(StatusTag, { value: userStatus, translations: translations }), items: [
261
+ { label: translations.labels.userId, value: jsxRuntime.jsx(ui.CopyableText, { text: (xUser === null || xUser === void 0 ? void 0 : xUser.userId) || '' }) },
262
+ { label: translations.labels.nickName, value: jsxRuntime.jsx(ui.CopyableText, { text: (xUser === null || xUser === void 0 ? void 0 : xUser.userName) || '' }) },
263
+ { label: translations.labels.fingerprintId, value: jsxRuntime.jsx(ui.CopyableText, { text: (xUser === null || xUser === void 0 ? void 0 : xUser.fingerprintId) || fingerprintId || '' }) },
264
+ { label: translations.labels.clerkUserId, value: jsxRuntime.jsx(ui.CopyableText, { text: (xUser === null || xUser === void 0 ? void 0 : xUser.clerkUserId) || '' }) },
265
+ { label: translations.labels.email, value: jsxRuntime.jsx(ui.CopyableText, { text: (xUser === null || xUser === void 0 ? void 0 : xUser.email) || '' }) },
266
+ { label: translations.labels.stripeCusId, value: jsxRuntime.jsx(ui.CopyableText, { text: (xUser === null || xUser === void 0 ? void 0 : xUser.stripeCusId) || '' }) },
267
+ { label: translations.labels.createdAt, value: (xUser === null || xUser === void 0 ? void 0 : xUser.createdAt) || '--' },
268
+ ] }), jsxRuntime.jsxs("div", { className: "space-y-2 rounded-xl border border-slate-200/70 bg-white/80 p-4 shadow-sm dark:border-white/12 dark:bg-slate-900/50", children: [jsxRuntime.jsx(PanelHeader, { icon: jsxRuntime.jsx(icons.GemIcon, { className: "size-4" }), title: translations.sections.creditsInfo, rightInfo: jsxRuntime.jsx("span", { className: utils.cn("font-semibold", lib.themeIconColor), children: totalCredits }) }), jsxRuntime.jsx("div", { className: "space-y-3", children: creditBuckets.length > 0 ? (creditBuckets.map((bucket) => {
263
269
  const percent = Math.round(computeProgress(bucket.balance, bucket.total) * 100);
264
- return (jsxRuntime.jsxs("div", { className: "rounded-lg border border-slate-200/70 bg-white/70 p-3 dark:border-white/10 dark:bg-slate-900/40", children: [jsxRuntime.jsxs("div", { className: "flex items-center justify-between text-xs font-medium text-slate-600 dark:text-slate-300", children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [bucket.icon, jsxRuntime.jsx("span", { children: bucket.label })] }), jsxRuntime.jsxs("span", { className: "font-semibold text-slate-700 dark:text-slate-100", children: [formatNumber(bucket.balance), " / ", formatNumber(bucket.total)] })] }), jsxRuntime.jsx("div", { className: "mt-2 h-1.5 w-full rounded-full bg-slate-200 dark:bg-slate-800", children: jsxRuntime.jsx("div", { className: "h-full rounded-full bg-linear-to-r from-purple-500 via-pink-500 to-rose-400 transition-[width]", style: { width: `${percent}%` } }) }), jsxRuntime.jsxs("div", { className: "mt-2 flex items-center justify-between text-[11px] text-slate-500 dark:text-slate-400", children: [jsxRuntime.jsx("span", { children: formatRangeText(bucket.start, bucket.end) }), jsxRuntime.jsxs("span", { children: [percent, "%"] })] })] }, bucket.key));
265
- })) : (jsxRuntime.jsx(EmptyPlaceholder, { label: "No Credits Yet", icon: jsxRuntime.jsx(icons.DatabaseZapIcon, { className: "size-4" }) })) })] }), jsxRuntime.jsx(PanelSection, { icon: jsxRuntime.jsx(icons.BellIcon, { className: "size-4" }), title: "Subscription", rightInfo: jsxRuntime.jsx(StatusTag, { value: subStatus }), items: [
266
- { label: 'Plan', value: subscriptionStatus.priceName },
267
- { label: 'Period', value: subscriptionStatus.period },
268
- { label: 'Allocated', value: subscriptionStatus.creditsAllocated },
269
- { label: 'SubID', value: jsxRuntime.jsx(ui.CopyableText, { text: (xSubscription === null || xSubscription === void 0 ? void 0 : xSubscription.paySubscriptionId) || '' }) },
270
- { label: 'OrderID', value: jsxRuntime.jsx(ui.CopyableText, { text: (xSubscription === null || xSubscription === void 0 ? void 0 : xSubscription.orderId) || '' }) },
271
- { label: 'PriceID', value: jsxRuntime.jsx(ui.CopyableText, { text: (xSubscription === null || xSubscription === void 0 ? void 0 : xSubscription.priceId) || '' }) },
272
- ] })] })) : (jsxRuntime.jsxs("div", { className: "space-y-3 rounded-xl border border-slate-200/70 bg-white/85 p-4 shadow-sm dark:border-white/12 dark:bg-slate-900/45", children: [jsxRuntime.jsx(PanelHeader, { icon: jsxRuntime.jsx(icons.DatabaseZapIcon, { className: "size-4" }), title: "Concurrent Base Info", rightInfo: jsxRuntime.jsx(StatusTag, { value: isRunningTest ? 'pending' : 'idle' }) }), jsxRuntime.jsxs("div", { className: "space-y-2 text-xs text-slate-500 dark:text-slate-300", children: [jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-3", children: [jsxRuntime.jsx("span", { className: "text-slate-400 dark:text-slate-500", children: "Real Browser" }), jsxRuntime.jsx(ui.CopyableText, { text: fingerprintId || '' })] }), jsxRuntime.jsxs("div", { className: "space-y-1", children: [jsxRuntime.jsx("span", { className: "text-slate-400 dark:text-slate-500", children: "Test Override" }), jsxRuntime.jsxs("div", { className: "flex items-center gap-2 py-1", children: [jsxRuntime.jsx("div", { className: "min-w-0 flex-1 rounded-lg border border-slate-200 bg-white px-3 py-2 font-mono text-[0.5rem] sm:text-[0.625rem] md:text-xs leading-tight text-slate-700 dark:border-white/10 dark:bg-slate-950 dark:text-slate-100", children: jsxRuntime.jsx(ui.CopyableText, { text: activeDebugFingerprintId || '' }) }), jsxRuntime.jsx("button", { type: "button", disabled: isRunningTest, onClick: regenerateTestFingerprint, "aria-label": "Generate new test fingerprint", className: "inline-flex size-9 items-center justify-center rounded-lg border border-slate-200 bg-slate-50 text-slate-700 transition hover:border-slate-300 hover:bg-slate-100 disabled:cursor-not-allowed disabled:opacity-50 dark:border-white/10 dark:bg-slate-950 dark:text-slate-100 dark:hover:bg-slate-900", children: jsxRuntime.jsx(icons.RefreshCcwIcon, { className: "size-4" }) })] })] })] }), jsxRuntime.jsxs("div", { className: "grid grid-cols-1 gap-2 sm:grid-cols-2", children: [jsxRuntime.jsx("button", { type: "button", disabled: isRunningTest, onClick: runContextParallelInitTest, className: utils.cn('shrink-0 rounded-full border px-3 py-2 text-xs font-semibold transition-all duration-200 disabled:cursor-not-allowed disabled:opacity-50', themedGhostButtonClass), children: "Frontend Prevention Test" }), jsxRuntime.jsx("button", { type: "button", disabled: isRunningTest, onClick: runRawParallelPostTest, className: utils.cn('shrink-0 rounded-full border px-3 py-2 text-xs font-semibold text-white shadow-sm transition-all duration-200 disabled:cursor-not-allowed disabled:opacity-50', 'border-transparent', lib.themeButtonGradientClass, lib.themeButtonGradientHoverClass), children: "Backend Idempotency Test" })] }), jsxRuntime.jsx("div", { className: "rounded-lg border border-dashed border-slate-200 bg-slate-50/80 p-3 dark:border-white/10 dark:bg-slate-950/50", children: jsxRuntime.jsx("pre", { className: "overflow-x-auto whitespace-pre-wrap break-all font-mono text-[11px] leading-5 text-slate-600 dark:text-slate-300", children: testResult || 'No test executed yet.' }) })] })), error && (jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-3 rounded-xl border border-amber-200 bg-amber-50 p-3 text-xs text-amber-600 shadow-sm dark:border-amber-500/40 dark:bg-amber-500/10 dark:text-amber-200", children: [jsxRuntime.jsxs("div", { className: "flex items-start gap-2", children: [jsxRuntime.jsx(icons.XIcon, { className: "mt-0.5 size-4 shrink-0" }), jsxRuntime.jsx("span", { children: error })] }), jsxRuntime.jsx("button", { type: "button", "aria-label": "Dismiss error", onClick: clearError, className: "shrink-0 rounded-full p-1 text-amber-500 transition hover:bg-amber-100 hover:text-amber-700 dark:text-amber-200 dark:hover:bg-amber-500/10 dark:hover:text-amber-100", children: jsxRuntime.jsx(icons.XIcon, { className: "size-4" }) })] }))] })] })] }))] }));
270
+ return (jsxRuntime.jsxs("div", { className: "rounded-lg border border-slate-200/70 bg-white/70 p-3 dark:border-white/10 dark:bg-slate-900/40", children: [jsxRuntime.jsxs("div", { className: "flex items-center justify-between text-xs font-medium text-slate-600 dark:text-slate-300", children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [bucket.icon, jsxRuntime.jsx("span", { children: bucket.label })] }), jsxRuntime.jsxs("span", { className: "font-semibold text-slate-700 dark:text-slate-100", children: [formatNumber(bucket.balance), " / ", formatNumber(bucket.total)] })] }), jsxRuntime.jsx("div", { className: "mt-2 h-1.5 w-full rounded-full bg-slate-200 dark:bg-slate-800", children: jsxRuntime.jsx("div", { className: "h-full rounded-full bg-linear-to-r from-purple-500 via-pink-500 to-rose-400 transition-[width]", style: { width: `${percent}%` } }) }), jsxRuntime.jsxs("div", { className: "mt-2 flex items-center justify-between text-[11px] text-slate-500 dark:text-slate-400", children: [jsxRuntime.jsx("span", { children: formatRangeText(bucket.start, bucket.end, translations) }), jsxRuntime.jsxs("span", { children: [percent, "%"] })] })] }, bucket.key));
271
+ })) : (jsxRuntime.jsx(EmptyPlaceholder, { label: translations.placeholders.noCreditsYet, icon: jsxRuntime.jsx(icons.DatabaseZapIcon, { className: "size-4" }) })) })] }), jsxRuntime.jsx(PanelSection, { icon: jsxRuntime.jsx(icons.BellIcon, { className: "size-4" }), title: translations.sections.subscription, rightInfo: jsxRuntime.jsx(StatusTag, { value: subStatus, translations: translations }), items: [
272
+ { label: translations.labels.plan, value: subscriptionStatus.priceName },
273
+ { label: translations.labels.period, value: subscriptionStatus.period },
274
+ { label: translations.labels.allocated, value: subscriptionStatus.creditsAllocated },
275
+ { label: translations.labels.subId, value: jsxRuntime.jsx(ui.CopyableText, { text: (xSubscription === null || xSubscription === void 0 ? void 0 : xSubscription.paySubscriptionId) || '' }) },
276
+ { label: translations.labels.orderId, value: jsxRuntime.jsx(ui.CopyableText, { text: (xSubscription === null || xSubscription === void 0 ? void 0 : xSubscription.orderId) || '' }) },
277
+ { label: translations.labels.priceId, value: jsxRuntime.jsx(ui.CopyableText, { text: (xSubscription === null || xSubscription === void 0 ? void 0 : xSubscription.priceId) || '' }) },
278
+ ] })] })) : (jsxRuntime.jsxs("div", { className: "space-y-3 rounded-xl border border-slate-200/70 bg-white/85 p-4 shadow-sm dark:border-white/12 dark:bg-slate-900/45", children: [jsxRuntime.jsx(PanelHeader, { icon: jsxRuntime.jsx(icons.DatabaseZapIcon, { className: "size-4" }), title: translations.sections.concurrentBaseInfo, rightInfo: jsxRuntime.jsx(StatusTag, { value: isRunningTest ? translations.status.pending : translations.status.idle, translations: translations }) }), jsxRuntime.jsxs("div", { className: "space-y-2 text-xs text-slate-500 dark:text-slate-300", children: [jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-3", children: [jsxRuntime.jsx("span", { className: "text-slate-400 dark:text-slate-500", children: translations.labels.realBrowser }), jsxRuntime.jsx(ui.CopyableText, { text: fingerprintId || '' })] }), jsxRuntime.jsxs("div", { className: "space-y-1", children: [jsxRuntime.jsx("span", { className: "text-slate-400 dark:text-slate-500", children: translations.labels.testOverride }), jsxRuntime.jsxs("div", { className: "flex items-center gap-2 py-1", children: [jsxRuntime.jsx("div", { className: "min-w-0 flex-1 rounded-lg border border-slate-200 bg-white px-3 py-2 font-mono text-[0.5rem] sm:text-[0.625rem] md:text-xs leading-tight text-slate-700 dark:border-white/10 dark:bg-slate-950 dark:text-slate-100", children: jsxRuntime.jsx(ui.CopyableText, { text: activeDebugFingerprintId || '' }) }), jsxRuntime.jsx("button", { type: "button", disabled: isRunningTest, onClick: regenerateTestFingerprint, "aria-label": translations.actions.generateNewTestFingerprintAriaLabel, className: "inline-flex size-9 items-center justify-center rounded-lg border border-slate-200 bg-slate-50 text-slate-700 transition hover:border-slate-300 hover:bg-slate-100 disabled:cursor-not-allowed disabled:opacity-50 dark:border-white/10 dark:bg-slate-950 dark:text-slate-100 dark:hover:bg-slate-900", children: jsxRuntime.jsx(icons.RefreshCcwIcon, { className: "size-4" }) })] })] })] }), jsxRuntime.jsxs("div", { className: "grid grid-cols-1 gap-2 sm:grid-cols-2", children: [jsxRuntime.jsx("button", { type: "button", disabled: isRunningTest, onClick: runContextParallelInitTest, className: utils.cn('shrink-0 rounded-full border px-3 py-2 text-xs font-semibold transition-all duration-200 disabled:cursor-not-allowed disabled:opacity-50', themedGhostButtonClass), children: translations.actions.frontendPreventionTest }), jsxRuntime.jsx("button", { type: "button", disabled: isRunningTest, onClick: runRawParallelPostTest, className: utils.cn('shrink-0 rounded-full border px-3 py-2 text-xs font-semibold text-white shadow-sm transition-all duration-200 disabled:cursor-not-allowed disabled:opacity-50', 'border-transparent', lib.themeButtonGradientClass, lib.themeButtonGradientHoverClass), children: translations.actions.backendIdempotencyTest })] }), jsxRuntime.jsx("div", { className: "rounded-lg border border-dashed border-slate-200 bg-slate-50/80 p-3 dark:border-white/10 dark:bg-slate-950/50", children: jsxRuntime.jsx("pre", { className: "overflow-x-auto whitespace-pre-wrap break-all font-mono text-[11px] leading-5 text-slate-600 dark:text-slate-300", children: testResult || translations.placeholders.noTestExecutedYet }) })] })), error && (jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-3 rounded-xl border border-amber-200 bg-amber-50 p-3 text-xs text-amber-600 shadow-sm dark:border-amber-500/40 dark:bg-amber-500/10 dark:text-amber-200", children: [jsxRuntime.jsxs("div", { className: "flex items-start gap-2", children: [jsxRuntime.jsx(icons.XIcon, { className: "mt-0.5 size-4 shrink-0" }), jsxRuntime.jsx("span", { children: error })] }), jsxRuntime.jsx("button", { type: "button", "aria-label": translations.actions.dismissErrorAriaLabel, onClick: clearError, className: "shrink-0 rounded-full p-1 text-amber-500 transition hover:bg-amber-100 hover:text-amber-700 dark:text-amber-200 dark:hover:bg-amber-500/10 dark:hover:text-amber-100", children: jsxRuntime.jsx(icons.XIcon, { className: "size-4" }) })] }))] })] })] }))] }));
273
279
  }
274
280
  /* ==================== 新增辅助组件 ==================== */
275
281
  // 标题行:左侧图标+标题,右侧信息(右对齐)
@@ -296,11 +302,11 @@ function computeProgress(balance, total) {
296
302
  return 0;
297
303
  return Math.min(Math.max(ratio, 0), 1);
298
304
  }
299
- function formatRangeText(start, end) {
305
+ function formatRangeText(start, end, translations) {
300
306
  const safeStart = start && start.trim() ? start : '';
301
307
  const safeEnd = end && end.trim() ? end : '';
302
308
  if (!safeStart && !safeEnd) {
303
- return 'No records';
309
+ return translations.placeholders.noRecords;
304
310
  }
305
311
  if (!safeStart) {
306
312
  return safeEnd;
@@ -310,9 +316,9 @@ function formatRangeText(start, end) {
310
316
  }
311
317
  return `${safeStart} - ${safeEnd}`;
312
318
  }
313
- function StatusTag({ value }) {
319
+ function StatusTag({ value, translations, }) {
314
320
  if (!value)
315
- return jsxRuntime.jsx("span", { className: "text-slate-400", children: "None" });
321
+ return jsxRuntime.jsx("span", { className: "text-slate-400", children: translations.placeholders.none });
316
322
  const normalized = value.toLowerCase();
317
323
  const colorMap = {
318
324
  // 绿色:正常/活跃
@@ -335,14 +341,17 @@ function StatusTag({ value }) {
335
341
  const badgeClass = colorMap[normalized] || defaultColor;
336
342
  return (jsxRuntime.jsx("span", { className: utils.cn('inline-block rounded-full px-2 py-0.5 text-xs capitalize font-medium', badgeClass), children: value }));
337
343
  }
338
- function formatErrorMessage(error) {
344
+ function formatErrorMessage(error, translations) {
339
345
  if (error instanceof Error) {
340
346
  return error.message;
341
347
  }
342
348
  if (typeof error === 'string') {
343
349
  return error;
344
350
  }
345
- return 'Unknown error';
351
+ return translations.placeholders.unknownError;
352
+ }
353
+ function tpl(template, values) {
354
+ return template.replace(/\{(\w+)\}/g, (_, key) => { var _a; return String((_a = values[key]) !== null && _a !== void 0 ? _a : ''); });
346
355
  }
347
356
 
348
357
  exports.FingerprintProvider = FingerprintProvider;