@softtynet/zca-js 2.3.6 → 2.3.7

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.
Files changed (51) hide show
  1. package/README.md +25 -2
  2. package/dist/apis/business/blockOA.d.ts +2 -0
  3. package/dist/apis/business/blockOA.js +28 -0
  4. package/dist/apis/business/convertOAIds.d.ts +4 -0
  5. package/dist/apis/business/convertOAIds.js +26 -0
  6. package/dist/apis/business/getOAProfile.d.ts +13 -0
  7. package/dist/apis/business/getOAProfile.js +64 -0
  8. package/dist/apis/business/unblockOA.d.ts +2 -0
  9. package/dist/apis/business/unblockOA.js +28 -0
  10. package/dist/apis/chat/preloadConversations.d.ts +3 -2
  11. package/dist/apis/chat/preloadConversations.js +14 -0
  12. package/dist/apis/sync/getSyncData.js +1 -1
  13. package/dist/apis.d.ts +12 -0
  14. package/dist/apis.js +20 -0
  15. package/dist/cjs/apis/business/blockOA.cjs +33 -0
  16. package/dist/cjs/apis/business/convertOAIds.cjs +31 -0
  17. package/dist/cjs/apis/business/getOAProfile.cjs +69 -0
  18. package/dist/cjs/apis/business/unblockOA.cjs +33 -0
  19. package/dist/cjs/apis/chat/preloadConversations.cjs +14 -0
  20. package/dist/cjs/apis/sync/getSyncData.cjs +20 -1
  21. package/dist/cjs/apis.cjs +20 -0
  22. package/dist/cjs/constants/defaults.cjs +2 -2
  23. package/dist/cjs/constants/protocol.cjs +1 -1
  24. package/dist/cjs/index.cjs +10 -0
  25. package/dist/cjs/models/Message.cjs +16 -1
  26. package/dist/cjs/models/OAMessage.cjs +375 -0
  27. package/dist/cjs/realtime/handlers/control.handler.cjs +9 -1
  28. package/dist/cjs/realtime/handlers/message.handler.cjs +103 -37
  29. package/dist/cjs/realtime/listener.cjs +39 -18
  30. package/dist/cjs/utils.cjs +21 -2
  31. package/dist/cjs/zalo.cjs +21 -2
  32. package/dist/constants/defaults.d.ts +2 -2
  33. package/dist/constants/defaults.js +2 -2
  34. package/dist/constants/protocol.d.ts +1 -1
  35. package/dist/constants/protocol.js +1 -1
  36. package/dist/index.d.ts +4 -0
  37. package/dist/models/Message.d.ts +12 -1
  38. package/dist/models/Message.js +16 -1
  39. package/dist/models/OAMessage.d.ts +221 -0
  40. package/dist/models/OAMessage.js +363 -0
  41. package/dist/models/index.d.ts +1 -0
  42. package/dist/models/index.js +1 -0
  43. package/dist/realtime/handlers/control.handler.js +9 -1
  44. package/dist/realtime/handlers/message.handler.js +103 -37
  45. package/dist/realtime/listener.d.ts +9 -3
  46. package/dist/realtime/listener.js +39 -18
  47. package/dist/realtime/types.d.ts +15 -1
  48. package/dist/utils.js +1 -1
  49. package/dist/zalo.d.ts +1 -1
  50. package/dist/zalo.js +1 -1
  51. package/package.json +2 -1
package/README.md CHANGED
@@ -14,10 +14,11 @@
14
14
 
15
15
  ## Điểm nổi bật
16
16
 
17
- - **Kiến trúc 12 Domains (`252 API nguyên bản`)**: Tổ chức trực quan qua `api.auth`, `api.chat`, `api.group`, `api.friend`, `api.profile`, `api.sync`, `api.zcloud`, `api.call`, `api.media`, `api.sticker`, `api.board`, `api.business` (vẫn hỗ trợ gọi phẳng `api.<method>` tương thích ngược 100%).
17
+ - **Kiến trúc 12 Domains (`256 API nguyên bản`)**: Tổ chức trực quan qua `api.auth`, `api.chat`, `api.group`, `api.friend`, `api.profile`, `api.sync`, `api.zcloud`, `api.call`, `api.media`, `api.sticker`, `api.board`, `api.business` (vẫn hỗ trợ gọi phẳng `api.<method>` tương thích ngược 100%).
18
18
  - **Đồng bộ lịch sử Mobile (`ZDB 4.0`) & Catch-up Sync**: Hỗ trợ đầy đủ luồng `requestSyncFromPhone` $\rightarrow$ `getSyncData` (giải mã RSA-2048 OAEP/PKCS1 + ZDB 4.0 64KB multi-chunk AES-256-CBC + Deflate) & `pullMobile`.
19
19
  - **ZCloud, MediaStore & Bảo toàn Số nguyên 64-bit (`preParseJsonIds`)**: Tự động giữ nguyên độ chính xác chuỗi 19 chữ số cho `owner_id`, `group_id`, `globalMsgId`, `cliMsgId` trước khi `JSON.parse()` và tích hợp bộ mã hóa `98yS` AES-256-CBC cho ZCloud/ZFamily.
20
20
  - **Zalo Call Engine thuần TypeScript (`30 API` trong `api.call` + `ZaloRtcSession` / `ZaloCallController`)**: Hỗ trợ đầy đủ cả **Gọi Đi** và **Nhận Cuộc Gọi Đến** (Thoại 1-1, Video Call H.264 FU-A Annex-B 2 chiều, Gọi Nhóm), nâng cấp Thoại $\rightarrow$ Video giữa cuộc gọi, bật/tắt Camera/Mic, Tạm giữ (Hold/Unhold), Tái kết nối UDP (`reconnectUdp`), và **Bàn giao kết nối UDP trực tiếp cho Mobile App (`signalingOnly` / `handoffUdpToExternal`)**.
21
+ - **Hội thoại & Quản lý Zalo Official Account (OA) 2 chiều (`api.business.getOAProfile`, `blockOA`, `unblockOA`, `convertOAIds`)**: Tự động bóc tách tin nhắn OA (`pageMsgs`, `chat.list.action`, `footerv2`), giải mã bitmask tích vàng (`isOAVerified`), Zalo Bot (`isZaloBot`), trạng thái DNR (`parseOADnrStatus`) và lắng nghe thời gian thực qua `oa_message` & `oa_event`.
21
22
 
22
23
  ---
23
24
 
@@ -66,7 +67,7 @@ const zalo = new Zalo({ imageMetadataGetter });
66
67
  | **Kho lưu trữ & Voice-to-Text** | `api.media` | 8 | [`docs/api/media.md`](docs/api/media.md) |
67
68
  | **Nhãn dán & Biểu cảm** | `api.sticker` | 10 | [`docs/api/sticker.md`](docs/api/sticker.md) |
68
69
  | **Bảng tin, Bình chọn & Lịch hẹn** | `api.board` | 16 | [`docs/api/board.md`](docs/api/board.md) |
69
- | **Zalo Business & Danh mục** | `api.business` | 26 | [`docs/api/business.md`](docs/api/business.md) |
70
+ | **Zalo Business, OA & Danh mục** | `api.business` | 30 | [`docs/api/business.md`](docs/api/business.md) |
70
71
 
71
72
  > Xem tổng quan toàn bộ tài liệu tại [`docs/api/index.md`](docs/api/index.md) hoặc chạy trang tài liệu VitePress cục bộ bằng lệnh `npm run docs:dev`.
72
73
 
@@ -161,6 +162,28 @@ const handoffParams = await session.startOutgoingCall("5249661060655759359", {
161
162
  });
162
163
  ```
163
164
 
165
+ ### 5. Nhận, Trả lời & Quản lý Zalo Official Account (OA) 2 chiều
166
+
167
+ ```ts
168
+ import { ThreadType } from "@softtynet/zca-js";
169
+
170
+ // 1) Lấy hồ sơ chi tiết của Zalo OA (tích vàng isVerified, hotline, website, giờ mở cửa, DNR)
171
+ const oaProfile = await api.business.getOAProfile("2359864726282056346");
172
+ console.log(oaProfile.displayName, oaProfile.isVerified, oaProfile.hotline);
173
+
174
+ // 2) Lắng nghe tin nhắn OA thời gian thực (`oa_chat`, `oa_list`, `info_chat`, `ecard`) và trả lời 2 chiều
175
+ api.listener.on("oa_message", async (msg) => {
176
+ console.log(`[OA ${msg.oaData?.kind}] ${msg.data.dName}: ${msg.oaData?.text}`);
177
+ if (!msg.isSelf) {
178
+ await api.chat.sendMessage({ msg: "Cảm ơn OA!" }, msg.threadId, ThreadType.User);
179
+ }
180
+ });
181
+
182
+ // 3) Chặn / Bỏ chặn OA & chuyển đổi OA ID
183
+ await api.business.blockOA("2359864726282056346");
184
+ await api.business.unblockOA("2359864726282056346");
185
+ ```
186
+
164
187
  ---
165
188
 
166
189
  ## Chạy trang Tài liệu (VitePress Docs)
@@ -0,0 +1,2 @@
1
+ export type BlockOAResponse = "" | Record<string, unknown>;
2
+ export declare const blockOAFactory: (ctx: import("../../context.js").ContextBase, api: import("../../apis.js").API) => (oaId: string) => Promise<BlockOAResponse>;
@@ -0,0 +1,28 @@
1
+ import { ZaloApiError } from "../../Errors/ZaloApiError.js";
2
+ import { apiFactory } from "../../utils.js";
3
+ export const blockOAFactory = apiFactory()((api, _ctx, utils) => {
4
+ const serviceURL = utils.makeURL(`${api.zpwServiceMap.profile[0]}/api/social/oa/block`);
5
+ /**
6
+ * Chặn nhận tin nhắn / thông báo từ một Zalo Official Account (OA).
7
+ * Tương ứng với hàm `setBlockOA` (`commandId = 12681`) trên Zalo Desktop.
8
+ *
9
+ * @param oaId UID hoặc OA ID của Official Account cần chặn
10
+ *
11
+ * @throws {ZaloApiError}
12
+ */
13
+ return async function blockOA(oaId) {
14
+ const params = {
15
+ oaid: String(oaId),
16
+ };
17
+ const encryptedParams = utils.encodeAES(JSON.stringify(params));
18
+ if (!encryptedParams)
19
+ throw new ZaloApiError("Failed to encrypt params");
20
+ const response = await utils.request(serviceURL, {
21
+ method: "POST",
22
+ body: new URLSearchParams({
23
+ params: encryptedParams,
24
+ }),
25
+ });
26
+ return utils.resolve(response);
27
+ };
28
+ });
@@ -0,0 +1,4 @@
1
+ export type ConvertOAIdsResponse = {
2
+ [oaId: string]: string | unknown;
3
+ };
4
+ export declare const convertOAIdsFactory: (ctx: import("../../context.js").ContextBase, api: import("../../apis.js").API) => (oaIds: string | string[]) => Promise<ConvertOAIdsResponse>;
@@ -0,0 +1,26 @@
1
+ import { ZaloApiError } from "../../Errors/ZaloApiError.js";
2
+ import { apiFactory } from "../../utils.js";
3
+ export const convertOAIdsFactory = apiFactory()((api, _ctx, utils) => {
4
+ const serviceURL = utils.makeURL(`${api.zpwServiceMap.profile[0]}/api/social/oa/convertid`);
5
+ /**
6
+ * Chuyển đổi danh sách OA ID sang Zalo UID nội bộ (hoặc ngược lại).
7
+ * Tương ứng với hàm `convertOAIds` (`commandId = 11863`) trên Zalo Desktop.
8
+ *
9
+ * @param oaIds Một OA ID hoặc mảng các OA ID cần chuyển đổi
10
+ *
11
+ * @throws {ZaloApiError}
12
+ */
13
+ return async function convertOAIds(oaIds) {
14
+ const normalizedIds = (Array.isArray(oaIds) ? oaIds : [oaIds]).map(String);
15
+ const params = {
16
+ oa_ids: normalizedIds,
17
+ };
18
+ const encryptedParams = utils.encodeAES(JSON.stringify(params));
19
+ if (!encryptedParams)
20
+ throw new ZaloApiError("Failed to encrypt params");
21
+ const response = await utils.request(utils.makeURL(serviceURL, { params: encryptedParams }), {
22
+ method: "GET",
23
+ });
24
+ return utils.resolve(response);
25
+ };
26
+ });
@@ -0,0 +1,13 @@
1
+ import { type OAProfileInfo } from "../../models/OAMessage.js";
2
+ export type GetOAProfileOptions = {
3
+ /**
4
+ * Kích thước ảnh đại diện (mặc định: `240`).
5
+ */
6
+ avatarSize?: number;
7
+ /**
8
+ * Có lấy kèm thông tin tài khoản Business (`/api/social/friend/get-bizacc`) hay không (mặc định: `true`).
9
+ */
10
+ includeBizAccount?: boolean;
11
+ };
12
+ export type GetOAProfileResponse = OAProfileInfo;
13
+ export declare const getOAProfileFactory: (ctx: import("../../context.js").ContextBase, api: import("../../apis.js").API) => (oaId: string, options?: GetOAProfileOptions) => Promise<GetOAProfileResponse>;
@@ -0,0 +1,64 @@
1
+ import { ZaloApiError } from "../../Errors/ZaloApiError.js";
2
+ import { normalizeOAProfile } from "../../models/OAMessage.js";
3
+ import { apiFactory } from "../../utils.js";
4
+ export const getOAProfileFactory = apiFactory()((api, ctx, utils) => {
5
+ const profileServiceURL = utils.makeURL(`${api.zpwServiceMap.profile[0]}/api/social/friend/getprofiles/v2`);
6
+ const bizServiceURL = utils.makeURL(`${api.zpwServiceMap.profile[0]}/api/social/friend/get-bizacc`);
7
+ /**
8
+ * Lấy hồ sơ đầy đủ của một Zalo Official Account (OA) theo `oaId`
9
+ * (bao gồm `oaInfo`, trạng thái tích vàng `isVerified`, `isZaloBot`, `isGroupedMsg`, trạng thái chặn/DNR `dnrStatus`, hotline, website, giờ mở cửa, địa chỉ, danh mục...).
10
+ *
11
+ * @param oaId UID của Zalo Official Account
12
+ * @param options Tùy chọn truy vấn
13
+ * @throws {ZaloApiError}
14
+ */
15
+ return async function getOAProfile(oaId, options = {}) {
16
+ const cleanId = String(oaId ?? "").trim().split("_")[0];
17
+ if (!cleanId) {
18
+ throw new ZaloApiError("Missing oaId");
19
+ }
20
+ const profileParams = {
21
+ phonebook_version: 0,
22
+ friend_pversion_map: [`${cleanId}_0`],
23
+ avatar_size: options.avatarSize ?? 240,
24
+ language: ctx.language ?? "vi",
25
+ show_online_status: 1,
26
+ isReqOAInfo: 1,
27
+ imei: ctx.imei,
28
+ };
29
+ const encryptedProfileParams = utils.encodeAES(JSON.stringify(profileParams));
30
+ if (!encryptedProfileParams) {
31
+ throw new ZaloApiError("Failed to encrypt OA profile params");
32
+ }
33
+ const fetchProfilePromise = utils
34
+ .request(profileServiceURL, {
35
+ method: "POST",
36
+ body: new URLSearchParams({
37
+ params: encryptedProfileParams,
38
+ }),
39
+ })
40
+ .then((res) => utils.resolve(res));
41
+ const fetchBizPromise = options.includeBizAccount !== false
42
+ ? (async () => {
43
+ const encryptedBizParams = utils.encodeAES(JSON.stringify({ fid: cleanId }));
44
+ if (!encryptedBizParams)
45
+ return null;
46
+ const res = await utils.request(bizServiceURL, {
47
+ method: "POST",
48
+ body: new URLSearchParams({
49
+ params: encryptedBizParams,
50
+ }),
51
+ });
52
+ return utils.resolve(res);
53
+ })().catch(() => null)
54
+ : Promise.resolve(null);
55
+ const [profileRes, bizRes] = await Promise.all([fetchProfilePromise, fetchBizPromise]);
56
+ const profileData = (profileRes ?? {});
57
+ const changedProfiles = (profileData.changed_profiles ?? profileData.profiles ?? {});
58
+ const rawProfile = changedProfiles[cleanId] ??
59
+ changedProfiles[`${cleanId}_0`] ??
60
+ Object.values(changedProfiles)[0] ??
61
+ null;
62
+ return normalizeOAProfile(cleanId, rawProfile, bizRes && typeof bizRes === "object" ? bizRes : null);
63
+ };
64
+ });
@@ -0,0 +1,2 @@
1
+ export type UnblockOAResponse = "" | Record<string, unknown>;
2
+ export declare const unblockOAFactory: (ctx: import("../../context.js").ContextBase, api: import("../../apis.js").API) => (oaId: string) => Promise<UnblockOAResponse>;
@@ -0,0 +1,28 @@
1
+ import { ZaloApiError } from "../../Errors/ZaloApiError.js";
2
+ import { apiFactory } from "../../utils.js";
3
+ export const unblockOAFactory = apiFactory()((api, _ctx, utils) => {
4
+ const serviceURL = utils.makeURL(`${api.zpwServiceMap.profile[0]}/api/social/oa/unblock`);
5
+ /**
6
+ * Bỏ chặn một Zalo Official Account (OA) để tiếp tục nhận tin nhắn / ZNS.
7
+ * Tương ứng với hàm `setBlockOA` (`commandId = 12682`) trên Zalo Desktop.
8
+ *
9
+ * @param oaId UID hoặc OA ID của Official Account cần bỏ chặn
10
+ *
11
+ * @throws {ZaloApiError}
12
+ */
13
+ return async function unblockOA(oaId) {
14
+ const params = {
15
+ oaid: String(oaId),
16
+ };
17
+ const encryptedParams = utils.encodeAES(JSON.stringify(params));
18
+ if (!encryptedParams)
19
+ throw new ZaloApiError("Failed to encrypt params");
20
+ const response = await utils.request(serviceURL, {
21
+ method: "POST",
22
+ body: new URLSearchParams({
23
+ params: encryptedParams,
24
+ }),
25
+ });
26
+ return utils.resolve(response);
27
+ };
28
+ });
@@ -1,4 +1,4 @@
1
- import { ClearUnread, type Message, type TClearUnreadItem, type TGroupMessage, type TMessage } from "../../models/index.js";
1
+ import { ClearUnread, UserMessage, type Message, type TClearUnreadItem, type TGroupMessage, type TMessage } from "../../models/index.js";
2
2
  export type PreloadConversationsRawResponse = {
3
3
  msgs?: TMessage[];
4
4
  groupMsgs?: TGroupMessage[];
@@ -6,7 +6,7 @@ export type PreloadConversationsRawResponse = {
6
6
  isGroup?: boolean | number;
7
7
  })>;
8
8
  eeMsgs?: unknown[];
9
- pageMsgs?: unknown[];
9
+ pageMsgs?: TMessage[];
10
10
  clearUnreads?: TClearUnreadItem[];
11
11
  clearUnreadsReact?: TClearUnreadItem[];
12
12
  seens?: unknown[];
@@ -23,6 +23,7 @@ export type PreloadConversationsRawResponse = {
23
23
  };
24
24
  export type PreloadConversationsResponse = PreloadConversationsRawResponse & {
25
25
  messages: Message[];
26
+ pageMessages: UserMessage[];
26
27
  unreadCleared: ClearUnread[];
27
28
  };
28
29
  export declare const preloadConversationsFactory: (ctx: import("../../context.js").ContextBase, api: import("../../apis.js").API) => (threadIdLocalMsgId?: Record<string, string | number>) => Promise<PreloadConversationsResponse>;
@@ -27,6 +27,7 @@ export const preloadConversationsFactory = apiFactory()((api, ctx, utils) => {
27
27
  data = JSON.parse(data);
28
28
  }
29
29
  const messages = [];
30
+ const pageMessages = [];
30
31
  const seenMsgIds = new Set();
31
32
  if (Array.isArray(data.msgs)) {
32
33
  for (const msg of data.msgs) {
@@ -38,6 +39,18 @@ export const preloadConversationsFactory = apiFactory()((api, ctx, utils) => {
38
39
  messages.push(new UserMessage(ctx.uid, msg));
39
40
  }
40
41
  }
42
+ if (Array.isArray(data.pageMsgs)) {
43
+ for (const msg of data.pageMsgs) {
44
+ const id = String(msg.msgId ?? "");
45
+ if (id && seenMsgIds.has(id))
46
+ continue;
47
+ if (id)
48
+ seenMsgIds.add(id);
49
+ const userMsg = new UserMessage(ctx.uid, msg, true);
50
+ pageMessages.push(userMsg);
51
+ messages.push(userMsg);
52
+ }
53
+ }
41
54
  if (Array.isArray(data.groupMsgs)) {
42
55
  for (const msg of data.groupMsgs) {
43
56
  const id = String(msg.msgId ?? "");
@@ -71,6 +84,7 @@ export const preloadConversationsFactory = apiFactory()((api, ctx, utils) => {
71
84
  return {
72
85
  ...data,
73
86
  messages,
87
+ pageMessages,
74
88
  unreadCleared,
75
89
  };
76
90
  });
@@ -1,6 +1,6 @@
1
1
  import fs from "node:fs";
2
2
  import path from "node:path";
3
- import toughCookie from "tough-cookie";
3
+ import * as toughCookie from "tough-cookie";
4
4
  import { ZaloApiError } from "../../Errors/ZaloApiError.js";
5
5
  import { apiFactory, ZALO_DOMAINS } from "../../utils.js";
6
6
  export const getSyncDataFactory = apiFactory()((api, ctx, utils) => {
package/dist/apis.d.ts CHANGED
@@ -12,6 +12,7 @@ import { analyseGroupFactory } from "./apis/group/analyseGroup.js";
12
12
  import { answerAckVoiceCallFactory } from "./apis/call/answerAckVoiceCall.js";
13
13
  import { answerGroupCallFactory } from "./apis/call/answerGroupCall.js";
14
14
  import { answerVoiceCallFactory } from "./apis/call/answerVoiceCall.js";
15
+ import { blockOAFactory } from "./apis/business/blockOA.js";
15
16
  import { blockUserFactory } from "./apis/friend/blockUser.js";
16
17
  import { blockViewFeedFactory } from "./apis/friend/blockViewFeed.js";
17
18
  import { broadcastGroupCallStateFactory } from "./apis/call/broadcastGroupCallState.js";
@@ -25,6 +26,7 @@ import { changeGroupNameFactory } from "./apis/group/changeGroupName.js";
25
26
  import { changeGroupOwnerFactory } from "./apis/group/changeGroupOwner.js";
26
27
  import { checkQuotaCommunityMemberFactory } from "./apis/group/checkQuotaCommunityMember.js";
27
28
  import { clearUnreadFriendRequestsFactory } from "./apis/friend/clearUnreadFriendRequests.js";
29
+ import { convertOAIdsFactory } from "./apis/business/convertOAIds.js";
28
30
  import { createAutoReplyFactory } from "./apis/business/createAutoReply.js";
29
31
  import { createBankAccountFactory } from "./apis/business/createBankAccount.js";
30
32
  import { createCatalogFactory } from "./apis/business/createCatalog.js";
@@ -126,6 +128,7 @@ import { getMultiGroupCloudMessagesFactory } from "./apis/group/getMultiGroupClo
126
128
  import { getMultiUsersByPhonesFactory } from "./apis/friend/getMultiUsersByPhones.js";
127
129
  import { getMuteFactory } from "./apis/chat/getMute.js";
128
130
  import { getNoisedIdsFactory } from "./apis/auth/getNoisedIds.js";
131
+ import { getOAProfileFactory } from "./apis/business/getOAProfile.js";
129
132
  import { getOwnIdFactory } from "./apis/auth/getOwnId.js";
130
133
  import { getPendingGroupMembersFactory } from "./apis/group/getPendingGroupMembers.js";
131
134
  import { getPersonalizedStickerListFactory } from "./apis/sticker/getPersonalizedStickerList.js";
@@ -221,6 +224,7 @@ import { setMuteFactory } from "./apis/chat/setMute.js";
221
224
  import { setPinnedConversationsFactory } from "./apis/chat/setPinnedConversations.js";
222
225
  import { sharePollFactory } from "./apis/board/sharePoll.js";
223
226
  import { shareScreenGroupCallFactory } from "./apis/call/shareScreenGroupCall.js";
227
+ import { unblockOAFactory } from "./apis/business/unblockOA.js";
224
228
  import { unblockUserFactory } from "./apis/friend/unblockUser.js";
225
229
  import { undoFactory } from "./apis/chat/undo.js";
226
230
  import { undoFriendRequestFactory } from "./apis/friend/undoFriendRequest.js";
@@ -289,6 +293,8 @@ export type BoardDomainAPI = {
289
293
  };
290
294
  export type BusinessDomainAPI = {
291
295
  readonly addQuickMessage: ReturnType<typeof addQuickMessageFactory>;
296
+ readonly blockOA: ReturnType<typeof blockOAFactory>;
297
+ readonly convertOAIds: ReturnType<typeof convertOAIdsFactory>;
292
298
  readonly createAutoReply: ReturnType<typeof createAutoReplyFactory>;
293
299
  readonly createBankAccount: ReturnType<typeof createBankAccountFactory>;
294
300
  readonly createCatalog: ReturnType<typeof createCatalogFactory>;
@@ -303,10 +309,12 @@ export type BusinessDomainAPI = {
303
309
  readonly getLabels: ReturnType<typeof getLabelsFactory>;
304
310
  readonly getListBank: ReturnType<typeof getListBankFactory>;
305
311
  readonly getListBankAccount: ReturnType<typeof getListBankAccountFactory>;
312
+ readonly getOAProfile: ReturnType<typeof getOAProfileFactory>;
306
313
  readonly getProductCatalogList: ReturnType<typeof getProductCatalogListFactory>;
307
314
  readonly getQuickMessageList: ReturnType<typeof getQuickMessageListFactory>;
308
315
  readonly registerCatalog: ReturnType<typeof registerCatalogFactory>;
309
316
  readonly removeQuickMessage: ReturnType<typeof removeQuickMessageFactory>;
317
+ readonly unblockOA: ReturnType<typeof unblockOAFactory>;
310
318
  readonly updateAutoReply: ReturnType<typeof updateAutoReplyFactory>;
311
319
  readonly updateBankAccount: ReturnType<typeof updateBankAccountFactory>;
312
320
  readonly updateCatalog: ReturnType<typeof updateCatalogFactory>;
@@ -562,6 +570,7 @@ export declare class API {
562
570
  get answerAckVoiceCall(): ReturnType<typeof answerAckVoiceCallFactory>;
563
571
  get answerGroupCall(): ReturnType<typeof answerGroupCallFactory>;
564
572
  get answerVoiceCall(): ReturnType<typeof answerVoiceCallFactory>;
573
+ get blockOA(): ReturnType<typeof blockOAFactory>;
565
574
  get blockUser(): ReturnType<typeof blockUserFactory>;
566
575
  get blockViewFeed(): ReturnType<typeof blockViewFeedFactory>;
567
576
  get broadcastGroupCallState(): ReturnType<typeof broadcastGroupCallStateFactory>;
@@ -575,6 +584,7 @@ export declare class API {
575
584
  get changeGroupOwner(): ReturnType<typeof changeGroupOwnerFactory>;
576
585
  get checkQuotaCommunityMember(): ReturnType<typeof checkQuotaCommunityMemberFactory>;
577
586
  get clearUnreadFriendRequests(): ReturnType<typeof clearUnreadFriendRequestsFactory>;
587
+ get convertOAIds(): ReturnType<typeof convertOAIdsFactory>;
578
588
  get createAutoReply(): ReturnType<typeof createAutoReplyFactory>;
579
589
  get createBankAccount(): ReturnType<typeof createBankAccountFactory>;
580
590
  get createCatalog(): ReturnType<typeof createCatalogFactory>;
@@ -676,6 +686,7 @@ export declare class API {
676
686
  get getMultiUsersByPhones(): ReturnType<typeof getMultiUsersByPhonesFactory>;
677
687
  get getMute(): ReturnType<typeof getMuteFactory>;
678
688
  get getNoisedIds(): ReturnType<typeof getNoisedIdsFactory>;
689
+ get getOAProfile(): ReturnType<typeof getOAProfileFactory>;
679
690
  get getOwnId(): ReturnType<typeof getOwnIdFactory>;
680
691
  get getPendingGroupMembers(): ReturnType<typeof getPendingGroupMembersFactory>;
681
692
  get getPersonalizedStickerList(): ReturnType<typeof getPersonalizedStickerListFactory>;
@@ -771,6 +782,7 @@ export declare class API {
771
782
  get setPinnedConversations(): ReturnType<typeof setPinnedConversationsFactory>;
772
783
  get sharePoll(): ReturnType<typeof sharePollFactory>;
773
784
  get shareScreenGroupCall(): ReturnType<typeof shareScreenGroupCallFactory>;
785
+ get unblockOA(): ReturnType<typeof unblockOAFactory>;
774
786
  get unblockUser(): ReturnType<typeof unblockUserFactory>;
775
787
  get undo(): ReturnType<typeof undoFactory>;
776
788
  get undoFriendRequest(): ReturnType<typeof undoFriendRequestFactory>;
package/dist/apis.js CHANGED
@@ -12,6 +12,7 @@ import { analyseGroupFactory } from "./apis/group/analyseGroup.js";
12
12
  import { answerAckVoiceCallFactory } from "./apis/call/answerAckVoiceCall.js";
13
13
  import { answerGroupCallFactory } from "./apis/call/answerGroupCall.js";
14
14
  import { answerVoiceCallFactory } from "./apis/call/answerVoiceCall.js";
15
+ import { blockOAFactory } from "./apis/business/blockOA.js";
15
16
  import { blockUserFactory } from "./apis/friend/blockUser.js";
16
17
  import { blockViewFeedFactory } from "./apis/friend/blockViewFeed.js";
17
18
  import { broadcastGroupCallStateFactory } from "./apis/call/broadcastGroupCallState.js";
@@ -25,6 +26,7 @@ import { changeGroupNameFactory } from "./apis/group/changeGroupName.js";
25
26
  import { changeGroupOwnerFactory } from "./apis/group/changeGroupOwner.js";
26
27
  import { checkQuotaCommunityMemberFactory } from "./apis/group/checkQuotaCommunityMember.js";
27
28
  import { clearUnreadFriendRequestsFactory } from "./apis/friend/clearUnreadFriendRequests.js";
29
+ import { convertOAIdsFactory } from "./apis/business/convertOAIds.js";
28
30
  import { createAutoReplyFactory } from "./apis/business/createAutoReply.js";
29
31
  import { createBankAccountFactory } from "./apis/business/createBankAccount.js";
30
32
  import { createCatalogFactory } from "./apis/business/createCatalog.js";
@@ -126,6 +128,7 @@ import { getMultiGroupCloudMessagesFactory } from "./apis/group/getMultiGroupClo
126
128
  import { getMultiUsersByPhonesFactory } from "./apis/friend/getMultiUsersByPhones.js";
127
129
  import { getMuteFactory } from "./apis/chat/getMute.js";
128
130
  import { getNoisedIdsFactory } from "./apis/auth/getNoisedIds.js";
131
+ import { getOAProfileFactory } from "./apis/business/getOAProfile.js";
129
132
  import { getOwnIdFactory } from "./apis/auth/getOwnId.js";
130
133
  import { getPendingGroupMembersFactory } from "./apis/group/getPendingGroupMembers.js";
131
134
  import { getPersonalizedStickerListFactory } from "./apis/sticker/getPersonalizedStickerList.js";
@@ -221,6 +224,7 @@ import { setMuteFactory } from "./apis/chat/setMute.js";
221
224
  import { setPinnedConversationsFactory } from "./apis/chat/setPinnedConversations.js";
222
225
  import { sharePollFactory } from "./apis/board/sharePoll.js";
223
226
  import { shareScreenGroupCallFactory } from "./apis/call/shareScreenGroupCall.js";
227
+ import { unblockOAFactory } from "./apis/business/unblockOA.js";
224
228
  import { unblockUserFactory } from "./apis/friend/unblockUser.js";
225
229
  import { undoFactory } from "./apis/chat/undo.js";
226
230
  import { undoFriendRequestFactory } from "./apis/friend/undoFriendRequest.js";
@@ -318,6 +322,8 @@ export class API {
318
322
  if (!this._domains.business) {
319
323
  const createNamespace = (api) => ({
320
324
  get addQuickMessage() { return api.addQuickMessage; },
325
+ get blockOA() { return api.blockOA; },
326
+ get convertOAIds() { return api.convertOAIds; },
321
327
  get createAutoReply() { return api.createAutoReply; },
322
328
  get createBankAccount() { return api.createBankAccount; },
323
329
  get createCatalog() { return api.createCatalog; },
@@ -332,10 +338,12 @@ export class API {
332
338
  get getLabels() { return api.getLabels; },
333
339
  get getListBank() { return api.getListBank; },
334
340
  get getListBankAccount() { return api.getListBankAccount; },
341
+ get getOAProfile() { return api.getOAProfile; },
335
342
  get getProductCatalogList() { return api.getProductCatalogList; },
336
343
  get getQuickMessageList() { return api.getQuickMessageList; },
337
344
  get registerCatalog() { return api.registerCatalog; },
338
345
  get removeQuickMessage() { return api.removeQuickMessage; },
346
+ get unblockOA() { return api.unblockOA; },
339
347
  get updateAutoReply() { return api.updateAutoReply; },
340
348
  get updateBankAccount() { return api.updateBankAccount; },
341
349
  get updateCatalog() { return api.updateCatalog; },
@@ -658,6 +666,9 @@ export class API {
658
666
  get answerVoiceCall() {
659
667
  return (this._cache.answerVoiceCall ??= answerVoiceCallFactory(this.ctx, this));
660
668
  }
669
+ get blockOA() {
670
+ return (this._cache.blockOA ??= blockOAFactory(this.ctx, this));
671
+ }
661
672
  get blockUser() {
662
673
  return (this._cache.blockUser ??= blockUserFactory(this.ctx, this));
663
674
  }
@@ -697,6 +708,9 @@ export class API {
697
708
  get clearUnreadFriendRequests() {
698
709
  return (this._cache.clearUnreadFriendRequests ??= clearUnreadFriendRequestsFactory(this.ctx, this));
699
710
  }
711
+ get convertOAIds() {
712
+ return (this._cache.convertOAIds ??= convertOAIdsFactory(this.ctx, this));
713
+ }
700
714
  get createAutoReply() {
701
715
  return (this._cache.createAutoReply ??= createAutoReplyFactory(this.ctx, this));
702
716
  }
@@ -1000,6 +1014,9 @@ export class API {
1000
1014
  get getNoisedIds() {
1001
1015
  return (this._cache.getNoisedIds ??= getNoisedIdsFactory(this.ctx, this));
1002
1016
  }
1017
+ get getOAProfile() {
1018
+ return (this._cache.getOAProfile ??= getOAProfileFactory(this.ctx, this));
1019
+ }
1003
1020
  get getOwnId() {
1004
1021
  return (this._cache.getOwnId ??= getOwnIdFactory(this.ctx, this));
1005
1022
  }
@@ -1285,6 +1302,9 @@ export class API {
1285
1302
  get shareScreenGroupCall() {
1286
1303
  return (this._cache.shareScreenGroupCall ??= shareScreenGroupCallFactory(this.ctx, this));
1287
1304
  }
1305
+ get unblockOA() {
1306
+ return (this._cache.unblockOA ??= unblockOAFactory(this.ctx, this));
1307
+ }
1288
1308
  get unblockUser() {
1289
1309
  return (this._cache.unblockUser ??= unblockUserFactory(this.ctx, this));
1290
1310
  }
@@ -0,0 +1,33 @@
1
+ 'use strict';
2
+
3
+ var ZaloApiError = require('../../Errors/ZaloApiError.cjs');
4
+ var utils = require('../../utils.cjs');
5
+
6
+ const blockOAFactory = utils.apiFactory()((api, _ctx, utils) => {
7
+ const serviceURL = utils.makeURL(`${api.zpwServiceMap.profile[0]}/api/social/oa/block`);
8
+ /**
9
+ * Chặn nhận tin nhắn / thông báo từ một Zalo Official Account (OA).
10
+ * Tương ứng với hàm `setBlockOA` (`commandId = 12681`) trên Zalo Desktop.
11
+ *
12
+ * @param oaId UID hoặc OA ID của Official Account cần chặn
13
+ *
14
+ * @throws {ZaloApiError}
15
+ */
16
+ return async function blockOA(oaId) {
17
+ const params = {
18
+ oaid: String(oaId),
19
+ };
20
+ const encryptedParams = utils.encodeAES(JSON.stringify(params));
21
+ if (!encryptedParams)
22
+ throw new ZaloApiError.ZaloApiError("Failed to encrypt params");
23
+ const response = await utils.request(serviceURL, {
24
+ method: "POST",
25
+ body: new URLSearchParams({
26
+ params: encryptedParams,
27
+ }),
28
+ });
29
+ return utils.resolve(response);
30
+ };
31
+ });
32
+
33
+ exports.blockOAFactory = blockOAFactory;
@@ -0,0 +1,31 @@
1
+ 'use strict';
2
+
3
+ var ZaloApiError = require('../../Errors/ZaloApiError.cjs');
4
+ var utils = require('../../utils.cjs');
5
+
6
+ const convertOAIdsFactory = utils.apiFactory()((api, _ctx, utils) => {
7
+ const serviceURL = utils.makeURL(`${api.zpwServiceMap.profile[0]}/api/social/oa/convertid`);
8
+ /**
9
+ * Chuyển đổi danh sách OA ID sang Zalo UID nội bộ (hoặc ngược lại).
10
+ * Tương ứng với hàm `convertOAIds` (`commandId = 11863`) trên Zalo Desktop.
11
+ *
12
+ * @param oaIds Một OA ID hoặc mảng các OA ID cần chuyển đổi
13
+ *
14
+ * @throws {ZaloApiError}
15
+ */
16
+ return async function convertOAIds(oaIds) {
17
+ const normalizedIds = (Array.isArray(oaIds) ? oaIds : [oaIds]).map(String);
18
+ const params = {
19
+ oa_ids: normalizedIds,
20
+ };
21
+ const encryptedParams = utils.encodeAES(JSON.stringify(params));
22
+ if (!encryptedParams)
23
+ throw new ZaloApiError.ZaloApiError("Failed to encrypt params");
24
+ const response = await utils.request(utils.makeURL(serviceURL, { params: encryptedParams }), {
25
+ method: "GET",
26
+ });
27
+ return utils.resolve(response);
28
+ };
29
+ });
30
+
31
+ exports.convertOAIdsFactory = convertOAIdsFactory;
@@ -0,0 +1,69 @@
1
+ 'use strict';
2
+
3
+ var ZaloApiError = require('../../Errors/ZaloApiError.cjs');
4
+ var OAMessage = require('../../models/OAMessage.cjs');
5
+ var utils = require('../../utils.cjs');
6
+
7
+ const getOAProfileFactory = utils.apiFactory()((api, ctx, utils) => {
8
+ const profileServiceURL = utils.makeURL(`${api.zpwServiceMap.profile[0]}/api/social/friend/getprofiles/v2`);
9
+ const bizServiceURL = utils.makeURL(`${api.zpwServiceMap.profile[0]}/api/social/friend/get-bizacc`);
10
+ /**
11
+ * Lấy hồ sơ đầy đủ của một Zalo Official Account (OA) theo `oaId`
12
+ * (bao gồm `oaInfo`, trạng thái tích vàng `isVerified`, `isZaloBot`, `isGroupedMsg`, trạng thái chặn/DNR `dnrStatus`, hotline, website, giờ mở cửa, địa chỉ, danh mục...).
13
+ *
14
+ * @param oaId UID của Zalo Official Account
15
+ * @param options Tùy chọn truy vấn
16
+ * @throws {ZaloApiError}
17
+ */
18
+ return async function getOAProfile(oaId, options = {}) {
19
+ const cleanId = String(oaId ?? "").trim().split("_")[0];
20
+ if (!cleanId) {
21
+ throw new ZaloApiError.ZaloApiError("Missing oaId");
22
+ }
23
+ const profileParams = {
24
+ phonebook_version: 0,
25
+ friend_pversion_map: [`${cleanId}_0`],
26
+ avatar_size: options.avatarSize ?? 240,
27
+ language: ctx.language ?? "vi",
28
+ show_online_status: 1,
29
+ isReqOAInfo: 1,
30
+ imei: ctx.imei,
31
+ };
32
+ const encryptedProfileParams = utils.encodeAES(JSON.stringify(profileParams));
33
+ if (!encryptedProfileParams) {
34
+ throw new ZaloApiError.ZaloApiError("Failed to encrypt OA profile params");
35
+ }
36
+ const fetchProfilePromise = utils
37
+ .request(profileServiceURL, {
38
+ method: "POST",
39
+ body: new URLSearchParams({
40
+ params: encryptedProfileParams,
41
+ }),
42
+ })
43
+ .then((res) => utils.resolve(res));
44
+ const fetchBizPromise = options.includeBizAccount !== false
45
+ ? (async () => {
46
+ const encryptedBizParams = utils.encodeAES(JSON.stringify({ fid: cleanId }));
47
+ if (!encryptedBizParams)
48
+ return null;
49
+ const res = await utils.request(bizServiceURL, {
50
+ method: "POST",
51
+ body: new URLSearchParams({
52
+ params: encryptedBizParams,
53
+ }),
54
+ });
55
+ return utils.resolve(res);
56
+ })().catch(() => null)
57
+ : Promise.resolve(null);
58
+ const [profileRes, bizRes] = await Promise.all([fetchProfilePromise, fetchBizPromise]);
59
+ const profileData = (profileRes ?? {});
60
+ const changedProfiles = (profileData.changed_profiles ?? profileData.profiles ?? {});
61
+ const rawProfile = changedProfiles[cleanId] ??
62
+ changedProfiles[`${cleanId}_0`] ??
63
+ Object.values(changedProfiles)[0] ??
64
+ null;
65
+ return OAMessage.normalizeOAProfile(cleanId, rawProfile, bizRes && typeof bizRes === "object" ? bizRes : null);
66
+ };
67
+ });
68
+
69
+ exports.getOAProfileFactory = getOAProfileFactory;
@@ -0,0 +1,33 @@
1
+ 'use strict';
2
+
3
+ var ZaloApiError = require('../../Errors/ZaloApiError.cjs');
4
+ var utils = require('../../utils.cjs');
5
+
6
+ const unblockOAFactory = utils.apiFactory()((api, _ctx, utils) => {
7
+ const serviceURL = utils.makeURL(`${api.zpwServiceMap.profile[0]}/api/social/oa/unblock`);
8
+ /**
9
+ * Bỏ chặn một Zalo Official Account (OA) để tiếp tục nhận tin nhắn / ZNS.
10
+ * Tương ứng với hàm `setBlockOA` (`commandId = 12682`) trên Zalo Desktop.
11
+ *
12
+ * @param oaId UID hoặc OA ID của Official Account cần bỏ chặn
13
+ *
14
+ * @throws {ZaloApiError}
15
+ */
16
+ return async function unblockOA(oaId) {
17
+ const params = {
18
+ oaid: String(oaId),
19
+ };
20
+ const encryptedParams = utils.encodeAES(JSON.stringify(params));
21
+ if (!encryptedParams)
22
+ throw new ZaloApiError.ZaloApiError("Failed to encrypt params");
23
+ const response = await utils.request(serviceURL, {
24
+ method: "POST",
25
+ body: new URLSearchParams({
26
+ params: encryptedParams,
27
+ }),
28
+ });
29
+ return utils.resolve(response);
30
+ };
31
+ });
32
+
33
+ exports.unblockOAFactory = unblockOAFactory;