@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.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
- if (options.headers) {
2433
- config.headers = { ...config.headers || {}, ...options.headers };
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
- return config;
2436
- },
2437
- requestInterceptorCatch: (err) => Promise.reject(err),
2438
- responseInterceptor: (res) => res,
2439
- responseInterceptorCatch: (err) => Promise.reject(err)
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/artifact-types.ts
2452
- function canAccessArtifact(a, ctx = {}) {
2453
- if (!a) return false;
2454
- if (a.visibility === "public") return true;
2455
- if (a.visibility === "project") {
2456
- if (ctx.projectId && a.projectId && ctx.projectId === a.projectId) return true;
2457
- if (ctx.tokenScopes && ctx.tokenScopes.includes("project:read")) return true;
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
- return false;
2471
- }
2472
-
2473
- // src/services/artifacts-client.ts
2474
- function createArtifactsClient(req) {
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
- // src/services/upload-client.ts
2504
- function createUploadClient(req, projectId) {
2505
- const uploadUrl = projectId ? `/entities/apps/${projectId}/files` : "/files";
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.content;
2731
+ const errorMsg = rawEvent.data?.content || DEFAULT_LIMIT_EXCEEDED_MESSAGE;
2715
2732
  result.errors.push(errorMsg);
2716
- showLimitUpgradeToast(
2717
- "Your credits are exhausted. Please upgrade your plan to continue generating projects.",
2718
- () => 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
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
- showLimitUpgradeToast(
3249
- "Your credits are exhausted. Please upgrade your plan to continue generating projects.",
3250
- () => 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
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,