innovators-bot2 2.0.0 → 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.
- package/README.md +222 -10
- package/example.js +509 -52
- package/index.js +609 -19
- package/package.json +2 -1
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
|
-
|
|
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
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
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
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
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');
|
|
@@ -1461,6 +1535,522 @@ class WhatsAppClient extends EventEmitter {
|
|
|
1461
1535
|
}
|
|
1462
1536
|
}
|
|
1463
1537
|
|
|
1538
|
+
// ═══════════════════════════════════════════════════════════
|
|
1539
|
+
// 📁 GROUP MANAGEMENT METHODS
|
|
1540
|
+
// ═══════════════════════════════════════════════════════════
|
|
1541
|
+
|
|
1542
|
+
/**
|
|
1543
|
+
* Create a new WhatsApp group
|
|
1544
|
+
* @param {string} name - The name/subject of the group
|
|
1545
|
+
* @param {Array<string>} participants - Array of participant JIDs (e.g., ['1234@s.whatsapp.net'])
|
|
1546
|
+
* @returns {Promise<object>} The created group info (includes gid/id)
|
|
1547
|
+
* @throws {Error} If client is not connected or group creation fails
|
|
1548
|
+
*/
|
|
1549
|
+
async createGroup(name, participants = []) {
|
|
1550
|
+
if (!this.isConnected) {
|
|
1551
|
+
throw new Error('Client is not connected');
|
|
1552
|
+
}
|
|
1553
|
+
|
|
1554
|
+
try {
|
|
1555
|
+
const group = await this.sock.groupCreate(name, participants);
|
|
1556
|
+
return group;
|
|
1557
|
+
} catch (error) {
|
|
1558
|
+
console.error('Error creating group:', error);
|
|
1559
|
+
throw error;
|
|
1560
|
+
}
|
|
1561
|
+
}
|
|
1562
|
+
|
|
1563
|
+
/**
|
|
1564
|
+
* Change the subject (name) of a group
|
|
1565
|
+
* @param {string} groupId - The group JID
|
|
1566
|
+
* @param {string} newSubject - The new subject/name for the group
|
|
1567
|
+
* @returns {Promise<void>}
|
|
1568
|
+
* @throws {Error} If client is not connected or update fails
|
|
1569
|
+
*/
|
|
1570
|
+
async changeGroupSubject(groupId, newSubject) {
|
|
1571
|
+
if (!this.isConnected) {
|
|
1572
|
+
throw new Error('Client is not connected');
|
|
1573
|
+
}
|
|
1574
|
+
|
|
1575
|
+
try {
|
|
1576
|
+
await this.sock.groupUpdateSubject(groupId, newSubject);
|
|
1577
|
+
// Update the cache with the new subject
|
|
1578
|
+
const cached = this.groupMetadataCache.get(groupId);
|
|
1579
|
+
if (cached) {
|
|
1580
|
+
cached.subject = newSubject;
|
|
1581
|
+
this.updateGroupMetadataCache(groupId, cached);
|
|
1582
|
+
}
|
|
1583
|
+
} catch (error) {
|
|
1584
|
+
console.error('Error changing group subject:', error);
|
|
1585
|
+
throw error;
|
|
1586
|
+
}
|
|
1587
|
+
}
|
|
1588
|
+
|
|
1589
|
+
/**
|
|
1590
|
+
* Change the description of a group
|
|
1591
|
+
* @param {string} groupId - The group JID
|
|
1592
|
+
* @param {string} newDescription - The new description for the group
|
|
1593
|
+
* @returns {Promise<void>}
|
|
1594
|
+
* @throws {Error} If client is not connected or update fails
|
|
1595
|
+
*/
|
|
1596
|
+
async changeGroupDescription(groupId, newDescription) {
|
|
1597
|
+
if (!this.isConnected) {
|
|
1598
|
+
throw new Error('Client is not connected');
|
|
1599
|
+
}
|
|
1600
|
+
|
|
1601
|
+
try {
|
|
1602
|
+
await this.sock.groupUpdateDescription(groupId, newDescription);
|
|
1603
|
+
// Update the cache with the new description
|
|
1604
|
+
const cached = this.groupMetadataCache.get(groupId);
|
|
1605
|
+
if (cached) {
|
|
1606
|
+
cached.desc = newDescription;
|
|
1607
|
+
this.updateGroupMetadataCache(groupId, cached);
|
|
1608
|
+
}
|
|
1609
|
+
} catch (error) {
|
|
1610
|
+
console.error('Error changing group description:', error);
|
|
1611
|
+
throw error;
|
|
1612
|
+
}
|
|
1613
|
+
}
|
|
1614
|
+
|
|
1615
|
+
/**
|
|
1616
|
+
* Change group settings (announcement mode, locked/unlocked)
|
|
1617
|
+
* @param {string} groupId - The group JID
|
|
1618
|
+
* @param {string} setting - The setting to apply: 'announcement' (only admins send), 'not_announcement' (everyone sends), 'locked' (only admins edit info), 'unlocked' (everyone edits info)
|
|
1619
|
+
* @returns {Promise<void>}
|
|
1620
|
+
* @throws {Error} If client is not connected or update fails
|
|
1621
|
+
*/
|
|
1622
|
+
async changeGroupSettings(groupId, setting) {
|
|
1623
|
+
if (!this.isConnected) {
|
|
1624
|
+
throw new Error('Client is not connected');
|
|
1625
|
+
}
|
|
1626
|
+
|
|
1627
|
+
const validSettings = ['announcement', 'not_announcement', 'locked', 'unlocked'];
|
|
1628
|
+
if (!validSettings.includes(setting)) {
|
|
1629
|
+
throw new Error(`Invalid setting: ${setting}. Must be one of: ${validSettings.join(', ')}`);
|
|
1630
|
+
}
|
|
1631
|
+
|
|
1632
|
+
try {
|
|
1633
|
+
await this.sock.groupSettingUpdate(groupId, setting);
|
|
1634
|
+
} catch (error) {
|
|
1635
|
+
console.error('Error changing group settings:', error);
|
|
1636
|
+
throw error;
|
|
1637
|
+
}
|
|
1638
|
+
}
|
|
1639
|
+
|
|
1640
|
+
/**
|
|
1641
|
+
* Get the invite code for a group
|
|
1642
|
+
* @param {string} groupId - The group JID
|
|
1643
|
+
* @returns {Promise<string>} The invite code (use with https://chat.whatsapp.com/{code})
|
|
1644
|
+
* @throws {Error} If client is not connected or fetch fails
|
|
1645
|
+
*/
|
|
1646
|
+
async getGroupInviteCode(groupId) {
|
|
1647
|
+
if (!this.isConnected) {
|
|
1648
|
+
throw new Error('Client is not connected');
|
|
1649
|
+
}
|
|
1650
|
+
|
|
1651
|
+
try {
|
|
1652
|
+
const code = await this.sock.groupInviteCode(groupId);
|
|
1653
|
+
return code;
|
|
1654
|
+
} catch (error) {
|
|
1655
|
+
console.error('Error getting group invite code:', error);
|
|
1656
|
+
throw error;
|
|
1657
|
+
}
|
|
1658
|
+
}
|
|
1659
|
+
|
|
1660
|
+
/**
|
|
1661
|
+
* Revoke the current invite code for a group (generates a new one)
|
|
1662
|
+
* @param {string} groupId - The group JID
|
|
1663
|
+
* @returns {Promise<string>} The new invite code
|
|
1664
|
+
* @throws {Error} If client is not connected or revoke fails
|
|
1665
|
+
*/
|
|
1666
|
+
async revokeGroupInviteCode(groupId) {
|
|
1667
|
+
if (!this.isConnected) {
|
|
1668
|
+
throw new Error('Client is not connected');
|
|
1669
|
+
}
|
|
1670
|
+
|
|
1671
|
+
try {
|
|
1672
|
+
const newCode = await this.sock.groupRevokeInvite(groupId);
|
|
1673
|
+
return newCode;
|
|
1674
|
+
} catch (error) {
|
|
1675
|
+
console.error('Error revoking group invite code:', error);
|
|
1676
|
+
throw error;
|
|
1677
|
+
}
|
|
1678
|
+
}
|
|
1679
|
+
|
|
1680
|
+
/**
|
|
1681
|
+
* Leave a group
|
|
1682
|
+
* @param {string} groupId - The group JID
|
|
1683
|
+
* @returns {Promise<void>}
|
|
1684
|
+
* @throws {Error} If client is not connected or leave fails
|
|
1685
|
+
*/
|
|
1686
|
+
async leaveGroup(groupId) {
|
|
1687
|
+
if (!this.isConnected) {
|
|
1688
|
+
throw new Error('Client is not connected');
|
|
1689
|
+
}
|
|
1690
|
+
|
|
1691
|
+
try {
|
|
1692
|
+
await this.sock.groupLeave(groupId);
|
|
1693
|
+
// Clean up the cache for this group
|
|
1694
|
+
this.clearGroupMetadataCache(groupId);
|
|
1695
|
+
} catch (error) {
|
|
1696
|
+
console.error('Error leaving group:', error);
|
|
1697
|
+
throw error;
|
|
1698
|
+
}
|
|
1699
|
+
}
|
|
1700
|
+
|
|
1701
|
+
/**
|
|
1702
|
+
* Join a group using an invitation code
|
|
1703
|
+
* @param {string} inviteCode - The invite code (without https://chat.whatsapp.com/)
|
|
1704
|
+
* @returns {Promise<string>} The group JID that was joined
|
|
1705
|
+
* @throws {Error} If client is not connected or join fails
|
|
1706
|
+
*/
|
|
1707
|
+
async joinGroupByInviteCode(inviteCode) {
|
|
1708
|
+
if (!this.isConnected) {
|
|
1709
|
+
throw new Error('Client is not connected');
|
|
1710
|
+
}
|
|
1711
|
+
|
|
1712
|
+
try {
|
|
1713
|
+
// Strip URL prefix if accidentally included
|
|
1714
|
+
const code = inviteCode.replace('https://chat.whatsapp.com/', '');
|
|
1715
|
+
const response = await this.sock.groupAcceptInvite(code);
|
|
1716
|
+
return response;
|
|
1717
|
+
} catch (error) {
|
|
1718
|
+
console.error('Error joining group by invite code:', error);
|
|
1719
|
+
throw error;
|
|
1720
|
+
}
|
|
1721
|
+
}
|
|
1722
|
+
|
|
1723
|
+
/**
|
|
1724
|
+
* Get group info by invite code (without joining)
|
|
1725
|
+
* @param {string} inviteCode - The invite code (without https://chat.whatsapp.com/)
|
|
1726
|
+
* @returns {Promise<object>} The group information
|
|
1727
|
+
* @throws {Error} If client is not connected or fetch fails
|
|
1728
|
+
*/
|
|
1729
|
+
|
|
1730
|
+
async getGroupInfoByInviteCode(inviteCode) {
|
|
1731
|
+
if (!this.isConnected) {
|
|
1732
|
+
throw new Error('Client is not connected');
|
|
1733
|
+
}
|
|
1734
|
+
|
|
1735
|
+
try {
|
|
1736
|
+
// Strip URL prefix if accidentally included
|
|
1737
|
+
const code = inviteCode.replace('https://chat.whatsapp.com/', '');
|
|
1738
|
+
const response = await this.sock.groupGetInviteInfo(code);
|
|
1739
|
+
return response;
|
|
1740
|
+
} catch (error) {
|
|
1741
|
+
console.error('Error getting group info by invite code:', error);
|
|
1742
|
+
throw error;
|
|
1743
|
+
}
|
|
1744
|
+
}
|
|
1745
|
+
|
|
1746
|
+
/**
|
|
1747
|
+
* Get the list of pending join requests for a group
|
|
1748
|
+
* @param {string} groupId - The group JID
|
|
1749
|
+
* @returns {Promise<Array>} Array of pending join requests
|
|
1750
|
+
* @throws {Error} If client is not connected or fetch fails
|
|
1751
|
+
*/
|
|
1752
|
+
|
|
1753
|
+
async getGroupJoinRequests(groupId) {
|
|
1754
|
+
if (!this.isConnected) {
|
|
1755
|
+
throw new Error('Client is not connected');
|
|
1756
|
+
}
|
|
1757
|
+
|
|
1758
|
+
try {
|
|
1759
|
+
const response = await this.sock.groupRequestParticipantsList(groupId);
|
|
1760
|
+
return response;
|
|
1761
|
+
} catch (error) {
|
|
1762
|
+
console.error('Error getting group join requests:', error);
|
|
1763
|
+
throw error;
|
|
1764
|
+
}
|
|
1765
|
+
}
|
|
1766
|
+
|
|
1767
|
+
/**
|
|
1768
|
+
* Approve or reject group join requests
|
|
1769
|
+
* @param {string} groupId - The group JID
|
|
1770
|
+
* @param {Array<string>} participantIds - Array of participant JIDs to approve/reject
|
|
1771
|
+
* @param {string} action - 'approve' or 'reject'
|
|
1772
|
+
* @returns {Promise<object>} The response from the action
|
|
1773
|
+
* @throws {Error} If client is not connected or action fails
|
|
1774
|
+
*/
|
|
1775
|
+
async handleGroupJoinRequest(groupId, participantIds, action) {
|
|
1776
|
+
if (!this.isConnected) {
|
|
1777
|
+
throw new Error('Client is not connected');
|
|
1778
|
+
}
|
|
1779
|
+
|
|
1780
|
+
const validActions = ['approve', 'reject'];
|
|
1781
|
+
if (!validActions.includes(action)) {
|
|
1782
|
+
throw new Error(`Invalid action: ${action}. Must be one of: ${validActions.join(', ')}`);
|
|
1783
|
+
}
|
|
1784
|
+
|
|
1785
|
+
try {
|
|
1786
|
+
const response = await this.sock.groupRequestParticipantsUpdate(groupId, participantIds, action);
|
|
1787
|
+
return response;
|
|
1788
|
+
} catch (error) {
|
|
1789
|
+
console.error(`Error ${action}ing group join request:`, error);
|
|
1790
|
+
throw error;
|
|
1791
|
+
}
|
|
1792
|
+
}
|
|
1793
|
+
|
|
1794
|
+
/**
|
|
1795
|
+
* Toggle ephemeral (disappearing) messages in a group
|
|
1796
|
+
* @param {string} groupId - The group JID
|
|
1797
|
+
* @param {number} ephemeralExpiration - Duration in seconds (0 = off, 86400 = 24h, 604800 = 7d, 7776000 = 90d)
|
|
1798
|
+
* @returns {Promise<void>}
|
|
1799
|
+
* @throws {Error} If client is not connected or toggle fails
|
|
1800
|
+
*/
|
|
1801
|
+
async toggleGroupEphemeral(groupId, ephemeralExpiration) {
|
|
1802
|
+
if (!this.isConnected) {
|
|
1803
|
+
throw new Error('Client is not connected');
|
|
1804
|
+
}
|
|
1805
|
+
|
|
1806
|
+
try {
|
|
1807
|
+
await this.sock.groupToggleEphemeral(groupId, ephemeralExpiration);
|
|
1808
|
+
} catch (error) {
|
|
1809
|
+
console.error('Error toggling group ephemeral:', error);
|
|
1810
|
+
throw error;
|
|
1811
|
+
}
|
|
1812
|
+
}
|
|
1813
|
+
|
|
1814
|
+
/**
|
|
1815
|
+
* Change who can add members to a group
|
|
1816
|
+
* @param {string} groupId - The group JID
|
|
1817
|
+
* @param {string} mode - 'all_member_add' (all members can add) or 'admin_add' (only admins can add)
|
|
1818
|
+
* @returns {Promise<void>}
|
|
1819
|
+
* @throws {Error} If client is not connected or update fails
|
|
1820
|
+
*/
|
|
1821
|
+
async changeGroupAddMode(groupId, mode) {
|
|
1822
|
+
if (!this.isConnected) {
|
|
1823
|
+
throw new Error('Client is not connected');
|
|
1824
|
+
}
|
|
1825
|
+
|
|
1826
|
+
const validModes = ['all_member_add', 'admin_add'];
|
|
1827
|
+
if (!validModes.includes(mode)) {
|
|
1828
|
+
throw new Error(`Invalid mode: ${mode}. Must be one of: ${validModes.join(', ')}`);
|
|
1829
|
+
}
|
|
1830
|
+
|
|
1831
|
+
try {
|
|
1832
|
+
await this.sock.groupMemberAddMode(groupId, mode);
|
|
1833
|
+
} catch (error) {
|
|
1834
|
+
console.error('Error changing group add mode:', error);
|
|
1835
|
+
throw error;
|
|
1836
|
+
}
|
|
1837
|
+
}
|
|
1838
|
+
|
|
1839
|
+
// ═══════════════════════════════════════════════════════════
|
|
1840
|
+
// 🔒 PRIVACY METHODS
|
|
1841
|
+
// ═══════════════════════════════════════════════════════════
|
|
1842
|
+
|
|
1843
|
+
/**
|
|
1844
|
+
* Block a user
|
|
1845
|
+
* @param {string} jid - The JID of the user to block
|
|
1846
|
+
* @returns {Promise<void>}
|
|
1847
|
+
* @throws {Error} If client is not connected or block fails
|
|
1848
|
+
*/
|
|
1849
|
+
async blockUser(jid) {
|
|
1850
|
+
if (!this.isConnected) {
|
|
1851
|
+
throw new Error('Client is not connected');
|
|
1852
|
+
}
|
|
1853
|
+
|
|
1854
|
+
try {
|
|
1855
|
+
await this.sock.updateBlockStatus(jid, 'block');
|
|
1856
|
+
} catch (error) {
|
|
1857
|
+
console.error('Error blocking user:', error);
|
|
1858
|
+
throw error;
|
|
1859
|
+
}
|
|
1860
|
+
}
|
|
1861
|
+
|
|
1862
|
+
/**
|
|
1863
|
+
* Unblock a user
|
|
1864
|
+
* @param {string} jid - The JID of the user to unblock
|
|
1865
|
+
* @returns {Promise<void>}
|
|
1866
|
+
* @throws {Error} If client is not connected or unblock fails
|
|
1867
|
+
*/
|
|
1868
|
+
async unblockUser(jid) {
|
|
1869
|
+
if (!this.isConnected) {
|
|
1870
|
+
throw new Error('Client is not connected');
|
|
1871
|
+
}
|
|
1872
|
+
|
|
1873
|
+
try {
|
|
1874
|
+
await this.sock.updateBlockStatus(jid, 'unblock');
|
|
1875
|
+
} catch (error) {
|
|
1876
|
+
console.error('Error unblocking user:', error);
|
|
1877
|
+
throw error;
|
|
1878
|
+
}
|
|
1879
|
+
}
|
|
1880
|
+
|
|
1881
|
+
/**
|
|
1882
|
+
* Get current privacy settings
|
|
1883
|
+
* @param {boolean} [forceGet=true] - Whether to force-fetch the latest settings
|
|
1884
|
+
* @returns {Promise<object>} The privacy settings object
|
|
1885
|
+
* @throws {Error} If client is not connected or fetch fails
|
|
1886
|
+
*/
|
|
1887
|
+
async getPrivacySettings(forceGet = true) {
|
|
1888
|
+
if (!this.isConnected) {
|
|
1889
|
+
throw new Error('Client is not connected');
|
|
1890
|
+
}
|
|
1891
|
+
|
|
1892
|
+
try {
|
|
1893
|
+
const settings = await this.sock.fetchPrivacySettings(forceGet);
|
|
1894
|
+
return settings;
|
|
1895
|
+
} catch (error) {
|
|
1896
|
+
console.error('Error fetching privacy settings:', error);
|
|
1897
|
+
throw error;
|
|
1898
|
+
}
|
|
1899
|
+
}
|
|
1900
|
+
|
|
1901
|
+
/**
|
|
1902
|
+
* Get the list of blocked contacts
|
|
1903
|
+
* @returns {Promise<Array<string>>} Array of blocked JIDs
|
|
1904
|
+
* @throws {Error} If client is not connected or fetch fails
|
|
1905
|
+
*/
|
|
1906
|
+
async getBlockList() {
|
|
1907
|
+
if (!this.isConnected) {
|
|
1908
|
+
throw new Error('Client is not connected');
|
|
1909
|
+
}
|
|
1910
|
+
|
|
1911
|
+
try {
|
|
1912
|
+
const blocklist = await this.sock.fetchBlocklist();
|
|
1913
|
+
return blocklist;
|
|
1914
|
+
} catch (error) {
|
|
1915
|
+
console.error('Error fetching block list:', error);
|
|
1916
|
+
throw error;
|
|
1917
|
+
}
|
|
1918
|
+
}
|
|
1919
|
+
|
|
1920
|
+
/**
|
|
1921
|
+
* Update last seen privacy setting
|
|
1922
|
+
* @param {string} value - 'all' | 'contacts' | 'contact_blacklist' | 'none'
|
|
1923
|
+
* @returns {Promise<void>}
|
|
1924
|
+
* @throws {Error} If client is not connected or update fails
|
|
1925
|
+
*/
|
|
1926
|
+
async updateLastSeenPrivacy(value) {
|
|
1927
|
+
if (!this.isConnected) {
|
|
1928
|
+
throw new Error('Client is not connected');
|
|
1929
|
+
}
|
|
1930
|
+
|
|
1931
|
+
try {
|
|
1932
|
+
await this.sock.updateLastSeenPrivacy(value);
|
|
1933
|
+
} catch (error) {
|
|
1934
|
+
console.error('Error updating last seen privacy:', error);
|
|
1935
|
+
throw error;
|
|
1936
|
+
}
|
|
1937
|
+
}
|
|
1938
|
+
|
|
1939
|
+
/**
|
|
1940
|
+
* Update online status privacy setting
|
|
1941
|
+
* @param {string} value - 'all' | 'match_last_seen'
|
|
1942
|
+
* @returns {Promise<void>}
|
|
1943
|
+
* @throws {Error} If client is not connected or update fails
|
|
1944
|
+
*/
|
|
1945
|
+
async updateOnlinePrivacy(value) {
|
|
1946
|
+
if (!this.isConnected) {
|
|
1947
|
+
throw new Error('Client is not connected');
|
|
1948
|
+
}
|
|
1949
|
+
|
|
1950
|
+
try {
|
|
1951
|
+
await this.sock.updateOnlinePrivacy(value);
|
|
1952
|
+
} catch (error) {
|
|
1953
|
+
console.error('Error updating online privacy:', error);
|
|
1954
|
+
throw error;
|
|
1955
|
+
}
|
|
1956
|
+
}
|
|
1957
|
+
|
|
1958
|
+
/**
|
|
1959
|
+
* Update profile picture privacy setting
|
|
1960
|
+
* @param {string} value - 'all' | 'contacts' | 'contact_blacklist' | 'none'
|
|
1961
|
+
* @returns {Promise<void>}
|
|
1962
|
+
* @throws {Error} If client is not connected or update fails
|
|
1963
|
+
*/
|
|
1964
|
+
async updateProfilePicturePrivacy(value) {
|
|
1965
|
+
if (!this.isConnected) {
|
|
1966
|
+
throw new Error('Client is not connected');
|
|
1967
|
+
}
|
|
1968
|
+
|
|
1969
|
+
try {
|
|
1970
|
+
await this.sock.updateProfilePicturePrivacy(value);
|
|
1971
|
+
} catch (error) {
|
|
1972
|
+
console.error('Error updating profile picture privacy:', error);
|
|
1973
|
+
throw error;
|
|
1974
|
+
}
|
|
1975
|
+
}
|
|
1976
|
+
|
|
1977
|
+
/**
|
|
1978
|
+
* Update status privacy setting
|
|
1979
|
+
* @param {string} value - 'all' | 'contacts' | 'contact_blacklist' | 'none'
|
|
1980
|
+
* @returns {Promise<void>}
|
|
1981
|
+
* @throws {Error} If client is not connected or update fails
|
|
1982
|
+
*/
|
|
1983
|
+
async updateStatusPrivacy(value) {
|
|
1984
|
+
if (!this.isConnected) {
|
|
1985
|
+
throw new Error('Client is not connected');
|
|
1986
|
+
}
|
|
1987
|
+
|
|
1988
|
+
try {
|
|
1989
|
+
await this.sock.updateStatusPrivacy(value);
|
|
1990
|
+
} catch (error) {
|
|
1991
|
+
console.error('Error updating status privacy:', error);
|
|
1992
|
+
throw error;
|
|
1993
|
+
}
|
|
1994
|
+
}
|
|
1995
|
+
|
|
1996
|
+
/**
|
|
1997
|
+
* Update read receipts privacy setting
|
|
1998
|
+
* @param {string} value - 'all' | 'none'
|
|
1999
|
+
* @returns {Promise<void>}
|
|
2000
|
+
* @throws {Error} If client is not connected or update fails
|
|
2001
|
+
*/
|
|
2002
|
+
|
|
2003
|
+
async updateReadReceiptsPrivacy(value) {
|
|
2004
|
+
if (!this.isConnected) {
|
|
2005
|
+
throw new Error('Client is not connected');
|
|
2006
|
+
}
|
|
2007
|
+
|
|
2008
|
+
try {
|
|
2009
|
+
await this.sock.updateReadReceiptsPrivacy(value);
|
|
2010
|
+
} catch (error) {
|
|
2011
|
+
console.error('Error updating read receipts privacy:', error);
|
|
2012
|
+
throw error;
|
|
2013
|
+
}
|
|
2014
|
+
}
|
|
2015
|
+
|
|
2016
|
+
/**
|
|
2017
|
+
* Update groups add privacy setting (who can add you to groups)
|
|
2018
|
+
* @param {string} value - 'all' | 'contacts' | 'contact_blacklist'
|
|
2019
|
+
* @returns {Promise<void>}
|
|
2020
|
+
* @throws {Error} If client is not connected or update fails
|
|
2021
|
+
*/
|
|
2022
|
+
|
|
2023
|
+
async updateGroupsAddPrivacy(value) {
|
|
2024
|
+
if (!this.isConnected) {
|
|
2025
|
+
throw new Error('Client is not connected');
|
|
2026
|
+
}
|
|
2027
|
+
try {
|
|
2028
|
+
await this.sock.updateGroupsAddPrivacy(value);
|
|
2029
|
+
} catch (error) {
|
|
2030
|
+
console.error('Error updating groups add privacy:', error);
|
|
2031
|
+
throw error;
|
|
2032
|
+
}
|
|
2033
|
+
}
|
|
2034
|
+
|
|
2035
|
+
/**
|
|
2036
|
+
* Update default disappearing mode for new chats
|
|
2037
|
+
* @param {number} duration - Duration in seconds (0 = off, 86400 = 24h, 604800 = 7d, 7776000 = 90d)
|
|
2038
|
+
* @returns {Promise<void>}
|
|
2039
|
+
* @throws {Error} If client is not connected or update fails
|
|
2040
|
+
*/
|
|
2041
|
+
|
|
2042
|
+
async updateDefaultDisappearingMode(duration) {
|
|
2043
|
+
if (!this.isConnected) {
|
|
2044
|
+
throw new Error('Client is not connected');
|
|
2045
|
+
}
|
|
2046
|
+
try {
|
|
2047
|
+
await this.sock.updateDefaultDisappearingMode(duration);
|
|
2048
|
+
} catch (error) {
|
|
2049
|
+
console.error('Error updating default disappearing mode:', error);
|
|
2050
|
+
throw error;
|
|
2051
|
+
}
|
|
2052
|
+
}
|
|
2053
|
+
|
|
1464
2054
|
/**
|
|
1465
2055
|
* Add EXIF metadata to an existing WebP buffer
|
|
1466
2056
|
* @param {Buffer} buffer - WebP buffer
|