@howone/sdk 0.3.21 → 0.3.23

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