From 9bcb3daf75924e33d3610914dba9dfbf21d65704 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ho=C3=A0ng=20H=C3=A0o?= Date: Wed, 15 Apr 2026 16:17:41 +0700 Subject: [PATCH 01/17] feat: add bank account and supported banks APIs - Introduced `getBankAccounts` and `getSupportedBanks` APIs to manage bank account information. - Added corresponding types `BankAccount` and `BankInfo` in the models. - Updated `apis.ts` and `index.ts` to include new API methods and types. - Bumped API version in `context.ts` to reflect new features. --- src/apis.ts | 6 +++ src/apis/getBankAccounts.ts | 48 +++++++++++++++++++++++ src/apis/getSupportedBanks.ts | 35 +++++++++++++++++ src/context.ts | 2 +- src/index.ts | 72 ++++++++++++++++++++++++++++++----- src/models/Bank.ts | 22 +++++++++++ src/models/index.ts | 1 + 7 files changed, 176 insertions(+), 10 deletions(-) create mode 100644 src/apis/getBankAccounts.ts create mode 100644 src/apis/getSupportedBanks.ts create mode 100644 src/models/Bank.ts diff --git a/src/apis.ts b/src/apis.ts index a3c914af..b27f6c65 100644 --- a/src/apis.ts +++ b/src/apis.ts @@ -46,6 +46,7 @@ import { getAutoDeleteChatFactory } from "./apis/getAutoDeleteChat.js"; import { getAutoReplyListFactory } from "./apis/getAutoReplyList.js"; import { getAvatarListFactory } from "./apis/getAvatarList.js"; import { getAvatarUrlProfileFactory } from "./apis/getAvatarUrlProfile.js"; +import { getBankAccountsFactory } from "./apis/getBankAccounts.js"; import { getBizAccountFactory } from "./apis/getBizAccount.js"; import { getCatalogListFactory } from "./apis/getCatalogList.js"; import { getCloseFriendsFactory } from "./apis/getCloseFriends.js"; @@ -85,6 +86,7 @@ import { getSettingsFactory } from "./apis/getSettings.js"; import { getStickerCategoryDetailFactory } from "./apis/getStickerCategoryDetail.js"; import { getStickersFactory } from "./apis/getStickers.js"; import { getStickersDetailFactory } from "./apis/getStickersDetail.js"; +import { getSupportedBanksFactory } from "./apis/getSupportedBanks.js"; import { getUnreadMarkFactory } from "./apis/getUnreadMark.js"; import { getUserInfoFactory } from "./apis/getUserInfo.js"; import { inviteUserToGroupsFactory } from "./apis/inviteUserToGroups.js"; @@ -198,6 +200,7 @@ export class API { public getAutoReplyList: ReturnType; public getAvatarList: ReturnType; public getAvatarUrlProfile: ReturnType; + public getBankAccounts: ReturnType; public getBizAccount: ReturnType; public getCatalogList: ReturnType; public getCloseFriends: ReturnType; @@ -237,6 +240,7 @@ export class API { public getStickerCategoryDetail: ReturnType; public getStickers: ReturnType; public getStickersDetail: ReturnType; + public getSupportedBanks: ReturnType; public getUnreadMark: ReturnType; public getUserInfo: ReturnType; public inviteUserToGroups: ReturnType; @@ -350,6 +354,7 @@ export class API { this.getAutoReplyList = getAutoReplyListFactory(ctx, this); this.getAvatarList = getAvatarListFactory(ctx, this); this.getAvatarUrlProfile = getAvatarUrlProfileFactory(ctx, this); + this.getBankAccounts = getBankAccountsFactory(ctx, this); this.getBizAccount = getBizAccountFactory(ctx, this); this.getCatalogList = getCatalogListFactory(ctx, this); this.getCloseFriends = getCloseFriendsFactory(ctx, this); @@ -389,6 +394,7 @@ export class API { this.getStickerCategoryDetail = getStickerCategoryDetailFactory(ctx, this); this.getStickers = getStickersFactory(ctx, this); this.getStickersDetail = getStickersDetailFactory(ctx, this); + this.getSupportedBanks = getSupportedBanksFactory(ctx, this); this.getUnreadMark = getUnreadMarkFactory(ctx, this); this.getUserInfo = getUserInfoFactory(ctx, this); this.inviteUserToGroups = inviteUserToGroupsFactory(ctx, this); diff --git a/src/apis/getBankAccounts.ts b/src/apis/getBankAccounts.ts new file mode 100644 index 00000000..8bb58bc3 --- /dev/null +++ b/src/apis/getBankAccounts.ts @@ -0,0 +1,48 @@ +import { ZaloApiError } from "../Errors/ZaloApiError.js"; +import { apiFactory } from "../utils.js"; + +export type GetBankAccountsResponse = { + hasMore: boolean; + total: number; + myBanks: { + id: string; + bin: number; + default: boolean; + bank_number: string; + bank_logo: string; + holder_name: string; + created_at: number; + updated_at: number; + account_id: number; + bank_name: string; + is_default: boolean; + }[]; +}; + +export const getBankAccountsFactory = apiFactory()((api, _ctx, utils) => { + const serviceURL = utils.makeURL(`${api.zpwServiceMap.zimsg[0]}/api/transfer/list`); + + /** + * Get bank accounts + * + * @param page Page number (default: 0) + * @param limit Number of items to retrieve (default: 20) + * + * @throws {ZaloApiError} + */ + return async function getBankAccounts(page: number = 0, limit: number = 20) { + const params = { + page: page, + limit: limit, + }; + + const encryptedParams = utils.encodeAES(JSON.stringify(params)); + if (!encryptedParams) throw new ZaloApiError("Failed to encrypt params"); + + const response = await utils.request(utils.makeURL(serviceURL, { params: encryptedParams }), { + method: "GET", + }); + + return utils.resolve(response); + }; +}); diff --git a/src/apis/getSupportedBanks.ts b/src/apis/getSupportedBanks.ts new file mode 100644 index 00000000..009fd30f --- /dev/null +++ b/src/apis/getSupportedBanks.ts @@ -0,0 +1,35 @@ +import { ZaloApiError } from "../Errors/ZaloApiError.js"; +import { apiFactory } from "../utils.js"; + +export type GetSupportedBanksResponse = { + banks: { + bin: number; + logo: string; + name: string; + name_eng: string; + short_name: string; + search_key_word: string; + }[]; +}; + +export const getSupportedBanksFactory = apiFactory()((api, _ctx, utils) => { + const serviceURL = utils.makeURL(`${api.zpwServiceMap.zimsg[0]}/api/transfer/conf`); + + /** + * Get supported banks + * + * @throws {ZaloApiError} + */ + return async function getSupportedBanks() { + const params = {}; + + const encryptedParams = utils.encodeAES(JSON.stringify(params)); + if (!encryptedParams) throw new ZaloApiError("Failed to encrypt params"); + + const response = await utils.request(utils.makeURL(serviceURL, { params: encryptedParams }), { + method: "GET", + }); + + return utils.resolve(response); + }; +}); diff --git a/src/context.ts b/src/context.ts index 21f2b20d..0fab251d 100644 --- a/src/context.ts +++ b/src/context.ts @@ -193,7 +193,7 @@ export type AppContextExtended = { export type ContextBase = Partial & AppContextExtended; -export const createContext = (apiType = 30, apiVersion = 671) => +export const createContext = (apiType = 30, apiVersion = 681) => ({ API_TYPE: apiType, API_VERSION: apiVersion, diff --git a/src/index.ts b/src/index.ts index ce84709c..7b8b3d95 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,7 +2,16 @@ export * from "./Errors/index.js"; export * from "./models/index.js"; export * from "./zalo.js"; -export type { ContextSession, ContextBase, AppContextExtended, AppContextBase, Options, ZPWServiceMap, ImageMetadataGetter,ImageMetadataGetterResponse } from "./context.js"; +export type { + ContextSession, + ContextBase, + AppContextExtended, + AppContextBase, + Options, + ZPWServiceMap, + ImageMetadataGetter, + ImageMetadataGetterResponse, +} from "./context.js"; // API TYPES export type { AcceptFriendRequestResponse } from "./apis/acceptFriendRequest.js"; @@ -26,7 +35,12 @@ export type { CreateGroupOptions, CreateGroupResponse } from "./apis/createGroup export type { CreateNoteOptions, CreateNoteResponse } from "./apis/createNote.js"; export type { CreatePollOptions, CreatePollResponse } from "./apis/createPoll.js"; export type { CreateProductCatalogPayload, CreateProductCatalogResponse } from "./apis/createProductCatalog.js"; -export type { CreateReminderOptions, CreateReminderResponse, CreateReminderUser, CreateReminderGroup } from "./apis/createReminder.js"; +export type { + CreateReminderOptions, + CreateReminderResponse, + CreateReminderUser, + CreateReminderGroup, +} from "./apis/createReminder.js"; export type { DeleteAutoReplyResponse } from "./apis/deleteAutoReply.js"; export type { DeleteAvatarResponse } from "./apis/deleteAvatar.js"; export type { DeleteCatalogResponse } from "./apis/deleteCatalog.js"; @@ -37,12 +51,22 @@ export type { DeleteProductCatalogPayload, DeleteProductCatalogResponse } from " export type { DisableGroupLinkResponse } from "./apis/disableGroupLink.js"; export type { DisperseGroupResponse } from "./apis/disperseGroup.js"; export type { EditNoteOptions, EditNoteResponse } from "./apis/editNote.js"; -export type { EditReminderGroup, EditReminderUser, EditReminderOptions, EditReminderResponse } from "./apis/editReminder.js"; +export type { + EditReminderGroup, + EditReminderUser, + EditReminderOptions, + EditReminderResponse, +} from "./apis/editReminder.js"; export type { EnableGroupLinkResponse } from "./apis/enableGroupLink.js"; export type { FetchAccountInfoResponse } from "./apis/fetchAccountInfo.js"; export type { FindUserResponse } from "./apis/findUser.js"; export type { FindUserByUsernameResponse } from "./apis/findUserByUsername.js"; -export type { ForwardMessageSuccess, ForwardMessageFail, ForwardMessagePayload, ForwardMessageResponse } from "./apis/forwardMessage.js"; +export type { + ForwardMessageSuccess, + ForwardMessageFail, + ForwardMessagePayload, + ForwardMessageResponse, +} from "./apis/forwardMessage.js"; export type { GetAliasListResponse } from "./apis/getAliasList.js"; export type { GetAllFriendsResponse } from "./apis/getAllFriends.js"; export type { GetAllGroupsResponse } from "./apis/getAllGroups.js"; @@ -51,12 +75,18 @@ export type { GetAutoDeleteChatResponse } from "./apis/getAutoDeleteChat.js"; export type { GetAutoReplyListResponse } from "./apis/getAutoReplyList.js"; export type { GetAvatarListResponse } from "./apis/getAvatarList.js"; export type { GetAvatarUrlProfileResponse } from "./apis/getAvatarUrlProfile.js"; +export type { GetBankAccountsResponse } from "./apis/getBankAccounts.js"; export type { GetBizAccountResponse } from "./apis/getBizAccount.js"; export type { GetCatalogListPayload, GetCatalogListResponse } from "./apis/getCatalogList.js"; export type { GetCloseFriendsResponse } from "./apis/getCloseFriends.js"; export type { GetFriendBoardListResponse } from "./apis/getFriendBoardList.js"; export type { GetFriendOnlinesResponse, GetFriendOnlinesStatus } from "./apis/getFriendOnlines.js"; -export type { GetFriendRecommendationsResponse, FriendRecommendationsCollapseMsgListConfig, FriendRecommendationsDataInfo, FriendRecommendationsRecommItem } from "./apis/getFriendRecommendations.js"; +export type { + GetFriendRecommendationsResponse, + FriendRecommendationsCollapseMsgListConfig, + FriendRecommendationsDataInfo, + FriendRecommendationsRecommItem, +} from "./apis/getFriendRecommendations.js"; export type { GetFriendRequestStatusResponse } from "./apis/getFriendRequestStatus.js"; export type { GetFullAvatarResponse } from "./apis/getFullAvatar.js"; export type { GetGroupBlockedMemberPayload, GetGroupBlockedMemberResponse } from "./apis/getGroupBlockedMember.js"; @@ -70,7 +100,12 @@ export type { GetGroupMembersInfoResponse, GroupMemberProfile } from "./apis/get export type { GetHiddenConversationsResponse } from "./apis/getHiddenConversations.js"; export type { GetLabelsResponse } from "./apis/getLabels.js"; export type { BoardItem, GetListBoardResponse, ListBoardOptions } from "./apis/getListBoard.js"; -export type { GetListReminderResponse, ListReminderOptions, ReminderListGroup, ReminderListUser } from "./apis/getListReminder.js"; +export type { + GetListReminderResponse, + ListReminderOptions, + ReminderListGroup, + ReminderListUser, +} from "./apis/getListReminder.js"; export type { GetMultiUsersByPhonesResponse } from "./apis/getMultiUsersByPhones.js"; export type { GetMuteResponse, MuteEntriesInfo } from "./apis/getMute.js"; export type { GetPendingGroupMembersResponse, GetPendingGroupMembersUserInfo } from "./apis/getPendingGroupMembers.js"; @@ -86,6 +121,7 @@ export type { GetSentFriendRequestResponse, SentFriendRequestInfo } from "./apis export type { GetSettingsResponse } from "./apis/getSettings.js"; export type { GetStickerCategoryDetailResponse } from "./apis/getStickerCategoryDetail.js"; export type { StickerDetailResponse } from "./apis/getStickersDetail.js"; +export type { GetSupportedBanksResponse } from "./apis/getSupportedBanks.js"; export type { GetUnreadMarkResponse, UnreadMark } from "./apis/getUnreadMark.js"; export type { ProfileInfo, UserInfoResponse } from "./apis/getUserInfo.js"; export type { InviteUserToGroupsResponse } from "./apis/inviteUserToGroups.js"; @@ -108,14 +144,24 @@ export type { RemoveUnreadMarkResponse } from "./apis/removeUnreadMark.js"; export type { RemoveUserFromGroupResponse } from "./apis/removeUserFromGroup.js"; export type { ResetHiddenConversPinResponse } from "./apis/resetHiddenConversPin.js"; export type { ReuseAvatarResponse } from "./apis/reuseAvatar.js"; -export type { ReviewPendingMemberRequestPayload, ReviewPendingMemberRequestResponse } from "./apis/reviewPendingMemberRequest.js"; +export type { + ReviewPendingMemberRequestPayload, + ReviewPendingMemberRequestResponse, +} from "./apis/reviewPendingMemberRequest.js"; export type { SearchStickerResponse } from "./apis/searchSticker.js"; export type { SendBankCardPayload, SendBankCardResponse } from "./apis/sendBankCard.js"; export type { SendCardOptions, SendCardResponse } from "./apis/sendCard.js"; export type { SendDeliveredEventMessageParams, SendDeliveredEventResponse } from "./apis/sendDeliveredEvent.js"; export type { SendFriendRequestResponse } from "./apis/sendFriendRequest.js"; export type { SendLinkOptions, SendLinkResponse } from "./apis/sendLink.js"; -export type { Mention, MessageContent, SendMessageQuote, SendMessageResponse, SendMessageResult, Style } from "./apis/sendMessage.js"; +export type { + Mention, + MessageContent, + SendMessageQuote, + SendMessageResponse, + SendMessageResult, + Style, +} from "./apis/sendMessage.js"; export type { SendReportOptions, SendReportResponse } from "./apis/sendReport.js"; export type { SendSeenEventMessageParams, SendSeenEventResponse } from "./apis/sendSeenEvent.js"; export type { SendStickerResponse, SendStickerPayload } from "./apis/sendSticker.js"; @@ -144,7 +190,15 @@ export type { UpdateProfileBioResponse } from "./apis/updateProfileBio.js"; export type { UpdateQuickMessagePayload, UpdateQuickMessageResponse } from "./apis/updateQuickMessage.js"; export type { UpdateSettingsResponse } from "./apis/updateSettings.js"; export type { UpgradeGroupToCommunityResponse } from "./apis/upgradeGroupToCommunity.js"; -export type { FileData, ImageData, UploadAttachmentResponse, UploadAttachmentType, UploadAttachmentImageResponse, UploadAttachmentVideoResponse, UploadAttachmentFileResponse } from "./apis/uploadAttachment.js"; +export type { + FileData, + ImageData, + UploadAttachmentResponse, + UploadAttachmentType, + UploadAttachmentImageResponse, + UploadAttachmentVideoResponse, + UploadAttachmentFileResponse, +} from "./apis/uploadAttachment.js"; export type { UploadProductPhotoPayload, UploadProductPhotoResponse } from "./apis/uploadProductPhoto.js"; export type { VotePollResponse } from "./apis/votePoll.js"; diff --git a/src/models/Bank.ts b/src/models/Bank.ts new file mode 100644 index 00000000..99a29c77 --- /dev/null +++ b/src/models/Bank.ts @@ -0,0 +1,22 @@ +export type BankInfo = { + bin: number; + logo: string; + name: string; + name_eng: string; + short_name: string; + search_key_word: string; +}; + +export type BankAccount = { + id: string; + bin: number; + default: boolean; + bank_number: string; + bank_logo: string; + holder_name: string; + created_at: number; + updated_at: number; + account_id: number; + bank_name: string; + is_default: boolean; +}; diff --git a/src/models/index.ts b/src/models/index.ts index 46f087d4..ae081288 100644 --- a/src/models/index.ts +++ b/src/models/index.ts @@ -1,5 +1,6 @@ export * from "./Attachment.js"; export * from "./AutoReply.js"; +export * from "./Bank.js"; export * from "./Board.js"; export * from "./Catalog.js"; export * from "./DeliveredMessage.js"; From 9f916962248a851c11d47971a9716b96d24bb9f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ho=C3=A0ng=20H=C3=A0o?= Date: Wed, 15 Apr 2026 16:22:41 +0700 Subject: [PATCH 02/17] refactor: streamline type exports in index.ts and enhance bank account APIs - Consolidated type exports in `index.ts` for improved readability. - Updated `GetBankAccountsResponse` and `GetSupportedBanksResponse` to utilize new `BankAccount` and `BankInfo` types, enhancing type safety and maintainability. - Removed redundant type definitions in favor of imported types from models. --- src/apis/getBankAccounts.ts | 15 +------- src/apis/getSupportedBanks.ts | 10 +---- src/index.ts | 70 +++++------------------------------ 3 files changed, 13 insertions(+), 82 deletions(-) diff --git a/src/apis/getBankAccounts.ts b/src/apis/getBankAccounts.ts index 8bb58bc3..027c3995 100644 --- a/src/apis/getBankAccounts.ts +++ b/src/apis/getBankAccounts.ts @@ -1,22 +1,11 @@ import { ZaloApiError } from "../Errors/ZaloApiError.js"; +import type { BankAccount } from "../models/index.js"; import { apiFactory } from "../utils.js"; export type GetBankAccountsResponse = { hasMore: boolean; total: number; - myBanks: { - id: string; - bin: number; - default: boolean; - bank_number: string; - bank_logo: string; - holder_name: string; - created_at: number; - updated_at: number; - account_id: number; - bank_name: string; - is_default: boolean; - }[]; + myBanks: BankAccount[]; }; export const getBankAccountsFactory = apiFactory()((api, _ctx, utils) => { diff --git a/src/apis/getSupportedBanks.ts b/src/apis/getSupportedBanks.ts index 009fd30f..279ae02a 100644 --- a/src/apis/getSupportedBanks.ts +++ b/src/apis/getSupportedBanks.ts @@ -1,15 +1,9 @@ import { ZaloApiError } from "../Errors/ZaloApiError.js"; +import type { BankInfo } from "../models/index.js"; import { apiFactory } from "../utils.js"; export type GetSupportedBanksResponse = { - banks: { - bin: number; - logo: string; - name: string; - name_eng: string; - short_name: string; - search_key_word: string; - }[]; + banks: BankInfo[]; }; export const getSupportedBanksFactory = apiFactory()((api, _ctx, utils) => { diff --git a/src/index.ts b/src/index.ts index 7b8b3d95..c0b07f9b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,16 +2,7 @@ export * from "./Errors/index.js"; export * from "./models/index.js"; export * from "./zalo.js"; -export type { - ContextSession, - ContextBase, - AppContextExtended, - AppContextBase, - Options, - ZPWServiceMap, - ImageMetadataGetter, - ImageMetadataGetterResponse, -} from "./context.js"; +export type { ContextSession, ContextBase, AppContextExtended, AppContextBase, Options, ZPWServiceMap, ImageMetadataGetter, ImageMetadataGetterResponse } from "./context.js"; // API TYPES export type { AcceptFriendRequestResponse } from "./apis/acceptFriendRequest.js"; @@ -35,12 +26,7 @@ export type { CreateGroupOptions, CreateGroupResponse } from "./apis/createGroup export type { CreateNoteOptions, CreateNoteResponse } from "./apis/createNote.js"; export type { CreatePollOptions, CreatePollResponse } from "./apis/createPoll.js"; export type { CreateProductCatalogPayload, CreateProductCatalogResponse } from "./apis/createProductCatalog.js"; -export type { - CreateReminderOptions, - CreateReminderResponse, - CreateReminderUser, - CreateReminderGroup, -} from "./apis/createReminder.js"; +export type { CreateReminderOptions, CreateReminderResponse, CreateReminderUser, CreateReminderGroup } from "./apis/createReminder.js"; export type { DeleteAutoReplyResponse } from "./apis/deleteAutoReply.js"; export type { DeleteAvatarResponse } from "./apis/deleteAvatar.js"; export type { DeleteCatalogResponse } from "./apis/deleteCatalog.js"; @@ -51,22 +37,12 @@ export type { DeleteProductCatalogPayload, DeleteProductCatalogResponse } from " export type { DisableGroupLinkResponse } from "./apis/disableGroupLink.js"; export type { DisperseGroupResponse } from "./apis/disperseGroup.js"; export type { EditNoteOptions, EditNoteResponse } from "./apis/editNote.js"; -export type { - EditReminderGroup, - EditReminderUser, - EditReminderOptions, - EditReminderResponse, -} from "./apis/editReminder.js"; +export type { EditReminderGroup, EditReminderUser, EditReminderOptions, EditReminderResponse } from "./apis/editReminder.js"; export type { EnableGroupLinkResponse } from "./apis/enableGroupLink.js"; export type { FetchAccountInfoResponse } from "./apis/fetchAccountInfo.js"; export type { FindUserResponse } from "./apis/findUser.js"; export type { FindUserByUsernameResponse } from "./apis/findUserByUsername.js"; -export type { - ForwardMessageSuccess, - ForwardMessageFail, - ForwardMessagePayload, - ForwardMessageResponse, -} from "./apis/forwardMessage.js"; +export type { ForwardMessageSuccess, ForwardMessageFail, ForwardMessagePayload, ForwardMessageResponse } from "./apis/forwardMessage.js"; export type { GetAliasListResponse } from "./apis/getAliasList.js"; export type { GetAllFriendsResponse } from "./apis/getAllFriends.js"; export type { GetAllGroupsResponse } from "./apis/getAllGroups.js"; @@ -81,12 +57,7 @@ export type { GetCatalogListPayload, GetCatalogListResponse } from "./apis/getCa export type { GetCloseFriendsResponse } from "./apis/getCloseFriends.js"; export type { GetFriendBoardListResponse } from "./apis/getFriendBoardList.js"; export type { GetFriendOnlinesResponse, GetFriendOnlinesStatus } from "./apis/getFriendOnlines.js"; -export type { - GetFriendRecommendationsResponse, - FriendRecommendationsCollapseMsgListConfig, - FriendRecommendationsDataInfo, - FriendRecommendationsRecommItem, -} from "./apis/getFriendRecommendations.js"; +export type { GetFriendRecommendationsResponse, FriendRecommendationsCollapseMsgListConfig, FriendRecommendationsDataInfo, FriendRecommendationsRecommItem } from "./apis/getFriendRecommendations.js"; export type { GetFriendRequestStatusResponse } from "./apis/getFriendRequestStatus.js"; export type { GetFullAvatarResponse } from "./apis/getFullAvatar.js"; export type { GetGroupBlockedMemberPayload, GetGroupBlockedMemberResponse } from "./apis/getGroupBlockedMember.js"; @@ -100,12 +71,7 @@ export type { GetGroupMembersInfoResponse, GroupMemberProfile } from "./apis/get export type { GetHiddenConversationsResponse } from "./apis/getHiddenConversations.js"; export type { GetLabelsResponse } from "./apis/getLabels.js"; export type { BoardItem, GetListBoardResponse, ListBoardOptions } from "./apis/getListBoard.js"; -export type { - GetListReminderResponse, - ListReminderOptions, - ReminderListGroup, - ReminderListUser, -} from "./apis/getListReminder.js"; +export type { GetListReminderResponse, ListReminderOptions, ReminderListGroup, ReminderListUser } from "./apis/getListReminder.js"; export type { GetMultiUsersByPhonesResponse } from "./apis/getMultiUsersByPhones.js"; export type { GetMuteResponse, MuteEntriesInfo } from "./apis/getMute.js"; export type { GetPendingGroupMembersResponse, GetPendingGroupMembersUserInfo } from "./apis/getPendingGroupMembers.js"; @@ -144,24 +110,14 @@ export type { RemoveUnreadMarkResponse } from "./apis/removeUnreadMark.js"; export type { RemoveUserFromGroupResponse } from "./apis/removeUserFromGroup.js"; export type { ResetHiddenConversPinResponse } from "./apis/resetHiddenConversPin.js"; export type { ReuseAvatarResponse } from "./apis/reuseAvatar.js"; -export type { - ReviewPendingMemberRequestPayload, - ReviewPendingMemberRequestResponse, -} from "./apis/reviewPendingMemberRequest.js"; +export type { ReviewPendingMemberRequestPayload, ReviewPendingMemberRequestResponse } from "./apis/reviewPendingMemberRequest.js"; export type { SearchStickerResponse } from "./apis/searchSticker.js"; export type { SendBankCardPayload, SendBankCardResponse } from "./apis/sendBankCard.js"; export type { SendCardOptions, SendCardResponse } from "./apis/sendCard.js"; export type { SendDeliveredEventMessageParams, SendDeliveredEventResponse } from "./apis/sendDeliveredEvent.js"; export type { SendFriendRequestResponse } from "./apis/sendFriendRequest.js"; export type { SendLinkOptions, SendLinkResponse } from "./apis/sendLink.js"; -export type { - Mention, - MessageContent, - SendMessageQuote, - SendMessageResponse, - SendMessageResult, - Style, -} from "./apis/sendMessage.js"; +export type { Mention, MessageContent, SendMessageQuote, SendMessageResponse, SendMessageResult, Style } from "./apis/sendMessage.js"; export type { SendReportOptions, SendReportResponse } from "./apis/sendReport.js"; export type { SendSeenEventMessageParams, SendSeenEventResponse } from "./apis/sendSeenEvent.js"; export type { SendStickerResponse, SendStickerPayload } from "./apis/sendSticker.js"; @@ -190,15 +146,7 @@ export type { UpdateProfileBioResponse } from "./apis/updateProfileBio.js"; export type { UpdateQuickMessagePayload, UpdateQuickMessageResponse } from "./apis/updateQuickMessage.js"; export type { UpdateSettingsResponse } from "./apis/updateSettings.js"; export type { UpgradeGroupToCommunityResponse } from "./apis/upgradeGroupToCommunity.js"; -export type { - FileData, - ImageData, - UploadAttachmentResponse, - UploadAttachmentType, - UploadAttachmentImageResponse, - UploadAttachmentVideoResponse, - UploadAttachmentFileResponse, -} from "./apis/uploadAttachment.js"; +export type { FileData, ImageData, UploadAttachmentResponse, UploadAttachmentType, UploadAttachmentImageResponse, UploadAttachmentVideoResponse, UploadAttachmentFileResponse } from "./apis/uploadAttachment.js"; export type { UploadProductPhotoPayload, UploadProductPhotoResponse } from "./apis/uploadProductPhoto.js"; export type { VotePollResponse } from "./apis/votePoll.js"; From ae85f18d676f7af51127629c1f82c825c7358c3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ho=C3=A0ng=20H=C3=A0o?= Date: Wed, 15 Apr 2026 16:29:57 +0700 Subject: [PATCH 03/17] refactor: improve type imports and update sendBankCardFactory - Streamlined type imports in `sendBankCard.ts` for better organization. - Updated `sendBankCardFactory` to use a more concise parameter naming convention. --- src/apis/sendBankCard.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/apis/sendBankCard.ts b/src/apis/sendBankCard.ts index 810c4222..caa3d64e 100644 --- a/src/apis/sendBankCard.ts +++ b/src/apis/sendBankCard.ts @@ -1,6 +1,5 @@ import { ZaloApiError } from "../Errors/ZaloApiError.js"; -import type { BinBankCard } from "../models/index.js"; -import { ThreadType } from "../models/index.js"; +import { ThreadType, type BinBankCard } from "../models/index.js"; import { apiFactory } from "../utils.js"; export type SendBankCardPayload = { @@ -11,7 +10,7 @@ export type SendBankCardPayload = { export type SendBankCardResponse = ""; -export const sendBankCardFactory = apiFactory()((api, ctx, utils) => { +export const sendBankCardFactory = apiFactory()((api, _ctx, utils) => { const serviceURL = utils.makeURL(`${api.zpwServiceMap.zimsg[0]}/api/transfer/card`); /** From f0995ba1d984e7a93e5a7656e44b95d3cbc44410 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ho=C3=A0ng=20H=C3=A0o?= Date: Wed, 15 Apr 2026 16:50:18 +0700 Subject: [PATCH 04/17] feat: add createBankAccount API and related types - Introduced `createBankAccount` API in `createBankAccount.ts` to facilitate bank account creation. - Added corresponding types `CreateBankAccountPayload` and `CreateBankAccountResponse`. - Updated `apis.ts` and `index.ts` to include the new API method and types. - Implemented a utility function `normalizeHolderName` in `utils.ts` for holder name normalization. - Enhanced `BankAccount` model to accommodate optional fields for better flexibility. --- src/apis.ts | 3 + src/apis/createBankAccount.ts | 40 ++++++ src/index.ts | 1 + src/models/Bank.ts | 242 +++++++++++++++++++++++++++++++++- src/models/Enum.ts | 235 --------------------------------- src/utils.ts | 13 ++ 6 files changed, 297 insertions(+), 237 deletions(-) create mode 100644 src/apis/createBankAccount.ts diff --git a/src/apis.ts b/src/apis.ts index b27f6c65..98972a57 100644 --- a/src/apis.ts +++ b/src/apis.ts @@ -16,6 +16,7 @@ import { changeGroupAvatarFactory } from "./apis/changeGroupAvatar.js"; import { changeGroupNameFactory } from "./apis/changeGroupName.js"; import { changeGroupOwnerFactory } from "./apis/changeGroupOwner.js"; import { createAutoReplyFactory } from "./apis/createAutoReply.js"; +import { createBankAccountFactory } from "./apis/createBankAccount.js"; import { createCatalogFactory } from "./apis/createCatalog.js"; import { createGroupFactory } from "./apis/createGroup.js"; import { createNoteFactory } from "./apis/createNote.js"; @@ -170,6 +171,7 @@ export class API { public changeGroupName: ReturnType; public changeGroupOwner: ReturnType; public createAutoReply: ReturnType; + public createBankAccount: ReturnType; public createCatalog: ReturnType; public createGroup: ReturnType; public createNote: ReturnType; @@ -324,6 +326,7 @@ export class API { this.changeGroupName = changeGroupNameFactory(ctx, this); this.changeGroupOwner = changeGroupOwnerFactory(ctx, this); this.createAutoReply = createAutoReplyFactory(ctx, this); + this.createBankAccount = createBankAccountFactory(ctx, this); this.createCatalog = createCatalogFactory(ctx, this); this.createGroup = createGroupFactory(ctx, this); this.createNote = createNoteFactory(ctx, this); diff --git a/src/apis/createBankAccount.ts b/src/apis/createBankAccount.ts new file mode 100644 index 00000000..8a4b51f9 --- /dev/null +++ b/src/apis/createBankAccount.ts @@ -0,0 +1,40 @@ +import { ZaloApiError } from "../Errors/ZaloApiError.js"; +import type { BankAccount, BinBankCard } from "../models/index.js"; +import { apiFactory, normalizeHolderName } from "../utils.js"; + +export type CreateBankAccountPayload = { + binBank: BinBankCard; + numAccBank: string; + nameAccBank: string; +}; + +export type CreateBankAccountResponse = BankAccount; + +export const createBankAccountFactory = apiFactory()((api, ctx, utils) => { + const serviceURL = utils.makeURL(`${api.zpwServiceMap.zimsg[0]}/api/transfer/create`); + + /** + * Create bank account + * + * @param payload The payload containing the bank account information + * + * @throws {ZaloApiError} + */ + return async function createBankAccount(payload: CreateBankAccountPayload) { + const params = { + bin: payload.binBank, + bank_number: payload.numAccBank, + holder_name: normalizeHolderName(payload.nameAccBank), + language: ctx.language, + }; + + const encryptedParams = utils.encodeAES(JSON.stringify(params)); + if (!encryptedParams) throw new ZaloApiError("Failed to encrypt params"); + + const response = await utils.request(utils.makeURL(serviceURL, { params: encryptedParams }), { + method: "GET", + }); + + return utils.resolve(response); + }; +}); diff --git a/src/index.ts b/src/index.ts index c0b07f9b..339977b3 100644 --- a/src/index.ts +++ b/src/index.ts @@ -21,6 +21,7 @@ export type { ChangeGroupAvatarResponse } from "./apis/changeGroupAvatar.js"; export type { ChangeGroupNameResponse } from "./apis/changeGroupName.js"; export type { ChangeGroupOwnerResponse } from "./apis/changeGroupOwner.js"; export type { CreateAutoReplyPayload, CreateAutoReplyResponse } from "./apis/createAutoReply.js"; +export type { CreateBankAccountPayload, CreateBankAccountResponse } from "./apis/createBankAccount.js"; export type { CreateCatalogResponse } from "./apis/createCatalog.js"; export type { CreateGroupOptions, CreateGroupResponse } from "./apis/createGroup.js"; export type { CreateNoteOptions, CreateNoteResponse } from "./apis/createNote.js"; diff --git a/src/models/Bank.ts b/src/models/Bank.ts index 99a29c77..4e8c60e5 100644 --- a/src/models/Bank.ts +++ b/src/models/Bank.ts @@ -8,15 +8,253 @@ export type BankInfo = { }; export type BankAccount = { + /** + * The fields marked with `?` may or may not be present for the getBankAccounts and createBankAccount APIs. + */ id: string; bin: number; default: boolean; bank_number: string; - bank_logo: string; + bank_logo?: string; holder_name: string; created_at: number; updated_at: number; account_id: number; - bank_name: string; + bank_name?: string; is_default: boolean; }; + +/** + * @note Bank codes list after Mitm on Mobile and Bank's supported by Zalo + * @documents https://developers.zalo.me/docs/zalo-notification-service/phu-luc/danh-sach-bin-code - docs missing bin code and short_name bank + */ +export enum BinBankCard { + /** + * NH TMCP An Bình + */ + ABBank = 970425, + /** + * NH TMCP Á Châu + */ + ACB = 970416, + /** + * NH Nông nghiệp và Phát triển Nông thôn Việt Nam + */ + Agribank = 970405, + /** + * NH TMCP Đầu tư và Phát triển Việt Nam + */ + BIDV = 970418, + /** + * NH TMCP Bản Việt + */ + BVBank = 970454, + /** + * NH TMCP Bắc Á + */ + BacA_Bank = 970409, + /** + * NH TMCP Bảo Việt + */ + BaoViet_Bank = 970438, + /** + * NH số CAKE by VPBank - TMCP Việt Nam Thịnh Vượng + */ + CAKE = 546034, + /** + * NH Thương mại TNHH MTV Xây dựng Việt Nam + */ + CB_Bank = 970444, + /** + * NH TNHH MTV CIMB Việt Nam + */ + CIMB_Bank = 422589, + /** + * NH Hợp tác xã Việt Nam + */ + Coop_Bank = 970446, + /** + * NH TNHH MTV Phát triển Singapore - CN TP. Hồ Chí Minh + */ + DBS_Bank = 796500, + /** + * NH TMCP Đông Á + */ + DongA_Bank = 970406, + /** + * NH TMCP Xuất Nhập khẩu Việt Nam + */ + Eximbank = 970431, + /** + * NH TMCP Dầu khí Toàn cầu + */ + GPBank = 970408, + /** + * NH TMCP Phát triển TP. Hồ Chí Minh + */ + HDBank = 970437, + /** + * NH TNHH MTV HSBC (Việt Nam) + */ + HSBC = 458761, + /** + * NH TNHH MTV Hong Leong Việt Nam + */ + HongLeong_Bank = 970442, + /** + * NH Công nghiệp Hàn Quốc - CN TP. Hồ Chí Minh + */ + IBK_HCM = 970456, + /** + * NH Công nghiệp Hàn Quốc - CN Hà Nội + */ + IBK_HN = 970455, + /** + * NH TNHH Indovina + */ + Indovina_Bank = 970434, + /** + * NH Đại chúng TNHH Kasikornbank - CN TP. Hồ Chí Minh + */ + KBank = 668888, + /** + * NH TMCP Kiên Long + */ + KienlongBank = 970452, + /** + * NH Kookmin - CN TP. Hồ Chí Minh + */ + Kookmin_Bank_HCM = 970463, + /** + * NH Kookmin - CN Hà Nội + */ + Kookmin_Bank_HN = 970462, + /** + * NH TMCP Lộc Phát Việt Nam + */ + LPBank = 970449, + /** + * NH TMCP Quân đội + */ + MB_Bank = 970422, + /** + * NH TMCP Hàng Hải + */ + MSB = 970426, + /** + * NH TMCP Quốc Dân + */ + NCB = 970419, + /** + * NH TMCP Nam Á + */ + Nam_A_Bank = 970428, + /** + * NH Nonghyup - CN Hà Nội + */ + NongHyup_Bank = 801011, + /** + * NH TMCP Phương Đông + */ + OCB = 970448, + /** + * NH Thương mại TNHH MTV Đại Dương + */ + Ocean_Bank = 970414, + /** + * NH TMCP Thịnh vượng và Phát triển + */ + PGBank = 970430, + /** + * NH TMCP Đại Chúng Việt Nam + */ + PVcomBank = 970412, + /** + * NH TNHH MTV Public Việt Nam + */ + Public_Bank_Vietnam = 970439, + /** + * NH TMCP Sài Gòn + */ + SCB = 970429, + /** + * NH TMCP Sài Gòn - Hà Nội + */ + SHB = 970443, + /** + * NH TMCP Sài Gòn Thương Tín + */ + Sacombank = 970403, + /** + * NH TMCP Sài Gòn Công Thương + */ + Saigon_Bank = 970400, + /** + * NH TMCP Đông Nam Á + */ + SeABank = 970440, + /** + * NH TNHH MTV Shinhan Việt Nam + */ + Shinhan_Bank = 970424, + /** + * NH TNHH MTV Standard Chartered Bank Việt Nam + */ + Standard_Chartered_Vietnam = 970410, + /** + * NH số TNEX + */ + TNEX = 9704261, + /** + * NH TMCP Tiên Phong + */ + TPBank = 970423, + /** + * NH TMCP Kỹ thương Việt Nam + */ + Techcombank = 970407, + /** + * NH số Timo by Bản Việt Bank + */ + Timo = 963388, + /** + * NH số UBank by VPBank + */ + UBank = 546035, + /** + * NH United Overseas Bank Việt Nam + */ + United_Overseas_Bank_Vietnam = 970458, + /** + * NH TMCP Quốc tế Việt Nam + */ + VIB = 970441, + /** + * NH TMCP Việt Nam Thịnh Vượng + */ + VPBank = 970432, + /** + * NH Liên doanh Việt - Nga + */ + VRB = 970421, + /** + * NH TMCP Việt Á + */ + VietABank = 970427, + /** + * NH TMCP Việt Nam Thương Tín + */ + VietBank = 970433, + /** + * NH TMCP Ngoại Thương Việt Nam + */ + Vietcombank = 970436, + /** + * NH TMCP Công thương Việt Nam + */ + VietinBank = 970415, + /** + * NH TNHH MTV Woori Việt Nam + */ + Woori_Bank = 970457, +}; diff --git a/src/models/Enum.ts b/src/models/Enum.ts index 2f6cdbff..3eb9010a 100644 --- a/src/models/Enum.ts +++ b/src/models/Enum.ts @@ -18,238 +18,3 @@ export enum AvatarSize { Small = 120, Large = 240, } - -/** - * @note Bank codes list after Mitm on Mobile and Bank's supported by Zalo - * @documents https://developers.zalo.me/docs/zalo-notification-service/phu-luc/danh-sach-bin-code - docs missing bin code and short_name bank - */ -export enum BinBankCard { - /** - * NH TMCP An Bình - */ - ABBank = 970425, - /** - * NH TMCP Á Châu - */ - ACB = 970416, - /** - * NH Nông nghiệp và Phát triển Nông thôn Việt Nam - */ - Agribank = 970405, - /** - * NH TMCP Đầu tư và Phát triển Việt Nam - */ - BIDV = 970418, - /** - * NH TMCP Bản Việt - */ - BVBank = 970454, - /** - * NH TMCP Bắc Á - */ - BacA_Bank = 970409, - /** - * NH TMCP Bảo Việt - */ - BaoViet_Bank = 970438, - /** - * NH số CAKE by VPBank - TMCP Việt Nam Thịnh Vượng - */ - CAKE = 546034, - /** - * NH Thương mại TNHH MTV Xây dựng Việt Nam - */ - CB_Bank = 970444, - /** - * NH TNHH MTV CIMB Việt Nam - */ - CIMB_Bank = 422589, - /** - * NH Hợp tác xã Việt Nam - */ - Coop_Bank = 970446, - /** - * NH TNHH MTV Phát triển Singapore - CN TP. Hồ Chí Minh - */ - DBS_Bank = 796500, - /** - * NH TMCP Đông Á - */ - DongA_Bank = 970406, - /** - * NH TMCP Xuất Nhập khẩu Việt Nam - */ - Eximbank = 970431, - /** - * NH TMCP Dầu khí Toàn cầu - */ - GPBank = 970408, - /** - * NH TMCP Phát triển TP. Hồ Chí Minh - */ - HDBank = 970437, - /** - * NH TNHH MTV HSBC (Việt Nam) - */ - HSBC = 458761, - /** - * NH TNHH MTV Hong Leong Việt Nam - */ - HongLeong_Bank = 970442, - /** - * NH Công nghiệp Hàn Quốc - CN TP. Hồ Chí Minh - */ - IBK_HCM = 970456, - /** - * NH Công nghiệp Hàn Quốc - CN Hà Nội - */ - IBK_HN = 970455, - /** - * NH TNHH Indovina - */ - Indovina_Bank = 970434, - /** - * NH Đại chúng TNHH Kasikornbank - CN TP. Hồ Chí Minh - */ - KBank = 668888, - /** - * NH TMCP Kiên Long - */ - KienlongBank = 970452, - /** - * NH Kookmin - CN TP. Hồ Chí Minh - */ - Kookmin_Bank_HCM = 970463, - /** - * NH Kookmin - CN Hà Nội - */ - Kookmin_Bank_HN = 970462, - /** - * NH TMCP Lộc Phát Việt Nam - */ - LPBank = 970449, - /** - * NH TMCP Quân đội - */ - MB_Bank = 970422, - /** - * NH TMCP Hàng Hải - */ - MSB = 970426, - /** - * NH TMCP Quốc Dân - */ - NCB = 970419, - /** - * NH TMCP Nam Á - */ - Nam_A_Bank = 970428, - /** - * NH Nonghyup - CN Hà Nội - */ - NongHyup_Bank = 801011, - /** - * NH TMCP Phương Đông - */ - OCB = 970448, - /** - * NH Thương mại TNHH MTV Đại Dương - */ - Ocean_Bank = 970414, - /** - * NH TMCP Thịnh vượng và Phát triển - */ - PGBank = 970430, - /** - * NH TMCP Đại Chúng Việt Nam - */ - PVcomBank = 970412, - /** - * NH TNHH MTV Public Việt Nam - */ - Public_Bank_Vietnam = 970439, - /** - * NH TMCP Sài Gòn - */ - SCB = 970429, - /** - * NH TMCP Sài Gòn - Hà Nội - */ - SHB = 970443, - /** - * NH TMCP Sài Gòn Thương Tín - */ - Sacombank = 970403, - /** - * NH TMCP Sài Gòn Công Thương - */ - Saigon_Bank = 970400, - /** - * NH TMCP Đông Nam Á - */ - SeABank = 970440, - /** - * NH TNHH MTV Shinhan Việt Nam - */ - Shinhan_Bank = 970424, - /** - * NH TNHH MTV Standard Chartered Bank Việt Nam - */ - Standard_Chartered_Vietnam = 970410, - /** - * NH số TNEX - */ - TNEX = 9704261, - /** - * NH TMCP Tiên Phong - */ - TPBank = 970423, - /** - * NH TMCP Kỹ thương Việt Nam - */ - Techcombank = 970407, - /** - * NH số Timo by Bản Việt Bank - */ - Timo = 963388, - /** - * NH số UBank by VPBank - */ - UBank = 546035, - /** - * NH United Overseas Bank Việt Nam - */ - United_Overseas_Bank_Vietnam = 970458, - /** - * NH TMCP Quốc tế Việt Nam - */ - VIB = 970441, - /** - * NH TMCP Việt Nam Thịnh Vượng - */ - VPBank = 970432, - /** - * NH Liên doanh Việt - Nga - */ - VRB = 970421, - /** - * NH TMCP Việt Á - */ - VietABank = 970427, - /** - * NH TMCP Việt Nam Thương Tín - */ - VietBank = 970433, - /** - * NH TMCP Ngoại Thương Việt Nam - */ - Vietcombank = 970436, - /** - * NH TMCP Công thương Việt Nam - */ - VietinBank = 970415, - /** - * NH TNHH MTV Woori Việt Nam - */ - Woori_Bank = 970457, -} diff --git a/src/utils.ts b/src/utils.ts index 6fcbeb7c..e463ccdd 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -789,3 +789,16 @@ export function negativeColorToHex(negativeColor: number): string { // return "#" + positiveColor.toString(16).padStart(6, "0"); // rgb no alpha return "#" + positiveColor.toString(16).slice(-6).padStart(6, "0"); // rgb with alpha } + +export function normalizeHolderName(input?: string) { + if (!input) return undefined; + return input + .normalize("NFD") + .replace(/[\u0300-\u036f]/g, "") + .replace(/đ/g, "d") + .replace(/Đ/g, "D") + .toUpperCase() + .replace(/[^A-Z0-9 ]+/g, " ") + .replace(/\s+/g, " ") + .trim(); +} From 47e529cfc235ff18e9689ea068752bb4d16436c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ho=C3=A0ng=20H=C3=A0o?= Date: Wed, 15 Apr 2026 21:14:53 +0700 Subject: [PATCH 05/17] feat: update Bank model with new bank codes and improve documentation - Enhanced the `BinBankCard` enum in `Bank.ts` by adding new bank codes for BNP Paribas, Cathay United, Citibank, Liobank, and MoMo. - Updated existing bank code for TNEX and improved documentation comments for clarity and completeness. --- src/models/Bank.ts | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/src/models/Bank.ts b/src/models/Bank.ts index 4e8c60e5..9ec7481a 100644 --- a/src/models/Bank.ts +++ b/src/models/Bank.ts @@ -25,7 +25,7 @@ export type BankAccount = { }; /** - * @note Bank codes list after Mitm on Mobile and Bank's supported by Zalo + * @note Bank codes list after Mitm on Mobile, WEB and Bank's supported by Zalo * @documents https://developers.zalo.me/docs/zalo-notification-service/phu-luc/danh-sach-bin-code - docs missing bin code and short_name bank */ export enum BinBankCard { @@ -45,6 +45,14 @@ export enum BinBankCard { * NH TMCP Đầu tư và Phát triển Việt Nam */ BIDV = 970418, + /** + * Ngân hàng BNP Paribas - CN TP. Hồ Chí Minh + */ + BNP_Paribas_HCM = 963666, + /** + * Ngân hàng BNP Paribas - CN Hà Nội + */ + BNP_Paribas_HN = 963668, /** * NH TMCP Bản Việt */ @@ -61,10 +69,16 @@ export enum BinBankCard { * NH số CAKE by VPBank - TMCP Việt Nam Thịnh Vượng */ CAKE = 546034, + /** + * Ngân hàng Cathay United - CN TP. Hồ Chí Minh + */ + Cathay_United_HCM = 168999, /** * NH Thương mại TNHH MTV Xây dựng Việt Nam + * + * @note Also observed as "VCBNeo" in supported banks list (same bin) - Old is bank: CB_Bank */ - CB_Bank = 970444, + VCBNeo = 970444, /** * NH TNHH MTV CIMB Việt Nam */ @@ -85,6 +99,10 @@ export enum BinBankCard { * NH TMCP Xuất Nhập khẩu Việt Nam */ Eximbank = 970431, + /** + * Ngân hàng Citibank Việt Nam + */ + Citibank = 533948, /** * NH TMCP Dầu khí Toàn cầu */ @@ -129,6 +147,10 @@ export enum BinBankCard { * NH Kookmin - CN Hà Nội */ Kookmin_Bank_HN = 970462, + /** + * Liobank by OCB + */ + Liobank = 963369, /** * NH TMCP Lộc Phát Việt Nam */ @@ -141,6 +163,10 @@ export enum BinBankCard { * NH TMCP Hàng Hải */ MSB = 970426, + /** + * MoMo + */ + MoMo = 971025, /** * NH TMCP Quốc Dân */ @@ -204,7 +230,7 @@ export enum BinBankCard { /** * NH số TNEX */ - TNEX = 9704261, + TNEX = 963326, /** * NH TMCP Tiên Phong */ From 5ec26a9177118536fae063952b7f4756b871fd85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ho=C3=A0ng=20H=C3=A0o?= Date: Wed, 15 Apr 2026 23:00:43 +0700 Subject: [PATCH 06/17] fix: enhance normalizeHolderName function for improved validation - Updated the `normalizeHolderName` function in `utils.ts` to return undefined for names shorter than 5 characters, ensuring better validation of holder names. --- src/utils.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/utils.ts b/src/utils.ts index e463ccdd..8aea7dae 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -792,7 +792,7 @@ export function negativeColorToHex(negativeColor: number): string { export function normalizeHolderName(input?: string) { if (!input) return undefined; - return input + const normalized = input .normalize("NFD") .replace(/[\u0300-\u036f]/g, "") .replace(/đ/g, "d") @@ -801,4 +801,6 @@ export function normalizeHolderName(input?: string) { .replace(/[^A-Z0-9 ]+/g, " ") .replace(/\s+/g, " ") .trim(); + + return normalized.length >= 5 ? normalized : undefined; } From c9445e6f1b44b8acc1b6effd3ee7723ba35960d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ho=C3=A0ng=20H=C3=A0o?= Date: Thu, 16 Apr 2026 14:16:58 +0700 Subject: [PATCH 07/17] feat: add new bank-related APIs and update type exports - Introduced `getListBank` and `getListBankCard` APIs to retrieve bank and bank card information. - Updated `apis.ts` and `index.ts` to include new API methods and corresponding types. - Removed deprecated `getBankAccounts` and `getSupportedBanks` references for cleaner code. --- src/apis.ts | 12 ++++++------ src/apis/{getSupportedBanks.ts => getListBank.ts} | 8 ++++---- src/apis/{getBankAccounts.ts => getListBankCard.ts} | 8 ++++---- src/index.ts | 4 ++-- 4 files changed, 16 insertions(+), 16 deletions(-) rename src/apis/{getSupportedBanks.ts => getListBank.ts} (76%) rename src/apis/{getBankAccounts.ts => getListBankCard.ts} (83%) diff --git a/src/apis.ts b/src/apis.ts index 98972a57..51113620 100644 --- a/src/apis.ts +++ b/src/apis.ts @@ -47,7 +47,6 @@ import { getAutoDeleteChatFactory } from "./apis/getAutoDeleteChat.js"; import { getAutoReplyListFactory } from "./apis/getAutoReplyList.js"; import { getAvatarListFactory } from "./apis/getAvatarList.js"; import { getAvatarUrlProfileFactory } from "./apis/getAvatarUrlProfile.js"; -import { getBankAccountsFactory } from "./apis/getBankAccounts.js"; import { getBizAccountFactory } from "./apis/getBizAccount.js"; import { getCatalogListFactory } from "./apis/getCatalogList.js"; import { getCloseFriendsFactory } from "./apis/getCloseFriends.js"; @@ -68,6 +67,8 @@ import { getGroupLinkInfoFactory } from "./apis/getGroupLinkInfo.js"; import { getGroupMembersInfoFactory } from "./apis/getGroupMembersInfo.js"; import { getHiddenConversationsFactory } from "./apis/getHiddenConversations.js"; import { getLabelsFactory } from "./apis/getLabels.js"; +import { getListBankFactory } from "./apis/getListBank.js"; +import { getListBankCardFactory } from "./apis/getListBankCard.js"; import { getListBoardFactory } from "./apis/getListBoard.js"; import { getListReminderFactory } from "./apis/getListReminder.js"; import { getMultiUsersByPhonesFactory } from "./apis/getMultiUsersByPhones.js"; @@ -87,7 +88,6 @@ import { getSettingsFactory } from "./apis/getSettings.js"; import { getStickerCategoryDetailFactory } from "./apis/getStickerCategoryDetail.js"; import { getStickersFactory } from "./apis/getStickers.js"; import { getStickersDetailFactory } from "./apis/getStickersDetail.js"; -import { getSupportedBanksFactory } from "./apis/getSupportedBanks.js"; import { getUnreadMarkFactory } from "./apis/getUnreadMark.js"; import { getUserInfoFactory } from "./apis/getUserInfo.js"; import { inviteUserToGroupsFactory } from "./apis/inviteUserToGroups.js"; @@ -202,7 +202,6 @@ export class API { public getAutoReplyList: ReturnType; public getAvatarList: ReturnType; public getAvatarUrlProfile: ReturnType; - public getBankAccounts: ReturnType; public getBizAccount: ReturnType; public getCatalogList: ReturnType; public getCloseFriends: ReturnType; @@ -223,6 +222,8 @@ export class API { public getGroupMembersInfo: ReturnType; public getHiddenConversations: ReturnType; public getLabels: ReturnType; + public getListBank: ReturnType; + public getListBankCard: ReturnType; public getListBoard: ReturnType; public getListReminder: ReturnType; public getMultiUsersByPhones: ReturnType; @@ -242,7 +243,6 @@ export class API { public getStickerCategoryDetail: ReturnType; public getStickers: ReturnType; public getStickersDetail: ReturnType; - public getSupportedBanks: ReturnType; public getUnreadMark: ReturnType; public getUserInfo: ReturnType; public inviteUserToGroups: ReturnType; @@ -357,7 +357,6 @@ export class API { this.getAutoReplyList = getAutoReplyListFactory(ctx, this); this.getAvatarList = getAvatarListFactory(ctx, this); this.getAvatarUrlProfile = getAvatarUrlProfileFactory(ctx, this); - this.getBankAccounts = getBankAccountsFactory(ctx, this); this.getBizAccount = getBizAccountFactory(ctx, this); this.getCatalogList = getCatalogListFactory(ctx, this); this.getCloseFriends = getCloseFriendsFactory(ctx, this); @@ -378,6 +377,8 @@ export class API { this.getGroupMembersInfo = getGroupMembersInfoFactory(ctx, this); this.getHiddenConversations = getHiddenConversationsFactory(ctx, this); this.getLabels = getLabelsFactory(ctx, this); + this.getListBank = getListBankFactory(ctx, this); + this.getListBankCard = getListBankCardFactory(ctx, this); this.getListBoard = getListBoardFactory(ctx, this); this.getListReminder = getListReminderFactory(ctx, this); this.getMultiUsersByPhones = getMultiUsersByPhonesFactory(ctx, this); @@ -397,7 +398,6 @@ export class API { this.getStickerCategoryDetail = getStickerCategoryDetailFactory(ctx, this); this.getStickers = getStickersFactory(ctx, this); this.getStickersDetail = getStickersDetailFactory(ctx, this); - this.getSupportedBanks = getSupportedBanksFactory(ctx, this); this.getUnreadMark = getUnreadMarkFactory(ctx, this); this.getUserInfo = getUserInfoFactory(ctx, this); this.inviteUserToGroups = inviteUserToGroupsFactory(ctx, this); diff --git a/src/apis/getSupportedBanks.ts b/src/apis/getListBank.ts similarity index 76% rename from src/apis/getSupportedBanks.ts rename to src/apis/getListBank.ts index 279ae02a..e1b11f4d 100644 --- a/src/apis/getSupportedBanks.ts +++ b/src/apis/getListBank.ts @@ -2,19 +2,19 @@ import { ZaloApiError } from "../Errors/ZaloApiError.js"; import type { BankInfo } from "../models/index.js"; import { apiFactory } from "../utils.js"; -export type GetSupportedBanksResponse = { +export type GetListBankResponse = { banks: BankInfo[]; }; -export const getSupportedBanksFactory = apiFactory()((api, _ctx, utils) => { +export const getListBankFactory = apiFactory()((api, _ctx, utils) => { const serviceURL = utils.makeURL(`${api.zpwServiceMap.zimsg[0]}/api/transfer/conf`); /** - * Get supported banks + * Get list bank * * @throws {ZaloApiError} */ - return async function getSupportedBanks() { + return async function getListBank() { const params = {}; const encryptedParams = utils.encodeAES(JSON.stringify(params)); diff --git a/src/apis/getBankAccounts.ts b/src/apis/getListBankCard.ts similarity index 83% rename from src/apis/getBankAccounts.ts rename to src/apis/getListBankCard.ts index 027c3995..1c0f3a35 100644 --- a/src/apis/getBankAccounts.ts +++ b/src/apis/getListBankCard.ts @@ -2,24 +2,24 @@ import { ZaloApiError } from "../Errors/ZaloApiError.js"; import type { BankAccount } from "../models/index.js"; import { apiFactory } from "../utils.js"; -export type GetBankAccountsResponse = { +export type GetListBankCardResponse = { hasMore: boolean; total: number; myBanks: BankAccount[]; }; -export const getBankAccountsFactory = apiFactory()((api, _ctx, utils) => { +export const getListBankCardFactory = apiFactory()((api, _ctx, utils) => { const serviceURL = utils.makeURL(`${api.zpwServiceMap.zimsg[0]}/api/transfer/list`); /** - * Get bank accounts + * Get list bank card * * @param page Page number (default: 0) * @param limit Number of items to retrieve (default: 20) * * @throws {ZaloApiError} */ - return async function getBankAccounts(page: number = 0, limit: number = 20) { + return async function getListBankCard(page: number = 0, limit: number = 20) { const params = { page: page, limit: limit, diff --git a/src/index.ts b/src/index.ts index 339977b3..e9f36e3e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -52,7 +52,6 @@ export type { GetAutoDeleteChatResponse } from "./apis/getAutoDeleteChat.js"; export type { GetAutoReplyListResponse } from "./apis/getAutoReplyList.js"; export type { GetAvatarListResponse } from "./apis/getAvatarList.js"; export type { GetAvatarUrlProfileResponse } from "./apis/getAvatarUrlProfile.js"; -export type { GetBankAccountsResponse } from "./apis/getBankAccounts.js"; export type { GetBizAccountResponse } from "./apis/getBizAccount.js"; export type { GetCatalogListPayload, GetCatalogListResponse } from "./apis/getCatalogList.js"; export type { GetCloseFriendsResponse } from "./apis/getCloseFriends.js"; @@ -71,6 +70,8 @@ export type { GetGroupLinkInfoPayload, GetGroupLinkInfoResponse } from "./apis/g export type { GetGroupMembersInfoResponse, GroupMemberProfile } from "./apis/getGroupMembersInfo.js"; export type { GetHiddenConversationsResponse } from "./apis/getHiddenConversations.js"; export type { GetLabelsResponse } from "./apis/getLabels.js"; +export type { GetListBankResponse } from "./apis/getListBank.js"; +export type { GetListBankCardResponse } from "./apis/getListBankCard.js"; export type { BoardItem, GetListBoardResponse, ListBoardOptions } from "./apis/getListBoard.js"; export type { GetListReminderResponse, ListReminderOptions, ReminderListGroup, ReminderListUser } from "./apis/getListReminder.js"; export type { GetMultiUsersByPhonesResponse } from "./apis/getMultiUsersByPhones.js"; @@ -88,7 +89,6 @@ export type { GetSentFriendRequestResponse, SentFriendRequestInfo } from "./apis export type { GetSettingsResponse } from "./apis/getSettings.js"; export type { GetStickerCategoryDetailResponse } from "./apis/getStickerCategoryDetail.js"; export type { StickerDetailResponse } from "./apis/getStickersDetail.js"; -export type { GetSupportedBanksResponse } from "./apis/getSupportedBanks.js"; export type { GetUnreadMarkResponse, UnreadMark } from "./apis/getUnreadMark.js"; export type { ProfileInfo, UserInfoResponse } from "./apis/getUserInfo.js"; export type { InviteUserToGroupsResponse } from "./apis/inviteUserToGroups.js"; From fd7a82ae5ef325edb340b954466b00fa6a9236bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ho=C3=A0ng=20H=C3=A0o?= Date: Thu, 16 Apr 2026 14:44:57 +0700 Subject: [PATCH 08/17] feat: add delete and update bank account APIs with corresponding types - Introduced `deleteBankAccount` and `updateBankAccount` APIs in their respective files to manage bank account deletion and updates. - Updated `apis.ts` and `index.ts` to include new API methods and their types. - Enhanced the `createBankAccount` API to use POST method for requests. --- src/apis.ts | 6 +++++ src/apis/createBankAccount.ts | 7 +++-- src/apis/deleteBankAccount.ts | 49 +++++++++++++++++++++++++++++++++++ src/apis/updateBankAccount.ts | 45 ++++++++++++++++++++++++++++++++ src/index.ts | 2 ++ 5 files changed, 107 insertions(+), 2 deletions(-) create mode 100644 src/apis/deleteBankAccount.ts create mode 100644 src/apis/updateBankAccount.ts diff --git a/src/apis.ts b/src/apis.ts index 51113620..bf90a06b 100644 --- a/src/apis.ts +++ b/src/apis.ts @@ -25,6 +25,7 @@ import { createProductCatalogFactory } from "./apis/createProductCatalog.js"; import { createReminderFactory } from "./apis/createReminder.js"; import { deleteAutoReplyFactory } from "./apis/deleteAutoReply.js"; import { deleteAvatarFactory } from "./apis/deleteAvatar.js"; +import { deleteBankAccountFactory } from "./apis/deleteBankAccount.js"; import { deleteCatalogFactory } from "./apis/deleteCatalog.js"; import { deleteChatFactory } from "./apis/deleteChat.js"; import { deleteGroupInviteBoxFactory } from "./apis/deleteGroupInviteBox.js"; @@ -134,6 +135,7 @@ import { updateActiveStatusFactory } from "./apis/updateActiveStatus.js"; import { updateArchivedChatListFactory } from "./apis/updateArchivedChatList.js"; import { updateAutoDeleteChatFactory } from "./apis/updateAutoDeleteChat.js"; import { updateAutoReplyFactory } from "./apis/updateAutoReply.js"; +import { updateBankAccountFactory } from "./apis/updateBankAccount.js"; import { updateCatalogFactory } from "./apis/updateCatalog.js"; import { updateGroupSettingsFactory } from "./apis/updateGroupSettings.js"; import { updateHiddenConversPinFactory } from "./apis/updateHiddenConversPin.js"; @@ -180,6 +182,7 @@ export class API { public createReminder: ReturnType; public deleteAutoReply: ReturnType; public deleteAvatar: ReturnType; + public deleteBankAccount: ReturnType; public deleteCatalog: ReturnType; public deleteChat: ReturnType; public deleteGroupInviteBox: ReturnType; @@ -289,6 +292,7 @@ export class API { public updateArchivedChatList: ReturnType; public updateAutoDeleteChat: ReturnType; public updateAutoReply: ReturnType; + public updateBankAccount: ReturnType; public updateCatalog: ReturnType; public updateGroupSettings: ReturnType; public updateHiddenConversPin: ReturnType; @@ -335,6 +339,7 @@ export class API { this.createReminder = createReminderFactory(ctx, this); this.deleteAutoReply = deleteAutoReplyFactory(ctx, this); this.deleteAvatar = deleteAvatarFactory(ctx, this); + this.deleteBankAccount = deleteBankAccountFactory(ctx, this); this.deleteCatalog = deleteCatalogFactory(ctx, this); this.deleteChat = deleteChatFactory(ctx, this); this.deleteGroupInviteBox = deleteGroupInviteBoxFactory(ctx, this); @@ -444,6 +449,7 @@ export class API { this.updateArchivedChatList = updateArchivedChatListFactory(ctx, this); this.updateAutoDeleteChat = updateAutoDeleteChatFactory(ctx, this); this.updateAutoReply = updateAutoReplyFactory(ctx, this); + this.updateBankAccount = updateBankAccountFactory(ctx, this); this.updateCatalog = updateCatalogFactory(ctx, this); this.updateGroupSettings = updateGroupSettingsFactory(ctx, this); this.updateHiddenConversPin = updateHiddenConversPinFactory(ctx, this); diff --git a/src/apis/createBankAccount.ts b/src/apis/createBankAccount.ts index 8a4b51f9..21dc3525 100644 --- a/src/apis/createBankAccount.ts +++ b/src/apis/createBankAccount.ts @@ -31,8 +31,11 @@ export const createBankAccountFactory = apiFactory()( const encryptedParams = utils.encodeAES(JSON.stringify(params)); if (!encryptedParams) throw new ZaloApiError("Failed to encrypt params"); - const response = await utils.request(utils.makeURL(serviceURL, { params: encryptedParams }), { - method: "GET", + const response = await utils.request(serviceURL, { + method: "POST", + body: new URLSearchParams({ + params: encryptedParams, + }), }); return utils.resolve(response); diff --git a/src/apis/deleteBankAccount.ts b/src/apis/deleteBankAccount.ts new file mode 100644 index 00000000..84e43aa9 --- /dev/null +++ b/src/apis/deleteBankAccount.ts @@ -0,0 +1,49 @@ +import { ZaloApiError } from "../Errors/ZaloApiError.js"; +import type { BankAccount } from "../models/index.js"; +import { apiFactory } from "../utils.js"; + +export type DeleteBankAccountPayload = { + accountId: number; + isDefault: boolean; +}; + +/** + * I'm really confused that the list of accounts that are not mine is returned by this `api.deleteBankAccount()` T.T + * @TODO check again later + */ +export type DeleteBankAccountResponse = { + hasMore: boolean; + total: number; + myBanks: BankAccount[]; +}; + +export const deleteBankAccountFactory = apiFactory()((api, ctx, utils) => { + const serviceURL = utils.makeURL(`${api.zpwServiceMap.zimsg[0]}/api/transfer/delete`); + + /** + * Delete bank account + * + * @param payload The payload containing the bank account information to delete + * + * @throws {ZaloApiError} + */ + return async function deleteBankAccount(payload: DeleteBankAccountPayload) { + const params = { + account_id: payload.accountId, + is_default: payload.isDefault, + language: ctx.language, + }; + + const encryptedParams = utils.encodeAES(JSON.stringify(params)); + if (!encryptedParams) throw new ZaloApiError("Failed to encrypt params"); + + const response = await utils.request(serviceURL, { + method: "POST", + body: new URLSearchParams({ + params: encryptedParams, + }), + }); + + return utils.resolve(response); + }; +}); diff --git a/src/apis/updateBankAccount.ts b/src/apis/updateBankAccount.ts new file mode 100644 index 00000000..82d1a192 --- /dev/null +++ b/src/apis/updateBankAccount.ts @@ -0,0 +1,45 @@ +import { ZaloApiError } from "../Errors/ZaloApiError.js"; +import type { BankAccount, BinBankCard } from "../models/index.js"; +import { apiFactory, normalizeHolderName } from "../utils.js"; + +export type UpdateBankAccountPayload = { + accountId: number; + binBank: BinBankCard; + numAccBank: string; + nameAccBank: string; +}; + +export type UpdateBankAccountResponse = BankAccount; + +export const updateBankAccountFactory = apiFactory()((api, ctx, utils) => { + const serviceURL = utils.makeURL(`${api.zpwServiceMap.zimsg[0]}/api/transfer/update`); + + /** + * Update bank account + * + * @param payload The payload containing the bank account information to update + * + * @throws {ZaloApiError} + */ + return async function updateBankAccount(payload: UpdateBankAccountPayload) { + const params = { + account_id: payload.accountId, + bin: payload.binBank, + bank_number: payload.numAccBank, + holder_name: normalizeHolderName(payload.nameAccBank), + language: ctx.language, + }; + + const encryptedParams = utils.encodeAES(JSON.stringify(params)); + if (!encryptedParams) throw new ZaloApiError("Failed to encrypt params"); + + const response = await utils.request(serviceURL, { + method: "POST", + body: new URLSearchParams({ + params: encryptedParams, + }), + }); + + return utils.resolve(response); + }; +}); diff --git a/src/index.ts b/src/index.ts index e9f36e3e..b8c59407 100644 --- a/src/index.ts +++ b/src/index.ts @@ -30,6 +30,7 @@ export type { CreateProductCatalogPayload, CreateProductCatalogResponse } from " export type { CreateReminderOptions, CreateReminderResponse, CreateReminderUser, CreateReminderGroup } from "./apis/createReminder.js"; export type { DeleteAutoReplyResponse } from "./apis/deleteAutoReply.js"; export type { DeleteAvatarResponse } from "./apis/deleteAvatar.js"; +export type { DeleteBankAccountPayload, DeleteBankAccountResponse } from "./apis/deleteBankAccount.js"; export type { DeleteCatalogResponse } from "./apis/deleteCatalog.js"; export type { DeleteChatLastMessage, DeleteChatResponse } from "./apis/deleteChat.js"; export type { DeleteGroupInviteBoxResponse } from "./apis/deleteGroupInviteBox.js"; @@ -136,6 +137,7 @@ export type { UpdateActiveStatusResponse } from "./apis/updateActiveStatus.js"; export type { UpdateArchivedChatListTarget, UpdateArchivedChatListResponse } from "./apis/updateArchivedChatList.js"; export type { UpdateAutoDeleteChatResponse } from "./apis/updateAutoDeleteChat.js"; export type { UpdateAutoReplyPayload, UpdateAutoReplyResponse } from "./apis/updateAutoReply.js"; +export type { UpdateBankAccountPayload, UpdateBankAccountResponse } from "./apis/updateBankAccount.js"; export type { UpdateCatalogPayload, UpdateCatalogResponse } from "./apis/updateCatalog.js"; export type { UpdateGroupSettingsOptions, UpdateGroupSettingsResponse } from "./apis/updateGroupSettings.js"; export type { UpdateHiddenConversPinResponse } from "./apis/updateHiddenConversPin.js"; From ff78bcf44be19fd8a39fca2be5f60a62155e2642 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ho=C3=A0ng=20H=C3=A0o?= Date: Thu, 16 Apr 2026 15:11:39 +0700 Subject: [PATCH 09/17] feat: add getListDevice API and corresponding types - Introduced `getListDevice` API in `getListDevice.ts` to retrieve linked devices. - Updated `apis.ts` and `index.ts` to include the new API method and its type `GetListDeviceResponse`. --- src/apis.ts | 3 +++ src/apis/getListDevice.ts | 36 ++++++++++++++++++++++++++++++++++++ src/index.ts | 1 + 3 files changed, 40 insertions(+) create mode 100644 src/apis/getListDevice.ts diff --git a/src/apis.ts b/src/apis.ts index bf90a06b..175d5039 100644 --- a/src/apis.ts +++ b/src/apis.ts @@ -71,6 +71,7 @@ import { getLabelsFactory } from "./apis/getLabels.js"; import { getListBankFactory } from "./apis/getListBank.js"; import { getListBankCardFactory } from "./apis/getListBankCard.js"; import { getListBoardFactory } from "./apis/getListBoard.js"; +import { getListDeviceFactory } from "./apis/getListDevice.js"; import { getListReminderFactory } from "./apis/getListReminder.js"; import { getMultiUsersByPhonesFactory } from "./apis/getMultiUsersByPhones.js"; import { getMuteFactory } from "./apis/getMute.js"; @@ -228,6 +229,7 @@ export class API { public getListBank: ReturnType; public getListBankCard: ReturnType; public getListBoard: ReturnType; + public getListDevice: ReturnType; public getListReminder: ReturnType; public getMultiUsersByPhones: ReturnType; public getMute: ReturnType; @@ -385,6 +387,7 @@ export class API { this.getListBank = getListBankFactory(ctx, this); this.getListBankCard = getListBankCardFactory(ctx, this); this.getListBoard = getListBoardFactory(ctx, this); + this.getListDevice = getListDeviceFactory(ctx, this); this.getListReminder = getListReminderFactory(ctx, this); this.getMultiUsersByPhones = getMultiUsersByPhonesFactory(ctx, this); this.getMute = getMuteFactory(ctx, this); diff --git a/src/apis/getListDevice.ts b/src/apis/getListDevice.ts new file mode 100644 index 00000000..f9a6830b --- /dev/null +++ b/src/apis/getListDevice.ts @@ -0,0 +1,36 @@ +import { ZaloApiError } from "../Errors/ZaloApiError.js"; +import { apiFactory } from "../utils.js"; + +export type GetListDeviceResponse = { + devices: { + masterId: string; + encIdentity: string; + lastUpdateTs: number; + encSignature: string; + companions: string[] | unknown[]; // @TODO check type later + }; +}; + +export const getListDeviceFactory = apiFactory()((api, ctx, utils) => { + const serviceURL = utils.makeURL(`${api.zpwServiceMap.aext[0]}/api/devices/linked`); + + /** + * Get list device + * + * @throws {ZaloApiError} + */ + return async function getListDevice() { + const params = { + imei: ctx.imei, + }; + + const encryptedParams = utils.encodeAES(JSON.stringify(params)); + if (!encryptedParams) throw new ZaloApiError("Failed to encrypt params"); + + const response = await utils.request(utils.makeURL(serviceURL, { params: encryptedParams }), { + method: "GET", + }); + + return utils.resolve(response); + }; +}); diff --git a/src/index.ts b/src/index.ts index b8c59407..18914c61 100644 --- a/src/index.ts +++ b/src/index.ts @@ -74,6 +74,7 @@ export type { GetLabelsResponse } from "./apis/getLabels.js"; export type { GetListBankResponse } from "./apis/getListBank.js"; export type { GetListBankCardResponse } from "./apis/getListBankCard.js"; export type { BoardItem, GetListBoardResponse, ListBoardOptions } from "./apis/getListBoard.js"; +export type { GetListDeviceResponse } from "./apis/getListDevice.js"; export type { GetListReminderResponse, ListReminderOptions, ReminderListGroup, ReminderListUser } from "./apis/getListReminder.js"; export type { GetMultiUsersByPhonesResponse } from "./apis/getMultiUsersByPhones.js"; export type { GetMuteResponse, MuteEntriesInfo } from "./apis/getMute.js"; From 3182c43fd364d79e2e0f727e317cb9ab7a382702 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ho=C3=A0ng=20H=C3=A0o?= Date: Thu, 16 Apr 2026 15:54:15 +0700 Subject: [PATCH 10/17] feat: add lostFocus API and corresponding types - Introduced `lostFocus` API in `lostFocus.ts` to handle focus loss events. - Updated `apis.ts` and `index.ts` to include the new API method and its type `LostFocusResponse`. --- src/apis.ts | 3 +++ src/apis/lostFocus.ts | 31 +++++++++++++++++++++++++++++++ src/index.ts | 1 + 3 files changed, 35 insertions(+) create mode 100644 src/apis/lostFocus.ts diff --git a/src/apis.ts b/src/apis.ts index 175d5039..f5946015 100644 --- a/src/apis.ts +++ b/src/apis.ts @@ -99,6 +99,7 @@ import { keepAliveFactory } from "./apis/keepAlive.js"; import { lastOnlineFactory } from "./apis/lastOnline.js"; import { leaveGroupFactory } from "./apis/leaveGroup.js"; import { lockPollFactory } from "./apis/lockPoll.js"; +import { lostFocusFactory } from "./apis/lostFocus.js"; import { parseLinkFactory } from "./apis/parseLink.js"; import { rejectFriendRequestFactory } from "./apis/rejectFriendRequest.js"; import { removeFriendFactory } from "./apis/removeFriend.js"; @@ -257,6 +258,7 @@ export class API { public lastOnline: ReturnType; public leaveGroup: ReturnType; public lockPoll: ReturnType; + public lostFocus: ReturnType; public parseLink: ReturnType; public rejectFriendRequest: ReturnType; public removeFriend: ReturnType; @@ -415,6 +417,7 @@ export class API { this.lastOnline = lastOnlineFactory(ctx, this); this.leaveGroup = leaveGroupFactory(ctx, this); this.lockPoll = lockPollFactory(ctx, this); + this.lostFocus = lostFocusFactory(ctx, this); this.parseLink = parseLinkFactory(ctx, this); this.rejectFriendRequest = rejectFriendRequestFactory(ctx, this); this.removeFriend = removeFriendFactory(ctx, this); diff --git a/src/apis/lostFocus.ts b/src/apis/lostFocus.ts new file mode 100644 index 00000000..558c397f --- /dev/null +++ b/src/apis/lostFocus.ts @@ -0,0 +1,31 @@ +import { ZaloApiError } from "../Errors/ZaloApiError.js"; +import { apiFactory } from "../utils.js"; + +export type LostFocusResponse = { + status: boolean; +}; + +export const lostFocusFactory = apiFactory()((api, _ctx, utils) => { + const serviceURL = utils.makeURL(`${api.zpwServiceMap.profile[0]}/api/social/profile/changefgtobg`); + + /** + * Lost focus + * + * @throws {ZaloApiError} + */ + return async function lostFocus() { + const params = {}; + + const encryptedParams = utils.encodeAES(JSON.stringify(params)); + if (!encryptedParams) throw new ZaloApiError("Failed to encrypt params"); + + const response = await utils.request(serviceURL, { + method: "POST", + body: new URLSearchParams({ + params: encryptedParams, + }), + }); + + return utils.resolve(response); + }; +}); diff --git a/src/index.ts b/src/index.ts index 18914c61..00555ad8 100644 --- a/src/index.ts +++ b/src/index.ts @@ -101,6 +101,7 @@ export type { LastOnlineResponse } from "./apis/lastOnline.js"; export type { LeaveGroupResponse } from "./apis/leaveGroup.js"; export type { LockPollResponse } from "./apis/lockPoll.js"; export type { LoginQRCallback, LoginQRCallbackEvent } from "./apis/loginQR.js"; +export type { LostFocusResponse } from "./apis/lostFocus.js"; export type { ParseLinkErrorMaps, ParseLinkResponse } from "./apis/parseLink.js"; export type { RejectFriendRequestResponse } from "./apis/rejectFriendRequest.js"; export type { RemoveFriendResponse } from "./apis/removeFriend.js"; From 86dde860f6eaf8e1a53a5b4b81e4048ad6268e1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ho=C3=A0ng=20H=C3=A0o?= Date: Fri, 17 Apr 2026 11:27:09 +0700 Subject: [PATCH 11/17] feat: add registerCatalog API and corresponding types - Introduced `registerCatalog` API in `registerCatalog.ts` to manage catalog registration. - Updated `apis.ts` and `index.ts` to include the new API method and its type `RegisterCatalogResponse`. --- src/apis.ts | 3 +++ src/apis/registerCatalog.ts | 35 +++++++++++++++++++++++++++++++++++ src/index.ts | 1 + 3 files changed, 39 insertions(+) create mode 100644 src/apis/registerCatalog.ts diff --git a/src/apis.ts b/src/apis.ts index f5946015..a5ecb792 100644 --- a/src/apis.ts +++ b/src/apis.ts @@ -101,6 +101,7 @@ import { leaveGroupFactory } from "./apis/leaveGroup.js"; import { lockPollFactory } from "./apis/lockPoll.js"; import { lostFocusFactory } from "./apis/lostFocus.js"; import { parseLinkFactory } from "./apis/parseLink.js"; +import { registerCatalogFactory } from "./apis/registerCatalog.js"; import { rejectFriendRequestFactory } from "./apis/rejectFriendRequest.js"; import { removeFriendFactory } from "./apis/removeFriend.js"; import { removeFriendAliasFactory } from "./apis/removeFriendAlias.js"; @@ -260,6 +261,7 @@ export class API { public lockPoll: ReturnType; public lostFocus: ReturnType; public parseLink: ReturnType; + public registerCatalog: ReturnType; public rejectFriendRequest: ReturnType; public removeFriend: ReturnType; public removeFriendAlias: ReturnType; @@ -419,6 +421,7 @@ export class API { this.lockPoll = lockPollFactory(ctx, this); this.lostFocus = lostFocusFactory(ctx, this); this.parseLink = parseLinkFactory(ctx, this); + this.registerCatalog = registerCatalogFactory(ctx, this); this.rejectFriendRequest = rejectFriendRequestFactory(ctx, this); this.removeFriend = removeFriendFactory(ctx, this); this.removeFriendAlias = removeFriendAliasFactory(ctx, this); diff --git a/src/apis/registerCatalog.ts b/src/apis/registerCatalog.ts new file mode 100644 index 00000000..c5b862d5 --- /dev/null +++ b/src/apis/registerCatalog.ts @@ -0,0 +1,35 @@ +import { ZaloApiError } from "../Errors/ZaloApiError.js"; +import { apiFactory } from "../utils.js"; + +export type RegisterCatalogResponse = { + status: boolean; +}; + +export const registerCatalogFactory = apiFactory()((api, _ctx, utils) => { + const serviceURL = utils.makeURL(`${api.zpwServiceMap.catalog[0]}/api/prodcatalog/catalog/register`); + + /** + * Register catalog + * + * @param enable enable or disable catalog + * + * @throws {ZaloApiError} + */ + return async function registerCatalog(enable: boolean) { + const params = { + enable: enable ? 1 : 0, + }; + + const encryptedParams = utils.encodeAES(JSON.stringify(params)); + if (!encryptedParams) throw new ZaloApiError("Failed to encrypt params"); + + const response = await utils.request(serviceURL, { + method: "POST", + body: new URLSearchParams({ + params: encryptedParams, + }), + }); + + return utils.resolve(response); + }; +}); diff --git a/src/index.ts b/src/index.ts index 00555ad8..43dece6f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -103,6 +103,7 @@ export type { LockPollResponse } from "./apis/lockPoll.js"; export type { LoginQRCallback, LoginQRCallbackEvent } from "./apis/loginQR.js"; export type { LostFocusResponse } from "./apis/lostFocus.js"; export type { ParseLinkErrorMaps, ParseLinkResponse } from "./apis/parseLink.js"; +export type { RegisterCatalogResponse } from "./apis/registerCatalog.js"; export type { RejectFriendRequestResponse } from "./apis/rejectFriendRequest.js"; export type { RemoveFriendResponse } from "./apis/removeFriend.js"; export type { RemoveFriendAliasResponse } from "./apis/removeFriendAlias.js"; From d925e90e7d2e189176f6d2de44cf98d3ab8de918 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ho=C3=A0ng=20H=C3=A0o?= Date: Fri, 17 Apr 2026 12:17:01 +0700 Subject: [PATCH 12/17] feat: add scanURL API and corresponding types - Introduced `scanURL` API in `scanURL.ts` to check the safety of URLs. - Updated `apis.ts` to include the new API method and its type `ScanURLResponse`. - Enhanced `index.ts` to export the new type for broader accessibility. --- src/apis.ts | 3 +++ src/apis/createCatalog.ts | 8 ++++---- src/apis/scanURL.ts | 36 ++++++++++++++++++++++++++++++++++++ src/index.ts | 1 + 4 files changed, 44 insertions(+), 4 deletions(-) create mode 100644 src/apis/scanURL.ts diff --git a/src/apis.ts b/src/apis.ts index a5ecb792..96890591 100644 --- a/src/apis.ts +++ b/src/apis.ts @@ -114,6 +114,7 @@ import { removeUserFromGroupFactory } from "./apis/removeUserFromGroup.js"; import { resetHiddenConversPinFactory } from "./apis/resetHiddenConversPin.js"; import { reuseAvatarFactory } from "./apis/reuseAvatar.js"; import { reviewPendingMemberRequestFactory } from "./apis/reviewPendingMemberRequest.js"; +import { scanURLFactory } from "./apis/scanURL.js"; import { searchStickerFactory } from "./apis/searchSticker.js"; import { sendBankCardFactory } from "./apis/sendBankCard.js"; import { sendCardFactory } from "./apis/sendCard.js"; @@ -274,6 +275,7 @@ export class API { public resetHiddenConversPin: ReturnType; public reuseAvatar: ReturnType; public reviewPendingMemberRequest: ReturnType; + public scanURL: ReturnType; public searchSticker: ReturnType; public sendBankCard: ReturnType; public sendCard: ReturnType; @@ -434,6 +436,7 @@ export class API { this.resetHiddenConversPin = resetHiddenConversPinFactory(ctx, this); this.reuseAvatar = reuseAvatarFactory(ctx, this); this.reviewPendingMemberRequest = reviewPendingMemberRequestFactory(ctx, this); + this.scanURL = scanURLFactory(ctx, this); this.searchSticker = searchStickerFactory(ctx, this); this.sendBankCard = sendBankCardFactory(ctx, this); this.sendCard = sendCardFactory(ctx, this); diff --git a/src/apis/createCatalog.ts b/src/apis/createCatalog.ts index a031d7af..8c0b937d 100644 --- a/src/apis/createCatalog.ts +++ b/src/apis/createCatalog.ts @@ -1,7 +1,6 @@ import { ZaloApiError } from "../Errors/ZaloApiError.js"; -import { apiFactory } from "../utils.js"; - import type { CatalogItem } from "../models/index.js"; +import { apiFactory } from "../utils.js"; export type CreateCatalogResponse = { item: CatalogItem; @@ -9,7 +8,7 @@ export type CreateCatalogResponse = { version_catalog: number; }; -export const createCatalogFactory = apiFactory()((api, _, utils) => { +export const createCatalogFactory = apiFactory()((api, _ctx, utils) => { const serviceURL = utils.makeURL(`${api.zpwServiceMap.catalog[0]}/api/prodcatalog/catalog/create`); /** @@ -17,7 +16,8 @@ export const createCatalogFactory = apiFactory()((api, _, * * @param catalogName catalog name * - * @note this API is used for zBusiness + * @note this API is used for zBasic + * * @throws {ZaloApiError} */ return async function createCatalog(catalogName: string) { diff --git a/src/apis/scanURL.ts b/src/apis/scanURL.ts new file mode 100644 index 00000000..75d9ce5f --- /dev/null +++ b/src/apis/scanURL.ts @@ -0,0 +1,36 @@ +import { ZaloApiError } from "../Errors/ZaloApiError.js"; +import { apiFactory } from "../utils.js"; + +export type ScanURLResponse = { + isSafe: boolean; +}; + +export const scanURLFactory = apiFactory()((api, _ctx, utils) => { + const serviceURL = utils.makeURL(`${api.zpwServiceMap.file[0]}/api/message/scanurl`); + + /** + * Scan URL + * + * @param url URL to scan check if it is safe (https) + * + * @throws {ZaloApiError} + */ + return async function scanURL(url: string) { + + const params = { + url: url, + }; + + const encryptedParams = utils.encodeAES(JSON.stringify(params)); + if (!encryptedParams) throw new ZaloApiError("Failed to encrypt params"); + + const response = await utils.request(serviceURL, { + method: "POST", + body: new URLSearchParams({ + params: encryptedParams, + }), + }); + + return utils.resolve(response); + }; +}); diff --git a/src/index.ts b/src/index.ts index 43dece6f..7753bc42 100644 --- a/src/index.ts +++ b/src/index.ts @@ -116,6 +116,7 @@ export type { RemoveUserFromGroupResponse } from "./apis/removeUserFromGroup.js" export type { ResetHiddenConversPinResponse } from "./apis/resetHiddenConversPin.js"; export type { ReuseAvatarResponse } from "./apis/reuseAvatar.js"; export type { ReviewPendingMemberRequestPayload, ReviewPendingMemberRequestResponse } from "./apis/reviewPendingMemberRequest.js"; +export type { ScanURLResponse } from "./apis/scanURL.js"; export type { SearchStickerResponse } from "./apis/searchSticker.js"; export type { SendBankCardPayload, SendBankCardResponse } from "./apis/sendBankCard.js"; export type { SendCardOptions, SendCardResponse } from "./apis/sendCard.js"; From c1bac16c10df87f294c29c4b276b3fba3531f868 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ho=C3=A0ng=20H=C3=A0o?= Date: Fri, 24 Apr 2026 12:30:46 +0700 Subject: [PATCH 13/17] feat: update User model and API response types - Added `UnchangedProfileInfo` type to the `User` model for better structure. - Updated `UserInfoResponse` in `getUserInfo.ts` to use `Partial` for `unchanged_profiles`, enhancing type safety and clarity. --- src/apis/getUserInfo.ts | 4 ++-- src/models/User.ts | 9 +++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/apis/getUserInfo.ts b/src/apis/getUserInfo.ts index d160836e..d94df799 100644 --- a/src/apis/getUserInfo.ts +++ b/src/apis/getUserInfo.ts @@ -1,12 +1,12 @@ import { ZaloApiError } from "../Errors/ZaloApiError.js"; import { apiFactory } from "../utils.js"; -import { AvatarSize, type User } from "../models/index.js"; +import { AvatarSize, type UnchangedProfileInfo, type User } from "../models/index.js"; export type ProfileInfo = User; export type UserInfoResponse = { - unchanged_profiles: Record; + unchanged_profiles: Record>; phonebook_version: number; changed_profiles: Record; }; diff --git a/src/models/User.ts b/src/models/User.ts index 03f52f15..3588fc1f 100644 --- a/src/models/User.ts +++ b/src/models/User.ts @@ -63,3 +63,12 @@ export type UserSetting = { view_birthday: number; setting_2FA_status: number; }; + +export type UnchangedProfileInfo = { + oa_status: { + blocked: number; + }; + isFr: number; + isBlocked: boolean; + lastActionTime: number; +}; From 98c8ae22f468d7ffd87fce9bf2ba47cb2f5f38a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ho=C3=A0ng=20H=C3=A0o?= Date: Thu, 4 Jun 2026 12:41:39 +0700 Subject: [PATCH 14/17] feat: update API version and enhance type definitions - Updated the `createContext` function to use a new API version (685). - Modified `GetGroupLinkInfoResponse` to use `GroupType` instead of a numeric type for better clarity. - Added new `Medium` and `ExtraLarge` sizes to the `AvatarSize` enum for expanded options. --- src/apis/getGroupLinkInfo.ts | 4 ++-- src/context.ts | 2 +- src/models/Enum.ts | 2 ++ 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/apis/getGroupLinkInfo.ts b/src/apis/getGroupLinkInfo.ts index 367eceeb..8b95de52 100644 --- a/src/apis/getGroupLinkInfo.ts +++ b/src/apis/getGroupLinkInfo.ts @@ -1,5 +1,5 @@ import { ZaloApiError } from "../Errors/ZaloApiError.js"; -import type { GroupSetting } from "../models/index.js"; +import type { GroupSetting, GroupType } from "../models/index.js"; import { apiFactory } from "../utils.js"; export type GetGroupLinkInfoPayload = { @@ -14,7 +14,7 @@ export type GetGroupLinkInfoResponse = { groupId: string; name: string; desc: string; - type: number; + type: GroupType; creatorId: string; avt: string; fullAvt: string; diff --git a/src/context.ts b/src/context.ts index 0fab251d..adfff166 100644 --- a/src/context.ts +++ b/src/context.ts @@ -193,7 +193,7 @@ export type AppContextExtended = { export type ContextBase = Partial & AppContextExtended; -export const createContext = (apiType = 30, apiVersion = 681) => +export const createContext = (apiType = 30, apiVersion = 685) => ({ API_TYPE: apiType, API_VERSION: apiVersion, diff --git a/src/models/Enum.ts b/src/models/Enum.ts index 3eb9010a..9ce5cf04 100644 --- a/src/models/Enum.ts +++ b/src/models/Enum.ts @@ -16,5 +16,7 @@ export enum Gender { export enum AvatarSize { Small = 120, + Medium = 180, Large = 240, + ExtraLarge = 360, } From 6635bfa0f498cc6087050216ed1d2dbce0f99b9f Mon Sep 17 00:00:00 2001 From: RFS-ADRENO Date: Thu, 18 Jun 2026 19:30:04 +0700 Subject: [PATCH 15/17] fix(apis): correct & revert unnecessary changes + revert createCatalog change + revert sendBankCard and change _ctx to _ to match project conventions --- src/apis/createCatalog.ts | 6 +++--- src/apis/sendBankCard.ts | 5 +++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/apis/createCatalog.ts b/src/apis/createCatalog.ts index 8c0b937d..3433f5a4 100644 --- a/src/apis/createCatalog.ts +++ b/src/apis/createCatalog.ts @@ -1,6 +1,6 @@ import { ZaloApiError } from "../Errors/ZaloApiError.js"; -import type { CatalogItem } from "../models/index.js"; import { apiFactory } from "../utils.js"; +import type { CatalogItem } from "../models/index.js"; export type CreateCatalogResponse = { item: CatalogItem; @@ -8,7 +8,7 @@ export type CreateCatalogResponse = { version_catalog: number; }; -export const createCatalogFactory = apiFactory()((api, _ctx, utils) => { +export const createCatalogFactory = apiFactory()((api, _, utils) => { const serviceURL = utils.makeURL(`${api.zpwServiceMap.catalog[0]}/api/prodcatalog/catalog/create`); /** @@ -16,7 +16,7 @@ export const createCatalogFactory = apiFactory()((api, _c * * @param catalogName catalog name * - * @note this API is used for zBasic + * @note this API is used for zBusiness * * @throws {ZaloApiError} */ diff --git a/src/apis/sendBankCard.ts b/src/apis/sendBankCard.ts index caa3d64e..e10d146d 100644 --- a/src/apis/sendBankCard.ts +++ b/src/apis/sendBankCard.ts @@ -1,5 +1,6 @@ import { ZaloApiError } from "../Errors/ZaloApiError.js"; -import { ThreadType, type BinBankCard } from "../models/index.js"; +import type { BinBankCard } from "../models/index.js"; +import { ThreadType } from "../models/index.js"; import { apiFactory } from "../utils.js"; export type SendBankCardPayload = { @@ -10,7 +11,7 @@ export type SendBankCardPayload = { export type SendBankCardResponse = ""; -export const sendBankCardFactory = apiFactory()((api, _ctx, utils) => { +export const sendBankCardFactory = apiFactory()((api, _, utils) => { const serviceURL = utils.makeURL(`${api.zpwServiceMap.zimsg[0]}/api/transfer/card`); /** From a80bb470dcea38efa9900552b1e51355b2e3a83a Mon Sep 17 00:00:00 2001 From: RFS-ADRENO Date: Thu, 18 Jun 2026 19:31:35 +0700 Subject: [PATCH 16/17] fix(createCatalog): restore to original --- src/apis/createCatalog.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/apis/createCatalog.ts b/src/apis/createCatalog.ts index 3433f5a4..8a1f6731 100644 --- a/src/apis/createCatalog.ts +++ b/src/apis/createCatalog.ts @@ -1,5 +1,6 @@ import { ZaloApiError } from "../Errors/ZaloApiError.js"; import { apiFactory } from "../utils.js"; + import type { CatalogItem } from "../models/index.js"; export type CreateCatalogResponse = { From 1c3e97912ff2ab81ef1a284fabea9d69f87f05cc Mon Sep 17 00:00:00 2001 From: RFS-ADRENO Date: Thu, 18 Jun 2026 19:32:30 +0700 Subject: [PATCH 17/17] fix(createCatalog): revert format --- src/apis/createCatalog.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/apis/createCatalog.ts b/src/apis/createCatalog.ts index 8a1f6731..a031d7af 100644 --- a/src/apis/createCatalog.ts +++ b/src/apis/createCatalog.ts @@ -18,7 +18,6 @@ export const createCatalogFactory = apiFactory()((api, _, * @param catalogName catalog name * * @note this API is used for zBusiness - * * @throws {ZaloApiError} */ return async function createCatalog(catalogName: string) {