wa-multi-mongodb 3.10.7 → 3.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/readme.md CHANGED
@@ -1,1196 +1,1302 @@
1
- # WhatsApp Multi MongoDB - Multi Session WhatsApp with MongoDB
2
-
3
- ## ⚠️ Important Note
4
- This repository is a modified version of [@mimamch/wa-multi-session](https://github.com/mimamch/wa-multi-session) with MongoDB session management integration. The original repository uses file-based session storage, while this version uses MongoDB for better scalability and session management.
5
-
6
- Lightweight library for WhatsApp with MongoDB integration. No Selenium or browser required.
7
-
8
- Built on [Baileys](https://github.com/WhiskeySockets/Baileys) Library.
9
-
10
- ## Features
11
- - Multi-session WhatsApp (multiple numbers simultaneously)
12
- - State (auth) storage in MongoDB instead of files
13
- - Automatic loading of all sessions from the database at startup
14
- - No need to scan QR again as long as MongoDB data is preserved
15
- - Automatic timeout handling for long-running operations
16
- - Auto-reconnect when connection is lost
17
- - Better group chat support
18
- - Automatic retry for failed message deliveries
19
- - Automatic group chat detection (v3.9.0+)
20
- - Hybrid caching system for group metadata (v3.9.4+)
21
- - Message deletion for self and others (v3.9.5+)
22
- - Custom browser configuration (v3.10.4+)
23
- - LID ↔ PN conversion utilities (v3.10.4+)
24
-
25
- ## Installation
26
-
27
- Install package using npm:
28
-
29
- ```bash
30
- npm install wa-multi-mongodb@latest
31
- ```
32
-
33
- Then import into your code:
34
-
35
- ```typescript
36
- // Using ES modules
37
- import * as whatsapp from "wa-multi-mongodb";
38
-
39
- // Or using CommonJS
40
- const whatsapp = require("wa-multi-mongodb");
41
- ```
42
-
43
- ## Environment Setup
44
-
45
- For secure MongoDB URI management, we recommend using environment variables:
46
-
47
- 1. Create a `.env` file in your project root (copy from `.env.example`):
48
- ```
49
- # MongoDB Configuration
50
- MONGODB_URI=mongodb://username:password@hostname:port/database
51
-
52
- # Optional database settings
53
- WA_DB_NAME=wa_session
54
- WA_COLLECTION_NAME=auth
55
- ```
56
-
57
- 2. Install and use the dotenv package:
58
- ```javascript
59
- // Load environment variables
60
- require('dotenv').config();
61
-
62
- // Use in your code
63
- const MONGODB_URI = process.env.MONGODB_URI;
64
- if (!MONGODB_URI) {
65
- console.error('Error: MONGODB_URI not found in environment variables');
66
- process.exit(1);
67
- }
68
-
69
- // Initialize WhatsApp with MongoDB
70
- await whatsapp.setMongoURI(MONGODB_URI);
71
- ```
72
-
73
- 3. Make sure to add `.env` to your `.gitignore` file to prevent exposing sensitive credentials
74
-
75
- ## MongoDB Configuration
76
-
77
- ### Setup MongoDB Connection
78
- 1. Make sure MongoDB is running (local/cloud)
79
- 2. Configure the connection using one of these methods:
80
-
81
- **Using environment variables (recommended):**
82
- ```javascript
83
- require('dotenv').config();
84
- await whatsapp.setMongoURI(process.env.MONGODB_URI);
85
- ```
86
-
87
- **Directly in code (not recommended for production):**
88
- ```javascript
89
- await whatsapp.setMongoURI("mongodb+srv://username:password@host/db?options");
90
- ```
91
-
92
- 3. Optionally customize the database and collection names:
93
- ```javascript
94
- // Default values are "wa_session" and "auth"
95
- whatsapp.setMongoDBNames("custom_database_name", "custom_collection_name");
96
- ```
97
-
98
- ## Basic Usage
99
-
100
- ### Session Management
101
-
102
- ```javascript
103
- // Start a new session with QR Code
104
- const session = await whatsapp.startSession("mysession");
105
-
106
- // Start with options
107
- await whatsapp.startSession("mysession2", {
108
- printQR: true,
109
- onConnected: () => console.log("Connected!"),
110
- onDisconnected: () => console.log("Disconnected!"),
111
- onQRUpdated: (qr) => {
112
- console.log("New QR:", qr);
113
- // QR data is raw and ready for frontend use
114
- // You can display this in React, Vue, Angular, etc.
115
- }
116
- });
117
-
118
- // Start with custom browser configuration (v3.10.4+)
119
- // Display: "Safari (Mac OS)" in WhatsApp Linked Devices
120
- await whatsapp.startSession("mysession3", {
121
- printQR: true,
122
- browserType: "macOS", // Options: "ubuntu", "macOS", "windows", "appropriate"
123
- browserName: "Safari", // Valid: Chrome, Safari, Firefox, Edge, Opera, IE, Desktop
124
- onConnected: () => console.log("Connected with custom browser!"),
125
- });
126
-
127
- // Start session with Pairing Code (v3.9.6+)
128
- await whatsapp.startSessionWithPairingCode("mysession4", "6281234567890", {
129
- onConnected: () => console.log("Pairing session connected!"),
130
- onDisconnected: () => console.log("Pairing session disconnected!"),
131
- onPairingCode: (code) => {
132
- console.log("Pairing code:", code);
133
- // Enter this code in your WhatsApp app: Settings > Linked Devices > Link a Device > Link with phone number
134
- }
135
- });
136
-
137
- // Pairing code with valid browser config - displays "Edge (Windows)"
138
- // ⚠️ IMPORTANT: Pairing code ONLY works with valid browser configurations!
139
- await whatsapp.startSessionWithPairingCode("mysession5", "6281234567890", {
140
- browserType: "windows",
141
- browserName: "Edge", // Must be valid: Chrome, Safari, Firefox, Edge, Opera, IE, Desktop
142
- onPairingCode: (code) => console.log("Code:", code),
143
- });
144
-
145
- // Get all active sessions
146
- const sessions = await whatsapp.getAllSession();
147
-
148
- // Get data for a specific session
149
- const sessionData = whatsapp.getSession("mysession");
150
-
151
- // Load all saved sessions from MongoDB
152
- await whatsapp.loadSessionsFromMongo();
153
-
154
- // Session Management Utilities (v3.9.6+)
155
- // Get session status with detailed information
156
- const status = await whatsapp.getSessionStatus("mysession");
157
- console.log("Session status:", status);
158
- // Returns: { exists: true, connected: true, sessionType: 'qr' | 'pairing' }
159
-
160
- // Manual reconnection for any session
161
- try {
162
- const reconnected = await whatsapp.reconnect("mysession");
163
- console.log("Reconnection successful:", reconnected);
164
- } catch (error) {
165
- console.error("Reconnection failed:", error);
166
- }
167
-
168
- // Get all pairing code sessions
169
- const pairingSessions = whatsapp.getPairingCodeSessions();
170
- console.log("Pairing code sessions:", pairingSessions);
171
-
172
- // Bulk reconnect all pairing code sessions
173
- await whatsapp.reconnectAllPairingCodeSessions();
174
- ```
175
-
176
- ### Custom Browser Configuration (v3.10.4+)
177
-
178
- Customize how your session appears in WhatsApp's "Linked Devices" list.
179
-
180
- **Display Format in WhatsApp**: `browserName (OsName)` - e.g., "Safari (Mac OS)"
181
-
182
- #### Valid browserName Values
183
-
184
- These are recognized by WhatsApp and will display correctly:
185
-
186
- | browserName | Description |
187
- |-------------|-------------|
188
- | `"Chrome"` | Google Chrome (default) |
189
- | `"Safari"` | Apple Safari |
190
- | `"Firefox"` | Mozilla Firefox |
191
- | `"Edge"` | Microsoft Edge |
192
- | `"Opera"` | Opera Browser |
193
- | `"IE"` | Internet Explorer |
194
- | `"Desktop"` | Generic Desktop App |
195
-
196
- #### browserType Options
197
-
198
- | browserType | OS Name Displayed | OS Version |
199
- |-------------|-------------------|------------|
200
- | `"ubuntu"` | Ubuntu | 22.04.4 |
201
- | `"macOS"` | Mac OS | 14.4.1 |
202
- | `"windows"` | Windows | 10.0.22631 |
203
- | `"appropriate"` | Auto-detect | Based on platform |
204
-
205
- #### Usage Examples
206
-
207
- ```javascript
208
- // Safari on macOS → displays as "Safari (Mac OS)"
209
- await whatsapp.startSession("session1", {
210
- printQR: true,
211
- browserType: "macOS",
212
- browserName: "Safari",
213
- });
214
-
215
- // Chrome on Windows → displays as "Chrome (Windows)"
216
- await whatsapp.startSession("session2", {
217
- printQR: true,
218
- browserType: "windows",
219
- browserName: "Chrome",
220
- });
221
-
222
- // Firefox on Ubuntu → displays as "Firefox (Ubuntu)"
223
- await whatsapp.startSession("session3", {
224
- printQR: true,
225
- browserType: "ubuntu",
226
- browserName: "Firefox",
227
- });
228
-
229
- // Edge on Windows → displays as "Edge (Windows)"
230
- await whatsapp.startSession("session4", {
231
- printQR: true,
232
- browserType: "windows",
233
- browserName: "Edge",
234
- });
235
-
236
- // Desktop app on macOS → displays as "Desktop (Mac OS)"
237
- await whatsapp.startSession("session5", {
238
- printQR: true,
239
- browserType: "macOS",
240
- browserName: "Desktop",
241
- });
242
-
243
- // Custom name (fallback to Chrome) → displays as "Chrome (My Bot App)"
244
- await whatsapp.startSession("session6", {
245
- printQR: true,
246
- browserType: "windows",
247
- browserName: "My Bot App",
248
- });
249
-
250
- // Custom name with Safari → displays as "Safari (My Bot App)"
251
- await whatsapp.startSession("session7", {
252
- printQR: true,
253
- browserType: "macOS",
254
- browserName: "My Bot App",
255
- displayBrowser: "Safari", // Choose which browser type to display
256
- });
257
-
258
- // Custom name with Firefox → displays as "Firefox (Device Bot)"
259
- await whatsapp.startSession("session8", {
260
- printQR: true,
261
- browserType: "ubuntu",
262
- browserName: "Device Bot",
263
- displayBrowser: "Firefox",
264
- });
265
- ```
266
-
267
- #### displayBrowser Parameter (v3.10.5+)
268
-
269
- When using a custom `browserName`, you can now choose which browser type to display using the `displayBrowser` parameter:
270
-
271
- | displayBrowser | Custom Name Example | Display Result |
272
- |----------------|---------------------|----------------|
273
- | `"Chrome"` (default) | "My Bot" | Chrome (My Bot) |
274
- | `"Safari"` | "My Bot" | Safari (My Bot) |
275
- | `"Firefox"` | "My Bot" | Firefox (My Bot) |
276
- | `"Edge"` | "My Bot" | Edge (My Bot) |
277
- | `"Opera"` | "My Bot" | Opera (My Bot) |
278
- | `"Desktop"` | "My Bot" | Desktop (My Bot) |
279
-
280
- > **Note**: `displayBrowser` is only used when `browserName` is a custom name (not a valid browser type like Chrome, Safari, etc.).
281
-
282
- > [!WARNING]
283
- > **Custom browserName and displayBrowser are NOT supported for Pairing Code sessions!**
284
- >
285
- > WhatsApp server validates browser configuration strictly during pairing code authentication. You MUST use valid browser configurations for pairing code:
286
- >
287
- > | browserType | browserName | Display | Pairing Code |
288
- > |-------------|-------------|---------|--------------|
289
- > | `"windows"` | `"Chrome"` | Chrome (Windows) | Works |
290
- > | `"macOS"` | `"Safari"` | Safari (Mac OS) | ✅ Works |
291
- > | `"windows"` | `"Edge"` | Edge (Windows) | ✅ Works |
292
- > | `"ubuntu"` | `"Firefox"` | Firefox (Ubuntu) | ✅ Works |
293
- > | `"windows"` | `"My Bot"` | Chrome (My Bot) | Fails |
294
- >
295
- > Custom names (like "My Bot App") only work with **QR Code** authentication.
296
-
297
-
298
-
299
- ### Sending Messages
300
-
301
- ```javascript
302
- // Send text message
303
- await whatsapp.sendTextMessage({
304
- sessionId: "mysession",
305
- to: "6281234567890", // always include country code
306
- text: "Hello from wa-multi-mongodb!"
307
- // isGroup parameter is optional (v3.9.0+)
308
- // The library will automatically detect if the destination is a group
309
- });
310
-
311
- // Send to a group (automatic detection in v3.9.0+)
312
- await whatsapp.sendTextMessage({
313
- sessionId: "mysession",
314
- to: "120363152682073800", // group ID
315
- text: "Hello group!"
316
- // No need for isGroup: true parameter in v3.9.0+
317
- });
318
-
319
- // Send to a group (compatible with older versions)
320
- await whatsapp.sendTextMessage({
321
- sessionId: "mysession",
322
- to: "120363152682073800", // group ID
323
- text: "Hello group!",
324
- isGroup: true // still works but optional in v3.9.0+
325
- });
326
-
327
- // Send media (unified function)
328
- await whatsapp.sendMedia({
329
- sessionId: "mysession",
330
- to: "6281234567890",
331
- type: "image", // options: image, video, pdf, doc, docx, xls, xlsx, zip, mp3
332
- media: fs.readFileSync("./image.jpg"), // or URL string
333
- caption: "Image caption",
334
- fileName: "image.jpg", // required for documents
335
- // isGroup parameter is optional (v3.9.0+)
336
- });
337
-
338
- // Send voice note
339
- await whatsapp.sendVoiceNote({
340
- sessionId: "mysession",
341
- to: "6281234567890",
342
- media: fs.readFileSync("./audio.mp3"),
343
- // isGroup parameter is optional (v3.9.0+)
344
- });
345
-
346
- // Mark message as read
347
- await whatsapp.readMessage({
348
- sessionId: "mysession",
349
- key: msg.key,
350
- });
351
-
352
- // Send typing indicator
353
- await whatsapp.sendTyping({
354
- sessionId: "mysession",
355
- to: "6281234567890", // or group ID
356
- duration: 3000, // milliseconds
357
- // isGroup parameter is optional (v3.9.0+)
358
- });
359
-
360
- // Delete message (v3.9.5+)
361
- // Delete own message for everyone
362
- await whatsapp.deleteMessage({
363
- sessionId: "mysession",
364
- key: messageObject.key, // message key from received or sent message
365
- });
366
-
367
- // Delete someone else's message (requires admin permissions in groups)
368
- await whatsapp.deleteMessage({
369
- sessionId: "mysession",
370
- key: {
371
- remoteJid: "120363152682073800@g.us", // group ID with @g.us
372
- fromMe: false,
373
- id: "MESSAGE_ID",
374
- participant: "SENDER_JID" // required for group messages
375
- }
376
- });
377
-
378
- // Auto-delete message after delay (helper function example)
379
- function autoDeleteMessage(sessionId, message, delayMs = 3000) {
380
- setTimeout(async () => {
381
- try {
382
- await whatsapp.deleteMessage({
383
- sessionId: sessionId,
384
- key: message.key
385
- });
386
- } catch (error) {
387
- console.error("Error auto-deleting message:", error);
388
- }
389
- }, delayMs);
390
- }
391
-
392
- // Send text message with mention (v3.9.8+)
393
- // Mention one user in a group
394
- await whatsapp.sendTextMessageWithMention({
395
- sessionId: "mysession",
396
- to: "6281234567890@g.us", // group JID
397
- text: "Halo @6281234567890, selamat datang di grup!",
398
- mentions: ["6281234567890@s.whatsapp.net"], // JID to mention
399
- isGroup: true
400
- });
401
-
402
- // Mention multiple users in a group
403
- await whatsapp.sendTextMessageWithMention({
404
- sessionId: "mysession",
405
- to: "6281234567890@g.us",
406
- text: "Halo @6281234567890 dan @6289876543210, ada yang bisa saya bantu?",
407
- mentions: [
408
- "6281234567890@s.whatsapp.net",
409
- "6289876543210@s.whatsapp.net"
410
- ],
411
- isGroup: true
412
- });
413
-
414
- // Mention in private chat (less common but supported)
415
- await whatsapp.sendTextMessageWithMention({
416
- sessionId: "mysession",
417
- to: "6281234567890",
418
- text: "Halo @6281234567890, ini adalah pesan pribadi dengan mention",
419
- mentions: ["6281234567890@s.whatsapp.net"]
420
- });
421
-
422
- // Alternative: Use sendTextMessage with mentions property
423
- // You can also use the regular sendTextMessage with mentions
424
- const session = whatsapp.getSession("mysession");
425
- if (session) {
426
- await session.sendMessage(
427
- "6281234567890@g.us",
428
- {
429
- text: "Halo @6281234567890, ini pesan dengan mention!",
430
- mentions: ["6281234567890@s.whatsapp.net"]
431
- },
432
- {
433
- quoted: null // or message to quote
434
- }
435
- );
436
- }
437
- ```
438
-
439
- ### Event Listeners
440
-
441
- ```javascript
442
- // Incoming messages
443
- whatsapp.onMessageReceived((msg) => {
444
- console.log(`Message from ${msg.key.remoteJid}:`, msg);
445
- });
446
-
447
- // QR code updates
448
- whatsapp.onQRUpdated(({ sessionId, qr }) => {
449
- console.log(`QR Code for ${sessionId}:`, qr);
450
- // You can display this QR in a UI or save it to a file
451
- });
452
-
453
- // Connection events
454
- whatsapp.onConnected((sessionId) => {
455
- console.log(`Session ${sessionId} connected`);
456
- });
457
-
458
- whatsapp.onDisconnected((sessionId) => {
459
- console.log(`Session ${sessionId} disconnected`);
460
- });
461
- ```
462
-
463
- ### Handling Media in Incoming Messages
464
-
465
- ```javascript
466
- whatsapp.onMessageReceived(async (msg) => {
467
- if (msg.message?.imageMessage) {
468
- await msg.saveImage("./saved-image.jpg");
469
- }
470
-
471
- if (msg.message?.videoMessage) {
472
- await msg.saveVideo("./saved-video.mp4");
473
- }
474
-
475
- if (msg.message?.documentMessage) {
476
- await msg.saveDocument("./saved-document"); // extension will be added automatically
477
- }
478
-
479
- if (msg.message?.audioMessage) {
480
- await msg.saveAudio("./saved-audio.mp3");
481
- }
482
- });
483
- ```
484
-
485
- ### Group Metadata Caching (v3.9.4+)
486
-
487
- The library now implements a hybrid caching system for group metadata using both in-memory (NodeCache) and persistent storage (MongoDB). This significantly improves performance for applications that frequently use group metadata information.
488
-
489
- ```javascript
490
- // Configure cache settings (optional, has default values)
491
- whatsapp.setGroupCacheConfig({
492
- stdTTL: 10 * 60, // Time-to-live in seconds (10 minutes)
493
- checkperiod: 120 // Check for expired keys every 2 minutes
494
- });
495
-
496
- // Get group metadata (automatically uses cache if available)
497
- const metadata = await whatsapp.getGroupMetadata(sessionId, groupJid);
498
- console.log(`Group name: ${metadata.subject}`);
499
- console.log(`Participants: ${metadata.participants.length}`);
500
- console.log(`Created on: ${new Date(metadata.creation * 1000).toLocaleString()}`);
501
-
502
- // Force fetch fresh data from server and update cache
503
- const freshData = await whatsapp.getGroupMetadata(sessionId, groupJid, true);
504
-
505
- // Clear cache for specific group in a specific session
506
- await whatsapp.clearGroupMetadataCache(sessionId, groupJid);
507
-
508
- // Clear all group metadata cache for a specific session
509
- await whatsapp.clearSessionGroupMetadataCache(sessionId);
510
-
511
- // Clear all cached group metadata for all sessions
512
- whatsapp.clearAllGroupMetadataCache();
513
- ```
514
-
515
- Benefits of the hybrid caching system:
516
- 1. Significantly reduces WhatsApp API calls for group metadata
517
- 2. Improves response time for group-related features
518
- 3. Persistent cache in MongoDB survives application restarts
519
- 4. In-memory cache provides ultra-fast access for frequently used groups
520
- 5. Automatic cache invalidation on group updates (members, settings, etc.)
521
- 6. **Full multi-session support** - each session has isolated cache for group metadata
522
- 7. Automatic cleanup when sessions are deleted or invalidated
523
-
524
- #### Multi-Session Caching Architecture
525
-
526
- The group metadata cache system is designed to support multiple WhatsApp sessions running simultaneously without any cache collision:
527
-
528
- - Each session maintains its own isolated cache for group metadata
529
- - Cache keys combine both session ID and group ID to ensure separation
530
- - MongoDB storage includes session information for persistent separation
531
- - Cache cleanup happens automatically when sessions are deleted or invalidated
532
- - Memory and database efficiency through shared infrastructure
533
-
534
- This approach ensures that in multi-session environments:
535
- - Session A and Session B can both cache metadata for the same group ID without conflicts
536
- - Each session gets its own view of its accessible groups
537
- - Cache invalidation in one session doesn't affect other sessions
538
-
539
- ## Utility Functions
540
-
541
- ```javascript
542
- // Create a delay
543
- import { createDelay } from "wa-multi-mongodb";
544
- await createDelay(2000); // wait 2 seconds
545
-
546
- // Execute with timeout
547
- import { withTimeout } from "wa-multi-mongodb";
548
- try {
549
- const result = await withTimeout(
550
- functionThatMightTakeTooLong(),
551
- 10000, // timeout in ms
552
- "Operation timed out" // error message if timeout occurs
553
- );
554
- } catch (error) {
555
- console.error(error.message);
556
- }
557
-
558
- // Attempt to reconnect a session
559
- import { reconnect } from "wa-multi-mongodb";
560
- try {
561
- const reconnected = await reconnect("mysession");
562
- console.log("Reconnect successful:", reconnected);
563
- } catch (error) {
564
- console.error("Reconnect failed:", error);
565
- }
566
- ```
567
-
568
- ## LID ↔ PN Conversion Utilities (v3.10.4+)
569
-
570
- WhatsApp has introduced LID (Linked ID) as a new anonymous identifier format to enhance user privacy. These utility functions help you convert between LID and Phone Number (PN) formats.
571
-
572
- ### Understanding LID and PN
573
-
574
- | Format | Description | Example |
575
- |--------|-------------|---------|
576
- | **LID** | Anonymous identifier (new format) | `1524746986546@lid` |
577
- | **PN/JID** | Phone number based identifier (traditional) | `6281234567890@s.whatsapp.net` |
578
-
579
- ### Converting LID to Phone Number
580
-
581
- ```javascript
582
- // Get phone number from LID
583
- const result = await whatsapp.getPNForLID("mysession", "1524746986546@lid");
584
- if (result.success && result.pn) {
585
- console.log(`Phone number: ${result.pn}`);
586
- } else {
587
- console.log("Phone number not found:", result.error);
588
- }
589
-
590
- // Returns: { success: boolean, lid: string, pn: string | null, error?: string }
591
- ```
592
-
593
- ### Converting Phone Number to LID
594
-
595
- ```javascript
596
- // Get LID from phone number
597
- const result = await whatsapp.getLIDForPN("mysession", "6281234567890");
598
- if (result.success && result.lid) {
599
- console.log(`LID: ${result.lid}`);
600
- } else {
601
- console.log("LID not found:", result.error);
602
- }
603
-
604
- // Returns: { success: boolean, pn: string, lid: string | null, error?: string }
605
- ```
606
-
607
- ### Smart Conversion (Auto-detect Format)
608
-
609
- ```javascript
610
- // Automatically convert any JID to phone number
611
- const phoneNumber = await whatsapp.toPhoneNumber("mysession", anyJid);
612
- if (phoneNumber) {
613
- console.log(`Phone: ${phoneNumber}`);
614
- }
615
-
616
- // Automatically convert any JID to LID
617
- const lid = await whatsapp.toLID("mysession", "6281234567890@s.whatsapp.net");
618
- if (lid) {
619
- console.log(`LID: ${lid}`);
620
- }
621
- ```
622
-
623
- ### Get All Known LID Mappings
624
-
625
- ```javascript
626
- // Get all LID-PN mappings for a session
627
- const mappings = await whatsapp.getAllLIDMappings("mysession");
628
- for (const { lid, pn } of mappings) {
629
- console.log(`${lid} => ${pn}`);
630
- }
631
- ```
632
-
633
- ### Format Detection Helpers
634
-
635
- ```javascript
636
- // Check if JID is in LID format
637
- if (whatsapp.isLIDFormat("1524746986546@lid")) {
638
- console.log("This is an LID");
639
- }
640
-
641
- // Check if JID is in PN format
642
- if (whatsapp.isPNFormat("6281234567890@s.whatsapp.net")) {
643
- console.log("This is a phone number JID");
644
- }
645
- ```
646
-
647
- ### Important Notes on LID Conversion
648
-
649
- > ⚠️ **Limitations**:
650
- > - `getPNForLID` may return `null` for new contacts or when WhatsApp hasn't provided the LID-PN mapping
651
- > - LID mappings are only available for contacts that have already interacted with your session
652
- > - WhatsApp is increasingly focusing on privacy, so not all LIDs have known phone numbers
653
-
654
- | Function | Description |
655
- |----------|-------------|
656
- | `getPNForLID(sessionId, lid)` | Convert LID to phone number |
657
- | `getLIDForPN(sessionId, pn)` | Convert phone number to LID |
658
- | `toPhoneNumber(sessionId, jid)` | Smart convert any JID to PN |
659
- | `toLID(sessionId, jid)` | Smart convert any JID to LID |
660
- | `getAllLIDMappings(sessionId)` | Get all known LID-PN mappings |
661
- | `isLIDFormat(jid)` | Check if JID is in LID format |
662
- | `isPNFormat(jid)` | Check if JID is in PN format |
663
-
664
- ## Complete Example: Auto-Reconnect Application
665
-
666
-
667
- ```javascript
668
- import * as whatsapp from "wa-multi-mongodb";
669
- import { withTimeout } from "wa-multi-mongodb";
670
- require('dotenv').config();
671
-
672
- // Store connection status
673
- const sessionStatus = {};
674
-
675
- // Function to check and reconnect if disconnected
676
- async function checkAndReconnect(sessionId) {
677
- if (sessionStatus[sessionId] === 'disconnected') {
678
- try {
679
- const reconnected = await whatsapp.reconnect(sessionId);
680
- if (reconnected) {
681
- sessionStatus[sessionId] = 'connected';
682
- console.log(`Session ${sessionId} reconnected`);
683
- }
684
- } catch (error) {
685
- console.error(`Error during reconnect: ${error.message}`);
686
- }
687
- }
688
- }
689
-
690
- async function startApp() {
691
- // MongoDB Configuration
692
- await whatsapp.setMongoURI(process.env.MONGODB_URI);
693
-
694
- // Event listeners
695
- whatsapp.onQRUpdated(({ sessionId, qr }) => {
696
- console.log(`QR Code for session ${sessionId}:`, qr);
697
- });
698
-
699
- whatsapp.onConnected((sessionId) => {
700
- console.log(`Session ${sessionId} connected!`);
701
- sessionStatus[sessionId] = 'connected';
702
- });
703
-
704
- whatsapp.onDisconnected((sessionId) => {
705
- console.log(`Session ${sessionId} disconnected!`);
706
- sessionStatus[sessionId] = 'disconnected';
707
-
708
- // Try to reconnect after a few seconds
709
- setTimeout(() => checkAndReconnect(sessionId), 10000);
710
- });
711
-
712
- // Message handler with error handling and group detection
713
- whatsapp.onMessageReceived(async (msg) => {
714
- try {
715
- if (msg.key.fromMe || msg.key.remoteJid.includes("status")) return;
716
-
717
- const messageContent = msg.message?.conversation ||
718
- msg.message?.extendedTextMessage?.text ||
719
- "";
720
-
721
- // Detect if message is from a group
722
- const isGroup = msg.key.remoteJid.endsWith('@g.us');
723
-
724
- // Using group metadata cache (v3.9.4+)
725
- if (isGroup) {
726
- const metadata = await whatsapp.getGroupMetadata(msg.sessionId, msg.key.remoteJid);
727
- console.log(`Message from group: ${metadata.subject} with ${metadata.participants.length} members`);
728
- }
729
-
730
- // Mark message as read
731
- try {
732
- await whatsapp.readMessage({
733
- sessionId: msg.sessionId,
734
- key: msg.key,
735
- });
736
- } catch (error) {
737
- if (error.message.includes('Connection Closed')) {
738
- sessionStatus[msg.sessionId] = 'disconnected';
739
- setTimeout(() => checkAndReconnect(msg.sessionId), 5000);
740
- }
741
- }
742
-
743
- // Reply to messages containing "hello"
744
- if (messageContent.toLowerCase().includes("hello")) {
745
- // Show typing indicator (works in both private and group chats since v3.9.1+)
746
- await whatsapp.sendTyping({
747
- sessionId: msg.sessionId,
748
- to: msg.key.remoteJid,
749
- duration: 2000,
750
- });
751
-
752
- // Use different timeouts for groups vs private chats
753
- const timeoutMs = isGroup ? 60000 : 30000;
754
-
755
- try {
756
- await withTimeout(
757
- whatsapp.sendTextMessage({
758
- sessionId: msg.sessionId,
759
- to: msg.key.remoteJid,
760
- text: "Hello! How can I help you?",
761
- answering: msg,
762
- }),
763
- timeoutMs,
764
- "Message sending timed out"
765
- );
766
- } catch (error) {
767
- console.error("Error sending message:", error.message);
768
- }
769
- }
770
-
771
- // Example command to get group info
772
- if (messageContent === "!groupinfo" && isGroup) {
773
- try {
774
- // Force fetch fresh data
775
- const metadata = await whatsapp.getGroupMetadata(msg.sessionId, msg.key.remoteJid, true);
776
-
777
- const adminList = metadata.participants
778
- .filter(p => p.admin)
779
- .map(p => p.id.split('@')[0])
780
- .join(", ");
781
-
782
- const infoText = `*Group Info*\n` +
783
- `Name: ${metadata.subject}\n` +
784
- `Description: ${metadata.desc || 'None'}\n` +
785
- `Members: ${metadata.participants.length}\n` +
786
- `Admins: ${adminList}\n` +
787
- `Created: ${new Date(metadata.creation * 1000).toLocaleString()}`;
788
-
789
- await whatsapp.sendTextMessage({
790
- sessionId: msg.sessionId,
791
- to: msg.key.remoteJid,
792
- text: infoText
793
- });
794
- } catch (error) {
795
- console.error("Error getting group info:", error.message);
796
- }
797
- }
798
- } catch (error) {
799
- // Prevent application crash
800
- console.error("Error processing message:", error.message);
801
- }
802
- });
803
-
804
- // Load all sessions from MongoDB
805
- await whatsapp.loadSessionsFromMongo();
806
-
807
- // Create a main session if it doesn't exist
808
- const mainSession = "main_session";
809
- const existingSessions = await whatsapp.getAllSession();
810
- if (!existingSessions.includes(mainSession)) {
811
- await whatsapp.startSession(mainSession);
812
- } else {
813
- sessionStatus[mainSession] = 'connected';
814
- }
815
-
816
- // Check connections periodically
817
- setInterval(() => {
818
- Object.keys(sessionStatus).forEach(sid => {
819
- checkAndReconnect(sid);
820
- });
821
- }, 5 * 60 * 1000); // check every 5 minutes
822
- }
823
-
824
- startApp().catch(err => {
825
- console.error("Failed to start application:", err);
826
- process.exit(1);
827
- });
828
- ```
829
-
830
- ## Complete Example: Pairing Code with Auto-Reconnect (v3.9.6+)
831
-
832
- ```javascript
833
- import * as whatsapp from "wa-multi-mongodb";
834
- require('dotenv').config();
835
-
836
- // Store connection status
837
- const sessionStatus = {};
838
-
839
- async function startPairingApp() {
840
- // MongoDB Configuration
841
- await whatsapp.setMongoURI(process.env.MONGODB_URI);
842
-
843
- // Event listeners for pairing code sessions
844
- whatsapp.onConnected((sessionId) => {
845
- console.log(`Pairing session ${sessionId} connected!`);
846
- sessionStatus[sessionId] = 'connected';
847
- });
848
-
849
- whatsapp.onDisconnected(async (sessionId) => {
850
- console.log(`Pairing session ${sessionId} disconnected!`);
851
- sessionStatus[sessionId] = 'disconnected';
852
-
853
- // Check if it's a pairing code session
854
- const status = await whatsapp.getSessionStatus(sessionId);
855
- if (status.sessionType === 'pairing') {
856
- console.log(`Attempting to reconnect pairing session ${sessionId}...`);
857
-
858
- // Auto-reconnect after 5 seconds
859
- setTimeout(async () => {
860
- try {
861
- const reconnected = await whatsapp.reconnect(sessionId);
862
- if (reconnected) {
863
- console.log(`Pairing session ${sessionId} reconnected successfully!`);
864
- sessionStatus[sessionId] = 'connected';
865
- }
866
- } catch (error) {
867
- console.error(`Failed to reconnect pairing session ${sessionId}:`, error);
868
- }
869
- }, 5000);
870
- }
871
- });
872
-
873
- // Message handler
874
- whatsapp.onMessageReceived(async (msg) => {
875
- if (msg.key.fromMe || msg.key.remoteJid.includes("status")) return;
876
-
877
- const messageContent = msg.message?.conversation ||
878
- msg.message?.extendedTextMessage?.text ||
879
- "";
880
-
881
- console.log(`Message from ${msg.key.remoteJid}: ${messageContent}`);
882
-
883
- // Auto-reply example
884
- if (messageContent.toLowerCase().includes("ping")) {
885
- await whatsapp.sendTextMessage({
886
- sessionId: msg.sessionId,
887
- to: msg.key.remoteJid,
888
- text: "Pong! Message received from pairing session.",
889
- answering: msg
890
- });
891
- }
892
- });
893
-
894
- // Load existing sessions from MongoDB
895
- await whatsapp.loadSessionsFromMongo();
896
-
897
- // Start a new pairing code session
898
- const pairingSessionId = "pairing_session_1";
899
- const yourPhoneNumber = "6281234567890"; // Replace with your phone number
900
-
901
- try {
902
- await whatsapp.startSessionWithPairingCode(pairingSessionId, yourPhoneNumber, {
903
- onConnected: () => {
904
- console.log("Pairing session connected successfully!");
905
- sessionStatus[pairingSessionId] = 'connected';
906
- },
907
- onDisconnected: () => {
908
- console.log("Pairing session disconnected!");
909
- sessionStatus[pairingSessionId] = 'disconnected';
910
- },
911
- onPairingCode: (code) => {
912
- console.log("\n" + "=".repeat(50));
913
- console.log("📱 PAIRING CODE:", code);
914
- console.log("=".repeat(50));
915
- console.log("1. Open WhatsApp on your phone");
916
- console.log("2. Go to Settings > Linked Devices");
917
- console.log("3. Tap 'Link a Device'");
918
- console.log("4. Tap 'Link with phone number instead'");
919
- console.log("5. Enter the pairing code above");
920
- console.log("=".repeat(50) + "\n");
921
- }
922
- });
923
-
924
- sessionStatus[pairingSessionId] = 'connecting';
925
- } catch (error) {
926
- console.error("Error starting pairing session:", error);
927
- }
928
-
929
- // Periodic health check for pairing sessions
930
- setInterval(async () => {
931
- const pairingSessions = whatsapp.getPairingCodeSessions();
932
- console.log(`Active pairing sessions: ${pairingSessions.length}`);
933
-
934
- // Check each pairing session status
935
- for (const sessionId of pairingSessions) {
936
- const status = await whatsapp.getSessionStatus(sessionId);
937
- console.log(`Session ${sessionId}: ${status.connected ? 'Connected' : 'Disconnected'}`);
938
-
939
- if (!status.connected && sessionStatus[sessionId] === 'connected') {
940
- console.log(`Detected disconnection for ${sessionId}, attempting reconnect...`);
941
- try {
942
- await whatsapp.reconnect(sessionId);
943
- } catch (error) {
944
- console.error(`Reconnect failed for ${sessionId}:`, error);
945
- }
946
- }
947
- }
948
- }, 30000); // Check every 30 seconds
949
-
950
- // Bulk reconnect utility
951
- setInterval(async () => {
952
- try {
953
- await whatsapp.reconnectAllPairingCodeSessions();
954
- console.log("Bulk reconnect completed for all pairing sessions");
955
- } catch (error) {
956
- console.error("Bulk reconnect failed:", error);
957
- }
958
- }, 10 * 60 * 1000); // Every 10 minutes
959
-
960
- console.log("Pairing code application started!");
961
- }
962
-
963
- startPairingApp().catch(err => {
964
- console.error("Failed to start pairing application:", err);
965
- process.exit(1);
966
- });
967
- ```
968
-
969
- ## Frontend Integration Example: QR Code Display (v3.9.6+)
970
-
971
- ```javascript
972
- // React.js example for QR code display
973
- import React, { useState, useEffect } from 'react';
974
- import QRCode from 'qrcode';
975
- import * as whatsapp from "wa-multi-mongodb";
976
-
977
- function WhatsAppQRComponent() {
978
- const [qrDataURL, setQrDataURL] = useState('');
979
- const [sessionStatus, setSessionStatus] = useState('disconnected');
980
-
981
- useEffect(() => {
982
- // Initialize WhatsApp connection
983
- const initWhatsApp = async () => {
984
- await whatsapp.setMongoURI(process.env.REACT_APP_MONGODB_URI);
985
-
986
- // Start session with simplified QR callback
987
- await whatsapp.startSession("frontend_session", {
988
- printQR: false, // Don't print in terminal
989
- onQRUpdated: async (qr) => {
990
- // QR data is raw and ready for frontend use
991
- try {
992
- const qrDataURL = await QRCode.toDataURL(qr);
993
- setQrDataURL(qrDataURL);
994
- } catch (error) {
995
- console.error('Error generating QR code:', error);
996
- }
997
- },
998
- onConnected: () => {
999
- setSessionStatus('connected');
1000
- setQrDataURL(''); // Clear QR when connected
1001
- },
1002
- onDisconnected: () => {
1003
- setSessionStatus('disconnected');
1004
- }
1005
- });
1006
- };
1007
-
1008
- initWhatsApp().catch(console.error);
1009
- }, []);
1010
-
1011
- return (
1012
- <div className="whatsapp-qr">
1013
- <h2>WhatsApp Connection</h2>
1014
- <div className="status">
1015
- Status: <span className={sessionStatus}>{sessionStatus}</span>
1016
- </div>
1017
-
1018
- {qrDataURL && (
1019
- <div className="qr-container">
1020
- <p>Scan this QR code with WhatsApp:</p>
1021
- <img src={qrDataURL} alt="WhatsApp QR Code" />
1022
- </div>
1023
- )}
1024
-
1025
- {sessionStatus === 'connected' && (
1026
- <div className="connected">
1027
- <p>✅ WhatsApp connected successfully!</p>
1028
- </div>
1029
- )}
1030
- </div>
1031
- );
1032
- }
1033
-
1034
- export default WhatsAppQRComponent;
1035
- ```
1036
-
1037
- ## Best Practices for Group Chats
1038
-
1039
- 1. **Auto Group Detection**: Since v3.9.0, the library automatically detects if a chat is a group based on its JID format
1040
- 2. **Typing Indicators**: Typing indicators now work in both private and group chats (v3.9.1+)
1041
- 3. **Longer Timeouts**: Use longer timeouts when sending media to groups (60+ seconds)
1042
- 4. **Handle Errors**: Implement retry mechanisms for failed group messages
1043
- 5. **Announcement Channels**: Groups with announcement channels may trigger `MessageCounterError` (handled automatically in v3.9.1+)
1044
- 6. **Retry Strategy**: For announcement channel groups, the library will automatically retry sending messages up to 3 times with increasing delays
1045
- 7. **Group Metadata Caching**: Use the hybrid caching system (v3.9.4+) to improve performance when working with groups
1046
- 8. **New `sendTextMessageWithMention` Function**: Comprehensive mention functionality for WhatsApp messages (v3.9.8+)
1047
-
1048
- ## WhatsApp Limitations
1049
-
1050
- 1. **Media Transfer**: Large media files to groups may take longer or timeout
1051
- 2. **Connection Stability**: Auto-reconnect may be needed in production apps
1052
- 3. **Announcement Channels**: Some groups with announcement channels may still fail after multiple retries
1053
-
1054
- ## Changelog
1055
-
1056
- ### v3.10.4 (latest)
1057
- - **Custom Browser Configuration**: Added ability to customize browser type and name for WhatsApp connection
1058
- - New `browserType` option: Choose from "ubuntu" (default), "macOS", "windows", or "appropriate"
1059
- - New `browserName` option: Customize the app name displayed in WhatsApp's "Linked Devices" list
1060
- - Works with both `startSession()` and `startSessionWithPairingCode()` methods
1061
- - Default behavior unchanged (Ubuntu browser with "Chrome" name)
1062
- - **LID PN Conversion Utilities**: Added comprehensive utilities for converting between LID (Linked ID) and Phone Number formats
1063
- - New `getPNForLID(sessionId, lid)` function to convert LID to phone number
1064
- - New `getLIDForPN(sessionId, pn)` function to convert phone number to LID
1065
- - New `toPhoneNumber(sessionId, jid)` smart conversion function (auto-detects format)
1066
- - New `toLID(sessionId, jid)` smart conversion function (auto-detects format)
1067
- - New `getAllLIDMappings(sessionId)` function to get all known LID-PN mappings
1068
- - New `isLIDFormat(jid)` and `isPNFormat(jid)` helper functions
1069
- - Uses Baileys' internal `signalRepository.lidMapping` for conversions
1070
-
1071
-
1072
- ### v3.10.2
1073
- - **Fixed Group JID Validation**: Resolved issue with group chat validation
1074
- - Fixed `isValidJid()` function to properly validate group JIDs without requiring dash (-) character
1075
- - Some WhatsApp group IDs don't use dash format, validation now accepts all valid group formats
1076
- - Error "Invalid JID format: [group-id]@g.us" has been resolved
1077
-
1078
- ### v3.10.1
1079
- - **Using Baileys New Version (7.x.x)**: Update & support function with latest baileys version
1080
- - **Added @lid Format Support**: Full support for WhatsApp's new @lid identifier format
1081
- - Updated `phoneToJid()` function to handle both @s.whatsapp.net and @lid formats
1082
- - Enhanced all message sending functions with JID validation:
1083
- - `sendTextMessage()`
1084
- - `sendTextMessageWithMention()`
1085
- - `sendMedia()`
1086
- - `sendVoiceNote()`
1087
- - `sendSticker()`
1088
- - `sendTyping()`
1089
- - No breaking changes - existing @s.whatsapp.net format continues to work
1090
- - Automatic detection and handling of @lid format to prevent 404 errors
1091
- - Added comprehensive error handling for invalid JID formats
1092
-
1093
- ### v3.9.8
1094
- ### Added
1095
- - **New `sendTextMessageWithMention` Function**: Comprehensive mention functionality for WhatsApp messages
1096
- - Support for mentioning single or multiple users in group chats
1097
- - Automatic JID format validation and conversion
1098
- - Full retry mechanism with error handling for mention messages
1099
- - Support for quoted messages with mentions
1100
- - Compatible with both group and private chat mentions
1101
- - Enhanced timeout handling for mention messages
1102
-
1103
- ### v3.9.7
1104
- - **Enhanced Message Processing for Group Chats**: Fixed issues with group message handling and improved message processing architecture
1105
- - **Multiple Message Processing**: Event handler `messages.upsert` now processes all messages in array instead of only the first message
1106
- - **Improved Message Filtering**: Added intelligent filtering to skip protocol messages and empty messages while preserving valid group messages
1107
- - **Enhanced Group Message Support**: Better detection and processing of group messages with participant information
1108
- - **Group vs Private Chat Detection**: Better differentiation between group and private messages
1109
- - **Improved Error Recovery**: Better error handling without changing existing error patterns
1110
-
1111
- ### v3.9.6
1112
- - **Enhanced Pairing Code Support**: Added comprehensive pairing code session management with auto-reconnect capabilities
1113
- - New `startSessionWithPairingCode()` function for creating sessions using pairing codes
1114
- - Intelligent session tracking system that preserves pairing code session data across disconnections
1115
- - Enhanced auto-reconnect mechanism that differentiates between QR code and pairing code sessions
1116
- - Session persistence in MongoDB for pairing code sessions to enable seamless reconnection
1117
- - **New Utility Functions for Session Management**:
1118
- - `reconnect(sessionId)` - Manual reconnection for any session type
1119
- - `reconnectAllPairingCodeSessions()` - Bulk reconnection for all tracked pairing code sessions
1120
- - `getPairingCodeSessions()` - Get list of all pairing code session IDs
1121
- - `getSessionStatus(sessionId)` - Get detailed session status information including session type
1122
- - **QR Data Raw for Frontend Integration**: Simplified QR handling optimized for frontend development
1123
- - Cleaned up QR callback to provide only essential QR data raw for frontend processing
1124
- - Removed unnecessary QR string complexity from callbacks for better performance
1125
- - QR data can be directly used with any frontend QR code library (React, Vue, Angular, etc.)
1126
- - Terminal QR display handled automatically via `printQR` option
1127
- - **Breaking Changes**:
1128
- - Simplified `onQRUpdated` callback signature: removed `qrString` parameter, now only provides raw QR data
1129
- - Session-level `onQRUpdated` option simplified from `(qr, qrString)` to `(qr)` only
1130
- - **Enhanced Session Persistence**: Pairing code sessions maintain authentication state in MongoDB during disconnections
1131
- - **Improved Error Handling**: Better error recovery and automatic session restoration for pairing code sessions
1132
-
1133
- ### v3.9.5
1134
- - New `deleteMessage()` function for deleting messages
1135
- - Support for deleting both own messages and others' messages (requires admin permissions in groups)
1136
- - Auto-delete message utility function example
1137
-
1138
- ### v3.9.4
1139
- - Updated baileys dependency to v6.7.18
1140
- - Added hybrid caching system for group metadata (NodeCache + MongoDB)
1141
- - Improved group operations performance with automatic caching
1142
- - New functions for group metadata management:
1143
- - `getGroupMetadata()` - Get metadata with automatic caching
1144
- - `setGroupCacheConfig()` - Configure cache TTL and check periods
1145
- - `clearGroupMetadataCache()` - Clear specific group metadata
1146
- - `clearAllGroupMetadataCache()` - Clear all cached group metadata
1147
-
1148
- ### v3.9.3
1149
- - Updated QR code implementation for better display in terminal
1150
- - Replaced deprecated `printQRInTerminal` option with `qrcode` library implementation
1151
- - Added support for latest Baileys version
1152
-
1153
- ### v3.9.2
1154
- - Updated Baileys dependency to v6.7.17 for improved stability and compatibility
1155
-
1156
- ### v3.9.1
1157
- - Added special handling for `MessageCounterError` in group chats with announcement channels
1158
- - Implemented automatic retry mechanism for messages to announcement channels
1159
- - Enhanced error reporting for group chat issues
1160
- - Fixed typing indicators to work properly in group chats
1161
-
1162
- ### v3.9.0
1163
- - Added automatic group chat detection - no need to specify `isGroup: true` parameter
1164
- - Improved message sending reliability for group chats
1165
- - Enhanced error handling with better timeout management
1166
- - Implemented automatic format detection for group IDs
1167
-
1168
- ### v3.8.1
1169
- - Updated baileys to v6.7.16
1170
- - Improved MongoDB integration
1171
- - Enhanced error handling and connection stability
1172
-
1173
- ### v3.8.0
1174
- - Package renamed from wa-multi-session to wa-multi-mongodb
1175
- - Added MongoDB session management
1176
- - Fixed connection and authentication issues
1177
-
1178
- ### v3.7.0
1179
- - Upgraded to baileys v6.7.9
1180
- - Fixed phone number validation
1181
- - Removed registered phone number validation requirement
1182
-
1183
- ## Links
1184
-
1185
- - [GitHub Repository](https://github.com/wahdalo/wa-multi-mongodb)
1186
- - [Issue Tracker](https://github.com/wahdalo/wa-multi-mongodb/issues)
1187
- - [Original wa-multi-session](https://github.com/mimamch/wa-multi-session)
1188
- - [Baileys Library](https://github.com/WhiskeySockets/Baileys)
1189
-
1190
- ## Author
1191
-
1192
- - [@wahdalo](https://github.com/wahdalo)
1193
-
1194
- ## License
1195
-
1196
- ISC
1
+ # WhatsApp Multi MongoDB - Multi Session WhatsApp with MongoDB
2
+
3
+ ## ⚠️ Important Note
4
+ This repository is a modified version of [@mimamch/wa-multi-session](https://github.com/mimamch/wa-multi-session) with MongoDB session management integration. The original repository uses file-based session storage, while this version uses MongoDB for better scalability and session management.
5
+
6
+ Lightweight library for WhatsApp with MongoDB integration. No Selenium or browser required.
7
+
8
+ Built on [Baileys](https://github.com/WhiskeySockets/Baileys) Library.
9
+
10
+ ## Features
11
+ - Multi-session WhatsApp (multiple numbers simultaneously)
12
+ - State (auth) storage in MongoDB instead of files
13
+ - Automatic loading of all sessions from the database at startup
14
+ - No need to scan QR again as long as MongoDB data is preserved
15
+ - Automatic timeout handling for long-running operations
16
+ - Auto-reconnect when connection is lost
17
+ - Better group chat support
18
+ - Automatic retry for failed message deliveries
19
+ - Automatic group chat detection (v3.9.0+)
20
+ - Hybrid caching system for group metadata (v3.9.4+)
21
+ - Message deletion for self and others (v3.9.5+)
22
+ - Custom browser configuration (v3.10.4+)
23
+ - LID ↔ PN conversion utilities (v3.10.4+)
24
+ - Proxy support for WebSocket and media connections (v3.10.8+)
25
+ - Download incoming media messages directly as Buffer with session-aware reupload support (v3.10.8+)
26
+
27
+ ## Installation
28
+
29
+ Install package using npm:
30
+
31
+ ```bash
32
+ npm install wa-multi-mongodb@latest
33
+ ```
34
+
35
+ Then import into your code:
36
+
37
+ ```typescript
38
+ // Using ES modules
39
+ import * as whatsapp from "wa-multi-mongodb";
40
+
41
+ // Or using CommonJS
42
+ const whatsapp = require("wa-multi-mongodb");
43
+ ```
44
+
45
+ ## Environment Setup
46
+
47
+ For secure MongoDB URI management, we recommend using environment variables:
48
+
49
+ 1. Create a `.env` file in your project root (copy from `.env.example`):
50
+ ```
51
+ # MongoDB Configuration
52
+ MONGODB_URI=mongodb://username:password@hostname:port/database
53
+
54
+ # Optional database settings
55
+ WA_DB_NAME=wa_session
56
+ WA_COLLECTION_NAME=auth
57
+ ```
58
+
59
+ 2. Install and use the dotenv package:
60
+ ```javascript
61
+ // Load environment variables
62
+ require('dotenv').config();
63
+
64
+ // Use in your code
65
+ const MONGODB_URI = process.env.MONGODB_URI;
66
+ if (!MONGODB_URI) {
67
+ console.error('Error: MONGODB_URI not found in environment variables');
68
+ process.exit(1);
69
+ }
70
+
71
+ // Initialize WhatsApp with MongoDB
72
+ await whatsapp.setMongoURI(MONGODB_URI);
73
+ ```
74
+
75
+ 3. Make sure to add `.env` to your `.gitignore` file to prevent exposing sensitive credentials
76
+
77
+ ## MongoDB Configuration
78
+
79
+ ### Setup MongoDB Connection
80
+ 1. Make sure MongoDB is running (local/cloud)
81
+ 2. Configure the connection using one of these methods:
82
+
83
+ **Using environment variables (recommended):**
84
+ ```javascript
85
+ require('dotenv').config();
86
+ await whatsapp.setMongoURI(process.env.MONGODB_URI);
87
+ ```
88
+
89
+ **Directly in code (not recommended for production):**
90
+ ```javascript
91
+ await whatsapp.setMongoURI("mongodb+srv://username:password@host/db?options");
92
+ ```
93
+
94
+ 3. Optionally customize the database and collection names:
95
+ ```javascript
96
+ // Default values are "wa_session" and "auth"
97
+ whatsapp.setMongoDBNames("custom_database_name", "custom_collection_name");
98
+ ```
99
+
100
+ ## Basic Usage
101
+
102
+ ### Session Management
103
+
104
+ ```javascript
105
+ // Start a new session with QR Code
106
+ const session = await whatsapp.startSession("mysession");
107
+
108
+ // Start with options
109
+ await whatsapp.startSession("mysession2", {
110
+ printQR: true,
111
+ onConnected: () => console.log("Connected!"),
112
+ onDisconnected: () => console.log("Disconnected!"),
113
+ onQRUpdated: (qr) => {
114
+ console.log("New QR:", qr);
115
+ // QR data is raw and ready for frontend use
116
+ // You can display this in React, Vue, Angular, etc.
117
+ }
118
+ });
119
+
120
+ // Start with custom browser configuration (v3.10.4+)
121
+ // Display: "Safari (Mac OS)" in WhatsApp Linked Devices
122
+ await whatsapp.startSession("mysession3", {
123
+ printQR: true,
124
+ browserType: "macOS", // Options: "ubuntu", "macOS", "windows", "appropriate"
125
+ browserName: "Safari", // Valid: Chrome, Safari, Firefox, Edge, Opera, IE, Desktop
126
+ onConnected: () => console.log("Connected with custom browser!"),
127
+ });
128
+
129
+ // Start session with Pairing Code (v3.9.6+)
130
+ await whatsapp.startSessionWithPairingCode("mysession4", "6281234567890", {
131
+ onConnected: () => console.log("Pairing session connected!"),
132
+ onDisconnected: () => console.log("Pairing session disconnected!"),
133
+ onPairingCode: (code) => {
134
+ console.log("Pairing code:", code);
135
+ // Enter this code in your WhatsApp app: Settings > Linked Devices > Link a Device > Link with phone number
136
+ }
137
+ });
138
+
139
+ // Pairing code with valid browser config - displays "Edge (Windows)"
140
+ // ⚠️ IMPORTANT: Pairing code ONLY works with valid browser configurations!
141
+ await whatsapp.startSessionWithPairingCode("mysession5", "6281234567890", {
142
+ browserType: "windows",
143
+ browserName: "Edge", // Must be valid: Chrome, Safari, Firefox, Edge, Opera, IE, Desktop
144
+ onPairingCode: (code) => console.log("Code:", code),
145
+ });
146
+
147
+ // Get all active sessions
148
+ const sessions = await whatsapp.getAllSession();
149
+
150
+ // Get data for a specific session
151
+ const sessionData = whatsapp.getSession("mysession");
152
+
153
+ // Load all saved sessions from MongoDB
154
+ await whatsapp.loadSessionsFromMongo();
155
+
156
+ // Session Management Utilities (v3.9.6+)
157
+ // Get session status with detailed information
158
+ const status = await whatsapp.getSessionStatus("mysession");
159
+ console.log("Session status:", status);
160
+ // Returns: { exists: true, connected: true, sessionType: 'qr' | 'pairing' }
161
+
162
+ // Manual reconnection for any session
163
+ try {
164
+ const reconnected = await whatsapp.reconnect("mysession");
165
+ console.log("Reconnection successful:", reconnected);
166
+ } catch (error) {
167
+ console.error("Reconnection failed:", error);
168
+ }
169
+
170
+ // Get all pairing code sessions
171
+ const pairingSessions = whatsapp.getPairingCodeSessions();
172
+ console.log("Pairing code sessions:", pairingSessions);
173
+
174
+ // Bulk reconnect all pairing code sessions
175
+ await whatsapp.reconnectAllPairingCodeSessions();
176
+ ```
177
+
178
+ ### Custom Browser Configuration (v3.10.4+)
179
+
180
+ Customize how your session appears in WhatsApp's "Linked Devices" list.
181
+
182
+ **Display Format in WhatsApp**: `browserName (OsName)` - e.g., "Safari (Mac OS)"
183
+
184
+ #### Valid browserName Values
185
+
186
+ These are recognized by WhatsApp and will display correctly:
187
+
188
+ | browserName | Description |
189
+ |-------------|-------------|
190
+ | `"Chrome"` | Google Chrome (default) |
191
+ | `"Safari"` | Apple Safari |
192
+ | `"Firefox"` | Mozilla Firefox |
193
+ | `"Edge"` | Microsoft Edge |
194
+ | `"Opera"` | Opera Browser |
195
+ | `"IE"` | Internet Explorer |
196
+ | `"Desktop"` | Generic Desktop App |
197
+
198
+ #### browserType Options
199
+
200
+ | browserType | OS Name Displayed | OS Version |
201
+ |-------------|-------------------|------------|
202
+ | `"ubuntu"` | Ubuntu | 22.04.4 |
203
+ | `"macOS"` | Mac OS | 14.4.1 |
204
+ | `"windows"` | Windows | 10.0.22631 |
205
+ | `"appropriate"` | Auto-detect | Based on platform |
206
+
207
+ #### Usage Examples
208
+
209
+ ```javascript
210
+ // Safari on macOS → displays as "Safari (Mac OS)"
211
+ await whatsapp.startSession("session1", {
212
+ printQR: true,
213
+ browserType: "macOS",
214
+ browserName: "Safari",
215
+ });
216
+
217
+ // Chrome on Windows → displays as "Chrome (Windows)"
218
+ await whatsapp.startSession("session2", {
219
+ printQR: true,
220
+ browserType: "windows",
221
+ browserName: "Chrome",
222
+ });
223
+
224
+ // Firefox on Ubuntu → displays as "Firefox (Ubuntu)"
225
+ await whatsapp.startSession("session3", {
226
+ printQR: true,
227
+ browserType: "ubuntu",
228
+ browserName: "Firefox",
229
+ });
230
+
231
+ // Edge on Windows → displays as "Edge (Windows)"
232
+ await whatsapp.startSession("session4", {
233
+ printQR: true,
234
+ browserType: "windows",
235
+ browserName: "Edge",
236
+ });
237
+
238
+ // Desktop app on macOS → displays as "Desktop (Mac OS)"
239
+ await whatsapp.startSession("session5", {
240
+ printQR: true,
241
+ browserType: "macOS",
242
+ browserName: "Desktop",
243
+ });
244
+
245
+ // Custom name (fallback to Chrome) → displays as "Chrome (My Bot App)"
246
+ await whatsapp.startSession("session6", {
247
+ printQR: true,
248
+ browserType: "windows",
249
+ browserName: "My Bot App",
250
+ });
251
+
252
+ // Custom name with Safari → displays as "Safari (My Bot App)"
253
+ await whatsapp.startSession("session7", {
254
+ printQR: true,
255
+ browserType: "macOS",
256
+ browserName: "My Bot App",
257
+ displayBrowser: "Safari", // Choose which browser type to display
258
+ });
259
+
260
+ // Custom name with Firefox → displays as "Firefox (Device Bot)"
261
+ await whatsapp.startSession("session8", {
262
+ printQR: true,
263
+ browserType: "ubuntu",
264
+ browserName: "Device Bot",
265
+ displayBrowser: "Firefox",
266
+ });
267
+ ```
268
+
269
+ #### displayBrowser Parameter (v3.10.5+)
270
+
271
+ When using a custom `browserName`, you can now choose which browser type to display using the `displayBrowser` parameter:
272
+
273
+ | displayBrowser | Custom Name Example | Display Result |
274
+ |----------------|---------------------|----------------|
275
+ | `"Chrome"` (default) | "My Bot" | Chrome (My Bot) |
276
+ | `"Safari"` | "My Bot" | Safari (My Bot) |
277
+ | `"Firefox"` | "My Bot" | Firefox (My Bot) |
278
+ | `"Edge"` | "My Bot" | Edge (My Bot) |
279
+ | `"Opera"` | "My Bot" | Opera (My Bot) |
280
+ | `"Desktop"` | "My Bot" | Desktop (My Bot) |
281
+
282
+ > **Note**: `displayBrowser` is only used when `browserName` is a custom name (not a valid browser type like Chrome, Safari, etc.).
283
+
284
+ > [!WARNING]
285
+ > **Custom browserName and displayBrowser are NOT supported for Pairing Code sessions!**
286
+ >
287
+ > WhatsApp server validates browser configuration strictly during pairing code authentication. You MUST use valid browser configurations for pairing code:
288
+ >
289
+ > | browserType | browserName | Display | Pairing Code |
290
+ > |-------------|-------------|---------|--------------|
291
+ > | `"windows"` | `"Chrome"` | Chrome (Windows) | ✅ Works |
292
+ > | `"macOS"` | `"Safari"` | Safari (Mac OS) | ✅ Works |
293
+ > | `"windows"` | `"Edge"` | Edge (Windows) | Works |
294
+ > | `"ubuntu"` | `"Firefox"` | Firefox (Ubuntu) | ✅ Works |
295
+ > | `"windows"` | `"My Bot"` | Chrome (My Bot) | ❌ Fails |
296
+ >
297
+ > Custom names (like "My Bot App") only work with **QR Code** authentication.
298
+
299
+ ### Proxy Support (v3.10.8+)
300
+
301
+ You can use a proxy for WebSocket connections and media upload/download. **No additional dependencies are included** - install your preferred proxy agent package if needed.
302
+
303
+ #### Install Proxy Agent (User's Choice)
304
+
305
+ ```bash
306
+ # For HTTP/HTTPS proxy
307
+ npm install https-proxy-agent
308
+
309
+ # For SOCKS4/SOCKS5 proxy
310
+ npm install socks-proxy-agent
311
+ ```
312
+
313
+ #### Usage Examples
314
+
315
+ ```javascript
316
+ // Using HTTPS proxy
317
+ import { HttpsProxyAgent } from 'https-proxy-agent';
318
+
319
+ const proxyAgent = new HttpsProxyAgent('http://proxy.example.com:8080');
320
+ // With authentication: new HttpsProxyAgent('http://user:pass@proxy.example.com:8080');
321
+
322
+ await whatsapp.startSession("mysession", {
323
+ printQR: true,
324
+ agent: proxyAgent, // Proxy for WebSocket connection
325
+ fetchAgent: proxyAgent, // Proxy for media upload/download (optional, defaults to agent)
326
+ });
327
+
328
+ // Using SOCKS5 proxy
329
+ import { SocksProxyAgent } from 'socks-proxy-agent';
330
+
331
+ const socksAgent = new SocksProxyAgent('socks5://127.0.0.1:1080');
332
+ // With authentication: new SocksProxyAgent('socks5://user:pass@127.0.0.1:1080');
333
+
334
+ await whatsapp.startSessionWithPairingCode("mysession", "6281234567890", {
335
+ browserType: "windows",
336
+ browserName: "Chrome",
337
+ agent: socksAgent,
338
+ });
339
+ ```
340
+
341
+ | Option | Type | Description |
342
+ |--------|------|-------------|
343
+ | `agent` | `Agent` | Proxy agent for WebSocket connection |
344
+ | `fetchAgent` | `Agent` | Proxy agent for media upload/download (defaults to `agent`) |
345
+
346
+ > **Note**: Proxy is optional. If not provided, direct connection is used.
347
+
348
+
349
+
350
+ ### Sending Messages
351
+
352
+ ```javascript
353
+ // Send text message
354
+ await whatsapp.sendTextMessage({
355
+ sessionId: "mysession",
356
+ to: "6281234567890", // always include country code
357
+ text: "Hello from wa-multi-mongodb!"
358
+ // isGroup parameter is optional (v3.9.0+)
359
+ // The library will automatically detect if the destination is a group
360
+ });
361
+
362
+ // Send to a group (automatic detection in v3.9.0+)
363
+ await whatsapp.sendTextMessage({
364
+ sessionId: "mysession",
365
+ to: "120363152682073800", // group ID
366
+ text: "Hello group!"
367
+ // No need for isGroup: true parameter in v3.9.0+
368
+ });
369
+
370
+ // Send to a group (compatible with older versions)
371
+ await whatsapp.sendTextMessage({
372
+ sessionId: "mysession",
373
+ to: "120363152682073800", // group ID
374
+ text: "Hello group!",
375
+ isGroup: true // still works but optional in v3.9.0+
376
+ });
377
+
378
+ // Send media (unified function)
379
+ await whatsapp.sendMedia({
380
+ sessionId: "mysession",
381
+ to: "6281234567890",
382
+ type: "image", // options: image, video, pdf, doc, docx, xls, xlsx, zip, mp3
383
+ media: fs.readFileSync("./image.jpg"), // or URL string
384
+ caption: "Image caption",
385
+ fileName: "image.jpg", // required for documents
386
+ // isGroup parameter is optional (v3.9.0+)
387
+ });
388
+
389
+ // Send voice note
390
+ await whatsapp.sendVoiceNote({
391
+ sessionId: "mysession",
392
+ to: "6281234567890",
393
+ media: fs.readFileSync("./audio.mp3"),
394
+ // isGroup parameter is optional (v3.9.0+)
395
+ });
396
+
397
+ // Mark message as read
398
+ await whatsapp.readMessage({
399
+ sessionId: "mysession",
400
+ key: msg.key,
401
+ });
402
+
403
+ // Send typing indicator
404
+ await whatsapp.sendTyping({
405
+ sessionId: "mysession",
406
+ to: "6281234567890", // or group ID
407
+ duration: 3000, // milliseconds
408
+ // isGroup parameter is optional (v3.9.0+)
409
+ });
410
+
411
+ // Delete message (v3.9.5+)
412
+ // Delete own message for everyone
413
+ await whatsapp.deleteMessage({
414
+ sessionId: "mysession",
415
+ key: messageObject.key, // message key from received or sent message
416
+ });
417
+
418
+ // Delete someone else's message (requires admin permissions in groups)
419
+ await whatsapp.deleteMessage({
420
+ sessionId: "mysession",
421
+ key: {
422
+ remoteJid: "120363152682073800@g.us", // group ID with @g.us
423
+ fromMe: false,
424
+ id: "MESSAGE_ID",
425
+ participant: "SENDER_JID" // required for group messages
426
+ }
427
+ });
428
+
429
+ // Auto-delete message after delay (helper function example)
430
+ function autoDeleteMessage(sessionId, message, delayMs = 3000) {
431
+ setTimeout(async () => {
432
+ try {
433
+ await whatsapp.deleteMessage({
434
+ sessionId: sessionId,
435
+ key: message.key
436
+ });
437
+ } catch (error) {
438
+ console.error("Error auto-deleting message:", error);
439
+ }
440
+ }, delayMs);
441
+ }
442
+
443
+ // Send text message with mention (v3.9.8+)
444
+ // Mention one user in a group
445
+ await whatsapp.sendTextMessageWithMention({
446
+ sessionId: "mysession",
447
+ to: "6281234567890@g.us", // group JID
448
+ text: "Halo @6281234567890, selamat datang di grup!",
449
+ mentions: ["6281234567890@s.whatsapp.net"], // JID to mention
450
+ isGroup: true
451
+ });
452
+
453
+ // Mention multiple users in a group
454
+ await whatsapp.sendTextMessageWithMention({
455
+ sessionId: "mysession",
456
+ to: "6281234567890@g.us",
457
+ text: "Halo @6281234567890 dan @6289876543210, ada yang bisa saya bantu?",
458
+ mentions: [
459
+ "6281234567890@s.whatsapp.net",
460
+ "6289876543210@s.whatsapp.net"
461
+ ],
462
+ isGroup: true
463
+ });
464
+
465
+ // Mention in private chat (less common but supported)
466
+ await whatsapp.sendTextMessageWithMention({
467
+ sessionId: "mysession",
468
+ to: "6281234567890",
469
+ text: "Halo @6281234567890, ini adalah pesan pribadi dengan mention",
470
+ mentions: ["6281234567890@s.whatsapp.net"]
471
+ });
472
+
473
+ // Alternative: Use sendTextMessage with mentions property
474
+ // You can also use the regular sendTextMessage with mentions
475
+ const session = whatsapp.getSession("mysession");
476
+ if (session) {
477
+ await session.sendMessage(
478
+ "6281234567890@g.us",
479
+ {
480
+ text: "Halo @6281234567890, ini pesan dengan mention!",
481
+ mentions: ["6281234567890@s.whatsapp.net"]
482
+ },
483
+ {
484
+ quoted: null // or message to quote
485
+ }
486
+ );
487
+ }
488
+ ```
489
+
490
+ ### Event Listeners
491
+
492
+ ```javascript
493
+ // Incoming messages
494
+ whatsapp.onMessageReceived((msg) => {
495
+ console.log(`Message from ${msg.key.remoteJid}:`, msg);
496
+ });
497
+
498
+ // QR code updates
499
+ whatsapp.onQRUpdated(({ sessionId, qr }) => {
500
+ console.log(`QR Code for ${sessionId}:`, qr);
501
+ // You can display this QR in a UI or save it to a file
502
+ });
503
+
504
+ // Connection events
505
+ whatsapp.onConnected((sessionId) => {
506
+ console.log(`Session ${sessionId} connected`);
507
+ });
508
+
509
+ whatsapp.onDisconnected((sessionId) => {
510
+ console.log(`Session ${sessionId} disconnected`);
511
+ });
512
+ ```
513
+
514
+ ### Handling Media in Incoming Messages
515
+
516
+ For simple file saving, incoming media messages include helper methods such as `saveImage`, `saveVideo`, `saveDocument`, and `saveAudio`.
517
+
518
+ ```javascript
519
+ whatsapp.onMessageReceived(async (msg) => {
520
+ if (msg.message?.imageMessage) {
521
+ await msg.saveImage("./saved-image.jpg");
522
+ }
523
+
524
+ if (msg.message?.videoMessage) {
525
+ await msg.saveVideo("./saved-video.mp4");
526
+ }
527
+
528
+ if (msg.message?.documentMessage) {
529
+ await msg.saveDocument("./saved-document"); // extension will be added automatically
530
+ }
531
+
532
+ if (msg.message?.audioMessage) {
533
+ await msg.saveAudio("./saved-audio.mp3");
534
+ }
535
+ });
536
+ ```
537
+
538
+ #### Download Media as Buffer (v3.10.8+)
539
+
540
+ Use `downloadMediaMessage` when you need the raw media `Buffer` instead of saving directly to disk. This is useful for uploading media to cloud storage, forwarding it to another service, processing it in memory, or returning it from an API endpoint.
541
+
542
+ ```javascript
543
+ whatsapp.onMessageReceived(async (msg) => {
544
+ const hasMedia =
545
+ msg.message?.imageMessage ||
546
+ msg.message?.videoMessage ||
547
+ msg.message?.documentMessage ||
548
+ msg.message?.audioMessage ||
549
+ msg.message?.stickerMessage;
550
+
551
+ if (!hasMedia) return;
552
+
553
+ try {
554
+ const buffer = await whatsapp.downloadMediaMessage({
555
+ sessionId: "mysession",
556
+ message: msg,
557
+ });
558
+
559
+ console.log("Downloaded media size:", buffer.length);
560
+ // Example: upload buffer to S3, save to your database, or process it in memory
561
+ } catch (error) {
562
+ console.error("Failed to download media:", error);
563
+ }
564
+ });
565
+ ```
566
+
567
+ Parameters:
568
+
569
+ | Parameter | Type | Required | Description |
570
+ |-----------|------|----------|-------------|
571
+ | `sessionId` | `string` | Yes | Active WhatsApp session ID used to download and reupload expired media if needed |
572
+ | `message` | `any` | Yes | Incoming Baileys message object from `onMessageReceived` |
573
+ | `key` | `any` | No | Reserved optional message key parameter |
574
+
575
+ Returns: `Promise<Buffer>` containing the downloaded media bytes.
576
+
577
+ Notes:
578
+
579
+ - The session must be active, otherwise `sessionNotFound` is thrown.
580
+ - The message must contain downloadable media content.
581
+ - Expired WhatsApp media can be reuploaded automatically through the active session's `updateMediaMessage` handler.
582
+
583
+ ### Group Metadata Caching (v3.9.4+)
584
+
585
+ The library now implements a hybrid caching system for group metadata using both in-memory (NodeCache) and persistent storage (MongoDB). This significantly improves performance for applications that frequently use group metadata information.
586
+
587
+ ```javascript
588
+ // Configure cache settings (optional, has default values)
589
+ whatsapp.setGroupCacheConfig({
590
+ stdTTL: 10 * 60, // Time-to-live in seconds (10 minutes)
591
+ checkperiod: 120 // Check for expired keys every 2 minutes
592
+ });
593
+
594
+ // Get group metadata (automatically uses cache if available)
595
+ const metadata = await whatsapp.getGroupMetadata(sessionId, groupJid);
596
+ console.log(`Group name: ${metadata.subject}`);
597
+ console.log(`Participants: ${metadata.participants.length}`);
598
+ console.log(`Created on: ${new Date(metadata.creation * 1000).toLocaleString()}`);
599
+
600
+ // Force fetch fresh data from server and update cache
601
+ const freshData = await whatsapp.getGroupMetadata(sessionId, groupJid, true);
602
+
603
+ // Clear cache for specific group in a specific session
604
+ await whatsapp.clearGroupMetadataCache(sessionId, groupJid);
605
+
606
+ // Clear all group metadata cache for a specific session
607
+ await whatsapp.clearSessionGroupMetadataCache(sessionId);
608
+
609
+ // Clear all cached group metadata for all sessions
610
+ whatsapp.clearAllGroupMetadataCache();
611
+ ```
612
+
613
+ Benefits of the hybrid caching system:
614
+ 1. Significantly reduces WhatsApp API calls for group metadata
615
+ 2. Improves response time for group-related features
616
+ 3. Persistent cache in MongoDB survives application restarts
617
+ 4. In-memory cache provides ultra-fast access for frequently used groups
618
+ 5. Automatic cache invalidation on group updates (members, settings, etc.)
619
+ 6. **Full multi-session support** - each session has isolated cache for group metadata
620
+ 7. Automatic cleanup when sessions are deleted or invalidated
621
+
622
+ #### Multi-Session Caching Architecture
623
+
624
+ The group metadata cache system is designed to support multiple WhatsApp sessions running simultaneously without any cache collision:
625
+
626
+ - Each session maintains its own isolated cache for group metadata
627
+ - Cache keys combine both session ID and group ID to ensure separation
628
+ - MongoDB storage includes session information for persistent separation
629
+ - Cache cleanup happens automatically when sessions are deleted or invalidated
630
+ - Memory and database efficiency through shared infrastructure
631
+
632
+ This approach ensures that in multi-session environments:
633
+ - Session A and Session B can both cache metadata for the same group ID without conflicts
634
+ - Each session gets its own view of its accessible groups
635
+ - Cache invalidation in one session doesn't affect other sessions
636
+
637
+ ## Utility Functions
638
+
639
+ ```javascript
640
+ // Create a delay
641
+ import { createDelay } from "wa-multi-mongodb";
642
+ await createDelay(2000); // wait 2 seconds
643
+
644
+ // Execute with timeout
645
+ import { withTimeout } from "wa-multi-mongodb";
646
+ try {
647
+ const result = await withTimeout(
648
+ functionThatMightTakeTooLong(),
649
+ 10000, // timeout in ms
650
+ "Operation timed out" // error message if timeout occurs
651
+ );
652
+ } catch (error) {
653
+ console.error(error.message);
654
+ }
655
+
656
+ // Attempt to reconnect a session
657
+ import { reconnect } from "wa-multi-mongodb";
658
+ try {
659
+ const reconnected = await reconnect("mysession");
660
+ console.log("Reconnect successful:", reconnected);
661
+ } catch (error) {
662
+ console.error("Reconnect failed:", error);
663
+ }
664
+ ```
665
+
666
+ ## LID ↔ PN Conversion Utilities (v3.10.4+)
667
+
668
+ WhatsApp has introduced LID (Linked ID) as a new anonymous identifier format to enhance user privacy. These utility functions help you convert between LID and Phone Number (PN) formats.
669
+
670
+ ### Understanding LID and PN
671
+
672
+ | Format | Description | Example |
673
+ |--------|-------------|---------|
674
+ | **LID** | Anonymous identifier (new format) | `1524746986546@lid` |
675
+ | **PN/JID** | Phone number based identifier (traditional) | `6281234567890@s.whatsapp.net` |
676
+
677
+ ### Converting LID to Phone Number
678
+
679
+ ```javascript
680
+ // Get phone number from LID
681
+ const result = await whatsapp.getPNForLID("mysession", "1524746986546@lid");
682
+ if (result.success && result.pn) {
683
+ console.log(`Phone number: ${result.pn}`);
684
+ } else {
685
+ console.log("Phone number not found:", result.error);
686
+ }
687
+
688
+ // Returns: { success: boolean, lid: string, pn: string | null, error?: string }
689
+ ```
690
+
691
+ ### Converting Phone Number to LID
692
+
693
+ ```javascript
694
+ // Get LID from phone number
695
+ const result = await whatsapp.getLIDForPN("mysession", "6281234567890");
696
+ if (result.success && result.lid) {
697
+ console.log(`LID: ${result.lid}`);
698
+ } else {
699
+ console.log("LID not found:", result.error);
700
+ }
701
+
702
+ // Returns: { success: boolean, pn: string, lid: string | null, error?: string }
703
+ ```
704
+
705
+ ### Smart Conversion (Auto-detect Format)
706
+
707
+ ```javascript
708
+ // Automatically convert any JID to phone number
709
+ const phoneNumber = await whatsapp.toPhoneNumber("mysession", anyJid);
710
+ if (phoneNumber) {
711
+ console.log(`Phone: ${phoneNumber}`);
712
+ }
713
+
714
+ // Automatically convert any JID to LID
715
+ const lid = await whatsapp.toLID("mysession", "6281234567890@s.whatsapp.net");
716
+ if (lid) {
717
+ console.log(`LID: ${lid}`);
718
+ }
719
+ ```
720
+
721
+ ### Get All Known LID Mappings
722
+
723
+ ```javascript
724
+ // Get all LID-PN mappings for a session
725
+ const mappings = await whatsapp.getAllLIDMappings("mysession");
726
+ for (const { lid, pn } of mappings) {
727
+ console.log(`${lid} => ${pn}`);
728
+ }
729
+ ```
730
+
731
+ ### Format Detection Helpers
732
+
733
+ ```javascript
734
+ // Check if JID is in LID format
735
+ if (whatsapp.isLIDFormat("1524746986546@lid")) {
736
+ console.log("This is an LID");
737
+ }
738
+
739
+ // Check if JID is in PN format
740
+ if (whatsapp.isPNFormat("6281234567890@s.whatsapp.net")) {
741
+ console.log("This is a phone number JID");
742
+ }
743
+ ```
744
+
745
+ ### Important Notes on LID Conversion
746
+
747
+ > ⚠️ **Limitations**:
748
+ > - `getPNForLID` may return `null` for new contacts or when WhatsApp hasn't provided the LID-PN mapping
749
+ > - LID mappings are only available for contacts that have already interacted with your session
750
+ > - WhatsApp is increasingly focusing on privacy, so not all LIDs have known phone numbers
751
+
752
+ | Function | Description |
753
+ |----------|-------------|
754
+ | `getPNForLID(sessionId, lid)` | Convert LID to phone number |
755
+ | `getLIDForPN(sessionId, pn)` | Convert phone number to LID |
756
+ | `toPhoneNumber(sessionId, jid)` | Smart convert any JID to PN |
757
+ | `toLID(sessionId, jid)` | Smart convert any JID to LID |
758
+ | `getAllLIDMappings(sessionId)` | Get all known LID-PN mappings |
759
+ | `isLIDFormat(jid)` | Check if JID is in LID format |
760
+ | `isPNFormat(jid)` | Check if JID is in PN format |
761
+
762
+ ## Complete Example: Auto-Reconnect Application
763
+
764
+
765
+ ```javascript
766
+ import * as whatsapp from "wa-multi-mongodb";
767
+ import { withTimeout } from "wa-multi-mongodb";
768
+ require('dotenv').config();
769
+
770
+ // Store connection status
771
+ const sessionStatus = {};
772
+
773
+ // Function to check and reconnect if disconnected
774
+ async function checkAndReconnect(sessionId) {
775
+ if (sessionStatus[sessionId] === 'disconnected') {
776
+ try {
777
+ const reconnected = await whatsapp.reconnect(sessionId);
778
+ if (reconnected) {
779
+ sessionStatus[sessionId] = 'connected';
780
+ console.log(`Session ${sessionId} reconnected`);
781
+ }
782
+ } catch (error) {
783
+ console.error(`Error during reconnect: ${error.message}`);
784
+ }
785
+ }
786
+ }
787
+
788
+ async function startApp() {
789
+ // MongoDB Configuration
790
+ await whatsapp.setMongoURI(process.env.MONGODB_URI);
791
+
792
+ // Event listeners
793
+ whatsapp.onQRUpdated(({ sessionId, qr }) => {
794
+ console.log(`QR Code for session ${sessionId}:`, qr);
795
+ });
796
+
797
+ whatsapp.onConnected((sessionId) => {
798
+ console.log(`Session ${sessionId} connected!`);
799
+ sessionStatus[sessionId] = 'connected';
800
+ });
801
+
802
+ whatsapp.onDisconnected((sessionId) => {
803
+ console.log(`Session ${sessionId} disconnected!`);
804
+ sessionStatus[sessionId] = 'disconnected';
805
+
806
+ // Try to reconnect after a few seconds
807
+ setTimeout(() => checkAndReconnect(sessionId), 10000);
808
+ });
809
+
810
+ // Message handler with error handling and group detection
811
+ whatsapp.onMessageReceived(async (msg) => {
812
+ try {
813
+ if (msg.key.fromMe || msg.key.remoteJid.includes("status")) return;
814
+
815
+ const messageContent = msg.message?.conversation ||
816
+ msg.message?.extendedTextMessage?.text ||
817
+ "";
818
+
819
+ // Detect if message is from a group
820
+ const isGroup = msg.key.remoteJid.endsWith('@g.us');
821
+
822
+ // Using group metadata cache (v3.9.4+)
823
+ if (isGroup) {
824
+ const metadata = await whatsapp.getGroupMetadata(msg.sessionId, msg.key.remoteJid);
825
+ console.log(`Message from group: ${metadata.subject} with ${metadata.participants.length} members`);
826
+ }
827
+
828
+ // Mark message as read
829
+ try {
830
+ await whatsapp.readMessage({
831
+ sessionId: msg.sessionId,
832
+ key: msg.key,
833
+ });
834
+ } catch (error) {
835
+ if (error.message.includes('Connection Closed')) {
836
+ sessionStatus[msg.sessionId] = 'disconnected';
837
+ setTimeout(() => checkAndReconnect(msg.sessionId), 5000);
838
+ }
839
+ }
840
+
841
+ // Reply to messages containing "hello"
842
+ if (messageContent.toLowerCase().includes("hello")) {
843
+ // Show typing indicator (works in both private and group chats since v3.9.1+)
844
+ await whatsapp.sendTyping({
845
+ sessionId: msg.sessionId,
846
+ to: msg.key.remoteJid,
847
+ duration: 2000,
848
+ });
849
+
850
+ // Use different timeouts for groups vs private chats
851
+ const timeoutMs = isGroup ? 60000 : 30000;
852
+
853
+ try {
854
+ await withTimeout(
855
+ whatsapp.sendTextMessage({
856
+ sessionId: msg.sessionId,
857
+ to: msg.key.remoteJid,
858
+ text: "Hello! How can I help you?",
859
+ answering: msg,
860
+ }),
861
+ timeoutMs,
862
+ "Message sending timed out"
863
+ );
864
+ } catch (error) {
865
+ console.error("Error sending message:", error.message);
866
+ }
867
+ }
868
+
869
+ // Example command to get group info
870
+ if (messageContent === "!groupinfo" && isGroup) {
871
+ try {
872
+ // Force fetch fresh data
873
+ const metadata = await whatsapp.getGroupMetadata(msg.sessionId, msg.key.remoteJid, true);
874
+
875
+ const adminList = metadata.participants
876
+ .filter(p => p.admin)
877
+ .map(p => p.id.split('@')[0])
878
+ .join(", ");
879
+
880
+ const infoText = `*Group Info*\n` +
881
+ `Name: ${metadata.subject}\n` +
882
+ `Description: ${metadata.desc || 'None'}\n` +
883
+ `Members: ${metadata.participants.length}\n` +
884
+ `Admins: ${adminList}\n` +
885
+ `Created: ${new Date(metadata.creation * 1000).toLocaleString()}`;
886
+
887
+ await whatsapp.sendTextMessage({
888
+ sessionId: msg.sessionId,
889
+ to: msg.key.remoteJid,
890
+ text: infoText
891
+ });
892
+ } catch (error) {
893
+ console.error("Error getting group info:", error.message);
894
+ }
895
+ }
896
+ } catch (error) {
897
+ // Prevent application crash
898
+ console.error("Error processing message:", error.message);
899
+ }
900
+ });
901
+
902
+ // Load all sessions from MongoDB
903
+ await whatsapp.loadSessionsFromMongo();
904
+
905
+ // Create a main session if it doesn't exist
906
+ const mainSession = "main_session";
907
+ const existingSessions = await whatsapp.getAllSession();
908
+ if (!existingSessions.includes(mainSession)) {
909
+ await whatsapp.startSession(mainSession);
910
+ } else {
911
+ sessionStatus[mainSession] = 'connected';
912
+ }
913
+
914
+ // Check connections periodically
915
+ setInterval(() => {
916
+ Object.keys(sessionStatus).forEach(sid => {
917
+ checkAndReconnect(sid);
918
+ });
919
+ }, 5 * 60 * 1000); // check every 5 minutes
920
+ }
921
+
922
+ startApp().catch(err => {
923
+ console.error("Failed to start application:", err);
924
+ process.exit(1);
925
+ });
926
+ ```
927
+
928
+ ## Complete Example: Pairing Code with Auto-Reconnect (v3.9.6+)
929
+
930
+ ```javascript
931
+ import * as whatsapp from "wa-multi-mongodb";
932
+ require('dotenv').config();
933
+
934
+ // Store connection status
935
+ const sessionStatus = {};
936
+
937
+ async function startPairingApp() {
938
+ // MongoDB Configuration
939
+ await whatsapp.setMongoURI(process.env.MONGODB_URI);
940
+
941
+ // Event listeners for pairing code sessions
942
+ whatsapp.onConnected((sessionId) => {
943
+ console.log(`Pairing session ${sessionId} connected!`);
944
+ sessionStatus[sessionId] = 'connected';
945
+ });
946
+
947
+ whatsapp.onDisconnected(async (sessionId) => {
948
+ console.log(`Pairing session ${sessionId} disconnected!`);
949
+ sessionStatus[sessionId] = 'disconnected';
950
+
951
+ // Check if it's a pairing code session
952
+ const status = await whatsapp.getSessionStatus(sessionId);
953
+ if (status.sessionType === 'pairing') {
954
+ console.log(`Attempting to reconnect pairing session ${sessionId}...`);
955
+
956
+ // Auto-reconnect after 5 seconds
957
+ setTimeout(async () => {
958
+ try {
959
+ const reconnected = await whatsapp.reconnect(sessionId);
960
+ if (reconnected) {
961
+ console.log(`Pairing session ${sessionId} reconnected successfully!`);
962
+ sessionStatus[sessionId] = 'connected';
963
+ }
964
+ } catch (error) {
965
+ console.error(`Failed to reconnect pairing session ${sessionId}:`, error);
966
+ }
967
+ }, 5000);
968
+ }
969
+ });
970
+
971
+ // Message handler
972
+ whatsapp.onMessageReceived(async (msg) => {
973
+ if (msg.key.fromMe || msg.key.remoteJid.includes("status")) return;
974
+
975
+ const messageContent = msg.message?.conversation ||
976
+ msg.message?.extendedTextMessage?.text ||
977
+ "";
978
+
979
+ console.log(`Message from ${msg.key.remoteJid}: ${messageContent}`);
980
+
981
+ // Auto-reply example
982
+ if (messageContent.toLowerCase().includes("ping")) {
983
+ await whatsapp.sendTextMessage({
984
+ sessionId: msg.sessionId,
985
+ to: msg.key.remoteJid,
986
+ text: "Pong! Message received from pairing session.",
987
+ answering: msg
988
+ });
989
+ }
990
+ });
991
+
992
+ // Load existing sessions from MongoDB
993
+ await whatsapp.loadSessionsFromMongo();
994
+
995
+ // Start a new pairing code session
996
+ const pairingSessionId = "pairing_session_1";
997
+ const yourPhoneNumber = "6281234567890"; // Replace with your phone number
998
+
999
+ try {
1000
+ await whatsapp.startSessionWithPairingCode(pairingSessionId, yourPhoneNumber, {
1001
+ onConnected: () => {
1002
+ console.log("Pairing session connected successfully!");
1003
+ sessionStatus[pairingSessionId] = 'connected';
1004
+ },
1005
+ onDisconnected: () => {
1006
+ console.log("Pairing session disconnected!");
1007
+ sessionStatus[pairingSessionId] = 'disconnected';
1008
+ },
1009
+ onPairingCode: (code) => {
1010
+ console.log("\n" + "=".repeat(50));
1011
+ console.log("📱 PAIRING CODE:", code);
1012
+ console.log("=".repeat(50));
1013
+ console.log("1. Open WhatsApp on your phone");
1014
+ console.log("2. Go to Settings > Linked Devices");
1015
+ console.log("3. Tap 'Link a Device'");
1016
+ console.log("4. Tap 'Link with phone number instead'");
1017
+ console.log("5. Enter the pairing code above");
1018
+ console.log("=".repeat(50) + "\n");
1019
+ }
1020
+ });
1021
+
1022
+ sessionStatus[pairingSessionId] = 'connecting';
1023
+ } catch (error) {
1024
+ console.error("Error starting pairing session:", error);
1025
+ }
1026
+
1027
+ // Periodic health check for pairing sessions
1028
+ setInterval(async () => {
1029
+ const pairingSessions = whatsapp.getPairingCodeSessions();
1030
+ console.log(`Active pairing sessions: ${pairingSessions.length}`);
1031
+
1032
+ // Check each pairing session status
1033
+ for (const sessionId of pairingSessions) {
1034
+ const status = await whatsapp.getSessionStatus(sessionId);
1035
+ console.log(`Session ${sessionId}: ${status.connected ? 'Connected' : 'Disconnected'}`);
1036
+
1037
+ if (!status.connected && sessionStatus[sessionId] === 'connected') {
1038
+ console.log(`Detected disconnection for ${sessionId}, attempting reconnect...`);
1039
+ try {
1040
+ await whatsapp.reconnect(sessionId);
1041
+ } catch (error) {
1042
+ console.error(`Reconnect failed for ${sessionId}:`, error);
1043
+ }
1044
+ }
1045
+ }
1046
+ }, 30000); // Check every 30 seconds
1047
+
1048
+ // Bulk reconnect utility
1049
+ setInterval(async () => {
1050
+ try {
1051
+ await whatsapp.reconnectAllPairingCodeSessions();
1052
+ console.log("Bulk reconnect completed for all pairing sessions");
1053
+ } catch (error) {
1054
+ console.error("Bulk reconnect failed:", error);
1055
+ }
1056
+ }, 10 * 60 * 1000); // Every 10 minutes
1057
+
1058
+ console.log("Pairing code application started!");
1059
+ }
1060
+
1061
+ startPairingApp().catch(err => {
1062
+ console.error("Failed to start pairing application:", err);
1063
+ process.exit(1);
1064
+ });
1065
+ ```
1066
+
1067
+ ## Frontend Integration Example: QR Code Display (v3.9.6+)
1068
+
1069
+ ```javascript
1070
+ // React.js example for QR code display
1071
+ import React, { useState, useEffect } from 'react';
1072
+ import QRCode from 'qrcode';
1073
+ import * as whatsapp from "wa-multi-mongodb";
1074
+
1075
+ function WhatsAppQRComponent() {
1076
+ const [qrDataURL, setQrDataURL] = useState('');
1077
+ const [sessionStatus, setSessionStatus] = useState('disconnected');
1078
+
1079
+ useEffect(() => {
1080
+ // Initialize WhatsApp connection
1081
+ const initWhatsApp = async () => {
1082
+ await whatsapp.setMongoURI(process.env.REACT_APP_MONGODB_URI);
1083
+
1084
+ // Start session with simplified QR callback
1085
+ await whatsapp.startSession("frontend_session", {
1086
+ printQR: false, // Don't print in terminal
1087
+ onQRUpdated: async (qr) => {
1088
+ // QR data is raw and ready for frontend use
1089
+ try {
1090
+ const qrDataURL = await QRCode.toDataURL(qr);
1091
+ setQrDataURL(qrDataURL);
1092
+ } catch (error) {
1093
+ console.error('Error generating QR code:', error);
1094
+ }
1095
+ },
1096
+ onConnected: () => {
1097
+ setSessionStatus('connected');
1098
+ setQrDataURL(''); // Clear QR when connected
1099
+ },
1100
+ onDisconnected: () => {
1101
+ setSessionStatus('disconnected');
1102
+ }
1103
+ });
1104
+ };
1105
+
1106
+ initWhatsApp().catch(console.error);
1107
+ }, []);
1108
+
1109
+ return (
1110
+ <div className="whatsapp-qr">
1111
+ <h2>WhatsApp Connection</h2>
1112
+ <div className="status">
1113
+ Status: <span className={sessionStatus}>{sessionStatus}</span>
1114
+ </div>
1115
+
1116
+ {qrDataURL && (
1117
+ <div className="qr-container">
1118
+ <p>Scan this QR code with WhatsApp:</p>
1119
+ <img src={qrDataURL} alt="WhatsApp QR Code" />
1120
+ </div>
1121
+ )}
1122
+
1123
+ {sessionStatus === 'connected' && (
1124
+ <div className="connected">
1125
+ <p>✅ WhatsApp connected successfully!</p>
1126
+ </div>
1127
+ )}
1128
+ </div>
1129
+ );
1130
+ }
1131
+
1132
+ export default WhatsAppQRComponent;
1133
+ ```
1134
+
1135
+ ## Best Practices for Group Chats
1136
+
1137
+ 1. **Auto Group Detection**: Since v3.9.0, the library automatically detects if a chat is a group based on its JID format
1138
+ 2. **Typing Indicators**: Typing indicators now work in both private and group chats (v3.9.1+)
1139
+ 3. **Longer Timeouts**: Use longer timeouts when sending media to groups (60+ seconds)
1140
+ 4. **Handle Errors**: Implement retry mechanisms for failed group messages
1141
+ 5. **Announcement Channels**: Groups with announcement channels may trigger `MessageCounterError` (handled automatically in v3.9.1+)
1142
+ 6. **Retry Strategy**: For announcement channel groups, the library will automatically retry sending messages up to 3 times with increasing delays
1143
+ 7. **Group Metadata Caching**: Use the hybrid caching system (v3.9.4+) to improve performance when working with groups
1144
+ 8. **New `sendTextMessageWithMention` Function**: Comprehensive mention functionality for WhatsApp messages (v3.9.8+)
1145
+
1146
+ ## WhatsApp Limitations
1147
+
1148
+ 1. **Media Transfer**: Large media files to groups may take longer or timeout
1149
+ 2. **Connection Stability**: Auto-reconnect may be needed in production apps
1150
+ 3. **Announcement Channels**: Some groups with announcement channels may still fail after multiple retries
1151
+
1152
+ ## Changelog
1153
+
1154
+ ### v3.11.0 (latest)
1155
+ - **New `downloadMediaMessage` Function**: Download incoming WhatsApp media messages directly as a `Buffer`
1156
+ - Supports images, videos, documents, audio, stickers, and other Baileys-supported media messages
1157
+ - Uses the active session for media reupload requests when WhatsApp media links have expired
1158
+ - Useful for cloud uploads, custom storage, media processing, forwarding workflows, and API responses
1159
+ - Throws clear `WhatsappError` messages when the session is missing, message is empty, or media download fails
1160
+ - **Proxy Support**: Added proxy support for WebSocket and media connections
1161
+
1162
+ ### v3.10.4
1163
+ - **Custom Browser Configuration**: Added ability to customize browser type and name for WhatsApp connection
1164
+ - New `browserType` option: Choose from "ubuntu" (default), "macOS", "windows", or "appropriate"
1165
+ - New `browserName` option: Customize the app name displayed in WhatsApp's "Linked Devices" list
1166
+ - Works with both `startSession()` and `startSessionWithPairingCode()` methods
1167
+ - Default behavior unchanged (Ubuntu browser with "Chrome" name)
1168
+ - **LID ↔ PN Conversion Utilities**: Added comprehensive utilities for converting between LID (Linked ID) and Phone Number formats
1169
+ - New `getPNForLID(sessionId, lid)` function to convert LID to phone number
1170
+ - New `getLIDForPN(sessionId, pn)` function to convert phone number to LID
1171
+ - New `toPhoneNumber(sessionId, jid)` smart conversion function (auto-detects format)
1172
+ - New `toLID(sessionId, jid)` smart conversion function (auto-detects format)
1173
+ - New `getAllLIDMappings(sessionId)` function to get all known LID-PN mappings
1174
+ - New `isLIDFormat(jid)` and `isPNFormat(jid)` helper functions
1175
+ - Uses Baileys' internal `signalRepository.lidMapping` for conversions
1176
+
1177
+
1178
+ ### v3.10.2
1179
+ - **Fixed Group JID Validation**: Resolved issue with group chat validation
1180
+ - Fixed `isValidJid()` function to properly validate group JIDs without requiring dash (-) character
1181
+ - Some WhatsApp group IDs don't use dash format, validation now accepts all valid group formats
1182
+ - Error "Invalid JID format: [group-id]@g.us" has been resolved
1183
+
1184
+ ### v3.10.1
1185
+ - **Using Baileys New Version (7.x.x)**: Update & support function with latest baileys version
1186
+ - **Added @lid Format Support**: Full support for WhatsApp's new @lid identifier format
1187
+ - Updated `phoneToJid()` function to handle both @s.whatsapp.net and @lid formats
1188
+ - Enhanced all message sending functions with JID validation:
1189
+ - `sendTextMessage()`
1190
+ - `sendTextMessageWithMention()`
1191
+ - `sendMedia()`
1192
+ - `sendVoiceNote()`
1193
+ - `sendSticker()`
1194
+ - `sendTyping()`
1195
+ - No breaking changes - existing @s.whatsapp.net format continues to work
1196
+ - Automatic detection and handling of @lid format to prevent 404 errors
1197
+ - Added comprehensive error handling for invalid JID formats
1198
+
1199
+ ### v3.9.8
1200
+ ### Added
1201
+ - **New `sendTextMessageWithMention` Function**: Comprehensive mention functionality for WhatsApp messages
1202
+ - Support for mentioning single or multiple users in group chats
1203
+ - Automatic JID format validation and conversion
1204
+ - Full retry mechanism with error handling for mention messages
1205
+ - Support for quoted messages with mentions
1206
+ - Compatible with both group and private chat mentions
1207
+ - Enhanced timeout handling for mention messages
1208
+
1209
+ ### v3.9.7
1210
+ - **Enhanced Message Processing for Group Chats**: Fixed issues with group message handling and improved message processing architecture
1211
+ - **Multiple Message Processing**: Event handler `messages.upsert` now processes all messages in array instead of only the first message
1212
+ - **Improved Message Filtering**: Added intelligent filtering to skip protocol messages and empty messages while preserving valid group messages
1213
+ - **Enhanced Group Message Support**: Better detection and processing of group messages with participant information
1214
+ - **Group vs Private Chat Detection**: Better differentiation between group and private messages
1215
+ - **Improved Error Recovery**: Better error handling without changing existing error patterns
1216
+
1217
+ ### v3.9.6
1218
+ - **Enhanced Pairing Code Support**: Added comprehensive pairing code session management with auto-reconnect capabilities
1219
+ - New `startSessionWithPairingCode()` function for creating sessions using pairing codes
1220
+ - Intelligent session tracking system that preserves pairing code session data across disconnections
1221
+ - Enhanced auto-reconnect mechanism that differentiates between QR code and pairing code sessions
1222
+ - Session persistence in MongoDB for pairing code sessions to enable seamless reconnection
1223
+ - **New Utility Functions for Session Management**:
1224
+ - `reconnect(sessionId)` - Manual reconnection for any session type
1225
+ - `reconnectAllPairingCodeSessions()` - Bulk reconnection for all tracked pairing code sessions
1226
+ - `getPairingCodeSessions()` - Get list of all pairing code session IDs
1227
+ - `getSessionStatus(sessionId)` - Get detailed session status information including session type
1228
+ - **QR Data Raw for Frontend Integration**: Simplified QR handling optimized for frontend development
1229
+ - Cleaned up QR callback to provide only essential QR data raw for frontend processing
1230
+ - Removed unnecessary QR string complexity from callbacks for better performance
1231
+ - QR data can be directly used with any frontend QR code library (React, Vue, Angular, etc.)
1232
+ - Terminal QR display handled automatically via `printQR` option
1233
+ - **Breaking Changes**:
1234
+ - Simplified `onQRUpdated` callback signature: removed `qrString` parameter, now only provides raw QR data
1235
+ - Session-level `onQRUpdated` option simplified from `(qr, qrString)` to `(qr)` only
1236
+ - **Enhanced Session Persistence**: Pairing code sessions maintain authentication state in MongoDB during disconnections
1237
+ - **Improved Error Handling**: Better error recovery and automatic session restoration for pairing code sessions
1238
+
1239
+ ### v3.9.5
1240
+ - New `deleteMessage()` function for deleting messages
1241
+ - Support for deleting both own messages and others' messages (requires admin permissions in groups)
1242
+ - Auto-delete message utility function example
1243
+
1244
+ ### v3.9.4
1245
+ - Updated baileys dependency to v6.7.18
1246
+ - Added hybrid caching system for group metadata (NodeCache + MongoDB)
1247
+ - Improved group operations performance with automatic caching
1248
+ - New functions for group metadata management:
1249
+ - `getGroupMetadata()` - Get metadata with automatic caching
1250
+ - `setGroupCacheConfig()` - Configure cache TTL and check periods
1251
+ - `clearGroupMetadataCache()` - Clear specific group metadata
1252
+ - `clearAllGroupMetadataCache()` - Clear all cached group metadata
1253
+
1254
+ ### v3.9.3
1255
+ - Updated QR code implementation for better display in terminal
1256
+ - Replaced deprecated `printQRInTerminal` option with `qrcode` library implementation
1257
+ - Added support for latest Baileys version
1258
+
1259
+ ### v3.9.2
1260
+ - Updated Baileys dependency to v6.7.17 for improved stability and compatibility
1261
+
1262
+ ### v3.9.1
1263
+ - Added special handling for `MessageCounterError` in group chats with announcement channels
1264
+ - Implemented automatic retry mechanism for messages to announcement channels
1265
+ - Enhanced error reporting for group chat issues
1266
+ - Fixed typing indicators to work properly in group chats
1267
+
1268
+ ### v3.9.0
1269
+ - Added automatic group chat detection - no need to specify `isGroup: true` parameter
1270
+ - Improved message sending reliability for group chats
1271
+ - Enhanced error handling with better timeout management
1272
+ - Implemented automatic format detection for group IDs
1273
+
1274
+ ### v3.8.1
1275
+ - Updated baileys to v6.7.16
1276
+ - Improved MongoDB integration
1277
+ - Enhanced error handling and connection stability
1278
+
1279
+ ### v3.8.0
1280
+ - Package renamed from wa-multi-session to wa-multi-mongodb
1281
+ - Added MongoDB session management
1282
+ - Fixed connection and authentication issues
1283
+
1284
+ ### v3.7.0
1285
+ - Upgraded to baileys v6.7.9
1286
+ - Fixed phone number validation
1287
+ - Removed registered phone number validation requirement
1288
+
1289
+ ## Links
1290
+
1291
+ - [GitHub Repository](https://github.com/wahdalo/wa-multi-mongodb)
1292
+ - [Issue Tracker](https://github.com/wahdalo/wa-multi-mongodb/issues)
1293
+ - [Original wa-multi-session](https://github.com/mimamch/wa-multi-session)
1294
+ - [Baileys Library](https://github.com/WhiskeySockets/Baileys)
1295
+
1296
+ ## Author
1297
+
1298
+ - [@wahdalo](https://github.com/wahdalo)
1299
+
1300
+ ## License
1301
+
1302
+ ISC