@innovatorssoft/innovators-bot2 2.0.1 → 2.0.2

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.
Files changed (4) hide show
  1. package/README.md +87 -3
  2. package/example.js +17 -50
  3. package/index.js +93 -19
  4. package/package.json +2 -1
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
- - 👥 Group management
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
@@ -277,7 +291,7 @@ await client.sendButtons('1234567890@s.whatsapp.net', {
277
291
  text: 'Do you like this bot?',
278
292
  title: 'Feedback',
279
293
  subtitle: 'Let us know!',
280
- footer: 'Powered by Baileys',
294
+ footer: 'Powered by Innovators Soft',
281
295
  interactiveButtons: [
282
296
  {
283
297
  name: 'quick_reply',
@@ -295,6 +309,43 @@ await client.sendButtons('1234567890@s.whatsapp.net', {
295
309
  }
296
310
  ]
297
311
  });
312
+
313
+ // Send interactive buttons with an image from URL + caption
314
+ await client.sendButtons('1234567890@s.whatsapp.net', {
315
+ image: { url: 'https://example.com/image.jpg' },
316
+ caption: 'Body',
317
+ title: 'Title',
318
+ subtitle: 'Subtitle',
319
+ footer: 'Footer',
320
+ interactiveButtons: [
321
+ {
322
+ name: 'quick_reply',
323
+ buttonParamsJson: JSON.stringify({
324
+ display_text: 'DisplayText',
325
+ id: 'ID1'
326
+ })
327
+ }
328
+ ],
329
+ hasMediaAttachment: false
330
+ });
331
+
332
+ // Send interactive buttons with a local image file + caption
333
+ await client.sendButtons('1234567890@s.whatsapp.net', {
334
+ imagePath: './image.jpg',
335
+ caption: 'Body',
336
+ title: 'Title',
337
+ subtitle: 'Subtitle',
338
+ footer: 'Footer',
339
+ interactiveButtons: [
340
+ {
341
+ name: 'quick_reply',
342
+ buttonParamsJson: JSON.stringify({
343
+ display_text: 'DisplayText',
344
+ id: 'ID1'
345
+ })
346
+ }
347
+ ]
348
+ });
298
349
  ```
299
350
 
300
351
  #### List Messages
@@ -444,6 +495,24 @@ client.on('disconnected', (error) => {
444
495
  })
445
496
  ```
446
497
 
498
+ ### Contact Events
499
+ ```javascript
500
+ // When contacts are received from history sync
501
+ client.on('contacts-received', (contacts) => {
502
+ console.log(`Received ${contacts.length} contacts`);
503
+ })
504
+
505
+ // When new contacts are added/updated
506
+ client.on('contacts-upsert', (contacts) => {
507
+ console.log(`New Contacts: ${contacts.length} contacts added/updated`);
508
+ })
509
+
510
+ // When existing contacts are updated (profile picture changes, etc.)
511
+ client.on('contacts-update', (updates) => {
512
+ console.log(`Contact Updates: ${updates.length} contacts modified`);
513
+ })
514
+ ```
515
+
447
516
  ### Message Events
448
517
  ```javascript
449
518
  // When a new message is received
@@ -457,7 +526,14 @@ client.on('message', async msg => {
457
526
  // Handle different message types
458
527
  if (msg.hasMedia) {
459
528
  console.log('Message contains media')
460
- // Handle media message
529
+ // Download media (image/video/audio/document)
530
+ const media = await client.downloadMedia(msg)
531
+ if (media) {
532
+ const fs = require('fs')
533
+ const fileName = `./download-${Date.now()}.${media.extension}`
534
+ fs.writeFileSync(fileName, media.buffer)
535
+ console.log('Saved media to:', fileName)
536
+ }
461
537
  }
462
538
  })
463
539
  ```
@@ -844,3 +920,11 @@ This project is licensed under the MIT License - see the LICENSE file for detail
844
920
  ## Credits
845
921
 
846
922
  Developed by [Innovators Soft](https://facebook.com/innovatorssoft). Based on the [@itsukichan/baileys](https://github.com/itsukichann/baileys) library.
923
+
924
+ # Special Thanks
925
+ - [@whiskeysockets/baileys](https://github.com/whiskeysockets/Baileys)
926
+ - [@itsukichan](https://github.com/itsukichann)
927
+ - [All Contributors](https://github.com/innovatorssoft/Baileys/)
928
+ - [@ZenboBot](https://discordbot.innovatorssoftpk.com/) - AI Powered Baileys Bot
929
+ # Sponsor Me
930
+ Buy me a coffee - [Innovators Soft](https://facebook.com/innovatorssoft)
package/example.js CHANGED
@@ -76,6 +76,19 @@ async function start() {
76
76
  console.log('📦 New LID/PN mappings received')
77
77
  })
78
78
 
79
+ // Handle Contact Events
80
+ client.on('contacts-received', (contacts) => {
81
+ console.log(`\n👥 History Sync: Received ${contacts.length} contacts`);
82
+ })
83
+
84
+ client.on('contacts-upsert', (contacts) => {
85
+ console.log(`\n👥 New Contacts: ${contacts.length} contacts added/updated`);
86
+ })
87
+
88
+ client.on('contacts-update', (updates) => {
89
+ console.log(`\n👥 Contact Updates: ${updates.length} contacts modified`);
90
+ })
91
+
79
92
  // Handle Anti-Delete system
80
93
  client.on('message-deleted', async (data) => {
81
94
  console.log(`\n🛡️ Message from ${data.jid} was deleted!`)
@@ -242,29 +255,6 @@ async function start() {
242
255
  { title: 'Security', id: 'security', description: 'Security and login options' },
243
256
  { title: 'Payments', id: 'payments', description: 'Manage payment methods' },
244
257
  { 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
258
  ]
269
259
  },
270
260
  {
@@ -277,29 +267,6 @@ async function start() {
277
267
  { title: 'Data Saver', id: 'data_saver', description: 'Reduce data usage' },
278
268
  { title: 'Storage', id: 'storage', description: 'Manage local storage' },
279
269
  { 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
270
  ]
304
271
  }
305
272
  ]
@@ -334,10 +301,10 @@ async function start() {
334
301
 
335
302
  await client.sendButtons(msg.from, {
336
303
  imagePath: './example.jpg',
337
- caption: '', // Keep it short and concise
338
- title: '', // Max 24 chars
339
- subtitle: '', // Optional, appears below title
340
- footer: '',
304
+ caption: 'here is captions of image\nwith linebreaks', // Keep it short and concise
305
+ title: 'Image Title', // Max 24 chars
306
+ subtitle: 'Image Subtitle (but optional)', // Optional, appears below title
307
+ footer: 'Image Footer',
341
308
  interactiveButtons: [
342
309
  {
343
310
  name: 'quick_reply',
package/index.js CHANGED
@@ -61,6 +61,8 @@ class WhatsAppClient extends EventEmitter {
61
61
  maxMessagesPerChat: config.maxMessagesPerChat || 1000,
62
62
  ttl: config.messageTTL || 24 * 60 * 60 * 1000
63
63
  });
64
+ // Initialize contacts cache
65
+ this.contactsCache = new NodeCache({ stdTTL: 0, checkperiod: 20 }); // No TTL, manual cleanup on logout
64
66
  }
65
67
 
66
68
  /**
@@ -150,13 +152,11 @@ class WhatsAppClient extends EventEmitter {
150
152
  console.error(`Error fetching metadata for group ${jid}:`, error);
151
153
  return null;
152
154
  }
153
- }
155
+ },
154
156
  });
155
157
 
156
158
  this.store = this.sock.signalRepository.lidMapping;
157
159
 
158
-
159
-
160
160
  this.sock.ev.on('connection.update', async (update) => {
161
161
  const { connection, lastDisconnect, qr } = update;
162
162
 
@@ -167,13 +167,13 @@ class WhatsAppClient extends EventEmitter {
167
167
  if (this._connectionState !== 'connected') {
168
168
  const user = getCurrentSenderInfo(this.sock.authState)
169
169
  if (user) {
170
+ this.isConnected = true;
170
171
  const userInfo = {
171
172
  name: user.pushName || 'Unknown',
172
173
  phone: user.phoneNumber,
173
174
  platform: user.platform || 'Unknown',
174
- isOnline: true
175
+ isOnline: true,
175
176
  };
176
- this.isConnected = true;
177
177
  this._connectionState = 'connected';
178
178
  this.emit('connected', userInfo);
179
179
  }
@@ -387,6 +387,8 @@ class WhatsAppClient extends EventEmitter {
387
387
 
388
388
  // 👍 Handle message reactions
389
389
  this.sock.ev.on('messages.reaction', async (reactions) => {
390
+
391
+
390
392
  try {
391
393
  for (const reaction of reactions) {
392
394
  // Get the chat JID, preferring PN over LID
@@ -509,6 +511,34 @@ class WhatsAppClient extends EventEmitter {
509
511
  }
510
512
  });
511
513
 
514
+ // Handle contacts from history sync
515
+ this.sock.ev.on('messaging-history.set', ({ contacts: newContacts }) => {
516
+ if (newContacts && newContacts.length > 0) {
517
+ for (const contact of newContacts) {
518
+ this.contactsCache.set(contact.id, contact);
519
+ }
520
+ this.emit('contacts-received', newContacts);
521
+
522
+ }
523
+ });
524
+
525
+ // Handle contacts upsert (new contacts added)
526
+ this.sock.ev.on('contacts.upsert', (newContacts) => {
527
+ for (const contact of newContacts) {
528
+ this.contactsCache.set(contact.id, contact);
529
+ }
530
+ this.emit('contacts-upsert', newContacts);
531
+ });
532
+
533
+ // Handle contacts update (profile picture changes, etc.)
534
+ this.sock.ev.on('contacts.update', (updates) => {
535
+ for (const update of updates) {
536
+ const existing = this.contactsCache.get(update.id) || {};
537
+ this.contactsCache.set(update.id, { ...existing, ...update });
538
+ }
539
+ this.emit('contacts-update', updates);
540
+ });
541
+
512
542
  } catch (error) {
513
543
  console.error('Error in connect:', error);
514
544
  this.emit('error', error);
@@ -654,6 +684,10 @@ class WhatsAppClient extends EventEmitter {
654
684
  throw new Error('Unsupported file type: ' + fileExtension);
655
685
  }
656
686
 
687
+ if (options.mentions) {
688
+ mediaMessage.mentions = options.mentions;
689
+ }
690
+
657
691
  return await this.sock.sendMessage(chatId, mediaMessage, { ai: true });
658
692
  } catch (error) {
659
693
  console.error('Error sending media:', error);
@@ -684,11 +718,20 @@ class WhatsAppClient extends EventEmitter {
684
718
  const fileName = path.basename(filePath);
685
719
  const mimeType = mime.getType(filePath);
686
720
 
687
- return await this.sock.sendMessage(chatId, {
721
+ const messageContent = {
688
722
  document: fileBuffer,
689
723
  caption: caption,
690
724
  mimetype: mimeType,
691
725
  fileName: fileName,
726
+ };
727
+
728
+ if (typeof caption === 'object' && caption !== null) {
729
+ if (caption.caption) messageContent.caption = caption.caption;
730
+ if (caption.mentions) messageContent.mentions = caption.mentions;
731
+ }
732
+
733
+ return await this.sock.sendMessage(chatId, {
734
+ ...messageContent,
692
735
  }, { ai: true });
693
736
  } catch (error) {
694
737
  console.error('Error sending document:', error);
@@ -719,8 +762,16 @@ class WhatsAppClient extends EventEmitter {
719
762
  const {
720
763
  text,
721
764
  imagePath,
765
+ image,
766
+ video,
767
+ document,
768
+ location,
769
+ product,
770
+ mimetype,
771
+ jpegThumbnail,
722
772
  caption,
723
773
  title,
774
+ subtitle,
724
775
  footer,
725
776
  interactiveButtons = [],
726
777
  hasMediaAttachment = false,
@@ -729,24 +780,40 @@ class WhatsAppClient extends EventEmitter {
729
780
  let messageContent = {};
730
781
 
731
782
  try {
783
+ const base = {
784
+ title: title,
785
+ subtitle: subtitle,
786
+ footer: footer,
787
+ interactiveButtons: interactiveButtons,
788
+ hasMediaAttachment: hasMediaAttachment,
789
+ };
790
+
732
791
  if (imagePath) {
733
- // Handle message with image
792
+ // Handle message with local image path
734
793
  const imageBuffer = fs.readFileSync(imagePath);
735
794
  messageContent = {
795
+ ...base,
736
796
  image: imageBuffer,
737
797
  caption: caption,
738
- title: title,
739
- footer: footer,
740
- interactiveButtons: interactiveButtons,
741
- hasMediaAttachment: hasMediaAttachment,
798
+ };
799
+ } else if (image || video || document || location || product) {
800
+ // Pass-through media objects (e.g. { image: { url } })
801
+ messageContent = {
802
+ ...base,
803
+ ...(image ? { image } : {}),
804
+ ...(video ? { video } : {}),
805
+ ...(document ? { document } : {}),
806
+ ...(location ? { location } : {}),
807
+ ...(product ? { product } : {}),
808
+ ...(mimetype ? { mimetype } : {}),
809
+ ...(jpegThumbnail ? { jpegThumbnail } : {}),
810
+ caption: caption,
742
811
  };
743
812
  } else {
744
813
  // Handle text-only message
745
814
  messageContent = {
815
+ ...base,
746
816
  text: text,
747
- title: title,
748
- footer: footer,
749
- interactiveButtons: interactiveButtons,
750
817
  };
751
818
  }
752
819
 
@@ -1183,6 +1250,12 @@ class WhatsAppClient extends EventEmitter {
1183
1250
  this.sock = null;
1184
1251
  }
1185
1252
 
1253
+ // Clear store interval
1254
+ if (this._storeInterval) {
1255
+ clearInterval(this._storeInterval);
1256
+ this._storeInterval = null;
1257
+ }
1258
+
1186
1259
  // Add a small delay before reconnecting
1187
1260
  await new Promise(resolve => setTimeout(resolve, 1000));
1188
1261
 
@@ -1332,6 +1405,7 @@ class WhatsAppClient extends EventEmitter {
1332
1405
 
1333
1406
  // Update connection state and emit event
1334
1407
  this.isConnected = false;
1408
+
1335
1409
  this.emit('logout', 'Logged out successfully');
1336
1410
 
1337
1411
  return true;
@@ -1343,11 +1417,11 @@ class WhatsAppClient extends EventEmitter {
1343
1417
  }
1344
1418
 
1345
1419
  /**
1346
- * Download media from a message
1347
- * @param {object} message - The message object containing media (must have raw property)
1348
- * @returns {Promise<object|null>} Object with buffer, mimetype, and extension, or null if no media
1349
- * @throws {Error} If client is not connected or download fails
1350
- */
1420
+ * Download media from a message
1421
+ * @param {object} message - The message object containing media (must have raw property)
1422
+ * @returns {Promise<object|null>} Object with buffer, mimetype, and extension, or null if no media
1423
+ * @throws {Error} If client is not connected or download fails
1424
+ */
1351
1425
  async downloadMedia(message) {
1352
1426
  if (!this.isConnected) {
1353
1427
  throw new Error('Client is not connected');
package/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "@innovatorssoft/innovators-bot2",
3
- "version": "2.0.1",
3
+ "version": "2.0.2",
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": [