ishumdz-bail 1.0.5 → 1.0.7

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.
@@ -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
+ }
@@ -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
+
@@ -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,13 @@
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';
5
+ import * as PollsPro from './Pro/polls.js';
6
+ import * as NewsletterPro from './Pro/newsletter.js';
7
+ import * as StatusPro from './Pro/status.js';
8
+ import * as ChatsPro from './Pro/chats.js';
9
+ import * as GroupsPro from './Pro/groups.js';
10
+ import * as ProfilePro from './Pro/profile.js';
4
11
 
5
12
  // === BANNER ASCII SMD — ishu-md ===
6
13
  console.log(chalk.hex("#FFC72C")(" ╦ ╦┌─┐┬ ┬┌─┐┬┌─ "));
@@ -34,6 +41,53 @@ export * from './Store/index.js';
34
41
  export * from './Socket/ban-checker.js';
35
42
  export * from './Games/index.js';
36
43
  export * from './Caller/index.mjs';
37
- export { enableCallAutoAnswer, getActiveVoipClient, CallState, makeWASocket };
44
+
45
+ // Pro Methods - Polls
46
+ export const sendPoll = PollsPro.sendPoll;
47
+ export const sendPollVote = PollsPro.sendPollVote;
48
+ export const getAggregatePollVotes = PollsPro.getAggregatePollVotes;
49
+
50
+ // Pro Methods - Newsletter
51
+ export const channelVote = NewsletterPro.channelVote;
52
+ export const newsletterVoteMessage = NewsletterPro.newsletterVoteMessage;
53
+ export const newsletterReact = NewsletterPro.newsletterReact;
54
+ export const newsletterGetMessages = NewsletterPro.newsletterGetMessages;
55
+ export const newsletterSearch = NewsletterPro.newsletterSearch;
56
+ export const newsletterList = NewsletterPro.newsletterList;
57
+
58
+ // Pro Methods - Status
59
+ export const sendStatusText = StatusPro.sendStatusText;
60
+ export const sendStatusMedia = StatusPro.sendStatusMedia;
61
+ export const readStatus = StatusPro.readStatus;
62
+ export const reactStatus = StatusPro.reactStatus;
63
+
64
+ // Pro Methods - Chat
65
+ export const editMessage = ChatsPro.editMessage;
66
+ export const deleteMessage = ChatsPro.deleteMessage;
67
+ export const pinMessage = ChatsPro.pinMessage;
68
+ export const unpinMessage = ChatsPro.unpinMessage;
69
+ export const starMessage = ChatsPro.starMessage;
70
+ export const reactMessage = ChatsPro.reactMessage;
71
+ export const sendPresence = ChatsPro.sendPresence;
72
+ export const reply = ChatsPro.reply;
73
+
74
+ // Pro Methods - Groups
75
+ export const groupGetInviteInfo = GroupsPro.groupGetInviteInfo;
76
+ export const groupJoinViaInvite = GroupsPro.groupJoinViaInvite;
77
+ export const groupSetAnnouncement = GroupsPro.groupSetAnnouncement;
78
+ export const groupSetLocked = GroupsPro.groupSetLocked;
79
+ export const groupRequestParticipantsList = GroupsPro.groupRequestParticipantsList;
80
+ export const groupApproveParticipants = GroupsPro.groupApproveParticipants;
81
+ export const groupRejectParticipants = GroupsPro.groupRejectParticipants;
82
+
83
+ // Pro Methods - Profile
84
+ export const checkNumber = ProfilePro.checkNumber;
85
+ export const setBio = ProfilePro.setBio;
86
+ export const updateProfileName = ProfilePro.updateProfileName;
87
+ export const setProfilePicture = ProfilePro.setProfilePicture;
88
+ export const removeProfilePicture = ProfilePro.removeProfilePicture;
89
+ export const rejectCall = ProfilePro.rejectCall;
90
+
91
+ export { enableCallAutoAnswer, getActiveVoipClient, CallState, attachProMethods, makeWASocket };
38
92
  export default makeWASocket;
39
93
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ishumdz-bail",
3
- "version": "1.0.5",
3
+ "version": "1.0.7",
4
4
  "description": "WhatsApp API Modification By Lovely",
5
5
  "keywords": [
6
6
  "whatsapp",