@howone/sdk 0.3.25 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -289,7 +289,6 @@ __export(index_exports, {
289
289
  ThemeToggle: () => ThemeToggle,
290
290
  aiWorkflow: () => aiWorkflow,
291
291
  canAccessArtifact: () => canAccessArtifact,
292
- clearGuestSession: () => clearGuestSession,
293
292
  createAIWorkflowClient: () => createAIWorkflowClient,
294
293
  createAIWorkflowClientAxios: () => createAIWorkflowClientAxios,
295
294
  createArtifactsClient: () => createArtifactsClient,
@@ -304,12 +303,10 @@ __export(index_exports, {
304
303
  getEnvironment: () => getEnvironment,
305
304
  getEnvs: () => getEnvs,
306
305
  getGlobalEnvironment: () => getGlobalEnvironment,
307
- getGuestSessionId: () => getGuestSessionId,
308
306
  getToken: () => getToken,
309
307
  howone: () => client_default,
310
308
  iframeNavigation: () => iframeNavigation,
311
309
  initIframeNavigation: () => initIframeNavigation,
312
- isGuestMode: () => isGuestMode,
313
310
  isTokenValid: () => isTokenValid,
314
311
  loginWithEmailCode: () => loginWithEmailCode,
315
312
  onAuthStateChanged: () => onAuthStateChanged,
@@ -320,8 +317,6 @@ __export(index_exports, {
320
317
  setEnvironment: () => setEnvironment,
321
318
  setToken: () => setToken,
322
319
  showLimitUpgradeToast: () => showLimitUpgradeToast,
323
- showPremiumActionToast: () => showPremiumActionToast,
324
- showSignInRequiredToast: () => showSignInRequiredToast,
325
320
  unifiedAuth: () => unifiedAuth,
326
321
  unifiedOAuth: () => unifiedOAuth,
327
322
  useAuth: () => useAuth,
@@ -1026,7 +1021,7 @@ var LoginForm = ({
1026
1021
  };
1027
1022
 
1028
1023
  // src/components/auth/HowoneProvider.tsx
1029
- var import_react11 = require("react");
1024
+ var import_react8 = require("react");
1030
1025
  init_auth();
1031
1026
 
1032
1027
  // src/components/theme/ThemeProvider.tsx
@@ -1325,985 +1320,851 @@ var ElementSelectorProvider = ({ children }) => {
1325
1320
 
1326
1321
  // src/components/auth/HowoneProvider.tsx
1327
1322
  init_config();
1328
-
1329
- // src/utils/session.ts
1330
- var GUEST_SESSION_KEY = "howone_guest_session";
1331
- function getGuestSessionId() {
1332
- if (typeof window === "undefined") return null;
1333
- try {
1334
- let sessionId = localStorage.getItem(GUEST_SESSION_KEY);
1335
- if (!sessionId) {
1336
- sessionId = crypto.randomUUID();
1337
- localStorage.setItem(GUEST_SESSION_KEY, sessionId);
1338
- }
1339
- return sessionId;
1340
- } catch {
1341
- return null;
1323
+ var import_jsx_runtime7 = require("react/jsx-runtime");
1324
+ var HowoneContext = (0, import_react8.createContext)(null);
1325
+ var redirectOverlayStylesInjected = false;
1326
+ var injectRedirectOverlayStyles = () => {
1327
+ if (redirectOverlayStylesInjected || typeof document === "undefined") return;
1328
+ const style = document.createElement("style");
1329
+ style.setAttribute("data-howone-auth-overlay", "true");
1330
+ style.textContent = `
1331
+ @keyframes howone-logo-pulse {
1332
+ 0%, 100% {
1333
+ opacity: 0.2;
1334
+ transform: scale(0.95);
1335
+ filter: drop-shadow(0 0 0 rgba(255, 255, 255, 0.2));
1342
1336
  }
1343
- }
1344
- function clearGuestSession() {
1345
- if (typeof window === "undefined") return;
1346
- try {
1347
- localStorage.removeItem(GUEST_SESSION_KEY);
1348
- } catch {
1337
+ 50% {
1338
+ opacity: 1;
1339
+ transform: scale(1.03);
1340
+ filter: drop-shadow(0 0 28px rgba(255, 255, 255, 0.55));
1349
1341
  }
1350
1342
  }
1351
- function isGuestMode() {
1352
- if (typeof window === "undefined") return false;
1353
- const hasAuthToken = !!localStorage.getItem("auth_token");
1354
- const hasSession = !!localStorage.getItem(GUEST_SESSION_KEY);
1355
- return !hasAuthToken && hasSession;
1356
- }
1357
- function getExistingSessionId() {
1358
- if (typeof window === "undefined") return null;
1359
- try {
1360
- return localStorage.getItem(GUEST_SESSION_KEY);
1361
- } catch {
1362
- return null;
1343
+
1344
+ @keyframes howone-glow-ring {
1345
+ 0%, 100% {
1346
+ opacity: 0.12;
1347
+ transform: scale(0.85);
1348
+ }
1349
+ 50% {
1350
+ opacity: 0.42;
1351
+ transform: scale(1.05);
1363
1352
  }
1364
1353
  }
1365
1354
 
1366
- // src/components/ui/Toast/ClayxToast.tsx
1367
- var import_react9 = __toESM(require("react"));
1368
- var import_react_toastify2 = require("react-toastify");
1369
- var import_react10 = require("@iconify/react");
1370
-
1371
- // src/components/theme/ThemeToggle.tsx
1372
- var React4 = __toESM(require("react"));
1373
- var import_react8 = require("@iconify/react");
1374
- var import_jsx_runtime7 = require("react/jsx-runtime");
1375
- function ThemeToggle({ className }) {
1376
- const { setTheme, theme } = useTheme();
1377
- const [mounted, setMounted] = React4.useState(false);
1378
- React4.useEffect(() => {
1379
- setMounted(true);
1355
+ [data-howone-auth-overlay-root] {
1356
+ position: fixed;
1357
+ inset: 0;
1358
+ z-index: 2147483646;
1359
+ display: flex;
1360
+ flex-direction: column;
1361
+ align-items: center;
1362
+ justify-content: center;
1363
+ width: 100vw;
1364
+ height: 100vh;
1365
+ color: #ffffff;
1366
+ background: rgba(0, 0, 0, 0.65);
1367
+ backdrop-filter: blur(6px);
1368
+ -webkit-backdrop-filter: blur(6px);
1369
+ text-align: center;
1370
+ }
1371
+ `;
1372
+ document.head.appendChild(style);
1373
+ redirectOverlayStylesInjected = true;
1374
+ };
1375
+ var HowOneProvider = ({
1376
+ children,
1377
+ showFloatingButton = true,
1378
+ projectId,
1379
+ defaultTheme = "system",
1380
+ themeStorageKey = "howone-theme",
1381
+ forceDefaultTheme = false,
1382
+ redirectOnUnauthenticated = true
1383
+ }) => {
1384
+ const [user, setUser] = (0, import_react8.useState)(() => parseUserFromToken(getToken()));
1385
+ const [token, setTokenState] = (0, import_react8.useState)(() => getToken());
1386
+ const [hasCheckedUrlToken, setHasCheckedUrlToken] = (0, import_react8.useState)(false);
1387
+ const [pendingRedirect, setPendingRedirect] = (0, import_react8.useState)(false);
1388
+ (0, import_react8.useEffect)(() => {
1389
+ try {
1390
+ const params = new URLSearchParams(window.location.search);
1391
+ let urlToken = params.get("access_token") || params.get("token");
1392
+ if (!urlToken && window.location.hash) {
1393
+ const hashParams = new URLSearchParams(window.location.hash.slice(1));
1394
+ urlToken = hashParams.get("access_token") || hashParams.get("token");
1395
+ }
1396
+ if (urlToken) {
1397
+ setToken(urlToken);
1398
+ setTokenState(urlToken);
1399
+ setUser(parseUserFromToken(urlToken));
1400
+ params.delete("access_token");
1401
+ params.delete("token");
1402
+ params.delete("project_id");
1403
+ const newSearch = params.toString();
1404
+ const newUrl = window.location.pathname + (newSearch ? "?" + newSearch : "");
1405
+ window.history.replaceState({}, "", newUrl);
1406
+ }
1407
+ } catch (e) {
1408
+ console.error("[HowOneProvider] Failed to capture token from URL:", e);
1409
+ } finally {
1410
+ setHasCheckedUrlToken(true);
1411
+ }
1380
1412
  }, []);
1381
- const handleToggle = () => {
1382
- if (theme === "dark") {
1383
- setTheme("light");
1384
- } else {
1385
- setTheme("dark");
1413
+ const resolvedAuthUrl = (0, import_react8.useMemo)(() => {
1414
+ const env3 = getGlobalEnvironment() ?? "dev";
1415
+ switch (env3) {
1416
+ case "local":
1417
+ return "http://localhost:3000/auth";
1418
+ case "prod":
1419
+ return "https://howone.ai/auth";
1420
+ case "dev":
1421
+ default:
1422
+ return "https://howone.dev/auth";
1423
+ }
1424
+ }, []);
1425
+ (0, import_react8.useEffect)(() => {
1426
+ if (pendingRedirect) {
1427
+ injectRedirectOverlayStyles();
1428
+ }
1429
+ }, [pendingRedirect]);
1430
+ (0, import_react8.useEffect)(() => {
1431
+ if (pendingRedirect) {
1432
+ injectRedirectOverlayStyles();
1433
+ }
1434
+ }, [pendingRedirect]);
1435
+ const redirectToAuth = (0, import_react8.useCallback)(() => {
1436
+ if (!redirectOnUnauthenticated || typeof window === "undefined") return;
1437
+ const activeProjectId = projectId ?? getDefaultProjectId();
1438
+ const navigateToResolvedAuth = () => {
1439
+ setPendingRedirect(true);
1440
+ requestAnimationFrame(() => {
1441
+ if (activeProjectId) {
1442
+ try {
1443
+ const url = new URL(resolvedAuthUrl);
1444
+ url.searchParams.set("redirect_uri", window.location.origin);
1445
+ url.searchParams.set("project_id", activeProjectId);
1446
+ window.location.href = url.toString();
1447
+ return;
1448
+ } catch (error) {
1449
+ console.error("[HowOneProvider] Failed to attach project_id to auth URL:", error);
1450
+ }
1451
+ }
1452
+ window.location.href = resolvedAuthUrl;
1453
+ });
1454
+ };
1455
+ try {
1456
+ const currentUrl = new URL(window.location.href);
1457
+ if (currentUrl.pathname.includes("/auth")) return;
1458
+ try {
1459
+ const authUrlObj = new URL(resolvedAuthUrl);
1460
+ authUrlObj.searchParams.set("redirect_uri", window.location.origin);
1461
+ if (activeProjectId) {
1462
+ authUrlObj.searchParams.set("project_id", activeProjectId);
1463
+ }
1464
+ setPendingRedirect(true);
1465
+ requestAnimationFrame(() => {
1466
+ window.location.href = authUrlObj.toString();
1467
+ });
1468
+ return;
1469
+ } catch (error) {
1470
+ console.error("[HowOneProvider] Failed to build auth URL:", error);
1471
+ }
1472
+ navigateToResolvedAuth();
1473
+ } catch {
1474
+ navigateToResolvedAuth();
1475
+ }
1476
+ }, [redirectOnUnauthenticated, resolvedAuthUrl, projectId]);
1477
+ (0, import_react8.useEffect)(() => {
1478
+ if (!hasCheckedUrlToken) return;
1479
+ if (!token && !user) {
1480
+ redirectToAuth();
1481
+ }
1482
+ }, [token, user, hasCheckedUrlToken, redirectToAuth]);
1483
+ const logout = () => {
1484
+ try {
1485
+ setToken(null);
1486
+ } catch {
1386
1487
  }
1488
+ setTokenState(null);
1489
+ setUser(null);
1490
+ redirectToAuth();
1387
1491
  };
1388
- if (!mounted) {
1389
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react8.Icon, { icon: "solar:sun-bold", width: 20, height: 20 });
1390
- }
1391
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1392
- "div",
1492
+ const value = {
1493
+ user,
1494
+ token,
1495
+ isAuthenticated: hasCheckedUrlToken && !!token,
1496
+ logout
1497
+ };
1498
+ if (!hasCheckedUrlToken) return null;
1499
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1500
+ ThemeProvider,
1393
1501
  {
1394
- className: `cursor-pointer ${className || ""}`,
1395
- onClick: handleToggle,
1396
- children: theme === "light" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react8.Icon, { icon: "solar:sun-bold", width: 20, height: 20 }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react8.Icon, { icon: "solar:moon-linear", width: 20, height: 20 })
1502
+ defaultTheme,
1503
+ storageKey: themeStorageKey,
1504
+ forceDefault: forceDefaultTheme,
1505
+ children: [
1506
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ElementSelectorProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(HowoneContext.Provider, { value, children: [
1507
+ children,
1508
+ showFloatingButton && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(FloatingButton, { onClick: () => window.open("https://howone.ai", "_blank") }),
1509
+ pendingRedirect && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1510
+ "div",
1511
+ {
1512
+ "data-howone-auth-overlay-root": true,
1513
+ className: "fixed inset-0 z-[100000] h-full w-full flex flex-col items-center justify-center bg-black/65 backdrop-blur-sm text-white",
1514
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "relative mt-6 flex h-[220px] w-[220px] items-center justify-center", children: [
1515
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1516
+ "div",
1517
+ {
1518
+ className: "absolute inset-0 rounded-full bg-white/20",
1519
+ style: { animation: "howone-glow-ring 2.4s ease-in-out infinite" }
1520
+ }
1521
+ ),
1522
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "absolute inset-0 rounded-full bg-gradient-to-br from-white/10 via-white/25 to-white/10 blur-2xl" }),
1523
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1524
+ "img",
1525
+ {
1526
+ style: { width: 250, animation: "howone-logo-pulse 2s ease-in-out infinite" },
1527
+ src: "https://sxwxqoixnnklnpeutjrj.supabase.co/storage/v1/object/public/create-x/logo/logo.svg",
1528
+ alt: "HowOne"
1529
+ }
1530
+ )
1531
+ ] })
1532
+ }
1533
+ )
1534
+ ] }) }),
1535
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(GlobalToastContainer, {})
1536
+ ]
1397
1537
  }
1398
1538
  );
1539
+ };
1540
+ function useHowoneContext() {
1541
+ const ctx = (0, import_react8.useContext)(HowoneContext);
1542
+ if (!ctx) {
1543
+ const t = getToken();
1544
+ return {
1545
+ user: parseUserFromToken(t),
1546
+ token: t,
1547
+ isAuthenticated: !!t,
1548
+ logout: () => {
1549
+ try {
1550
+ setToken(null);
1551
+ } catch {
1552
+ }
1553
+ }
1554
+ };
1555
+ }
1556
+ return ctx;
1399
1557
  }
1400
1558
 
1401
- // src/components/ui/Toast/ClayxToast.tsx
1402
- var import_jsx_runtime8 = require("react/jsx-runtime");
1403
- var TOAST_ICONS = {
1404
- success: {
1405
- icon: "mdi:success",
1406
- color: "text-green-400",
1407
- className: "text-green-400",
1408
- // 深色主题配置
1409
- dark: {
1410
- bgGradient: "bg-[#14181d]",
1411
- // 移除透明度 f2
1412
- gradientColor: "#389726",
1413
- borderGradient: "border-[#389726]",
1414
- borderGradientColor: "#389726"
1415
- },
1416
- // 浅色主题配置
1417
- light: {
1418
- bgGradient: "bg-[#fafafa]",
1419
- // 移除透明度 ff
1420
- gradientColor: "#22c55e",
1421
- borderGradient: "border-[#22c55e]",
1422
- borderGradientColor: "#22c55e"
1423
- }
1424
- },
1425
- error: {
1426
- icon: "ic:outline-close",
1427
- color: "text-red-400",
1428
- className: "text-red-400",
1429
- dark: {
1430
- bgGradient: "bg-[#14181d]",
1431
- // 移除透明度 f2
1432
- gradientColor: "#ef4444",
1433
- borderGradient: "border-[#ef4444]",
1434
- borderGradientColor: "#ef4444"
1435
- },
1436
- light: {
1437
- bgGradient: "bg-[#fafafa]",
1438
- // 移除透明度 ff
1439
- gradientColor: "#f87171",
1440
- borderGradient: "border-[#f87171]",
1441
- borderGradientColor: "#f87171"
1442
- }
1443
- },
1444
- warning: {
1445
- icon: "mi:warning",
1446
- color: "text-yellow-400",
1447
- className: "text-yellow-400",
1448
- dark: {
1449
- bgGradient: "bg-[#14181d]",
1450
- // 移除透明度 f2
1451
- gradientColor: "#facc15",
1452
- borderGradient: "border-[#facc15]",
1453
- borderGradientColor: "#facc15"
1454
- },
1455
- light: {
1456
- bgGradient: "bg-[#fafafa]",
1457
- // 移除透明度 ff
1458
- gradientColor: "#f59e0b",
1459
- borderGradient: "border-[#f59e0b]",
1460
- borderGradientColor: "#f59e0b"
1461
- }
1462
- },
1463
- info: {
1464
- icon: "ic:outline-info",
1465
- color: "text-blue-400",
1466
- className: "text-blue-400",
1467
- dark: {
1468
- bgGradient: "bg-[#14181d]",
1469
- // 移除透明度 f2
1470
- gradientColor: "#60a5fa",
1471
- borderGradient: "border-[#60a5fa]",
1472
- borderGradientColor: "#f0f0f0"
1473
- },
1474
- light: {
1475
- bgGradient: "bg-[#fafafa]",
1476
- // 移除透明度 ff
1477
- gradientColor: "#3b82f6",
1478
- borderGradient: "border-[#3b82f6]",
1479
- borderGradientColor: "#3b82f6"
1480
- }
1481
- },
1482
- default: {
1483
- icon: "ic:round-notifications",
1484
- color: "text-gray-400",
1485
- className: "text-gray-400",
1486
- dark: {
1487
- bgGradient: "bg-[#14181d]",
1488
- // 移除透明度 f2
1489
- gradientColor: "#9ca3af",
1490
- borderGradient: "border-[#9ca3af]",
1491
- borderGradientColor: "#9ca3af"
1492
- },
1493
- light: {
1494
- bgGradient: "bg-[#fafafa]",
1495
- // 移除透明度 ff
1496
- gradientColor: "#6b7280",
1497
- borderGradient: "border-[#6b7280]",
1498
- borderGradientColor: "#6b7280"
1499
- }
1559
+ // src/components/index.ts
1560
+ init_auth();
1561
+
1562
+ // src/howone/client.ts
1563
+ init_auth();
1564
+ init_config();
1565
+ var HowoneAuthClient = class {
1566
+ constructor() {
1567
+ this.listeners = /* @__PURE__ */ new Set();
1568
+ this.loading = false;
1500
1569
  }
1501
- };
1502
- var CloseButton = import_react9.default.memo(({ closeToast }) => {
1503
- const { theme } = useTheme();
1504
- const handleClick = (0, import_react9.useCallback)((e) => {
1505
- e.preventDefault();
1506
- e.stopPropagation();
1507
- closeToast?.();
1508
- }, [closeToast]);
1509
- const getCloseButtonColor = () => {
1510
- const actualTheme = theme === "system" ? window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light" : theme;
1511
- return actualTheme === "dark" ? "#b4b4b4" : "#6b7280";
1512
- };
1513
- const getCloseButtonHoverColor = () => {
1514
- const actualTheme = theme === "system" ? window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light" : theme;
1515
- return actualTheme === "dark" ? "white" : "#374151";
1516
- };
1517
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1518
- import_react10.Icon,
1519
- {
1520
- icon: "vaadin:close",
1521
- className: "flex items-center justify-center rounded-full relative z-10 flex-shrink-0 cursor-pointer \n transition-colors duration-200 drop-shadow-sm",
1522
- onClick: handleClick,
1523
- width: 14,
1524
- height: 14,
1525
- style: {
1526
- color: getCloseButtonColor()
1527
- },
1528
- onMouseEnter: (e) => {
1529
- e.currentTarget.style.color = getCloseButtonHoverColor();
1530
- },
1531
- onMouseLeave: (e) => {
1532
- e.currentTarget.style.color = getCloseButtonColor();
1570
+ emit() {
1571
+ const state = {
1572
+ user: parseUserFromToken(getToken()),
1573
+ isLoading: this.loading
1574
+ };
1575
+ for (const l of this.listeners) {
1576
+ try {
1577
+ l(state);
1578
+ } catch (e) {
1579
+ void e;
1533
1580
  }
1534
1581
  }
1535
- );
1536
- });
1537
- CloseButton.displayName = "CloseButton";
1538
- var ToastContent = ({ type, title, message, component, closeToast }) => {
1539
- const iconConfig = TOAST_ICONS[type];
1540
- const { theme } = useTheme();
1541
- const handleClose = (0, import_react9.useCallback)(() => {
1542
- closeToast?.();
1543
- }, [closeToast]);
1544
- const getTextColor = () => {
1545
- const actualTheme = theme === "system" ? window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light" : theme;
1546
- return actualTheme === "dark" ? "white" : "#1f2937";
1547
- };
1548
- const getThemeConfig = () => {
1549
- const actualTheme = theme === "system" ? window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light" : theme;
1550
- return actualTheme === "dark" ? iconConfig.dark : iconConfig.light;
1551
- };
1552
- const themeConfig = getThemeConfig();
1553
- const lightBaseBackgroundByType = {
1554
- success: "#f0fdf4",
1555
- // green-50
1556
- error: "#fef2f2",
1557
- // red-50
1558
- warning: "#fffbeb",
1559
- // amber-50
1560
- info: "#eff6ff",
1561
- // blue-50
1562
- default: "#f9fafb"
1563
- // gray-50
1564
- };
1565
- if (component) {
1566
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: `flex items-start gap-3 !min-h-[90px] w-full backdrop-blur-md p-4 shadow-2xl overflow-hidden ${themeConfig.bgGradient}`, children: [
1567
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "flex-1 relative z-10", children: component }),
1568
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "relative z-10", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(CloseButton, { closeToast: handleClose }) })
1569
- ] });
1570
1582
  }
1571
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: `flex items-start gap-3 !min-h-[90px] w-full backdrop-blur-md p-4 shadow-2xl relative overflow-hidden ${themeConfig.bgGradient}`, children: [
1572
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1573
- "div",
1574
- {
1575
- className: "absolute left-0 top-0 w-full h-full rounded-xl",
1576
- style: {
1577
- background: theme === "dark" || theme === "system" && window.matchMedia("(prefers-color-scheme: dark)").matches ? "#0f1419" : lightBaseBackgroundByType[type],
1578
- zIndex: -2
1579
- }
1583
+ onAuthStateChanged(listener) {
1584
+ this.listeners.add(listener);
1585
+ try {
1586
+ listener({ user: parseUserFromToken(getToken()), isLoading: this.loading });
1587
+ } catch (e) {
1588
+ void e;
1589
+ }
1590
+ return () => {
1591
+ this.listeners.delete(listener);
1592
+ };
1593
+ }
1594
+ // Simple redirect-based login trigger (consumer can override)
1595
+ login() {
1596
+ const root = getEnvs().AUTH_ROOT_VALUE;
1597
+ try {
1598
+ const loc = window.location.href;
1599
+ const authUrl = new URL("/auth", String(root));
1600
+ authUrl.searchParams.set("redirect_uri", String(loc));
1601
+ try {
1602
+ const cfg = (init_config(), __toCommonJS(config_exports));
1603
+ const pid = cfg.getDefaultProjectId && cfg.getDefaultProjectId();
1604
+ if (pid) authUrl.searchParams.set("project_id", String(pid));
1605
+ } catch {
1580
1606
  }
1581
- ),
1582
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1583
- "div",
1584
- {
1585
- className: "absolute left-0 top-0 w-full h-full pointer-events-none rounded-xl",
1586
- style: {
1587
- background: theme === "dark" || theme === "system" && window.matchMedia("(prefers-color-scheme: dark)").matches ? `linear-gradient(135deg, ${themeConfig.gradientColor}30 0%, ${themeConfig.gradientColor}20 15%, #14181df2 30%)` : `linear-gradient(135deg, ${themeConfig.gradientColor}20 0%, ${themeConfig.gradientColor}12 15%, #ffffff 30%)`,
1588
- zIndex: -1
1607
+ try {
1608
+ if (window.top && window.top !== window) {
1609
+ window.top.location.replace(authUrl.toString());
1610
+ } else {
1611
+ window.location.replace(authUrl.toString());
1612
+ }
1613
+ } catch {
1614
+ try {
1615
+ window.location.replace(String(root));
1616
+ } catch {
1589
1617
  }
1590
1618
  }
1591
- ),
1619
+ } catch {
1620
+ try {
1621
+ window.location.replace(String(root));
1622
+ } catch {
1623
+ }
1624
+ }
1625
+ }
1626
+ logout() {
1627
+ setToken(null);
1628
+ this.emit();
1629
+ }
1630
+ getUser() {
1631
+ return parseUserFromToken(getToken());
1632
+ }
1633
+ // helper to programmatically set token (e.g., after callback handling)
1634
+ setToken(token) {
1635
+ setToken(token);
1636
+ this.emit();
1637
+ }
1638
+ };
1639
+ var howone = {
1640
+ auth: new HowoneAuthClient()
1641
+ };
1642
+ var client_default = howone;
1643
+
1644
+ // src/components/ui/Loading.tsx
1645
+ var import_jsx_runtime8 = require("react/jsx-runtime");
1646
+ var Loading = ({
1647
+ size = "md",
1648
+ text = "Loading...",
1649
+ className = "",
1650
+ fullScreen = false
1651
+ }) => {
1652
+ const sizeClasses = {
1653
+ sm: "h-4 w-4",
1654
+ md: "h-8 w-8",
1655
+ lg: "h-12 w-12"
1656
+ };
1657
+ const containerClasses = fullScreen ? "fixed inset-0 flex items-center justify-center bg-white/80 backdrop-blur-sm z-50" : "flex items-center justify-center p-4";
1658
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: `${containerClasses} ${className}`, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "text-center", children: [
1592
1659
  /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1593
1660
  "div",
1594
1661
  {
1595
- className: "absolute left-0 top-0 w-full h-full pointer-events-none rounded-xl",
1596
- style: {
1597
- border: "2px solid transparent",
1598
- backgroundImage: theme === "dark" || theme === "system" && window.matchMedia("(prefers-color-scheme: dark)").matches ? `linear-gradient(135deg, ${themeConfig.borderGradientColor}60 0%, ${themeConfig.borderGradientColor}40 5%, transparent 22%)` : `linear-gradient(135deg, ${themeConfig.borderGradientColor}99 0%, ${themeConfig.borderGradientColor}66 5%, transparent 22%)`,
1599
- backgroundOrigin: "border-box",
1600
- backgroundClip: "border-box",
1601
- WebkitMask: "linear-gradient(#ffffff 0 0) padding-box, linear-gradient(#ffffff 0 0)",
1602
- WebkitMaskComposite: "xor",
1603
- zIndex: 0
1604
- }
1662
+ className: `animate-spin rounded-full border-2 border-gray-300 border-t-blue-600 mx-auto ${sizeClasses[size]}`
1605
1663
  }
1606
1664
  ),
1607
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "flex-shrink-0 flex-grow-0 mt-0.5 relative z-10", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1608
- "div",
1609
- {
1610
- className: "backdrop-blur-sm rounded-full flex items-center justify-center overflow-hidden flex-shrink-0 flex-grow-0",
1611
- style: {
1612
- backgroundColor: theme === "dark" || theme === "system" && window.matchMedia("(prefers-color-scheme: dark)").matches ? "rgba(255, 255, 255, 0.1)" : "rgba(0, 0, 0, 0.05)",
1613
- width: "28px",
1614
- height: "28px"
1615
- },
1616
- children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "rounded-full flex items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1617
- import_react10.Icon,
1618
- {
1619
- icon: iconConfig.icon,
1620
- width: 16,
1621
- height: 16,
1622
- className: `flex-shrink-0`,
1623
- style: {
1624
- color: themeConfig.gradientColor,
1625
- display: "block"
1626
- }
1627
- }
1628
- ) })
1629
- }
1630
- ) }),
1631
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex flex-col gap-1 flex-1 relative z-10", children: [
1632
- title && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1633
- "div",
1634
- {
1635
- className: "text-[16px] font-semibold leading-tight drop-shadow-sm",
1636
- style: {
1637
- color: getTextColor(),
1638
- backgroundClip: "text"
1639
- },
1640
- children: title
1641
- }
1642
- ),
1643
- message && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1644
- "div",
1645
- {
1646
- className: "text-[13px] font-normal leading-relaxed drop-shadow-sm",
1647
- style: {
1648
- color: getTextColor(),
1649
- backgroundClip: "text"
1650
- },
1651
- children: message
1652
- }
1653
- )
1654
- ] }),
1655
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "relative z-10", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(CloseButton, { closeToast: handleClose }) })
1656
- ] });
1657
- };
1658
- var defaultToastOptions = {
1659
- position: "bottom-right",
1660
- autoClose: 1500,
1661
- hideProgressBar: true,
1662
- closeOnClick: false,
1663
- pauseOnHover: true,
1664
- draggable: true,
1665
- pauseOnFocusLoss: false,
1666
- transition: import_react_toastify2.Bounce
1667
- };
1668
- var getToastifyTheme = () => {
1669
- if (typeof window !== "undefined") {
1670
- const root = document.documentElement;
1671
- if (root.classList.contains("dark")) return "dark";
1672
- if (root.classList.contains("light")) return "light";
1673
- return window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
1674
- }
1675
- return "light";
1665
+ text && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "mt-2 text-sm text-gray-600", children: text })
1666
+ ] }) });
1676
1667
  };
1677
- var createToast = (type) => {
1678
- return (params) => {
1679
- const { title, message, component, options } = params;
1680
- (0, import_react_toastify2.toast)(
1681
- ({ closeToast }) => {
1682
- if (params.render) return params.render(closeToast);
1683
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1684
- ToastContent,
1685
- {
1686
- type,
1687
- title,
1688
- message: message || "",
1689
- component,
1690
- closeToast
1691
- }
1692
- );
1693
- },
1694
- {
1695
- ...defaultToastOptions,
1696
- ...options,
1697
- theme: getToastifyTheme(),
1698
- // 确保圆角样式不被覆盖,添加 rounded-xl 类
1699
- className: "!p-0 !shadow-none !rounded-xl",
1700
- style: { padding: 0, borderRadius: "0.75rem", backgroundColor: "transparent" }
1701
- }
1702
- );
1668
+ var LoadingSpinner = ({
1669
+ size = "md",
1670
+ className = ""
1671
+ }) => {
1672
+ const sizeClasses = {
1673
+ sm: "h-4 w-4",
1674
+ md: "h-8 w-8",
1675
+ lg: "h-12 w-12"
1703
1676
  };
1704
- };
1705
- var ClayxToast = {
1706
- success: createToast("success"),
1707
- error: createToast("error"),
1708
- warning: createToast("warning"),
1709
- info: createToast("info"),
1710
- default: createToast("default")
1677
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1678
+ "div",
1679
+ {
1680
+ className: `animate-spin rounded-full border-2 border-gray-300 border-t-blue-600 ${sizeClasses[size]} ${className}`
1681
+ }
1682
+ );
1711
1683
  };
1712
1684
 
1713
- // src/components/auth/HowoneProvider.tsx
1685
+ // src/components/ui/ErrorBoundary.tsx
1686
+ var import_react9 = require("react");
1714
1687
  var import_jsx_runtime9 = require("react/jsx-runtime");
1715
- var HowoneContext = (0, import_react11.createContext)(null);
1716
- var redirectOverlayStylesInjected = false;
1717
- var injectRedirectOverlayStyles = () => {
1718
- if (redirectOverlayStylesInjected || typeof document === "undefined") return;
1719
- const style = document.createElement("style");
1720
- style.setAttribute("data-howone-auth-overlay", "true");
1721
- style.textContent = `
1722
- @keyframes howone-logo-pulse {
1723
- 0%, 100% {
1724
- opacity: 0.2;
1725
- transform: scale(0.95);
1726
- filter: drop-shadow(0 0 0 rgba(255, 255, 255, 0.2));
1688
+ var ErrorBoundary = class extends import_react9.Component {
1689
+ constructor(props) {
1690
+ super(props);
1691
+ this.handleRetry = () => {
1692
+ this.setState({ hasError: false, error: void 0, errorInfo: void 0 });
1693
+ };
1694
+ this.state = { hasError: false };
1727
1695
  }
1728
- 50% {
1729
- opacity: 1;
1730
- transform: scale(1.03);
1731
- filter: drop-shadow(0 0 28px rgba(255, 255, 255, 0.55));
1696
+ static getDerivedStateFromError(error) {
1697
+ return { hasError: true, error };
1732
1698
  }
1733
- }
1734
-
1735
- @keyframes howone-glow-ring {
1736
- 0%, 100% {
1737
- opacity: 0.12;
1738
- transform: scale(0.85);
1699
+ componentDidCatch(error, errorInfo) {
1700
+ this.setState({
1701
+ error,
1702
+ errorInfo
1703
+ });
1704
+ this.props.onError?.(error, errorInfo);
1739
1705
  }
1740
- 50% {
1741
- opacity: 0.42;
1742
- transform: scale(1.05);
1706
+ render() {
1707
+ if (this.state.hasError) {
1708
+ if (this.props.fallback) {
1709
+ const FallbackComponent = this.props.fallback;
1710
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(FallbackComponent, { error: this.state.error, retry: this.handleRetry });
1711
+ }
1712
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "min-h-[400px] flex items-center justify-center p-4", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "text-center max-w-md", children: [
1713
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "text-red-500 text-6xl mb-4", children: "\u26A0\uFE0F" }),
1714
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h2", { className: "text-xl font-semibold text-gray-900 mb-2", children: "Something went wrong" }),
1715
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { className: "text-gray-600 mb-4", children: "An unexpected error occurred. Please try refreshing the page." }),
1716
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1717
+ "button",
1718
+ {
1719
+ onClick: this.handleRetry,
1720
+ className: "px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition-colors",
1721
+ children: "Try Again"
1722
+ }
1723
+ ),
1724
+ false
1725
+ ] }) });
1726
+ }
1727
+ return this.props.children;
1743
1728
  }
1744
- }
1745
-
1746
- [data-howone-auth-overlay-root] {
1747
- position: fixed;
1748
- inset: 0;
1749
- z-index: 2147483646;
1750
- display: flex;
1751
- flex-direction: column;
1752
- align-items: center;
1753
- justify-content: center;
1754
- width: 100vw;
1755
- height: 100vh;
1756
- color: #ffffff;
1757
- background: rgba(0, 0, 0, 0.65);
1758
- backdrop-filter: blur(6px);
1759
- -webkit-backdrop-filter: blur(6px);
1760
- text-align: center;
1761
- }
1762
- `;
1763
- document.head.appendChild(style);
1764
- redirectOverlayStylesInjected = true;
1765
1729
  };
1766
- var HowOneProvider = ({
1767
- children,
1768
- showFloatingButton = true,
1769
- projectId,
1770
- defaultTheme = "system",
1771
- themeStorageKey = "howone-theme",
1772
- forceDefaultTheme = false,
1773
- redirectOnUnauthenticated = false
1774
- }) => {
1775
- const [user, setUser] = (0, import_react11.useState)(() => parseUserFromToken(getToken()));
1776
- const [token, setTokenState] = (0, import_react11.useState)(() => getToken());
1777
- const [hasCheckedUrlToken, setHasCheckedUrlToken] = (0, import_react11.useState)(false);
1778
- const [pendingRedirect, setPendingRedirect] = (0, import_react11.useState)(false);
1779
- const [isGuest, setIsGuest] = (0, import_react11.useState)(false);
1780
- (0, import_react11.useEffect)(() => {
1781
- try {
1782
- const params = new URLSearchParams(window.location.search);
1783
- let urlToken = params.get("access_token") || params.get("token");
1784
- if (!urlToken && window.location.hash) {
1785
- const hashParams = new URLSearchParams(window.location.hash.slice(1));
1786
- urlToken = hashParams.get("access_token") || hashParams.get("token");
1787
- }
1788
- if (urlToken) {
1789
- setToken(urlToken);
1790
- setTokenState(urlToken);
1791
- setUser(parseUserFromToken(urlToken));
1792
- params.delete("access_token");
1793
- params.delete("token");
1794
- params.delete("project_id");
1795
- const newSearch = params.toString();
1796
- const newUrl = window.location.pathname + (newSearch ? "?" + newSearch : "");
1797
- window.history.replaceState({}, "", newUrl);
1798
- }
1799
- } catch (e) {
1800
- console.error("[HowOneProvider] Failed to capture token from URL:", e);
1801
- } finally {
1802
- setHasCheckedUrlToken(true);
1730
+ var DefaultErrorFallback = ({ retry }) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "min-h-[200px] flex items-center justify-center p-4", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "text-center", children: [
1731
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "text-red-500 text-4xl mb-2", children: "\u26A0\uFE0F" }),
1732
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { className: "text-gray-600 mb-2", children: "Something went wrong" }),
1733
+ retry && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1734
+ "button",
1735
+ {
1736
+ onClick: retry,
1737
+ className: "px-3 py-1 bg-blue-600 text-white text-sm rounded hover:bg-blue-700 transition-colors",
1738
+ children: "Retry"
1803
1739
  }
1804
- }, []);
1805
- const resolvedAuthUrl = (0, import_react11.useMemo)(() => {
1806
- const env3 = getGlobalEnvironment() ?? "dev";
1807
- switch (env3) {
1808
- case "local":
1809
- return "http://localhost:3000/auth";
1810
- case "prod":
1811
- return "https://howone.ai/auth";
1812
- case "dev":
1740
+ )
1741
+ ] }) });
1742
+
1743
+ // src/components/ui/ClayxButton.tsx
1744
+ var import_jsx_runtime10 = require("react/jsx-runtime");
1745
+ var getSizeClasses = (size, isIconOnly) => {
1746
+ if (isIconOnly) {
1747
+ switch (size) {
1748
+ case "sm":
1749
+ return "h-8 w-8 min-w-8 p-0";
1750
+ case "md":
1751
+ return "h-10 w-10 min-w-10 p-0";
1752
+ case "lg":
1753
+ return "h-12 w-12 min-w-12 p-0";
1813
1754
  default:
1814
- return "https://howone.dev/auth";
1815
- }
1816
- }, []);
1817
- (0, import_react11.useEffect)(() => {
1818
- if (pendingRedirect) {
1819
- injectRedirectOverlayStyles();
1820
- }
1821
- }, [pendingRedirect]);
1822
- (0, import_react11.useEffect)(() => {
1823
- if (pendingRedirect) {
1824
- injectRedirectOverlayStyles();
1755
+ return "h-10 w-10 min-w-10 p-0";
1825
1756
  }
1826
- }, [pendingRedirect]);
1827
- const redirectToAuth = (0, import_react11.useCallback)(() => {
1828
- if (!redirectOnUnauthenticated || typeof window === "undefined") return;
1829
- const activeProjectId = projectId ?? getDefaultProjectId();
1830
- const navigateToResolvedAuth = () => {
1831
- setPendingRedirect(true);
1832
- requestAnimationFrame(() => {
1833
- if (activeProjectId) {
1834
- try {
1835
- const url = new URL(resolvedAuthUrl);
1836
- url.searchParams.set("redirect_uri", window.location.origin);
1837
- url.searchParams.set("project_id", activeProjectId);
1838
- window.location.href = url.toString();
1839
- return;
1840
- } catch (error) {
1841
- console.error("[HowOneProvider] Failed to attach project_id to auth URL:", error);
1842
- }
1843
- }
1844
- window.location.href = resolvedAuthUrl;
1845
- });
1846
- };
1847
- try {
1848
- const currentUrl = new URL(window.location.href);
1849
- if (currentUrl.pathname.includes("/auth")) return;
1850
- try {
1851
- const authUrlObj = new URL(resolvedAuthUrl);
1852
- authUrlObj.searchParams.set("redirect_uri", window.location.origin);
1853
- if (activeProjectId) {
1854
- authUrlObj.searchParams.set("project_id", activeProjectId);
1855
- }
1856
- setPendingRedirect(true);
1857
- requestAnimationFrame(() => {
1858
- window.location.href = authUrlObj.toString();
1859
- });
1860
- return;
1861
- } catch (error) {
1862
- console.error("[HowOneProvider] Failed to build auth URL:", error);
1863
- }
1864
- navigateToResolvedAuth();
1865
- } catch {
1866
- navigateToResolvedAuth();
1867
- }
1868
- }, [redirectOnUnauthenticated, resolvedAuthUrl, projectId]);
1869
- (0, import_react11.useEffect)(() => {
1870
- if (!hasCheckedUrlToken) return;
1871
- if (token || user) {
1872
- setIsGuest(false);
1873
- return;
1874
- }
1875
- const sessionId = getGuestSessionId();
1876
- const guestMode = !!sessionId;
1877
- setIsGuest(guestMode);
1878
- if (guestMode) {
1879
- return;
1757
+ }
1758
+ switch (size) {
1759
+ case "sm":
1760
+ return "h-8 px-3 text-sm";
1761
+ case "md":
1762
+ return "h-10 px-4 text-base";
1763
+ case "lg":
1764
+ return "h-12 px-6 text-lg";
1765
+ default:
1766
+ return "h-10 px-4 text-base";
1767
+ }
1768
+ };
1769
+ var getVariantClasses = (variant) => {
1770
+ switch (variant) {
1771
+ case "solid":
1772
+ return "bg-primary text-white hover:bg-primary/90";
1773
+ case "ghost":
1774
+ return "bg-transparent hover:bg-white/10";
1775
+ case "flat":
1776
+ return "bg-white/5 hover:bg-white/10";
1777
+ default:
1778
+ return "";
1779
+ }
1780
+ };
1781
+ var ClayxButton = ({
1782
+ isIconOnly = false,
1783
+ size = "md",
1784
+ variant = "solid",
1785
+ className = "",
1786
+ children,
1787
+ disabled = false,
1788
+ ...props
1789
+ }) => {
1790
+ const sizeClasses = getSizeClasses(size, isIconOnly);
1791
+ const variantClasses = getVariantClasses(variant);
1792
+ const baseClasses = `
1793
+ inline-flex items-center justify-center
1794
+ rounded-md font-medium
1795
+ transition-all duration-200
1796
+ focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-transparent
1797
+ disabled:opacity-50 disabled:cursor-not-allowed disabled:pointer-events-none
1798
+ `.replace(/\s+/g, " ").trim();
1799
+ const combinedClasses = `${baseClasses} ${sizeClasses} ${variantClasses} ${className}`.trim();
1800
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1801
+ "button",
1802
+ {
1803
+ className: combinedClasses,
1804
+ disabled,
1805
+ ...props,
1806
+ children
1880
1807
  }
1881
- redirectToAuth();
1882
- }, [token, user, hasCheckedUrlToken, redirectToAuth]);
1883
- (0, import_react11.useEffect)(() => {
1884
- if (!hasCheckedUrlToken || !token || !user) return;
1885
- const migrateGuestData = async () => {
1886
- try {
1887
- const guestSessionId = getExistingSessionId();
1888
- if (!guestSessionId) return;
1889
- const activeProjectId = projectId ?? getDefaultProjectId();
1890
- if (!activeProjectId) {
1891
- console.warn("[HowOneProvider] No projectId available for guest data migration");
1892
- return;
1893
- }
1894
- const baseUrl = getEnvs().baseUrl;
1895
- const response = await fetch(
1896
- `${baseUrl}/entities/apps/${activeProjectId}/migrate-guest-data`,
1897
- {
1898
- method: "POST",
1899
- headers: {
1900
- "Content-Type": "application/json",
1901
- "Authorization": `Bearer ${token}`
1902
- },
1903
- body: JSON.stringify({ guestSessionId })
1904
- }
1905
- );
1906
- if (response.ok) {
1907
- const result = await response.json();
1908
- console.log("[HowOneProvider] Guest data migration result:", result);
1909
- clearGuestSession();
1910
- setIsGuest(false);
1911
- if (result.totalCount > 0) {
1912
- const entityList = result.details?.map((d) => `${d.entityName} (${d.count})`).join(", ") || "";
1913
- ClayxToast.success({
1914
- title: "Data Synced",
1915
- message: `Migrated ${result.totalCount} records${entityList ? `: ${entityList}` : ""}`
1916
- });
1917
- }
1918
- } else {
1919
- console.error("[HowOneProvider] Guest data migration failed:", response.status);
1920
- }
1921
- } catch (error) {
1922
- console.error("[HowOneProvider] Failed to migrate guest data:", error);
1923
- }
1924
- };
1925
- migrateGuestData();
1926
- }, [token, user, hasCheckedUrlToken, projectId]);
1927
- const logout = () => {
1928
- try {
1929
- setToken(null);
1930
- } catch {
1808
+ );
1809
+ };
1810
+
1811
+ // src/components/ui/LimitUpgradeToast.tsx
1812
+ var import_react13 = __toESM(require("react"));
1813
+ var import_react14 = require("@iconify/react");
1814
+
1815
+ // src/components/ui/Toast/ClayxToast.tsx
1816
+ var import_react11 = __toESM(require("react"));
1817
+ var import_react_toastify2 = require("react-toastify");
1818
+ var import_react12 = require("@iconify/react");
1819
+
1820
+ // src/components/theme/ThemeToggle.tsx
1821
+ var React6 = __toESM(require("react"));
1822
+ var import_react10 = require("@iconify/react");
1823
+ var import_jsx_runtime11 = require("react/jsx-runtime");
1824
+ function ThemeToggle({ className }) {
1825
+ const { setTheme, theme } = useTheme();
1826
+ const [mounted, setMounted] = React6.useState(false);
1827
+ React6.useEffect(() => {
1828
+ setMounted(true);
1829
+ }, []);
1830
+ const handleToggle = () => {
1831
+ if (theme === "dark") {
1832
+ setTheme("light");
1833
+ } else {
1834
+ setTheme("dark");
1931
1835
  }
1932
- setTokenState(null);
1933
- setUser(null);
1934
- redirectToAuth();
1935
1836
  };
1936
- const value = {
1937
- user,
1938
- token,
1939
- isAuthenticated: hasCheckedUrlToken && (!!token || isGuest),
1940
- isGuest,
1941
- logout
1942
- };
1943
- if (!hasCheckedUrlToken) return null;
1944
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1945
- ThemeProvider,
1837
+ if (!mounted) {
1838
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react10.Icon, { icon: "solar:sun-bold", width: 20, height: 20 });
1839
+ }
1840
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1841
+ "div",
1946
1842
  {
1947
- defaultTheme,
1948
- storageKey: themeStorageKey,
1949
- forceDefault: forceDefaultTheme,
1950
- children: [
1951
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ElementSelectorProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(HowoneContext.Provider, { value, children: [
1952
- children,
1953
- showFloatingButton && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(FloatingButton, { onClick: () => window.open("https://howone.ai", "_blank") }),
1954
- pendingRedirect && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1955
- "div",
1956
- {
1957
- "data-howone-auth-overlay-root": true,
1958
- className: "fixed inset-0 z-[100000] h-full w-full flex flex-col items-center justify-center bg-black/65 backdrop-blur-sm text-white",
1959
- children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "relative mt-6 flex h-[220px] w-[220px] items-center justify-center", children: [
1960
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1961
- "div",
1962
- {
1963
- className: "absolute inset-0 rounded-full bg-white/20",
1964
- style: { animation: "howone-glow-ring 2.4s ease-in-out infinite" }
1965
- }
1966
- ),
1967
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "absolute inset-0 rounded-full bg-gradient-to-br from-white/10 via-white/25 to-white/10 blur-2xl" }),
1968
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1969
- "img",
1970
- {
1971
- style: { width: 250, animation: "howone-logo-pulse 2s ease-in-out infinite" },
1972
- src: "https://sxwxqoixnnklnpeutjrj.supabase.co/storage/v1/object/public/create-x/logo/logo.svg",
1973
- alt: "HowOne"
1974
- }
1975
- )
1976
- ] })
1977
- }
1978
- )
1979
- ] }) }),
1980
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(GlobalToastContainer, {})
1981
- ]
1843
+ className: `cursor-pointer ${className || ""}`,
1844
+ onClick: handleToggle,
1845
+ children: theme === "light" ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react10.Icon, { icon: "solar:sun-bold", width: 20, height: 20 }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react10.Icon, { icon: "solar:moon-linear", width: 20, height: 20 })
1982
1846
  }
1983
1847
  );
1984
- };
1985
- function useHowoneContext() {
1986
- const ctx = (0, import_react11.useContext)(HowoneContext);
1987
- if (!ctx) {
1988
- const t = getToken();
1989
- const guestMode = isGuestMode() || !!getExistingSessionId();
1990
- return {
1991
- user: parseUserFromToken(t),
1992
- token: t,
1993
- isAuthenticated: !!t || guestMode,
1994
- isGuest: guestMode,
1995
- logout: () => {
1996
- try {
1997
- setToken(null);
1998
- } catch {
1999
- }
2000
- }
2001
- };
2002
- }
2003
- return ctx;
2004
1848
  }
2005
1849
 
2006
- // src/components/index.ts
2007
- init_auth();
2008
-
2009
- // src/howone/client.ts
2010
- init_auth();
2011
- init_config();
2012
- var HowoneAuthClient = class {
2013
- constructor() {
2014
- this.listeners = /* @__PURE__ */ new Set();
2015
- this.loading = false;
2016
- }
2017
- emit() {
2018
- const state = {
2019
- user: parseUserFromToken(getToken()),
2020
- isLoading: this.loading
2021
- };
2022
- for (const l of this.listeners) {
2023
- try {
2024
- l(state);
2025
- } catch (e) {
2026
- void e;
2027
- }
1850
+ // src/components/ui/Toast/ClayxToast.tsx
1851
+ var import_jsx_runtime12 = require("react/jsx-runtime");
1852
+ var TOAST_ICONS = {
1853
+ success: {
1854
+ icon: "mdi:success",
1855
+ color: "text-green-400",
1856
+ className: "text-green-400",
1857
+ // 深色主题配置
1858
+ dark: {
1859
+ bgGradient: "bg-[#14181d]",
1860
+ // 移除透明度 f2
1861
+ gradientColor: "#389726",
1862
+ borderGradient: "border-[#389726]",
1863
+ borderGradientColor: "#389726"
1864
+ },
1865
+ // 浅色主题配置
1866
+ light: {
1867
+ bgGradient: "bg-[#fafafa]",
1868
+ // 移除透明度 ff
1869
+ gradientColor: "#22c55e",
1870
+ borderGradient: "border-[#22c55e]",
1871
+ borderGradientColor: "#22c55e"
2028
1872
  }
2029
- }
2030
- onAuthStateChanged(listener) {
2031
- this.listeners.add(listener);
2032
- try {
2033
- listener({ user: parseUserFromToken(getToken()), isLoading: this.loading });
2034
- } catch (e) {
2035
- void e;
1873
+ },
1874
+ error: {
1875
+ icon: "ic:outline-close",
1876
+ color: "text-red-400",
1877
+ className: "text-red-400",
1878
+ dark: {
1879
+ bgGradient: "bg-[#14181d]",
1880
+ // 移除透明度 f2
1881
+ gradientColor: "#ef4444",
1882
+ borderGradient: "border-[#ef4444]",
1883
+ borderGradientColor: "#ef4444"
1884
+ },
1885
+ light: {
1886
+ bgGradient: "bg-[#fafafa]",
1887
+ // 移除透明度 ff
1888
+ gradientColor: "#f87171",
1889
+ borderGradient: "border-[#f87171]",
1890
+ borderGradientColor: "#f87171"
2036
1891
  }
2037
- return () => {
2038
- this.listeners.delete(listener);
2039
- };
2040
- }
2041
- // Simple redirect-based login trigger (consumer can override)
2042
- login() {
2043
- const root = getEnvs().AUTH_ROOT_VALUE;
2044
- try {
2045
- const loc = window.location.href;
2046
- const authUrl = new URL("/auth", String(root));
2047
- authUrl.searchParams.set("redirect_uri", String(loc));
2048
- try {
2049
- const cfg = (init_config(), __toCommonJS(config_exports));
2050
- const pid = cfg.getDefaultProjectId && cfg.getDefaultProjectId();
2051
- if (pid) authUrl.searchParams.set("project_id", String(pid));
2052
- } catch {
2053
- }
2054
- try {
2055
- if (window.top && window.top !== window) {
2056
- window.top.location.replace(authUrl.toString());
2057
- } else {
2058
- window.location.replace(authUrl.toString());
2059
- }
2060
- } catch {
2061
- try {
2062
- window.location.replace(String(root));
2063
- } catch {
2064
- }
2065
- }
2066
- } catch {
2067
- try {
2068
- window.location.replace(String(root));
2069
- } catch {
2070
- }
1892
+ },
1893
+ warning: {
1894
+ icon: "mi:warning",
1895
+ color: "text-yellow-400",
1896
+ className: "text-yellow-400",
1897
+ dark: {
1898
+ bgGradient: "bg-[#14181d]",
1899
+ // 移除透明度 f2
1900
+ gradientColor: "#facc15",
1901
+ borderGradient: "border-[#facc15]",
1902
+ borderGradientColor: "#facc15"
1903
+ },
1904
+ light: {
1905
+ bgGradient: "bg-[#fafafa]",
1906
+ // 移除透明度 ff
1907
+ gradientColor: "#f59e0b",
1908
+ borderGradient: "border-[#f59e0b]",
1909
+ borderGradientColor: "#f59e0b"
1910
+ }
1911
+ },
1912
+ info: {
1913
+ icon: "ic:outline-info",
1914
+ color: "text-blue-400",
1915
+ className: "text-blue-400",
1916
+ dark: {
1917
+ bgGradient: "bg-[#14181d]",
1918
+ // 移除透明度 f2
1919
+ gradientColor: "#60a5fa",
1920
+ borderGradient: "border-[#60a5fa]",
1921
+ borderGradientColor: "#f0f0f0"
1922
+ },
1923
+ light: {
1924
+ bgGradient: "bg-[#fafafa]",
1925
+ // 移除透明度 ff
1926
+ gradientColor: "#3b82f6",
1927
+ borderGradient: "border-[#3b82f6]",
1928
+ borderGradientColor: "#3b82f6"
1929
+ }
1930
+ },
1931
+ default: {
1932
+ icon: "ic:round-notifications",
1933
+ color: "text-gray-400",
1934
+ className: "text-gray-400",
1935
+ dark: {
1936
+ bgGradient: "bg-[#14181d]",
1937
+ // 移除透明度 f2
1938
+ gradientColor: "#9ca3af",
1939
+ borderGradient: "border-[#9ca3af]",
1940
+ borderGradientColor: "#9ca3af"
1941
+ },
1942
+ light: {
1943
+ bgGradient: "bg-[#fafafa]",
1944
+ // 移除透明度 ff
1945
+ gradientColor: "#6b7280",
1946
+ borderGradient: "border-[#6b7280]",
1947
+ borderGradientColor: "#6b7280"
2071
1948
  }
2072
1949
  }
2073
- logout() {
2074
- setToken(null);
2075
- this.emit();
2076
- }
2077
- getUser() {
2078
- return parseUserFromToken(getToken());
2079
- }
2080
- // helper to programmatically set token (e.g., after callback handling)
2081
- setToken(token) {
2082
- setToken(token);
2083
- this.emit();
2084
- }
2085
- };
2086
- var howone = {
2087
- auth: new HowoneAuthClient()
2088
1950
  };
2089
- var client_default = howone;
2090
-
2091
- // src/components/ui/Loading.tsx
2092
- var import_jsx_runtime10 = require("react/jsx-runtime");
2093
- var Loading = ({
2094
- size = "md",
2095
- text = "Loading...",
2096
- className = "",
2097
- fullScreen = false
2098
- }) => {
2099
- const sizeClasses = {
2100
- sm: "h-4 w-4",
2101
- md: "h-8 w-8",
2102
- lg: "h-12 w-12"
1951
+ var CloseButton = import_react11.default.memo(({ closeToast }) => {
1952
+ const { theme } = useTheme();
1953
+ const handleClick = (0, import_react11.useCallback)((e) => {
1954
+ e.preventDefault();
1955
+ e.stopPropagation();
1956
+ closeToast?.();
1957
+ }, [closeToast]);
1958
+ const getCloseButtonColor = () => {
1959
+ const actualTheme = theme === "system" ? window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light" : theme;
1960
+ return actualTheme === "dark" ? "#b4b4b4" : "#6b7280";
2103
1961
  };
2104
- const containerClasses = fullScreen ? "fixed inset-0 flex items-center justify-center bg-white/80 backdrop-blur-sm z-50" : "flex items-center justify-center p-4";
2105
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: `${containerClasses} ${className}`, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "text-center", children: [
2106
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1962
+ const getCloseButtonHoverColor = () => {
1963
+ const actualTheme = theme === "system" ? window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light" : theme;
1964
+ return actualTheme === "dark" ? "white" : "#374151";
1965
+ };
1966
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1967
+ import_react12.Icon,
1968
+ {
1969
+ icon: "vaadin:close",
1970
+ className: "flex items-center justify-center rounded-full relative z-10 flex-shrink-0 cursor-pointer \n transition-colors duration-200 drop-shadow-sm",
1971
+ onClick: handleClick,
1972
+ width: 14,
1973
+ height: 14,
1974
+ style: {
1975
+ color: getCloseButtonColor()
1976
+ },
1977
+ onMouseEnter: (e) => {
1978
+ e.currentTarget.style.color = getCloseButtonHoverColor();
1979
+ },
1980
+ onMouseLeave: (e) => {
1981
+ e.currentTarget.style.color = getCloseButtonColor();
1982
+ }
1983
+ }
1984
+ );
1985
+ });
1986
+ CloseButton.displayName = "CloseButton";
1987
+ var ToastContent = ({ type, title, message, component, closeToast }) => {
1988
+ const iconConfig = TOAST_ICONS[type];
1989
+ const { theme } = useTheme();
1990
+ const handleClose = (0, import_react11.useCallback)(() => {
1991
+ closeToast?.();
1992
+ }, [closeToast]);
1993
+ const getTextColor = () => {
1994
+ const actualTheme = theme === "system" ? window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light" : theme;
1995
+ return actualTheme === "dark" ? "white" : "#1f2937";
1996
+ };
1997
+ const getThemeConfig = () => {
1998
+ const actualTheme = theme === "system" ? window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light" : theme;
1999
+ return actualTheme === "dark" ? iconConfig.dark : iconConfig.light;
2000
+ };
2001
+ const themeConfig = getThemeConfig();
2002
+ const lightBaseBackgroundByType = {
2003
+ success: "#f0fdf4",
2004
+ // green-50
2005
+ error: "#fef2f2",
2006
+ // red-50
2007
+ warning: "#fffbeb",
2008
+ // amber-50
2009
+ info: "#eff6ff",
2010
+ // blue-50
2011
+ default: "#f9fafb"
2012
+ // gray-50
2013
+ };
2014
+ if (component) {
2015
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: `flex items-start gap-3 !min-h-[90px] w-full backdrop-blur-md p-4 shadow-2xl overflow-hidden ${themeConfig.bgGradient}`, children: [
2016
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "flex-1 relative z-10", children: component }),
2017
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "relative z-10", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(CloseButton, { closeToast: handleClose }) })
2018
+ ] });
2019
+ }
2020
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: `flex items-start gap-3 !min-h-[90px] w-full backdrop-blur-md p-4 shadow-2xl relative overflow-hidden ${themeConfig.bgGradient}`, children: [
2021
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2022
+ "div",
2023
+ {
2024
+ className: "absolute left-0 top-0 w-full h-full rounded-xl",
2025
+ style: {
2026
+ background: theme === "dark" || theme === "system" && window.matchMedia("(prefers-color-scheme: dark)").matches ? "#0f1419" : lightBaseBackgroundByType[type],
2027
+ zIndex: -2
2028
+ }
2029
+ }
2030
+ ),
2031
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2107
2032
  "div",
2108
2033
  {
2109
- className: `animate-spin rounded-full border-2 border-gray-300 border-t-blue-600 mx-auto ${sizeClasses[size]}`
2034
+ className: "absolute left-0 top-0 w-full h-full pointer-events-none rounded-xl",
2035
+ style: {
2036
+ background: theme === "dark" || theme === "system" && window.matchMedia("(prefers-color-scheme: dark)").matches ? `linear-gradient(135deg, ${themeConfig.gradientColor}30 0%, ${themeConfig.gradientColor}20 15%, #14181df2 30%)` : `linear-gradient(135deg, ${themeConfig.gradientColor}20 0%, ${themeConfig.gradientColor}12 15%, #ffffff 30%)`,
2037
+ zIndex: -1
2038
+ }
2110
2039
  }
2111
2040
  ),
2112
- text && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "mt-2 text-sm text-gray-600", children: text })
2113
- ] }) });
2114
- };
2115
- var LoadingSpinner = ({
2116
- size = "md",
2117
- className = ""
2118
- }) => {
2119
- const sizeClasses = {
2120
- sm: "h-4 w-4",
2121
- md: "h-8 w-8",
2122
- lg: "h-12 w-12"
2123
- };
2124
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2125
- "div",
2126
- {
2127
- className: `animate-spin rounded-full border-2 border-gray-300 border-t-blue-600 ${sizeClasses[size]} ${className}`
2128
- }
2129
- );
2130
- };
2131
-
2132
- // src/components/ui/ErrorBoundary.tsx
2133
- var import_react12 = require("react");
2134
- var import_jsx_runtime11 = require("react/jsx-runtime");
2135
- var ErrorBoundary = class extends import_react12.Component {
2136
- constructor(props) {
2137
- super(props);
2138
- this.handleRetry = () => {
2139
- this.setState({ hasError: false, error: void 0, errorInfo: void 0 });
2140
- };
2141
- this.state = { hasError: false };
2142
- }
2143
- static getDerivedStateFromError(error) {
2144
- return { hasError: true, error };
2145
- }
2146
- componentDidCatch(error, errorInfo) {
2147
- this.setState({
2148
- error,
2149
- errorInfo
2150
- });
2151
- this.props.onError?.(error, errorInfo);
2152
- }
2153
- render() {
2154
- if (this.state.hasError) {
2155
- if (this.props.fallback) {
2156
- const FallbackComponent = this.props.fallback;
2157
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(FallbackComponent, { error: this.state.error, retry: this.handleRetry });
2041
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2042
+ "div",
2043
+ {
2044
+ className: "absolute left-0 top-0 w-full h-full pointer-events-none rounded-xl",
2045
+ style: {
2046
+ border: "2px solid transparent",
2047
+ backgroundImage: theme === "dark" || theme === "system" && window.matchMedia("(prefers-color-scheme: dark)").matches ? `linear-gradient(135deg, ${themeConfig.borderGradientColor}60 0%, ${themeConfig.borderGradientColor}40 5%, transparent 22%)` : `linear-gradient(135deg, ${themeConfig.borderGradientColor}99 0%, ${themeConfig.borderGradientColor}66 5%, transparent 22%)`,
2048
+ backgroundOrigin: "border-box",
2049
+ backgroundClip: "border-box",
2050
+ WebkitMask: "linear-gradient(#ffffff 0 0) padding-box, linear-gradient(#ffffff 0 0)",
2051
+ WebkitMaskComposite: "xor",
2052
+ zIndex: 0
2053
+ }
2158
2054
  }
2159
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "min-h-[400px] flex items-center justify-center p-4", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "text-center max-w-md", children: [
2160
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "text-red-500 text-6xl mb-4", children: "\u26A0\uFE0F" }),
2161
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("h2", { className: "text-xl font-semibold text-gray-900 mb-2", children: "Something went wrong" }),
2162
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: "text-gray-600 mb-4", children: "An unexpected error occurred. Please try refreshing the page." }),
2163
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2164
- "button",
2055
+ ),
2056
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "flex-shrink-0 flex-grow-0 mt-0.5 relative z-10", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2057
+ "div",
2058
+ {
2059
+ className: "backdrop-blur-sm rounded-full flex items-center justify-center overflow-hidden flex-shrink-0 flex-grow-0",
2060
+ style: {
2061
+ backgroundColor: theme === "dark" || theme === "system" && window.matchMedia("(prefers-color-scheme: dark)").matches ? "rgba(255, 255, 255, 0.1)" : "rgba(0, 0, 0, 0.05)",
2062
+ width: "28px",
2063
+ height: "28px"
2064
+ },
2065
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "rounded-full flex items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2066
+ import_react12.Icon,
2165
2067
  {
2166
- onClick: this.handleRetry,
2167
- className: "px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition-colors",
2168
- children: "Try Again"
2068
+ icon: iconConfig.icon,
2069
+ width: 16,
2070
+ height: 16,
2071
+ className: `flex-shrink-0`,
2072
+ style: {
2073
+ color: themeConfig.gradientColor,
2074
+ display: "block"
2075
+ }
2169
2076
  }
2170
- ),
2171
- false
2172
- ] }) });
2173
- }
2174
- return this.props.children;
2175
- }
2077
+ ) })
2078
+ }
2079
+ ) }),
2080
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex flex-col gap-1 flex-1 relative z-10", children: [
2081
+ title && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2082
+ "div",
2083
+ {
2084
+ className: "text-[16px] font-semibold leading-tight drop-shadow-sm",
2085
+ style: {
2086
+ color: getTextColor(),
2087
+ backgroundClip: "text"
2088
+ },
2089
+ children: title
2090
+ }
2091
+ ),
2092
+ message && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2093
+ "div",
2094
+ {
2095
+ className: "text-[13px] font-normal leading-relaxed drop-shadow-sm",
2096
+ style: {
2097
+ color: getTextColor(),
2098
+ backgroundClip: "text"
2099
+ },
2100
+ children: message
2101
+ }
2102
+ )
2103
+ ] }),
2104
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "relative z-10", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(CloseButton, { closeToast: handleClose }) })
2105
+ ] });
2176
2106
  };
2177
- var DefaultErrorFallback = ({ retry }) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "min-h-[200px] flex items-center justify-center p-4", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "text-center", children: [
2178
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "text-red-500 text-4xl mb-2", children: "\u26A0\uFE0F" }),
2179
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: "text-gray-600 mb-2", children: "Something went wrong" }),
2180
- retry && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2181
- "button",
2182
- {
2183
- onClick: retry,
2184
- className: "px-3 py-1 bg-blue-600 text-white text-sm rounded hover:bg-blue-700 transition-colors",
2185
- children: "Retry"
2186
- }
2187
- )
2188
- ] }) });
2189
-
2190
- // src/components/ui/ClayxButton.tsx
2191
- var import_jsx_runtime12 = require("react/jsx-runtime");
2192
- var getSizeClasses = (size, isIconOnly) => {
2193
- if (isIconOnly) {
2194
- switch (size) {
2195
- case "sm":
2196
- return "h-8 w-8 min-w-8 p-0";
2197
- case "md":
2198
- return "h-10 w-10 min-w-10 p-0";
2199
- case "lg":
2200
- return "h-12 w-12 min-w-12 p-0";
2201
- default:
2202
- return "h-10 w-10 min-w-10 p-0";
2203
- }
2204
- }
2205
- switch (size) {
2206
- case "sm":
2207
- return "h-8 px-3 text-sm";
2208
- case "md":
2209
- return "h-10 px-4 text-base";
2210
- case "lg":
2211
- return "h-12 px-6 text-lg";
2212
- default:
2213
- return "h-10 px-4 text-base";
2214
- }
2107
+ var defaultToastOptions = {
2108
+ position: "bottom-right",
2109
+ autoClose: 1500,
2110
+ hideProgressBar: true,
2111
+ closeOnClick: false,
2112
+ pauseOnHover: true,
2113
+ draggable: true,
2114
+ pauseOnFocusLoss: false,
2115
+ transition: import_react_toastify2.Bounce
2215
2116
  };
2216
- var getVariantClasses = (variant) => {
2217
- switch (variant) {
2218
- case "solid":
2219
- return "bg-primary text-white hover:bg-primary/90";
2220
- case "ghost":
2221
- return "bg-transparent hover:bg-white/10";
2222
- case "flat":
2223
- return "bg-white/5 hover:bg-white/10";
2224
- default:
2225
- return "";
2117
+ var getToastifyTheme = () => {
2118
+ if (typeof window !== "undefined") {
2119
+ const root = document.documentElement;
2120
+ if (root.classList.contains("dark")) return "dark";
2121
+ if (root.classList.contains("light")) return "light";
2122
+ return window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
2226
2123
  }
2124
+ return "light";
2227
2125
  };
2228
- var ClayxButton = ({
2229
- isIconOnly = false,
2230
- size = "md",
2231
- variant = "solid",
2232
- className = "",
2233
- children,
2234
- disabled = false,
2235
- ...props
2236
- }) => {
2237
- const sizeClasses = getSizeClasses(size, isIconOnly);
2238
- const variantClasses = getVariantClasses(variant);
2239
- const baseClasses = `
2240
- inline-flex items-center justify-center
2241
- rounded-md font-medium
2242
- transition-all duration-200
2243
- focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-transparent
2244
- disabled:opacity-50 disabled:cursor-not-allowed disabled:pointer-events-none
2245
- `.replace(/\s+/g, " ").trim();
2246
- const combinedClasses = `${baseClasses} ${sizeClasses} ${variantClasses} ${className}`.trim();
2247
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2248
- "button",
2249
- {
2250
- className: combinedClasses,
2251
- disabled,
2252
- ...props,
2253
- children
2254
- }
2255
- );
2126
+ var createToast = (type) => {
2127
+ return (params) => {
2128
+ const { title, message, component, options } = params;
2129
+ (0, import_react_toastify2.toast)(
2130
+ ({ closeToast }) => {
2131
+ if (params.render) return params.render(closeToast);
2132
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2133
+ ToastContent,
2134
+ {
2135
+ type,
2136
+ title,
2137
+ message: message || "",
2138
+ component,
2139
+ closeToast
2140
+ }
2141
+ );
2142
+ },
2143
+ {
2144
+ ...defaultToastOptions,
2145
+ ...options,
2146
+ theme: getToastifyTheme(),
2147
+ // 确保圆角样式不被覆盖,添加 rounded-xl 类
2148
+ className: "!p-0 !shadow-none !rounded-xl",
2149
+ style: { padding: 0, borderRadius: "0.75rem", backgroundColor: "transparent" }
2150
+ }
2151
+ );
2152
+ };
2153
+ };
2154
+ var ClayxToast = {
2155
+ success: createToast("success"),
2156
+ error: createToast("error"),
2157
+ warning: createToast("warning"),
2158
+ info: createToast("info"),
2159
+ default: createToast("default")
2256
2160
  };
2257
2161
 
2258
2162
  // src/components/ui/LimitUpgradeToast.tsx
2259
- var import_react13 = __toESM(require("react"));
2260
- var import_react14 = require("@iconify/react");
2261
2163
  var import_jsx_runtime13 = require("react/jsx-runtime");
2262
- var PremiumActionToast = ({
2263
- message,
2264
- onAction,
2265
- closeToast,
2266
- buttonText = "Upgrade Now",
2267
- title = "Information",
2268
- variant = "purple"
2269
- }) => {
2164
+ var LimitToastContainer = ({ message, onUpgrade, closeToast }) => {
2270
2165
  const [hover, setHover] = import_react13.default.useState(false);
2271
2166
  const [closeHover, setCloseHover] = import_react13.default.useState(false);
2272
- const colors = {
2273
- purple: {
2274
- gradient1: "rgba(168,85,247,0.3)",
2275
- gradient2: "rgba(168,85,247,0.2)",
2276
- borderStart: "rgba(168,85,247,0.8)",
2277
- borderEnd: "rgba(168,85,247,0.5)",
2278
- bgGlow1: "from-purple-500/20 via-pink-500/10",
2279
- bgGlow2: "from-blue-500/10",
2280
- tagBg: "bg-purple-500/30",
2281
- tagText: "text-white",
2282
- tagBorder: "border border-purple-400/50",
2283
- borderColor: "#a855f7",
2284
- btnGradient: hover ? "linear-gradient(to right, #9333ea, #db2777)" : "linear-gradient(to right, #a855f7, #ec4899)",
2285
- btnShadow: "0 10px 15px -3px rgba(168,85,247,0.3), 0 4px 6px -2px rgba(168,85,247,0.3)",
2286
- shadow: "0_20px_60px_rgba(168,85,247,0.2)",
2287
- badge: "Premium"
2288
- },
2289
- blue: {
2290
- gradient1: "rgba(59,130,246,0.3)",
2291
- gradient2: "rgba(59,130,246,0.2)",
2292
- borderStart: "rgba(59,130,246,0.8)",
2293
- borderEnd: "rgba(59,130,246,0.5)",
2294
- bgGlow1: "from-blue-500/20 via-cyan-500/10",
2295
- bgGlow2: "from-indigo-500/10",
2296
- tagBg: "bg-blue-500/30",
2297
- tagText: "text-white",
2298
- tagBorder: "border border-blue-400/50",
2299
- borderColor: "#3b82f6",
2300
- btnGradient: hover ? "linear-gradient(to right, #1d4ed8, #0ea5e9)" : "linear-gradient(to right, #3b82f6, #06b6d4)",
2301
- btnShadow: "0 10px 15px -3px rgba(59,130,246,0.3), 0 4px 6px -2px rgba(59,130,246,0.3)",
2302
- shadow: "0_20px_60px_rgba(59,130,246,0.2)",
2303
- badge: "Secure"
2304
- }
2305
- }[variant];
2306
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: `relative w-full max-w-[420px] overflow-hidden rounded-md bg-gradient-to-br from-[#1A1A1A] via-[#151515] to-[#1A1A1A] shadow-[${colors.shadow}] backdrop-blur-sm`, children: [
2167
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "relative w-full max-w-[420px] overflow-hidden rounded-md bg-gradient-to-br from-[#1A1A1A] via-[#151515] to-[#1A1A1A] shadow-[0_20px_60px_rgba(168,85,247,0.2)] backdrop-blur-sm", children: [
2307
2168
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2308
2169
  "div",
2309
2170
  {
@@ -2319,7 +2180,7 @@ var PremiumActionToast = ({
2319
2180
  {
2320
2181
  className: "absolute left-0 top-0 w-full h-full pointer-events-none rounded-md",
2321
2182
  style: {
2322
- background: `linear-gradient(135deg, ${colors.gradient1} 0%, ${colors.gradient2} 15%, #1A1A1A 30%)`,
2183
+ background: `linear-gradient(135deg, rgba(168,85,247,0.3) 0%, rgba(168,85,247,0.2) 15%, #1A1A1A 30%)`,
2323
2184
  zIndex: -1
2324
2185
  }
2325
2186
  }
@@ -2330,7 +2191,7 @@ var PremiumActionToast = ({
2330
2191
  className: "absolute left-0 top-0 w-full h-full pointer-events-none rounded-md",
2331
2192
  style: {
2332
2193
  border: "2px solid transparent",
2333
- backgroundImage: `linear-gradient(135deg, ${colors.borderStart} 0%, ${colors.borderEnd} 5%, transparent 22%)`,
2194
+ backgroundImage: `linear-gradient(135deg, rgba(168,85,247,0.6) 0%, rgba(168,85,247,0.4) 5%, transparent 22%)`,
2334
2195
  backgroundOrigin: "border-box",
2335
2196
  backgroundClip: "border-box",
2336
2197
  WebkitMask: "linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0)",
@@ -2340,20 +2201,13 @@ var PremiumActionToast = ({
2340
2201
  }
2341
2202
  }
2342
2203
  ),
2343
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: `absolute -top-16 -right-16 h-32 w-32 rounded-full bg-gradient-to-br ${colors.bgGlow1} to-transparent blur-3xl animate-pulse` }),
2344
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: `absolute -bottom-16 -left-16 h-32 w-32 rounded-full bg-gradient-to-tr ${colors.bgGlow2} to-transparent blur-2xl animate-pulse`, style: { animationDelay: "1s" } }),
2204
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "absolute -top-16 -right-16 h-32 w-32 rounded-full bg-gradient-to-br from-purple-500/20 via-pink-500/10 to-transparent blur-3xl animate-pulse" }),
2205
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "absolute -bottom-16 -left-16 h-32 w-32 rounded-full bg-gradient-to-tr from-blue-500/10 to-transparent blur-2xl animate-pulse", style: { animationDelay: "1s" } }),
2345
2206
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "relative z-10 flex items-start gap-4 p-4", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex flex-1 flex-col gap-3", children: [
2346
2207
  /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center justify-between", children: [
2347
2208
  /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center gap-2", children: [
2348
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "text-lg font-bold text-white", children: title }),
2349
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2350
- "div",
2351
- {
2352
- className: `px-2 py-0.5 text-xs font-bold ${colors.tagBg} ${colors.tagText} rounded-md border`,
2353
- style: { borderColor: colors.borderColor },
2354
- children: colors.badge
2355
- }
2356
- )
2209
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "text-lg font-bold text-white", children: "Upgrade Required" }),
2210
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "px-2 py-0.5 text-xs font-bold bg-purple-500/20 text-purple-400 rounded-md border border-purple-500/30", children: "Premium" })
2357
2211
  ] }),
2358
2212
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2359
2213
  ClayxButton,
@@ -2372,16 +2226,16 @@ var PremiumActionToast = ({
2372
2226
  transition: "background-color 150ms ease",
2373
2227
  cursor: "pointer"
2374
2228
  },
2375
- children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react14.Icon, { icon: "iconamoon:close", className: "w-4 h-4 text-gray-300" })
2229
+ children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react14.Icon, { icon: "iconamoon:close", className: "w-4 h-4 text-gray-400" })
2376
2230
  }
2377
2231
  )
2378
2232
  ] }),
2379
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "text-sm text-white leading-relaxed font-medium", children: message }),
2233
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "text-sm text-gray-300 leading-relaxed", children: message }),
2380
2234
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "mt-1 flex items-center gap-3", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2381
2235
  ClayxButton,
2382
2236
  {
2383
2237
  onClick: () => {
2384
- onAction();
2238
+ onUpgrade();
2385
2239
  closeToast?.();
2386
2240
  },
2387
2241
  onMouseEnter: () => setHover(true),
@@ -2392,31 +2246,21 @@ var PremiumActionToast = ({
2392
2246
  fontWeight: 600,
2393
2247
  cursor: "pointer",
2394
2248
  transition: "all 300ms ease-in-out",
2395
- backgroundImage: colors.btnGradient,
2396
- boxShadow: hover ? colors.btnShadow : "none"
2249
+ backgroundImage: hover ? "linear-gradient(to right, #9333ea, #db2777)" : "linear-gradient(to right, #a855f7, #ec4899)",
2250
+ boxShadow: hover ? "0 10px 15px -3px rgba(168,85,247,0.3), 0 4px 6px -2px rgba(168,85,247,0.3)" : "none"
2397
2251
  },
2398
2252
  children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { className: "flex items-center gap-2", children: [
2399
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react14.Icon, { icon: variant === "purple" ? "solar:rocket-2-bold" : "solar:login-3-bold", className: "w-4 h-4" }),
2400
- buttonText
2253
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react14.Icon, { icon: "solar:rocket-2-bold", className: "w-4 h-4" }),
2254
+ "Upgrade Now"
2401
2255
  ] })
2402
2256
  }
2403
2257
  ) })
2404
2258
  ] }) })
2405
2259
  ] });
2406
2260
  };
2407
- function showPremiumActionToast(message, onAction, buttonText, title, variant = "purple") {
2261
+ function showLimitUpgradeToast(message, onUpgrade) {
2408
2262
  ClayxToast.default({
2409
- render: (closeToast) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2410
- PremiumActionToast,
2411
- {
2412
- message,
2413
- onAction,
2414
- closeToast,
2415
- buttonText,
2416
- title,
2417
- variant
2418
- }
2419
- ),
2263
+ render: (closeToast) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(LimitToastContainer, { message, onUpgrade, closeToast }),
2420
2264
  options: {
2421
2265
  position: "bottom-right",
2422
2266
  closeOnClick: false,
@@ -2434,12 +2278,6 @@ function showPremiumActionToast(message, onAction, buttonText, title, variant =
2434
2278
  }
2435
2279
  });
2436
2280
  }
2437
- function showLimitUpgradeToast(message, onUpgrade, buttonText, title) {
2438
- showPremiumActionToast(message, onUpgrade, buttonText, title, "purple");
2439
- }
2440
- function showSignInRequiredToast(message, onSignIn, buttonText, title) {
2441
- showPremiumActionToast(message, onSignIn, buttonText, title, "blue");
2442
- }
2443
2281
 
2444
2282
  // src/services/ai-workflow.ts
2445
2283
  var AIWorkflowClient = class {
@@ -2815,11 +2653,6 @@ async function executeSSEWorkflow(request, options = {}) {
2815
2653
  };
2816
2654
  if (options.authToken) {
2817
2655
  headers["Authorization"] = `Bearer ${options.authToken}`;
2818
- } else {
2819
- const sessionId = getGuestSessionId();
2820
- if (sessionId) {
2821
- headers["X-Session-Id"] = sessionId;
2822
- }
2823
2656
  }
2824
2657
  const method = request.method?.toUpperCase() ?? "POST";
2825
2658
  const hasBody = request.body && Object.keys(request.body).length > 0;
@@ -2834,23 +2667,7 @@ async function executeSSEWorkflow(request, options = {}) {
2834
2667
  signal: options.signal
2835
2668
  });
2836
2669
  if (!response.ok) {
2837
- if (response.status === 403) {
2838
- showSignInRequiredToast(
2839
- "Free trial limit reached. Please sign in to continue.",
2840
- () => {
2841
- const authUrl = getEnvs().AUTH_ROOT_VALUE;
2842
- const redirectUri = window.location.href;
2843
- const projectId = getDefaultProjectId();
2844
- let authHref = `${authUrl}/auth?redirect_uri=${encodeURIComponent(redirectUri)}`;
2845
- if (projectId) {
2846
- authHref += `&project_id=${encodeURIComponent(projectId)}`;
2847
- }
2848
- window.location.href = authHref;
2849
- },
2850
- "Sign In",
2851
- "Sign In Required"
2852
- );
2853
- }
2670
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
2854
2671
  }
2855
2672
  const reader = response.body?.getReader();
2856
2673
  if (!reader) {
@@ -3603,11 +3420,6 @@ function createClient(opts) {
3603
3420
  const availableToken = getAvailableToken();
3604
3421
  if (availableToken) {
3605
3422
  config.headers["Authorization"] = `Bearer ${availableToken}`;
3606
- } else {
3607
- const sessionId = getGuestSessionId();
3608
- if (sessionId) {
3609
- config.headers["X-Session-Id"] = sessionId;
3610
- }
3611
3423
  }
3612
3424
  }
3613
3425
  return config;
@@ -4429,7 +4241,6 @@ var elementSelector = {
4429
4241
  ThemeToggle,
4430
4242
  aiWorkflow,
4431
4243
  canAccessArtifact,
4432
- clearGuestSession,
4433
4244
  createAIWorkflowClient,
4434
4245
  createAIWorkflowClientAxios,
4435
4246
  createArtifactsClient,
@@ -4444,12 +4255,10 @@ var elementSelector = {
4444
4255
  getEnvironment,
4445
4256
  getEnvs,
4446
4257
  getGlobalEnvironment,
4447
- getGuestSessionId,
4448
4258
  getToken,
4449
4259
  howone,
4450
4260
  iframeNavigation,
4451
4261
  initIframeNavigation,
4452
- isGuestMode,
4453
4262
  isTokenValid,
4454
4263
  loginWithEmailCode,
4455
4264
  onAuthStateChanged,
@@ -4460,8 +4269,6 @@ var elementSelector = {
4460
4269
  setEnvironment,
4461
4270
  setToken,
4462
4271
  showLimitUpgradeToast,
4463
- showPremiumActionToast,
4464
- showSignInRequiredToast,
4465
4272
  unifiedAuth,
4466
4273
  unifiedOAuth,
4467
4274
  useAuth,