@softtynet/zca-js 2.2.6 → 2.2.8
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 +159 -177
- package/dist/cjs/update.cjs +8 -6
- package/dist/update.js +8 -6
- package/docs/INTEGRATION_GUIDE_SYNC_AND_CALL.md +371 -0
- package/package.json +12 -9
- package/CODE_OF_CONDUCT.md +0 -163
- package/CONTRIBUTING.md +0 -470
- package/SECURITY.md +0 -83
package/README.md
CHANGED
|
@@ -1,54 +1,72 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @softtynet/zca-js — Softtynet Zalo API SDK for Node.js & Bun
|
|
2
2
|
|
|
3
|
-
>
|
|
4
|
-
|
|
5
|
-
>
|
|
6
|
-
|
|
3
|
+
<p align="left">
|
|
4
|
+
<a href="https://www.npmjs.com/package/@softtynet/zca-js"><img src="https://img.shields.io/npm/v/@softtynet/zca-js.svg?label=%40softtynet%2Fzca-js&color=0068ff" alt="npm version" /></a>
|
|
5
|
+
<a href="https://github.com/softtyos/zca-js"><img src="https://img.shields.io/badge/Maintained%20by-Softtynet%20Co.%2C%20Ltd.-0a7cff" alt="Maintained by Softtynet" /></a>
|
|
6
|
+
<a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-green.svg" alt="License: MIT" /></a>
|
|
7
|
+
</p>
|
|
8
|
+
|
|
9
|
+
**`@softtynet/zca-js`** là bộ thư viện Zalo API nâng cao dành cho Node.js / TypeScript / Bun, được phát triển, tối ưu hoá và duy trì bởi **Softtynet Co., Ltd.** nhằm đáp ứng các bài toán tích hợp chuyên sâu: **Đồng bộ dữ liệu đa thiết bị (Offline Catch-up & Mobile Backup Sync `ZDB4.0`)**, **Tín hiệu Gọi Thoại & Gọi Video (Voice / Video Call Signaling)**, và **Xử lý WebSocket thời gian thực độ tin cậy cao**.
|
|
7
10
|
|
|
8
11
|
> [!WARNING]
|
|
9
|
-
>
|
|
12
|
+
> Đây là thư viện tương tác không chính thức thông qua giao thức Zalo Web / Zalo PC dành cho tài khoản cá nhân. Vui lòng sử dụng có trách nhiệm và tuân thủ quy định an toàn tài khoản.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Mục lục
|
|
17
|
+
|
|
18
|
+
- [Điểm nổi bật trên phiên bản Softtynet (`@softtynet/zca-js`)](#-điểm-nổi-bật-trên-phiên-bản-softtynet-softtynetzca-js)
|
|
19
|
+
- [Cài đặt](#-cài-đặt)
|
|
20
|
+
- [Tài liệu chuyên sâu](#-tài-liệu-chuyên-sâu)
|
|
21
|
+
- [Hướng dẫn sử dụng nhanh](#-hướng-dẫn-sử-dụng-nhanh)
|
|
22
|
+
- [1. Đăng nhập & Lưu phiên](#1-đăng-nhập--lưu-phiên)
|
|
23
|
+
- [2. Lắng nghe tin nhắn thời gian thực](#2-lắng-nghe-tin-nhắn-thời-gian-thực)
|
|
24
|
+
- [3. Đồng bộ bù tin nhắn khi Offline (Catch-up Sync)](#3-đồng-bộ-bù-tin-nhắn-khi-offline-catch-up-sync)
|
|
25
|
+
- [4. Đồng bộ lịch sử sao lưu từ Điện thoại (`ZDB4.0`)](#4-đồng-bộ-lịch-sử-sao-lưu-từ-điện-thoại-zdb40)
|
|
26
|
+
- [5. Khởi tạo Cuộc gọi Thoại & Gọi Video](#5-khởi-tạo-cuộc-gọi-thoại--gọi-video)
|
|
27
|
+
- [6. Gửi tin nhắn & Sticker](#6-gửi-tin-nhắn--sticker)
|
|
28
|
+
- [Kiểm định & Chạy thử nghiệm](#-kiểm-định--chạy-thử-nghiệm)
|
|
29
|
+
- [Nguồn gốc & Ghi nhận (Credits & Attribution)](#-nguồn-gốc--ghi-nhận-credits--attribution)
|
|
30
|
+
- [Giấy phép (License)](#-giấy-phép-license)
|
|
10
31
|
|
|
11
32
|
---
|
|
12
33
|
|
|
13
|
-
##
|
|
14
|
-
|
|
15
|
-
-
|
|
16
|
-
|
|
17
|
-
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
- [Support Us](#support-us)
|
|
29
|
-
|
|
30
|
-
## Installation
|
|
34
|
+
## 🚀 Điểm nổi bật trên phiên bản Softtynet (`@softtynet/zca-js`)
|
|
35
|
+
|
|
36
|
+
So với phiên bản cộng đồng tiêu chuẩn, **`@softtynet/zca-js`** bổ sung các phân hệ cốt lõi đã được kiểm định trực tiếp trên máy chủ Zalo thật:
|
|
37
|
+
|
|
38
|
+
| Phân hệ | Tính năng trên `@softtynet/zca-js` |
|
|
39
|
+
| :--- | :--- |
|
|
40
|
+
| **Đồng bộ bù khi Offline (Catch-up Sync)** | Hỗ trợ [`api.preloadConversations()`](src/apis/preloadConversations.ts) (`cmd 10053`), kéo hàng đợi tin nhắn cá nhân & nhóm qua [`api.listener.requestOldMessages()`](src/apis/listen.ts) (`cmd 510` / `511`, cả `subCmd 0` & `1`), kèm cờ phân trang `hasMore`, tách biệt sự kiện thu hồi `undo` và đồng bộ trạng thái đã đọc `unread_cleared` (`cmd 504` / `524`). |
|
|
41
|
+
| **Đồng bộ sao lưu từ Điện thoại (`ZDB4.0`)** | Hỗ trợ trọn vẹn chu trình [`api.requestSyncFromPhone()`](src/apis/requestSyncFromPhone.ts) (`cmd 12000`), [`api.cancelPullMobile()`](src/apis/cancelPullMobile.ts) (`cmd 12700`), sự kiện `sync_event` (`user_confirm`, `syncmsg_info`, `transfer_after_login`), tải gói `.db.crypt` qua [`api.getSyncData()`](src/apis/getSyncData.ts) và giải mã RSA-2048 PKCS#1 v1.5 + AES-256-CBC đa khối 64KB + đọc mục lục SQLite (`parseZdbHeader`). |
|
|
42
|
+
| **Ánh xạ ID ẩn danh (Noised / Global ID)** | Hỗ trợ [`api.getNoisedIds()`](src/apis/getNoisedIds.ts) (`cmd 12390` kèm cơ chế tự động fallback sang `zwid.api.zalo.me`) và [`api.decryptGids()`](src/apis/decryptGids.ts) (`cmd 12054`) để ánh xạ tên file SQLite `3_<me>_<peer>.db` về User ID / Group ID thật. |
|
|
43
|
+
| **Gọi Thoại & Gọi Video (Signaling 2 bước)** | Hỗ trợ [`api.sendVoiceCall()`](src/apis/sendVoiceCall.ts) (`cmd 11300` + `11301`), [`api.cancelVoiceCall()`](src/apis/cancelVoiceCall.ts) (`cmd 11305`), [`api.endVoiceCall()`](src/apis/endVoiceCall.ts) (`cmd 11306`) và sự kiện `call_event` chuẩn giao thức C++ `ZaloCall` cho cả **Gọi Thoại (`CallType.Audio = 1`)** lẫn **Gọi Video (`CallType.Video = 3`, H.264)**. |
|
|
44
|
+
| **Độ ổn định & Bảo vệ bộ nhớ** | Tự động giải phóng bộ nhớ `uploadCallbacks` sau 5 phút trong [`uploadAttachment`](src/apis/uploadAttachment.ts), xử lý phản hồi rỗng hợp lệ (`error_code === 0, data === ""`) và bảo toàn độ chính xác chuỗi UID 19 chữ số. |
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## 📦 Cài đặt
|
|
31
49
|
|
|
32
50
|
```bash
|
|
33
|
-
|
|
51
|
+
npm install @softtynet/zca-js
|
|
52
|
+
# hoặc dùng Bun
|
|
53
|
+
bun add @softtynet/zca-js
|
|
34
54
|
```
|
|
35
55
|
|
|
36
|
-
###
|
|
56
|
+
### Cấu hình `imageMetadataGetter` (Khi gửi ảnh từ đường dẫn file)
|
|
37
57
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
Example of custom `imageMetadataGetter` using `sharp`:
|
|
58
|
+
Từ kiến trúc V2, thư viện tách rời phụ thuộc xử lý ảnh để giữ dung lượng gọn nhẹ. Nếu ứng dụng của bạn gửi ảnh/GIF từ file nội bộ, hãy truyền hàm `imageMetadataGetter` (ví dụ dùng `sharp`):
|
|
41
59
|
|
|
42
60
|
```bash
|
|
43
|
-
|
|
61
|
+
npm install sharp
|
|
44
62
|
```
|
|
45
63
|
|
|
46
|
-
```
|
|
47
|
-
import { Zalo } from "zca-js";
|
|
64
|
+
```ts
|
|
65
|
+
import { Zalo } from "@softtynet/zca-js";
|
|
48
66
|
import sharp from "sharp";
|
|
49
67
|
import fs from "node:fs";
|
|
50
68
|
|
|
51
|
-
async function imageMetadataGetter(filePath) {
|
|
69
|
+
async function imageMetadataGetter(filePath: string) {
|
|
52
70
|
const data = await fs.promises.readFile(filePath);
|
|
53
71
|
const metadata = await sharp(data).metadata();
|
|
54
72
|
return {
|
|
@@ -58,78 +76,75 @@ async function imageMetadataGetter(filePath) {
|
|
|
58
76
|
};
|
|
59
77
|
}
|
|
60
78
|
|
|
61
|
-
const zalo = new Zalo({
|
|
62
|
-
imageMetadataGetter,
|
|
63
|
-
});
|
|
79
|
+
const zalo = new Zalo({ imageMetadataGetter });
|
|
64
80
|
```
|
|
65
81
|
|
|
66
82
|
---
|
|
67
83
|
|
|
68
|
-
##
|
|
84
|
+
## 📚 Tài liệu chuyên sâu
|
|
69
85
|
|
|
70
|
-
|
|
86
|
+
- **[Hướng dẫn Tích hợp: Đồng bộ Tin nhắn Đa Thiết bị (`ZDB4.0`) & Gọi Thoại / Video](docs/INTEGRATION_GUIDE_SYNC_AND_CALL.md)** — Tài liệu đầy đủ kèm sơ đồ kiến trúc và code mẫu tích hợp thực tế của Softtynet.
|
|
87
|
+
- **[Kế hoạch & Hướng dẫn Dịch ngược Zalo bằng REA (`morluto/rea`)](docs/REA_REVERSE_ENGINEERING_PLAN.md)** — Tài liệu quy trình phân tích tĩnh Binary C++ (`ZaloCall`, `libzdatabase.dylib`) và ASAR.
|
|
88
|
+
- **[API Reference Cơ bản](https://zca-js.tdung.com)** — Tra cứu danh mục các API cơ bản.
|
|
71
89
|
|
|
72
90
|
---
|
|
73
91
|
|
|
74
|
-
##
|
|
92
|
+
## ⚡ Hướng dẫn sử dụng nhanh
|
|
75
93
|
|
|
76
|
-
###
|
|
94
|
+
### 1. Đăng nhập & Lưu phiên
|
|
77
95
|
|
|
78
|
-
```
|
|
79
|
-
import { Zalo } from "zca-js";
|
|
96
|
+
```ts
|
|
97
|
+
import { Zalo } from "@softtynet/zca-js";
|
|
80
98
|
|
|
81
|
-
const zalo = new Zalo();
|
|
99
|
+
const zalo = new Zalo({ selfListen: true });
|
|
82
100
|
const api = await zalo.loginQR();
|
|
101
|
+
console.log("Đã đăng nhập với UID:", api.getOwnId());
|
|
83
102
|
```
|
|
84
103
|
|
|
85
|
-
###
|
|
104
|
+
### 2. Lắng nghe tin nhắn thời gian thực
|
|
86
105
|
|
|
87
|
-
```
|
|
88
|
-
import { Zalo, ThreadType } from "zca-js";
|
|
106
|
+
```ts
|
|
107
|
+
import { Zalo, ThreadType } from "@softtynet/zca-js";
|
|
89
108
|
|
|
90
|
-
const zalo = new Zalo();
|
|
109
|
+
const zalo = new Zalo({ selfListen: true });
|
|
91
110
|
const api = await zalo.loginQR();
|
|
92
111
|
|
|
93
112
|
api.listener.on("message", (message) => {
|
|
94
113
|
const isPlainText = typeof message.data.content === "string";
|
|
114
|
+
if (!isPlainText) return;
|
|
95
115
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
}
|
|
101
|
-
break;
|
|
102
|
-
}
|
|
103
|
-
case ThreadType.Group: {
|
|
104
|
-
if (isPlainText) {
|
|
105
|
-
// received plain text group message
|
|
106
|
-
}
|
|
107
|
-
break;
|
|
108
|
-
}
|
|
116
|
+
if (message.type === ThreadType.User) {
|
|
117
|
+
console.log(`[Cá nhân] ${message.data.dName}: ${message.data.content}`);
|
|
118
|
+
} else if (message.type === ThreadType.Group) {
|
|
119
|
+
console.log(`[Nhóm ${message.threadId}] ${message.data.dName}: ${message.data.content}`);
|
|
109
120
|
}
|
|
110
121
|
});
|
|
111
122
|
|
|
112
|
-
api.listener.start();
|
|
123
|
+
api.listener.start({ retryOnClose: true });
|
|
113
124
|
```
|
|
114
125
|
|
|
115
126
|
> [!IMPORTANT]
|
|
116
|
-
>
|
|
127
|
+
> Mỗi tài khoản Zalo chỉ duy trì một kết nối WebSocket Web tại một thời điểm. Nếu bạn mở thêm tab Zalo Web trên trình duyệt, kết nối WebSocket cũ sẽ nhận sự kiện `duplicate_connection`.
|
|
117
128
|
|
|
118
|
-
###
|
|
129
|
+
### 3. Đồng bộ bù tin nhắn khi Offline (Catch-up Sync)
|
|
119
130
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
#### 1. Catch Up Missed Messages After Reconnect / Restart
|
|
123
|
-
```javascript
|
|
124
|
-
import { Zalo, ThreadType } from "zca-js";
|
|
131
|
+
```ts
|
|
132
|
+
import { ThreadType } from "@softtynet/zca-js";
|
|
125
133
|
|
|
134
|
+
// 1. Lấy nhanh các tin nhắn mới nhất & danh sách đã đọc qua HTTP (cmd 10053)
|
|
126
135
|
const preload = await api.preloadConversations();
|
|
127
|
-
console.log(`Preloaded ${preload.messages.length}
|
|
136
|
+
console.log(`Preloaded: ${preload.messages.length} tin nhắn, ${preload.unreadCleared.length} trạng thái đã đọc`);
|
|
128
137
|
|
|
138
|
+
// 2. Nhận tin nhắn từ hàng đợi WebSocket (cmd 510 & 511)
|
|
129
139
|
api.listener.on("old_messages", (messages, type, hasMore) => {
|
|
130
|
-
console.log(`
|
|
140
|
+
console.log(`Nhận ${messages.length} tin nhắn cũ (type=${type}, hasMore=${hasMore})`);
|
|
141
|
+
if (hasMore && messages.length > 0) {
|
|
142
|
+
const lastMsgId = messages[messages.length - 1].data.msgId;
|
|
143
|
+
api.listener.requestOldMessages(type, lastMsgId);
|
|
144
|
+
}
|
|
131
145
|
});
|
|
132
146
|
|
|
147
|
+
// 3. Kích hoạt kéo hàng đợi ngay khi nhận khoá giải mã WebSocket
|
|
133
148
|
api.listener.on("cipher_key", () => {
|
|
134
149
|
api.listener.requestOldMessages(ThreadType.User);
|
|
135
150
|
api.listener.requestOldMessages(ThreadType.Group);
|
|
@@ -138,155 +153,122 @@ api.listener.on("cipher_key", () => {
|
|
|
138
153
|
api.listener.start({ retryOnClose: true });
|
|
139
154
|
```
|
|
140
155
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
156
|
+
### 4. Đồng bộ lịch sử sao lưu từ Điện thoại (`ZDB4.0`)
|
|
157
|
+
|
|
158
|
+
```ts
|
|
159
|
+
import fs from "node:fs";
|
|
160
|
+
import {
|
|
161
|
+
SyncEventType,
|
|
162
|
+
decryptWithPrivateKey,
|
|
163
|
+
deriveZdbAesKey,
|
|
164
|
+
decryptZdbBuffer,
|
|
165
|
+
parseZdbHeader,
|
|
166
|
+
} from "@softtynet/zca-js";
|
|
144
167
|
|
|
145
168
|
let privateKey = "";
|
|
146
169
|
|
|
147
170
|
api.listener.on("sync_event", async (event) => {
|
|
148
171
|
if (event.type === SyncEventType.USER_CONFIRM) {
|
|
149
|
-
console.log("
|
|
172
|
+
console.log("Người dùng đã bấm xác nhận trên điện thoại, đang chờ tải gói sao lưu...");
|
|
150
173
|
} else if (event.type === SyncEventType.SYNCMSG_INFO) {
|
|
151
174
|
const res = await api.getSyncData({ ...event.data, savePath: "./sync_data" });
|
|
152
175
|
if (res.success && res.data && privateKey) {
|
|
153
176
|
const rawRsa = decryptWithPrivateKey(privateKey, res.data.encrypted_key);
|
|
154
177
|
const aesKey = deriveZdbAesKey(rawRsa);
|
|
155
|
-
|
|
178
|
+
const zdbPlain = decryptZdbBuffer(fs.readFileSync(res.data.file_path), aesKey);
|
|
179
|
+
const toc = parseZdbHeader(zdbPlain);
|
|
180
|
+
console.log(`Giải mã thành công ZDB4.0 (${toc.entries.length} hội thoại SQLite):`, toc.entries.slice(0, 5));
|
|
156
181
|
}
|
|
157
182
|
}
|
|
158
183
|
});
|
|
159
184
|
|
|
160
|
-
api.listener.on("
|
|
161
|
-
const session = await api.requestSyncFromPhone();
|
|
185
|
+
api.listener.on("cipher_key", async () => {
|
|
186
|
+
const session = await api.requestSyncFromPhone({ pcName: "Web" });
|
|
162
187
|
privateKey = session.privateKey;
|
|
163
|
-
console.log("
|
|
188
|
+
console.log("Vui lòng mở điện thoại và bấm 'Đồng bộ ngay' trên thông báo Zalo!");
|
|
164
189
|
});
|
|
165
|
-
|
|
166
|
-
api.listener.start();
|
|
167
190
|
```
|
|
168
191
|
|
|
169
|
-
###
|
|
192
|
+
### 5. Khởi tạo Cuộc gọi Thoại & Gọi Video
|
|
170
193
|
|
|
171
|
-
```
|
|
172
|
-
import { CallType } from "zca-js";
|
|
194
|
+
```ts
|
|
195
|
+
import { CallType } from "@softtynet/zca-js";
|
|
173
196
|
|
|
174
|
-
|
|
175
|
-
const call = await api.sendVoiceCall("target_user_id", { callType: CallType.Audio });
|
|
176
|
-
console.log("Ringing callId:", call.callId, "session:", call.sessId);
|
|
177
|
-
|
|
178
|
-
// Cancel ringing or end an active call
|
|
179
|
-
await api.cancelVoiceCall("target_user_id", call.callId);
|
|
180
|
-
```
|
|
197
|
+
const targetUid = "5249661060655759359"; // Chuỗi UID 19 chữ số
|
|
181
198
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
const zalo = new Zalo();
|
|
188
|
-
const api = await zalo.loginQR();
|
|
199
|
+
// Gọi Video (CallType.Video = 3, tự động đính kèm H.264 payload 97)
|
|
200
|
+
const videoCall = await api.sendVoiceCall(targetUid, {
|
|
201
|
+
callType: CallType.Video,
|
|
202
|
+
});
|
|
203
|
+
console.log("Đang đổ chuông Video:", videoCall.callId, videoCall.rtpServer);
|
|
189
204
|
|
|
190
|
-
//
|
|
191
|
-
api.
|
|
192
|
-
|
|
193
|
-
if (message.isSelf || !isPlainText) return;
|
|
194
|
-
|
|
195
|
-
switch (message.type) {
|
|
196
|
-
case ThreadType.User: {
|
|
197
|
-
api.sendMessage(
|
|
198
|
-
{
|
|
199
|
-
msg: "echo: " + message.data.content,
|
|
200
|
-
quote: message.data, // the message to reply to (optional)
|
|
201
|
-
},
|
|
202
|
-
message.threadId,
|
|
203
|
-
message.type, // ThreadType.User
|
|
204
|
-
);
|
|
205
|
-
break;
|
|
206
|
-
}
|
|
207
|
-
case ThreadType.Group: {
|
|
208
|
-
api.sendMessage(
|
|
209
|
-
{
|
|
210
|
-
msg: "echo: " + message.data.content,
|
|
211
|
-
quote: message.data, // the message to reply to (optional)
|
|
212
|
-
},
|
|
213
|
-
message.threadId,
|
|
214
|
-
message.type, // ThreadType.Group
|
|
215
|
-
);
|
|
216
|
-
break;
|
|
217
|
-
}
|
|
218
|
-
}
|
|
205
|
+
// Huỷ cuộc gọi khi đang đổ chuông
|
|
206
|
+
await api.cancelVoiceCall(targetUid, videoCall.callId, {
|
|
207
|
+
callType: CallType.Video,
|
|
219
208
|
});
|
|
220
209
|
|
|
221
|
-
|
|
210
|
+
// Hoặc gọi Thoại (CallType.Audio = 1)
|
|
211
|
+
const audioCall = await api.sendVoiceCall(targetUid, {
|
|
212
|
+
callType: CallType.Audio,
|
|
213
|
+
});
|
|
214
|
+
await api.cancelVoiceCall(targetUid, audioCall.callId);
|
|
222
215
|
```
|
|
223
216
|
|
|
224
|
-
###
|
|
225
|
-
|
|
226
|
-
```
|
|
227
|
-
|
|
228
|
-
|
|
217
|
+
### 6. Gửi tin nhắn & Sticker
|
|
218
|
+
|
|
219
|
+
```ts
|
|
220
|
+
// Trả lời tin nhắn văn bản
|
|
221
|
+
await api.sendMessage(
|
|
222
|
+
{
|
|
223
|
+
msg: "Xin chào từ hệ thống Softtynet!",
|
|
224
|
+
quote: message.data,
|
|
225
|
+
},
|
|
226
|
+
message.threadId,
|
|
227
|
+
message.type,
|
|
228
|
+
);
|
|
229
|
+
|
|
230
|
+
// Tìm và gửi Sticker
|
|
231
|
+
const stickerIds = await api.getStickers("xin chào");
|
|
232
|
+
if (stickerIds.length > 0) {
|
|
229
233
|
const stickerObject = await api.getStickersDetail(stickerIds[0]);
|
|
230
|
-
api.sendMessageSticker(
|
|
231
|
-
|
|
232
|
-
message.threadId,
|
|
233
|
-
message.type, // ThreadType.User or ThreadType.Group
|
|
234
|
-
);
|
|
235
|
-
});
|
|
234
|
+
await api.sendMessageSticker(stickerObject, message.threadId, message.type);
|
|
235
|
+
}
|
|
236
236
|
```
|
|
237
237
|
|
|
238
238
|
---
|
|
239
239
|
|
|
240
|
-
##
|
|
241
|
-
|
|
242
|
-
See [examples](examples) folder for more details.
|
|
243
|
-
|
|
244
|
-
---
|
|
240
|
+
## 🧪 Kiểm định & Chạy thử nghiệm
|
|
245
241
|
|
|
246
|
-
|
|
242
|
+
Dự án đi kèm bộ kiểm định 2 lớp trong thư mục [`test/`](test):
|
|
247
243
|
|
|
248
|
-
|
|
244
|
+
1. **Kiểm định tự động (Offline / Unit Verification Suite)**:
|
|
245
|
+
```bash
|
|
246
|
+
npm run test:verify
|
|
247
|
+
```
|
|
248
|
+
Kiểm tra tự động toàn bộ 6 hạng mục: `preloadConversations`, `requestSyncFromPhone` / `pullMobile` / `cancelPullMobile`, `getNoisedIds` / `decryptGids`, giải mã `RSA-2048` + `ZDB4.0` đa khối 64KB, `sendVoiceCall` (Audio & Video) / `cancelVoiceCall` / `endVoiceCall`, và các sự kiện WebSocket (`510`, `511`, `504`, `601`).
|
|
249
249
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
| [**n8n-nodes-zalo-tools**](https://github.com/ChickenAI/zalo-node) | N8N node for personal Zalo account. |
|
|
255
|
-
| [**Zalo-F12**](https://github.com/ElectroHeavenVN/Zalo-F12) | A collection of JavaScript code snippets to paste into DevTools to change how Zalo Web/PC works. |
|
|
256
|
-
| [**Zalo-F12-Tools**](https://github.com/JustKemForFun/Zalo-F12-Tools) | Toggle hidden modes for Zalo Web. |
|
|
250
|
+
2. **Kiểm định trực tiếp trên tài khoản Zalo thật (Live Verification Suite)**:
|
|
251
|
+
```bash
|
|
252
|
+
# Chạy toàn bộ 6 bước (Quét QR -> Preload -> ZNoise -> OldMessages -> Đồng bộ ZDB4.0 từ ĐT -> Voice/Video Call)
|
|
253
|
+
npm run test:live
|
|
257
254
|
|
|
258
|
-
|
|
255
|
+
# Chỉ test nhanh Gọi Thoại + Gọi Video tới 1 UID bạn bè
|
|
256
|
+
npm run test:live -- --only-call --call <UID_BAN_BE>
|
|
257
|
+
```
|
|
259
258
|
|
|
260
259
|
---
|
|
261
260
|
|
|
262
|
-
##
|
|
263
|
-
|
|
264
|
-
We welcome contributions from the community! Please see our [Contributing Guidelines](CONTRIBUTING.md) for details on how to:
|
|
265
|
-
|
|
266
|
-
- 🐛 Report bugs and issues
|
|
267
|
-
- ✨ Suggest new features
|
|
268
|
-
- 🔧 Submit code contributions
|
|
269
|
-
- 📚 Improve documentation
|
|
270
|
-
- 🧪 Add or improve tests
|
|
271
|
-
- 🔒 Report security vulnerabilities
|
|
261
|
+
## 🤝 Nguồn gốc & Ghi nhận (Credits & Attribution)
|
|
272
262
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
---
|
|
263
|
+
Dự án **`@softtynet/zca-js`** được phát triển, nâng cấp và duy trì bởi **Softtynet Co., Ltd.** ([`softtyos/zca-js`](https://github.com/softtyos/zca-js)), kế thừa nền tảng mã nguồn mở từ dự án gốc:
|
|
276
264
|
|
|
277
|
-
|
|
265
|
+
- **Dự án gốc**: [RFS-ADRENO/zca-js](https://github.com/RFS-ADRENO/zca-js)
|
|
266
|
+
- **Tác giả nền tảng gốc**: RFS-ADRENO, truong9c2208, JustKemForFun cùng các thành viên đóng góp từ cộng đồng mã nguồn mở.
|
|
278
267
|
|
|
279
|
-
|
|
268
|
+
Chúng tôi trân trọng cảm ơn các tác giả của dự án gốc đã xây dựng nền tảng ban đầu cho cộng đồng JavaScript/TypeScript.
|
|
280
269
|
|
|
281
270
|
---
|
|
282
271
|
|
|
283
|
-
##
|
|
272
|
+
## 📄 Giấy phép (License)
|
|
284
273
|
|
|
285
|
-
|
|
286
|
-
- 🔄 **Share** with your network to help us grow
|
|
287
|
-
- 💡 **Contribute** your ideas and code
|
|
288
|
-
- ☕ **A coffee**:
|
|
289
|
-
- [Buy Me a Coffee](https://ko-fi.com/grosse)
|
|
290
|
-
- [Paypal](https://www.paypal.com/paypalme/dungto213)
|
|
291
|
-
- [VietQR](https://github.com/user-attachments/assets/e1f319d6-9d11-4082-8248-55b55e645caa)
|
|
292
|
-
- [Momo](https://me.momo.vn/gMIMulsaUqsbf6iAiXt3)
|
|
274
|
+
Phát hành theo giấy phép [MIT License](LICENSE).
|
package/dist/cjs/update.cjs
CHANGED
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
var semver = require('semver');
|
|
4
4
|
var utils = require('./utils.cjs');
|
|
5
5
|
|
|
6
|
-
const VERSION = "2.2.
|
|
7
|
-
const NPM_REGISTRY = "https://registry.npmjs.org/zca-js";
|
|
6
|
+
const VERSION = "2.2.7";
|
|
7
|
+
const NPM_REGISTRY = "https://registry.npmjs.org/@softtynet/zca-js";
|
|
8
8
|
async function checkUpdate(ctx) {
|
|
9
|
-
var _a, _b;
|
|
9
|
+
var _a, _b, _c;
|
|
10
10
|
if (!ctx.options.checkUpdate)
|
|
11
11
|
return;
|
|
12
12
|
const _options = Object.assign({}, (utils.isBun
|
|
@@ -22,12 +22,14 @@ async function checkUpdate(ctx) {
|
|
|
22
22
|
const data = await response.json().catch(() => null);
|
|
23
23
|
if (!data)
|
|
24
24
|
return;
|
|
25
|
-
const latestVersion = data["dist-tags"].latest;
|
|
25
|
+
const latestVersion = (_c = data["dist-tags"]) === null || _c === void 0 ? void 0 : _c.latest;
|
|
26
|
+
if (!latestVersion)
|
|
27
|
+
return;
|
|
26
28
|
if (semver.compare(VERSION, latestVersion) === -1) {
|
|
27
|
-
utils.logger(ctx).info(`A new version of zca-js is available: ${latestVersion}`);
|
|
29
|
+
utils.logger(ctx).info(`A new version of @softtynet/zca-js is available: ${latestVersion}`);
|
|
28
30
|
}
|
|
29
31
|
else {
|
|
30
|
-
utils.logger(ctx).info("zca-js is up to date");
|
|
32
|
+
utils.logger(ctx).info("@softtynet/zca-js is up to date");
|
|
31
33
|
}
|
|
32
34
|
}
|
|
33
35
|
|
package/dist/update.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { compare } from "semver";
|
|
2
2
|
import { isBun, logger } from "./utils.js";
|
|
3
|
-
const VERSION = "2.2.
|
|
4
|
-
const NPM_REGISTRY = "https://registry.npmjs.org/zca-js";
|
|
3
|
+
const VERSION = "2.2.7";
|
|
4
|
+
const NPM_REGISTRY = "https://registry.npmjs.org/@softtynet/zca-js";
|
|
5
5
|
export async function checkUpdate(ctx) {
|
|
6
|
-
var _a, _b;
|
|
6
|
+
var _a, _b, _c;
|
|
7
7
|
if (!ctx.options.checkUpdate)
|
|
8
8
|
return;
|
|
9
9
|
const _options = Object.assign({}, (isBun
|
|
@@ -19,11 +19,13 @@ export async function checkUpdate(ctx) {
|
|
|
19
19
|
const data = await response.json().catch(() => null);
|
|
20
20
|
if (!data)
|
|
21
21
|
return;
|
|
22
|
-
const latestVersion = data["dist-tags"].latest;
|
|
22
|
+
const latestVersion = (_c = data["dist-tags"]) === null || _c === void 0 ? void 0 : _c.latest;
|
|
23
|
+
if (!latestVersion)
|
|
24
|
+
return;
|
|
23
25
|
if (compare(VERSION, latestVersion) === -1) {
|
|
24
|
-
logger(ctx).info(`A new version of zca-js is available: ${latestVersion}`);
|
|
26
|
+
logger(ctx).info(`A new version of @softtynet/zca-js is available: ${latestVersion}`);
|
|
25
27
|
}
|
|
26
28
|
else {
|
|
27
|
-
logger(ctx).info("zca-js is up to date");
|
|
29
|
+
logger(ctx).info("@softtynet/zca-js is up to date");
|
|
28
30
|
}
|
|
29
31
|
}
|