@softtynet/zca-js 2.3.5 → 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/downloadTransferSync.js +19 -1
- package/dist/apis/sync/getSyncData.js +1 -1
- package/dist/apis.d.ts +12 -0
- package/dist/apis.js +20 -0
- package/dist/call-engine/ZaloCallTransport.js +28 -2
- package/dist/call-engine/ZaloRtcSession.js +9 -1
- 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/downloadTransferSync.cjs +19 -1
- package/dist/cjs/apis/sync/getSyncData.cjs +20 -1
- package/dist/cjs/apis.cjs +20 -0
- package/dist/cjs/call-engine/ZaloCallTransport.cjs +28 -2
- package/dist/cjs/call-engine/ZaloRtcSession.cjs +9 -1
- package/dist/cjs/constants/defaults.cjs +2 -2
- package/dist/cjs/constants/protocol.cjs +1 -1
- package/dist/cjs/crypto/aes.cjs +3 -1
- package/dist/cjs/crypto/zdb-cipher.cjs +10 -3
- 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/crypto/aes.js +3 -1
- package/dist/crypto/zdb-cipher.js +10 -3
- 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
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/crypto/aes.js
CHANGED
|
@@ -167,5 +167,7 @@ export function encryptPin(pin) {
|
|
|
167
167
|
}
|
|
168
168
|
export function validatePin(encryptedPin, pin) {
|
|
169
169
|
const hash = crypto.createHash("md5").update(pin).digest("hex");
|
|
170
|
-
|
|
170
|
+
const a = Buffer.from(hash, "utf8");
|
|
171
|
+
const b = Buffer.from(String(encryptedPin), "utf8");
|
|
172
|
+
return a.length === b.length && crypto.timingSafeEqual(a, b);
|
|
171
173
|
}
|
|
@@ -146,6 +146,9 @@ export function parseZdbHeader(zdbPlaintext) {
|
|
|
146
146
|
throw new ZaloApiError("Buffer is not a valid decrypted ZDB4.0 container");
|
|
147
147
|
}
|
|
148
148
|
const count = zdbPlaintext.readUInt32BE(COUNT_OFFSET);
|
|
149
|
+
if (count > 100000) {
|
|
150
|
+
throw new ZaloApiError(`ZDB4.0 header entry count exceeds safety limit (${count})`);
|
|
151
|
+
}
|
|
149
152
|
let offset = COUNT_OFFSET + 4;
|
|
150
153
|
const entries = [];
|
|
151
154
|
for (let i = 0; i < count; i++) {
|
|
@@ -153,12 +156,16 @@ export function parseZdbHeader(zdbPlaintext) {
|
|
|
153
156
|
throw new ZaloApiError("Truncated ZDB4.0 header while reading entry name length");
|
|
154
157
|
}
|
|
155
158
|
const nameLen = zdbPlaintext.readUInt32BE(offset);
|
|
156
|
-
if (offset + 4 + nameLen + 4 > zdbPlaintext.length) {
|
|
157
|
-
throw new ZaloApiError("Truncated ZDB4.0 header while reading entry metadata");
|
|
159
|
+
if (nameLen > 4096 || offset + 4 + nameLen + 4 > zdbPlaintext.length) {
|
|
160
|
+
throw new ZaloApiError("Truncated or invalid ZDB4.0 header while reading entry metadata");
|
|
158
161
|
}
|
|
159
|
-
const
|
|
162
|
+
const rawName = zdbPlaintext
|
|
160
163
|
.toString("utf8", offset + 4, offset + 4 + nameLen)
|
|
161
164
|
.replace(/\0+$/, "");
|
|
165
|
+
const name = rawName.split(/[\\/]/).pop() || rawName;
|
|
166
|
+
if (name === ".." || name === "." || name.includes("..")) {
|
|
167
|
+
throw new ZaloApiError(`Unsafe entry name in ZDB4.0 header: ${rawName}`);
|
|
168
|
+
}
|
|
162
169
|
const size = zdbPlaintext.readUInt32BE(offset + 4 + nameLen);
|
|
163
170
|
entries.push({ name, size });
|
|
164
171
|
offset += 4 + nameLen + 4;
|
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;
|