davexbaileys 2.5.15 → 2.5.16

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 CHANGED
@@ -5,111 +5,194 @@
5
5
 
6
6
  A lightweight, full-featured WhatsApp Web API library for Node.js — maintained by **Dave Tech**.
7
7
 
8
- > Built on top of the Baileys protocol layer with extended features for bots, channels, groups, and business.
9
-
10
8
  ## Installation
11
9
 
12
10
  ```bash
13
11
  npm install davexbaileys
14
12
  ```
15
13
 
16
- ## Usage
14
+ ## Quick Start
17
15
 
18
16
  ```js
19
17
  const { makeWASocket, useMultiFileAuthState, fetchLatestBaileysVersion } = require('davexbaileys');
20
18
 
21
- const { version } = await fetchLatestBaileysVersion(); // fetches live from WhatsApp
19
+ const { version } = await fetchLatestBaileysVersion();
22
20
  const { state, saveCreds } = await useMultiFileAuthState('auth_info');
23
-
24
21
  const sock = makeWASocket({ version, auth: state });
25
22
  sock.ev.on('creds.update', saveCreds);
26
23
  ```
27
24
 
28
- ## Features
25
+ ---
26
+
27
+ ## Feature Reference
29
28
 
30
- ### Connection
31
- - `fetchLatestBaileysVersion()` — fetches live WA version from WhatsApp web (no stale versions)
32
- - `fetchLatestWaWebVersion()` — alternative live version fetch
33
- - Multi-device (MD) support with pairing code & QR
34
- - Automatic reconnection with smart keepalive
29
+ ### Connection & Version
30
+ - `fetchLatestBaileysVersion()` — get bundled WA version
31
+ - `fetchLatestWaWebVersion()` — fetch live WA version from WhatsApp web
32
+ - Multi-device (MD) with pairing code or QR
33
+ - Auto reconnect, smart keepalive
34
+
35
+ ---
35
36
 
36
37
  ### Messaging
37
- - Send text, images, videos, audio, documents, stickers, reactions, polls
38
- - Edit and delete messages
39
- - Quote / reply, forward, mention contacts
38
+ - Send text, images, videos, audio, documents, stickers, GIFs, reactions, polls, contacts, locations, events
39
+ - Edit, delete, forward messages
40
+ - Quote/reply, mention contacts
41
+ - `sock.sendMessage(jid, { pin: key })` — pin/unpin a message in a chat
42
+ - `sock.pinMessage(jid, key, type)` — explicit pin (type=1 pin, type=2 unpin)
43
+
44
+ ---
40
45
 
41
- ### Groups
42
- - Create, update, leave, join (invite link or code)
43
- - Manage participants (add, remove, promote, demote)
44
- - Update group settings (subject, description, icon, restrictions)
45
- - `isAntiGroupMention(message, participants, threshold?)` detect mass @everyone mentions
46
+ ### Private Chat Commands
47
+ | Method | Description |
48
+ |--------|-------------|
49
+ | `sock.pinChat(jid, true/false)` | Pin or unpin a chat |
50
+ | `sock.archiveChat(jid, lastMsgs)` | Archive a chat |
51
+ | `sock.unarchiveChat(jid, lastMsgs)` | Unarchive a chat |
52
+ | `sock.markChatRead(jid, lastMsgs)` | Mark chat as read |
53
+ | `sock.markChatUnread(jid, lastMsgs)` | Mark chat as unread |
54
+ | `sock.muteChat(jid, durationMs)` | Mute a chat (ms=0 to unmute) |
55
+ | `sock.unmuteChat(jid)` | Unmute a chat |
56
+ | `sock.deleteChat(jid, lastMsgs)` | Delete a chat |
57
+ | `sock.clearChat(jid, lastMsgs)` | Clear all messages |
58
+ | `sock.star(jid, messages, star)` | Star/unstar messages |
59
+ | `sock.addOrEditContact(jid, contact)` | Add or edit a contact |
60
+ | `sock.removeContact(jid)` | Remove a contact |
61
+ | `sock.chatModify(mod, jid)` | Raw chat modification |
62
+
63
+ ---
46
64
 
65
+ ### Privacy & Settings
66
+ | Method | Description |
67
+ |--------|-------------|
68
+ | `sock.updateLastSeenPrivacy(value)` | Who sees your last seen (`all`/`contacts`/`contact_blacklist`/`none`) |
69
+ | `sock.updateOnlinePrivacy(value)` | Online status visibility |
70
+ | `sock.updateProfilePicturePrivacy(value)` | Profile photo visibility |
71
+ | `sock.updateStatusPrivacy(value)` | Status (about) text visibility |
72
+ | `sock.updateReadReceiptsPrivacy(value)` | Read receipts (blue ticks) |
73
+ | `sock.updateCallPrivacy(value)` | Who can call you |
74
+ | `sock.updateGroupsAddPrivacy(value)` | Who can add you to groups |
75
+ | `sock.updateGroupsJoinPrivacy(value)` | Alias for groups add privacy |
76
+ | `sock.updateAboutPrivacy(value)` | Bio/about visibility |
77
+ | `sock.updateMessagesPrivacy(value)` | Messages privacy |
78
+ | `sock.updateDefaultDisappearingMode(duration)` | Default disappearing mode (seconds) |
79
+ | `sock.updateDisableLinkPreviewsPrivacy(bool)` | Disable/enable link previews |
80
+ | `sock.updateStatusResharePrivacy(bool)` | Prevent others from resharing your status |
81
+ | `sock.silenceUnknownCallers()` | Silence calls from unknown numbers |
82
+ | `sock.allowUnknownCallers()` | Allow calls from everyone |
83
+ | `sock.fetchPrivacySettings()` | Fetch all current privacy settings |
84
+ | `sock.fetchDisappearingDuration(...jids)` | Fetch disappearing message settings for contacts |
85
+ | `sock.updateProfileStatus(text)` | Update bio/about text |
86
+ | `sock.updateProfileName(name)` | Update display name |
87
+ | `sock.updateProfilePicture(jid, buffer)` | Update profile picture |
88
+ | `sock.removeProfilePicture(jid)` | Remove profile picture |
89
+
90
+ ---
91
+
92
+ ### Group Commands
93
+ - Create, leave, join by invite link/code
94
+ - Add, remove, promote, demote participants
95
+ - Update subject, description, icon, settings
96
+ - Toggle ephemeral (disappearing messages)
97
+ - `sock.groupSettingUpdate(jid, setting)` — lock/unlock settings
98
+
99
+ #### Anti-Feature Helpers (Group Moderation)
47
100
  ```js
48
- // Anti group mention detection
101
+ const { isAntiLink, isAntiSticker, isAntiImage, isAntiVideo, isAntiAudio,
102
+ isAntiDocument, isAntiViewOnce, isAntiBug, isAntiFiles,
103
+ getMessageType, hasLink, extractLinks,
104
+ isSticker, isImage, isVideo, isAudio, isDocument,
105
+ isViewOnce, isReaction, isPoll, isGif, isForwarded,
106
+ LINK_REGEX } = require('davexbaileys');
107
+
49
108
  sock.ev.on('messages.upsert', async ({ messages }) => {
50
109
  const msg = messages[0];
51
- if (!msg.key.fromMe && msg.key.remoteJid.endsWith('@g.us')) {
52
- const meta = await sock.groupMetadata(msg.key.remoteJid);
53
- if (sock.isAntiGroupMention(msg, meta.participants.map(p => p.id))) {
54
- // Someone mentioned everyone take action
55
- await sock.sendMessage(msg.key.remoteJid, { text: '⚠️ Mass mentions are not allowed!' });
56
- }
57
- }
110
+ if (msg.key.fromMe || !msg.key.remoteJid.endsWith('@g.us')) return;
111
+
112
+ if (isAntiLink(msg)) { /* delete message, warn user */ }
113
+ if (isAntiSticker(msg)) { /* no stickers allowed */ }
114
+ if (isAntiImage(msg)) { /* no images */ }
115
+ if (isAntiVideo(msg)) { /* no videos */ }
116
+ if (isAntiAudio(msg)) { /* no voice notes */ }
117
+ if (isAntiDocument(msg)){ /* no documents */ }
118
+ if (isAntiViewOnce(msg)){ /* no view-once messages */ }
119
+ if (isAntiBug(msg)) { /* potential crash message */ }
120
+ if (isAntiFiles(msg)) { /* no files of any kind */ }
121
+
122
+ console.log('Message type:', getMessageType(msg));
58
123
  });
59
124
  ```
60
125
 
61
- ### Private Chat Commands
62
- - `sock.pinChat(jid, true|false)` — pin or unpin a chat
63
- - `sock.archiveChat(jid, lastMessages)` archive a chat
64
- - `sock.unarchiveChat(jid, lastMessages)` — unarchive a chat
65
- - `sock.markChatRead(jid, lastMessages)` mark chat as read
66
- - `sock.markChatUnread(jid, lastMessages)` — mark chat as unread
67
- - `sock.chatModify(mod, jid)` raw chat modification
68
- - `sock.star(jid, messages, star)` star/unstar messages
126
+ #### Anti-Group-Mention (detect group JIDs in messages/statuses)
127
+ ```js
128
+ const { isAntiGroupMention, getGroupMentions } = require('davexbaileys');
129
+
130
+ // true if any @g.us JID is mentioned in the message
131
+ if (isAntiGroupMention(msg)) {
132
+ const groups = getGroupMentions(msg); // array of group JIDs mentioned
133
+ await sock.sendMessage(msg.key.remoteJid, { text: '❌ Group mentions are not allowed!' });
134
+ }
135
+ ```
136
+
137
+ ---
69
138
 
70
139
  ### Newsletter (Channel) Commands
71
- - `sock.newsletterCreate(name, description)` create a new channel
72
- - `sock.newsletterFollow(jid)` — follow a channel
73
- - `sock.newsletterUnfollow(jid)` unfollow a channel
74
- - `sock.newsletterMute(jid)` / `sock.newsletterUnmute(jid)` mute/unmute
75
- - `sock.newsletterMetadata(type, key)` get channel metadata
76
- - `sock.newsletterSubscribers(jid)` get subscriber list
77
- - `sock.newsletterReactMessage(jid, serverId, emoji)` react to a channel post
78
- - `sock.newsletterFetchMessages(jid, count, since, after)` fetch channel messages
79
- - `sock.newsletterUpdateName(jid, name)` update channel name
80
- - `sock.newsletterUpdateDescription(jid, description)` update channel description
81
- - `sock.newsletterUpdatePicture(jid, buffer)` update channel picture
82
- - `sock.newsletterRemovePicture(jid)` remove channel picture
83
- - `sock.newsletterDelete(jid)` delete channel
84
- - `sock.newsletterChangeOwner(jid, newOwnerJid)` transfer ownership
85
- - `sock.subscribeNewsletterUpdates(jid)` subscribe to live updates
86
-
87
- > **Auto-react:** davexbaileys automatically reacts 👍 to new posts from the Dave Tech official channel.
88
-
89
- ### WhatsApp Business Commands
90
- - `sock.getCatalog({ jid, limit, cursor })` — fetch business product catalog
91
- - `sock.getCollections(jid, limit)` — fetch product collections
92
- - `sock.getOrderDetails(orderId, tokenBase64)` get order details
93
- - `sock.getBusinessProfile(jid)` get business profile
140
+ | Method | Description |
141
+ |--------|-------------|
142
+ | `sock.newsletterCreate(name, desc)` | Create a channel |
143
+ | `sock.newsletterFollow(jid)` | Follow a channel |
144
+ | `sock.newsletterUnfollow(jid)` | Unfollow |
145
+ | `sock.newsletterMute(jid)` | Mute a channel |
146
+ | `sock.newsletterUnmute(jid)` | Unmute |
147
+ | `sock.newsletterMetadata(type, key)` | Get channel metadata |
148
+ | `sock.newsletterSubscribers(jid)` | Get subscribers |
149
+ | `sock.newsletterReactMessage(jid, serverId, emoji)` | React to a post |
150
+ | `sock.newsletterFetchMessages(jid, count, since)` | Fetch posts |
151
+ | `sock.newsletterUpdateName(jid, name)` | Update channel name |
152
+ | `sock.newsletterUpdateDescription(jid, desc)` | Update description |
153
+ | `sock.newsletterUpdatePicture(jid, buffer)` | Update channel photo |
154
+ | `sock.newsletterRemovePicture(jid)` | Remove channel photo |
155
+ | `sock.newsletterDelete(jid)` | Delete channel |
156
+ | `sock.newsletterChangeOwner(jid, newOwnerJid)` | Transfer ownership |
157
+ | `sock.subscribeNewsletterUpdates(jid)` | Subscribe to live updates |
158
+
159
+ **Events:**
160
+ ```js
161
+ sock.ev.on('newsletter.reaction', ({ id, server_id, reaction }) => {});
162
+ sock.ev.on('newsletter.view', ({ id, server_id, count }) => {});
163
+ sock.ev.on('newsletter-participants.update', update => {});
164
+ sock.ev.on('newsletter-settings.update', update => {});
165
+ ```
94
166
 
95
- ### Privacy & Settings
96
- - `sock.updateLastSeenPrivacy(value)`
97
- - `sock.updateOnlinePrivacy(value)`
98
- - `sock.updateProfilePicturePrivacy(value)`
99
- - `sock.updateStatusPrivacy(value)`
100
- - `sock.updateReadReceiptsPrivacy(value)`
101
- - `sock.updateGroupsAddPrivacy(value)`
102
- - `sock.updateDefaultDisappearingMode(duration)`
103
- - `sock.updateBlockStatus(jid, action)`
104
-
105
- ### Newsletter Events
167
+ > Auto-react: davexbaileys automatically reacts 👍 to new posts from the Dave Tech channel.
168
+
169
+ ---
170
+
171
+ ### WhatsApp Business
172
+ - `sock.getCatalog({ jid, limit, cursor })`
173
+ - `sock.getCollections(jid, limit)`
174
+ - `sock.getOrderDetails(orderId, tokenBase64)`
175
+ - `sock.getBusinessProfile(jid)`
176
+ - `sock.addOrEditQuickReply(quickReply)` — business quick replies
177
+ - `sock.removeQuickReply(timestamp)`
178
+
179
+ ---
180
+
181
+ ### Link Preview
106
182
  ```js
107
- sock.ev.on('newsletter.reaction', update => { /* { id, server_id, reaction } */ });
108
- sock.ev.on('newsletter.view', update => { /* { id, server_id, count } */ });
109
- sock.ev.on('newsletter-participants.update', update => { /* participant changes */ });
110
- sock.ev.on('newsletter-settings.update', update => { /* settings changes */ });
183
+ // Enable rich link previews:
184
+ const sock = makeWASocket({ generateHighQualityLinkPreview: true, ... });
185
+
186
+ // Disable link previews in your account settings:
187
+ await sock.updateDisableLinkPreviewsPrivacy(true);
188
+
189
+ // Utility helper (basic preview object):
190
+ const { generateLinkPreview } = require('davexbaileys');
191
+ const preview = generateLinkPreview('https://example.com', 'Example', 'Description');
111
192
  ```
112
193
 
194
+ ---
195
+
113
196
  ## Author
114
197
 
115
198
  **Dave Tech**
@@ -711,6 +711,121 @@ const makeChatsSocket = (config) => {
711
711
  return chatModify({ markRead: false, lastMessages }, jid);
712
712
  };
713
713
  /**
714
+ * Mute a chat for a given duration
715
+ * @param jid - JID of the chat
716
+ * @param durationMs - duration in milliseconds, 0 = unmute
717
+ */
718
+ const muteChat = (jid, durationMs) => {
719
+ return chatModify({ mute: durationMs || false }, jid);
720
+ };
721
+ /**
722
+ * Unmute a chat
723
+ */
724
+ const unmuteChat = (jid) => {
725
+ return chatModify({ mute: false }, jid);
726
+ };
727
+ /**
728
+ * Delete a chat (clear + remove from list)
729
+ * @param jid - JID of the chat
730
+ * @param lastMessages - last messages for sync
731
+ */
732
+ const deleteChat = (jid, lastMessages) => {
733
+ return chatModify({ delete: true, lastMessages }, jid);
734
+ };
735
+ /**
736
+ * Clear a chat (delete all messages)
737
+ * @param jid - JID of the chat
738
+ * @param lastMessages - last messages for sync
739
+ */
740
+ const clearChat = (jid, lastMessages) => {
741
+ return chatModify({ clear: { messages: lastMessages || [] } }, jid);
742
+ };
743
+ /**
744
+ * Enable/Disable link preview privacy
745
+ * (whether WA shows link previews for messages you send)
746
+ * @param isPreviewsDisabled - true to disable, false to enable
747
+ */
748
+ const updateDisableLinkPreviewsPrivacy = (isPreviewsDisabled) => {
749
+ return chatModify({ disableLinkPreviews: { isPreviewsDisabled } }, '');
750
+ };
751
+ /**
752
+ * Add or Edit a contact
753
+ */
754
+ const addOrEditContact = (jid, contact) => {
755
+ return chatModify({ contact }, jid);
756
+ };
757
+ /**
758
+ * Remove a contact
759
+ */
760
+ const removeContact = (jid) => {
761
+ return chatModify({ contact: null }, jid);
762
+ };
763
+ /**
764
+ * Add or Edit a quick reply (business feature)
765
+ */
766
+ const addOrEditQuickReply = (quickReply) => {
767
+ return chatModify({ quickReply }, '');
768
+ };
769
+ /**
770
+ * Remove a quick reply
771
+ * @param timestamp - timestamp of the quick reply to remove
772
+ */
773
+ const removeQuickReply = (timestamp) => {
774
+ return chatModify({ quickReply: { timestamp, deleted: true } }, '');
775
+ };
776
+ /**
777
+ * Silence unknown callers — only allow contacts to call you
778
+ * Wrapper around updateCallPrivacy('contacts')
779
+ */
780
+ const silenceUnknownCallers = () => {
781
+ return privacyQuery('calladd', 'contacts');
782
+ };
783
+ /**
784
+ * Allow unknown callers (default) — anyone can call
785
+ */
786
+ const allowUnknownCallers = () => {
787
+ return privacyQuery('calladd', 'all');
788
+ };
789
+ /**
790
+ * Update "Who can add me to groups" privacy
791
+ * @param value - 'all' | 'contacts' | 'contact_blacklist' | 'none'
792
+ */
793
+ const updateGroupsJoinPrivacy = (value) => {
794
+ return privacyQuery('groups', value);
795
+ };
796
+ /**
797
+ * Update bio/about visibility privacy
798
+ * @param value - 'all' | 'contacts' | 'contact_blacklist' | 'none'
799
+ */
800
+ const updateAboutPrivacy = (value) => {
801
+ return privacyQuery('status', value);
802
+ };
803
+ /**
804
+ * Update status (story) reshare privacy
805
+ * Controls who can reshare your status updates
806
+ * @param isDisabled - true to disable resharing
807
+ */
808
+ const updateStatusResharePrivacy = (isDisabled) => {
809
+ return chatModify({ disableStatusReshare: { isDisabled } }, '');
810
+ };
811
+ /**
812
+ * Fetch disappearing message duration for contacts
813
+ */
814
+ const fetchDisappearingDuration = async (...jids) => {
815
+ const { WAUSync_1 } = (() => {
816
+ try { return { WAUSync_1: require('../WAUSync') }; } catch { return { WAUSync_1: null }; }
817
+ })();
818
+ if (!WAUSync_1) return null;
819
+ try {
820
+ const usyncQuery = new WAUSync_1.USyncQuery().withDisappearingModeProtocol();
821
+ for (const jid of jids) {
822
+ usyncQuery.withUser(new WAUSync_1.USyncUser().withId(jid));
823
+ }
824
+ const result = await sock.executeUSyncQuery(usyncQuery);
825
+ return result ? result.list : null;
826
+ } catch { return null; }
827
+ };
828
+ /**
714
829
  * Star or Unstar a message
715
830
  */
716
831
  const star = (jid, messages, star) => {
@@ -916,10 +1031,25 @@ const makeChatsSocket = (config) => {
916
1031
  removeMessageLabel,
917
1032
  star,
918
1033
  pinChat,
919
- archiveChat,
920
- unarchiveChat,
921
- markChatRead,
922
- markChatUnread
923
- };
1034
+ archiveChat,
1035
+ unarchiveChat,
1036
+ markChatRead,
1037
+ markChatUnread,
1038
+ muteChat,
1039
+ unmuteChat,
1040
+ deleteChat,
1041
+ clearChat,
1042
+ updateDisableLinkPreviewsPrivacy,
1043
+ addOrEditContact,
1044
+ removeContact,
1045
+ addOrEditQuickReply,
1046
+ removeQuickReply,
1047
+ silenceUnknownCallers,
1048
+ allowUnknownCallers,
1049
+ updateGroupsJoinPrivacy,
1050
+ updateAboutPrivacy,
1051
+ updateStatusResharePrivacy,
1052
+ fetchDisappearingDuration
1053
+ };
924
1054
  };
925
1055
  exports.makeChatsSocket = makeChatsSocket;
@@ -1,7 +1,8 @@
1
1
  ,
2
- isAntiGroupMention"use strict";
2
+ isAntiGroupMention,
3
+ getGroupMentions"use strict";
3
4
  Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.isAntiGroupMention = exports.extractGroupMetadata = exports.makeGroupsSocket = void 0;
5
+ exports.getGroupMentions = exports.isAntiGroupMention = exports.extractGroupMetadata = exports.makeGroupsSocket = void 0;
5
6
  const WAProto_1 = require("../../WAProto");
6
7
  const Types_1 = require("../Types");
7
8
  const Utils_1 = require("../Utils");
@@ -9,22 +10,33 @@ const WABinary_1 = require("../WABinary");
9
10
  const chats_1 = require("./chats");
10
11
 
11
12
  /**
12
- * Detect if a message is an "everyone" / anti-group-mention
13
- * i.e. someone mentioned all or a large number of group participants
13
+ * Detect if a message mentions any group JID (@g.us)
14
+ * "antiGroupMention" prevents users from tagging groups inside private chats or status updates.
15
+ * Works on text, extendedText, image captions, video captions, etc.
14
16
  * @param message - the WebMessageInfo object
15
- * @param groupParticipants - array of participant JIDs in the group
16
- * @param threshold - fraction of participants that must be mentioned (default 0.5 = 50%)
17
- * @returns true if it qualifies as a group-wide mention
17
+ * @returns array of group JIDs that were mentioned (empty array = no group mentions)
18
18
  */
19
- const isAntiGroupMention = (message, groupParticipants, threshold = 0.5) => {
20
- var _a, _b, _c;
21
- const mentioned = ((_c = (_b = (_a = message === null || message === void 0 ? void 0 : message.message) === null || _a === void 0 ? void 0 : _a.extendedTextMessage) === null || _b === void 0 ? void 0 : _b.contextInfo) === null || _c === void 0 ? void 0 : _c.mentionedJid) || [];
22
- if (!mentioned.length || !groupParticipants.length) return false;
23
- // Normalise JIDs so user@s.whatsapp.net vs user@lid don't mismatch
24
- const normMentioned = mentioned.map(j => j.split('@')[0]);
25
- const normParticipants = groupParticipants.map(j => j.split('@')[0]);
26
- const overlap = normMentioned.filter(m => normParticipants.includes(m));
27
- return overlap.length >= Math.ceil(normParticipants.length * threshold);
19
+ const getGroupMentions = (message) => {
20
+ var _a, _b, _c, _d, _e, _f, _g, _h;
21
+ const getAllMentioned = (contextInfo) => {
22
+ return (contextInfo === null || contextInfo === void 0 ? void 0 : contextInfo.mentionedJid) || [];
23
+ };
24
+ const msg = message === null || message === void 0 ? void 0 : message.message;
25
+ if (!msg) return [];
26
+ const mentioned =
27
+ getAllMentioned((_b = (_a = msg.extendedTextMessage) === null || _a === void 0 ? void 0 : _a.contextInfo) !== null && _b !== void 0 ? _b : null) ||
28
+ getAllMentioned((_d = (_c = msg.imageMessage) === null || _c === void 0 ? void 0 : _c.contextInfo) !== null && _d !== void 0 ? _d : null) ||
29
+ getAllMentioned((_f = (_e = msg.videoMessage) === null || _e === void 0 ? void 0 : _e.contextInfo) !== null && _f !== void 0 ? _f : null) ||
30
+ getAllMentioned((_h = (_g = msg.documentMessage) === null || _g === void 0 ? void 0 : _g.contextInfo) !== null && _h !== void 0 ? _h : null) ||
31
+ [];
32
+ return mentioned.filter(jid => typeof jid === 'string' && jid.endsWith('@g.us'));
33
+ };
34
+ /**
35
+ * Returns true if the message contains any group mention (@g.us JID)
36
+ * Use this to enforce "antiGroupMention" policy in private chats or status updates.
37
+ */
38
+ const isAntiGroupMention = (message) => {
39
+ return getGroupMentions(message).length > 0;
28
40
  };
29
41
 
30
42
  const makeGroupsSocket = (config) => {
@@ -360,3 +372,4 @@ const extractGroupMetadata = (result) => {
360
372
  };
361
373
  exports.extractGroupMetadata = extractGroupMetadata;
362
374
  exports.isAntiGroupMention = isAntiGroupMention;
375
+ exports.getGroupMentions = getGroupMentions;
@@ -851,8 +851,30 @@ const makeMessagesSocket = (config) => {
851
851
  ev,
852
852
  "messages.media-update",
853
853
  );
854
- return {
854
+ /**
855
+ * Pin a message in a chat
856
+ * @param jid - JID of the chat
857
+ * @param key - message key of the message to pin (key.id, key.remoteJid, key.fromMe, key.participant)
858
+ * @param type - 1 = pin, 2 = unpin (default 1)
859
+ */
860
+ const pinMessage = async (jid, key, type = 1) => {
861
+ const WAProto_1 = require('../../WAProto');
862
+ const { unixTimestampSeconds, generateMessageIDV2 } = require('../Utils/generics');
863
+ const senderMs = BigInt(unixTimestampSeconds() * 1000);
864
+ const msg = {
865
+ pinInChatMessage: {
866
+ key,
867
+ type,
868
+ senderTimestampMs: WAProto_1.proto.Message.PinInChatMessage.create
869
+ ? WAProto_1.proto.Message.PinInChatMessage.create({ senderTimestampMs: senderMs })?.senderTimestampMs ?? senderMs
870
+ : senderMs
871
+ }
872
+ };
873
+ return relayMessage(jid, msg, { messageId: generateMessageIDV2(authState.creds.me?.id) });
874
+ };
875
+ return {
855
876
  ...sock,
877
+ pinMessage,
856
878
  getPrivacyTokens,
857
879
  assertSessions,
858
880
  relayMessage,
@@ -4,26 +4,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.isWABusinessPlatform = exports.getCodeFromWSError = exports.getCallStatusFromNode = exports.getErrorCodeFromStreamError = exports.getStatusFromReceiptType = exports.generateMdTagPrefix = exports.fetchLatestWaWebVersion = exports.fetchLatestBaileysVersion = async (options = {}) => {
7
- // Fetch live WA version from WhatsApp web so bots always get the current version
8
- try {
9
- const defaultHeaders = {
10
- 'sec-fetch-site': 'none',
11
- 'user-agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36'
12
- };
13
- const headers = { ...defaultHeaders, ...(options.headers || {}) };
14
- const response = await (0, axios_1.default)({ method: 'GET', url: 'https://web.whatsapp.com/sw.js', headers, timeout: 8000 });
15
- const match = response.data.match(/"?client_revision"?:\s*(\d+)/);
16
- if (match?.[1]) {
17
- return { version: [2, 3000, +match[1]], isLatest: true };
18
- }
19
- } catch {}
20
- // Fallback to bundled version
21
7
  return {
22
8
  version: baileys_version_json_1.version,
23
- isLatest: false
9
+ isLatest: true
24
10
  };
25
11
  };
26
- exports.fetchLatestWaWebVersion = exports.fetchLatestBaileysVersion = exports.bindWaitForConnectionUpdate = exports.generateMessageID = exports.generateMessageIDV2 = exports.delayCancellable = exports.delay = exports.debouncedTimeout = exports.unixTimestampSeconds = exports.toNumber = exports.encodeBigEndian = exports.generateRegistrationId = exports.encodeWAMessage = exports.unpadRandomMax16 = exports.writeRandomPadMax16 = exports.getKeyAuthor = exports.BufferJSON = exports.getPlatformId = exports.Browsers = void 0;
12
+ exports.fetchLatestWaWebVersion = exports.fetchLatestBaileysVersion = exports.bindWaitForConnectionUpdate = exports.generateMessageID = exports.generateMessageIDV2 = exports.delayCancellable = exports.delay = exports.debouncedTimeout = exports.unixTimestampSeconds = exports.toNumber = exports.encodeBigEndian = exports.generateRegistrationId = exports.encodeWAMessage = exports.unpadRandomMax16 = exports.writeRandomPadMax16 = exports.getKeyAuthor = exports.BufferJSON = exports.getPlatformId = exports.Browsers = void 0;
27
13
  exports.promiseTimeout = promiseTimeout;
28
14
  exports.bindWaitForEvent = bindWaitForEvent;
29
15
  exports.trimUndefined = trimUndefined;
@@ -32,3 +32,4 @@ __exportStar(require("./link-preview"), exports);
32
32
  __exportStar(require("./event-buffer"), exports);
33
33
  __exportStar(require("./process-message"), exports);
34
34
  __exportStar(require("./lid-mapping"), exports);
35
+ __exportStar(require("./message-type-utils"), exports);
@@ -0,0 +1,215 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getMessageType = exports.generateLinkPreview = exports.isAntiFiles = exports.isAntiBug = exports.isAntiViewOnce = exports.isAntiDocument = exports.isAntiVideo = exports.isAntiAudio = exports.isAntiImage = exports.isAntiSticker = exports.isAntiLink = exports.isViewOnce = exports.isDocument = exports.isVideo = exports.isAudio = exports.isImage = exports.isSticker = exports.isGif = exports.isReaction = exports.isPoll = exports.isLocation = exports.isContact = exports.isLiveLocation = exports.isButton = exports.isForwarded = exports.hasLink = exports.LINK_REGEX = void 0;
4
+
5
+ /**
6
+ * Regex to detect URLs/links in messages (same pattern as official Baileys internals)
7
+ * Matches http(s), ftp links and bare domains like example.com
8
+ */
9
+ const LINK_REGEX = /(?:(?:https?|ftp):\/\/|www\.)[a-z0-9-]+(?:\.[a-z0-9-]+)*(?::[0-9]+)?(?:\/[^\s]*)?/gi;
10
+ exports.LINK_REGEX = LINK_REGEX;
11
+
12
+ // ─── helpers ────────────────────────────────────────────────────────────────
13
+
14
+ /**
15
+ * Extract the innermost/normalised message content object
16
+ */
17
+ const normalise = (msg) => {
18
+ var _a;
19
+ const m = (msg === null || msg === void 0 ? void 0 : msg.message) || msg;
20
+ if (!m) return null;
21
+ // unwrap ephemeral / view-once / document-with-caption wrappers
22
+ return m.ephemeralMessage?.message
23
+ || m.viewOnceMessage?.message
24
+ || m.viewOnceMessageV2?.message
25
+ || m.viewOnceMessageV2Extension?.message
26
+ || m.documentWithCaptionMessage?.message
27
+ || m.editedMessage?.message?.protocolMessage?.editedMessage
28
+ || m;
29
+ };
30
+
31
+ /**
32
+ * Get the caption/text from any message type
33
+ */
34
+ const getCaption = (msg) => {
35
+ const m = normalise(msg);
36
+ if (!m) return '';
37
+ return m.conversation
38
+ || m.extendedTextMessage?.text
39
+ || m.imageMessage?.caption
40
+ || m.videoMessage?.caption
41
+ || m.documentMessage?.caption
42
+ || m.audioMessage?.caption
43
+ || '';
44
+ };
45
+
46
+ // ─── link detection ─────────────────────────────────────────────────────────
47
+
48
+ /**
49
+ * Returns true if the message body contains a URL/link
50
+ */
51
+ const hasLink = (msg) => {
52
+ const text = getCaption(msg);
53
+ LINK_REGEX.lastIndex = 0;
54
+ return LINK_REGEX.test(text);
55
+ };
56
+ exports.hasLink = hasLink;
57
+
58
+ /**
59
+ * Extract all URLs from a message (returns empty array if none)
60
+ */
61
+ const extractLinks = (msg) => {
62
+ const text = getCaption(msg);
63
+ return text.match(LINK_REGEX) || [];
64
+ };
65
+ exports.extractLinks = extractLinks;
66
+
67
+ // ─── type checks (return true/false) ────────────────────────────────────────
68
+
69
+ const isSticker = (msg) => !!(normalise(msg)?.stickerMessage);
70
+ const isImage = (msg) => !!(normalise(msg)?.imageMessage);
71
+ const isVideo = (msg) => !!(normalise(msg)?.videoMessage);
72
+ const isAudio = (msg) => !!(normalise(msg)?.audioMessage);
73
+ const isDocument = (msg) => !!(normalise(msg)?.documentMessage || normalise(msg)?.documentWithCaptionMessage);
74
+ const isLocation = (msg) => !!(normalise(msg)?.locationMessage || normalise(msg)?.liveLocationMessage);
75
+ const isLiveLocation = (msg) => !!(normalise(msg)?.liveLocationMessage);
76
+ const isContact = (msg) => !!(normalise(msg)?.contactMessage || normalise(msg)?.contactsArrayMessage);
77
+ const isReaction = (msg) => !!(normalise(msg)?.reactionMessage);
78
+ const isPoll = (msg) => !!(normalise(msg)?.pollCreationMessage || normalise(msg)?.pollCreationMessageV2 || normalise(msg)?.pollCreationMessageV3);
79
+ const isGif = (msg) => {
80
+ const m = normalise(msg);
81
+ return !!(m?.videoMessage?.gifPlayback || m?.gifMessage);
82
+ };
83
+ const isButton = (msg) => {
84
+ const m = normalise(msg);
85
+ return !!(m?.buttonsMessage || m?.templateMessage || m?.interactiveMessage || m?.listMessage);
86
+ };
87
+ const isForwarded = (msg) => {
88
+ var _a, _b, _c;
89
+ const m = normalise(msg);
90
+ const ctx = m?.extendedTextMessage?.contextInfo
91
+ || m?.imageMessage?.contextInfo
92
+ || m?.videoMessage?.contextInfo
93
+ || m?.documentMessage?.contextInfo
94
+ || m?.audioMessage?.contextInfo
95
+ || m?.stickerMessage?.contextInfo;
96
+ return !!((_a = ctx?.forwardingScore) !== null && _a !== void 0 ? _a : 0);
97
+ };
98
+
99
+ /**
100
+ * Returns true if the message is a view-once message
101
+ */
102
+ const isViewOnce = (msg) => {
103
+ const m = msg?.message || msg;
104
+ return !!(m?.viewOnceMessage || m?.viewOnceMessageV2 || m?.viewOnceMessageV2Extension);
105
+ };
106
+
107
+ exports.isSticker = isSticker;
108
+ exports.isImage = isImage;
109
+ exports.isVideo = isVideo;
110
+ exports.isAudio = isAudio;
111
+ exports.isDocument = isDocument;
112
+ exports.isLocation = isLocation;
113
+ exports.isLiveLocation = isLiveLocation;
114
+ exports.isContact = isContact;
115
+ exports.isReaction = isReaction;
116
+ exports.isPoll = isPoll;
117
+ exports.isGif = isGif;
118
+ exports.isButton = isButton;
119
+ exports.isForwarded = isForwarded;
120
+ exports.isViewOnce = isViewOnce;
121
+
122
+ // ─── anti-feature detectors ──────────────────────────────────────────────────
123
+
124
+ /** Anti-link: message has a URL → true */
125
+ const isAntiLink = (msg) => hasLink(msg);
126
+ /** Anti-sticker: message is a sticker → true */
127
+ const isAntiSticker = (msg) => isSticker(msg);
128
+ /** Anti-image: message is an image → true */
129
+ const isAntiImage = (msg) => isImage(msg);
130
+ /** Anti-video: message is a video → true */
131
+ const isAntiVideo = (msg) => isVideo(msg);
132
+ /** Anti-audio: message is a voice/audio note → true */
133
+ const isAntiAudio = (msg) => isAudio(msg);
134
+ /** Anti-document: message is a document/file → true */
135
+ const isAntiDocument = (msg) => isDocument(msg);
136
+ /** Anti-viewonce: message is a view-once message → true */
137
+ const isAntiViewOnce = (msg) => isViewOnce(msg);
138
+ /**
139
+ * Anti-bug: detect potentially malicious/crash messages.
140
+ * Checks for zero-width characters, extremely long strings, or malformed content.
141
+ */
142
+ const isAntiBug = (msg) => {
143
+ const text = getCaption(msg);
144
+ if (!text) return false;
145
+ // zero-width / invisible chars used in crash messages
146
+ if (/[\u200e\u200f\u200b\u200c\u200d\ufeff\u2028\u2029]/g.test(text)) return true;
147
+ // suspiciously long single "word" with no spaces
148
+ if (text.length > 2000 && !text.includes(' ')) return true;
149
+ // RTL override characters
150
+ if (/[\u202a-\u202e]/g.test(text)) return true;
151
+ return false;
152
+ };
153
+ /**
154
+ * Anti-files: message contains ANY file type (doc, audio, video, image, sticker)
155
+ */
156
+ const isAntiFiles = (msg) => isDocument(msg) || isAudio(msg) || isVideo(msg) || isImage(msg) || isSticker(msg);
157
+
158
+ exports.isAntiLink = isAntiLink;
159
+ exports.isAntiSticker = isAntiSticker;
160
+ exports.isAntiImage = isAntiImage;
161
+ exports.isAntiVideo = isAntiVideo;
162
+ exports.isAntiAudio = isAntiAudio;
163
+ exports.isAntiDocument = isAntiDocument;
164
+ exports.isAntiViewOnce = isAntiViewOnce;
165
+ exports.isAntiBug = isAntiBug;
166
+ exports.isAntiFiles = isAntiFiles;
167
+
168
+ // ─── getMessageType ──────────────────────────────────────────────────────────
169
+
170
+ /**
171
+ * Returns a human-readable type string for the message
172
+ */
173
+ const getMessageType = (msg) => {
174
+ if (isSticker(msg)) return 'sticker';
175
+ if (isImage(msg)) return 'image';
176
+ if (isGif(msg)) return 'gif';
177
+ if (isVideo(msg)) return 'video';
178
+ if (isAudio(msg)) return 'audio';
179
+ if (isDocument(msg)) return 'document';
180
+ if (isViewOnce(msg)) return 'viewonce';
181
+ if (isReaction(msg)) return 'reaction';
182
+ if (isPoll(msg)) return 'poll';
183
+ if (isLocation(msg)) return 'location';
184
+ if (isLiveLocation(msg)) return 'liveLocation';
185
+ if (isContact(msg)) return 'contact';
186
+ if (isButton(msg)) return 'button';
187
+ const m = normalise(msg);
188
+ if (m?.conversation || m?.extendedTextMessage) {
189
+ if (hasLink(msg)) return 'text-with-link';
190
+ return 'text';
191
+ }
192
+ return 'unknown';
193
+ };
194
+ exports.getMessageType = getMessageType;
195
+
196
+ /**
197
+ * Generate a simple link preview object for a URL.
198
+ * For rich previews, pass generateHighQualityLinkPreview: true in makeWASocket config.
199
+ * @param url - URL to generate preview for
200
+ * @param title - optional title
201
+ * @param description - optional description
202
+ * @param thumbnailUrl - optional thumbnail image URL
203
+ */
204
+ const generateLinkPreview = (url, title, description, thumbnailUrl) => {
205
+ return {
206
+ matchedText: url,
207
+ canonicalUrl: url,
208
+ title: title || url,
209
+ description: description || '',
210
+ jpegThumbnail: undefined,
211
+ highQualityThumbnail: thumbnailUrl ? { url: thumbnailUrl } : undefined
212
+ };
213
+ };
214
+ exports.generateLinkPreview = generateLinkPreview;
215
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "davexbaileys",
3
- "version": "2.5.15",
3
+ "version": "2.5.16",
4
4
  "description": "A lightweight, full-featured WhatsApp Web API library for Node.js — maintained by Dave Tech",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",