@howone/sdk 0.7.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.d.mts +29 -3
- package/dist/index.d.ts +29 -3
- package/dist/index.js +499 -440
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +496 -440
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -760,6 +760,355 @@ function getCodeStatus(email) {
|
|
|
760
760
|
return unifiedAuth.getCodeStatus(email);
|
|
761
761
|
}
|
|
762
762
|
|
|
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
|
+
}
|
|
804
|
+
return data || { success: true };
|
|
805
|
+
} catch (error) {
|
|
806
|
+
return { success: false, error: error instanceof Error ? error.message : "Network error" };
|
|
807
|
+
}
|
|
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;
|
|
825
|
+
}
|
|
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);
|
|
842
|
+
}
|
|
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);
|
|
860
|
+
}
|
|
861
|
+
);
|
|
862
|
+
}
|
|
863
|
+
cancelRequest(url) {
|
|
864
|
+
this.abortControllers.forEach((controller, key) => {
|
|
865
|
+
if (key.includes(url)) {
|
|
866
|
+
controller.abort();
|
|
867
|
+
this.abortControllers.delete(key);
|
|
868
|
+
}
|
|
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
|
+
|
|
763
1112
|
// src/components/auth/LoginForm.tsx
|
|
764
1113
|
import { useState as useState2, useEffect as useEffect2 } from "react";
|
|
765
1114
|
import { Icon as Icon2 } from "@iconify/react";
|
|
@@ -2180,437 +2529,105 @@ var LimitToastContainer = ({ message, onUpgrade, closeToast }) => {
|
|
|
2180
2529
|
backgroundImage: `linear-gradient(135deg, rgba(168,85,247,0.6) 0%, rgba(168,85,247,0.4) 5%, transparent 22%)`,
|
|
2181
2530
|
backgroundOrigin: "border-box",
|
|
2182
2531
|
backgroundClip: "border-box",
|
|
2183
|
-
WebkitMask: "linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0)",
|
|
2184
|
-
WebkitMaskComposite: "xor",
|
|
2185
|
-
mask: "linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0)",
|
|
2186
|
-
maskComposite: "exclude"
|
|
2187
|
-
}
|
|
2188
|
-
}
|
|
2189
|
-
),
|
|
2190
|
-
/* @__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" }),
|
|
2191
|
-
/* @__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" } }),
|
|
2192
|
-
/* @__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: [
|
|
2193
|
-
/* @__PURE__ */ jsxs9("div", { className: "flex items-center justify-between", children: [
|
|
2194
|
-
/* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-2", children: [
|
|
2195
|
-
/* @__PURE__ */ jsx13("div", { className: "text-lg font-bold text-white", children: "Upgrade Required" }),
|
|
2196
|
-
/* @__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" })
|
|
2197
|
-
] }),
|
|
2198
|
-
/* @__PURE__ */ jsx13(
|
|
2199
|
-
ClayxButton,
|
|
2200
|
-
{
|
|
2201
|
-
onClick: closeToast,
|
|
2202
|
-
isIconOnly: true,
|
|
2203
|
-
size: "sm",
|
|
2204
|
-
onMouseEnter: () => setCloseHover(true),
|
|
2205
|
-
onMouseLeave: () => setCloseHover(false),
|
|
2206
|
-
style: {
|
|
2207
|
-
height: "1.5rem",
|
|
2208
|
-
width: "1.5rem",
|
|
2209
|
-
minWidth: "1.5rem",
|
|
2210
|
-
borderRadius: "9999px",
|
|
2211
|
-
backgroundColor: closeHover ? "rgba(255,255,255,0.1)" : "rgba(255,255,255,0.05)",
|
|
2212
|
-
transition: "background-color 150ms ease",
|
|
2213
|
-
cursor: "pointer"
|
|
2214
|
-
},
|
|
2215
|
-
children: /* @__PURE__ */ jsx13(Icon5, { icon: "iconamoon:close", className: "w-4 h-4 text-gray-400" })
|
|
2216
|
-
}
|
|
2217
|
-
)
|
|
2218
|
-
] }),
|
|
2219
|
-
/* @__PURE__ */ jsx13("p", { className: "text-sm text-gray-300 leading-relaxed", children: message }),
|
|
2220
|
-
/* @__PURE__ */ jsx13("div", { className: "mt-1 flex items-center gap-3", children: /* @__PURE__ */ jsx13(
|
|
2221
|
-
ClayxButton,
|
|
2222
|
-
{
|
|
2223
|
-
onClick: () => {
|
|
2224
|
-
onUpgrade();
|
|
2225
|
-
closeToast?.();
|
|
2226
|
-
},
|
|
2227
|
-
onMouseEnter: () => setHover(true),
|
|
2228
|
-
onMouseLeave: () => setHover(false),
|
|
2229
|
-
style: {
|
|
2230
|
-
flex: 1,
|
|
2231
|
-
color: "#ffffff",
|
|
2232
|
-
fontWeight: 600,
|
|
2233
|
-
cursor: "pointer",
|
|
2234
|
-
transition: "all 300ms ease-in-out",
|
|
2235
|
-
backgroundImage: hover ? "linear-gradient(to right, #9333ea, #db2777)" : "linear-gradient(to right, #a855f7, #ec4899)",
|
|
2236
|
-
boxShadow: hover ? "0 10px 15px -3px rgba(168,85,247,0.3), 0 4px 6px -2px rgba(168,85,247,0.3)" : "none"
|
|
2237
|
-
},
|
|
2238
|
-
children: /* @__PURE__ */ jsxs9("span", { className: "flex items-center gap-2", children: [
|
|
2239
|
-
/* @__PURE__ */ jsx13(Icon5, { icon: "solar:rocket-2-bold", className: "w-4 h-4" }),
|
|
2240
|
-
"Upgrade Now"
|
|
2241
|
-
] })
|
|
2242
|
-
}
|
|
2243
|
-
) })
|
|
2244
|
-
] }) })
|
|
2245
|
-
] });
|
|
2246
|
-
};
|
|
2247
|
-
function showLimitUpgradeToast(message, onUpgrade) {
|
|
2248
|
-
ClayxToast.default({
|
|
2249
|
-
render: (closeToast) => /* @__PURE__ */ jsx13(LimitToastContainer, { message, onUpgrade, closeToast }),
|
|
2250
|
-
options: {
|
|
2251
|
-
autoClose: false
|
|
2252
|
-
}
|
|
2253
|
-
});
|
|
2254
|
-
}
|
|
2255
|
-
|
|
2256
|
-
// src/services/ai-workflow.ts
|
|
2257
|
-
var AIWorkflowClient = class {
|
|
2258
|
-
constructor(options = {}) {
|
|
2259
|
-
this.baseUrl = options.baseUrl?.replace(/\/+$/, "") || "";
|
|
2260
|
-
this.apiKey = options.apiKey;
|
|
2261
|
-
this.headers = { "Content-Type": "application/json", ...options.headers || {} };
|
|
2262
|
-
this.fetchImpl = options.fetchImpl || fetch.bind(globalThis);
|
|
2263
|
-
}
|
|
2264
|
-
buildHeaders(extra) {
|
|
2265
|
-
const h = { ...this.headers, ...extra || {} };
|
|
2266
|
-
if (this.apiKey && !h["Authorization"]) {
|
|
2267
|
-
h["Authorization"] = `Bearer ${this.apiKey}`;
|
|
2268
|
-
}
|
|
2269
|
-
return h;
|
|
2270
|
-
}
|
|
2271
|
-
async safeJson(resp) {
|
|
2272
|
-
try {
|
|
2273
|
-
return await resp.json();
|
|
2274
|
-
} catch (_e) {
|
|
2275
|
-
return null;
|
|
2276
|
-
}
|
|
2277
|
-
}
|
|
2278
|
-
/**
|
|
2279
|
-
* 按 ID 执行工作流:POST {baseUrl}/workflow/{workflowId}/execute
|
|
2280
|
-
* body: { input, options }
|
|
2281
|
-
*/
|
|
2282
|
-
async executeWorkflow(workflowId, inputs, options) {
|
|
2283
|
-
if (!this.baseUrl) {
|
|
2284
|
-
throw new Error("AI workflow client requires a baseUrl (e.g. https://evoagentx-server.fly.dev)");
|
|
2285
|
-
}
|
|
2286
|
-
const url = `${this.baseUrl}/workflow/${workflowId}/execute`;
|
|
2287
|
-
try {
|
|
2288
|
-
const res = await this.fetchImpl(url, {
|
|
2289
|
-
method: "POST",
|
|
2290
|
-
headers: this.buildHeaders(),
|
|
2291
|
-
body: JSON.stringify({ inputs, options })
|
|
2292
|
-
});
|
|
2293
|
-
const data = await this.safeJson(res);
|
|
2294
|
-
if (!res.ok) {
|
|
2295
|
-
return { success: false, error: data?.error || `HTTP ${res.status}` };
|
|
2296
|
-
}
|
|
2297
|
-
if (data && data.status && data.status === 4003) {
|
|
2298
|
-
showLimitUpgradeToast(
|
|
2299
|
-
"Your credits are exhausted. Please upgrade your plan to continue generating projects.",
|
|
2300
|
-
() => window.open("https://clayx.ai/pricing", "_blank")
|
|
2301
|
-
);
|
|
2302
|
-
return null;
|
|
2303
|
-
}
|
|
2304
|
-
return data || { success: true };
|
|
2305
|
-
} catch (error) {
|
|
2306
|
-
return { success: false, error: error instanceof Error ? error.message : "Network error" };
|
|
2307
|
-
}
|
|
2308
|
-
}
|
|
2309
|
-
};
|
|
2310
|
-
function createAIWorkflowClient(options = {}) {
|
|
2311
|
-
return new AIWorkflowClient(options);
|
|
2312
|
-
}
|
|
2313
|
-
var aiWorkflow = createAIWorkflowClient({ baseUrl: "https://evoagentx-server" });
|
|
2314
|
-
|
|
2315
|
-
// src/services/request/index.ts
|
|
2316
|
-
import axios from "axios";
|
|
2317
|
-
var Request = class {
|
|
2318
|
-
constructor(config) {
|
|
2319
|
-
this.abortControllers = /* @__PURE__ */ new Map();
|
|
2320
|
-
this.instance = axios.create({
|
|
2321
|
-
...config,
|
|
2322
|
-
withCredentials: true,
|
|
2323
|
-
validateStatus: (status) => {
|
|
2324
|
-
return status >= 200 && status < 300;
|
|
2325
|
-
}
|
|
2326
|
-
});
|
|
2327
|
-
this.interceptors = config.interceptors;
|
|
2328
|
-
this.instance.interceptors.request.use(
|
|
2329
|
-
this.interceptors?.requestInterceptor,
|
|
2330
|
-
this.interceptors?.requestInterceptorCatch
|
|
2331
|
-
);
|
|
2332
|
-
this.instance.interceptors.response.use(
|
|
2333
|
-
this.interceptors?.responseInterceptor,
|
|
2334
|
-
this.interceptors?.responseInterceptorCatch
|
|
2335
|
-
);
|
|
2336
|
-
this.instance.interceptors.request.use(
|
|
2337
|
-
(config2) => {
|
|
2338
|
-
return config2;
|
|
2339
|
-
},
|
|
2340
|
-
(err) => {
|
|
2341
|
-
return Promise.reject(err);
|
|
2342
|
-
}
|
|
2343
|
-
);
|
|
2344
|
-
this.instance.interceptors.response.use(
|
|
2345
|
-
(res) => {
|
|
2346
|
-
return res.data;
|
|
2347
|
-
},
|
|
2348
|
-
(err) => {
|
|
2349
|
-
if (axios.isCancel(err)) {
|
|
2350
|
-
return Promise.reject({
|
|
2351
|
-
isCanceled: true,
|
|
2352
|
-
message: "request canceled",
|
|
2353
|
-
originalError: err
|
|
2354
|
-
});
|
|
2355
|
-
}
|
|
2356
|
-
if (err.response?.data?.error) {
|
|
2357
|
-
return Promise.reject(err.response.data.error);
|
|
2358
|
-
}
|
|
2359
|
-
return Promise.reject(err);
|
|
2360
|
-
}
|
|
2361
|
-
);
|
|
2362
|
-
}
|
|
2363
|
-
cancelRequest(url) {
|
|
2364
|
-
this.abortControllers.forEach((controller, key) => {
|
|
2365
|
-
if (key.includes(url)) {
|
|
2366
|
-
controller.abort();
|
|
2367
|
-
this.abortControllers.delete(key);
|
|
2368
|
-
}
|
|
2369
|
-
});
|
|
2370
|
-
}
|
|
2371
|
-
cancelAllRequests() {
|
|
2372
|
-
this.abortControllers.forEach((controller) => {
|
|
2373
|
-
controller.abort();
|
|
2374
|
-
});
|
|
2375
|
-
this.abortControllers.clear();
|
|
2376
|
-
}
|
|
2377
|
-
request(config) {
|
|
2378
|
-
const controller = new AbortController();
|
|
2379
|
-
const url = config.url || "";
|
|
2380
|
-
const method = config.method || "GET";
|
|
2381
|
-
const key = `${method}:${url}`;
|
|
2382
|
-
this.abortControllers.set(key, controller);
|
|
2383
|
-
config.signal = controller.signal;
|
|
2384
|
-
return new Promise((resolve, reject) => {
|
|
2385
|
-
if (config.interceptors?.requestInterceptor) {
|
|
2386
|
-
config = config.interceptors.requestInterceptor(config);
|
|
2387
|
-
}
|
|
2388
|
-
this.instance.request(config).then((res) => {
|
|
2389
|
-
this.abortControllers.delete(key);
|
|
2390
|
-
if (config.interceptors?.responseInterceptor) {
|
|
2391
|
-
res = config.interceptors.responseInterceptor(res);
|
|
2392
|
-
}
|
|
2393
|
-
resolve(res);
|
|
2394
|
-
}).catch((err) => {
|
|
2395
|
-
this.abortControllers.delete(key);
|
|
2396
|
-
reject(err);
|
|
2397
|
-
});
|
|
2398
|
-
});
|
|
2399
|
-
}
|
|
2400
|
-
get(config) {
|
|
2401
|
-
return this.request({ ...config, method: "GET" });
|
|
2402
|
-
}
|
|
2403
|
-
post(config) {
|
|
2404
|
-
return this.request({ ...config, method: "POST" });
|
|
2405
|
-
}
|
|
2406
|
-
delete(config) {
|
|
2407
|
-
return this.request({ ...config, method: "DELETE" });
|
|
2408
|
-
}
|
|
2409
|
-
put(config) {
|
|
2410
|
-
return this.request({ ...config, method: "PUT" });
|
|
2411
|
-
}
|
|
2412
|
-
patch(config) {
|
|
2413
|
-
return this.request({ ...config, method: "PATCH" });
|
|
2414
|
-
}
|
|
2415
|
-
};
|
|
2416
|
-
var request_default = Request;
|
|
2417
|
-
|
|
2418
|
-
// src/services/ai-workflow-axios.ts
|
|
2419
|
-
function createAIWorkflowClientAxios(options = {}) {
|
|
2420
|
-
const basePath = options.basePath ?? "/api";
|
|
2421
|
-
const baseUrl = (options.baseUrl || "https://evoagentx-server.fly.dev").replace(/\/+$/, "");
|
|
2422
|
-
const baseAPI = `${baseUrl}${basePath.startsWith("/") ? "" : "/"}${basePath}`.replace(/\/+$/, "");
|
|
2423
|
-
const client = options.requestInstance || new request_default({
|
|
2424
|
-
baseURL: baseAPI,
|
|
2425
|
-
timeout: options.timeout ?? 6e4,
|
|
2426
|
-
interceptors: {
|
|
2427
|
-
requestInterceptor: (config) => {
|
|
2428
|
-
config.headers = config.headers || {};
|
|
2429
|
-
if (options.apiKey && !config.headers["Authorization"]) {
|
|
2430
|
-
config.headers["Authorization"] = `Bearer ${options.apiKey}`;
|
|
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"
|
|
2431
2536
|
}
|
|
2432
|
-
|
|
2433
|
-
|
|
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
|
+
] })
|
|
2434
2591
|
}
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
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
|
|
2440
2601
|
}
|
|
2441
2602
|
});
|
|
2442
|
-
return {
|
|
2443
|
-
async executeWorkflow(workflowId, inputs, opts) {
|
|
2444
|
-
const url = `${baseUrl}/workflow/${workflowId}/execute`;
|
|
2445
|
-
const data = await client.post({ url, data: { inputs, options: opts } });
|
|
2446
|
-
return data;
|
|
2447
|
-
}
|
|
2448
|
-
};
|
|
2449
2603
|
}
|
|
2450
2604
|
|
|
2451
|
-
// src/services/
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
return false;
|
|
2459
|
-
}
|
|
2460
|
-
if (a.visibility === "private") {
|
|
2461
|
-
if (ctx.userId && a.ownerId && ctx.userId === a.ownerId) return true;
|
|
2462
|
-
if (ctx.tokenScopes && (ctx.tokenScopes.includes("artifact:read:all") || ctx.tokenScopes.includes("admin"))) return true;
|
|
2463
|
-
return false;
|
|
2464
|
-
}
|
|
2465
|
-
if (a.visibility === "shared") {
|
|
2466
|
-
if (ctx.userId && a.sharedWith && a.sharedWith.includes(ctx.userId)) return true;
|
|
2467
|
-
if (ctx.tokenScopes && (ctx.tokenScopes.includes("artifact:read:all") || ctx.tokenScopes.includes("admin"))) return true;
|
|
2468
|
-
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;
|
|
2469
2612
|
}
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
return {
|
|
2476
|
-
async create(input) {
|
|
2477
|
-
return await req.post({ url: "/artifacts", data: input });
|
|
2478
|
-
},
|
|
2479
|
-
async list(query) {
|
|
2480
|
-
return await req.get({ url: "/artifacts", params: query });
|
|
2481
|
-
},
|
|
2482
|
-
async get(id) {
|
|
2483
|
-
return await req.get({ url: `/artifacts/${encodeURIComponent(id)}` });
|
|
2484
|
-
},
|
|
2485
|
-
async setVisibility(id, visibility) {
|
|
2486
|
-
await req.patch({ url: `/artifacts/${encodeURIComponent(id)}/visibility`, data: { visibility } });
|
|
2487
|
-
},
|
|
2488
|
-
async delete(id) {
|
|
2489
|
-
await req.delete({ url: `/artifacts/${encodeURIComponent(id)}` });
|
|
2490
|
-
},
|
|
2491
|
-
// convenience local check (server is authoritative)
|
|
2492
|
-
canAccessLocal(a, ctx) {
|
|
2493
|
-
if (!a) return false;
|
|
2494
|
-
if (a.visibility === "public") return true;
|
|
2495
|
-
if (a.visibility === "project") return Boolean(ctx.projectId && a.projectId && ctx.projectId === a.projectId);
|
|
2496
|
-
if (a.visibility === "private") return Boolean(ctx.userId && a.ownerId && ctx.userId === a.ownerId);
|
|
2497
|
-
if (a.visibility === "shared") return Boolean(ctx.userId && a.sharedWith && a.sharedWith.includes(ctx.userId));
|
|
2498
|
-
return false;
|
|
2499
|
-
}
|
|
2500
|
-
};
|
|
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
|
+
);
|
|
2501
2618
|
}
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2619
|
+
function mergeLimitExceededOptions(base, override) {
|
|
2620
|
+
if (!base && !override) {
|
|
2621
|
+
return void 0;
|
|
2622
|
+
}
|
|
2506
2623
|
return {
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
* @example
|
|
2511
|
-
* ```typescript
|
|
2512
|
-
* const { url } = await client.upload.file(imageFile)
|
|
2513
|
-
* console.log('文件地址:', url)
|
|
2514
|
-
* ```
|
|
2515
|
-
*/
|
|
2516
|
-
async file(file, options) {
|
|
2517
|
-
const formData = new FormData();
|
|
2518
|
-
if (typeof file === "string") {
|
|
2519
|
-
if (file.startsWith("data:")) {
|
|
2520
|
-
const response2 = await fetch(file);
|
|
2521
|
-
const blob = await response2.blob();
|
|
2522
|
-
formData.append("file", blob, "upload.bin");
|
|
2523
|
-
} else {
|
|
2524
|
-
formData.append("fileUrl", file);
|
|
2525
|
-
}
|
|
2526
|
-
} else if (file instanceof File) {
|
|
2527
|
-
formData.append("file", file, file.name);
|
|
2528
|
-
} else {
|
|
2529
|
-
formData.append("file", file, "upload.bin");
|
|
2530
|
-
}
|
|
2531
|
-
if (options?.metadata) {
|
|
2532
|
-
formData.append("metadata", JSON.stringify(options.metadata));
|
|
2533
|
-
}
|
|
2534
|
-
const response = await req.post({
|
|
2535
|
-
url: uploadUrl,
|
|
2536
|
-
data: formData,
|
|
2537
|
-
signal: options?.signal
|
|
2538
|
-
});
|
|
2539
|
-
return {
|
|
2540
|
-
url: response.data.publicUrl
|
|
2541
|
-
};
|
|
2542
|
-
},
|
|
2543
|
-
/**
|
|
2544
|
-
* 上传图片(快捷方法,专为 AI 设计)
|
|
2545
|
-
*
|
|
2546
|
-
* @example
|
|
2547
|
-
* ```typescript
|
|
2548
|
-
* const { url } = await client.upload.image(imageFile)
|
|
2549
|
-
* ```
|
|
2550
|
-
*/
|
|
2551
|
-
async image(file) {
|
|
2552
|
-
const result = await this.file(file);
|
|
2553
|
-
return { url: result.url };
|
|
2554
|
-
},
|
|
2555
|
-
/**
|
|
2556
|
-
* 批量上传文件
|
|
2557
|
-
*
|
|
2558
|
-
* @example
|
|
2559
|
-
* ```typescript
|
|
2560
|
-
* const result = await client.upload.batch({
|
|
2561
|
-
* files: [file1, file2, file3],
|
|
2562
|
-
* concurrent: 3,
|
|
2563
|
-
* onProgress: (completed, total) => {
|
|
2564
|
-
* console.log(`${completed}/${total}`)
|
|
2565
|
-
* }
|
|
2566
|
-
* })
|
|
2567
|
-
* ```
|
|
2568
|
-
*/
|
|
2569
|
-
async batch(options) {
|
|
2570
|
-
const { files, concurrent = 3, onProgress, onFileComplete, signal } = options;
|
|
2571
|
-
const success = [];
|
|
2572
|
-
const failed = [];
|
|
2573
|
-
let completed = 0;
|
|
2574
|
-
for (let i = 0; i < files.length; i += concurrent) {
|
|
2575
|
-
if (signal?.aborted) break;
|
|
2576
|
-
const batch = files.slice(i, Math.min(i + concurrent, files.length));
|
|
2577
|
-
const promises = batch.map(async (file, batchIndex) => {
|
|
2578
|
-
const globalIndex = i + batchIndex;
|
|
2579
|
-
try {
|
|
2580
|
-
const result = await this.file(file, { signal });
|
|
2581
|
-
success.push(result);
|
|
2582
|
-
if (onFileComplete) {
|
|
2583
|
-
onFileComplete(result, globalIndex);
|
|
2584
|
-
}
|
|
2585
|
-
} catch (error) {
|
|
2586
|
-
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
2587
|
-
failed.push({ index: globalIndex, error: errorMsg });
|
|
2588
|
-
if (onFileComplete) {
|
|
2589
|
-
onFileComplete(
|
|
2590
|
-
error instanceof Error ? error : new Error(errorMsg),
|
|
2591
|
-
globalIndex
|
|
2592
|
-
);
|
|
2593
|
-
}
|
|
2594
|
-
} finally {
|
|
2595
|
-
completed++;
|
|
2596
|
-
if (onProgress) {
|
|
2597
|
-
onProgress(completed, files.length);
|
|
2598
|
-
}
|
|
2599
|
-
}
|
|
2600
|
-
});
|
|
2601
|
-
await Promise.all(promises);
|
|
2602
|
-
}
|
|
2603
|
-
return {
|
|
2604
|
-
success,
|
|
2605
|
-
failed,
|
|
2606
|
-
total: files.length
|
|
2607
|
-
};
|
|
2608
|
-
}
|
|
2624
|
+
...base,
|
|
2625
|
+
...override,
|
|
2626
|
+
onLimitExceeded: override?.onLimitExceeded ?? base?.onLimitExceeded
|
|
2609
2627
|
};
|
|
2610
2628
|
}
|
|
2611
2629
|
|
|
2612
2630
|
// src/services/sse-executor.ts
|
|
2613
|
-
init_config();
|
|
2614
2631
|
async function executeSSEWorkflow(request, options = {}) {
|
|
2615
2632
|
const startTime = Date.now();
|
|
2616
2633
|
const result = {
|
|
@@ -2711,11 +2728,16 @@ async function executeSSEWorkflow(request, options = {}) {
|
|
|
2711
2728
|
options.onStreamContent(rawEvent.delta);
|
|
2712
2729
|
}
|
|
2713
2730
|
if (rawEvent.type === "key_limit_exceed") {
|
|
2714
|
-
const errorMsg = rawEvent.data
|
|
2731
|
+
const errorMsg = rawEvent.data?.content || DEFAULT_LIMIT_EXCEEDED_MESSAGE;
|
|
2715
2732
|
result.errors.push(errorMsg);
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2733
|
+
handleLimitExceeded(
|
|
2734
|
+
{
|
|
2735
|
+
source: "sse-executor",
|
|
2736
|
+
message: errorMsg,
|
|
2737
|
+
eventType: rawEvent.type,
|
|
2738
|
+
rawData: rawEvent.data
|
|
2739
|
+
},
|
|
2740
|
+
options.limitExceeded
|
|
2719
2741
|
);
|
|
2720
2742
|
if (options.onError) {
|
|
2721
2743
|
options.onError(new Error(errorMsg));
|
|
@@ -2926,7 +2948,7 @@ function createEventIterable(streamFactory, config) {
|
|
|
2926
2948
|
};
|
|
2927
2949
|
}
|
|
2928
2950
|
function createSSEClient(config) {
|
|
2929
|
-
const { baseUrl, projectId, getAuthToken } = config;
|
|
2951
|
+
const { baseUrl, projectId, getAuthToken, limitExceeded } = config;
|
|
2930
2952
|
const stream = (streamConfig) => {
|
|
2931
2953
|
const { signal: externalSignal, ...callbacks } = streamConfig;
|
|
2932
2954
|
const request = resolveRequest(baseUrl, projectId, streamConfig);
|
|
@@ -2942,7 +2964,11 @@ function createSSEClient(config) {
|
|
|
2942
2964
|
{
|
|
2943
2965
|
...callbacks,
|
|
2944
2966
|
authToken,
|
|
2945
|
-
signal: controller.signal
|
|
2967
|
+
signal: controller.signal,
|
|
2968
|
+
limitExceeded: mergeLimitExceededOptions(
|
|
2969
|
+
limitExceeded,
|
|
2970
|
+
streamConfig.limitExceeded
|
|
2971
|
+
)
|
|
2946
2972
|
}
|
|
2947
2973
|
).finally(() => {
|
|
2948
2974
|
controller.cleanup();
|
|
@@ -3118,6 +3144,19 @@ async function executeWorkflowStreamPost(baseUrl, projectId, workflowId, request
|
|
|
3118
3144
|
break;
|
|
3119
3145
|
case "error":
|
|
3120
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
|
+
}
|
|
3121
3160
|
}
|
|
3122
3161
|
} catch (err) {
|
|
3123
3162
|
console.error("Failed to parse SSE event:", err);
|
|
@@ -3136,12 +3175,12 @@ async function executeWorkflowStreamPost(baseUrl, projectId, workflowId, request
|
|
|
3136
3175
|
}
|
|
3137
3176
|
|
|
3138
3177
|
// src/services/workflow-executor.ts
|
|
3139
|
-
init_config();
|
|
3140
3178
|
var WorkflowExecutor = class {
|
|
3141
|
-
constructor(baseUrl, projectId, authToken) {
|
|
3179
|
+
constructor(baseUrl, projectId, authToken, limitExceeded) {
|
|
3142
3180
|
this.baseUrl = baseUrl.replace(/\/$/, "");
|
|
3143
3181
|
this.projectId = projectId;
|
|
3144
3182
|
this.authToken = authToken;
|
|
3183
|
+
this.limitExceeded = limitExceeded;
|
|
3145
3184
|
}
|
|
3146
3185
|
/**
|
|
3147
3186
|
* 执行工作流 (SSE 模式)
|
|
@@ -3191,6 +3230,10 @@ var WorkflowExecutor = class {
|
|
|
3191
3230
|
errors: []
|
|
3192
3231
|
};
|
|
3193
3232
|
let streamContent = "";
|
|
3233
|
+
const limitExceededOptions = mergeLimitExceededOptions(
|
|
3234
|
+
this.limitExceeded,
|
|
3235
|
+
options?.limitExceeded
|
|
3236
|
+
);
|
|
3194
3237
|
try {
|
|
3195
3238
|
const response = await fetch(url, {
|
|
3196
3239
|
method: "POST",
|
|
@@ -3243,11 +3286,16 @@ var WorkflowExecutor = class {
|
|
|
3243
3286
|
}
|
|
3244
3287
|
}
|
|
3245
3288
|
} else if (event.type === "key_limit_exceed") {
|
|
3246
|
-
const errorMsg = event.data?.content;
|
|
3289
|
+
const errorMsg = event.data?.content || DEFAULT_LIMIT_EXCEEDED_MESSAGE;
|
|
3247
3290
|
result.errors.push(errorMsg);
|
|
3248
|
-
|
|
3249
|
-
|
|
3250
|
-
|
|
3291
|
+
handleLimitExceeded(
|
|
3292
|
+
{
|
|
3293
|
+
source: "workflow-executor-sse",
|
|
3294
|
+
message: errorMsg,
|
|
3295
|
+
eventType: event.type,
|
|
3296
|
+
rawData: event.data
|
|
3297
|
+
},
|
|
3298
|
+
limitExceededOptions
|
|
3251
3299
|
);
|
|
3252
3300
|
if (options?.onError) {
|
|
3253
3301
|
options.onError(new Error(errorMsg));
|
|
@@ -3331,6 +3379,17 @@ var WorkflowExecutor = class {
|
|
|
3331
3379
|
body: JSON.stringify({ inputs })
|
|
3332
3380
|
});
|
|
3333
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
|
+
}
|
|
3334
3393
|
return {
|
|
3335
3394
|
status: response.status,
|
|
3336
3395
|
data
|
|
@@ -3412,14 +3471,6 @@ function createClient(opts) {
|
|
|
3412
3471
|
},
|
|
3413
3472
|
requestInterceptorCatch: (err) => Promise.reject(err),
|
|
3414
3473
|
responseInterceptor: (res) => {
|
|
3415
|
-
const data = res.data;
|
|
3416
|
-
if (data && data.status && data.status === 4003) {
|
|
3417
|
-
showLimitUpgradeToast(
|
|
3418
|
-
"Your credits are exhausted. Please upgrade your plan to continue generating projects.",
|
|
3419
|
-
() => window.open(`${getEnvs().AUTH_ROOT_VALUE}/price`, "_blank")
|
|
3420
|
-
);
|
|
3421
|
-
return res;
|
|
3422
|
-
}
|
|
3423
3474
|
return res;
|
|
3424
3475
|
},
|
|
3425
3476
|
responseInterceptorCatch: (err) => Promise.reject(err)
|
|
@@ -3527,7 +3578,8 @@ function createClient(opts) {
|
|
|
3527
3578
|
void fetchExternalToken();
|
|
3528
3579
|
}
|
|
3529
3580
|
return token ?? cachedExternalToken ?? getToken() ?? null;
|
|
3530
|
-
}
|
|
3581
|
+
},
|
|
3582
|
+
limitExceeded: opts.limitExceeded
|
|
3531
3583
|
});
|
|
3532
3584
|
const assignMethod = (config, method) => method ? { ...config, method } : config;
|
|
3533
3585
|
function createMethodInvoker(invoker) {
|
|
@@ -3589,7 +3641,8 @@ function createClient(opts) {
|
|
|
3589
3641
|
const executor = new WorkflowExecutor(
|
|
3590
3642
|
actualAiBaseUrl,
|
|
3591
3643
|
opts.projectId,
|
|
3592
|
-
getCachedOrGlobalToken() ?? void 0
|
|
3644
|
+
getCachedOrGlobalToken() ?? void 0,
|
|
3645
|
+
opts.limitExceeded
|
|
3593
3646
|
);
|
|
3594
3647
|
return {
|
|
3595
3648
|
executeSse: (inputs, options) => {
|
|
@@ -4219,6 +4272,7 @@ export {
|
|
|
4219
4272
|
AUTH_TOKEN_KEY,
|
|
4220
4273
|
ClayxButton,
|
|
4221
4274
|
ClayxToast,
|
|
4275
|
+
DEFAULT_LIMIT_EXCEEDED_MESSAGE,
|
|
4222
4276
|
DefaultErrorFallback,
|
|
4223
4277
|
ElementSelector,
|
|
4224
4278
|
ElementSelectorProvider,
|
|
@@ -4248,11 +4302,13 @@ export {
|
|
|
4248
4302
|
getEnvs,
|
|
4249
4303
|
getGlobalEnvironment,
|
|
4250
4304
|
getToken,
|
|
4305
|
+
handleLimitExceeded,
|
|
4251
4306
|
client_default as howone,
|
|
4252
4307
|
iframeNavigation,
|
|
4253
4308
|
initIframeNavigation,
|
|
4254
4309
|
isTokenValid,
|
|
4255
4310
|
loginWithEmailCode,
|
|
4311
|
+
mergeLimitExceededOptions,
|
|
4256
4312
|
onAuthStateChanged,
|
|
4257
4313
|
parseUserFromToken,
|
|
4258
4314
|
sendElementSelectionToParent,
|