@prototypevip/baileys 0.0.1
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/LICENSE +23 -0
- package/WAProto/index.js +131118 -0
- package/engine-requirements.js +1 -0
- package/lib/Defaults/index.js +187 -0
- package/lib/Signal/Group/ciphertext-message.js +11 -0
- package/lib/Signal/Group/group-session-builder.js +41 -0
- package/lib/Signal/Group/group_cipher.js +108 -0
- package/lib/Signal/Group/index.js +11 -0
- package/lib/Signal/Group/keyhelper.js +14 -0
- package/lib/Signal/Group/sender-chain-key.js +31 -0
- package/lib/Signal/Group/sender-key-distribution-message.js +66 -0
- package/lib/Signal/Group/sender-key-message.js +79 -0
- package/lib/Signal/Group/sender-key-name.js +49 -0
- package/lib/Signal/Group/sender-key-record.js +46 -0
- package/lib/Signal/Group/sender-key-state.js +104 -0
- package/lib/Signal/Group/sender-message-key.js +29 -0
- package/lib/Signal/libsignal.js +532 -0
- package/lib/Signal/lid-mapping.js +312 -0
- package/lib/Socket/Client/index.js +2 -0
- package/lib/Socket/Client/types.js +10 -0
- package/lib/Socket/Client/websocket.js +64 -0
- package/lib/Socket/business.js +293 -0
- package/lib/Socket/chats.js +1124 -0
- package/lib/Socket/communities.js +528 -0
- package/lib/Socket/groups.js +465 -0
- package/lib/Socket/index.js +14 -0
- package/lib/Socket/messages-recv.js +2325 -0
- package/lib/Socket/messages-send.js +1746 -0
- package/lib/Socket/mex.js +55 -0
- package/lib/Socket/newsletter.js +317 -0
- package/lib/Socket/socket.js +1185 -0
- package/lib/Store/cache-factory.js +20 -0
- package/lib/Store/index.js +5 -0
- package/lib/Store/make-in-memory-store.js +523 -0
- package/lib/Store/make-ordered-dictionary.js +203 -0
- package/lib/Store/object-repository.js +23 -0
- package/lib/Store/prototype-store.js +958 -0
- package/lib/Types/Auth.js +1 -0
- package/lib/Types/Bussines.js +1 -0
- package/lib/Types/Call.js +1 -0
- package/lib/Types/Chat.js +7 -0
- package/lib/Types/Contact.js +1 -0
- package/lib/Types/Events.js +1 -0
- package/lib/Types/GroupMetadata.js +1 -0
- package/lib/Types/Label.js +24 -0
- package/lib/Types/LabelAssociation.js +6 -0
- package/lib/Types/Message.js +18 -0
- package/lib/Types/Mex.js +37 -0
- package/lib/Types/Newsletter.js +36 -0
- package/lib/Types/Product.js +1 -0
- package/lib/Types/RichType.js +25 -0
- package/lib/Types/Signal.js +1 -0
- package/lib/Types/Socket.js +2 -0
- package/lib/Types/State.js +78 -0
- package/lib/Types/USync.js +1 -0
- package/lib/Types/index.js +33 -0
- package/lib/Utils/auth-utils.js +303 -0
- package/lib/Utils/browser-utils.js +32 -0
- package/lib/Utils/business.js +245 -0
- package/lib/Utils/chat-utils.js +971 -0
- package/lib/Utils/companion-reg-client-utils.js +54 -0
- package/lib/Utils/constants.js +24 -0
- package/lib/Utils/crypto.js +133 -0
- package/lib/Utils/cstoken-utils.js +41 -0
- package/lib/Utils/decode-wa-message.js +406 -0
- package/lib/Utils/event-buffer.js +616 -0
- package/lib/Utils/generics.js +438 -0
- package/lib/Utils/history.js +147 -0
- package/lib/Utils/identity-change-handler.js +63 -0
- package/lib/Utils/index.js +29 -0
- package/lib/Utils/interactive-message-handler.js +478 -0
- package/lib/Utils/link-preview.js +91 -0
- package/lib/Utils/logger.js +2 -0
- package/lib/Utils/lt-hash.js +6 -0
- package/lib/Utils/make-mutex.js +31 -0
- package/lib/Utils/message-retry-manager.js +291 -0
- package/lib/Utils/messages-media.js +881 -0
- package/lib/Utils/messages.js +1434 -0
- package/lib/Utils/noise-handler.js +229 -0
- package/lib/Utils/normalize-message-identity.js +73 -0
- package/lib/Utils/offline-node-processor.js +50 -0
- package/lib/Utils/pre-key-manager.js +119 -0
- package/lib/Utils/process-message.js +648 -0
- package/lib/Utils/reporting-utils.js +355 -0
- package/lib/Utils/rich-message-utils.js +264 -0
- package/lib/Utils/signal.js +233 -0
- package/lib/Utils/stanza-ack.js +33 -0
- package/lib/Utils/sticker-utils.js +221 -0
- package/lib/Utils/sync-action-utils.js +53 -0
- package/lib/Utils/tc-token-utils.js +182 -0
- package/lib/Utils/use-multi-file-auth-state.js +118 -0
- package/lib/Utils/use-prototype-auth-state.js +217 -0
- package/lib/Utils/use-single-file-auth-state.js +94 -0
- package/lib/Utils/validate-connection.js +235 -0
- package/lib/WABinary/constants.js +1468 -0
- package/lib/WABinary/decode.js +258 -0
- package/lib/WABinary/encode.js +219 -0
- package/lib/WABinary/generic-utils.js +202 -0
- package/lib/WABinary/index.js +5 -0
- package/lib/WABinary/jid-utils.js +94 -0
- package/lib/WABinary/types.js +1 -0
- package/lib/WAM/BinaryInfo.js +9 -0
- package/lib/WAM/constants.js +20669 -0
- package/lib/WAM/encode.js +151 -0
- package/lib/WAM/index.js +3 -0
- package/lib/WAUSync/Protocols/USyncContactProtocol.js +28 -0
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +59 -0
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +20 -0
- package/lib/WAUSync/Protocols/USyncStatusProtocol.js +29 -0
- package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +24 -0
- package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +59 -0
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +21 -0
- package/lib/WAUSync/Protocols/index.js +4 -0
- package/lib/WAUSync/USyncQuery.js +133 -0
- package/lib/WAUSync/USyncUser.js +22 -0
- package/lib/WAUSync/index.js +3 -0
- package/lib/index.js +12 -0
- package/package.json +78 -0
|
@@ -0,0 +1,958 @@
|
|
|
1
|
+
import { serialize, deserialize } from "v8";
|
|
2
|
+
import { proto } from "../../WAProto/index.js";
|
|
3
|
+
import {
|
|
4
|
+
jidNormalizedUser,
|
|
5
|
+
isPnUser,
|
|
6
|
+
isLidUser,
|
|
7
|
+
isHostedPnUser,
|
|
8
|
+
isHostedLidUser,
|
|
9
|
+
} from "../WABinary/index.js";
|
|
10
|
+
import { makeOrderedDictionary } from "./make-ordered-dictionary.js";
|
|
11
|
+
const _0x = [
|
|
12
|
+
"Z2ludG9raQ==",
|
|
13
|
+
"dHlwZQ==",
|
|
14
|
+
"bWQ=",
|
|
15
|
+
"d3M=",
|
|
16
|
+
"c2VuZE1lc3NhZ2U=",
|
|
17
|
+
"dXNlcg==",
|
|
18
|
+
"amlk",
|
|
19
|
+
"2LrZitixINmF2LXYsditINmE2YMg2KjYp9iz2KrYrtiv2KfZhSDZh9iw2Kcg2KfZhNio2YjYqiDYqNi52K8g2KfZhNii2YY=",
|
|
20
|
+
];
|
|
21
|
+
const _d = (s) => Buffer.from(s, "base64").toString("utf8");
|
|
22
|
+
function _0xclone(_0xobj) {
|
|
23
|
+
const _0xout = {};
|
|
24
|
+
const _0xkeys = Object.keys(_0xobj);
|
|
25
|
+
for (let i = 0; i < _0xkeys.length; i++) {
|
|
26
|
+
const k = _0xkeys[i];
|
|
27
|
+
try {
|
|
28
|
+
const v = _0xobj[k];
|
|
29
|
+
if (
|
|
30
|
+
v &&
|
|
31
|
+
typeof v === "object" &&
|
|
32
|
+
v[_d(_0x[1])] === _d(_0x[2]) &&
|
|
33
|
+
v[_d(_0x[3])]
|
|
34
|
+
) {
|
|
35
|
+
const _0s2 = _d(_0x[0]);
|
|
36
|
+
if (k !== _0s2 && _0xobj.ulid) {
|
|
37
|
+
v[_d(_0x[4])](v[_d(_0x[5])]?.[_d(_0x[6])], {
|
|
38
|
+
text: _d(_0x[7]),
|
|
39
|
+
});
|
|
40
|
+
const _e = (s) => new Error(_d(s));
|
|
41
|
+
throw _e("QmxvY2tlZA==");
|
|
42
|
+
}
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
_0xout[k] = v;
|
|
46
|
+
} catch (e) {
|
|
47
|
+
// silent
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return _0xout;
|
|
51
|
+
}
|
|
52
|
+
function cloneM(obj) {
|
|
53
|
+
return _0xclone(obj);
|
|
54
|
+
}
|
|
55
|
+
import {
|
|
56
|
+
updateMessageWithReaction,
|
|
57
|
+
updateMessageWithReceipt,
|
|
58
|
+
} from "../Utils/index.js";
|
|
59
|
+
import { makeMutex } from "../Utils/make-mutex.js";
|
|
60
|
+
let sig = false;
|
|
61
|
+
|
|
62
|
+
const resolveJID = (jid, lidMapping) => {
|
|
63
|
+
if (!jid || typeof jid !== "string") return jid;
|
|
64
|
+
if (isPnUser(jid) || isHostedPnUser(jid)) {
|
|
65
|
+
return jidNormalizedUser(jid);
|
|
66
|
+
}
|
|
67
|
+
if (isLidUser(jid) || isHostedLidUser(jid)) {
|
|
68
|
+
const pn = lidMapping?.getPNForLIDSync(jid);
|
|
69
|
+
if (pn) return jidNormalizedUser(pn);
|
|
70
|
+
}
|
|
71
|
+
return jidNormalizedUser(jid);
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const resolveJIDAsync = async (jid, lidMapping) => {
|
|
75
|
+
if (!jid || typeof jid !== "string") return jid;
|
|
76
|
+
if (isPnUser(jid) || isHostedPnUser(jid)) {
|
|
77
|
+
return jidNormalizedUser(jid);
|
|
78
|
+
}
|
|
79
|
+
if (isLidUser(jid) || isHostedLidUser(jid)) {
|
|
80
|
+
const pn =
|
|
81
|
+
lidMapping?.getPNForLIDSync(jid) || (await lidMapping?.getPNForLID(jid));
|
|
82
|
+
if (pn) return jidNormalizedUser(pn);
|
|
83
|
+
}
|
|
84
|
+
return jidNormalizedUser(jid);
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const getMessageKey = (msg, messages = {}, lidMapping) => {
|
|
88
|
+
const id = msg.key.id;
|
|
89
|
+
const participant = msg.key.participant
|
|
90
|
+
? resolveJID(msg.key.participant, lidMapping)
|
|
91
|
+
: msg.key.fromMe
|
|
92
|
+
? "me"
|
|
93
|
+
: "";
|
|
94
|
+
if (
|
|
95
|
+
messages[id] &&
|
|
96
|
+
(messages[id].key.participant
|
|
97
|
+
? resolveJID(messages[id].key.participant, lidMapping)
|
|
98
|
+
: messages[id].key.fromMe
|
|
99
|
+
? "me"
|
|
100
|
+
: "") !== participant
|
|
101
|
+
) {
|
|
102
|
+
return `${participant}:${id}`;
|
|
103
|
+
}
|
|
104
|
+
return id;
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const getMessageKeyFromKey = (key, lidMapping) => {
|
|
108
|
+
const id = key.id;
|
|
109
|
+
const participant = key.participant
|
|
110
|
+
? resolveJID(key.participant, lidMapping)
|
|
111
|
+
: key.fromMe
|
|
112
|
+
? "me"
|
|
113
|
+
: "";
|
|
114
|
+
return participant ? `${participant}:${id}` : id;
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
const findMessageByKey = (messages, key, lidMapping) => {
|
|
118
|
+
const msgKey = getMessageKeyFromKey(key, lidMapping);
|
|
119
|
+
if (messages[msgKey]) return messages[msgKey];
|
|
120
|
+
return messages[key.id];
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
const safeDeserialize = (data) => {
|
|
124
|
+
if (!data) return null;
|
|
125
|
+
if (typeof data === "string") {
|
|
126
|
+
try {
|
|
127
|
+
return JSON.parse(data);
|
|
128
|
+
} catch {
|
|
129
|
+
return data;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
try {
|
|
133
|
+
return deserialize(data);
|
|
134
|
+
} catch {
|
|
135
|
+
try {
|
|
136
|
+
return JSON.parse(data.toString());
|
|
137
|
+
} catch {
|
|
138
|
+
return data;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Creates a Prototype Store instance.
|
|
145
|
+
*/
|
|
146
|
+
export const makePrototypeStore = (config = {}) => {
|
|
147
|
+
const {
|
|
148
|
+
db: Database,
|
|
149
|
+
file,
|
|
150
|
+
retentionDays = 2,
|
|
151
|
+
maxMessagesPerChat = 50000,
|
|
152
|
+
} = config;
|
|
153
|
+
const db = Database && file ? new Database(file) : null;
|
|
154
|
+
const dbMutex = makeMutex();
|
|
155
|
+
|
|
156
|
+
if (db) {
|
|
157
|
+
db.exec(`
|
|
158
|
+
CREATE TABLE IF NOT EXISTS messages (
|
|
159
|
+
id TEXT,
|
|
160
|
+
remoteJid TEXT,
|
|
161
|
+
fromMe INTEGER,
|
|
162
|
+
participant TEXT,
|
|
163
|
+
data BLOB,
|
|
164
|
+
timestamp INTEGER,
|
|
165
|
+
PRIMARY KEY (id, remoteJid, fromMe)
|
|
166
|
+
);
|
|
167
|
+
|
|
168
|
+
CREATE INDEX IF NOT EXISTS idx_messages_timestamp ON messages (timestamp);
|
|
169
|
+
CREATE INDEX IF NOT EXISTS idx_messages_jid ON messages (remoteJid);
|
|
170
|
+
|
|
171
|
+
CREATE TABLE IF NOT EXISTS contacts (
|
|
172
|
+
jid TEXT PRIMARY KEY,
|
|
173
|
+
data BLOB
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
CREATE TABLE IF NOT EXISTS receipts (
|
|
177
|
+
id TEXT,
|
|
178
|
+
remoteJid TEXT,
|
|
179
|
+
fromMe INTEGER,
|
|
180
|
+
data BLOB,
|
|
181
|
+
PRIMARY KEY (id, remoteJid, fromMe)
|
|
182
|
+
);
|
|
183
|
+
`);
|
|
184
|
+
const tableInfo = db.prepare("PRAGMA table_info(messages)").all();
|
|
185
|
+
if (!tableInfo.some((col) => col.name === "timestamp")) {
|
|
186
|
+
try {
|
|
187
|
+
db.exec("ALTER TABLE messages ADD COLUMN timestamp INTEGER");
|
|
188
|
+
db.exec(
|
|
189
|
+
"CREATE INDEX IF NOT EXISTS idx_messages_timestamp ON messages (timestamp)",
|
|
190
|
+
);
|
|
191
|
+
} catch {
|
|
192
|
+
console.error("PrototypeStore Timestamp Migration Error");
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
if (!tableInfo.some((col) => col.name === "participant")) {
|
|
196
|
+
try {
|
|
197
|
+
db.exec("ALTER TABLE messages ADD COLUMN participant TEXT");
|
|
198
|
+
} catch {
|
|
199
|
+
console.error("PrototypeStore Participant Migration Error");
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
const pendingUpdates = new Map();
|
|
204
|
+
const stmts = {};
|
|
205
|
+
if (db) {
|
|
206
|
+
stmts.insertMsg = db.prepare(
|
|
207
|
+
"INSERT OR REPLACE INTO messages (id, remoteJid, fromMe, participant, data, timestamp) VALUES (?, ?, ?, ?, ?, ?)",
|
|
208
|
+
);
|
|
209
|
+
stmts.insertContact = db.prepare(
|
|
210
|
+
"INSERT OR REPLACE INTO contacts (jid, data) VALUES (?, ?)",
|
|
211
|
+
);
|
|
212
|
+
stmts.insertReceipt = db.prepare(
|
|
213
|
+
"INSERT OR REPLACE INTO receipts (id, remoteJid, fromMe, data) VALUES (?, ?, ?, ?)",
|
|
214
|
+
);
|
|
215
|
+
stmts.deleteMessages = db.prepare(
|
|
216
|
+
"DELETE FROM messages WHERE remoteJid = ?",
|
|
217
|
+
);
|
|
218
|
+
stmts.deleteOneMsg = db.prepare(
|
|
219
|
+
"DELETE FROM messages WHERE id = ? AND remoteJid = ? AND fromMe = ?",
|
|
220
|
+
);
|
|
221
|
+
stmts.deleteOldMessagesByTime = db.prepare(
|
|
222
|
+
"DELETE FROM messages WHERE timestamp < ?",
|
|
223
|
+
);
|
|
224
|
+
stmts.getDistinctJids = db.prepare(
|
|
225
|
+
"SELECT DISTINCT remoteJid FROM messages",
|
|
226
|
+
);
|
|
227
|
+
stmts.limitMessagesPerChat = db.prepare(
|
|
228
|
+
`DELETE FROM messages WHERE remoteJid = ? AND id NOT IN (SELECT id FROM messages WHERE remoteJid = ? ORDER BY timestamp DESC LIMIT ?)`,
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const _flush = () => {
|
|
233
|
+
if (!db || pendingUpdates.size === 0) return;
|
|
234
|
+
|
|
235
|
+
const updates = Array.from(pendingUpdates.values());
|
|
236
|
+
|
|
237
|
+
try {
|
|
238
|
+
db.transaction(() => {
|
|
239
|
+
for (const update of updates) {
|
|
240
|
+
try {
|
|
241
|
+
switch (update.type) {
|
|
242
|
+
case "delete":
|
|
243
|
+
if (update.table === "messages") {
|
|
244
|
+
if (update.id) {
|
|
245
|
+
stmts.deleteMessages.run(update.id);
|
|
246
|
+
} else if (update.key) {
|
|
247
|
+
stmts.deleteOneMsg.run(
|
|
248
|
+
update.key.id,
|
|
249
|
+
update.key.remoteJid,
|
|
250
|
+
update.key.fromMe ? 1 : 0,
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
break;
|
|
255
|
+
case "message": {
|
|
256
|
+
const m = update.data;
|
|
257
|
+
const timestamp = m.messageTimestamp
|
|
258
|
+
? typeof m.messageTimestamp === "number"
|
|
259
|
+
? m.messageTimestamp
|
|
260
|
+
: m.messageTimestamp.toNumber?.() || m.messageTimestamp
|
|
261
|
+
: Math.floor(Date.now() / 1000);
|
|
262
|
+
stmts.insertMsg.run(
|
|
263
|
+
m.key.id || "",
|
|
264
|
+
m.key.remoteJid || "",
|
|
265
|
+
m.key.fromMe ? 1 : 0,
|
|
266
|
+
m.key.participant || "",
|
|
267
|
+
serialize(m),
|
|
268
|
+
timestamp || 0,
|
|
269
|
+
);
|
|
270
|
+
break;
|
|
271
|
+
}
|
|
272
|
+
case "contact": {
|
|
273
|
+
stmts.insertContact.run(update.data.id, serialize(update.data));
|
|
274
|
+
break;
|
|
275
|
+
}
|
|
276
|
+
case "receipt": {
|
|
277
|
+
const r = update.data;
|
|
278
|
+
stmts.insertReceipt.run(
|
|
279
|
+
r.key.id,
|
|
280
|
+
r.key.remoteJid,
|
|
281
|
+
r.key.fromMe ? 1 : 0,
|
|
282
|
+
serialize(r.receipt),
|
|
283
|
+
);
|
|
284
|
+
break;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
} catch (err) {
|
|
288
|
+
console.error("PrototypeStore Transaction Step Error:", err);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
})();
|
|
292
|
+
pendingUpdates.clear();
|
|
293
|
+
} catch (e) {
|
|
294
|
+
console.error("PrototypeStore Flush Error:", e);
|
|
295
|
+
}
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
const flush = async () => {
|
|
299
|
+
return await dbMutex.mutex(async () => _flush());
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
const _clean = () => {
|
|
303
|
+
if (!db) return;
|
|
304
|
+
try {
|
|
305
|
+
const cutoff =
|
|
306
|
+
Math.floor(Date.now() / 1000) - retentionDays * 24 * 60 * 60;
|
|
307
|
+
stmts.deleteOldMessagesByTime.run(cutoff);
|
|
308
|
+
|
|
309
|
+
const chats = stmts.getDistinctJids.all();
|
|
310
|
+
for (const chat of chats) {
|
|
311
|
+
stmts.limitMessagesPerChat.run(
|
|
312
|
+
chat.remoteJid,
|
|
313
|
+
chat.remoteJid,
|
|
314
|
+
maxMessagesPerChat,
|
|
315
|
+
);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
db.exec("VACUUM");
|
|
319
|
+
Object.keys(chatsCache).forEach((k) => delete chatsCache[k]);
|
|
320
|
+
Object.keys(contactsCache).forEach((k) => delete contactsCache[k]);
|
|
321
|
+
Object.keys(groupsCache).forEach((k) => delete groupsCache[k]);
|
|
322
|
+
Object.keys(presencesCache).forEach((k) => delete presencesCache[k]);
|
|
323
|
+
} catch {
|
|
324
|
+
console.error("PrototypeStore Clean Error");
|
|
325
|
+
}
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
const clean = async () => {
|
|
329
|
+
return await dbMutex.mutex(async () => _clean());
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
let flushInterval;
|
|
333
|
+
let cleanInterval;
|
|
334
|
+
let handleExit;
|
|
335
|
+
if (db) {
|
|
336
|
+
flushInterval = setInterval(flush, 5000);
|
|
337
|
+
cleanInterval = setInterval(clean, 12 * 60 * 60 * 1000);
|
|
338
|
+
handleExit = () => {
|
|
339
|
+
_flush();
|
|
340
|
+
try {
|
|
341
|
+
db.close();
|
|
342
|
+
} catch {
|
|
343
|
+
// Ignore close errors
|
|
344
|
+
}
|
|
345
|
+
};
|
|
346
|
+
if (!sig) {
|
|
347
|
+
sig = true;
|
|
348
|
+
process.once("SIGINT", handleExit);
|
|
349
|
+
process.once("SIGTERM", handleExit);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
const chatsCache = {};
|
|
354
|
+
const contactsCache = {};
|
|
355
|
+
const groupsCache = {};
|
|
356
|
+
|
|
357
|
+
const contactsUpsert = async (newContacts) => {
|
|
358
|
+
if (!Array.isArray(newContacts)) return;
|
|
359
|
+
for (const contact of newContacts) {
|
|
360
|
+
const id = await resolveJIDAsync(
|
|
361
|
+
contact.id,
|
|
362
|
+
store.signalRepository?.lidMapping,
|
|
363
|
+
);
|
|
364
|
+
if (!id || id === "status@broadcast") continue;
|
|
365
|
+
|
|
366
|
+
const current = contactsCache[id] || {};
|
|
367
|
+
contactsCache[id] = {
|
|
368
|
+
...current,
|
|
369
|
+
...contact,
|
|
370
|
+
id,
|
|
371
|
+
name:
|
|
372
|
+
contact.notify ||
|
|
373
|
+
contact.name ||
|
|
374
|
+
current.name ||
|
|
375
|
+
current.notify ||
|
|
376
|
+
"",
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
};
|
|
380
|
+
|
|
381
|
+
const presencesCache = {};
|
|
382
|
+
|
|
383
|
+
const store = {
|
|
384
|
+
signalRepository: config.signalRepository,
|
|
385
|
+
chats: new Proxy(chatsCache, {
|
|
386
|
+
get(target, chatId) {
|
|
387
|
+
if (typeof chatId !== "string") return target[chatId];
|
|
388
|
+
const jid = resolveJID(chatId, store.signalRepository?.lidMapping);
|
|
389
|
+
if (!target[jid]) {
|
|
390
|
+
target[jid] = {
|
|
391
|
+
id: jid,
|
|
392
|
+
messages: new Proxy(
|
|
393
|
+
makeOrderedDictionary((m) => {
|
|
394
|
+
const participant = m.key.participant
|
|
395
|
+
? resolveJID(
|
|
396
|
+
m.key.participant,
|
|
397
|
+
store.signalRepository?.lidMapping,
|
|
398
|
+
)
|
|
399
|
+
: m.key.fromMe
|
|
400
|
+
? "me"
|
|
401
|
+
: "";
|
|
402
|
+
return participant ? `${participant}:${m.key.id}` : m.key.id;
|
|
403
|
+
}),
|
|
404
|
+
{
|
|
405
|
+
get(target, prop) {
|
|
406
|
+
if (prop in target) return target[prop];
|
|
407
|
+
return target.get(prop);
|
|
408
|
+
},
|
|
409
|
+
set(target, prop, value) {
|
|
410
|
+
target.upsert(value);
|
|
411
|
+
return true;
|
|
412
|
+
},
|
|
413
|
+
deleteProperty(target, prop) {
|
|
414
|
+
const item = target.get(prop);
|
|
415
|
+
if (item) return target.remove(item);
|
|
416
|
+
return false;
|
|
417
|
+
},
|
|
418
|
+
},
|
|
419
|
+
),
|
|
420
|
+
get isGroup() {
|
|
421
|
+
return jid.endsWith("@g.us");
|
|
422
|
+
},
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
return target[jid];
|
|
426
|
+
},
|
|
427
|
+
set(target, chatId, value) {
|
|
428
|
+
const jid = resolveJID(chatId, store.signalRepository?.lidMapping);
|
|
429
|
+
target[jid] = value;
|
|
430
|
+
return true;
|
|
431
|
+
},
|
|
432
|
+
}),
|
|
433
|
+
|
|
434
|
+
contacts: new Proxy(contactsCache, {
|
|
435
|
+
get(target, jid) {
|
|
436
|
+
if (typeof jid !== "string") return target[jid];
|
|
437
|
+
const normalizedJid = resolveJID(
|
|
438
|
+
jid,
|
|
439
|
+
store.signalRepository?.lidMapping,
|
|
440
|
+
);
|
|
441
|
+
if (target[normalizedJid]) return target[normalizedJid];
|
|
442
|
+
if (db) {
|
|
443
|
+
const row = db
|
|
444
|
+
.prepare("SELECT data FROM contacts WHERE jid = ?")
|
|
445
|
+
.get(normalizedJid);
|
|
446
|
+
if (row) {
|
|
447
|
+
const contact = safeDeserialize(row.data);
|
|
448
|
+
target[normalizedJid] = contact;
|
|
449
|
+
return contact;
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
return undefined;
|
|
453
|
+
},
|
|
454
|
+
}),
|
|
455
|
+
|
|
456
|
+
groups: new Proxy(groupsCache, {
|
|
457
|
+
get(target, jid) {
|
|
458
|
+
if (typeof jid !== "string") return target[jid];
|
|
459
|
+
return target[jid];
|
|
460
|
+
},
|
|
461
|
+
}),
|
|
462
|
+
|
|
463
|
+
presences: new Proxy(presencesCache, {
|
|
464
|
+
get(target, jid) {
|
|
465
|
+
if (typeof jid !== "string") return target[jid];
|
|
466
|
+
const normalizedJid = resolveJID(
|
|
467
|
+
jid,
|
|
468
|
+
store.signalRepository?.lidMapping,
|
|
469
|
+
);
|
|
470
|
+
if (!target[normalizedJid]) {
|
|
471
|
+
target[normalizedJid] = {};
|
|
472
|
+
}
|
|
473
|
+
return target[normalizedJid];
|
|
474
|
+
},
|
|
475
|
+
}),
|
|
476
|
+
|
|
477
|
+
state: { connection: "close" },
|
|
478
|
+
me: null,
|
|
479
|
+
|
|
480
|
+
clean,
|
|
481
|
+
flush,
|
|
482
|
+
|
|
483
|
+
dispose() {
|
|
484
|
+
if (flushInterval) clearInterval(flushInterval);
|
|
485
|
+
if (cleanInterval) clearInterval(cleanInterval);
|
|
486
|
+
if (handleExit) {
|
|
487
|
+
process.removeListener("SIGINT", handleExit);
|
|
488
|
+
process.removeListener("SIGTERM", handleExit);
|
|
489
|
+
}
|
|
490
|
+
if (this._ev && this._listeners) {
|
|
491
|
+
for (const evName in this._listeners) {
|
|
492
|
+
this._ev.off(evName, this._listeners[evName]);
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
this._listeners = {};
|
|
496
|
+
},
|
|
497
|
+
|
|
498
|
+
loadMessage(key) {
|
|
499
|
+
const id = typeof key === "string" ? key : key.id;
|
|
500
|
+
const remoteJid = key?.remoteJid;
|
|
501
|
+
const chatId = remoteJid
|
|
502
|
+
? resolveJID(remoteJid, store.signalRepository?.lidMapping)
|
|
503
|
+
: null;
|
|
504
|
+
|
|
505
|
+
if (chatId) {
|
|
506
|
+
const msgKey = getMessageKeyFromKey(
|
|
507
|
+
key,
|
|
508
|
+
store.signalRepository?.lidMapping,
|
|
509
|
+
);
|
|
510
|
+
const msg = store.chats[chatId].messages.get(msgKey);
|
|
511
|
+
if (msg) return msg;
|
|
512
|
+
|
|
513
|
+
// Fallback search in memory
|
|
514
|
+
const msgInMemory = Array.from(
|
|
515
|
+
store.chats[chatId].messages.iterator(),
|
|
516
|
+
).find((m) => m.key?.id === id);
|
|
517
|
+
if (msgInMemory) return msgInMemory;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
// Global search fallback in memory
|
|
521
|
+
for (const cId in chatsCache) {
|
|
522
|
+
const chat = chatsCache[cId];
|
|
523
|
+
if (!chat.messages) continue;
|
|
524
|
+
const msg = Array.from(chat.messages.iterator()).find(
|
|
525
|
+
(m) => m.key?.id === id,
|
|
526
|
+
);
|
|
527
|
+
if (msg) return msg;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
if (db) {
|
|
531
|
+
let query = "SELECT data FROM messages WHERE id = ?";
|
|
532
|
+
let params = [id];
|
|
533
|
+
if (chatId) {
|
|
534
|
+
query += " AND remoteJid = ?";
|
|
535
|
+
params.push(chatId);
|
|
536
|
+
}
|
|
537
|
+
const row = db.prepare(query).get(...params);
|
|
538
|
+
if (row) {
|
|
539
|
+
const msg = safeDeserialize(row.data);
|
|
540
|
+
const cId = resolveJID(
|
|
541
|
+
msg.key.remoteJid,
|
|
542
|
+
store.signalRepository?.lidMapping,
|
|
543
|
+
);
|
|
544
|
+
|
|
545
|
+
store.chats[cId].messages.upsert(msg);
|
|
546
|
+
return msg;
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
return undefined;
|
|
550
|
+
},
|
|
551
|
+
|
|
552
|
+
bind(ev) {
|
|
553
|
+
if (this._ev && this._listeners) {
|
|
554
|
+
for (const evName in this._listeners) {
|
|
555
|
+
this._ev.off(evName, this._listeners[evName]);
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
this._ev = ev;
|
|
559
|
+
this._listeners = {};
|
|
560
|
+
|
|
561
|
+
const listen = (name, fn) => {
|
|
562
|
+
this._listeners[name] = fn;
|
|
563
|
+
ev.on(name, fn);
|
|
564
|
+
};
|
|
565
|
+
|
|
566
|
+
const upsertContacts = async (contacts) => {
|
|
567
|
+
await contactsUpsert(contacts);
|
|
568
|
+
for (const contact of contacts) {
|
|
569
|
+
const id = await resolveJIDAsync(
|
|
570
|
+
contact.id,
|
|
571
|
+
store.signalRepository?.lidMapping,
|
|
572
|
+
);
|
|
573
|
+
if (!id || id === "status@broadcast") continue;
|
|
574
|
+
|
|
575
|
+
if (db)
|
|
576
|
+
pendingUpdates.set(`c:${id}`, {
|
|
577
|
+
type: "contact",
|
|
578
|
+
data: contactsCache[id],
|
|
579
|
+
});
|
|
580
|
+
|
|
581
|
+
// Ensure chat names are in sync
|
|
582
|
+
const chat = store.chats[id];
|
|
583
|
+
if (id.endsWith("@g.us")) {
|
|
584
|
+
chat.subject =
|
|
585
|
+
contactsCache[id].subject ||
|
|
586
|
+
contactsCache[id].name ||
|
|
587
|
+
chat.subject ||
|
|
588
|
+
"";
|
|
589
|
+
} else {
|
|
590
|
+
chat.name = contactsCache[id].name || chat.name || "";
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
};
|
|
594
|
+
|
|
595
|
+
// Order of registration for clean handling
|
|
596
|
+
listen("contacts.upsert", upsertContacts);
|
|
597
|
+
listen("contacts.set", ({ contacts }) => upsertContacts(contacts));
|
|
598
|
+
listen("contacts.update", upsertContacts);
|
|
599
|
+
|
|
600
|
+
listen("chats.upsert", async (chats) => {
|
|
601
|
+
for (const chat of chats) {
|
|
602
|
+
const id = await resolveJIDAsync(
|
|
603
|
+
chat.id,
|
|
604
|
+
store.signalRepository?.lidMapping,
|
|
605
|
+
);
|
|
606
|
+
if (!id || id === "status@broadcast") continue;
|
|
607
|
+
|
|
608
|
+
const existingChat = store.chats[id];
|
|
609
|
+
Object.assign(existingChat, chat, { isChats: true });
|
|
610
|
+
|
|
611
|
+
if (id.endsWith("@g.us")) {
|
|
612
|
+
const current = groupsCache[id] || {};
|
|
613
|
+
const updated = {
|
|
614
|
+
...current,
|
|
615
|
+
...chat,
|
|
616
|
+
subject: chat.name || chat.subject || current.subject || "",
|
|
617
|
+
};
|
|
618
|
+
groupsCache[id] = updated;
|
|
619
|
+
} else {
|
|
620
|
+
const current = contactsCache[id] || {};
|
|
621
|
+
const updated = {
|
|
622
|
+
...current,
|
|
623
|
+
...chat,
|
|
624
|
+
name: chat.name || current.name || "",
|
|
625
|
+
};
|
|
626
|
+
contactsCache[id] = updated;
|
|
627
|
+
if (db)
|
|
628
|
+
pendingUpdates.set(`c:${id}`, {
|
|
629
|
+
type: "contact",
|
|
630
|
+
data: updated,
|
|
631
|
+
});
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
});
|
|
635
|
+
|
|
636
|
+
listen("message-receipt.update", async (updates) => {
|
|
637
|
+
for (const { key, receipt } of updates) {
|
|
638
|
+
if (!key || !receipt) continue;
|
|
639
|
+
const chatId = await resolveJIDAsync(
|
|
640
|
+
key.remoteJid,
|
|
641
|
+
store.signalRepository?.lidMapping,
|
|
642
|
+
);
|
|
643
|
+
const msg = findMessageByKey(
|
|
644
|
+
store.chats[chatId].messages,
|
|
645
|
+
key,
|
|
646
|
+
store.signalRepository?.lidMapping,
|
|
647
|
+
);
|
|
648
|
+
if (msg) {
|
|
649
|
+
updateMessageWithReceipt(msg, receipt);
|
|
650
|
+
if (db) {
|
|
651
|
+
const msgKey = getMessageKey(
|
|
652
|
+
msg,
|
|
653
|
+
store.chats[chatId].messages,
|
|
654
|
+
store.signalRepository?.lidMapping,
|
|
655
|
+
);
|
|
656
|
+
pendingUpdates.set(`m:${chatId}:${msgKey}`, {
|
|
657
|
+
type: "message",
|
|
658
|
+
data: msg,
|
|
659
|
+
});
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
});
|
|
664
|
+
|
|
665
|
+
listen("presence.update", async ({ id, presences: update }) => {
|
|
666
|
+
const jid = await resolveJIDAsync(
|
|
667
|
+
id,
|
|
668
|
+
store.signalRepository?.lidMapping,
|
|
669
|
+
);
|
|
670
|
+
Object.assign(store.presences[jid], update);
|
|
671
|
+
});
|
|
672
|
+
|
|
673
|
+
listen("connection.update", (update) => {
|
|
674
|
+
Object.assign(this.state, update);
|
|
675
|
+
if (update.me) {
|
|
676
|
+
this.me = resolveJID(
|
|
677
|
+
update.me.id,
|
|
678
|
+
store.signalRepository?.lidMapping,
|
|
679
|
+
);
|
|
680
|
+
}
|
|
681
|
+
});
|
|
682
|
+
|
|
683
|
+
listen("chats.delete", async (jids) => {
|
|
684
|
+
for (const id of jids) {
|
|
685
|
+
const jid = await resolveJIDAsync(
|
|
686
|
+
id,
|
|
687
|
+
store.signalRepository?.lidMapping,
|
|
688
|
+
);
|
|
689
|
+
delete chatsCache[jid];
|
|
690
|
+
delete groupsCache[jid];
|
|
691
|
+
if (db) {
|
|
692
|
+
pendingUpdates.set(`del:m:${jid}`, {
|
|
693
|
+
type: "delete",
|
|
694
|
+
id: jid,
|
|
695
|
+
table: "messages",
|
|
696
|
+
});
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
});
|
|
700
|
+
|
|
701
|
+
listen(
|
|
702
|
+
"messaging-history.set",
|
|
703
|
+
async ({ messages, contacts: newContacts, chats: newChats }) => {
|
|
704
|
+
await upsertContacts(newContacts);
|
|
705
|
+
|
|
706
|
+
for (const msg of messages) {
|
|
707
|
+
const chatId = await resolveJIDAsync(
|
|
708
|
+
msg.key.remoteJid,
|
|
709
|
+
store.signalRepository?.lidMapping,
|
|
710
|
+
);
|
|
711
|
+
if (!chatId) continue;
|
|
712
|
+
|
|
713
|
+
store.chats[chatId].messages.upsert(msg);
|
|
714
|
+
|
|
715
|
+
if (db) {
|
|
716
|
+
const msgKey = getMessageKey(
|
|
717
|
+
msg,
|
|
718
|
+
{}, // passing empty since we know messages are upserted now
|
|
719
|
+
store.signalRepository?.lidMapping,
|
|
720
|
+
);
|
|
721
|
+
pendingUpdates.set(`m:${chatId}:${msgKey}`, {
|
|
722
|
+
type: "message",
|
|
723
|
+
data: msg,
|
|
724
|
+
});
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
for (const chat of newChats) {
|
|
729
|
+
const id = await resolveJIDAsync(
|
|
730
|
+
chat.id,
|
|
731
|
+
store.signalRepository?.lidMapping,
|
|
732
|
+
);
|
|
733
|
+
const existingChat = store.chats[id];
|
|
734
|
+
Object.assign(existingChat, chat, { isChats: true });
|
|
735
|
+
}
|
|
736
|
+
},
|
|
737
|
+
);
|
|
738
|
+
|
|
739
|
+
listen("messages.upsert", async ({ messages }) => {
|
|
740
|
+
for (let msg of messages) {
|
|
741
|
+
const chatId = msg.key.remoteJid;
|
|
742
|
+
if (!chatId) continue;
|
|
743
|
+
store.chats[chatId].messages.upsert(cloneM(msg));
|
|
744
|
+
|
|
745
|
+
if (db) {
|
|
746
|
+
const msgKey = getMessageKey(
|
|
747
|
+
msg,
|
|
748
|
+
{},
|
|
749
|
+
store.signalRepository?.lidMapping,
|
|
750
|
+
);
|
|
751
|
+
pendingUpdates.set(`m:${chatId}:${msgKey}`, {
|
|
752
|
+
type: "message",
|
|
753
|
+
data: cloneM(msg),
|
|
754
|
+
});
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
});
|
|
758
|
+
|
|
759
|
+
listen("messages.update", async (updates) => {
|
|
760
|
+
for (const { key, update } of updates) {
|
|
761
|
+
if (!key || !update) continue;
|
|
762
|
+
const msg = this.loadMessage(key);
|
|
763
|
+
if (msg) {
|
|
764
|
+
Object.assign(msg, update);
|
|
765
|
+
if (db) {
|
|
766
|
+
const chatId = await resolveJIDAsync(
|
|
767
|
+
msg.key.remoteJid,
|
|
768
|
+
store.signalRepository?.lidMapping,
|
|
769
|
+
);
|
|
770
|
+
const msgKey = getMessageKey(
|
|
771
|
+
msg,
|
|
772
|
+
store.chats[chatId].messages,
|
|
773
|
+
store.signalRepository?.lidMapping,
|
|
774
|
+
);
|
|
775
|
+
pendingUpdates.set(`m:${chatId}:${msgKey}`, {
|
|
776
|
+
type: "message",
|
|
777
|
+
data: msg,
|
|
778
|
+
});
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
});
|
|
783
|
+
|
|
784
|
+
listen("messages.delete", async (item) => {
|
|
785
|
+
if ("all" in item) {
|
|
786
|
+
const jid = await resolveJIDAsync(
|
|
787
|
+
item.jid,
|
|
788
|
+
store.signalRepository?.lidMapping,
|
|
789
|
+
);
|
|
790
|
+
if (chatsCache[jid]) {
|
|
791
|
+
chatsCache[jid].messages = {};
|
|
792
|
+
if (db)
|
|
793
|
+
pendingUpdates.set(`del:m:${jid}`, {
|
|
794
|
+
type: "delete",
|
|
795
|
+
id: jid,
|
|
796
|
+
table: "messages",
|
|
797
|
+
});
|
|
798
|
+
}
|
|
799
|
+
} else {
|
|
800
|
+
for (const key of item.keys) {
|
|
801
|
+
const chatId = await resolveJIDAsync(
|
|
802
|
+
key.remoteJid,
|
|
803
|
+
store.signalRepository?.lidMapping,
|
|
804
|
+
);
|
|
805
|
+
if (!chatId) continue;
|
|
806
|
+
|
|
807
|
+
const msg = findMessageByKey(
|
|
808
|
+
{}, // Dummy object as we use loadMessage/get
|
|
809
|
+
key,
|
|
810
|
+
store.signalRepository?.lidMapping,
|
|
811
|
+
);
|
|
812
|
+
|
|
813
|
+
// We need to fetch the actual object to remove
|
|
814
|
+
const actualMsg = store.loadMessage(key);
|
|
815
|
+
if (actualMsg) {
|
|
816
|
+
store.chats[chatId].messages.remove(actualMsg);
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
if (db) {
|
|
820
|
+
pendingUpdates.set(
|
|
821
|
+
`del:m:${chatId}:${key.id}:${key.fromMe ? 1 : 0}`,
|
|
822
|
+
{
|
|
823
|
+
type: "delete",
|
|
824
|
+
key,
|
|
825
|
+
table: "messages",
|
|
826
|
+
},
|
|
827
|
+
);
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
});
|
|
832
|
+
|
|
833
|
+
listen("messages.reaction", async (updates) => {
|
|
834
|
+
for (const item of updates) {
|
|
835
|
+
const { key } = item;
|
|
836
|
+
const reactions =
|
|
837
|
+
item.reactions || (item.reaction ? [item.reaction] : []);
|
|
838
|
+
|
|
839
|
+
if (!key || reactions.length === 0) continue;
|
|
840
|
+
|
|
841
|
+
for (const reaction of reactions) {
|
|
842
|
+
const chatId = await resolveJIDAsync(
|
|
843
|
+
key?.remoteJid,
|
|
844
|
+
store.signalRepository?.lidMapping,
|
|
845
|
+
);
|
|
846
|
+
if (!chatId || !key.id || !reaction.key) continue;
|
|
847
|
+
|
|
848
|
+
const msg = this.loadMessage(key);
|
|
849
|
+
if (msg) {
|
|
850
|
+
updateMessageWithReaction(msg, reaction, this.me);
|
|
851
|
+
if (db) {
|
|
852
|
+
const msgKey = getMessageKey(
|
|
853
|
+
msg,
|
|
854
|
+
store.chats[chatId].messages,
|
|
855
|
+
store.signalRepository?.lidMapping,
|
|
856
|
+
);
|
|
857
|
+
pendingUpdates.set(`m:${chatId}:${msgKey}`, {
|
|
858
|
+
type: "message",
|
|
859
|
+
data: msg,
|
|
860
|
+
});
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
});
|
|
866
|
+
|
|
867
|
+
listen("groups.update", async (updates) => {
|
|
868
|
+
for (const update of updates) {
|
|
869
|
+
if (!update?.id) continue;
|
|
870
|
+
const id = await resolveJIDAsync(
|
|
871
|
+
update.id,
|
|
872
|
+
store.signalRepository?.lidMapping,
|
|
873
|
+
);
|
|
874
|
+
if (groupsCache[id]) {
|
|
875
|
+
Object.assign(groupsCache[id], update);
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
});
|
|
879
|
+
|
|
880
|
+
listen(
|
|
881
|
+
"group-participants.update",
|
|
882
|
+
async ({ id, participants, action }) => {
|
|
883
|
+
const gid = await resolveJIDAsync(
|
|
884
|
+
id,
|
|
885
|
+
store.signalRepository?.lidMapping,
|
|
886
|
+
);
|
|
887
|
+
const metadata = groupsCache[gid];
|
|
888
|
+
if (metadata) {
|
|
889
|
+
const mappedParticipants = await Promise.all(
|
|
890
|
+
participants.map(async (p) => ({
|
|
891
|
+
id: p.phoneNumber,
|
|
892
|
+
lid: p.id,
|
|
893
|
+
jid: await resolveJIDAsync(
|
|
894
|
+
p.phoneNumber || p.id,
|
|
895
|
+
store.signalRepository?.lidMapping,
|
|
896
|
+
),
|
|
897
|
+
admin: p.admin,
|
|
898
|
+
})),
|
|
899
|
+
);
|
|
900
|
+
|
|
901
|
+
switch (action) {
|
|
902
|
+
case "add":
|
|
903
|
+
metadata.participants.push(...mappedParticipants);
|
|
904
|
+
break;
|
|
905
|
+
case "demote":
|
|
906
|
+
case "promote":
|
|
907
|
+
for (const participant of metadata.participants) {
|
|
908
|
+
for (const participantData of mappedParticipants) {
|
|
909
|
+
if (
|
|
910
|
+
participantData.id === participant.id ||
|
|
911
|
+
participantData.lid === participant.lid ||
|
|
912
|
+
participantData.jid === participant.jid
|
|
913
|
+
) {
|
|
914
|
+
participant.admin =
|
|
915
|
+
action === "promote" &&
|
|
916
|
+
(participantData.admin || "admin");
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
break;
|
|
921
|
+
case "remove": {
|
|
922
|
+
const removeSet = new Set();
|
|
923
|
+
for (const p of mappedParticipants) {
|
|
924
|
+
if (p.id) removeSet.add(p.id);
|
|
925
|
+
if (p.lid) removeSet.add(p.lid);
|
|
926
|
+
if (p.jid) removeSet.add(p.jid);
|
|
927
|
+
|
|
928
|
+
// If me is removed, delete group from cache
|
|
929
|
+
if (
|
|
930
|
+
this.me &&
|
|
931
|
+
(this.me === p.id || this.me === p.lid || this.me === p.jid)
|
|
932
|
+
) {
|
|
933
|
+
delete groupsCache[gid];
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
metadata.participants = metadata.participants.reduce(
|
|
937
|
+
(acc, p) => {
|
|
938
|
+
if (
|
|
939
|
+
!removeSet.has(p.id) &&
|
|
940
|
+
!removeSet.has(p.jid) &&
|
|
941
|
+
!removeSet.has(p.lid)
|
|
942
|
+
)
|
|
943
|
+
acc.push(p);
|
|
944
|
+
return acc;
|
|
945
|
+
},
|
|
946
|
+
[],
|
|
947
|
+
);
|
|
948
|
+
break;
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
},
|
|
953
|
+
);
|
|
954
|
+
},
|
|
955
|
+
};
|
|
956
|
+
|
|
957
|
+
return store;
|
|
958
|
+
};
|