innovators-bot2 2.0.1 → 2.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +172 -10
- package/STORE_PERSISTENCE.md +62 -0
- package/example.js +205 -67
- package/index.js +395 -24
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -9,12 +9,14 @@ A powerful WhatsApp client library that provides seamless integration between Ba
|
|
|
9
9
|
- 💬 Send and receive messages
|
|
10
10
|
- � Message reactions (add/remove emoji reactions)
|
|
11
11
|
- �📸 Media handling (images, videos, documents)
|
|
12
|
-
-
|
|
12
|
+
- � Mentions support in text and media messages
|
|
13
|
+
- �👥 Group management
|
|
13
14
|
- 💾 Message history and chat management
|
|
14
15
|
- 🔄 Auto-reconnect functionality
|
|
15
16
|
- 📝 Read receipts
|
|
16
17
|
- 🔐 LID (Local Identifier) support for enhanced privacy
|
|
17
18
|
- 🗂️ Signal repository store for LID/PN mapping
|
|
19
|
+
- 🧩 Interactive buttons support for both text and media (URL or local file)
|
|
18
20
|
|
|
19
21
|
## Installation
|
|
20
22
|
|
|
@@ -97,10 +99,22 @@ await client.sendMedia('1234567890@s.whatsapp.net', './image.jpg', {
|
|
|
97
99
|
caption: 'Check out this image!'
|
|
98
100
|
})
|
|
99
101
|
|
|
102
|
+
// Send an image with mentions
|
|
103
|
+
await client.sendMedia('1234567890@s.whatsapp.net', './image.jpg', {
|
|
104
|
+
caption: 'Hey @user, check this out!',
|
|
105
|
+
mentions: ['user@s.whatsapp.net']
|
|
106
|
+
})
|
|
107
|
+
|
|
100
108
|
// Send a document
|
|
101
109
|
await client.sendDocument('1234567890@s.whatsapp.net', './document.pdf',
|
|
102
110
|
'Check out this document!'
|
|
103
111
|
)
|
|
112
|
+
|
|
113
|
+
// Send a document with mentions (caption object is supported)
|
|
114
|
+
await client.sendDocument('1234567890@s.whatsapp.net', './document.pdf', {
|
|
115
|
+
caption: 'Hey @user, please read this',
|
|
116
|
+
mentions: ['user@s.whatsapp.net']
|
|
117
|
+
})
|
|
104
118
|
```
|
|
105
119
|
|
|
106
120
|
### 3. Sticker Management
|
|
@@ -144,10 +158,20 @@ client.on('message-deleted', async (data) => {
|
|
|
144
158
|
```javascript
|
|
145
159
|
// Get all groups
|
|
146
160
|
const groups = await client.getAllGroups()
|
|
161
|
+
groups.forEach(g => console.log(g.subject, g.id, g.notify, g.participants.length))
|
|
147
162
|
|
|
148
|
-
// Get group metadata (participants, name, description...)
|
|
163
|
+
// Get group metadata (participants, name, description, settings...)
|
|
149
164
|
const metadata = await client.getGroupMetadata(groupId)
|
|
150
|
-
console.log(metadata.id, metadata.subject, metadata.desc)
|
|
165
|
+
console.log(metadata.id, metadata.subject, metadata.desc, metadata.notify)
|
|
166
|
+
console.log('Owner:', metadata.owner, 'Created:', new Date(metadata.creation * 1000))
|
|
167
|
+
console.log('Announce:', metadata.announce, 'Restrict:', metadata.restrict)
|
|
168
|
+
|
|
169
|
+
// Access participants with roles and notify names
|
|
170
|
+
metadata.participants.forEach(p => {
|
|
171
|
+
const role = p.admin === 'superadmin' ? 'Super Admin'
|
|
172
|
+
: p.admin === 'admin' ? 'Admin' : 'Member'
|
|
173
|
+
console.log(`${p.id} - ${role} - Name: ${p.notify || 'N/A'}`)
|
|
174
|
+
})
|
|
151
175
|
|
|
152
176
|
// Create a new group
|
|
153
177
|
const newGroup = await client.createGroup('Group Name', ['1234567890@s.whatsapp.net'])
|
|
@@ -277,7 +301,7 @@ await client.sendButtons('1234567890@s.whatsapp.net', {
|
|
|
277
301
|
text: 'Do you like this bot?',
|
|
278
302
|
title: 'Feedback',
|
|
279
303
|
subtitle: 'Let us know!',
|
|
280
|
-
footer: 'Powered by
|
|
304
|
+
footer: 'Powered by Innovators Soft',
|
|
281
305
|
interactiveButtons: [
|
|
282
306
|
{
|
|
283
307
|
name: 'quick_reply',
|
|
@@ -295,6 +319,43 @@ await client.sendButtons('1234567890@s.whatsapp.net', {
|
|
|
295
319
|
}
|
|
296
320
|
]
|
|
297
321
|
});
|
|
322
|
+
|
|
323
|
+
// Send interactive buttons with an image from URL + caption
|
|
324
|
+
await client.sendButtons('1234567890@s.whatsapp.net', {
|
|
325
|
+
image: { url: 'https://example.com/image.jpg' },
|
|
326
|
+
caption: 'Body',
|
|
327
|
+
title: 'Title',
|
|
328
|
+
subtitle: 'Subtitle',
|
|
329
|
+
footer: 'Footer',
|
|
330
|
+
interactiveButtons: [
|
|
331
|
+
{
|
|
332
|
+
name: 'quick_reply',
|
|
333
|
+
buttonParamsJson: JSON.stringify({
|
|
334
|
+
display_text: 'DisplayText',
|
|
335
|
+
id: 'ID1'
|
|
336
|
+
})
|
|
337
|
+
}
|
|
338
|
+
],
|
|
339
|
+
hasMediaAttachment: false
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
// Send interactive buttons with a local image file + caption
|
|
343
|
+
await client.sendButtons('1234567890@s.whatsapp.net', {
|
|
344
|
+
imagePath: './image.jpg',
|
|
345
|
+
caption: 'Body',
|
|
346
|
+
title: 'Title',
|
|
347
|
+
subtitle: 'Subtitle',
|
|
348
|
+
footer: 'Footer',
|
|
349
|
+
interactiveButtons: [
|
|
350
|
+
{
|
|
351
|
+
name: 'quick_reply',
|
|
352
|
+
buttonParamsJson: JSON.stringify({
|
|
353
|
+
display_text: 'DisplayText',
|
|
354
|
+
id: 'ID1'
|
|
355
|
+
})
|
|
356
|
+
}
|
|
357
|
+
]
|
|
358
|
+
});
|
|
298
359
|
```
|
|
299
360
|
|
|
300
361
|
#### List Messages
|
|
@@ -327,11 +388,72 @@ await client.SendList('1234567890@s.whatsapp.net', {
|
|
|
327
388
|
### 8. Message History
|
|
328
389
|
|
|
329
390
|
```javascript
|
|
330
|
-
|
|
331
|
-
|
|
391
|
+
### 8. Message Store (History)
|
|
392
|
+
|
|
393
|
+
The library includes a robust message store to keep track of chat history, even across reloads.
|
|
394
|
+
|
|
395
|
+
#### Basic Store Operations
|
|
396
|
+
```javascript
|
|
397
|
+
// Get all stored messages for a specific chat
|
|
398
|
+
const messages = client.getStoredMessages('1234567890@s.whatsapp.net');
|
|
399
|
+
|
|
400
|
+
// Get all stored messages across all chats
|
|
401
|
+
const allMessages = client.getAllStoredMessages();
|
|
332
402
|
|
|
333
|
-
// Get
|
|
334
|
-
const
|
|
403
|
+
// Get list of all chat JIDs in the store
|
|
404
|
+
const activeChats = client.getStoredChatIds();
|
|
405
|
+
|
|
406
|
+
// Get statistics about the message store
|
|
407
|
+
const stats = client.getStoreStats();
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
#### Message Store Persistence
|
|
411
|
+
|
|
412
|
+
The message store can be saved to and loaded from a file for consistency across restarts:
|
|
413
|
+
|
|
414
|
+
```javascript
|
|
415
|
+
// Initialize client with persistence configuration
|
|
416
|
+
const client = new WhatsAppClient({
|
|
417
|
+
sessionName: 'my-session',
|
|
418
|
+
messageStoreFilePath: './data/my-session/message-store.json', // Optional custom path
|
|
419
|
+
autoSaveInterval: 5 * 60 * 1000, // Auto-save every 5 minutes (default)
|
|
420
|
+
maxMessagesPerChat: 1000, // Maximum messages to keep per chat
|
|
421
|
+
messageTTL: 24 * 60 * 60 * 1000 // Message time-to-live (24 hours default)
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
// The store will automatically:
|
|
425
|
+
// - Load from file when connected
|
|
426
|
+
// - Save to file when disconnected
|
|
427
|
+
// - Auto-save periodically (every 5 minutes by default)
|
|
428
|
+
|
|
429
|
+
// Manual save/load operations
|
|
430
|
+
await client.saveMessageStore(); // Returns {success, path, messageCount, savedAt}
|
|
431
|
+
await client.loadMessageStore(); // Returns {success, messageCount, loadedFrom}
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
**Features:**
|
|
435
|
+
- 💾 **Auto-save**: Automatically saves the store at regular intervals
|
|
436
|
+
- 🔄 **Auto-load**: Loads the store when connecting
|
|
437
|
+
- 🛡️ **Safe shutdown**: Saves the store before disconnecting
|
|
438
|
+
- 📊 **Change tracking**: Only saves when there are new messages
|
|
439
|
+
- 🗂️ **Custom paths**: Configure where to save the store file
|
|
440
|
+
|
|
441
|
+
#### Events
|
|
442
|
+
The message store emits events you can listen to:
|
|
443
|
+
- `message-stored`: Emitted when messages are added to the cache.
|
|
444
|
+
- `store-loaded`: Emitted when the store is loaded from file.
|
|
445
|
+
- `store-cleared`: Emitted when the entire store is cleared.
|
|
446
|
+
- `chat-store-cleared`: Emitted when a specific chat's history is cleared.
|
|
447
|
+
|
|
448
|
+
```javascript
|
|
449
|
+
client.on('message-stored', (messages) => {
|
|
450
|
+
console.log('Messages cached:', messages.length);
|
|
451
|
+
});
|
|
452
|
+
|
|
453
|
+
client.on('store-loaded', (info) => {
|
|
454
|
+
console.log(`Loaded ${info.messageCount} messages from file`);
|
|
455
|
+
});
|
|
456
|
+
```
|
|
335
457
|
```
|
|
336
458
|
|
|
337
459
|
## More Examples and Information
|
|
@@ -387,7 +509,7 @@ The library includes example bot commands that you can use:
|
|
|
387
509
|
- `!revokeinvite` - Revoke current invite code and generate new one
|
|
388
510
|
- `!leavegroup` - Leave the current group
|
|
389
511
|
- `!joingroup <code>` - Join a group by invite code
|
|
390
|
-
- `!groupinfo
|
|
512
|
+
- `!groupinfo [jid|code]` - Get full group details (use in-group, by JID, or by invite code) — shows participants, roles, names, and group settings
|
|
391
513
|
- `!joinrequests` - List pending join requests
|
|
392
514
|
- `!approvejoin <number>` - Approve a join request
|
|
393
515
|
- `!rejectjoin <number>` - Reject a join request
|
|
@@ -412,6 +534,11 @@ The library includes example bot commands that you can use:
|
|
|
412
534
|
- `!list` - Display a scrollable list
|
|
413
535
|
- `!logout` - Logout from current session
|
|
414
536
|
|
|
537
|
+
### 💾 Message Store
|
|
538
|
+
- `!messages` - Get stored messages for current chat
|
|
539
|
+
- `!message <id>` - Get a specific message by ID
|
|
540
|
+
- `!stats` - View store capacity statistics
|
|
541
|
+
|
|
415
542
|
### 🛡️ Protection
|
|
416
543
|
- `Anti-Delete` - Automatically tracks and emits events for deleted messages
|
|
417
544
|
|
|
@@ -444,6 +571,24 @@ client.on('disconnected', (error) => {
|
|
|
444
571
|
})
|
|
445
572
|
```
|
|
446
573
|
|
|
574
|
+
### Contact Events
|
|
575
|
+
```javascript
|
|
576
|
+
// When contacts are received from history sync
|
|
577
|
+
client.on('contacts-received', (contacts) => {
|
|
578
|
+
console.log(`Received ${contacts.length} contacts`);
|
|
579
|
+
})
|
|
580
|
+
|
|
581
|
+
// When new contacts are added/updated
|
|
582
|
+
client.on('contacts-upsert', (contacts) => {
|
|
583
|
+
console.log(`New Contacts: ${contacts.length} contacts added/updated`);
|
|
584
|
+
})
|
|
585
|
+
|
|
586
|
+
// When existing contacts are updated (profile picture changes, etc.)
|
|
587
|
+
client.on('contacts-update', (updates) => {
|
|
588
|
+
console.log(`Contact Updates: ${updates.length} contacts modified`);
|
|
589
|
+
})
|
|
590
|
+
```
|
|
591
|
+
|
|
447
592
|
### Message Events
|
|
448
593
|
```javascript
|
|
449
594
|
// When a new message is received
|
|
@@ -457,7 +602,14 @@ client.on('message', async msg => {
|
|
|
457
602
|
// Handle different message types
|
|
458
603
|
if (msg.hasMedia) {
|
|
459
604
|
console.log('Message contains media')
|
|
460
|
-
//
|
|
605
|
+
// Download media (image/video/audio/document)
|
|
606
|
+
const media = await client.downloadMedia(msg)
|
|
607
|
+
if (media) {
|
|
608
|
+
const fs = require('fs')
|
|
609
|
+
const fileName = `./download-${Date.now()}.${media.extension}`
|
|
610
|
+
fs.writeFileSync(fileName, media.buffer)
|
|
611
|
+
console.log('Saved media to:', fileName)
|
|
612
|
+
}
|
|
461
613
|
}
|
|
462
614
|
})
|
|
463
615
|
```
|
|
@@ -832,6 +984,8 @@ For more detailed information about the LID system implementation, see:
|
|
|
832
984
|
- [LID_STORE_GUIDE.md](./LID_STORE_GUIDE.md) - Complete implementation guide
|
|
833
985
|
- [Baileys Migration Guide](https://baileys.wiki/docs/migration/to-v7.0.0/) - Official migration documentation
|
|
834
986
|
- [example.js](./example.js) - Working examples with LID handling
|
|
987
|
+
- [Read Baileys Documentation](https://innovatorssoftpk.com/)
|
|
988
|
+
- [Deep Knowlege](https://deepwiki.com/innovatorssoft/Baileys)
|
|
835
989
|
|
|
836
990
|
## Contributing
|
|
837
991
|
|
|
@@ -844,3 +998,11 @@ This project is licensed under the MIT License - see the LICENSE file for detail
|
|
|
844
998
|
## Credits
|
|
845
999
|
|
|
846
1000
|
Developed by [Innovators Soft](https://facebook.com/innovatorssoft). Based on the [@itsukichan/baileys](https://github.com/itsukichann/baileys) library.
|
|
1001
|
+
|
|
1002
|
+
# Special Thanks
|
|
1003
|
+
- [@whiskeysockets/baileys](https://github.com/whiskeysockets/Baileys)
|
|
1004
|
+
- [@itsukichan](https://github.com/itsukichann)
|
|
1005
|
+
- [All Contributors](https://github.com/innovatorssoft/Baileys/)
|
|
1006
|
+
- [@ZenboBot](https://discordbot.innovatorssoftpk.com/) - AI Powered Baileys Bot
|
|
1007
|
+
# Sponsor Me
|
|
1008
|
+
Buy me a coffee - [Innovators Soft](https://facebook.com/innovatorssoft)
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
## Message Store Persistence Commands
|
|
2
|
+
|
|
3
|
+
The following commands have been added to demonstrate the message store persistence functionality:
|
|
4
|
+
|
|
5
|
+
### !savestore
|
|
6
|
+
Manually saves the current message store to a JSON file.
|
|
7
|
+
- Creates/updates the file at the configured path (default: `{sessionName}/message-store.json`)
|
|
8
|
+
- Returns statistics about the save operation
|
|
9
|
+
|
|
10
|
+
**Usage:**
|
|
11
|
+
```
|
|
12
|
+
!savestore
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
**Example Response:**
|
|
16
|
+
```
|
|
17
|
+
✅ Store Saved Successfully
|
|
18
|
+
|
|
19
|
+
• Messages: 2547
|
|
20
|
+
• Path: auth_info_baileys/message-store.json
|
|
21
|
+
• Saved at: 2/17/2026, 11:15:30 AM
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### !loadstore
|
|
25
|
+
Manually loads the message store from the saved JSON file.
|
|
26
|
+
- Clears current in-memory store
|
|
27
|
+
- Loads messages from the file
|
|
28
|
+
- Returns statistics about the load operation
|
|
29
|
+
|
|
30
|
+
**Usage:**
|
|
31
|
+
```
|
|
32
|
+
!loadstore
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**Example Response:**
|
|
36
|
+
```
|
|
37
|
+
✅ Store Loaded Successfully
|
|
38
|
+
|
|
39
|
+
• Messages: 2547
|
|
40
|
+
• Loaded from: 2026-02-17T06:10:25.123Z
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Automatic Persistence
|
|
44
|
+
|
|
45
|
+
The message store automatically:
|
|
46
|
+
- **Loads** when the client connects
|
|
47
|
+
- **Saves** when the client disconnects
|
|
48
|
+
- **Auto-saves** every 5 minutes (configurable) if there are changes
|
|
49
|
+
|
|
50
|
+
## Configuration
|
|
51
|
+
|
|
52
|
+
Configure persistence in the client initialization:
|
|
53
|
+
|
|
54
|
+
```javascript
|
|
55
|
+
const client = new WhatsAppClient({
|
|
56
|
+
sessionName: 'my-session',
|
|
57
|
+
messageStoreFilePath: './data/my-session/message-store.json', // Optional
|
|
58
|
+
autoSaveInterval: 5 * 60 * 1000, // 5 minutes (default)
|
|
59
|
+
maxMessagesPerChat: 1000,
|
|
60
|
+
messageTTL: 24 * 60 * 60 * 1000
|
|
61
|
+
});
|
|
62
|
+
```
|
package/example.js
CHANGED
|
@@ -43,7 +43,12 @@ async function start() {
|
|
|
43
43
|
const client = new WhatsAppClient({
|
|
44
44
|
sessionName: sessionDir,
|
|
45
45
|
authmethod: authMethod,
|
|
46
|
-
pairingPhoneNumber: pairingPhoneNumber
|
|
46
|
+
pairingPhoneNumber: pairingPhoneNumber,
|
|
47
|
+
// Message store persistence configuration
|
|
48
|
+
messageStoreFilePath: path.join(sessionDir, 'message-store.json'),
|
|
49
|
+
autoSaveInterval: 5 * 60 * 1000, // Auto-save every 5 minutes
|
|
50
|
+
maxMessagesPerChat: 1000, // Keep last 1000 messages per chat
|
|
51
|
+
messageTTL: 24 * 60 * 60 * 1000 // Messages expire after 24 hours
|
|
47
52
|
});
|
|
48
53
|
|
|
49
54
|
console.log(`\n🚀 Initializing with ${authMethod} method...`);
|
|
@@ -76,12 +81,36 @@ async function start() {
|
|
|
76
81
|
console.log('📦 New LID/PN mappings received')
|
|
77
82
|
})
|
|
78
83
|
|
|
84
|
+
// Handle Contact Events
|
|
85
|
+
client.on('contacts-received', (contacts) => {
|
|
86
|
+
console.log(`\n👥 History Sync: Received ${contacts.length} contacts`);
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
client.on('contacts-upsert', (contacts) => {
|
|
90
|
+
console.log(`\n👥 New Contacts: ${contacts.length} contacts added/updated`);
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
client.on('contacts-update', (updates) => {
|
|
94
|
+
console.log(`\n👥 Contact Updates: ${updates.length} contacts modified`);
|
|
95
|
+
})
|
|
96
|
+
|
|
79
97
|
// Handle Anti-Delete system
|
|
80
98
|
client.on('message-deleted', async (data) => {
|
|
81
99
|
console.log(`\n🛡️ Message from ${data.jid} was deleted!`)
|
|
82
100
|
await client.sendMessage(data.jid, '⚠️ I saw you deleted that message! I have it saved in my memory. 😉', { quoted: data.originalMessage });
|
|
83
101
|
})
|
|
102
|
+
// Example of listening to the new events
|
|
103
|
+
client.on('message-stored', (messages) => {
|
|
104
|
+
//console.log(`${messages.length} messages were just cached in the store.`);
|
|
105
|
+
});
|
|
84
106
|
|
|
107
|
+
client.on('store-loaded', (info) => {
|
|
108
|
+
console.log(`\n💾 Message store loaded: ${info.messageCount} messages restored from file`);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
client.on('store-cleared', () => {
|
|
112
|
+
console.log('Main message store has been purged.');
|
|
113
|
+
});
|
|
85
114
|
// Handle message reactions
|
|
86
115
|
client.on('message-reaction', async (reaction) => {
|
|
87
116
|
console.log('\n👍 Message Reaction Received!')
|
|
@@ -242,29 +271,6 @@ async function start() {
|
|
|
242
271
|
{ title: 'Security', id: 'security', description: 'Security and login options' },
|
|
243
272
|
{ title: 'Payments', id: 'payments', description: 'Manage payment methods' },
|
|
244
273
|
{ title: 'Subscriptions', id: 'subscriptions', description: 'View your subscriptions' },
|
|
245
|
-
{ title: 'Orders', id: 'orders', description: 'View order history' },
|
|
246
|
-
{ title: 'Wishlist', id: 'wishlist', description: 'Your saved items' },
|
|
247
|
-
{ title: 'Addresses', id: 'addresses', description: 'Manage shipping addresses' },
|
|
248
|
-
{ title: 'Help Center', id: 'help', description: 'Get help and support' },
|
|
249
|
-
{ title: 'Contact Us', id: 'contact', description: 'Reach out to our team' },
|
|
250
|
-
{ title: 'FAQs', id: 'faqs', description: 'Frequently asked questions' },
|
|
251
|
-
{ title: 'About Us', id: 'about', description: 'Learn about our company' },
|
|
252
|
-
{ title: 'Careers', id: 'careers', description: 'Join our team' },
|
|
253
|
-
{ title: 'Blog', id: 'blog', description: 'Read our latest articles' },
|
|
254
|
-
{ title: 'Newsletter', id: 'newsletter', description: 'Subscribe to updates' },
|
|
255
|
-
{ title: 'Events', id: 'events', description: 'Upcoming events' },
|
|
256
|
-
{ title: 'Webinars', id: 'webinars', description: 'Join live webinars' },
|
|
257
|
-
{ title: 'Tutorials', id: 'tutorials', description: 'Learn how to use features' },
|
|
258
|
-
{ title: 'Documentation', id: 'docs', description: 'Technical documentation' },
|
|
259
|
-
{ title: 'API', id: 'api', description: 'Developer API' },
|
|
260
|
-
{ title: 'Integrations', id: 'integrations', description: 'Third-party integrations' },
|
|
261
|
-
{ title: 'Download', id: 'download', description: 'Download our app' },
|
|
262
|
-
{ title: 'Pricing', id: 'pricing', description: 'View pricing plans' },
|
|
263
|
-
{ title: 'Upgrade', id: 'upgrade', description: 'Upgrade your plan' },
|
|
264
|
-
{ title: 'Refer a Friend', id: 'refer', description: 'Earn rewards' },
|
|
265
|
-
{ title: 'Feedback', id: 'feedback', description: 'Share your thoughts' },
|
|
266
|
-
{ title: 'Report Issue', id: 'report', description: 'Report a problem' },
|
|
267
|
-
{ title: 'Language', id: 'language', description: 'Change language' }
|
|
268
274
|
]
|
|
269
275
|
},
|
|
270
276
|
{
|
|
@@ -277,29 +283,6 @@ async function start() {
|
|
|
277
283
|
{ title: 'Data Saver', id: 'data_saver', description: 'Reduce data usage' },
|
|
278
284
|
{ title: 'Storage', id: 'storage', description: 'Manage local storage' },
|
|
279
285
|
{ title: 'Cache', id: 'cache', description: 'Clear cached data' },
|
|
280
|
-
{ title: 'Backup', id: 'backup', description: 'Backup your data' },
|
|
281
|
-
{ title: 'Restore', id: 'restore', description: 'Restore from backup' },
|
|
282
|
-
{ title: 'Export Data', id: 'export', description: 'Download your data' },
|
|
283
|
-
{ title: 'Delete Account', id: 'delete', description: 'Permanently remove account' },
|
|
284
|
-
{ title: 'Terms of Service', id: 'tos', description: 'Read terms and conditions' },
|
|
285
|
-
{ title: 'Privacy Policy', id: 'privacy_policy', description: 'How we handle your data' },
|
|
286
|
-
{ title: 'Cookie Policy', id: 'cookies', description: 'About our use of cookies' },
|
|
287
|
-
{ title: 'Accessibility', id: 'accessibility', description: 'Accessibility features' },
|
|
288
|
-
{ title: 'Version', id: 'version', description: 'App version information' },
|
|
289
|
-
{ title: 'Changelog', id: 'changelog', description: 'Recent updates' },
|
|
290
|
-
{ title: 'Roadmap', id: 'roadmap', description: 'Upcoming features' },
|
|
291
|
-
{ title: 'Status', id: 'status', description: 'Service status' },
|
|
292
|
-
{ title: 'Legal', id: 'legal', description: 'Legal information' },
|
|
293
|
-
{ title: 'Partners', id: 'partners', description: 'Our partners' },
|
|
294
|
-
{ title: 'Press', id: 'press', description: 'Press resources' },
|
|
295
|
-
{ title: 'Investors', id: 'investors', description: 'Investor relations' },
|
|
296
|
-
{ title: 'Affiliates', id: 'affiliates', description: 'Become an affiliate' },
|
|
297
|
-
{ title: 'Merchandise', id: 'merch', description: 'Official merchandise' },
|
|
298
|
-
{ title: 'Donate', id: 'donate', description: 'Support our work' },
|
|
299
|
-
{ title: 'Volunteer', id: 'volunteer', description: 'Get involved' },
|
|
300
|
-
{ title: 'Community', id: 'community', description: 'Join our community' },
|
|
301
|
-
{ title: 'Forum', id: 'forum', description: 'Community discussions' },
|
|
302
|
-
{ title: 'Beta Program', id: 'beta', description: 'Try beta features' }
|
|
303
286
|
]
|
|
304
287
|
}
|
|
305
288
|
]
|
|
@@ -334,10 +317,10 @@ async function start() {
|
|
|
334
317
|
|
|
335
318
|
await client.sendButtons(msg.from, {
|
|
336
319
|
imagePath: './example.jpg',
|
|
337
|
-
caption: '', // Keep it short and concise
|
|
338
|
-
title: '', // Max 24 chars
|
|
339
|
-
subtitle: '', // Optional, appears below title
|
|
340
|
-
footer: '',
|
|
320
|
+
caption: 'here is captions of image\nwith linebreaks', // Keep it short and concise
|
|
321
|
+
title: 'Image Title', // Max 24 chars
|
|
322
|
+
subtitle: 'Image Subtitle (but optional)', // Optional, appears below title
|
|
323
|
+
footer: 'Image Footer',
|
|
341
324
|
interactiveButtons: [
|
|
342
325
|
{
|
|
343
326
|
name: 'quick_reply',
|
|
@@ -415,7 +398,7 @@ async function start() {
|
|
|
415
398
|
`• !revokeinvite - Revoke group invite code\n` +
|
|
416
399
|
`• !leavegroup - Leave the group\n` +
|
|
417
400
|
`• !joingroup <code> - Join group by invite code\n` +
|
|
418
|
-
`• !groupinfo
|
|
401
|
+
`• !groupinfo [jid|code] - Full group details with participants\n` +
|
|
419
402
|
`• !joinrequests - List pending join requests\n` +
|
|
420
403
|
`• !approvejoin <number> - Approve join request\n` +
|
|
421
404
|
`• !rejectjoin <number> - Reject join request\n` +
|
|
@@ -439,7 +422,13 @@ async function start() {
|
|
|
439
422
|
`• !buttons - Button template\n` +
|
|
440
423
|
`• !list - Scrollable list\n\n` +
|
|
441
424
|
|
|
442
|
-
|
|
425
|
+
`*� Message Store*\n` +
|
|
426
|
+
`• !messages - Get stored messages for this chat\n` +
|
|
427
|
+
`• !allmessages - Get statistics for all stored chats\n` +
|
|
428
|
+
`• !message - Get a specific message by ID\n` +
|
|
429
|
+
`• !stats - Get store capacity statistics\n\n` +
|
|
430
|
+
|
|
431
|
+
`*�🔐 LID/PN/JID Management*\n` +
|
|
443
432
|
`• !lid - Get your LID\n` +
|
|
444
433
|
`• !pn <lid> - Get PN from LID\n` +
|
|
445
434
|
`• !parse <jid> - Parse JID info\n` +
|
|
@@ -467,6 +456,7 @@ async function start() {
|
|
|
467
456
|
groups.forEach((group, index) => {
|
|
468
457
|
groupList += `${index + 1}. *${group.subject}*\n`
|
|
469
458
|
groupList += ` ID: ${group.id}\n`
|
|
459
|
+
if (group.notify) groupList += ` Notify: ${group.notify}\n`
|
|
470
460
|
groupList += ` Members: ${group.participants.length}\n`
|
|
471
461
|
if (group.desc) groupList += ` Description: ${group.desc}\n`
|
|
472
462
|
groupList += '\n'
|
|
@@ -481,6 +471,45 @@ async function start() {
|
|
|
481
471
|
}
|
|
482
472
|
break
|
|
483
473
|
|
|
474
|
+
case '!groupinfo':
|
|
475
|
+
try {
|
|
476
|
+
// Use provided group JID or current group
|
|
477
|
+
const groupJid = args.trim() || msg.raw.key.remoteJid
|
|
478
|
+
if (!groupJid || !groupJid.endsWith('@g.us')) {
|
|
479
|
+
await client.sendMessage(msg.from, '❌ Please provide a group JID or use this command in a group.\nUsage: !groupinfo <groupJid>')
|
|
480
|
+
break
|
|
481
|
+
}
|
|
482
|
+
const groupInfo = await client.getGroupMetadata(groupJid)
|
|
483
|
+
if (groupInfo) {
|
|
484
|
+
let groupList = `*Group Info:*\n\n` +
|
|
485
|
+
`ID: ${groupInfo.id}\n` +
|
|
486
|
+
`Notify: ${groupInfo.notify || 'N/A'}\n` +
|
|
487
|
+
`Subject: ${groupInfo.subject}\n` +
|
|
488
|
+
`Owner: ${groupInfo.owner || 'N/A'}\n` +
|
|
489
|
+
`Created: ${new Date(groupInfo.creation * 1000).toLocaleString()}\n` +
|
|
490
|
+
`Members: ${groupInfo.participants.length}\n` +
|
|
491
|
+
`Description: ${groupInfo.desc || 'N/A'}\n\n` +
|
|
492
|
+
`*👥 Participants:*\n\n`
|
|
493
|
+
|
|
494
|
+
groupInfo.participants.forEach((p, i) => {
|
|
495
|
+
const role = p.admin === 'superadmin' ? '👑 Super Admin'
|
|
496
|
+
: p.admin === 'admin' ? '🛡️ Admin'
|
|
497
|
+
: '👤 Member'
|
|
498
|
+
groupList += `${i + 1}. ${p.id}\n`
|
|
499
|
+
groupList += ` Role: ${role}\n`
|
|
500
|
+
if (p.notify) groupList += ` Name: ${p.notify}\n`
|
|
501
|
+
groupList += '\n'
|
|
502
|
+
})
|
|
503
|
+
|
|
504
|
+
await client.sendMessage(msg.from, groupList)
|
|
505
|
+
} else {
|
|
506
|
+
await client.sendMessage(msg.from, 'Group not found')
|
|
507
|
+
}
|
|
508
|
+
} catch (error) {
|
|
509
|
+
console.error('Error fetching group info:', error)
|
|
510
|
+
await client.sendMessage(msg.from, 'Failed to fetch group info')
|
|
511
|
+
}
|
|
512
|
+
break
|
|
484
513
|
case '!logout':
|
|
485
514
|
// Ask for confirmation before logging out
|
|
486
515
|
await client.sendButtons(msg.from, {
|
|
@@ -864,22 +893,65 @@ async function start() {
|
|
|
864
893
|
|
|
865
894
|
case '!groupinfo':
|
|
866
895
|
try {
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
896
|
+
const input = args.trim()
|
|
897
|
+
let groupInfoResult
|
|
898
|
+
|
|
899
|
+
if (!input) {
|
|
900
|
+
// No args: use current group
|
|
901
|
+
if (!msg.raw.key.remoteJid.endsWith('@g.us')) {
|
|
902
|
+
await client.sendMessage(msg.from, '❌ Use this command in a group, or provide a group JID / invite code.\nUsage:\n• !groupinfo (in a group)\n• !groupinfo 120363xxxxx@g.us\n• !groupinfo AbCdEfGhIjK')
|
|
903
|
+
break
|
|
904
|
+
}
|
|
905
|
+
groupInfoResult = await client.getGroupMetadata(msg.raw.key.remoteJid)
|
|
906
|
+
} else if (input.includes('@g.us')) {
|
|
907
|
+
// Argument is a group JID
|
|
908
|
+
groupInfoResult = await client.getGroupMetadata(input)
|
|
909
|
+
} else {
|
|
910
|
+
// Argument is an invite code (or full link)
|
|
911
|
+
groupInfoResult = await client.getGroupInfoByInviteCode(input)
|
|
870
912
|
}
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
infoText
|
|
879
|
-
|
|
913
|
+
|
|
914
|
+
if (!groupInfoResult) {
|
|
915
|
+
await client.sendMessage(msg.from, '❌ Group not found.')
|
|
916
|
+
break
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
// Build group info header
|
|
920
|
+
let infoText = `*📋 Group Info*\n\n`
|
|
921
|
+
infoText += `*Name:* ${groupInfoResult.subject || 'N/A'}\n`
|
|
922
|
+
infoText += `*ID:* ${groupInfoResult.id || 'N/A'}\n`
|
|
923
|
+
if (groupInfoResult.notify) infoText += `*Notify:* ${groupInfoResult.notify}\n`
|
|
924
|
+
infoText += `*Owner:* ${groupInfoResult.owner || 'N/A'}\n`
|
|
925
|
+
infoText += `*Created:* ${groupInfoResult.creation ? new Date(groupInfoResult.creation * 1000).toLocaleString() : 'N/A'}\n`
|
|
926
|
+
infoText += `*Size:* ${groupInfoResult.size || groupInfoResult.participants?.length || 'N/A'}\n`
|
|
927
|
+
infoText += `*Description:* ${groupInfoResult.desc || 'No description'}\n`
|
|
928
|
+
if (groupInfoResult.announce !== undefined) infoText += `*Announce:* ${groupInfoResult.announce ? 'Yes (admins only)' : 'No'}\n`
|
|
929
|
+
if (groupInfoResult.restrict !== undefined) infoText += `*Restricted:* ${groupInfoResult.restrict ? 'Yes (admins only edit info)' : 'No'}\n`
|
|
930
|
+
if (groupInfoResult.ephemeralDuration) infoText += `*Disappearing:* ${groupInfoResult.ephemeralDuration}s\n`
|
|
931
|
+
if (groupInfoResult.memberAddMode !== undefined) infoText += `*Member Add:* ${groupInfoResult.memberAddMode ? 'All members' : 'Admins only'}\n`
|
|
932
|
+
if (groupInfoResult.isCommunity) infoText += `*Community:* Yes\n`
|
|
933
|
+
if (groupInfoResult.linkedParent) infoText += `*Linked Parent:* ${groupInfoResult.linkedParent}\n`
|
|
934
|
+
|
|
935
|
+
// Build participants list if available
|
|
936
|
+
if (groupInfoResult.participants && groupInfoResult.participants.length > 0) {
|
|
937
|
+
infoText += `\n*👥 Participants (${groupInfoResult.participants.length}):*\n\n`
|
|
938
|
+
groupInfoResult.participants.forEach((p, i) => {
|
|
939
|
+
const role = p.admin === 'superadmin' ? '👑 Super Admin'
|
|
940
|
+
: p.admin === 'admin' ? '🛡️ Admin'
|
|
941
|
+
: '👤 Member'
|
|
942
|
+
infoText += `${i + 1}. ${p.id}\n`
|
|
943
|
+
infoText += ` Role: ${role}\n`
|
|
944
|
+
if (p.notify) infoText += ` Name: ${p.notify}\n`
|
|
945
|
+
if (p.lid) infoText += ` LID: ${p.lid}\n`
|
|
946
|
+
if (p.phoneNumber) infoText += ` Phone: ${p.phoneNumber}\n`
|
|
947
|
+
infoText += '\n'
|
|
948
|
+
})
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
await client.sendMessage(msg.from, infoText)
|
|
880
952
|
} catch (error) {
|
|
881
|
-
console.error('Error getting group info:', error)
|
|
882
|
-
await client.sendMessage(msg.from, `❌ Failed to get group info: ${error.message}`)
|
|
953
|
+
console.error('Error getting group info:', error)
|
|
954
|
+
await client.sendMessage(msg.from, `❌ Failed to get group info: ${error.message}`)
|
|
883
955
|
}
|
|
884
956
|
break;
|
|
885
957
|
|
|
@@ -1188,6 +1260,72 @@ async function start() {
|
|
|
1188
1260
|
await client.sendMessage(msg.from, `❌ Failed to update: ${error.message}`);
|
|
1189
1261
|
}
|
|
1190
1262
|
break;
|
|
1263
|
+
|
|
1264
|
+
case '!messages':
|
|
1265
|
+
const history = client.getStoredMessages(msg.from);
|
|
1266
|
+
let historyText = `*💾 Stored Messages for this chat (${history.length}):*\n\n`;
|
|
1267
|
+
history.slice(-10).forEach((m, i) => {
|
|
1268
|
+
const content = m.message.conversation || m.message.extendedTextMessage?.text || "[Media/Other]";
|
|
1269
|
+
historyText += `${i + 1}. ID: ${m.key.id}\n Text: ${content.substring(0, 50)}${content.length > 50 ? '...' : ''}\n\n`;
|
|
1270
|
+
});
|
|
1271
|
+
await client.sendMessage(msg.from, historyText);
|
|
1272
|
+
break;
|
|
1273
|
+
|
|
1274
|
+
case '!message':
|
|
1275
|
+
if (!args) {
|
|
1276
|
+
await client.sendMessage(msg.from, "❌ Please provide a message ID.");
|
|
1277
|
+
break;
|
|
1278
|
+
}
|
|
1279
|
+
const storedMsg = client.getStoredMessage({ remoteJid: msg.from, id: args.trim(), fromMe: false });
|
|
1280
|
+
if (storedMsg) {
|
|
1281
|
+
await client.sendMessage(msg.from, `✅ Found message!\n\nContent: ${JSON.stringify(storedMsg.message, null, 2).substring(0, 1000)}`);
|
|
1282
|
+
} else {
|
|
1283
|
+
await client.sendMessage(msg.from, "❌ Message not found in store.");
|
|
1284
|
+
}
|
|
1285
|
+
break;
|
|
1286
|
+
|
|
1287
|
+
case '!stats':
|
|
1288
|
+
const stats = client.getStoreStats();
|
|
1289
|
+
await client.sendMessage(msg.from, `*📊 Message Store Statistics*\n\n• Total Chats: ${stats.totalChats}\n• Total Messages: ${stats.totalMessages}\n• Total Deleted: ${stats.totalDeleted}`);
|
|
1290
|
+
break;
|
|
1291
|
+
|
|
1292
|
+
case '!allmessages':
|
|
1293
|
+
const allMsgs = client.getAllStoredMessages();
|
|
1294
|
+
const activeChats = client.getStoredChatIds();
|
|
1295
|
+
await client.sendMessage(msg.from, `*🌐 Global Message Store*\n\n• Total Messages Held: ${allMsgs.length}\n• Total Active Chats: ${activeChats.length}\n\n*Active JIDs:* \n${activeChats.join('\n')}`);
|
|
1296
|
+
break;
|
|
1297
|
+
|
|
1298
|
+
case '!savestore':
|
|
1299
|
+
await client.sendMessage(msg.from, '💾 Saving message store to file...');
|
|
1300
|
+
const saveResult = await client.saveMessageStore();
|
|
1301
|
+
if (saveResult.success) {
|
|
1302
|
+
await client.sendMessage(msg.from,
|
|
1303
|
+
`✅ *Store Saved Successfully*\n\n` +
|
|
1304
|
+
`• Messages: ${saveResult.messageCount}\n` +
|
|
1305
|
+
`• Path: ${saveResult.path}\n` +
|
|
1306
|
+
`• Saved at: ${saveResult.savedAt.toLocaleString()}`
|
|
1307
|
+
);
|
|
1308
|
+
} else {
|
|
1309
|
+
await client.sendMessage(msg.from, `❌ Failed to save store: ${saveResult.error}`);
|
|
1310
|
+
}
|
|
1311
|
+
break;
|
|
1312
|
+
|
|
1313
|
+
case '!loadstore':
|
|
1314
|
+
await client.sendMessage(msg.from, '📂 Loading message store from file...');
|
|
1315
|
+
const loadResult = await client.loadMessageStore();
|
|
1316
|
+
if (loadResult.success) {
|
|
1317
|
+
await client.sendMessage(msg.from,
|
|
1318
|
+
`✅ *Store Loaded Successfully*\n\n` +
|
|
1319
|
+
`• Messages: ${loadResult.messageCount}\n` +
|
|
1320
|
+
`• Loaded from: ${loadResult.loadedFrom}`
|
|
1321
|
+
);
|
|
1322
|
+
} else {
|
|
1323
|
+
await client.sendMessage(msg.from,
|
|
1324
|
+
`⚠️ Could not load store\n` +
|
|
1325
|
+
`Reason: ${loadResult.reason || loadResult.error}`
|
|
1326
|
+
);
|
|
1327
|
+
}
|
|
1328
|
+
break;
|
|
1191
1329
|
}
|
|
1192
1330
|
})
|
|
1193
1331
|
|
package/index.js
CHANGED
|
@@ -38,6 +38,7 @@ class Group {
|
|
|
38
38
|
constructor(client, groupData) {
|
|
39
39
|
this.client = client
|
|
40
40
|
this.id = groupData.id
|
|
41
|
+
this.notify = groupData.notify
|
|
41
42
|
this.subject = groupData.subject
|
|
42
43
|
this.creation = groupData.creation
|
|
43
44
|
this.owner = groupData.owner
|
|
@@ -61,6 +62,16 @@ class WhatsAppClient extends EventEmitter {
|
|
|
61
62
|
maxMessagesPerChat: config.maxMessagesPerChat || 1000,
|
|
62
63
|
ttl: config.messageTTL || 24 * 60 * 60 * 1000
|
|
63
64
|
});
|
|
65
|
+
// Initialize contacts cache
|
|
66
|
+
this.contactsCache = new NodeCache({ stdTTL: 0, checkperiod: 20 }); // No TTL, manual cleanup on logout
|
|
67
|
+
|
|
68
|
+
// Message store persistence configuration
|
|
69
|
+
this.messageStoreFilePath = config.messageStoreFilePath || path.join(this.sessionName, 'message-store.json');
|
|
70
|
+
this.autoSaveInterval = config.autoSaveInterval || 5 * 60 * 1000; // Default: 5 minutes
|
|
71
|
+
this._autoSaveTimer = null;
|
|
72
|
+
this._storeChangeCount = 0;
|
|
73
|
+
this._pairingCodeTimer = null;
|
|
74
|
+
this._lastStoreSave = null;
|
|
64
75
|
}
|
|
65
76
|
|
|
66
77
|
/**
|
|
@@ -115,7 +126,7 @@ class WhatsAppClient extends EventEmitter {
|
|
|
115
126
|
}
|
|
116
127
|
|
|
117
128
|
const browserConfig = this.authmethod === 'pairing'
|
|
118
|
-
? Browsers.
|
|
129
|
+
? Browsers.iOS('chrome')
|
|
119
130
|
: ["Innovators Soft", "chrome", "1000.26100.275.0"];
|
|
120
131
|
|
|
121
132
|
const { version: baileysVersion, isLatest: baileysIsLatest } = await fetchLatestBaileysVersion();
|
|
@@ -132,6 +143,7 @@ class WhatsAppClient extends EventEmitter {
|
|
|
132
143
|
logger,
|
|
133
144
|
markOnlineOnConnect: false,
|
|
134
145
|
syncFullHistory: true,
|
|
146
|
+
getMessage: async (key) => (this.messageStore.getOriginalMessage(key))?.message,
|
|
135
147
|
generateHighQualityLinkPreview: true,
|
|
136
148
|
linkPreviewImageThumbnailWidth: 192,
|
|
137
149
|
emitOwnEvents: true,
|
|
@@ -150,15 +162,16 @@ class WhatsAppClient extends EventEmitter {
|
|
|
150
162
|
console.error(`Error fetching metadata for group ${jid}:`, error);
|
|
151
163
|
return null;
|
|
152
164
|
}
|
|
153
|
-
}
|
|
165
|
+
},
|
|
154
166
|
});
|
|
155
167
|
|
|
156
168
|
this.store = this.sock.signalRepository.lidMapping;
|
|
157
169
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
170
|
+
this.sock.ev.on('connection.update', async ({ connection, lastDisconnect, qr }) => {
|
|
171
|
+
if (connection === 'close' && this._pairingCodeTimer) {
|
|
172
|
+
clearTimeout(this._pairingCodeTimer);
|
|
173
|
+
this._pairingCodeTimer = null;
|
|
174
|
+
}
|
|
162
175
|
|
|
163
176
|
if (qr && this.authmethod === 'qr') {
|
|
164
177
|
this.emit('qr', qr);
|
|
@@ -167,15 +180,21 @@ class WhatsAppClient extends EventEmitter {
|
|
|
167
180
|
if (this._connectionState !== 'connected') {
|
|
168
181
|
const user = getCurrentSenderInfo(this.sock.authState)
|
|
169
182
|
if (user) {
|
|
183
|
+
this.isConnected = true;
|
|
170
184
|
const userInfo = {
|
|
171
185
|
name: user.pushName || 'Unknown',
|
|
172
186
|
phone: user.phoneNumber,
|
|
173
187
|
platform: user.platform || 'Unknown',
|
|
174
|
-
isOnline: true
|
|
188
|
+
isOnline: true,
|
|
175
189
|
};
|
|
176
|
-
this.isConnected = true;
|
|
177
190
|
this._connectionState = 'connected';
|
|
178
191
|
this.emit('connected', userInfo);
|
|
192
|
+
|
|
193
|
+
// Load message store from file
|
|
194
|
+
await this.loadMessageStore();
|
|
195
|
+
|
|
196
|
+
// Start auto-save
|
|
197
|
+
this._startAutoSave();
|
|
179
198
|
}
|
|
180
199
|
}
|
|
181
200
|
}
|
|
@@ -186,6 +205,13 @@ class WhatsAppClient extends EventEmitter {
|
|
|
186
205
|
if (this._connectionState !== 'disconnected') {
|
|
187
206
|
this.isConnected = false;
|
|
188
207
|
this._connectionState = 'disconnected';
|
|
208
|
+
|
|
209
|
+
// Save message store before disconnecting
|
|
210
|
+
await this.saveMessageStore();
|
|
211
|
+
|
|
212
|
+
// Stop auto-save
|
|
213
|
+
this._stopAutoSave();
|
|
214
|
+
|
|
189
215
|
this.emit('disconnected', lastDisconnect?.error);
|
|
190
216
|
}
|
|
191
217
|
|
|
@@ -203,9 +229,20 @@ class WhatsAppClient extends EventEmitter {
|
|
|
203
229
|
if (phoneNumber) {
|
|
204
230
|
try {
|
|
205
231
|
// Wait a bit for the connection to initialize properly
|
|
206
|
-
|
|
232
|
+
if (this._pairingCodeTimer) {
|
|
233
|
+
clearTimeout(this._pairingCodeTimer);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
this._pairingCodeTimer = setTimeout(async () => {
|
|
207
237
|
const customeCode = "INOVATOR";
|
|
208
238
|
try {
|
|
239
|
+
if (!this.sock || this._connectionState === 'disconnected') {
|
|
240
|
+
const err = new Error('Socket is not available to request pairing code');
|
|
241
|
+
console.error('Error requesting pairing code:', err);
|
|
242
|
+
this.emit('error', err);
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
|
|
209
246
|
const code = await this.sock.requestPairingCode(phoneNumber, customeCode);
|
|
210
247
|
if (code) {
|
|
211
248
|
// Emit pairing code event so clients can handle it
|
|
@@ -216,6 +253,8 @@ class WhatsAppClient extends EventEmitter {
|
|
|
216
253
|
} catch (error) {
|
|
217
254
|
console.error('Error requesting pairing code:', error);
|
|
218
255
|
this.emit('error', error);
|
|
256
|
+
} finally {
|
|
257
|
+
this._pairingCodeTimer = null;
|
|
219
258
|
}
|
|
220
259
|
}, 2000); // Wait 2 seconds before requesting pairing code
|
|
221
260
|
} catch (error) {
|
|
@@ -234,7 +273,17 @@ class WhatsAppClient extends EventEmitter {
|
|
|
234
273
|
|
|
235
274
|
this.sock.ev.on('messages.upsert', async (update) => {
|
|
236
275
|
// 📝 Store message for the Anti-Delete system
|
|
237
|
-
createMessageStoreHandler(this.messageStore)
|
|
276
|
+
const storeHandler = createMessageStoreHandler(this.messageStore);
|
|
277
|
+
storeHandler(update);
|
|
278
|
+
|
|
279
|
+
// 📢 Emit event that messages were stored
|
|
280
|
+
this.emit('message-stored', update.messages);
|
|
281
|
+
|
|
282
|
+
// Increment change counter for auto-save
|
|
283
|
+
this._incrementStoreChangeCount();
|
|
284
|
+
|
|
285
|
+
// Save message store to file immediately
|
|
286
|
+
await this.saveMessageStore();
|
|
238
287
|
|
|
239
288
|
try {
|
|
240
289
|
if (update.type !== 'notify' || !update.messages?.length) return;
|
|
@@ -387,6 +436,8 @@ class WhatsAppClient extends EventEmitter {
|
|
|
387
436
|
|
|
388
437
|
// 👍 Handle message reactions
|
|
389
438
|
this.sock.ev.on('messages.reaction', async (reactions) => {
|
|
439
|
+
|
|
440
|
+
|
|
390
441
|
try {
|
|
391
442
|
for (const reaction of reactions) {
|
|
392
443
|
// Get the chat JID, preferring PN over LID
|
|
@@ -509,6 +560,34 @@ class WhatsAppClient extends EventEmitter {
|
|
|
509
560
|
}
|
|
510
561
|
});
|
|
511
562
|
|
|
563
|
+
// Handle contacts from history sync
|
|
564
|
+
this.sock.ev.on('messaging-history.set', ({ contacts: newContacts }) => {
|
|
565
|
+
if (newContacts && newContacts.length > 0) {
|
|
566
|
+
for (const contact of newContacts) {
|
|
567
|
+
this.contactsCache.set(contact.id, contact);
|
|
568
|
+
}
|
|
569
|
+
this.emit('contacts-received', newContacts);
|
|
570
|
+
|
|
571
|
+
}
|
|
572
|
+
});
|
|
573
|
+
|
|
574
|
+
// Handle contacts upsert (new contacts added)
|
|
575
|
+
this.sock.ev.on('contacts.upsert', (newContacts) => {
|
|
576
|
+
for (const contact of newContacts) {
|
|
577
|
+
this.contactsCache.set(contact.id, contact);
|
|
578
|
+
}
|
|
579
|
+
this.emit('contacts-upsert', newContacts);
|
|
580
|
+
});
|
|
581
|
+
|
|
582
|
+
// Handle contacts update (profile picture changes, etc.)
|
|
583
|
+
this.sock.ev.on('contacts.update', (updates) => {
|
|
584
|
+
for (const update of updates) {
|
|
585
|
+
const existing = this.contactsCache.get(update.id) || {};
|
|
586
|
+
this.contactsCache.set(update.id, { ...existing, ...update });
|
|
587
|
+
}
|
|
588
|
+
this.emit('contacts-update', updates);
|
|
589
|
+
});
|
|
590
|
+
|
|
512
591
|
} catch (error) {
|
|
513
592
|
console.error('Error in connect:', error);
|
|
514
593
|
this.emit('error', error);
|
|
@@ -654,6 +733,10 @@ class WhatsAppClient extends EventEmitter {
|
|
|
654
733
|
throw new Error('Unsupported file type: ' + fileExtension);
|
|
655
734
|
}
|
|
656
735
|
|
|
736
|
+
if (options.mentions) {
|
|
737
|
+
mediaMessage.mentions = options.mentions;
|
|
738
|
+
}
|
|
739
|
+
|
|
657
740
|
return await this.sock.sendMessage(chatId, mediaMessage, { ai: true });
|
|
658
741
|
} catch (error) {
|
|
659
742
|
console.error('Error sending media:', error);
|
|
@@ -684,11 +767,20 @@ class WhatsAppClient extends EventEmitter {
|
|
|
684
767
|
const fileName = path.basename(filePath);
|
|
685
768
|
const mimeType = mime.getType(filePath);
|
|
686
769
|
|
|
687
|
-
|
|
770
|
+
const messageContent = {
|
|
688
771
|
document: fileBuffer,
|
|
689
772
|
caption: caption,
|
|
690
773
|
mimetype: mimeType,
|
|
691
774
|
fileName: fileName,
|
|
775
|
+
};
|
|
776
|
+
|
|
777
|
+
if (typeof caption === 'object' && caption !== null) {
|
|
778
|
+
if (caption.caption) messageContent.caption = caption.caption;
|
|
779
|
+
if (caption.mentions) messageContent.mentions = caption.mentions;
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
return await this.sock.sendMessage(chatId, {
|
|
783
|
+
...messageContent,
|
|
692
784
|
}, { ai: true });
|
|
693
785
|
} catch (error) {
|
|
694
786
|
console.error('Error sending document:', error);
|
|
@@ -719,8 +811,16 @@ class WhatsAppClient extends EventEmitter {
|
|
|
719
811
|
const {
|
|
720
812
|
text,
|
|
721
813
|
imagePath,
|
|
814
|
+
image,
|
|
815
|
+
video,
|
|
816
|
+
document,
|
|
817
|
+
location,
|
|
818
|
+
product,
|
|
819
|
+
mimetype,
|
|
820
|
+
jpegThumbnail,
|
|
722
821
|
caption,
|
|
723
822
|
title,
|
|
823
|
+
subtitle,
|
|
724
824
|
footer,
|
|
725
825
|
interactiveButtons = [],
|
|
726
826
|
hasMediaAttachment = false,
|
|
@@ -729,24 +829,40 @@ class WhatsAppClient extends EventEmitter {
|
|
|
729
829
|
let messageContent = {};
|
|
730
830
|
|
|
731
831
|
try {
|
|
832
|
+
const base = {
|
|
833
|
+
title: title,
|
|
834
|
+
subtitle: subtitle,
|
|
835
|
+
footer: footer,
|
|
836
|
+
interactiveButtons: interactiveButtons,
|
|
837
|
+
hasMediaAttachment: hasMediaAttachment,
|
|
838
|
+
};
|
|
839
|
+
|
|
732
840
|
if (imagePath) {
|
|
733
|
-
// Handle message with image
|
|
841
|
+
// Handle message with local image path
|
|
734
842
|
const imageBuffer = fs.readFileSync(imagePath);
|
|
735
843
|
messageContent = {
|
|
844
|
+
...base,
|
|
736
845
|
image: imageBuffer,
|
|
737
846
|
caption: caption,
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
847
|
+
};
|
|
848
|
+
} else if (image || video || document || location || product) {
|
|
849
|
+
// Pass-through media objects (e.g. { image: { url } })
|
|
850
|
+
messageContent = {
|
|
851
|
+
...base,
|
|
852
|
+
...(image ? { image } : {}),
|
|
853
|
+
...(video ? { video } : {}),
|
|
854
|
+
...(document ? { document } : {}),
|
|
855
|
+
...(location ? { location } : {}),
|
|
856
|
+
...(product ? { product } : {}),
|
|
857
|
+
...(mimetype ? { mimetype } : {}),
|
|
858
|
+
...(jpegThumbnail ? { jpegThumbnail } : {}),
|
|
859
|
+
caption: caption,
|
|
742
860
|
};
|
|
743
861
|
} else {
|
|
744
862
|
// Handle text-only message
|
|
745
863
|
messageContent = {
|
|
864
|
+
...base,
|
|
746
865
|
text: text,
|
|
747
|
-
title: title,
|
|
748
|
-
footer: footer,
|
|
749
|
-
interactiveButtons: interactiveButtons,
|
|
750
866
|
};
|
|
751
867
|
}
|
|
752
868
|
|
|
@@ -1183,6 +1299,12 @@ class WhatsAppClient extends EventEmitter {
|
|
|
1183
1299
|
this.sock = null;
|
|
1184
1300
|
}
|
|
1185
1301
|
|
|
1302
|
+
// Clear store interval
|
|
1303
|
+
if (this._storeInterval) {
|
|
1304
|
+
clearInterval(this._storeInterval);
|
|
1305
|
+
this._storeInterval = null;
|
|
1306
|
+
}
|
|
1307
|
+
|
|
1186
1308
|
// Add a small delay before reconnecting
|
|
1187
1309
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
1188
1310
|
|
|
@@ -1332,6 +1454,7 @@ class WhatsAppClient extends EventEmitter {
|
|
|
1332
1454
|
|
|
1333
1455
|
// Update connection state and emit event
|
|
1334
1456
|
this.isConnected = false;
|
|
1457
|
+
|
|
1335
1458
|
this.emit('logout', 'Logged out successfully');
|
|
1336
1459
|
|
|
1337
1460
|
return true;
|
|
@@ -1343,11 +1466,11 @@ class WhatsAppClient extends EventEmitter {
|
|
|
1343
1466
|
}
|
|
1344
1467
|
|
|
1345
1468
|
/**
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1469
|
+
* Download media from a message
|
|
1470
|
+
* @param {object} message - The message object containing media (must have raw property)
|
|
1471
|
+
* @returns {Promise<object|null>} Object with buffer, mimetype, and extension, or null if no media
|
|
1472
|
+
* @throws {Error} If client is not connected or download fails
|
|
1473
|
+
*/
|
|
1351
1474
|
async downloadMedia(message) {
|
|
1352
1475
|
if (!this.isConnected) {
|
|
1353
1476
|
throw new Error('Client is not connected');
|
|
@@ -1461,6 +1584,254 @@ class WhatsAppClient extends EventEmitter {
|
|
|
1461
1584
|
}
|
|
1462
1585
|
}
|
|
1463
1586
|
|
|
1587
|
+
/**
|
|
1588
|
+
* Get all stored messages for a specific chat
|
|
1589
|
+
* @param {string} chatId - The JID of the chat
|
|
1590
|
+
* @returns {Array} Array of stored messages (WebMessageInfo)
|
|
1591
|
+
*/
|
|
1592
|
+
getStoredMessages(chatId) {
|
|
1593
|
+
return this.messageStore.getChatMessages(chatId);
|
|
1594
|
+
}
|
|
1595
|
+
|
|
1596
|
+
/**
|
|
1597
|
+
* Get a specific stored message by its key
|
|
1598
|
+
* @param {object} key - The message key { remoteJid, id, fromMe }
|
|
1599
|
+
* @returns {object|undefined} The stored message (WebMessageInfo)
|
|
1600
|
+
*/
|
|
1601
|
+
getStoredMessage(key) {
|
|
1602
|
+
return this.messageStore.getOriginalMessage(key);
|
|
1603
|
+
}
|
|
1604
|
+
|
|
1605
|
+
/**
|
|
1606
|
+
* Get statistics about the message store
|
|
1607
|
+
* @returns {object} Store statistics
|
|
1608
|
+
*/
|
|
1609
|
+
getStoreStats() {
|
|
1610
|
+
return this.messageStore.getStats();
|
|
1611
|
+
}
|
|
1612
|
+
|
|
1613
|
+
/**
|
|
1614
|
+
* Get all stored messages from all chats
|
|
1615
|
+
* @returns {Array} Array of all stored messages
|
|
1616
|
+
*/
|
|
1617
|
+
getAllStoredMessages() {
|
|
1618
|
+
return this.messageStore.getChatIds().flatMap(chatId => this.messageStore.getChatMessages(chatId));
|
|
1619
|
+
}
|
|
1620
|
+
|
|
1621
|
+
/**
|
|
1622
|
+
* Get IDs of all chats that have stored messages
|
|
1623
|
+
* @returns {Array<string>} Array of chat JIDs
|
|
1624
|
+
*/
|
|
1625
|
+
getStoredChatIds() {
|
|
1626
|
+
return this.messageStore.getChatIds();
|
|
1627
|
+
}
|
|
1628
|
+
|
|
1629
|
+
/**
|
|
1630
|
+
* Clear the entire message store
|
|
1631
|
+
*/
|
|
1632
|
+
clearMessageStore() {
|
|
1633
|
+
this.messageStore.clear();
|
|
1634
|
+
this.emit('store-cleared');
|
|
1635
|
+
}
|
|
1636
|
+
|
|
1637
|
+
/**
|
|
1638
|
+
* Clear stored messages for a specific chat
|
|
1639
|
+
* @param {string} chatId - The JID of the chat to clear
|
|
1640
|
+
*/
|
|
1641
|
+
clearChatStore(chatId) {
|
|
1642
|
+
this.messageStore.clearChat(chatId);
|
|
1643
|
+
this.emit('chat-store-cleared', chatId);
|
|
1644
|
+
}
|
|
1645
|
+
|
|
1646
|
+
/**
|
|
1647
|
+
* Save the message store to a JSON file
|
|
1648
|
+
* @returns {Promise<{success: boolean, path: string, messageCount: number}>}
|
|
1649
|
+
*/
|
|
1650
|
+
async saveMessageStore() {
|
|
1651
|
+
try {
|
|
1652
|
+
const rawAllMessages = this.messageStore.getAllMessages();
|
|
1653
|
+
const stats = this.messageStore.getStats();
|
|
1654
|
+
|
|
1655
|
+
let allMessages = [];
|
|
1656
|
+
if (Array.isArray(rawAllMessages)) {
|
|
1657
|
+
allMessages = rawAllMessages;
|
|
1658
|
+
} else if (rawAllMessages && typeof rawAllMessages[Symbol.iterator] === 'function') {
|
|
1659
|
+
allMessages = Array.from(rawAllMessages);
|
|
1660
|
+
} else if (rawAllMessages && typeof rawAllMessages === 'object') {
|
|
1661
|
+
allMessages = Object.values(rawAllMessages);
|
|
1662
|
+
} else {
|
|
1663
|
+
try {
|
|
1664
|
+
allMessages = this.messageStore.getChatIds().flatMap(chatId => this.messageStore.getChatMessages(chatId));
|
|
1665
|
+
} catch {
|
|
1666
|
+
allMessages = [];
|
|
1667
|
+
}
|
|
1668
|
+
}
|
|
1669
|
+
|
|
1670
|
+
// Serialize the store data
|
|
1671
|
+
const storeData = {
|
|
1672
|
+
version: '1.0.0',
|
|
1673
|
+
savedAt: new Date().toISOString(),
|
|
1674
|
+
sessionName: this.sessionName,
|
|
1675
|
+
stats: stats,
|
|
1676
|
+
messages: []
|
|
1677
|
+
};
|
|
1678
|
+
|
|
1679
|
+
// Convert Map structure to serializable array format
|
|
1680
|
+
for (const msg of allMessages) {
|
|
1681
|
+
try {
|
|
1682
|
+
storeData.messages.push({
|
|
1683
|
+
key: msg.key,
|
|
1684
|
+
message: msg.message,
|
|
1685
|
+
messageTimestamp: msg.messageTimestamp,
|
|
1686
|
+
pushName: msg.pushName,
|
|
1687
|
+
broadcast: msg.broadcast,
|
|
1688
|
+
isDeleted: msg.isDeleted
|
|
1689
|
+
});
|
|
1690
|
+
} catch (err) {
|
|
1691
|
+
console.error('Error serializing message:', err);
|
|
1692
|
+
}
|
|
1693
|
+
}
|
|
1694
|
+
|
|
1695
|
+
// Ensure directory exists
|
|
1696
|
+
const dir = path.dirname(this.messageStoreFilePath);
|
|
1697
|
+
if (!fs.existsSync(dir)) {
|
|
1698
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
1699
|
+
}
|
|
1700
|
+
|
|
1701
|
+
// Write to file
|
|
1702
|
+
fs.writeFileSync(
|
|
1703
|
+
this.messageStoreFilePath,
|
|
1704
|
+
JSON.stringify(storeData, null, 2),
|
|
1705
|
+
'utf8'
|
|
1706
|
+
);
|
|
1707
|
+
|
|
1708
|
+
this._lastStoreSave = new Date();
|
|
1709
|
+
this._storeChangeCount = 0;
|
|
1710
|
+
|
|
1711
|
+
// console.log(`[MessageStore] Saved ${storeData.messages.length} messages to ${this.messageStoreFilePath}`);
|
|
1712
|
+
|
|
1713
|
+
return {
|
|
1714
|
+
success: true,
|
|
1715
|
+
path: this.messageStoreFilePath,
|
|
1716
|
+
messageCount: storeData.messages.length,
|
|
1717
|
+
savedAt: this._lastStoreSave
|
|
1718
|
+
};
|
|
1719
|
+
} catch (error) {
|
|
1720
|
+
console.error('[MessageStore] Error saving store:', error);
|
|
1721
|
+
return {
|
|
1722
|
+
success: false,
|
|
1723
|
+
error: error.message
|
|
1724
|
+
};
|
|
1725
|
+
}
|
|
1726
|
+
}
|
|
1727
|
+
|
|
1728
|
+
/**
|
|
1729
|
+
* Load the message store from a JSON file
|
|
1730
|
+
* @returns {Promise<{success: boolean, messageCount: number}>}
|
|
1731
|
+
*/
|
|
1732
|
+
async loadMessageStore() {
|
|
1733
|
+
try {
|
|
1734
|
+
if (!fs.existsSync(this.messageStoreFilePath)) {
|
|
1735
|
+
// console.log('[MessageStore] No saved store file found');
|
|
1736
|
+
return { success: false, reason: 'file_not_found' };
|
|
1737
|
+
}
|
|
1738
|
+
|
|
1739
|
+
const fileContent = fs.readFileSync(this.messageStoreFilePath, 'utf8');
|
|
1740
|
+
const storeData = JSON.parse(fileContent);
|
|
1741
|
+
|
|
1742
|
+
// Validate data structure
|
|
1743
|
+
if (!storeData.messages || !Array.isArray(storeData.messages)) {
|
|
1744
|
+
throw new Error('Invalid store file format');
|
|
1745
|
+
}
|
|
1746
|
+
|
|
1747
|
+
// Clear existing store
|
|
1748
|
+
this.messageStore.clear();
|
|
1749
|
+
|
|
1750
|
+
// Load messages into the store
|
|
1751
|
+
let loadedCount = 0;
|
|
1752
|
+
for (const msgData of storeData.messages) {
|
|
1753
|
+
try {
|
|
1754
|
+
// Use the message store's internal handler to properly store messages
|
|
1755
|
+
const storeHandler = createMessageStoreHandler(this.messageStore);
|
|
1756
|
+
storeHandler({
|
|
1757
|
+
messages: [{
|
|
1758
|
+
key: msgData.key,
|
|
1759
|
+
message: msgData.message,
|
|
1760
|
+
messageTimestamp: msgData.messageTimestamp,
|
|
1761
|
+
pushName: msgData.pushName,
|
|
1762
|
+
broadcast: msgData.broadcast
|
|
1763
|
+
}],
|
|
1764
|
+
type: 'append'
|
|
1765
|
+
});
|
|
1766
|
+
loadedCount++;
|
|
1767
|
+
} catch (err) {
|
|
1768
|
+
console.error('[MessageStore] Error loading message:', err);
|
|
1769
|
+
}
|
|
1770
|
+
}
|
|
1771
|
+
|
|
1772
|
+
this._lastStoreSave = new Date(storeData.savedAt);
|
|
1773
|
+
this._storeChangeCount = 0;
|
|
1774
|
+
|
|
1775
|
+
// console.log(`[MessageStore] Loaded ${loadedCount}/${storeData.messages.length} messages from ${this.messageStoreFilePath}`);
|
|
1776
|
+
|
|
1777
|
+
this.emit('store-loaded', { messageCount: loadedCount });
|
|
1778
|
+
|
|
1779
|
+
return {
|
|
1780
|
+
success: true,
|
|
1781
|
+
messageCount: loadedCount,
|
|
1782
|
+
loadedFrom: storeData.savedAt
|
|
1783
|
+
};
|
|
1784
|
+
} catch (error) {
|
|
1785
|
+
console.error('[MessageStore] Error loading store:', error);
|
|
1786
|
+
return {
|
|
1787
|
+
success: false,
|
|
1788
|
+
error: error.message
|
|
1789
|
+
};
|
|
1790
|
+
}
|
|
1791
|
+
}
|
|
1792
|
+
|
|
1793
|
+
/**
|
|
1794
|
+
* Start auto-save timer
|
|
1795
|
+
* @private
|
|
1796
|
+
*/
|
|
1797
|
+
_startAutoSave() {
|
|
1798
|
+
if (this._autoSaveTimer) {
|
|
1799
|
+
clearInterval(this._autoSaveTimer);
|
|
1800
|
+
}
|
|
1801
|
+
|
|
1802
|
+
if (this.autoSaveInterval > 0) {
|
|
1803
|
+
this._autoSaveTimer = setInterval(async () => {
|
|
1804
|
+
// Only save if there have been changes
|
|
1805
|
+
if (this._storeChangeCount > 0) {
|
|
1806
|
+
// console.log(`[MessageStore] Auto-saving (${this._storeChangeCount} changes since last save)`);
|
|
1807
|
+
await this.saveMessageStore();
|
|
1808
|
+
}
|
|
1809
|
+
}, this.autoSaveInterval);
|
|
1810
|
+
|
|
1811
|
+
// console.log(`[MessageStore] Auto-save enabled (interval: ${this.autoSaveInterval}ms)`);
|
|
1812
|
+
}
|
|
1813
|
+
}
|
|
1814
|
+
|
|
1815
|
+
/**
|
|
1816
|
+
* Stop auto-save timer
|
|
1817
|
+
* @private
|
|
1818
|
+
*/
|
|
1819
|
+
_stopAutoSave() {
|
|
1820
|
+
if (this._autoSaveTimer) {
|
|
1821
|
+
clearInterval(this._autoSaveTimer);
|
|
1822
|
+
this._autoSaveTimer = null;
|
|
1823
|
+
// console.log('[MessageStore] Auto-save disabled');
|
|
1824
|
+
}
|
|
1825
|
+
}
|
|
1826
|
+
|
|
1827
|
+
/**
|
|
1828
|
+
* Increment the store change counter (called when messages are added)
|
|
1829
|
+
* @private
|
|
1830
|
+
*/
|
|
1831
|
+
_incrementStoreChangeCount() {
|
|
1832
|
+
this._storeChangeCount++;
|
|
1833
|
+
}
|
|
1834
|
+
|
|
1464
1835
|
// ═══════════════════════════════════════════════════════════
|
|
1465
1836
|
// 📁 GROUP MANAGEMENT METHODS
|
|
1466
1837
|
// ═══════════════════════════════════════════════════════════
|
package/package.json
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "innovators-bot2",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.3",
|
|
4
4
|
"description": "WhatsApp API",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"start": "node example.js",
|
|
8
|
+
"dev": "node --watch example.js",
|
|
8
9
|
"publish:all": "node publish-dual.js"
|
|
9
10
|
},
|
|
10
11
|
"keywords": [
|
|
@@ -29,7 +30,7 @@
|
|
|
29
30
|
},
|
|
30
31
|
"homepage": "https://github.com/innovatorssoft/WhatsAppAPI?tab=readme-ov-file#whatsapp-api",
|
|
31
32
|
"dependencies": {
|
|
32
|
-
"@innovatorssoft/baileys": "
|
|
33
|
+
"@innovatorssoft/baileys": "latest",
|
|
33
34
|
"figlet": "^1.8.0",
|
|
34
35
|
"mime": "^3.0.0",
|
|
35
36
|
"mime-types": "^2.1.35",
|
|
@@ -38,4 +39,4 @@
|
|
|
38
39
|
"qrcode-terminal": "^0.12.0",
|
|
39
40
|
"wa-sticker-formatter": "^4.4.4"
|
|
40
41
|
}
|
|
41
|
-
}
|
|
42
|
+
}
|