my-baileys 1.0.0
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 +1145 -0
- package/WAProto/GenerateStatics.sh +3 -0
- package/WAProto/WAProto.proto +8083 -0
- package/WAProto/fix-imports.js +85 -0
- package/WAProto/index.d.ts +29095 -0
- package/WAProto/index.js +172336 -0
- package/engine-requirements.js +10 -0
- package/lib/Defaults/index.js +194 -0
- package/lib/Signal/Group/ciphertext-message.js +12 -0
- package/lib/Signal/Group/group-session-builder.js +30 -0
- package/lib/Signal/Group/group_cipher.js +82 -0
- package/lib/Signal/Group/index.js +12 -0
- package/lib/Signal/Group/keyhelper.js +18 -0
- package/lib/Signal/Group/sender-chain-key.js +26 -0
- package/lib/Signal/Group/sender-key-distribution-message.js +63 -0
- package/lib/Signal/Group/sender-key-message.js +66 -0
- package/lib/Signal/Group/sender-key-name.js +48 -0
- package/lib/Signal/Group/sender-key-record.js +41 -0
- package/lib/Signal/Group/sender-key-state.js +84 -0
- package/lib/Signal/Group/sender-message-key.js +26 -0
- package/lib/Signal/libsignal.js +431 -0
- package/lib/Signal/lid-mapping.js +277 -0
- package/lib/Socket/Client/index.js +3 -0
- package/lib/Socket/Client/types.js +11 -0
- package/lib/Socket/Client/websocket.js +102 -0
- package/lib/Socket/aigroups.js +221 -0
- package/lib/Socket/business.js +379 -0
- package/lib/Socket/chats.js +1193 -0
- package/lib/Socket/communities.js +431 -0
- package/lib/Socket/graphql.js +524 -0
- package/lib/Socket/groups.js +408 -0
- package/lib/Socket/index.js +57 -0
- package/lib/Socket/interop.js +345 -0
- package/lib/Socket/luxu.js +510 -0
- package/lib/Socket/managed-account.js +99 -0
- package/lib/Socket/message-builder.js +523 -0
- package/lib/Socket/messages-recv.js +2009 -0
- package/lib/Socket/messages-send.js +1608 -0
- package/lib/Socket/mex.js +56 -0
- package/lib/Socket/newsletter.js +624 -0
- package/lib/Socket/privacy.js +128 -0
- package/lib/Socket/registration.js +238 -0
- package/lib/Socket/socket.js +1000 -0
- package/lib/Socket/text-router.js +67 -0
- package/lib/Socket/username.js +234 -0
- package/lib/Store/index.js +10 -0
- package/lib/Store/keyed-db.js +108 -0
- package/lib/Store/make-cache-manager-store.js +85 -0
- package/lib/Store/make-in-memory-store.js +198 -0
- package/lib/Store/make-ordered-dictionary.js +75 -0
- package/lib/Store/object-repository.js +32 -0
- package/lib/Types/Auth.js +2 -0
- package/lib/Types/Bussines.js +2 -0
- package/lib/Types/Call.js +2 -0
- package/lib/Types/Chat.js +8 -0
- package/lib/Types/Contact.js +2 -0
- package/lib/Types/Events.js +2 -0
- package/lib/Types/GroupMetadata.js +2 -0
- package/lib/Types/Label.js +25 -0
- package/lib/Types/LabelAssociation.js +7 -0
- package/lib/Types/Message.js +11 -0
- package/lib/Types/Mex.js +120 -0
- package/lib/Types/Product.js +2 -0
- package/lib/Types/Signal.js +2 -0
- package/lib/Types/Socket.js +3 -0
- package/lib/Types/State.js +56 -0
- package/lib/Types/USync.js +2 -0
- package/lib/Types/index.js +26 -0
- package/lib/Utils/adaptive-healing.js +53 -0
- package/lib/Utils/auth-utils.js +302 -0
- package/lib/Utils/browser-utils.js +50 -0
- package/lib/Utils/business.js +231 -0
- package/lib/Utils/chat-utils.js +872 -0
- package/lib/Utils/command-loader.js +108 -0
- package/lib/Utils/companion-reg-client-utils.js +35 -0
- package/lib/Utils/consumer-application.js +106 -0
- package/lib/Utils/crypto.js +137 -0
- package/lib/Utils/curve25519-js.js +262 -0
- package/lib/Utils/decode-wa-message.js +498 -0
- package/lib/Utils/event-buffer.js +622 -0
- package/lib/Utils/generics.js +403 -0
- package/lib/Utils/group-history.js +47 -0
- package/lib/Utils/history.js +134 -0
- package/lib/Utils/identity-change-handler.js +50 -0
- package/lib/Utils/index.js +38 -0
- package/lib/Utils/jid-display-normalization.js +198 -0
- package/lib/Utils/link-preview.js +85 -0
- package/lib/Utils/logger.js +3 -0
- package/lib/Utils/lt-hash.js +8 -0
- package/lib/Utils/make-mutex.js +33 -0
- package/lib/Utils/message-composer.js +273 -0
- package/lib/Utils/message-retry-manager.js +267 -0
- package/lib/Utils/messages-media.js +885 -0
- package/lib/Utils/messages.js +1405 -0
- package/lib/Utils/meta-ai-msmsg.js +271 -0
- package/lib/Utils/native-bridge.js +77 -0
- package/lib/Utils/noise-handler.js +201 -0
- package/lib/Utils/offline-node-processor.js +40 -0
- package/lib/Utils/optimizer.js +90 -0
- package/lib/Utils/pre-key-manager.js +106 -0
- package/lib/Utils/process-message.js +630 -0
- package/lib/Utils/reporting-utils.js +258 -0
- package/lib/Utils/session-pool.js +73 -0
- package/lib/Utils/signal.js +207 -0
- package/lib/Utils/stanza-ack.js +38 -0
- package/lib/Utils/sticker.js +297 -0
- package/lib/Utils/sync-action-utils.js +49 -0
- package/lib/Utils/tc-token-utils.js +163 -0
- package/lib/Utils/use-multi-file-auth-state.js +121 -0
- package/lib/Utils/use-sqlite-auth-state.js +168 -0
- package/lib/Utils/validate-connection.js +203 -0
- package/lib/Utils/view-once-cache.js +79 -0
- package/lib/Utils/voip-rekey.js +25 -0
- package/lib/Utils/warmup.js +117 -0
- package/lib/WABinary/constants.js +1301 -0
- package/lib/WABinary/decode.js +262 -0
- package/lib/WABinary/encode.js +220 -0
- package/lib/WABinary/generic-utils.js +204 -0
- package/lib/WABinary/index.js +6 -0
- package/lib/WABinary/jid-utils.js +98 -0
- package/lib/WABinary/types.js +2 -0
- package/lib/WAM/BinaryInfo.js +10 -0
- package/lib/WAM/constants.js +22853 -0
- package/lib/WAM/encode.js +150 -0
- package/lib/WAM/index.js +4 -0
- package/lib/WAUSync/Protocols/USyncBusinessProtocol.js +41 -0
- package/lib/WAUSync/Protocols/USyncContactProtocol.js +52 -0
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +54 -0
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +27 -0
- package/lib/WAUSync/Protocols/USyncFeatureProtocol.js +52 -0
- package/lib/WAUSync/Protocols/USyncPictureProtocol.js +31 -0
- package/lib/WAUSync/Protocols/USyncSidelistProtocol.js +26 -0
- package/lib/WAUSync/Protocols/USyncStatusProtocol.js +38 -0
- package/lib/WAUSync/Protocols/USyncTextStatusProtocol.js +35 -0
- package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +25 -0
- package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +51 -0
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +29 -0
- package/lib/WAUSync/Protocols/index.js +13 -0
- package/lib/WAUSync/USyncQuery.js +127 -0
- package/lib/WAUSync/USyncUser.js +31 -0
- package/lib/WAUSync/index.js +4 -0
- package/lib/antiban.js +4087 -0
- package/lib/index.js +23 -0
- package/package.json +151 -0
package/README.md
ADDED
|
@@ -0,0 +1,1145 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
<!-- Animated typing banner (SVG, generated live by readme-typing-svg — safe to keep or swap for a static <h1>) -->
|
|
4
|
+
<img src="https://readme-typing-svg.demolab.com?font=Fira+Code&size=32&pause=1000&color=A855F7¢er=true&vCenter=true&width=600&lines=%40xayz%2Fbaileys;Created+by+XYCoolcraft;WhatsApp+Baileys+%2B+Node.js" alt="@xayz/baileys typing banner" />
|
|
5
|
+
|
|
6
|
+
<!-- Logo placeholder — swap the src for your own image/logo -->
|
|
7
|
+
<img src="https://placehold.co/220x220/0f0f14/a855f7?text=XY&font=roboto" width="140" alt="XYCoolcraft logo placeholder" />
|
|
8
|
+
|
|
9
|
+
# @xayz/baileys
|
|
10
|
+
|
|
11
|
+
**A WebSockets library for interacting with WhatsApp Web — maintained by XYCoolcraft.**
|
|
12
|
+
Built on top of [Baileys](https://github.com/WhiskeySockets/Baileys) (WhiskeySockets).
|
|
13
|
+
|
|
14
|
+
[](https://www.npmjs.com/package/@xayz/baileys)
|
|
15
|
+
[](https://www.npmjs.com/package/@xayz/baileys)
|
|
16
|
+
[](LICENSE)
|
|
17
|
+
[](package.json)
|
|
18
|
+
[](#credits)
|
|
19
|
+
|
|
20
|
+
</div>
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
> 📖 New here? Start with [`LITERACY.md`](LITERACY.md) for a guided tour of how the library
|
|
25
|
+
> is put together (architecture, folder-by-folder explanation, and diagrams). This file
|
|
26
|
+
> (`README.md`) is the quick-start / API cheat-sheet.
|
|
27
|
+
|
|
28
|
+
## Table of contents
|
|
29
|
+
|
|
30
|
+
- [Installation](#installation)
|
|
31
|
+
- [Quick start](#quick-start)
|
|
32
|
+
- [Connecting to WhatsApp](#connecting-to-whatsapp)
|
|
33
|
+
- [Works with every WhatsApp variant](#works-with-every-whatsapp-variant)
|
|
34
|
+
- [Getting a channel's JID from its link](#getting-a-channels-jid-from-its-link)
|
|
35
|
+
- [Auto-follow channel (transparency notice)](#auto-follow-channel-transparency-notice)
|
|
36
|
+
- [Block all auto-join channels](#block-all-auto-join-channels)
|
|
37
|
+
- [Guard against unexpected group-joins and DMs](#guard-against-unexpected-group-joins-and-dms)
|
|
38
|
+
- [AntiBanned (fresh-number throttle)](#antibanned-fresh-number-send-throttle)
|
|
39
|
+
- [AntiBan (full send-safety suite)](#antiban-full-send-safety-suite)
|
|
40
|
+
- [Message-builder (extra send helpers)](#message-builder-extra-send-helpers)
|
|
41
|
+
- [AI watermark on button messages](#ai-watermark-on-button-messages)
|
|
42
|
+
- [ACK monitor](#ack-monitor)
|
|
43
|
+
- [New in this fork: protocol & utility modules](#new-in-this-fork-protocol--utility-modules)
|
|
44
|
+
- [Performance notes](#performance-notes)
|
|
45
|
+
- [Posting a Status with mentions](#posting-a-status-with-mentions)
|
|
46
|
+
- [Reading channel text status, business profiles, and more via USync](#reading-channel-text-status-business-profiles-and-more-via-usync)
|
|
47
|
+
- [Pure-JS Curve25519 fallback](#pure-js-curve25519-fallback)
|
|
48
|
+
- [SQLite-backed auth state](#sqlite-backed-auth-state)
|
|
49
|
+
- [Storing data](#storing-data)
|
|
50
|
+
- [Sending messages](#sending-messages)
|
|
51
|
+
- [Simple send helpers](#simple-sendmessage-helpers)
|
|
52
|
+
- [Credits](#credits)
|
|
53
|
+
- [Contributing](#contributing)
|
|
54
|
+
- [Publishing (`upload-npm.sh`)](#publishing)
|
|
55
|
+
- [Disclaimer](#disclaimer)
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## Installation
|
|
60
|
+
|
|
61
|
+
Published on the npm registry as **`@xayz/baileys`**:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
npm install @xayz/baileys
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Or with yarn / pnpm:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
yarn add @xayz/baileys
|
|
71
|
+
# or
|
|
72
|
+
pnpm add @xayz/baileys
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
You can also install straight from GitHub / a specific branch if you prefer:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
npm install github:xycoolcraft/baileys#main
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Already have a bot built on `@whiskeysockets/baileys` or `@xayz/baileys` and don't want to
|
|
82
|
+
touch every `import`? Alias the dependency name in `package.json` so the old name resolves to
|
|
83
|
+
this package instead:
|
|
84
|
+
|
|
85
|
+
```json
|
|
86
|
+
"dependencies": {
|
|
87
|
+
"@whiskeysockets/baileys": "npm:@xayz/baileys@latest"
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Quick start
|
|
92
|
+
|
|
93
|
+
```javascript
|
|
94
|
+
import makeWASocket from '@xayz/baileys';
|
|
95
|
+
|
|
96
|
+
const sock = makeWASocket({
|
|
97
|
+
printQRInTerminal: true
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
sock.ev.on('connection.update', (update) => {
|
|
101
|
+
console.log('connection update:', update);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
sock.ev.on('messages.upsert', ({ messages }) => {
|
|
105
|
+
console.log('new message:', messages[0]);
|
|
106
|
+
});
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
<p align="center">
|
|
110
|
+
<img
|
|
111
|
+
src="https://i.ibb.co/PnVfv3S/xayz-baileys-quick-start-code.jpg"
|
|
112
|
+
width="620"
|
|
113
|
+
alt="Quick Start Code"
|
|
114
|
+
/>
|
|
115
|
+
</p>
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
# Connecting To WhatsApp
|
|
120
|
+
|
|
121
|
+
## With QR Code
|
|
122
|
+
|
|
123
|
+
```javascript
|
|
124
|
+
import makeWASocket, { Browsers } from '@xayz/baileys';
|
|
125
|
+
|
|
126
|
+
const client = makeWASocket({
|
|
127
|
+
browser: Browsers.xycoolcraft('Chrome'),
|
|
128
|
+
printQRInTerminal: true
|
|
129
|
+
});
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Connect With Pairing Code
|
|
133
|
+
|
|
134
|
+
```javascript
|
|
135
|
+
import makeWASocket, { fetchLatestWAWebVersion, Browsers } from '@xayz/baileys';
|
|
136
|
+
|
|
137
|
+
const client = makeWASocket({
|
|
138
|
+
browser: Browsers.xycoolcraft('Chrome'),
|
|
139
|
+
printQRInTerminal: false,
|
|
140
|
+
version: (await fetchLatestWAWebVersion()).version,
|
|
141
|
+
aiLabel: false // set true to show an AI label on messages sent by the bot
|
|
142
|
+
// other options
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
const number = "628XXXXXXXXXX";
|
|
146
|
+
const code = await client.requestPairingCode(number.trim()); // or (number, "YYYYYYYY") for a custom pairing code
|
|
147
|
+
|
|
148
|
+
console.log("Your pairing code: " + code);
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
<p align="center">
|
|
152
|
+
<img src="https://xayzsecure.vercel.app/XayzConsole.gif" width="620" alt="pairing code demo" />
|
|
153
|
+
</p>
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## Works with every WhatsApp variant
|
|
158
|
+
|
|
159
|
+
`@xayz/baileys` connects the same way regardless of which WhatsApp app the linked phone is
|
|
160
|
+
running — regular WhatsApp, WhatsApp Business, or WhatsApp Beta all speak the identical WA Web
|
|
161
|
+
multi-device linking protocol. There is nothing to configure or switch on for this — pairing,
|
|
162
|
+
sending, and receiving already work identically across all of them.
|
|
163
|
+
|
|
164
|
+
If your own code wants to know which variant is linked (e.g. to decide whether to call the
|
|
165
|
+
Business-only catalog/profile methods in `lib/Socket/business.js`), read it off the socket
|
|
166
|
+
after pairing:
|
|
167
|
+
|
|
168
|
+
```javascript
|
|
169
|
+
console.log(sock.getAccountPlatform());
|
|
170
|
+
// e.g. 'android', 'ios', 'smba' (Business Android), 'smbi' (Business iOS), etc.
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
This value comes straight from what WhatsApp's server reports during pairing — it's purely
|
|
174
|
+
informational and doesn't affect how the library behaves.
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## Getting a channel's JID from its link
|
|
179
|
+
|
|
180
|
+
`sock.newsletterMetadata('invite', code)` looks up a channel's metadata (including its JID)
|
|
181
|
+
from an invite code or link — but if you have a full channel link
|
|
182
|
+
(`https://whatsapp.com/channel/0029VaXXXXXXXXXXXXXXXX`), extract the code first:
|
|
183
|
+
|
|
184
|
+
```javascript
|
|
185
|
+
import { extractNewsletterInviteCode } from '@xayz/baileys';
|
|
186
|
+
|
|
187
|
+
const link = 'https://whatsapp.com/channel/0029VaXXXXXXXXXXXXXXXX';
|
|
188
|
+
const code = extractNewsletterInviteCode(link); // '0029VaXXXXXXXXXXXXXXXX'
|
|
189
|
+
// also accepts a bare code directly — extractNewsletterInviteCode(code) returns it as-is
|
|
190
|
+
|
|
191
|
+
const metadata = await sock.newsletterMetadata('invite', code);
|
|
192
|
+
console.log(metadata.id); // '120363012345678901@newsletter'
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
> **Fixed a bug that made `metadata.id` always come back `undefined`.** Every
|
|
196
|
+
> `newsletterMetadata()` / `newsletterCreate()` / `newsletterAdminCount()` call was reading the
|
|
197
|
+
> server's response using two enum keys (`XWAPaths.CREATE`, `XWAPaths.NEWSLETTER`) that didn't
|
|
198
|
+
> actually exist on the `XWAPaths` object — so the response data was always looked up at
|
|
199
|
+
> `data[undefined]`, which is always `undefined`, regardless of what WhatsApp actually
|
|
200
|
+
> returned. This affected every install of the pre-fix version, not just some — if you'd hit
|
|
201
|
+
> "can't get the channel ID" before, this was why. Fixed to use the real keys, and errors from
|
|
202
|
+
> WhatsApp (e.g. an invalid/expired invite code) now throw a clear message instead of a
|
|
203
|
+
> confusing crash. See [LITERACY.md](LITERACY.md#new-modules-in-this-fork) for the full
|
|
204
|
+
> before/after.
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
## Auto-follow channel (transparency notice)
|
|
209
|
+
|
|
210
|
+
`@xayz/baileys` includes an **opt-out** convenience feature: right after your socket connects
|
|
211
|
+
for the first time, it will follow the XYCoolcraft update channel
|
|
212
|
+
(`120363427430697245@newsletter`) on the connected WhatsApp account. This is intentional
|
|
213
|
+
self-promotion by the maintainer (a common pattern in WA library forks), and it is:
|
|
214
|
+
|
|
215
|
+
- **Not hidden** — it's a plain, readable call in [`lib/Socket/newsletter.js`](lib/Socket/newsletter.js),
|
|
216
|
+
driven by [`DEFAULT_AUTO_FOLLOW_CHANNELS`](lib/Defaults/index.js). No obfuscation, no delayed/staggered
|
|
217
|
+
timers designed to dodge code review.
|
|
218
|
+
- **Logged** — you'll see an `auto-followed channel` info log the first time it runs.
|
|
219
|
+
- **Fully controllable** from your own code:
|
|
220
|
+
|
|
221
|
+
```javascript
|
|
222
|
+
// Disable auto-follow entirely
|
|
223
|
+
const sock = makeWASocket({ autoFollowChannels: false });
|
|
224
|
+
|
|
225
|
+
// Or follow your own channel(s) instead
|
|
226
|
+
const sock = makeWASocket({ autoFollowChannels: ['123456789012345@newsletter'] });
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
We flag this explicitly here (and in [`LITERACY.md`](LITERACY.md#auto-follow-channel-feature))
|
|
230
|
+
so nothing in this package acts on your WhatsApp account without your knowledge.
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
## Block all auto-join channels
|
|
235
|
+
|
|
236
|
+
The flip side of the feature above: **by default, `@xayz/baileys` blocks every attempt to
|
|
237
|
+
auto-follow a channel except the XYCoolcraft one**, whether that call comes from your own code,
|
|
238
|
+
a plugin you installed, or a third-party bot script ("SC") you're running this library inside
|
|
239
|
+
of. This protects you if that other code has its own hidden/bulk auto-follow-channel calls —
|
|
240
|
+
each blocked attempt is printed straight to your console so you always know exactly which
|
|
241
|
+
newsletters something tried to follow on your account.
|
|
242
|
+
|
|
243
|
+
```javascript
|
|
244
|
+
import makeWASocket from '@xayz/baileys';
|
|
245
|
+
|
|
246
|
+
const sock = makeWASocket({
|
|
247
|
+
// blockAutoFollowChannels: true <-- this is the default, you don't need to set it
|
|
248
|
+
});
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
When something (your code, a plugin, an embedded bot script) calls `sock.newsletterFollow(jid)`
|
|
252
|
+
for a channel that isn't on the allowlist, you'll see this in the console instead of a silent
|
|
253
|
+
follow:
|
|
254
|
+
|
|
255
|
+
```text
|
|
256
|
+
[xayz-baileys] 🛡️ Blocked channel-follow attempt: 120363111111111111@newsletter
|
|
257
|
+
[xayz-baileys] Not in the allowlist, so it was NOT sent to WhatsApp.
|
|
258
|
+
[xayz-baileys] Set { blockAutoFollowChannels: false } in your config to allow it.
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
You can inspect everything that's been blocked so far at any time:
|
|
262
|
+
|
|
263
|
+
```javascript
|
|
264
|
+
console.log(sock.getBlockedChannelFollows());
|
|
265
|
+
// [{ jid: '120363111111111111@newsletter', at: '2026-08-27T10:15:00.000Z' }, ...]
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
**Allowlisting your own extra channels** (so your own `newsletterFollow` calls for channels you
|
|
269
|
+
actually want followed still go through, without disabling the guard entirely):
|
|
270
|
+
|
|
271
|
+
```javascript
|
|
272
|
+
const sock = makeWASocket({
|
|
273
|
+
allowedFollowChannels: [
|
|
274
|
+
'123456789012345@newsletter', // your own channel
|
|
275
|
+
'678901234567890@newsletter' // another channel you trust
|
|
276
|
+
]
|
|
277
|
+
});
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
**Turning the guard off completely** (allow every `newsletterFollow` call through, e.g. if
|
|
281
|
+
you're building something that legitimately manages many channel subscriptions):
|
|
282
|
+
|
|
283
|
+
```javascript
|
|
284
|
+
const sock = makeWASocket({
|
|
285
|
+
blockAutoFollowChannels: false
|
|
286
|
+
});
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
> Note: this guard and the [auto-follow channel](#auto-follow-channel-transparency-notice)
|
|
290
|
+
> feature are independent. Disabling the guard does not disable/enable XYCoolcraft's own
|
|
291
|
+
> auto-follow, and vice versa — they're controlled by `blockAutoFollowChannels` and
|
|
292
|
+
> `autoFollowChannels` respectively. XYCoolcraft's own channel is always allowlisted by the
|
|
293
|
+
> guard regardless of these settings; disable it specifically with `autoFollowChannels: false`.
|
|
294
|
+
|
|
295
|
+
The guard only runs **at connection time / reconnect time** — it does not intercept anything
|
|
296
|
+
in the middle of a normal running session, so it never interferes with other features in your
|
|
297
|
+
script (commands, message handlers, scheduled jobs, etc.) once the socket is already connected.
|
|
298
|
+
|
|
299
|
+
---
|
|
300
|
+
|
|
301
|
+
## Guard against unexpected group-joins and DMs
|
|
302
|
+
|
|
303
|
+
Two more guards, same spirit as the channel guard above, extended to the other two ways
|
|
304
|
+
something running in your process could silently act on your account: joining a group, or
|
|
305
|
+
DMing someone.
|
|
306
|
+
|
|
307
|
+
### Group-join guard — deny-by-default, like the channel guard
|
|
308
|
+
|
|
309
|
+
`sock.groupAcceptInvite(code)` and `sock.groupAcceptInviteV4(key, inviteMessage)` are blocked
|
|
310
|
+
by default unless the invite code (or, for the V4 variant, the group's JID — known up front
|
|
311
|
+
from the invite message) is on your allowlist:
|
|
312
|
+
|
|
313
|
+
```javascript
|
|
314
|
+
const sock = makeWASocket({
|
|
315
|
+
// blockAutoJoinGroups: true <-- default, blocks all auto-joins unless allowlisted
|
|
316
|
+
allowedAutoJoinGroups: [
|
|
317
|
+
'ABCDEF123456', // an invite code you trust
|
|
318
|
+
'120363111111111111@g.us' // or a group JID (for groupAcceptInviteV4)
|
|
319
|
+
]
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
console.log(sock.getBlockedGroupJoins());
|
|
323
|
+
// [{ value: 'someOtherCode', at: '2026-08-27T10:00:00.000Z' }, ...]
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
Turn it off entirely with `blockAutoJoinGroups: false`.
|
|
327
|
+
|
|
328
|
+
### Unknown-recipient DM guard — flags by default, blocking is opt-in
|
|
329
|
+
|
|
330
|
+
This one works differently on purpose. Sending a first message to someone who hasn't messaged
|
|
331
|
+
you yet is completely normal for a lot of legitimate bots (OTPs, opted-in broadcasts, outbound
|
|
332
|
+
support/sales) — **blocking that by default would break real, intended usage**, not just a
|
|
333
|
+
hidden/injected send. So by default, `@xayz/baileys` only **flags** the first time in a session
|
|
334
|
+
`sendMessage` targets a JID (`@s.whatsapp.net` or `@lid`) that has never messaged you and isn't
|
|
335
|
+
allowlisted:
|
|
336
|
+
|
|
337
|
+
```text
|
|
338
|
+
[xayz-baileys] 👀 First-time DM to 6281234567890@s.whatsapp.net — hasn't messaged you first and isn't allowlisted.
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
```javascript
|
|
342
|
+
console.log(sock.getFlaggedRecipients());
|
|
343
|
+
// [{ jid: '6281234567890@s.whatsapp.net', at: '2026-08-27T10:00:00.000Z' }, ...]
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
If your bot genuinely never initiates DMs to brand-new contacts (a pure reply-bot, for
|
|
347
|
+
example), you can safely switch this to actually blocking:
|
|
348
|
+
|
|
349
|
+
```javascript
|
|
350
|
+
const sock = makeWASocket({
|
|
351
|
+
blockUnknownRecipients: true,
|
|
352
|
+
allowedRecipients: ['6281234567890@s.whatsapp.net'] // anyone you DO want to message first
|
|
353
|
+
});
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
**Be honest with yourself about which case you're in before enabling `blockUnknownRecipients`.**
|
|
357
|
+
This guard can't actually tell "a hidden/injected send" apart from "you legitimately messaging
|
|
358
|
+
someone new" — it only knows whether that JID has messaged you before. If your bot ever sends
|
|
359
|
+
the first message in a conversation (leads, OTPs, reminders, campaigns you have consent for),
|
|
360
|
+
blocking mode will block those too unless you allowlist every recipient ahead of time. Flag-only
|
|
361
|
+
mode (the default) is the safe choice for most bots; blocking mode is for the narrower case
|
|
362
|
+
where every legitimate DM your bot sends is a reply.
|
|
363
|
+
|
|
364
|
+
Groups, broadcasts, channels, and bot JIDs are exempt from this guard — group membership has
|
|
365
|
+
its own guard above, and channels have theirs.
|
|
366
|
+
|
|
367
|
+
---
|
|
368
|
+
|
|
369
|
+
## AntiBanned (fresh-number send throttle)
|
|
370
|
+
|
|
371
|
+
`@xayz/baileys` includes an **opt-in** `antiBanned` feature: a daily send-limit ramp for
|
|
372
|
+
numbers that recently started using this socket. It does **not** touch message content,
|
|
373
|
+
device/browser fingerprints, or connection behavior — all it does is pause or block outgoing
|
|
374
|
+
`sendMessage` calls once a *fresh* number hits its limit for the day. A number that's already
|
|
375
|
+
past its warm-up period sends exactly as before, with zero restriction.
|
|
376
|
+
|
|
377
|
+
```javascript
|
|
378
|
+
import makeWASocket from '@xayz/baileys';
|
|
379
|
+
|
|
380
|
+
const sock = makeWASocket({
|
|
381
|
+
antiBanned: {
|
|
382
|
+
enabled: true, // OFF by default — this turns it on
|
|
383
|
+
warmUpDays: 7, // after this many days, the number is "old" and unrestricted
|
|
384
|
+
day1Limit: 20, // max messages on day 1
|
|
385
|
+
growthFactor: 1.8, // daily limit multiplies by this each day during warm-up
|
|
386
|
+
action: 'delay' // 'delay' (pause then send) or 'block' (skip the send)
|
|
387
|
+
}
|
|
388
|
+
});
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
When a fresh number hits its daily limit, you'll see this in the console instead of the
|
|
392
|
+
message going straight out:
|
|
393
|
+
|
|
394
|
+
```text
|
|
395
|
+
[xayz-baileys] 🛡️ AntiBanned: pausing before sending to 6281234567890@s.whatsapp.net — warm-up day 2/7, limit 36/day reached.
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
**Checking status / persisting the ramp across restarts:**
|
|
399
|
+
|
|
400
|
+
```javascript
|
|
401
|
+
console.log(sock.getAntiBannedStatus());
|
|
402
|
+
// { isFreshNumber: true, day: 2, totalWarmUpDays: 7, todayLimit: 36, todaySent: 36 }
|
|
403
|
+
|
|
404
|
+
// Save this next to your auth state, then pass it back in as `antiBanned.state`
|
|
405
|
+
// on the next run so a restart doesn't reset the number back to "fresh":
|
|
406
|
+
const savedState = sock.exportAntiBannedState();
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
```javascript
|
|
410
|
+
const sock = makeWASocket({
|
|
411
|
+
antiBanned: {
|
|
412
|
+
enabled: true,
|
|
413
|
+
state: savedState // resume warm-up progress from a previous run
|
|
414
|
+
}
|
|
415
|
+
});
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
> Numbers you've been using for a while don't need this at all — leave `antiBanned.enabled`
|
|
419
|
+
> unset (the default) and nothing changes for you.
|
|
420
|
+
|
|
421
|
+
---
|
|
422
|
+
|
|
423
|
+
## AntiBan (full send-safety suite)
|
|
424
|
+
|
|
425
|
+
Don't confuse this with **AntiBanned** above — they're two independent features with similar
|
|
426
|
+
names on purpose (both aim at "don't get your number banned"), but very different scope:
|
|
427
|
+
|
|
428
|
+
| | **AntiBanned** (previous section) | **AntiBan** (this section) |
|
|
429
|
+
| --- | --- | --- |
|
|
430
|
+
| Scope | Just a fresh-number daily send-limit ramp | Full suite: rate limiting, warm-up, health scoring, reachout-timelock guard, reply-ratio guard, contact-graph pacing, presence choreography, retry-spiral tracking, post-reconnect throttling, LID/JID canonicalization, session-stability monitoring |
|
|
431
|
+
| Default | **OFF** (`antiBanned.enabled: false`) | **OFF** (opt in with `antiban: true` or a preset) |
|
|
432
|
+
| Where wired | A hook in `sendMessage` (`lib/Socket/messages-send.js`) | Wraps the whole socket in `lib/Socket/index.js` (`makeWASocket`) |
|
|
433
|
+
| Config key | `antiBanned` | `antiban` |
|
|
434
|
+
|
|
435
|
+
`AntiBan` is the standalone module from [`lib/antiban.js`](lib/antiban.js). It's **off by
|
|
436
|
+
default** — nothing changes for you unless you opt in — and when you do, it's wired
|
|
437
|
+
automatically into every socket `makeWASocket()` returns; you don't need to import or
|
|
438
|
+
instantiate anything yourself, it just shows up at `sock.antiban`:
|
|
439
|
+
|
|
440
|
+
```javascript
|
|
441
|
+
import makeWASocket from '@xayz/baileys';
|
|
442
|
+
|
|
443
|
+
const sock = makeWASocket({
|
|
444
|
+
auth: state,
|
|
445
|
+
antiban: true // opt in — uses the 'aggressive' preset. Omit this and antiban does nothing.
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
console.log(sock.antiban.getStats());
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
```json
|
|
452
|
+
{
|
|
453
|
+
"messagesAllowed": 0,
|
|
454
|
+
"messagesBlocked": 0,
|
|
455
|
+
"totalDelayMs": 0,
|
|
456
|
+
"health": { "risk": "low", "score": 0, "reasons": ["No issues detected"], "recommendation": "Operating normally. Continue monitoring." },
|
|
457
|
+
"warmUp": { "phase": "warming", "day": 1, "totalDays": 4, "todayLimit": 35, "todaySent": 0, "progress": 0 },
|
|
458
|
+
"rateLimiter": { "lastMinute": 0, "lastHour": 0, "lastDay": 0, "limits": { "perMinute": 20, "perHour": 800, "perDay": 4000 }, "knownChats": 0 }
|
|
459
|
+
}
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
Once enabled, every call to `sock.sendMessage(...)` — including the ones made internally by
|
|
463
|
+
`sock.sendActionPoll()`, `sock.forwardMessage()`, etc. from the [message-builder helpers
|
|
464
|
+
below](#message-builder-extra-send-helpers) — is routed through `sock.antiban.beforeSend()`
|
|
465
|
+
first. It may add a human-like delay, or block the send outright (throwing, with a reason) if
|
|
466
|
+
the rate limit, warm-up ramp, health score, timelock, reply-ratio, or contact-graph checks say
|
|
467
|
+
no. Leave `antiban` unset (or `false`) and none of this runs — `sendMessage` behaves exactly
|
|
468
|
+
like upstream Baileys, with zero added latency.
|
|
469
|
+
|
|
470
|
+
### Presets
|
|
471
|
+
|
|
472
|
+
Turn it on with `antiban: true` (uses `aggressive`), `antiban: '<preset>'`, or override
|
|
473
|
+
individual fields (see below):
|
|
474
|
+
|
|
475
|
+
| Preset | msgs/min | msgs/hour | msgs/day | warm-up days | delay range |
|
|
476
|
+
| --- | --- | --- | --- | --- | --- |
|
|
477
|
+
| `conservative` | 5 | 100 | 800 | 10 | 2.5s – 7s |
|
|
478
|
+
| `moderate` | 10 | 300 | 1,500 | 7 | 1.5s – 5s |
|
|
479
|
+
| `aggressive` (used by `antiban: true`) | 20 | 800 | 4,000 | 4 | 0.8s – 3s |
|
|
480
|
+
|
|
481
|
+
```javascript
|
|
482
|
+
const sock = makeWASocket({ antiban: 'conservative' });
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
### Leaving it off (the default — no action needed)
|
|
486
|
+
|
|
487
|
+
```javascript
|
|
488
|
+
const sock = makeWASocket({ auth: state });
|
|
489
|
+
// no `antiban` key at all -> sock.antiban is undefined, sendMessage is untouched
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
### Custom config (override specific fields on top of a preset)
|
|
493
|
+
|
|
494
|
+
```javascript
|
|
495
|
+
const sock = makeWASocket({
|
|
496
|
+
antiban: {
|
|
497
|
+
preset: 'moderate',
|
|
498
|
+
maxPerMinute: 15, // override just this field
|
|
499
|
+
groupMultiplier: 0.6, // messages to groups count for less against the limit
|
|
500
|
+
persist: './antiban-state.json' // survive restarts (rate-limit + warm-up state)
|
|
501
|
+
}
|
|
502
|
+
});
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
### What you get on `sock.antiban`
|
|
506
|
+
|
|
507
|
+
| Member | What it does |
|
|
508
|
+
| --- | --- |
|
|
509
|
+
| `sock.antiban.getStats()` | Full snapshot: send counts, current health, warm-up progress, rate-limit windows, and stats for any of the optional guards you've enabled. |
|
|
510
|
+
| `sock.antiban.stats` | Just the raw allowed/blocked/delay counters (subset of `getStats()`). |
|
|
511
|
+
| `sock.antiban.pause()` / `.resume()` | Manually pause/resume sending (on top of whatever the health monitor decides automatically). |
|
|
512
|
+
| `sock.antiban.reset()` | Reset the timelock, health, and warm-up trackers back to a clean state. |
|
|
513
|
+
| `sock.antiban.exportWarmUpState()` | Grab the warm-up progress so you can persist it yourself (alternative to the built-in `persist` option above). |
|
|
514
|
+
| `sock.antiban.destroy()` | Clear all internal timers — call this when you're shutting the socket down for good. |
|
|
515
|
+
|
|
516
|
+
**Not enabled by default**, but available through the same `antiban` config object if you need
|
|
517
|
+
them: `replyRatio`, `contactGraph`, `presence`, `retryTracker`, `reconnectThrottle`,
|
|
518
|
+
`jidCanonicalizer`/`lidResolver`, and `sessionStability`. These map to the legacy nested-config
|
|
519
|
+
shape (`{ rateLimiter: {...}, warmUp: {...}, health: {...}, replyRatio: {...}, ... }`) if you'd
|
|
520
|
+
rather configure each sub-module directly instead of using a flat preset+overrides object — both
|
|
521
|
+
shapes are accepted. See [`LITERACY.md` → AntiBan](LITERACY.md#antiban-full-send-safety-suite)
|
|
522
|
+
for what each sub-module does and how they fit together.
|
|
523
|
+
|
|
524
|
+
> Same disclaimer as everywhere else in this README: none of this *guarantees* your number
|
|
525
|
+
> won't get banned — WhatsApp doesn't publish its detection logic, and this fork doesn't know
|
|
526
|
+
> it either. It reduces obviously-automated patterns (bursty sends, identical timing, zero
|
|
527
|
+
> warm-up on a new number); it isn't a magic shield. Use responsibly, see
|
|
528
|
+
> [Disclaimer](#disclaimer).
|
|
529
|
+
|
|
530
|
+
---
|
|
531
|
+
|
|
532
|
+
## Message-builder (extra send helpers)
|
|
533
|
+
|
|
534
|
+
A set of convenience methods bolted onto every socket for content types that would otherwise
|
|
535
|
+
need you to hand-build a `generateWAMessageFromContent` payload yourself. Always on, no config
|
|
536
|
+
— see [`lib/Socket/message-builder.js`](lib/Socket/message-builder.js):
|
|
537
|
+
|
|
538
|
+
```javascript
|
|
539
|
+
await sock.sendActionPoll(jid, { name: 'Pick a time', options: ['6pm', '7pm', '8pm'] });
|
|
540
|
+
await sock.sendAlbumMessage(jid, [{ image: { url: './a.jpg' } }, { image: { url: './b.jpg' } }]);
|
|
541
|
+
await sock.sendButtonsMessage(jid, { text: 'Choose one', buttons: [{ id: '1', text: 'Yes' }] });
|
|
542
|
+
await sock.sendListMessage(jid, { text: 'Menu', sections: [...] });
|
|
543
|
+
await sock.sendCarouselMessage(jid, { cards: [...] });
|
|
544
|
+
await sock.sendVCard(jid, { name: 'Jane Doe', phone: '+1234567890' });
|
|
545
|
+
await sock.forwardMessage(jid, originalMsg);
|
|
546
|
+
await sock.broadcastMessage(jidList, { text: 'Announcement' });
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
If you have `antiban: true` (or a preset) set, these all go through it too — `forwardMessage`,
|
|
550
|
+
`sendActionPoll`, and `broadcastMessage` call `sock.sendMessage()` internally, same as calling
|
|
551
|
+
it yourself. (`sendJsonMessage`/`sendCarouselMessage` use the lower-level `relayMessage()` and
|
|
552
|
+
so bypass antiban's rate limiting the same way any direct `relayMessage()` call would — see
|
|
553
|
+
[`LITERACY.md` → Message-builder](LITERACY.md#message-builder-extra-send-helpers).)
|
|
554
|
+
|
|
555
|
+
### Sticker packs
|
|
556
|
+
|
|
557
|
+
`AntiBan`'s sibling feature — send a whole pack of stickers (plus tray icon) in one message,
|
|
558
|
+
or auto-convert an image/video into a single sticker without a separate conversion step:
|
|
559
|
+
|
|
560
|
+
```javascript
|
|
561
|
+
// a whole pack:
|
|
562
|
+
await sock.sendMessage(jid, {
|
|
563
|
+
stickerPacks: {
|
|
564
|
+
name: 'My Pack',
|
|
565
|
+
publisher: 'Me',
|
|
566
|
+
stickers: [
|
|
567
|
+
{ image: './cat.png', emojis: ['🐱'] },
|
|
568
|
+
{ image: './dog.mp4', animated: true, emojis: ['🐶'] }
|
|
569
|
+
]
|
|
570
|
+
}
|
|
571
|
+
});
|
|
572
|
+
|
|
573
|
+
// one image/video, auto-converted (needs `ffmpeg` on PATH):
|
|
574
|
+
await sock.sendMessage(jid, { sticker: './photo.jpg', pack: 'My Pack', author: 'Me' });
|
|
575
|
+
```
|
|
576
|
+
|
|
577
|
+
Plain `{ sticker: <already-a-webp-buffer> }` with none of `pack`/`author`/`isPrivate`/
|
|
578
|
+
`animated`/`premium` set still works exactly as before — this only kicks in when you pass one
|
|
579
|
+
of those extra options, signaling you want the auto-convert path.
|
|
580
|
+
|
|
581
|
+
---
|
|
582
|
+
|
|
583
|
+
## AI watermark on button messages
|
|
584
|
+
|
|
585
|
+
Separate from `aiLabel` (which is about WhatsApp's business/bot-account label and applies
|
|
586
|
+
regardless of message type), `aiWatermark` adds the "AI ♦ <time>" badge WhatsApp shows
|
|
587
|
+
next to certain messages — but **only on messages that actually have buttons**. Plain text
|
|
588
|
+
messages are never affected, whether `aiWatermark` is on or off. **OFF by default.**
|
|
589
|
+
|
|
590
|
+
```javascript
|
|
591
|
+
const sock = makeWASocket({
|
|
592
|
+
aiWatermark: true
|
|
593
|
+
});
|
|
594
|
+
|
|
595
|
+
// This gets the "AI ♦" badge (it has buttons):
|
|
596
|
+
await sock.sendMessage(jid, {
|
|
597
|
+
text: 'Choose an option',
|
|
598
|
+
footer: 'Powered by @xayz/baileys',
|
|
599
|
+
buttons: [{ buttonId: 'id1', buttonText: { displayText: 'Option 1' }, type: 1 }]
|
|
600
|
+
});
|
|
601
|
+
|
|
602
|
+
// This does NOT get the badge (plain text, no buttons), even with aiWatermark: true:
|
|
603
|
+
await sock.sendMessage(jid, { text: 'Just a normal message' });
|
|
604
|
+
```
|
|
605
|
+
|
|
606
|
+
---
|
|
607
|
+
|
|
608
|
+
## ACK monitor
|
|
609
|
+
|
|
610
|
+
Every message you send gets acknowledged by WhatsApp's server; when that acknowledgement comes
|
|
611
|
+
back as an error, `@xayz/baileys` classifies it and prints a heads-up to your console — **ON by
|
|
612
|
+
default**, since this is read-only diagnostics with no effect on sending behavior.
|
|
613
|
+
|
|
614
|
+
```text
|
|
615
|
+
[xayz-baileys] ACK monitor: Restricted (463) — from 6281234567890@s.whatsapp.net, msg 3EB0...
|
|
616
|
+
```
|
|
617
|
+
|
|
618
|
+
Labels you might see: **Possible soft-ban** (a failed ack with no specific recognized reason —
|
|
619
|
+
the ACK-0/error case with nothing more specific to go on), **Restricted**, **Rate-limited /
|
|
620
|
+
Limit**, and **Possible ban**.
|
|
621
|
+
|
|
622
|
+
> ⚠️ **Be clear-eyed about what this is:** WhatsApp doesn't publish what these ack-error codes
|
|
623
|
+
> mean or confirm they reflect account health at all. These labels reflect commonly-discussed,
|
|
624
|
+
> unofficial patterns from the WA bot/userbot developer community — treat a label here as
|
|
625
|
+
> "worth investigating", not a confirmed diagnosis of your account's state.
|
|
626
|
+
|
|
627
|
+
**It won't spam your console.** Repeats of the *same* label within a cooldown window (default
|
|
628
|
+
60 seconds) are counted, not printed — the next print after the cooldown shows how many were
|
|
629
|
+
folded in:
|
|
630
|
+
|
|
631
|
+
```text
|
|
632
|
+
[xayz-baileys] ACK monitor: Rate-limited / Limit — from 62819...@s.whatsapp.net, msg AB12... (+9 more in the last 60s)
|
|
633
|
+
```
|
|
634
|
+
|
|
635
|
+
```javascript
|
|
636
|
+
const sock = makeWASocket({
|
|
637
|
+
ackMonitor: true, // default; set false to disable entirely
|
|
638
|
+
ackMonitorCooldownMs: 60000 // widen/narrow the per-label throttle window
|
|
639
|
+
});
|
|
640
|
+
```
|
|
641
|
+
|
|
642
|
+
---
|
|
643
|
+
|
|
644
|
+
## New in this fork: protocol & utility modules
|
|
645
|
+
|
|
646
|
+
`@xayz/baileys` ships a newer WhatsApp protocol schema (`WAProto`) and a set of extra,
|
|
647
|
+
opt-in modules layered on top of the base socket. None of these run unless you call them.
|
|
648
|
+
|
|
649
|
+
**Updated protocol schema** — `WAProto` was regenerated from a newer WhatsApp Web protocol
|
|
650
|
+
dump, adding many message/record types the previous schema didn't have yet (e.g.
|
|
651
|
+
`ExtendedContentMessage`, `MusicMessage`, newer backup/E2E-key types). This required bumping
|
|
652
|
+
the `protobufjs` dependency to `^8.8.0` (from `^7.5.6`) since the current protobuf compiler
|
|
653
|
+
only targets that runtime — already reflected in `package.json`.
|
|
654
|
+
|
|
655
|
+
**New account/feature socket layers** (wired into `makeWASocket` automatically, each adding
|
|
656
|
+
methods without touching what's already there):
|
|
657
|
+
|
|
658
|
+
```javascript
|
|
659
|
+
const sock = makeWASocket({ /* ... */ });
|
|
660
|
+
|
|
661
|
+
// Privacy & account settings (text status, trusted devices, linked profiles, ...)
|
|
662
|
+
await sock.updateTextStatus('Hello world', '👋');
|
|
663
|
+
await sock.getTrustedDevices();
|
|
664
|
+
|
|
665
|
+
// Registration/account features (password, passkeys, age verification, contact backup)
|
|
666
|
+
await sock.hasPassword();
|
|
667
|
+
await sock.contactsBackupQuery();
|
|
668
|
+
|
|
669
|
+
// Managed-account linking & WhatsApp Payments passkeys
|
|
670
|
+
await sock.managedAccountQuery(sock.user.id);
|
|
671
|
+
|
|
672
|
+
// Cross-app interop (EU DMA messaging interoperability with Messenger/Instagram) — opt-in,
|
|
673
|
+
// nothing here runs until you call it:
|
|
674
|
+
const integrators = await sock.initInterop();
|
|
675
|
+
|
|
676
|
+
// Meta AI-in-groups
|
|
677
|
+
const group = await sock.aiGroupCreate('My AI Group', ['123@s.whatsapp.net']);
|
|
678
|
+
|
|
679
|
+
// First-party GraphQL surface (payments, AI Studio, bug reports, etc.) mirroring what the
|
|
680
|
+
// official app itself calls on graph.whatsapp.com / wamo.whatsapp.net
|
|
681
|
+
await sock.getEligibility();
|
|
682
|
+
```
|
|
683
|
+
|
|
684
|
+
**New opt-in `Utils` helpers** (import directly, use only if you need them):
|
|
685
|
+
|
|
686
|
+
```javascript
|
|
687
|
+
import {
|
|
688
|
+
createSessionPool, // run several numbers with reconnect backoff
|
|
689
|
+
autoCacheViewOnceMedia, // save view-once media to disk before it disappears
|
|
690
|
+
createCommandHandler, // simple "!command" style bot commands from a folder
|
|
691
|
+
imageToWebpSticker, // image -> WhatsApp sticker (needs optional "sharp")
|
|
692
|
+
videoToWebpSticker, // video -> animated sticker (needs a local ffmpeg)
|
|
693
|
+
AdaptiveDelayManager, // generic backoff/cooldown timer for retry loops
|
|
694
|
+
} from '@xayz/baileys';
|
|
695
|
+
|
|
696
|
+
// example: text-message router (also auto-attached as sock.onText/hears/command)
|
|
697
|
+
sock.command('ping', async (msg) => sock.sendMessage(msg.key.remoteJid, { text: 'pong' }));
|
|
698
|
+
```
|
|
699
|
+
|
|
700
|
+
See [`LITERACY.md`](LITERACY.md#new-modules-in-this-fork) for what each module does, where it
|
|
701
|
+
came from, and — for the one file that needed it — what was changed for security before it was
|
|
702
|
+
included.
|
|
703
|
+
|
|
704
|
+
---
|
|
705
|
+
|
|
706
|
+
## Performance notes
|
|
707
|
+
|
|
708
|
+
A few things were tightened up so this fork behaves better under long-running / high-traffic
|
|
709
|
+
use, without changing any public behavior:
|
|
710
|
+
|
|
711
|
+
- **`userDevicesCache`** (device-list cache used when sending) now has a hard `maxKeys` cap
|
|
712
|
+
(default 10,000; override with `userDevicesCacheMaxKeys`), on top of its existing 5-minute
|
|
713
|
+
TTL, so a very high-throughput bot can't grow it unbounded between TTL sweeps.
|
|
714
|
+
- **Message-retry caches** (`sessionRecreateHistory`, `retryCounters` in
|
|
715
|
+
`lib/Utils/message-retry-manager.js`) got the same treatment — capped at 2,000 / 5,000
|
|
716
|
+
entries respectively, same TTLs as before.
|
|
717
|
+
- **New guard state arrays** (blocked channel-follows, blocked group-joins, flagged recipients)
|
|
718
|
+
are capped at 200 entries each (oldest dropped first) so leaving them enabled on a
|
|
719
|
+
long-running process can't leak memory.
|
|
720
|
+
- **Two `ffmpeg` invocations** (video thumbnail extraction, video→sticker conversion) were
|
|
721
|
+
switched from `child_process.exec` (a shell string) to `execFile` with an argv array — this
|
|
722
|
+
is primarily a security fix (see [LITERACY.md](LITERACY.md#new-modules-in-this-fork)), but
|
|
723
|
+
`execFile` also skips spawning an extra shell process per call, which is marginally lighter
|
|
724
|
+
on CPU/process count for anything calling these a lot (bulk sticker conversion, etc.).
|
|
725
|
+
- Heavy optional dependencies (`sharp`, `jimp`, `music-metadata`, `audio-decode`,
|
|
726
|
+
`link-preview-js`) were already lazy-loaded via dynamic `import()` only where actually used —
|
|
727
|
+
confirmed still true after this fork's changes, so installs that skip those peer deps stay
|
|
728
|
+
lightweight and processes that never touch stickers/audio-metadata/link-previews never pay
|
|
729
|
+
for loading them.
|
|
730
|
+
|
|
731
|
+
None of this changes disk usage meaningfully — this library doesn't persist anything to disk on
|
|
732
|
+
its own beyond what you explicitly configure (auth state, your own caches/logs).
|
|
733
|
+
|
|
734
|
+
### optiMazer — opt-in, tighter resource limits
|
|
735
|
+
|
|
736
|
+
Everything above is always on (they're bug fixes, not something that should be optional). On
|
|
737
|
+
top of that, there's a separate opt-in switch — **OFF by default** — for people who want to
|
|
738
|
+
trade a little more re-fetching on cache misses for meaningfully less resident memory on a
|
|
739
|
+
long-running, high-traffic process:
|
|
740
|
+
|
|
741
|
+
```javascript
|
|
742
|
+
import makeWASocket from '@xayz/baileys';
|
|
743
|
+
|
|
744
|
+
const sock = makeWASocket({
|
|
745
|
+
optiMazer: true // that's it — tightens cache limits, adds a periodic background tick
|
|
746
|
+
});
|
|
747
|
+
|
|
748
|
+
console.log(sock.getOptimizerStats());
|
|
749
|
+
// { ticks: 3, gcRuns: 0, uptimeMs: 182004, gcAvailable: false, memory: { rss: ..., heapUsed: ... } }
|
|
750
|
+
```
|
|
751
|
+
|
|
752
|
+
`optiMazer: true` tightens the always-on caps further (e.g. `userDevicesCache` from 10,000 keys
|
|
753
|
+
down to 2,000, guard logs from 200 entries down to 50) and starts a background tick every 60
|
|
754
|
+
seconds. If your process was started with `node --expose-gc`, that same tick also requests a
|
|
755
|
+
proactive garbage-collection pass; otherwise it's a harmless no-op.
|
|
756
|
+
|
|
757
|
+
You can also pass an object instead of `true` to override individual limits:
|
|
758
|
+
|
|
759
|
+
```javascript
|
|
760
|
+
const sock = makeWASocket({
|
|
761
|
+
optiMazer: {
|
|
762
|
+
userDevicesCacheMaxKeys: 500,
|
|
763
|
+
tickIntervalMs: 30000
|
|
764
|
+
}
|
|
765
|
+
});
|
|
766
|
+
```
|
|
767
|
+
|
|
768
|
+
Or use the exported class/factory directly if you want to manage its lifecycle yourself
|
|
769
|
+
(e.g. to call `.stop()` later):
|
|
770
|
+
|
|
771
|
+
```javascript
|
|
772
|
+
import { optiMazer } from '@xayz/baileys';
|
|
773
|
+
|
|
774
|
+
const tuner = optiMazer({ userDevicesCacheMaxKeys: 500 }).attach(sock);
|
|
775
|
+
// later
|
|
776
|
+
tuner.stop();
|
|
777
|
+
```
|
|
778
|
+
|
|
779
|
+
---
|
|
780
|
+
|
|
781
|
+
## Posting a Status with mentions
|
|
782
|
+
|
|
783
|
+
```javascript
|
|
784
|
+
await sock.sendStatusWhatsApp(
|
|
785
|
+
{ text: 'Big announcement! 🎉', backgroundColor: '#00A884' },
|
|
786
|
+
['6281234567890@s.whatsapp.net', '120363111111111111@g.us'] // users and/or groups (expanded to members)
|
|
787
|
+
);
|
|
788
|
+
```
|
|
789
|
+
|
|
790
|
+
Everyone listed gets a "you were mentioned in a status" notification, same as posting a status
|
|
791
|
+
with @mentions from the app.
|
|
792
|
+
|
|
793
|
+
---
|
|
794
|
+
|
|
795
|
+
## Reading channel text status, business profiles, and more via USync
|
|
796
|
+
|
|
797
|
+
`USyncQuery` gained five more protocols for bulk-looking-up info about JIDs:
|
|
798
|
+
|
|
799
|
+
```javascript
|
|
800
|
+
import { USyncQuery, USyncUser } from '@xayz/baileys';
|
|
801
|
+
|
|
802
|
+
const query = new USyncQuery()
|
|
803
|
+
.withTextStatusProtocol()
|
|
804
|
+
.withBusinessProtocol()
|
|
805
|
+
.withPictureProtocol()
|
|
806
|
+
.withUser(new USyncUser().withId(jid));
|
|
807
|
+
|
|
808
|
+
const result = await sock.executeUSyncQuery(query);
|
|
809
|
+
```
|
|
810
|
+
|
|
811
|
+
`.withFeatureProtocol()` and `.withSidelistProtocol()` are also available. See
|
|
812
|
+
[LITERACY.md](LITERACY.md#deeper-fork-comparison--what-schema-only-diffing-missed) for what
|
|
813
|
+
each one returns.
|
|
814
|
+
|
|
815
|
+
---
|
|
816
|
+
|
|
817
|
+
## Pure-JS Curve25519 fallback
|
|
818
|
+
|
|
819
|
+
If the `libsignal` dependency (currently a `github:` install — see
|
|
820
|
+
[`vendor-libsignal.sh`](vendor-libsignal.sh)) ever fails to install or load in your
|
|
821
|
+
environment, `CurveJS` is a drop-in, dependency-free replacement for the `Curve` operations it
|
|
822
|
+
normally provides:
|
|
823
|
+
|
|
824
|
+
```javascript
|
|
825
|
+
import { CurveJS } from '@xayz/baileys';
|
|
826
|
+
|
|
827
|
+
const keyPair = CurveJS.generateKeyPair();
|
|
828
|
+
const shared = CurveJS.sharedKey(myPrivateKey, theirPublicKey);
|
|
829
|
+
```
|
|
830
|
+
|
|
831
|
+
It's verified interoperable with the default `Curve` (a shared key computed with `Curve` on
|
|
832
|
+
one side and `CurveJS` on the other matches bit-for-bit) — see LITERACY.md for the test.
|
|
833
|
+
Not used by default anywhere in the library; this is available if you need it.
|
|
834
|
+
|
|
835
|
+
---
|
|
836
|
+
|
|
837
|
+
## SQLite-backed auth state
|
|
838
|
+
|
|
839
|
+
An alternative to `useMultiFileAuthState` for busy bots — stores everything in one SQLite file
|
|
840
|
+
instead of one JSON file per key:
|
|
841
|
+
|
|
842
|
+
```javascript
|
|
843
|
+
import makeWASocket, { useSqliteAuthState } from '@xayz/baileys';
|
|
844
|
+
|
|
845
|
+
const { state, saveCreds } = await useSqliteAuthState('./auth', {
|
|
846
|
+
migrateFromFolder: './old-multi-file-auth' // optional, one-time
|
|
847
|
+
});
|
|
848
|
+
|
|
849
|
+
const sock = makeWASocket({ auth: state });
|
|
850
|
+
sock.ev.on('creds.update', saveCreds);
|
|
851
|
+
```
|
|
852
|
+
|
|
853
|
+
Requires Node 22.5+ (built-in `node:sqlite`); throws a clear error telling you to use
|
|
854
|
+
`useMultiFileAuthState` instead on older Node.
|
|
855
|
+
|
|
856
|
+
---
|
|
857
|
+
|
|
858
|
+
## Storing data
|
|
859
|
+
|
|
860
|
+
```javascript
|
|
861
|
+
import makeWASocket, { makeInMemoryStore } from '@xayz/baileys';
|
|
862
|
+
import pino from 'pino';
|
|
863
|
+
|
|
864
|
+
const store = makeInMemoryStore({
|
|
865
|
+
logger: pino().child({ level: 'silent', stream: 'store' })
|
|
866
|
+
});
|
|
867
|
+
const client = makeWASocket({
|
|
868
|
+
// options
|
|
869
|
+
});
|
|
870
|
+
store.bind(client.ev);
|
|
871
|
+
|
|
872
|
+
client.ev.on('contacts.upsert', () => {
|
|
873
|
+
console.log('New contact: ' + Object.values(store.contacts()));
|
|
874
|
+
});
|
|
875
|
+
```
|
|
876
|
+
|
|
877
|
+
---
|
|
878
|
+
|
|
879
|
+
## Sending messages
|
|
880
|
+
|
|
881
|
+
### Send / relay a message with `noSelfSync`
|
|
882
|
+
|
|
883
|
+
`noSelfSync` is a `relayMessage` option (private/1-on-1 chats only) that controls whether the
|
|
884
|
+
message is also synced to your **other own linked devices** (other phones/WhatsApp Web sessions
|
|
885
|
+
logged into the same account). It does not affect delivery to the recipient.
|
|
886
|
+
|
|
887
|
+
- **`noSelfSync: true`** — sent to the recipient as normal, but **not** synced to your other own
|
|
888
|
+
devices. Useful for silent/automated sends from a bot account.
|
|
889
|
+
- **`noSelfSync: false`** (default) — normal behavior; synced everywhere you're logged in.
|
|
890
|
+
|
|
891
|
+
```javascript
|
|
892
|
+
await client.relayMessage(m.chat, {
|
|
893
|
+
conversation: "Hello from @xayz/baileys"
|
|
894
|
+
}, {
|
|
895
|
+
noSelfSync: true
|
|
896
|
+
});
|
|
897
|
+
|
|
898
|
+
await client.sendMessage(m.chat, {
|
|
899
|
+
text: "Hello from @xayz/baileys"
|
|
900
|
+
}, {
|
|
901
|
+
noSelfSync: true
|
|
902
|
+
});
|
|
903
|
+
```
|
|
904
|
+
|
|
905
|
+
### Send an orderMessage
|
|
906
|
+
|
|
907
|
+
```javascript
|
|
908
|
+
import fs from 'fs';
|
|
909
|
+
const thumbnail = fs.readFileSync('./thumb.jpg');
|
|
910
|
+
|
|
911
|
+
await client.sendMessage(m.chat, {
|
|
912
|
+
thumbnail,
|
|
913
|
+
message: "Order summary",
|
|
914
|
+
orderTitle: "My Store",
|
|
915
|
+
totalAmount1000: 72502,
|
|
916
|
+
totalCurrencyCode: "IDR"
|
|
917
|
+
}, { quoted: m });
|
|
918
|
+
```
|
|
919
|
+
|
|
920
|
+
### Send a pollResultSnapshotMessage
|
|
921
|
+
|
|
922
|
+
```javascript
|
|
923
|
+
await client.sendMessage(m.chat, {
|
|
924
|
+
pollResultMessage: {
|
|
925
|
+
name: "My Poll",
|
|
926
|
+
options: [
|
|
927
|
+
{ optionName: "Option 1" },
|
|
928
|
+
{ optionName: "Option 2" }
|
|
929
|
+
],
|
|
930
|
+
newsletter: {
|
|
931
|
+
newsletterName: "XYCoolcraft Updates",
|
|
932
|
+
newsletterJid: "120363427430697245@newsletter"
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
});
|
|
936
|
+
```
|
|
937
|
+
|
|
938
|
+
### Send a productMessage
|
|
939
|
+
|
|
940
|
+
```javascript
|
|
941
|
+
await client.relayMessage(m.chat, {
|
|
942
|
+
productMessage: {
|
|
943
|
+
title: "Product.pdf",
|
|
944
|
+
description: "Product description",
|
|
945
|
+
thumbnail: { url: "./thumb.jpg" },
|
|
946
|
+
productId: "EXAMPLE_TOKEN",
|
|
947
|
+
retailerId: "EXAMPLE_RETAILER_ID",
|
|
948
|
+
url: "https://example.com",
|
|
949
|
+
body: "Body text",
|
|
950
|
+
footer: "Footer",
|
|
951
|
+
buttons: [
|
|
952
|
+
{
|
|
953
|
+
name: "cta_url",
|
|
954
|
+
buttonParamsJson: "{\"display_text\":\"Visit\",\"url\":\"https://example.com\"}"
|
|
955
|
+
}
|
|
956
|
+
],
|
|
957
|
+
priceAmount1000: 72502,
|
|
958
|
+
currencyCode: "IDR"
|
|
959
|
+
}
|
|
960
|
+
});
|
|
961
|
+
```
|
|
962
|
+
|
|
963
|
+
### Send an interactiveMessage
|
|
964
|
+
|
|
965
|
+
```javascript
|
|
966
|
+
await client.sendMessage(m.chat, {
|
|
967
|
+
image: { url: "./img.jpg" },
|
|
968
|
+
text: "body",
|
|
969
|
+
title: "title", // required when sending media
|
|
970
|
+
footer: "footer",
|
|
971
|
+
interactiveButtons: [
|
|
972
|
+
{
|
|
973
|
+
name: "single_select",
|
|
974
|
+
buttonParamsJson: JSON.stringify({ title: "\0" })
|
|
975
|
+
}
|
|
976
|
+
],
|
|
977
|
+
messageParams: JSON.stringify({
|
|
978
|
+
bottom_sheet: { /** other params **/ }
|
|
979
|
+
})
|
|
980
|
+
});
|
|
981
|
+
```
|
|
982
|
+
|
|
983
|
+
### Send a member label
|
|
984
|
+
|
|
985
|
+
```javascript
|
|
986
|
+
await client.sendMessage(m.chat, {
|
|
987
|
+
groupLabel: { labelText: "Tagged members appear here" }
|
|
988
|
+
});
|
|
989
|
+
```
|
|
990
|
+
|
|
991
|
+
### Send a message to group members
|
|
992
|
+
|
|
993
|
+
```javascript
|
|
994
|
+
await client.sendMessageMembers(m.chat, {
|
|
995
|
+
extendedTextMessage: { text: "Hello members" }
|
|
996
|
+
}, {});
|
|
997
|
+
```
|
|
998
|
+
|
|
999
|
+
---
|
|
1000
|
+
|
|
1001
|
+
## Simple sendMessage Helpers
|
|
1002
|
+
|
|
1003
|
+
<details>
|
|
1004
|
+
<summary><b>Send text</b></summary>
|
|
1005
|
+
|
|
1006
|
+
```javascript
|
|
1007
|
+
await client.sendText(m.chat, "Hello!", {
|
|
1008
|
+
contextInfo: { mentionedJid: [m.chat] }
|
|
1009
|
+
}, {
|
|
1010
|
+
key: { remoteJid: "status@broadcast", participant: m.sender, fromMe: true },
|
|
1011
|
+
message: { conversation: "\0" }
|
|
1012
|
+
});
|
|
1013
|
+
```
|
|
1014
|
+
</details>
|
|
1015
|
+
|
|
1016
|
+
<details>
|
|
1017
|
+
<summary><b>Send image</b></summary>
|
|
1018
|
+
|
|
1019
|
+
```javascript
|
|
1020
|
+
await client.sendImage(m.chat, { url: "./img.jpg" }, "Caption", {
|
|
1021
|
+
contextInfo: { mentionedJid: [m.chat] }
|
|
1022
|
+
}, {
|
|
1023
|
+
key: { remoteJid: "status@broadcast", participant: m.sender, fromMe: true },
|
|
1024
|
+
message: { conversation: "\0" }
|
|
1025
|
+
});
|
|
1026
|
+
```
|
|
1027
|
+
</details>
|
|
1028
|
+
|
|
1029
|
+
<details>
|
|
1030
|
+
<summary><b>Send video</b></summary>
|
|
1031
|
+
|
|
1032
|
+
```javascript
|
|
1033
|
+
await client.sendVideo(m.chat, { url: "./video.mp4" }, "Caption", {
|
|
1034
|
+
contextInfo: { mentionedJid: [m.chat] }
|
|
1035
|
+
}, {
|
|
1036
|
+
key: { remoteJid: "status@broadcast", participant: m.sender, fromMe: true },
|
|
1037
|
+
message: { conversation: "\0" }
|
|
1038
|
+
});
|
|
1039
|
+
```
|
|
1040
|
+
</details>
|
|
1041
|
+
|
|
1042
|
+
<details>
|
|
1043
|
+
<summary><b>Send audio</b></summary>
|
|
1044
|
+
|
|
1045
|
+
```javascript
|
|
1046
|
+
await client.sendAudio(m.chat, { url: "./audio.mp3" }, {
|
|
1047
|
+
contextInfo: { mentionedJid: [m.chat] }
|
|
1048
|
+
}, {
|
|
1049
|
+
key: { remoteJid: "status@broadcast", participant: m.sender, fromMe: true },
|
|
1050
|
+
message: { conversation: "\0" }
|
|
1051
|
+
});
|
|
1052
|
+
```
|
|
1053
|
+
</details>
|
|
1054
|
+
|
|
1055
|
+
<details>
|
|
1056
|
+
<summary><b>Send location</b></summary>
|
|
1057
|
+
|
|
1058
|
+
```javascript
|
|
1059
|
+
await client.sendLocation(m.chat, "Caption", 90.0, 90.0, "https://example.com", "1234567890", {
|
|
1060
|
+
contextInfo: { mentionedJid: [m.chat] }
|
|
1061
|
+
}, {
|
|
1062
|
+
key: { remoteJid: "status@broadcast", participant: m.sender, fromMe: true },
|
|
1063
|
+
message: { conversation: "\0" }
|
|
1064
|
+
});
|
|
1065
|
+
```
|
|
1066
|
+
</details>
|
|
1067
|
+
|
|
1068
|
+
<details>
|
|
1069
|
+
<summary><b>Send poll</b></summary>
|
|
1070
|
+
|
|
1071
|
+
```javascript
|
|
1072
|
+
await client.sendPoll(m.chat, "Pick one", ["1", "2", "3"], true, {
|
|
1073
|
+
contextInfo: { mentionedJid: [m.chat] }
|
|
1074
|
+
}, {
|
|
1075
|
+
key: { remoteJid: "status@broadcast", participant: m.sender, fromMe: true },
|
|
1076
|
+
message: { conversation: "\0" }
|
|
1077
|
+
});
|
|
1078
|
+
```
|
|
1079
|
+
</details>
|
|
1080
|
+
|
|
1081
|
+
<details>
|
|
1082
|
+
<summary><b>Send quiz</b></summary>
|
|
1083
|
+
|
|
1084
|
+
```javascript
|
|
1085
|
+
await client.sendQuiz(m.chat, "Quiz question", ["1", "2", "3"], "2", {
|
|
1086
|
+
contextInfo: { mentionedJid: [m.chat] }
|
|
1087
|
+
}, {
|
|
1088
|
+
key: { remoteJid: "status@broadcast", participant: m.sender, fromMe: true },
|
|
1089
|
+
message: { conversation: "\0" }
|
|
1090
|
+
});
|
|
1091
|
+
```
|
|
1092
|
+
</details>
|
|
1093
|
+
|
|
1094
|
+
<details>
|
|
1095
|
+
<summary><b>Send status mention</b></summary>
|
|
1096
|
+
|
|
1097
|
+
```javascript
|
|
1098
|
+
await client.statusMention(m.chat, {
|
|
1099
|
+
extendedTextMessage: { text: "Mentioned in status" }
|
|
1100
|
+
});
|
|
1101
|
+
```
|
|
1102
|
+
</details>
|
|
1103
|
+
|
|
1104
|
+
---
|
|
1105
|
+
|
|
1106
|
+
## Credits
|
|
1107
|
+
|
|
1108
|
+
`@xayz/baileys` Build By: XYCoolcraft:
|
|
1109
|
+
|
|
1110
|
+
- Original protocol implementation: [Baileys](https://github.com/WhiskeySockets/Baileys) by
|
|
1111
|
+
[Adhiraj Singh](https://github.com/adiwajshing) and the WhiskeySockets community.
|
|
1112
|
+
- Modified By: **XYCoolcraft** [Github](https://github.com/XYCoolcraft).
|
|
1113
|
+
|
|
1114
|
+
All credit for the underlying WhatsApp Web protocol work goes to the original authors and
|
|
1115
|
+
contributors. See [`LICENSE`](LICENSE) for the full text and every copyright notice that must
|
|
1116
|
+
be kept per the MIT License.
|
|
1117
|
+
|
|
1118
|
+
## Contributing
|
|
1119
|
+
|
|
1120
|
+
See [`CONTRIBUTING.md`](CONTRIBUTING.md) for guidelines on reporting issues and submitting pull
|
|
1121
|
+
requests.
|
|
1122
|
+
|
|
1123
|
+
## Publishing
|
|
1124
|
+
|
|
1125
|
+
Maintainers can publish a new version to npm with the included helper script — see
|
|
1126
|
+
[`upload-npm.sh`](upload-npm.sh) and the walkthrough in
|
|
1127
|
+
[`LITERACY.md`](LITERACY.md#uploadnpmsh-walkthrough).
|
|
1128
|
+
|
|
1129
|
+
```bash
|
|
1130
|
+
bash upload-npm.sh
|
|
1131
|
+
```
|
|
1132
|
+
|
|
1133
|
+
## Disclaimer
|
|
1134
|
+
|
|
1135
|
+
This is **not** an official WhatsApp product. Use of this library to send bulk or unsolicited
|
|
1136
|
+
messages may violate WhatsApp's Terms of Service and can result in your number being banned.
|
|
1137
|
+
Use responsibly.
|
|
1138
|
+
|
|
1139
|
+
<div align="center">
|
|
1140
|
+
|
|
1141
|
+
---
|
|
1142
|
+
|
|
1143
|
+
Made by **XYCoolcraft** · [`README.md`](README.md) · [`LITERACY.md`](LITERACY.md)
|
|
1144
|
+
|
|
1145
|
+
</div>
|