@softtynet/zca-js 2.3.6 → 2.3.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -2
- package/dist/apis/business/blockOA.d.ts +2 -0
- package/dist/apis/business/blockOA.js +28 -0
- package/dist/apis/business/convertOAIds.d.ts +4 -0
- package/dist/apis/business/convertOAIds.js +26 -0
- package/dist/apis/business/getOAProfile.d.ts +13 -0
- package/dist/apis/business/getOAProfile.js +64 -0
- package/dist/apis/business/unblockOA.d.ts +2 -0
- package/dist/apis/business/unblockOA.js +28 -0
- package/dist/apis/chat/preloadConversations.d.ts +3 -2
- package/dist/apis/chat/preloadConversations.js +14 -0
- package/dist/apis/sync/getSyncData.js +1 -1
- package/dist/apis.d.ts +12 -0
- package/dist/apis.js +20 -0
- package/dist/cjs/apis/business/blockOA.cjs +33 -0
- package/dist/cjs/apis/business/convertOAIds.cjs +31 -0
- package/dist/cjs/apis/business/getOAProfile.cjs +69 -0
- package/dist/cjs/apis/business/unblockOA.cjs +33 -0
- package/dist/cjs/apis/chat/preloadConversations.cjs +14 -0
- package/dist/cjs/apis/sync/getSyncData.cjs +20 -1
- package/dist/cjs/apis.cjs +20 -0
- package/dist/cjs/constants/defaults.cjs +2 -2
- package/dist/cjs/constants/protocol.cjs +1 -1
- package/dist/cjs/index.cjs +10 -0
- package/dist/cjs/models/Message.cjs +16 -1
- package/dist/cjs/models/OAMessage.cjs +375 -0
- package/dist/cjs/realtime/handlers/control.handler.cjs +9 -1
- package/dist/cjs/realtime/handlers/message.handler.cjs +103 -37
- package/dist/cjs/realtime/listener.cjs +39 -18
- package/dist/cjs/utils.cjs +21 -2
- package/dist/cjs/zalo.cjs +21 -2
- package/dist/constants/defaults.d.ts +2 -2
- package/dist/constants/defaults.js +2 -2
- package/dist/constants/protocol.d.ts +1 -1
- package/dist/constants/protocol.js +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/models/Message.d.ts +12 -1
- package/dist/models/Message.js +16 -1
- package/dist/models/OAMessage.d.ts +221 -0
- package/dist/models/OAMessage.js +363 -0
- package/dist/models/index.d.ts +1 -0
- package/dist/models/index.js +1 -0
- package/dist/realtime/handlers/control.handler.js +9 -1
- package/dist/realtime/handlers/message.handler.js +103 -37
- package/dist/realtime/listener.d.ts +9 -3
- package/dist/realtime/listener.js +39 -18
- package/dist/realtime/types.d.ts +15 -1
- package/dist/utils.js +1 -1
- package/dist/zalo.d.ts +1 -1
- package/dist/zalo.js +1 -1
- package/package.json +2 -1
|
@@ -17,64 +17,130 @@ require('../../models/CallEvent.cjs');
|
|
|
17
17
|
var utils = require('../../utils.cjs');
|
|
18
18
|
var wsCipher = require('../../crypto/ws-cipher.cjs');
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
20
|
+
function processIncomingUserMessages(listener, ctx, selfListen, onMessageCallback, messages, isPageMsg = false) {
|
|
21
|
+
for (const msg of messages) {
|
|
22
|
+
if (!msg)
|
|
23
|
+
continue;
|
|
24
|
+
if (typeof msg.content == "object" && msg.content !== null && utils.hasOwn(msg.content, "deleteMsg")) {
|
|
25
|
+
const undoObject = new Undo.Undo(ctx.uid, msg, false);
|
|
26
|
+
if (undoObject.isSelf && !selfListen)
|
|
27
|
+
continue;
|
|
28
|
+
listener.emit("undo", undoObject);
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
const messageObject = new Message.UserMessage(ctx.uid, msg, isPageMsg);
|
|
32
|
+
if (messageObject.isSelf && !selfListen)
|
|
33
|
+
continue;
|
|
34
|
+
onMessageCallback(messageObject);
|
|
35
|
+
listener.emit("message", messageObject);
|
|
36
|
+
if (messageObject.isOAMessage()) {
|
|
37
|
+
listener.emit("oa_message", messageObject);
|
|
37
38
|
}
|
|
38
39
|
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function processIncomingGroupMessages(listener, ctx, selfListen, onMessageCallback, groupMessages) {
|
|
43
|
+
for (const msg of groupMessages) {
|
|
44
|
+
if (!msg)
|
|
45
|
+
continue;
|
|
46
|
+
if (typeof msg.content == "object" && msg.content !== null && utils.hasOwn(msg.content, "deleteMsg")) {
|
|
47
|
+
const undoObject = new Undo.Undo(ctx.uid, msg, true);
|
|
48
|
+
if (undoObject.isSelf && !selfListen)
|
|
49
|
+
continue;
|
|
50
|
+
listener.emit("undo", undoObject);
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
const messageObject = new Message.GroupMessage(ctx.uid, msg);
|
|
54
|
+
if (messageObject.isSelf && !selfListen)
|
|
55
|
+
continue;
|
|
56
|
+
onMessageCallback(messageObject);
|
|
57
|
+
listener.emit("message", messageObject);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
async function handleRealtimeMessagePacket(listener, ctx, selfListen, onMessageCallback, version, cmd, subCmd, parsed, cipherKey) {
|
|
62
|
+
if (version == 1 && [501, 551].includes(cmd) && subCmd == 0) {
|
|
63
|
+
const decoded = await wsCipher.decodeEventData(parsed, cipherKey);
|
|
64
|
+
const parsedData = decoded?.data ?? decoded;
|
|
65
|
+
const msgs = (Array.isArray(parsedData?.msgs) ? parsedData.msgs : []);
|
|
66
|
+
const pageMsgs = (Array.isArray(parsedData?.pageMsgs) ? parsedData.pageMsgs : []);
|
|
67
|
+
if (msgs.length > 0)
|
|
68
|
+
processIncomingUserMessages(listener, ctx, selfListen, onMessageCallback, msgs, false);
|
|
69
|
+
if (pageMsgs.length > 0)
|
|
70
|
+
processIncomingUserMessages(listener, ctx, selfListen, onMessageCallback, pageMsgs, true);
|
|
39
71
|
return true;
|
|
40
72
|
}
|
|
41
73
|
if (version == 1 && cmd == 521 && subCmd == 0) {
|
|
42
|
-
const
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
74
|
+
const decoded = await wsCipher.decodeEventData(parsed, cipherKey);
|
|
75
|
+
const parsedData = decoded?.data ?? decoded;
|
|
76
|
+
const groupMsgs = (Array.isArray(parsedData?.groupMsgs) ? parsedData.groupMsgs : []);
|
|
77
|
+
processIncomingGroupMessages(listener, ctx, selfListen, onMessageCallback, groupMsgs);
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
// HAS_MSG (cmd = 533): Server báo có tin nhắn đang chờ (thường gặp với OA / Missed Queue) -> kéo ngay qua cmd = 570 (GET_MSG)
|
|
81
|
+
if (cmd == 533 && subCmd == 0) {
|
|
82
|
+
const decoded = await wsCipher.decodeEventData(parsed, cipherKey);
|
|
83
|
+
const parsedData = (decoded?.data ?? decoded);
|
|
84
|
+
if (parsedData?.queueId && Array.isArray(parsedData.ids) && parsedData.ids.length > 0) {
|
|
85
|
+
listener.requestMessagesByIds(parsedData.queueId, parsedData.ids);
|
|
86
|
+
}
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
// PUSH_MISS_MSG (cmd = 534) & GET_MSG (cmd = 570): Gói tin trả về các tin nhắn OA (`pageMsgs`), User (`msgs`) và Group (`groupMsgs`)
|
|
90
|
+
if ((cmd == 534 || cmd == 570) && subCmd == 0) {
|
|
91
|
+
const decoded = await wsCipher.decodeEventData(parsed, cipherKey);
|
|
92
|
+
const parsedData = decoded?.data ?? decoded;
|
|
93
|
+
const msgs = (Array.isArray(parsedData?.msgs) ? parsedData.msgs : []);
|
|
94
|
+
const pageMsgs = (Array.isArray(parsedData?.pageMsgs) ? parsedData.pageMsgs : []);
|
|
95
|
+
const groupMsgs = (Array.isArray(parsedData?.groupMsgs) ? parsedData.groupMsgs : []);
|
|
96
|
+
if (msgs.length > 0) {
|
|
97
|
+
processIncomingUserMessages(listener, ctx, selfListen, onMessageCallback, msgs, false);
|
|
98
|
+
}
|
|
99
|
+
if (pageMsgs.length > 0) {
|
|
100
|
+
processIncomingUserMessages(listener, ctx, selfListen, onMessageCallback, pageMsgs, true);
|
|
101
|
+
}
|
|
102
|
+
if (groupMsgs.length > 0) {
|
|
103
|
+
processIncomingGroupMessages(listener, ctx, selfListen, onMessageCallback, groupMsgs);
|
|
58
104
|
}
|
|
59
105
|
return true;
|
|
60
106
|
}
|
|
61
107
|
if (cmd == 510 && (subCmd == 0 || subCmd == 1)) {
|
|
62
108
|
const decoded = await wsCipher.decodeEventData(parsed, cipherKey);
|
|
63
109
|
const parsedData = decoded?.data ?? decoded;
|
|
64
|
-
const msgs = (parsedData?.msgs
|
|
110
|
+
const msgs = (Array.isArray(parsedData?.msgs) ? parsedData.msgs : []);
|
|
111
|
+
const pageMsgs = (Array.isArray(parsedData?.pageMsgs) ? parsedData.pageMsgs : []);
|
|
65
112
|
const responseMsgs = [];
|
|
66
113
|
for (const msg of msgs) {
|
|
67
|
-
if (typeof msg.content == "object" && utils.hasOwn(msg.content, "deleteMsg")) {
|
|
114
|
+
if (typeof msg.content == "object" && msg.content !== null && utils.hasOwn(msg.content, "deleteMsg")) {
|
|
115
|
+
const undoObject = new Undo.Undo(ctx.uid, msg, false);
|
|
116
|
+
if (undoObject.isSelf && !selfListen)
|
|
117
|
+
continue;
|
|
118
|
+
listener.emit("undo", undoObject);
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
const userMsg = new Message.UserMessage(ctx.uid, msg, false);
|
|
122
|
+
responseMsgs.push(userMsg);
|
|
123
|
+
if (userMsg.isOAMessage() && (!userMsg.isSelf || selfListen)) {
|
|
124
|
+
listener.emit("oa_message", userMsg);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
for (const msg of pageMsgs) {
|
|
129
|
+
if (typeof msg.content == "object" && msg.content !== null && utils.hasOwn(msg.content, "deleteMsg")) {
|
|
68
130
|
const undoObject = new Undo.Undo(ctx.uid, msg, false);
|
|
69
131
|
if (undoObject.isSelf && !selfListen)
|
|
70
132
|
continue;
|
|
71
133
|
listener.emit("undo", undoObject);
|
|
72
134
|
}
|
|
73
135
|
else {
|
|
74
|
-
|
|
136
|
+
const oaUserMsg = new Message.UserMessage(ctx.uid, msg, true);
|
|
137
|
+
responseMsgs.push(oaUserMsg);
|
|
138
|
+
if (oaUserMsg.isOAMessage() && (!oaUserMsg.isSelf || selfListen)) {
|
|
139
|
+
listener.emit("oa_message", oaUserMsg);
|
|
140
|
+
}
|
|
75
141
|
}
|
|
76
142
|
}
|
|
77
|
-
if (responseMsgs.length > 0 || msgs.length === 0) {
|
|
143
|
+
if (responseMsgs.length > 0 || (msgs.length === 0 && pageMsgs.length === 0)) {
|
|
78
144
|
listener.emit("old_messages", responseMsgs, Enum.ThreadType.User, parsedData?.more === 1);
|
|
79
145
|
}
|
|
80
146
|
return true;
|
|
@@ -330,18 +330,19 @@ class Listener extends EventEmitter {
|
|
|
330
330
|
}
|
|
331
331
|
sendWs(payload, requireId = true) {
|
|
332
332
|
if (this.ws && (this.ws.readyState === undefined || this.ws.readyState === WebSocket.OPEN)) {
|
|
333
|
-
if (requireId)
|
|
334
|
-
|
|
333
|
+
if (requireId) {
|
|
334
|
+
const reqId = `req_${this.id++}`;
|
|
335
|
+
payload.data["req_id"] = reqId;
|
|
336
|
+
payload.data["reqId"] = reqId;
|
|
337
|
+
}
|
|
335
338
|
const encodedData = new TextEncoder().encode(JSON.stringify(payload.data));
|
|
336
339
|
const dataLength = encodedData.length;
|
|
337
|
-
const
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
encodedData.
|
|
342
|
-
|
|
343
|
-
});
|
|
344
|
-
this.ws.send(data);
|
|
340
|
+
const buf = Buffer.alloc(4 + dataLength);
|
|
341
|
+
buf.writeUInt8(payload.version, 0);
|
|
342
|
+
buf.writeUInt16LE(payload.cmd, 1);
|
|
343
|
+
buf.writeInt8(payload.subCmd, 3);
|
|
344
|
+
Buffer.from(encodedData).copy(buf, 4);
|
|
345
|
+
this.ws.send(buf);
|
|
345
346
|
}
|
|
346
347
|
}
|
|
347
348
|
/**
|
|
@@ -376,16 +377,36 @@ class Listener extends EventEmitter {
|
|
|
376
377
|
this.sendWs(payload);
|
|
377
378
|
}
|
|
378
379
|
/**
|
|
379
|
-
*
|
|
380
|
-
*
|
|
380
|
+
* Kéo danh sách tin nhắn cụ thể theo `queueId` và mảng `ids` (`cmd 570` GET_MSG)
|
|
381
|
+
* khi nhận tín hiệu `cmd 533` (`HAS_MSG`) từ Zalo WebSocket (thường dùng cho tin nhắn OA / ZNS / Missed Queue).
|
|
382
|
+
* Tự động chia batch tối đa 20 ID mỗi gói theo đúng cấu hình `max_msg_get = 20` trên Zalo Desktop.
|
|
383
|
+
*/
|
|
384
|
+
requestMessagesByIds(queueId, ids, lastId = "0") {
|
|
385
|
+
if (!queueId || !Array.isArray(ids) || ids.length === 0)
|
|
386
|
+
return;
|
|
387
|
+
const maxBatchSize = 20;
|
|
388
|
+
for (let i = 0; i < ids.length; i += maxBatchSize) {
|
|
389
|
+
const chunk = ids.slice(i, i + maxBatchSize);
|
|
390
|
+
const reqId = `req_${this.id++}`;
|
|
391
|
+
this.sendWs({
|
|
392
|
+
version: 1,
|
|
393
|
+
cmd: 570,
|
|
394
|
+
subCmd: 0,
|
|
395
|
+
data: {
|
|
396
|
+
queueId,
|
|
397
|
+
ids: chunk,
|
|
398
|
+
lastId,
|
|
399
|
+
reqId,
|
|
400
|
+
req_id: reqId,
|
|
401
|
+
},
|
|
402
|
+
}, false);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
* Kích hoạt và kéo hàng đợi sự kiện điều khiển / VoIP (`cmd 603` CTRL_PULL_CTRL).
|
|
407
|
+
* Giúp nhận ngay các cuộc gọi đến đang đổ chuông và sự kiện điều khiển ngay cả khi vừa mở kết nối WebSocket.
|
|
381
408
|
*/
|
|
382
409
|
requestOfflineVoipControls() {
|
|
383
|
-
this.sendWs({
|
|
384
|
-
version: 1,
|
|
385
|
-
cmd: 604,
|
|
386
|
-
subCmd: 0,
|
|
387
|
-
data: { first: true, lastId: 1, preIds: [] },
|
|
388
|
-
});
|
|
389
410
|
this.sendWs({
|
|
390
411
|
version: 1,
|
|
391
412
|
cmd: 603,
|
package/dist/cjs/utils.cjs
CHANGED
|
@@ -17,6 +17,25 @@ var defaults = require('./constants/defaults.cjs');
|
|
|
17
17
|
var aes = require('./crypto/aes.cjs');
|
|
18
18
|
var wsCipher = require('./crypto/ws-cipher.cjs');
|
|
19
19
|
|
|
20
|
+
function _interopNamespaceDefault(e) {
|
|
21
|
+
var n = Object.create(null);
|
|
22
|
+
if (e) {
|
|
23
|
+
Object.keys(e).forEach(function (k) {
|
|
24
|
+
if (k !== 'default') {
|
|
25
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
26
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
27
|
+
enumerable: true,
|
|
28
|
+
get: function () { return e[k]; }
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
n.default = e;
|
|
34
|
+
return Object.freeze(n);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
var toughCookie__namespace = /*#__PURE__*/_interopNamespaceDefault(toughCookie);
|
|
38
|
+
|
|
20
39
|
const isBun = typeof Bun !== "undefined";
|
|
21
40
|
function hasOwn(obj, key) {
|
|
22
41
|
return Object.prototype.hasOwnProperty.call(obj, key);
|
|
@@ -143,7 +162,7 @@ async function getDefaultHeaders(ctx, origin = domains.ZALO_DOMAINS.CHAT_WEB) {
|
|
|
143
162
|
}
|
|
144
163
|
async function request(ctx, url, options, raw = false) {
|
|
145
164
|
if (!ctx.cookie)
|
|
146
|
-
ctx.cookie = new
|
|
165
|
+
ctx.cookie = new toughCookie__namespace.CookieJar();
|
|
147
166
|
const origin = new URL(url).origin;
|
|
148
167
|
const defaultHeaders = await getDefaultHeaders(ctx, origin);
|
|
149
168
|
if (!raw) {
|
|
@@ -208,7 +227,7 @@ async function request(ctx, url, options, raw = false) {
|
|
|
208
227
|
cookieStrings = setCookieRaw.split(/,\s*(?=[a-zA-Z0-9_-]+\s*=)/);
|
|
209
228
|
}
|
|
210
229
|
for (const cookie of cookieStrings) {
|
|
211
|
-
const parsed =
|
|
230
|
+
const parsed = toughCookie__namespace.Cookie.parse(cookie);
|
|
212
231
|
try {
|
|
213
232
|
if (parsed)
|
|
214
233
|
await ctx.cookie.setCookie(parsed, parsed.domain != "zalo.me" ? `https://${parsed.domain}` : origin);
|
package/dist/cjs/zalo.cjs
CHANGED
|
@@ -11,6 +11,25 @@ var apis = require('./apis.cjs');
|
|
|
11
11
|
var domains = require('./constants/domains.cjs');
|
|
12
12
|
var defaults = require('./constants/defaults.cjs');
|
|
13
13
|
|
|
14
|
+
function _interopNamespaceDefault(e) {
|
|
15
|
+
var n = Object.create(null);
|
|
16
|
+
if (e) {
|
|
17
|
+
Object.keys(e).forEach(function (k) {
|
|
18
|
+
if (k !== 'default') {
|
|
19
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
20
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
21
|
+
enumerable: true,
|
|
22
|
+
get: function () { return e[k]; }
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
n.default = e;
|
|
28
|
+
return Object.freeze(n);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
var toughCookie__namespace = /*#__PURE__*/_interopNamespaceDefault(toughCookie);
|
|
32
|
+
|
|
14
33
|
class Zalo {
|
|
15
34
|
options;
|
|
16
35
|
enableEncryptParam = true;
|
|
@@ -23,10 +42,10 @@ class Zalo {
|
|
|
23
42
|
if (typeof e.domain == "string" && e.domain.startsWith("."))
|
|
24
43
|
cookieArr[i].domain = e.domain.slice(1);
|
|
25
44
|
});
|
|
26
|
-
const jar = new
|
|
45
|
+
const jar = new toughCookie__namespace.CookieJar();
|
|
27
46
|
for (const each of cookieArr) {
|
|
28
47
|
try {
|
|
29
|
-
const cookieObj =
|
|
48
|
+
const cookieObj = toughCookie__namespace.Cookie.fromJSON({
|
|
30
49
|
...each,
|
|
31
50
|
key: each.key || each.name,
|
|
32
51
|
});
|
|
@@ -35,8 +35,8 @@ export declare const ZALO_DEFAULTS: {
|
|
|
35
35
|
/** Số lần lỗi 1006 liên tiếp trước khi xoay sang WebSocket endpoint tiếp theo */
|
|
36
36
|
readonly CONSECUTIVE_1006_ROTATE_THRESHOLD: 2;
|
|
37
37
|
/** Con trỏ mặc định khi bắt đầu kéo hàng đợi tin nhắn cũ (cmd 510 / 511) */
|
|
38
|
-
readonly OLD_MSG_INITIAL_CURSOR: "
|
|
39
|
-
readonly INITIAL_OLD_MESSAGES_CURSOR: "
|
|
38
|
+
readonly OLD_MSG_INITIAL_CURSOR: "1";
|
|
39
|
+
readonly INITIAL_OLD_MESSAGES_CURSOR: "1";
|
|
40
40
|
};
|
|
41
41
|
readonly UPLOAD: {
|
|
42
42
|
/** Thời gian sống tối đa của uploadCallback trong bộ nhớ trước khi tự hủy (5 phút) */
|
|
@@ -35,8 +35,8 @@ export const ZALO_DEFAULTS = {
|
|
|
35
35
|
/** Số lần lỗi 1006 liên tiếp trước khi xoay sang WebSocket endpoint tiếp theo */
|
|
36
36
|
CONSECUTIVE_1006_ROTATE_THRESHOLD: 2,
|
|
37
37
|
/** Con trỏ mặc định khi bắt đầu kéo hàng đợi tin nhắn cũ (cmd 510 / 511) */
|
|
38
|
-
OLD_MSG_INITIAL_CURSOR: "
|
|
39
|
-
INITIAL_OLD_MESSAGES_CURSOR: "
|
|
38
|
+
OLD_MSG_INITIAL_CURSOR: "1",
|
|
39
|
+
INITIAL_OLD_MESSAGES_CURSOR: "1",
|
|
40
40
|
},
|
|
41
41
|
UPLOAD: {
|
|
42
42
|
/** Thời gian sống tối đa của uploadCallback trong bộ nhớ trước khi tự hủy (5 phút) */
|
|
@@ -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.7";
|
|
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.7",
|
|
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/index.d.ts
CHANGED
|
@@ -256,6 +256,10 @@ export type { SendRequestVoiceCallOptions, SendRequestVoiceCallResponse } from "
|
|
|
256
256
|
export type { ShareScreenGroupCallOptions, ShareScreenGroupCallResponse } from "./apis/call/shareScreenGroupCall.js";
|
|
257
257
|
export type { UnholdVoiceCallOptions, UnholdVoiceCallResponse } from "./apis/call/unholdVoiceCall.js";
|
|
258
258
|
export type { UpdateCallMediaStateOptions, UpdateCallMediaStateResponse } from "./apis/call/updateCallMediaState.js";
|
|
259
|
+
export type { BlockOAResponse } from "./apis/business/blockOA.js";
|
|
260
|
+
export type { UnblockOAResponse } from "./apis/business/unblockOA.js";
|
|
261
|
+
export type { ConvertOAIdsResponse } from "./apis/business/convertOAIds.js";
|
|
262
|
+
export type { GetOAProfileOptions, GetOAProfileResponse } from "./apis/business/getOAProfile.js";
|
|
259
263
|
export { CloseReason } from "./apis/listen.js";
|
|
260
264
|
export { LoginQRCallbackEventType } from "./apis/loginQR.js";
|
|
261
265
|
export { FriendRecommendationsType } from "./apis/friend/getFriendRecommendations.js";
|
package/dist/models/Message.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ThreadType } from "./Enum.js";
|
|
2
|
+
import { type ParsedOAMessage } from "./OAMessage.js";
|
|
2
3
|
export type TAttachmentContent = {
|
|
3
4
|
title: string;
|
|
4
5
|
description: string;
|
|
@@ -76,7 +77,17 @@ export declare class UserMessage {
|
|
|
76
77
|
* true if the message is sent by the logged in account
|
|
77
78
|
*/
|
|
78
79
|
isSelf: boolean;
|
|
79
|
-
|
|
80
|
+
/**
|
|
81
|
+
* Dữ liệu đã giải mã nếu đây là tin nhắn từ Zalo Official Account (OA) (`pageMsgs`, `footerv2`, `chat.list.action`, `msginfo.actionlist`, hoặc `chat.ecard`).
|
|
82
|
+
*/
|
|
83
|
+
oaData?: ParsedOAMessage;
|
|
84
|
+
constructor(uid: string, data: TMessage, isPageMsg?: boolean);
|
|
85
|
+
/**
|
|
86
|
+
* Kiểm tra xem tin nhắn có phải là tin nhắn Zalo Official Account (OA) hay không.
|
|
87
|
+
*/
|
|
88
|
+
isOAMessage(): this is UserMessage & {
|
|
89
|
+
oaData: ParsedOAMessage;
|
|
90
|
+
};
|
|
80
91
|
}
|
|
81
92
|
export declare class GroupMessage {
|
|
82
93
|
type: ThreadType.Group;
|
package/dist/models/Message.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ThreadType } from "./Enum.js";
|
|
2
|
+
import { parseOAMessage } from "./OAMessage.js";
|
|
2
3
|
export class UserMessage {
|
|
3
4
|
type = ThreadType.User;
|
|
4
5
|
data;
|
|
@@ -7,7 +8,11 @@ export class UserMessage {
|
|
|
7
8
|
* true if the message is sent by the logged in account
|
|
8
9
|
*/
|
|
9
10
|
isSelf;
|
|
10
|
-
|
|
11
|
+
/**
|
|
12
|
+
* Dữ liệu đã giải mã nếu đây là tin nhắn từ Zalo Official Account (OA) (`pageMsgs`, `footerv2`, `chat.list.action`, `msginfo.actionlist`, hoặc `chat.ecard`).
|
|
13
|
+
*/
|
|
14
|
+
oaData;
|
|
15
|
+
constructor(uid, data, isPageMsg = false) {
|
|
11
16
|
this.data = data;
|
|
12
17
|
this.threadId = data.uidFrom == "0" ? data.idTo : data.uidFrom;
|
|
13
18
|
this.isSelf = data.uidFrom == "0";
|
|
@@ -18,6 +23,16 @@ export class UserMessage {
|
|
|
18
23
|
if (data.quote) {
|
|
19
24
|
data.quote.ownerId = String(data.quote.ownerId);
|
|
20
25
|
}
|
|
26
|
+
const parsedOA = parseOAMessage(data, { isPageMsg });
|
|
27
|
+
if (parsedOA) {
|
|
28
|
+
this.oaData = parsedOA;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Kiểm tra xem tin nhắn có phải là tin nhắn Zalo Official Account (OA) hay không.
|
|
33
|
+
*/
|
|
34
|
+
isOAMessage() {
|
|
35
|
+
return this.oaData !== undefined;
|
|
21
36
|
}
|
|
22
37
|
}
|
|
23
38
|
export class GroupMessage {
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
export type OAHighlightItem = string | number | {
|
|
2
|
+
type?: number;
|
|
3
|
+
uid?: string;
|
|
4
|
+
dpn?: string;
|
|
5
|
+
text?: string;
|
|
6
|
+
value?: string;
|
|
7
|
+
ts?: number;
|
|
8
|
+
[key: string]: unknown;
|
|
9
|
+
};
|
|
10
|
+
export type OACustomMessage = {
|
|
11
|
+
msg?: {
|
|
12
|
+
vi?: string;
|
|
13
|
+
en?: string;
|
|
14
|
+
[lang: string]: string | undefined;
|
|
15
|
+
};
|
|
16
|
+
previewTxt?: string;
|
|
17
|
+
highLightsV2?: OAHighlightItem[];
|
|
18
|
+
[key: string]: unknown;
|
|
19
|
+
};
|
|
20
|
+
export type OAListActionItem = {
|
|
21
|
+
type?: string;
|
|
22
|
+
title?: string;
|
|
23
|
+
description?: string;
|
|
24
|
+
thumb?: string;
|
|
25
|
+
href?: string;
|
|
26
|
+
childnumber?: number;
|
|
27
|
+
action?: string;
|
|
28
|
+
params?: string | Record<string, unknown>;
|
|
29
|
+
childAction?: unknown[];
|
|
30
|
+
[key: string]: unknown;
|
|
31
|
+
};
|
|
32
|
+
export type OAFooterItem = {
|
|
33
|
+
title?: string;
|
|
34
|
+
label?: string;
|
|
35
|
+
text?: string;
|
|
36
|
+
type?: number | string;
|
|
37
|
+
action?: string;
|
|
38
|
+
href?: string;
|
|
39
|
+
url?: string;
|
|
40
|
+
data?: unknown;
|
|
41
|
+
[key: string]: unknown;
|
|
42
|
+
};
|
|
43
|
+
export type OAFooterData = {
|
|
44
|
+
type?: number;
|
|
45
|
+
canForward: boolean;
|
|
46
|
+
footerList: OAFooterItem[];
|
|
47
|
+
raw?: unknown;
|
|
48
|
+
};
|
|
49
|
+
export type OAMessageKind = "oa_chat" | "oa_list" | "info_chat" | "ecard";
|
|
50
|
+
export type ParsedOAMessage = {
|
|
51
|
+
/**
|
|
52
|
+
* Phân loại tin nhắn Zalo Official Account (OA):
|
|
53
|
+
* - `"oa_chat"`: Tin nhắn hội thoại trực tiếp 2 chiều từ/đến Zalo OA (`pageMsgs`, có `footerv2`, hoặc `topOut === "1"`).
|
|
54
|
+
* - `"oa_list"`: `msgType === "chat.list.action"` (Danh sách bài viết / thẻ hành động đa phương tiện từ OA).
|
|
55
|
+
* - `"info_chat"`: `msgType === "webchat"` với `content.action === "msginfo.actionlist"` hoặc `"msginfo.action"` (Thông báo sự kiện/trạng thái OA).
|
|
56
|
+
* - `"ecard"`: `msgType === "chat.ecard"` (Thiệp chúc mừng / thông báo sinh nhật / sự kiện OA).
|
|
57
|
+
*/
|
|
58
|
+
kind: OAMessageKind;
|
|
59
|
+
/**
|
|
60
|
+
* Nội dung văn bản hiển thị đã được giải mã và điền đầy đủ các biến `%1$s` / `$1$s`.
|
|
61
|
+
*/
|
|
62
|
+
text: string;
|
|
63
|
+
/**
|
|
64
|
+
* Văn bản thông báo tiếng Việt (nếu có trong `customMsg.msg.vi`).
|
|
65
|
+
*/
|
|
66
|
+
textVi?: string;
|
|
67
|
+
/**
|
|
68
|
+
* Văn bản thông báo tiếng Anh (nếu có trong `customMsg.msg.en`).
|
|
69
|
+
*/
|
|
70
|
+
textEn?: string;
|
|
71
|
+
/**
|
|
72
|
+
* Dữ liệu chi tiết đính kèm trong `content` / `params` của tin nhắn OA.
|
|
73
|
+
*/
|
|
74
|
+
bundleData: Record<string, unknown>;
|
|
75
|
+
/**
|
|
76
|
+
* Danh sách các thẻ bài viết / nút hành động (dành cho `chat.list.action`).
|
|
77
|
+
*/
|
|
78
|
+
items?: OAListActionItem[];
|
|
79
|
+
/**
|
|
80
|
+
* Cấu hình chân trang tương tác (`footerv2`) đính kèm tin nhắn OA (danh sách nút bấm `footerList`, cờ `canForward`).
|
|
81
|
+
*/
|
|
82
|
+
footer?: OAFooterData;
|
|
83
|
+
/**
|
|
84
|
+
* Cờ đánh dấu tin nhắn nổi bật từ OA (`topOut === "1"`).
|
|
85
|
+
*/
|
|
86
|
+
topOut?: boolean;
|
|
87
|
+
/**
|
|
88
|
+
* Cờ cho phép trả lời trực tiếp tin nhắn OA.
|
|
89
|
+
*/
|
|
90
|
+
canReply?: boolean;
|
|
91
|
+
/**
|
|
92
|
+
* Dữ liệu `customMsg` / `params` nguyên bản sau khi parse JSON.
|
|
93
|
+
*/
|
|
94
|
+
metadata?: {
|
|
95
|
+
customMsg?: OACustomMessage;
|
|
96
|
+
[key: string]: unknown;
|
|
97
|
+
};
|
|
98
|
+
};
|
|
99
|
+
export type OAFieldEntry = {
|
|
100
|
+
label?: string;
|
|
101
|
+
value?: string;
|
|
102
|
+
icon?: string;
|
|
103
|
+
[key: string]: unknown;
|
|
104
|
+
};
|
|
105
|
+
export type OARawInfo = {
|
|
106
|
+
description?: string | null;
|
|
107
|
+
appUrl?: string | null;
|
|
108
|
+
hotline?: OAFieldEntry | null;
|
|
109
|
+
category?: OAFieldEntry | null;
|
|
110
|
+
website?: OAFieldEntry | null;
|
|
111
|
+
address?: OAFieldEntry | null;
|
|
112
|
+
openTime?: OAFieldEntry | null;
|
|
113
|
+
group_msg?: number;
|
|
114
|
+
[key: string]: unknown;
|
|
115
|
+
};
|
|
116
|
+
export type OADnrStatus = {
|
|
117
|
+
isBlocked: boolean;
|
|
118
|
+
enableDnr: boolean;
|
|
119
|
+
dnrType: number | null;
|
|
120
|
+
dnrText: string | null;
|
|
121
|
+
raw?: unknown;
|
|
122
|
+
};
|
|
123
|
+
export type OAProfileInfo = {
|
|
124
|
+
oaId: string;
|
|
125
|
+
displayName: string;
|
|
126
|
+
zaloName: string;
|
|
127
|
+
username: string;
|
|
128
|
+
avatar: string;
|
|
129
|
+
cover: string;
|
|
130
|
+
globalId: string;
|
|
131
|
+
type: number;
|
|
132
|
+
isOA: boolean;
|
|
133
|
+
isVerified: boolean;
|
|
134
|
+
isZaloBot: boolean;
|
|
135
|
+
isBlocked: boolean;
|
|
136
|
+
isGroupedMsg: boolean;
|
|
137
|
+
description: string;
|
|
138
|
+
category: string;
|
|
139
|
+
address: string;
|
|
140
|
+
website: string;
|
|
141
|
+
hotline: string;
|
|
142
|
+
openTime: string;
|
|
143
|
+
email: string;
|
|
144
|
+
appUrl: string | null;
|
|
145
|
+
dnrStatus: OADnrStatus;
|
|
146
|
+
oaInfo: OARawInfo | null;
|
|
147
|
+
rawProfile: Record<string, unknown>;
|
|
148
|
+
bizAccount?: Record<string, unknown> | null;
|
|
149
|
+
};
|
|
150
|
+
export type TOAEventData = {
|
|
151
|
+
uids: string[];
|
|
152
|
+
[key: string]: unknown;
|
|
153
|
+
};
|
|
154
|
+
export type OAEvent = {
|
|
155
|
+
act: "block" | "unblock" | string;
|
|
156
|
+
act_type: "oa";
|
|
157
|
+
data: TOAEventData;
|
|
158
|
+
isBlocked: boolean;
|
|
159
|
+
oaIds: string[];
|
|
160
|
+
};
|
|
161
|
+
/**
|
|
162
|
+
* Điền các biến `%1$s`, `%2$s`... và `$1$s`, `$2$s`... trong mẫu chuỗi thông báo Zalo OA
|
|
163
|
+
* theo chuẩn hàm `_renderItemReplace` trên Zalo PC.
|
|
164
|
+
*/
|
|
165
|
+
export declare function formatOAHighlightText(templateText?: string, highLightsV2?: OAHighlightItem[]): string;
|
|
166
|
+
/**
|
|
167
|
+
* Bóc tách cấu hình chân trang tương tác `footerv2` / `footer` của tin nhắn Zalo OA
|
|
168
|
+
* (`footerList`, `canForward`, `type`).
|
|
169
|
+
*/
|
|
170
|
+
export declare function parseOAFooter(rawFooter: unknown): OAFooterData | undefined;
|
|
171
|
+
/**
|
|
172
|
+
* Kiểm tra xem một hồ sơ người dùng có phải là Zalo Official Account (OA) hay không.
|
|
173
|
+
* Theo chuẩn `isOA(profile)` trên Zalo PC: `profile.type > 0` hoặc có `profile.oaInfo`.
|
|
174
|
+
*/
|
|
175
|
+
export declare function isOAProfile(profile: {
|
|
176
|
+
type?: number;
|
|
177
|
+
oaInfo?: unknown;
|
|
178
|
+
} | null | undefined): boolean;
|
|
179
|
+
/**
|
|
180
|
+
* Kiểm tra xem Zalo OA có tích vàng xác thực (Verified OA) hay không.
|
|
181
|
+
* Theo chuẩn `isOAVerifiedByInfo(profile)` trên Zalo PC (`@10388120`):
|
|
182
|
+
* Chuyển `profile.type` sang nhị phân (`Number(type).toString(2)`), kiểm tra độ dài >= 3 và ký tự index `2` là `"1"`.
|
|
183
|
+
* Ví dụ: `type = 7` (`"111"`) -> Verified OA; `type = 5` (`"101"`) -> Verified OA.
|
|
184
|
+
*/
|
|
185
|
+
export declare function isOAVerified(profileOrType: {
|
|
186
|
+
type?: number;
|
|
187
|
+
} | number | null | undefined): boolean;
|
|
188
|
+
/**
|
|
189
|
+
* Kiểm tra xem tài khoản có phải là Zalo Bot hay không.
|
|
190
|
+
* Theo chuẩn `isZaloBotByInfo(profile)` trên Zalo PC (`@10388180`):
|
|
191
|
+
* Chuyển `profile.type` sang nhị phân (`Number(type).toString(2)`), kiểm tra độ dài >= 4 và ký tự đầu tiên là `"1"`.
|
|
192
|
+
*/
|
|
193
|
+
export declare function isZaloBot(profileOrType: {
|
|
194
|
+
type?: number;
|
|
195
|
+
} | number | null | undefined): boolean;
|
|
196
|
+
/**
|
|
197
|
+
* Giải mã trạng thái chặn & Do-Not-Disturb (`oa_status`) của Zalo OA
|
|
198
|
+
* theo chuẩn `_getOAStatus` trên Zalo PC (`@1719856`).
|
|
199
|
+
*/
|
|
200
|
+
export declare function parseOADnrStatus(oaStatus: unknown, fallbackIsBlocked?: number | boolean): OADnrStatus;
|
|
201
|
+
/**
|
|
202
|
+
* Chuẩn hóa dữ liệu hồ sơ Zalo Official Account (`getUserInfo` + `getBizAccount`) thành cấu trúc `OAProfileInfo` đồng nhất.
|
|
203
|
+
*/
|
|
204
|
+
export declare function normalizeOAProfile(oaId: string, rawProfile?: Record<string, unknown> | null, bizAccount?: Record<string, unknown> | null): OAProfileInfo;
|
|
205
|
+
/**
|
|
206
|
+
* Bóc tách và giải mã các loại tin nhắn từ Zalo Official Account (OA):
|
|
207
|
+
* - Danh sách bài viết / thẻ hành động OA (`chat.list.action`, bao gồm `l.a.header.full`, `l.a.normal`)
|
|
208
|
+
* - Thông báo sự kiện OA (`webchat` với `action === "msginfo.actionlist"` hoặc `"msginfo.action"`)
|
|
209
|
+
* - Thiệp chúc mừng / sự kiện OA (`chat.ecard`)
|
|
210
|
+
* - Tin nhắn hội thoại trực tiếp 2 chiều với OA (`pageMsgs`, có `footerv2`, hoặc `topOut === "1"`)
|
|
211
|
+
*
|
|
212
|
+
* Trả về `undefined` nếu tin nhắn là tin nhắn cá nhân thông thường không thuộc Zalo OA.
|
|
213
|
+
*/
|
|
214
|
+
export declare function parseOAMessage(msg: {
|
|
215
|
+
msgType: string;
|
|
216
|
+
content: unknown;
|
|
217
|
+
[key: string]: unknown;
|
|
218
|
+
}, options?: {
|
|
219
|
+
isPageMsg?: boolean;
|
|
220
|
+
}): ParsedOAMessage | undefined;
|
|
221
|
+
export declare function initializeOAEvent(data: TOAEventData, act: string): OAEvent;
|