@howone/sdk 0.6.0 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -164,7 +164,20 @@ function decodeJwtPayload(token) {
164
164
  if (pad === 2) base64 += "==";
165
165
  else if (pad === 3) base64 += "=";
166
166
  else if (pad !== 0) return null;
167
- const json = atob(base64);
167
+ const binary = atob(base64);
168
+ let json = binary;
169
+ try {
170
+ if (typeof TextDecoder !== "undefined") {
171
+ const bytes = Uint8Array.from(binary, (ch) => ch.charCodeAt(0));
172
+ json = new TextDecoder("utf-8", { fatal: false }).decode(bytes);
173
+ } else {
174
+ json = decodeURIComponent(
175
+ binary.split("").map((ch) => `%${ch.charCodeAt(0).toString(16).padStart(2, "0")}`).join("")
176
+ );
177
+ }
178
+ } catch {
179
+ json = binary;
180
+ }
168
181
  return JSON.parse(json);
169
182
  } catch {
170
183
  return null;
@@ -284,13 +297,14 @@ var index_exports = {};
284
297
  __export(index_exports, {
285
298
  AUTH_TOKEN_KEY: () => AUTH_TOKEN_KEY,
286
299
  ClayxButton: () => ClayxButton,
300
+ ClayxToast: () => ClayxToast,
301
+ DEFAULT_LIMIT_EXCEEDED_MESSAGE: () => DEFAULT_LIMIT_EXCEEDED_MESSAGE,
287
302
  DefaultErrorFallback: () => DefaultErrorFallback,
288
303
  ElementSelector: () => ElementSelector,
289
304
  ElementSelectorProvider: () => ElementSelectorProvider,
290
305
  ErrorBoundary: () => ErrorBoundary,
291
306
  FloatingButton: () => FloatingButton,
292
307
  GlobalToastContainer: () => GlobalToastContainer,
293
- GoeyToast: () => GoeyToast,
294
308
  HowOneProvider: () => HowOneProvider,
295
309
  Loading: () => Loading,
296
310
  LoadingSpinner: () => LoadingSpinner,
@@ -314,11 +328,13 @@ __export(index_exports, {
314
328
  getEnvs: () => getEnvs,
315
329
  getGlobalEnvironment: () => getGlobalEnvironment,
316
330
  getToken: () => getToken,
331
+ handleLimitExceeded: () => handleLimitExceeded,
317
332
  howone: () => client_default,
318
333
  iframeNavigation: () => iframeNavigation,
319
334
  initIframeNavigation: () => initIframeNavigation,
320
335
  isTokenValid: () => isTokenValid,
321
336
  loginWithEmailCode: () => loginWithEmailCode,
337
+ mergeLimitExceededOptions: () => mergeLimitExceededOptions,
322
338
  onAuthStateChanged: () => onAuthStateChanged,
323
339
  parseUserFromToken: () => parseUserFromToken,
324
340
  sendElementSelectionToParent: () => sendElementSelectionToParent,
@@ -818,162 +834,511 @@ function getCodeStatus(email) {
818
834
  return unifiedAuth.getCodeStatus(email);
819
835
  }
820
836
 
821
- // src/components/auth/LoginForm.tsx
822
- var import_react2 = require("react");
823
- var import_react3 = require("@iconify/react");
824
- var import_lucide_react = require("lucide-react");
825
- var import_jsx_runtime2 = require("react/jsx-runtime");
826
- var LoginForm = ({
827
- onLoginSuccess,
828
- appName = "AI Application Platform",
829
- className = ""
830
- }) => {
831
- const [email, setEmail] = (0, import_react2.useState)("");
832
- const [code, setCode] = (0, import_react2.useState)("");
833
- const [validationErrors, setValidationErrors] = (0, import_react2.useState)({});
834
- const [isAnyLoading, setIsAnyLoading] = (0, import_react2.useState)(false);
835
- const [codeSent, setCodeSent] = (0, import_react2.useState)(false);
836
- const [loginError, setLoginError] = (0, import_react2.useState)(null);
837
- const googleLogin = async () => {
838
- };
839
- const githubLogin = async () => {
840
- };
841
- const sendEmailCode = async (email2) => {
842
- setCodeSent(true);
843
- };
844
- const loginWithEmail = async (email2, code2) => {
845
- if (onLoginSuccess) onLoginSuccess();
846
- };
847
- const clearError = () => {
848
- setLoginError(null);
849
- setValidationErrors({});
850
- };
851
- (0, import_react2.useEffect)(() => {
852
- if (loginError) {
853
- try {
854
- const errorObj = JSON.parse(loginError);
855
- const newErrors = {};
856
- if (errorObj.code === 429) {
857
- newErrors.form = errorObj.msg || "\u8BF7\u6C42\u8FC7\u4E8E\u9891\u7E41\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5";
858
- } else if (errorObj.data?.code === 401 && errorObj.data?.message) {
859
- if (codeSent) {
860
- newErrors.code = errorObj.data.message;
861
- } else {
862
- newErrors.form = errorObj.data.message;
863
- }
864
- } else if (errorObj.msg) {
865
- newErrors.form = errorObj.msg;
866
- } else if (errorObj.data?.message) {
867
- newErrors.form = errorObj.data.message;
868
- } else {
869
- newErrors.form = "\u53D1\u751F\u672A\u77E5\u9519\u8BEF\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5";
870
- }
871
- setValidationErrors(newErrors);
872
- } catch (e) {
873
- setValidationErrors({ form: loginError });
837
+ // src/services/ai-workflow.ts
838
+ var AIWorkflowClient = class {
839
+ constructor(options = {}) {
840
+ this.baseUrl = options.baseUrl?.replace(/\/+$/, "") || "";
841
+ this.apiKey = options.apiKey;
842
+ this.headers = { "Content-Type": "application/json", ...options.headers || {} };
843
+ this.fetchImpl = options.fetchImpl || fetch.bind(globalThis);
844
+ }
845
+ buildHeaders(extra) {
846
+ const h = { ...this.headers, ...extra || {} };
847
+ if (this.apiKey && !h["Authorization"]) {
848
+ h["Authorization"] = `Bearer ${this.apiKey}`;
849
+ }
850
+ return h;
851
+ }
852
+ async safeJson(resp) {
853
+ try {
854
+ return await resp.json();
855
+ } catch (_e) {
856
+ return null;
857
+ }
858
+ }
859
+ /**
860
+ * ID 执行工作流:POST {baseUrl}/workflow/{workflowId}/execute
861
+ * body: { input, options }
862
+ */
863
+ async executeWorkflow(workflowId, inputs, options) {
864
+ if (!this.baseUrl) {
865
+ throw new Error("AI workflow client requires a baseUrl (e.g. https://evoagentx-server.fly.dev)");
866
+ }
867
+ const url = `${this.baseUrl}/workflow/${workflowId}/execute`;
868
+ try {
869
+ const res = await this.fetchImpl(url, {
870
+ method: "POST",
871
+ headers: this.buildHeaders(),
872
+ body: JSON.stringify({ inputs, options })
873
+ });
874
+ const data = await this.safeJson(res);
875
+ if (!res.ok) {
876
+ return { success: false, error: data?.error || `HTTP ${res.status}` };
874
877
  }
875
- const timer = setTimeout(() => {
876
- clearError();
877
- }, 8e3);
878
- return () => clearTimeout(timer);
878
+ return data || { success: true };
879
+ } catch (error) {
880
+ return { success: false, error: error instanceof Error ? error.message : "Network error" };
879
881
  }
880
- }, [loginError, codeSent]);
881
- const handleSubmit = async (e) => {
882
- e.preventDefault();
883
- const formData = new FormData(e.currentTarget);
884
- setValidationErrors({});
885
- if (!codeSent) {
886
- const emailValue = formData.get("email");
887
- if (!emailValue) {
888
- setValidationErrors({ email: "Please enter your email address" });
889
- return;
882
+ }
883
+ };
884
+ function createAIWorkflowClient(options = {}) {
885
+ return new AIWorkflowClient(options);
886
+ }
887
+ var aiWorkflow = createAIWorkflowClient({ baseUrl: "https://evoagentx-server" });
888
+
889
+ // src/services/request/index.ts
890
+ var import_axios = __toESM(require("axios"));
891
+ var Request = class {
892
+ constructor(config) {
893
+ this.abortControllers = /* @__PURE__ */ new Map();
894
+ this.instance = import_axios.default.create({
895
+ ...config,
896
+ withCredentials: true,
897
+ validateStatus: (status) => {
898
+ return status >= 200 && status < 300;
890
899
  }
891
- setIsAnyLoading(true);
892
- try {
893
- await sendEmailCode(emailValue);
894
- setEmail(emailValue);
895
- } catch (error) {
896
- setLoginError(error instanceof Error ? error.message : "Failed to send code");
897
- } finally {
898
- setIsAnyLoading(false);
900
+ });
901
+ this.interceptors = config.interceptors;
902
+ this.instance.interceptors.request.use(
903
+ this.interceptors?.requestInterceptor,
904
+ this.interceptors?.requestInterceptorCatch
905
+ );
906
+ this.instance.interceptors.response.use(
907
+ this.interceptors?.responseInterceptor,
908
+ this.interceptors?.responseInterceptorCatch
909
+ );
910
+ this.instance.interceptors.request.use(
911
+ (config2) => {
912
+ return config2;
913
+ },
914
+ (err) => {
915
+ return Promise.reject(err);
899
916
  }
900
- } else {
901
- const codeValue = code;
902
- if (!codeValue || codeValue.length !== 6) {
903
- setValidationErrors({ code: "Please enter the 6-digit verification code" });
904
- return;
917
+ );
918
+ this.instance.interceptors.response.use(
919
+ (res) => {
920
+ return res.data;
921
+ },
922
+ (err) => {
923
+ if (import_axios.default.isCancel(err)) {
924
+ return Promise.reject({
925
+ isCanceled: true,
926
+ message: "request canceled",
927
+ originalError: err
928
+ });
929
+ }
930
+ if (err.response?.data?.error) {
931
+ return Promise.reject(err.response.data.error);
932
+ }
933
+ return Promise.reject(err);
905
934
  }
906
- setIsAnyLoading(true);
907
- try {
908
- await loginWithEmail(email, codeValue);
909
- } catch (error) {
910
- setLoginError(error instanceof Error ? error.message : "Login failed");
911
- } finally {
912
- setIsAnyLoading(false);
935
+ );
936
+ }
937
+ cancelRequest(url) {
938
+ this.abortControllers.forEach((controller, key) => {
939
+ if (key.includes(url)) {
940
+ controller.abort();
941
+ this.abortControllers.delete(key);
913
942
  }
914
- }
915
- };
916
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: `w-full space-y-6 ${className}`, children: [
917
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "space-y-1", children: [
918
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h1", { className: "text-3xl font-bold text-gray-900", children: "Welcome Back!" }),
919
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-sm text-gray-600", children: "Please enter log in details below" })
920
- ] }),
921
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("form", { className: "space-y-5", onSubmit: handleSubmit, children: [
922
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "space-y-2", children: [
923
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { htmlFor: "email", className: "text-gray-700 font-medium text-sm block", children: "Email" }),
924
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
925
- "input",
926
- {
927
- id: "email",
928
- type: "email",
929
- name: "email",
930
- value: email,
931
- onChange: (e) => {
932
- const value = e.target.value;
933
- setEmail(value);
934
- if (validationErrors.email) {
935
- const newErrors = { ...validationErrors };
936
- delete newErrors.email;
937
- setValidationErrors(newErrors);
938
- }
939
- },
940
- required: true,
941
- "aria-invalid": !!validationErrors.email,
942
- className: "w-full text-sm bg-gray-50 rounded-md h-11 px-3 hover:bg-gray-100 focus:bg-white border border-gray-200 focus:border-gray-400 focus:outline-none",
943
- placeholder: ""
944
- }
945
- ),
946
- validationErrors.email && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-red-600 text-sm", children: validationErrors.email })
947
- ] }),
948
- codeSent && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "space-y-2", children: [
949
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { className: "text-gray-700 font-medium text-sm block", children: "Verification Code" }),
950
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
951
- "input",
952
- {
953
- type: "text",
954
- maxLength: 6,
955
- value: code,
956
- onChange: (e) => {
957
- const value = e.target.value.replace(/\D/g, "");
958
- setCode(value);
959
- if (validationErrors.code) {
960
- const newErrors = { ...validationErrors };
961
- delete newErrors.code;
962
- setValidationErrors(newErrors);
963
- }
964
- },
965
- "aria-invalid": !!validationErrors.code,
966
- className: "w-full text-center text-sm bg-gray-50 rounded-md h-11 px-3 hover:bg-gray-100 focus:bg-white border border-gray-200 focus:border-gray-400 focus:outline-none tracking-widest",
967
- placeholder: "000000"
968
- }
969
- ),
970
- validationErrors.code && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-red-600 text-sm", children: validationErrors.code })
971
- ] }),
972
- validationErrors.form && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "text-red-600 text-sm p-3 bg-red-50 rounded-md border border-red-200", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-center", children: [
973
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react3.Icon, { icon: "material-symbols:error", className: "text-red-600 mr-2" }),
974
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: validationErrors.form })
975
- ] }) }),
976
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
943
+ });
944
+ }
945
+ cancelAllRequests() {
946
+ this.abortControllers.forEach((controller) => {
947
+ controller.abort();
948
+ });
949
+ this.abortControllers.clear();
950
+ }
951
+ request(config) {
952
+ const controller = new AbortController();
953
+ const url = config.url || "";
954
+ const method = config.method || "GET";
955
+ const key = `${method}:${url}`;
956
+ this.abortControllers.set(key, controller);
957
+ config.signal = controller.signal;
958
+ return new Promise((resolve, reject) => {
959
+ if (config.interceptors?.requestInterceptor) {
960
+ config = config.interceptors.requestInterceptor(config);
961
+ }
962
+ this.instance.request(config).then((res) => {
963
+ this.abortControllers.delete(key);
964
+ if (config.interceptors?.responseInterceptor) {
965
+ res = config.interceptors.responseInterceptor(res);
966
+ }
967
+ resolve(res);
968
+ }).catch((err) => {
969
+ this.abortControllers.delete(key);
970
+ reject(err);
971
+ });
972
+ });
973
+ }
974
+ get(config) {
975
+ return this.request({ ...config, method: "GET" });
976
+ }
977
+ post(config) {
978
+ return this.request({ ...config, method: "POST" });
979
+ }
980
+ delete(config) {
981
+ return this.request({ ...config, method: "DELETE" });
982
+ }
983
+ put(config) {
984
+ return this.request({ ...config, method: "PUT" });
985
+ }
986
+ patch(config) {
987
+ return this.request({ ...config, method: "PATCH" });
988
+ }
989
+ };
990
+ var request_default = Request;
991
+
992
+ // src/services/ai-workflow-axios.ts
993
+ function createAIWorkflowClientAxios(options = {}) {
994
+ const basePath = options.basePath ?? "/api";
995
+ const baseUrl = (options.baseUrl || "https://evoagentx-server.fly.dev").replace(/\/+$/, "");
996
+ const baseAPI = `${baseUrl}${basePath.startsWith("/") ? "" : "/"}${basePath}`.replace(/\/+$/, "");
997
+ const client = options.requestInstance || new request_default({
998
+ baseURL: baseAPI,
999
+ timeout: options.timeout ?? 6e4,
1000
+ interceptors: {
1001
+ requestInterceptor: (config) => {
1002
+ config.headers = config.headers || {};
1003
+ if (options.apiKey && !config.headers["Authorization"]) {
1004
+ config.headers["Authorization"] = `Bearer ${options.apiKey}`;
1005
+ }
1006
+ if (options.headers) {
1007
+ config.headers = { ...config.headers || {}, ...options.headers };
1008
+ }
1009
+ return config;
1010
+ },
1011
+ requestInterceptorCatch: (err) => Promise.reject(err),
1012
+ responseInterceptor: (res) => res,
1013
+ responseInterceptorCatch: (err) => Promise.reject(err)
1014
+ }
1015
+ });
1016
+ return {
1017
+ async executeWorkflow(workflowId, inputs, opts) {
1018
+ const url = `${baseUrl}/workflow/${workflowId}/execute`;
1019
+ const data = await client.post({ url, data: { inputs, options: opts } });
1020
+ return data;
1021
+ }
1022
+ };
1023
+ }
1024
+
1025
+ // src/services/artifact-types.ts
1026
+ function canAccessArtifact(a, ctx = {}) {
1027
+ if (!a) return false;
1028
+ if (a.visibility === "public") return true;
1029
+ if (a.visibility === "project") {
1030
+ if (ctx.projectId && a.projectId && ctx.projectId === a.projectId) return true;
1031
+ if (ctx.tokenScopes && ctx.tokenScopes.includes("project:read")) return true;
1032
+ return false;
1033
+ }
1034
+ if (a.visibility === "private") {
1035
+ if (ctx.userId && a.ownerId && ctx.userId === a.ownerId) return true;
1036
+ if (ctx.tokenScopes && (ctx.tokenScopes.includes("artifact:read:all") || ctx.tokenScopes.includes("admin"))) return true;
1037
+ return false;
1038
+ }
1039
+ if (a.visibility === "shared") {
1040
+ if (ctx.userId && a.sharedWith && a.sharedWith.includes(ctx.userId)) return true;
1041
+ if (ctx.tokenScopes && (ctx.tokenScopes.includes("artifact:read:all") || ctx.tokenScopes.includes("admin"))) return true;
1042
+ return false;
1043
+ }
1044
+ return false;
1045
+ }
1046
+
1047
+ // src/services/artifacts-client.ts
1048
+ function createArtifactsClient(req) {
1049
+ return {
1050
+ async create(input) {
1051
+ return await req.post({ url: "/artifacts", data: input });
1052
+ },
1053
+ async list(query) {
1054
+ return await req.get({ url: "/artifacts", params: query });
1055
+ },
1056
+ async get(id) {
1057
+ return await req.get({ url: `/artifacts/${encodeURIComponent(id)}` });
1058
+ },
1059
+ async setVisibility(id, visibility) {
1060
+ await req.patch({ url: `/artifacts/${encodeURIComponent(id)}/visibility`, data: { visibility } });
1061
+ },
1062
+ async delete(id) {
1063
+ await req.delete({ url: `/artifacts/${encodeURIComponent(id)}` });
1064
+ },
1065
+ // convenience local check (server is authoritative)
1066
+ canAccessLocal(a, ctx) {
1067
+ if (!a) return false;
1068
+ if (a.visibility === "public") return true;
1069
+ if (a.visibility === "project") return Boolean(ctx.projectId && a.projectId && ctx.projectId === a.projectId);
1070
+ if (a.visibility === "private") return Boolean(ctx.userId && a.ownerId && ctx.userId === a.ownerId);
1071
+ if (a.visibility === "shared") return Boolean(ctx.userId && a.sharedWith && a.sharedWith.includes(ctx.userId));
1072
+ return false;
1073
+ }
1074
+ };
1075
+ }
1076
+
1077
+ // src/services/upload-client.ts
1078
+ function createUploadClient(req, projectId) {
1079
+ const uploadUrl = projectId ? `/entities/apps/${projectId}/files` : "/files";
1080
+ return {
1081
+ /**
1082
+ * 上传单个文件
1083
+ *
1084
+ * @example
1085
+ * ```typescript
1086
+ * const { url } = await client.upload.file(imageFile)
1087
+ * console.log('文件地址:', url)
1088
+ * ```
1089
+ */
1090
+ async file(file, options) {
1091
+ const formData = new FormData();
1092
+ if (typeof file === "string") {
1093
+ if (file.startsWith("data:")) {
1094
+ const response2 = await fetch(file);
1095
+ const blob = await response2.blob();
1096
+ formData.append("file", blob, "upload.bin");
1097
+ } else {
1098
+ formData.append("fileUrl", file);
1099
+ }
1100
+ } else if (file instanceof File) {
1101
+ formData.append("file", file, file.name);
1102
+ } else {
1103
+ formData.append("file", file, "upload.bin");
1104
+ }
1105
+ if (options?.metadata) {
1106
+ formData.append("metadata", JSON.stringify(options.metadata));
1107
+ }
1108
+ const response = await req.post({
1109
+ url: uploadUrl,
1110
+ data: formData,
1111
+ signal: options?.signal
1112
+ });
1113
+ return {
1114
+ url: response.data.publicUrl
1115
+ };
1116
+ },
1117
+ /**
1118
+ * 上传图片(快捷方法,专为 AI 设计)
1119
+ *
1120
+ * @example
1121
+ * ```typescript
1122
+ * const { url } = await client.upload.image(imageFile)
1123
+ * ```
1124
+ */
1125
+ async image(file) {
1126
+ const result = await this.file(file);
1127
+ return { url: result.url };
1128
+ },
1129
+ /**
1130
+ * 批量上传文件
1131
+ *
1132
+ * @example
1133
+ * ```typescript
1134
+ * const result = await client.upload.batch({
1135
+ * files: [file1, file2, file3],
1136
+ * concurrent: 3,
1137
+ * onProgress: (completed, total) => {
1138
+ * console.log(`${completed}/${total}`)
1139
+ * }
1140
+ * })
1141
+ * ```
1142
+ */
1143
+ async batch(options) {
1144
+ const { files, concurrent = 3, onProgress, onFileComplete, signal } = options;
1145
+ const success = [];
1146
+ const failed = [];
1147
+ let completed = 0;
1148
+ for (let i = 0; i < files.length; i += concurrent) {
1149
+ if (signal?.aborted) break;
1150
+ const batch = files.slice(i, Math.min(i + concurrent, files.length));
1151
+ const promises = batch.map(async (file, batchIndex) => {
1152
+ const globalIndex = i + batchIndex;
1153
+ try {
1154
+ const result = await this.file(file, { signal });
1155
+ success.push(result);
1156
+ if (onFileComplete) {
1157
+ onFileComplete(result, globalIndex);
1158
+ }
1159
+ } catch (error) {
1160
+ const errorMsg = error instanceof Error ? error.message : String(error);
1161
+ failed.push({ index: globalIndex, error: errorMsg });
1162
+ if (onFileComplete) {
1163
+ onFileComplete(
1164
+ error instanceof Error ? error : new Error(errorMsg),
1165
+ globalIndex
1166
+ );
1167
+ }
1168
+ } finally {
1169
+ completed++;
1170
+ if (onProgress) {
1171
+ onProgress(completed, files.length);
1172
+ }
1173
+ }
1174
+ });
1175
+ await Promise.all(promises);
1176
+ }
1177
+ return {
1178
+ success,
1179
+ failed,
1180
+ total: files.length
1181
+ };
1182
+ }
1183
+ };
1184
+ }
1185
+
1186
+ // src/components/auth/LoginForm.tsx
1187
+ var import_react2 = require("react");
1188
+ var import_react3 = require("@iconify/react");
1189
+ var import_lucide_react = require("lucide-react");
1190
+ var import_jsx_runtime2 = require("react/jsx-runtime");
1191
+ var LoginForm = ({
1192
+ onLoginSuccess,
1193
+ appName = "AI Application Platform",
1194
+ className = ""
1195
+ }) => {
1196
+ const [email, setEmail] = (0, import_react2.useState)("");
1197
+ const [code, setCode] = (0, import_react2.useState)("");
1198
+ const [validationErrors, setValidationErrors] = (0, import_react2.useState)({});
1199
+ const [isAnyLoading, setIsAnyLoading] = (0, import_react2.useState)(false);
1200
+ const [codeSent, setCodeSent] = (0, import_react2.useState)(false);
1201
+ const [loginError, setLoginError] = (0, import_react2.useState)(null);
1202
+ const googleLogin = async () => {
1203
+ };
1204
+ const githubLogin = async () => {
1205
+ };
1206
+ const sendEmailCode = async (email2) => {
1207
+ setCodeSent(true);
1208
+ };
1209
+ const loginWithEmail = async (email2, code2) => {
1210
+ if (onLoginSuccess) onLoginSuccess();
1211
+ };
1212
+ const clearError = () => {
1213
+ setLoginError(null);
1214
+ setValidationErrors({});
1215
+ };
1216
+ (0, import_react2.useEffect)(() => {
1217
+ if (loginError) {
1218
+ try {
1219
+ const errorObj = JSON.parse(loginError);
1220
+ const newErrors = {};
1221
+ if (errorObj.code === 429) {
1222
+ newErrors.form = errorObj.msg || "\u8BF7\u6C42\u8FC7\u4E8E\u9891\u7E41\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5";
1223
+ } else if (errorObj.data?.code === 401 && errorObj.data?.message) {
1224
+ if (codeSent) {
1225
+ newErrors.code = errorObj.data.message;
1226
+ } else {
1227
+ newErrors.form = errorObj.data.message;
1228
+ }
1229
+ } else if (errorObj.msg) {
1230
+ newErrors.form = errorObj.msg;
1231
+ } else if (errorObj.data?.message) {
1232
+ newErrors.form = errorObj.data.message;
1233
+ } else {
1234
+ newErrors.form = "\u53D1\u751F\u672A\u77E5\u9519\u8BEF\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5";
1235
+ }
1236
+ setValidationErrors(newErrors);
1237
+ } catch (e) {
1238
+ setValidationErrors({ form: loginError });
1239
+ }
1240
+ const timer = setTimeout(() => {
1241
+ clearError();
1242
+ }, 8e3);
1243
+ return () => clearTimeout(timer);
1244
+ }
1245
+ }, [loginError, codeSent]);
1246
+ const handleSubmit = async (e) => {
1247
+ e.preventDefault();
1248
+ const formData = new FormData(e.currentTarget);
1249
+ setValidationErrors({});
1250
+ if (!codeSent) {
1251
+ const emailValue = formData.get("email");
1252
+ if (!emailValue) {
1253
+ setValidationErrors({ email: "Please enter your email address" });
1254
+ return;
1255
+ }
1256
+ setIsAnyLoading(true);
1257
+ try {
1258
+ await sendEmailCode(emailValue);
1259
+ setEmail(emailValue);
1260
+ } catch (error) {
1261
+ setLoginError(error instanceof Error ? error.message : "Failed to send code");
1262
+ } finally {
1263
+ setIsAnyLoading(false);
1264
+ }
1265
+ } else {
1266
+ const codeValue = code;
1267
+ if (!codeValue || codeValue.length !== 6) {
1268
+ setValidationErrors({ code: "Please enter the 6-digit verification code" });
1269
+ return;
1270
+ }
1271
+ setIsAnyLoading(true);
1272
+ try {
1273
+ await loginWithEmail(email, codeValue);
1274
+ } catch (error) {
1275
+ setLoginError(error instanceof Error ? error.message : "Login failed");
1276
+ } finally {
1277
+ setIsAnyLoading(false);
1278
+ }
1279
+ }
1280
+ };
1281
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: `w-full space-y-6 ${className}`, children: [
1282
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "space-y-1", children: [
1283
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h1", { className: "text-3xl font-bold text-gray-900", children: "Welcome Back!" }),
1284
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-sm text-gray-600", children: "Please enter log in details below" })
1285
+ ] }),
1286
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("form", { className: "space-y-5", onSubmit: handleSubmit, children: [
1287
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "space-y-2", children: [
1288
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { htmlFor: "email", className: "text-gray-700 font-medium text-sm block", children: "Email" }),
1289
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1290
+ "input",
1291
+ {
1292
+ id: "email",
1293
+ type: "email",
1294
+ name: "email",
1295
+ value: email,
1296
+ onChange: (e) => {
1297
+ const value = e.target.value;
1298
+ setEmail(value);
1299
+ if (validationErrors.email) {
1300
+ const newErrors = { ...validationErrors };
1301
+ delete newErrors.email;
1302
+ setValidationErrors(newErrors);
1303
+ }
1304
+ },
1305
+ required: true,
1306
+ "aria-invalid": !!validationErrors.email,
1307
+ className: "w-full text-sm bg-gray-50 rounded-md h-11 px-3 hover:bg-gray-100 focus:bg-white border border-gray-200 focus:border-gray-400 focus:outline-none",
1308
+ placeholder: ""
1309
+ }
1310
+ ),
1311
+ validationErrors.email && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-red-600 text-sm", children: validationErrors.email })
1312
+ ] }),
1313
+ codeSent && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "space-y-2", children: [
1314
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { className: "text-gray-700 font-medium text-sm block", children: "Verification Code" }),
1315
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1316
+ "input",
1317
+ {
1318
+ type: "text",
1319
+ maxLength: 6,
1320
+ value: code,
1321
+ onChange: (e) => {
1322
+ const value = e.target.value.replace(/\D/g, "");
1323
+ setCode(value);
1324
+ if (validationErrors.code) {
1325
+ const newErrors = { ...validationErrors };
1326
+ delete newErrors.code;
1327
+ setValidationErrors(newErrors);
1328
+ }
1329
+ },
1330
+ "aria-invalid": !!validationErrors.code,
1331
+ className: "w-full text-center text-sm bg-gray-50 rounded-md h-11 px-3 hover:bg-gray-100 focus:bg-white border border-gray-200 focus:border-gray-400 focus:outline-none tracking-widest",
1332
+ placeholder: "000000"
1333
+ }
1334
+ ),
1335
+ validationErrors.code && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-red-600 text-sm", children: validationErrors.code })
1336
+ ] }),
1337
+ validationErrors.form && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "text-red-600 text-sm p-3 bg-red-50 rounded-md border border-red-200", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-center", children: [
1338
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react3.Icon, { icon: "material-symbols:error", className: "text-red-600 mr-2" }),
1339
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: validationErrors.form })
1340
+ ] }) }),
1341
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
977
1342
  "button",
978
1343
  {
979
1344
  type: "submit",
@@ -1031,7 +1396,7 @@ var LoginForm = ({
1031
1396
  };
1032
1397
 
1033
1398
  // src/components/auth/HowoneProvider.tsx
1034
- var import_react9 = require("react");
1399
+ var import_react8 = require("react");
1035
1400
  init_auth();
1036
1401
 
1037
1402
  // src/components/theme/ThemeProvider.tsx
@@ -1088,68 +1453,33 @@ var useTheme = () => {
1088
1453
  };
1089
1454
 
1090
1455
  // src/components/ui/Toast/GlobalToastContainer.tsx
1091
- var import_goey_toast = require("goey-toast");
1092
- var import_styles = require("goey-toast/styles.css");
1093
-
1094
- // src/components/theme/ThemeToggle.tsx
1095
- var React2 = __toESM(require("react"));
1096
- var import_react5 = require("@iconify/react");
1456
+ var import_react_toastify = require("react-toastify");
1097
1457
  var import_jsx_runtime4 = require("react/jsx-runtime");
1098
- function ThemeToggle({ className }) {
1099
- const { setTheme, theme } = useTheme();
1100
- const [mounted, setMounted] = React2.useState(false);
1101
- React2.useEffect(() => {
1102
- setMounted(true);
1103
- }, []);
1104
- const handleToggle = () => {
1105
- if (theme === "dark") {
1106
- setTheme("light");
1107
- } else {
1108
- setTheme("dark");
1109
- }
1110
- };
1111
- if (!mounted) {
1112
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react5.Icon, { icon: "solar:sun-bold", width: 20, height: 20 });
1113
- }
1114
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1115
- "div",
1116
- {
1117
- className: `cursor-pointer ${className || ""}`,
1118
- onClick: handleToggle,
1119
- children: theme === "light" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react5.Icon, { icon: "solar:sun-bold", width: 20, height: 20 }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react5.Icon, { icon: "solar:moon-linear", width: 20, height: 20 })
1120
- }
1121
- );
1122
- }
1123
-
1124
- // src/components/ui/Toast/GlobalToastContainer.tsx
1125
- var import_jsx_runtime5 = require("react/jsx-runtime");
1126
1458
  function GlobalToastContainer() {
1127
- const { theme } = useTheme();
1128
- const resolvedTheme = theme === "dark" ? "dark" : "light";
1129
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1130
- import_goey_toast.GoeyToaster,
1459
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1460
+ import_react_toastify.ToastContainer,
1131
1461
  {
1132
- position: "bottom-right",
1133
- theme: resolvedTheme
1462
+ newestOnTop: false,
1463
+ closeButton: false
1134
1464
  }
1135
1465
  );
1136
1466
  }
1137
1467
 
1138
1468
  // src/components/ElementSelectorProvider.tsx
1139
- var import_react8 = require("react");
1469
+ var import_react7 = require("react");
1140
1470
 
1141
1471
  // src/components/ElementSelector.tsx
1142
- var import_react6 = require("react");
1143
- var import_jsx_runtime6 = require("react/jsx-runtime");
1472
+ var import_react5 = require("react");
1473
+ var import_jsx_runtime5 = require("react/jsx-runtime");
1144
1474
  var ElementSelector = ({
1145
1475
  active,
1146
1476
  onSelect,
1147
1477
  onCancel
1148
1478
  }) => {
1149
- const [hoveredElement, setHoveredElement] = (0, import_react6.useState)(null);
1150
- const [highlightRect, setHighlightRect] = (0, import_react6.useState)(null);
1151
- const overlayRef = (0, import_react6.useRef)(null);
1152
- const getSourceLocation = (0, import_react6.useCallback)((element) => {
1479
+ const [hoveredElement, setHoveredElement] = (0, import_react5.useState)(null);
1480
+ const [highlightRect, setHighlightRect] = (0, import_react5.useState)(null);
1481
+ const overlayRef = (0, import_react5.useRef)(null);
1482
+ const getSourceLocation = (0, import_react5.useCallback)((element) => {
1153
1483
  let current = element;
1154
1484
  while (current && current !== document.body) {
1155
1485
  const sourceLocationAttr = current.getAttribute("data-source-location");
@@ -1164,7 +1494,7 @@ var ElementSelector = ({
1164
1494
  }
1165
1495
  return null;
1166
1496
  }, []);
1167
- const handleMouseMove = (0, import_react6.useCallback)((e) => {
1497
+ const handleMouseMove = (0, import_react5.useCallback)((e) => {
1168
1498
  if (!active) return;
1169
1499
  const elements = document.elementsFromPoint(e.clientX, e.clientY);
1170
1500
  const targetElement = elements.find(
@@ -1176,7 +1506,7 @@ var ElementSelector = ({
1176
1506
  setHighlightRect(rect);
1177
1507
  }
1178
1508
  }, [active, hoveredElement]);
1179
- const handleClick = (0, import_react6.useCallback)((e) => {
1509
+ const handleClick = (0, import_react5.useCallback)((e) => {
1180
1510
  if (!active || !hoveredElement) return;
1181
1511
  e.preventDefault();
1182
1512
  e.stopPropagation();
@@ -1204,7 +1534,7 @@ var ElementSelector = ({
1204
1534
  }
1205
1535
  }
1206
1536
  }, [active, hoveredElement, getSourceLocation, onSelect, onCancel]);
1207
- (0, import_react6.useEffect)(() => {
1537
+ (0, import_react5.useEffect)(() => {
1208
1538
  if (active) {
1209
1539
  document.addEventListener("mousemove", handleMouseMove);
1210
1540
  document.addEventListener("click", handleClick, true);
@@ -1220,8 +1550,8 @@ var ElementSelector = ({
1220
1550
  }
1221
1551
  }, [active, handleMouseMove, handleClick]);
1222
1552
  if (!active) return null;
1223
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
1224
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1553
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1554
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1225
1555
  "div",
1226
1556
  {
1227
1557
  ref: overlayRef,
@@ -1238,7 +1568,7 @@ var ElementSelector = ({
1238
1568
  }
1239
1569
  }
1240
1570
  ),
1241
- highlightRect && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1571
+ highlightRect && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1242
1572
  "div",
1243
1573
  {
1244
1574
  style: {
@@ -1256,7 +1586,7 @@ var ElementSelector = ({
1256
1586
  }
1257
1587
  }
1258
1588
  ),
1259
- hoveredElement && highlightRect && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1589
+ hoveredElement && highlightRect && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1260
1590
  "div",
1261
1591
  {
1262
1592
  style: {
@@ -1282,17 +1612,17 @@ var ElementSelector = ({
1282
1612
  };
1283
1613
 
1284
1614
  // src/hooks/use-element-selector.ts
1285
- var import_react7 = require("react");
1615
+ var import_react6 = require("react");
1286
1616
  function useElementSelector() {
1287
- const [isSelecting, setIsSelecting] = (0, import_react7.useState)(false);
1288
- const [selectedElement, setSelectedElement] = (0, import_react7.useState)(null);
1289
- const startSelecting = (0, import_react7.useCallback)(() => {
1617
+ const [isSelecting, setIsSelecting] = (0, import_react6.useState)(false);
1618
+ const [selectedElement, setSelectedElement] = (0, import_react6.useState)(null);
1619
+ const startSelecting = (0, import_react6.useCallback)(() => {
1290
1620
  setIsSelecting(true);
1291
1621
  }, []);
1292
- const stopSelecting = (0, import_react7.useCallback)(() => {
1622
+ const stopSelecting = (0, import_react6.useCallback)(() => {
1293
1623
  setIsSelecting(false);
1294
1624
  }, []);
1295
- const clearSelection = (0, import_react7.useCallback)(() => {
1625
+ const clearSelection = (0, import_react6.useCallback)(() => {
1296
1626
  setSelectedElement(null);
1297
1627
  }, []);
1298
1628
  return {
@@ -1313,10 +1643,10 @@ function sendElementSelectionToParent(data) {
1313
1643
  }
1314
1644
 
1315
1645
  // src/components/ElementSelectorProvider.tsx
1316
- var import_jsx_runtime7 = require("react/jsx-runtime");
1646
+ var import_jsx_runtime6 = require("react/jsx-runtime");
1317
1647
  var ElementSelectorProvider = ({ children }) => {
1318
- const [isSelecting, setIsSelecting] = (0, import_react8.useState)(false);
1319
- const handleCancel = (0, import_react8.useCallback)(() => {
1648
+ const [isSelecting, setIsSelecting] = (0, import_react7.useState)(false);
1649
+ const handleCancel = (0, import_react7.useCallback)(() => {
1320
1650
  setIsSelecting(false);
1321
1651
  if (window.parent && window.parent !== window) {
1322
1652
  window.parent.postMessage({
@@ -1324,10 +1654,10 @@ var ElementSelectorProvider = ({ children }) => {
1324
1654
  }, "*");
1325
1655
  }
1326
1656
  }, []);
1327
- const handleSelect = (0, import_react8.useCallback)((data) => {
1657
+ const handleSelect = (0, import_react7.useCallback)((data) => {
1328
1658
  sendElementSelectionToParent(data);
1329
1659
  }, []);
1330
- (0, import_react8.useEffect)(() => {
1660
+ (0, import_react7.useEffect)(() => {
1331
1661
  const handleStartSelection = () => {
1332
1662
  setIsSelecting(true);
1333
1663
  };
@@ -1350,9 +1680,9 @@ var ElementSelectorProvider = ({ children }) => {
1350
1680
  window.removeEventListener("message", handleMessage);
1351
1681
  };
1352
1682
  }, [handleCancel]);
1353
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
1683
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
1354
1684
  children,
1355
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1685
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1356
1686
  ElementSelector,
1357
1687
  {
1358
1688
  active: isSelecting,
@@ -1365,8 +1695,8 @@ var ElementSelectorProvider = ({ children }) => {
1365
1695
 
1366
1696
  // src/components/auth/HowoneProvider.tsx
1367
1697
  init_config();
1368
- var import_jsx_runtime8 = require("react/jsx-runtime");
1369
- var HowoneContext = (0, import_react9.createContext)(null);
1698
+ var import_jsx_runtime7 = require("react/jsx-runtime");
1699
+ var HowoneContext = (0, import_react8.createContext)(null);
1370
1700
  var consumedTokenCache = /* @__PURE__ */ new Set();
1371
1701
  var redirectOverlayStylesInjected = false;
1372
1702
  var injectRedirectOverlayStyles = () => {
@@ -1427,15 +1757,15 @@ var HowOneProvider = ({
1427
1757
  forceDefaultTheme = false,
1428
1758
  redirectOnUnauthenticated = true
1429
1759
  }) => {
1430
- const [user, setUser] = (0, import_react9.useState)(() => parseUserFromToken(getToken()));
1431
- const [token, setTokenState] = (0, import_react9.useState)(() => getToken());
1432
- const [hasCheckedUrlToken, setHasCheckedUrlToken] = (0, import_react9.useState)(false);
1433
- const [pendingRedirect, setPendingRedirect] = (0, import_react9.useState)(false);
1434
- const authCookieRoot = (0, import_react9.useMemo)(() => {
1760
+ const [user, setUser] = (0, import_react8.useState)(() => parseUserFromToken(getToken()));
1761
+ const [token, setTokenState] = (0, import_react8.useState)(() => getToken());
1762
+ const [hasCheckedUrlToken, setHasCheckedUrlToken] = (0, import_react8.useState)(false);
1763
+ const [pendingRedirect, setPendingRedirect] = (0, import_react8.useState)(false);
1764
+ const authCookieRoot = (0, import_react8.useMemo)(() => {
1435
1765
  const env3 = getGlobalEnvironment() ?? "dev";
1436
1766
  return setEnvironment(env3).AUTH_COOKIE_ROOT_VALUE;
1437
1767
  }, []);
1438
- const consumeTokenToCookie = (0, import_react9.useCallback)(async (value2) => {
1768
+ const consumeTokenToCookie = (0, import_react8.useCallback)(async (value2) => {
1439
1769
  if (!value2) return;
1440
1770
  if (consumedTokenCache.has(value2)) return;
1441
1771
  consumedTokenCache.add(value2);
@@ -1462,7 +1792,7 @@ var HowOneProvider = ({
1462
1792
  console.warn("[HowOneProvider] Failed to consume token:", error);
1463
1793
  }
1464
1794
  }, [authCookieRoot]);
1465
- const logoutFromCookie = (0, import_react9.useCallback)(async () => {
1795
+ const logoutFromCookie = (0, import_react8.useCallback)(async () => {
1466
1796
  try {
1467
1797
  await fetch(`${authCookieRoot}/logout`, {
1468
1798
  method: "POST",
@@ -1472,7 +1802,7 @@ var HowOneProvider = ({
1472
1802
  console.warn("[HowOneProvider] Failed to logout from cookie:", error);
1473
1803
  }
1474
1804
  }, [authCookieRoot]);
1475
- const readAccessTokenCookie = (0, import_react9.useCallback)(() => {
1805
+ const readAccessTokenCookie = (0, import_react8.useCallback)(() => {
1476
1806
  if (typeof document === "undefined") return null;
1477
1807
  try {
1478
1808
  const parts = document.cookie.split("; ");
@@ -1488,7 +1818,7 @@ var HowOneProvider = ({
1488
1818
  }
1489
1819
  return null;
1490
1820
  }, []);
1491
- (0, import_react9.useEffect)(() => {
1821
+ (0, import_react8.useEffect)(() => {
1492
1822
  try {
1493
1823
  const params = new URLSearchParams(window.location.search);
1494
1824
  let urlToken = params.get("access_token") || params.get("token");
@@ -1522,7 +1852,7 @@ var HowOneProvider = ({
1522
1852
  setHasCheckedUrlToken(true);
1523
1853
  }
1524
1854
  }, [consumeTokenToCookie, readAccessTokenCookie]);
1525
- const resolvedAuthUrl = (0, import_react9.useMemo)(() => {
1855
+ const resolvedAuthUrl = (0, import_react8.useMemo)(() => {
1526
1856
  const env3 = getGlobalEnvironment() ?? "dev";
1527
1857
  switch (env3) {
1528
1858
  case "local":
@@ -1534,12 +1864,12 @@ var HowOneProvider = ({
1534
1864
  return "https://howone.dev/auth";
1535
1865
  }
1536
1866
  }, []);
1537
- (0, import_react9.useEffect)(() => {
1867
+ (0, import_react8.useEffect)(() => {
1538
1868
  if (pendingRedirect) {
1539
1869
  injectRedirectOverlayStyles();
1540
1870
  }
1541
1871
  }, [pendingRedirect]);
1542
- const redirectToAuth = (0, import_react9.useCallback)(() => {
1872
+ const redirectToAuth = (0, import_react8.useCallback)(() => {
1543
1873
  if (!redirectOnUnauthenticated || typeof window === "undefined") return;
1544
1874
  const activeProjectId = projectId ?? getDefaultProjectId();
1545
1875
  const navigateToResolvedAuth = () => {
@@ -1581,7 +1911,7 @@ var HowOneProvider = ({
1581
1911
  navigateToResolvedAuth();
1582
1912
  }
1583
1913
  }, [redirectOnUnauthenticated, resolvedAuthUrl, projectId]);
1584
- (0, import_react9.useEffect)(() => {
1914
+ (0, import_react8.useEffect)(() => {
1585
1915
  if (!hasCheckedUrlToken) return;
1586
1916
  if (!token && !user) {
1587
1917
  redirectToAuth();
@@ -1604,31 +1934,31 @@ var HowOneProvider = ({
1604
1934
  logout
1605
1935
  };
1606
1936
  if (!hasCheckedUrlToken) return null;
1607
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1937
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1608
1938
  ThemeProvider,
1609
1939
  {
1610
1940
  defaultTheme,
1611
1941
  storageKey: themeStorageKey,
1612
1942
  forceDefault: forceDefaultTheme,
1613
1943
  children: [
1614
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ElementSelectorProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(HowoneContext.Provider, { value, children: [
1944
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ElementSelectorProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(HowoneContext.Provider, { value, children: [
1615
1945
  children,
1616
- showHowOneFlag && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(FloatingButton, { onClick: () => window.open("https://howone.ai", "_blank") }),
1617
- pendingRedirect && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1946
+ showHowOneFlag && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(FloatingButton, { onClick: () => window.open("https://howone.ai", "_blank") }),
1947
+ pendingRedirect && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1618
1948
  "div",
1619
1949
  {
1620
1950
  "data-howone-auth-overlay-root": true,
1621
1951
  className: "fixed inset-0 z-[100000] h-full w-full flex flex-col items-center justify-center bg-black/65 backdrop-blur-sm text-white",
1622
- children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "relative mt-6 flex h-[220px] w-[220px] items-center justify-center", children: [
1623
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1952
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "relative mt-6 flex h-[220px] w-[220px] items-center justify-center", children: [
1953
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1624
1954
  "div",
1625
1955
  {
1626
1956
  className: "absolute inset-0 rounded-full bg-white/20",
1627
1957
  style: { animation: "howone-glow-ring 2.4s ease-in-out infinite" }
1628
1958
  }
1629
1959
  ),
1630
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "absolute inset-0 rounded-full bg-gradient-to-br from-white/10 via-white/25 to-white/10 blur-2xl" }),
1631
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1960
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "absolute inset-0 rounded-full bg-gradient-to-br from-white/10 via-white/25 to-white/10 blur-2xl" }),
1961
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1632
1962
  "img",
1633
1963
  {
1634
1964
  style: { width: 250, animation: "howone-logo-pulse 2s ease-in-out infinite" },
@@ -1640,13 +1970,13 @@ var HowOneProvider = ({
1640
1970
  }
1641
1971
  )
1642
1972
  ] }) }),
1643
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(GlobalToastContainer, {})
1973
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(GlobalToastContainer, {})
1644
1974
  ]
1645
1975
  }
1646
1976
  );
1647
1977
  };
1648
1978
  function useHowoneContext() {
1649
- const ctx = (0, import_react9.useContext)(HowoneContext);
1979
+ const ctx = (0, import_react8.useContext)(HowoneContext);
1650
1980
  if (!ctx) {
1651
1981
  const t = getToken();
1652
1982
  return {
@@ -1750,7 +2080,7 @@ var howone = {
1750
2080
  var client_default = howone;
1751
2081
 
1752
2082
  // src/components/ui/Loading.tsx
1753
- var import_jsx_runtime9 = require("react/jsx-runtime");
2083
+ var import_jsx_runtime8 = require("react/jsx-runtime");
1754
2084
  var Loading = ({
1755
2085
  size = "md",
1756
2086
  text = "Loading...",
@@ -1763,14 +2093,14 @@ var Loading = ({
1763
2093
  lg: "h-12 w-12"
1764
2094
  };
1765
2095
  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";
1766
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: `${containerClasses} ${className}`, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "text-center", children: [
1767
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2096
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: `${containerClasses} ${className}`, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "text-center", children: [
2097
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1768
2098
  "div",
1769
2099
  {
1770
2100
  className: `animate-spin rounded-full border-2 border-gray-300 border-t-blue-600 mx-auto ${sizeClasses[size]}`
1771
2101
  }
1772
2102
  ),
1773
- text && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { className: "mt-2 text-sm text-gray-600", children: text })
2103
+ text && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "mt-2 text-sm text-gray-600", children: text })
1774
2104
  ] }) });
1775
2105
  };
1776
2106
  var LoadingSpinner = ({
@@ -1782,7 +2112,7 @@ var LoadingSpinner = ({
1782
2112
  md: "h-8 w-8",
1783
2113
  lg: "h-12 w-12"
1784
2114
  };
1785
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2115
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1786
2116
  "div",
1787
2117
  {
1788
2118
  className: `animate-spin rounded-full border-2 border-gray-300 border-t-blue-600 ${sizeClasses[size]} ${className}`
@@ -1791,9 +2121,9 @@ var LoadingSpinner = ({
1791
2121
  };
1792
2122
 
1793
2123
  // src/components/ui/ErrorBoundary.tsx
1794
- var import_react10 = require("react");
1795
- var import_jsx_runtime10 = require("react/jsx-runtime");
1796
- var ErrorBoundary = class extends import_react10.Component {
2124
+ var import_react9 = require("react");
2125
+ var import_jsx_runtime9 = require("react/jsx-runtime");
2126
+ var ErrorBoundary = class extends import_react9.Component {
1797
2127
  constructor(props) {
1798
2128
  super(props);
1799
2129
  this.handleRetry = () => {
@@ -1815,13 +2145,13 @@ var ErrorBoundary = class extends import_react10.Component {
1815
2145
  if (this.state.hasError) {
1816
2146
  if (this.props.fallback) {
1817
2147
  const FallbackComponent = this.props.fallback;
1818
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(FallbackComponent, { error: this.state.error, retry: this.handleRetry });
2148
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(FallbackComponent, { error: this.state.error, retry: this.handleRetry });
1819
2149
  }
1820
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "min-h-[400px] flex items-center justify-center p-4", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "text-center max-w-md", children: [
1821
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "text-red-500 text-6xl mb-4", children: "\u26A0\uFE0F" }),
1822
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h2", { className: "text-xl font-semibold text-gray-900 mb-2", children: "Something went wrong" }),
1823
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "text-gray-600 mb-4", children: "An unexpected error occurred. Please try refreshing the page." }),
1824
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2150
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "min-h-[400px] flex items-center justify-center p-4", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "text-center max-w-md", children: [
2151
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "text-red-500 text-6xl mb-4", children: "\u26A0\uFE0F" }),
2152
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h2", { className: "text-xl font-semibold text-gray-900 mb-2", children: "Something went wrong" }),
2153
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { className: "text-gray-600 mb-4", children: "An unexpected error occurred. Please try refreshing the page." }),
2154
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1825
2155
  "button",
1826
2156
  {
1827
2157
  onClick: this.handleRetry,
@@ -1835,10 +2165,10 @@ var ErrorBoundary = class extends import_react10.Component {
1835
2165
  return this.props.children;
1836
2166
  }
1837
2167
  };
1838
- var DefaultErrorFallback = ({ retry }) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "min-h-[200px] flex items-center justify-center p-4", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "text-center", children: [
1839
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "text-red-500 text-4xl mb-2", children: "\u26A0\uFE0F" }),
1840
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "text-gray-600 mb-2", children: "Something went wrong" }),
1841
- retry && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2168
+ var DefaultErrorFallback = ({ retry }) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "min-h-[200px] flex items-center justify-center p-4", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "text-center", children: [
2169
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "text-red-500 text-4xl mb-2", children: "\u26A0\uFE0F" }),
2170
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { className: "text-gray-600 mb-2", children: "Something went wrong" }),
2171
+ retry && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1842
2172
  "button",
1843
2173
  {
1844
2174
  onClick: retry,
@@ -1849,7 +2179,7 @@ var DefaultErrorFallback = ({ retry }) => /* @__PURE__ */ (0, import_jsx_runtime
1849
2179
  ] }) });
1850
2180
 
1851
2181
  // src/components/ui/ClayxButton.tsx
1852
- var import_jsx_runtime11 = require("react/jsx-runtime");
2182
+ var import_jsx_runtime10 = require("react/jsx-runtime");
1853
2183
  var getSizeClasses = (size, isIconOnly) => {
1854
2184
  if (isIconOnly) {
1855
2185
  switch (size) {
@@ -1905,7 +2235,7 @@ var ClayxButton = ({
1905
2235
  disabled:opacity-50 disabled:cursor-not-allowed disabled:pointer-events-none
1906
2236
  `.replace(/\s+/g, " ").trim();
1907
2237
  const combinedClasses = `${baseClasses} ${sizeClasses} ${variantClasses} ${className}`.trim();
1908
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2238
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1909
2239
  "button",
1910
2240
  {
1911
2241
  className: combinedClasses,
@@ -1917,57 +2247,204 @@ var ClayxButton = ({
1917
2247
  };
1918
2248
 
1919
2249
  // src/components/ui/LimitUpgradeToast.tsx
2250
+ var import_react13 = __toESM(require("react"));
2251
+ var import_react14 = require("@iconify/react");
2252
+
2253
+ // src/components/ui/Toast/ClayxToast.tsx
1920
2254
  var import_react11 = __toESM(require("react"));
2255
+ var import_react_toastify2 = require("react-toastify");
1921
2256
  var import_react12 = require("@iconify/react");
1922
2257
 
1923
- // src/components/ui/Toast/GoeyToast.tsx
1924
- var import_goey_toast2 = require("goey-toast");
1925
- var resolveDuration = (autoClose) => {
1926
- if (typeof autoClose === "number") return autoClose;
1927
- if (autoClose === false) return 24 * 60 * 60 * 1e3;
1928
- return void 0;
1929
- };
1930
- var createToast = (type) => {
1931
- return (params) => {
1932
- const { autoClose, ...rawOptions } = params.options ?? {};
1933
- const id = params.options?.id ?? `goey-${Date.now()}-${Math.random()}`;
1934
- const closeToast = () => import_goey_toast2.goeyToast.dismiss(id);
1935
- const description = params.component ?? (params.render ? params.render(closeToast) : params.message);
1936
- const duration = resolveDuration(autoClose);
1937
- const goeyOptions = {
1938
- ...rawOptions,
1939
- id,
1940
- description,
1941
- ...duration !== void 0 ? { duration } : {}
1942
- };
1943
- const title = params.title ?? "";
1944
- if (type === "default") {
1945
- (0, import_goey_toast2.goeyToast)(title, goeyOptions);
1946
- return;
2258
+ // src/components/theme/ThemeToggle.tsx
2259
+ var React6 = __toESM(require("react"));
2260
+ var import_react10 = require("@iconify/react");
2261
+ var import_jsx_runtime11 = require("react/jsx-runtime");
2262
+ function ThemeToggle({ className }) {
2263
+ const { setTheme, theme } = useTheme();
2264
+ const [mounted, setMounted] = React6.useState(false);
2265
+ React6.useEffect(() => {
2266
+ setMounted(true);
2267
+ }, []);
2268
+ const handleToggle = () => {
2269
+ if (theme === "dark") {
2270
+ setTheme("light");
2271
+ } else {
2272
+ setTheme("dark");
1947
2273
  }
1948
- import_goey_toast2.goeyToast[type](title, goeyOptions);
1949
2274
  };
1950
- };
1951
- var GoeyToast = {
1952
- success: createToast("success"),
1953
- error: createToast("error"),
1954
- warning: createToast("warning"),
1955
- info: createToast("info"),
1956
- default: createToast("default")
1957
- };
2275
+ if (!mounted) {
2276
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react10.Icon, { icon: "solar:sun-bold", width: 20, height: 20 });
2277
+ }
2278
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2279
+ "div",
2280
+ {
2281
+ className: `cursor-pointer ${className || ""}`,
2282
+ onClick: handleToggle,
2283
+ children: theme === "light" ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react10.Icon, { icon: "solar:sun-bold", width: 20, height: 20 }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react10.Icon, { icon: "solar:moon-linear", width: 20, height: 20 })
2284
+ }
2285
+ );
2286
+ }
1958
2287
 
1959
- // src/components/ui/LimitUpgradeToast.tsx
2288
+ // src/components/ui/Toast/ClayxToast.tsx
1960
2289
  var import_jsx_runtime12 = require("react/jsx-runtime");
1961
- var LimitToastContainer = ({ message, onUpgrade, closeToast }) => {
1962
- const [hover, setHover] = import_react11.default.useState(false);
1963
- const [closeHover, setCloseHover] = import_react11.default.useState(false);
1964
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "relative w-full max-w-[420px] overflow-hidden rounded-md bg-gradient-to-br from-[#1A1A1A] via-[#151515] to-[#1A1A1A] shadow-[0_20px_60px_rgba(168,85,247,0.2)] backdrop-blur-sm", children: [
2290
+ var TOAST_ICONS = {
2291
+ success: {
2292
+ icon: "mdi:success",
2293
+ color: "text-green-400",
2294
+ className: "text-green-400",
2295
+ dark: {
2296
+ bgGradient: "bg-[#14181d]",
2297
+ gradientColor: "#389726",
2298
+ borderGradient: "border-[#389726]",
2299
+ borderGradientColor: "#389726"
2300
+ },
2301
+ light: {
2302
+ bgGradient: "bg-[#fafafa]",
2303
+ gradientColor: "#22c55e",
2304
+ borderGradient: "border-[#22c55e]",
2305
+ borderGradientColor: "#22c55e"
2306
+ }
2307
+ },
2308
+ error: {
2309
+ icon: "ic:outline-close",
2310
+ color: "text-red-400",
2311
+ className: "text-red-400",
2312
+ dark: {
2313
+ bgGradient: "bg-[#14181d]",
2314
+ gradientColor: "#ef4444",
2315
+ borderGradient: "border-[#ef4444]",
2316
+ borderGradientColor: "#ef4444"
2317
+ },
2318
+ light: {
2319
+ bgGradient: "bg-[#fafafa]",
2320
+ gradientColor: "#f87171",
2321
+ borderGradient: "border-[#f87171]",
2322
+ borderGradientColor: "#f87171"
2323
+ }
2324
+ },
2325
+ warning: {
2326
+ icon: "mi:warning",
2327
+ color: "text-yellow-400",
2328
+ className: "text-yellow-400",
2329
+ dark: {
2330
+ bgGradient: "bg-[#14181d]",
2331
+ gradientColor: "#facc15",
2332
+ borderGradient: "border-[#facc15]",
2333
+ borderGradientColor: "#facc15"
2334
+ },
2335
+ light: {
2336
+ bgGradient: "bg-[#fafafa]",
2337
+ gradientColor: "#f59e0b",
2338
+ borderGradient: "border-[#f59e0b]",
2339
+ borderGradientColor: "#f59e0b"
2340
+ }
2341
+ },
2342
+ info: {
2343
+ icon: "ic:outline-info",
2344
+ color: "text-blue-400",
2345
+ className: "text-blue-400",
2346
+ dark: {
2347
+ bgGradient: "bg-[#14181d]",
2348
+ gradientColor: "#60a5fa",
2349
+ borderGradient: "border-[#60a5fa]",
2350
+ borderGradientColor: "#f0f0f0"
2351
+ },
2352
+ light: {
2353
+ bgGradient: "bg-[#fafafa]",
2354
+ gradientColor: "#3b82f6",
2355
+ borderGradient: "border-[#3b82f6]",
2356
+ borderGradientColor: "#3b82f6"
2357
+ }
2358
+ },
2359
+ default: {
2360
+ icon: "ic:round-notifications",
2361
+ color: "text-gray-400",
2362
+ className: "text-gray-400",
2363
+ dark: {
2364
+ bgGradient: "bg-[#14181d]",
2365
+ gradientColor: "#9ca3af",
2366
+ borderGradient: "border-[#9ca3af]",
2367
+ borderGradientColor: "#9ca3af"
2368
+ },
2369
+ light: {
2370
+ bgGradient: "bg-[#fafafa]",
2371
+ gradientColor: "#6b7280",
2372
+ borderGradient: "border-[#6b7280]",
2373
+ borderGradientColor: "#6b7280"
2374
+ }
2375
+ }
2376
+ };
2377
+ var CloseButton = import_react11.default.memo(({ closeToast }) => {
2378
+ const { theme } = useTheme();
2379
+ const handleClick = (0, import_react11.useCallback)((e) => {
2380
+ e.preventDefault();
2381
+ e.stopPropagation();
2382
+ closeToast?.();
2383
+ }, [closeToast]);
2384
+ const getCloseButtonColor = () => {
2385
+ const actualTheme = theme === "system" ? window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light" : theme;
2386
+ return actualTheme === "dark" ? "#b4b4b4" : "#6b7280";
2387
+ };
2388
+ const getCloseButtonHoverColor = () => {
2389
+ const actualTheme = theme === "system" ? window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light" : theme;
2390
+ return actualTheme === "dark" ? "white" : "#374151";
2391
+ };
2392
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2393
+ import_react12.Icon,
2394
+ {
2395
+ icon: "vaadin:close",
2396
+ className: "flex items-center justify-center rounded-full relative z-10 flex-shrink-0 cursor-pointer transition-colors duration-200 drop-shadow-sm",
2397
+ onClick: handleClick,
2398
+ width: 14,
2399
+ height: 14,
2400
+ style: {
2401
+ color: getCloseButtonColor()
2402
+ },
2403
+ onMouseEnter: (e) => {
2404
+ e.currentTarget.style.color = getCloseButtonHoverColor();
2405
+ },
2406
+ onMouseLeave: (e) => {
2407
+ e.currentTarget.style.color = getCloseButtonColor();
2408
+ }
2409
+ }
2410
+ );
2411
+ });
2412
+ CloseButton.displayName = "CloseButton";
2413
+ var ToastContent = ({ type, title, message, component, closeToast }) => {
2414
+ const iconConfig = TOAST_ICONS[type];
2415
+ const { theme } = useTheme();
2416
+ const handleClose = (0, import_react11.useCallback)(() => {
2417
+ closeToast?.();
2418
+ }, [closeToast]);
2419
+ const getTextColor = () => {
2420
+ const actualTheme = theme === "system" ? window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light" : theme;
2421
+ return actualTheme === "dark" ? "white" : "#1f2937";
2422
+ };
2423
+ const getThemeConfig = () => {
2424
+ const actualTheme = theme === "system" ? window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light" : theme;
2425
+ return actualTheme === "dark" ? iconConfig.dark : iconConfig.light;
2426
+ };
2427
+ const themeConfig = getThemeConfig();
2428
+ const lightBaseBackgroundByType = {
2429
+ success: "#f0fdf4",
2430
+ error: "#fef2f2",
2431
+ warning: "#fffbeb",
2432
+ info: "#eff6ff",
2433
+ default: "#f9fafb"
2434
+ };
2435
+ if (component) {
2436
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: `flex items-start gap-3 !min-h-[90px] w-full backdrop-blur-md p-4 shadow-2xl overflow-hidden ${themeConfig.bgGradient}`, children: [
2437
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "flex-1 relative z-10", children: component }),
2438
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "relative z-10", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(CloseButton, { closeToast: handleClose }) })
2439
+ ] });
2440
+ }
2441
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: `flex items-start gap-3 !min-h-[90px] w-full backdrop-blur-md p-4 shadow-2xl relative overflow-hidden ${themeConfig.bgGradient}`, children: [
1965
2442
  /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1966
2443
  "div",
1967
2444
  {
1968
- className: "absolute left-0 top-0 w-full h-full rounded-md",
2445
+ className: "absolute left-0 top-0 w-full h-full rounded-xl",
1969
2446
  style: {
1970
- background: "#0f1419",
2447
+ background: theme === "dark" || theme === "system" && window.matchMedia("(prefers-color-scheme: dark)").matches ? "#0f1419" : lightBaseBackgroundByType[type],
1971
2448
  zIndex: -2
1972
2449
  }
1973
2450
  }
@@ -1975,9 +2452,9 @@ var LimitToastContainer = ({ message, onUpgrade, closeToast }) => {
1975
2452
  /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1976
2453
  "div",
1977
2454
  {
1978
- className: "absolute left-0 top-0 w-full h-full pointer-events-none rounded-md",
2455
+ className: "absolute left-0 top-0 w-full h-full pointer-events-none rounded-xl",
1979
2456
  style: {
1980
- background: `linear-gradient(135deg, rgba(168,85,247,0.3) 0%, rgba(168,85,247,0.2) 15%, #1A1A1A 30%)`,
2457
+ background: theme === "dark" || theme === "system" && window.matchMedia("(prefers-color-scheme: dark)").matches ? `linear-gradient(135deg, ${themeConfig.gradientColor}30 0%, ${themeConfig.gradientColor}20 15%, #14181df2 30%)` : `linear-gradient(135deg, ${themeConfig.gradientColor}20 0%, ${themeConfig.gradientColor}12 15%, #ffffff 30%)`,
1981
2458
  zIndex: -1
1982
2459
  }
1983
2460
  }
@@ -1985,443 +2462,246 @@ var LimitToastContainer = ({ message, onUpgrade, closeToast }) => {
1985
2462
  /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1986
2463
  "div",
1987
2464
  {
1988
- className: "absolute left-0 top-0 w-full h-full pointer-events-none rounded-md",
2465
+ className: "absolute left-0 top-0 w-full h-full pointer-events-none rounded-xl",
1989
2466
  style: {
1990
2467
  border: "2px solid transparent",
1991
- backgroundImage: `linear-gradient(135deg, rgba(168,85,247,0.6) 0%, rgba(168,85,247,0.4) 5%, transparent 22%)`,
2468
+ backgroundImage: theme === "dark" || theme === "system" && window.matchMedia("(prefers-color-scheme: dark)").matches ? `linear-gradient(135deg, ${themeConfig.borderGradientColor}60 0%, ${themeConfig.borderGradientColor}40 5%, transparent 22%)` : `linear-gradient(135deg, ${themeConfig.borderGradientColor}99 0%, ${themeConfig.borderGradientColor}66 5%, transparent 22%)`,
1992
2469
  backgroundOrigin: "border-box",
1993
2470
  backgroundClip: "border-box",
1994
- WebkitMask: "linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0)",
2471
+ WebkitMask: "linear-gradient(#ffffff 0 0) padding-box, linear-gradient(#ffffff 0 0)",
1995
2472
  WebkitMaskComposite: "xor",
1996
- mask: "linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0)",
1997
- maskComposite: "exclude"
2473
+ zIndex: 0
1998
2474
  }
1999
2475
  }
2000
2476
  ),
2001
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "absolute -top-16 -right-16 h-32 w-32 rounded-full bg-gradient-to-br from-purple-500/20 via-pink-500/10 to-transparent blur-3xl animate-pulse" }),
2002
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "absolute -bottom-16 -left-16 h-32 w-32 rounded-full bg-gradient-to-tr from-blue-500/10 to-transparent blur-2xl animate-pulse", style: { animationDelay: "1s" } }),
2003
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "relative z-10 flex items-start gap-4 p-4", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex flex-1 flex-col gap-3", children: [
2004
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex items-center justify-between", children: [
2005
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex items-center gap-2", children: [
2006
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "text-lg font-bold text-white", children: "Upgrade Required" }),
2007
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "px-2 py-0.5 text-xs font-bold bg-purple-500/20 text-purple-400 rounded-md border border-purple-500/30", children: "Premium" })
2008
- ] }),
2009
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2010
- ClayxButton,
2011
- {
2012
- onClick: closeToast,
2013
- isIconOnly: true,
2014
- size: "sm",
2015
- onMouseEnter: () => setCloseHover(true),
2016
- onMouseLeave: () => setCloseHover(false),
2017
- style: {
2018
- height: "1.5rem",
2019
- width: "1.5rem",
2020
- minWidth: "1.5rem",
2021
- borderRadius: "9999px",
2022
- backgroundColor: closeHover ? "rgba(255,255,255,0.1)" : "rgba(255,255,255,0.05)",
2023
- transition: "background-color 150ms ease",
2024
- cursor: "pointer"
2025
- },
2026
- children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react12.Icon, { icon: "iconamoon:close", className: "w-4 h-4 text-gray-400" })
2027
- }
2028
- )
2029
- ] }),
2030
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "text-sm text-gray-300 leading-relaxed", children: message }),
2031
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "mt-1 flex items-center gap-3", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2032
- ClayxButton,
2477
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "flex-shrink-0 mt-0.5 relative z-10", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: `w-7 h-7 backdrop-blur-sm rounded-full flex items-center justify-center ${theme === "dark" || theme === "system" && window.matchMedia("(prefers-color-scheme: dark)").matches ? "bg-white/10" : "bg-black/5"}`, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2478
+ import_react12.Icon,
2479
+ {
2480
+ icon: iconConfig.icon,
2481
+ width: 16,
2482
+ height: 16,
2483
+ className: iconConfig.color,
2484
+ style: {
2485
+ color: themeConfig.gradientColor
2486
+ }
2487
+ }
2488
+ ) }) }),
2489
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex flex-col gap-1 flex-1 relative z-10", children: [
2490
+ title && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2491
+ "div",
2033
2492
  {
2034
- onClick: () => {
2035
- onUpgrade();
2036
- closeToast?.();
2493
+ className: "text-[16px] font-semibold leading-tight drop-shadow-sm",
2494
+ style: {
2495
+ color: getTextColor(),
2496
+ backgroundClip: "text"
2037
2497
  },
2038
- onMouseEnter: () => setHover(true),
2039
- onMouseLeave: () => setHover(false),
2498
+ children: title
2499
+ }
2500
+ ),
2501
+ message && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2502
+ "div",
2503
+ {
2504
+ className: "text-[13px] font-normal leading-relaxed drop-shadow-sm",
2040
2505
  style: {
2041
- flex: 1,
2042
- color: "#ffffff",
2043
- fontWeight: 600,
2044
- cursor: "pointer",
2045
- transition: "all 300ms ease-in-out",
2046
- backgroundImage: hover ? "linear-gradient(to right, #9333ea, #db2777)" : "linear-gradient(to right, #a855f7, #ec4899)",
2047
- boxShadow: hover ? "0 10px 15px -3px rgba(168,85,247,0.3), 0 4px 6px -2px rgba(168,85,247,0.3)" : "none"
2506
+ color: getTextColor(),
2507
+ backgroundClip: "text"
2048
2508
  },
2049
- children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "flex items-center gap-2", children: [
2050
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react12.Icon, { icon: "solar:rocket-2-bold", className: "w-4 h-4" }),
2051
- "Upgrade Now"
2052
- ] })
2509
+ children: message
2053
2510
  }
2054
- ) })
2055
- ] }) })
2511
+ )
2512
+ ] }),
2513
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "relative z-10", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(CloseButton, { closeToast: handleClose }) })
2056
2514
  ] });
2057
2515
  };
2058
- function showLimitUpgradeToast(message, onUpgrade) {
2059
- GoeyToast.default({
2060
- render: (closeToast) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(LimitToastContainer, { message, onUpgrade, closeToast }),
2061
- options: {
2062
- autoClose: false
2063
- }
2064
- });
2065
- }
2066
-
2067
- // src/services/ai-workflow.ts
2068
- var AIWorkflowClient = class {
2069
- constructor(options = {}) {
2070
- this.baseUrl = options.baseUrl?.replace(/\/+$/, "") || "";
2071
- this.apiKey = options.apiKey;
2072
- this.headers = { "Content-Type": "application/json", ...options.headers || {} };
2073
- this.fetchImpl = options.fetchImpl || fetch.bind(globalThis);
2074
- }
2075
- buildHeaders(extra) {
2076
- const h = { ...this.headers, ...extra || {} };
2077
- if (this.apiKey && !h["Authorization"]) {
2078
- h["Authorization"] = `Bearer ${this.apiKey}`;
2079
- }
2080
- return h;
2081
- }
2082
- async safeJson(resp) {
2083
- try {
2084
- return await resp.json();
2085
- } catch (_e) {
2086
- return null;
2087
- }
2088
- }
2089
- /**
2090
- * 按 ID 执行工作流:POST {baseUrl}/workflow/{workflowId}/execute
2091
- * body: { input, options }
2092
- */
2093
- async executeWorkflow(workflowId, inputs, options) {
2094
- if (!this.baseUrl) {
2095
- throw new Error("AI workflow client requires a baseUrl (e.g. https://evoagentx-server.fly.dev)");
2096
- }
2097
- const url = `${this.baseUrl}/workflow/${workflowId}/execute`;
2098
- try {
2099
- const res = await this.fetchImpl(url, {
2100
- method: "POST",
2101
- headers: this.buildHeaders(),
2102
- body: JSON.stringify({ inputs, options })
2103
- });
2104
- const data = await this.safeJson(res);
2105
- if (!res.ok) {
2106
- return { success: false, error: data?.error || `HTTP ${res.status}` };
2107
- }
2108
- if (data && data.status && data.status === 4003) {
2109
- showLimitUpgradeToast(
2110
- "Your credits are exhausted. Please upgrade your plan to continue generating projects.",
2111
- () => window.open("https://clayx.ai/pricing", "_blank")
2112
- );
2113
- return null;
2114
- }
2115
- return data || { success: true };
2116
- } catch (error) {
2117
- return { success: false, error: error instanceof Error ? error.message : "Network error" };
2118
- }
2516
+ var defaultToastOptions = {
2517
+ position: "bottom-right",
2518
+ autoClose: 3e3,
2519
+ hideProgressBar: true,
2520
+ closeOnClick: false,
2521
+ pauseOnHover: true,
2522
+ draggable: true,
2523
+ pauseOnFocusLoss: false,
2524
+ transition: import_react_toastify2.Bounce
2525
+ };
2526
+ var getToastifyTheme = () => {
2527
+ if (typeof window !== "undefined") {
2528
+ const root = document.documentElement;
2529
+ if (root.classList.contains("dark")) return "dark";
2530
+ if (root.classList.contains("light")) return "light";
2531
+ return window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
2119
2532
  }
2533
+ return "light";
2120
2534
  };
2121
- function createAIWorkflowClient(options = {}) {
2122
- return new AIWorkflowClient(options);
2123
- }
2124
- var aiWorkflow = createAIWorkflowClient({ baseUrl: "https://evoagentx-server" });
2125
-
2126
- // src/services/request/index.ts
2127
- var import_axios = __toESM(require("axios"));
2128
- var Request = class {
2129
- constructor(config) {
2130
- this.abortControllers = /* @__PURE__ */ new Map();
2131
- this.instance = import_axios.default.create({
2132
- ...config,
2133
- withCredentials: true,
2134
- validateStatus: (status) => {
2135
- return status >= 200 && status < 300;
2136
- }
2137
- });
2138
- this.interceptors = config.interceptors;
2139
- this.instance.interceptors.request.use(
2140
- this.interceptors?.requestInterceptor,
2141
- this.interceptors?.requestInterceptorCatch
2142
- );
2143
- this.instance.interceptors.response.use(
2144
- this.interceptors?.responseInterceptor,
2145
- this.interceptors?.responseInterceptorCatch
2146
- );
2147
- this.instance.interceptors.request.use(
2148
- (config2) => {
2149
- return config2;
2150
- },
2151
- (err) => {
2152
- return Promise.reject(err);
2153
- }
2154
- );
2155
- this.instance.interceptors.response.use(
2156
- (res) => {
2157
- return res.data;
2535
+ var createToast = (type) => {
2536
+ return (params) => {
2537
+ const { title, message, component, options } = params;
2538
+ (0, import_react_toastify2.toast)(
2539
+ ({ closeToast }) => {
2540
+ if (params.render) return params.render(closeToast ?? (() => {
2541
+ }));
2542
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2543
+ ToastContent,
2544
+ {
2545
+ type,
2546
+ title,
2547
+ message: message || "",
2548
+ component,
2549
+ closeToast
2550
+ }
2551
+ );
2158
2552
  },
2159
- (err) => {
2160
- if (import_axios.default.isCancel(err)) {
2161
- return Promise.reject({
2162
- isCanceled: true,
2163
- message: "request canceled",
2164
- originalError: err
2165
- });
2166
- }
2167
- if (err.response?.data?.error) {
2168
- return Promise.reject(err.response.data.error);
2169
- }
2170
- return Promise.reject(err);
2553
+ {
2554
+ ...defaultToastOptions,
2555
+ ...options,
2556
+ theme: getToastifyTheme(),
2557
+ className: "!p-0 !shadow-none !rounded-xl",
2558
+ style: { padding: 0, borderRadius: "0.75rem" }
2171
2559
  }
2172
2560
  );
2173
- }
2174
- cancelRequest(url) {
2175
- this.abortControllers.forEach((controller, key) => {
2176
- if (key.includes(url)) {
2177
- controller.abort();
2178
- this.abortControllers.delete(key);
2179
- }
2180
- });
2181
- }
2182
- cancelAllRequests() {
2183
- this.abortControllers.forEach((controller) => {
2184
- controller.abort();
2185
- });
2186
- this.abortControllers.clear();
2187
- }
2188
- request(config) {
2189
- const controller = new AbortController();
2190
- const url = config.url || "";
2191
- const method = config.method || "GET";
2192
- const key = `${method}:${url}`;
2193
- this.abortControllers.set(key, controller);
2194
- config.signal = controller.signal;
2195
- return new Promise((resolve, reject) => {
2196
- if (config.interceptors?.requestInterceptor) {
2197
- config = config.interceptors.requestInterceptor(config);
2198
- }
2199
- this.instance.request(config).then((res) => {
2200
- this.abortControllers.delete(key);
2201
- if (config.interceptors?.responseInterceptor) {
2202
- res = config.interceptors.responseInterceptor(res);
2203
- }
2204
- resolve(res);
2205
- }).catch((err) => {
2206
- this.abortControllers.delete(key);
2207
- reject(err);
2208
- });
2209
- });
2210
- }
2211
- get(config) {
2212
- return this.request({ ...config, method: "GET" });
2213
- }
2214
- post(config) {
2215
- return this.request({ ...config, method: "POST" });
2216
- }
2217
- delete(config) {
2218
- return this.request({ ...config, method: "DELETE" });
2219
- }
2220
- put(config) {
2221
- return this.request({ ...config, method: "PUT" });
2222
- }
2223
- patch(config) {
2224
- return this.request({ ...config, method: "PATCH" });
2225
- }
2561
+ };
2562
+ };
2563
+ var ClayxToast = {
2564
+ success: createToast("success"),
2565
+ error: createToast("error"),
2566
+ warning: createToast("warning"),
2567
+ info: createToast("info"),
2568
+ default: createToast("default")
2226
2569
  };
2227
- var request_default = Request;
2228
2570
 
2229
- // src/services/ai-workflow-axios.ts
2230
- function createAIWorkflowClientAxios(options = {}) {
2231
- const basePath = options.basePath ?? "/api";
2232
- const baseUrl = (options.baseUrl || "https://evoagentx-server.fly.dev").replace(/\/+$/, "");
2233
- const baseAPI = `${baseUrl}${basePath.startsWith("/") ? "" : "/"}${basePath}`.replace(/\/+$/, "");
2234
- const client = options.requestInstance || new request_default({
2235
- baseURL: baseAPI,
2236
- timeout: options.timeout ?? 6e4,
2237
- interceptors: {
2238
- requestInterceptor: (config) => {
2239
- config.headers = config.headers || {};
2240
- if (options.apiKey && !config.headers["Authorization"]) {
2241
- config.headers["Authorization"] = `Bearer ${options.apiKey}`;
2571
+ // src/components/ui/LimitUpgradeToast.tsx
2572
+ var import_jsx_runtime13 = require("react/jsx-runtime");
2573
+ var LimitToastContainer = ({ message, onUpgrade, closeToast }) => {
2574
+ const [hover, setHover] = import_react13.default.useState(false);
2575
+ const [closeHover, setCloseHover] = import_react13.default.useState(false);
2576
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "relative w-full max-w-[420px] overflow-hidden rounded-md bg-gradient-to-br from-[#1A1A1A] via-[#151515] to-[#1A1A1A] shadow-[0_20px_60px_rgba(168,85,247,0.2)] backdrop-blur-sm", children: [
2577
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2578
+ "div",
2579
+ {
2580
+ className: "absolute left-0 top-0 w-full h-full rounded-md",
2581
+ style: {
2582
+ background: "#0f1419",
2583
+ zIndex: -2
2584
+ }
2585
+ }
2586
+ ),
2587
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2588
+ "div",
2589
+ {
2590
+ className: "absolute left-0 top-0 w-full h-full pointer-events-none rounded-md",
2591
+ style: {
2592
+ background: `linear-gradient(135deg, rgba(168,85,247,0.3) 0%, rgba(168,85,247,0.2) 15%, #1A1A1A 30%)`,
2593
+ zIndex: -1
2242
2594
  }
2243
- if (options.headers) {
2244
- config.headers = { ...config.headers || {}, ...options.headers };
2595
+ }
2596
+ ),
2597
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2598
+ "div",
2599
+ {
2600
+ className: "absolute left-0 top-0 w-full h-full pointer-events-none rounded-md",
2601
+ style: {
2602
+ border: "2px solid transparent",
2603
+ backgroundImage: `linear-gradient(135deg, rgba(168,85,247,0.6) 0%, rgba(168,85,247,0.4) 5%, transparent 22%)`,
2604
+ backgroundOrigin: "border-box",
2605
+ backgroundClip: "border-box",
2606
+ WebkitMask: "linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0)",
2607
+ WebkitMaskComposite: "xor",
2608
+ mask: "linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0)",
2609
+ maskComposite: "exclude"
2245
2610
  }
2246
- return config;
2247
- },
2248
- requestInterceptorCatch: (err) => Promise.reject(err),
2249
- responseInterceptor: (res) => res,
2250
- responseInterceptorCatch: (err) => Promise.reject(err)
2611
+ }
2612
+ ),
2613
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "absolute -top-16 -right-16 h-32 w-32 rounded-full bg-gradient-to-br from-purple-500/20 via-pink-500/10 to-transparent blur-3xl animate-pulse" }),
2614
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "absolute -bottom-16 -left-16 h-32 w-32 rounded-full bg-gradient-to-tr from-blue-500/10 to-transparent blur-2xl animate-pulse", style: { animationDelay: "1s" } }),
2615
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "relative z-10 flex items-start gap-4 p-4", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex flex-1 flex-col gap-3", children: [
2616
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center justify-between", children: [
2617
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center gap-2", children: [
2618
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "text-lg font-bold text-white", children: "Upgrade Required" }),
2619
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "px-2 py-0.5 text-xs font-bold bg-purple-500/20 text-purple-400 rounded-md border border-purple-500/30", children: "Premium" })
2620
+ ] }),
2621
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2622
+ ClayxButton,
2623
+ {
2624
+ onClick: closeToast,
2625
+ isIconOnly: true,
2626
+ size: "sm",
2627
+ onMouseEnter: () => setCloseHover(true),
2628
+ onMouseLeave: () => setCloseHover(false),
2629
+ style: {
2630
+ height: "1.5rem",
2631
+ width: "1.5rem",
2632
+ minWidth: "1.5rem",
2633
+ borderRadius: "9999px",
2634
+ backgroundColor: closeHover ? "rgba(255,255,255,0.1)" : "rgba(255,255,255,0.05)",
2635
+ transition: "background-color 150ms ease",
2636
+ cursor: "pointer"
2637
+ },
2638
+ children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react14.Icon, { icon: "iconamoon:close", className: "w-4 h-4 text-gray-400" })
2639
+ }
2640
+ )
2641
+ ] }),
2642
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "text-sm text-gray-300 leading-relaxed", children: message }),
2643
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "mt-1 flex items-center gap-3", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2644
+ ClayxButton,
2645
+ {
2646
+ onClick: () => {
2647
+ onUpgrade();
2648
+ closeToast?.();
2649
+ },
2650
+ onMouseEnter: () => setHover(true),
2651
+ onMouseLeave: () => setHover(false),
2652
+ style: {
2653
+ flex: 1,
2654
+ color: "#ffffff",
2655
+ fontWeight: 600,
2656
+ cursor: "pointer",
2657
+ transition: "all 300ms ease-in-out",
2658
+ backgroundImage: hover ? "linear-gradient(to right, #9333ea, #db2777)" : "linear-gradient(to right, #a855f7, #ec4899)",
2659
+ boxShadow: hover ? "0 10px 15px -3px rgba(168,85,247,0.3), 0 4px 6px -2px rgba(168,85,247,0.3)" : "none"
2660
+ },
2661
+ children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { className: "flex items-center gap-2", children: [
2662
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react14.Icon, { icon: "solar:rocket-2-bold", className: "w-4 h-4" }),
2663
+ "Upgrade Now"
2664
+ ] })
2665
+ }
2666
+ ) })
2667
+ ] }) })
2668
+ ] });
2669
+ };
2670
+ function showLimitUpgradeToast(message, onUpgrade) {
2671
+ ClayxToast.default({
2672
+ render: (closeToast) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(LimitToastContainer, { message, onUpgrade, closeToast }),
2673
+ options: {
2674
+ autoClose: false
2251
2675
  }
2252
2676
  });
2253
- return {
2254
- async executeWorkflow(workflowId, inputs, opts) {
2255
- const url = `${baseUrl}/workflow/${workflowId}/execute`;
2256
- const data = await client.post({ url, data: { inputs, options: opts } });
2257
- return data;
2258
- }
2259
- };
2260
2677
  }
2261
2678
 
2262
- // src/services/artifact-types.ts
2263
- function canAccessArtifact(a, ctx = {}) {
2264
- if (!a) return false;
2265
- if (a.visibility === "public") return true;
2266
- if (a.visibility === "project") {
2267
- if (ctx.projectId && a.projectId && ctx.projectId === a.projectId) return true;
2268
- if (ctx.tokenScopes && ctx.tokenScopes.includes("project:read")) return true;
2269
- return false;
2270
- }
2271
- if (a.visibility === "private") {
2272
- if (ctx.userId && a.ownerId && ctx.userId === a.ownerId) return true;
2273
- if (ctx.tokenScopes && (ctx.tokenScopes.includes("artifact:read:all") || ctx.tokenScopes.includes("admin"))) return true;
2274
- return false;
2275
- }
2276
- if (a.visibility === "shared") {
2277
- if (ctx.userId && a.sharedWith && a.sharedWith.includes(ctx.userId)) return true;
2278
- if (ctx.tokenScopes && (ctx.tokenScopes.includes("artifact:read:all") || ctx.tokenScopes.includes("admin"))) return true;
2279
- return false;
2679
+ // src/services/limit-exceeded.ts
2680
+ init_config();
2681
+ var DEFAULT_LIMIT_EXCEEDED_MESSAGE = "Your credits are exhausted. Please upgrade your plan to continue generating projects.";
2682
+ function handleLimitExceeded(context, options) {
2683
+ options?.onLimitExceeded?.(context);
2684
+ if (options?.showUpgradeToast === false) {
2685
+ return;
2280
2686
  }
2281
- return false;
2282
- }
2283
-
2284
- // src/services/artifacts-client.ts
2285
- function createArtifactsClient(req) {
2286
- return {
2287
- async create(input) {
2288
- return await req.post({ url: "/artifacts", data: input });
2289
- },
2290
- async list(query) {
2291
- return await req.get({ url: "/artifacts", params: query });
2292
- },
2293
- async get(id) {
2294
- return await req.get({ url: `/artifacts/${encodeURIComponent(id)}` });
2295
- },
2296
- async setVisibility(id, visibility) {
2297
- await req.patch({ url: `/artifacts/${encodeURIComponent(id)}/visibility`, data: { visibility } });
2298
- },
2299
- async delete(id) {
2300
- await req.delete({ url: `/artifacts/${encodeURIComponent(id)}` });
2301
- },
2302
- // convenience local check (server is authoritative)
2303
- canAccessLocal(a, ctx) {
2304
- if (!a) return false;
2305
- if (a.visibility === "public") return true;
2306
- if (a.visibility === "project") return Boolean(ctx.projectId && a.projectId && ctx.projectId === a.projectId);
2307
- if (a.visibility === "private") return Boolean(ctx.userId && a.ownerId && ctx.userId === a.ownerId);
2308
- if (a.visibility === "shared") return Boolean(ctx.userId && a.sharedWith && a.sharedWith.includes(ctx.userId));
2309
- return false;
2310
- }
2311
- };
2687
+ const upgradeUrl = options?.upgradeUrl || `${getEnvs().AUTH_ROOT_VALUE}/price`;
2688
+ showLimitUpgradeToast(
2689
+ context.message || DEFAULT_LIMIT_EXCEEDED_MESSAGE,
2690
+ () => window.open(upgradeUrl, "_blank")
2691
+ );
2312
2692
  }
2313
-
2314
- // src/services/upload-client.ts
2315
- function createUploadClient(req, projectId) {
2316
- const uploadUrl = projectId ? `/entities/apps/${projectId}/files` : "/files";
2693
+ function mergeLimitExceededOptions(base, override) {
2694
+ if (!base && !override) {
2695
+ return void 0;
2696
+ }
2317
2697
  return {
2318
- /**
2319
- * 上传单个文件
2320
- *
2321
- * @example
2322
- * ```typescript
2323
- * const { url } = await client.upload.file(imageFile)
2324
- * console.log('文件地址:', url)
2325
- * ```
2326
- */
2327
- async file(file, options) {
2328
- const formData = new FormData();
2329
- if (typeof file === "string") {
2330
- if (file.startsWith("data:")) {
2331
- const response2 = await fetch(file);
2332
- const blob = await response2.blob();
2333
- formData.append("file", blob, "upload.bin");
2334
- } else {
2335
- formData.append("fileUrl", file);
2336
- }
2337
- } else if (file instanceof File) {
2338
- formData.append("file", file, file.name);
2339
- } else {
2340
- formData.append("file", file, "upload.bin");
2341
- }
2342
- if (options?.metadata) {
2343
- formData.append("metadata", JSON.stringify(options.metadata));
2344
- }
2345
- const response = await req.post({
2346
- url: uploadUrl,
2347
- data: formData,
2348
- signal: options?.signal
2349
- });
2350
- return {
2351
- url: response.data.publicUrl
2352
- };
2353
- },
2354
- /**
2355
- * 上传图片(快捷方法,专为 AI 设计)
2356
- *
2357
- * @example
2358
- * ```typescript
2359
- * const { url } = await client.upload.image(imageFile)
2360
- * ```
2361
- */
2362
- async image(file) {
2363
- const result = await this.file(file);
2364
- return { url: result.url };
2365
- },
2366
- /**
2367
- * 批量上传文件
2368
- *
2369
- * @example
2370
- * ```typescript
2371
- * const result = await client.upload.batch({
2372
- * files: [file1, file2, file3],
2373
- * concurrent: 3,
2374
- * onProgress: (completed, total) => {
2375
- * console.log(`${completed}/${total}`)
2376
- * }
2377
- * })
2378
- * ```
2379
- */
2380
- async batch(options) {
2381
- const { files, concurrent = 3, onProgress, onFileComplete, signal } = options;
2382
- const success = [];
2383
- const failed = [];
2384
- let completed = 0;
2385
- for (let i = 0; i < files.length; i += concurrent) {
2386
- if (signal?.aborted) break;
2387
- const batch = files.slice(i, Math.min(i + concurrent, files.length));
2388
- const promises = batch.map(async (file, batchIndex) => {
2389
- const globalIndex = i + batchIndex;
2390
- try {
2391
- const result = await this.file(file, { signal });
2392
- success.push(result);
2393
- if (onFileComplete) {
2394
- onFileComplete(result, globalIndex);
2395
- }
2396
- } catch (error) {
2397
- const errorMsg = error instanceof Error ? error.message : String(error);
2398
- failed.push({ index: globalIndex, error: errorMsg });
2399
- if (onFileComplete) {
2400
- onFileComplete(
2401
- error instanceof Error ? error : new Error(errorMsg),
2402
- globalIndex
2403
- );
2404
- }
2405
- } finally {
2406
- completed++;
2407
- if (onProgress) {
2408
- onProgress(completed, files.length);
2409
- }
2410
- }
2411
- });
2412
- await Promise.all(promises);
2413
- }
2414
- return {
2415
- success,
2416
- failed,
2417
- total: files.length
2418
- };
2419
- }
2698
+ ...base,
2699
+ ...override,
2700
+ onLimitExceeded: override?.onLimitExceeded ?? base?.onLimitExceeded
2420
2701
  };
2421
2702
  }
2422
2703
 
2423
2704
  // src/services/sse-executor.ts
2424
- init_config();
2425
2705
  async function executeSSEWorkflow(request, options = {}) {
2426
2706
  const startTime = Date.now();
2427
2707
  const result = {
@@ -2512,7 +2792,7 @@ async function executeSSEWorkflow(request, options = {}) {
2512
2792
  if (errorData.log_type === "execution_display_error") {
2513
2793
  const errorContent = errorData.content;
2514
2794
  const displayMessage = errorContent || "Workflow execution failed";
2515
- GoeyToast.error({
2795
+ ClayxToast.error({
2516
2796
  title: "Execution Error",
2517
2797
  message: displayMessage
2518
2798
  });
@@ -2522,11 +2802,16 @@ async function executeSSEWorkflow(request, options = {}) {
2522
2802
  options.onStreamContent(rawEvent.delta);
2523
2803
  }
2524
2804
  if (rawEvent.type === "key_limit_exceed") {
2525
- const errorMsg = rawEvent.data.content;
2805
+ const errorMsg = rawEvent.data?.content || DEFAULT_LIMIT_EXCEEDED_MESSAGE;
2526
2806
  result.errors.push(errorMsg);
2527
- showLimitUpgradeToast(
2528
- "Your credits are exhausted. Please upgrade your plan to continue generating projects.",
2529
- () => window.open(`${getEnvs().AUTH_ROOT_VALUE}/price`, "_blank")
2807
+ handleLimitExceeded(
2808
+ {
2809
+ source: "sse-executor",
2810
+ message: errorMsg,
2811
+ eventType: rawEvent.type,
2812
+ rawData: rawEvent.data
2813
+ },
2814
+ options.limitExceeded
2530
2815
  );
2531
2816
  if (options.onError) {
2532
2817
  options.onError(new Error(errorMsg));
@@ -2737,7 +3022,7 @@ function createEventIterable(streamFactory, config) {
2737
3022
  };
2738
3023
  }
2739
3024
  function createSSEClient(config) {
2740
- const { baseUrl, projectId, getAuthToken } = config;
3025
+ const { baseUrl, projectId, getAuthToken, limitExceeded } = config;
2741
3026
  const stream = (streamConfig) => {
2742
3027
  const { signal: externalSignal, ...callbacks } = streamConfig;
2743
3028
  const request = resolveRequest(baseUrl, projectId, streamConfig);
@@ -2753,7 +3038,11 @@ function createSSEClient(config) {
2753
3038
  {
2754
3039
  ...callbacks,
2755
3040
  authToken,
2756
- signal: controller.signal
3041
+ signal: controller.signal,
3042
+ limitExceeded: mergeLimitExceededOptions(
3043
+ limitExceeded,
3044
+ streamConfig.limitExceeded
3045
+ )
2757
3046
  }
2758
3047
  ).finally(() => {
2759
3048
  controller.cleanup();
@@ -2929,6 +3218,19 @@ async function executeWorkflowStreamPost(baseUrl, projectId, workflowId, request
2929
3218
  break;
2930
3219
  case "error":
2931
3220
  throw new Error(event.message || "Workflow execution failed");
3221
+ case "key_limit_exceed": {
3222
+ const errorMessage = event?.data?.content || event.message || DEFAULT_LIMIT_EXCEEDED_MESSAGE;
3223
+ handleLimitExceeded(
3224
+ {
3225
+ source: "sse-executor",
3226
+ message: errorMessage,
3227
+ eventType: event.type,
3228
+ rawData: event.data
3229
+ },
3230
+ options.limitExceeded
3231
+ );
3232
+ throw new Error(errorMessage);
3233
+ }
2932
3234
  }
2933
3235
  } catch (err) {
2934
3236
  console.error("Failed to parse SSE event:", err);
@@ -2947,12 +3249,12 @@ async function executeWorkflowStreamPost(baseUrl, projectId, workflowId, request
2947
3249
  }
2948
3250
 
2949
3251
  // src/services/workflow-executor.ts
2950
- init_config();
2951
3252
  var WorkflowExecutor = class {
2952
- constructor(baseUrl, projectId, authToken) {
3253
+ constructor(baseUrl, projectId, authToken, limitExceeded) {
2953
3254
  this.baseUrl = baseUrl.replace(/\/$/, "");
2954
3255
  this.projectId = projectId;
2955
3256
  this.authToken = authToken;
3257
+ this.limitExceeded = limitExceeded;
2956
3258
  }
2957
3259
  /**
2958
3260
  * 执行工作流 (SSE 模式)
@@ -3002,6 +3304,10 @@ var WorkflowExecutor = class {
3002
3304
  errors: []
3003
3305
  };
3004
3306
  let streamContent = "";
3307
+ const limitExceededOptions = mergeLimitExceededOptions(
3308
+ this.limitExceeded,
3309
+ options?.limitExceeded
3310
+ );
3005
3311
  try {
3006
3312
  const response = await fetch(url, {
3007
3313
  method: "POST",
@@ -3054,11 +3360,16 @@ var WorkflowExecutor = class {
3054
3360
  }
3055
3361
  }
3056
3362
  } else if (event.type === "key_limit_exceed") {
3057
- const errorMsg = event.data?.content;
3363
+ const errorMsg = event.data?.content || DEFAULT_LIMIT_EXCEEDED_MESSAGE;
3058
3364
  result.errors.push(errorMsg);
3059
- showLimitUpgradeToast(
3060
- "Your credits are exhausted. Please upgrade your plan to continue generating projects.",
3061
- () => window.open(`${getEnvs().AUTH_ROOT_VALUE}/price`, "_blank")
3365
+ handleLimitExceeded(
3366
+ {
3367
+ source: "workflow-executor-sse",
3368
+ message: errorMsg,
3369
+ eventType: event.type,
3370
+ rawData: event.data
3371
+ },
3372
+ limitExceededOptions
3062
3373
  );
3063
3374
  if (options?.onError) {
3064
3375
  options.onError(new Error(errorMsg));
@@ -3142,6 +3453,17 @@ var WorkflowExecutor = class {
3142
3453
  body: JSON.stringify({ inputs })
3143
3454
  });
3144
3455
  const data = await response.json();
3456
+ if (data && data.status === 4003) {
3457
+ handleLimitExceeded(
3458
+ {
3459
+ source: "workflow-executor-rest",
3460
+ message: data?.error || data?.message || DEFAULT_LIMIT_EXCEEDED_MESSAGE,
3461
+ status: response.status,
3462
+ rawData: data
3463
+ },
3464
+ this.limitExceeded
3465
+ );
3466
+ }
3145
3467
  return {
3146
3468
  status: response.status,
3147
3469
  data
@@ -3223,14 +3545,6 @@ function createClient(opts) {
3223
3545
  },
3224
3546
  requestInterceptorCatch: (err) => Promise.reject(err),
3225
3547
  responseInterceptor: (res) => {
3226
- const data = res.data;
3227
- if (data && data.status && data.status === 4003) {
3228
- showLimitUpgradeToast(
3229
- "Your credits are exhausted. Please upgrade your plan to continue generating projects.",
3230
- () => window.open(`${getEnvs().AUTH_ROOT_VALUE}/price`, "_blank")
3231
- );
3232
- return res;
3233
- }
3234
3548
  return res;
3235
3549
  },
3236
3550
  responseInterceptorCatch: (err) => Promise.reject(err)
@@ -3338,7 +3652,8 @@ function createClient(opts) {
3338
3652
  void fetchExternalToken();
3339
3653
  }
3340
3654
  return token ?? cachedExternalToken ?? getToken() ?? null;
3341
- }
3655
+ },
3656
+ limitExceeded: opts.limitExceeded
3342
3657
  });
3343
3658
  const assignMethod = (config, method) => method ? { ...config, method } : config;
3344
3659
  function createMethodInvoker(invoker) {
@@ -3400,7 +3715,8 @@ function createClient(opts) {
3400
3715
  const executor = new WorkflowExecutor(
3401
3716
  actualAiBaseUrl,
3402
3717
  opts.projectId,
3403
- getCachedOrGlobalToken() ?? void 0
3718
+ getCachedOrGlobalToken() ?? void 0,
3719
+ opts.limitExceeded
3404
3720
  );
3405
3721
  return {
3406
3722
  executeSse: (inputs, options) => {
@@ -3618,11 +3934,11 @@ function createClient(opts) {
3618
3934
  }
3619
3935
 
3620
3936
  // src/hooks/use-mobile.ts
3621
- var React8 = __toESM(require("react"));
3937
+ var React9 = __toESM(require("react"));
3622
3938
  var MOBILE_BREAKPOINT = 768;
3623
3939
  function useIsMobile() {
3624
- const [isMobile, setIsMobile] = React8.useState(void 0);
3625
- React8.useEffect(() => {
3940
+ const [isMobile, setIsMobile] = React9.useState(void 0);
3941
+ React9.useEffect(() => {
3626
3942
  const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
3627
3943
  const onChange = () => {
3628
3944
  setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
@@ -3635,10 +3951,10 @@ function useIsMobile() {
3635
3951
  }
3636
3952
 
3637
3953
  // src/hooks/use-debounce.ts
3638
- var import_react13 = require("react");
3954
+ var import_react15 = require("react");
3639
3955
  function useDebounce(value, delay) {
3640
- const [debouncedValue, setDebouncedValue] = (0, import_react13.useState)(value);
3641
- (0, import_react13.useEffect)(() => {
3956
+ const [debouncedValue, setDebouncedValue] = (0, import_react15.useState)(value);
3957
+ (0, import_react15.useEffect)(() => {
3642
3958
  const handler = setTimeout(() => {
3643
3959
  setDebouncedValue(value);
3644
3960
  }, delay);
@@ -3650,9 +3966,9 @@ function useDebounce(value, delay) {
3650
3966
  }
3651
3967
 
3652
3968
  // src/hooks/use-workflow-stream.ts
3653
- var import_react14 = require("react");
3969
+ var import_react16 = require("react");
3654
3970
  function useWorkflowStream() {
3655
- const [state, setState] = (0, import_react14.useState)({
3971
+ const [state, setState] = (0, import_react16.useState)({
3656
3972
  loading: false,
3657
3973
  progress: 0,
3658
3974
  streamContent: "",
@@ -3660,8 +3976,8 @@ function useWorkflowStream() {
3660
3976
  result: null,
3661
3977
  error: null
3662
3978
  });
3663
- const abortControllerRef = (0, import_react14.useRef)(null);
3664
- const execute = (0, import_react14.useCallback)(async (executeWorkflowStream, workflowId, inputs) => {
3979
+ const abortControllerRef = (0, import_react16.useRef)(null);
3980
+ const execute = (0, import_react16.useCallback)(async (executeWorkflowStream, workflowId, inputs) => {
3665
3981
  setState({
3666
3982
  loading: true,
3667
3983
  progress: 0,
@@ -3714,7 +4030,7 @@ function useWorkflowStream() {
3714
4030
  throw error;
3715
4031
  }
3716
4032
  }, []);
3717
- const cancel = (0, import_react14.useCallback)(() => {
4033
+ const cancel = (0, import_react16.useCallback)(() => {
3718
4034
  if (abortControllerRef.current) {
3719
4035
  abortControllerRef.current.abort();
3720
4036
  setState((prev) => ({
@@ -3724,7 +4040,7 @@ function useWorkflowStream() {
3724
4040
  }));
3725
4041
  }
3726
4042
  }, []);
3727
- const reset = (0, import_react14.useCallback)(() => {
4043
+ const reset = (0, import_react16.useCallback)(() => {
3728
4044
  setState({
3729
4045
  loading: false,
3730
4046
  progress: 0,
@@ -4030,13 +4346,14 @@ var elementSelector = {
4030
4346
  0 && (module.exports = {
4031
4347
  AUTH_TOKEN_KEY,
4032
4348
  ClayxButton,
4349
+ ClayxToast,
4350
+ DEFAULT_LIMIT_EXCEEDED_MESSAGE,
4033
4351
  DefaultErrorFallback,
4034
4352
  ElementSelector,
4035
4353
  ElementSelectorProvider,
4036
4354
  ErrorBoundary,
4037
4355
  FloatingButton,
4038
4356
  GlobalToastContainer,
4039
- GoeyToast,
4040
4357
  HowOneProvider,
4041
4358
  Loading,
4042
4359
  LoadingSpinner,
@@ -4060,11 +4377,13 @@ var elementSelector = {
4060
4377
  getEnvs,
4061
4378
  getGlobalEnvironment,
4062
4379
  getToken,
4380
+ handleLimitExceeded,
4063
4381
  howone,
4064
4382
  iframeNavigation,
4065
4383
  initIframeNavigation,
4066
4384
  isTokenValid,
4067
4385
  loginWithEmailCode,
4386
+ mergeLimitExceededOptions,
4068
4387
  onAuthStateChanged,
4069
4388
  parseUserFromToken,
4070
4389
  sendElementSelectionToParent,