@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.d.mts +34 -10
- package/dist/index.d.ts +34 -10
- package/dist/index.js +1064 -745
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1033 -717
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -6
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
|
|
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/
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
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
|
-
|
|
805
|
-
|
|
806
|
-
|
|
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
|
-
}
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
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
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
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
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
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
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
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
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
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
|
|
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 {
|
|
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
|
-
|
|
1057
|
-
|
|
1058
|
-
return /* @__PURE__ */ jsx5(
|
|
1059
|
-
GoeyToaster,
|
|
1385
|
+
return /* @__PURE__ */ jsx4(
|
|
1386
|
+
ToastContainer,
|
|
1060
1387
|
{
|
|
1061
|
-
|
|
1062
|
-
|
|
1388
|
+
newestOnTop: false,
|
|
1389
|
+
closeButton: false
|
|
1063
1390
|
}
|
|
1064
1391
|
);
|
|
1065
1392
|
}
|
|
1066
1393
|
|
|
1067
1394
|
// src/components/ElementSelectorProvider.tsx
|
|
1068
|
-
import { useEffect as
|
|
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
|
|
1072
|
-
import { Fragment, jsx as
|
|
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] =
|
|
1079
|
-
const [highlightRect, setHighlightRect] =
|
|
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
|
-
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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
|
|
1541
|
+
import { useState as useState5, useCallback as useCallback2 } from "react";
|
|
1215
1542
|
function useElementSelector() {
|
|
1216
|
-
const [isSelecting, setIsSelecting] =
|
|
1217
|
-
const [selectedElement, setSelectedElement] =
|
|
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
|
|
1572
|
+
import { Fragment as Fragment2, jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1246
1573
|
var ElementSelectorProvider = ({ children }) => {
|
|
1247
|
-
const [isSelecting, setIsSelecting] =
|
|
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
|
-
|
|
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__ */
|
|
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
|
|
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] =
|
|
1360
|
-
const [token, setTokenState] =
|
|
1361
|
-
const [hasCheckedUrlToken, setHasCheckedUrlToken] =
|
|
1362
|
-
const [pendingRedirect, setPendingRedirect] =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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__ */
|
|
1870
|
+
/* @__PURE__ */ jsx7(ElementSelectorProvider, { children: /* @__PURE__ */ jsxs5(HowoneContext.Provider, { value, children: [
|
|
1544
1871
|
children,
|
|
1545
|
-
showHowOneFlag && /* @__PURE__ */
|
|
1546
|
-
pendingRedirect && /* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
1560
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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
|
|
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__ */
|
|
1696
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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
|
|
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__ */
|
|
2074
|
+
return /* @__PURE__ */ jsx9(FallbackComponent, { error: this.state.error, retry: this.handleRetry });
|
|
1748
2075
|
}
|
|
1749
|
-
return /* @__PURE__ */
|
|
1750
|
-
/* @__PURE__ */
|
|
1751
|
-
/* @__PURE__ */
|
|
1752
|
-
/* @__PURE__ */
|
|
1753
|
-
/* @__PURE__ */
|
|
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__ */
|
|
1768
|
-
/* @__PURE__ */
|
|
1769
|
-
/* @__PURE__ */
|
|
1770
|
-
retry && /* @__PURE__ */
|
|
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
|
|
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__ */
|
|
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
|
|
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/
|
|
1853
|
-
import
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
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
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
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/
|
|
2214
|
+
// src/components/ui/Toast/ClayxToast.tsx
|
|
1889
2215
|
import { jsx as jsx12, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1890
|
-
var
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
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-
|
|
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-
|
|
2381
|
+
className: "absolute left-0 top-0 w-full h-full pointer-events-none rounded-xl",
|
|
1908
2382
|
style: {
|
|
1909
|
-
background: `linear-gradient(135deg,
|
|
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-
|
|
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,
|
|
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(#
|
|
2397
|
+
WebkitMask: "linear-gradient(#ffffff 0 0) padding-box, linear-gradient(#ffffff 0 0)",
|
|
1924
2398
|
WebkitMaskComposite: "xor",
|
|
1925
|
-
|
|
1926
|
-
maskComposite: "exclude"
|
|
2399
|
+
zIndex: 0
|
|
1927
2400
|
}
|
|
1928
2401
|
}
|
|
1929
2402
|
),
|
|
1930
|
-
/* @__PURE__ */ jsx12("div", { className: "
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
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
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
2419
|
+
className: "text-[16px] font-semibold leading-tight drop-shadow-sm",
|
|
2420
|
+
style: {
|
|
2421
|
+
color: getTextColor(),
|
|
2422
|
+
backgroundClip: "text"
|
|
1966
2423
|
},
|
|
1967
|
-
|
|
1968
|
-
|
|
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
|
-
|
|
1971
|
-
|
|
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:
|
|
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
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
var
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
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
|
-
|
|
2051
|
-
return
|
|
2052
|
-
}
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
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
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
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
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
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/
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
const
|
|
2162
|
-
const
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
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
|
-
|
|
2173
|
-
|
|
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
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
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/
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
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
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
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
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
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
|
-
|
|
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
|
|
2731
|
+
const errorMsg = rawEvent.data?.content || DEFAULT_LIMIT_EXCEEDED_MESSAGE;
|
|
2455
2732
|
result.errors.push(errorMsg);
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
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
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
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
|
|
3863
|
+
import * as React9 from "react";
|
|
3551
3864
|
var MOBILE_BREAKPOINT = 768;
|
|
3552
3865
|
function useIsMobile() {
|
|
3553
|
-
const [isMobile, setIsMobile] =
|
|
3554
|
-
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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,
|