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