@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.mjs CHANGED
@@ -154,7 +154,20 @@ function decodeJwtPayload(token) {
154
154
  if (pad === 2) base64 += "==";
155
155
  else if (pad === 3) base64 += "=";
156
156
  else if (pad !== 0) return null;
157
- const json = atob(base64);
157
+ const binary = atob(base64);
158
+ let json = binary;
159
+ try {
160
+ if (typeof TextDecoder !== "undefined") {
161
+ const bytes = Uint8Array.from(binary, (ch) => ch.charCodeAt(0));
162
+ json = new TextDecoder("utf-8", { fatal: false }).decode(bytes);
163
+ } else {
164
+ json = decodeURIComponent(
165
+ binary.split("").map((ch) => `%${ch.charCodeAt(0).toString(16).padStart(2, "0")}`).join("")
166
+ );
167
+ }
168
+ } catch {
169
+ json = binary;
170
+ }
158
171
  return JSON.parse(json);
159
172
  } catch {
160
173
  return null;
@@ -747,162 +760,511 @@ function getCodeStatus(email) {
747
760
  return unifiedAuth.getCodeStatus(email);
748
761
  }
749
762
 
750
- // src/components/auth/LoginForm.tsx
751
- import { useState as useState2, useEffect as useEffect2 } from "react";
752
- import { Icon as Icon2 } from "@iconify/react";
753
- import { Loader2 } from "lucide-react";
754
- import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
755
- var LoginForm = ({
756
- onLoginSuccess,
757
- appName = "AI Application Platform",
758
- className = ""
759
- }) => {
760
- const [email, setEmail] = useState2("");
761
- const [code, setCode] = useState2("");
762
- const [validationErrors, setValidationErrors] = useState2({});
763
- const [isAnyLoading, setIsAnyLoading] = useState2(false);
764
- const [codeSent, setCodeSent] = useState2(false);
765
- const [loginError, setLoginError] = useState2(null);
766
- const googleLogin = async () => {
767
- };
768
- const githubLogin = async () => {
769
- };
770
- const sendEmailCode = async (email2) => {
771
- setCodeSent(true);
772
- };
773
- const loginWithEmail = async (email2, code2) => {
774
- if (onLoginSuccess) onLoginSuccess();
775
- };
776
- const clearError = () => {
777
- setLoginError(null);
778
- setValidationErrors({});
779
- };
780
- useEffect2(() => {
781
- if (loginError) {
782
- try {
783
- const errorObj = JSON.parse(loginError);
784
- const newErrors = {};
785
- if (errorObj.code === 429) {
786
- newErrors.form = errorObj.msg || "\u8BF7\u6C42\u8FC7\u4E8E\u9891\u7E41\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5";
787
- } else if (errorObj.data?.code === 401 && errorObj.data?.message) {
788
- if (codeSent) {
789
- newErrors.code = errorObj.data.message;
790
- } else {
791
- newErrors.form = errorObj.data.message;
792
- }
793
- } else if (errorObj.msg) {
794
- newErrors.form = errorObj.msg;
795
- } else if (errorObj.data?.message) {
796
- newErrors.form = errorObj.data.message;
797
- } else {
798
- newErrors.form = "\u53D1\u751F\u672A\u77E5\u9519\u8BEF\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5";
799
- }
800
- setValidationErrors(newErrors);
801
- } catch (e) {
802
- setValidationErrors({ form: loginError });
763
+ // src/services/ai-workflow.ts
764
+ var AIWorkflowClient = class {
765
+ constructor(options = {}) {
766
+ this.baseUrl = options.baseUrl?.replace(/\/+$/, "") || "";
767
+ this.apiKey = options.apiKey;
768
+ this.headers = { "Content-Type": "application/json", ...options.headers || {} };
769
+ this.fetchImpl = options.fetchImpl || fetch.bind(globalThis);
770
+ }
771
+ buildHeaders(extra) {
772
+ const h = { ...this.headers, ...extra || {} };
773
+ if (this.apiKey && !h["Authorization"]) {
774
+ h["Authorization"] = `Bearer ${this.apiKey}`;
775
+ }
776
+ return h;
777
+ }
778
+ async safeJson(resp) {
779
+ try {
780
+ return await resp.json();
781
+ } catch (_e) {
782
+ return null;
783
+ }
784
+ }
785
+ /**
786
+ * ID 执行工作流:POST {baseUrl}/workflow/{workflowId}/execute
787
+ * body: { input, options }
788
+ */
789
+ async executeWorkflow(workflowId, inputs, options) {
790
+ if (!this.baseUrl) {
791
+ throw new Error("AI workflow client requires a baseUrl (e.g. https://evoagentx-server.fly.dev)");
792
+ }
793
+ const url = `${this.baseUrl}/workflow/${workflowId}/execute`;
794
+ try {
795
+ const res = await this.fetchImpl(url, {
796
+ method: "POST",
797
+ headers: this.buildHeaders(),
798
+ body: JSON.stringify({ inputs, options })
799
+ });
800
+ const data = await this.safeJson(res);
801
+ if (!res.ok) {
802
+ return { success: false, error: data?.error || `HTTP ${res.status}` };
803
803
  }
804
- const timer = setTimeout(() => {
805
- clearError();
806
- }, 8e3);
807
- return () => clearTimeout(timer);
804
+ return data || { success: true };
805
+ } catch (error) {
806
+ return { success: false, error: error instanceof Error ? error.message : "Network error" };
808
807
  }
809
- }, [loginError, codeSent]);
810
- const handleSubmit = async (e) => {
811
- e.preventDefault();
812
- const formData = new FormData(e.currentTarget);
813
- setValidationErrors({});
814
- if (!codeSent) {
815
- const emailValue = formData.get("email");
816
- if (!emailValue) {
817
- setValidationErrors({ email: "Please enter your email address" });
818
- return;
808
+ }
809
+ };
810
+ function createAIWorkflowClient(options = {}) {
811
+ return new AIWorkflowClient(options);
812
+ }
813
+ var aiWorkflow = createAIWorkflowClient({ baseUrl: "https://evoagentx-server" });
814
+
815
+ // src/services/request/index.ts
816
+ import axios from "axios";
817
+ var Request = class {
818
+ constructor(config) {
819
+ this.abortControllers = /* @__PURE__ */ new Map();
820
+ this.instance = axios.create({
821
+ ...config,
822
+ withCredentials: true,
823
+ validateStatus: (status) => {
824
+ return status >= 200 && status < 300;
819
825
  }
820
- setIsAnyLoading(true);
821
- try {
822
- await sendEmailCode(emailValue);
823
- setEmail(emailValue);
824
- } catch (error) {
825
- setLoginError(error instanceof Error ? error.message : "Failed to send code");
826
- } finally {
827
- setIsAnyLoading(false);
826
+ });
827
+ this.interceptors = config.interceptors;
828
+ this.instance.interceptors.request.use(
829
+ this.interceptors?.requestInterceptor,
830
+ this.interceptors?.requestInterceptorCatch
831
+ );
832
+ this.instance.interceptors.response.use(
833
+ this.interceptors?.responseInterceptor,
834
+ this.interceptors?.responseInterceptorCatch
835
+ );
836
+ this.instance.interceptors.request.use(
837
+ (config2) => {
838
+ return config2;
839
+ },
840
+ (err) => {
841
+ return Promise.reject(err);
828
842
  }
829
- } else {
830
- const codeValue = code;
831
- if (!codeValue || codeValue.length !== 6) {
832
- setValidationErrors({ code: "Please enter the 6-digit verification code" });
833
- return;
843
+ );
844
+ this.instance.interceptors.response.use(
845
+ (res) => {
846
+ return res.data;
847
+ },
848
+ (err) => {
849
+ if (axios.isCancel(err)) {
850
+ return Promise.reject({
851
+ isCanceled: true,
852
+ message: "request canceled",
853
+ originalError: err
854
+ });
855
+ }
856
+ if (err.response?.data?.error) {
857
+ return Promise.reject(err.response.data.error);
858
+ }
859
+ return Promise.reject(err);
834
860
  }
835
- setIsAnyLoading(true);
836
- try {
837
- await loginWithEmail(email, codeValue);
838
- } catch (error) {
839
- setLoginError(error instanceof Error ? error.message : "Login failed");
840
- } finally {
841
- setIsAnyLoading(false);
861
+ );
862
+ }
863
+ cancelRequest(url) {
864
+ this.abortControllers.forEach((controller, key) => {
865
+ if (key.includes(url)) {
866
+ controller.abort();
867
+ this.abortControllers.delete(key);
842
868
  }
843
- }
844
- };
845
- return /* @__PURE__ */ jsxs2("div", { className: `w-full space-y-6 ${className}`, children: [
846
- /* @__PURE__ */ jsxs2("div", { className: "space-y-1", children: [
847
- /* @__PURE__ */ jsx2("h1", { className: "text-3xl font-bold text-gray-900", children: "Welcome Back!" }),
848
- /* @__PURE__ */ jsx2("p", { className: "text-sm text-gray-600", children: "Please enter log in details below" })
849
- ] }),
850
- /* @__PURE__ */ jsxs2("form", { className: "space-y-5", onSubmit: handleSubmit, children: [
851
- /* @__PURE__ */ jsxs2("div", { className: "space-y-2", children: [
852
- /* @__PURE__ */ jsx2("label", { htmlFor: "email", className: "text-gray-700 font-medium text-sm block", children: "Email" }),
853
- /* @__PURE__ */ jsx2(
854
- "input",
855
- {
856
- id: "email",
857
- type: "email",
858
- name: "email",
859
- value: email,
860
- onChange: (e) => {
861
- const value = e.target.value;
862
- setEmail(value);
863
- if (validationErrors.email) {
864
- const newErrors = { ...validationErrors };
865
- delete newErrors.email;
866
- setValidationErrors(newErrors);
867
- }
868
- },
869
- required: true,
870
- "aria-invalid": !!validationErrors.email,
871
- 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",
872
- placeholder: ""
873
- }
874
- ),
875
- validationErrors.email && /* @__PURE__ */ jsx2("p", { className: "text-red-600 text-sm", children: validationErrors.email })
876
- ] }),
877
- codeSent && /* @__PURE__ */ jsxs2("div", { className: "space-y-2", children: [
878
- /* @__PURE__ */ jsx2("label", { className: "text-gray-700 font-medium text-sm block", children: "Verification Code" }),
879
- /* @__PURE__ */ jsx2(
880
- "input",
881
- {
882
- type: "text",
883
- maxLength: 6,
884
- value: code,
885
- onChange: (e) => {
886
- const value = e.target.value.replace(/\D/g, "");
887
- setCode(value);
888
- if (validationErrors.code) {
889
- const newErrors = { ...validationErrors };
890
- delete newErrors.code;
891
- setValidationErrors(newErrors);
892
- }
893
- },
894
- "aria-invalid": !!validationErrors.code,
895
- 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",
896
- placeholder: "000000"
897
- }
898
- ),
899
- validationErrors.code && /* @__PURE__ */ jsx2("p", { className: "text-red-600 text-sm", children: validationErrors.code })
900
- ] }),
901
- validationErrors.form && /* @__PURE__ */ jsx2("div", { className: "text-red-600 text-sm p-3 bg-red-50 rounded-md border border-red-200", children: /* @__PURE__ */ jsxs2("div", { className: "flex items-center", children: [
902
- /* @__PURE__ */ jsx2(Icon2, { icon: "material-symbols:error", className: "text-red-600 mr-2" }),
903
- /* @__PURE__ */ jsx2("span", { children: validationErrors.form })
904
- ] }) }),
905
- /* @__PURE__ */ jsxs2(
869
+ });
870
+ }
871
+ cancelAllRequests() {
872
+ this.abortControllers.forEach((controller) => {
873
+ controller.abort();
874
+ });
875
+ this.abortControllers.clear();
876
+ }
877
+ request(config) {
878
+ const controller = new AbortController();
879
+ const url = config.url || "";
880
+ const method = config.method || "GET";
881
+ const key = `${method}:${url}`;
882
+ this.abortControllers.set(key, controller);
883
+ config.signal = controller.signal;
884
+ return new Promise((resolve, reject) => {
885
+ if (config.interceptors?.requestInterceptor) {
886
+ config = config.interceptors.requestInterceptor(config);
887
+ }
888
+ this.instance.request(config).then((res) => {
889
+ this.abortControllers.delete(key);
890
+ if (config.interceptors?.responseInterceptor) {
891
+ res = config.interceptors.responseInterceptor(res);
892
+ }
893
+ resolve(res);
894
+ }).catch((err) => {
895
+ this.abortControllers.delete(key);
896
+ reject(err);
897
+ });
898
+ });
899
+ }
900
+ get(config) {
901
+ return this.request({ ...config, method: "GET" });
902
+ }
903
+ post(config) {
904
+ return this.request({ ...config, method: "POST" });
905
+ }
906
+ delete(config) {
907
+ return this.request({ ...config, method: "DELETE" });
908
+ }
909
+ put(config) {
910
+ return this.request({ ...config, method: "PUT" });
911
+ }
912
+ patch(config) {
913
+ return this.request({ ...config, method: "PATCH" });
914
+ }
915
+ };
916
+ var request_default = Request;
917
+
918
+ // src/services/ai-workflow-axios.ts
919
+ function createAIWorkflowClientAxios(options = {}) {
920
+ const basePath = options.basePath ?? "/api";
921
+ const baseUrl = (options.baseUrl || "https://evoagentx-server.fly.dev").replace(/\/+$/, "");
922
+ const baseAPI = `${baseUrl}${basePath.startsWith("/") ? "" : "/"}${basePath}`.replace(/\/+$/, "");
923
+ const client = options.requestInstance || new request_default({
924
+ baseURL: baseAPI,
925
+ timeout: options.timeout ?? 6e4,
926
+ interceptors: {
927
+ requestInterceptor: (config) => {
928
+ config.headers = config.headers || {};
929
+ if (options.apiKey && !config.headers["Authorization"]) {
930
+ config.headers["Authorization"] = `Bearer ${options.apiKey}`;
931
+ }
932
+ if (options.headers) {
933
+ config.headers = { ...config.headers || {}, ...options.headers };
934
+ }
935
+ return config;
936
+ },
937
+ requestInterceptorCatch: (err) => Promise.reject(err),
938
+ responseInterceptor: (res) => res,
939
+ responseInterceptorCatch: (err) => Promise.reject(err)
940
+ }
941
+ });
942
+ return {
943
+ async executeWorkflow(workflowId, inputs, opts) {
944
+ const url = `${baseUrl}/workflow/${workflowId}/execute`;
945
+ const data = await client.post({ url, data: { inputs, options: opts } });
946
+ return data;
947
+ }
948
+ };
949
+ }
950
+
951
+ // src/services/artifact-types.ts
952
+ function canAccessArtifact(a, ctx = {}) {
953
+ if (!a) return false;
954
+ if (a.visibility === "public") return true;
955
+ if (a.visibility === "project") {
956
+ if (ctx.projectId && a.projectId && ctx.projectId === a.projectId) return true;
957
+ if (ctx.tokenScopes && ctx.tokenScopes.includes("project:read")) return true;
958
+ return false;
959
+ }
960
+ if (a.visibility === "private") {
961
+ if (ctx.userId && a.ownerId && ctx.userId === a.ownerId) return true;
962
+ if (ctx.tokenScopes && (ctx.tokenScopes.includes("artifact:read:all") || ctx.tokenScopes.includes("admin"))) return true;
963
+ return false;
964
+ }
965
+ if (a.visibility === "shared") {
966
+ if (ctx.userId && a.sharedWith && a.sharedWith.includes(ctx.userId)) return true;
967
+ if (ctx.tokenScopes && (ctx.tokenScopes.includes("artifact:read:all") || ctx.tokenScopes.includes("admin"))) return true;
968
+ return false;
969
+ }
970
+ return false;
971
+ }
972
+
973
+ // src/services/artifacts-client.ts
974
+ function createArtifactsClient(req) {
975
+ return {
976
+ async create(input) {
977
+ return await req.post({ url: "/artifacts", data: input });
978
+ },
979
+ async list(query) {
980
+ return await req.get({ url: "/artifacts", params: query });
981
+ },
982
+ async get(id) {
983
+ return await req.get({ url: `/artifacts/${encodeURIComponent(id)}` });
984
+ },
985
+ async setVisibility(id, visibility) {
986
+ await req.patch({ url: `/artifacts/${encodeURIComponent(id)}/visibility`, data: { visibility } });
987
+ },
988
+ async delete(id) {
989
+ await req.delete({ url: `/artifacts/${encodeURIComponent(id)}` });
990
+ },
991
+ // convenience local check (server is authoritative)
992
+ canAccessLocal(a, ctx) {
993
+ if (!a) return false;
994
+ if (a.visibility === "public") return true;
995
+ if (a.visibility === "project") return Boolean(ctx.projectId && a.projectId && ctx.projectId === a.projectId);
996
+ if (a.visibility === "private") return Boolean(ctx.userId && a.ownerId && ctx.userId === a.ownerId);
997
+ if (a.visibility === "shared") return Boolean(ctx.userId && a.sharedWith && a.sharedWith.includes(ctx.userId));
998
+ return false;
999
+ }
1000
+ };
1001
+ }
1002
+
1003
+ // src/services/upload-client.ts
1004
+ function createUploadClient(req, projectId) {
1005
+ const uploadUrl = projectId ? `/entities/apps/${projectId}/files` : "/files";
1006
+ return {
1007
+ /**
1008
+ * 上传单个文件
1009
+ *
1010
+ * @example
1011
+ * ```typescript
1012
+ * const { url } = await client.upload.file(imageFile)
1013
+ * console.log('文件地址:', url)
1014
+ * ```
1015
+ */
1016
+ async file(file, options) {
1017
+ const formData = new FormData();
1018
+ if (typeof file === "string") {
1019
+ if (file.startsWith("data:")) {
1020
+ const response2 = await fetch(file);
1021
+ const blob = await response2.blob();
1022
+ formData.append("file", blob, "upload.bin");
1023
+ } else {
1024
+ formData.append("fileUrl", file);
1025
+ }
1026
+ } else if (file instanceof File) {
1027
+ formData.append("file", file, file.name);
1028
+ } else {
1029
+ formData.append("file", file, "upload.bin");
1030
+ }
1031
+ if (options?.metadata) {
1032
+ formData.append("metadata", JSON.stringify(options.metadata));
1033
+ }
1034
+ const response = await req.post({
1035
+ url: uploadUrl,
1036
+ data: formData,
1037
+ signal: options?.signal
1038
+ });
1039
+ return {
1040
+ url: response.data.publicUrl
1041
+ };
1042
+ },
1043
+ /**
1044
+ * 上传图片(快捷方法,专为 AI 设计)
1045
+ *
1046
+ * @example
1047
+ * ```typescript
1048
+ * const { url } = await client.upload.image(imageFile)
1049
+ * ```
1050
+ */
1051
+ async image(file) {
1052
+ const result = await this.file(file);
1053
+ return { url: result.url };
1054
+ },
1055
+ /**
1056
+ * 批量上传文件
1057
+ *
1058
+ * @example
1059
+ * ```typescript
1060
+ * const result = await client.upload.batch({
1061
+ * files: [file1, file2, file3],
1062
+ * concurrent: 3,
1063
+ * onProgress: (completed, total) => {
1064
+ * console.log(`${completed}/${total}`)
1065
+ * }
1066
+ * })
1067
+ * ```
1068
+ */
1069
+ async batch(options) {
1070
+ const { files, concurrent = 3, onProgress, onFileComplete, signal } = options;
1071
+ const success = [];
1072
+ const failed = [];
1073
+ let completed = 0;
1074
+ for (let i = 0; i < files.length; i += concurrent) {
1075
+ if (signal?.aborted) break;
1076
+ const batch = files.slice(i, Math.min(i + concurrent, files.length));
1077
+ const promises = batch.map(async (file, batchIndex) => {
1078
+ const globalIndex = i + batchIndex;
1079
+ try {
1080
+ const result = await this.file(file, { signal });
1081
+ success.push(result);
1082
+ if (onFileComplete) {
1083
+ onFileComplete(result, globalIndex);
1084
+ }
1085
+ } catch (error) {
1086
+ const errorMsg = error instanceof Error ? error.message : String(error);
1087
+ failed.push({ index: globalIndex, error: errorMsg });
1088
+ if (onFileComplete) {
1089
+ onFileComplete(
1090
+ error instanceof Error ? error : new Error(errorMsg),
1091
+ globalIndex
1092
+ );
1093
+ }
1094
+ } finally {
1095
+ completed++;
1096
+ if (onProgress) {
1097
+ onProgress(completed, files.length);
1098
+ }
1099
+ }
1100
+ });
1101
+ await Promise.all(promises);
1102
+ }
1103
+ return {
1104
+ success,
1105
+ failed,
1106
+ total: files.length
1107
+ };
1108
+ }
1109
+ };
1110
+ }
1111
+
1112
+ // src/components/auth/LoginForm.tsx
1113
+ import { useState as useState2, useEffect as useEffect2 } from "react";
1114
+ import { Icon as Icon2 } from "@iconify/react";
1115
+ import { Loader2 } from "lucide-react";
1116
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
1117
+ var LoginForm = ({
1118
+ onLoginSuccess,
1119
+ appName = "AI Application Platform",
1120
+ className = ""
1121
+ }) => {
1122
+ const [email, setEmail] = useState2("");
1123
+ const [code, setCode] = useState2("");
1124
+ const [validationErrors, setValidationErrors] = useState2({});
1125
+ const [isAnyLoading, setIsAnyLoading] = useState2(false);
1126
+ const [codeSent, setCodeSent] = useState2(false);
1127
+ const [loginError, setLoginError] = useState2(null);
1128
+ const googleLogin = async () => {
1129
+ };
1130
+ const githubLogin = async () => {
1131
+ };
1132
+ const sendEmailCode = async (email2) => {
1133
+ setCodeSent(true);
1134
+ };
1135
+ const loginWithEmail = async (email2, code2) => {
1136
+ if (onLoginSuccess) onLoginSuccess();
1137
+ };
1138
+ const clearError = () => {
1139
+ setLoginError(null);
1140
+ setValidationErrors({});
1141
+ };
1142
+ useEffect2(() => {
1143
+ if (loginError) {
1144
+ try {
1145
+ const errorObj = JSON.parse(loginError);
1146
+ const newErrors = {};
1147
+ if (errorObj.code === 429) {
1148
+ newErrors.form = errorObj.msg || "\u8BF7\u6C42\u8FC7\u4E8E\u9891\u7E41\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5";
1149
+ } else if (errorObj.data?.code === 401 && errorObj.data?.message) {
1150
+ if (codeSent) {
1151
+ newErrors.code = errorObj.data.message;
1152
+ } else {
1153
+ newErrors.form = errorObj.data.message;
1154
+ }
1155
+ } else if (errorObj.msg) {
1156
+ newErrors.form = errorObj.msg;
1157
+ } else if (errorObj.data?.message) {
1158
+ newErrors.form = errorObj.data.message;
1159
+ } else {
1160
+ newErrors.form = "\u53D1\u751F\u672A\u77E5\u9519\u8BEF\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5";
1161
+ }
1162
+ setValidationErrors(newErrors);
1163
+ } catch (e) {
1164
+ setValidationErrors({ form: loginError });
1165
+ }
1166
+ const timer = setTimeout(() => {
1167
+ clearError();
1168
+ }, 8e3);
1169
+ return () => clearTimeout(timer);
1170
+ }
1171
+ }, [loginError, codeSent]);
1172
+ const handleSubmit = async (e) => {
1173
+ e.preventDefault();
1174
+ const formData = new FormData(e.currentTarget);
1175
+ setValidationErrors({});
1176
+ if (!codeSent) {
1177
+ const emailValue = formData.get("email");
1178
+ if (!emailValue) {
1179
+ setValidationErrors({ email: "Please enter your email address" });
1180
+ return;
1181
+ }
1182
+ setIsAnyLoading(true);
1183
+ try {
1184
+ await sendEmailCode(emailValue);
1185
+ setEmail(emailValue);
1186
+ } catch (error) {
1187
+ setLoginError(error instanceof Error ? error.message : "Failed to send code");
1188
+ } finally {
1189
+ setIsAnyLoading(false);
1190
+ }
1191
+ } else {
1192
+ const codeValue = code;
1193
+ if (!codeValue || codeValue.length !== 6) {
1194
+ setValidationErrors({ code: "Please enter the 6-digit verification code" });
1195
+ return;
1196
+ }
1197
+ setIsAnyLoading(true);
1198
+ try {
1199
+ await loginWithEmail(email, codeValue);
1200
+ } catch (error) {
1201
+ setLoginError(error instanceof Error ? error.message : "Login failed");
1202
+ } finally {
1203
+ setIsAnyLoading(false);
1204
+ }
1205
+ }
1206
+ };
1207
+ return /* @__PURE__ */ jsxs2("div", { className: `w-full space-y-6 ${className}`, children: [
1208
+ /* @__PURE__ */ jsxs2("div", { className: "space-y-1", children: [
1209
+ /* @__PURE__ */ jsx2("h1", { className: "text-3xl font-bold text-gray-900", children: "Welcome Back!" }),
1210
+ /* @__PURE__ */ jsx2("p", { className: "text-sm text-gray-600", children: "Please enter log in details below" })
1211
+ ] }),
1212
+ /* @__PURE__ */ jsxs2("form", { className: "space-y-5", onSubmit: handleSubmit, children: [
1213
+ /* @__PURE__ */ jsxs2("div", { className: "space-y-2", children: [
1214
+ /* @__PURE__ */ jsx2("label", { htmlFor: "email", className: "text-gray-700 font-medium text-sm block", children: "Email" }),
1215
+ /* @__PURE__ */ jsx2(
1216
+ "input",
1217
+ {
1218
+ id: "email",
1219
+ type: "email",
1220
+ name: "email",
1221
+ value: email,
1222
+ onChange: (e) => {
1223
+ const value = e.target.value;
1224
+ setEmail(value);
1225
+ if (validationErrors.email) {
1226
+ const newErrors = { ...validationErrors };
1227
+ delete newErrors.email;
1228
+ setValidationErrors(newErrors);
1229
+ }
1230
+ },
1231
+ required: true,
1232
+ "aria-invalid": !!validationErrors.email,
1233
+ 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",
1234
+ placeholder: ""
1235
+ }
1236
+ ),
1237
+ validationErrors.email && /* @__PURE__ */ jsx2("p", { className: "text-red-600 text-sm", children: validationErrors.email })
1238
+ ] }),
1239
+ codeSent && /* @__PURE__ */ jsxs2("div", { className: "space-y-2", children: [
1240
+ /* @__PURE__ */ jsx2("label", { className: "text-gray-700 font-medium text-sm block", children: "Verification Code" }),
1241
+ /* @__PURE__ */ jsx2(
1242
+ "input",
1243
+ {
1244
+ type: "text",
1245
+ maxLength: 6,
1246
+ value: code,
1247
+ onChange: (e) => {
1248
+ const value = e.target.value.replace(/\D/g, "");
1249
+ setCode(value);
1250
+ if (validationErrors.code) {
1251
+ const newErrors = { ...validationErrors };
1252
+ delete newErrors.code;
1253
+ setValidationErrors(newErrors);
1254
+ }
1255
+ },
1256
+ "aria-invalid": !!validationErrors.code,
1257
+ 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",
1258
+ placeholder: "000000"
1259
+ }
1260
+ ),
1261
+ validationErrors.code && /* @__PURE__ */ jsx2("p", { className: "text-red-600 text-sm", children: validationErrors.code })
1262
+ ] }),
1263
+ validationErrors.form && /* @__PURE__ */ jsx2("div", { className: "text-red-600 text-sm p-3 bg-red-50 rounded-md border border-red-200", children: /* @__PURE__ */ jsxs2("div", { className: "flex items-center", children: [
1264
+ /* @__PURE__ */ jsx2(Icon2, { icon: "material-symbols:error", className: "text-red-600 mr-2" }),
1265
+ /* @__PURE__ */ jsx2("span", { children: validationErrors.form })
1266
+ ] }) }),
1267
+ /* @__PURE__ */ jsxs2(
906
1268
  "button",
907
1269
  {
908
1270
  type: "submit",
@@ -961,7 +1323,7 @@ var LoginForm = ({
961
1323
 
962
1324
  // src/components/auth/HowoneProvider.tsx
963
1325
  init_auth();
964
- import { createContext as createContext2, useContext as useContext2, useState as useState8, useEffect as useEffect7, useMemo, useCallback as useCallback4 } from "react";
1326
+ import { createContext as createContext2, useContext as useContext2, useState as useState7, useEffect as useEffect6, useMemo, useCallback as useCallback4 } from "react";
965
1327
 
966
1328
  // src/components/theme/ThemeProvider.tsx
967
1329
  import { createContext, useContext, useEffect as useEffect3, useState as useState3 } from "react";
@@ -1017,66 +1379,31 @@ var useTheme = () => {
1017
1379
  };
1018
1380
 
1019
1381
  // src/components/ui/Toast/GlobalToastContainer.tsx
1020
- import { GoeyToaster } from "goey-toast";
1021
- import "goey-toast/styles.css";
1022
-
1023
- // src/components/theme/ThemeToggle.tsx
1024
- import * as React2 from "react";
1025
- import { Icon as Icon3 } from "@iconify/react";
1382
+ import { ToastContainer } from "react-toastify";
1026
1383
  import { jsx as jsx4 } from "react/jsx-runtime";
1027
- function ThemeToggle({ className }) {
1028
- const { setTheme, theme } = useTheme();
1029
- const [mounted, setMounted] = React2.useState(false);
1030
- React2.useEffect(() => {
1031
- setMounted(true);
1032
- }, []);
1033
- const handleToggle = () => {
1034
- if (theme === "dark") {
1035
- setTheme("light");
1036
- } else {
1037
- setTheme("dark");
1038
- }
1039
- };
1040
- if (!mounted) {
1041
- return /* @__PURE__ */ jsx4(Icon3, { icon: "solar:sun-bold", width: 20, height: 20 });
1042
- }
1043
- return /* @__PURE__ */ jsx4(
1044
- "div",
1045
- {
1046
- className: `cursor-pointer ${className || ""}`,
1047
- onClick: handleToggle,
1048
- children: theme === "light" ? /* @__PURE__ */ jsx4(Icon3, { icon: "solar:sun-bold", width: 20, height: 20 }) : /* @__PURE__ */ jsx4(Icon3, { icon: "solar:moon-linear", width: 20, height: 20 })
1049
- }
1050
- );
1051
- }
1052
-
1053
- // src/components/ui/Toast/GlobalToastContainer.tsx
1054
- import { jsx as jsx5 } from "react/jsx-runtime";
1055
1384
  function GlobalToastContainer() {
1056
- const { theme } = useTheme();
1057
- const resolvedTheme = theme === "dark" ? "dark" : "light";
1058
- return /* @__PURE__ */ jsx5(
1059
- GoeyToaster,
1385
+ return /* @__PURE__ */ jsx4(
1386
+ ToastContainer,
1060
1387
  {
1061
- position: "bottom-right",
1062
- theme: resolvedTheme
1388
+ newestOnTop: false,
1389
+ closeButton: false
1063
1390
  }
1064
1391
  );
1065
1392
  }
1066
1393
 
1067
1394
  // src/components/ElementSelectorProvider.tsx
1068
- import { useEffect as useEffect6, useState as useState7, useCallback as useCallback3 } from "react";
1395
+ import { useEffect as useEffect5, useState as useState6, useCallback as useCallback3 } from "react";
1069
1396
 
1070
1397
  // src/components/ElementSelector.tsx
1071
- import { useEffect as useEffect5, useState as useState5, useCallback, useRef } from "react";
1072
- import { Fragment, jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
1398
+ import { useEffect as useEffect4, useState as useState4, useCallback, useRef } from "react";
1399
+ import { Fragment, jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
1073
1400
  var ElementSelector = ({
1074
1401
  active,
1075
1402
  onSelect,
1076
1403
  onCancel
1077
1404
  }) => {
1078
- const [hoveredElement, setHoveredElement] = useState5(null);
1079
- const [highlightRect, setHighlightRect] = useState5(null);
1405
+ const [hoveredElement, setHoveredElement] = useState4(null);
1406
+ const [highlightRect, setHighlightRect] = useState4(null);
1080
1407
  const overlayRef = useRef(null);
1081
1408
  const getSourceLocation = useCallback((element) => {
1082
1409
  let current = element;
@@ -1133,7 +1460,7 @@ var ElementSelector = ({
1133
1460
  }
1134
1461
  }
1135
1462
  }, [active, hoveredElement, getSourceLocation, onSelect, onCancel]);
1136
- useEffect5(() => {
1463
+ useEffect4(() => {
1137
1464
  if (active) {
1138
1465
  document.addEventListener("mousemove", handleMouseMove);
1139
1466
  document.addEventListener("click", handleClick, true);
@@ -1150,7 +1477,7 @@ var ElementSelector = ({
1150
1477
  }, [active, handleMouseMove, handleClick]);
1151
1478
  if (!active) return null;
1152
1479
  return /* @__PURE__ */ jsxs3(Fragment, { children: [
1153
- /* @__PURE__ */ jsx6(
1480
+ /* @__PURE__ */ jsx5(
1154
1481
  "div",
1155
1482
  {
1156
1483
  ref: overlayRef,
@@ -1167,7 +1494,7 @@ var ElementSelector = ({
1167
1494
  }
1168
1495
  }
1169
1496
  ),
1170
- highlightRect && /* @__PURE__ */ jsx6(
1497
+ highlightRect && /* @__PURE__ */ jsx5(
1171
1498
  "div",
1172
1499
  {
1173
1500
  style: {
@@ -1185,7 +1512,7 @@ var ElementSelector = ({
1185
1512
  }
1186
1513
  }
1187
1514
  ),
1188
- hoveredElement && highlightRect && /* @__PURE__ */ jsx6(
1515
+ hoveredElement && highlightRect && /* @__PURE__ */ jsx5(
1189
1516
  "div",
1190
1517
  {
1191
1518
  style: {
@@ -1211,10 +1538,10 @@ var ElementSelector = ({
1211
1538
  };
1212
1539
 
1213
1540
  // src/hooks/use-element-selector.ts
1214
- import { useState as useState6, useCallback as useCallback2 } from "react";
1541
+ import { useState as useState5, useCallback as useCallback2 } from "react";
1215
1542
  function useElementSelector() {
1216
- const [isSelecting, setIsSelecting] = useState6(false);
1217
- const [selectedElement, setSelectedElement] = useState6(null);
1543
+ const [isSelecting, setIsSelecting] = useState5(false);
1544
+ const [selectedElement, setSelectedElement] = useState5(null);
1218
1545
  const startSelecting = useCallback2(() => {
1219
1546
  setIsSelecting(true);
1220
1547
  }, []);
@@ -1242,9 +1569,9 @@ function sendElementSelectionToParent(data) {
1242
1569
  }
1243
1570
 
1244
1571
  // src/components/ElementSelectorProvider.tsx
1245
- import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
1572
+ import { Fragment as Fragment2, jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
1246
1573
  var ElementSelectorProvider = ({ children }) => {
1247
- const [isSelecting, setIsSelecting] = useState7(false);
1574
+ const [isSelecting, setIsSelecting] = useState6(false);
1248
1575
  const handleCancel = useCallback3(() => {
1249
1576
  setIsSelecting(false);
1250
1577
  if (window.parent && window.parent !== window) {
@@ -1256,7 +1583,7 @@ var ElementSelectorProvider = ({ children }) => {
1256
1583
  const handleSelect = useCallback3((data) => {
1257
1584
  sendElementSelectionToParent(data);
1258
1585
  }, []);
1259
- useEffect6(() => {
1586
+ useEffect5(() => {
1260
1587
  const handleStartSelection = () => {
1261
1588
  setIsSelecting(true);
1262
1589
  };
@@ -1281,7 +1608,7 @@ var ElementSelectorProvider = ({ children }) => {
1281
1608
  }, [handleCancel]);
1282
1609
  return /* @__PURE__ */ jsxs4(Fragment2, { children: [
1283
1610
  children,
1284
- /* @__PURE__ */ jsx7(
1611
+ /* @__PURE__ */ jsx6(
1285
1612
  ElementSelector,
1286
1613
  {
1287
1614
  active: isSelecting,
@@ -1294,7 +1621,7 @@ var ElementSelectorProvider = ({ children }) => {
1294
1621
 
1295
1622
  // src/components/auth/HowoneProvider.tsx
1296
1623
  init_config();
1297
- import { jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
1624
+ import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
1298
1625
  var HowoneContext = createContext2(null);
1299
1626
  var consumedTokenCache = /* @__PURE__ */ new Set();
1300
1627
  var redirectOverlayStylesInjected = false;
@@ -1356,10 +1683,10 @@ var HowOneProvider = ({
1356
1683
  forceDefaultTheme = false,
1357
1684
  redirectOnUnauthenticated = true
1358
1685
  }) => {
1359
- const [user, setUser] = useState8(() => parseUserFromToken(getToken()));
1360
- const [token, setTokenState] = useState8(() => getToken());
1361
- const [hasCheckedUrlToken, setHasCheckedUrlToken] = useState8(false);
1362
- const [pendingRedirect, setPendingRedirect] = useState8(false);
1686
+ const [user, setUser] = useState7(() => parseUserFromToken(getToken()));
1687
+ const [token, setTokenState] = useState7(() => getToken());
1688
+ const [hasCheckedUrlToken, setHasCheckedUrlToken] = useState7(false);
1689
+ const [pendingRedirect, setPendingRedirect] = useState7(false);
1363
1690
  const authCookieRoot = useMemo(() => {
1364
1691
  const env3 = getGlobalEnvironment() ?? "dev";
1365
1692
  return setEnvironment(env3).AUTH_COOKIE_ROOT_VALUE;
@@ -1417,7 +1744,7 @@ var HowOneProvider = ({
1417
1744
  }
1418
1745
  return null;
1419
1746
  }, []);
1420
- useEffect7(() => {
1747
+ useEffect6(() => {
1421
1748
  try {
1422
1749
  const params = new URLSearchParams(window.location.search);
1423
1750
  let urlToken = params.get("access_token") || params.get("token");
@@ -1463,7 +1790,7 @@ var HowOneProvider = ({
1463
1790
  return "https://howone.dev/auth";
1464
1791
  }
1465
1792
  }, []);
1466
- useEffect7(() => {
1793
+ useEffect6(() => {
1467
1794
  if (pendingRedirect) {
1468
1795
  injectRedirectOverlayStyles();
1469
1796
  }
@@ -1510,7 +1837,7 @@ var HowOneProvider = ({
1510
1837
  navigateToResolvedAuth();
1511
1838
  }
1512
1839
  }, [redirectOnUnauthenticated, resolvedAuthUrl, projectId]);
1513
- useEffect7(() => {
1840
+ useEffect6(() => {
1514
1841
  if (!hasCheckedUrlToken) return;
1515
1842
  if (!token && !user) {
1516
1843
  redirectToAuth();
@@ -1540,24 +1867,24 @@ var HowOneProvider = ({
1540
1867
  storageKey: themeStorageKey,
1541
1868
  forceDefault: forceDefaultTheme,
1542
1869
  children: [
1543
- /* @__PURE__ */ jsx8(ElementSelectorProvider, { children: /* @__PURE__ */ jsxs5(HowoneContext.Provider, { value, children: [
1870
+ /* @__PURE__ */ jsx7(ElementSelectorProvider, { children: /* @__PURE__ */ jsxs5(HowoneContext.Provider, { value, children: [
1544
1871
  children,
1545
- showHowOneFlag && /* @__PURE__ */ jsx8(FloatingButton, { onClick: () => window.open("https://howone.ai", "_blank") }),
1546
- pendingRedirect && /* @__PURE__ */ jsx8(
1872
+ showHowOneFlag && /* @__PURE__ */ jsx7(FloatingButton, { onClick: () => window.open("https://howone.ai", "_blank") }),
1873
+ pendingRedirect && /* @__PURE__ */ jsx7(
1547
1874
  "div",
1548
1875
  {
1549
1876
  "data-howone-auth-overlay-root": true,
1550
1877
  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",
1551
1878
  children: /* @__PURE__ */ jsxs5("div", { className: "relative mt-6 flex h-[220px] w-[220px] items-center justify-center", children: [
1552
- /* @__PURE__ */ jsx8(
1879
+ /* @__PURE__ */ jsx7(
1553
1880
  "div",
1554
1881
  {
1555
1882
  className: "absolute inset-0 rounded-full bg-white/20",
1556
1883
  style: { animation: "howone-glow-ring 2.4s ease-in-out infinite" }
1557
1884
  }
1558
1885
  ),
1559
- /* @__PURE__ */ jsx8("div", { className: "absolute inset-0 rounded-full bg-gradient-to-br from-white/10 via-white/25 to-white/10 blur-2xl" }),
1560
- /* @__PURE__ */ jsx8(
1886
+ /* @__PURE__ */ jsx7("div", { className: "absolute inset-0 rounded-full bg-gradient-to-br from-white/10 via-white/25 to-white/10 blur-2xl" }),
1887
+ /* @__PURE__ */ jsx7(
1561
1888
  "img",
1562
1889
  {
1563
1890
  style: { width: 250, animation: "howone-logo-pulse 2s ease-in-out infinite" },
@@ -1569,7 +1896,7 @@ var HowOneProvider = ({
1569
1896
  }
1570
1897
  )
1571
1898
  ] }) }),
1572
- /* @__PURE__ */ jsx8(GlobalToastContainer, {})
1899
+ /* @__PURE__ */ jsx7(GlobalToastContainer, {})
1573
1900
  ]
1574
1901
  }
1575
1902
  );
@@ -1679,7 +2006,7 @@ var howone = {
1679
2006
  var client_default = howone;
1680
2007
 
1681
2008
  // src/components/ui/Loading.tsx
1682
- import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
2009
+ import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
1683
2010
  var Loading = ({
1684
2011
  size = "md",
1685
2012
  text = "Loading...",
@@ -1692,14 +2019,14 @@ var Loading = ({
1692
2019
  lg: "h-12 w-12"
1693
2020
  };
1694
2021
  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";
1695
- return /* @__PURE__ */ jsx9("div", { className: `${containerClasses} ${className}`, children: /* @__PURE__ */ jsxs6("div", { className: "text-center", children: [
1696
- /* @__PURE__ */ jsx9(
2022
+ return /* @__PURE__ */ jsx8("div", { className: `${containerClasses} ${className}`, children: /* @__PURE__ */ jsxs6("div", { className: "text-center", children: [
2023
+ /* @__PURE__ */ jsx8(
1697
2024
  "div",
1698
2025
  {
1699
2026
  className: `animate-spin rounded-full border-2 border-gray-300 border-t-blue-600 mx-auto ${sizeClasses[size]}`
1700
2027
  }
1701
2028
  ),
1702
- text && /* @__PURE__ */ jsx9("p", { className: "mt-2 text-sm text-gray-600", children: text })
2029
+ text && /* @__PURE__ */ jsx8("p", { className: "mt-2 text-sm text-gray-600", children: text })
1703
2030
  ] }) });
1704
2031
  };
1705
2032
  var LoadingSpinner = ({
@@ -1711,7 +2038,7 @@ var LoadingSpinner = ({
1711
2038
  md: "h-8 w-8",
1712
2039
  lg: "h-12 w-12"
1713
2040
  };
1714
- return /* @__PURE__ */ jsx9(
2041
+ return /* @__PURE__ */ jsx8(
1715
2042
  "div",
1716
2043
  {
1717
2044
  className: `animate-spin rounded-full border-2 border-gray-300 border-t-blue-600 ${sizeClasses[size]} ${className}`
@@ -1721,7 +2048,7 @@ var LoadingSpinner = ({
1721
2048
 
1722
2049
  // src/components/ui/ErrorBoundary.tsx
1723
2050
  import { Component } from "react";
1724
- import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
2051
+ import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
1725
2052
  var ErrorBoundary = class extends Component {
1726
2053
  constructor(props) {
1727
2054
  super(props);
@@ -1744,13 +2071,13 @@ var ErrorBoundary = class extends Component {
1744
2071
  if (this.state.hasError) {
1745
2072
  if (this.props.fallback) {
1746
2073
  const FallbackComponent = this.props.fallback;
1747
- return /* @__PURE__ */ jsx10(FallbackComponent, { error: this.state.error, retry: this.handleRetry });
2074
+ return /* @__PURE__ */ jsx9(FallbackComponent, { error: this.state.error, retry: this.handleRetry });
1748
2075
  }
1749
- return /* @__PURE__ */ jsx10("div", { className: "min-h-[400px] flex items-center justify-center p-4", children: /* @__PURE__ */ jsxs7("div", { className: "text-center max-w-md", children: [
1750
- /* @__PURE__ */ jsx10("div", { className: "text-red-500 text-6xl mb-4", children: "\u26A0\uFE0F" }),
1751
- /* @__PURE__ */ jsx10("h2", { className: "text-xl font-semibold text-gray-900 mb-2", children: "Something went wrong" }),
1752
- /* @__PURE__ */ jsx10("p", { className: "text-gray-600 mb-4", children: "An unexpected error occurred. Please try refreshing the page." }),
1753
- /* @__PURE__ */ jsx10(
2076
+ return /* @__PURE__ */ jsx9("div", { className: "min-h-[400px] flex items-center justify-center p-4", children: /* @__PURE__ */ jsxs7("div", { className: "text-center max-w-md", children: [
2077
+ /* @__PURE__ */ jsx9("div", { className: "text-red-500 text-6xl mb-4", children: "\u26A0\uFE0F" }),
2078
+ /* @__PURE__ */ jsx9("h2", { className: "text-xl font-semibold text-gray-900 mb-2", children: "Something went wrong" }),
2079
+ /* @__PURE__ */ jsx9("p", { className: "text-gray-600 mb-4", children: "An unexpected error occurred. Please try refreshing the page." }),
2080
+ /* @__PURE__ */ jsx9(
1754
2081
  "button",
1755
2082
  {
1756
2083
  onClick: this.handleRetry,
@@ -1764,10 +2091,10 @@ var ErrorBoundary = class extends Component {
1764
2091
  return this.props.children;
1765
2092
  }
1766
2093
  };
1767
- var DefaultErrorFallback = ({ retry }) => /* @__PURE__ */ jsx10("div", { className: "min-h-[200px] flex items-center justify-center p-4", children: /* @__PURE__ */ jsxs7("div", { className: "text-center", children: [
1768
- /* @__PURE__ */ jsx10("div", { className: "text-red-500 text-4xl mb-2", children: "\u26A0\uFE0F" }),
1769
- /* @__PURE__ */ jsx10("p", { className: "text-gray-600 mb-2", children: "Something went wrong" }),
1770
- retry && /* @__PURE__ */ jsx10(
2094
+ var DefaultErrorFallback = ({ retry }) => /* @__PURE__ */ jsx9("div", { className: "min-h-[200px] flex items-center justify-center p-4", children: /* @__PURE__ */ jsxs7("div", { className: "text-center", children: [
2095
+ /* @__PURE__ */ jsx9("div", { className: "text-red-500 text-4xl mb-2", children: "\u26A0\uFE0F" }),
2096
+ /* @__PURE__ */ jsx9("p", { className: "text-gray-600 mb-2", children: "Something went wrong" }),
2097
+ retry && /* @__PURE__ */ jsx9(
1771
2098
  "button",
1772
2099
  {
1773
2100
  onClick: retry,
@@ -1778,7 +2105,7 @@ var DefaultErrorFallback = ({ retry }) => /* @__PURE__ */ jsx10("div", { classNa
1778
2105
  ] }) });
1779
2106
 
1780
2107
  // src/components/ui/ClayxButton.tsx
1781
- import { jsx as jsx11 } from "react/jsx-runtime";
2108
+ import { jsx as jsx10 } from "react/jsx-runtime";
1782
2109
  var getSizeClasses = (size, isIconOnly) => {
1783
2110
  if (isIconOnly) {
1784
2111
  switch (size) {
@@ -1834,7 +2161,7 @@ var ClayxButton = ({
1834
2161
  disabled:opacity-50 disabled:cursor-not-allowed disabled:pointer-events-none
1835
2162
  `.replace(/\s+/g, " ").trim();
1836
2163
  const combinedClasses = `${baseClasses} ${sizeClasses} ${variantClasses} ${className}`.trim();
1837
- return /* @__PURE__ */ jsx11(
2164
+ return /* @__PURE__ */ jsx10(
1838
2165
  "button",
1839
2166
  {
1840
2167
  className: combinedClasses,
@@ -1846,57 +2173,204 @@ var ClayxButton = ({
1846
2173
  };
1847
2174
 
1848
2175
  // src/components/ui/LimitUpgradeToast.tsx
1849
- import React7 from "react";
2176
+ import React8 from "react";
2177
+ import { Icon as Icon5 } from "@iconify/react";
2178
+
2179
+ // src/components/ui/Toast/ClayxToast.tsx
2180
+ import React7, { useCallback as useCallback5 } from "react";
2181
+ import { Bounce, toast } from "react-toastify";
1850
2182
  import { Icon as Icon4 } from "@iconify/react";
1851
2183
 
1852
- // src/components/ui/Toast/GoeyToast.tsx
1853
- import { goeyToast } from "goey-toast";
1854
- var resolveDuration = (autoClose) => {
1855
- if (typeof autoClose === "number") return autoClose;
1856
- if (autoClose === false) return 24 * 60 * 60 * 1e3;
1857
- return void 0;
1858
- };
1859
- var createToast = (type) => {
1860
- return (params) => {
1861
- const { autoClose, ...rawOptions } = params.options ?? {};
1862
- const id = params.options?.id ?? `goey-${Date.now()}-${Math.random()}`;
1863
- const closeToast = () => goeyToast.dismiss(id);
1864
- const description = params.component ?? (params.render ? params.render(closeToast) : params.message);
1865
- const duration = resolveDuration(autoClose);
1866
- const goeyOptions = {
1867
- ...rawOptions,
1868
- id,
1869
- description,
1870
- ...duration !== void 0 ? { duration } : {}
1871
- };
1872
- const title = params.title ?? "";
1873
- if (type === "default") {
1874
- goeyToast(title, goeyOptions);
1875
- return;
2184
+ // src/components/theme/ThemeToggle.tsx
2185
+ import * as React6 from "react";
2186
+ import { Icon as Icon3 } from "@iconify/react";
2187
+ import { jsx as jsx11 } from "react/jsx-runtime";
2188
+ function ThemeToggle({ className }) {
2189
+ const { setTheme, theme } = useTheme();
2190
+ const [mounted, setMounted] = React6.useState(false);
2191
+ React6.useEffect(() => {
2192
+ setMounted(true);
2193
+ }, []);
2194
+ const handleToggle = () => {
2195
+ if (theme === "dark") {
2196
+ setTheme("light");
2197
+ } else {
2198
+ setTheme("dark");
1876
2199
  }
1877
- goeyToast[type](title, goeyOptions);
1878
2200
  };
1879
- };
1880
- var GoeyToast = {
1881
- success: createToast("success"),
1882
- error: createToast("error"),
1883
- warning: createToast("warning"),
1884
- info: createToast("info"),
1885
- default: createToast("default")
1886
- };
2201
+ if (!mounted) {
2202
+ return /* @__PURE__ */ jsx11(Icon3, { icon: "solar:sun-bold", width: 20, height: 20 });
2203
+ }
2204
+ return /* @__PURE__ */ jsx11(
2205
+ "div",
2206
+ {
2207
+ className: `cursor-pointer ${className || ""}`,
2208
+ onClick: handleToggle,
2209
+ children: theme === "light" ? /* @__PURE__ */ jsx11(Icon3, { icon: "solar:sun-bold", width: 20, height: 20 }) : /* @__PURE__ */ jsx11(Icon3, { icon: "solar:moon-linear", width: 20, height: 20 })
2210
+ }
2211
+ );
2212
+ }
1887
2213
 
1888
- // src/components/ui/LimitUpgradeToast.tsx
2214
+ // src/components/ui/Toast/ClayxToast.tsx
1889
2215
  import { jsx as jsx12, jsxs as jsxs8 } from "react/jsx-runtime";
1890
- var LimitToastContainer = ({ message, onUpgrade, closeToast }) => {
1891
- const [hover, setHover] = React7.useState(false);
1892
- const [closeHover, setCloseHover] = React7.useState(false);
1893
- return /* @__PURE__ */ jsxs8("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: [
2216
+ var TOAST_ICONS = {
2217
+ success: {
2218
+ icon: "mdi:success",
2219
+ color: "text-green-400",
2220
+ className: "text-green-400",
2221
+ dark: {
2222
+ bgGradient: "bg-[#14181d]",
2223
+ gradientColor: "#389726",
2224
+ borderGradient: "border-[#389726]",
2225
+ borderGradientColor: "#389726"
2226
+ },
2227
+ light: {
2228
+ bgGradient: "bg-[#fafafa]",
2229
+ gradientColor: "#22c55e",
2230
+ borderGradient: "border-[#22c55e]",
2231
+ borderGradientColor: "#22c55e"
2232
+ }
2233
+ },
2234
+ error: {
2235
+ icon: "ic:outline-close",
2236
+ color: "text-red-400",
2237
+ className: "text-red-400",
2238
+ dark: {
2239
+ bgGradient: "bg-[#14181d]",
2240
+ gradientColor: "#ef4444",
2241
+ borderGradient: "border-[#ef4444]",
2242
+ borderGradientColor: "#ef4444"
2243
+ },
2244
+ light: {
2245
+ bgGradient: "bg-[#fafafa]",
2246
+ gradientColor: "#f87171",
2247
+ borderGradient: "border-[#f87171]",
2248
+ borderGradientColor: "#f87171"
2249
+ }
2250
+ },
2251
+ warning: {
2252
+ icon: "mi:warning",
2253
+ color: "text-yellow-400",
2254
+ className: "text-yellow-400",
2255
+ dark: {
2256
+ bgGradient: "bg-[#14181d]",
2257
+ gradientColor: "#facc15",
2258
+ borderGradient: "border-[#facc15]",
2259
+ borderGradientColor: "#facc15"
2260
+ },
2261
+ light: {
2262
+ bgGradient: "bg-[#fafafa]",
2263
+ gradientColor: "#f59e0b",
2264
+ borderGradient: "border-[#f59e0b]",
2265
+ borderGradientColor: "#f59e0b"
2266
+ }
2267
+ },
2268
+ info: {
2269
+ icon: "ic:outline-info",
2270
+ color: "text-blue-400",
2271
+ className: "text-blue-400",
2272
+ dark: {
2273
+ bgGradient: "bg-[#14181d]",
2274
+ gradientColor: "#60a5fa",
2275
+ borderGradient: "border-[#60a5fa]",
2276
+ borderGradientColor: "#f0f0f0"
2277
+ },
2278
+ light: {
2279
+ bgGradient: "bg-[#fafafa]",
2280
+ gradientColor: "#3b82f6",
2281
+ borderGradient: "border-[#3b82f6]",
2282
+ borderGradientColor: "#3b82f6"
2283
+ }
2284
+ },
2285
+ default: {
2286
+ icon: "ic:round-notifications",
2287
+ color: "text-gray-400",
2288
+ className: "text-gray-400",
2289
+ dark: {
2290
+ bgGradient: "bg-[#14181d]",
2291
+ gradientColor: "#9ca3af",
2292
+ borderGradient: "border-[#9ca3af]",
2293
+ borderGradientColor: "#9ca3af"
2294
+ },
2295
+ light: {
2296
+ bgGradient: "bg-[#fafafa]",
2297
+ gradientColor: "#6b7280",
2298
+ borderGradient: "border-[#6b7280]",
2299
+ borderGradientColor: "#6b7280"
2300
+ }
2301
+ }
2302
+ };
2303
+ var CloseButton = React7.memo(({ closeToast }) => {
2304
+ const { theme } = useTheme();
2305
+ const handleClick = useCallback5((e) => {
2306
+ e.preventDefault();
2307
+ e.stopPropagation();
2308
+ closeToast?.();
2309
+ }, [closeToast]);
2310
+ const getCloseButtonColor = () => {
2311
+ const actualTheme = theme === "system" ? window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light" : theme;
2312
+ return actualTheme === "dark" ? "#b4b4b4" : "#6b7280";
2313
+ };
2314
+ const getCloseButtonHoverColor = () => {
2315
+ const actualTheme = theme === "system" ? window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light" : theme;
2316
+ return actualTheme === "dark" ? "white" : "#374151";
2317
+ };
2318
+ return /* @__PURE__ */ jsx12(
2319
+ Icon4,
2320
+ {
2321
+ icon: "vaadin:close",
2322
+ className: "flex items-center justify-center rounded-full relative z-10 flex-shrink-0 cursor-pointer transition-colors duration-200 drop-shadow-sm",
2323
+ onClick: handleClick,
2324
+ width: 14,
2325
+ height: 14,
2326
+ style: {
2327
+ color: getCloseButtonColor()
2328
+ },
2329
+ onMouseEnter: (e) => {
2330
+ e.currentTarget.style.color = getCloseButtonHoverColor();
2331
+ },
2332
+ onMouseLeave: (e) => {
2333
+ e.currentTarget.style.color = getCloseButtonColor();
2334
+ }
2335
+ }
2336
+ );
2337
+ });
2338
+ CloseButton.displayName = "CloseButton";
2339
+ var ToastContent = ({ type, title, message, component, closeToast }) => {
2340
+ const iconConfig = TOAST_ICONS[type];
2341
+ const { theme } = useTheme();
2342
+ const handleClose = useCallback5(() => {
2343
+ closeToast?.();
2344
+ }, [closeToast]);
2345
+ const getTextColor = () => {
2346
+ const actualTheme = theme === "system" ? window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light" : theme;
2347
+ return actualTheme === "dark" ? "white" : "#1f2937";
2348
+ };
2349
+ const getThemeConfig = () => {
2350
+ const actualTheme = theme === "system" ? window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light" : theme;
2351
+ return actualTheme === "dark" ? iconConfig.dark : iconConfig.light;
2352
+ };
2353
+ const themeConfig = getThemeConfig();
2354
+ const lightBaseBackgroundByType = {
2355
+ success: "#f0fdf4",
2356
+ error: "#fef2f2",
2357
+ warning: "#fffbeb",
2358
+ info: "#eff6ff",
2359
+ default: "#f9fafb"
2360
+ };
2361
+ if (component) {
2362
+ return /* @__PURE__ */ jsxs8("div", { className: `flex items-start gap-3 !min-h-[90px] w-full backdrop-blur-md p-4 shadow-2xl overflow-hidden ${themeConfig.bgGradient}`, children: [
2363
+ /* @__PURE__ */ jsx12("div", { className: "flex-1 relative z-10", children: component }),
2364
+ /* @__PURE__ */ jsx12("div", { className: "relative z-10", children: /* @__PURE__ */ jsx12(CloseButton, { closeToast: handleClose }) })
2365
+ ] });
2366
+ }
2367
+ return /* @__PURE__ */ jsxs8("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: [
1894
2368
  /* @__PURE__ */ jsx12(
1895
2369
  "div",
1896
2370
  {
1897
- className: "absolute left-0 top-0 w-full h-full rounded-md",
2371
+ className: "absolute left-0 top-0 w-full h-full rounded-xl",
1898
2372
  style: {
1899
- background: "#0f1419",
2373
+ background: theme === "dark" || theme === "system" && window.matchMedia("(prefers-color-scheme: dark)").matches ? "#0f1419" : lightBaseBackgroundByType[type],
1900
2374
  zIndex: -2
1901
2375
  }
1902
2376
  }
@@ -1904,9 +2378,9 @@ var LimitToastContainer = ({ message, onUpgrade, closeToast }) => {
1904
2378
  /* @__PURE__ */ jsx12(
1905
2379
  "div",
1906
2380
  {
1907
- className: "absolute left-0 top-0 w-full h-full pointer-events-none rounded-md",
2381
+ className: "absolute left-0 top-0 w-full h-full pointer-events-none rounded-xl",
1908
2382
  style: {
1909
- background: `linear-gradient(135deg, rgba(168,85,247,0.3) 0%, rgba(168,85,247,0.2) 15%, #1A1A1A 30%)`,
2383
+ 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%)`,
1910
2384
  zIndex: -1
1911
2385
  }
1912
2386
  }
@@ -1914,443 +2388,246 @@ var LimitToastContainer = ({ message, onUpgrade, closeToast }) => {
1914
2388
  /* @__PURE__ */ jsx12(
1915
2389
  "div",
1916
2390
  {
1917
- className: "absolute left-0 top-0 w-full h-full pointer-events-none rounded-md",
2391
+ className: "absolute left-0 top-0 w-full h-full pointer-events-none rounded-xl",
1918
2392
  style: {
1919
2393
  border: "2px solid transparent",
1920
- backgroundImage: `linear-gradient(135deg, rgba(168,85,247,0.6) 0%, rgba(168,85,247,0.4) 5%, transparent 22%)`,
2394
+ 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%)`,
1921
2395
  backgroundOrigin: "border-box",
1922
2396
  backgroundClip: "border-box",
1923
- WebkitMask: "linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0)",
2397
+ WebkitMask: "linear-gradient(#ffffff 0 0) padding-box, linear-gradient(#ffffff 0 0)",
1924
2398
  WebkitMaskComposite: "xor",
1925
- mask: "linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0)",
1926
- maskComposite: "exclude"
2399
+ zIndex: 0
1927
2400
  }
1928
2401
  }
1929
2402
  ),
1930
- /* @__PURE__ */ jsx12("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" }),
1931
- /* @__PURE__ */ jsx12("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" } }),
1932
- /* @__PURE__ */ jsx12("div", { className: "relative z-10 flex items-start gap-4 p-4", children: /* @__PURE__ */ jsxs8("div", { className: "flex flex-1 flex-col gap-3", children: [
1933
- /* @__PURE__ */ jsxs8("div", { className: "flex items-center justify-between", children: [
1934
- /* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-2", children: [
1935
- /* @__PURE__ */ jsx12("div", { className: "text-lg font-bold text-white", children: "Upgrade Required" }),
1936
- /* @__PURE__ */ jsx12("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" })
1937
- ] }),
1938
- /* @__PURE__ */ jsx12(
1939
- ClayxButton,
1940
- {
1941
- onClick: closeToast,
1942
- isIconOnly: true,
1943
- size: "sm",
1944
- onMouseEnter: () => setCloseHover(true),
1945
- onMouseLeave: () => setCloseHover(false),
1946
- style: {
1947
- height: "1.5rem",
1948
- width: "1.5rem",
1949
- minWidth: "1.5rem",
1950
- borderRadius: "9999px",
1951
- backgroundColor: closeHover ? "rgba(255,255,255,0.1)" : "rgba(255,255,255,0.05)",
1952
- transition: "background-color 150ms ease",
1953
- cursor: "pointer"
1954
- },
1955
- children: /* @__PURE__ */ jsx12(Icon4, { icon: "iconamoon:close", className: "w-4 h-4 text-gray-400" })
1956
- }
1957
- )
1958
- ] }),
1959
- /* @__PURE__ */ jsx12("p", { className: "text-sm text-gray-300 leading-relaxed", children: message }),
1960
- /* @__PURE__ */ jsx12("div", { className: "mt-1 flex items-center gap-3", children: /* @__PURE__ */ jsx12(
1961
- ClayxButton,
2403
+ /* @__PURE__ */ jsx12("div", { className: "flex-shrink-0 mt-0.5 relative z-10", children: /* @__PURE__ */ jsx12("div", { className: `w-7 h-7 backdrop-blur-sm rounded-full flex items-center justify-center ${theme === "dark" || theme === "system" && window.matchMedia("(prefers-color-scheme: dark)").matches ? "bg-white/10" : "bg-black/5"}`, children: /* @__PURE__ */ jsx12(
2404
+ Icon4,
2405
+ {
2406
+ icon: iconConfig.icon,
2407
+ width: 16,
2408
+ height: 16,
2409
+ className: iconConfig.color,
2410
+ style: {
2411
+ color: themeConfig.gradientColor
2412
+ }
2413
+ }
2414
+ ) }) }),
2415
+ /* @__PURE__ */ jsxs8("div", { className: "flex flex-col gap-1 flex-1 relative z-10", children: [
2416
+ title && /* @__PURE__ */ jsx12(
2417
+ "div",
1962
2418
  {
1963
- onClick: () => {
1964
- onUpgrade();
1965
- closeToast?.();
2419
+ className: "text-[16px] font-semibold leading-tight drop-shadow-sm",
2420
+ style: {
2421
+ color: getTextColor(),
2422
+ backgroundClip: "text"
1966
2423
  },
1967
- onMouseEnter: () => setHover(true),
1968
- onMouseLeave: () => setHover(false),
2424
+ children: title
2425
+ }
2426
+ ),
2427
+ message && /* @__PURE__ */ jsx12(
2428
+ "div",
2429
+ {
2430
+ className: "text-[13px] font-normal leading-relaxed drop-shadow-sm",
1969
2431
  style: {
1970
- flex: 1,
1971
- color: "#ffffff",
1972
- fontWeight: 600,
1973
- cursor: "pointer",
1974
- transition: "all 300ms ease-in-out",
1975
- backgroundImage: hover ? "linear-gradient(to right, #9333ea, #db2777)" : "linear-gradient(to right, #a855f7, #ec4899)",
1976
- boxShadow: hover ? "0 10px 15px -3px rgba(168,85,247,0.3), 0 4px 6px -2px rgba(168,85,247,0.3)" : "none"
2432
+ color: getTextColor(),
2433
+ backgroundClip: "text"
1977
2434
  },
1978
- children: /* @__PURE__ */ jsxs8("span", { className: "flex items-center gap-2", children: [
1979
- /* @__PURE__ */ jsx12(Icon4, { icon: "solar:rocket-2-bold", className: "w-4 h-4" }),
1980
- "Upgrade Now"
1981
- ] })
2435
+ children: message
1982
2436
  }
1983
- ) })
1984
- ] }) })
2437
+ )
2438
+ ] }),
2439
+ /* @__PURE__ */ jsx12("div", { className: "relative z-10", children: /* @__PURE__ */ jsx12(CloseButton, { closeToast: handleClose }) })
1985
2440
  ] });
1986
2441
  };
1987
- function showLimitUpgradeToast(message, onUpgrade) {
1988
- GoeyToast.default({
1989
- render: (closeToast) => /* @__PURE__ */ jsx12(LimitToastContainer, { message, onUpgrade, closeToast }),
1990
- options: {
1991
- autoClose: false
1992
- }
1993
- });
1994
- }
1995
-
1996
- // src/services/ai-workflow.ts
1997
- var AIWorkflowClient = class {
1998
- constructor(options = {}) {
1999
- this.baseUrl = options.baseUrl?.replace(/\/+$/, "") || "";
2000
- this.apiKey = options.apiKey;
2001
- this.headers = { "Content-Type": "application/json", ...options.headers || {} };
2002
- this.fetchImpl = options.fetchImpl || fetch.bind(globalThis);
2003
- }
2004
- buildHeaders(extra) {
2005
- const h = { ...this.headers, ...extra || {} };
2006
- if (this.apiKey && !h["Authorization"]) {
2007
- h["Authorization"] = `Bearer ${this.apiKey}`;
2008
- }
2009
- return h;
2010
- }
2011
- async safeJson(resp) {
2012
- try {
2013
- return await resp.json();
2014
- } catch (_e) {
2015
- return null;
2016
- }
2017
- }
2018
- /**
2019
- * 按 ID 执行工作流:POST {baseUrl}/workflow/{workflowId}/execute
2020
- * body: { input, options }
2021
- */
2022
- async executeWorkflow(workflowId, inputs, options) {
2023
- if (!this.baseUrl) {
2024
- throw new Error("AI workflow client requires a baseUrl (e.g. https://evoagentx-server.fly.dev)");
2025
- }
2026
- const url = `${this.baseUrl}/workflow/${workflowId}/execute`;
2027
- try {
2028
- const res = await this.fetchImpl(url, {
2029
- method: "POST",
2030
- headers: this.buildHeaders(),
2031
- body: JSON.stringify({ inputs, options })
2032
- });
2033
- const data = await this.safeJson(res);
2034
- if (!res.ok) {
2035
- return { success: false, error: data?.error || `HTTP ${res.status}` };
2036
- }
2037
- if (data && data.status && data.status === 4003) {
2038
- showLimitUpgradeToast(
2039
- "Your credits are exhausted. Please upgrade your plan to continue generating projects.",
2040
- () => window.open("https://clayx.ai/pricing", "_blank")
2041
- );
2042
- return null;
2043
- }
2044
- return data || { success: true };
2045
- } catch (error) {
2046
- return { success: false, error: error instanceof Error ? error.message : "Network error" };
2047
- }
2442
+ var defaultToastOptions = {
2443
+ position: "bottom-right",
2444
+ autoClose: 3e3,
2445
+ hideProgressBar: true,
2446
+ closeOnClick: false,
2447
+ pauseOnHover: true,
2448
+ draggable: true,
2449
+ pauseOnFocusLoss: false,
2450
+ transition: Bounce
2451
+ };
2452
+ var getToastifyTheme = () => {
2453
+ if (typeof window !== "undefined") {
2454
+ const root = document.documentElement;
2455
+ if (root.classList.contains("dark")) return "dark";
2456
+ if (root.classList.contains("light")) return "light";
2457
+ return window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
2048
2458
  }
2459
+ return "light";
2049
2460
  };
2050
- function createAIWorkflowClient(options = {}) {
2051
- return new AIWorkflowClient(options);
2052
- }
2053
- var aiWorkflow = createAIWorkflowClient({ baseUrl: "https://evoagentx-server" });
2054
-
2055
- // src/services/request/index.ts
2056
- import axios from "axios";
2057
- var Request = class {
2058
- constructor(config) {
2059
- this.abortControllers = /* @__PURE__ */ new Map();
2060
- this.instance = axios.create({
2061
- ...config,
2062
- withCredentials: true,
2063
- validateStatus: (status) => {
2064
- return status >= 200 && status < 300;
2065
- }
2066
- });
2067
- this.interceptors = config.interceptors;
2068
- this.instance.interceptors.request.use(
2069
- this.interceptors?.requestInterceptor,
2070
- this.interceptors?.requestInterceptorCatch
2071
- );
2072
- this.instance.interceptors.response.use(
2073
- this.interceptors?.responseInterceptor,
2074
- this.interceptors?.responseInterceptorCatch
2075
- );
2076
- this.instance.interceptors.request.use(
2077
- (config2) => {
2078
- return config2;
2079
- },
2080
- (err) => {
2081
- return Promise.reject(err);
2082
- }
2083
- );
2084
- this.instance.interceptors.response.use(
2085
- (res) => {
2086
- return res.data;
2461
+ var createToast = (type) => {
2462
+ return (params) => {
2463
+ const { title, message, component, options } = params;
2464
+ toast(
2465
+ ({ closeToast }) => {
2466
+ if (params.render) return params.render(closeToast ?? (() => {
2467
+ }));
2468
+ return /* @__PURE__ */ jsx12(
2469
+ ToastContent,
2470
+ {
2471
+ type,
2472
+ title,
2473
+ message: message || "",
2474
+ component,
2475
+ closeToast
2476
+ }
2477
+ );
2087
2478
  },
2088
- (err) => {
2089
- if (axios.isCancel(err)) {
2090
- return Promise.reject({
2091
- isCanceled: true,
2092
- message: "request canceled",
2093
- originalError: err
2094
- });
2095
- }
2096
- if (err.response?.data?.error) {
2097
- return Promise.reject(err.response.data.error);
2098
- }
2099
- return Promise.reject(err);
2479
+ {
2480
+ ...defaultToastOptions,
2481
+ ...options,
2482
+ theme: getToastifyTheme(),
2483
+ className: "!p-0 !shadow-none !rounded-xl",
2484
+ style: { padding: 0, borderRadius: "0.75rem" }
2100
2485
  }
2101
2486
  );
2102
- }
2103
- cancelRequest(url) {
2104
- this.abortControllers.forEach((controller, key) => {
2105
- if (key.includes(url)) {
2106
- controller.abort();
2107
- this.abortControllers.delete(key);
2108
- }
2109
- });
2110
- }
2111
- cancelAllRequests() {
2112
- this.abortControllers.forEach((controller) => {
2113
- controller.abort();
2114
- });
2115
- this.abortControllers.clear();
2116
- }
2117
- request(config) {
2118
- const controller = new AbortController();
2119
- const url = config.url || "";
2120
- const method = config.method || "GET";
2121
- const key = `${method}:${url}`;
2122
- this.abortControllers.set(key, controller);
2123
- config.signal = controller.signal;
2124
- return new Promise((resolve, reject) => {
2125
- if (config.interceptors?.requestInterceptor) {
2126
- config = config.interceptors.requestInterceptor(config);
2127
- }
2128
- this.instance.request(config).then((res) => {
2129
- this.abortControllers.delete(key);
2130
- if (config.interceptors?.responseInterceptor) {
2131
- res = config.interceptors.responseInterceptor(res);
2132
- }
2133
- resolve(res);
2134
- }).catch((err) => {
2135
- this.abortControllers.delete(key);
2136
- reject(err);
2137
- });
2138
- });
2139
- }
2140
- get(config) {
2141
- return this.request({ ...config, method: "GET" });
2142
- }
2143
- post(config) {
2144
- return this.request({ ...config, method: "POST" });
2145
- }
2146
- delete(config) {
2147
- return this.request({ ...config, method: "DELETE" });
2148
- }
2149
- put(config) {
2150
- return this.request({ ...config, method: "PUT" });
2151
- }
2152
- patch(config) {
2153
- return this.request({ ...config, method: "PATCH" });
2154
- }
2487
+ };
2488
+ };
2489
+ var ClayxToast = {
2490
+ success: createToast("success"),
2491
+ error: createToast("error"),
2492
+ warning: createToast("warning"),
2493
+ info: createToast("info"),
2494
+ default: createToast("default")
2155
2495
  };
2156
- var request_default = Request;
2157
2496
 
2158
- // src/services/ai-workflow-axios.ts
2159
- function createAIWorkflowClientAxios(options = {}) {
2160
- const basePath = options.basePath ?? "/api";
2161
- const baseUrl = (options.baseUrl || "https://evoagentx-server.fly.dev").replace(/\/+$/, "");
2162
- const baseAPI = `${baseUrl}${basePath.startsWith("/") ? "" : "/"}${basePath}`.replace(/\/+$/, "");
2163
- const client = options.requestInstance || new request_default({
2164
- baseURL: baseAPI,
2165
- timeout: options.timeout ?? 6e4,
2166
- interceptors: {
2167
- requestInterceptor: (config) => {
2168
- config.headers = config.headers || {};
2169
- if (options.apiKey && !config.headers["Authorization"]) {
2170
- config.headers["Authorization"] = `Bearer ${options.apiKey}`;
2497
+ // src/components/ui/LimitUpgradeToast.tsx
2498
+ import { jsx as jsx13, jsxs as jsxs9 } from "react/jsx-runtime";
2499
+ var LimitToastContainer = ({ message, onUpgrade, closeToast }) => {
2500
+ const [hover, setHover] = React8.useState(false);
2501
+ const [closeHover, setCloseHover] = React8.useState(false);
2502
+ return /* @__PURE__ */ jsxs9("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: [
2503
+ /* @__PURE__ */ jsx13(
2504
+ "div",
2505
+ {
2506
+ className: "absolute left-0 top-0 w-full h-full rounded-md",
2507
+ style: {
2508
+ background: "#0f1419",
2509
+ zIndex: -2
2510
+ }
2511
+ }
2512
+ ),
2513
+ /* @__PURE__ */ jsx13(
2514
+ "div",
2515
+ {
2516
+ className: "absolute left-0 top-0 w-full h-full pointer-events-none rounded-md",
2517
+ style: {
2518
+ background: `linear-gradient(135deg, rgba(168,85,247,0.3) 0%, rgba(168,85,247,0.2) 15%, #1A1A1A 30%)`,
2519
+ zIndex: -1
2171
2520
  }
2172
- if (options.headers) {
2173
- config.headers = { ...config.headers || {}, ...options.headers };
2521
+ }
2522
+ ),
2523
+ /* @__PURE__ */ jsx13(
2524
+ "div",
2525
+ {
2526
+ className: "absolute left-0 top-0 w-full h-full pointer-events-none rounded-md",
2527
+ style: {
2528
+ border: "2px solid transparent",
2529
+ backgroundImage: `linear-gradient(135deg, rgba(168,85,247,0.6) 0%, rgba(168,85,247,0.4) 5%, transparent 22%)`,
2530
+ backgroundOrigin: "border-box",
2531
+ backgroundClip: "border-box",
2532
+ WebkitMask: "linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0)",
2533
+ WebkitMaskComposite: "xor",
2534
+ mask: "linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0)",
2535
+ maskComposite: "exclude"
2174
2536
  }
2175
- return config;
2176
- },
2177
- requestInterceptorCatch: (err) => Promise.reject(err),
2178
- responseInterceptor: (res) => res,
2179
- responseInterceptorCatch: (err) => Promise.reject(err)
2537
+ }
2538
+ ),
2539
+ /* @__PURE__ */ jsx13("div", { className: "absolute -top-16 -right-16 h-32 w-32 rounded-full bg-gradient-to-br from-purple-500/20 via-pink-500/10 to-transparent blur-3xl animate-pulse" }),
2540
+ /* @__PURE__ */ jsx13("div", { className: "absolute -bottom-16 -left-16 h-32 w-32 rounded-full bg-gradient-to-tr from-blue-500/10 to-transparent blur-2xl animate-pulse", style: { animationDelay: "1s" } }),
2541
+ /* @__PURE__ */ jsx13("div", { className: "relative z-10 flex items-start gap-4 p-4", children: /* @__PURE__ */ jsxs9("div", { className: "flex flex-1 flex-col gap-3", children: [
2542
+ /* @__PURE__ */ jsxs9("div", { className: "flex items-center justify-between", children: [
2543
+ /* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-2", children: [
2544
+ /* @__PURE__ */ jsx13("div", { className: "text-lg font-bold text-white", children: "Upgrade Required" }),
2545
+ /* @__PURE__ */ jsx13("div", { className: "px-2 py-0.5 text-xs font-bold bg-purple-500/20 text-purple-400 rounded-md border border-purple-500/30", children: "Premium" })
2546
+ ] }),
2547
+ /* @__PURE__ */ jsx13(
2548
+ ClayxButton,
2549
+ {
2550
+ onClick: closeToast,
2551
+ isIconOnly: true,
2552
+ size: "sm",
2553
+ onMouseEnter: () => setCloseHover(true),
2554
+ onMouseLeave: () => setCloseHover(false),
2555
+ style: {
2556
+ height: "1.5rem",
2557
+ width: "1.5rem",
2558
+ minWidth: "1.5rem",
2559
+ borderRadius: "9999px",
2560
+ backgroundColor: closeHover ? "rgba(255,255,255,0.1)" : "rgba(255,255,255,0.05)",
2561
+ transition: "background-color 150ms ease",
2562
+ cursor: "pointer"
2563
+ },
2564
+ children: /* @__PURE__ */ jsx13(Icon5, { icon: "iconamoon:close", className: "w-4 h-4 text-gray-400" })
2565
+ }
2566
+ )
2567
+ ] }),
2568
+ /* @__PURE__ */ jsx13("p", { className: "text-sm text-gray-300 leading-relaxed", children: message }),
2569
+ /* @__PURE__ */ jsx13("div", { className: "mt-1 flex items-center gap-3", children: /* @__PURE__ */ jsx13(
2570
+ ClayxButton,
2571
+ {
2572
+ onClick: () => {
2573
+ onUpgrade();
2574
+ closeToast?.();
2575
+ },
2576
+ onMouseEnter: () => setHover(true),
2577
+ onMouseLeave: () => setHover(false),
2578
+ style: {
2579
+ flex: 1,
2580
+ color: "#ffffff",
2581
+ fontWeight: 600,
2582
+ cursor: "pointer",
2583
+ transition: "all 300ms ease-in-out",
2584
+ backgroundImage: hover ? "linear-gradient(to right, #9333ea, #db2777)" : "linear-gradient(to right, #a855f7, #ec4899)",
2585
+ boxShadow: hover ? "0 10px 15px -3px rgba(168,85,247,0.3), 0 4px 6px -2px rgba(168,85,247,0.3)" : "none"
2586
+ },
2587
+ children: /* @__PURE__ */ jsxs9("span", { className: "flex items-center gap-2", children: [
2588
+ /* @__PURE__ */ jsx13(Icon5, { icon: "solar:rocket-2-bold", className: "w-4 h-4" }),
2589
+ "Upgrade Now"
2590
+ ] })
2591
+ }
2592
+ ) })
2593
+ ] }) })
2594
+ ] });
2595
+ };
2596
+ function showLimitUpgradeToast(message, onUpgrade) {
2597
+ ClayxToast.default({
2598
+ render: (closeToast) => /* @__PURE__ */ jsx13(LimitToastContainer, { message, onUpgrade, closeToast }),
2599
+ options: {
2600
+ autoClose: false
2180
2601
  }
2181
2602
  });
2182
- return {
2183
- async executeWorkflow(workflowId, inputs, opts) {
2184
- const url = `${baseUrl}/workflow/${workflowId}/execute`;
2185
- const data = await client.post({ url, data: { inputs, options: opts } });
2186
- return data;
2187
- }
2188
- };
2189
2603
  }
2190
2604
 
2191
- // src/services/artifact-types.ts
2192
- function canAccessArtifact(a, ctx = {}) {
2193
- if (!a) return false;
2194
- if (a.visibility === "public") return true;
2195
- if (a.visibility === "project") {
2196
- if (ctx.projectId && a.projectId && ctx.projectId === a.projectId) return true;
2197
- if (ctx.tokenScopes && ctx.tokenScopes.includes("project:read")) return true;
2198
- return false;
2199
- }
2200
- if (a.visibility === "private") {
2201
- if (ctx.userId && a.ownerId && ctx.userId === a.ownerId) return true;
2202
- if (ctx.tokenScopes && (ctx.tokenScopes.includes("artifact:read:all") || ctx.tokenScopes.includes("admin"))) return true;
2203
- return false;
2204
- }
2205
- if (a.visibility === "shared") {
2206
- if (ctx.userId && a.sharedWith && a.sharedWith.includes(ctx.userId)) return true;
2207
- if (ctx.tokenScopes && (ctx.tokenScopes.includes("artifact:read:all") || ctx.tokenScopes.includes("admin"))) return true;
2208
- return false;
2605
+ // src/services/limit-exceeded.ts
2606
+ init_config();
2607
+ var DEFAULT_LIMIT_EXCEEDED_MESSAGE = "Your credits are exhausted. Please upgrade your plan to continue generating projects.";
2608
+ function handleLimitExceeded(context, options) {
2609
+ options?.onLimitExceeded?.(context);
2610
+ if (options?.showUpgradeToast === false) {
2611
+ return;
2209
2612
  }
2210
- return false;
2211
- }
2212
-
2213
- // src/services/artifacts-client.ts
2214
- function createArtifactsClient(req) {
2215
- return {
2216
- async create(input) {
2217
- return await req.post({ url: "/artifacts", data: input });
2218
- },
2219
- async list(query) {
2220
- return await req.get({ url: "/artifacts", params: query });
2221
- },
2222
- async get(id) {
2223
- return await req.get({ url: `/artifacts/${encodeURIComponent(id)}` });
2224
- },
2225
- async setVisibility(id, visibility) {
2226
- await req.patch({ url: `/artifacts/${encodeURIComponent(id)}/visibility`, data: { visibility } });
2227
- },
2228
- async delete(id) {
2229
- await req.delete({ url: `/artifacts/${encodeURIComponent(id)}` });
2230
- },
2231
- // convenience local check (server is authoritative)
2232
- canAccessLocal(a, ctx) {
2233
- if (!a) return false;
2234
- if (a.visibility === "public") return true;
2235
- if (a.visibility === "project") return Boolean(ctx.projectId && a.projectId && ctx.projectId === a.projectId);
2236
- if (a.visibility === "private") return Boolean(ctx.userId && a.ownerId && ctx.userId === a.ownerId);
2237
- if (a.visibility === "shared") return Boolean(ctx.userId && a.sharedWith && a.sharedWith.includes(ctx.userId));
2238
- return false;
2239
- }
2240
- };
2613
+ const upgradeUrl = options?.upgradeUrl || `${getEnvs().AUTH_ROOT_VALUE}/price`;
2614
+ showLimitUpgradeToast(
2615
+ context.message || DEFAULT_LIMIT_EXCEEDED_MESSAGE,
2616
+ () => window.open(upgradeUrl, "_blank")
2617
+ );
2241
2618
  }
2242
-
2243
- // src/services/upload-client.ts
2244
- function createUploadClient(req, projectId) {
2245
- const uploadUrl = projectId ? `/entities/apps/${projectId}/files` : "/files";
2619
+ function mergeLimitExceededOptions(base, override) {
2620
+ if (!base && !override) {
2621
+ return void 0;
2622
+ }
2246
2623
  return {
2247
- /**
2248
- * 上传单个文件
2249
- *
2250
- * @example
2251
- * ```typescript
2252
- * const { url } = await client.upload.file(imageFile)
2253
- * console.log('文件地址:', url)
2254
- * ```
2255
- */
2256
- async file(file, options) {
2257
- const formData = new FormData();
2258
- if (typeof file === "string") {
2259
- if (file.startsWith("data:")) {
2260
- const response2 = await fetch(file);
2261
- const blob = await response2.blob();
2262
- formData.append("file", blob, "upload.bin");
2263
- } else {
2264
- formData.append("fileUrl", file);
2265
- }
2266
- } else if (file instanceof File) {
2267
- formData.append("file", file, file.name);
2268
- } else {
2269
- formData.append("file", file, "upload.bin");
2270
- }
2271
- if (options?.metadata) {
2272
- formData.append("metadata", JSON.stringify(options.metadata));
2273
- }
2274
- const response = await req.post({
2275
- url: uploadUrl,
2276
- data: formData,
2277
- signal: options?.signal
2278
- });
2279
- return {
2280
- url: response.data.publicUrl
2281
- };
2282
- },
2283
- /**
2284
- * 上传图片(快捷方法,专为 AI 设计)
2285
- *
2286
- * @example
2287
- * ```typescript
2288
- * const { url } = await client.upload.image(imageFile)
2289
- * ```
2290
- */
2291
- async image(file) {
2292
- const result = await this.file(file);
2293
- return { url: result.url };
2294
- },
2295
- /**
2296
- * 批量上传文件
2297
- *
2298
- * @example
2299
- * ```typescript
2300
- * const result = await client.upload.batch({
2301
- * files: [file1, file2, file3],
2302
- * concurrent: 3,
2303
- * onProgress: (completed, total) => {
2304
- * console.log(`${completed}/${total}`)
2305
- * }
2306
- * })
2307
- * ```
2308
- */
2309
- async batch(options) {
2310
- const { files, concurrent = 3, onProgress, onFileComplete, signal } = options;
2311
- const success = [];
2312
- const failed = [];
2313
- let completed = 0;
2314
- for (let i = 0; i < files.length; i += concurrent) {
2315
- if (signal?.aborted) break;
2316
- const batch = files.slice(i, Math.min(i + concurrent, files.length));
2317
- const promises = batch.map(async (file, batchIndex) => {
2318
- const globalIndex = i + batchIndex;
2319
- try {
2320
- const result = await this.file(file, { signal });
2321
- success.push(result);
2322
- if (onFileComplete) {
2323
- onFileComplete(result, globalIndex);
2324
- }
2325
- } catch (error) {
2326
- const errorMsg = error instanceof Error ? error.message : String(error);
2327
- failed.push({ index: globalIndex, error: errorMsg });
2328
- if (onFileComplete) {
2329
- onFileComplete(
2330
- error instanceof Error ? error : new Error(errorMsg),
2331
- globalIndex
2332
- );
2333
- }
2334
- } finally {
2335
- completed++;
2336
- if (onProgress) {
2337
- onProgress(completed, files.length);
2338
- }
2339
- }
2340
- });
2341
- await Promise.all(promises);
2342
- }
2343
- return {
2344
- success,
2345
- failed,
2346
- total: files.length
2347
- };
2348
- }
2624
+ ...base,
2625
+ ...override,
2626
+ onLimitExceeded: override?.onLimitExceeded ?? base?.onLimitExceeded
2349
2627
  };
2350
2628
  }
2351
2629
 
2352
2630
  // src/services/sse-executor.ts
2353
- init_config();
2354
2631
  async function executeSSEWorkflow(request, options = {}) {
2355
2632
  const startTime = Date.now();
2356
2633
  const result = {
@@ -2441,7 +2718,7 @@ async function executeSSEWorkflow(request, options = {}) {
2441
2718
  if (errorData.log_type === "execution_display_error") {
2442
2719
  const errorContent = errorData.content;
2443
2720
  const displayMessage = errorContent || "Workflow execution failed";
2444
- GoeyToast.error({
2721
+ ClayxToast.error({
2445
2722
  title: "Execution Error",
2446
2723
  message: displayMessage
2447
2724
  });
@@ -2451,11 +2728,16 @@ async function executeSSEWorkflow(request, options = {}) {
2451
2728
  options.onStreamContent(rawEvent.delta);
2452
2729
  }
2453
2730
  if (rawEvent.type === "key_limit_exceed") {
2454
- const errorMsg = rawEvent.data.content;
2731
+ const errorMsg = rawEvent.data?.content || DEFAULT_LIMIT_EXCEEDED_MESSAGE;
2455
2732
  result.errors.push(errorMsg);
2456
- showLimitUpgradeToast(
2457
- "Your credits are exhausted. Please upgrade your plan to continue generating projects.",
2458
- () => window.open(`${getEnvs().AUTH_ROOT_VALUE}/price`, "_blank")
2733
+ handleLimitExceeded(
2734
+ {
2735
+ source: "sse-executor",
2736
+ message: errorMsg,
2737
+ eventType: rawEvent.type,
2738
+ rawData: rawEvent.data
2739
+ },
2740
+ options.limitExceeded
2459
2741
  );
2460
2742
  if (options.onError) {
2461
2743
  options.onError(new Error(errorMsg));
@@ -2666,7 +2948,7 @@ function createEventIterable(streamFactory, config) {
2666
2948
  };
2667
2949
  }
2668
2950
  function createSSEClient(config) {
2669
- const { baseUrl, projectId, getAuthToken } = config;
2951
+ const { baseUrl, projectId, getAuthToken, limitExceeded } = config;
2670
2952
  const stream = (streamConfig) => {
2671
2953
  const { signal: externalSignal, ...callbacks } = streamConfig;
2672
2954
  const request = resolveRequest(baseUrl, projectId, streamConfig);
@@ -2682,7 +2964,11 @@ function createSSEClient(config) {
2682
2964
  {
2683
2965
  ...callbacks,
2684
2966
  authToken,
2685
- signal: controller.signal
2967
+ signal: controller.signal,
2968
+ limitExceeded: mergeLimitExceededOptions(
2969
+ limitExceeded,
2970
+ streamConfig.limitExceeded
2971
+ )
2686
2972
  }
2687
2973
  ).finally(() => {
2688
2974
  controller.cleanup();
@@ -2858,6 +3144,19 @@ async function executeWorkflowStreamPost(baseUrl, projectId, workflowId, request
2858
3144
  break;
2859
3145
  case "error":
2860
3146
  throw new Error(event.message || "Workflow execution failed");
3147
+ case "key_limit_exceed": {
3148
+ const errorMessage = event?.data?.content || event.message || DEFAULT_LIMIT_EXCEEDED_MESSAGE;
3149
+ handleLimitExceeded(
3150
+ {
3151
+ source: "sse-executor",
3152
+ message: errorMessage,
3153
+ eventType: event.type,
3154
+ rawData: event.data
3155
+ },
3156
+ options.limitExceeded
3157
+ );
3158
+ throw new Error(errorMessage);
3159
+ }
2861
3160
  }
2862
3161
  } catch (err) {
2863
3162
  console.error("Failed to parse SSE event:", err);
@@ -2876,12 +3175,12 @@ async function executeWorkflowStreamPost(baseUrl, projectId, workflowId, request
2876
3175
  }
2877
3176
 
2878
3177
  // src/services/workflow-executor.ts
2879
- init_config();
2880
3178
  var WorkflowExecutor = class {
2881
- constructor(baseUrl, projectId, authToken) {
3179
+ constructor(baseUrl, projectId, authToken, limitExceeded) {
2882
3180
  this.baseUrl = baseUrl.replace(/\/$/, "");
2883
3181
  this.projectId = projectId;
2884
3182
  this.authToken = authToken;
3183
+ this.limitExceeded = limitExceeded;
2885
3184
  }
2886
3185
  /**
2887
3186
  * 执行工作流 (SSE 模式)
@@ -2931,6 +3230,10 @@ var WorkflowExecutor = class {
2931
3230
  errors: []
2932
3231
  };
2933
3232
  let streamContent = "";
3233
+ const limitExceededOptions = mergeLimitExceededOptions(
3234
+ this.limitExceeded,
3235
+ options?.limitExceeded
3236
+ );
2934
3237
  try {
2935
3238
  const response = await fetch(url, {
2936
3239
  method: "POST",
@@ -2983,11 +3286,16 @@ var WorkflowExecutor = class {
2983
3286
  }
2984
3287
  }
2985
3288
  } else if (event.type === "key_limit_exceed") {
2986
- const errorMsg = event.data?.content;
3289
+ const errorMsg = event.data?.content || DEFAULT_LIMIT_EXCEEDED_MESSAGE;
2987
3290
  result.errors.push(errorMsg);
2988
- showLimitUpgradeToast(
2989
- "Your credits are exhausted. Please upgrade your plan to continue generating projects.",
2990
- () => window.open(`${getEnvs().AUTH_ROOT_VALUE}/price`, "_blank")
3291
+ handleLimitExceeded(
3292
+ {
3293
+ source: "workflow-executor-sse",
3294
+ message: errorMsg,
3295
+ eventType: event.type,
3296
+ rawData: event.data
3297
+ },
3298
+ limitExceededOptions
2991
3299
  );
2992
3300
  if (options?.onError) {
2993
3301
  options.onError(new Error(errorMsg));
@@ -3071,6 +3379,17 @@ var WorkflowExecutor = class {
3071
3379
  body: JSON.stringify({ inputs })
3072
3380
  });
3073
3381
  const data = await response.json();
3382
+ if (data && data.status === 4003) {
3383
+ handleLimitExceeded(
3384
+ {
3385
+ source: "workflow-executor-rest",
3386
+ message: data?.error || data?.message || DEFAULT_LIMIT_EXCEEDED_MESSAGE,
3387
+ status: response.status,
3388
+ rawData: data
3389
+ },
3390
+ this.limitExceeded
3391
+ );
3392
+ }
3074
3393
  return {
3075
3394
  status: response.status,
3076
3395
  data
@@ -3152,14 +3471,6 @@ function createClient(opts) {
3152
3471
  },
3153
3472
  requestInterceptorCatch: (err) => Promise.reject(err),
3154
3473
  responseInterceptor: (res) => {
3155
- const data = res.data;
3156
- if (data && data.status && data.status === 4003) {
3157
- showLimitUpgradeToast(
3158
- "Your credits are exhausted. Please upgrade your plan to continue generating projects.",
3159
- () => window.open(`${getEnvs().AUTH_ROOT_VALUE}/price`, "_blank")
3160
- );
3161
- return res;
3162
- }
3163
3474
  return res;
3164
3475
  },
3165
3476
  responseInterceptorCatch: (err) => Promise.reject(err)
@@ -3267,7 +3578,8 @@ function createClient(opts) {
3267
3578
  void fetchExternalToken();
3268
3579
  }
3269
3580
  return token ?? cachedExternalToken ?? getToken() ?? null;
3270
- }
3581
+ },
3582
+ limitExceeded: opts.limitExceeded
3271
3583
  });
3272
3584
  const assignMethod = (config, method) => method ? { ...config, method } : config;
3273
3585
  function createMethodInvoker(invoker) {
@@ -3329,7 +3641,8 @@ function createClient(opts) {
3329
3641
  const executor = new WorkflowExecutor(
3330
3642
  actualAiBaseUrl,
3331
3643
  opts.projectId,
3332
- getCachedOrGlobalToken() ?? void 0
3644
+ getCachedOrGlobalToken() ?? void 0,
3645
+ opts.limitExceeded
3333
3646
  );
3334
3647
  return {
3335
3648
  executeSse: (inputs, options) => {
@@ -3547,11 +3860,11 @@ function createClient(opts) {
3547
3860
  }
3548
3861
 
3549
3862
  // src/hooks/use-mobile.ts
3550
- import * as React8 from "react";
3863
+ import * as React9 from "react";
3551
3864
  var MOBILE_BREAKPOINT = 768;
3552
3865
  function useIsMobile() {
3553
- const [isMobile, setIsMobile] = React8.useState(void 0);
3554
- React8.useEffect(() => {
3866
+ const [isMobile, setIsMobile] = React9.useState(void 0);
3867
+ React9.useEffect(() => {
3555
3868
  const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
3556
3869
  const onChange = () => {
3557
3870
  setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
@@ -3579,7 +3892,7 @@ function useDebounce(value, delay) {
3579
3892
  }
3580
3893
 
3581
3894
  // src/hooks/use-workflow-stream.ts
3582
- import { useState as useState11, useCallback as useCallback5, useRef as useRef2 } from "react";
3895
+ import { useState as useState11, useCallback as useCallback6, useRef as useRef2 } from "react";
3583
3896
  function useWorkflowStream() {
3584
3897
  const [state, setState] = useState11({
3585
3898
  loading: false,
@@ -3590,7 +3903,7 @@ function useWorkflowStream() {
3590
3903
  error: null
3591
3904
  });
3592
3905
  const abortControllerRef = useRef2(null);
3593
- const execute = useCallback5(async (executeWorkflowStream, workflowId, inputs) => {
3906
+ const execute = useCallback6(async (executeWorkflowStream, workflowId, inputs) => {
3594
3907
  setState({
3595
3908
  loading: true,
3596
3909
  progress: 0,
@@ -3643,7 +3956,7 @@ function useWorkflowStream() {
3643
3956
  throw error;
3644
3957
  }
3645
3958
  }, []);
3646
- const cancel = useCallback5(() => {
3959
+ const cancel = useCallback6(() => {
3647
3960
  if (abortControllerRef.current) {
3648
3961
  abortControllerRef.current.abort();
3649
3962
  setState((prev) => ({
@@ -3653,7 +3966,7 @@ function useWorkflowStream() {
3653
3966
  }));
3654
3967
  }
3655
3968
  }, []);
3656
- const reset = useCallback5(() => {
3969
+ const reset = useCallback6(() => {
3657
3970
  setState({
3658
3971
  loading: false,
3659
3972
  progress: 0,
@@ -3958,13 +4271,14 @@ var elementSelector = {
3958
4271
  export {
3959
4272
  AUTH_TOKEN_KEY,
3960
4273
  ClayxButton,
4274
+ ClayxToast,
4275
+ DEFAULT_LIMIT_EXCEEDED_MESSAGE,
3961
4276
  DefaultErrorFallback,
3962
4277
  ElementSelector,
3963
4278
  ElementSelectorProvider,
3964
4279
  ErrorBoundary,
3965
4280
  FloatingButton,
3966
4281
  GlobalToastContainer,
3967
- GoeyToast,
3968
4282
  HowOneProvider,
3969
4283
  Loading,
3970
4284
  LoadingSpinner,
@@ -3988,11 +4302,13 @@ export {
3988
4302
  getEnvs,
3989
4303
  getGlobalEnvironment,
3990
4304
  getToken,
4305
+ handleLimitExceeded,
3991
4306
  client_default as howone,
3992
4307
  iframeNavigation,
3993
4308
  initIframeNavigation,
3994
4309
  isTokenValid,
3995
4310
  loginWithEmailCode,
4311
+ mergeLimitExceededOptions,
3996
4312
  onAuthStateChanged,
3997
4313
  parseUserFromToken,
3998
4314
  sendElementSelectionToParent,