@tacoreai/web-sdk 1.19.0 → 1.20.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.
@@ -142,8 +142,8 @@ export class AppsAuthManager extends BaseAppsClient {
142
142
  'verifyRegistration': ({ email, token }) => this.verifyRegistration(email, token),
143
143
  'loginWithPassword': ({ email, password }) => this.loginWithPassword(email, password),
144
144
  'loginWithWechatH5': ({ code, scope }) => this.loginWithWechatH5(code, scope),
145
- 'forgotPassword': ({ email, redirectTo }) => this.forgotPassword(email, redirectTo),
146
- 'updatePassword': ({ accessToken, newPassword }) => this.updatePassword(accessToken, newPassword),
145
+ 'auth/forgot-password': ({ email }) => this.forgotPassword(email),
146
+ 'auth/reset-password': ({ email, token, newPassword }) => this.resetPassword(email, token, newPassword),
147
147
  'logout': () => this.logout(),
148
148
  'getCurrentUser': () => this.getCurrentUser(),
149
149
  'getSession': () => this.getSession(),
@@ -432,34 +432,34 @@ export class AppsAuthManager extends BaseAppsClient {
432
432
  }
433
433
 
434
434
  /**
435
- * 请求发送密码重置邮件
435
+ * 请求发送密码重置邮件(包含 recovery 验证码)
436
436
  * @param {string} email - 用户的邮箱
437
- * @param {string} redirectTo - 用户点击邮件链接后重定向到的前端页面URL
438
437
  * @returns {Promise<Object>}
439
438
  */
440
- async forgotPassword(email, redirectTo) {
441
- if (!email || !redirectTo) {
442
- throw new Error("Email and redirectTo URL are required.");
439
+ async forgotPassword(email) {
440
+ if (!email) {
441
+ throw new Error("Email is required.");
443
442
  }
444
443
  return this._apiRequest("/apps/auth/forgot-password", {
445
444
  method: "POST",
446
- body: JSON.stringify({ email, redirectTo }),
445
+ body: JSON.stringify({ email }),
447
446
  });
448
447
  }
449
448
 
450
449
  /**
451
- * 使用令牌更新用户密码
452
- * @param {string} accessToken - 从重定向URL中获取的访问令牌
450
+ * 使用邮箱验证码更新用户密码
451
+ * @param {string} email - 用户邮箱
452
+ * @param {string} token - 邮箱收到的 recovery OTP
453
453
  * @param {string} newPassword - 用户输入的新密码
454
454
  * @returns {Promise<Object>}
455
455
  */
456
- async updatePassword(accessToken, newPassword) {
457
- if (!accessToken || !newPassword) {
458
- throw new Error("Access token and new password are required.");
456
+ async resetPassword(email, token, newPassword) {
457
+ if (!email || !token || !newPassword) {
458
+ throw new Error("Email, token and new password are required.");
459
459
  }
460
- return this._apiRequest("/apps/auth/update-password", {
460
+ return this._apiRequest("/apps/auth/reset-password", {
461
461
  method: "POST",
462
- body: JSON.stringify({ accessToken, newPassword }),
462
+ body: JSON.stringify({ email, token, newPassword }),
463
463
  });
464
464
  }
465
465
 
@@ -46,4 +46,20 @@ export const appsClientUserMethods = {
46
46
  role: role,
47
47
  });
48
48
  },
49
+
50
+ /**
51
+ * [新增] 更新或重置一个用户在当前应用中的登录密码
52
+ * @param {Object} params { userId: string, password: string }
53
+ * @returns {Promise<{success: boolean, data: {userId: string, appId: string}}>}
54
+ */
55
+ async updateUserPassword({ userId, password }) {
56
+ if (!userId || !password) {
57
+ throw new Error("userId and password are required.");
58
+ }
59
+ return this._post("/apps/users/update-password", {
60
+ appId: this.appId,
61
+ targetUserId: userId,
62
+ password,
63
+ });
64
+ },
49
65
  };
@@ -0,0 +1,155 @@
1
+ import { isBrowser } from "../../../utils/index.js";
2
+
3
+ const appendWechatFileToForm = (form, file) => {
4
+ if (!file) {
5
+ throw new Error("file is required");
6
+ }
7
+
8
+ if (isBrowser) {
9
+ if (file instanceof File || file instanceof Blob) {
10
+ form.append("file", file, file.name || "file");
11
+ return;
12
+ }
13
+
14
+ throw new Error("Invalid file input in browser. Provide a File or Blob object.");
15
+ }
16
+
17
+ if (typeof file === "object" && file?.data && file?.encoding === "base64" && file?.name) {
18
+ const buffer = Buffer.from(file.data, "base64");
19
+ const blob = new Blob([buffer], {
20
+ type: file.type || file.mimeType || "application/octet-stream",
21
+ });
22
+ form.append("file", blob, file.name);
23
+ return;
24
+ }
25
+
26
+ if (file instanceof Blob) {
27
+ form.append("file", file, file.name || "file");
28
+ return;
29
+ }
30
+
31
+ throw new Error(
32
+ "Invalid file input in Node.js. Provide { data: base64_string, encoding: 'base64', name: string } or a Blob."
33
+ );
34
+ };
35
+
36
+ const postWechatMultipart = async function(endpoint, form) {
37
+ const headers = this._getRequestHeaders();
38
+ delete headers["Content-Type"];
39
+ delete headers["content-type"];
40
+
41
+ const response = await fetch(`${this.config.apiBaseUrl}${endpoint}`, {
42
+ method: "POST",
43
+ headers,
44
+ body: form,
45
+ });
46
+
47
+ const result = await response.json().catch(() => ({}));
48
+ if (!response.ok) {
49
+ throw new Error(result.message || result.error || `HTTP ${response.status}: ${response.statusText}`);
50
+ }
51
+
52
+ if (typeof this._validateResponse === "function") {
53
+ this._validateResponse(result);
54
+ }
55
+
56
+ return result;
57
+ };
58
+
59
+ export const appsClientWechatMethods = {
60
+ async wechatGetCapabilities(options = {}) {
61
+ return this._post("/apps/wechat/capabilities", options);
62
+ },
63
+
64
+ async wechatUploadArticleImage({ file }) {
65
+ const form = new FormData();
66
+ form.append("appId", this.appId);
67
+ appendWechatFileToForm(form, file);
68
+ return await postWechatMultipart.call(this, "/apps/wechat/official-account/materials/upload-article-image", form);
69
+ },
70
+
71
+ async wechatUploadTemporaryMaterial({ file, type }) {
72
+ if (!type) {
73
+ throw new Error("type is required for wechatUploadTemporaryMaterial");
74
+ }
75
+
76
+ const form = new FormData();
77
+ form.append("appId", this.appId);
78
+ form.append("type", type);
79
+ appendWechatFileToForm(form, file);
80
+ return await postWechatMultipart.call(this, "/apps/wechat/official-account/materials/upload-temporary", form);
81
+ },
82
+
83
+ async wechatUploadPermanentMaterial({ file, type, title, introduction }) {
84
+ if (!type) {
85
+ throw new Error("type is required for wechatUploadPermanentMaterial");
86
+ }
87
+
88
+ const form = new FormData();
89
+ form.append("appId", this.appId);
90
+ form.append("type", type);
91
+ if (title) form.append("title", title);
92
+ if (introduction) form.append("introduction", introduction);
93
+ appendWechatFileToForm(form, file);
94
+ return await postWechatMultipart.call(this, "/apps/wechat/official-account/materials/upload-permanent", form);
95
+ },
96
+
97
+ async wechatGetPermanentMaterialCount() {
98
+ return this._post("/apps/wechat/official-account/materials/count", {});
99
+ },
100
+
101
+ async wechatListPermanentMaterials(options = {}) {
102
+ return this._post("/apps/wechat/official-account/materials/list", options);
103
+ },
104
+
105
+ async wechatDeletePermanentMaterial({ mediaId }) {
106
+ return this._post("/apps/wechat/official-account/materials/delete", { mediaId });
107
+ },
108
+
109
+ async wechatCreateDraft({ articles }) {
110
+ return this._post("/apps/wechat/official-account/drafts/add", { articles });
111
+ },
112
+
113
+ async wechatUpdateDraft({ mediaId, index = 0, article }) {
114
+ return this._post("/apps/wechat/official-account/drafts/update", {
115
+ mediaId,
116
+ index,
117
+ article,
118
+ });
119
+ },
120
+
121
+ async wechatGetDraft({ mediaId }) {
122
+ return this._post("/apps/wechat/official-account/drafts/get", { mediaId });
123
+ },
124
+
125
+ async wechatListDrafts(options = {}) {
126
+ return this._post("/apps/wechat/official-account/drafts/list", options);
127
+ },
128
+
129
+ async wechatDeleteDraft({ mediaId }) {
130
+ return this._post("/apps/wechat/official-account/drafts/delete", { mediaId });
131
+ },
132
+
133
+ async wechatPublishDraft({ mediaId }) {
134
+ return this._post("/apps/wechat/official-account/publish/submit", { mediaId });
135
+ },
136
+
137
+ async wechatGetPublishStatus({ publishId }) {
138
+ return this._post("/apps/wechat/official-account/publish/status", { publishId });
139
+ },
140
+
141
+ async wechatGetPublishedArticle({ articleId }) {
142
+ return this._post("/apps/wechat/official-account/publish/get-article", { articleId });
143
+ },
144
+
145
+ async wechatListPublishedArticles(options = {}) {
146
+ return this._post("/apps/wechat/official-account/publish/list", options);
147
+ },
148
+
149
+ async wechatDeletePublishedArticle({ articleId, index }) {
150
+ return this._post("/apps/wechat/official-account/publish/delete-article", {
151
+ articleId,
152
+ index,
153
+ });
154
+ },
155
+ };
@@ -17,6 +17,7 @@ import { appsClientTextInMethods } from "./AppsClient.TextIn.js";
17
17
  import { appsClientToolsMethods } from "./AppsClient.Tools.js";
18
18
  import { appsClientDebugMethods } from "./AppsClient.Debug.js";
19
19
  import { appsClientCrawlerMethods } from "./AppsClient.Crawler.js";
20
+ import { appsClientWechatMethods } from "./AppsClient.Wechat.js";
20
21
 
21
22
  const instanceMap = new Map();
22
23
  /**
@@ -101,6 +102,7 @@ class AppsClient extends BaseAppsClient {
101
102
  // === 用户与角色 ===
102
103
  "createRole": params => this.createRole(params),
103
104
  "updateUserRole": params => this.updateUserRole(params),
105
+ "users/update-password": params => this.updateUserPassword(params),
104
106
  "listAppUsers": params => this.listAppUsers(params),
105
107
 
106
108
  // === 文件存储 ===
@@ -210,7 +212,8 @@ Object.assign(
210
212
  appsClientTextInMethods,
211
213
  appsClientToolsMethods,
212
214
  appsClientDebugMethods,
213
- appsClientCrawlerMethods
215
+ appsClientCrawlerMethods,
216
+ appsClientWechatMethods
214
217
  );
215
218
 
216
219
  export { AppsClient };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tacoreai/web-sdk",
3
3
  "description": "This file is for app server package, not the real npm package",
4
- "version": "1.19.0",
4
+ "version": "1.20.0",
5
5
  "type": "module",
6
6
  "publishConfig": {
7
7
  "access": "public",