@howone/sdk 0.2.1 → 0.2.2

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.mjs CHANGED
@@ -1210,14 +1210,12 @@ var ERROR_CONFIG = {
1210
1210
  LOW: ["info", "debug", "trace", "notice"]
1211
1211
  },
1212
1212
  CATEGORY_KEYWORDS: {
1213
- SYNTAX: ["syntaxerror", "unexpected token", "parse error", "invalid syntax"],
1213
+ SYNTAX: ["syntaxerror", "unexpected token", "parse error", "invalid syntax", "expected", "transform failed"],
1214
1214
  NETWORK: ["fetch", "xhr", "network", "cors", "timeout", "connection"],
1215
1215
  RUNTIME: ["referenceerror", "typeerror", "rangeerror", "undefined"],
1216
1216
  SECURITY: ["csp", "xss", "csrf", "security", "unauthorized"],
1217
1217
  PERFORMANCE: ["slow", "memory", "leak", "performance", "timeout"],
1218
- DEVELOPMENT: ["vite", "hmr", "hot reload", "dev server", "webpack"],
1219
- REACT: ["react", "jsx", "component", "hook", "render"],
1220
- VITE: ["vite", "[vite]", "vite:react", "transform failed"]
1218
+ DEVELOPMENT: ["vite", "hmr", "hot reload", "dev server", "webpack", "esbuild", "plugin:vite:esbuild"]
1221
1219
  }
1222
1220
  };
1223
1221
  var GLOBAL_CONFIG = {
@@ -1558,9 +1556,13 @@ var ViteHMRDetector = class {
1558
1556
  setupHMREventListeners() {
1559
1557
  if (typeof window !== "undefined" && window.import?.meta?.hot) {
1560
1558
  const hot = window.import.meta.hot;
1561
- hot.on("vite:error", () => {
1559
+ hot.on("vite:error", (data) => {
1560
+ this.handleViteError(data);
1562
1561
  requestAnimationFrame(() => this.checkForViteErrorOverlay());
1563
1562
  });
1563
+ hot.on("vite:invalidate", (data) => {
1564
+ setTimeout(() => this.checkForCompileErrors(), 500);
1565
+ });
1564
1566
  hot.on("vite:beforeUpdate", () => {
1565
1567
  console.log("[ViteHMRDetector] HMR \u66F4\u65B0\u5F00\u59CB");
1566
1568
  });
@@ -1737,6 +1739,90 @@ File: ${errorInfo.fileText}`;
1737
1739
  }
1738
1740
  }
1739
1741
  }
1742
+ /**
1743
+ * 处理 Vite 错误事件
1744
+ */
1745
+ handleViteError(errorData) {
1746
+ try {
1747
+ const errorPayload = {
1748
+ id: `vite-error-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
1749
+ type: "vite_hmr",
1750
+ error: {
1751
+ name: "ViteError",
1752
+ message: errorData?.message || "Vite error",
1753
+ stack: errorData?.stack || ""
1754
+ },
1755
+ source: "vite:error",
1756
+ timestamp: Date.now(),
1757
+ severity: "error",
1758
+ context: {
1759
+ viteErrorData: errorData,
1760
+ url: window.location.href,
1761
+ userAgent: navigator.userAgent
1762
+ }
1763
+ };
1764
+ if (window.__AUTO_ENGINEER_ERRORS__) {
1765
+ window.__AUTO_ENGINEER_ERRORS__.push(errorPayload);
1766
+ }
1767
+ this.sendMessage({
1768
+ type: "SYSTEM_EVENT",
1769
+ payload: errorPayload,
1770
+ timestamp: Date.now()
1771
+ });
1772
+ } catch (error) {
1773
+ console.error("[ViteHMRDetector] \u5904\u7406 Vite \u9519\u8BEF\u5931\u8D25:", error);
1774
+ }
1775
+ }
1776
+ /**
1777
+ * 检查编译错误
1778
+ */
1779
+ async checkForCompileErrors() {
1780
+ try {
1781
+ if (document.querySelector("vite-error-overlay")) {
1782
+ this.checkForViteErrorOverlay();
1783
+ return;
1784
+ }
1785
+ const response = await fetch(window.location.href, {
1786
+ method: "HEAD",
1787
+ cache: "no-cache"
1788
+ });
1789
+ if (!response.ok) {
1790
+ this.handleCompileError(`HTTP ${response.status}: ${response.statusText}`);
1791
+ }
1792
+ } catch (error) {
1793
+ this.handleCompileError(`Error: ${error.message}`);
1794
+ }
1795
+ }
1796
+ /**
1797
+ * 处理编译错误
1798
+ */
1799
+ handleCompileError(errorMessage) {
1800
+ const errorPayload = {
1801
+ id: `compile-error-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
1802
+ type: "compile_error",
1803
+ error: {
1804
+ name: "CompileError",
1805
+ message: `Compile error: ${errorMessage}`,
1806
+ stack: ""
1807
+ },
1808
+ source: "vite:compile",
1809
+ timestamp: Date.now(),
1810
+ severity: "error",
1811
+ context: {
1812
+ url: window.location.href,
1813
+ userAgent: navigator.userAgent,
1814
+ compilationFailed: true
1815
+ }
1816
+ };
1817
+ if (window.__AUTO_ENGINEER_ERRORS__) {
1818
+ window.__AUTO_ENGINEER_ERRORS__.push(errorPayload);
1819
+ }
1820
+ this.sendMessage({
1821
+ type: "SYSTEM_EVENT",
1822
+ payload: errorPayload,
1823
+ timestamp: Date.now()
1824
+ });
1825
+ }
1740
1826
  /**
1741
1827
  * 检查当前环境是否支持 Vite HMR
1742
1828
  */
@@ -3345,12 +3431,6 @@ var ErrorTracking = class {
3345
3431
  if (ERROR_CONFIG.CATEGORY_KEYWORDS.DEVELOPMENT.some((keyword) => lowerMessage.includes(keyword))) {
3346
3432
  return "DEVELOPMENT";
3347
3433
  }
3348
- if (ERROR_CONFIG.CATEGORY_KEYWORDS.REACT.some((keyword) => lowerMessage.includes(keyword))) {
3349
- return "REACT";
3350
- }
3351
- if (ERROR_CONFIG.CATEGORY_KEYWORDS.VITE.some((keyword) => lowerMessage.includes(keyword))) {
3352
- return "VITE";
3353
- }
3354
3434
  return "UNKNOWN";
3355
3435
  }
3356
3436
  /**
@@ -5762,1708 +5842,1709 @@ var ErrorHandler = class {
5762
5842
  }
5763
5843
  };
5764
5844
 
5765
- // src/utils/iframe-navigation.ts
5766
- function getNavState() {
5767
- if (typeof window === "undefined") {
5768
- return {
5769
- navigationHistory: [],
5770
- currentHistoryIndex: -1,
5771
- initialized: false
5772
- };
5845
+ // src/components/auth/HowoneProvider.tsx
5846
+ import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
5847
+ var globalErrorHandler = null;
5848
+ var initializeErrorHandler = () => {
5849
+ if (!globalErrorHandler) {
5850
+ console.log("[HowOneProvider] \u5728\u6A21\u5757\u9876\u5C42\u521D\u59CB\u5316\u9519\u8BEF\u5904\u7406\u5668...");
5851
+ globalErrorHandler = new ErrorHandler({
5852
+ enableViteHMR: true,
5853
+ enableElementSelector: true,
5854
+ enableInteractionTracking: true
5855
+ });
5856
+ globalErrorHandler.init();
5857
+ window.__ERROR_HANDLER__ = globalErrorHandler;
5858
+ console.log("[HowOneProvider] \u9519\u8BEF\u5904\u7406\u5668\u5DF2\u5728\u6A21\u5757\u9876\u5C42\u521D\u59CB\u5316\u5B8C\u6210");
5773
5859
  }
5774
- if (!window.customNavigationState) {
5775
- window.customNavigationState = {
5776
- navigationHistory: [],
5777
- currentHistoryIndex: -1,
5778
- initialized: false
5860
+ return globalErrorHandler;
5861
+ };
5862
+ initializeErrorHandler();
5863
+ var HowoneContext = createContext2(null);
5864
+ var HowOneProvider = ({
5865
+ children,
5866
+ showFloatingButton = true,
5867
+ projectId,
5868
+ defaultTheme = "system",
5869
+ themeStorageKey = "howone-theme",
5870
+ forceDefaultTheme = false,
5871
+ authUrl = "https://howone.dev/auth",
5872
+ redirectOnUnauthenticated = true
5873
+ }) => {
5874
+ const [user, setUser] = useState7(() => parseUserFromToken(getToken()));
5875
+ const [token, setTokenState] = useState7(() => getToken());
5876
+ const [hasCheckedUrlToken, setHasCheckedUrlToken] = useState7(false);
5877
+ useEffect6(() => {
5878
+ try {
5879
+ const params = new URLSearchParams(window.location.search);
5880
+ let urlToken = params.get("access_token") || params.get("token");
5881
+ if (!urlToken && window.location.hash) {
5882
+ const hashParams = new URLSearchParams(window.location.hash.slice(1));
5883
+ urlToken = hashParams.get("access_token") || hashParams.get("token");
5884
+ }
5885
+ if (urlToken) {
5886
+ console.log("[HowOneProvider] Token captured from URL, storing to localStorage...");
5887
+ setToken(urlToken);
5888
+ setTokenState(urlToken);
5889
+ setUser(parseUserFromToken(urlToken));
5890
+ params.delete("access_token");
5891
+ params.delete("token");
5892
+ params.delete("project_id");
5893
+ const newSearch = params.toString();
5894
+ const newUrl = window.location.pathname + (newSearch ? "?" + newSearch : "");
5895
+ window.history.replaceState({}, "", newUrl);
5896
+ console.log("[HowOneProvider] Token stored successfully, URL cleaned");
5897
+ }
5898
+ } catch (e) {
5899
+ console.error("[HowOneProvider] Failed to capture token from URL:", e);
5900
+ } finally {
5901
+ setHasCheckedUrlToken(true);
5902
+ }
5903
+ }, []);
5904
+ useEffect6(() => {
5905
+ if (!hasCheckedUrlToken) {
5906
+ return;
5907
+ }
5908
+ if (redirectOnUnauthenticated && !token && !user) {
5909
+ const currentUrl = new URL(window.location.href);
5910
+ if (!currentUrl.pathname.includes("/auth")) {
5911
+ console.log("[HowOneProvider] No token found, redirecting to auth page...");
5912
+ try {
5913
+ const authUrlObj = new URL(authUrl);
5914
+ const redirectUri = window.location.href;
5915
+ authUrlObj.searchParams.set("redirect_uri", redirectUri);
5916
+ if (projectId) {
5917
+ authUrlObj.searchParams.set("project_id", projectId);
5918
+ }
5919
+ console.log("[HowOneProvider] Redirecting to:", authUrlObj.toString());
5920
+ window.location.href = authUrlObj.toString();
5921
+ } catch (error) {
5922
+ console.error("[HowOneProvider] Failed to build auth URL:", error);
5923
+ window.location.href = authUrl;
5924
+ }
5925
+ }
5926
+ }
5927
+ }, [token, user, redirectOnUnauthenticated, authUrl, projectId, hasCheckedUrlToken]);
5928
+ const logout = () => {
5929
+ try {
5930
+ setToken(null);
5931
+ } catch {
5932
+ }
5933
+ setTokenState(null);
5934
+ setUser(null);
5935
+ };
5936
+ const value = {
5937
+ user,
5938
+ token,
5939
+ isAuthenticated: hasCheckedUrlToken && !!token,
5940
+ logout
5941
+ };
5942
+ return /* @__PURE__ */ jsxs5(
5943
+ ThemeProvider,
5944
+ {
5945
+ defaultTheme,
5946
+ storageKey: themeStorageKey,
5947
+ forceDefault: forceDefaultTheme,
5948
+ children: [
5949
+ /* @__PURE__ */ jsx7(ElementSelectorProvider, { children: /* @__PURE__ */ jsxs5(HowoneContext.Provider, { value, children: [
5950
+ children,
5951
+ showFloatingButton && /* @__PURE__ */ jsx7(FloatingButton, { onClick: () => window.open("https://howone.ai", "_blank") })
5952
+ ] }) }),
5953
+ /* @__PURE__ */ jsx7(GlobalToastContainer, {})
5954
+ ]
5955
+ }
5956
+ );
5957
+ };
5958
+ function useHowoneContext() {
5959
+ const ctx = useContext2(HowoneContext);
5960
+ if (!ctx) {
5961
+ const t = getToken();
5962
+ return {
5963
+ user: parseUserFromToken(t),
5964
+ token: t,
5965
+ isAuthenticated: !!t,
5966
+ logout: () => {
5967
+ try {
5968
+ setToken(null);
5969
+ } catch {
5970
+ }
5971
+ }
5779
5972
  };
5780
5973
  }
5781
- return window.customNavigationState;
5974
+ return ctx;
5782
5975
  }
5783
- function getElementSelectorState() {
5784
- if (typeof window === "undefined") {
5785
- return { active: false, callback: null };
5976
+
5977
+ // src/components/index.ts
5978
+ init_auth();
5979
+
5980
+ // src/howone/client.ts
5981
+ init_auth();
5982
+ init_config();
5983
+ var HowoneAuthClient = class {
5984
+ constructor() {
5985
+ this.listeners = /* @__PURE__ */ new Set();
5986
+ this.loading = false;
5786
5987
  }
5787
- if (!window.elementSelectorState) {
5788
- window.elementSelectorState = {
5789
- active: false,
5790
- callback: null
5988
+ emit() {
5989
+ const state = {
5990
+ user: parseUserFromToken(getToken()),
5991
+ isLoading: this.loading
5791
5992
  };
5792
- }
5793
- return window.elementSelectorState;
5794
- }
5795
- function sendNavigationState(targetWindow, targetOrigin) {
5796
- const navState = getNavState();
5797
- const canGoBack = navState.currentHistoryIndex > 0;
5798
- const canGoForward = navState.currentHistoryIndex < navState.navigationHistory.length - 1;
5799
- const state = {
5800
- type: "NAVIGATION_STATE",
5801
- payload: {
5802
- canGoBack,
5803
- canGoForward,
5804
- historyLength: navState.navigationHistory.length,
5805
- currentIndex: navState.currentHistoryIndex,
5806
- maxIndex: navState.navigationHistory.length - 1
5993
+ for (const l of this.listeners) {
5994
+ try {
5995
+ l(state);
5996
+ } catch (e) {
5997
+ void e;
5998
+ }
5807
5999
  }
5808
- };
5809
- if (targetWindow && targetOrigin) {
6000
+ }
6001
+ onAuthStateChanged(listener) {
6002
+ this.listeners.add(listener);
5810
6003
  try {
5811
- targetWindow.postMessage(state, targetOrigin);
6004
+ listener({ user: parseUserFromToken(getToken()), isLoading: this.loading });
5812
6005
  } catch (e) {
5813
- if (typeof console !== "undefined" && console.warn) {
5814
- console.warn("Failed to send navigation state:", e.message);
5815
- }
6006
+ void e;
5816
6007
  }
6008
+ return () => {
6009
+ this.listeners.delete(listener);
6010
+ };
5817
6011
  }
5818
- }
5819
- function addToNavigationHistory(url, title) {
5820
- const navState = getNavState();
5821
- if (navState.currentHistoryIndex < navState.navigationHistory.length - 1) {
5822
- navState.navigationHistory = navState.navigationHistory.slice(
5823
- 0,
5824
- navState.currentHistoryIndex + 1
5825
- );
5826
- }
5827
- const currentPage = navState.navigationHistory[navState.currentHistoryIndex];
5828
- if (currentPage && currentPage.url === url) {
5829
- return;
5830
- }
5831
- const pageInfo = {
5832
- url,
5833
- title: title || (typeof document !== "undefined" ? document.title : "") || url,
5834
- timestamp: Date.now()
5835
- };
5836
- navState.navigationHistory.push(pageInfo);
5837
- navState.currentHistoryIndex = navState.navigationHistory.length - 1;
5838
- if (typeof window !== "undefined" && window.parent && window.parent !== window) {
5839
- sendNavigationState(window.parent, "*");
5840
- }
5841
- }
5842
- function customGoBack() {
5843
- const navState = getNavState();
5844
- if (navState.currentHistoryIndex > 0) {
5845
- navState.currentHistoryIndex--;
5846
- if (typeof window !== "undefined" && window.parent && window.parent !== window) {
5847
- sendNavigationState(window.parent, "*");
5848
- }
5849
- return true;
5850
- }
5851
- return false;
5852
- }
5853
- function customGoForward() {
5854
- const navState = getNavState();
5855
- if (navState.currentHistoryIndex < navState.navigationHistory.length - 1) {
5856
- navState.currentHistoryIndex++;
5857
- if (typeof window !== "undefined" && window.parent && window.parent !== window) {
5858
- sendNavigationState(window.parent, "*");
5859
- }
5860
- return true;
5861
- }
5862
- return false;
5863
- }
5864
- function triggerElementSelection() {
5865
- if (typeof window === "undefined") return;
5866
- const event = new CustomEvent("howone:start-element-selection");
5867
- window.dispatchEvent(event);
5868
- getElementSelectorState().active = true;
5869
- }
5870
- function cancelElementSelection() {
5871
- if (typeof window === "undefined") return;
5872
- const event = new CustomEvent("howone:cancel-element-selection");
5873
- window.dispatchEvent(event);
5874
- getElementSelectorState().active = false;
5875
- }
5876
- function handlePageChange() {
5877
- if (typeof window === "undefined") return;
5878
- const currentUrl = window.location.href;
5879
- const currentTitle = document.title;
5880
- addToNavigationHistory(currentUrl, currentTitle);
5881
- }
5882
- function initIframeNavigation() {
5883
- if (typeof window === "undefined") return;
5884
- const navState = getNavState();
5885
- window.addEventListener("keydown", function(e) {
5886
- if (e.key === "Escape" && getElementSelectorState().active) {
5887
- cancelElementSelection();
5888
- }
5889
- });
5890
- window.addEventListener("message", (event) => {
6012
+ // Simple redirect-based login trigger (consumer can override)
6013
+ login() {
6014
+ const root = getEnvs().AUTH_ROOT_VALUE;
5891
6015
  try {
5892
- const { type, payload } = event.data;
5893
- switch (type) {
5894
- case "NAVIGATE_BACK":
5895
- case "GO_BACK":
5896
- customGoBack();
5897
- break;
5898
- case "NAVIGATE_FORWARD":
5899
- case "GO_FORWARD":
5900
- customGoForward();
5901
- break;
5902
- case "REQUEST_NAVIGATION_STATE":
5903
- case "CHECK_NAVIGATION_STATE":
5904
- sendNavigationState(event.source, event.origin);
5905
- break;
5906
- case "START_ELEMENT_SELECTION":
5907
- triggerElementSelection();
5908
- break;
5909
- case "ELEMENT_SELECTED":
5910
- if (event.source && event.source !== window) {
5911
- window.parent.postMessage(
5912
- {
5913
- type: "ELEMENT_SELECTED",
5914
- payload
5915
- },
5916
- "*"
5917
- );
5918
- }
5919
- break;
5920
- case "CANCEL_ELEMENT_SELECTION":
5921
- cancelElementSelection();
5922
- break;
5923
- }
5924
- } catch (e) {
5925
- }
5926
- });
5927
- window.addEventListener("popstate", () => {
5928
- setTimeout(() => {
5929
- if (window.parent && window.parent !== window) {
5930
- sendNavigationState(window.parent, "*");
6016
+ const loc = window.location.href;
6017
+ const authUrl = new URL("/auth", String(root));
6018
+ authUrl.searchParams.set("redirect_uri", String(loc));
6019
+ try {
6020
+ const cfg = (init_config(), __toCommonJS(config_exports));
6021
+ const pid = cfg.getDefaultProjectId && cfg.getDefaultProjectId();
6022
+ if (pid) authUrl.searchParams.set("project_id", String(pid));
6023
+ } catch {
5931
6024
  }
5932
- }, 50);
5933
- });
5934
- window.addEventListener("hashchange", () => {
5935
- handlePageChange();
5936
- });
5937
- window.addEventListener("load", () => {
5938
- if (!navState.initialized) {
5939
- addToNavigationHistory(window.location.href, document.title);
5940
- navState.initialized = true;
5941
- }
5942
- setTimeout(() => {
5943
- if (window.parent && window.parent !== window) {
5944
- sendNavigationState(window.parent, "*");
6025
+ try {
6026
+ if (window.top && window.top !== window) {
6027
+ window.top.location.replace(authUrl.toString());
6028
+ } else {
6029
+ window.location.replace(authUrl.toString());
6030
+ }
6031
+ } catch {
6032
+ try {
6033
+ window.location.replace(String(root));
6034
+ } catch {
6035
+ }
5945
6036
  }
5946
- }, 500);
5947
- });
5948
- if (document.readyState === "loading") {
5949
- document.addEventListener("DOMContentLoaded", () => {
5950
- if (!navState.initialized) {
5951
- addToNavigationHistory(window.location.href, document.title);
5952
- navState.initialized = true;
6037
+ } catch {
6038
+ try {
6039
+ window.location.replace(String(root));
6040
+ } catch {
5953
6041
  }
5954
- });
5955
- } else if (!navState.initialized) {
5956
- addToNavigationHistory(window.location.href, document.title);
5957
- navState.initialized = true;
5958
- }
5959
- window.iframeElementSelector = {
5960
- startSelection: function() {
5961
- triggerElementSelection();
5962
6042
  }
6043
+ }
6044
+ logout() {
6045
+ setToken(null);
6046
+ this.emit();
6047
+ }
6048
+ getUser() {
6049
+ return parseUserFromToken(getToken());
6050
+ }
6051
+ // helper to programmatically set token (e.g., after callback handling)
6052
+ setToken(token) {
6053
+ setToken(token);
6054
+ this.emit();
6055
+ }
6056
+ };
6057
+ var howone = {
6058
+ auth: new HowoneAuthClient()
6059
+ };
6060
+ var client_default = howone;
6061
+
6062
+ // src/components/ui/Loading.tsx
6063
+ import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
6064
+ var Loading = ({
6065
+ size = "md",
6066
+ text = "Loading...",
6067
+ className = "",
6068
+ fullScreen = false
6069
+ }) => {
6070
+ const sizeClasses = {
6071
+ sm: "h-4 w-4",
6072
+ md: "h-8 w-8",
6073
+ lg: "h-12 w-12"
5963
6074
  };
5964
- window.iframeNavigation = {
5965
- addPage: function(url, title) {
5966
- addToNavigationHistory(
5967
- url || window.location.href,
5968
- title || document.title
5969
- );
5970
- },
5971
- getState: function() {
5972
- return {
5973
- canGoBack: navState.currentHistoryIndex > 0,
5974
- canGoForward: navState.currentHistoryIndex < navState.navigationHistory.length - 1,
5975
- historyLength: navState.navigationHistory.length,
5976
- currentIndex: navState.currentHistoryIndex,
5977
- currentPage: navState.navigationHistory[navState.currentHistoryIndex]
5978
- };
5979
- },
5980
- updateState: function() {
5981
- if (window.parent && window.parent !== window) {
5982
- sendNavigationState(window.parent, "*");
6075
+ 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";
6076
+ return /* @__PURE__ */ jsx8("div", { className: `${containerClasses} ${className}`, children: /* @__PURE__ */ jsxs6("div", { className: "text-center", children: [
6077
+ /* @__PURE__ */ jsx8(
6078
+ "div",
6079
+ {
6080
+ className: `animate-spin rounded-full border-2 border-gray-300 border-t-blue-600 mx-auto ${sizeClasses[size]}`
5983
6081
  }
5984
- }
6082
+ ),
6083
+ text && /* @__PURE__ */ jsx8("p", { className: "mt-2 text-sm text-gray-600", children: text })
6084
+ ] }) });
6085
+ };
6086
+ var LoadingSpinner = ({
6087
+ size = "md",
6088
+ className = ""
6089
+ }) => {
6090
+ const sizeClasses = {
6091
+ sm: "h-4 w-4",
6092
+ md: "h-8 w-8",
6093
+ lg: "h-12 w-12"
5985
6094
  };
5986
- }
5987
- var iframeNavigation = {
5988
- /**
5989
- * Initialize the navigation system
5990
- */
5991
- init: initIframeNavigation,
5992
- /**
5993
- * Add a page to navigation history
5994
- */
5995
- addPage: (url, title) => {
5996
- if (typeof window === "undefined") return;
5997
- addToNavigationHistory(
5998
- url || window.location.href,
5999
- title || (typeof document !== "undefined" ? document.title : "")
6000
- );
6001
- },
6002
- /**
6003
- * Get current navigation state
6004
- */
6005
- getState: () => {
6006
- const navState = getNavState();
6007
- return {
6008
- canGoBack: navState.currentHistoryIndex > 0,
6009
- canGoForward: navState.currentHistoryIndex < navState.navigationHistory.length - 1,
6010
- historyLength: navState.navigationHistory.length,
6011
- currentIndex: navState.currentHistoryIndex,
6012
- currentPage: navState.navigationHistory[navState.currentHistoryIndex]
6013
- };
6014
- },
6015
- /**
6016
- * Update navigation state (send to parent)
6017
- */
6018
- updateState: () => {
6019
- if (typeof window !== "undefined" && window.parent && window.parent !== window) {
6020
- sendNavigationState(window.parent, "*");
6095
+ return /* @__PURE__ */ jsx8(
6096
+ "div",
6097
+ {
6098
+ className: `animate-spin rounded-full border-2 border-gray-300 border-t-blue-600 ${sizeClasses[size]} ${className}`
6021
6099
  }
6022
- },
6023
- /**
6024
- * Go back in history
6025
- */
6026
- goBack: customGoBack,
6027
- /**
6028
- * Go forward in history
6029
- */
6030
- goForward: customGoForward
6100
+ );
6031
6101
  };
6032
- var elementSelector = {
6033
- /**
6034
- * Start element selection mode
6035
- */
6036
- startSelection: triggerElementSelection,
6037
- /**
6038
- * Cancel element selection mode
6039
- */
6040
- cancel: cancelElementSelection,
6041
- /**
6042
- * Check if selector is active
6043
- */
6044
- isActive: () => getElementSelectorState().active
6102
+
6103
+ // src/components/ui/ErrorBoundary.tsx
6104
+ import { Component } from "react";
6105
+ import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
6106
+ var ErrorBoundary = class extends Component {
6107
+ constructor(props) {
6108
+ super(props);
6109
+ this.handleRetry = () => {
6110
+ this.setState({ hasError: false, error: void 0, errorInfo: void 0 });
6111
+ };
6112
+ this.state = { hasError: false };
6113
+ }
6114
+ static getDerivedStateFromError(error) {
6115
+ return { hasError: true, error };
6116
+ }
6117
+ componentDidCatch(error, errorInfo) {
6118
+ this.setState({
6119
+ error,
6120
+ errorInfo
6121
+ });
6122
+ this.props.onError?.(error, errorInfo);
6123
+ }
6124
+ render() {
6125
+ if (this.state.hasError) {
6126
+ if (this.props.fallback) {
6127
+ const FallbackComponent = this.props.fallback;
6128
+ return /* @__PURE__ */ jsx9(FallbackComponent, { error: this.state.error, retry: this.handleRetry });
6129
+ }
6130
+ return /* @__PURE__ */ jsx9("div", { className: "min-h-[400px] flex items-center justify-center p-4", children: /* @__PURE__ */ jsxs7("div", { className: "text-center max-w-md", children: [
6131
+ /* @__PURE__ */ jsx9("div", { className: "text-red-500 text-6xl mb-4", children: "\u26A0\uFE0F" }),
6132
+ /* @__PURE__ */ jsx9("h2", { className: "text-xl font-semibold text-gray-900 mb-2", children: "Something went wrong" }),
6133
+ /* @__PURE__ */ jsx9("p", { className: "text-gray-600 mb-4", children: "An unexpected error occurred. Please try refreshing the page." }),
6134
+ /* @__PURE__ */ jsx9(
6135
+ "button",
6136
+ {
6137
+ onClick: this.handleRetry,
6138
+ className: "px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition-colors",
6139
+ children: "Try Again"
6140
+ }
6141
+ ),
6142
+ false
6143
+ ] }) });
6144
+ }
6145
+ return this.props.children;
6146
+ }
6045
6147
  };
6148
+ var DefaultErrorFallback = ({ retry }) => /* @__PURE__ */ jsx9("div", { className: "min-h-[200px] flex items-center justify-center p-4", children: /* @__PURE__ */ jsxs7("div", { className: "text-center", children: [
6149
+ /* @__PURE__ */ jsx9("div", { className: "text-red-500 text-4xl mb-2", children: "\u26A0\uFE0F" }),
6150
+ /* @__PURE__ */ jsx9("p", { className: "text-gray-600 mb-2", children: "Something went wrong" }),
6151
+ retry && /* @__PURE__ */ jsx9(
6152
+ "button",
6153
+ {
6154
+ onClick: retry,
6155
+ className: "px-3 py-1 bg-blue-600 text-white text-sm rounded hover:bg-blue-700 transition-colors",
6156
+ children: "Retry"
6157
+ }
6158
+ )
6159
+ ] }) });
6046
6160
 
6047
- // src/components/auth/HowoneProvider.tsx
6048
- import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
6049
- var HowoneContext = createContext2(null);
6050
- var HowOneProvider = ({
6161
+ // src/components/ui/ClayxButton.tsx
6162
+ import { jsx as jsx10 } from "react/jsx-runtime";
6163
+ var getSizeClasses = (size, isIconOnly) => {
6164
+ if (isIconOnly) {
6165
+ switch (size) {
6166
+ case "sm":
6167
+ return "h-8 w-8 min-w-8 p-0";
6168
+ case "md":
6169
+ return "h-10 w-10 min-w-10 p-0";
6170
+ case "lg":
6171
+ return "h-12 w-12 min-w-12 p-0";
6172
+ default:
6173
+ return "h-10 w-10 min-w-10 p-0";
6174
+ }
6175
+ }
6176
+ switch (size) {
6177
+ case "sm":
6178
+ return "h-8 px-3 text-sm";
6179
+ case "md":
6180
+ return "h-10 px-4 text-base";
6181
+ case "lg":
6182
+ return "h-12 px-6 text-lg";
6183
+ default:
6184
+ return "h-10 px-4 text-base";
6185
+ }
6186
+ };
6187
+ var getVariantClasses = (variant) => {
6188
+ switch (variant) {
6189
+ case "solid":
6190
+ return "bg-primary text-white hover:bg-primary/90";
6191
+ case "ghost":
6192
+ return "bg-transparent hover:bg-white/10";
6193
+ case "flat":
6194
+ return "bg-white/5 hover:bg-white/10";
6195
+ default:
6196
+ return "";
6197
+ }
6198
+ };
6199
+ var ClayxButton = ({
6200
+ isIconOnly = false,
6201
+ size = "md",
6202
+ variant = "solid",
6203
+ className = "",
6051
6204
  children,
6052
- showFloatingButton = true,
6053
- projectId,
6054
- defaultTheme = "system",
6055
- themeStorageKey = "howone-theme",
6056
- forceDefaultTheme = false,
6057
- authUrl = "https://howone.dev/auth",
6058
- redirectOnUnauthenticated = true
6205
+ disabled = false,
6206
+ ...props
6059
6207
  }) => {
6060
- const [user, setUser] = useState7(() => parseUserFromToken(getToken()));
6061
- const [token, setTokenState] = useState7(() => getToken());
6062
- const [hasCheckedUrlToken, setHasCheckedUrlToken] = useState7(false);
6063
- useEffect6(() => {
6064
- const errorHandler = new ErrorHandler({
6065
- enableViteHMR: true,
6066
- enableElementSelector: true,
6067
- enableInteractionTracking: true
6068
- // enableConsoleCapture: true,
6069
- // enableNetworkCapture: true,
6070
- // maxErrors: 100,
6071
- // maxInteractions: 50,
6072
- // debounceTime: 100,
6073
- // reportToParent: true,
6074
- // reportToConsole: true
6075
- });
6076
- errorHandler.init();
6077
- window.__ERROR_HANDLER__ = errorHandler;
6078
- initIframeNavigation();
6079
- try {
6080
- const params = new URLSearchParams(window.location.search);
6081
- let urlToken = params.get("access_token") || params.get("token");
6082
- if (!urlToken && window.location.hash) {
6083
- const hashParams = new URLSearchParams(window.location.hash.slice(1));
6084
- urlToken = hashParams.get("access_token") || hashParams.get("token");
6085
- }
6086
- if (urlToken) {
6087
- console.log("[HowOneProvider] Token captured from URL, storing to localStorage...");
6088
- setToken(urlToken);
6089
- setTokenState(urlToken);
6090
- setUser(parseUserFromToken(urlToken));
6091
- params.delete("access_token");
6092
- params.delete("token");
6093
- params.delete("project_id");
6094
- const newSearch = params.toString();
6095
- const newUrl = window.location.pathname + (newSearch ? "?" + newSearch : "");
6096
- window.history.replaceState({}, "", newUrl);
6097
- console.log("[HowOneProvider] Token stored successfully, URL cleaned");
6098
- }
6099
- } catch (e) {
6100
- console.error("[HowOneProvider] Failed to capture token from URL:", e);
6101
- } finally {
6102
- setHasCheckedUrlToken(true);
6208
+ const sizeClasses = getSizeClasses(size, isIconOnly);
6209
+ const variantClasses = getVariantClasses(variant);
6210
+ const baseClasses = `
6211
+ inline-flex items-center justify-center
6212
+ rounded-md font-medium
6213
+ transition-all duration-200
6214
+ focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-transparent
6215
+ disabled:opacity-50 disabled:cursor-not-allowed disabled:pointer-events-none
6216
+ `.replace(/\s+/g, " ").trim();
6217
+ const combinedClasses = `${baseClasses} ${sizeClasses} ${variantClasses} ${className}`.trim();
6218
+ return /* @__PURE__ */ jsx10(
6219
+ "button",
6220
+ {
6221
+ className: combinedClasses,
6222
+ disabled,
6223
+ ...props,
6224
+ children
6103
6225
  }
6226
+ );
6227
+ };
6228
+
6229
+ // src/components/ui/LimitUpgradeToast.tsx
6230
+ import { Icon as Icon5 } from "@iconify/react";
6231
+
6232
+ // src/components/ui/Toast/ClayxToast.tsx
6233
+ import React7, { useCallback as useCallback4 } from "react";
6234
+ import { Bounce, toast } from "react-toastify";
6235
+ import { Icon as Icon4 } from "@iconify/react";
6236
+
6237
+ // src/components/theme/ThemeToggle.tsx
6238
+ import * as React6 from "react";
6239
+ import { Icon as Icon3 } from "@iconify/react";
6240
+ import { jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
6241
+ function ThemeToggle({ className }) {
6242
+ const { setTheme, theme } = useTheme();
6243
+ const [mounted, setMounted] = React6.useState(false);
6244
+ React6.useEffect(() => {
6245
+ setMounted(true);
6104
6246
  }, []);
6105
- useEffect6(() => {
6106
- if (!hasCheckedUrlToken) {
6107
- return;
6247
+ const handleToggle = () => {
6248
+ if (theme === "dark") {
6249
+ setTheme("light");
6250
+ } else {
6251
+ setTheme("dark");
6108
6252
  }
6109
- if (redirectOnUnauthenticated && !token && !user) {
6110
- const currentUrl = new URL(window.location.href);
6111
- if (!currentUrl.pathname.includes("/auth")) {
6112
- console.log("[HowOneProvider] No token found, redirecting to auth page...");
6113
- try {
6114
- const authUrlObj = new URL(authUrl);
6115
- const redirectUri = window.location.href;
6116
- authUrlObj.searchParams.set("redirect_uri", redirectUri);
6117
- if (projectId) {
6118
- authUrlObj.searchParams.set("project_id", projectId);
6119
- }
6120
- console.log("[HowOneProvider] Redirecting to:", authUrlObj.toString());
6121
- window.location.href = authUrlObj.toString();
6122
- } catch (error) {
6123
- console.error("[HowOneProvider] Failed to build auth URL:", error);
6124
- window.location.href = authUrl;
6253
+ };
6254
+ if (!mounted) {
6255
+ return /* @__PURE__ */ jsxs8(
6256
+ "button",
6257
+ {
6258
+ 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 || ""}`,
6259
+ disabled: true,
6260
+ children: [
6261
+ /* @__PURE__ */ jsx11(Icon3, { icon: "solar:sun-bold", width: 20, height: 20 }),
6262
+ /* @__PURE__ */ jsx11("span", { className: "sr-only", children: "\u5207\u6362\u4E3B\u9898" })
6263
+ ]
6264
+ }
6265
+ );
6266
+ }
6267
+ return /* @__PURE__ */ jsxs8(
6268
+ "button",
6269
+ {
6270
+ 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 || ""}`,
6271
+ onClick: handleToggle,
6272
+ children: [
6273
+ theme === "light" ? /* @__PURE__ */ jsx11(Icon3, { icon: "solar:sun-bold", width: 20, height: 20 }) : /* @__PURE__ */ jsx11(Icon3, { icon: "solar:moon-linear", width: 20, height: 20 }),
6274
+ /* @__PURE__ */ jsx11("span", { className: "sr-only", children: "\u5207\u6362\u4E3B\u9898" })
6275
+ ]
6276
+ }
6277
+ );
6278
+ }
6279
+
6280
+ // src/components/ui/Toast/ClayxToast.tsx
6281
+ import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
6282
+ var TOAST_ICONS = {
6283
+ success: {
6284
+ icon: "mdi:success",
6285
+ color: "text-green-400",
6286
+ className: "text-green-400",
6287
+ // 深色主题配置
6288
+ dark: {
6289
+ bgGradient: "bg-[#14181d]",
6290
+ // 移除透明度 f2
6291
+ gradientColor: "#389726",
6292
+ borderGradient: "border-[#389726]",
6293
+ borderGradientColor: "#389726"
6294
+ },
6295
+ // 浅色主题配置
6296
+ light: {
6297
+ bgGradient: "bg-[#fafafa]",
6298
+ // 移除透明度 ff
6299
+ gradientColor: "#22c55e",
6300
+ borderGradient: "border-[#22c55e]",
6301
+ borderGradientColor: "#22c55e"
6302
+ }
6303
+ },
6304
+ error: {
6305
+ icon: "ic:outline-close",
6306
+ color: "text-red-400",
6307
+ className: "text-red-400",
6308
+ dark: {
6309
+ bgGradient: "bg-[#14181d]",
6310
+ // 移除透明度 f2
6311
+ gradientColor: "#ef4444",
6312
+ borderGradient: "border-[#ef4444]",
6313
+ borderGradientColor: "#ef4444"
6314
+ },
6315
+ light: {
6316
+ bgGradient: "bg-[#fafafa]",
6317
+ // 移除透明度 ff
6318
+ gradientColor: "#f87171",
6319
+ borderGradient: "border-[#f87171]",
6320
+ borderGradientColor: "#f87171"
6321
+ }
6322
+ },
6323
+ warning: {
6324
+ icon: "mi:warning",
6325
+ color: "text-yellow-400",
6326
+ className: "text-yellow-400",
6327
+ dark: {
6328
+ bgGradient: "bg-[#14181d]",
6329
+ // 移除透明度 f2
6330
+ gradientColor: "#facc15",
6331
+ borderGradient: "border-[#facc15]",
6332
+ borderGradientColor: "#facc15"
6333
+ },
6334
+ light: {
6335
+ bgGradient: "bg-[#fafafa]",
6336
+ // 移除透明度 ff
6337
+ gradientColor: "#f59e0b",
6338
+ borderGradient: "border-[#f59e0b]",
6339
+ borderGradientColor: "#f59e0b"
6340
+ }
6341
+ },
6342
+ info: {
6343
+ icon: "ic:outline-info",
6344
+ color: "text-blue-400",
6345
+ className: "text-blue-400",
6346
+ dark: {
6347
+ bgGradient: "bg-[#14181d]",
6348
+ // 移除透明度 f2
6349
+ gradientColor: "#60a5fa",
6350
+ borderGradient: "border-[#60a5fa]",
6351
+ borderGradientColor: "#f0f0f0"
6352
+ },
6353
+ light: {
6354
+ bgGradient: "bg-[#fafafa]",
6355
+ // 移除透明度 ff
6356
+ gradientColor: "#3b82f6",
6357
+ borderGradient: "border-[#3b82f6]",
6358
+ borderGradientColor: "#3b82f6"
6359
+ }
6360
+ },
6361
+ default: {
6362
+ icon: "ic:round-notifications",
6363
+ color: "text-gray-400",
6364
+ className: "text-gray-400",
6365
+ dark: {
6366
+ bgGradient: "bg-[#14181d]",
6367
+ // 移除透明度 f2
6368
+ gradientColor: "#9ca3af",
6369
+ borderGradient: "border-[#9ca3af]",
6370
+ borderGradientColor: "#9ca3af"
6371
+ },
6372
+ light: {
6373
+ bgGradient: "bg-[#fafafa]",
6374
+ // 移除透明度 ff
6375
+ gradientColor: "#6b7280",
6376
+ borderGradient: "border-[#6b7280]",
6377
+ borderGradientColor: "#6b7280"
6378
+ }
6379
+ }
6380
+ };
6381
+ var CloseButton = React7.memo(({ closeToast }) => {
6382
+ const { theme } = useTheme();
6383
+ const handleClick = useCallback4((e) => {
6384
+ e.preventDefault();
6385
+ e.stopPropagation();
6386
+ closeToast?.();
6387
+ }, [closeToast]);
6388
+ const getCloseButtonColor = () => {
6389
+ const actualTheme = theme === "system" ? window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light" : theme;
6390
+ return actualTheme === "dark" ? "#b4b4b4" : "#6b7280";
6391
+ };
6392
+ const getCloseButtonHoverColor = () => {
6393
+ const actualTheme = theme === "system" ? window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light" : theme;
6394
+ return actualTheme === "dark" ? "white" : "#374151";
6395
+ };
6396
+ return /* @__PURE__ */ jsx12(
6397
+ Icon4,
6398
+ {
6399
+ icon: "vaadin:close",
6400
+ className: "flex items-center justify-center rounded-full relative z-10 flex-shrink-0 cursor-pointer \n transition-colors duration-200 drop-shadow-sm",
6401
+ onClick: handleClick,
6402
+ width: 14,
6403
+ height: 14,
6404
+ style: {
6405
+ color: getCloseButtonColor()
6406
+ },
6407
+ onMouseEnter: (e) => {
6408
+ e.currentTarget.style.color = getCloseButtonHoverColor();
6409
+ },
6410
+ onMouseLeave: (e) => {
6411
+ e.currentTarget.style.color = getCloseButtonColor();
6412
+ }
6413
+ }
6414
+ );
6415
+ });
6416
+ CloseButton.displayName = "CloseButton";
6417
+ var ToastContent = ({ type, title, message, component, closeToast }) => {
6418
+ const iconConfig = TOAST_ICONS[type];
6419
+ const { theme } = useTheme();
6420
+ const handleClose = useCallback4(() => {
6421
+ closeToast?.();
6422
+ }, [closeToast]);
6423
+ const getTextColor = () => {
6424
+ const actualTheme = theme === "system" ? window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light" : theme;
6425
+ return actualTheme === "dark" ? "white" : "#1f2937";
6426
+ };
6427
+ const getThemeConfig = () => {
6428
+ const actualTheme = theme === "system" ? window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light" : theme;
6429
+ return actualTheme === "dark" ? iconConfig.dark : iconConfig.light;
6430
+ };
6431
+ const themeConfig = getThemeConfig();
6432
+ if (component) {
6433
+ return /* @__PURE__ */ jsxs9("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: [
6434
+ /* @__PURE__ */ jsx12("div", { className: "flex-1 relative z-10", children: component }),
6435
+ /* @__PURE__ */ jsx12("div", { className: "relative z-10", children: /* @__PURE__ */ jsx12(CloseButton, { closeToast: handleClose }) })
6436
+ ] });
6437
+ }
6438
+ return /* @__PURE__ */ jsxs9("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: [
6439
+ /* @__PURE__ */ jsx12(
6440
+ "div",
6441
+ {
6442
+ className: "absolute left-0 top-0 w-full h-full rounded-xl",
6443
+ style: {
6444
+ background: theme === "dark" || theme === "system" && window.matchMedia("(prefers-color-scheme: dark)").matches ? "#0f1419" : "#ffffff",
6445
+ zIndex: -2
6446
+ }
6447
+ }
6448
+ ),
6449
+ /* @__PURE__ */ jsx12(
6450
+ "div",
6451
+ {
6452
+ className: "absolute left-0 top-0 w-full h-full pointer-events-none rounded-xl",
6453
+ style: {
6454
+ 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%)`,
6455
+ zIndex: -1
6456
+ }
6457
+ }
6458
+ ),
6459
+ /* @__PURE__ */ jsx12(
6460
+ "div",
6461
+ {
6462
+ className: "absolute left-0 top-0 w-full h-full pointer-events-none rounded-xl",
6463
+ style: {
6464
+ border: "2px solid transparent",
6465
+ 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%)`,
6466
+ backgroundOrigin: "border-box",
6467
+ backgroundClip: "border-box",
6468
+ WebkitMask: "linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0)",
6469
+ WebkitMaskComposite: "xor",
6470
+ mask: "linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0)",
6471
+ maskComposite: "exclude"
6472
+ }
6473
+ }
6474
+ ),
6475
+ /* @__PURE__ */ jsx12("div", { className: "flex-shrink-0 mt-0.5 relative z-10", children: /* @__PURE__ */ jsx12("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__ */ jsx12(
6476
+ Icon4,
6477
+ {
6478
+ icon: iconConfig.icon,
6479
+ width: 16,
6480
+ height: 16,
6481
+ className: iconConfig.color,
6482
+ style: {
6483
+ color: themeConfig.gradientColor
6484
+ }
6485
+ }
6486
+ ) }) }),
6487
+ /* @__PURE__ */ jsxs9("div", { className: "flex flex-col gap-1 flex-1 relative z-10", children: [
6488
+ title && /* @__PURE__ */ jsx12(
6489
+ "div",
6490
+ {
6491
+ className: "text-[16px] font-semibold leading-tight drop-shadow-sm",
6492
+ style: {
6493
+ color: getTextColor(),
6494
+ backgroundClip: "text"
6495
+ },
6496
+ children: title
6497
+ }
6498
+ ),
6499
+ message && /* @__PURE__ */ jsx12(
6500
+ "div",
6501
+ {
6502
+ className: "text-[13px] font-normal leading-relaxed drop-shadow-sm",
6503
+ style: {
6504
+ color: getTextColor(),
6505
+ backgroundClip: "text"
6506
+ },
6507
+ children: message
6508
+ }
6509
+ )
6510
+ ] }),
6511
+ /* @__PURE__ */ jsx12("div", { className: "relative z-10", children: /* @__PURE__ */ jsx12(CloseButton, { closeToast: handleClose }) })
6512
+ ] });
6513
+ };
6514
+ var defaultToastOptions = {
6515
+ position: "bottom-right",
6516
+ autoClose: 3e3,
6517
+ hideProgressBar: true,
6518
+ closeOnClick: false,
6519
+ pauseOnHover: true,
6520
+ draggable: true,
6521
+ pauseOnFocusLoss: false,
6522
+ theme: "dark",
6523
+ transition: Bounce
6524
+ };
6525
+ var createToast = (type) => {
6526
+ return (params) => {
6527
+ const { title, message, component, options } = params;
6528
+ toast(
6529
+ ({ closeToast }) => {
6530
+ if (params.render) return params.render(closeToast);
6531
+ return /* @__PURE__ */ jsx12(
6532
+ ToastContent,
6533
+ {
6534
+ type,
6535
+ title,
6536
+ message: message || "",
6537
+ component,
6538
+ closeToast
6539
+ }
6540
+ );
6541
+ },
6542
+ {
6543
+ ...defaultToastOptions,
6544
+ ...options,
6545
+ // 确保圆角样式不被覆盖,添加 rounded-xl 类
6546
+ className: "!p-0 !shadow-none !rounded-xl",
6547
+ style: { padding: 0, borderRadius: "0.75rem" }
6548
+ }
6549
+ );
6550
+ };
6551
+ };
6552
+ var ClayxToast = {
6553
+ success: createToast("success"),
6554
+ error: createToast("error"),
6555
+ warning: createToast("warning"),
6556
+ info: createToast("info"),
6557
+ default: createToast("default")
6558
+ };
6559
+
6560
+ // src/components/ui/LimitUpgradeToast.tsx
6561
+ import { jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
6562
+ var LimitToastContainer = ({ message, onUpgrade, closeToast }) => {
6563
+ return /* @__PURE__ */ jsxs10("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: [
6564
+ /* @__PURE__ */ jsx13(
6565
+ "div",
6566
+ {
6567
+ className: "absolute left-0 top-0 w-full h-full rounded-md",
6568
+ style: {
6569
+ background: "#0f1419",
6570
+ zIndex: -2
6571
+ }
6572
+ }
6573
+ ),
6574
+ /* @__PURE__ */ jsx13(
6575
+ "div",
6576
+ {
6577
+ className: "absolute left-0 top-0 w-full h-full pointer-events-none rounded-md",
6578
+ style: {
6579
+ background: `linear-gradient(135deg, rgba(168,85,247,0.3) 0%, rgba(168,85,247,0.2) 15%, #1A1A1A 30%)`,
6580
+ zIndex: -1
6581
+ }
6582
+ }
6583
+ ),
6584
+ /* @__PURE__ */ jsx13(
6585
+ "div",
6586
+ {
6587
+ className: "absolute left-0 top-0 w-full h-full pointer-events-none rounded-md",
6588
+ style: {
6589
+ border: "2px solid transparent",
6590
+ backgroundImage: `linear-gradient(135deg, rgba(168,85,247,0.6) 0%, rgba(168,85,247,0.4) 5%, transparent 22%)`,
6591
+ backgroundOrigin: "border-box",
6592
+ backgroundClip: "border-box",
6593
+ WebkitMask: "linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0)",
6594
+ WebkitMaskComposite: "xor",
6595
+ mask: "linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0)",
6596
+ maskComposite: "exclude"
6597
+ }
6598
+ }
6599
+ ),
6600
+ /* @__PURE__ */ jsx13("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" }),
6601
+ /* @__PURE__ */ jsx13("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" } }),
6602
+ /* @__PURE__ */ jsx13("div", { className: "relative z-10 flex items-start gap-4 p-4", children: /* @__PURE__ */ jsxs10("div", { className: "flex flex-1 flex-col gap-3", children: [
6603
+ /* @__PURE__ */ jsxs10("div", { className: "flex items-center justify-between", children: [
6604
+ /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-2", children: [
6605
+ /* @__PURE__ */ jsx13("div", { className: "text-lg font-bold bg-gradient-to-r from-white to-gray-400 bg-clip-text text-transparent", children: "Upgrade Required" }),
6606
+ /* @__PURE__ */ jsx13("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" })
6607
+ ] }),
6608
+ /* @__PURE__ */ jsx13(
6609
+ ClayxButton,
6610
+ {
6611
+ onClick: closeToast,
6612
+ isIconOnly: true,
6613
+ size: "sm",
6614
+ className: "h-6 w-6 min-w-6 rounded-full bg-white/5 hover:bg-white/10 transition-colors",
6615
+ children: /* @__PURE__ */ jsx13(Icon5, { icon: "iconamoon:close", className: "w-4 h-4 text-gray-400" })
6616
+ }
6617
+ )
6618
+ ] }),
6619
+ /* @__PURE__ */ jsx13("p", { className: "text-sm text-gray-300 leading-relaxed", children: message }),
6620
+ /* @__PURE__ */ jsx13("div", { className: "mt-1 flex items-center gap-3", children: /* @__PURE__ */ jsx13(
6621
+ ClayxButton,
6622
+ {
6623
+ onClick: () => {
6624
+ onUpgrade();
6625
+ closeToast?.();
6626
+ },
6627
+ className: "flex-1 bg-gradient-to-r from-purple-500 to-pink-500 hover:from-purple-600 hover:to-pink-600 text-white font-semibold transition-all duration-300 hover:shadow-lg hover:shadow-purple-500/30 cursor-pointer",
6628
+ style: { cursor: "pointer" },
6629
+ children: /* @__PURE__ */ jsxs10("span", { className: "flex items-center gap-2", children: [
6630
+ /* @__PURE__ */ jsx13(Icon5, { icon: "solar:rocket-2-bold", className: "w-4 h-4" }),
6631
+ "Upgrade Now"
6632
+ ] })
6125
6633
  }
6126
- }
6127
- }
6128
- }, [token, user, redirectOnUnauthenticated, authUrl, projectId, hasCheckedUrlToken]);
6129
- const logout = () => {
6130
- try {
6131
- setToken(null);
6132
- } catch {
6133
- }
6134
- setTokenState(null);
6135
- setUser(null);
6136
- };
6137
- const value = {
6138
- user,
6139
- token,
6140
- isAuthenticated: hasCheckedUrlToken && !!token,
6141
- logout
6142
- };
6143
- return /* @__PURE__ */ jsxs5(
6144
- ThemeProvider,
6145
- {
6146
- defaultTheme,
6147
- storageKey: themeStorageKey,
6148
- forceDefault: forceDefaultTheme,
6149
- children: [
6150
- /* @__PURE__ */ jsx7(ElementSelectorProvider, { children: /* @__PURE__ */ jsxs5(HowoneContext.Provider, { value, children: [
6151
- children,
6152
- showFloatingButton && /* @__PURE__ */ jsx7(FloatingButton, { onClick: () => window.open("https://howone.ai", "_blank") })
6153
- ] }) }),
6154
- /* @__PURE__ */ jsx7(GlobalToastContainer, {})
6155
- ]
6156
- }
6157
- );
6634
+ ) })
6635
+ ] }) })
6636
+ ] });
6158
6637
  };
6159
- function useHowoneContext() {
6160
- const ctx = useContext2(HowoneContext);
6161
- if (!ctx) {
6162
- const t = getToken();
6163
- return {
6164
- user: parseUserFromToken(t),
6165
- token: t,
6166
- isAuthenticated: !!t,
6167
- logout: () => {
6168
- try {
6169
- setToken(null);
6170
- } catch {
6171
- }
6638
+ function showLimitUpgradeToast(message, onUpgrade) {
6639
+ ClayxToast.default({
6640
+ render: (closeToast) => /* @__PURE__ */ jsx13(LimitToastContainer, { message, onUpgrade, closeToast }),
6641
+ options: {
6642
+ position: "bottom-right",
6643
+ closeOnClick: false,
6644
+ autoClose: false,
6645
+ hideProgressBar: true,
6646
+ draggable: false,
6647
+ pauseOnHover: true,
6648
+ className: "!bg-transparent !shadow-none",
6649
+ style: {
6650
+ background: "transparent",
6651
+ padding: 0,
6652
+ width: "auto",
6653
+ maxWidth: "420px"
6172
6654
  }
6173
- };
6174
- }
6175
- return ctx;
6655
+ }
6656
+ });
6176
6657
  }
6177
6658
 
6178
- // src/components/index.ts
6179
- init_auth();
6180
-
6181
- // src/howone/client.ts
6182
- init_auth();
6183
- init_config();
6184
- var HowoneAuthClient = class {
6185
- constructor() {
6186
- this.listeners = /* @__PURE__ */ new Set();
6187
- this.loading = false;
6659
+ // src/services/ai-workflow.ts
6660
+ var AIWorkflowClient = class {
6661
+ constructor(options = {}) {
6662
+ this.baseUrl = options.baseUrl?.replace(/\/+$/, "") || "";
6663
+ this.apiKey = options.apiKey;
6664
+ this.headers = { "Content-Type": "application/json", ...options.headers || {} };
6665
+ this.fetchImpl = options.fetchImpl || fetch.bind(globalThis);
6188
6666
  }
6189
- emit() {
6190
- const state = {
6191
- user: parseUserFromToken(getToken()),
6192
- isLoading: this.loading
6193
- };
6194
- for (const l of this.listeners) {
6195
- try {
6196
- l(state);
6197
- } catch (e) {
6198
- void e;
6199
- }
6667
+ buildHeaders(extra) {
6668
+ const h = { ...this.headers, ...extra || {} };
6669
+ if (this.apiKey && !h["Authorization"]) {
6670
+ h["Authorization"] = `Bearer ${this.apiKey}`;
6200
6671
  }
6672
+ return h;
6201
6673
  }
6202
- onAuthStateChanged(listener) {
6203
- this.listeners.add(listener);
6674
+ async safeJson(resp) {
6204
6675
  try {
6205
- listener({ user: parseUserFromToken(getToken()), isLoading: this.loading });
6206
- } catch (e) {
6207
- void e;
6676
+ return await resp.json();
6677
+ } catch (_e) {
6678
+ return null;
6208
6679
  }
6209
- return () => {
6210
- this.listeners.delete(listener);
6211
- };
6212
6680
  }
6213
- // Simple redirect-based login trigger (consumer can override)
6214
- login() {
6215
- const root = getEnvs().AUTH_ROOT_VALUE;
6681
+ /**
6682
+ * 按 ID 执行工作流:POST {baseUrl}/workflow/{workflowId}/execute
6683
+ * body: { input, options }
6684
+ */
6685
+ async executeWorkflow(workflowId, inputs, options) {
6686
+ if (!this.baseUrl) {
6687
+ throw new Error("AI workflow client requires a baseUrl (e.g. https://evoagentx-server.fly.dev)");
6688
+ }
6689
+ const url = `${this.baseUrl}/workflow/${workflowId}/execute`;
6216
6690
  try {
6217
- const loc = window.location.href;
6218
- const authUrl = new URL("/auth", String(root));
6219
- authUrl.searchParams.set("redirect_uri", String(loc));
6220
- try {
6221
- const cfg = (init_config(), __toCommonJS(config_exports));
6222
- const pid = cfg.getDefaultProjectId && cfg.getDefaultProjectId();
6223
- if (pid) authUrl.searchParams.set("project_id", String(pid));
6224
- } catch {
6225
- }
6226
- try {
6227
- if (window.top && window.top !== window) {
6228
- window.top.location.replace(authUrl.toString());
6229
- } else {
6230
- window.location.replace(authUrl.toString());
6231
- }
6232
- } catch {
6233
- try {
6234
- window.location.replace(String(root));
6235
- } catch {
6236
- }
6691
+ const res = await this.fetchImpl(url, {
6692
+ method: "POST",
6693
+ headers: this.buildHeaders(),
6694
+ body: JSON.stringify({ inputs, options })
6695
+ });
6696
+ const data = await this.safeJson(res);
6697
+ if (!res.ok) {
6698
+ return { success: false, error: data?.error || `HTTP ${res.status}` };
6237
6699
  }
6238
- } catch {
6239
- try {
6240
- window.location.replace(String(root));
6241
- } catch {
6700
+ if (data && data.status && data.status === 4003) {
6701
+ showLimitUpgradeToast(
6702
+ "Your credits are exhausted. Please upgrade your plan to continue generating projects.",
6703
+ () => window.open("https://clayx.ai/pricing", "_blank")
6704
+ );
6705
+ return null;
6242
6706
  }
6707
+ return data || { success: true };
6708
+ } catch (error) {
6709
+ return { success: false, error: error instanceof Error ? error.message : "Network error" };
6243
6710
  }
6244
6711
  }
6245
- logout() {
6246
- setToken(null);
6247
- this.emit();
6248
- }
6249
- getUser() {
6250
- return parseUserFromToken(getToken());
6251
- }
6252
- // helper to programmatically set token (e.g., after callback handling)
6253
- setToken(token) {
6254
- setToken(token);
6255
- this.emit();
6256
- }
6257
- };
6258
- var howone = {
6259
- auth: new HowoneAuthClient()
6260
6712
  };
6261
- var client_default = howone;
6713
+ function createAIWorkflowClient(options = {}) {
6714
+ return new AIWorkflowClient(options);
6715
+ }
6716
+ var aiWorkflow = createAIWorkflowClient({ baseUrl: "https://evoagentx-server" });
6262
6717
 
6263
- // src/components/ui/Loading.tsx
6264
- import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
6265
- var Loading = ({
6266
- size = "md",
6267
- text = "Loading...",
6268
- className = "",
6269
- fullScreen = false
6270
- }) => {
6271
- const sizeClasses = {
6272
- sm: "h-4 w-4",
6273
- md: "h-8 w-8",
6274
- lg: "h-12 w-12"
6275
- };
6276
- 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";
6277
- return /* @__PURE__ */ jsx8("div", { className: `${containerClasses} ${className}`, children: /* @__PURE__ */ jsxs6("div", { className: "text-center", children: [
6278
- /* @__PURE__ */ jsx8(
6279
- "div",
6280
- {
6281
- className: `animate-spin rounded-full border-2 border-gray-300 border-t-blue-600 mx-auto ${sizeClasses[size]}`
6718
+ // src/services/request/index.ts
6719
+ import axios from "axios";
6720
+ var Request = class {
6721
+ constructor(config) {
6722
+ this.abortControllers = /* @__PURE__ */ new Map();
6723
+ this.instance = axios.create({
6724
+ ...config,
6725
+ validateStatus: (status) => {
6726
+ return status >= 200 && status < 300;
6727
+ }
6728
+ });
6729
+ this.interceptors = config.interceptors;
6730
+ this.instance.interceptors.request.use(
6731
+ this.interceptors?.requestInterceptor,
6732
+ this.interceptors?.requestInterceptorCatch
6733
+ );
6734
+ this.instance.interceptors.response.use(
6735
+ this.interceptors?.responseInterceptor,
6736
+ this.interceptors?.responseInterceptorCatch
6737
+ );
6738
+ this.instance.interceptors.request.use(
6739
+ (config2) => {
6740
+ return config2;
6741
+ },
6742
+ (err) => {
6743
+ return Promise.reject(err);
6744
+ }
6745
+ );
6746
+ this.instance.interceptors.response.use(
6747
+ (res) => {
6748
+ return res.data;
6749
+ },
6750
+ (err) => {
6751
+ if (axios.isCancel(err)) {
6752
+ return Promise.reject({
6753
+ isCanceled: true,
6754
+ message: "request canceled",
6755
+ originalError: err
6756
+ });
6757
+ }
6758
+ if (err.response?.data?.error) {
6759
+ return Promise.reject(err.response.data.error);
6760
+ }
6761
+ return Promise.reject(err);
6282
6762
  }
6283
- ),
6284
- text && /* @__PURE__ */ jsx8("p", { className: "mt-2 text-sm text-gray-600", children: text })
6285
- ] }) });
6286
- };
6287
- var LoadingSpinner = ({
6288
- size = "md",
6289
- className = ""
6290
- }) => {
6291
- const sizeClasses = {
6292
- sm: "h-4 w-4",
6293
- md: "h-8 w-8",
6294
- lg: "h-12 w-12"
6295
- };
6296
- return /* @__PURE__ */ jsx8(
6297
- "div",
6298
- {
6299
- className: `animate-spin rounded-full border-2 border-gray-300 border-t-blue-600 ${sizeClasses[size]} ${className}`
6300
- }
6301
- );
6302
- };
6303
-
6304
- // src/components/ui/ErrorBoundary.tsx
6305
- import { Component } from "react";
6306
- import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
6307
- var ErrorBoundary = class extends Component {
6308
- constructor(props) {
6309
- super(props);
6310
- this.handleRetry = () => {
6311
- this.setState({ hasError: false, error: void 0, errorInfo: void 0 });
6312
- };
6313
- this.state = { hasError: false };
6763
+ );
6314
6764
  }
6315
- static getDerivedStateFromError(error) {
6316
- return { hasError: true, error };
6765
+ cancelRequest(url) {
6766
+ this.abortControllers.forEach((controller, key) => {
6767
+ if (key.includes(url)) {
6768
+ controller.abort();
6769
+ this.abortControllers.delete(key);
6770
+ }
6771
+ });
6317
6772
  }
6318
- componentDidCatch(error, errorInfo) {
6319
- this.setState({
6320
- error,
6321
- errorInfo
6773
+ cancelAllRequests() {
6774
+ this.abortControllers.forEach((controller) => {
6775
+ controller.abort();
6322
6776
  });
6323
- this.props.onError?.(error, errorInfo);
6777
+ this.abortControllers.clear();
6324
6778
  }
6325
- render() {
6326
- if (this.state.hasError) {
6327
- if (this.props.fallback) {
6328
- const FallbackComponent = this.props.fallback;
6329
- return /* @__PURE__ */ jsx9(FallbackComponent, { error: this.state.error, retry: this.handleRetry });
6779
+ request(config) {
6780
+ const controller = new AbortController();
6781
+ const url = config.url || "";
6782
+ const method = config.method || "GET";
6783
+ const key = `${method}:${url}`;
6784
+ this.abortControllers.set(key, controller);
6785
+ config.signal = controller.signal;
6786
+ return new Promise((resolve, reject) => {
6787
+ if (config.interceptors?.requestInterceptor) {
6788
+ config = config.interceptors.requestInterceptor(config);
6330
6789
  }
6331
- return /* @__PURE__ */ jsx9("div", { className: "min-h-[400px] flex items-center justify-center p-4", children: /* @__PURE__ */ jsxs7("div", { className: "text-center max-w-md", children: [
6332
- /* @__PURE__ */ jsx9("div", { className: "text-red-500 text-6xl mb-4", children: "\u26A0\uFE0F" }),
6333
- /* @__PURE__ */ jsx9("h2", { className: "text-xl font-semibold text-gray-900 mb-2", children: "Something went wrong" }),
6334
- /* @__PURE__ */ jsx9("p", { className: "text-gray-600 mb-4", children: "An unexpected error occurred. Please try refreshing the page." }),
6335
- /* @__PURE__ */ jsx9(
6336
- "button",
6337
- {
6338
- onClick: this.handleRetry,
6339
- className: "px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition-colors",
6340
- children: "Try Again"
6341
- }
6342
- ),
6343
- false
6344
- ] }) });
6345
- }
6346
- return this.props.children;
6790
+ this.instance.request(config).then((res) => {
6791
+ this.abortControllers.delete(key);
6792
+ if (config.interceptors?.responseInterceptor) {
6793
+ res = config.interceptors.responseInterceptor(res);
6794
+ }
6795
+ resolve(res);
6796
+ }).catch((err) => {
6797
+ this.abortControllers.delete(key);
6798
+ reject(err);
6799
+ });
6800
+ });
6347
6801
  }
6348
- };
6349
- var DefaultErrorFallback = ({ retry }) => /* @__PURE__ */ jsx9("div", { className: "min-h-[200px] flex items-center justify-center p-4", children: /* @__PURE__ */ jsxs7("div", { className: "text-center", children: [
6350
- /* @__PURE__ */ jsx9("div", { className: "text-red-500 text-4xl mb-2", children: "\u26A0\uFE0F" }),
6351
- /* @__PURE__ */ jsx9("p", { className: "text-gray-600 mb-2", children: "Something went wrong" }),
6352
- retry && /* @__PURE__ */ jsx9(
6353
- "button",
6354
- {
6355
- onClick: retry,
6356
- className: "px-3 py-1 bg-blue-600 text-white text-sm rounded hover:bg-blue-700 transition-colors",
6357
- children: "Retry"
6358
- }
6359
- )
6360
- ] }) });
6361
-
6362
- // src/components/ui/ClayxButton.tsx
6363
- import { jsx as jsx10 } from "react/jsx-runtime";
6364
- var getSizeClasses = (size, isIconOnly) => {
6365
- if (isIconOnly) {
6366
- switch (size) {
6367
- case "sm":
6368
- return "h-8 w-8 min-w-8 p-0";
6369
- case "md":
6370
- return "h-10 w-10 min-w-10 p-0";
6371
- case "lg":
6372
- return "h-12 w-12 min-w-12 p-0";
6373
- default:
6374
- return "h-10 w-10 min-w-10 p-0";
6375
- }
6802
+ get(config) {
6803
+ return this.request({ ...config, method: "GET" });
6376
6804
  }
6377
- switch (size) {
6378
- case "sm":
6379
- return "h-8 px-3 text-sm";
6380
- case "md":
6381
- return "h-10 px-4 text-base";
6382
- case "lg":
6383
- return "h-12 px-6 text-lg";
6384
- default:
6385
- return "h-10 px-4 text-base";
6805
+ post(config) {
6806
+ return this.request({ ...config, method: "POST" });
6386
6807
  }
6387
- };
6388
- var getVariantClasses = (variant) => {
6389
- switch (variant) {
6390
- case "solid":
6391
- return "bg-primary text-white hover:bg-primary/90";
6392
- case "ghost":
6393
- return "bg-transparent hover:bg-white/10";
6394
- case "flat":
6395
- return "bg-white/5 hover:bg-white/10";
6396
- default:
6397
- return "";
6808
+ delete(config) {
6809
+ return this.request({ ...config, method: "DELETE" });
6810
+ }
6811
+ put(config) {
6812
+ return this.request({ ...config, method: "PUT" });
6813
+ }
6814
+ patch(config) {
6815
+ return this.request({ ...config, method: "PATCH" });
6398
6816
  }
6399
6817
  };
6400
- var ClayxButton = ({
6401
- isIconOnly = false,
6402
- size = "md",
6403
- variant = "solid",
6404
- className = "",
6405
- children,
6406
- disabled = false,
6407
- ...props
6408
- }) => {
6409
- const sizeClasses = getSizeClasses(size, isIconOnly);
6410
- const variantClasses = getVariantClasses(variant);
6411
- const baseClasses = `
6412
- inline-flex items-center justify-center
6413
- rounded-md font-medium
6414
- transition-all duration-200
6415
- focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-transparent
6416
- disabled:opacity-50 disabled:cursor-not-allowed disabled:pointer-events-none
6417
- `.replace(/\s+/g, " ").trim();
6418
- const combinedClasses = `${baseClasses} ${sizeClasses} ${variantClasses} ${className}`.trim();
6419
- return /* @__PURE__ */ jsx10(
6420
- "button",
6421
- {
6422
- className: combinedClasses,
6423
- disabled,
6424
- ...props,
6425
- children
6426
- }
6427
- );
6428
- };
6429
-
6430
- // src/components/ui/LimitUpgradeToast.tsx
6431
- import { Icon as Icon5 } from "@iconify/react";
6432
-
6433
- // src/components/ui/Toast/ClayxToast.tsx
6434
- import React7, { useCallback as useCallback4 } from "react";
6435
- import { Bounce, toast } from "react-toastify";
6436
- import { Icon as Icon4 } from "@iconify/react";
6818
+ var request_default = Request;
6437
6819
 
6438
- // src/components/theme/ThemeToggle.tsx
6439
- import * as React6 from "react";
6440
- import { Icon as Icon3 } from "@iconify/react";
6441
- import { jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
6442
- function ThemeToggle({ className }) {
6443
- const { setTheme, theme } = useTheme();
6444
- const [mounted, setMounted] = React6.useState(false);
6445
- React6.useEffect(() => {
6446
- setMounted(true);
6447
- }, []);
6448
- const handleToggle = () => {
6449
- if (theme === "dark") {
6450
- setTheme("light");
6451
- } else {
6452
- setTheme("dark");
6453
- }
6454
- };
6455
- if (!mounted) {
6456
- return /* @__PURE__ */ jsxs8(
6457
- "button",
6458
- {
6459
- 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 || ""}`,
6460
- disabled: true,
6461
- children: [
6462
- /* @__PURE__ */ jsx11(Icon3, { icon: "solar:sun-bold", width: 20, height: 20 }),
6463
- /* @__PURE__ */ jsx11("span", { className: "sr-only", children: "\u5207\u6362\u4E3B\u9898" })
6464
- ]
6465
- }
6466
- );
6467
- }
6468
- return /* @__PURE__ */ jsxs8(
6469
- "button",
6470
- {
6471
- 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 || ""}`,
6472
- onClick: handleToggle,
6473
- children: [
6474
- theme === "light" ? /* @__PURE__ */ jsx11(Icon3, { icon: "solar:sun-bold", width: 20, height: 20 }) : /* @__PURE__ */ jsx11(Icon3, { icon: "solar:moon-linear", width: 20, height: 20 }),
6475
- /* @__PURE__ */ jsx11("span", { className: "sr-only", children: "\u5207\u6362\u4E3B\u9898" })
6476
- ]
6820
+ // src/services/ai-workflow-axios.ts
6821
+ function createAIWorkflowClientAxios(options = {}) {
6822
+ const basePath = options.basePath ?? "/api";
6823
+ const baseUrl = (options.baseUrl || "https://evoagentx-server.fly.dev").replace(/\/+$/, "");
6824
+ const baseAPI = `${baseUrl}${basePath.startsWith("/") ? "" : "/"}${basePath}`.replace(/\/+$/, "");
6825
+ const client = options.requestInstance || new request_default({
6826
+ baseURL: baseAPI,
6827
+ timeout: options.timeout ?? 6e4,
6828
+ interceptors: {
6829
+ requestInterceptor: (config) => {
6830
+ config.headers = config.headers || {};
6831
+ if (options.apiKey && !config.headers["Authorization"]) {
6832
+ config.headers["Authorization"] = `Bearer ${options.apiKey}`;
6833
+ }
6834
+ if (options.headers) {
6835
+ config.headers = { ...config.headers || {}, ...options.headers };
6836
+ }
6837
+ return config;
6838
+ },
6839
+ requestInterceptorCatch: (err) => Promise.reject(err),
6840
+ responseInterceptor: (res) => res,
6841
+ responseInterceptorCatch: (err) => Promise.reject(err)
6477
6842
  }
6478
- );
6843
+ });
6844
+ return {
6845
+ async executeWorkflow(workflowId, inputs, opts) {
6846
+ const url = `${baseUrl}/workflow/${workflowId}/execute`;
6847
+ const data = await client.post({ url, data: { inputs, options: opts } });
6848
+ return data;
6849
+ }
6850
+ };
6479
6851
  }
6480
6852
 
6481
- // src/components/ui/Toast/ClayxToast.tsx
6482
- import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
6483
- var TOAST_ICONS = {
6484
- success: {
6485
- icon: "mdi:success",
6486
- color: "text-green-400",
6487
- className: "text-green-400",
6488
- // 深色主题配置
6489
- dark: {
6490
- bgGradient: "bg-[#14181d]",
6491
- // 移除透明度 f2
6492
- gradientColor: "#389726",
6493
- borderGradient: "border-[#389726]",
6494
- borderGradientColor: "#389726"
6853
+ // src/services/artifact-types.ts
6854
+ function canAccessArtifact(a, ctx = {}) {
6855
+ if (!a) return false;
6856
+ if (a.visibility === "public") return true;
6857
+ if (a.visibility === "project") {
6858
+ if (ctx.projectId && a.projectId && ctx.projectId === a.projectId) return true;
6859
+ if (ctx.tokenScopes && ctx.tokenScopes.includes("project:read")) return true;
6860
+ return false;
6861
+ }
6862
+ if (a.visibility === "private") {
6863
+ if (ctx.userId && a.ownerId && ctx.userId === a.ownerId) return true;
6864
+ if (ctx.tokenScopes && (ctx.tokenScopes.includes("artifact:read:all") || ctx.tokenScopes.includes("admin"))) return true;
6865
+ return false;
6866
+ }
6867
+ if (a.visibility === "shared") {
6868
+ if (ctx.userId && a.sharedWith && a.sharedWith.includes(ctx.userId)) return true;
6869
+ if (ctx.tokenScopes && (ctx.tokenScopes.includes("artifact:read:all") || ctx.tokenScopes.includes("admin"))) return true;
6870
+ return false;
6871
+ }
6872
+ return false;
6873
+ }
6874
+
6875
+ // src/services/artifacts-client.ts
6876
+ function createArtifactsClient(req) {
6877
+ return {
6878
+ async create(input) {
6879
+ return await req.post({ url: "/artifacts", data: input });
6495
6880
  },
6496
- // 浅色主题配置
6497
- light: {
6498
- bgGradient: "bg-[#fafafa]",
6499
- // 移除透明度 ff
6500
- gradientColor: "#22c55e",
6501
- borderGradient: "border-[#22c55e]",
6502
- borderGradientColor: "#22c55e"
6503
- }
6504
- },
6505
- error: {
6506
- icon: "ic:outline-close",
6507
- color: "text-red-400",
6508
- className: "text-red-400",
6509
- dark: {
6510
- bgGradient: "bg-[#14181d]",
6511
- // 移除透明度 f2
6512
- gradientColor: "#ef4444",
6513
- borderGradient: "border-[#ef4444]",
6514
- borderGradientColor: "#ef4444"
6881
+ async list(query) {
6882
+ return await req.get({ url: "/artifacts", params: query });
6515
6883
  },
6516
- light: {
6517
- bgGradient: "bg-[#fafafa]",
6518
- // 移除透明度 ff
6519
- gradientColor: "#f87171",
6520
- borderGradient: "border-[#f87171]",
6521
- borderGradientColor: "#f87171"
6522
- }
6523
- },
6524
- warning: {
6525
- icon: "mi:warning",
6526
- color: "text-yellow-400",
6527
- className: "text-yellow-400",
6528
- dark: {
6529
- bgGradient: "bg-[#14181d]",
6530
- // 移除透明度 f2
6531
- gradientColor: "#facc15",
6532
- borderGradient: "border-[#facc15]",
6533
- borderGradientColor: "#facc15"
6884
+ async get(id) {
6885
+ return await req.get({ url: `/artifacts/${encodeURIComponent(id)}` });
6534
6886
  },
6535
- light: {
6536
- bgGradient: "bg-[#fafafa]",
6537
- // 移除透明度 ff
6538
- gradientColor: "#f59e0b",
6539
- borderGradient: "border-[#f59e0b]",
6540
- borderGradientColor: "#f59e0b"
6541
- }
6542
- },
6543
- info: {
6544
- icon: "ic:outline-info",
6545
- color: "text-blue-400",
6546
- className: "text-blue-400",
6547
- dark: {
6548
- bgGradient: "bg-[#14181d]",
6549
- // 移除透明度 f2
6550
- gradientColor: "#60a5fa",
6551
- borderGradient: "border-[#60a5fa]",
6552
- borderGradientColor: "#f0f0f0"
6887
+ async setVisibility(id, visibility) {
6888
+ await req.patch({ url: `/artifacts/${encodeURIComponent(id)}/visibility`, data: { visibility } });
6553
6889
  },
6554
- light: {
6555
- bgGradient: "bg-[#fafafa]",
6556
- // 移除透明度 ff
6557
- gradientColor: "#3b82f6",
6558
- borderGradient: "border-[#3b82f6]",
6559
- borderGradientColor: "#3b82f6"
6560
- }
6561
- },
6562
- default: {
6563
- icon: "ic:round-notifications",
6564
- color: "text-gray-400",
6565
- className: "text-gray-400",
6566
- dark: {
6567
- bgGradient: "bg-[#14181d]",
6568
- // 移除透明度 f2
6569
- gradientColor: "#9ca3af",
6570
- borderGradient: "border-[#9ca3af]",
6571
- borderGradientColor: "#9ca3af"
6890
+ async delete(id) {
6891
+ await req.delete({ url: `/artifacts/${encodeURIComponent(id)}` });
6572
6892
  },
6573
- light: {
6574
- bgGradient: "bg-[#fafafa]",
6575
- // 移除透明度 ff
6576
- gradientColor: "#6b7280",
6577
- borderGradient: "border-[#6b7280]",
6578
- borderGradientColor: "#6b7280"
6579
- }
6580
- }
6581
- };
6582
- var CloseButton = React7.memo(({ closeToast }) => {
6583
- const { theme } = useTheme();
6584
- const handleClick = useCallback4((e) => {
6585
- e.preventDefault();
6586
- e.stopPropagation();
6587
- closeToast?.();
6588
- }, [closeToast]);
6589
- const getCloseButtonColor = () => {
6590
- const actualTheme = theme === "system" ? window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light" : theme;
6591
- return actualTheme === "dark" ? "#b4b4b4" : "#6b7280";
6592
- };
6593
- const getCloseButtonHoverColor = () => {
6594
- const actualTheme = theme === "system" ? window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light" : theme;
6595
- return actualTheme === "dark" ? "white" : "#374151";
6596
- };
6597
- return /* @__PURE__ */ jsx12(
6598
- Icon4,
6599
- {
6600
- icon: "vaadin:close",
6601
- className: "flex items-center justify-center rounded-full relative z-10 flex-shrink-0 cursor-pointer \n transition-colors duration-200 drop-shadow-sm",
6602
- onClick: handleClick,
6603
- width: 14,
6604
- height: 14,
6605
- style: {
6606
- color: getCloseButtonColor()
6607
- },
6608
- onMouseEnter: (e) => {
6609
- e.currentTarget.style.color = getCloseButtonHoverColor();
6610
- },
6611
- onMouseLeave: (e) => {
6612
- e.currentTarget.style.color = getCloseButtonColor();
6613
- }
6893
+ // convenience local check (server is authoritative)
6894
+ canAccessLocal(a, ctx) {
6895
+ if (!a) return false;
6896
+ if (a.visibility === "public") return true;
6897
+ if (a.visibility === "project") return Boolean(ctx.projectId && a.projectId && ctx.projectId === a.projectId);
6898
+ if (a.visibility === "private") return Boolean(ctx.userId && a.ownerId && ctx.userId === a.ownerId);
6899
+ if (a.visibility === "shared") return Boolean(ctx.userId && a.sharedWith && a.sharedWith.includes(ctx.userId));
6900
+ return false;
6614
6901
  }
6615
- );
6616
- });
6617
- CloseButton.displayName = "CloseButton";
6618
- var ToastContent = ({ type, title, message, component, closeToast }) => {
6619
- const iconConfig = TOAST_ICONS[type];
6620
- const { theme } = useTheme();
6621
- const handleClose = useCallback4(() => {
6622
- closeToast?.();
6623
- }, [closeToast]);
6624
- const getTextColor = () => {
6625
- const actualTheme = theme === "system" ? window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light" : theme;
6626
- return actualTheme === "dark" ? "white" : "#1f2937";
6627
6902
  };
6628
- const getThemeConfig = () => {
6629
- const actualTheme = theme === "system" ? window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light" : theme;
6630
- return actualTheme === "dark" ? iconConfig.dark : iconConfig.light;
6631
- };
6632
- const themeConfig = getThemeConfig();
6633
- if (component) {
6634
- return /* @__PURE__ */ jsxs9("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: [
6635
- /* @__PURE__ */ jsx12("div", { className: "flex-1 relative z-10", children: component }),
6636
- /* @__PURE__ */ jsx12("div", { className: "relative z-10", children: /* @__PURE__ */ jsx12(CloseButton, { closeToast: handleClose }) })
6637
- ] });
6638
- }
6639
- return /* @__PURE__ */ jsxs9("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: [
6640
- /* @__PURE__ */ jsx12(
6641
- "div",
6642
- {
6643
- className: "absolute left-0 top-0 w-full h-full rounded-xl",
6644
- style: {
6645
- background: theme === "dark" || theme === "system" && window.matchMedia("(prefers-color-scheme: dark)").matches ? "#0f1419" : "#ffffff",
6646
- zIndex: -2
6647
- }
6648
- }
6649
- ),
6650
- /* @__PURE__ */ jsx12(
6651
- "div",
6652
- {
6653
- className: "absolute left-0 top-0 w-full h-full pointer-events-none rounded-xl",
6654
- style: {
6655
- 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%)`,
6656
- zIndex: -1
6657
- }
6658
- }
6659
- ),
6660
- /* @__PURE__ */ jsx12(
6661
- "div",
6662
- {
6663
- className: "absolute left-0 top-0 w-full h-full pointer-events-none rounded-xl",
6664
- style: {
6665
- border: "2px solid transparent",
6666
- 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%)`,
6667
- backgroundOrigin: "border-box",
6668
- backgroundClip: "border-box",
6669
- WebkitMask: "linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0)",
6670
- WebkitMaskComposite: "xor",
6671
- mask: "linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0)",
6672
- maskComposite: "exclude"
6903
+ }
6904
+
6905
+ // src/services/index.ts
6906
+ init_auth();
6907
+ init_config();
6908
+ init_config();
6909
+ init_auth();
6910
+
6911
+ // src/utils/urlSanitizer.ts
6912
+ var DEFAULT_SENSITIVE = ["token", "access_token", "auth", "auth_token"];
6913
+ function removeSensitiveParamsFromUrl(opts) {
6914
+ if (typeof window === "undefined") return;
6915
+ try {
6916
+ const { clearAll, sensitiveParams, includeHash = true, onChanged } = opts || {};
6917
+ const sens = (sensitiveParams && sensitiveParams.length > 0 ? sensitiveParams : DEFAULT_SENSITIVE).map((s) => s.toLowerCase());
6918
+ const before = window.location.href;
6919
+ const url = new URL(before);
6920
+ if (clearAll) {
6921
+ url.search = "";
6922
+ } else if (url.search) {
6923
+ let changed = false;
6924
+ for (const [k] of url.searchParams) {
6925
+ if (sens.includes(k.toLowerCase())) {
6926
+ url.searchParams.delete(k);
6927
+ changed = true;
6673
6928
  }
6674
6929
  }
6675
- ),
6676
- /* @__PURE__ */ jsx12("div", { className: "flex-shrink-0 mt-0.5 relative z-10", children: /* @__PURE__ */ jsx12("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__ */ jsx12(
6677
- Icon4,
6678
- {
6679
- icon: iconConfig.icon,
6680
- width: 16,
6681
- height: 16,
6682
- className: iconConfig.color,
6683
- style: {
6684
- color: themeConfig.gradientColor
6685
- }
6930
+ if (changed) {
6931
+ const qs = url.searchParams.toString();
6932
+ url.search = qs ? `?${qs}` : "";
6686
6933
  }
6687
- ) }) }),
6688
- /* @__PURE__ */ jsxs9("div", { className: "flex flex-col gap-1 flex-1 relative z-10", children: [
6689
- title && /* @__PURE__ */ jsx12(
6690
- "div",
6691
- {
6692
- className: "text-[16px] font-semibold leading-tight drop-shadow-sm",
6693
- style: {
6694
- color: getTextColor(),
6695
- backgroundClip: "text"
6696
- },
6697
- children: title
6698
- }
6699
- ),
6700
- message && /* @__PURE__ */ jsx12(
6701
- "div",
6702
- {
6703
- className: "text-[13px] font-normal leading-relaxed drop-shadow-sm",
6704
- style: {
6705
- color: getTextColor(),
6706
- backgroundClip: "text"
6707
- },
6708
- children: message
6709
- }
6710
- )
6711
- ] }),
6712
- /* @__PURE__ */ jsx12("div", { className: "relative z-10", children: /* @__PURE__ */ jsx12(CloseButton, { closeToast: handleClose }) })
6713
- ] });
6714
- };
6715
- var defaultToastOptions = {
6716
- position: "bottom-right",
6717
- autoClose: 3e3,
6718
- hideProgressBar: true,
6719
- closeOnClick: false,
6720
- pauseOnHover: true,
6721
- draggable: true,
6722
- pauseOnFocusLoss: false,
6723
- theme: "dark",
6724
- transition: Bounce
6725
- };
6726
- var createToast = (type) => {
6727
- return (params) => {
6728
- const { title, message, component, options } = params;
6729
- toast(
6730
- ({ closeToast }) => {
6731
- if (params.render) return params.render(closeToast);
6732
- return /* @__PURE__ */ jsx12(
6733
- ToastContent,
6734
- {
6735
- type,
6736
- title,
6737
- message: message || "",
6738
- component,
6739
- closeToast
6934
+ }
6935
+ if (includeHash && url.hash) {
6936
+ const raw = url.hash.slice(1);
6937
+ if (raw.includes("=")) {
6938
+ const hp = new URLSearchParams(raw);
6939
+ let changed = false;
6940
+ for (const [k] of hp) {
6941
+ if (clearAll || sens.includes(k.toLowerCase())) {
6942
+ hp.delete(k);
6943
+ changed = true;
6740
6944
  }
6741
- );
6742
- },
6743
- {
6744
- ...defaultToastOptions,
6745
- ...options,
6746
- // 确保圆角样式不被覆盖,添加 rounded-xl 类
6747
- className: "!p-0 !shadow-none !rounded-xl",
6748
- style: { padding: 0, borderRadius: "0.75rem" }
6749
- }
6750
- );
6751
- };
6752
- };
6753
- var ClayxToast = {
6754
- success: createToast("success"),
6755
- error: createToast("error"),
6756
- warning: createToast("warning"),
6757
- info: createToast("info"),
6758
- default: createToast("default")
6759
- };
6760
-
6761
- // src/components/ui/LimitUpgradeToast.tsx
6762
- import { jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
6763
- var LimitToastContainer = ({ message, onUpgrade, closeToast }) => {
6764
- return /* @__PURE__ */ jsxs10("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: [
6765
- /* @__PURE__ */ jsx13(
6766
- "div",
6767
- {
6768
- className: "absolute left-0 top-0 w-full h-full rounded-md",
6769
- style: {
6770
- background: "#0f1419",
6771
- zIndex: -2
6772
6945
  }
6773
- }
6774
- ),
6775
- /* @__PURE__ */ jsx13(
6776
- "div",
6777
- {
6778
- className: "absolute left-0 top-0 w-full h-full pointer-events-none rounded-md",
6779
- style: {
6780
- background: `linear-gradient(135deg, rgba(168,85,247,0.3) 0%, rgba(168,85,247,0.2) 15%, #1A1A1A 30%)`,
6781
- zIndex: -1
6946
+ if (changed) {
6947
+ const hs = hp.toString();
6948
+ url.hash = hs ? `#${hs}` : "";
6782
6949
  }
6783
- }
6784
- ),
6785
- /* @__PURE__ */ jsx13(
6786
- "div",
6787
- {
6788
- className: "absolute left-0 top-0 w-full h-full pointer-events-none rounded-md",
6789
- style: {
6790
- border: "2px solid transparent",
6791
- backgroundImage: `linear-gradient(135deg, rgba(168,85,247,0.6) 0%, rgba(168,85,247,0.4) 5%, transparent 22%)`,
6792
- backgroundOrigin: "border-box",
6793
- backgroundClip: "border-box",
6794
- WebkitMask: "linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0)",
6795
- WebkitMaskComposite: "xor",
6796
- mask: "linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0)",
6797
- maskComposite: "exclude"
6950
+ } else {
6951
+ if (!clearAll && sens.some((p) => raw.toLowerCase().startsWith(p))) {
6952
+ url.hash = "";
6953
+ } else if (clearAll) {
6954
+ url.hash = "";
6798
6955
  }
6799
6956
  }
6800
- ),
6801
- /* @__PURE__ */ jsx13("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" }),
6802
- /* @__PURE__ */ jsx13("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" } }),
6803
- /* @__PURE__ */ jsx13("div", { className: "relative z-10 flex items-start gap-4 p-4", children: /* @__PURE__ */ jsxs10("div", { className: "flex flex-1 flex-col gap-3", children: [
6804
- /* @__PURE__ */ jsxs10("div", { className: "flex items-center justify-between", children: [
6805
- /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-2", children: [
6806
- /* @__PURE__ */ jsx13("div", { className: "text-lg font-bold bg-gradient-to-r from-white to-gray-400 bg-clip-text text-transparent", children: "Upgrade Required" }),
6807
- /* @__PURE__ */ jsx13("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" })
6808
- ] }),
6809
- /* @__PURE__ */ jsx13(
6810
- ClayxButton,
6811
- {
6812
- onClick: closeToast,
6813
- isIconOnly: true,
6814
- size: "sm",
6815
- className: "h-6 w-6 min-w-6 rounded-full bg-white/5 hover:bg-white/10 transition-colors",
6816
- children: /* @__PURE__ */ jsx13(Icon5, { icon: "iconamoon:close", className: "w-4 h-4 text-gray-400" })
6817
- }
6818
- )
6819
- ] }),
6820
- /* @__PURE__ */ jsx13("p", { className: "text-sm text-gray-300 leading-relaxed", children: message }),
6821
- /* @__PURE__ */ jsx13("div", { className: "mt-1 flex items-center gap-3", children: /* @__PURE__ */ jsx13(
6822
- ClayxButton,
6823
- {
6824
- onClick: () => {
6825
- onUpgrade();
6826
- closeToast?.();
6827
- },
6828
- className: "flex-1 bg-gradient-to-r from-purple-500 to-pink-500 hover:from-purple-600 hover:to-pink-600 text-white font-semibold transition-all duration-300 hover:shadow-lg hover:shadow-purple-500/30 cursor-pointer",
6829
- style: { cursor: "pointer" },
6830
- children: /* @__PURE__ */ jsxs10("span", { className: "flex items-center gap-2", children: [
6831
- /* @__PURE__ */ jsx13(Icon5, { icon: "solar:rocket-2-bold", className: "w-4 h-4" }),
6832
- "Upgrade Now"
6833
- ] })
6957
+ }
6958
+ const next = url.pathname + url.search + url.hash;
6959
+ if (next !== window.location.pathname + window.location.search + window.location.hash) {
6960
+ window.history.replaceState(window.history.state, document.title, next);
6961
+ onChanged && onChanged(next);
6962
+ }
6963
+ } catch (e) {
6964
+ console.warn("[howone][urlSanitizer] failed", e);
6965
+ }
6966
+ }
6967
+
6968
+ // src/services/index.ts
6969
+ function getGlobalAvailableToken() {
6970
+ try {
6971
+ return getToken() || null;
6972
+ } catch {
6973
+ return null;
6974
+ }
6975
+ }
6976
+ function wrapRequestWithProjectPrefix(biz, projectId) {
6977
+ if (!projectId) return biz;
6978
+ const prefix = `/entities/apps/${String(projectId)}`;
6979
+ function shouldPrefix(url) {
6980
+ if (!url) return false;
6981
+ const u = String(url);
6982
+ if (u.startsWith(prefix)) return false;
6983
+ if (/^https?:\/\//.test(u) || u.startsWith("//")) return false;
6984
+ if (u.startsWith("/data")) return true;
6985
+ return false;
6986
+ }
6987
+ const wrapped = {
6988
+ instance: biz.instance,
6989
+ request: (config) => {
6990
+ try {
6991
+ if (config && typeof config.url === "string" && shouldPrefix(config.url)) {
6992
+ config = { ...config, url: `${prefix}${config.url}` };
6834
6993
  }
6835
- ) })
6836
- ] }) })
6837
- ] });
6838
- };
6839
- function showLimitUpgradeToast(message, onUpgrade) {
6840
- ClayxToast.default({
6841
- render: (closeToast) => /* @__PURE__ */ jsx13(LimitToastContainer, { message, onUpgrade, closeToast }),
6842
- options: {
6843
- position: "bottom-right",
6844
- closeOnClick: false,
6845
- autoClose: false,
6846
- hideProgressBar: true,
6847
- draggable: false,
6848
- pauseOnHover: true,
6849
- className: "!bg-transparent !shadow-none",
6850
- style: {
6851
- background: "transparent",
6852
- padding: 0,
6853
- width: "auto",
6854
- maxWidth: "420px"
6994
+ } catch (_e) {
6855
6995
  }
6856
- }
6857
- });
6996
+ return biz.request(config);
6997
+ },
6998
+ get: (config) => wrapped.request({ ...config, method: "GET" }),
6999
+ post: (config) => wrapped.request({ ...config, method: "POST" }),
7000
+ put: (config) => wrapped.request({ ...config, method: "PUT" }),
7001
+ patch: (config) => wrapped.request({ ...config, method: "PATCH" }),
7002
+ delete: (config) => wrapped.request({ ...config, method: "DELETE" }),
7003
+ cancelRequest: (url) => biz.cancelRequest(url),
7004
+ cancelAllRequests: () => biz.cancelAllRequests()
7005
+ };
7006
+ return wrapped;
6858
7007
  }
6859
-
6860
- // src/services/ai-workflow.ts
6861
- var AIWorkflowClient = class {
6862
- constructor(options = {}) {
6863
- this.baseUrl = options.baseUrl?.replace(/\/+$/, "") || "";
6864
- this.apiKey = options.apiKey;
6865
- this.headers = { "Content-Type": "application/json", ...options.headers || {} };
6866
- this.fetchImpl = options.fetchImpl || fetch.bind(globalThis);
7008
+ function createClient(opts) {
7009
+ const envValue = opts.env || getGlobalEnvironment() || "prod";
7010
+ const env2 = setEnvironment(envValue);
7011
+ function makeRequestFromBase(base) {
7012
+ return new request_default({
7013
+ baseURL: base,
7014
+ timeout: 6e4,
7015
+ interceptors: {
7016
+ requestInterceptor: (config) => {
7017
+ config.headers = config.headers || {};
7018
+ if (!config.headers["Authorization"]) {
7019
+ const availableToken = getAvailableToken();
7020
+ if (availableToken) {
7021
+ config.headers["Authorization"] = `Bearer ${availableToken}`;
7022
+ }
7023
+ }
7024
+ return config;
7025
+ },
7026
+ requestInterceptorCatch: (err) => Promise.reject(err),
7027
+ responseInterceptor: (res) => {
7028
+ const data = res.data;
7029
+ if (data && data.status && data.status === 4003) {
7030
+ showLimitUpgradeToast(
7031
+ "Your credits are exhausted. Please upgrade your plan to continue generating projects.",
7032
+ () => window.open(`${getEnvs().AUTH_ROOT_VALUE}/price`, "_blank")
7033
+ );
7034
+ return res;
7035
+ }
7036
+ return res;
7037
+ },
7038
+ responseInterceptorCatch: (err) => Promise.reject(err)
7039
+ }
7040
+ });
6867
7041
  }
6868
- buildHeaders(extra) {
6869
- const h = { ...this.headers, ...extra || {} };
6870
- if (this.apiKey && !h["Authorization"]) {
6871
- h["Authorization"] = `Bearer ${this.apiKey}`;
6872
- }
6873
- return h;
7042
+ const biz = makeRequestFromBase(env2.baseUrl);
7043
+ const ai = makeRequestFromBase(env2.aiBaseUrl);
7044
+ const bizWrapped = wrapRequestWithProjectPrefix(biz, opts?.projectId);
7045
+ let token = null;
7046
+ function getAvailableToken() {
7047
+ return token || getGlobalAvailableToken();
6874
7048
  }
6875
- async safeJson(resp) {
6876
- try {
6877
- return await resp.json();
6878
- } catch (_e) {
6879
- return null;
7049
+ try {
7050
+ if (opts?.projectId) {
7051
+ setDefaultProjectId(String(opts.projectId));
6880
7052
  }
7053
+ } catch {
6881
7054
  }
6882
- /**
6883
- * 按 ID 执行工作流:POST {baseUrl}/workflow/{workflowId}/execute
6884
- * body: { input, options }
6885
- */
6886
- async executeWorkflow(workflowId, inputs, options) {
6887
- if (!this.baseUrl) {
6888
- throw new Error("AI workflow client requires a baseUrl (e.g. https://evoagentx-server.fly.dev)");
6889
- }
6890
- const url = `${this.baseUrl}/workflow/${workflowId}/execute`;
7055
+ function applyToken(t) {
6891
7056
  try {
6892
- const res = await this.fetchImpl(url, {
6893
- method: "POST",
6894
- headers: this.buildHeaders(),
6895
- body: JSON.stringify({ inputs, options })
6896
- });
6897
- const data = await this.safeJson(res);
6898
- if (!res.ok) {
6899
- return { success: false, error: data?.error || `HTTP ${res.status}` };
6900
- }
6901
- if (data && data.status && data.status === 4003) {
6902
- showLimitUpgradeToast(
6903
- "Your credits are exhausted. Please upgrade your plan to continue generating projects.",
6904
- () => window.open("https://clayx.ai/pricing", "_blank")
6905
- );
6906
- return null;
7057
+ try {
7058
+ if (biz && biz.instance) {
7059
+ if (t) biz.instance.defaults.headers.common["Authorization"] = `Bearer ${t}`;
7060
+ else delete biz.instance.defaults.headers.common["Authorization"];
7061
+ }
7062
+ if (ai && ai.instance) {
7063
+ if (t) ai.instance.defaults.headers.common["Authorization"] = `Bearer ${t}`;
7064
+ else delete ai.instance.defaults.headers.common["Authorization"];
7065
+ }
7066
+ } catch (_e) {
6907
7067
  }
6908
- return data || { success: true };
6909
- } catch (error) {
6910
- return { success: false, error: error instanceof Error ? error.message : "Network error" };
7068
+ } catch (_e) {
6911
7069
  }
6912
7070
  }
6913
- };
6914
- function createAIWorkflowClient(options = {}) {
6915
- return new AIWorkflowClient(options);
6916
- }
6917
- var aiWorkflow = createAIWorkflowClient({ baseUrl: "https://evoagentx-server" });
6918
-
6919
- // src/services/request/index.ts
6920
- import axios from "axios";
6921
- var Request = class {
6922
- constructor(config) {
6923
- this.abortControllers = /* @__PURE__ */ new Map();
6924
- this.instance = axios.create({
6925
- ...config,
6926
- validateStatus: (status) => {
6927
- return status >= 200 && status < 300;
7071
+ const workflowRequestWrapped = {
7072
+ get: ai.get.bind(ai),
7073
+ post: (config) => {
7074
+ const modifiedConfig = { ...config };
7075
+ if (opts?.projectId && modifiedConfig.url) {
7076
+ const workflowPattern = /^\/?(?:workflow\/)?([^\/]+)\/execute/;
7077
+ const match = modifiedConfig.url.match(workflowPattern);
7078
+ if (match) {
7079
+ const workflowId = match[1];
7080
+ modifiedConfig.url = `/workflow/${opts.projectId}/${workflowId}/execute`;
7081
+ }
6928
7082
  }
6929
- });
6930
- this.interceptors = config.interceptors;
6931
- this.instance.interceptors.request.use(
6932
- this.interceptors?.requestInterceptor,
6933
- this.interceptors?.requestInterceptorCatch
6934
- );
6935
- this.instance.interceptors.response.use(
6936
- this.interceptors?.responseInterceptor,
6937
- this.interceptors?.responseInterceptorCatch
6938
- );
6939
- this.instance.interceptors.request.use(
6940
- (config2) => {
6941
- return config2;
6942
- },
6943
- (err) => {
6944
- return Promise.reject(err);
7083
+ return ai.post(modifiedConfig);
7084
+ },
7085
+ put: ai.put.bind(ai),
7086
+ delete: ai.delete.bind(ai),
7087
+ request: ai.request.bind(ai),
7088
+ cancelRequest: ai.cancelRequest?.bind(ai),
7089
+ cancelAllRequests: ai.cancelAllRequests?.bind(ai)
7090
+ };
7091
+ return {
7092
+ // expose projectId so consumers can read it from the client instance
7093
+ projectId: opts?.projectId ?? null,
7094
+ request: bizWrapped,
7095
+ aiRequest: ai,
7096
+ workflowRequest: workflowRequestWrapped,
7097
+ // artifact helpers using artifacts-client
7098
+ artifacts: createArtifactsClient(biz),
7099
+ me: async () => {
7100
+ try {
7101
+ const t = token ?? (opts?.auth?.getToken ? await opts.auth.getToken() : null) ?? getToken();
7102
+ if (!t) return null;
7103
+ return parseUserFromToken(t);
7104
+ } catch (_e2) {
7105
+ return null;
6945
7106
  }
6946
- );
6947
- this.instance.interceptors.response.use(
6948
- (res) => {
6949
- return res.data;
7107
+ },
7108
+ // auth helpers
7109
+ auth: {
7110
+ setToken: (t) => {
7111
+ token = t;
7112
+ applyToken(t);
6950
7113
  },
6951
- (err) => {
6952
- if (axios.isCancel(err)) {
6953
- return Promise.reject({
6954
- isCanceled: true,
6955
- message: "request canceled",
6956
- originalError: err
6957
- });
6958
- }
6959
- if (err.response?.data?.error) {
6960
- return Promise.reject(err.response.data.error);
7114
+ getToken: () => token,
7115
+ isAuthenticated: () => Boolean(token),
7116
+ // minimal login/logout stubs - consumers can override behavior
7117
+ login: (redirect) => {
7118
+ if (typeof window === "undefined") return;
7119
+ const loc = redirect || window.location.href;
7120
+ try {
7121
+ const root = env2.baseUrl;
7122
+ const authUrl = new URL("/auth", String(root));
7123
+ authUrl.searchParams.set("redirect_uri", String(loc));
7124
+ if (opts?.projectId) authUrl.searchParams.set("project_id", String(opts.projectId));
7125
+ window.location.href = authUrl.toString();
7126
+ } catch {
7127
+ const encoded = encodeURIComponent(String(loc));
7128
+ const pid = opts?.projectId ? `&project_id=${encodeURIComponent(String(opts.projectId))}` : "";
7129
+ const root = env2.baseUrl;
7130
+ window.location.href = `${root}/auth?redirect_uri=${encoded}${pid}`;
6961
7131
  }
6962
- return Promise.reject(err);
6963
- }
6964
- );
6965
- }
6966
- cancelRequest(url) {
6967
- this.abortControllers.forEach((controller, key) => {
6968
- if (key.includes(url)) {
6969
- controller.abort();
6970
- this.abortControllers.delete(key);
7132
+ },
7133
+ logout: () => {
7134
+ token = null;
7135
+ applyToken(null);
6971
7136
  }
6972
- });
7137
+ },
7138
+ sanitizeUrl: (o) => {
7139
+ if (typeof window === "undefined") return;
7140
+ removeSensitiveParamsFromUrl({
7141
+ clearAll: o?.clearAll,
7142
+ sensitiveParams: o?.sensitiveParams
7143
+ });
7144
+ }
7145
+ };
7146
+ }
7147
+
7148
+ // src/hooks/use-mobile.ts
7149
+ import * as React8 from "react";
7150
+ var MOBILE_BREAKPOINT = 768;
7151
+ function useIsMobile() {
7152
+ const [isMobile, setIsMobile] = React8.useState(void 0);
7153
+ React8.useEffect(() => {
7154
+ const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
7155
+ const onChange = () => {
7156
+ setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
7157
+ };
7158
+ mql.addEventListener("change", onChange);
7159
+ setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
7160
+ return () => mql.removeEventListener("change", onChange);
7161
+ }, []);
7162
+ return !!isMobile;
7163
+ }
7164
+
7165
+ // src/hooks/use-debounce.ts
7166
+ import { useState as useState10, useEffect as useEffect9 } from "react";
7167
+ function useDebounce(value, delay) {
7168
+ const [debouncedValue, setDebouncedValue] = useState10(value);
7169
+ useEffect9(() => {
7170
+ const handler = setTimeout(() => {
7171
+ setDebouncedValue(value);
7172
+ }, delay);
7173
+ return () => {
7174
+ clearTimeout(handler);
7175
+ };
7176
+ }, [value, delay]);
7177
+ return debouncedValue;
7178
+ }
7179
+
7180
+ // src/utils/unified-error-handler/simple.ts
7181
+ var SimpleErrorHandler = class {
7182
+ constructor() {
7183
+ this.initialized = false;
6973
7184
  }
6974
- cancelAllRequests() {
6975
- this.abortControllers.forEach((controller) => {
6976
- controller.abort();
7185
+ // 使用明确赋值断言,因为在 init() 方法中会初始化
7186
+ /**
7187
+ * 初始化错误处理器
7188
+ */
7189
+ init() {
7190
+ if (this.initialized) return;
7191
+ this.sendMessage = createSimpleSendFunction({
7192
+ addTimestamp: false,
7193
+ // 简化版自己处理时间戳
7194
+ enableDebugLog: false
6977
7195
  });
6978
- this.abortControllers.clear();
7196
+ this.setupErrorListeners();
7197
+ this.setupCompatibility();
7198
+ this.initialized = true;
7199
+ console.log("[\u7B80\u5316\u9519\u8BEF\u5904\u7406] \u521D\u59CB\u5316\u5B8C\u6210");
6979
7200
  }
6980
- request(config) {
6981
- const controller = new AbortController();
6982
- const url = config.url || "";
6983
- const method = config.method || "GET";
6984
- const key = `${method}:${url}`;
6985
- this.abortControllers.set(key, controller);
6986
- config.signal = controller.signal;
6987
- return new Promise((resolve, reject) => {
6988
- if (config.interceptors?.requestInterceptor) {
6989
- config = config.interceptors.requestInterceptor(config);
6990
- }
6991
- this.instance.request(config).then((res) => {
6992
- this.abortControllers.delete(key);
6993
- if (config.interceptors?.responseInterceptor) {
6994
- res = config.interceptors.responseInterceptor(res);
6995
- }
6996
- resolve(res);
6997
- }).catch((err) => {
6998
- this.abortControllers.delete(key);
6999
- reject(err);
7201
+ /**
7202
+ * 设置错误监听器
7203
+ */
7204
+ setupErrorListeners() {
7205
+ window.addEventListener("error", (event) => {
7206
+ this.sendError(event.error || new Error(event.message), {
7207
+ filename: event.filename,
7208
+ lineno: event.lineno,
7209
+ colno: event.colno,
7210
+ type: "runtime"
7000
7211
  });
7001
7212
  });
7213
+ window.addEventListener("unhandledrejection", (event) => {
7214
+ const error = event.reason instanceof Error ? event.reason : new Error(String(event.reason));
7215
+ this.sendError(error, { type: "promise" });
7216
+ });
7002
7217
  }
7003
- get(config) {
7004
- return this.request({ ...config, method: "GET" });
7005
- }
7006
- post(config) {
7007
- return this.request({ ...config, method: "POST" });
7008
- }
7009
- delete(config) {
7010
- return this.request({ ...config, method: "DELETE" });
7218
+ /**
7219
+ * 设置兼容性函数
7220
+ */
7221
+ setupCompatibility() {
7222
+ window.__SEND_ERROR_TO_PARENT__ = (error, details) => {
7223
+ const errorObj = error instanceof Error ? error : new Error(String(error));
7224
+ this.sendError(errorObj, details);
7225
+ };
7011
7226
  }
7012
- put(config) {
7013
- return this.request({ ...config, method: "PUT" });
7227
+ /**
7228
+ * 发送错误到父窗口
7229
+ */
7230
+ sendError(error, details = {}) {
7231
+ const payload = {
7232
+ message: error.message,
7233
+ stack: error.stack,
7234
+ filename: details.filename || details.file,
7235
+ lineno: details.lineno || details.line,
7236
+ colno: details.colno || details.column,
7237
+ timestamp: Date.now(),
7238
+ type: details.type || "unknown",
7239
+ severity: "medium",
7240
+ // 简化版使用默认严重性级别
7241
+ details
7242
+ };
7243
+ try {
7244
+ this.sendMessage({
7245
+ type: "ERROR_EVENT",
7246
+ payload,
7247
+ timestamp: Date.now()
7248
+ });
7249
+ } catch (e) {
7250
+ const originalConsole = window.__originalConsole;
7251
+ if (originalConsole?.error) {
7252
+ originalConsole.error("[\u7B80\u5316\u9519\u8BEF\u5904\u7406] \u53D1\u9001\u5931\u8D25:", e);
7253
+ }
7254
+ }
7014
7255
  }
7015
- patch(config) {
7016
- return this.request({ ...config, method: "PATCH" });
7256
+ /**
7257
+ * 手动捕获错误
7258
+ */
7259
+ captureError(error, details) {
7260
+ this.sendError(error, details);
7017
7261
  }
7018
7262
  };
7019
- var request_default = Request;
7020
7263
 
7021
- // src/services/ai-workflow-axios.ts
7022
- function createAIWorkflowClientAxios(options = {}) {
7023
- const basePath = options.basePath ?? "/api";
7024
- const baseUrl = (options.baseUrl || "https://evoagentx-server.fly.dev").replace(/\/+$/, "");
7025
- const baseAPI = `${baseUrl}${basePath.startsWith("/") ? "" : "/"}${basePath}`.replace(/\/+$/, "");
7026
- const client = options.requestInstance || new request_default({
7027
- baseURL: baseAPI,
7028
- timeout: options.timeout ?? 6e4,
7029
- interceptors: {
7030
- requestInterceptor: (config) => {
7031
- config.headers = config.headers || {};
7032
- if (options.apiKey && !config.headers["Authorization"]) {
7033
- config.headers["Authorization"] = `Bearer ${options.apiKey}`;
7034
- }
7035
- if (options.headers) {
7036
- config.headers = { ...config.headers || {}, ...options.headers };
7037
- }
7038
- return config;
7039
- },
7040
- requestInterceptorCatch: (err) => Promise.reject(err),
7041
- responseInterceptor: (res) => res,
7042
- responseInterceptorCatch: (err) => Promise.reject(err)
7043
- }
7044
- });
7045
- return {
7046
- async executeWorkflow(workflowId, inputs, opts) {
7047
- const url = `${baseUrl}/workflow/${workflowId}/execute`;
7048
- const data = await client.post({ url, data: { inputs, options: opts } });
7049
- return data;
7050
- }
7051
- };
7052
- }
7264
+ // src/index.ts
7265
+ init_config();
7053
7266
 
7054
- // src/services/artifact-types.ts
7055
- function canAccessArtifact(a, ctx = {}) {
7056
- if (!a) return false;
7057
- if (a.visibility === "public") return true;
7058
- if (a.visibility === "project") {
7059
- if (ctx.projectId && a.projectId && ctx.projectId === a.projectId) return true;
7060
- if (ctx.tokenScopes && ctx.tokenScopes.includes("project:read")) return true;
7061
- return false;
7062
- }
7063
- if (a.visibility === "private") {
7064
- if (ctx.userId && a.ownerId && ctx.userId === a.ownerId) return true;
7065
- if (ctx.tokenScopes && (ctx.tokenScopes.includes("artifact:read:all") || ctx.tokenScopes.includes("admin"))) return true;
7066
- return false;
7267
+ // src/utils/iframe-navigation.ts
7268
+ function getNavState() {
7269
+ if (typeof window === "undefined") {
7270
+ return {
7271
+ navigationHistory: [],
7272
+ currentHistoryIndex: -1,
7273
+ initialized: false
7274
+ };
7067
7275
  }
7068
- if (a.visibility === "shared") {
7069
- if (ctx.userId && a.sharedWith && a.sharedWith.includes(ctx.userId)) return true;
7070
- if (ctx.tokenScopes && (ctx.tokenScopes.includes("artifact:read:all") || ctx.tokenScopes.includes("admin"))) return true;
7071
- return false;
7276
+ if (!window.customNavigationState) {
7277
+ window.customNavigationState = {
7278
+ navigationHistory: [],
7279
+ currentHistoryIndex: -1,
7280
+ initialized: false
7281
+ };
7072
7282
  }
7073
- return false;
7283
+ return window.customNavigationState;
7074
7284
  }
7075
-
7076
- // src/services/artifacts-client.ts
7077
- function createArtifactsClient(req) {
7078
- return {
7079
- async create(input) {
7080
- return await req.post({ url: "/artifacts", data: input });
7081
- },
7082
- async list(query) {
7083
- return await req.get({ url: "/artifacts", params: query });
7084
- },
7085
- async get(id) {
7086
- return await req.get({ url: `/artifacts/${encodeURIComponent(id)}` });
7087
- },
7088
- async setVisibility(id, visibility) {
7089
- await req.patch({ url: `/artifacts/${encodeURIComponent(id)}/visibility`, data: { visibility } });
7090
- },
7091
- async delete(id) {
7092
- await req.delete({ url: `/artifacts/${encodeURIComponent(id)}` });
7093
- },
7094
- // convenience local check (server is authoritative)
7095
- canAccessLocal(a, ctx) {
7096
- if (!a) return false;
7097
- if (a.visibility === "public") return true;
7098
- if (a.visibility === "project") return Boolean(ctx.projectId && a.projectId && ctx.projectId === a.projectId);
7099
- if (a.visibility === "private") return Boolean(ctx.userId && a.ownerId && ctx.userId === a.ownerId);
7100
- if (a.visibility === "shared") return Boolean(ctx.userId && a.sharedWith && a.sharedWith.includes(ctx.userId));
7101
- return false;
7102
- }
7103
- };
7285
+ function getElementSelectorState() {
7286
+ if (typeof window === "undefined") {
7287
+ return { active: false, callback: null };
7288
+ }
7289
+ if (!window.elementSelectorState) {
7290
+ window.elementSelectorState = {
7291
+ active: false,
7292
+ callback: null
7293
+ };
7294
+ }
7295
+ return window.elementSelectorState;
7104
7296
  }
7105
-
7106
- // src/services/index.ts
7107
- init_auth();
7108
- init_config();
7109
- init_config();
7110
- init_auth();
7111
-
7112
- // src/utils/urlSanitizer.ts
7113
- var DEFAULT_SENSITIVE = ["token", "access_token", "auth", "auth_token"];
7114
- function removeSensitiveParamsFromUrl(opts) {
7115
- if (typeof window === "undefined") return;
7116
- try {
7117
- const { clearAll, sensitiveParams, includeHash = true, onChanged } = opts || {};
7118
- const sens = (sensitiveParams && sensitiveParams.length > 0 ? sensitiveParams : DEFAULT_SENSITIVE).map((s) => s.toLowerCase());
7119
- const before = window.location.href;
7120
- const url = new URL(before);
7121
- if (clearAll) {
7122
- url.search = "";
7123
- } else if (url.search) {
7124
- let changed = false;
7125
- for (const [k] of url.searchParams) {
7126
- if (sens.includes(k.toLowerCase())) {
7127
- url.searchParams.delete(k);
7128
- changed = true;
7129
- }
7130
- }
7131
- if (changed) {
7132
- const qs = url.searchParams.toString();
7133
- url.search = qs ? `?${qs}` : "";
7134
- }
7297
+ function sendNavigationState(targetWindow, targetOrigin) {
7298
+ const navState = getNavState();
7299
+ const canGoBack = navState.currentHistoryIndex > 0;
7300
+ const canGoForward = navState.currentHistoryIndex < navState.navigationHistory.length - 1;
7301
+ const state = {
7302
+ type: "NAVIGATION_STATE",
7303
+ payload: {
7304
+ canGoBack,
7305
+ canGoForward,
7306
+ historyLength: navState.navigationHistory.length,
7307
+ currentIndex: navState.currentHistoryIndex,
7308
+ maxIndex: navState.navigationHistory.length - 1
7135
7309
  }
7136
- if (includeHash && url.hash) {
7137
- const raw = url.hash.slice(1);
7138
- if (raw.includes("=")) {
7139
- const hp = new URLSearchParams(raw);
7140
- let changed = false;
7141
- for (const [k] of hp) {
7142
- if (clearAll || sens.includes(k.toLowerCase())) {
7143
- hp.delete(k);
7144
- changed = true;
7145
- }
7146
- }
7147
- if (changed) {
7148
- const hs = hp.toString();
7149
- url.hash = hs ? `#${hs}` : "";
7150
- }
7151
- } else {
7152
- if (!clearAll && sens.some((p) => raw.toLowerCase().startsWith(p))) {
7153
- url.hash = "";
7154
- } else if (clearAll) {
7155
- url.hash = "";
7156
- }
7310
+ };
7311
+ if (targetWindow && targetOrigin) {
7312
+ try {
7313
+ targetWindow.postMessage(state, targetOrigin);
7314
+ } catch (e) {
7315
+ if (typeof console !== "undefined" && console.warn) {
7316
+ console.warn("Failed to send navigation state:", e.message);
7157
7317
  }
7158
7318
  }
7159
- const next = url.pathname + url.search + url.hash;
7160
- if (next !== window.location.pathname + window.location.search + window.location.hash) {
7161
- window.history.replaceState(window.history.state, document.title, next);
7162
- onChanged && onChanged(next);
7163
- }
7164
- } catch (e) {
7165
- console.warn("[howone][urlSanitizer] failed", e);
7166
7319
  }
7167
7320
  }
7168
-
7169
- // src/services/index.ts
7170
- function getGlobalAvailableToken() {
7171
- try {
7172
- return getToken() || null;
7173
- } catch {
7174
- return null;
7321
+ function addToNavigationHistory(url, title) {
7322
+ const navState = getNavState();
7323
+ if (navState.currentHistoryIndex < navState.navigationHistory.length - 1) {
7324
+ navState.navigationHistory = navState.navigationHistory.slice(
7325
+ 0,
7326
+ navState.currentHistoryIndex + 1
7327
+ );
7175
7328
  }
7176
- }
7177
- function wrapRequestWithProjectPrefix(biz, projectId) {
7178
- if (!projectId) return biz;
7179
- const prefix = `/entities/apps/${String(projectId)}`;
7180
- function shouldPrefix(url) {
7181
- if (!url) return false;
7182
- const u = String(url);
7183
- if (u.startsWith(prefix)) return false;
7184
- if (/^https?:\/\//.test(u) || u.startsWith("//")) return false;
7185
- if (u.startsWith("/data")) return true;
7186
- return false;
7329
+ const currentPage = navState.navigationHistory[navState.currentHistoryIndex];
7330
+ if (currentPage && currentPage.url === url) {
7331
+ return;
7187
7332
  }
7188
- const wrapped = {
7189
- instance: biz.instance,
7190
- request: (config) => {
7191
- try {
7192
- if (config && typeof config.url === "string" && shouldPrefix(config.url)) {
7193
- config = { ...config, url: `${prefix}${config.url}` };
7194
- }
7195
- } catch (_e) {
7196
- }
7197
- return biz.request(config);
7198
- },
7199
- get: (config) => wrapped.request({ ...config, method: "GET" }),
7200
- post: (config) => wrapped.request({ ...config, method: "POST" }),
7201
- put: (config) => wrapped.request({ ...config, method: "PUT" }),
7202
- patch: (config) => wrapped.request({ ...config, method: "PATCH" }),
7203
- delete: (config) => wrapped.request({ ...config, method: "DELETE" }),
7204
- cancelRequest: (url) => biz.cancelRequest(url),
7205
- cancelAllRequests: () => biz.cancelAllRequests()
7333
+ const pageInfo = {
7334
+ url,
7335
+ title: title || (typeof document !== "undefined" ? document.title : "") || url,
7336
+ timestamp: Date.now()
7206
7337
  };
7207
- return wrapped;
7208
- }
7209
- function createClient(opts) {
7210
- const envValue = opts.env || getGlobalEnvironment() || "prod";
7211
- const env2 = setEnvironment(envValue);
7212
- function makeRequestFromBase(base) {
7213
- return new request_default({
7214
- baseURL: base,
7215
- timeout: 6e4,
7216
- interceptors: {
7217
- requestInterceptor: (config) => {
7218
- config.headers = config.headers || {};
7219
- if (!config.headers["Authorization"]) {
7220
- const availableToken = getAvailableToken();
7221
- if (availableToken) {
7222
- config.headers["Authorization"] = `Bearer ${availableToken}`;
7223
- }
7224
- }
7225
- return config;
7226
- },
7227
- requestInterceptorCatch: (err) => Promise.reject(err),
7228
- responseInterceptor: (res) => {
7229
- const data = res.data;
7230
- if (data && data.status && data.status === 4003) {
7231
- showLimitUpgradeToast(
7232
- "Your credits are exhausted. Please upgrade your plan to continue generating projects.",
7233
- () => window.open(`${getEnvs().AUTH_ROOT_VALUE}/price`, "_blank")
7234
- );
7235
- return res;
7236
- }
7237
- return res;
7238
- },
7239
- responseInterceptorCatch: (err) => Promise.reject(err)
7240
- }
7241
- });
7338
+ navState.navigationHistory.push(pageInfo);
7339
+ navState.currentHistoryIndex = navState.navigationHistory.length - 1;
7340
+ if (typeof window !== "undefined" && window.parent && window.parent !== window) {
7341
+ sendNavigationState(window.parent, "*");
7242
7342
  }
7243
- const biz = makeRequestFromBase(env2.baseUrl);
7244
- const ai = makeRequestFromBase(env2.aiBaseUrl);
7245
- const bizWrapped = wrapRequestWithProjectPrefix(biz, opts?.projectId);
7246
- let token = null;
7247
- function getAvailableToken() {
7248
- return token || getGlobalAvailableToken();
7343
+ }
7344
+ function customGoBack() {
7345
+ const navState = getNavState();
7346
+ if (navState.currentHistoryIndex > 0) {
7347
+ navState.currentHistoryIndex--;
7348
+ if (typeof window !== "undefined" && window.parent && window.parent !== window) {
7349
+ sendNavigationState(window.parent, "*");
7350
+ }
7351
+ return true;
7249
7352
  }
7250
- try {
7251
- if (opts?.projectId) {
7252
- setDefaultProjectId(String(opts.projectId));
7353
+ return false;
7354
+ }
7355
+ function customGoForward() {
7356
+ const navState = getNavState();
7357
+ if (navState.currentHistoryIndex < navState.navigationHistory.length - 1) {
7358
+ navState.currentHistoryIndex++;
7359
+ if (typeof window !== "undefined" && window.parent && window.parent !== window) {
7360
+ sendNavigationState(window.parent, "*");
7253
7361
  }
7254
- } catch {
7362
+ return true;
7255
7363
  }
7256
- function applyToken(t) {
7364
+ return false;
7365
+ }
7366
+ function triggerElementSelection() {
7367
+ if (typeof window === "undefined") return;
7368
+ const event = new CustomEvent("howone:start-element-selection");
7369
+ window.dispatchEvent(event);
7370
+ getElementSelectorState().active = true;
7371
+ }
7372
+ function cancelElementSelection() {
7373
+ if (typeof window === "undefined") return;
7374
+ const event = new CustomEvent("howone:cancel-element-selection");
7375
+ window.dispatchEvent(event);
7376
+ getElementSelectorState().active = false;
7377
+ }
7378
+ function handlePageChange() {
7379
+ if (typeof window === "undefined") return;
7380
+ const currentUrl = window.location.href;
7381
+ const currentTitle = document.title;
7382
+ addToNavigationHistory(currentUrl, currentTitle);
7383
+ }
7384
+ function initIframeNavigation() {
7385
+ if (typeof window === "undefined") return;
7386
+ const navState = getNavState();
7387
+ window.addEventListener("keydown", function(e) {
7388
+ if (e.key === "Escape" && getElementSelectorState().active) {
7389
+ cancelElementSelection();
7390
+ }
7391
+ });
7392
+ window.addEventListener("message", (event) => {
7257
7393
  try {
7258
- try {
7259
- if (biz && biz.instance) {
7260
- if (t) biz.instance.defaults.headers.common["Authorization"] = `Bearer ${t}`;
7261
- else delete biz.instance.defaults.headers.common["Authorization"];
7262
- }
7263
- if (ai && ai.instance) {
7264
- if (t) ai.instance.defaults.headers.common["Authorization"] = `Bearer ${t}`;
7265
- else delete ai.instance.defaults.headers.common["Authorization"];
7266
- }
7267
- } catch (_e) {
7394
+ const { type, payload } = event.data;
7395
+ switch (type) {
7396
+ case "NAVIGATE_BACK":
7397
+ case "GO_BACK":
7398
+ customGoBack();
7399
+ break;
7400
+ case "NAVIGATE_FORWARD":
7401
+ case "GO_FORWARD":
7402
+ customGoForward();
7403
+ break;
7404
+ case "REQUEST_NAVIGATION_STATE":
7405
+ case "CHECK_NAVIGATION_STATE":
7406
+ sendNavigationState(event.source, event.origin);
7407
+ break;
7408
+ case "START_ELEMENT_SELECTION":
7409
+ triggerElementSelection();
7410
+ break;
7411
+ case "ELEMENT_SELECTED":
7412
+ if (event.source && event.source !== window) {
7413
+ window.parent.postMessage(
7414
+ {
7415
+ type: "ELEMENT_SELECTED",
7416
+ payload
7417
+ },
7418
+ "*"
7419
+ );
7420
+ }
7421
+ break;
7422
+ case "CANCEL_ELEMENT_SELECTION":
7423
+ cancelElementSelection();
7424
+ break;
7425
+ }
7426
+ } catch (e) {
7427
+ }
7428
+ });
7429
+ window.addEventListener("popstate", () => {
7430
+ setTimeout(() => {
7431
+ if (window.parent && window.parent !== window) {
7432
+ sendNavigationState(window.parent, "*");
7433
+ }
7434
+ }, 50);
7435
+ });
7436
+ window.addEventListener("hashchange", () => {
7437
+ handlePageChange();
7438
+ });
7439
+ window.addEventListener("load", () => {
7440
+ if (!navState.initialized) {
7441
+ addToNavigationHistory(window.location.href, document.title);
7442
+ navState.initialized = true;
7443
+ }
7444
+ setTimeout(() => {
7445
+ if (window.parent && window.parent !== window) {
7446
+ sendNavigationState(window.parent, "*");
7447
+ }
7448
+ }, 500);
7449
+ });
7450
+ if (document.readyState === "loading") {
7451
+ document.addEventListener("DOMContentLoaded", () => {
7452
+ if (!navState.initialized) {
7453
+ addToNavigationHistory(window.location.href, document.title);
7454
+ navState.initialized = true;
7268
7455
  }
7269
- } catch (_e) {
7270
- }
7456
+ });
7457
+ } else if (!navState.initialized) {
7458
+ addToNavigationHistory(window.location.href, document.title);
7459
+ navState.initialized = true;
7271
7460
  }
7272
- const workflowRequestWrapped = {
7273
- get: ai.get.bind(ai),
7274
- post: (config) => {
7275
- const modifiedConfig = { ...config };
7276
- if (opts?.projectId && modifiedConfig.url) {
7277
- const workflowPattern = /^\/?(?:workflow\/)?([^\/]+)\/execute/;
7278
- const match = modifiedConfig.url.match(workflowPattern);
7279
- if (match) {
7280
- const workflowId = match[1];
7281
- modifiedConfig.url = `/workflow/${opts.projectId}/${workflowId}/execute`;
7282
- }
7283
- }
7284
- return ai.post(modifiedConfig);
7285
- },
7286
- put: ai.put.bind(ai),
7287
- delete: ai.delete.bind(ai),
7288
- request: ai.request.bind(ai),
7289
- cancelRequest: ai.cancelRequest?.bind(ai),
7290
- cancelAllRequests: ai.cancelAllRequests?.bind(ai)
7461
+ window.iframeElementSelector = {
7462
+ startSelection: function() {
7463
+ triggerElementSelection();
7464
+ }
7291
7465
  };
7292
- return {
7293
- // expose projectId so consumers can read it from the client instance
7294
- projectId: opts?.projectId ?? null,
7295
- request: bizWrapped,
7296
- aiRequest: ai,
7297
- workflowRequest: workflowRequestWrapped,
7298
- // artifact helpers using artifacts-client
7299
- artifacts: createArtifactsClient(biz),
7300
- me: async () => {
7301
- try {
7302
- const t = token ?? (opts?.auth?.getToken ? await opts.auth.getToken() : null) ?? getToken();
7303
- if (!t) return null;
7304
- return parseUserFromToken(t);
7305
- } catch (_e2) {
7306
- return null;
7307
- }
7466
+ window.iframeNavigation = {
7467
+ addPage: function(url, title) {
7468
+ addToNavigationHistory(
7469
+ url || window.location.href,
7470
+ title || document.title
7471
+ );
7308
7472
  },
7309
- // auth helpers
7310
- auth: {
7311
- setToken: (t) => {
7312
- token = t;
7313
- applyToken(t);
7314
- },
7315
- getToken: () => token,
7316
- isAuthenticated: () => Boolean(token),
7317
- // minimal login/logout stubs - consumers can override behavior
7318
- login: (redirect) => {
7319
- if (typeof window === "undefined") return;
7320
- const loc = redirect || window.location.href;
7321
- try {
7322
- const root = env2.baseUrl;
7323
- const authUrl = new URL("/auth", String(root));
7324
- authUrl.searchParams.set("redirect_uri", String(loc));
7325
- if (opts?.projectId) authUrl.searchParams.set("project_id", String(opts.projectId));
7326
- window.location.href = authUrl.toString();
7327
- } catch {
7328
- const encoded = encodeURIComponent(String(loc));
7329
- const pid = opts?.projectId ? `&project_id=${encodeURIComponent(String(opts.projectId))}` : "";
7330
- const root = env2.baseUrl;
7331
- window.location.href = `${root}/auth?redirect_uri=${encoded}${pid}`;
7332
- }
7333
- },
7334
- logout: () => {
7335
- token = null;
7336
- applyToken(null);
7337
- }
7473
+ getState: function() {
7474
+ return {
7475
+ canGoBack: navState.currentHistoryIndex > 0,
7476
+ canGoForward: navState.currentHistoryIndex < navState.navigationHistory.length - 1,
7477
+ historyLength: navState.navigationHistory.length,
7478
+ currentIndex: navState.currentHistoryIndex,
7479
+ currentPage: navState.navigationHistory[navState.currentHistoryIndex]
7480
+ };
7338
7481
  },
7339
- sanitizeUrl: (o) => {
7340
- if (typeof window === "undefined") return;
7341
- removeSensitiveParamsFromUrl({
7342
- clearAll: o?.clearAll,
7343
- sensitiveParams: o?.sensitiveParams
7344
- });
7482
+ updateState: function() {
7483
+ if (window.parent && window.parent !== window) {
7484
+ sendNavigationState(window.parent, "*");
7485
+ }
7345
7486
  }
7346
7487
  };
7347
7488
  }
7348
-
7349
- // src/hooks/use-mobile.ts
7350
- import * as React8 from "react";
7351
- var MOBILE_BREAKPOINT = 768;
7352
- function useIsMobile() {
7353
- const [isMobile, setIsMobile] = React8.useState(void 0);
7354
- React8.useEffect(() => {
7355
- const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
7356
- const onChange = () => {
7357
- setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
7358
- };
7359
- mql.addEventListener("change", onChange);
7360
- setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
7361
- return () => mql.removeEventListener("change", onChange);
7362
- }, []);
7363
- return !!isMobile;
7364
- }
7365
-
7366
- // src/hooks/use-debounce.ts
7367
- import { useState as useState10, useEffect as useEffect9 } from "react";
7368
- function useDebounce(value, delay) {
7369
- const [debouncedValue, setDebouncedValue] = useState10(value);
7370
- useEffect9(() => {
7371
- const handler = setTimeout(() => {
7372
- setDebouncedValue(value);
7373
- }, delay);
7374
- return () => {
7375
- clearTimeout(handler);
7376
- };
7377
- }, [value, delay]);
7378
- return debouncedValue;
7379
- }
7380
-
7381
- // src/utils/unified-error-handler/simple.ts
7382
- var SimpleErrorHandler = class {
7383
- constructor() {
7384
- this.initialized = false;
7385
- }
7386
- // 使用明确赋值断言,因为在 init() 方法中会初始化
7489
+ var iframeNavigation = {
7387
7490
  /**
7388
- * 初始化错误处理器
7491
+ * Initialize the navigation system
7389
7492
  */
7390
- init() {
7391
- if (this.initialized) return;
7392
- this.sendMessage = createSimpleSendFunction({
7393
- addTimestamp: false,
7394
- // 简化版自己处理时间戳
7395
- enableDebugLog: false
7396
- });
7397
- this.setupErrorListeners();
7398
- this.setupCompatibility();
7399
- this.initialized = true;
7400
- console.log("[\u7B80\u5316\u9519\u8BEF\u5904\u7406] \u521D\u59CB\u5316\u5B8C\u6210");
7401
- }
7493
+ init: initIframeNavigation,
7402
7494
  /**
7403
- * 设置错误监听器
7495
+ * Add a page to navigation history
7404
7496
  */
7405
- setupErrorListeners() {
7406
- window.addEventListener("error", (event) => {
7407
- this.sendError(event.error || new Error(event.message), {
7408
- filename: event.filename,
7409
- lineno: event.lineno,
7410
- colno: event.colno,
7411
- type: "runtime"
7412
- });
7413
- });
7414
- window.addEventListener("unhandledrejection", (event) => {
7415
- const error = event.reason instanceof Error ? event.reason : new Error(String(event.reason));
7416
- this.sendError(error, { type: "promise" });
7417
- });
7418
- }
7497
+ addPage: (url, title) => {
7498
+ if (typeof window === "undefined") return;
7499
+ addToNavigationHistory(
7500
+ url || window.location.href,
7501
+ title || (typeof document !== "undefined" ? document.title : "")
7502
+ );
7503
+ },
7419
7504
  /**
7420
- * 设置兼容性函数
7505
+ * Get current navigation state
7421
7506
  */
7422
- setupCompatibility() {
7423
- window.__SEND_ERROR_TO_PARENT__ = (error, details) => {
7424
- const errorObj = error instanceof Error ? error : new Error(String(error));
7425
- this.sendError(errorObj, details);
7507
+ getState: () => {
7508
+ const navState = getNavState();
7509
+ return {
7510
+ canGoBack: navState.currentHistoryIndex > 0,
7511
+ canGoForward: navState.currentHistoryIndex < navState.navigationHistory.length - 1,
7512
+ historyLength: navState.navigationHistory.length,
7513
+ currentIndex: navState.currentHistoryIndex,
7514
+ currentPage: navState.navigationHistory[navState.currentHistoryIndex]
7426
7515
  };
7427
- }
7516
+ },
7428
7517
  /**
7429
- * 发送错误到父窗口
7518
+ * Update navigation state (send to parent)
7430
7519
  */
7431
- sendError(error, details = {}) {
7432
- const payload = {
7433
- message: error.message,
7434
- stack: error.stack,
7435
- filename: details.filename || details.file,
7436
- lineno: details.lineno || details.line,
7437
- colno: details.colno || details.column,
7438
- timestamp: Date.now(),
7439
- type: details.type || "unknown",
7440
- severity: "medium",
7441
- // 简化版使用默认严重性级别
7442
- details
7443
- };
7444
- try {
7445
- this.sendMessage({
7446
- type: "ERROR_EVENT",
7447
- payload,
7448
- timestamp: Date.now()
7449
- });
7450
- } catch (e) {
7451
- const originalConsole = window.__originalConsole;
7452
- if (originalConsole?.error) {
7453
- originalConsole.error("[\u7B80\u5316\u9519\u8BEF\u5904\u7406] \u53D1\u9001\u5931\u8D25:", e);
7454
- }
7520
+ updateState: () => {
7521
+ if (typeof window !== "undefined" && window.parent && window.parent !== window) {
7522
+ sendNavigationState(window.parent, "*");
7455
7523
  }
7456
- }
7524
+ },
7457
7525
  /**
7458
- * 手动捕获错误
7526
+ * Go back in history
7459
7527
  */
7460
- captureError(error, details) {
7461
- this.sendError(error, details);
7462
- }
7528
+ goBack: customGoBack,
7529
+ /**
7530
+ * Go forward in history
7531
+ */
7532
+ goForward: customGoForward
7533
+ };
7534
+ var elementSelector = {
7535
+ /**
7536
+ * Start element selection mode
7537
+ */
7538
+ startSelection: triggerElementSelection,
7539
+ /**
7540
+ * Cancel element selection mode
7541
+ */
7542
+ cancel: cancelElementSelection,
7543
+ /**
7544
+ * Check if selector is active
7545
+ */
7546
+ isActive: () => getElementSelectorState().active
7463
7547
  };
7464
-
7465
- // src/index.ts
7466
- init_config();
7467
7548
  export {
7468
7549
  AUTH_TOKEN_KEY,
7469
7550
  ClayxButton,