@innovatorssoft/innovators-bot2 2.0.4 → 2.0.5
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 +85 -2
- package/example.js +134 -3
- package/index.js +134 -6
- package/package.json +1 -1
- package/publish-dual.js +0 -40
package/README.md
CHANGED
|
@@ -308,6 +308,12 @@ await client.updateGroupsAddPrivacy('contacts')
|
|
|
308
308
|
// Update default disappearing mode for new chats
|
|
309
309
|
// Options: 0 (off), 86400 (24h), 604800 (7d), 7776000 (90d)
|
|
310
310
|
await client.updateDefaultDisappearingMode(604800)
|
|
311
|
+
|
|
312
|
+
// Update profile status
|
|
313
|
+
await client.updateProfileStatus('Hello World!')
|
|
314
|
+
|
|
315
|
+
// Update profile name
|
|
316
|
+
await client.updateProfileName('My name')
|
|
311
317
|
```
|
|
312
318
|
|
|
313
319
|
### 7. Interactive Messages
|
|
@@ -403,10 +409,85 @@ await client.SendList('1234567890@s.whatsapp.net', {
|
|
|
403
409
|
});
|
|
404
410
|
```
|
|
405
411
|
|
|
406
|
-
|
|
412
|
+
#### Interactive Messages (V2)
|
|
413
|
+
|
|
414
|
+
Modern interactive message generation with simplified API.
|
|
415
|
+
|
|
416
|
+
**Quick Reply Buttons (V2)**
|
|
417
|
+
```javascript
|
|
418
|
+
await client.sendQuickReplyV2(jid, 'Please select an option below:', [
|
|
419
|
+
{ id: 'btn-1', displayText: '✅ Accept' },
|
|
420
|
+
{ id: 'btn-2', displayText: '❌ Reject' }
|
|
421
|
+
], { footer: 'Powered by Innovators Soft' });
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
**URL Button (V2)**
|
|
425
|
+
```javascript
|
|
426
|
+
await client.sendUrlButtonV2(jid, 'Visit our website for more info', [
|
|
427
|
+
{ displayText: '🌐 Open Website', url: 'https://example.com' }
|
|
428
|
+
], { title: 'Product Info', footer: 'Click to open' });
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
**Copy Code Button (V2)**
|
|
432
|
+
```javascript
|
|
433
|
+
await client.sendCopyCodeV2(jid, 'Your OTP Code is:', '123456', '📋 Copy Code');
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
**Combined Buttons (Mix URL, Reply, Copy, Call) (V2)**
|
|
437
|
+
```javascript
|
|
438
|
+
await client.sendCombinedButtonsV2(jid, 'Choose an action:', [
|
|
439
|
+
{ type: 'reply', displayText: '🛒 Order Now', id: 'order' },
|
|
440
|
+
{ type: 'url', displayText: '🌐 Website', url: 'https://example.com' },
|
|
441
|
+
{ type: 'call', displayText: '📞 Phone', phoneNumber: '+923224559543' },
|
|
442
|
+
{ type: 'copy', displayText: '📋 Copy Promo', copyCode: 'PROMO2024' }
|
|
443
|
+
], { title: 'Main Menu', footer: 'Innovators Soft' });
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
**List Message (V2)**
|
|
447
|
+
```javascript
|
|
448
|
+
await client.sendListV2(jid, {
|
|
449
|
+
title: '📋 Product Menu',
|
|
450
|
+
buttonText: 'View Menu',
|
|
451
|
+
description: 'Please select a product',
|
|
452
|
+
footer: 'Powered by Innovators Soft',
|
|
453
|
+
sections: [
|
|
454
|
+
{
|
|
455
|
+
title: 'Food',
|
|
456
|
+
rows: [
|
|
457
|
+
{ rowId: 'nasi-goreng', title: 'Fried Rice', description: '$2.50' },
|
|
458
|
+
{ rowId: 'mie-goreng', title: 'Fried Noodles', description: '$2.00' }
|
|
459
|
+
]
|
|
460
|
+
}
|
|
461
|
+
]
|
|
462
|
+
});
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
### 8. Typing & Presence Control
|
|
466
|
+
|
|
467
|
+
Use `createPresenceController` for manual or standalone typing/recording presence control — without needing the auto-reply system.
|
|
407
468
|
|
|
408
469
|
```javascript
|
|
409
|
-
|
|
470
|
+
const typing = client.createPresenceController();
|
|
471
|
+
|
|
472
|
+
// Show "typing..." for 2 s, then send the message — all in one call
|
|
473
|
+
const sent = await typing.simulateTyping(jid, 2000, async () => {
|
|
474
|
+
await client.sendMessage(jid, 'Here is your answer! ✅');
|
|
475
|
+
});
|
|
476
|
+
|
|
477
|
+
// Manual start (auto-pauses after 5 s by default)
|
|
478
|
+
await typing.startTyping(jid, { duration: 5000 });
|
|
479
|
+
|
|
480
|
+
// Manual stop
|
|
481
|
+
await typing.stopTyping(jid);
|
|
482
|
+
|
|
483
|
+
// Voice note recording indicator
|
|
484
|
+
await typing.startRecording(jid, { duration: 3000 });
|
|
485
|
+
|
|
486
|
+
// Stop all active indicators (e.g. on socket close)
|
|
487
|
+
await typing.stopAll();
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
### 9. Message History (Store)
|
|
410
491
|
|
|
411
492
|
The library includes a robust message store to keep track of chat history, even across reloads.
|
|
412
493
|
|
|
@@ -546,6 +627,8 @@ The library includes example bot commands that you can use:
|
|
|
546
627
|
- `!readreceiptprivacy <value>` - Update read receipts privacy (all/none)
|
|
547
628
|
- `!groupaddprivacy <value>` - Update who can add you to groups (all/contacts/contact_blacklist)
|
|
548
629
|
- `!disappearing <seconds>` - Update default disappearing mode (0/86400/604800/7776000)
|
|
630
|
+
- `!updatestatus <text>` - Update profile status
|
|
631
|
+
- `!updatename <text>` - Update profile name
|
|
549
632
|
|
|
550
633
|
### Interactive Messages
|
|
551
634
|
- `!buttons` - Show interactive buttons
|
package/example.js
CHANGED
|
@@ -9,6 +9,10 @@ const rl = readline.createInterface({
|
|
|
9
9
|
output: process.stdout
|
|
10
10
|
});
|
|
11
11
|
|
|
12
|
+
String.prototype.toTitleCase = function () {
|
|
13
|
+
return this.split(' ').map(w => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase()).join(' ');
|
|
14
|
+
};
|
|
15
|
+
|
|
12
16
|
const question = (text) => new Promise((resolve) => rl.question(text, resolve));
|
|
13
17
|
|
|
14
18
|
async function start() {
|
|
@@ -367,6 +371,59 @@ async function start() {
|
|
|
367
371
|
});
|
|
368
372
|
break
|
|
369
373
|
|
|
374
|
+
case '!quickreplyv2':
|
|
375
|
+
await client.sendQuickReplyV2(msg.from, 'Please select an option below:', [
|
|
376
|
+
{ id: 'btn-1', displayText: '✅ Accept' },
|
|
377
|
+
{ id: 'btn-2', displayText: '❌ Reject' },
|
|
378
|
+
{ id: 'btn-3', displayText: '📞 Contact Support' }
|
|
379
|
+
], { footer: 'Powered by Innovators Soft' });
|
|
380
|
+
break
|
|
381
|
+
|
|
382
|
+
case '!urlbuttonv2':
|
|
383
|
+
await client.sendUrlButtonV2(msg.from, 'Visit our website for more info', [
|
|
384
|
+
{ displayText: '🌐 Open Website', url: 'https://example.com' }
|
|
385
|
+
], { title: 'Product Info', footer: 'Click to open' });
|
|
386
|
+
break
|
|
387
|
+
|
|
388
|
+
case '!copycodev2':
|
|
389
|
+
await client.sendCopyCodeV2(msg.from, 'Your OTP Code is:', '123456', '📋 Copy Code');
|
|
390
|
+
break
|
|
391
|
+
|
|
392
|
+
case '!combinedv2':
|
|
393
|
+
await client.sendCombinedButtonsV2(msg.from, 'Choose an action:', [
|
|
394
|
+
{ type: 'reply', displayText: '🛒 Order Now', id: 'order' },
|
|
395
|
+
{ type: 'url', displayText: '🌐 Website', url: 'https://example.com' },
|
|
396
|
+
{ type: 'call', displayText: '📞 Phone', phoneNumber: '+923224559543' },
|
|
397
|
+
{ type: 'copy', displayText: '📋 Copy Promo', copyCode: 'PROMO2024' }
|
|
398
|
+
], { title: 'Main Menu', footer: 'Innovators Soft' });
|
|
399
|
+
break
|
|
400
|
+
|
|
401
|
+
case '!listv2':
|
|
402
|
+
await client.sendListV2(msg.from, {
|
|
403
|
+
title: '📋 Product Menu',
|
|
404
|
+
buttonText: 'View Menu',
|
|
405
|
+
description: 'Please select a product',
|
|
406
|
+
footer: 'Powered by Innovators Soft',
|
|
407
|
+
sections: [
|
|
408
|
+
{
|
|
409
|
+
title: 'Food',
|
|
410
|
+
rows: [
|
|
411
|
+
{ rowId: 'nasi-goreng', title: 'Fried Rice', description: '$2.50' },
|
|
412
|
+
{ rowId: 'mie-goreng', title: 'Fried Noodles', description: '$2.00' }
|
|
413
|
+
]
|
|
414
|
+
},
|
|
415
|
+
{
|
|
416
|
+
title: 'Beverages',
|
|
417
|
+
rows: [
|
|
418
|
+
{ rowId: 'es-teh', title: 'Ice Tea', description: '$0.50' },
|
|
419
|
+
{ rowId: 'kopi', title: 'Coffee', description: '$1.00' }
|
|
420
|
+
]
|
|
421
|
+
}
|
|
422
|
+
]
|
|
423
|
+
});
|
|
424
|
+
break
|
|
425
|
+
|
|
426
|
+
|
|
370
427
|
case '!call':
|
|
371
428
|
try {
|
|
372
429
|
if (autoCancelCallTimer) {
|
|
@@ -376,7 +433,7 @@ async function start() {
|
|
|
376
433
|
const result = await client.initiateCall(msg.from);
|
|
377
434
|
lastOutgoingCallId = result?.callId || null;
|
|
378
435
|
lastOutgoingCallJid = msg.from;
|
|
379
|
-
|
|
436
|
+
|
|
380
437
|
await client.sendMessage(msg.from, `Calling... CallId: ${lastOutgoingCallId || 'unknown'}`);
|
|
381
438
|
|
|
382
439
|
if (lastOutgoingCallId) {
|
|
@@ -501,11 +558,18 @@ async function start() {
|
|
|
501
558
|
`• !statusprivacy <value> - Update status privacy\n` +
|
|
502
559
|
`• !readreceiptprivacy <value> - Update read receipts\n` +
|
|
503
560
|
`• !groupaddprivacy <value> - Who can add to groups\n` +
|
|
504
|
-
`• !disappearing <seconds> - Default disappearing mode\n
|
|
561
|
+
`• !disappearing <seconds> - Default disappearing mode\n` +
|
|
562
|
+
`• !updatestatus <text> - Update profile status\n` +
|
|
563
|
+
`• !updatename <text> - Update profile name\n\n` +
|
|
505
564
|
|
|
506
565
|
`*🎛️ Templates & Buttons*\n` +
|
|
507
566
|
`• !buttons - Button template\n` +
|
|
508
|
-
`• !list - Scrollable list\n
|
|
567
|
+
`• !list - Scrollable list\n` +
|
|
568
|
+
`• !quickreplyv2 - Quick reply buttons V2\n` +
|
|
569
|
+
`• !urlbuttonv2 - URL button V2\n` +
|
|
570
|
+
`• !copycodev2 - Copy code button V2\n` +
|
|
571
|
+
`• !combinedv2 - Mixed buttons V2\n` +
|
|
572
|
+
`• !listv2 - Interactive list V2\n\n` +
|
|
509
573
|
|
|
510
574
|
`*📞 Calls*\n` +
|
|
511
575
|
`• !call - Initiate a voice call\n` +
|
|
@@ -532,6 +596,10 @@ async function start() {
|
|
|
532
596
|
`• !typing - Show typing indicator\n` +
|
|
533
597
|
`• !recording - Show recording indicator\n` +
|
|
534
598
|
`• !paused - Clear typing or recording indicator\n` +
|
|
599
|
+
`• !typing_simulate - Simulate typing for 5s then send msg\n` +
|
|
600
|
+
`• !typing_start - Start typing with auto-pause\n` +
|
|
601
|
+
`• !typing_stop - Stop typing indicator\n` +
|
|
602
|
+
`• !recording_start - Start recording indicator\n` +
|
|
535
603
|
`• !logout - End session\n\n` +
|
|
536
604
|
|
|
537
605
|
`*📝 Note*:\nReplace <number> with phone number\n(without + or spaces)`
|
|
@@ -725,6 +793,40 @@ async function start() {
|
|
|
725
793
|
await client.sendMessage(msg.from, 'Stopped typing/recording indicator sent!');
|
|
726
794
|
break;
|
|
727
795
|
|
|
796
|
+
case '!typing_simulate':
|
|
797
|
+
// Show "typing..." for 5 seconds, then send the message — all in one call
|
|
798
|
+
await client.sendMessage(msg.from, 'Simulating typing for 5 seconds...');
|
|
799
|
+
const typing = client.createPresenceController();
|
|
800
|
+
await typing.simulateTyping(msg.from, 5000, async () => {
|
|
801
|
+
await client.sendMessage(msg.from, 'This message was sent after 5 seconds of typing! ✅');
|
|
802
|
+
});
|
|
803
|
+
break;
|
|
804
|
+
|
|
805
|
+
case '!typing_start':
|
|
806
|
+
// Manual start (auto-pauses after 5 s by default if not specified)
|
|
807
|
+
const typingStart = client.createPresenceController();
|
|
808
|
+
await typingStart.startTyping(msg.from, { duration: 10000 }); // Show for 10s
|
|
809
|
+
await client.sendMessage(msg.from, 'Typing indicator started for 10 seconds.');
|
|
810
|
+
break;
|
|
811
|
+
|
|
812
|
+
case '!typing_stop':
|
|
813
|
+
const typingStop = client.createPresenceController();
|
|
814
|
+
await typingStop.stopTyping(msg.from);
|
|
815
|
+
await client.sendMessage(msg.from, 'Typing indicator stopped.');
|
|
816
|
+
break;
|
|
817
|
+
|
|
818
|
+
case '!recording_start':
|
|
819
|
+
const recordingIndicator = client.createPresenceController();
|
|
820
|
+
await recordingIndicator.startRecording(msg.from, { duration: 5000 });
|
|
821
|
+
await client.sendMessage(msg.from, 'Recording indicator started for 5 seconds.');
|
|
822
|
+
break;
|
|
823
|
+
|
|
824
|
+
case '!typing_stop_all':
|
|
825
|
+
const typingStopAll = client.createPresenceController();
|
|
826
|
+
await typingStopAll.stopAll();
|
|
827
|
+
await client.sendMessage(msg.from, 'All active indicators for this controller stopped.');
|
|
828
|
+
break;
|
|
829
|
+
|
|
728
830
|
case '!read':
|
|
729
831
|
await client.readMessage(msg.raw.key);
|
|
730
832
|
await client.sendMessage(msg.from, 'Message marked as read!');
|
|
@@ -1351,6 +1453,35 @@ async function start() {
|
|
|
1351
1453
|
}
|
|
1352
1454
|
break;
|
|
1353
1455
|
|
|
1456
|
+
case '!updatestatus':
|
|
1457
|
+
try {
|
|
1458
|
+
if (!args) {
|
|
1459
|
+
await client.sendMessage(msg.from, '❌ Please provide a new status.\nUsage: !updatestatus <text>');
|
|
1460
|
+
break;
|
|
1461
|
+
}
|
|
1462
|
+
await client.updateProfileStatus(args.trim());
|
|
1463
|
+
await client.sendMessage(msg.from, `✅ Profile status updated successfully!`);
|
|
1464
|
+
} catch (error) {
|
|
1465
|
+
console.error('Error updating profile status:', error);
|
|
1466
|
+
await client.sendMessage(msg.from, `❌ Failed to update profile status: ${error.message}`);
|
|
1467
|
+
}
|
|
1468
|
+
break;
|
|
1469
|
+
|
|
1470
|
+
case '!updatename':
|
|
1471
|
+
try {
|
|
1472
|
+
if (!args) {
|
|
1473
|
+
await client.sendMessage(msg.from, '❌ Please provide a new name.\nUsage: !updatename <text>');
|
|
1474
|
+
break;
|
|
1475
|
+
}
|
|
1476
|
+
const newName = args.trim().toTitleCase();
|
|
1477
|
+
await client.updateProfileName(newName);
|
|
1478
|
+
await client.sendMessage(msg.from, `✅ *${newName}* \nProfile name updated successfully!`);
|
|
1479
|
+
} catch (error) {
|
|
1480
|
+
console.error('Error updating profile name:', error);
|
|
1481
|
+
await client.sendMessage(msg.from, `❌ Failed to update profile name: ${error.message}`);
|
|
1482
|
+
}
|
|
1483
|
+
break;
|
|
1484
|
+
|
|
1354
1485
|
case '!messages':
|
|
1355
1486
|
const history = client.getStoredMessages(msg.from);
|
|
1356
1487
|
let historyText = `*💾 Stored Messages for this chat (${history.length}):*\n\n`;
|
package/index.js
CHANGED
|
@@ -14,7 +14,14 @@ const {
|
|
|
14
14
|
// Anti-Delete
|
|
15
15
|
MessageStore,
|
|
16
16
|
createMessageStoreHandler,
|
|
17
|
-
createAntiDeleteHandler
|
|
17
|
+
createAntiDeleteHandler,
|
|
18
|
+
createTypingIndicator,
|
|
19
|
+
generateInteractiveButtonMessage,
|
|
20
|
+
generateInteractiveListMessage,
|
|
21
|
+
generateCombinedButtons,
|
|
22
|
+
generateCopyCodeButton,
|
|
23
|
+
generateUrlButtonMessage,
|
|
24
|
+
generateQuickReplyButtons
|
|
18
25
|
} = require('@innovatorssoft/baileys');
|
|
19
26
|
|
|
20
27
|
const { Sticker, StickerTypes } = require('wa-sticker-formatter');
|
|
@@ -119,16 +126,15 @@ class WhatsAppClient extends EventEmitter {
|
|
|
119
126
|
|
|
120
127
|
async connect() {
|
|
121
128
|
try {
|
|
129
|
+
if (this._connectionState === 'connecting' && this.sock) {
|
|
130
|
+
return; // Prevent concurrent connection attempts
|
|
131
|
+
}
|
|
122
132
|
|
|
123
133
|
if (this._connectionState !== 'connecting') {
|
|
124
134
|
this._connectionState = 'connecting';
|
|
125
135
|
this.emit('connecting', 'Connecting to WhatsApp...');
|
|
126
136
|
}
|
|
127
137
|
|
|
128
|
-
const browserConfig = this.authmethod === 'pairing'
|
|
129
|
-
? Browsers.iOS('chrome')
|
|
130
|
-
: ["Innovators Soft", "chrome", "1000.26100.275.0"];
|
|
131
|
-
|
|
132
138
|
const { version: baileysVersion, isLatest: baileysIsLatest } = await fetchLatestBaileysVersion();
|
|
133
139
|
const { version: waWebVersion, isLatest: waWebIsLatest } = await fetchLatestWaWebVersion();
|
|
134
140
|
|
|
@@ -147,7 +153,7 @@ class WhatsAppClient extends EventEmitter {
|
|
|
147
153
|
generateHighQualityLinkPreview: true,
|
|
148
154
|
linkPreviewImageThumbnailWidth: 192,
|
|
149
155
|
emitOwnEvents: true,
|
|
150
|
-
browser:
|
|
156
|
+
browser: Browsers.android('Innovators Soft'),
|
|
151
157
|
version: waWebVersion,
|
|
152
158
|
cachedGroupMetadata: async (jid) => {
|
|
153
159
|
const cached = this.groupMetadataCache.get(jid);
|
|
@@ -440,6 +446,7 @@ class WhatsAppClient extends EventEmitter {
|
|
|
440
446
|
|
|
441
447
|
try {
|
|
442
448
|
for (const reaction of reactions) {
|
|
449
|
+
|
|
443
450
|
// Get the chat JID, preferring PN over LID
|
|
444
451
|
let jid = reaction.key.remoteJid;
|
|
445
452
|
if (typeof reaction.key.remoteJidAlt === 'string' &&
|
|
@@ -913,6 +920,80 @@ class WhatsAppClient extends EventEmitter {
|
|
|
913
920
|
throw error;
|
|
914
921
|
}
|
|
915
922
|
}
|
|
923
|
+
|
|
924
|
+
/**
|
|
925
|
+
* Send Quick Reply Buttons (V2)
|
|
926
|
+
* @param {string} jid - Target JID
|
|
927
|
+
* @param {string} text - Message text
|
|
928
|
+
* @param {Array<object>} buttons - Array of { id, displayText }
|
|
929
|
+
* @param {object} options - { footer }
|
|
930
|
+
*/
|
|
931
|
+
async sendQuickReplyV2(jid, text, buttons, options = {}) {
|
|
932
|
+
if (!this.isConnected) throw new Error('Client is not connected');
|
|
933
|
+
const message = generateQuickReplyButtons(text, buttons, options);
|
|
934
|
+
return await this.sock.sendMessage(jid, message, { ai: true });
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
/**
|
|
938
|
+
* Send Generic Interactive Button Message (V2)
|
|
939
|
+
* @param {string} jid - Target JID
|
|
940
|
+
* @param {object} options - Button options
|
|
941
|
+
*/
|
|
942
|
+
async sendInteractiveButtonV2(jid, options) {
|
|
943
|
+
if (!this.isConnected) throw new Error('Client is not connected');
|
|
944
|
+
const message = generateInteractiveButtonMessage(options);
|
|
945
|
+
return await this.sock.sendMessage(jid, message, { ai: true });
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
/**
|
|
949
|
+
* Send URL Button (V2)
|
|
950
|
+
* @param {string} jid - Target JID
|
|
951
|
+
* @param {string} text - Message text
|
|
952
|
+
* @param {Array<object>} buttons - Array of { displayText, url }
|
|
953
|
+
* @param {object} options - { title, footer }
|
|
954
|
+
*/
|
|
955
|
+
async sendUrlButtonV2(jid, text, buttons, options = {}) {
|
|
956
|
+
if (!this.isConnected) throw new Error('Client is not connected');
|
|
957
|
+
const message = generateUrlButtonMessage(text, buttons, options);
|
|
958
|
+
return await this.sock.sendMessage(jid, message, { ai: true });
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
/**
|
|
962
|
+
* Send Copy Code Button (V2)
|
|
963
|
+
* @param {string} jid - Target JID
|
|
964
|
+
* @param {string} text - Message text
|
|
965
|
+
* @param {string} code - Code to be copied
|
|
966
|
+
* @param {string} buttonText - Text on the copy button
|
|
967
|
+
*/
|
|
968
|
+
async sendCopyCodeV2(jid, text, code, buttonText) {
|
|
969
|
+
if (!this.isConnected) throw new Error('Client is not connected');
|
|
970
|
+
const message = generateCopyCodeButton(text, code, buttonText);
|
|
971
|
+
return await this.sock.sendMessage(jid, message, { ai: true });
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
/**
|
|
975
|
+
* Send Combined Buttons (V2)
|
|
976
|
+
* @param {string} jid - Target JID
|
|
977
|
+
* @param {string} text - Message text
|
|
978
|
+
* @param {Array<object>} buttons - Mix of { type: 'reply'|'url'|'call'|'copy', ... }
|
|
979
|
+
* @param {object} options - { title, footer }
|
|
980
|
+
*/
|
|
981
|
+
async sendCombinedButtonsV2(jid, text, buttons, options = {}) {
|
|
982
|
+
if (!this.isConnected) throw new Error('Client is not connected');
|
|
983
|
+
const message = generateCombinedButtons(text, buttons, options);
|
|
984
|
+
return await this.sock.sendMessage(jid, message, { ai: true });
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
/**
|
|
988
|
+
* Send Interactive List Message (V2)
|
|
989
|
+
* @param {string} jid - Target JID
|
|
990
|
+
* @param {object} options - List options (title, buttonText, description, footer, sections)
|
|
991
|
+
*/
|
|
992
|
+
async sendListV2(jid, options) {
|
|
993
|
+
if (!this.isConnected) throw new Error('Client is not connected');
|
|
994
|
+
const message = generateInteractiveListMessage(options);
|
|
995
|
+
return await this.sock.sendMessage(jid, message, { ai: true });
|
|
996
|
+
}
|
|
916
997
|
/**
|
|
917
998
|
* Send an external ad reply with a local image
|
|
918
999
|
* @param {string} number - The phone number to send the ad to
|
|
@@ -1294,6 +1375,17 @@ class WhatsAppClient extends EventEmitter {
|
|
|
1294
1375
|
await this.sock.sendPresenceUpdate("paused", jid);
|
|
1295
1376
|
}
|
|
1296
1377
|
|
|
1378
|
+
/**
|
|
1379
|
+
* Create a typing indicator controller for manual or standalone presence control
|
|
1380
|
+
* @returns {object} The typing indicator controller
|
|
1381
|
+
*/
|
|
1382
|
+
createPresenceController() {
|
|
1383
|
+
if (!this.sock) throw new Error('Client is not connected');
|
|
1384
|
+
return createTypingIndicator(
|
|
1385
|
+
(jid, presence) => this.sock.sendPresenceUpdate(presence, jid)
|
|
1386
|
+
);
|
|
1387
|
+
}
|
|
1388
|
+
|
|
1297
1389
|
/**
|
|
1298
1390
|
* Reinitialize the WhatsApp client by clearing the session and reconnecting
|
|
1299
1391
|
* @returns {Promise<void>}
|
|
@@ -2374,6 +2466,42 @@ class WhatsAppClient extends EventEmitter {
|
|
|
2374
2466
|
}
|
|
2375
2467
|
}
|
|
2376
2468
|
|
|
2469
|
+
/**
|
|
2470
|
+
* Update profile status (about)
|
|
2471
|
+
* @param {string} status - The new status message
|
|
2472
|
+
* @returns {Promise<void>}
|
|
2473
|
+
* @throws {Error} If client is not connected or update fails
|
|
2474
|
+
*/
|
|
2475
|
+
async updateProfileStatus(status) {
|
|
2476
|
+
if (!this.isConnected) {
|
|
2477
|
+
throw new Error('Client is not connected');
|
|
2478
|
+
}
|
|
2479
|
+
try {
|
|
2480
|
+
await this.sock.updateProfileStatus(status);
|
|
2481
|
+
} catch (error) {
|
|
2482
|
+
console.error('Error updating profile status:', error);
|
|
2483
|
+
throw error;
|
|
2484
|
+
}
|
|
2485
|
+
}
|
|
2486
|
+
|
|
2487
|
+
/**
|
|
2488
|
+
* Update profile name
|
|
2489
|
+
* @param {string} name - The new profile name
|
|
2490
|
+
* @returns {Promise<void>}
|
|
2491
|
+
* @throws {Error} If client is not connected or update fails
|
|
2492
|
+
*/
|
|
2493
|
+
async updateProfileName(name) {
|
|
2494
|
+
if (!this.isConnected) {
|
|
2495
|
+
throw new Error('Client is not connected');
|
|
2496
|
+
}
|
|
2497
|
+
try {
|
|
2498
|
+
await this.sock.updateProfileName(name);
|
|
2499
|
+
} catch (error) {
|
|
2500
|
+
console.error('Error updating profile name:', error);
|
|
2501
|
+
throw error;
|
|
2502
|
+
}
|
|
2503
|
+
}
|
|
2504
|
+
|
|
2377
2505
|
/**
|
|
2378
2506
|
* Add EXIF metadata to an existing WebP buffer
|
|
2379
2507
|
* @param {Buffer} buffer - WebP buffer
|
package/package.json
CHANGED
package/publish-dual.js
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
const { execSync } = require('child_process');
|
|
2
|
-
const fs = require('fs');
|
|
3
|
-
const path = require('path');
|
|
4
|
-
|
|
5
|
-
const packagePath = path.join(__dirname, 'package.json');
|
|
6
|
-
|
|
7
|
-
// Read the original package.json
|
|
8
|
-
const originalPackage = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
|
|
9
|
-
const originalName = originalPackage.name;
|
|
10
|
-
|
|
11
|
-
console.log('🚀 Starting dual npm publish...\n');
|
|
12
|
-
|
|
13
|
-
try {
|
|
14
|
-
// Step 1: Publish as unscoped package (innovators-bot2)
|
|
15
|
-
console.log(`📦 Publishing as "${originalName}"...`);
|
|
16
|
-
execSync('npm publish', { stdio: 'inherit', cwd: __dirname });
|
|
17
|
-
console.log(`✅ Successfully published "${originalName}"\n`);
|
|
18
|
-
|
|
19
|
-
// Step 2: Change name to scoped package
|
|
20
|
-
const scopedName = '@innovatorssoft/innovators-bot2';
|
|
21
|
-
console.log(`📦 Publishing as "${scopedName}"...`);
|
|
22
|
-
|
|
23
|
-
originalPackage.name = scopedName;
|
|
24
|
-
fs.writeFileSync(packagePath, JSON.stringify(originalPackage, null, 2) + '\n');
|
|
25
|
-
|
|
26
|
-
// Step 3: Publish as scoped package with public access
|
|
27
|
-
execSync('npm publish --access public', { stdio: 'inherit', cwd: __dirname });
|
|
28
|
-
console.log(`✅ Successfully published "${scopedName}"\n`);
|
|
29
|
-
|
|
30
|
-
} catch (error) {
|
|
31
|
-
console.error('❌ Error during publish:', error.message);
|
|
32
|
-
process.exitCode = 1;
|
|
33
|
-
} finally {
|
|
34
|
-
// Step 4: Always restore original package.json
|
|
35
|
-
console.log('🔄 Restoring original package.json...');
|
|
36
|
-
originalPackage.name = originalName;
|
|
37
|
-
fs.writeFileSync(packagePath, JSON.stringify(originalPackage, null, 2) + '\n');
|
|
38
|
-
console.log('✅ Original package.json restored');
|
|
39
|
-
console.log('\n🎉 Dual publish complete!');
|
|
40
|
-
}
|