@howone/sdk 0.1.27 → 0.1.28

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
@@ -239,6 +239,8 @@ __export(index_exports, {
239
239
  DEFAULT_SELECTOR_CONFIG: () => DEFAULT_SELECTOR_CONFIG,
240
240
  DefaultErrorFallback: () => DefaultErrorFallback,
241
241
  ERROR_CONFIG: () => ERROR_CONFIG,
242
+ ElementSelector: () => ElementSelector,
243
+ ElementSelectorProvider: () => ElementSelectorProvider,
242
244
  ErrorBoundary: () => ErrorBoundary,
243
245
  ErrorHandler: () => ErrorHandler,
244
246
  FloatingButton: () => FloatingButton,
@@ -268,6 +270,7 @@ __export(index_exports, {
268
270
  onAuthStateChanged: () => onAuthStateChanged,
269
271
  parseUserFromToken: () => parseUserFromToken,
270
272
  request: () => request,
273
+ sendElementSelectionToParent: () => sendElementSelectionToParent,
271
274
  sendEmailVerificationCode: () => sendEmailVerificationCode,
272
275
  setAuthRoot: () => setAuthRoot,
273
276
  setDefaultProjectId: () => setDefaultProjectId,
@@ -276,6 +279,7 @@ __export(index_exports, {
276
279
  unifiedOAuth: () => unifiedOAuth,
277
280
  useAuth: () => useAuth,
278
281
  useDebounce: () => useDebounce,
282
+ useElementSelector: () => useElementSelector,
279
283
  useHowoneContext: () => useHowoneContext,
280
284
  useIsMobile: () => useIsMobile,
281
285
  useTheme: () => useTheme,
@@ -1581,7 +1585,7 @@ var LoginForm = ({
1581
1585
  };
1582
1586
 
1583
1587
  // src/components/auth/HowoneProvider.tsx
1584
- var import_react5 = require("react");
1588
+ var import_react8 = require("react");
1585
1589
  init_auth();
1586
1590
 
1587
1591
  // src/components/theme/ThemeProvider.tsx
@@ -1650,869 +1654,444 @@ function GlobalToastContainer() {
1650
1654
  );
1651
1655
  }
1652
1656
 
1653
- // src/components/auth/HowoneProvider.tsx
1657
+ // src/components/ElementSelectorProvider.tsx
1658
+ var import_react7 = require("react");
1659
+
1660
+ // src/components/ElementSelector.tsx
1661
+ var import_react5 = require("react");
1654
1662
  var import_jsx_runtime5 = require("react/jsx-runtime");
1655
- var HowoneContext = (0, import_react5.createContext)(null);
1656
- var HowOneProvider = ({
1657
- children,
1658
- showFloatingButton = true,
1659
- projectId,
1660
- defaultTheme = "system",
1661
- themeStorageKey = "howone-theme",
1662
- forceDefaultTheme = false,
1663
- authUrl = "https://howone.dev/auth",
1664
- redirectOnUnauthenticated = true
1663
+ var ElementSelector = ({
1664
+ active,
1665
+ onSelect,
1666
+ onCancel
1665
1667
  }) => {
1666
- const [user, setUser] = (0, import_react5.useState)(() => parseUserFromToken(getToken()));
1667
- const [token, setTokenState] = (0, import_react5.useState)(() => getToken());
1668
- const [hasCheckedUrlToken, setHasCheckedUrlToken] = (0, import_react5.useState)(false);
1669
- (0, import_react5.useEffect)(() => {
1670
- try {
1671
- const params = new URLSearchParams(window.location.search);
1672
- let urlToken = params.get("access_token") || params.get("token");
1673
- if (!urlToken && window.location.hash) {
1674
- const hashParams = new URLSearchParams(window.location.hash.slice(1));
1675
- urlToken = hashParams.get("access_token") || hashParams.get("token");
1676
- }
1677
- if (urlToken) {
1678
- console.log("[HowOneProvider] Token captured from URL, storing to localStorage...");
1679
- setToken(urlToken);
1680
- setTokenState(urlToken);
1681
- setUser(parseUserFromToken(urlToken));
1682
- params.delete("access_token");
1683
- params.delete("token");
1684
- params.delete("project_id");
1685
- const newSearch = params.toString();
1686
- const newUrl = window.location.pathname + (newSearch ? "?" + newSearch : "");
1687
- window.history.replaceState({}, "", newUrl);
1688
- console.log("[HowOneProvider] Token stored successfully, URL cleaned");
1689
- }
1690
- } catch (e) {
1691
- console.error("[HowOneProvider] Failed to capture token from URL:", e);
1692
- } finally {
1693
- setHasCheckedUrlToken(true);
1694
- }
1695
- }, []);
1696
- (0, import_react5.useEffect)(() => {
1697
- if (!hasCheckedUrlToken) {
1698
- return;
1699
- }
1700
- if (redirectOnUnauthenticated && !token && !user) {
1701
- const currentUrl = new URL(window.location.href);
1702
- if (!currentUrl.pathname.includes("/auth")) {
1703
- console.log("[HowOneProvider] No token found, redirecting to auth page...");
1668
+ const [hoveredElement, setHoveredElement] = (0, import_react5.useState)(null);
1669
+ const [highlightRect, setHighlightRect] = (0, import_react5.useState)(null);
1670
+ const overlayRef = (0, import_react5.useRef)(null);
1671
+ const getSourceLocation = (0, import_react5.useCallback)((element) => {
1672
+ let current = element;
1673
+ while (current && current !== document.body) {
1674
+ const sourceLocationAttr = current.getAttribute("data-source-location");
1675
+ if (sourceLocationAttr) {
1704
1676
  try {
1705
- const authUrlObj = new URL(authUrl);
1706
- const redirectUri = window.location.href;
1707
- authUrlObj.searchParams.set("redirect_uri", redirectUri);
1708
- if (projectId) {
1709
- authUrlObj.searchParams.set("project_id", projectId);
1710
- }
1711
- console.log("[HowOneProvider] Redirecting to:", authUrlObj.toString());
1712
- window.location.href = authUrlObj.toString();
1713
- } catch (error) {
1714
- console.error("[HowOneProvider] Failed to build auth URL:", error);
1715
- window.location.href = authUrl;
1677
+ return JSON.parse(sourceLocationAttr.replace(/"/g, '"'));
1678
+ } catch (e) {
1679
+ console.error("Failed to parse source location:", e);
1716
1680
  }
1717
1681
  }
1682
+ current = current.parentElement;
1718
1683
  }
1719
- }, [token, user, redirectOnUnauthenticated, authUrl, projectId, hasCheckedUrlToken]);
1720
- const logout = () => {
1721
- try {
1722
- setToken(null);
1723
- } catch {
1724
- }
1725
- setTokenState(null);
1726
- setUser(null);
1727
- };
1728
- const value = {
1729
- user,
1730
- token,
1731
- isAuthenticated: !!token,
1732
- logout
1733
- };
1734
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1735
- ThemeProvider,
1736
- {
1737
- defaultTheme,
1738
- storageKey: themeStorageKey,
1739
- forceDefault: forceDefaultTheme,
1740
- children: [
1741
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(HowoneContext.Provider, { value, children: [
1742
- children,
1743
- showFloatingButton && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(FloatingButton, { onClick: () => window.open("https://howone.ai", "_blank") })
1744
- ] }),
1745
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(GlobalToastContainer, {})
1746
- ]
1747
- }
1748
- );
1749
- };
1750
- function useHowoneContext() {
1751
- const ctx = (0, import_react5.useContext)(HowoneContext);
1752
- if (!ctx) {
1753
- const t = getToken();
1754
- return {
1755
- user: parseUserFromToken(t),
1756
- token: t,
1757
- isAuthenticated: !!t,
1758
- logout: () => {
1759
- try {
1760
- setToken(null);
1761
- } catch {
1762
- }
1684
+ return null;
1685
+ }, []);
1686
+ const handleMouseMove = (0, import_react5.useCallback)((e) => {
1687
+ if (!active) return;
1688
+ const elements = document.elementsFromPoint(e.clientX, e.clientY);
1689
+ const targetElement = elements.find(
1690
+ (el) => el !== overlayRef.current && !overlayRef.current?.contains(el) && el !== document.body && el !== document.documentElement
1691
+ );
1692
+ if (targetElement && targetElement !== hoveredElement) {
1693
+ setHoveredElement(targetElement);
1694
+ const rect = targetElement.getBoundingClientRect();
1695
+ setHighlightRect(rect);
1696
+ }
1697
+ }, [active, hoveredElement]);
1698
+ const handleClick = (0, import_react5.useCallback)((e) => {
1699
+ if (!active || !hoveredElement) return;
1700
+ e.preventDefault();
1701
+ e.stopPropagation();
1702
+ const sourceLocation = getSourceLocation(hoveredElement);
1703
+ const rect = hoveredElement.getBoundingClientRect();
1704
+ const elementData = {
1705
+ sourceLocation,
1706
+ element: {
1707
+ tagName: hoveredElement.tagName,
1708
+ className: hoveredElement.className,
1709
+ id: hoveredElement.id,
1710
+ text: hoveredElement.textContent?.substring(0, 100) || ""
1711
+ },
1712
+ rect: {
1713
+ top: rect.top,
1714
+ left: rect.left,
1715
+ width: rect.width,
1716
+ height: rect.height
1763
1717
  }
1764
1718
  };
1765
- }
1766
- return ctx;
1767
- }
1768
-
1769
- // src/components/index.ts
1770
- init_auth();
1771
-
1772
- // src/howone/client.ts
1773
- init_auth();
1774
- init_config();
1775
- var HowoneAuthClient = class {
1776
- constructor() {
1777
- this.listeners = /* @__PURE__ */ new Set();
1778
- this.loading = false;
1779
- }
1780
- emit() {
1781
- const state = {
1782
- user: parseUserFromToken(getToken()),
1783
- isLoading: this.loading
1784
- };
1785
- for (const l of this.listeners) {
1786
- try {
1787
- l(state);
1788
- } catch (e) {
1789
- void e;
1719
+ if (onSelect) {
1720
+ onSelect(elementData);
1721
+ if (onCancel) {
1722
+ onCancel();
1790
1723
  }
1791
1724
  }
1792
- }
1793
- onAuthStateChanged(listener) {
1794
- this.listeners.add(listener);
1795
- try {
1796
- listener({ user: parseUserFromToken(getToken()), isLoading: this.loading });
1797
- } catch (e) {
1798
- void e;
1725
+ }, [active, hoveredElement, getSourceLocation, onSelect, onCancel]);
1726
+ (0, import_react5.useEffect)(() => {
1727
+ if (active) {
1728
+ document.addEventListener("mousemove", handleMouseMove);
1729
+ document.addEventListener("click", handleClick, true);
1730
+ document.body.style.overflow = "hidden";
1731
+ return () => {
1732
+ document.removeEventListener("mousemove", handleMouseMove);
1733
+ document.removeEventListener("click", handleClick, true);
1734
+ document.body.style.overflow = "";
1735
+ };
1736
+ } else {
1737
+ setHoveredElement(null);
1738
+ setHighlightRect(null);
1799
1739
  }
1800
- return () => {
1801
- this.listeners.delete(listener);
1802
- };
1803
- }
1804
- // Simple redirect-based login trigger (consumer can override)
1805
- login() {
1806
- const root = getAuthRoot() || "https://create-x-backend-dev.fly.dev";
1807
- try {
1808
- const loc = window.location.href;
1809
- const authUrl = new URL("/auth", String(root));
1810
- authUrl.searchParams.set("redirect_uri", String(loc));
1811
- try {
1812
- const cfg = (init_config(), __toCommonJS(config_exports));
1813
- const pid = cfg.getDefaultProjectId && cfg.getDefaultProjectId();
1814
- if (pid) authUrl.searchParams.set("project_id", String(pid));
1815
- } catch {
1816
- }
1817
- try {
1818
- if (window.top && window.top !== window) {
1819
- window.top.location.replace(authUrl.toString());
1820
- } else {
1821
- window.location.replace(authUrl.toString());
1740
+ }, [active, handleMouseMove, handleClick]);
1741
+ if (!active) return null;
1742
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1743
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1744
+ "div",
1745
+ {
1746
+ ref: overlayRef,
1747
+ style: {
1748
+ position: "fixed",
1749
+ top: 0,
1750
+ left: 0,
1751
+ right: 0,
1752
+ bottom: 0,
1753
+ backgroundColor: "rgba(0, 0, 0, 0.3)",
1754
+ zIndex: 999998,
1755
+ cursor: "crosshair",
1756
+ pointerEvents: "none"
1822
1757
  }
1823
- } catch {
1824
- try {
1825
- window.location.replace(String(root));
1826
- } catch {
1758
+ }
1759
+ ),
1760
+ highlightRect && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1761
+ "div",
1762
+ {
1763
+ style: {
1764
+ position: "fixed",
1765
+ top: highlightRect.top,
1766
+ left: highlightRect.left,
1767
+ width: highlightRect.width,
1768
+ height: highlightRect.height,
1769
+ border: "2px dashed #36D2A6",
1770
+ borderRadius: "5px",
1771
+ backgroundColor: "rgba(54, 210, 166, 0.1)",
1772
+ zIndex: 999999,
1773
+ pointerEvents: "none",
1774
+ transition: "all 0.1s ease"
1827
1775
  }
1828
1776
  }
1829
- } catch {
1830
- try {
1831
- window.location.replace(String(root));
1832
- } catch {
1777
+ ),
1778
+ hoveredElement && highlightRect && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1779
+ "div",
1780
+ {
1781
+ style: {
1782
+ position: "fixed",
1783
+ top: highlightRect.top - 30,
1784
+ left: highlightRect.left,
1785
+ backgroundColor: "#36D2A6",
1786
+ color: "white",
1787
+ padding: "4px 8px",
1788
+ borderRadius: "4px",
1789
+ fontSize: "12px",
1790
+ zIndex: 1e6,
1791
+ pointerEvents: "none",
1792
+ whiteSpace: "nowrap"
1793
+ },
1794
+ children: (() => {
1795
+ const location = getSourceLocation(hoveredElement);
1796
+ return location ? `${location.component} (${location.file}:${location.line})` : hoveredElement.tagName.toLowerCase();
1797
+ })()
1833
1798
  }
1834
- }
1835
- }
1836
- logout() {
1837
- setToken(null);
1838
- this.emit();
1839
- }
1840
- getUser() {
1841
- return parseUserFromToken(getToken());
1842
- }
1843
- // helper to programmatically set token (e.g., after callback handling)
1844
- setToken(token) {
1845
- setToken(token);
1846
- this.emit();
1847
- }
1848
- };
1849
- var howone = {
1850
- auth: new HowoneAuthClient()
1799
+ )
1800
+ ] });
1851
1801
  };
1852
- var client_default = howone;
1853
1802
 
1854
- // src/components/ui/Loading.tsx
1855
- var import_jsx_runtime6 = require("react/jsx-runtime");
1856
- var Loading = ({
1857
- size = "md",
1858
- text = "Loading...",
1859
- className = "",
1860
- fullScreen = false
1861
- }) => {
1862
- const sizeClasses = {
1863
- sm: "h-4 w-4",
1864
- md: "h-8 w-8",
1865
- lg: "h-12 w-12"
1803
+ // src/hooks/use-element-selector.ts
1804
+ var import_react6 = require("react");
1805
+ function useElementSelector() {
1806
+ const [isSelecting, setIsSelecting] = (0, import_react6.useState)(false);
1807
+ const [selectedElement, setSelectedElement] = (0, import_react6.useState)(null);
1808
+ const startSelecting = (0, import_react6.useCallback)(() => {
1809
+ setIsSelecting(true);
1810
+ }, []);
1811
+ const stopSelecting = (0, import_react6.useCallback)(() => {
1812
+ setIsSelecting(false);
1813
+ }, []);
1814
+ const clearSelection = (0, import_react6.useCallback)(() => {
1815
+ setSelectedElement(null);
1816
+ }, []);
1817
+ return {
1818
+ isSelecting,
1819
+ selectedElement,
1820
+ startSelecting,
1821
+ stopSelecting,
1822
+ clearSelection
1866
1823
  };
1867
- 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";
1868
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: `${containerClasses} ${className}`, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "text-center", children: [
1824
+ }
1825
+ function sendElementSelectionToParent(data) {
1826
+ if (window.parent && window.parent !== window) {
1827
+ window.parent.postMessage({
1828
+ type: "ELEMENT_SELECTED",
1829
+ payload: data
1830
+ }, "*");
1831
+ }
1832
+ }
1833
+
1834
+ // src/components/ElementSelectorProvider.tsx
1835
+ var import_jsx_runtime6 = require("react/jsx-runtime");
1836
+ var ElementSelectorProvider = ({ children }) => {
1837
+ const [isSelecting, setIsSelecting] = (0, import_react7.useState)(false);
1838
+ const handleCancel = (0, import_react7.useCallback)(() => {
1839
+ setIsSelecting(false);
1840
+ if (window.parent && window.parent !== window) {
1841
+ window.parent.postMessage({
1842
+ type: "ELEMENT_SELECTION_CANCELLED"
1843
+ }, "*");
1844
+ }
1845
+ console.log("\u{1F6AB} \u5143\u7D20\u9009\u62E9\u5DF2\u53D6\u6D88 (ESC)");
1846
+ }, []);
1847
+ const handleSelect = (0, import_react7.useCallback)((data) => {
1848
+ sendElementSelectionToParent(data);
1849
+ console.log("\u{1F3AF} \u5143\u7D20\u5DF2\u9009\u4E2D:", data.element.tagName, data.sourceLocation?.file);
1850
+ }, []);
1851
+ (0, import_react7.useEffect)(() => {
1852
+ const handleStartSelection = () => {
1853
+ setIsSelecting(true);
1854
+ };
1855
+ const handleCancelSelection = () => {
1856
+ handleCancel();
1857
+ };
1858
+ window.addEventListener("howone:start-element-selection", handleStartSelection);
1859
+ window.addEventListener("howone:cancel-element-selection", handleCancelSelection);
1860
+ const handleMessage = (event) => {
1861
+ if (event.data.type === "START_ELEMENT_SELECTION") {
1862
+ setIsSelecting(true);
1863
+ } else if (event.data.type === "CANCEL_ELEMENT_SELECTION") {
1864
+ handleCancel();
1865
+ }
1866
+ };
1867
+ window.addEventListener("message", handleMessage);
1868
+ return () => {
1869
+ window.removeEventListener("howone:start-element-selection", handleStartSelection);
1870
+ window.removeEventListener("howone:cancel-element-selection", handleCancelSelection);
1871
+ window.removeEventListener("message", handleMessage);
1872
+ };
1873
+ }, [handleCancel]);
1874
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
1875
+ children,
1869
1876
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1870
- "div",
1877
+ ElementSelector,
1871
1878
  {
1872
- className: `animate-spin rounded-full border-2 border-gray-300 border-t-blue-600 mx-auto ${sizeClasses[size]}`
1879
+ active: isSelecting,
1880
+ onSelect: handleSelect,
1881
+ onCancel: handleCancel
1873
1882
  }
1874
- ),
1875
- text && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "mt-2 text-sm text-gray-600", children: text })
1876
- ] }) });
1877
- };
1878
- var LoadingSpinner = ({
1879
- size = "md",
1880
- className = ""
1881
- }) => {
1882
- const sizeClasses = {
1883
- sm: "h-4 w-4",
1884
- md: "h-8 w-8",
1885
- lg: "h-12 w-12"
1886
- };
1887
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1888
- "div",
1889
- {
1890
- className: `animate-spin rounded-full border-2 border-gray-300 border-t-blue-600 ${sizeClasses[size]} ${className}`
1891
- }
1892
- );
1883
+ )
1884
+ ] });
1893
1885
  };
1894
1886
 
1895
- // src/components/ui/ErrorBoundary.tsx
1896
- var import_react6 = require("react");
1897
- var import_jsx_runtime7 = require("react/jsx-runtime");
1898
- var ErrorBoundary = class extends import_react6.Component {
1899
- constructor(props) {
1900
- super(props);
1901
- this.handleRetry = () => {
1902
- this.setState({ hasError: false, error: void 0, errorInfo: void 0 });
1903
- };
1904
- this.state = { hasError: false };
1905
- }
1906
- static getDerivedStateFromError(error) {
1907
- return { hasError: true, error };
1908
- }
1909
- componentDidCatch(error, errorInfo) {
1910
- this.setState({
1911
- error,
1912
- errorInfo
1913
- });
1914
- this.props.onError?.(error, errorInfo);
1887
+ // src/utils/unified-error-handler/types.ts
1888
+ var ERROR_CONFIG = {
1889
+ MAX_ERRORS: 100,
1890
+ MAX_INTERACTIONS: 50,
1891
+ DEDUP_WINDOW: 1e3,
1892
+ DEBOUNCE_TIME: 100,
1893
+ CACHE_DURATION: 3e5,
1894
+ SEVERITY_KEYWORDS: {
1895
+ CRITICAL: ["fatal", "critical", "security", "crash", "corruption"],
1896
+ HIGH: ["error", "exception", "failed", "timeout", "network error"],
1897
+ MEDIUM: ["warning", "deprecated", "slow", "performance"],
1898
+ LOW: ["info", "debug", "trace", "notice"]
1899
+ },
1900
+ CATEGORY_KEYWORDS: {
1901
+ SYNTAX: ["syntaxerror", "unexpected token", "parse error", "invalid syntax"],
1902
+ NETWORK: ["fetch", "xhr", "network", "cors", "timeout", "connection"],
1903
+ RUNTIME: ["referenceerror", "typeerror", "rangeerror", "undefined"],
1904
+ SECURITY: ["csp", "xss", "csrf", "security", "unauthorized"],
1905
+ PERFORMANCE: ["slow", "memory", "leak", "performance", "timeout"],
1906
+ DEVELOPMENT: ["vite", "hmr", "hot reload", "dev server", "webpack"],
1907
+ REACT: ["react", "jsx", "component", "hook", "render"],
1908
+ VITE: ["vite", "[vite]", "vite:react", "transform failed"]
1915
1909
  }
1916
- render() {
1917
- if (this.state.hasError) {
1918
- if (this.props.fallback) {
1919
- const FallbackComponent = this.props.fallback;
1920
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(FallbackComponent, { error: this.state.error, retry: this.handleRetry });
1921
- }
1922
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "min-h-[400px] flex items-center justify-center p-4", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "text-center max-w-md", children: [
1923
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "text-red-500 text-6xl mb-4", children: "\u26A0\uFE0F" }),
1924
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h2", { className: "text-xl font-semibold text-gray-900 mb-2", children: "Something went wrong" }),
1925
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "text-gray-600 mb-4", children: "An unexpected error occurred. Please try refreshing the page." }),
1926
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1927
- "button",
1928
- {
1929
- onClick: this.handleRetry,
1930
- className: "px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition-colors",
1931
- children: "Try Again"
1932
- }
1933
- ),
1934
- false
1935
- ] }) });
1936
- }
1937
- return this.props.children;
1910
+ };
1911
+ var GLOBAL_CONFIG = {
1912
+ ALLOWED_ORIGINS: [
1913
+ "https://howone.ai",
1914
+ "https://howone.dev",
1915
+ "http://localhost:3000",
1916
+ "http://localhost:5173"
1917
+ ],
1918
+ DEBOUNCE_DELAY: 10,
1919
+ OVERRIDE_STYLESHEET_ID: "howone-override-styles"
1920
+ };
1921
+ var DEFAULT_SELECTOR_CONFIG = {
1922
+ HIGHLIGHT_COLOR: "#ff6b6b",
1923
+ HIGHLIGHT_BORDER_WIDTH: "2px",
1924
+ HIGHLIGHT_BORDER_STYLE: "solid",
1925
+ SELECTED_COLOR: "#4ecdc4",
1926
+ SELECTED_BORDER_WIDTH: "3px",
1927
+ TOOLTIP_BACKGROUND: "#333",
1928
+ TOOLTIP_COLOR: "#fff",
1929
+ TOOLTIP_PADDING: "8px 12px",
1930
+ TOOLTIP_BORDER_RADIUS: "4px",
1931
+ TOOLTIP_FONT_SIZE: "12px",
1932
+ TOOLTIP_Z_INDEX: "10000",
1933
+ FULL_WIDTH_TOOLTIP_OFFSET: 10,
1934
+ highlightClass: "howone-highlight",
1935
+ selectedClass: "howone-selected",
1936
+ cursor: "crosshair"
1937
+ };
1938
+
1939
+ // src/utils/unified-error-handler/utils/DeepSerializer.ts
1940
+ var CircularReference = class {
1941
+ constructor(path) {
1942
+ this.message = `[Circular Reference to ${path}]`;
1938
1943
  }
1939
1944
  };
1940
- var DefaultErrorFallback = ({ retry }) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "min-h-[200px] flex items-center justify-center p-4", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "text-center", children: [
1941
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "text-red-500 text-4xl mb-2", children: "\u26A0\uFE0F" }),
1942
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "text-gray-600 mb-2", children: "Something went wrong" }),
1943
- retry && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1944
- "button",
1945
- {
1946
- onClick: retry,
1947
- className: "px-3 py-1 bg-blue-600 text-white text-sm rounded hover:bg-blue-700 transition-colors",
1948
- children: "Retry"
1945
+ var TypeWrapper = class {
1946
+ constructor(type, value) {
1947
+ this._type = type;
1948
+ this.value = value;
1949
+ }
1950
+ };
1951
+ var DeepSerializer = class {
1952
+ /**
1953
+ * 深度序列化对象
1954
+ */
1955
+ static serialize(obj, options = {}, visitedObjects = /* @__PURE__ */ new WeakMap(), path = "root") {
1956
+ const opts = { ...this.DEFAULT_OPTIONS, ...options };
1957
+ if (path.split(".").length > opts.maxDepth) {
1958
+ return new TypeWrapper(
1959
+ "MaxDepthReached",
1960
+ `[Max depth of ${opts.maxDepth} reached]`
1961
+ );
1949
1962
  }
1950
- )
1951
- ] }) });
1952
-
1953
- // src/components/theme/ThemeToggle.tsx
1954
- var React4 = __toESM(require("react"));
1955
- var import_react7 = require("@iconify/react");
1956
- var import_jsx_runtime8 = require("react/jsx-runtime");
1957
- function ThemeToggle({ className }) {
1958
- const { setTheme, theme } = useTheme();
1959
- const [mounted, setMounted] = React4.useState(false);
1960
- React4.useEffect(() => {
1961
- setMounted(true);
1962
- }, []);
1963
- const handleToggle = () => {
1964
- if (theme === "dark") {
1965
- setTheme("light");
1966
- } else {
1967
- setTheme("dark");
1963
+ if (obj === void 0) {
1964
+ return new TypeWrapper("undefined", "undefined");
1968
1965
  }
1969
- };
1970
- if (!mounted) {
1971
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1972
- "button",
1973
- {
1974
- className: `relative inline-flex h-10 w-12 items-center justify-center rounded-md border border-input bg-background hover:bg-accent hover:text-accent-foreground ${className || ""}`,
1975
- disabled: true,
1976
- children: [
1977
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react7.Icon, { icon: "solar:sun-bold", width: 20, height: 20 }),
1978
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "sr-only", children: "\u5207\u6362\u4E3B\u9898" })
1979
- ]
1980
- }
1981
- );
1982
- }
1983
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1984
- "button",
1985
- {
1986
- className: `inline-flex h-10 w-12 items-center justify-center rounded-md border border-input bg-background hover:bg-accent hover:text-accent-foreground transition-colors ${className || ""}`,
1987
- onClick: handleToggle,
1988
- children: [
1989
- theme === "light" ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react7.Icon, { icon: "solar:sun-bold", width: 20, height: 20 }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react7.Icon, { icon: "solar:moon-linear", width: 20, height: 20 }),
1990
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "sr-only", children: "\u5207\u6362\u4E3B\u9898" })
1991
- ]
1966
+ if (obj === null) {
1967
+ return null;
1992
1968
  }
1993
- );
1994
- }
1995
-
1996
- // src/components/ui/Toast/ClayxToast.tsx
1997
- var import_react8 = __toESM(require("react"));
1998
- var import_react_toastify2 = require("react-toastify");
1999
- var import_react9 = require("@iconify/react");
2000
- var import_jsx_runtime9 = require("react/jsx-runtime");
2001
- var TOAST_ICONS = {
2002
- success: {
2003
- icon: "mdi:success",
2004
- color: "text-green-400",
2005
- className: "text-green-400",
2006
- // 深色主题配置
2007
- dark: {
2008
- bgGradient: "bg-[#14181d]",
2009
- // 移除透明度 f2
2010
- gradientColor: "#389726",
2011
- borderGradient: "border-[#389726]",
2012
- borderGradientColor: "#389726"
2013
- },
2014
- // 浅色主题配置
2015
- light: {
2016
- bgGradient: "bg-[#fafafa]",
2017
- // 移除透明度 ff
2018
- gradientColor: "#22c55e",
2019
- borderGradient: "border-[#22c55e]",
2020
- borderGradientColor: "#22c55e"
1969
+ if (typeof obj === "string") {
1970
+ return obj.length > opts.maxStringLength ? new TypeWrapper(
1971
+ "String",
1972
+ `${obj.slice(0, opts.maxStringLength)}... [${obj.length - opts.maxStringLength} more characters]`
1973
+ ) : obj;
2021
1974
  }
2022
- },
2023
- error: {
2024
- icon: "ic:outline-close",
2025
- color: "text-red-400",
2026
- className: "text-red-400",
2027
- dark: {
2028
- bgGradient: "bg-[#14181d]",
2029
- // 移除透明度 f2
2030
- gradientColor: "#ef4444",
2031
- borderGradient: "border-[#ef4444]",
2032
- borderGradientColor: "#ef4444"
2033
- },
2034
- light: {
2035
- bgGradient: "bg-[#fafafa]",
2036
- // 移除透明度 ff
2037
- gradientColor: "#f87171",
2038
- borderGradient: "border-[#f87171]",
2039
- borderGradientColor: "#f87171"
1975
+ if (typeof obj === "number") {
1976
+ return Number.isNaN(obj) ? new TypeWrapper("Number", "NaN") : Number.isFinite(obj) ? obj : new TypeWrapper("Number", obj > 0 ? "Infinity" : "-Infinity");
2040
1977
  }
2041
- },
2042
- warning: {
2043
- icon: "mi:warning",
2044
- color: "text-yellow-400",
2045
- className: "text-yellow-400",
2046
- dark: {
2047
- bgGradient: "bg-[#14181d]",
2048
- // 移除透明度 f2
2049
- gradientColor: "#facc15",
2050
- borderGradient: "border-[#facc15]",
2051
- borderGradientColor: "#facc15"
2052
- },
2053
- light: {
2054
- bgGradient: "bg-[#fafafa]",
2055
- // 移除透明度 ff
2056
- gradientColor: "#f59e0b",
2057
- borderGradient: "border-[#f59e0b]",
2058
- borderGradientColor: "#f59e0b"
1978
+ if (typeof obj === "boolean") {
1979
+ return obj;
2059
1980
  }
2060
- },
2061
- info: {
2062
- icon: "ic:outline-info",
2063
- color: "text-blue-400",
2064
- className: "text-blue-400",
2065
- dark: {
2066
- bgGradient: "bg-[#14181d]",
2067
- // 移除透明度 f2
2068
- gradientColor: "#60a5fa",
2069
- borderGradient: "border-[#60a5fa]",
2070
- borderGradientColor: "#f0f0f0"
2071
- },
2072
- light: {
2073
- bgGradient: "bg-[#fafafa]",
2074
- // 移除透明度 ff
2075
- gradientColor: "#3b82f6",
2076
- borderGradient: "border-[#3b82f6]",
2077
- borderGradientColor: "#3b82f6"
1981
+ if (typeof obj === "bigint") {
1982
+ return new TypeWrapper("BigInt", obj.toString());
2078
1983
  }
2079
- },
2080
- default: {
2081
- icon: "ic:round-notifications",
2082
- color: "text-gray-400",
2083
- className: "text-gray-400",
2084
- dark: {
2085
- bgGradient: "bg-[#14181d]",
2086
- // 移除透明度 f2
2087
- gradientColor: "#9ca3af",
2088
- borderGradient: "border-[#9ca3af]",
2089
- borderGradientColor: "#9ca3af"
2090
- },
2091
- light: {
2092
- bgGradient: "bg-[#fafafa]",
2093
- // 移除透明度 ff
2094
- gradientColor: "#6b7280",
2095
- borderGradient: "border-[#6b7280]",
2096
- borderGradientColor: "#6b7280"
1984
+ if (typeof obj === "symbol") {
1985
+ return new TypeWrapper("Symbol", obj.toString());
2097
1986
  }
2098
- }
2099
- };
2100
- var CloseButton = import_react8.default.memo(({ closeToast }) => {
2101
- const { theme } = useTheme();
2102
- const handleClick = (0, import_react8.useCallback)((e) => {
2103
- e.preventDefault();
2104
- e.stopPropagation();
2105
- closeToast?.();
2106
- }, [closeToast]);
2107
- const getCloseButtonColor = () => {
2108
- const actualTheme = theme === "system" ? window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light" : theme;
2109
- return actualTheme === "dark" ? "#b4b4b4" : "#6b7280";
2110
- };
2111
- const getCloseButtonHoverColor = () => {
2112
- const actualTheme = theme === "system" ? window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light" : theme;
2113
- return actualTheme === "dark" ? "white" : "#374151";
2114
- };
2115
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2116
- import_react9.Icon,
2117
- {
2118
- icon: "vaadin:close",
2119
- className: "flex items-center justify-center rounded-full relative z-10 flex-shrink-0 cursor-pointer \n transition-colors duration-200 drop-shadow-sm",
2120
- onClick: handleClick,
2121
- width: 14,
2122
- height: 14,
2123
- style: {
2124
- color: getCloseButtonColor()
2125
- },
2126
- onMouseEnter: (e) => {
2127
- e.currentTarget.style.color = getCloseButtonHoverColor();
2128
- },
2129
- onMouseLeave: (e) => {
2130
- e.currentTarget.style.color = getCloseButtonColor();
1987
+ if (typeof obj === "function") {
1988
+ return new TypeWrapper("Function", {
1989
+ name: obj.name || "anonymous",
1990
+ stringValue: obj.toString().slice(0, opts.maxStringLength),
1991
+ length: obj.length
1992
+ });
1993
+ }
1994
+ if (obj && typeof obj === "object") {
1995
+ if (visitedObjects.has(obj)) {
1996
+ return new CircularReference(visitedObjects.get(obj));
2131
1997
  }
1998
+ visitedObjects.set(obj, path);
2132
1999
  }
2133
- );
2134
- });
2135
- CloseButton.displayName = "CloseButton";
2136
- var ToastContent = ({ type, title, message, component, closeToast }) => {
2137
- const iconConfig = TOAST_ICONS[type];
2138
- const { theme } = useTheme();
2139
- const handleClose = (0, import_react8.useCallback)(() => {
2140
- closeToast?.();
2141
- }, [closeToast]);
2142
- const getTextColor = () => {
2143
- const actualTheme = theme === "system" ? window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light" : theme;
2144
- return actualTheme === "dark" ? "white" : "#1f2937";
2145
- };
2146
- const getThemeConfig = () => {
2147
- const actualTheme = theme === "system" ? window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light" : theme;
2148
- return actualTheme === "dark" ? iconConfig.dark : iconConfig.light;
2149
- };
2150
- const themeConfig = getThemeConfig();
2151
- if (component) {
2152
- return /* @__PURE__ */ (0, import_jsx_runtime9.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: [
2153
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "flex-1 relative z-10", children: component }),
2154
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "relative z-10", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(CloseButton, { closeToast: handleClose }) })
2155
- ] });
2000
+ if (obj instanceof Error) {
2001
+ return this.serializeError(obj, opts, visitedObjects, path);
2002
+ }
2003
+ if (obj instanceof Date) {
2004
+ return new TypeWrapper("Date", {
2005
+ iso: obj.toISOString(),
2006
+ value: obj.valueOf(),
2007
+ local: obj.toString()
2008
+ });
2009
+ }
2010
+ if (obj instanceof RegExp) {
2011
+ return new TypeWrapper("RegExp", {
2012
+ source: obj.source,
2013
+ flags: obj.flags,
2014
+ string: obj.toString()
2015
+ });
2016
+ }
2017
+ if (obj instanceof Promise) {
2018
+ return new TypeWrapper("Promise", "[Promise]");
2019
+ }
2020
+ if (obj instanceof WeakMap || obj instanceof WeakSet) {
2021
+ return new TypeWrapper(
2022
+ obj.constructor.name,
2023
+ "[" + obj.constructor.name + "]"
2024
+ );
2025
+ }
2026
+ if (obj instanceof Set) {
2027
+ return this.serializeSet(obj, opts, visitedObjects, path);
2028
+ }
2029
+ if (obj instanceof Map) {
2030
+ return this.serializeMap(obj, opts, visitedObjects, path);
2031
+ }
2032
+ if (ArrayBuffer.isView(obj)) {
2033
+ return this.serializeTypedArray(obj);
2034
+ }
2035
+ if (Array.isArray(obj)) {
2036
+ return this.serializeArray(obj, opts, visitedObjects, path);
2037
+ }
2038
+ return this.serializeObject(obj, opts, visitedObjects, path);
2156
2039
  }
2157
- return /* @__PURE__ */ (0, import_jsx_runtime9.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: [
2158
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2159
- "div",
2160
- {
2161
- className: "absolute left-0 top-0 w-full h-full rounded-xl",
2162
- style: {
2163
- background: theme === "dark" || theme === "system" && window.matchMedia("(prefers-color-scheme: dark)").matches ? "#0f1419" : "#ffffff",
2164
- zIndex: -2
2165
- }
2166
- }
2167
- ),
2168
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2169
- "div",
2170
- {
2171
- className: "absolute left-0 top-0 w-full h-full pointer-events-none rounded-xl",
2172
- style: {
2173
- 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}15 0%, ${themeConfig.gradientColor}08 15%, #fafafaff 30%)`,
2174
- zIndex: -1
2175
- }
2176
- }
2177
- ),
2178
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2179
- "div",
2180
- {
2181
- className: "absolute left-0 top-0 w-full h-full pointer-events-none rounded-xl",
2182
- style: {
2183
- border: "2px solid transparent",
2184
- 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}40 0%, ${themeConfig.borderGradientColor}25 5%, transparent 22%)`,
2185
- backgroundOrigin: "border-box",
2186
- backgroundClip: "border-box",
2187
- WebkitMask: "linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0)",
2188
- WebkitMaskComposite: "xor",
2189
- mask: "linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0)",
2190
- maskComposite: "exclude"
2191
- }
2192
- }
2193
- ),
2194
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "flex-shrink-0 mt-0.5 relative z-10", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: `w-7 h-7 backdrop-blur-sm rounded-full flex items-center justify-center ${theme === "dark" || theme === "system" && window.matchMedia("(prefers-color-scheme: dark)").matches ? "bg-white/10" : "bg-black/5"}`, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2195
- import_react9.Icon,
2196
- {
2197
- icon: iconConfig.icon,
2198
- width: 16,
2199
- height: 16,
2200
- className: iconConfig.color,
2201
- style: {
2202
- color: themeConfig.gradientColor
2040
+ /**
2041
+ * 序列化错误对象
2042
+ */
2043
+ static serializeError(error, opts, visitedObjects, path) {
2044
+ const errorObj = {
2045
+ name: error.name,
2046
+ message: error.message,
2047
+ stack: error.stack
2048
+ };
2049
+ for (const key of Object.getOwnPropertyNames(error)) {
2050
+ if (!errorObj[key]) {
2051
+ try {
2052
+ errorObj[key] = this.serialize(
2053
+ error[key],
2054
+ opts,
2055
+ visitedObjects,
2056
+ `${path}.${key}`
2057
+ );
2058
+ } catch (e) {
2059
+ errorObj[key] = new TypeWrapper("Error", `[Unable to serialize: ${e}]`);
2203
2060
  }
2204
2061
  }
2205
- ) }) }),
2206
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-col gap-1 flex-1 relative z-10", children: [
2207
- title && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2208
- "div",
2209
- {
2210
- className: "text-[16px] font-semibold leading-tight drop-shadow-sm",
2211
- style: {
2212
- color: getTextColor(),
2213
- backgroundClip: "text"
2214
- },
2215
- children: title
2216
- }
2217
- ),
2218
- message && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2219
- "div",
2220
- {
2221
- className: "text-[13px] font-normal leading-relaxed drop-shadow-sm",
2222
- style: {
2223
- color: getTextColor(),
2224
- backgroundClip: "text"
2225
- },
2226
- children: message
2227
- }
2062
+ }
2063
+ return new TypeWrapper("Error", errorObj);
2064
+ }
2065
+ /**
2066
+ * 序列化 Set
2067
+ */
2068
+ static serializeSet(set, opts, visitedObjects, path) {
2069
+ const values = Array.from(set);
2070
+ if (values.length > opts.maxArrayLength) {
2071
+ return new TypeWrapper("Set", {
2072
+ values: values.slice(0, opts.maxArrayLength).map(
2073
+ (item, index) => this.serialize(item, opts, visitedObjects, `${path}.Set[${index}]`)
2074
+ ),
2075
+ truncated: values.length - opts.maxArrayLength
2076
+ });
2077
+ }
2078
+ return new TypeWrapper("Set", {
2079
+ values: values.map(
2080
+ (item, index) => this.serialize(item, opts, visitedObjects, `${path}.Set[${index}]`)
2228
2081
  )
2229
- ] }),
2230
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "relative z-10", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(CloseButton, { closeToast: handleClose }) })
2231
- ] });
2232
- };
2233
- var defaultToastOptions = {
2234
- position: "bottom-right",
2235
- autoClose: 3e3,
2236
- hideProgressBar: true,
2237
- closeOnClick: false,
2238
- pauseOnHover: true,
2239
- draggable: true,
2240
- pauseOnFocusLoss: false,
2241
- theme: "dark",
2242
- transition: import_react_toastify2.Bounce
2243
- };
2244
- var createToast = (type) => {
2245
- return (params) => {
2246
- const { title, message, component, options } = params;
2247
- (0, import_react_toastify2.toast)(
2248
- ({ closeToast }) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2249
- ToastContent,
2250
- {
2251
- type,
2252
- title,
2253
- message: message || "",
2254
- component,
2255
- closeToast
2256
- }
2257
- ),
2258
- {
2259
- ...defaultToastOptions,
2260
- ...options,
2261
- // 确保圆角样式不被覆盖,添加 rounded-xl 类
2262
- className: "!p-0 !shadow-none !rounded-xl",
2263
- style: { padding: 0, borderRadius: "0.75rem" }
2264
- }
2265
- );
2266
- };
2267
- };
2268
- var ClayxToast = {
2269
- success: createToast("success"),
2270
- error: createToast("error"),
2271
- warning: createToast("warning"),
2272
- info: createToast("info"),
2273
- default: createToast("default")
2274
- };
2275
-
2276
- // src/hooks/use-mobile.ts
2277
- var React6 = __toESM(require("react"));
2278
- var MOBILE_BREAKPOINT = 768;
2279
- function useIsMobile() {
2280
- const [isMobile, setIsMobile] = React6.useState(void 0);
2281
- React6.useEffect(() => {
2282
- const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
2283
- const onChange = () => {
2284
- setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
2285
- };
2286
- mql.addEventListener("change", onChange);
2287
- setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
2288
- return () => mql.removeEventListener("change", onChange);
2289
- }, []);
2290
- return !!isMobile;
2291
- }
2292
-
2293
- // src/hooks/use-debounce.ts
2294
- var import_react10 = require("react");
2295
- function useDebounce(value, delay) {
2296
- const [debouncedValue, setDebouncedValue] = (0, import_react10.useState)(value);
2297
- (0, import_react10.useEffect)(() => {
2298
- const handler = setTimeout(() => {
2299
- setDebouncedValue(value);
2300
- }, delay);
2301
- return () => {
2302
- clearTimeout(handler);
2303
- };
2304
- }, [value, delay]);
2305
- return debouncedValue;
2306
- }
2307
-
2308
- // src/utils/unified-error-handler/types.ts
2309
- var ERROR_CONFIG = {
2310
- MAX_ERRORS: 100,
2311
- MAX_INTERACTIONS: 50,
2312
- DEDUP_WINDOW: 1e3,
2313
- DEBOUNCE_TIME: 100,
2314
- CACHE_DURATION: 3e5,
2315
- SEVERITY_KEYWORDS: {
2316
- CRITICAL: ["fatal", "critical", "security", "crash", "corruption"],
2317
- HIGH: ["error", "exception", "failed", "timeout", "network error"],
2318
- MEDIUM: ["warning", "deprecated", "slow", "performance"],
2319
- LOW: ["info", "debug", "trace", "notice"]
2320
- },
2321
- CATEGORY_KEYWORDS: {
2322
- SYNTAX: ["syntaxerror", "unexpected token", "parse error", "invalid syntax"],
2323
- NETWORK: ["fetch", "xhr", "network", "cors", "timeout", "connection"],
2324
- RUNTIME: ["referenceerror", "typeerror", "rangeerror", "undefined"],
2325
- SECURITY: ["csp", "xss", "csrf", "security", "unauthorized"],
2326
- PERFORMANCE: ["slow", "memory", "leak", "performance", "timeout"],
2327
- DEVELOPMENT: ["vite", "hmr", "hot reload", "dev server", "webpack"],
2328
- REACT: ["react", "jsx", "component", "hook", "render"],
2329
- VITE: ["vite", "[vite]", "vite:react", "transform failed"]
2330
- }
2331
- };
2332
- var GLOBAL_CONFIG = {
2333
- ALLOWED_ORIGINS: [
2334
- "https://howone.ai",
2335
- "https://howone.dev",
2336
- "http://localhost:3000",
2337
- "http://localhost:5173"
2338
- ],
2339
- DEBOUNCE_DELAY: 10,
2340
- OVERRIDE_STYLESHEET_ID: "howone-override-styles"
2341
- };
2342
- var DEFAULT_SELECTOR_CONFIG = {
2343
- HIGHLIGHT_COLOR: "#ff6b6b",
2344
- HIGHLIGHT_BORDER_WIDTH: "2px",
2345
- HIGHLIGHT_BORDER_STYLE: "solid",
2346
- SELECTED_COLOR: "#4ecdc4",
2347
- SELECTED_BORDER_WIDTH: "3px",
2348
- TOOLTIP_BACKGROUND: "#333",
2349
- TOOLTIP_COLOR: "#fff",
2350
- TOOLTIP_PADDING: "8px 12px",
2351
- TOOLTIP_BORDER_RADIUS: "4px",
2352
- TOOLTIP_FONT_SIZE: "12px",
2353
- TOOLTIP_Z_INDEX: "10000",
2354
- FULL_WIDTH_TOOLTIP_OFFSET: 10,
2355
- highlightClass: "howone-highlight",
2356
- selectedClass: "howone-selected",
2357
- cursor: "crosshair"
2358
- };
2359
-
2360
- // src/utils/unified-error-handler/utils/DeepSerializer.ts
2361
- var CircularReference = class {
2362
- constructor(path) {
2363
- this.message = `[Circular Reference to ${path}]`;
2364
- }
2365
- };
2366
- var TypeWrapper = class {
2367
- constructor(type, value) {
2368
- this._type = type;
2369
- this.value = value;
2370
- }
2371
- };
2372
- var DeepSerializer = class {
2373
- /**
2374
- * 深度序列化对象
2375
- */
2376
- static serialize(obj, options = {}, visitedObjects = /* @__PURE__ */ new WeakMap(), path = "root") {
2377
- const opts = { ...this.DEFAULT_OPTIONS, ...options };
2378
- if (path.split(".").length > opts.maxDepth) {
2379
- return new TypeWrapper(
2380
- "MaxDepthReached",
2381
- `[Max depth of ${opts.maxDepth} reached]`
2382
- );
2383
- }
2384
- if (obj === void 0) {
2385
- return new TypeWrapper("undefined", "undefined");
2386
- }
2387
- if (obj === null) {
2388
- return null;
2389
- }
2390
- if (typeof obj === "string") {
2391
- return obj.length > opts.maxStringLength ? new TypeWrapper(
2392
- "String",
2393
- `${obj.slice(0, opts.maxStringLength)}... [${obj.length - opts.maxStringLength} more characters]`
2394
- ) : obj;
2395
- }
2396
- if (typeof obj === "number") {
2397
- return Number.isNaN(obj) ? new TypeWrapper("Number", "NaN") : Number.isFinite(obj) ? obj : new TypeWrapper("Number", obj > 0 ? "Infinity" : "-Infinity");
2398
- }
2399
- if (typeof obj === "boolean") {
2400
- return obj;
2401
- }
2402
- if (typeof obj === "bigint") {
2403
- return new TypeWrapper("BigInt", obj.toString());
2404
- }
2405
- if (typeof obj === "symbol") {
2406
- return new TypeWrapper("Symbol", obj.toString());
2407
- }
2408
- if (typeof obj === "function") {
2409
- return new TypeWrapper("Function", {
2410
- name: obj.name || "anonymous",
2411
- stringValue: obj.toString().slice(0, opts.maxStringLength),
2412
- length: obj.length
2413
- });
2414
- }
2415
- if (obj && typeof obj === "object") {
2416
- if (visitedObjects.has(obj)) {
2417
- return new CircularReference(visitedObjects.get(obj));
2418
- }
2419
- visitedObjects.set(obj, path);
2420
- }
2421
- if (obj instanceof Error) {
2422
- return this.serializeError(obj, opts, visitedObjects, path);
2423
- }
2424
- if (obj instanceof Date) {
2425
- return new TypeWrapper("Date", {
2426
- iso: obj.toISOString(),
2427
- value: obj.valueOf(),
2428
- local: obj.toString()
2429
- });
2430
- }
2431
- if (obj instanceof RegExp) {
2432
- return new TypeWrapper("RegExp", {
2433
- source: obj.source,
2434
- flags: obj.flags,
2435
- string: obj.toString()
2436
- });
2437
- }
2438
- if (obj instanceof Promise) {
2439
- return new TypeWrapper("Promise", "[Promise]");
2440
- }
2441
- if (obj instanceof WeakMap || obj instanceof WeakSet) {
2442
- return new TypeWrapper(
2443
- obj.constructor.name,
2444
- "[" + obj.constructor.name + "]"
2445
- );
2446
- }
2447
- if (obj instanceof Set) {
2448
- return this.serializeSet(obj, opts, visitedObjects, path);
2449
- }
2450
- if (obj instanceof Map) {
2451
- return this.serializeMap(obj, opts, visitedObjects, path);
2452
- }
2453
- if (ArrayBuffer.isView(obj)) {
2454
- return this.serializeTypedArray(obj);
2455
- }
2456
- if (Array.isArray(obj)) {
2457
- return this.serializeArray(obj, opts, visitedObjects, path);
2458
- }
2459
- return this.serializeObject(obj, opts, visitedObjects, path);
2460
- }
2461
- /**
2462
- * 序列化错误对象
2463
- */
2464
- static serializeError(error, opts, visitedObjects, path) {
2465
- const errorObj = {
2466
- name: error.name,
2467
- message: error.message,
2468
- stack: error.stack
2469
- };
2470
- for (const key of Object.getOwnPropertyNames(error)) {
2471
- if (!errorObj[key]) {
2472
- try {
2473
- errorObj[key] = this.serialize(
2474
- error[key],
2475
- opts,
2476
- visitedObjects,
2477
- `${path}.${key}`
2478
- );
2479
- } catch (e) {
2480
- errorObj[key] = new TypeWrapper("Error", `[Unable to serialize: ${e}]`);
2481
- }
2482
- }
2483
- }
2484
- return new TypeWrapper("Error", errorObj);
2485
- }
2486
- /**
2487
- * 序列化 Set
2488
- */
2489
- static serializeSet(set, opts, visitedObjects, path) {
2490
- const values = Array.from(set);
2491
- if (values.length > opts.maxArrayLength) {
2492
- return new TypeWrapper("Set", {
2493
- values: values.slice(0, opts.maxArrayLength).map(
2494
- (item, index) => this.serialize(item, opts, visitedObjects, `${path}.Set[${index}]`)
2495
- ),
2496
- truncated: values.length - opts.maxArrayLength
2497
- });
2498
- }
2499
- return new TypeWrapper("Set", {
2500
- values: values.map(
2501
- (item, index) => this.serialize(item, opts, visitedObjects, `${path}.Set[${index}]`)
2502
- )
2503
- });
2504
- }
2505
- /**
2506
- * 序列化 Map
2507
- */
2508
- static serializeMap(map, opts, visitedObjects, path) {
2509
- const entries = {};
2510
- let truncatedCount = 0;
2511
- let addedCount = 0;
2512
- for (const [key, value] of map.entries()) {
2513
- if (addedCount >= opts.maxObjectKeys) {
2514
- truncatedCount++;
2515
- continue;
2082
+ });
2083
+ }
2084
+ /**
2085
+ * 序列化 Map
2086
+ */
2087
+ static serializeMap(map, opts, visitedObjects, path) {
2088
+ const entries = {};
2089
+ let truncatedCount = 0;
2090
+ let addedCount = 0;
2091
+ for (const [key, value] of map.entries()) {
2092
+ if (addedCount >= opts.maxObjectKeys) {
2093
+ truncatedCount++;
2094
+ continue;
2516
2095
  }
2517
2096
  const keyString = typeof key === "object" ? JSON.stringify(
2518
2097
  this.serialize(key, opts, visitedObjects, `${path}.MapKey`)
@@ -5069,7 +4648,7 @@ var InteractionTracking = class {
5069
4648
  };
5070
4649
 
5071
4650
  // src/utils/unified-error-handler/features/ElementSelector.ts
5072
- var ElementSelector = class {
4651
+ var ElementSelector2 = class {
5073
4652
  constructor(sendMessage) {
5074
4653
  this.config = { ...DEFAULT_SELECTOR_CONFIG };
5075
4654
  this.isActive = false;
@@ -6063,7 +5642,6 @@ var MessageBridge = class {
6063
5642
  this.handleSetStylesheet(payload);
6064
5643
  break;
6065
5644
  default:
6066
- console.warn("[MessageBridge] \u672A\u77E5\u6D88\u606F\u7C7B\u578B:", type);
6067
5645
  break;
6068
5646
  }
6069
5647
  } catch (error) {
@@ -6595,7 +6173,7 @@ var ErrorHandler = class {
6595
6173
  const sendMessage = this.messageSender.createSendFunction();
6596
6174
  this.errorTracking = new ErrorTracking(sendMessage);
6597
6175
  this.interactionTracking = new InteractionTracking(sendMessage);
6598
- this.elementSelector = new ElementSelector(sendMessage);
6176
+ this.elementSelector = new ElementSelector2(sendMessage);
6599
6177
  this.messageBridge = new MessageBridge();
6600
6178
  this.viewDetector = new ViewDetector();
6601
6179
  this.hardRefreshManager = new HardRefreshManager(GLOBAL_CONFIG.ALLOWED_ORIGINS);
@@ -6872,6 +6450,656 @@ var ErrorHandler = class {
6872
6450
  }
6873
6451
  };
6874
6452
 
6453
+ // src/components/auth/HowoneProvider.tsx
6454
+ var import_jsx_runtime7 = require("react/jsx-runtime");
6455
+ var HowoneContext = (0, import_react8.createContext)(null);
6456
+ var HowOneProvider = ({
6457
+ children,
6458
+ showFloatingButton = true,
6459
+ projectId,
6460
+ defaultTheme = "system",
6461
+ themeStorageKey = "howone-theme",
6462
+ forceDefaultTheme = false,
6463
+ authUrl = "https://howone.dev/auth",
6464
+ redirectOnUnauthenticated = true
6465
+ }) => {
6466
+ const [user, setUser] = (0, import_react8.useState)(() => parseUserFromToken(getToken()));
6467
+ const [token, setTokenState] = (0, import_react8.useState)(() => getToken());
6468
+ const [hasCheckedUrlToken, setHasCheckedUrlToken] = (0, import_react8.useState)(false);
6469
+ (0, import_react8.useEffect)(() => {
6470
+ const errorHandler = new ErrorHandler({
6471
+ enableViteHMR: true,
6472
+ enableElementSelector: true,
6473
+ enableInteractionTracking: true
6474
+ // enableConsoleCapture: true,
6475
+ // enableNetworkCapture: true,
6476
+ // maxErrors: 100,
6477
+ // maxInteractions: 50,
6478
+ // debounceTime: 100,
6479
+ // reportToParent: true,
6480
+ // reportToConsole: true
6481
+ });
6482
+ errorHandler.init();
6483
+ window.__ERROR_HANDLER__ = errorHandler;
6484
+ try {
6485
+ const params = new URLSearchParams(window.location.search);
6486
+ let urlToken = params.get("access_token") || params.get("token");
6487
+ if (!urlToken && window.location.hash) {
6488
+ const hashParams = new URLSearchParams(window.location.hash.slice(1));
6489
+ urlToken = hashParams.get("access_token") || hashParams.get("token");
6490
+ }
6491
+ if (urlToken) {
6492
+ console.log("[HowOneProvider] Token captured from URL, storing to localStorage...");
6493
+ setToken(urlToken);
6494
+ setTokenState(urlToken);
6495
+ setUser(parseUserFromToken(urlToken));
6496
+ params.delete("access_token");
6497
+ params.delete("token");
6498
+ params.delete("project_id");
6499
+ const newSearch = params.toString();
6500
+ const newUrl = window.location.pathname + (newSearch ? "?" + newSearch : "");
6501
+ window.history.replaceState({}, "", newUrl);
6502
+ console.log("[HowOneProvider] Token stored successfully, URL cleaned");
6503
+ }
6504
+ } catch (e) {
6505
+ console.error("[HowOneProvider] Failed to capture token from URL:", e);
6506
+ } finally {
6507
+ setHasCheckedUrlToken(true);
6508
+ }
6509
+ }, []);
6510
+ (0, import_react8.useEffect)(() => {
6511
+ if (!hasCheckedUrlToken) {
6512
+ return;
6513
+ }
6514
+ }, [token, user, redirectOnUnauthenticated, authUrl, projectId, hasCheckedUrlToken]);
6515
+ const logout = () => {
6516
+ try {
6517
+ setToken(null);
6518
+ } catch {
6519
+ }
6520
+ setTokenState(null);
6521
+ setUser(null);
6522
+ };
6523
+ const value = {
6524
+ user,
6525
+ token,
6526
+ isAuthenticated: !!token,
6527
+ logout
6528
+ };
6529
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
6530
+ ThemeProvider,
6531
+ {
6532
+ defaultTheme,
6533
+ storageKey: themeStorageKey,
6534
+ forceDefault: forceDefaultTheme,
6535
+ children: [
6536
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ElementSelectorProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(HowoneContext.Provider, { value, children: [
6537
+ children,
6538
+ showFloatingButton && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(FloatingButton, { onClick: () => window.open("https://howone.ai", "_blank") })
6539
+ ] }) }),
6540
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(GlobalToastContainer, {})
6541
+ ]
6542
+ }
6543
+ );
6544
+ };
6545
+ function useHowoneContext() {
6546
+ const ctx = (0, import_react8.useContext)(HowoneContext);
6547
+ if (!ctx) {
6548
+ const t = getToken();
6549
+ return {
6550
+ user: parseUserFromToken(t),
6551
+ token: t,
6552
+ isAuthenticated: !!t,
6553
+ logout: () => {
6554
+ try {
6555
+ setToken(null);
6556
+ } catch {
6557
+ }
6558
+ }
6559
+ };
6560
+ }
6561
+ return ctx;
6562
+ }
6563
+
6564
+ // src/components/index.ts
6565
+ init_auth();
6566
+
6567
+ // src/howone/client.ts
6568
+ init_auth();
6569
+ init_config();
6570
+ var HowoneAuthClient = class {
6571
+ constructor() {
6572
+ this.listeners = /* @__PURE__ */ new Set();
6573
+ this.loading = false;
6574
+ }
6575
+ emit() {
6576
+ const state = {
6577
+ user: parseUserFromToken(getToken()),
6578
+ isLoading: this.loading
6579
+ };
6580
+ for (const l of this.listeners) {
6581
+ try {
6582
+ l(state);
6583
+ } catch (e) {
6584
+ void e;
6585
+ }
6586
+ }
6587
+ }
6588
+ onAuthStateChanged(listener) {
6589
+ this.listeners.add(listener);
6590
+ try {
6591
+ listener({ user: parseUserFromToken(getToken()), isLoading: this.loading });
6592
+ } catch (e) {
6593
+ void e;
6594
+ }
6595
+ return () => {
6596
+ this.listeners.delete(listener);
6597
+ };
6598
+ }
6599
+ // Simple redirect-based login trigger (consumer can override)
6600
+ login() {
6601
+ const root = getAuthRoot() || "https://create-x-backend-dev.fly.dev";
6602
+ try {
6603
+ const loc = window.location.href;
6604
+ const authUrl = new URL("/auth", String(root));
6605
+ authUrl.searchParams.set("redirect_uri", String(loc));
6606
+ try {
6607
+ const cfg = (init_config(), __toCommonJS(config_exports));
6608
+ const pid = cfg.getDefaultProjectId && cfg.getDefaultProjectId();
6609
+ if (pid) authUrl.searchParams.set("project_id", String(pid));
6610
+ } catch {
6611
+ }
6612
+ try {
6613
+ if (window.top && window.top !== window) {
6614
+ window.top.location.replace(authUrl.toString());
6615
+ } else {
6616
+ window.location.replace(authUrl.toString());
6617
+ }
6618
+ } catch {
6619
+ try {
6620
+ window.location.replace(String(root));
6621
+ } catch {
6622
+ }
6623
+ }
6624
+ } catch {
6625
+ try {
6626
+ window.location.replace(String(root));
6627
+ } catch {
6628
+ }
6629
+ }
6630
+ }
6631
+ logout() {
6632
+ setToken(null);
6633
+ this.emit();
6634
+ }
6635
+ getUser() {
6636
+ return parseUserFromToken(getToken());
6637
+ }
6638
+ // helper to programmatically set token (e.g., after callback handling)
6639
+ setToken(token) {
6640
+ setToken(token);
6641
+ this.emit();
6642
+ }
6643
+ };
6644
+ var howone = {
6645
+ auth: new HowoneAuthClient()
6646
+ };
6647
+ var client_default = howone;
6648
+
6649
+ // src/components/ui/Loading.tsx
6650
+ var import_jsx_runtime8 = require("react/jsx-runtime");
6651
+ var Loading = ({
6652
+ size = "md",
6653
+ text = "Loading...",
6654
+ className = "",
6655
+ fullScreen = false
6656
+ }) => {
6657
+ const sizeClasses = {
6658
+ sm: "h-4 w-4",
6659
+ md: "h-8 w-8",
6660
+ lg: "h-12 w-12"
6661
+ };
6662
+ 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";
6663
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: `${containerClasses} ${className}`, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "text-center", children: [
6664
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
6665
+ "div",
6666
+ {
6667
+ className: `animate-spin rounded-full border-2 border-gray-300 border-t-blue-600 mx-auto ${sizeClasses[size]}`
6668
+ }
6669
+ ),
6670
+ text && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "mt-2 text-sm text-gray-600", children: text })
6671
+ ] }) });
6672
+ };
6673
+ var LoadingSpinner = ({
6674
+ size = "md",
6675
+ className = ""
6676
+ }) => {
6677
+ const sizeClasses = {
6678
+ sm: "h-4 w-4",
6679
+ md: "h-8 w-8",
6680
+ lg: "h-12 w-12"
6681
+ };
6682
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
6683
+ "div",
6684
+ {
6685
+ className: `animate-spin rounded-full border-2 border-gray-300 border-t-blue-600 ${sizeClasses[size]} ${className}`
6686
+ }
6687
+ );
6688
+ };
6689
+
6690
+ // src/components/ui/ErrorBoundary.tsx
6691
+ var import_react9 = require("react");
6692
+ var import_jsx_runtime9 = require("react/jsx-runtime");
6693
+ var ErrorBoundary = class extends import_react9.Component {
6694
+ constructor(props) {
6695
+ super(props);
6696
+ this.handleRetry = () => {
6697
+ this.setState({ hasError: false, error: void 0, errorInfo: void 0 });
6698
+ };
6699
+ this.state = { hasError: false };
6700
+ }
6701
+ static getDerivedStateFromError(error) {
6702
+ return { hasError: true, error };
6703
+ }
6704
+ componentDidCatch(error, errorInfo) {
6705
+ this.setState({
6706
+ error,
6707
+ errorInfo
6708
+ });
6709
+ this.props.onError?.(error, errorInfo);
6710
+ }
6711
+ render() {
6712
+ if (this.state.hasError) {
6713
+ if (this.props.fallback) {
6714
+ const FallbackComponent = this.props.fallback;
6715
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(FallbackComponent, { error: this.state.error, retry: this.handleRetry });
6716
+ }
6717
+ 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: [
6718
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "text-red-500 text-6xl mb-4", children: "\u26A0\uFE0F" }),
6719
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h2", { className: "text-xl font-semibold text-gray-900 mb-2", children: "Something went wrong" }),
6720
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { className: "text-gray-600 mb-4", children: "An unexpected error occurred. Please try refreshing the page." }),
6721
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
6722
+ "button",
6723
+ {
6724
+ onClick: this.handleRetry,
6725
+ className: "px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition-colors",
6726
+ children: "Try Again"
6727
+ }
6728
+ ),
6729
+ false
6730
+ ] }) });
6731
+ }
6732
+ return this.props.children;
6733
+ }
6734
+ };
6735
+ 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: [
6736
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "text-red-500 text-4xl mb-2", children: "\u26A0\uFE0F" }),
6737
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { className: "text-gray-600 mb-2", children: "Something went wrong" }),
6738
+ retry && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
6739
+ "button",
6740
+ {
6741
+ onClick: retry,
6742
+ className: "px-3 py-1 bg-blue-600 text-white text-sm rounded hover:bg-blue-700 transition-colors",
6743
+ children: "Retry"
6744
+ }
6745
+ )
6746
+ ] }) });
6747
+
6748
+ // src/components/theme/ThemeToggle.tsx
6749
+ var React6 = __toESM(require("react"));
6750
+ var import_react10 = require("@iconify/react");
6751
+ var import_jsx_runtime10 = require("react/jsx-runtime");
6752
+ function ThemeToggle({ className }) {
6753
+ const { setTheme, theme } = useTheme();
6754
+ const [mounted, setMounted] = React6.useState(false);
6755
+ React6.useEffect(() => {
6756
+ setMounted(true);
6757
+ }, []);
6758
+ const handleToggle = () => {
6759
+ if (theme === "dark") {
6760
+ setTheme("light");
6761
+ } else {
6762
+ setTheme("dark");
6763
+ }
6764
+ };
6765
+ if (!mounted) {
6766
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
6767
+ "button",
6768
+ {
6769
+ className: `relative inline-flex h-10 w-12 items-center justify-center rounded-md border border-input bg-background hover:bg-accent hover:text-accent-foreground ${className || ""}`,
6770
+ disabled: true,
6771
+ children: [
6772
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react10.Icon, { icon: "solar:sun-bold", width: 20, height: 20 }),
6773
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "sr-only", children: "\u5207\u6362\u4E3B\u9898" })
6774
+ ]
6775
+ }
6776
+ );
6777
+ }
6778
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
6779
+ "button",
6780
+ {
6781
+ className: `inline-flex h-10 w-12 items-center justify-center rounded-md border border-input bg-background hover:bg-accent hover:text-accent-foreground transition-colors ${className || ""}`,
6782
+ onClick: handleToggle,
6783
+ children: [
6784
+ theme === "light" ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react10.Icon, { icon: "solar:sun-bold", width: 20, height: 20 }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react10.Icon, { icon: "solar:moon-linear", width: 20, height: 20 }),
6785
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "sr-only", children: "\u5207\u6362\u4E3B\u9898" })
6786
+ ]
6787
+ }
6788
+ );
6789
+ }
6790
+
6791
+ // src/components/ui/Toast/ClayxToast.tsx
6792
+ var import_react11 = __toESM(require("react"));
6793
+ var import_react_toastify2 = require("react-toastify");
6794
+ var import_react12 = require("@iconify/react");
6795
+ var import_jsx_runtime11 = require("react/jsx-runtime");
6796
+ var TOAST_ICONS = {
6797
+ success: {
6798
+ icon: "mdi:success",
6799
+ color: "text-green-400",
6800
+ className: "text-green-400",
6801
+ // 深色主题配置
6802
+ dark: {
6803
+ bgGradient: "bg-[#14181d]",
6804
+ // 移除透明度 f2
6805
+ gradientColor: "#389726",
6806
+ borderGradient: "border-[#389726]",
6807
+ borderGradientColor: "#389726"
6808
+ },
6809
+ // 浅色主题配置
6810
+ light: {
6811
+ bgGradient: "bg-[#fafafa]",
6812
+ // 移除透明度 ff
6813
+ gradientColor: "#22c55e",
6814
+ borderGradient: "border-[#22c55e]",
6815
+ borderGradientColor: "#22c55e"
6816
+ }
6817
+ },
6818
+ error: {
6819
+ icon: "ic:outline-close",
6820
+ color: "text-red-400",
6821
+ className: "text-red-400",
6822
+ dark: {
6823
+ bgGradient: "bg-[#14181d]",
6824
+ // 移除透明度 f2
6825
+ gradientColor: "#ef4444",
6826
+ borderGradient: "border-[#ef4444]",
6827
+ borderGradientColor: "#ef4444"
6828
+ },
6829
+ light: {
6830
+ bgGradient: "bg-[#fafafa]",
6831
+ // 移除透明度 ff
6832
+ gradientColor: "#f87171",
6833
+ borderGradient: "border-[#f87171]",
6834
+ borderGradientColor: "#f87171"
6835
+ }
6836
+ },
6837
+ warning: {
6838
+ icon: "mi:warning",
6839
+ color: "text-yellow-400",
6840
+ className: "text-yellow-400",
6841
+ dark: {
6842
+ bgGradient: "bg-[#14181d]",
6843
+ // 移除透明度 f2
6844
+ gradientColor: "#facc15",
6845
+ borderGradient: "border-[#facc15]",
6846
+ borderGradientColor: "#facc15"
6847
+ },
6848
+ light: {
6849
+ bgGradient: "bg-[#fafafa]",
6850
+ // 移除透明度 ff
6851
+ gradientColor: "#f59e0b",
6852
+ borderGradient: "border-[#f59e0b]",
6853
+ borderGradientColor: "#f59e0b"
6854
+ }
6855
+ },
6856
+ info: {
6857
+ icon: "ic:outline-info",
6858
+ color: "text-blue-400",
6859
+ className: "text-blue-400",
6860
+ dark: {
6861
+ bgGradient: "bg-[#14181d]",
6862
+ // 移除透明度 f2
6863
+ gradientColor: "#60a5fa",
6864
+ borderGradient: "border-[#60a5fa]",
6865
+ borderGradientColor: "#f0f0f0"
6866
+ },
6867
+ light: {
6868
+ bgGradient: "bg-[#fafafa]",
6869
+ // 移除透明度 ff
6870
+ gradientColor: "#3b82f6",
6871
+ borderGradient: "border-[#3b82f6]",
6872
+ borderGradientColor: "#3b82f6"
6873
+ }
6874
+ },
6875
+ default: {
6876
+ icon: "ic:round-notifications",
6877
+ color: "text-gray-400",
6878
+ className: "text-gray-400",
6879
+ dark: {
6880
+ bgGradient: "bg-[#14181d]",
6881
+ // 移除透明度 f2
6882
+ gradientColor: "#9ca3af",
6883
+ borderGradient: "border-[#9ca3af]",
6884
+ borderGradientColor: "#9ca3af"
6885
+ },
6886
+ light: {
6887
+ bgGradient: "bg-[#fafafa]",
6888
+ // 移除透明度 ff
6889
+ gradientColor: "#6b7280",
6890
+ borderGradient: "border-[#6b7280]",
6891
+ borderGradientColor: "#6b7280"
6892
+ }
6893
+ }
6894
+ };
6895
+ var CloseButton = import_react11.default.memo(({ closeToast }) => {
6896
+ const { theme } = useTheme();
6897
+ const handleClick = (0, import_react11.useCallback)((e) => {
6898
+ e.preventDefault();
6899
+ e.stopPropagation();
6900
+ closeToast?.();
6901
+ }, [closeToast]);
6902
+ const getCloseButtonColor = () => {
6903
+ const actualTheme = theme === "system" ? window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light" : theme;
6904
+ return actualTheme === "dark" ? "#b4b4b4" : "#6b7280";
6905
+ };
6906
+ const getCloseButtonHoverColor = () => {
6907
+ const actualTheme = theme === "system" ? window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light" : theme;
6908
+ return actualTheme === "dark" ? "white" : "#374151";
6909
+ };
6910
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
6911
+ import_react12.Icon,
6912
+ {
6913
+ icon: "vaadin:close",
6914
+ className: "flex items-center justify-center rounded-full relative z-10 flex-shrink-0 cursor-pointer \n transition-colors duration-200 drop-shadow-sm",
6915
+ onClick: handleClick,
6916
+ width: 14,
6917
+ height: 14,
6918
+ style: {
6919
+ color: getCloseButtonColor()
6920
+ },
6921
+ onMouseEnter: (e) => {
6922
+ e.currentTarget.style.color = getCloseButtonHoverColor();
6923
+ },
6924
+ onMouseLeave: (e) => {
6925
+ e.currentTarget.style.color = getCloseButtonColor();
6926
+ }
6927
+ }
6928
+ );
6929
+ });
6930
+ CloseButton.displayName = "CloseButton";
6931
+ var ToastContent = ({ type, title, message, component, closeToast }) => {
6932
+ const iconConfig = TOAST_ICONS[type];
6933
+ const { theme } = useTheme();
6934
+ const handleClose = (0, import_react11.useCallback)(() => {
6935
+ closeToast?.();
6936
+ }, [closeToast]);
6937
+ const getTextColor = () => {
6938
+ const actualTheme = theme === "system" ? window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light" : theme;
6939
+ return actualTheme === "dark" ? "white" : "#1f2937";
6940
+ };
6941
+ const getThemeConfig = () => {
6942
+ const actualTheme = theme === "system" ? window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light" : theme;
6943
+ return actualTheme === "dark" ? iconConfig.dark : iconConfig.light;
6944
+ };
6945
+ const themeConfig = getThemeConfig();
6946
+ if (component) {
6947
+ return /* @__PURE__ */ (0, import_jsx_runtime11.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: [
6948
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "flex-1 relative z-10", children: component }),
6949
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "relative z-10", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(CloseButton, { closeToast: handleClose }) })
6950
+ ] });
6951
+ }
6952
+ return /* @__PURE__ */ (0, import_jsx_runtime11.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: [
6953
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
6954
+ "div",
6955
+ {
6956
+ className: "absolute left-0 top-0 w-full h-full rounded-xl",
6957
+ style: {
6958
+ background: theme === "dark" || theme === "system" && window.matchMedia("(prefers-color-scheme: dark)").matches ? "#0f1419" : "#ffffff",
6959
+ zIndex: -2
6960
+ }
6961
+ }
6962
+ ),
6963
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
6964
+ "div",
6965
+ {
6966
+ className: "absolute left-0 top-0 w-full h-full pointer-events-none rounded-xl",
6967
+ style: {
6968
+ 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}15 0%, ${themeConfig.gradientColor}08 15%, #fafafaff 30%)`,
6969
+ zIndex: -1
6970
+ }
6971
+ }
6972
+ ),
6973
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
6974
+ "div",
6975
+ {
6976
+ className: "absolute left-0 top-0 w-full h-full pointer-events-none rounded-xl",
6977
+ style: {
6978
+ border: "2px solid transparent",
6979
+ 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}40 0%, ${themeConfig.borderGradientColor}25 5%, transparent 22%)`,
6980
+ backgroundOrigin: "border-box",
6981
+ backgroundClip: "border-box",
6982
+ WebkitMask: "linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0)",
6983
+ WebkitMaskComposite: "xor",
6984
+ mask: "linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0)",
6985
+ maskComposite: "exclude"
6986
+ }
6987
+ }
6988
+ ),
6989
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "flex-shrink-0 mt-0.5 relative z-10", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: `w-7 h-7 backdrop-blur-sm rounded-full flex items-center justify-center ${theme === "dark" || theme === "system" && window.matchMedia("(prefers-color-scheme: dark)").matches ? "bg-white/10" : "bg-black/5"}`, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
6990
+ import_react12.Icon,
6991
+ {
6992
+ icon: iconConfig.icon,
6993
+ width: 16,
6994
+ height: 16,
6995
+ className: iconConfig.color,
6996
+ style: {
6997
+ color: themeConfig.gradientColor
6998
+ }
6999
+ }
7000
+ ) }) }),
7001
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex flex-col gap-1 flex-1 relative z-10", children: [
7002
+ title && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
7003
+ "div",
7004
+ {
7005
+ className: "text-[16px] font-semibold leading-tight drop-shadow-sm",
7006
+ style: {
7007
+ color: getTextColor(),
7008
+ backgroundClip: "text"
7009
+ },
7010
+ children: title
7011
+ }
7012
+ ),
7013
+ message && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
7014
+ "div",
7015
+ {
7016
+ className: "text-[13px] font-normal leading-relaxed drop-shadow-sm",
7017
+ style: {
7018
+ color: getTextColor(),
7019
+ backgroundClip: "text"
7020
+ },
7021
+ children: message
7022
+ }
7023
+ )
7024
+ ] }),
7025
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "relative z-10", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(CloseButton, { closeToast: handleClose }) })
7026
+ ] });
7027
+ };
7028
+ var defaultToastOptions = {
7029
+ position: "bottom-right",
7030
+ autoClose: 3e3,
7031
+ hideProgressBar: true,
7032
+ closeOnClick: false,
7033
+ pauseOnHover: true,
7034
+ draggable: true,
7035
+ pauseOnFocusLoss: false,
7036
+ theme: "dark",
7037
+ transition: import_react_toastify2.Bounce
7038
+ };
7039
+ var createToast = (type) => {
7040
+ return (params) => {
7041
+ const { title, message, component, options } = params;
7042
+ (0, import_react_toastify2.toast)(
7043
+ ({ closeToast }) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
7044
+ ToastContent,
7045
+ {
7046
+ type,
7047
+ title,
7048
+ message: message || "",
7049
+ component,
7050
+ closeToast
7051
+ }
7052
+ ),
7053
+ {
7054
+ ...defaultToastOptions,
7055
+ ...options,
7056
+ // 确保圆角样式不被覆盖,添加 rounded-xl 类
7057
+ className: "!p-0 !shadow-none !rounded-xl",
7058
+ style: { padding: 0, borderRadius: "0.75rem" }
7059
+ }
7060
+ );
7061
+ };
7062
+ };
7063
+ var ClayxToast = {
7064
+ success: createToast("success"),
7065
+ error: createToast("error"),
7066
+ warning: createToast("warning"),
7067
+ info: createToast("info"),
7068
+ default: createToast("default")
7069
+ };
7070
+
7071
+ // src/hooks/use-mobile.ts
7072
+ var React8 = __toESM(require("react"));
7073
+ var MOBILE_BREAKPOINT = 768;
7074
+ function useIsMobile() {
7075
+ const [isMobile, setIsMobile] = React8.useState(void 0);
7076
+ React8.useEffect(() => {
7077
+ const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
7078
+ const onChange = () => {
7079
+ setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
7080
+ };
7081
+ mql.addEventListener("change", onChange);
7082
+ setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
7083
+ return () => mql.removeEventListener("change", onChange);
7084
+ }, []);
7085
+ return !!isMobile;
7086
+ }
7087
+
7088
+ // src/hooks/use-debounce.ts
7089
+ var import_react13 = require("react");
7090
+ function useDebounce(value, delay) {
7091
+ const [debouncedValue, setDebouncedValue] = (0, import_react13.useState)(value);
7092
+ (0, import_react13.useEffect)(() => {
7093
+ const handler = setTimeout(() => {
7094
+ setDebouncedValue(value);
7095
+ }, delay);
7096
+ return () => {
7097
+ clearTimeout(handler);
7098
+ };
7099
+ }, [value, delay]);
7100
+ return debouncedValue;
7101
+ }
7102
+
6875
7103
  // src/utils/unified-error-handler/simple.ts
6876
7104
  var SimpleErrorHandler = class {
6877
7105
  constructor() {
@@ -6967,6 +7195,8 @@ init_config();
6967
7195
  DEFAULT_SELECTOR_CONFIG,
6968
7196
  DefaultErrorFallback,
6969
7197
  ERROR_CONFIG,
7198
+ ElementSelector,
7199
+ ElementSelectorProvider,
6970
7200
  ErrorBoundary,
6971
7201
  ErrorHandler,
6972
7202
  FloatingButton,
@@ -6996,6 +7226,7 @@ init_config();
6996
7226
  onAuthStateChanged,
6997
7227
  parseUserFromToken,
6998
7228
  request,
7229
+ sendElementSelectionToParent,
6999
7230
  sendEmailVerificationCode,
7000
7231
  setAuthRoot,
7001
7232
  setDefaultProjectId,
@@ -7004,6 +7235,7 @@ init_config();
7004
7235
  unifiedOAuth,
7005
7236
  useAuth,
7006
7237
  useDebounce,
7238
+ useElementSelector,
7007
7239
  useHowoneContext,
7008
7240
  useIsMobile,
7009
7241
  useTheme,