ishumdz-bail 1.0.5 → 1.0.6
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/lib/Pro/chats.js +119 -0
- package/lib/Pro/groups.js +72 -0
- package/lib/Pro/index.js +69 -0
- package/lib/Pro/newsletter.js +363 -0
- package/lib/Pro/polls.js +214 -0
- package/lib/Pro/profile.js +100 -0
- package/lib/Pro/status.js +76 -0
- package/lib/index.js +3 -1
- package/package.json +1 -1
package/lib/Pro/chats.js
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* High-level Pro Messaging & Chat Actions for chama-bailez-pro
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Edit a previously sent message
|
|
7
|
+
* @param {any} sock Baileys socket instance
|
|
8
|
+
* @param {string} jid Target chat JID
|
|
9
|
+
* @param {any} key Key of message to edit
|
|
10
|
+
* @param {string} newText New text content
|
|
11
|
+
*/
|
|
12
|
+
export async function editMessage(sock, jid, key, newText) {
|
|
13
|
+
if (!key) throw new Error('Message key is required to edit');
|
|
14
|
+
return await sock.sendMessage(jid, {
|
|
15
|
+
text: newText,
|
|
16
|
+
edit: key
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Revoke/delete a message
|
|
22
|
+
* @param {any} sock Baileys socket instance
|
|
23
|
+
* @param {string} jid Target chat JID
|
|
24
|
+
* @param {any} key Key of message to delete
|
|
25
|
+
*/
|
|
26
|
+
export async function deleteMessage(sock, jid, key) {
|
|
27
|
+
if (!key) throw new Error('Message key is required to delete');
|
|
28
|
+
return await sock.sendMessage(jid, {
|
|
29
|
+
delete: key
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Pin a message in chat
|
|
35
|
+
* @param {any} sock Baileys socket instance
|
|
36
|
+
* @param {string} jid Target chat JID
|
|
37
|
+
* @param {any} key Key of message to pin
|
|
38
|
+
* @param {number} [durationInSeconds=86400] 86400 (24h), 604800 (7d), or 2592000 (30d)
|
|
39
|
+
*/
|
|
40
|
+
export async function pinMessage(sock, jid, key, durationInSeconds = 86400) {
|
|
41
|
+
if (!key) throw new Error('Message key is required to pin');
|
|
42
|
+
return await sock.sendMessage(jid, {
|
|
43
|
+
pin: key,
|
|
44
|
+
type: 1, // 1 = pin, 2 = unpin
|
|
45
|
+
time: durationInSeconds
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Unpin a message in chat
|
|
51
|
+
* @param {any} sock Baileys socket instance
|
|
52
|
+
* @param {string} jid Target chat JID
|
|
53
|
+
* @param {any} key Key of message to unpin
|
|
54
|
+
*/
|
|
55
|
+
export async function unpinMessage(sock, jid, key) {
|
|
56
|
+
if (!key) throw new Error('Message key is required to unpin');
|
|
57
|
+
return await sock.sendMessage(jid, {
|
|
58
|
+
pin: key,
|
|
59
|
+
type: 2
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Star or unstar a message
|
|
65
|
+
* @param {any} sock Baileys socket instance
|
|
66
|
+
* @param {string} jid Target chat JID
|
|
67
|
+
* @param {any} key Message key
|
|
68
|
+
* @param {boolean} [star=true] True to star, false to unstar
|
|
69
|
+
*/
|
|
70
|
+
export async function starMessage(sock, jid, key, star = true) {
|
|
71
|
+
if (!key?.id) throw new Error('Message key with id is required');
|
|
72
|
+
return await sock.chatModify({
|
|
73
|
+
star: {
|
|
74
|
+
messages: [{ id: key.id, fromMe: key.fromMe || false }],
|
|
75
|
+
star
|
|
76
|
+
}
|
|
77
|
+
}, jid);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* React to a message with an emoji or remove reaction
|
|
82
|
+
* @param {any} sock Baileys socket instance
|
|
83
|
+
* @param {string} jid Target chat JID
|
|
84
|
+
* @param {any} key Key of message to react to
|
|
85
|
+
* @param {string} [emoji=''] Emoji character, or empty string to remove reaction
|
|
86
|
+
*/
|
|
87
|
+
export async function reactMessage(sock, jid, key, emoji = '') {
|
|
88
|
+
if (!key) throw new Error('Message key is required to react');
|
|
89
|
+
return await sock.sendMessage(jid, {
|
|
90
|
+
react: {
|
|
91
|
+
text: emoji,
|
|
92
|
+
key
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Send typing, recording, or online presence
|
|
99
|
+
* @param {any} sock Baileys socket instance
|
|
100
|
+
* @param {string} jid Target chat JID
|
|
101
|
+
* @param {'composing'|'recording'|'paused'|'available'|'unavailable'} [presence='composing']
|
|
102
|
+
*/
|
|
103
|
+
export async function sendPresence(sock, jid, presence = 'composing') {
|
|
104
|
+
if (presence === 'available' || presence === 'unavailable') {
|
|
105
|
+
return await sock.sendPresenceUpdate(presence);
|
|
106
|
+
}
|
|
107
|
+
return await sock.sendPresenceUpdate(presence, jid);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Send instant quoted text reply
|
|
112
|
+
* @param {any} sock Baileys socket instance
|
|
113
|
+
* @param {string} jid Target chat JID
|
|
114
|
+
* @param {string} text Message text
|
|
115
|
+
* @param {any} [quotedMessage] Quoted message object
|
|
116
|
+
*/
|
|
117
|
+
export async function reply(sock, jid, text, quotedMessage = undefined) {
|
|
118
|
+
return await sock.sendMessage(jid, { text }, { quoted: quotedMessage });
|
|
119
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* High-level Pro Group Management API for chama-bailez-pro
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Get group metadata and preview info from invite link/code without joining
|
|
7
|
+
* @param {any} sock Baileys socket instance
|
|
8
|
+
* @param {string} inviteCode Group invite code or full WhatsApp invite URL
|
|
9
|
+
*/
|
|
10
|
+
export async function groupGetInviteInfo(sock, inviteCode) {
|
|
11
|
+
const code = inviteCode.replace(/.*chat\.whatsapp\.com\//, '').trim();
|
|
12
|
+
return await sock.groupGetInviteInfo(code);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Join a group using an invite code or URL
|
|
17
|
+
* @param {any} sock Baileys socket instance
|
|
18
|
+
* @param {string} inviteCode Group invite code or URL
|
|
19
|
+
*/
|
|
20
|
+
export async function groupJoinViaInvite(sock, inviteCode) {
|
|
21
|
+
const code = inviteCode.replace(/.*chat\.whatsapp\.com\//, '').trim();
|
|
22
|
+
return await sock.groupAcceptInvite(code);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Toggle announcement mode (only admins can send messages)
|
|
27
|
+
* @param {any} sock Baileys socket instance
|
|
28
|
+
* @param {string} jid Group JID
|
|
29
|
+
* @param {boolean} [onlyAdminsCanSend=true]
|
|
30
|
+
*/
|
|
31
|
+
export async function groupSetAnnouncement(sock, jid, onlyAdminsCanSend = true) {
|
|
32
|
+
return await sock.groupSettingUpdate(jid, onlyAdminsCanSend ? 'announcement' : 'not_announcement');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Toggle locked mode (only admins can modify group icon/description/name)
|
|
37
|
+
* @param {any} sock Baileys socket instance
|
|
38
|
+
* @param {string} jid Group JID
|
|
39
|
+
* @param {boolean} [onlyAdminsCanEdit=true]
|
|
40
|
+
*/
|
|
41
|
+
export async function groupSetLocked(sock, jid, onlyAdminsCanEdit = true) {
|
|
42
|
+
return await sock.groupSettingUpdate(jid, onlyAdminsCanEdit ? 'locked' : 'unlocked');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* List pending membership approval requests in a group
|
|
47
|
+
* @param {any} sock Baileys socket instance
|
|
48
|
+
* @param {string} jid Group JID
|
|
49
|
+
*/
|
|
50
|
+
export async function groupRequestParticipantsList(sock, jid) {
|
|
51
|
+
return await sock.groupRequestParticipantsList(jid);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Approve pending join requests
|
|
56
|
+
* @param {any} sock Baileys socket instance
|
|
57
|
+
* @param {string} jid Group JID
|
|
58
|
+
* @param {string[]} participants Array of participant JIDs to approve
|
|
59
|
+
*/
|
|
60
|
+
export async function groupApproveParticipants(sock, jid, participants) {
|
|
61
|
+
return await sock.groupRequestParticipantsUpdate(jid, participants, 'approve');
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Reject pending join requests
|
|
66
|
+
* @param {any} sock Baileys socket instance
|
|
67
|
+
* @param {string} jid Group JID
|
|
68
|
+
* @param {string[]} participants Array of participant JIDs to reject
|
|
69
|
+
*/
|
|
70
|
+
export async function groupRejectParticipants(sock, jid, participants) {
|
|
71
|
+
return await sock.groupRequestParticipantsUpdate(jid, participants, 'reject');
|
|
72
|
+
}
|
package/lib/Pro/index.js
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import * as PollsPro from './polls.js';
|
|
2
|
+
import * as NewsletterPro from './newsletter.js';
|
|
3
|
+
import * as StatusPro from './status.js';
|
|
4
|
+
import * as ChatsPro from './chats.js';
|
|
5
|
+
import * as GroupsPro from './groups.js';
|
|
6
|
+
import * as ProfilePro from './profile.js';
|
|
7
|
+
|
|
8
|
+
export * from './polls.js';
|
|
9
|
+
export * from './newsletter.js';
|
|
10
|
+
export * from './status.js';
|
|
11
|
+
export * from './chats.js';
|
|
12
|
+
export * from './groups.js';
|
|
13
|
+
export * from './profile.js';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Attaches all high-level Pro features directly onto the Baileys socket instance
|
|
17
|
+
* @param {any} sock The Baileys socket instance
|
|
18
|
+
*/
|
|
19
|
+
export function attachProMethods(sock) {
|
|
20
|
+
if (!sock) return sock;
|
|
21
|
+
|
|
22
|
+
// --- 📊 Polls Pro ---
|
|
23
|
+
sock.sendPoll = (jid, pollData) => PollsPro.sendPoll(sock, jid, pollData);
|
|
24
|
+
sock.sendPollVote = (jid, pollKeyOrMsg, selectedOptions) => PollsPro.sendPollVote(sock, jid, pollKeyOrMsg, selectedOptions);
|
|
25
|
+
sock.getAggregatePollVotes = (pollMsg) => PollsPro.getAggregatePollVotes(sock, pollMsg);
|
|
26
|
+
|
|
27
|
+
// --- 📢 Newsletter & Channels Pro ---
|
|
28
|
+
sock.channelVote = (target, option, serverId) => NewsletterPro.channelVote(sock, target, option, serverId);
|
|
29
|
+
sock.newsletterVoteMessage = (jid, serverId, option) => NewsletterPro.newsletterVoteMessage(sock, jid, serverId, option);
|
|
30
|
+
sock.newsletterReact = (jid, serverId, reaction) => NewsletterPro.newsletterReact(sock, jid, serverId, reaction);
|
|
31
|
+
sock.newsletterGetMessages = (jid, count, since, after) => NewsletterPro.newsletterGetMessages(sock, jid, count, since, after);
|
|
32
|
+
sock.newsletterSearch = (query) => NewsletterPro.newsletterSearch(sock, query);
|
|
33
|
+
sock.newsletterList = () => NewsletterPro.newsletterList(sock);
|
|
34
|
+
|
|
35
|
+
// --- 🟢 Status / Stories Pro ---
|
|
36
|
+
sock.sendStatusText = (text, options) => StatusPro.sendStatusText(sock, text, options);
|
|
37
|
+
sock.sendStatusMedia = (media, options) => StatusPro.sendStatusMedia(sock, media, options);
|
|
38
|
+
sock.readStatus = (key) => StatusPro.readStatus(sock, key);
|
|
39
|
+
sock.reactStatus = (key, emoji) => StatusPro.reactStatus(sock, key, emoji);
|
|
40
|
+
|
|
41
|
+
// --- 💬 Messaging & Chats Pro ---
|
|
42
|
+
sock.editMessage = (jid, key, newText) => ChatsPro.editMessage(sock, jid, key, newText);
|
|
43
|
+
sock.deleteMessage = (jid, key) => ChatsPro.deleteMessage(sock, jid, key);
|
|
44
|
+
sock.pinMessage = (jid, key, durationInSeconds) => ChatsPro.pinMessage(sock, jid, key, durationInSeconds);
|
|
45
|
+
sock.unpinMessage = (jid, key) => ChatsPro.unpinMessage(sock, jid, key);
|
|
46
|
+
sock.starMessage = (jid, key, star) => ChatsPro.starMessage(sock, jid, key, star);
|
|
47
|
+
sock.reactMessage = (jid, key, emoji) => ChatsPro.reactMessage(sock, jid, key, emoji);
|
|
48
|
+
sock.sendPresence = (jid, presence) => ChatsPro.sendPresence(sock, jid, presence);
|
|
49
|
+
sock.reply = (jid, text, quotedMessage) => ChatsPro.reply(sock, jid, text, quotedMessage);
|
|
50
|
+
|
|
51
|
+
// --- 👥 Group Management Pro ---
|
|
52
|
+
sock.groupGetInviteInfo = (code) => GroupsPro.groupGetInviteInfo(sock, code);
|
|
53
|
+
sock.groupJoinViaInvite = (code) => GroupsPro.groupJoinViaInvite(sock, code);
|
|
54
|
+
sock.groupSetAnnouncement = (jid, onlyAdminsCanSend) => GroupsPro.groupSetAnnouncement(sock, jid, onlyAdminsCanSend);
|
|
55
|
+
sock.groupSetLocked = (jid, onlyAdminsCanEdit) => GroupsPro.groupSetLocked(sock, jid, onlyAdminsCanEdit);
|
|
56
|
+
sock.groupRequestParticipantsList = (jid) => GroupsPro.groupRequestParticipantsList(sock, jid);
|
|
57
|
+
sock.groupApproveParticipants = (jid, participants) => GroupsPro.groupApproveParticipants(sock, jid, participants);
|
|
58
|
+
sock.groupRejectParticipants = (jid, participants) => GroupsPro.groupRejectParticipants(sock, jid, participants);
|
|
59
|
+
|
|
60
|
+
// --- 👤 Profile, Contacts & Calls Pro ---
|
|
61
|
+
sock.checkNumber = (phoneNumber) => ProfilePro.checkNumber(sock, phoneNumber);
|
|
62
|
+
sock.setBio = (text) => ProfilePro.setBio(sock, text);
|
|
63
|
+
sock.updateProfileName = (name) => ProfilePro.updateProfileName(sock, name);
|
|
64
|
+
sock.setProfilePicture = (jid, content) => ProfilePro.setProfilePicture(sock, jid, content);
|
|
65
|
+
sock.removeProfilePicture = (jid) => ProfilePro.removeProfilePicture(sock, jid);
|
|
66
|
+
sock.rejectCall = (callId, callFrom) => ProfilePro.rejectCall(sock, callId, callFrom);
|
|
67
|
+
|
|
68
|
+
return sock;
|
|
69
|
+
}
|
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
import crypto from 'crypto';
|
|
2
|
+
import { proto } from '../../WAProto/index.js';
|
|
3
|
+
import { getBinaryNodeChild, getBinaryNodeChildren } from '../WABinary/index.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* High-level Pro Newsletter (WhatsApp Channel) API for chama-bailez-pro
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Cast a vote on a WhatsApp channel poll
|
|
11
|
+
* @param {any} sock Baileys socket instance
|
|
12
|
+
* @param {string} jid Newsletter JID (e.g. 120363427108046852@newsletter)
|
|
13
|
+
* @param {string|number} serverId Server ID of the poll message
|
|
14
|
+
* @param {string} option Option text to vote for
|
|
15
|
+
*/
|
|
16
|
+
export async function newsletterVoteMessage(sock, jid, serverId, option) {
|
|
17
|
+
const sId = serverId.toString();
|
|
18
|
+
const optionText = option || 'TEST';
|
|
19
|
+
const optionHash = crypto.createHash('sha256').update(optionText).digest();
|
|
20
|
+
const optionHashHex = optionHash.toString('hex');
|
|
21
|
+
|
|
22
|
+
const channelPollUpdateMsg = {
|
|
23
|
+
pollUpdateMessage: {
|
|
24
|
+
pollCreationMessageKey: {
|
|
25
|
+
remoteJid: jid,
|
|
26
|
+
id: sId,
|
|
27
|
+
fromMe: false
|
|
28
|
+
},
|
|
29
|
+
senderTimestampMs: Date.now()
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const relayResult = await sock.relayMessage(jid, channelPollUpdateMsg, {
|
|
34
|
+
additionalAttributes: {
|
|
35
|
+
server_id: sId
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
await sock.query({
|
|
41
|
+
tag: 'message',
|
|
42
|
+
attrs: {
|
|
43
|
+
to: jid,
|
|
44
|
+
type: 'poll',
|
|
45
|
+
server_id: sId,
|
|
46
|
+
id: sock.generateMessageTag()
|
|
47
|
+
},
|
|
48
|
+
content: [
|
|
49
|
+
{
|
|
50
|
+
tag: 'poll_vote',
|
|
51
|
+
attrs: {
|
|
52
|
+
option: optionHashHex
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
]
|
|
56
|
+
}).catch(() => {});
|
|
57
|
+
} catch (e) {}
|
|
58
|
+
|
|
59
|
+
return {
|
|
60
|
+
success: true,
|
|
61
|
+
channelJid: jid,
|
|
62
|
+
serverId: sId,
|
|
63
|
+
option: optionText,
|
|
64
|
+
optionHashHex,
|
|
65
|
+
relayResult
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* React to a channel post or remove reaction
|
|
71
|
+
* @param {any} sock Baileys socket instance
|
|
72
|
+
* @param {string} jid Newsletter JID
|
|
73
|
+
* @param {string|number} serverId Server ID of message
|
|
74
|
+
* @param {string} [reaction] Emoji string to react, or empty string to remove reaction
|
|
75
|
+
*/
|
|
76
|
+
export async function newsletterReact(sock, jid, serverId, reaction = '') {
|
|
77
|
+
return await sock.newsletterReactMessage(jid, serverId.toString(), reaction);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Fetch and decode clean messages from a WhatsApp Channel
|
|
82
|
+
* @param {any} sock Baileys socket instance
|
|
83
|
+
* @param {string} jid Newsletter JID
|
|
84
|
+
* @param {number} [count=20] Number of messages to retrieve
|
|
85
|
+
* @param {number} [since] Optional timestamp filter
|
|
86
|
+
* @param {number} [after] Optional serverId filter (fetch after serverId)
|
|
87
|
+
*/
|
|
88
|
+
export async function newsletterGetMessages(sock, jid, count = 20, since = undefined, after = undefined) {
|
|
89
|
+
const rawUpdates = await sock.newsletterFetchMessages(jid, count, since, after);
|
|
90
|
+
const updatesNode = getBinaryNodeChild(rawUpdates, 'message_updates');
|
|
91
|
+
const messageContainers = getBinaryNodeChildren(updatesNode, 'messages');
|
|
92
|
+
|
|
93
|
+
const result = [];
|
|
94
|
+
if (!messageContainers) return result;
|
|
95
|
+
|
|
96
|
+
for (const container of messageContainers) {
|
|
97
|
+
const msgNodes = getBinaryNodeChildren(container, 'message');
|
|
98
|
+
for (const m of msgNodes) {
|
|
99
|
+
const serverId = m.attrs?.server_id;
|
|
100
|
+
const messageId = m.attrs?.id;
|
|
101
|
+
const timestamp = m.attrs?.time ? parseInt(m.attrs.time, 10) : null;
|
|
102
|
+
|
|
103
|
+
// Extract views and reactions
|
|
104
|
+
const viewsNode = getBinaryNodeChild(m, 'views_count');
|
|
105
|
+
const viewsCount = viewsNode?.attrs?.count ? parseInt(viewsNode.attrs.count, 10) : 0;
|
|
106
|
+
|
|
107
|
+
const reactionsNode = getBinaryNodeChild(m, 'reactions');
|
|
108
|
+
const reactions = [];
|
|
109
|
+
if (reactionsNode) {
|
|
110
|
+
const reactionList = getBinaryNodeChildren(reactionsNode, 'reaction');
|
|
111
|
+
for (const r of reactionList) {
|
|
112
|
+
reactions.push({
|
|
113
|
+
emoji: r.attrs?.code,
|
|
114
|
+
count: parseInt(r.attrs?.count || '0', 10)
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Extract poll votes
|
|
120
|
+
const votesNode = getBinaryNodeChild(m, 'votes');
|
|
121
|
+
const pollVotes = [];
|
|
122
|
+
if (votesNode) {
|
|
123
|
+
const voteList = getBinaryNodeChildren(votesNode, 'vote');
|
|
124
|
+
for (const v of voteList) {
|
|
125
|
+
const hashBuffer = v.content;
|
|
126
|
+
pollVotes.push({
|
|
127
|
+
count: parseInt(v.attrs?.count || '0', 10),
|
|
128
|
+
optionHash: Buffer.isBuffer(hashBuffer) ? hashBuffer.toString('hex') : null
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Extract protobuf message if available
|
|
134
|
+
const pTextNode = getBinaryNodeChild(m, 'plaintext');
|
|
135
|
+
let decodedMessage = null;
|
|
136
|
+
let text = null;
|
|
137
|
+
let mediaType = null;
|
|
138
|
+
let poll = null;
|
|
139
|
+
|
|
140
|
+
if (pTextNode && pTextNode.content) {
|
|
141
|
+
try {
|
|
142
|
+
decodedMessage = proto.Message.decode(pTextNode.content);
|
|
143
|
+
text = decodedMessage.conversation ||
|
|
144
|
+
decodedMessage.extendedTextMessage?.text ||
|
|
145
|
+
decodedMessage.imageMessage?.caption ||
|
|
146
|
+
decodedMessage.videoMessage?.caption;
|
|
147
|
+
|
|
148
|
+
if (decodedMessage.imageMessage) mediaType = 'image';
|
|
149
|
+
else if (decodedMessage.videoMessage) mediaType = 'video';
|
|
150
|
+
else if (decodedMessage.audioMessage) mediaType = 'audio';
|
|
151
|
+
else if (decodedMessage.documentMessage) mediaType = 'document';
|
|
152
|
+
|
|
153
|
+
const pollMsg = decodedMessage.pollCreationMessage ||
|
|
154
|
+
decodedMessage.pollCreationMessageV2 ||
|
|
155
|
+
decodedMessage.pollCreationMessageV3;
|
|
156
|
+
|
|
157
|
+
if (pollMsg) {
|
|
158
|
+
mediaType = 'poll';
|
|
159
|
+
poll = {
|
|
160
|
+
name: pollMsg.name,
|
|
161
|
+
options: (pollMsg.options || []).map(o => ({
|
|
162
|
+
name: o.optionName,
|
|
163
|
+
hash: crypto.createHash('sha256').update(o.optionName || '').digest('hex')
|
|
164
|
+
})),
|
|
165
|
+
selectableCount: pollMsg.selectableOptionsCount || 1,
|
|
166
|
+
votes: pollVotes
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
} catch (e) {}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
result.push({
|
|
173
|
+
serverId,
|
|
174
|
+
messageId,
|
|
175
|
+
timestamp,
|
|
176
|
+
mediaType: mediaType || (pollVotes.length > 0 ? 'poll' : 'text'),
|
|
177
|
+
text,
|
|
178
|
+
poll,
|
|
179
|
+
viewsCount,
|
|
180
|
+
reactions,
|
|
181
|
+
rawProto: decodedMessage
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return result;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Search public WhatsApp Channels via directory
|
|
191
|
+
* @param {any} sock Baileys socket instance
|
|
192
|
+
* @param {string} query Search keyword
|
|
193
|
+
*/
|
|
194
|
+
export async function newsletterSearch(sock, query) {
|
|
195
|
+
if (!query) throw new Error('Search query is required');
|
|
196
|
+
const result = await sock.query({
|
|
197
|
+
tag: 'iq',
|
|
198
|
+
attrs: {
|
|
199
|
+
id: sock.generateMessageTag(),
|
|
200
|
+
type: 'get',
|
|
201
|
+
xmlns: 'newsletter',
|
|
202
|
+
to: 's.whatsapp.net'
|
|
203
|
+
},
|
|
204
|
+
content: [
|
|
205
|
+
{
|
|
206
|
+
tag: 'search',
|
|
207
|
+
attrs: { query }
|
|
208
|
+
}
|
|
209
|
+
]
|
|
210
|
+
}).catch(async () => {
|
|
211
|
+
// Fallback to metadata lookup if query is an invite code
|
|
212
|
+
return await sock.newsletterMetadata('invite', query);
|
|
213
|
+
});
|
|
214
|
+
return result;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Fetch list of followed / joined newsletters
|
|
219
|
+
* @param {any} sock Baileys socket instance
|
|
220
|
+
*/
|
|
221
|
+
export async function newsletterList(sock) {
|
|
222
|
+
try {
|
|
223
|
+
const result = await sock.query({
|
|
224
|
+
tag: 'iq',
|
|
225
|
+
attrs: {
|
|
226
|
+
id: sock.generateMessageTag(),
|
|
227
|
+
type: 'get',
|
|
228
|
+
xmlns: 'newsletter',
|
|
229
|
+
to: 's.whatsapp.net'
|
|
230
|
+
},
|
|
231
|
+
content: [{ tag: 'subscribed', attrs: {} }]
|
|
232
|
+
});
|
|
233
|
+
return result;
|
|
234
|
+
} catch (e) {
|
|
235
|
+
return [];
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Smart Channel (Newsletter) Poll Vote
|
|
241
|
+
* Automatically resolves channel links, quoted messages, message IDs, and option indexes.
|
|
242
|
+
*
|
|
243
|
+
* @param {any} sock Baileys socket instance
|
|
244
|
+
* @param {string|object} target Channel URL, JID, or quoted message/contextInfo
|
|
245
|
+
* @param {string|number} option Option text or 1-based index (e.g. 1, 2)
|
|
246
|
+
* @param {string|number} [explicitServerId] Optional explicit message server ID
|
|
247
|
+
*/
|
|
248
|
+
export async function channelVote(sock, target, option, explicitServerId = null) {
|
|
249
|
+
if (!sock) throw new Error('Socket instance is required');
|
|
250
|
+
if (!target) throw new Error('Target (link, JID, or quoted message) is required');
|
|
251
|
+
if (option === undefined || option === null || option === '') {
|
|
252
|
+
throw new Error('Option or option number to vote for is required');
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
let jid = null;
|
|
256
|
+
let serverId = explicitServerId ? explicitServerId.toString() : null;
|
|
257
|
+
let pollOptions = null;
|
|
258
|
+
|
|
259
|
+
// Case 1: Target is an object (quoted message or contextInfo)
|
|
260
|
+
if (typeof target === 'object') {
|
|
261
|
+
const ctx = target.extendedTextMessage?.contextInfo || target.contextInfo || target;
|
|
262
|
+
|
|
263
|
+
// Try to get newsletter JID
|
|
264
|
+
if (ctx.forwardedNewsletterMessageInfo?.newsletterJid) {
|
|
265
|
+
jid = ctx.forwardedNewsletterMessageInfo.newsletterJid;
|
|
266
|
+
if (ctx.forwardedNewsletterMessageInfo.serverMessageId) {
|
|
267
|
+
serverId = ctx.forwardedNewsletterMessageInfo.serverMessageId.toString();
|
|
268
|
+
}
|
|
269
|
+
} else if (ctx.remoteJid?.endsWith('@newsletter')) {
|
|
270
|
+
jid = ctx.remoteJid;
|
|
271
|
+
} else if (ctx.participant?.endsWith('@newsletter')) {
|
|
272
|
+
jid = ctx.participant;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
if (!serverId && (ctx.stanzaId || ctx.server_id || ctx.serverId)) {
|
|
276
|
+
serverId = (ctx.server_id || ctx.serverId || ctx.stanzaId).toString();
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// Try to extract poll options from quoted message
|
|
280
|
+
const qm = ctx.quotedMessage || target.message;
|
|
281
|
+
const pollMsg = qm?.pollCreationMessage || qm?.pollCreationMessageV2 || qm?.pollCreationMessageV3;
|
|
282
|
+
if (pollMsg?.options?.length) {
|
|
283
|
+
pollOptions = pollMsg.options.map((o) => o.optionName);
|
|
284
|
+
}
|
|
285
|
+
} else if (typeof target === 'string') {
|
|
286
|
+
const trimmed = target.trim();
|
|
287
|
+
// Check for WhatsApp Channel link (e.g. https://whatsapp.com/channel/0029Va84sN7J93wUd3cWwX2c/123)
|
|
288
|
+
const channelLinkMatch = trimmed.match(/whatsapp\.com\/channel\/([a-zA-Z0-9_-]+)(?:\/(\d+))?/i);
|
|
289
|
+
if (channelLinkMatch) {
|
|
290
|
+
const inviteCode = channelLinkMatch[1];
|
|
291
|
+
const urlServerId = channelLinkMatch[2];
|
|
292
|
+
if (urlServerId) serverId = urlServerId;
|
|
293
|
+
|
|
294
|
+
// Resolve invite code to newsletter metadata
|
|
295
|
+
try {
|
|
296
|
+
const meta = await sock.newsletterMetadata('invite', inviteCode);
|
|
297
|
+
jid = meta?.id || meta?.jid;
|
|
298
|
+
} catch (err) {
|
|
299
|
+
throw new Error(`Could not resolve channel invite "${inviteCode}": ${err.message}`);
|
|
300
|
+
}
|
|
301
|
+
} else if (trimmed.endsWith('@newsletter')) {
|
|
302
|
+
jid = trimmed;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
if (!jid) {
|
|
307
|
+
throw new Error('Could not determine Channel (Newsletter) JID from target.');
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// If serverId or pollOptions is missing, attempt to fetch recent messages to locate the poll
|
|
311
|
+
if (!serverId || !pollOptions) {
|
|
312
|
+
try {
|
|
313
|
+
const recent = await newsletterGetMessages(sock, jid, 25);
|
|
314
|
+
const targetPoll = serverId
|
|
315
|
+
? recent.find((m) => m.serverId?.toString() === serverId && (m.mediaType === 'poll' || m.poll)) ||
|
|
316
|
+
recent.find((m) => m.serverId?.toString() === serverId)
|
|
317
|
+
: recent.find((m) => m.mediaType === 'poll' || m.poll);
|
|
318
|
+
if (targetPoll) {
|
|
319
|
+
if (!serverId) serverId = targetPoll.serverId?.toString();
|
|
320
|
+
if (targetPoll.poll?.options?.length) {
|
|
321
|
+
pollOptions = targetPoll.poll.options.map((o) => o.name);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
} catch {}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
if (!serverId) {
|
|
328
|
+
throw new Error('Could not find poll message server ID in this channel.');
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// Map numeric index (1, 2...), single letter (A, B, C...), or match case-insensitively
|
|
332
|
+
let selectedOptionText = String(option).trim();
|
|
333
|
+
if (pollOptions && pollOptions.length > 0) {
|
|
334
|
+
if (/^\d+$/.test(selectedOptionText)) {
|
|
335
|
+
const idx = parseInt(selectedOptionText, 10) - 1;
|
|
336
|
+
if (idx >= 0 && idx < pollOptions.length) {
|
|
337
|
+
selectedOptionText = pollOptions[idx];
|
|
338
|
+
}
|
|
339
|
+
} else if (/^[a-zA-Z]$/.test(selectedOptionText)) {
|
|
340
|
+
const letterIdx = selectedOptionText.toUpperCase().charCodeAt(0) - 65;
|
|
341
|
+
const exactLetterMatch = pollOptions.find((o) => o.trim().toUpperCase() === selectedOptionText.toUpperCase());
|
|
342
|
+
if (exactLetterMatch) {
|
|
343
|
+
selectedOptionText = exactLetterMatch;
|
|
344
|
+
} else if (letterIdx >= 0 && letterIdx < pollOptions.length) {
|
|
345
|
+
selectedOptionText = pollOptions[letterIdx];
|
|
346
|
+
}
|
|
347
|
+
} else {
|
|
348
|
+
const matched = pollOptions.find((o) => o.toLowerCase() === selectedOptionText.toLowerCase());
|
|
349
|
+
if (matched) selectedOptionText = matched;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// Cast the vote
|
|
354
|
+
const voteResult = await newsletterVoteMessage(sock, jid, serverId, selectedOptionText);
|
|
355
|
+
return {
|
|
356
|
+
...voteResult,
|
|
357
|
+
channelJid: jid,
|
|
358
|
+
serverId,
|
|
359
|
+
selectedOption: selectedOptionText,
|
|
360
|
+
option: selectedOptionText
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
|
package/lib/Pro/polls.js
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import crypto from 'crypto';
|
|
2
|
+
import { proto } from '../../WAProto/index.js';
|
|
3
|
+
import { getAggregateVotesInPollMessage } from '../Utils/messages.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* High-level Pro Polls API for chama-bailez-pro
|
|
7
|
+
* Supports creating polls and voting in both E2EE chats/groups and WhatsApp Channels (Newsletters).
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Send a poll to a user, group, or channel
|
|
12
|
+
* @param {any} sock Baileys socket instance
|
|
13
|
+
* @param {string} jid Target chat, group, or channel JID
|
|
14
|
+
* @param {{ name: string, values: string[], selectableCount?: number, toNewsletter?: boolean }} pollData
|
|
15
|
+
*/
|
|
16
|
+
export async function sendPoll(sock, jid, pollData) {
|
|
17
|
+
if (!pollData || !pollData.name || !Array.isArray(pollData.values) || pollData.values.length < 2) {
|
|
18
|
+
throw new Error('Poll requires a name (question) and at least 2 option values.');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const selectableCount = pollData.selectableCount || 1;
|
|
22
|
+
|
|
23
|
+
// Direct channel poll formatting
|
|
24
|
+
if (jid.endsWith('@newsletter') || pollData.toNewsletter) {
|
|
25
|
+
const options = pollData.values.map(val => ({ optionName: val }));
|
|
26
|
+
return await sock.sendMessage(jid, {
|
|
27
|
+
poll: {
|
|
28
|
+
name: pollData.name,
|
|
29
|
+
values: pollData.values,
|
|
30
|
+
selectableCount
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Standard individual or group chat poll
|
|
36
|
+
return await sock.sendMessage(jid, {
|
|
37
|
+
poll: {
|
|
38
|
+
name: pollData.name,
|
|
39
|
+
values: pollData.values,
|
|
40
|
+
selectableCount
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Programmatically cast a vote on a poll
|
|
47
|
+
* @param {any} sock Baileys socket instance
|
|
48
|
+
* @param {string} jid Target chat, group, or channel JID
|
|
49
|
+
* @param {any} pollKeyOrMsg Poll creation message key or message object or serverId
|
|
50
|
+
* @param {string[]|string} selectedOptions Array of option strings or single option string
|
|
51
|
+
*/
|
|
52
|
+
export async function sendPollVote(sock, jid, pollKeyOrMsg, selectedOptions) {
|
|
53
|
+
const optionsArray = Array.isArray(selectedOptions) ? selectedOptions : [selectedOptions];
|
|
54
|
+
if (!optionsArray.length) {
|
|
55
|
+
throw new Error('Must specify at least one option to vote for.');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// 1. Channel (Newsletter) Poll Vote
|
|
59
|
+
if (jid.endsWith('@newsletter')) {
|
|
60
|
+
let serverId = null;
|
|
61
|
+
if (typeof pollKeyOrMsg === 'string' || typeof pollKeyOrMsg === 'number') {
|
|
62
|
+
serverId = pollKeyOrMsg.toString();
|
|
63
|
+
} else if (pollKeyOrMsg?.server_id || pollKeyOrMsg?.newsletterServerId || pollKeyOrMsg?.serverId) {
|
|
64
|
+
serverId = (pollKeyOrMsg.server_id || pollKeyOrMsg.newsletterServerId || pollKeyOrMsg.serverId).toString();
|
|
65
|
+
} else if (pollKeyOrMsg?.key?.server_id || pollKeyOrMsg?.key?.id) {
|
|
66
|
+
serverId = (pollKeyOrMsg.key.server_id || pollKeyOrMsg.key.id).toString();
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (!serverId) {
|
|
70
|
+
throw new Error('Server ID is required to vote on a newsletter poll.');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const primaryOption = optionsArray[0];
|
|
74
|
+
const optionHash = crypto.createHash('sha256').update(primaryOption).digest();
|
|
75
|
+
const optionHashHex = optionHash.toString('hex');
|
|
76
|
+
|
|
77
|
+
// Relay channel poll update message
|
|
78
|
+
const channelPollUpdateMsg = {
|
|
79
|
+
pollUpdateMessage: {
|
|
80
|
+
pollCreationMessageKey: {
|
|
81
|
+
remoteJid: jid,
|
|
82
|
+
id: serverId,
|
|
83
|
+
fromMe: false
|
|
84
|
+
},
|
|
85
|
+
senderTimestampMs: Date.now()
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const relayResult = await sock.relayMessage(jid, channelPollUpdateMsg, {
|
|
90
|
+
additionalAttributes: {
|
|
91
|
+
server_id: serverId
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
// Also query standard stanza
|
|
96
|
+
try {
|
|
97
|
+
await sock.query({
|
|
98
|
+
tag: 'message',
|
|
99
|
+
attrs: {
|
|
100
|
+
to: jid,
|
|
101
|
+
type: 'poll',
|
|
102
|
+
server_id: serverId,
|
|
103
|
+
id: sock.generateMessageTag()
|
|
104
|
+
},
|
|
105
|
+
content: [
|
|
106
|
+
{
|
|
107
|
+
tag: 'poll_vote',
|
|
108
|
+
attrs: {
|
|
109
|
+
option: optionHashHex
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
]
|
|
113
|
+
}).catch(() => {});
|
|
114
|
+
} catch (e) {}
|
|
115
|
+
|
|
116
|
+
return {
|
|
117
|
+
success: true,
|
|
118
|
+
type: 'newsletter',
|
|
119
|
+
serverId,
|
|
120
|
+
option: primaryOption,
|
|
121
|
+
optionHashHex,
|
|
122
|
+
relayResult
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// 2. Standard E2EE Chat / Group Poll Vote
|
|
127
|
+
let pollCreation = null;
|
|
128
|
+
let pollMsgId = null;
|
|
129
|
+
let pollCreatorJid = null;
|
|
130
|
+
let fromMe = false;
|
|
131
|
+
|
|
132
|
+
if (pollKeyOrMsg?.message) {
|
|
133
|
+
// Full message passed
|
|
134
|
+
pollCreation = pollKeyOrMsg.message.pollCreationMessage ||
|
|
135
|
+
pollKeyOrMsg.message.pollCreationMessageV2 ||
|
|
136
|
+
pollKeyOrMsg.message.pollCreationMessageV3;
|
|
137
|
+
pollMsgId = pollKeyOrMsg.key?.id;
|
|
138
|
+
pollCreatorJid = pollKeyOrMsg.key?.participant || pollKeyOrMsg.key?.remoteJid;
|
|
139
|
+
fromMe = pollKeyOrMsg.key?.fromMe || false;
|
|
140
|
+
} else if (pollKeyOrMsg?.id) {
|
|
141
|
+
// Message key passed
|
|
142
|
+
pollMsgId = pollKeyOrMsg.id;
|
|
143
|
+
pollCreatorJid = pollKeyOrMsg.participant || pollKeyOrMsg.remoteJid;
|
|
144
|
+
fromMe = pollKeyOrMsg.fromMe || false;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (!pollMsgId) {
|
|
148
|
+
throw new Error('Invalid poll key or message provided. Could not determine poll message ID.');
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const voterJid = sock.user?.id?.split(':')[0] + '@s.whatsapp.net';
|
|
152
|
+
const selectedOptionHashes = optionsArray.map(opt => crypto.createHash('sha256').update(opt).digest());
|
|
153
|
+
|
|
154
|
+
let encPayload = null;
|
|
155
|
+
let encIv = null;
|
|
156
|
+
|
|
157
|
+
if (pollCreation && pollCreation.encKey) {
|
|
158
|
+
const sign = Buffer.concat([
|
|
159
|
+
Buffer.from(pollMsgId),
|
|
160
|
+
Buffer.from(pollCreatorJid || jid),
|
|
161
|
+
Buffer.from(voterJid),
|
|
162
|
+
Buffer.from('Poll Vote'),
|
|
163
|
+
new Uint8Array([1])
|
|
164
|
+
]);
|
|
165
|
+
const key0 = crypto.createHmac('sha256', new Uint8Array(32)).update(pollCreation.encKey).digest();
|
|
166
|
+
const encKey = crypto.createHmac('sha256', key0).update(sign).digest();
|
|
167
|
+
const aad = Buffer.from(`${pollMsgId}\u0000${voterJid}`);
|
|
168
|
+
encIv = crypto.randomBytes(12);
|
|
169
|
+
|
|
170
|
+
const voteMsgBytes = proto.Message.PollVoteMessage.encode({
|
|
171
|
+
selectedOptions: selectedOptionHashes
|
|
172
|
+
}).finish();
|
|
173
|
+
|
|
174
|
+
const cipher = crypto.createCipheriv('aes-256-gcm', encKey, encIv);
|
|
175
|
+
cipher.setAAD(aad);
|
|
176
|
+
const ct = cipher.update(voteMsgBytes);
|
|
177
|
+
const final = cipher.final();
|
|
178
|
+
const tag = cipher.getAuthTag();
|
|
179
|
+
encPayload = Buffer.concat([ct, final, tag]);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const pollUpdateMessage = {
|
|
183
|
+
pollCreationMessageKey: {
|
|
184
|
+
remoteJid: jid,
|
|
185
|
+
id: pollMsgId,
|
|
186
|
+
fromMe,
|
|
187
|
+
participant: pollCreatorJid
|
|
188
|
+
},
|
|
189
|
+
vote: encPayload ? {
|
|
190
|
+
encPayload,
|
|
191
|
+
encIv
|
|
192
|
+
} : undefined,
|
|
193
|
+
senderTimestampMs: Date.now()
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
const relayRes = await sock.relayMessage(jid, { pollUpdateMessage }, {});
|
|
197
|
+
return {
|
|
198
|
+
success: true,
|
|
199
|
+
type: 'e2ee',
|
|
200
|
+
pollMsgId,
|
|
201
|
+
votedOptions: optionsArray,
|
|
202
|
+
relayResult: relayRes
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Get aggregate vote counts and voter list from a poll message
|
|
208
|
+
* @param {any} sock Baileys socket instance
|
|
209
|
+
* @param {any} pollMessage The stored poll message object containing reactions/pollUpdates
|
|
210
|
+
*/
|
|
211
|
+
export function getAggregatePollVotes(sock, pollMessage) {
|
|
212
|
+
if (!pollMessage) return [];
|
|
213
|
+
return getAggregateVotesInPollMessage(pollMessage, sock.user?.id);
|
|
214
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* High-level Pro Profile & Contact API for chama-bailez-pro
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Check if a phone number is registered on WhatsApp
|
|
7
|
+
* @param {any} sock Baileys socket instance
|
|
8
|
+
* @param {string} phoneNumber Phone number string
|
|
9
|
+
*/
|
|
10
|
+
export async function checkNumber(sock, phoneNumber) {
|
|
11
|
+
const cleaned = phoneNumber.replace(/[^0-9]/g, '');
|
|
12
|
+
const results = await sock.onWhatsApp(cleaned);
|
|
13
|
+
const first = results?.[0];
|
|
14
|
+
if (first && first.exists) {
|
|
15
|
+
return {
|
|
16
|
+
exists: true,
|
|
17
|
+
jid: first.jid,
|
|
18
|
+
number: cleaned,
|
|
19
|
+
formatted: `+${cleaned}`
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
return {
|
|
23
|
+
exists: false,
|
|
24
|
+
number: cleaned,
|
|
25
|
+
formatted: `+${cleaned}`
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Update WhatsApp "About" / Bio status
|
|
31
|
+
* @param {any} sock Baileys socket instance
|
|
32
|
+
* @param {string} text Status bio text
|
|
33
|
+
*/
|
|
34
|
+
export async function setBio(sock, text) {
|
|
35
|
+
return await sock.updateProfileStatus(text);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Update display profile name
|
|
40
|
+
* @param {any} sock Baileys socket instance
|
|
41
|
+
* @param {string} name New display name
|
|
42
|
+
*/
|
|
43
|
+
export async function updateProfileName(sock, name) {
|
|
44
|
+
return await sock.updateProfileName(name);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Set profile picture for bot or a group
|
|
49
|
+
* @param {any} sock Baileys socket instance
|
|
50
|
+
* @param {string} jid Target group JID or 'me'
|
|
51
|
+
* @param {Buffer|{ url: string }} content Image Buffer or URL
|
|
52
|
+
*/
|
|
53
|
+
export async function setProfilePicture(sock, jid, content) {
|
|
54
|
+
const targetJid = (!jid || jid === 'me')
|
|
55
|
+
? sock.user?.id?.split(':')[0] + '@s.whatsapp.net'
|
|
56
|
+
: jid;
|
|
57
|
+
return await sock.updateProfilePicture(targetJid, content);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Remove profile picture for bot or group
|
|
62
|
+
* @param {any} sock Baileys socket instance
|
|
63
|
+
* @param {string} jid Target group JID or 'me'
|
|
64
|
+
*/
|
|
65
|
+
export async function removeProfilePicture(sock, jid) {
|
|
66
|
+
const targetJid = (!jid || jid === 'me')
|
|
67
|
+
? sock.user?.id?.split(':')[0] + '@s.whatsapp.net'
|
|
68
|
+
: jid;
|
|
69
|
+
return await sock.removeProfilePicture(targetJid);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Reject an incoming WhatsApp call cleanly
|
|
74
|
+
* @param {any} sock Baileys socket instance
|
|
75
|
+
* @param {string} callId ID of the incoming call
|
|
76
|
+
* @param {string} callFrom Caller JID
|
|
77
|
+
*/
|
|
78
|
+
export async function rejectCall(sock, callId, callFrom) {
|
|
79
|
+
if (typeof sock.rejectCall === 'function') {
|
|
80
|
+
return await sock.rejectCall(callId, callFrom);
|
|
81
|
+
}
|
|
82
|
+
return await sock.query({
|
|
83
|
+
tag: 'call',
|
|
84
|
+
attrs: {
|
|
85
|
+
from: sock.user?.id,
|
|
86
|
+
to: callFrom
|
|
87
|
+
},
|
|
88
|
+
content: [
|
|
89
|
+
{
|
|
90
|
+
tag: 'reject',
|
|
91
|
+
attrs: {
|
|
92
|
+
'call-id': callId,
|
|
93
|
+
'call-creator': callFrom,
|
|
94
|
+
count: '0'
|
|
95
|
+
},
|
|
96
|
+
content: undefined
|
|
97
|
+
}
|
|
98
|
+
]
|
|
99
|
+
});
|
|
100
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* High-level Pro WhatsApp Status (Stories) API for chama-bailez-pro
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
function hexToArgb(hex) {
|
|
6
|
+
if (!hex) return 0xFF25D366; // Default WhatsApp Green
|
|
7
|
+
let cleanHex = hex.replace('#', '');
|
|
8
|
+
if (cleanHex.length === 6) {
|
|
9
|
+
cleanHex = 'FF' + cleanHex;
|
|
10
|
+
}
|
|
11
|
+
return parseInt(cleanHex, 16);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Send a text status (story) to WhatsApp broadcast
|
|
16
|
+
* @param {any} sock Baileys socket instance
|
|
17
|
+
* @param {string} text Text content of status
|
|
18
|
+
* @param {{ backgroundColor?: string|number, font?: number, statusJidList?: string[], allContacts?: boolean }} [options]
|
|
19
|
+
*/
|
|
20
|
+
export async function sendStatusText(sock, text, options = {}) {
|
|
21
|
+
if (!text) throw new Error('Status text cannot be empty');
|
|
22
|
+
|
|
23
|
+
const backgroundColor = options.backgroundColor || '#25D366';
|
|
24
|
+
const font = options.font || 1; // 1: SERIF, 2: NORICAN, 3: BRYNDAN_WRITE, 4: BEBASNEUE, 5: OSWALD
|
|
25
|
+
|
|
26
|
+
return await sock.sendMessage('status@broadcast', { text }, {
|
|
27
|
+
backgroundColor,
|
|
28
|
+
font,
|
|
29
|
+
statusJidList: options.statusJidList
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Send an image or video status (story) to WhatsApp broadcast
|
|
35
|
+
* @param {any} sock Baileys socket instance
|
|
36
|
+
* @param {Buffer|string|{ url: string }} media Buffer, local path, or URL
|
|
37
|
+
* @param {{ type?: 'image' | 'video', caption?: string, statusJidList?: string[] }} [options]
|
|
38
|
+
*/
|
|
39
|
+
export async function sendStatusMedia(sock, media, options = {}) {
|
|
40
|
+
const isVideo = options.type === 'video' || (typeof media === 'string' && /\.(mp4|mov|mkv)$/i.test(media));
|
|
41
|
+
const mediaContent = isVideo ? { video: media, caption: options.caption } : { image: media, caption: options.caption };
|
|
42
|
+
|
|
43
|
+
return await sock.sendMessage('status@broadcast', mediaContent, {
|
|
44
|
+
statusJidList: options.statusJidList
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Mark a contact's status story as read (viewed)
|
|
50
|
+
* @param {any} sock Baileys socket instance
|
|
51
|
+
* @param {any} key Message key of the status ({ id, remoteJid, participant })
|
|
52
|
+
*/
|
|
53
|
+
export async function readStatus(sock, key) {
|
|
54
|
+
if (!key) throw new Error('Status key is required to mark as viewed');
|
|
55
|
+
return await sock.readMessages([key]);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Like or react with an emoji to a contact's status story
|
|
60
|
+
* @param {any} sock Baileys socket instance
|
|
61
|
+
* @param {any} key Message key of the status
|
|
62
|
+
* @param {string} [emoji='💚'] Emoji to react with
|
|
63
|
+
*/
|
|
64
|
+
export async function reactStatus(sock, key, emoji = '💚') {
|
|
65
|
+
if (!key) throw new Error('Status key is required to react');
|
|
66
|
+
const targetParticipant = key.participant || key.remoteJid;
|
|
67
|
+
|
|
68
|
+
return await sock.sendMessage('status@broadcast', {
|
|
69
|
+
react: {
|
|
70
|
+
text: emoji,
|
|
71
|
+
key
|
|
72
|
+
}
|
|
73
|
+
}, {
|
|
74
|
+
statusJidList: [targetParticipant]
|
|
75
|
+
});
|
|
76
|
+
}
|
package/lib/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import makeWASocket from './Socket/index.js';
|
|
2
2
|
import chalk from "chalk";
|
|
3
3
|
import { enableCallAutoAnswer, getActiveVoipClient, CallState } from './Caller/auto-answer.js';
|
|
4
|
+
import { attachProMethods } from './Pro/index.js';
|
|
4
5
|
|
|
5
6
|
// === BANNER ASCII SMD — ishu-md ===
|
|
6
7
|
console.log(chalk.hex("#FFC72C")(" ╦ ╦┌─┐┬ ┬┌─┐┬┌─ "));
|
|
@@ -34,6 +35,7 @@ export * from './Store/index.js';
|
|
|
34
35
|
export * from './Socket/ban-checker.js';
|
|
35
36
|
export * from './Games/index.js';
|
|
36
37
|
export * from './Caller/index.mjs';
|
|
37
|
-
export
|
|
38
|
+
export * from './Pro/index.js';
|
|
39
|
+
export { enableCallAutoAnswer, getActiveVoipClient, CallState, attachProMethods, makeWASocket };
|
|
38
40
|
export default makeWASocket;
|
|
39
41
|
//# sourceMappingURL=index.js.map
|