@softtynet/zca-js 2.3.2 → 2.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +63 -21
- package/dist/apis/auth/exportSession.d.ts +7 -0
- package/dist/apis/auth/exportSession.js +17 -0
- package/dist/apis/chat/getDirectMessageStatus.d.ts +14 -0
- package/dist/apis/chat/getDirectMessageStatus.js +52 -0
- package/dist/apis/chat/getSuggestedConversations.d.ts +5 -0
- package/dist/apis/chat/getSuggestedConversations.js +24 -0
- package/dist/apis/chat/updatePinConversations.d.ts +24 -0
- package/dist/apis/chat/updatePinConversations.js +40 -0
- package/dist/apis/friend/getFriendProfilesV2.d.ts +26 -0
- package/dist/apis/friend/getFriendProfilesV2.js +38 -0
- package/dist/apis/friend/getFriendsActivePCWeb.d.ts +6 -0
- package/dist/apis/friend/getFriendsActivePCWeb.js +15 -0
- package/dist/apis/friend/verifyFriend.d.ts +11 -0
- package/dist/apis/friend/verifyFriend.js +37 -0
- package/dist/apis/group/analyseGroup.d.ts +4 -0
- package/dist/apis/group/analyseGroup.js +28 -0
- package/dist/apis/group/checkQuotaCommunityMember.d.ts +6 -0
- package/dist/apis/group/checkQuotaCommunityMember.js +34 -0
- package/dist/apis/group/getE2eeGroupList.d.ts +7 -0
- package/dist/apis/group/getE2eeGroupList.js +15 -0
- package/dist/apis/group/getGroupChatHistory.d.ts +37 -6
- package/dist/apis/group/getGroupChatHistory.js +41 -19
- package/dist/apis/group/getGroupCloudMessagePath.d.ts +19 -0
- package/dist/apis/group/getGroupCloudMessagePath.js +51 -0
- package/dist/apis/group/getGroupHistoryLegacy.d.ts +7 -0
- package/dist/apis/group/getGroupHistoryLegacy.js +62 -0
- package/dist/apis/group/getGroupInfoV2.d.ts +30 -0
- package/dist/apis/group/getGroupInfoV2.js +48 -0
- package/dist/apis/group/getGroupListV3.d.ts +19 -0
- package/dist/apis/group/getGroupListV3.js +29 -0
- package/dist/apis/group/getGroupMessageStatus.d.ts +26 -0
- package/dist/apis/group/getGroupMessageStatus.js +77 -0
- package/dist/apis/group/getMultiGroupCloudMessages.d.ts +5 -0
- package/dist/apis/group/getMultiGroupCloudMessages.js +29 -0
- package/dist/apis/media/getConversationMedia.d.ts +10 -0
- package/dist/apis/media/getPersonalMedia.d.ts +8 -0
- package/dist/apis/media/getPersonalMedia.js +31 -0
- package/dist/apis/media/getPersonalMediaPreview.d.ts +3 -0
- package/dist/apis/media/getPersonalMediaPreview.js +24 -0
- package/dist/apis/media/removePersonalMedia.d.ts +9 -0
- package/dist/apis/media/removePersonalMedia.js +28 -0
- package/dist/apis.d.ts +57 -0
- package/dist/apis.js +95 -0
- package/dist/cjs/apis/auth/exportSession.cjs +22 -0
- package/dist/cjs/apis/chat/getDirectMessageStatus.cjs +58 -0
- package/dist/cjs/apis/chat/getSuggestedConversations.cjs +29 -0
- package/dist/cjs/apis/chat/updatePinConversations.cjs +45 -0
- package/dist/cjs/apis/friend/getFriendProfilesV2.cjs +43 -0
- package/dist/cjs/apis/friend/getFriendsActivePCWeb.cjs +20 -0
- package/dist/cjs/apis/friend/verifyFriend.cjs +42 -0
- package/dist/cjs/apis/group/analyseGroup.cjs +33 -0
- package/dist/cjs/apis/group/checkQuotaCommunityMember.cjs +39 -0
- package/dist/cjs/apis/group/getE2eeGroupList.cjs +20 -0
- package/dist/cjs/apis/group/getGroupChatHistory.cjs +41 -18
- package/dist/cjs/apis/group/getGroupCloudMessagePath.cjs +69 -0
- package/dist/cjs/apis/group/getGroupHistoryLegacy.cjs +80 -0
- package/dist/cjs/apis/group/getGroupInfoV2.cjs +53 -0
- package/dist/cjs/apis/group/getGroupListV3.cjs +34 -0
- package/dist/cjs/apis/group/getGroupMessageStatus.cjs +83 -0
- package/dist/cjs/apis/group/getMultiGroupCloudMessages.cjs +34 -0
- package/dist/cjs/apis/media/getPersonalMedia.cjs +36 -0
- package/dist/cjs/apis/media/getPersonalMediaPreview.cjs +29 -0
- package/dist/cjs/apis/media/removePersonalMedia.cjs +33 -0
- package/dist/cjs/apis.cjs +95 -0
- package/dist/cjs/constants/endpoints.cjs +13 -0
- package/dist/cjs/constants/protocol.cjs +1 -1
- package/dist/cjs/context.cjs +20 -2
- package/dist/cjs/core/zcloud-client.cjs +1 -2
- package/dist/cjs/crypto/ws-cipher.cjs +66 -2
- package/dist/cjs/index.cjs +2 -0
- package/dist/cjs/realtime/listener.cjs +18 -6
- package/dist/cjs/update.cjs +10 -1
- package/dist/cjs/utils.cjs +22 -5
- package/dist/constants/endpoints.d.ts +13 -0
- package/dist/constants/endpoints.js +13 -0
- package/dist/constants/protocol.d.ts +1 -1
- package/dist/constants/protocol.js +1 -1
- package/dist/context.d.ts +10 -0
- package/dist/context.js +20 -2
- package/dist/crypto/ws-cipher.d.ts +7 -0
- package/dist/crypto/ws-cipher.js +64 -2
- package/dist/index.d.ts +22 -3
- package/dist/index.js +1 -1
- package/dist/realtime/listener.d.ts +1 -0
- package/dist/realtime/listener.js +18 -6
- package/dist/update.js +10 -1
- package/dist/utils.js +17 -4
- package/index.d.ts +1 -1
- package/package.json +15 -5
package/dist/cjs/utils.cjs
CHANGED
|
@@ -15,8 +15,7 @@ var protocol = require('./constants/protocol.cjs');
|
|
|
15
15
|
var domains = require('./constants/domains.cjs');
|
|
16
16
|
var defaults = require('./constants/defaults.cjs');
|
|
17
17
|
var aes = require('./crypto/aes.cjs');
|
|
18
|
-
require('
|
|
19
|
-
require('json-bigint');
|
|
18
|
+
var wsCipher = require('./crypto/ws-cipher.cjs');
|
|
20
19
|
|
|
21
20
|
const isBun = typeof Bun !== "undefined";
|
|
22
21
|
function hasOwn(obj, key) {
|
|
@@ -166,8 +165,20 @@ async function request(ctx, url, options, raw = false) {
|
|
|
166
165
|
options = { ...(options || {}), headers: defaultHeaders };
|
|
167
166
|
}
|
|
168
167
|
}
|
|
168
|
+
const timeoutMs = ctx.options?.requestTimeout;
|
|
169
|
+
const defaultSignal = !options?.signal &&
|
|
170
|
+
typeof timeoutMs === "number" &&
|
|
171
|
+
timeoutMs > 0 &&
|
|
172
|
+
typeof AbortSignal !== "undefined" &&
|
|
173
|
+
typeof AbortSignal.timeout === "function"
|
|
174
|
+
? AbortSignal.timeout(timeoutMs)
|
|
175
|
+
: undefined;
|
|
176
|
+
const isAgentUndiciDispatcher = Boolean(ctx.options.agent && typeof ctx.options.agent.dispatch === "function");
|
|
177
|
+
const resolvedDispatcher = ctx.options.dispatcher ?? (isAgentUndiciDispatcher ? ctx.options.agent : undefined);
|
|
178
|
+
const resolvedAgent = ctx.options.agent && !isAgentUndiciDispatcher ? ctx.options.agent : undefined;
|
|
169
179
|
const _options = {
|
|
170
180
|
...(options ?? {}),
|
|
181
|
+
...(defaultSignal ? { signal: defaultSignal } : {}),
|
|
171
182
|
...(isBun
|
|
172
183
|
? {
|
|
173
184
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
@@ -175,8 +186,8 @@ async function request(ctx, url, options, raw = false) {
|
|
|
175
186
|
proxy: ctx.options.agent?.proxy?.href,
|
|
176
187
|
}
|
|
177
188
|
: {
|
|
178
|
-
agent:
|
|
179
|
-
dispatcher:
|
|
189
|
+
...(resolvedAgent ? { agent: resolvedAgent } : {}),
|
|
190
|
+
...(resolvedDispatcher ? { dispatcher: resolvedDispatcher } : {}),
|
|
180
191
|
}),
|
|
181
192
|
};
|
|
182
193
|
const response = await ctx.options.polyfill(url, _options);
|
|
@@ -481,7 +492,8 @@ async function handleZaloResponse(ctx, response, isEncrypted = true) {
|
|
|
481
492
|
result.data = {};
|
|
482
493
|
return result;
|
|
483
494
|
}
|
|
484
|
-
const
|
|
495
|
+
const safeJsonStr = isEncrypted ? wsCipher.preParseJsonIds(decodedStr) : null;
|
|
496
|
+
const decodedData = isEncrypted ? JSON.parse(safeJsonStr) : jsonData;
|
|
485
497
|
if (decodedData.error_code != 0) {
|
|
486
498
|
result.error = {
|
|
487
499
|
message: decodedData.error_message,
|
|
@@ -554,6 +566,11 @@ exports.decryptResp = aes.decryptResp;
|
|
|
554
566
|
exports.encodeAES = aes.encodeAES;
|
|
555
567
|
exports.encryptPin = aes.encryptPin;
|
|
556
568
|
exports.validatePin = aes.validatePin;
|
|
569
|
+
exports.DEFAULT_BIGINT_ID_FIELDS = wsCipher.DEFAULT_BIGINT_ID_FIELDS;
|
|
570
|
+
exports.decodeBase64ToBuffer = wsCipher.decodeBase64ToBuffer;
|
|
571
|
+
exports.decodeEventData = wsCipher.decodeEventData;
|
|
572
|
+
exports.decodeUnit8Array = wsCipher.decodeUnit8Array;
|
|
573
|
+
exports.preParseJsonIds = wsCipher.preParseJsonIds;
|
|
557
574
|
exports.apiFactory = apiFactory;
|
|
558
575
|
exports.formatTime = formatTime;
|
|
559
576
|
exports.generateZaloUUID = generateZaloUUID;
|
|
@@ -64,4 +64,17 @@ export declare const ZALO_ENDPOINTS: {
|
|
|
64
64
|
readonly LIST: "/api/recentsearch/list";
|
|
65
65
|
readonly UPDATE: "/api/recentsearch/update";
|
|
66
66
|
};
|
|
67
|
+
readonly GROUP: {
|
|
68
|
+
readonly GET_LIST_V3: "/api/group/getlg/v3";
|
|
69
|
+
readonly GET_LIST_V4: "/api/group/getlg/v4";
|
|
70
|
+
readonly GET_INFO_V1: "/api/group/getgi";
|
|
71
|
+
readonly GET_INFO_V2: "/api/group/getgi/v2";
|
|
72
|
+
readonly GET_MULTI_INFO_V1: "/api/group/getmg";
|
|
73
|
+
readonly GET_MULTI_INFO_V2: "/api/group/getmg-v2";
|
|
74
|
+
readonly GET_STATUS_MSG: "/api/group/getStatusMsg";
|
|
75
|
+
readonly HISTORY_LEGACY: "/api/group/history";
|
|
76
|
+
readonly CLOUD_MSG_RECENT_V2: "/api/cm/getrecentv2";
|
|
77
|
+
readonly CLOUD_MSG_OLD_V2: "/api/cm/getoldv2";
|
|
78
|
+
readonly CLOUD_MSG_JUMP_V2: "/api/cm/rgetv2";
|
|
79
|
+
};
|
|
67
80
|
};
|
|
@@ -64,4 +64,17 @@ export const ZALO_ENDPOINTS = {
|
|
|
64
64
|
LIST: "/api/recentsearch/list",
|
|
65
65
|
UPDATE: "/api/recentsearch/update",
|
|
66
66
|
},
|
|
67
|
+
GROUP: {
|
|
68
|
+
GET_LIST_V3: "/api/group/getlg/v3",
|
|
69
|
+
GET_LIST_V4: "/api/group/getlg/v4",
|
|
70
|
+
GET_INFO_V1: "/api/group/getgi",
|
|
71
|
+
GET_INFO_V2: "/api/group/getgi/v2",
|
|
72
|
+
GET_MULTI_INFO_V1: "/api/group/getmg",
|
|
73
|
+
GET_MULTI_INFO_V2: "/api/group/getmg-v2",
|
|
74
|
+
GET_STATUS_MSG: "/api/group/getStatusMsg",
|
|
75
|
+
HISTORY_LEGACY: "/api/group/history",
|
|
76
|
+
CLOUD_MSG_RECENT_V2: "/api/cm/getrecentv2",
|
|
77
|
+
CLOUD_MSG_OLD_V2: "/api/cm/getoldv2",
|
|
78
|
+
CLOUD_MSG_JUMP_V2: "/api/cm/rgetv2",
|
|
79
|
+
},
|
|
67
80
|
};
|
|
@@ -10,7 +10,7 @@ export declare const ZALO_PROTOCOL: {
|
|
|
10
10
|
readonly API_VERSION: 689;
|
|
11
11
|
readonly DEFAULT_API_VERSION: 689;
|
|
12
12
|
/** Phiên bản SDK hiện tại */
|
|
13
|
-
readonly SDK_VERSION: "2.3.
|
|
13
|
+
readonly SDK_VERSION: "2.3.4";
|
|
14
14
|
/** Mã zpw_type đặc thù dành riêng cho phân hệ Gọi Thoại & Video (binary C++ ZaloCall) */
|
|
15
15
|
readonly VOICECALL_API_TYPE: 24;
|
|
16
16
|
/** Phiên bản mã hóa ZCID (ParamDecryptor) */
|
|
@@ -10,7 +10,7 @@ export const ZALO_PROTOCOL = {
|
|
|
10
10
|
API_VERSION: 689,
|
|
11
11
|
DEFAULT_API_VERSION: 689,
|
|
12
12
|
/** Phiên bản SDK hiện tại */
|
|
13
|
-
SDK_VERSION: "2.3.
|
|
13
|
+
SDK_VERSION: "2.3.4",
|
|
14
14
|
/** Mã zpw_type đặc thù dành riêng cho phân hệ Gọi Thoại & Video (binary C++ ZaloCall) */
|
|
15
15
|
VOICECALL_API_TYPE: 24,
|
|
16
16
|
/** Phiên bản mã hóa ZCID (ParamDecryptor) */
|
package/dist/context.d.ts
CHANGED
|
@@ -154,18 +154,28 @@ export type Options = {
|
|
|
154
154
|
apiType: number;
|
|
155
155
|
apiVersion: number;
|
|
156
156
|
agent?: Agent;
|
|
157
|
+
/**
|
|
158
|
+
* Bộ điều phối kết nối (Undici `Dispatcher` / `ProxyAgent`) dành cho `globalThis.fetch` mặc định của Node.js 18+.
|
|
159
|
+
*/
|
|
160
|
+
dispatcher?: unknown;
|
|
157
161
|
/**
|
|
158
162
|
* Optional fetch implementation for polyfills in non-standard environments.
|
|
159
163
|
* If using proxy, `node-fetch` is highly recommended.
|
|
160
164
|
*/
|
|
161
165
|
polyfill: typeof fetch;
|
|
162
166
|
imageMetadataGetter?: ImageMetadataGetter;
|
|
167
|
+
/**
|
|
168
|
+
* Thời gian chờ tối đa cho mỗi HTTP request tính bằng mili-giây (mặc định: `30000`ms = 30s, đặt `0` để tắt).
|
|
169
|
+
*/
|
|
170
|
+
requestTimeout?: number;
|
|
163
171
|
};
|
|
164
172
|
declare class CallbacksMap extends Map<string, UploadCallback> {
|
|
173
|
+
private timers;
|
|
165
174
|
/**
|
|
166
175
|
* @param ttl Time to live in milliseconds. Default is 5 minutes.
|
|
167
176
|
*/
|
|
168
177
|
set(key: string, value: UploadCallback, ttl?: number): this;
|
|
178
|
+
delete(key: string): boolean;
|
|
169
179
|
}
|
|
170
180
|
export type ViewerKeyCacheEntry = {
|
|
171
181
|
viewer_key: string;
|
package/dist/context.js
CHANGED
|
@@ -1,15 +1,32 @@
|
|
|
1
1
|
import { ZALO_DEFAULTS, ZALO_PROTOCOL } from "./constants/index.js";
|
|
2
2
|
const _5_MINUTES = ZALO_DEFAULTS.UPLOAD.CALLBACK_TTL_MS;
|
|
3
3
|
class CallbacksMap extends Map {
|
|
4
|
+
timers = new Map();
|
|
4
5
|
/**
|
|
5
6
|
* @param ttl Time to live in milliseconds. Default is 5 minutes.
|
|
6
7
|
*/
|
|
7
8
|
set(key, value, ttl = _5_MINUTES) {
|
|
8
|
-
|
|
9
|
-
|
|
9
|
+
const existing = this.timers.get(key);
|
|
10
|
+
if (existing)
|
|
11
|
+
clearTimeout(existing);
|
|
12
|
+
const timer = setTimeout(() => {
|
|
13
|
+
this.timers.delete(key);
|
|
14
|
+
super.delete(key);
|
|
10
15
|
}, ttl);
|
|
16
|
+
if (typeof timer === "object" && timer !== null && "unref" in timer && typeof timer.unref === "function") {
|
|
17
|
+
timer.unref();
|
|
18
|
+
}
|
|
19
|
+
this.timers.set(key, timer);
|
|
11
20
|
return super.set(key, value);
|
|
12
21
|
}
|
|
22
|
+
delete(key) {
|
|
23
|
+
const existing = this.timers.get(key);
|
|
24
|
+
if (existing) {
|
|
25
|
+
clearTimeout(existing);
|
|
26
|
+
this.timers.delete(key);
|
|
27
|
+
}
|
|
28
|
+
return super.delete(key);
|
|
29
|
+
}
|
|
13
30
|
}
|
|
14
31
|
export const createContext = (apiType = ZALO_PROTOCOL.API_TYPE, apiVersion = ZALO_PROTOCOL.API_VERSION) => ({
|
|
15
32
|
API_TYPE: apiType,
|
|
@@ -20,6 +37,7 @@ export const createContext = (apiType = ZALO_PROTOCOL.API_TYPE, apiVersion = ZAL
|
|
|
20
37
|
checkUpdate: ZALO_DEFAULTS.OPTIONS.CHECK_UPDATE,
|
|
21
38
|
logging: ZALO_DEFAULTS.OPTIONS.LOGGING,
|
|
22
39
|
polyfill: global.fetch,
|
|
40
|
+
requestTimeout: 30000,
|
|
23
41
|
},
|
|
24
42
|
secretKey: null,
|
|
25
43
|
});
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
export declare const DEFAULT_BIGINT_ID_FIELDS: readonly ["owner_id", "group_id", "uidFrom", "uidTo", "uid", "ownerId", "destId", "srcId", "fromUid", "threadId", "globalMsgId", "global_msg_id", "globalDelMsgId", "msgId", "refMessageId", "cliMsgId", "client_msg_id", "actionId", "lastActionIdOther", "lastActionId", "resetLastActionId", "lastId", "ids", "topicId", "reminderId", "eventId"];
|
|
2
|
+
/**
|
|
3
|
+
* Tiền xử lý chuỗi JSON trước khi `JSON.parse` (tương đương `preParse(e, t)` trong `app.asar` của Zalo PC).
|
|
4
|
+
* Bọc dấu ngoặc kép quanh các trường định danh 64-bit (`owner_id`, `group_id`, hoặc các số nguyên >= 16 chữ số
|
|
5
|
+
* vượt quá `Number.MAX_SAFE_INTEGER`) để tránh mất 3 chữ số cuối của UID/MsgId do làm tròn IEEE-754.
|
|
6
|
+
*/
|
|
7
|
+
export declare function preParseJsonIds(jsonStr: string, alwaysStringFields?: readonly string[], bigIntSafeFields?: readonly string[]): string;
|
|
1
8
|
export declare function decodeBase64ToBuffer(data: string): Buffer;
|
|
2
9
|
export declare function decodeUnit8Array(data: Uint8Array): string | null;
|
|
3
10
|
export declare function decodeEventData(parsed: Record<string, unknown>, cipherKey?: string): Promise<any>;
|
package/dist/crypto/ws-cipher.js
CHANGED
|
@@ -2,6 +2,68 @@ import crypto from "node:crypto";
|
|
|
2
2
|
import pako from "pako";
|
|
3
3
|
import JSONBig from "json-bigint";
|
|
4
4
|
import { ZaloApiError } from "../Errors/index.js";
|
|
5
|
+
const jsonBigString = JSONBig({ storeAsString: true });
|
|
6
|
+
export const DEFAULT_BIGINT_ID_FIELDS = [
|
|
7
|
+
"owner_id",
|
|
8
|
+
"group_id",
|
|
9
|
+
"uidFrom",
|
|
10
|
+
"uidTo",
|
|
11
|
+
"uid",
|
|
12
|
+
"ownerId",
|
|
13
|
+
"destId",
|
|
14
|
+
"srcId",
|
|
15
|
+
"fromUid",
|
|
16
|
+
"threadId",
|
|
17
|
+
"globalMsgId",
|
|
18
|
+
"global_msg_id",
|
|
19
|
+
"globalDelMsgId",
|
|
20
|
+
"msgId",
|
|
21
|
+
"refMessageId",
|
|
22
|
+
"cliMsgId",
|
|
23
|
+
"client_msg_id",
|
|
24
|
+
"actionId",
|
|
25
|
+
"lastActionIdOther",
|
|
26
|
+
"lastActionId",
|
|
27
|
+
"resetLastActionId",
|
|
28
|
+
"lastId",
|
|
29
|
+
"ids",
|
|
30
|
+
"topicId",
|
|
31
|
+
"reminderId",
|
|
32
|
+
"eventId",
|
|
33
|
+
];
|
|
34
|
+
/**
|
|
35
|
+
* Tiền xử lý chuỗi JSON trước khi `JSON.parse` (tương đương `preParse(e, t)` trong `app.asar` của Zalo PC).
|
|
36
|
+
* Bọc dấu ngoặc kép quanh các trường định danh 64-bit (`owner_id`, `group_id`, hoặc các số nguyên >= 16 chữ số
|
|
37
|
+
* vượt quá `Number.MAX_SAFE_INTEGER`) để tránh mất 3 chữ số cuối của UID/MsgId do làm tròn IEEE-754.
|
|
38
|
+
*/
|
|
39
|
+
export function preParseJsonIds(jsonStr, alwaysStringFields = ["owner_id", "group_id"], bigIntSafeFields = DEFAULT_BIGINT_ID_FIELDS) {
|
|
40
|
+
if (!jsonStr || typeof jsonStr !== "string")
|
|
41
|
+
return jsonStr;
|
|
42
|
+
const alwaysSet = new Set(alwaysStringFields);
|
|
43
|
+
const allFields = Array.from(new Set([...alwaysStringFields, ...bigIntSafeFields]));
|
|
44
|
+
if (allFields.length === 0)
|
|
45
|
+
return jsonStr;
|
|
46
|
+
const escapedKeys = allFields.map((k) => k.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|");
|
|
47
|
+
const keyValueRegex = new RegExp(`"(${escapedKeys})"(\\s*:\\s*)(\\d+|\\[\\s*\\d+(?:\\s*,\\s*\\d+)*\\s*\\])`, "g");
|
|
48
|
+
return jsonStr.replace(keyValueRegex, (fullMatch, key, sep, rawVal) => {
|
|
49
|
+
const forceString = alwaysSet.has(key);
|
|
50
|
+
if (rawVal.startsWith("[")) {
|
|
51
|
+
const inner = rawVal.slice(1, -1);
|
|
52
|
+
const parts = inner.split(",").map((part) => {
|
|
53
|
+
const trimmed = part.trim();
|
|
54
|
+
if (forceString || trimmed.length >= 16 || Number(trimmed) > Number.MAX_SAFE_INTEGER) {
|
|
55
|
+
return `"${trimmed}"`;
|
|
56
|
+
}
|
|
57
|
+
return trimmed;
|
|
58
|
+
});
|
|
59
|
+
return `"${key}"${sep}[${parts.join(",")}]`;
|
|
60
|
+
}
|
|
61
|
+
if (forceString || rawVal.length >= 16 || Number(rawVal) > Number.MAX_SAFE_INTEGER) {
|
|
62
|
+
return `"${key}"${sep}"${rawVal}"`;
|
|
63
|
+
}
|
|
64
|
+
return fullMatch;
|
|
65
|
+
});
|
|
66
|
+
}
|
|
5
67
|
export function decodeBase64ToBuffer(data) {
|
|
6
68
|
return Buffer.from(data, "base64");
|
|
7
69
|
}
|
|
@@ -23,7 +85,7 @@ export async function decodeEventData(parsed, cipherKey) {
|
|
|
23
85
|
const rawData = parsed.data;
|
|
24
86
|
const encryptType = parsed.encrypt;
|
|
25
87
|
if (encryptType === 0)
|
|
26
|
-
return
|
|
88
|
+
return jsonBigString.parse(preParseJsonIds(rawData));
|
|
27
89
|
const decodedBuffer = decodeBase64ToBuffer(encryptType === 1 ? rawData : decodeURIComponent(rawData));
|
|
28
90
|
let decryptedBuffer = decodedBuffer;
|
|
29
91
|
if (encryptType !== 1) {
|
|
@@ -48,5 +110,5 @@ export async function decodeEventData(parsed, cipherKey) {
|
|
|
48
110
|
const decodedData = decodeUnit8Array(decompressedBuffer);
|
|
49
111
|
if (!decodedData)
|
|
50
112
|
return;
|
|
51
|
-
return
|
|
113
|
+
return jsonBigString.parse(preParseJsonIds(decodedData));
|
|
52
114
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -68,8 +68,27 @@ export type { GetFriendRecommendationsResponse, FriendRecommendationsCollapseMsg
|
|
|
68
68
|
export type { GetFriendRequestStatusResponse } from "./apis/friend/getFriendRequestStatus.js";
|
|
69
69
|
export type { GetFullAvatarResponse } from "./apis/profile/getFullAvatar.js";
|
|
70
70
|
export type { GetGroupBlockedMemberPayload, GetGroupBlockedMemberResponse } from "./apis/group/getGroupBlockedMember.js";
|
|
71
|
-
export type { GetGroupChatHistoryResponse } from "./apis/group/getGroupChatHistory.js";
|
|
71
|
+
export type { GetGroupChatHistoryOptions, GetGroupChatHistoryResponse } from "./apis/group/getGroupChatHistory.js";
|
|
72
|
+
export type { GetGroupHistoryLegacyResponse } from "./apis/group/getGroupHistoryLegacy.js";
|
|
72
73
|
export type { GroupInfoPendingApprove, GroupInfoResponse } from "./apis/group/getGroupInfo.js";
|
|
74
|
+
export type { GetGroupInfoV2Options, GetGroupInfoV2Response } from "./apis/group/getGroupInfoV2.js";
|
|
75
|
+
export type { GetGroupListV3Options, GetGroupListV3Response } from "./apis/group/getGroupListV3.js";
|
|
76
|
+
export type { GetGroupMessageStatusQueryItem, GetGroupMessageStatusResponse, GroupMessageStatusMemberItem, GroupMessageStatusThreadInfo, } from "./apis/group/getGroupMessageStatus.js";
|
|
77
|
+
export type { CheckQuotaCommunityMemberResponse } from "./apis/group/checkQuotaCommunityMember.js";
|
|
78
|
+
export type { GetE2eeGroupListResponse } from "./apis/group/getE2eeGroupList.js";
|
|
79
|
+
export type { GetMultiGroupCloudMessagesResponse } from "./apis/group/getMultiGroupCloudMessages.js";
|
|
80
|
+
export type { GetGroupCloudMessagePathOptions, GetGroupCloudMessagePathResponse } from "./apis/group/getGroupCloudMessagePath.js";
|
|
81
|
+
export type { AnalyseGroupResponse } from "./apis/group/analyseGroup.js";
|
|
82
|
+
export type { DirectMessageStatusItem, GetDirectMessageStatusResponse } from "./apis/chat/getDirectMessageStatus.js";
|
|
83
|
+
export type { GetSuggestedConversationsResponse } from "./apis/chat/getSuggestedConversations.js";
|
|
84
|
+
export type { UpdatePinConversationsOptions, UpdatePinConversationsResponse } from "./apis/chat/updatePinConversations.js";
|
|
85
|
+
export type { GetFriendProfilesV2Options, GetFriendProfilesV2Response } from "./apis/friend/getFriendProfilesV2.js";
|
|
86
|
+
export type { GetFriendsActivePCWebResponse } from "./apis/friend/getFriendsActivePCWeb.js";
|
|
87
|
+
export type { VerifyFriendOptions, VerifyFriendResponse } from "./apis/friend/verifyFriend.js";
|
|
88
|
+
export type { GetPersonalMediaOptions } from "./apis/media/getPersonalMedia.js";
|
|
89
|
+
export type { GetPersonalMediaPreviewResponse } from "./apis/media/getPersonalMediaPreview.js";
|
|
90
|
+
export type { RemovePersonalMediaOptions, RemovePersonalMediaResponse } from "./apis/media/removePersonalMedia.js";
|
|
91
|
+
export type { ExportedSession } from "./apis/auth/exportSession.js";
|
|
73
92
|
export type { GetGroupInviteBoxInfoPayload, GetGroupInviteBoxInfoResponse } from "./apis/group/getGroupInviteBoxInfo.js";
|
|
74
93
|
export type { GetGroupInviteBoxListPayload, GetGroupInviteBoxListResponse } from "./apis/group/getGroupInviteBoxList.js";
|
|
75
94
|
export type { GetGroupLinkDetailResponse } from "./apis/group/getGroupLinkDetail.js";
|
|
@@ -176,7 +195,7 @@ export type { GetBlockFriendsResponse } from "./apis/friend/getBlockFriends.js";
|
|
|
176
195
|
export type { GetCloudInfoResponse } from "./apis/zcloud/getCloudInfo.js";
|
|
177
196
|
export type { GetCloudSettingsResponse } from "./apis/zcloud/getCloudSettings.js";
|
|
178
197
|
export type { GetCloudViewerKeyResponse } from "./apis/zcloud/getCloudViewerKey.js";
|
|
179
|
-
export type { GetConversationMediaOptions, GetConversationMediaResponse } from "./apis/media/getConversationMedia.js";
|
|
198
|
+
export type { GetConversationMediaOptions, GetConversationMediaResponse, MediaStoreItem, MediaStoreType, } from "./apis/media/getConversationMedia.js";
|
|
180
199
|
export type { GetEmojiStatusConfigResponse } from "./apis/profile/getEmojiStatusConfig.js";
|
|
181
200
|
export type { GetExtraFriendInfoResponse } from "./apis/friend/getExtraFriendInfo.js";
|
|
182
201
|
export type { GetExtraGroupInfoResponse } from "./apis/group/getExtraGroupInfo.js";
|
|
@@ -221,4 +240,4 @@ export { ChatTTL } from "./apis/chat/updateAutoDeleteChat.js";
|
|
|
221
240
|
export { UpdateLangAvailableLanguages } from "./apis/auth/updateLang.js";
|
|
222
241
|
export { UpdateSettingsType } from "./apis/profile/updateSettings.js";
|
|
223
242
|
export { CallType } from "./apis/call/sendVoiceCall.js";
|
|
224
|
-
export { generateRSAKeyPair, decryptWithPrivateKey, deriveZdbAesKey, decryptZdbBuffer, parseZdbHeader, encryptZCloudAES, decryptZCloudAES, type ZdbTocEntry, } from "./utils.js";
|
|
243
|
+
export { generateRSAKeyPair, decryptWithPrivateKey, deriveZdbAesKey, decryptZdbBuffer, parseZdbHeader, encryptZCloudAES, decryptZCloudAES, preParseJsonIds, type ZdbTocEntry, } from "./utils.js";
|
package/dist/index.js
CHANGED
|
@@ -16,4 +16,4 @@ export { ChatTTL } from "./apis/chat/updateAutoDeleteChat.js";
|
|
|
16
16
|
export { UpdateLangAvailableLanguages } from "./apis/auth/updateLang.js";
|
|
17
17
|
export { UpdateSettingsType } from "./apis/profile/updateSettings.js";
|
|
18
18
|
export { CallType } from "./apis/call/sendVoiceCall.js";
|
|
19
|
-
export { generateRSAKeyPair, decryptWithPrivateKey, deriveZdbAesKey, decryptZdbBuffer, parseZdbHeader, encryptZCloudAES, decryptZCloudAES, } from "./utils.js";
|
|
19
|
+
export { generateRSAKeyPair, decryptWithPrivateKey, deriveZdbAesKey, decryptZdbBuffer, parseZdbHeader, encryptZCloudAES, decryptZCloudAES, preParseJsonIds, } from "./utils.js";
|
|
@@ -27,6 +27,7 @@ export class Listener extends EventEmitter {
|
|
|
27
27
|
retryTimeout;
|
|
28
28
|
watchdogTimeout;
|
|
29
29
|
consecutive1006Count = 0;
|
|
30
|
+
isManualStop = false;
|
|
30
31
|
id = 0;
|
|
31
32
|
constructor(ctx, urls) {
|
|
32
33
|
super();
|
|
@@ -152,6 +153,7 @@ export class Listener extends EventEmitter {
|
|
|
152
153
|
logger(this.ctx).verbose(`Rotating endpoint to ${this.wsURL}`);
|
|
153
154
|
}
|
|
154
155
|
start({ retryOnClose = false } = {}) {
|
|
156
|
+
this.isManualStop = false;
|
|
155
157
|
if (this.retryTimeout) {
|
|
156
158
|
clearTimeout(this.retryTimeout);
|
|
157
159
|
this.retryTimeout = undefined;
|
|
@@ -175,6 +177,10 @@ export class Listener extends EventEmitter {
|
|
|
175
177
|
t: Date.now(),
|
|
176
178
|
});
|
|
177
179
|
const cookie = this.ctx.cookie.getCookieStringSync(ZALO_DOMAINS.CHAT_WEB);
|
|
180
|
+
const wsAgent = this.ctx.options.agent &&
|
|
181
|
+
typeof this.ctx.options.agent.dispatch !== "function"
|
|
182
|
+
? this.ctx.options.agent
|
|
183
|
+
: undefined;
|
|
178
184
|
const ws = new WebSocket(this.wsURL, {
|
|
179
185
|
headers: {
|
|
180
186
|
"accept-language": getBrowserLanguage(this.ctx.language),
|
|
@@ -189,7 +195,7 @@ export class Listener extends EventEmitter {
|
|
|
189
195
|
"user-agent": this.userAgent,
|
|
190
196
|
cookie,
|
|
191
197
|
},
|
|
192
|
-
agent:
|
|
198
|
+
...(wsAgent ? { agent: wsAgent } : {}),
|
|
193
199
|
});
|
|
194
200
|
this.ws = ws;
|
|
195
201
|
ws.onopen = () => {
|
|
@@ -202,7 +208,8 @@ export class Listener extends EventEmitter {
|
|
|
202
208
|
ws.onclose = (event) => {
|
|
203
209
|
this.reset();
|
|
204
210
|
this.emit("disconnected", event.code, event.reason);
|
|
205
|
-
const retry =
|
|
211
|
+
const retry = !this.isManualStop &&
|
|
212
|
+
retryOnClose &&
|
|
206
213
|
this.isRetryable(event.code) &&
|
|
207
214
|
this.canRetry(event.code);
|
|
208
215
|
if (retry && retryOnClose) {
|
|
@@ -288,19 +295,24 @@ export class Listener extends EventEmitter {
|
|
|
288
295
|
};
|
|
289
296
|
}
|
|
290
297
|
stop() {
|
|
291
|
-
|
|
298
|
+
this.isManualStop = true;
|
|
299
|
+
if (this.retryTimeout) {
|
|
292
300
|
clearTimeout(this.retryTimeout);
|
|
293
|
-
|
|
301
|
+
this.retryTimeout = undefined;
|
|
302
|
+
}
|
|
303
|
+
if (this.watchdogTimeout) {
|
|
294
304
|
clearTimeout(this.watchdogTimeout);
|
|
305
|
+
this.watchdogTimeout = undefined;
|
|
306
|
+
}
|
|
295
307
|
if (this.ws) {
|
|
296
|
-
if (this.ws.readyState !== WebSocket.CLOSED) {
|
|
308
|
+
if (this.ws.readyState !== WebSocket.CLOSED && this.ws.readyState !== WebSocket.CLOSING) {
|
|
297
309
|
this.ws.close(CloseReason.ManualClosure);
|
|
298
310
|
}
|
|
299
311
|
}
|
|
300
312
|
this.reset();
|
|
301
313
|
}
|
|
302
314
|
sendWs(payload, requireId = true) {
|
|
303
|
-
if (this.ws) {
|
|
315
|
+
if (this.ws && (this.ws.readyState === undefined || this.ws.readyState === WebSocket.OPEN)) {
|
|
304
316
|
if (requireId)
|
|
305
317
|
payload.data["req_id"] = `req_${this.id++}`;
|
|
306
318
|
const encodedData = new TextEncoder().encode(JSON.stringify(payload.data));
|
package/dist/update.js
CHANGED
|
@@ -6,6 +6,9 @@ const NPM_REGISTRY = ZALO_DOMAINS.NPM_REGISTRY;
|
|
|
6
6
|
export async function checkUpdate(ctx) {
|
|
7
7
|
if (!ctx.options.checkUpdate)
|
|
8
8
|
return;
|
|
9
|
+
const isAgentUndiciDispatcher = Boolean(ctx.options.agent && typeof ctx.options.agent.dispatch === "function");
|
|
10
|
+
const resolvedDispatcher = ctx.options.dispatcher ?? (isAgentUndiciDispatcher ? ctx.options.agent : undefined);
|
|
11
|
+
const resolvedAgent = ctx.options.agent && !isAgentUndiciDispatcher ? ctx.options.agent : undefined;
|
|
9
12
|
const _options = {
|
|
10
13
|
...(isBun
|
|
11
14
|
? {
|
|
@@ -13,7 +16,13 @@ export async function checkUpdate(ctx) {
|
|
|
13
16
|
// @ts-ignore
|
|
14
17
|
proxy: ctx.options.agent?.proxy?.href,
|
|
15
18
|
}
|
|
16
|
-
: {
|
|
19
|
+
: {
|
|
20
|
+
...(resolvedAgent ? { agent: resolvedAgent } : {}),
|
|
21
|
+
...(resolvedDispatcher ? { dispatcher: resolvedDispatcher } : {}),
|
|
22
|
+
}),
|
|
23
|
+
...(typeof AbortSignal !== "undefined" && typeof AbortSignal.timeout === "function"
|
|
24
|
+
? { signal: AbortSignal.timeout(3000) }
|
|
25
|
+
: {}),
|
|
17
26
|
};
|
|
18
27
|
const response = await ctx.options.polyfill(NPM_REGISTRY, _options).catch(() => null);
|
|
19
28
|
if (!response || !response.ok)
|
package/dist/utils.js
CHANGED
|
@@ -9,7 +9,7 @@ import { ZaloApiError, ZaloApiMissingImageMetadataGetter } from "./Errors/index.
|
|
|
9
9
|
import { FriendEventType } from "./models/FriendEvent.js";
|
|
10
10
|
import { GroupEventType } from "./models/GroupEvent.js";
|
|
11
11
|
import { ZALO_DEFAULTS, ZALO_DOMAINS, ZALO_PROTOCOL } from "./constants/index.js";
|
|
12
|
-
import { decodeAES, encodeAES } from "./crypto/index.js";
|
|
12
|
+
import { decodeAES, encodeAES, preParseJsonIds } from "./crypto/index.js";
|
|
13
13
|
export * from "./constants/index.js";
|
|
14
14
|
export * from "./crypto/index.js";
|
|
15
15
|
export * from "./core/index.js";
|
|
@@ -161,8 +161,20 @@ export async function request(ctx, url, options, raw = false) {
|
|
|
161
161
|
options = { ...(options || {}), headers: defaultHeaders };
|
|
162
162
|
}
|
|
163
163
|
}
|
|
164
|
+
const timeoutMs = ctx.options?.requestTimeout;
|
|
165
|
+
const defaultSignal = !options?.signal &&
|
|
166
|
+
typeof timeoutMs === "number" &&
|
|
167
|
+
timeoutMs > 0 &&
|
|
168
|
+
typeof AbortSignal !== "undefined" &&
|
|
169
|
+
typeof AbortSignal.timeout === "function"
|
|
170
|
+
? AbortSignal.timeout(timeoutMs)
|
|
171
|
+
: undefined;
|
|
172
|
+
const isAgentUndiciDispatcher = Boolean(ctx.options.agent && typeof ctx.options.agent.dispatch === "function");
|
|
173
|
+
const resolvedDispatcher = ctx.options.dispatcher ?? (isAgentUndiciDispatcher ? ctx.options.agent : undefined);
|
|
174
|
+
const resolvedAgent = ctx.options.agent && !isAgentUndiciDispatcher ? ctx.options.agent : undefined;
|
|
164
175
|
const _options = {
|
|
165
176
|
...(options ?? {}),
|
|
177
|
+
...(defaultSignal ? { signal: defaultSignal } : {}),
|
|
166
178
|
...(isBun
|
|
167
179
|
? {
|
|
168
180
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
@@ -170,8 +182,8 @@ export async function request(ctx, url, options, raw = false) {
|
|
|
170
182
|
proxy: ctx.options.agent?.proxy?.href,
|
|
171
183
|
}
|
|
172
184
|
: {
|
|
173
|
-
agent:
|
|
174
|
-
dispatcher:
|
|
185
|
+
...(resolvedAgent ? { agent: resolvedAgent } : {}),
|
|
186
|
+
...(resolvedDispatcher ? { dispatcher: resolvedDispatcher } : {}),
|
|
175
187
|
}),
|
|
176
188
|
};
|
|
177
189
|
const response = await ctx.options.polyfill(url, _options);
|
|
@@ -476,7 +488,8 @@ export async function handleZaloResponse(ctx, response, isEncrypted = true) {
|
|
|
476
488
|
result.data = {};
|
|
477
489
|
return result;
|
|
478
490
|
}
|
|
479
|
-
const
|
|
491
|
+
const safeJsonStr = isEncrypted ? preParseJsonIds(decodedStr) : null;
|
|
492
|
+
const decodedData = isEncrypted ? JSON.parse(safeJsonStr) : jsonData;
|
|
480
493
|
if (decodedData.error_code != 0) {
|
|
481
494
|
result.error = {
|
|
482
495
|
message: decodedData.error_message,
|
package/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export * from "./dist";
|
|
1
|
+
export * from "./dist/index.js";
|
|
2
2
|
export as namespace Zalo;
|
package/package.json
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@softtynet/zca-js",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.4",
|
|
4
4
|
"description": "Zalo API client library for Node.js and Bun, maintained by Softtynet.",
|
|
5
|
-
"main": "dist/index.
|
|
5
|
+
"main": "dist/cjs/index.cjs",
|
|
6
|
+
"module": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
6
8
|
"type": "module",
|
|
7
9
|
"files": [
|
|
8
10
|
"dist",
|
|
@@ -12,8 +14,9 @@
|
|
|
12
14
|
],
|
|
13
15
|
"exports": {
|
|
14
16
|
".": {
|
|
17
|
+
"types": "./dist/index.d.ts",
|
|
18
|
+
"import": "./dist/index.js",
|
|
15
19
|
"require": "./dist/cjs/index.cjs",
|
|
16
|
-
"types": "./index.d.ts",
|
|
17
20
|
"default": "./dist/index.js"
|
|
18
21
|
}
|
|
19
22
|
},
|
|
@@ -23,8 +26,14 @@
|
|
|
23
26
|
"build:esm": "tsc",
|
|
24
27
|
"build:cjs": "rollup -c rollup.config.js",
|
|
25
28
|
"build": "npm run build:clean && npm run build:esm && npm run build:cjs",
|
|
26
|
-
"
|
|
29
|
+
"typecheck": "tsc --noEmit && tsc -p test/tsconfig.json --noEmit && tsc -p examples/tsconfig.json --noEmit && tsc -p docs/tsconfig.json --noEmit",
|
|
30
|
+
"test:verify": "npm run typecheck && npx --yes tsx test/verify_upgrades.ts",
|
|
27
31
|
"test:live": "npx --yes tsx test/verify_live.ts",
|
|
32
|
+
"docs:gen": "node scripts/generateDocs.js",
|
|
33
|
+
"docs:dev": "node scripts/generateDocs.js && vitepress dev docs",
|
|
34
|
+
"docs:build": "node scripts/generateDocs.js && vitepress build docs",
|
|
35
|
+
"docs:preview": "vitepress preview docs",
|
|
36
|
+
"docs:deploy": "node scripts/deployDocs.js",
|
|
28
37
|
"prettier": "prettier --write .",
|
|
29
38
|
"lint": "eslint .",
|
|
30
39
|
"lint:fix": "eslint . --fix",
|
|
@@ -79,7 +88,8 @@
|
|
|
79
88
|
"rimraf": "^5.0.10",
|
|
80
89
|
"rollup": "^4.24.0",
|
|
81
90
|
"typescript": "^5.5.3",
|
|
82
|
-
"typescript-eslint": "^8.41.0"
|
|
91
|
+
"typescript-eslint": "^8.41.0",
|
|
92
|
+
"vitepress": "^1.6.4"
|
|
83
93
|
},
|
|
84
94
|
"lint-staged": {
|
|
85
95
|
"*.{js,ts}": "eslint"
|