@tacoreai/web-sdk 1.0.12 → 1.3.0
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/README.md +404 -0
- package/database/core/apps/AppsAuthManager.js +336 -0
- package/database/core/apps/AppsClient.AI.js +229 -0
- package/database/core/apps/AppsClient.AppServer.js +92 -0
- package/database/core/apps/AppsClient.Crawler.js +71 -0
- package/database/core/apps/AppsClient.Data.js +187 -0
- package/database/core/apps/AppsClient.Debug.js +41 -0
- package/database/core/apps/AppsClient.Deploy.js +66 -0
- package/database/core/apps/AppsClient.Ecommerce.js +151 -0
- package/database/core/apps/AppsClient.KV.js +72 -0
- package/database/core/apps/AppsClient.KnowledgeBase.js +130 -0
- package/database/core/apps/AppsClient.Message.js +27 -0
- package/database/core/apps/AppsClient.Realtime.js +46 -0
- package/database/core/apps/AppsClient.Storage.js +275 -0
- package/database/core/apps/AppsClient.TextIn.js +341 -0
- package/database/core/apps/AppsClient.Tools.js +36 -0
- package/database/core/apps/AppsClient.Users.js +49 -0
- package/database/core/apps/AppsClient.VoiceVideo.js +106 -0
- package/database/core/apps/AppsClient.Volcengine.js +169 -0
- package/database/core/apps/AppsClient.js +215 -0
- package/database/core/apps/AppsPublicClient.js +107 -0
- package/database/core/apps/BaseAppsClient.js +216 -0
- package/index.js +9 -0
- package/package.json +11 -23
- package/utils/errorLogger.js +28 -0
- package/utils/index.js +114 -0
- package/dist/index.umd.js +0 -1
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
export const appsClientCrawlerMethods = {
|
|
2
|
+
// ==================== 网页爬虫服务 ====================
|
|
3
|
+
|
|
4
|
+
async scrapeUrl(options = {}) {
|
|
5
|
+
try {
|
|
6
|
+
if (!options.url) {
|
|
7
|
+
throw new Error("url is required for scraping.");
|
|
8
|
+
}
|
|
9
|
+
const result = await this._post("/apps/crawler/scrape", {
|
|
10
|
+
appId: this.appId,
|
|
11
|
+
...options,
|
|
12
|
+
});
|
|
13
|
+
console.log(`✅ [AppsClient] URL scraped successfully for app: ${this.appId}`);
|
|
14
|
+
return result;
|
|
15
|
+
} catch (error) {
|
|
16
|
+
console.error(`网页爬取失败 (app: ${this.appId}):`, error);
|
|
17
|
+
throw error;
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
|
|
21
|
+
async scrapeMultipleUrls(options = {}) {
|
|
22
|
+
try {
|
|
23
|
+
if (!options.urls || !Array.isArray(options.urls) || options.urls.length === 0) {
|
|
24
|
+
throw new Error("urls array is required for batch scraping.");
|
|
25
|
+
}
|
|
26
|
+
const result = await this._post("/apps/crawler/scrape-batch", {
|
|
27
|
+
appId: this.appId,
|
|
28
|
+
...options,
|
|
29
|
+
});
|
|
30
|
+
console.log(`✅ [AppsClient] Batch URL scraping completed for app: ${this.appId}`);
|
|
31
|
+
return result;
|
|
32
|
+
} catch (error) {
|
|
33
|
+
console.error(`批量爬取失败 (app: ${this.appId}):`, error);
|
|
34
|
+
throw error;
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
|
|
38
|
+
async firecrawlScrape(options = {}) {
|
|
39
|
+
try {
|
|
40
|
+
if (!options.url) {
|
|
41
|
+
throw new Error("url is required for firecrawl scrape.");
|
|
42
|
+
}
|
|
43
|
+
const result = await this._post("/apps/firecrawl/scrape", {
|
|
44
|
+
appId: this.appId,
|
|
45
|
+
...options,
|
|
46
|
+
});
|
|
47
|
+
console.log(`✅ [AppsClient] Firecrawl scrape completed for app: ${this.appId}`);
|
|
48
|
+
return result;
|
|
49
|
+
} catch (error) {
|
|
50
|
+
console.error(`Firecrawl 爬取失败 (app: ${this.appId}):`, error);
|
|
51
|
+
throw error;
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
|
|
55
|
+
async firecrawlMap(options = {}) {
|
|
56
|
+
try {
|
|
57
|
+
if (!options.url) {
|
|
58
|
+
throw new Error("url is required for firecrawl map.");
|
|
59
|
+
}
|
|
60
|
+
const result = await this._post("/apps/firecrawl/map", {
|
|
61
|
+
appId: this.appId,
|
|
62
|
+
...options,
|
|
63
|
+
});
|
|
64
|
+
console.log(`✅ [AppsClient] Firecrawl map completed for app: ${this.appId}`);
|
|
65
|
+
return result;
|
|
66
|
+
} catch (error) {
|
|
67
|
+
console.error(`Firecrawl 站点地图生成失败 (app: ${this.appId}):`, error);
|
|
68
|
+
throw error;
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
};
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
export const appsClientDataMethods = {
|
|
2
|
+
// ==================== 核心数据操作 (多模型) ====================
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @deprecated Use `createData` or `updateData` instead.
|
|
6
|
+
*/
|
|
7
|
+
async writeData(modelName, data, wyID, publicConfig = {}) {
|
|
8
|
+
console.warn(
|
|
9
|
+
"`writeData` is deprecated. Please use `createData` for new records or `updateData` for existing ones."
|
|
10
|
+
);
|
|
11
|
+
if (wyID) {
|
|
12
|
+
// 如果提供了 wyID,我们认为是更新操作
|
|
13
|
+
return this.updateData(modelName, wyID, data, undefined, publicConfig);
|
|
14
|
+
}
|
|
15
|
+
// 如果没有 wyID,我们认为是创建操作
|
|
16
|
+
// 注意:旧的 writeData 不支持在创建时传递 permissions,所以这里是 undefined
|
|
17
|
+
return this.createData(modelName, data, undefined, publicConfig);
|
|
18
|
+
},
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* [新增] 创建一条新数据
|
|
22
|
+
* @param {string} modelName - 模型的名称
|
|
23
|
+
* @param {object} data - 要创建的数据
|
|
24
|
+
* @param {object} [permissions] - 可选的权限对象,例如 { read: ["group:all_users"], update: ["role:creater"] }
|
|
25
|
+
* @param {object} [publicConfig] - 可选的公共配置
|
|
26
|
+
* @returns {Promise<string>} - 新创建数据的 wyID
|
|
27
|
+
*/
|
|
28
|
+
async createData(modelName, data, permissions, publicConfig) {
|
|
29
|
+
try {
|
|
30
|
+
const requestData = {
|
|
31
|
+
appId: this.appId,
|
|
32
|
+
modelName,
|
|
33
|
+
data: data,
|
|
34
|
+
permissions, // 可以是 undefined
|
|
35
|
+
publicConfig,
|
|
36
|
+
};
|
|
37
|
+
const result = await this._post("/apps/data/create", requestData);
|
|
38
|
+
return result.wyID;
|
|
39
|
+
} catch (error) {
|
|
40
|
+
console.error(`创建AI应用数据失败 (model: ${modelName}):`, error);
|
|
41
|
+
throw error;
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* [新增] 更新一条现有数据
|
|
47
|
+
* @param {string} modelName - 模型的名称
|
|
48
|
+
* @param {string} wyID - 要更新数据的 wyID
|
|
49
|
+
* @param {object} data - 新的数据内容
|
|
50
|
+
* @param {object} [permissions] - 可选的权限对象,用于修改记录的访问权限
|
|
51
|
+
* @param {object} [publicConfig] - 可选的公共配置
|
|
52
|
+
* @returns {Promise<string>} - 被更新数据的 wyID
|
|
53
|
+
*/
|
|
54
|
+
async updateData(modelName, wyID, data, permissions, publicConfig) {
|
|
55
|
+
try {
|
|
56
|
+
const requestData = {
|
|
57
|
+
appId: this.appId,
|
|
58
|
+
modelName,
|
|
59
|
+
wyID,
|
|
60
|
+
data: data,
|
|
61
|
+
permissions,
|
|
62
|
+
publicConfig,
|
|
63
|
+
};
|
|
64
|
+
const result = await this._post("/apps/data/update", requestData);
|
|
65
|
+
return result.wyID;
|
|
66
|
+
} catch (error) {
|
|
67
|
+
console.error(`更新AI应用数据失败 (model: ${modelName}, wyID: ${wyID}):`, error);
|
|
68
|
+
throw error;
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
|
|
72
|
+
async readData(modelName, query) {
|
|
73
|
+
try {
|
|
74
|
+
if (!modelName) {
|
|
75
|
+
throw new Error("modelName is required");
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const params = {
|
|
79
|
+
appId: this.appId,
|
|
80
|
+
modelName: modelName,
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
if (typeof query === "string") {
|
|
84
|
+
params.wyID = query;
|
|
85
|
+
} else if (query && typeof query === "object") {
|
|
86
|
+
const { page = 1, pageSize = 20, fields, filter } = query;
|
|
87
|
+
params.page = Math.max(1, parseInt(page));
|
|
88
|
+
params.pageSize = parseInt(pageSize) || 1000;
|
|
89
|
+
console.log(params);
|
|
90
|
+
if (fields && Array.isArray(fields)) {
|
|
91
|
+
params.fields = fields;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (filter && typeof filter === "object") {
|
|
95
|
+
params.filter = filter;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const result = await this._get("/apps/data/read", params);
|
|
100
|
+
|
|
101
|
+
if (result.data === null && params.wyID) {
|
|
102
|
+
console.log(`📋 [AppsClient] No data found for app: ${this.appId}, model: ${modelName}, wyID: ${params.wyID}`);
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
console.log(`✅ [AppsClient] Data read successfully for app: ${this.appId}, model: ${modelName}`);
|
|
107
|
+
return result;
|
|
108
|
+
} catch (error) {
|
|
109
|
+
// 404 Not Found and 403 Forbidden are business logic, not exceptions
|
|
110
|
+
if (error.message.includes("404") || error.message.includes("403")) {
|
|
111
|
+
console.warn(`读取AI应用数据警告 (model: ${modelName}):`, error.message);
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
console.error(`读取AI应用数据失败 (model: ${modelName}):`, error);
|
|
115
|
+
throw error;
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
|
|
119
|
+
async deleteData(modelName, wyID, options = {}) {
|
|
120
|
+
try {
|
|
121
|
+
if (!modelName) {
|
|
122
|
+
throw new Error("modelName is required");
|
|
123
|
+
}
|
|
124
|
+
if (!wyID) {
|
|
125
|
+
throw new Error("wyID is required");
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const { hard = false } = options;
|
|
129
|
+
|
|
130
|
+
const requestData = {
|
|
131
|
+
appId: this.appId,
|
|
132
|
+
modelName: modelName,
|
|
133
|
+
wyID: wyID,
|
|
134
|
+
hard: hard,
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
const result = await this._delete("/apps/data/delete", requestData);
|
|
138
|
+
|
|
139
|
+
const deleteType = hard ? "hard deleted" : "soft deleted";
|
|
140
|
+
console.log(
|
|
141
|
+
`✅ [AppsClient] Data ${deleteType} successfully for app: ${this.appId}, model: ${modelName}, wyID: ${wyID}`
|
|
142
|
+
);
|
|
143
|
+
return result.wyID;
|
|
144
|
+
} catch (error) {
|
|
145
|
+
console.error(`删除AI应用数据失败 (model: ${modelName}, wyID: ${wyID}):`, error);
|
|
146
|
+
throw error;
|
|
147
|
+
}
|
|
148
|
+
},
|
|
149
|
+
|
|
150
|
+
// ==================== 便捷方法 ====================
|
|
151
|
+
|
|
152
|
+
async hasData(modelName) {
|
|
153
|
+
try {
|
|
154
|
+
if (!modelName) throw new Error("modelName is required for hasData");
|
|
155
|
+
const result = await this.readData(modelName, { page: 1, pageSize: 1 });
|
|
156
|
+
return result && result.data && result.data.length > 0;
|
|
157
|
+
} catch (error) {
|
|
158
|
+
console.error(`检查应用数据失败 (model: ${modelName}):`, error);
|
|
159
|
+
return false;
|
|
160
|
+
}
|
|
161
|
+
},
|
|
162
|
+
|
|
163
|
+
async clearData(modelName) {
|
|
164
|
+
try {
|
|
165
|
+
if (!modelName) throw new Error("modelName is required for clearData");
|
|
166
|
+
// This is not a correct implementation of clear. It just writes an empty object.
|
|
167
|
+
// A proper clear would require a dedicated backend endpoint.
|
|
168
|
+
// For now, we keep the old behavior.
|
|
169
|
+
return await this.createData(modelName, {});
|
|
170
|
+
} catch (error) {
|
|
171
|
+
console.error(`清空应用数据失败 (model: ${modelName}):`, error);
|
|
172
|
+
throw error;
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
|
|
176
|
+
async getDataVersion(modelName, wyID) {
|
|
177
|
+
try {
|
|
178
|
+
if (!modelName) throw new Error("modelName is required for getDataVersion");
|
|
179
|
+
if (!wyID) throw new Error("wyID is required for getDataVersion");
|
|
180
|
+
const result = await this.readData(modelName, wyID);
|
|
181
|
+
return result ? result.meta : null;
|
|
182
|
+
} catch (error) {
|
|
183
|
+
console.error(`获取数据版本失败 (model: ${modelName}):`, error);
|
|
184
|
+
throw error;
|
|
185
|
+
}
|
|
186
|
+
},
|
|
187
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { isBrowser } from "../../../utils/index.js";
|
|
2
|
+
|
|
3
|
+
export const appsClientDebugMethods = {
|
|
4
|
+
// ==================== 便捷方法 ====================
|
|
5
|
+
|
|
6
|
+
updateConfig(newConfig) {
|
|
7
|
+
this.config = { ...this.config, ...newConfig };
|
|
8
|
+
},
|
|
9
|
+
|
|
10
|
+
getConfig() {
|
|
11
|
+
return { ...this.config };
|
|
12
|
+
},
|
|
13
|
+
|
|
14
|
+
// ==================== 调试和监控 ====================
|
|
15
|
+
|
|
16
|
+
async getClientStatus() {
|
|
17
|
+
try {
|
|
18
|
+
const status = {
|
|
19
|
+
appId: this.appId,
|
|
20
|
+
config: this.getConfig(),
|
|
21
|
+
clientType: "AppsClient (Multi-Model with AI)",
|
|
22
|
+
};
|
|
23
|
+
if (isBrowser) {
|
|
24
|
+
status.hasAccessToken = !!localStorage.getItem("tacoreai_apps_access_token");
|
|
25
|
+
}
|
|
26
|
+
return status;
|
|
27
|
+
} catch (error) {
|
|
28
|
+
console.error("获取AI应用客户端状态失败:", error);
|
|
29
|
+
const status = {
|
|
30
|
+
appId: this.appId,
|
|
31
|
+
config: this.getConfig(),
|
|
32
|
+
error: error.message,
|
|
33
|
+
clientType: "AppsClient (Multi-Model with AI)",
|
|
34
|
+
};
|
|
35
|
+
if (isBrowser) {
|
|
36
|
+
status.hasAccessToken = !!localStorage.getItem("tacoreai_apps_access_token");
|
|
37
|
+
}
|
|
38
|
+
return status;
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
export const appsClientDeployMethods = {
|
|
2
|
+
// ==================== [新增] 部署与环境管理 ====================
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 独立部署 (Deploy Customer / Pro Plan)
|
|
6
|
+
* @param {object} params
|
|
7
|
+
* @param {string} params.appId
|
|
8
|
+
* @param {object} params.files
|
|
9
|
+
* @param {string} [params.envName='default']
|
|
10
|
+
* @param {string} params.appVersion
|
|
11
|
+
* @param {string} params.appHistoryVersionId
|
|
12
|
+
*/
|
|
13
|
+
async deployCustomer(params) {
|
|
14
|
+
if (!params.appId || !params.files) {
|
|
15
|
+
throw new Error("appId and files are required for deployCustomer.");
|
|
16
|
+
}
|
|
17
|
+
console.log("🚀 [AppsClient] Starting deployCustomer for app:", params.appId);
|
|
18
|
+
return this._post("/apps/deploy-customer", params);
|
|
19
|
+
},
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* 添加自定义域名
|
|
23
|
+
* @param {object} params { appId, hostname, envName }
|
|
24
|
+
*/
|
|
25
|
+
async addCustomDomain(params) {
|
|
26
|
+
if (!params.appId || !params.hostname) {
|
|
27
|
+
throw new Error("appId and hostname are required.");
|
|
28
|
+
}
|
|
29
|
+
return this._post("/apps/applications/addCustomDomain", params);
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* 删除自定义域名
|
|
34
|
+
* @param {object} params { appId, hostname, envName }
|
|
35
|
+
*/
|
|
36
|
+
async deleteCustomDomain(params) {
|
|
37
|
+
if (!params.appId || !params.hostname) {
|
|
38
|
+
throw new Error("appId and hostname are required.");
|
|
39
|
+
}
|
|
40
|
+
return this._post("/apps/applications/deleteCustomDomain", params);
|
|
41
|
+
},
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* 创建自定义环境
|
|
45
|
+
* @param {object} params { appId, envName, description }
|
|
46
|
+
*/
|
|
47
|
+
async createEnvironment(params) {
|
|
48
|
+
return this._post("/apps/applications/createEnvironment", params);
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* 更新环境信息
|
|
53
|
+
* @param {object} params { appId, envName, updates }
|
|
54
|
+
*/
|
|
55
|
+
async updateEnvironment(params) {
|
|
56
|
+
return this._post("/apps/applications/updateEnvironment", params);
|
|
57
|
+
},
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* 删除环境
|
|
61
|
+
* @param {object} params { appId, envName }
|
|
62
|
+
*/
|
|
63
|
+
async deleteEnvironment(params) {
|
|
64
|
+
return this._post("/apps/applications/deleteEnvironment", params);
|
|
65
|
+
},
|
|
66
|
+
};
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
export const appsClientEcommerceMethods = {
|
|
2
|
+
// ==================== [新增] 电商模块 ====================
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* (管理员) 创建一个新商品。
|
|
6
|
+
* @param {object} productData - 商品数据。
|
|
7
|
+
* @param {string} productData.name - (必填) 商品名称。
|
|
8
|
+
* @param {number} productData.price - (必填) 商品价格。
|
|
9
|
+
* @param {string} [productData.description] - (可选) 商品描述。
|
|
10
|
+
* @param {Array<{url: string, name?: string, size?: number}>} [productData.images] - (可选) 商品图片对象数组。
|
|
11
|
+
* @param {'active' | 'inactive'} [productData.status='active'] - (可选) 商品状态, 'active' (上架) 或 'inactive' (下架)。
|
|
12
|
+
* @returns {Promise<{success: boolean, data: {wyID: string}}>} 返回一个包含新商品 wyID 的对象。
|
|
13
|
+
*/
|
|
14
|
+
async createProduct(productData) {
|
|
15
|
+
if (!productData || typeof productData !== "object") {
|
|
16
|
+
throw new Error("productData must be an object.");
|
|
17
|
+
}
|
|
18
|
+
if (!productData.name || typeof productData.name !== "string") {
|
|
19
|
+
throw new Error("productData.name is required and must be a string.");
|
|
20
|
+
}
|
|
21
|
+
if (productData.price === undefined || typeof productData.price !== "number") {
|
|
22
|
+
throw new Error("productData.price is required and must be a number.");
|
|
23
|
+
}
|
|
24
|
+
return this._post("/apps/product/create", { appId: this.appId, data: productData });
|
|
25
|
+
},
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* (公开) 获取单个商品详情。
|
|
29
|
+
* @param {string} productId - 要获取的商品的 wyID。
|
|
30
|
+
* @returns {Promise<{success: boolean, data: object|null}>} 返回一个包含商品完整文档的对象。如果找不到,data 为 null。
|
|
31
|
+
*/
|
|
32
|
+
async getProduct(productId) {
|
|
33
|
+
if (!productId || typeof productId !== "string") {
|
|
34
|
+
throw new Error("productId is required and must be a string.");
|
|
35
|
+
}
|
|
36
|
+
return this._get("/apps/product/read", { appId: this.appId, wyID: productId });
|
|
37
|
+
},
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* (公开) 获取商品列表。
|
|
41
|
+
* @param {object} [options] - 分页选项。
|
|
42
|
+
* @param {number} [options.page=1] - 页码,从1开始。
|
|
43
|
+
* @param {number} [options.pageSize=20] - 每页数量。
|
|
44
|
+
* @returns {Promise<{success: boolean, data: object[], total: number, page: number, pageSize: number, totalPages: number, hasNext: boolean, hasPrev: boolean}>} 返回商品文档列表和分页信息。
|
|
45
|
+
*/
|
|
46
|
+
async listProducts(options = {}) {
|
|
47
|
+
return this._get("/apps/product/read", { appId: this.appId, ...options });
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* (管理员) 更新一个商品。
|
|
52
|
+
* @param {string} productId - 要更新的商品的 wyID。
|
|
53
|
+
* @param {object} productData - 要更新的商品数据,可包含 name, description, price, images, status 中的任意字段。
|
|
54
|
+
* @returns {Promise<{success: boolean, data: {wyID: string}}>} 返回一个包含被更新商品 wyID 的对象。
|
|
55
|
+
*/
|
|
56
|
+
async updateProduct(productId, productData) {
|
|
57
|
+
if (!productId || typeof productId !== "string") {
|
|
58
|
+
throw new Error("productId is required and must be a string.");
|
|
59
|
+
}
|
|
60
|
+
if (!productData || typeof productData !== "object" || Object.keys(productData).length === 0) {
|
|
61
|
+
throw new Error("productData must be a non-empty object.");
|
|
62
|
+
}
|
|
63
|
+
return this._post("/apps/product/update", { appId: this.appId, wyID: productId, data: productData });
|
|
64
|
+
},
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* (管理员) 删除一个商品 (软删除)。
|
|
68
|
+
* @param {string} productId - 要删除的商品的 wyID。
|
|
69
|
+
* @returns {Promise<{success: boolean, data: {wyID: string}}>} 返回一个包含被删除商品 wyID 的对象。
|
|
70
|
+
*/
|
|
71
|
+
async deleteProduct(productId) {
|
|
72
|
+
if (!productId || typeof productId !== "string") {
|
|
73
|
+
throw new Error("productId is required and must be a string.");
|
|
74
|
+
}
|
|
75
|
+
return this._post("/apps/product/delete", { appId: this.appId, wyID: productId });
|
|
76
|
+
},
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* (用户) 创建一个新订单,并获取支付链接。
|
|
80
|
+
* @param {object} orderData - 订单数据。
|
|
81
|
+
* @param {Array<{productId: string, units: number}>} orderData.products - (必填) 商品列表,包含商品ID和数量。
|
|
82
|
+
* @param {string} orderData.successUrlPrefix - (必填) 支付成功后的跳转页面URL前缀,后端会自动附加 ?orderId=xxx。
|
|
83
|
+
* @param {object} [orderData.metadata] - (可选) 附加的元数据,如客户备注等。
|
|
84
|
+
* @returns {Promise<{success: boolean, data: {checkoutUrl: string, orderId: string}}>} 返回支付网关的URL和内部订单ID。
|
|
85
|
+
*/
|
|
86
|
+
async createOrder(orderData) {
|
|
87
|
+
if (!orderData || typeof orderData !== "object") {
|
|
88
|
+
throw new Error("orderData must be an object.");
|
|
89
|
+
}
|
|
90
|
+
if (!Array.isArray(orderData.products) || orderData.products.length === 0) {
|
|
91
|
+
throw new Error("orderData.products is required and must be a non-empty array.");
|
|
92
|
+
}
|
|
93
|
+
if (!orderData.successUrlPrefix || typeof orderData.successUrlPrefix !== "string") {
|
|
94
|
+
throw new Error("orderData.successUrlPrefix is required and must be a string.");
|
|
95
|
+
}
|
|
96
|
+
return this._post("/apps/order/create", { appId: this.appId, ...orderData });
|
|
97
|
+
},
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* (用户/管理员) 获取单个订单详情。
|
|
101
|
+
* 普通用户只能获取自己的订单,管理员可以获取应用下任意订单。
|
|
102
|
+
* @param {string} orderId - 要获取的订单的 wyID。
|
|
103
|
+
* @returns {Promise<{success: boolean, data: object|null}>} 返回一个包含订单完整文档的对象。如果找不到或无权限,data 为 null。
|
|
104
|
+
*/
|
|
105
|
+
async getOrder(orderId) {
|
|
106
|
+
if (!orderId || typeof orderId !== "string") {
|
|
107
|
+
throw new Error("orderId is required and must be a string.");
|
|
108
|
+
}
|
|
109
|
+
return this._get("/apps/order/read", { appId: this.appId, wyID: orderId });
|
|
110
|
+
},
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* (用户/管理员) 获取订单列表。
|
|
114
|
+
* 普通用户只能获取自己的订单列表,管理员可以获取应用下所有订单列表。
|
|
115
|
+
* @param {object} [options] - 分页选项。
|
|
116
|
+
* @param {number} [options.page=1] - 页码,从1开始。
|
|
117
|
+
* @param {number} [options.pageSize=20] - 每页数量。
|
|
118
|
+
* @returns {Promise<{success: boolean, data: object[], total: number, ...}>} 返回订单文档列表和分页信息。
|
|
119
|
+
*/
|
|
120
|
+
async listOrders(options = {}) {
|
|
121
|
+
return this._get("/apps/order/read", { appId: this.appId, ...options });
|
|
122
|
+
},
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* (管理员) 更新一个订单。
|
|
126
|
+
* @param {string} orderId - 要更新的订单的 wyID。
|
|
127
|
+
* @param {object} orderData - 要更新的订单数据。
|
|
128
|
+
* @returns {Promise<{success: boolean, data: {wyID: string}}>} 返回一个包含被更新订单 wyID 的对象。
|
|
129
|
+
*/
|
|
130
|
+
async updateOrder(orderId, orderData) {
|
|
131
|
+
if (!orderId || typeof orderId !== "string") {
|
|
132
|
+
throw new Error("orderId is required and must be a string.");
|
|
133
|
+
}
|
|
134
|
+
if (!orderData || typeof orderData !== "object" || Object.keys(orderData).length === 0) {
|
|
135
|
+
throw new Error("orderData must be a non-empty object.");
|
|
136
|
+
}
|
|
137
|
+
return this._post("/apps/order/update", { appId: this.appId, wyID: orderId, data: orderData });
|
|
138
|
+
},
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* (管理员) 删除一个订单 (软删除)。
|
|
142
|
+
* @param {string} orderId - 要删除的订单的 wyID。
|
|
143
|
+
* @returns {Promise<{success: boolean, data: {wyID: string}}>} 返回一个包含被删除订单 wyID 的对象。
|
|
144
|
+
*/
|
|
145
|
+
async deleteOrder(orderId) {
|
|
146
|
+
if (!orderId || typeof orderId !== "string") {
|
|
147
|
+
throw new Error("orderId is required and must be a string.");
|
|
148
|
+
}
|
|
149
|
+
return this._post("/apps/order/delete", { appId: this.appId, wyID: orderId });
|
|
150
|
+
},
|
|
151
|
+
};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
export const appsClientKvMethods = {
|
|
2
|
+
// ==================== KV 存储 ====================
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Cloudflare KV: 获取数据
|
|
6
|
+
* @param {string} key
|
|
7
|
+
* @param {object} params - 查询参数
|
|
8
|
+
* @returns {Promise<any>}
|
|
9
|
+
*/
|
|
10
|
+
async kvGet(key, params = {}) {
|
|
11
|
+
if (!key) throw new Error("key is required");
|
|
12
|
+
let endpoint = `/apps/kv/${encodeURIComponent(key)}`;
|
|
13
|
+
|
|
14
|
+
const searchParams = new URLSearchParams();
|
|
15
|
+
Object.keys(params).forEach(k => {
|
|
16
|
+
if (params[k] !== undefined && params[k] !== null) {
|
|
17
|
+
searchParams.append(k, params[k]);
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
const queryString = searchParams.toString();
|
|
21
|
+
if (queryString) {
|
|
22
|
+
endpoint += `?${queryString}`;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const result = await this._apiRequest(endpoint, {
|
|
26
|
+
method: "GET",
|
|
27
|
+
});
|
|
28
|
+
return result.data;
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Cloudflare KV: 写入数据
|
|
33
|
+
* @param {string} key
|
|
34
|
+
* @param {any} value
|
|
35
|
+
* @param {object} options - { expirationTtl?: number, expiration?: number }
|
|
36
|
+
* @returns {Promise<boolean>}
|
|
37
|
+
*/
|
|
38
|
+
async kvPut(key, value, options = {}) {
|
|
39
|
+
if (!key) throw new Error("key is required");
|
|
40
|
+
const endpoint = `/apps/kv/${encodeURIComponent(key)}`;
|
|
41
|
+
const result = await this._apiRequest(endpoint, {
|
|
42
|
+
method: "PUT",
|
|
43
|
+
body: JSON.stringify({ value, ...options }),
|
|
44
|
+
});
|
|
45
|
+
return result.success;
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Cloudflare KV: 删除数据
|
|
50
|
+
* @param {string} key
|
|
51
|
+
* @param {object} params - 查询参数
|
|
52
|
+
* @returns {Promise<boolean>}
|
|
53
|
+
*/
|
|
54
|
+
async kvDelete(key, params = {}) {
|
|
55
|
+
if (!key) throw new Error("key is required");
|
|
56
|
+
let endpoint = `/apps/kv/${encodeURIComponent(key)}`;
|
|
57
|
+
|
|
58
|
+
const searchParams = new URLSearchParams();
|
|
59
|
+
Object.keys(params).forEach(k => {
|
|
60
|
+
if (params[k] !== undefined && params[k] !== null) {
|
|
61
|
+
searchParams.append(k, params[k]);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
const queryString = searchParams.toString();
|
|
65
|
+
if (queryString) {
|
|
66
|
+
endpoint += `?${queryString}`;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const result = await this._delete(endpoint);
|
|
70
|
+
return result.success;
|
|
71
|
+
},
|
|
72
|
+
};
|