whatsapp-store-db 1.3.43
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/.env.example +2 -0
- package/LICENSE +21 -0
- package/README.md +101 -0
- package/dist/handlers/chat.d.ts +5 -0
- package/dist/handlers/chat.js +163 -0
- package/dist/handlers/contact.d.ts +5 -0
- package/dist/handlers/contact.js +118 -0
- package/dist/handlers/index.d.ts +3 -0
- package/dist/handlers/index.js +12 -0
- package/dist/handlers/message.d.ts +5 -0
- package/dist/handlers/message.js +369 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +20 -0
- package/dist/session.d.ts +20 -0
- package/dist/session.js +133 -0
- package/dist/shared.d.ts +6 -0
- package/dist/shared.js +27 -0
- package/dist/store.d.ts +22 -0
- package/dist/store.js +56 -0
- package/dist/types.d.ts +17 -0
- package/dist/types.js +2 -0
- package/dist/utils.d.ts +27 -0
- package/dist/utils.js +553 -0
- package/package.json +43 -0
- package/prisma/schema.prisma +134 -0
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const baileys_1 = require("baileys");
|
|
4
|
+
const shared_1 = require("../shared");
|
|
5
|
+
const utils_1 = require("../utils");
|
|
6
|
+
const getKeyAuthor = (key) => ((key === null || key === void 0 ? void 0 : key.fromMe) ? 'me' : (key === null || key === void 0 ? void 0 : key.participant) || (key === null || key === void 0 ? void 0 : key.remoteJid)) || '';
|
|
7
|
+
function messageHandler(sessionId, event, getJid = undefined) {
|
|
8
|
+
const prisma = (0, shared_1.usePrisma)();
|
|
9
|
+
const logger = (0, shared_1.useLogger)();
|
|
10
|
+
let listening = false;
|
|
11
|
+
const resolveRemoteJid = (key) => {
|
|
12
|
+
let jid = undefined;
|
|
13
|
+
if (key.remoteJid && key.remoteJidAlt) {
|
|
14
|
+
if (!key.remoteJid.includes('s.whatsapp.net') && key.remoteJidAlt.includes('s.whatsapp.net')) {
|
|
15
|
+
jid = key.remoteJidAlt;
|
|
16
|
+
}
|
|
17
|
+
else if (key.remoteJid.includes('s.whatsapp.net')) {
|
|
18
|
+
jid = key.remoteJid;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return (0, baileys_1.jidNormalizedUser)(jid !== null && jid !== void 0 ? jid : key.remoteJid);
|
|
22
|
+
};
|
|
23
|
+
const stringifySafe = (value) => {
|
|
24
|
+
try {
|
|
25
|
+
return JSON.stringify(value, (_k, v) => (typeof v === 'bigint' ? v.toString() : v));
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
logger.error({ error }, 'Failed to stringify value for logging');
|
|
29
|
+
return '';
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
// Configurable batch sizes based on environment or dataset size
|
|
33
|
+
const getBatchConfig = (messageCount) => {
|
|
34
|
+
if (messageCount > 10000) {
|
|
35
|
+
// Emergency mode for very large datasets
|
|
36
|
+
return {
|
|
37
|
+
BATCH_SIZE: 10,
|
|
38
|
+
MAX_CONCURRENT_BATCHES: 2,
|
|
39
|
+
TIMEOUT: 45000, // 45 seconds
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
else if (messageCount > 5000) {
|
|
43
|
+
// Large dataset mode
|
|
44
|
+
return {
|
|
45
|
+
BATCH_SIZE: 15,
|
|
46
|
+
MAX_CONCURRENT_BATCHES: 2,
|
|
47
|
+
TIMEOUT: 30000, // 30 seconds
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
else if (messageCount > 1000) {
|
|
51
|
+
// Medium dataset mode
|
|
52
|
+
return {
|
|
53
|
+
BATCH_SIZE: 25,
|
|
54
|
+
MAX_CONCURRENT_BATCHES: 3,
|
|
55
|
+
TIMEOUT: 25000, // 25 seconds
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
// Small dataset mode
|
|
60
|
+
return {
|
|
61
|
+
BATCH_SIZE: 50,
|
|
62
|
+
MAX_CONCURRENT_BATCHES: 4,
|
|
63
|
+
TIMEOUT: 20000, // 20 seconds
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
const set = async ({ messages, isLatest }) => {
|
|
68
|
+
try {
|
|
69
|
+
logger.info({ messageCount: messages.length }, 'Starting message sync');
|
|
70
|
+
const { BATCH_SIZE, MAX_CONCURRENT_BATCHES, TIMEOUT } = getBatchConfig(messages.length);
|
|
71
|
+
const batches = [];
|
|
72
|
+
for (let i = 0; i < messages.length; i += BATCH_SIZE) {
|
|
73
|
+
batches.push(messages.slice(i, i + BATCH_SIZE));
|
|
74
|
+
}
|
|
75
|
+
logger.info({ totalBatches: batches.length, batchSize: BATCH_SIZE }, 'Processing in batches');
|
|
76
|
+
// Process batches with limited concurrency
|
|
77
|
+
for (let i = 0; i < batches.length; i += MAX_CONCURRENT_BATCHES) {
|
|
78
|
+
const currentBatches = batches.slice(i, i + MAX_CONCURRENT_BATCHES);
|
|
79
|
+
await Promise.all(currentBatches.map(async (batch, batchIndex) => {
|
|
80
|
+
const actualBatchIndex = i + batchIndex;
|
|
81
|
+
try {
|
|
82
|
+
await prisma.$transaction(async (tx) => {
|
|
83
|
+
// Use createMany where possible for better performance
|
|
84
|
+
const messagesToCreate = [];
|
|
85
|
+
const messagesToUpdate = [];
|
|
86
|
+
for (const message of batch) {
|
|
87
|
+
const jid = resolveRemoteJid(message.key);
|
|
88
|
+
const transformedMessage = Object.assign(Object.assign({}, (0, utils_1.transformPrisma)(message)), { remoteJid: jid, id: message.key.id, sessionId });
|
|
89
|
+
// Check if message exists
|
|
90
|
+
const existing = await tx.message.findUnique({
|
|
91
|
+
where: {
|
|
92
|
+
sessionId_remoteJid_id: {
|
|
93
|
+
sessionId,
|
|
94
|
+
remoteJid: jid,
|
|
95
|
+
id: message.key.id,
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
select: { pkId: true },
|
|
99
|
+
});
|
|
100
|
+
if (existing) {
|
|
101
|
+
messagesToUpdate.push({
|
|
102
|
+
where: {
|
|
103
|
+
sessionId_remoteJid_id: {
|
|
104
|
+
sessionId,
|
|
105
|
+
remoteJid: jid,
|
|
106
|
+
id: message.key.id,
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
data: (0, utils_1.validateMessageData)((0, utils_1.transformPrisma)(message)),
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
messagesToCreate.push(transformedMessage);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
// Bulk create new messages
|
|
117
|
+
if (messagesToCreate.length > 0) {
|
|
118
|
+
// Validate and transform messages before bulk insertion
|
|
119
|
+
const validatedMessages = messagesToCreate.map((msg) => (0, utils_1.validateMessageData)(msg));
|
|
120
|
+
// Log validation summary for bulk operations
|
|
121
|
+
const totalOriginalFields = messagesToCreate.reduce((sum, msg) => sum + Object.keys(msg).length, 0);
|
|
122
|
+
const totalValidatedFields = validatedMessages.reduce((sum, msg) => sum + Object.keys(msg).length, 0);
|
|
123
|
+
if (totalOriginalFields !== totalValidatedFields) {
|
|
124
|
+
logger.info({
|
|
125
|
+
batchSize: messagesToCreate.length,
|
|
126
|
+
totalOriginalFields,
|
|
127
|
+
totalValidatedFields,
|
|
128
|
+
fieldsFiltered: totalOriginalFields - totalValidatedFields
|
|
129
|
+
}, 'Bulk message validation filtered out unknown fields');
|
|
130
|
+
}
|
|
131
|
+
await tx.message.createMany({
|
|
132
|
+
data: validatedMessages,
|
|
133
|
+
skipDuplicates: true,
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
// Update existing messages individually (unfortunately updateMany doesn't support unique constraints)
|
|
137
|
+
for (const updateOp of messagesToUpdate) {
|
|
138
|
+
await tx.message.update(updateOp);
|
|
139
|
+
}
|
|
140
|
+
}, {
|
|
141
|
+
timeout: TIMEOUT,
|
|
142
|
+
maxWait: 10000, // 10 seconds max wait
|
|
143
|
+
});
|
|
144
|
+
if (actualBatchIndex % 10 === 0) {
|
|
145
|
+
logger.info({
|
|
146
|
+
completedBatches: actualBatchIndex + 1,
|
|
147
|
+
totalBatches: batches.length,
|
|
148
|
+
progress: `${Math.round(((actualBatchIndex + 1) / batches.length) * 100)}%`
|
|
149
|
+
}, 'Batch progress');
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
catch (e) {
|
|
153
|
+
logger.error({ batchIndex: actualBatchIndex, error: e }, 'Error processing message batch');
|
|
154
|
+
throw e; // Re-throw to stop processing
|
|
155
|
+
}
|
|
156
|
+
}));
|
|
157
|
+
}
|
|
158
|
+
logger.info({
|
|
159
|
+
messages: messages.length,
|
|
160
|
+
batches: batches.length,
|
|
161
|
+
batchSize: BATCH_SIZE
|
|
162
|
+
}, 'Successfully synced all messages');
|
|
163
|
+
}
|
|
164
|
+
catch (e) {
|
|
165
|
+
logger.error(e, 'An error occured during messages set');
|
|
166
|
+
throw e; // Re-throw for upstream handling
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
const upsert = async ({ messages, type }) => {
|
|
170
|
+
switch (type) {
|
|
171
|
+
case 'append':
|
|
172
|
+
case 'notify':
|
|
173
|
+
for (const message of messages) {
|
|
174
|
+
try {
|
|
175
|
+
const jid = resolveRemoteJid(message.key);
|
|
176
|
+
const data = (0, utils_1.transformPrisma)(message);
|
|
177
|
+
// Validate data before upsert
|
|
178
|
+
const validatedData = (0, utils_1.validateMessageData)(data);
|
|
179
|
+
// Log if any fields were filtered out during validation
|
|
180
|
+
if (Object.keys(validatedData).length !== Object.keys(data).length) {
|
|
181
|
+
logger.info({
|
|
182
|
+
messageId: message.key.id,
|
|
183
|
+
originalFieldCount: Object.keys(data).length,
|
|
184
|
+
validatedFieldCount: Object.keys(validatedData).length
|
|
185
|
+
}, 'Message data was filtered during validation');
|
|
186
|
+
}
|
|
187
|
+
await (0, utils_1.retryDatabaseOperation)(() => prisma.message.upsert({
|
|
188
|
+
select: { pkId: true },
|
|
189
|
+
create: Object.assign(Object.assign({}, validatedData), { remoteJid: jid, id: message.key.id, sessionId }),
|
|
190
|
+
update: Object.assign({}, validatedData),
|
|
191
|
+
where: { sessionId_remoteJid_id: { remoteJid: jid, id: message.key.id, sessionId } },
|
|
192
|
+
}), 'message.upsert', logger);
|
|
193
|
+
const chatExists = (await prisma.chat.count({ where: { id: jid, sessionId } })) > 0;
|
|
194
|
+
if (type === 'notify' && !chatExists) {
|
|
195
|
+
event.emit('chats.upsert', [
|
|
196
|
+
{
|
|
197
|
+
id: jid,
|
|
198
|
+
conversationTimestamp: (0, baileys_1.toNumber)(message.messageTimestamp),
|
|
199
|
+
unreadCount: 1,
|
|
200
|
+
},
|
|
201
|
+
]);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
catch (e) {
|
|
205
|
+
logger.error(e, 'An error occured during message upsert');
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
break;
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
const update = async (updates) => {
|
|
212
|
+
for (const { update, key } of updates) {
|
|
213
|
+
try {
|
|
214
|
+
const jid = resolveRemoteJid(key);
|
|
215
|
+
await (0, utils_1.retryDatabaseOperation)(() => prisma.$transaction(async (tx) => {
|
|
216
|
+
const prevData = await tx.message.findFirst({
|
|
217
|
+
where: { id: key.id, remoteJid: jid, sessionId },
|
|
218
|
+
});
|
|
219
|
+
if (!prevData) {
|
|
220
|
+
return logger.info({ update }, 'Got update for non existent message');
|
|
221
|
+
}
|
|
222
|
+
const data = Object.assign(Object.assign({}, prevData), update);
|
|
223
|
+
const transformedData = (0, utils_1.transformPrisma)(data);
|
|
224
|
+
// Validate and filter data before upsert
|
|
225
|
+
const validatedData = (0, utils_1.validateMessageData)(transformedData);
|
|
226
|
+
// Additional debug logging for Buffer issues
|
|
227
|
+
if (stringifySafe(validatedData).includes('"type":"Buffer"')) {
|
|
228
|
+
logger.error({
|
|
229
|
+
messageId: key.id,
|
|
230
|
+
issue: 'Buffer objects still present after validation',
|
|
231
|
+
data: validatedData
|
|
232
|
+
}, 'Buffer serialization issue detected');
|
|
233
|
+
}
|
|
234
|
+
// Log if any fields were filtered out during validation
|
|
235
|
+
if (Object.keys(validatedData).length !== Object.keys(transformedData).length) {
|
|
236
|
+
logger.info({
|
|
237
|
+
messageId: key.id,
|
|
238
|
+
originalFieldCount: Object.keys(transformedData).length,
|
|
239
|
+
validatedFieldCount: Object.keys(validatedData).length
|
|
240
|
+
}, 'Message data was filtered during validation in update');
|
|
241
|
+
}
|
|
242
|
+
await tx.message.upsert({
|
|
243
|
+
select: { pkId: true },
|
|
244
|
+
where: {
|
|
245
|
+
sessionId_remoteJid_id: {
|
|
246
|
+
id: key.id,
|
|
247
|
+
remoteJid: jid,
|
|
248
|
+
sessionId,
|
|
249
|
+
},
|
|
250
|
+
},
|
|
251
|
+
create: Object.assign(Object.assign({}, validatedData), { id: key.id, remoteJid: jid, sessionId }),
|
|
252
|
+
update: Object.assign({}, validatedData),
|
|
253
|
+
});
|
|
254
|
+
}, {
|
|
255
|
+
timeout: 10000, // 10 seconds
|
|
256
|
+
}), 'message.update.transaction', logger);
|
|
257
|
+
}
|
|
258
|
+
catch (e) {
|
|
259
|
+
logger.error(e, 'An error occured during message update');
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
};
|
|
263
|
+
const del = async (item) => {
|
|
264
|
+
// try {
|
|
265
|
+
// if ('all' in item) {
|
|
266
|
+
// await prisma.message.deleteMany({ where: { remoteJid: item.jid, sessionId } });
|
|
267
|
+
// return;
|
|
268
|
+
// }
|
|
269
|
+
// const jid = item.keys[0].remoteJid!;
|
|
270
|
+
// await prisma.message.deleteMany({
|
|
271
|
+
// where: { id: { in: item.keys.map((k) => k.id!) }, remoteJid: jid, sessionId },
|
|
272
|
+
// });
|
|
273
|
+
// } catch (e) {
|
|
274
|
+
// logger.error(e, 'An error occured during message delete');
|
|
275
|
+
// }
|
|
276
|
+
};
|
|
277
|
+
const updateReceipt = async (updates) => {
|
|
278
|
+
for (const { key, receipt } of updates) {
|
|
279
|
+
try {
|
|
280
|
+
const jid = resolveRemoteJid(key);
|
|
281
|
+
await (0, utils_1.retryDatabaseOperation)(() => prisma.$transaction(async (tx) => {
|
|
282
|
+
const message = await tx.message.findFirst({
|
|
283
|
+
select: { userReceipt: true },
|
|
284
|
+
where: { id: key.id, remoteJid: jid, sessionId },
|
|
285
|
+
});
|
|
286
|
+
if (!message) {
|
|
287
|
+
return logger.debug({ update }, 'Got receipt update for non existent message');
|
|
288
|
+
}
|
|
289
|
+
let userReceipt = (message.userReceipt || []);
|
|
290
|
+
const recepient = userReceipt.find((m) => m.userJid === receipt.userJid);
|
|
291
|
+
if (recepient) {
|
|
292
|
+
userReceipt = [...userReceipt.filter((m) => m.userJid !== receipt.userJid), receipt];
|
|
293
|
+
}
|
|
294
|
+
else {
|
|
295
|
+
userReceipt.push(receipt);
|
|
296
|
+
}
|
|
297
|
+
await tx.message.update({
|
|
298
|
+
select: { pkId: true },
|
|
299
|
+
data: (0, utils_1.validateMessageData)((0, utils_1.transformPrisma)({ userReceipt: userReceipt })),
|
|
300
|
+
where: {
|
|
301
|
+
sessionId_remoteJid_id: { id: key.id, remoteJid: jid, sessionId },
|
|
302
|
+
},
|
|
303
|
+
});
|
|
304
|
+
}, {
|
|
305
|
+
timeout: 10000, // 10 seconds
|
|
306
|
+
}), 'message.receipt.update.transaction', logger);
|
|
307
|
+
}
|
|
308
|
+
catch (e) {
|
|
309
|
+
logger.error(e, 'An error occured during message receipt update');
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
};
|
|
313
|
+
const updateReaction = async (reactions) => {
|
|
314
|
+
for (const { key, reaction } of reactions) {
|
|
315
|
+
try {
|
|
316
|
+
const jid = resolveRemoteJid(key);
|
|
317
|
+
await (0, utils_1.retryDatabaseOperation)(() => prisma.$transaction(async (tx) => {
|
|
318
|
+
const message = await tx.message.findFirst({
|
|
319
|
+
select: { reactions: true },
|
|
320
|
+
where: { id: key.id, remoteJid: jid, sessionId },
|
|
321
|
+
});
|
|
322
|
+
if (!message) {
|
|
323
|
+
return logger.debug({ update }, 'Got reaction update for non existent message');
|
|
324
|
+
}
|
|
325
|
+
const authorID = getKeyAuthor(reaction.key);
|
|
326
|
+
const existingReactions = (message.reactions || []);
|
|
327
|
+
const filteredReactions = existingReactions.filter((r) => r.key && getKeyAuthor(r.key) !== authorID);
|
|
328
|
+
const updatedReactions = reaction.text ? [...filteredReactions, reaction] : filteredReactions;
|
|
329
|
+
await tx.message.update({
|
|
330
|
+
select: { pkId: true },
|
|
331
|
+
data: (0, utils_1.validateMessageData)((0, utils_1.transformPrisma)({ reactions: updatedReactions })),
|
|
332
|
+
where: {
|
|
333
|
+
sessionId_remoteJid_id: { id: key.id, remoteJid: jid, sessionId },
|
|
334
|
+
},
|
|
335
|
+
});
|
|
336
|
+
}, {
|
|
337
|
+
timeout: 10000, // 10 seconds
|
|
338
|
+
}), 'message.reaction.update.transaction', logger);
|
|
339
|
+
}
|
|
340
|
+
catch (e) {
|
|
341
|
+
logger.error(e, 'An error occured during message reaction update');
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
};
|
|
345
|
+
const listen = () => {
|
|
346
|
+
if (listening)
|
|
347
|
+
return;
|
|
348
|
+
event.on('messaging-history.set', set);
|
|
349
|
+
event.on('messages.upsert', upsert);
|
|
350
|
+
event.on('messages.update', update);
|
|
351
|
+
event.on('messages.delete', del);
|
|
352
|
+
event.on('message-receipt.update', updateReceipt);
|
|
353
|
+
event.on('messages.reaction', updateReaction);
|
|
354
|
+
listening = true;
|
|
355
|
+
};
|
|
356
|
+
const unlisten = () => {
|
|
357
|
+
if (!listening)
|
|
358
|
+
return;
|
|
359
|
+
event.off('messaging-history.set', set);
|
|
360
|
+
event.off('messages.upsert', upsert);
|
|
361
|
+
event.off('messages.update', update);
|
|
362
|
+
event.off('messages.delete', del);
|
|
363
|
+
event.off('message-receipt.update', updateReceipt);
|
|
364
|
+
event.off('messages.reaction', updateReaction);
|
|
365
|
+
listening = false;
|
|
366
|
+
};
|
|
367
|
+
return { listen, unlisten };
|
|
368
|
+
}
|
|
369
|
+
exports.default = messageHandler;
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./store"), exports);
|
|
18
|
+
__exportStar(require("./session"), exports);
|
|
19
|
+
__exportStar(require("./utils"), exports);
|
|
20
|
+
__exportStar(require("./types"), exports);
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import type { AuthenticationCreds, SignalDataTypeMap } from 'baileys';
|
|
3
|
+
import { proto } from 'baileys';
|
|
4
|
+
export declare function useSession(sessionId: string): Promise<{
|
|
5
|
+
state: {
|
|
6
|
+
creds: AuthenticationCreds;
|
|
7
|
+
keys: {
|
|
8
|
+
get: (type: keyof SignalDataTypeMap, ids: string[]) => Promise<{
|
|
9
|
+
[key: string]: string | Uint8Array | string[] | import("baileys").KeyPair | {
|
|
10
|
+
[jid: string]: boolean;
|
|
11
|
+
} | proto.Message.IAppStateSyncKeyData | import("baileys").LTHashState | {
|
|
12
|
+
token: Buffer;
|
|
13
|
+
timestamp?: string | undefined;
|
|
14
|
+
};
|
|
15
|
+
}>;
|
|
16
|
+
set: (data: any) => Promise<void>;
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
saveCreds: () => Promise<void>;
|
|
20
|
+
}>;
|
package/dist/session.js
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useSession = void 0;
|
|
4
|
+
const baileys_1 = require("baileys");
|
|
5
|
+
const baileys_2 = require("baileys");
|
|
6
|
+
const shared_1 = require("./shared");
|
|
7
|
+
const fixId = (id) => id.replace(/\//g, '__').replace(/:/g, '-');
|
|
8
|
+
async function useSession(sessionId) {
|
|
9
|
+
const model = (0, shared_1.usePrisma)().session;
|
|
10
|
+
const logger = (0, shared_1.useLogger)();
|
|
11
|
+
const persistSessionRecord = async (jsonData, id) => {
|
|
12
|
+
const where = { sessionId, id };
|
|
13
|
+
const createPayload = { data: jsonData, id, sessionId };
|
|
14
|
+
const updatePayload = { data: jsonData };
|
|
15
|
+
for (let attempt = 0; attempt < 3; attempt++) {
|
|
16
|
+
try {
|
|
17
|
+
const updateResult = await model.updateMany({
|
|
18
|
+
data: updatePayload,
|
|
19
|
+
where,
|
|
20
|
+
});
|
|
21
|
+
if (updateResult.count > 0) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
await model.create({
|
|
25
|
+
select: { pkId: true },
|
|
26
|
+
data: createPayload,
|
|
27
|
+
});
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
catch (err) {
|
|
31
|
+
if ((err === null || err === void 0 ? void 0 : err.code) === 'P2002') {
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
throw err;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
logger.error({ id, sessionId }, 'Failed to persist session record after repeated retries');
|
|
38
|
+
};
|
|
39
|
+
const write = async (data, id) => {
|
|
40
|
+
try {
|
|
41
|
+
const jsonData = JSON.stringify(data, baileys_2.BufferJSON.replacer);
|
|
42
|
+
try {
|
|
43
|
+
JSON.parse(jsonData, baileys_2.BufferJSON.reviver);
|
|
44
|
+
}
|
|
45
|
+
catch (parseError) {
|
|
46
|
+
logger.error({ id, parseError, dataLength: jsonData === null || jsonData === void 0 ? void 0 : jsonData.length }, 'Cannot serialize session data properly. Skipping write.');
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
id = fixId(id);
|
|
50
|
+
await persistSessionRecord(jsonData, id);
|
|
51
|
+
}
|
|
52
|
+
catch (e) {
|
|
53
|
+
logger.error(e, 'An error occured during session write');
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
const read = async (id) => {
|
|
57
|
+
var _a;
|
|
58
|
+
try {
|
|
59
|
+
const result = await model.findUnique({
|
|
60
|
+
select: { data: true },
|
|
61
|
+
where: { sessionId_id: { id: fixId(id), sessionId } },
|
|
62
|
+
});
|
|
63
|
+
if (!result || typeof result.data === 'undefined') {
|
|
64
|
+
logger.info({ id }, 'Session data not found or value is undefined');
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
try {
|
|
68
|
+
return JSON.parse(result.data, baileys_2.BufferJSON.reviver);
|
|
69
|
+
}
|
|
70
|
+
catch (parseError) {
|
|
71
|
+
logger.error({ id, error: parseError, dataLength: (_a = result.data) === null || _a === void 0 ? void 0 : _a.length }, 'Failed to parse session data JSON. The data might be corrupted.');
|
|
72
|
+
if (id === 'creds') {
|
|
73
|
+
logger.info('Returning fresh credentials due to parsing error');
|
|
74
|
+
return (0, baileys_2.initAuthCreds)();
|
|
75
|
+
}
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
catch (e) {
|
|
80
|
+
logger.error(e, 'An error occured during session read');
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
const del = async (id) => {
|
|
85
|
+
try {
|
|
86
|
+
await model.delete({
|
|
87
|
+
select: { pkId: true },
|
|
88
|
+
where: { sessionId_id: { id: fixId(id), sessionId } },
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
catch (e) {
|
|
92
|
+
const code = e === null || e === void 0 ? void 0 : e.code;
|
|
93
|
+
// P2025: Record to delete does not exist - this is expected behavior
|
|
94
|
+
if (code === 'P2025') {
|
|
95
|
+
logger.debug({ id, sessionId }, 'Session record already deleted or does not exist');
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
logger.error(e, 'An error occured during session delete');
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
const creds = (await read('creds')) || (0, baileys_2.initAuthCreds)();
|
|
102
|
+
return {
|
|
103
|
+
state: {
|
|
104
|
+
creds,
|
|
105
|
+
keys: {
|
|
106
|
+
get: async (type, ids) => {
|
|
107
|
+
const data = {};
|
|
108
|
+
await Promise.all(ids.map(async (id) => {
|
|
109
|
+
let value = await read(`${type}-${id}`);
|
|
110
|
+
if (type === 'app-state-sync-key' && value) {
|
|
111
|
+
value = baileys_1.proto.Message.AppStateSyncKeyData.create(value);
|
|
112
|
+
}
|
|
113
|
+
data[id] = value;
|
|
114
|
+
}));
|
|
115
|
+
return data;
|
|
116
|
+
},
|
|
117
|
+
set: async (data) => {
|
|
118
|
+
const tasks = [];
|
|
119
|
+
for (const category in data) {
|
|
120
|
+
for (const id in data[category]) {
|
|
121
|
+
const value = data[category][id];
|
|
122
|
+
const sId = `${category}-${id}`;
|
|
123
|
+
tasks.push(value ? write(value, sId) : del(sId));
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
await Promise.all(tasks);
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
saveCreds: () => write(creds, 'creds'),
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
exports.useSession = useSession;
|
package/dist/shared.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { PrismaClient } from '@prisma/client';
|
|
2
|
+
import type { SocketConfig } from 'baileys';
|
|
3
|
+
export declare function setPrisma(prismaClient: PrismaClient): void;
|
|
4
|
+
export declare function setLogger(pinoLogger?: SocketConfig['logger']): void;
|
|
5
|
+
export declare function usePrisma(): PrismaClient<import(".prisma/client").Prisma.PrismaClientOptions, never, import("@prisma/client/runtime/library").DefaultArgs>;
|
|
6
|
+
export declare function useLogger(): import("baileys/lib/Utils/logger").ILogger;
|
package/dist/shared.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.useLogger = exports.usePrisma = exports.setLogger = exports.setPrisma = void 0;
|
|
7
|
+
const baileys_1 = require("baileys");
|
|
8
|
+
const tiny_invariant_1 = __importDefault(require("tiny-invariant"));
|
|
9
|
+
let prisma = null;
|
|
10
|
+
let logger = null;
|
|
11
|
+
function setPrisma(prismaClient) {
|
|
12
|
+
prisma = prismaClient;
|
|
13
|
+
}
|
|
14
|
+
exports.setPrisma = setPrisma;
|
|
15
|
+
function setLogger(pinoLogger) {
|
|
16
|
+
logger = pinoLogger || baileys_1.DEFAULT_CONNECTION_CONFIG.logger;
|
|
17
|
+
}
|
|
18
|
+
exports.setLogger = setLogger;
|
|
19
|
+
function usePrisma() {
|
|
20
|
+
(0, tiny_invariant_1.default)(prisma, 'Prisma client cannot be used before initialization');
|
|
21
|
+
return prisma;
|
|
22
|
+
}
|
|
23
|
+
exports.usePrisma = usePrisma;
|
|
24
|
+
function useLogger() {
|
|
25
|
+
return logger || baileys_1.DEFAULT_CONNECTION_CONFIG.logger;
|
|
26
|
+
}
|
|
27
|
+
exports.useLogger = useLogger;
|
package/dist/store.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { BaileysEventEmitter, SocketConfig } from 'baileys';
|
|
2
|
+
import type { PrismaClient } from '@prisma/client';
|
|
3
|
+
type initStoreOptions = {
|
|
4
|
+
/** Prisma client instance */
|
|
5
|
+
prisma: PrismaClient;
|
|
6
|
+
/** Baileys pino logger */
|
|
7
|
+
logger?: SocketConfig['logger'];
|
|
8
|
+
};
|
|
9
|
+
/** Initialize shared instances that will be consumed by the Store instance */
|
|
10
|
+
export declare function initStore({ prisma, logger }: initStoreOptions): void;
|
|
11
|
+
export declare class Store {
|
|
12
|
+
private getJid;
|
|
13
|
+
private readonly chatHandler;
|
|
14
|
+
private readonly messageHandler;
|
|
15
|
+
private readonly contactHandler;
|
|
16
|
+
constructor(sessionId: string, event: BaileysEventEmitter, getJid?: Function | undefined);
|
|
17
|
+
/** Start listening to the events */
|
|
18
|
+
listen(): void;
|
|
19
|
+
/** Stop listening to the events */
|
|
20
|
+
unlisten(): void;
|
|
21
|
+
}
|
|
22
|
+
export {};
|
package/dist/store.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.Store = exports.initStore = void 0;
|
|
27
|
+
const shared_1 = require("./shared");
|
|
28
|
+
const handlers = __importStar(require("./handlers"));
|
|
29
|
+
/** Initialize shared instances that will be consumed by the Store instance */
|
|
30
|
+
function initStore({ prisma, logger }) {
|
|
31
|
+
(0, shared_1.setPrisma)(prisma);
|
|
32
|
+
(0, shared_1.setLogger)(logger);
|
|
33
|
+
}
|
|
34
|
+
exports.initStore = initStore;
|
|
35
|
+
class Store {
|
|
36
|
+
constructor(sessionId, event, getJid = undefined) {
|
|
37
|
+
this.getJid = getJid;
|
|
38
|
+
this.chatHandler = handlers.chatHandler(sessionId, event, this.getJid);
|
|
39
|
+
this.messageHandler = handlers.messageHandler(sessionId, event, this.getJid);
|
|
40
|
+
this.contactHandler = handlers.contactHandler(sessionId, event, this.getJid);
|
|
41
|
+
this.listen();
|
|
42
|
+
}
|
|
43
|
+
/** Start listening to the events */
|
|
44
|
+
listen() {
|
|
45
|
+
this.chatHandler.listen();
|
|
46
|
+
this.messageHandler.listen();
|
|
47
|
+
this.contactHandler.listen();
|
|
48
|
+
}
|
|
49
|
+
/** Stop listening to the events */
|
|
50
|
+
unlisten() {
|
|
51
|
+
this.chatHandler.unlisten();
|
|
52
|
+
this.messageHandler.unlisten();
|
|
53
|
+
this.contactHandler.unlisten();
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
exports.Store = Store;
|