zalo-toolkit 1.0.2 → 1.0.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/dist/apis/fetchAccountInfo.d.ts +4 -2
- package/dist/cjs/apis/listen.cjs +822 -0
- package/dist/cjs/models/Listen.cjs +32 -0
- package/dist/cjs/socket/config-socket.cjs +203 -0
- package/dist/cjs/utils.cjs +184 -4
- package/dist/cjs/zalo.cjs +4 -0
- package/dist/zalo.d.ts +2 -0
- package/dist/zalo.js +4 -0
- package/package.json +1 -1
|
@@ -122,6 +122,7 @@ exports.PingType = void 0;
|
|
|
122
122
|
PingType[PingType["SwitchToBackground"] = 3] = "SwitchToBackground";
|
|
123
123
|
PingType[PingType["BackgroundKeepAlive"] = 4] = "BackgroundKeepAlive";
|
|
124
124
|
})(exports.PingType || (exports.PingType = {}));
|
|
125
|
+
const DEFAULT_RETRY_DELAYS = [1000, 10000, 30000, 60000];
|
|
125
126
|
exports.EventTypes = void 0;
|
|
126
127
|
(function (EventTypes) {
|
|
127
128
|
EventTypes["GOT_CLEAR_UNREADS"] = "GOT_CLEAR_UNREADS";
|
|
@@ -132,3 +133,34 @@ exports.EventTypes = void 0;
|
|
|
132
133
|
EventTypes["SOCKET_STATE_CHANGED"] = "ON_SOCKET_STT_CHANGED";
|
|
133
134
|
EventTypes["DONE_CHECK_OVERFLOW"] = "DONE_CHECK_OVERFLOW";
|
|
134
135
|
})(exports.EventTypes || (exports.EventTypes = {}));
|
|
136
|
+
const MessageTypes = {
|
|
137
|
+
'516': 'SESSION_OFFLINE',
|
|
138
|
+
'517': 'SESSION_OFFLINE',
|
|
139
|
+
'518': 'OFFLINE_ACK_ONE_ONE',
|
|
140
|
+
'519': 'OFFLINE_ACK_GROUP',
|
|
141
|
+
'543': 'INIT_SESSION',
|
|
142
|
+
'544': 'ACK_INIT_SESSION',
|
|
143
|
+
'545': 'INIT_SESSION',
|
|
144
|
+
'546': 'RECEIVE_ACK_GROUP_SESSIONS_STALE',
|
|
145
|
+
'548': 'NOTIFY_DELETE_KEY',
|
|
146
|
+
'549': 'REQUEST_PREKEYS',
|
|
147
|
+
'559': 'RECEIVE_ACK_PROCESS_INIT_GROUP_FAILED',
|
|
148
|
+
'561': 'INIT_SESSION_GROUP',
|
|
149
|
+
'580': 'DISABLE_E2EE',
|
|
150
|
+
'581': 'ENABLE_E2EE',
|
|
151
|
+
'582': 'RECEIVE_DOWNGRADE_E2EE_GROUP',
|
|
152
|
+
};
|
|
153
|
+
const SignalCommands = {
|
|
154
|
+
INIT: {
|
|
155
|
+
OFFLINE_ACK_GROUP: 519},
|
|
156
|
+
ACK: {
|
|
157
|
+
DELETE_QUEUE_ACK_ONEONE: 557,
|
|
158
|
+
DELETE_QUEUE_ACK_GROUP: 558,
|
|
159
|
+
},
|
|
160
|
+
};
|
|
161
|
+
const MAX_CHUNK_WS = 5;
|
|
162
|
+
|
|
163
|
+
exports.DEFAULT_RETRY_DELAYS = DEFAULT_RETRY_DELAYS;
|
|
164
|
+
exports.MAX_CHUNK_WS = MAX_CHUNK_WS;
|
|
165
|
+
exports.MessageTypes = MessageTypes;
|
|
166
|
+
exports.SignalCommands = SignalCommands;
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var Listen = require('../models/Listen.cjs');
|
|
4
|
+
var WebSocket = require('ws');
|
|
5
|
+
|
|
6
|
+
class ConfigSocket {
|
|
7
|
+
constructor(ws, features, ctx, listen) {
|
|
8
|
+
this.overflowTracker = {};
|
|
9
|
+
this.offlineCmds = new Map();
|
|
10
|
+
this.offlineWaiter = new Map();
|
|
11
|
+
this.pollId = {};
|
|
12
|
+
this.isDoneOffline = false;
|
|
13
|
+
this.emitter = ws;
|
|
14
|
+
this.features = features;
|
|
15
|
+
this.ctx = ctx;
|
|
16
|
+
this.listen = listen;
|
|
17
|
+
}
|
|
18
|
+
getLastActionIdsForSocket(socketKey) {
|
|
19
|
+
const defaultResult = { lastId: 1, preIds: [] };
|
|
20
|
+
if (this.pollId.hasOwnProperty(socketKey)) {
|
|
21
|
+
const { lastId } = this.pollId[socketKey];
|
|
22
|
+
const preIds = this.pollId[socketKey].control.getLastActionIdsArray(lastId).slice(0, 10);
|
|
23
|
+
return { lastId, preIds };
|
|
24
|
+
}
|
|
25
|
+
return defaultResult;
|
|
26
|
+
}
|
|
27
|
+
immediateDoNextOfflineReq(cmd) {
|
|
28
|
+
var _a;
|
|
29
|
+
return !((_a = this.features.socket.none_ids_queue) === null || _a === void 0 ? void 0 : _a.includes(cmd + ''));
|
|
30
|
+
}
|
|
31
|
+
getSocketState() {
|
|
32
|
+
return this.emitter ? this.emitter.readyState : -1;
|
|
33
|
+
}
|
|
34
|
+
sendWs(payload) {
|
|
35
|
+
if (this.emitter && this.getSocketState() === WebSocket.WebSocket.OPEN) {
|
|
36
|
+
const encodedData = new TextEncoder().encode(JSON.stringify(payload.data));
|
|
37
|
+
const dataLength = encodedData.length;
|
|
38
|
+
const data = new DataView(Buffer.alloc(4 + dataLength).buffer);
|
|
39
|
+
data.setUint8(0, payload.version);
|
|
40
|
+
data.setInt32(1, payload.cmd, true);
|
|
41
|
+
data.setInt8(3, payload.subCmd);
|
|
42
|
+
encodedData.forEach((e, i) => {
|
|
43
|
+
data.setUint8(4 + i, e);
|
|
44
|
+
});
|
|
45
|
+
this.emitter.send(data);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
async doGetOffline(cmd, subCmd, first, lastActionId) {
|
|
49
|
+
var _a;
|
|
50
|
+
if (typeof cmd !== 'number' || typeof subCmd !== 'number') {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
const requestPayload = {
|
|
54
|
+
cmd,
|
|
55
|
+
subCmd,
|
|
56
|
+
data: {
|
|
57
|
+
first,
|
|
58
|
+
reqId: this.listen.genNextReqId(),
|
|
59
|
+
lastId: 1,
|
|
60
|
+
preIds: [],
|
|
61
|
+
},
|
|
62
|
+
version: 1,
|
|
63
|
+
};
|
|
64
|
+
if (!((_a = this.features.socket.none_ids_queue) === null || _a === void 0 ? void 0 : _a.includes(`${cmd}`))) {
|
|
65
|
+
const trackerKey = `${cmd}_${subCmd}`;
|
|
66
|
+
this.offlineWaiter.set(trackerKey, this.createOfflineWaiter());
|
|
67
|
+
const { lastId, preIds } = this.getLastActionIdsForSocket(`${cmd}_${subCmd}`);
|
|
68
|
+
requestPayload.data.lastId = lastActionId !== undefined ? lastActionId : lastId;
|
|
69
|
+
requestPayload.data.preIds = preIds;
|
|
70
|
+
}
|
|
71
|
+
this.sendWs(requestPayload);
|
|
72
|
+
}
|
|
73
|
+
createOfflineWaiter() {
|
|
74
|
+
const waiter = { resolve: null, reject: null, promise: null };
|
|
75
|
+
const promise = new Promise((resolve, reject) => {
|
|
76
|
+
waiter.resolve = resolve;
|
|
77
|
+
waiter.reject = reject;
|
|
78
|
+
});
|
|
79
|
+
waiter.promise = promise;
|
|
80
|
+
return waiter;
|
|
81
|
+
}
|
|
82
|
+
ackOfflineQueue(isGroup, data) {
|
|
83
|
+
const command = isGroup ? Listen.SignalCommands.ACK.DELETE_QUEUE_ACK_GROUP : Listen.SignalCommands.ACK.DELETE_QUEUE_ACK_ONEONE;
|
|
84
|
+
return this.requestAsyncV2({
|
|
85
|
+
cmd: command,
|
|
86
|
+
data: { data },
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
isValidSendPayload(payload) {
|
|
90
|
+
if (!payload || !payload.cmd || payload.data == null) {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
getReqId(e) {
|
|
96
|
+
return [Listen.MessageCommand.PingActive].includes(e) ? `cmd_${e}` : this.listen.genNextReqId();
|
|
97
|
+
}
|
|
98
|
+
addCommonParams(payload) {
|
|
99
|
+
const reqId = this.getReqId(payload.cmd);
|
|
100
|
+
return Object.assign(Object.assign({}, payload), { data: Object.assign(Object.assign({}, payload.data), { reqId }) });
|
|
101
|
+
}
|
|
102
|
+
requestAsyncV2(payload) {
|
|
103
|
+
return new Promise((resolve, reject) => {
|
|
104
|
+
if (!this.isValidSendPayload(payload)) {
|
|
105
|
+
return reject('Invalid params');
|
|
106
|
+
}
|
|
107
|
+
const requestData = this.addCommonParams(payload);
|
|
108
|
+
this.sendWs(requestData);
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
async onOfflineData(cmd, subCmd, data, options = { isLastQueue: false }) {
|
|
112
|
+
var _a;
|
|
113
|
+
if (this.features.e2ee.debug.make_slow_pull_offline && this.features.e2ee.debug.enable) {
|
|
114
|
+
await new Promise((resolve) => setTimeout(resolve, 5000));
|
|
115
|
+
}
|
|
116
|
+
if (((_a = this.features.socket.none_ids_queue) === null || _a === void 0 ? void 0 : _a.includes(`${cmd}`)) && data.data.delivereds.length) {
|
|
117
|
+
const delivereds = [...data.data.delivereds];
|
|
118
|
+
const isAckGroup = cmd === Listen.SignalCommands.INIT.OFFLINE_ACK_GROUP;
|
|
119
|
+
const chunkPromises = [];
|
|
120
|
+
while (delivereds.length > 0) {
|
|
121
|
+
const chunk = delivereds.splice(0, Listen.MAX_CHUNK_WS);
|
|
122
|
+
chunkPromises.push(this.ackOfflineQueue(isAckGroup, { delivereds: chunk }));
|
|
123
|
+
}
|
|
124
|
+
await Promise.all(chunkPromises).catch((error) => console.log(['Error when deleting queue offline {}'], error));
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
async onGotOffline(cmd, subCmd, data) {
|
|
128
|
+
var _a;
|
|
129
|
+
if (data && data.data) {
|
|
130
|
+
// this.webStartUp.onPollData(`${cmd}_${subCmd}`, data);
|
|
131
|
+
// this.checkQueueOverflow(cmd, subCmd, data);
|
|
132
|
+
if (data.data.more) {
|
|
133
|
+
const lastActionId = (_a = data.data) === null || _a === void 0 ? void 0 : _a.lastActionId;
|
|
134
|
+
if (this.immediateDoNextOfflineReq(cmd)) {
|
|
135
|
+
await this.doGetOffline(cmd, subCmd, false, lastActionId);
|
|
136
|
+
this.onOfflineData(cmd, subCmd, data, { isLastQueue: false });
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
await this.onOfflineData(cmd, subCmd, data, { isLastQueue: false });
|
|
140
|
+
await this.doGetOffline(cmd, subCmd, false, lastActionId);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
const trackerKey = `${cmd}_${subCmd}`;
|
|
145
|
+
const isLastQueue = this.offlineWaiter.size === 1;
|
|
146
|
+
// this.webStartUp.onEndPoll(trackerKey, data.data.lastActionId);
|
|
147
|
+
this.onOfflineData(cmd, subCmd, data, { isLastQueue });
|
|
148
|
+
this.onDoneOfflineQueue(trackerKey);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
checkQueueOverflow(cmd, subCmd, data) {
|
|
153
|
+
var _a, _b, _c;
|
|
154
|
+
const trackerKey = `${cmd}_${subCmd}`;
|
|
155
|
+
if (this.overflowTracker[trackerKey] !== undefined)
|
|
156
|
+
return;
|
|
157
|
+
if (!this.offlineCmds.has(cmd))
|
|
158
|
+
return;
|
|
159
|
+
const isEvicted = ((_c = (_b = (_a = data === null || data === void 0 ? void 0 : data.data) === null || _a === void 0 ? void 0 : _a.queueStatus) === null || _b === void 0 ? void 0 : _b[trackerKey]) === null || _c === void 0 ? void 0 : _c.evict) === 1;
|
|
160
|
+
this.overflowTracker[trackerKey] = isEvicted;
|
|
161
|
+
const trackerKeys = Object.keys(this.overflowTracker);
|
|
162
|
+
if (this.offlineCmds.size === trackerKeys.length) {
|
|
163
|
+
const overflowedKeys = trackerKeys.filter((key) => this.overflowTracker[key]);
|
|
164
|
+
this.emitter.emit(Listen.EventTypes.DONE_CHECK_OVERFLOW, overflowedKeys);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
handleSocketMsg(cmd, payload) {
|
|
168
|
+
if (!this.features.e2ee.enable && this.features.e2ee.skip_on_disabled) {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
const actionHandler = Listen.MessageTypes[cmd];
|
|
172
|
+
if (!actionHandler) {
|
|
173
|
+
throw new Error(`Unsupported action type: ${cmd}`);
|
|
174
|
+
}
|
|
175
|
+
return this.emitter.emit(actionHandler, {
|
|
176
|
+
cmd,
|
|
177
|
+
payload,
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
onDoneOfflineQueue(queueId) {
|
|
181
|
+
const waiter = this.offlineWaiter.get(queueId);
|
|
182
|
+
if (waiter) {
|
|
183
|
+
// Resolve the waiter and remove it from the map
|
|
184
|
+
waiter.resolve(true);
|
|
185
|
+
this.offlineWaiter.delete(queueId);
|
|
186
|
+
// If all waiters are done, process the completion of all offline tasks
|
|
187
|
+
if (this.offlineWaiter.size === 0) {
|
|
188
|
+
this.onDoneOfflineAll();
|
|
189
|
+
// this.processPending(null);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
onDoneOfflineAll() {
|
|
194
|
+
this.isDoneOffline = true;
|
|
195
|
+
// Clear offline timer if it's set
|
|
196
|
+
if (this.offlineTimer) {
|
|
197
|
+
clearTimeout(this.offlineTimer);
|
|
198
|
+
this.offlineTimer = null;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
exports.ConfigSocket = ConfigSocket;
|
package/dist/cjs/utils.cjs
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var cryptojs = require('crypto-js');
|
|
4
|
-
require('json-bigint');
|
|
4
|
+
var JSONBig = require('json-bigint');
|
|
5
5
|
var crypto = require('node:crypto');
|
|
6
6
|
require('node:fs');
|
|
7
7
|
var path = require('node:path');
|
|
8
|
-
require('pako');
|
|
8
|
+
var pako = require('pako');
|
|
9
9
|
var SparkMD5 = require('spark-md5');
|
|
10
10
|
var ToughCookie = require('tough-cookie');
|
|
11
11
|
var sharp = require('sharp');
|
|
12
12
|
var context = require('./context.cjs');
|
|
13
13
|
var ZaloApiError = require('./Errors/ZaloApiError.cjs');
|
|
14
|
-
require('./models/FriendEvent.cjs');
|
|
15
|
-
require('./models/GroupEvent.cjs');
|
|
14
|
+
var FriendEvent = require('./models/FriendEvent.cjs');
|
|
15
|
+
var GroupEvent = require('./models/GroupEvent.cjs');
|
|
16
16
|
|
|
17
17
|
// export const isBun = typeof Bun !== "undefined";
|
|
18
18
|
function hasOwn(obj, key) {
|
|
@@ -192,6 +192,17 @@ function decodeRespAES(key, data) {
|
|
|
192
192
|
padding: cryptojs.pad.Pkcs7,
|
|
193
193
|
}).toString(cryptojs.enc.Utf8);
|
|
194
194
|
}
|
|
195
|
+
function decodeBase64ToBuffer(data) {
|
|
196
|
+
return Buffer.from(data, 'base64');
|
|
197
|
+
}
|
|
198
|
+
function decodeUnit8Array(data) {
|
|
199
|
+
try {
|
|
200
|
+
return new TextDecoder().decode(data);
|
|
201
|
+
}
|
|
202
|
+
catch (_a) {
|
|
203
|
+
return null;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
195
206
|
function encodeAES(secretKey, data, t = 0) {
|
|
196
207
|
try {
|
|
197
208
|
const key = cryptojs.enc.Base64.parse(secretKey);
|
|
@@ -295,6 +306,41 @@ async function getGifMetaData(file) {
|
|
|
295
306
|
height: gifData.height,
|
|
296
307
|
};
|
|
297
308
|
}
|
|
309
|
+
async function decodeEventData(parsed, cipherKey) {
|
|
310
|
+
if (typeof parsed.data !== 'string')
|
|
311
|
+
throw new ZaloApiError.ZaloApiError(`Invalid data, expected string but got ${typeof parsed.data}`);
|
|
312
|
+
if (typeof parsed.encrypt !== 'number')
|
|
313
|
+
throw new ZaloApiError.ZaloApiError(`Invalid encrypt type, expected number but got ${typeof parsed.encrypt}`);
|
|
314
|
+
if (parsed.encrypt < 0 || parsed.encrypt > 3)
|
|
315
|
+
throw new ZaloApiError.ZaloApiError(`Invalid encrypt type, expected 0-3 but got ${parsed.encrypt}`);
|
|
316
|
+
const rawData = parsed.data;
|
|
317
|
+
const encryptType = parsed.encrypt;
|
|
318
|
+
if (encryptType === 0)
|
|
319
|
+
return JSON.parse(rawData);
|
|
320
|
+
const decodedBuffer = decodeBase64ToBuffer(encryptType === 1 ? rawData : decodeURIComponent(rawData));
|
|
321
|
+
let decryptedBuffer = decodedBuffer;
|
|
322
|
+
if (encryptType !== 1) {
|
|
323
|
+
if (cipherKey && decodedBuffer.length >= 48) {
|
|
324
|
+
const algorithm = {
|
|
325
|
+
name: 'AES-GCM',
|
|
326
|
+
iv: decodedBuffer.subarray(0, 16),
|
|
327
|
+
tagLength: 128,
|
|
328
|
+
additionalData: decodedBuffer.subarray(16, 32),
|
|
329
|
+
};
|
|
330
|
+
const dataSource = decodedBuffer.subarray(32);
|
|
331
|
+
const cryptoKey = await crypto.subtle.importKey('raw', decodeBase64ToBuffer(cipherKey), algorithm, false, ['decrypt']);
|
|
332
|
+
decryptedBuffer = await crypto.subtle.decrypt(algorithm, cryptoKey, dataSource);
|
|
333
|
+
}
|
|
334
|
+
else {
|
|
335
|
+
throw new ZaloApiError.ZaloApiError('Invalid data length or missing cipher key');
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
const decompressedBuffer = encryptType === 3 ? new Uint8Array(decryptedBuffer) : pako.inflate(decryptedBuffer);
|
|
339
|
+
const decodedData = decodeUnit8Array(decompressedBuffer);
|
|
340
|
+
if (!decodedData)
|
|
341
|
+
return;
|
|
342
|
+
return JSONBig.parse(decodedData);
|
|
343
|
+
}
|
|
298
344
|
function getMd5LargeFileObject(file) {
|
|
299
345
|
return new Promise(async (resolve, reject) => {
|
|
300
346
|
let chunkSize = 2097152, // Read in chunks of 2MB
|
|
@@ -409,6 +455,80 @@ function removeUndefinedKeys(e) {
|
|
|
409
455
|
delete e[t];
|
|
410
456
|
return e;
|
|
411
457
|
}
|
|
458
|
+
function getGroupEventType(act) {
|
|
459
|
+
if (act == 'join_request')
|
|
460
|
+
return GroupEvent.GroupEventType.JOIN_REQUEST;
|
|
461
|
+
if (act == 'join')
|
|
462
|
+
return GroupEvent.GroupEventType.JOIN;
|
|
463
|
+
if (act == 'leave')
|
|
464
|
+
return GroupEvent.GroupEventType.LEAVE;
|
|
465
|
+
if (act == 'remove_member')
|
|
466
|
+
return GroupEvent.GroupEventType.REMOVE_MEMBER;
|
|
467
|
+
if (act == 'block_member')
|
|
468
|
+
return GroupEvent.GroupEventType.BLOCK_MEMBER;
|
|
469
|
+
if (act == 'update_setting')
|
|
470
|
+
return GroupEvent.GroupEventType.UPDATE_SETTING;
|
|
471
|
+
if (act == 'update_avatar')
|
|
472
|
+
return GroupEvent.GroupEventType.UPDATE_AVATAR;
|
|
473
|
+
if (act == 'update')
|
|
474
|
+
return GroupEvent.GroupEventType.UPDATE;
|
|
475
|
+
if (act == 'new_link')
|
|
476
|
+
return GroupEvent.GroupEventType.NEW_LINK;
|
|
477
|
+
if (act == 'add_admin')
|
|
478
|
+
return GroupEvent.GroupEventType.ADD_ADMIN;
|
|
479
|
+
if (act == 'remove_admin')
|
|
480
|
+
return GroupEvent.GroupEventType.REMOVE_ADMIN;
|
|
481
|
+
if (act == 'new_pin_topic')
|
|
482
|
+
return GroupEvent.GroupEventType.NEW_PIN_TOPIC;
|
|
483
|
+
if (act == 'update_pin_topic')
|
|
484
|
+
return GroupEvent.GroupEventType.UPDATE_PIN_TOPIC;
|
|
485
|
+
if (act == 'update_topic')
|
|
486
|
+
return GroupEvent.GroupEventType.UPDATE_TOPIC;
|
|
487
|
+
if (act == 'update_board')
|
|
488
|
+
return GroupEvent.GroupEventType.UPDATE_BOARD;
|
|
489
|
+
if (act == 'remove_board')
|
|
490
|
+
return GroupEvent.GroupEventType.REMOVE_BOARD;
|
|
491
|
+
if (act == 'reorder_pin_topic')
|
|
492
|
+
return GroupEvent.GroupEventType.REORDER_PIN_TOPIC;
|
|
493
|
+
if (act == 'unpin_topic')
|
|
494
|
+
return GroupEvent.GroupEventType.UNPIN_TOPIC;
|
|
495
|
+
if (act == 'remove_topic')
|
|
496
|
+
return GroupEvent.GroupEventType.REMOVE_TOPIC;
|
|
497
|
+
if (act == 'accept_remind')
|
|
498
|
+
return GroupEvent.GroupEventType.ACCEPT_REMIND;
|
|
499
|
+
if (act == 'reject_remind')
|
|
500
|
+
return GroupEvent.GroupEventType.REJECT_REMIND;
|
|
501
|
+
if (act == 'remind_topic')
|
|
502
|
+
return GroupEvent.GroupEventType.REMIND_TOPIC;
|
|
503
|
+
return GroupEvent.GroupEventType.UNKNOWN;
|
|
504
|
+
}
|
|
505
|
+
function getFriendEventType(act) {
|
|
506
|
+
if (act == 'add')
|
|
507
|
+
return FriendEvent.FriendEventType.ADD;
|
|
508
|
+
if (act == 'remove')
|
|
509
|
+
return FriendEvent.FriendEventType.REMOVE;
|
|
510
|
+
if (act == 'block')
|
|
511
|
+
return FriendEvent.FriendEventType.BLOCK;
|
|
512
|
+
if (act == 'unblock')
|
|
513
|
+
return FriendEvent.FriendEventType.UNBLOCK;
|
|
514
|
+
if (act == 'block_call')
|
|
515
|
+
return FriendEvent.FriendEventType.BLOCK_CALL;
|
|
516
|
+
if (act == 'unblock_call')
|
|
517
|
+
return FriendEvent.FriendEventType.UNBLOCK_CALL;
|
|
518
|
+
if (act == 'req_v2')
|
|
519
|
+
return FriendEvent.FriendEventType.REQUEST;
|
|
520
|
+
if (act == 'reject')
|
|
521
|
+
return FriendEvent.FriendEventType.REJECT_REQUEST;
|
|
522
|
+
if (act == 'undo_req')
|
|
523
|
+
return FriendEvent.FriendEventType.UNDO_REQUEST;
|
|
524
|
+
if (act == 'seen_fr_req')
|
|
525
|
+
return FriendEvent.FriendEventType.SEEN_FRIEND_REQUEST;
|
|
526
|
+
if (act == 'pin_unpin')
|
|
527
|
+
return FriendEvent.FriendEventType.PIN_UNPIN;
|
|
528
|
+
if (act == 'pin_create')
|
|
529
|
+
return FriendEvent.FriendEventType.PIN_CREATE;
|
|
530
|
+
return FriendEvent.FriendEventType.UNKNOWN;
|
|
531
|
+
}
|
|
412
532
|
async function handleZaloResponse(ctx, response, isEncrypted = true) {
|
|
413
533
|
const result = {
|
|
414
534
|
data: null,
|
|
@@ -511,16 +631,73 @@ function getSecChUaPlatform(userAgent = '') {
|
|
|
511
631
|
}
|
|
512
632
|
return '"Unknown"';
|
|
513
633
|
}
|
|
634
|
+
class FibonacciRetry {
|
|
635
|
+
constructor(maxItem = 2000, delta = 10, saltRange = 0.2) {
|
|
636
|
+
this.caches = [1, 2];
|
|
637
|
+
this.maxItem = maxItem;
|
|
638
|
+
this.delta = delta;
|
|
639
|
+
this.saltRange = saltRange;
|
|
640
|
+
}
|
|
641
|
+
/**
|
|
642
|
+
* Lấy giá trị Fibonacci tại index e (1-based)
|
|
643
|
+
* @param index - Thứ tự Fibonacci cần lấy (1-based)
|
|
644
|
+
* @returns Giá trị Fibonacci tương ứng
|
|
645
|
+
*/
|
|
646
|
+
getFibo(index) {
|
|
647
|
+
if (index <= 0)
|
|
648
|
+
throw new Error('Index must be greater than 0');
|
|
649
|
+
if (this.caches.length >= index) {
|
|
650
|
+
return this.caches[index - 1];
|
|
651
|
+
}
|
|
652
|
+
let next = 1;
|
|
653
|
+
for (let i = this.caches.length; i < index; i++) {
|
|
654
|
+
const len = this.caches.length;
|
|
655
|
+
next = this.caches[len - 1] + this.caches[len - 2];
|
|
656
|
+
this.caches.push(next);
|
|
657
|
+
}
|
|
658
|
+
if (this.caches.length > this.maxItem + this.delta) {
|
|
659
|
+
this.caches = this.caches.slice(0, this.maxItem);
|
|
660
|
+
}
|
|
661
|
+
return next;
|
|
662
|
+
}
|
|
663
|
+
/**
|
|
664
|
+
* Tính toán thời gian retry tiếp theo dựa vào số lần retry hiện tại
|
|
665
|
+
* @param count - Lần retry thứ mấy (1-based)
|
|
666
|
+
* @param multiplier - Hệ số nhân (delay mỗi lần retry)
|
|
667
|
+
* @param maxDelay - Giới hạn tối đa delay (ms)
|
|
668
|
+
* @returns Số mili giây cần chờ trước khi retry tiếp theo
|
|
669
|
+
*/
|
|
670
|
+
getNextRetry(count, multiplier, maxDelay) {
|
|
671
|
+
if (count <= 0)
|
|
672
|
+
throw new Error('Count must be greater than 0');
|
|
673
|
+
if (multiplier <= 0)
|
|
674
|
+
throw new Error('Multiplier must be greater than 0');
|
|
675
|
+
const fiboValue = this.getFibo(count);
|
|
676
|
+
const baseDelay = fiboValue * multiplier;
|
|
677
|
+
const randomFactor = 1 + this.saltRange * Math.random();
|
|
678
|
+
if (maxDelay !== undefined && baseDelay > maxDelay) {
|
|
679
|
+
return maxDelay * randomFactor;
|
|
680
|
+
}
|
|
681
|
+
return baseDelay * randomFactor;
|
|
682
|
+
}
|
|
683
|
+
}
|
|
514
684
|
function handleQueueStatus(queueStatus) {
|
|
515
685
|
for (const key in queueStatus) {
|
|
516
686
|
delete queueStatus[key].ids;
|
|
517
687
|
}
|
|
518
688
|
return queueStatus;
|
|
519
689
|
}
|
|
690
|
+
function looksLikeJson(str) {
|
|
691
|
+
return /^[\[{].*[\]}]$/.test(str.trim());
|
|
692
|
+
}
|
|
520
693
|
|
|
694
|
+
exports.FibonacciRetry = FibonacciRetry;
|
|
521
695
|
exports.ParamsEncryptor = ParamsEncryptor;
|
|
522
696
|
exports.apiFactory = apiFactory;
|
|
523
697
|
exports.decodeAES = decodeAES;
|
|
698
|
+
exports.decodeBase64ToBuffer = decodeBase64ToBuffer;
|
|
699
|
+
exports.decodeEventData = decodeEventData;
|
|
700
|
+
exports.decodeUnit8Array = decodeUnit8Array;
|
|
524
701
|
exports.decryptResp = decryptResp;
|
|
525
702
|
exports.encodeAES = encodeAES;
|
|
526
703
|
exports.encryptPin = encryptPin;
|
|
@@ -529,8 +706,10 @@ exports.generateZaloUUID = generateZaloUUID;
|
|
|
529
706
|
exports.getClientMessageType = getClientMessageType;
|
|
530
707
|
exports.getDefaultHeaders = getDefaultHeaders;
|
|
531
708
|
exports.getFileExtension = getFileExtension;
|
|
709
|
+
exports.getFriendEventType = getFriendEventType;
|
|
532
710
|
exports.getFullTimeFromMillisecond = getFullTimeFromMillisecond;
|
|
533
711
|
exports.getGifMetaData = getGifMetaData;
|
|
712
|
+
exports.getGroupEventType = getGroupEventType;
|
|
534
713
|
exports.getImageMetaData = getImageMetaData;
|
|
535
714
|
exports.getMd5LargeFileObject = getMd5LargeFileObject;
|
|
536
715
|
exports.getSecChUaPlatform = getSecChUaPlatform;
|
|
@@ -539,6 +718,7 @@ exports.handleQueueStatus = handleQueueStatus;
|
|
|
539
718
|
exports.handleZaloResponse = handleZaloResponse;
|
|
540
719
|
exports.hasOwn = hasOwn;
|
|
541
720
|
exports.logger = logger;
|
|
721
|
+
exports.looksLikeJson = looksLikeJson;
|
|
542
722
|
exports.makeURL = makeURL;
|
|
543
723
|
exports.removeUndefinedKeys = removeUndefinedKeys;
|
|
544
724
|
exports.request = request;
|
package/dist/cjs/zalo.cjs
CHANGED
|
@@ -7,6 +7,7 @@ var context = require('./context.cjs');
|
|
|
7
7
|
var ZaloApiError = require('./Errors/ZaloApiError.cjs');
|
|
8
8
|
var utils = require('./utils.cjs');
|
|
9
9
|
var apis = require('./apis.cjs');
|
|
10
|
+
var listen = require('./apis/listen.cjs');
|
|
10
11
|
|
|
11
12
|
function _interopNamespaceDefault(e) {
|
|
12
13
|
var n = Object.create(null);
|
|
@@ -133,6 +134,9 @@ class Zalo {
|
|
|
133
134
|
async getUserInfo(ctx) {
|
|
134
135
|
return await loginQR.getUserInfo(ctx);
|
|
135
136
|
}
|
|
137
|
+
listener(api) {
|
|
138
|
+
return new listen.Listener(api);
|
|
139
|
+
}
|
|
136
140
|
}
|
|
137
141
|
|
|
138
142
|
exports.Zalo = Zalo;
|
package/dist/zalo.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as ToughCookie from 'tough-cookie';
|
|
2
2
|
import { type ContextBase, type Options, type ServerInfo } from './context.js';
|
|
3
3
|
import { ZaloAPI, type ZaloAPIOptions } from './apis.js';
|
|
4
|
+
import { Listener } from './apis/listen.js';
|
|
4
5
|
export type Credentials = {
|
|
5
6
|
imei: string;
|
|
6
7
|
cookie: ToughCookie.Cookie[] | ToughCookie.SerializedCookie[] | {
|
|
@@ -68,4 +69,5 @@ export declare class Zalo {
|
|
|
68
69
|
error_code: number;
|
|
69
70
|
error_message: string;
|
|
70
71
|
} | undefined>;
|
|
72
|
+
listener(api: ZaloAPI): Listener;
|
|
71
73
|
}
|
package/dist/zalo.js
CHANGED
|
@@ -5,6 +5,7 @@ import { createContext, isContextSession } from './context.js';
|
|
|
5
5
|
import { ZaloApiError } from './Errors/ZaloApiError.js';
|
|
6
6
|
import { generateZaloUUID, logger } from './utils.js';
|
|
7
7
|
import { ZaloAPI } from './apis.js';
|
|
8
|
+
import { Listener } from './apis/listen.js';
|
|
8
9
|
export class Zalo {
|
|
9
10
|
constructor(options = {}) {
|
|
10
11
|
this.options = options;
|
|
@@ -111,4 +112,7 @@ export class Zalo {
|
|
|
111
112
|
async getUserInfo(ctx) {
|
|
112
113
|
return await getUserInfo(ctx);
|
|
113
114
|
}
|
|
115
|
+
listener(api) {
|
|
116
|
+
return new Listener(api);
|
|
117
|
+
}
|
|
114
118
|
}
|