ishumdz-bail 1.0.9 → 1.0.11
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 +807 -395
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,300 +1,179 @@
|
|
|
1
|
-
<div align="center">
|
|
2
1
|
|
|
3
2
|
```
|
|
4
|
-
|
|
5
|
-
║
|
|
6
|
-
|
|
7
|
-
║
|
|
8
|
-
║
|
|
9
|
-
║
|
|
10
|
-
║
|
|
11
|
-
║
|
|
12
|
-
║
|
|
13
|
-
║
|
|
14
|
-
║
|
|
15
|
-
║
|
|
16
|
-
║
|
|
17
|
-
║
|
|
18
|
-
║
|
|
19
|
-
║
|
|
20
|
-
║
|
|
21
|
-
║
|
|
22
|
-
║
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
3
|
+
╔═══════════════════════════════════════════════════════════════════════════╗
|
|
4
|
+
║ 📱 MAIN FEATURES ║
|
|
5
|
+
╠═══════════════════════════════════════════════════════════════════════════╣
|
|
6
|
+
║ ║
|
|
7
|
+
║ ┌─────────────────────────────────────────────────────────────────────┐ ║
|
|
8
|
+
║ │ 🎮 GAMES │ 📞 VOIP CALLER │ ⚡ PRO METHODS │ ║
|
|
9
|
+
║ │ ├─ Blackjack │ ├─ Auto Answer │ ├─ sendPoll │ ║
|
|
10
|
+
║ │ ├─ Slots │ ├─ Audio Playback │ ├─ sendPollVote │ ║
|
|
11
|
+
║ │ ├─ Dice │ └─ VoipClient │ ├─ editMessage │ ║
|
|
12
|
+
║ │ ├─ Coin Flip │ │ ├─ deleteMessage │ ║
|
|
13
|
+
║ │ ├─ Roulette │ 📊 POLLS │ ├─ pinMessage │ ║
|
|
14
|
+
║ │ ├─ Mines │ ├─ Create Poll │ ├─ starMessage │ ║
|
|
15
|
+
║ │ ├─ Trivia │ ├─ Vote Poll │ ├─ reactMessage │ ║
|
|
16
|
+
║ │ └─ RPS │ └─ Get Results │ ├─ sendPresence │ ║
|
|
17
|
+
║ └─────────────────────────────────────────────────────────────────────┘ ║
|
|
18
|
+
║ ║
|
|
19
|
+
║ ┌─────────────────────────────────────────────────────────────────────┐ ║
|
|
20
|
+
║ │ 📢 NEWSLETTER │ 🟢 STATUS │ 💬 CHAT │ ║
|
|
21
|
+
║ │ ├─ channelVote │ ├─ sendText │ ├─ editMessage │ ║
|
|
22
|
+
║ │ ├─ newsletterReact │ ├─ sendMedia │ ├─ deleteMessage │ ║
|
|
23
|
+
║ │ ├─ getMessages │ ├─ readStatus │ ├─ pinMessage │ ║
|
|
24
|
+
║ │ ├─ searchChannels │ └─ reactStatus │ ├─ unpinMessage │ ║
|
|
25
|
+
║ │ └─ listChannels │ │ ├─ starMessage │ ║
|
|
26
|
+
║ └─────────────────────────────────────────────────────────────────────┘ ║
|
|
27
|
+
║ ║
|
|
28
|
+
║ ┌─────────────────────────────────────────────────────────────────────┐ ║
|
|
29
|
+
║ │ 👥 GROUPS │ 👤 PROFILE │ 📰 MEDIA │ ║
|
|
30
|
+
║ │ ├─ Get Invite Info │ ├─ checkNumber │ ├─ Newsletter Paths │ ║
|
|
31
|
+
║ │ ├─ Join via Invite │ ├─ setBio │ ├─ Image Upload │ ║
|
|
32
|
+
║ │ ├─ Set Announcement │ ├─ updateName │ ├─ Video Upload │ ║
|
|
33
|
+
║ │ ├─ Set Locked │ ├─ setProfilePic │ ├─ Audio Upload │ ║
|
|
34
|
+
║ │ ├─ Request List │ ├─ removeProfilePic │ ├─ Document Upload │ ║
|
|
35
|
+
║ │ ├─ Approve │ └─ rejectCall │ └─ Sticker Upload │ ║
|
|
36
|
+
║ │ └─ Reject │ │ │ ║
|
|
37
|
+
║ └─────────────────────────────────────────────────────────────────────┘ ║
|
|
38
|
+
║ ║
|
|
39
|
+
║ ✅ No Browser Required ✅ Multi-Device ✅ WebSocket Based ║
|
|
40
|
+
║ ✅ Active Maintenance ✅ MIT License ✅ Full API Coverage ║
|
|
41
|
+
║ ║
|
|
42
|
+
╚═══════════════════════════════════════════════════════════════════════════╝
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
<div align="center">
|
|
46
|
+
<img src="https://capsule-render.vercel.app/api?type=waving&height=220&color=0:ff6b6b,40:f06595,100:845ef7&text=ishumdz-bail&fontAlignY=40&fontSize=44&fontColor=ffffff&desc=Stable%20WhatsApp%20Web%20API%20Fork%20for%20Production%20Bots&descAlignY=60&descSize=16" alt="Header Banner" />
|
|
27
47
|
|
|
28
48
|
<br/>
|
|
29
49
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
50
|
+
<!-- Rounded + border image -->
|
|
51
|
+
<a href="https://ishanx-pro.site.je">
|
|
52
|
+
<kbd>
|
|
53
|
+
<img src="https://i.postimg.cc/9Q6q2Pv6/IMG-20260925-WA4965.jpg" alt="WhatsApp Baileys 2026" width="720" />
|
|
54
|
+
</kbd>
|
|
55
|
+
</a>
|
|
56
|
+
|
|
57
|
+
<br/><br/>
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
# 🧑💻 ishumdz-bail
|
|
61
|
+
|
|
62
|
+
<p>
|
|
63
|
+
<img src="https://img.shields.io/badge/Node.js-%3E%3D20-339933?style=for-the-badge&logo=nodedotjs&logoColor=white" />
|
|
64
|
+
<img src="https://img.shields.io/badge/WhatsApp-25D366?style=for-the-badge&logo=whatsapp&logoColor=white" />
|
|
65
|
+
<img src="https://img.shields.io/badge/WebSocket-010101?style=for-the-badge&logo=socketdotio&logoColor=white" />
|
|
66
|
+
<img src="https://img.shields.io/badge/Open%20Source-FF4500?style=for-the-badge&logo=github&logoColor=white" />
|
|
67
|
+
<img src="https://img.shields.io/badge/license-MIT-blue?style=for-the-badge" />
|
|
68
|
+
</p>
|
|
69
|
+
|
|
70
|
+
<p>
|
|
71
|
+
<img src="https://img.shields.io/npm/v/ishumdz-bail?style=flat-square&color=25D366&label=npm" />
|
|
72
|
+
<img src="https://img.shields.io/badge/maintained%20by-Lovely-black?style=flat-square" />
|
|
73
|
+
</p>
|
|
35
74
|
|
|
36
75
|
**Open-source WhatsApp automation library — no browser required.**
|
|
37
76
|
Built on WebSocket for speed, stability, and full multi-device support.
|
|
38
77
|
|
|
39
|
-
|
|
78
|
+
<br/>
|
|
40
79
|
|
|
41
|
-
|
|
80
|
+
[Installation](#-getting-started) • [Features](#-main-features) • [Stability](#-stability--disconnect-handling) • [Website](https://ishanx-pro.site.je) • [WhatsApp Channel](https://shyracore.indevs.in)
|
|
42
81
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
- [✨ What is ishumdz-bail?](#-what-is-ishumdz-bail)
|
|
46
|
-
- [🚀 Installation](#-installation)
|
|
47
|
-
- [⚡ Quick Start](#-quick-start)
|
|
48
|
-
- [🎯 Features Overview](#-features-overview)
|
|
49
|
-
- [🎮 Games](#-games)
|
|
50
|
-
- [📞 VoIP Caller](#-voip-caller)
|
|
51
|
-
- [⚡ Pro Methods](#-pro-methods)
|
|
52
|
-
- [📊 Polls](#-polls)
|
|
53
|
-
- [📢 Newsletter/Channels](#-newsletterchannels)
|
|
54
|
-
- [🟢 Status/Stories](#-statusstories)
|
|
55
|
-
- [💬 Chat Actions](#-chat-actions)
|
|
56
|
-
- [👥 Group Management](#-group-management)
|
|
57
|
-
- [👤 Profile Management](#-profile-management)
|
|
58
|
-
- [📰 Newsletter Media](#-newsletter-media)
|
|
59
|
-
- [🔌 API Reference](#-api-reference)
|
|
60
|
-
- [📝 Examples](#-examples)
|
|
82
|
+
</div>
|
|
61
83
|
|
|
62
84
|
---
|
|
63
85
|
|
|
64
86
|
## ✨ What is ishumdz-bail?
|
|
65
87
|
|
|
66
|
-
**ishumdz-bail** is a powerful, open-source WhatsApp Web library built on top of the Baileys protocol stack — extended with features not found in any other public fork.
|
|
67
|
-
|
|
68
|
-
**Why choose ishumdz-bail?**
|
|
88
|
+
**ishumdz-bail** (`ishumdz-bail`) is a powerful, open-source WhatsApp Web library built on top of the Baileys protocol stack — extended with features not found in any other public fork. It connects directly to WhatsApp's multi-device WebSocket protocol. No Selenium, no Puppeteer, no browser overhead.
|
|
69
89
|
|
|
70
|
-
|
|
71
|
-
┌─────────────────────────────────────────────────────────────────┐
|
|
72
|
-
│ ✅ No Browser Required │ ✅ Multi-Device Support │
|
|
73
|
-
│ ✅ WebSocket Based │ ✅ Full API Coverage │
|
|
74
|
-
│ ✅ Built-in Games (8) │ ✅ VoIP Call Answer │
|
|
75
|
-
│ ✅ Pro Methods (34) │ ✅ Newsletter/Channel Support │
|
|
76
|
-
│ ✅ Active Maintenance │ ✅ MIT Licensed │
|
|
77
|
-
└─────────────────────────────────────────────────────────────────┘
|
|
78
|
-
```
|
|
90
|
+
> ⚡ **Node.js ≥ 20 required.**
|
|
79
91
|
|
|
80
92
|
---
|
|
81
93
|
|
|
82
|
-
## 🚀
|
|
94
|
+
## 🚀 Getting Started
|
|
83
95
|
|
|
84
96
|
```bash
|
|
85
97
|
npm install ishumdz-bail
|
|
86
98
|
```
|
|
87
99
|
|
|
88
|
-
**Requirements:**
|
|
89
|
-
- Node.js ≥ 20
|
|
90
|
-
- npm or yarn
|
|
91
|
-
|
|
92
|
-
---
|
|
93
|
-
|
|
94
|
-
## ⚡ Quick Start
|
|
95
|
-
|
|
96
100
|
```javascript
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
const { state, saveCreds } = await useMultiFileAuthState('auth_info');
|
|
101
|
+
import { makeWASocket, useMultiFileAuthState } from 'ishumdz-bail'
|
|
100
102
|
|
|
103
|
+
const { state, saveCreds } = await useMultiFileAuthState('auth_info')
|
|
101
104
|
const sock = makeWASocket({
|
|
102
105
|
auth: state,
|
|
103
|
-
syncFullHistory: false,
|
|
104
|
-
aiLabel: true,
|
|
105
|
-
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
sock.ev.on('creds.update', saveCreds);
|
|
109
|
-
|
|
110
|
-
sock.ev.on('connection.update', ({ connection }) => {
|
|
111
|
-
if (connection === 'open') {
|
|
112
|
-
console.log('✅ Connected to WhatsApp!');
|
|
113
|
-
|
|
114
|
-
// Attach Pro methods
|
|
115
|
-
attachProMethods(sock);
|
|
116
|
-
}
|
|
117
|
-
});
|
|
118
|
-
```
|
|
106
|
+
syncFullHistory: false, // skip history sync — bot works immediately
|
|
107
|
+
aiLabel: true, // stamp messages with AI bot marker (default: true)
|
|
108
|
+
})
|
|
119
109
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
## 🎯 Features Overview
|
|
123
|
-
|
|
124
|
-
```
|
|
125
|
-
┌─────────────────────────────────────────────────────────────────────────┐
|
|
126
|
-
│ ISHUMDZ-BAIL FEATURES │
|
|
127
|
-
├─────────────────────────────────────────────────────────────────────────┤
|
|
128
|
-
│ │
|
|
129
|
-
│ 🎮 GAMES (8) │ 📞 VOIP (3) │ ⚡ PRO METHODS (34) │
|
|
130
|
-
│ ├─ Blackjack │ ├─ VoipClient │ ├─ sendPoll │
|
|
131
|
-
│ ├─ Slots │ ├─ ActiveCall │ ├─ sendPollVote │
|
|
132
|
-
│ ├─ Dice │ └─ AudioFeeder │ ├─ editMessage │
|
|
133
|
-
│ ├─ Coin Flip │ │ ├─ deleteMessage │
|
|
134
|
-
│ ├─ Roulette │ 📊 POLLS (3) │ ├─ pinMessage │
|
|
135
|
-
│ ├─ Mines │ ├─ sendPoll │ ├─ reactMessage │
|
|
136
|
-
│ ├─ Trivia │ ├─ sendPollVote │ ├─ sendStatusText │
|
|
137
|
-
│ └─ Rock Paper │ └─ getAggregate │ ├─ checkNumber │
|
|
138
|
-
│ Scissors │ Votes │ └─ ... and more! │
|
|
139
|
-
│ │
|
|
140
|
-
│ 📢 NEWSLETTER (6) │ 🟢 STATUS (4) │ 💬 CHAT (8) │
|
|
141
|
-
│ ├─ channelVote │ ├─ sendStatusText │ ├─ editMessage │
|
|
142
|
-
│ ├─ newsletterReact │ ├─ sendStatusMedia │ ├─ deleteMessage │
|
|
143
|
-
│ ├─ newsletterGet │ ├─ readStatus │ ├─ pinMessage │
|
|
144
|
-
│ │ Messages │ └─ reactStatus │ ├─ unpinMessage │
|
|
145
|
-
│ ├─ newsletterSearch │ │ ├─ starMessage │
|
|
146
|
-
│ └─ newsletterList │ 👥 GROUPS (7) │ ├─ sendPresence │
|
|
147
|
-
│ │ ├─ groupGetInvite │ └─ reply │
|
|
148
|
-
│ 👤 PROFILE (6) │ ├─ groupJoinVia │ │
|
|
149
|
-
│ ├─ checkNumber │ │ Invite │ │
|
|
150
|
-
│ ├─ setBio │ ├─ groupSet │ │
|
|
151
|
-
│ ├─ updateProfileName │ │ Announcement │ │
|
|
152
|
-
│ ├─ setProfilePicture │ ├─ groupSetLocked │ │
|
|
153
|
-
│ ├─ removeProfile │ ├─ groupRequest │ │
|
|
154
|
-
│ │ Picture │ │ Participants │ │
|
|
155
|
-
│ └─ rejectCall │ ├─ groupApprove │ │
|
|
156
|
-
│ │ │ Participants │ │
|
|
157
|
-
│ │ └─ groupReject │ │
|
|
158
|
-
│ │ Participants │ │
|
|
159
|
-
│ │
|
|
160
|
-
└─────────────────────────────────────────────────────────────────────────┘
|
|
110
|
+
sock.ev.on('creds.update', saveCreds)
|
|
161
111
|
```
|
|
162
112
|
|
|
163
113
|
---
|
|
164
114
|
|
|
165
|
-
##
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
### 🎰 Slots
|
|
191
|
-
|
|
192
|
-
```javascript
|
|
193
|
-
const slots = slotMachine(100);
|
|
194
|
-
console.log(slots.reels); // ['🍒', '🍋', '🍊']
|
|
195
|
-
console.log(slots.payout); // 0-500 (multiplier)
|
|
196
|
-
```
|
|
197
|
-
|
|
198
|
-
### 🎲 Dice
|
|
199
|
-
|
|
200
|
-
```javascript
|
|
201
|
-
const dice = diceGame(100, 'high'); // 'high', 'low', or specific number
|
|
202
|
-
console.log(dice.dice1); // 1-6
|
|
203
|
-
console.log(dice.dice2); // 1-6
|
|
204
|
-
console.log(dice.total); // 2-12
|
|
205
|
-
console.log(dice.win); // true/false
|
|
206
|
-
```
|
|
207
|
-
|
|
208
|
-
### 🪙 Coin Flip
|
|
209
|
-
|
|
210
|
-
```javascript
|
|
211
|
-
const flip = coinFlip(100, 'heads'); // 'heads' or 'tails'
|
|
212
|
-
console.log(flip.result); // 'heads' or 'tails'
|
|
213
|
-
console.log(flip.payout); // 0 or 200
|
|
214
|
-
```
|
|
215
|
-
|
|
216
|
-
### 🎡 Roulette
|
|
217
|
-
|
|
218
|
-
```javascript
|
|
219
|
-
const spin = roulette(100, 'red'); // 'red', 'black', 'green', or number
|
|
220
|
-
console.log(spin.number); // 0-36
|
|
221
|
-
console.log(spin.color); // 'red', 'black', or 'green'
|
|
222
|
-
console.log(spin.payout); // 0-3600
|
|
223
|
-
```
|
|
224
|
-
|
|
225
|
-
### ✊ Rock Paper Scissors
|
|
226
|
-
|
|
227
|
-
```javascript
|
|
228
|
-
const game = rps('rock'); // 'rock', 'paper', or 'scissors'
|
|
229
|
-
console.log(game.playerChoice); // 'rock'
|
|
230
|
-
console.log(game.botChoice); // 'paper'
|
|
231
|
-
console.log(game.result); // 'win', 'lose', or 'draw'
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
### 🧠 Trivia
|
|
235
|
-
|
|
236
|
-
```javascript
|
|
237
|
-
const question = trivia(100);
|
|
238
|
-
console.log(question.question); // 'What is the capital of France?'
|
|
239
|
-
console.log(question.options); // ['A) Paris', 'B) London', ...]
|
|
240
|
-
console.log(question.answer); // 'A'
|
|
241
|
-
```
|
|
242
|
-
|
|
243
|
-
### 💣 Mines
|
|
244
|
-
|
|
245
|
-
```javascript
|
|
246
|
-
// Create a 5x5 grid with 5 mines
|
|
247
|
-
const game = createMines(5, 5, 5);
|
|
248
|
-
console.log(game.totalSafe); // 20
|
|
249
|
-
|
|
250
|
-
// Reveal a tile
|
|
251
|
-
const tile = revealTile(game, 0, 0);
|
|
252
|
-
console.log(tile.safe); // true (diamond) or false (mine)
|
|
253
|
-
console.log(tile.mine); // true or false
|
|
254
|
-
|
|
255
|
-
// Cash out
|
|
256
|
-
const cashout = cashoutMines(game, 100);
|
|
257
|
-
console.log(cashout.payout); // based on revealed tiles
|
|
258
|
-
```
|
|
115
|
+
## 🧩 Main Features
|
|
116
|
+
|
|
117
|
+
| Feature | Description |
|
|
118
|
+
|---|---|
|
|
119
|
+
| 💬 **Rich Response (GenAI Bubble)** | Send Meta AI-style messages: markdown, code blocks, tables, LaTeX, maps, inline images, HTML — rendered natively as GenAI bubble in WA client |
|
|
120
|
+
| 🚫 **4-Factor Ban Checker** | Detect ban status via 4 independent signals: live registry, public send-page, identity-key probe, device-count signature |
|
|
121
|
+
| 🆔 **Username Socket (w:mex)** | Full WA username API: check availability, set, delete, pin, find by username, fetch recommendations — via WhatsApp's internal Pando/MEX GraphQL protocol |
|
|
122
|
+
| 🏘️ **Communities Socket** | Full community management: create, link/unlink groups, manage participants, invite codes, ephemeral toggle, approval mode |
|
|
123
|
+
| 🔕 **noSelfSync** | Skip syncing outgoing messages to your own other devices — reduces noise and bandwidth. Includes silent-drop guard (throws 421 instead of pretending the send succeeded) |
|
|
124
|
+
| ⚙️ **Rust-powered Crypto** | `md5`, `hkdf`, LT-Hash anti-tampering offloaded to `whatsapp-rust-bridge` native module for raw speed |
|
|
125
|
+
| 🗂️ **LID Mapping Store** | Persistent LID ↔ phone-number bi-directional cache with LRU eviction and in-flight dedup — prevents duplicate USync lookups |
|
|
126
|
+
| 🔐 **Pre-Key Manager** | Concurrency-safe Signal pre-key operations via per-key-type PQueue — no race conditions on key updates/deletions |
|
|
127
|
+
| 🔄 **Classify Disconnect** | Maps every WA disconnect code to `{ category, shouldReconnect, backoffMs }` — properly handles code 515 (restartRequired) as recoverable, not fatal |
|
|
128
|
+
| ⏱️ **Rate Limiter** | Anti-spam pacing calculator: enforces per-minute/hour/day caps, burst allowance, new-chat delays, identical-message dedup |
|
|
129
|
+
| 🖼️ **Album Message** | Send multiple images/videos as a single WA album/grid, with per-item or top-level caption and `gifPlayback` support |
|
|
130
|
+
| 🤖 **AI Label Config** | `aiLabel: true/false` in socket config — controls whether outgoing messages carry the `biz_bot` attribute that WA uses to render the AI icon |
|
|
131
|
+
| 🔎 **USync Username Protocol** | Username resolution baked into USync queries — resolve WA usernames alongside contacts in a single round-trip |
|
|
132
|
+
| 📥 **Offline Node Processor** | Batch-processes pending stanzas received while offline, preventing message loss on reconnect |
|
|
133
|
+
| 🔑 **Identity Change Handler** | Dedicated handler for Signal identity key changes — prevents session corruption when a contact re-registers |
|
|
134
|
+
| 📣 **Newsletter/Channel Media Upload** | Full support for uploading images, videos, audio, stickers to channels using correct `/newsletter/newsletter-*` paths |
|
|
135
|
+
| 😀 **Newsletter Reactions** | React to channel messages with emojis, track votes, and manage newsletter engagement |
|
|
136
|
+
| 📊 **Poll Voting** | Create polls, track encrypted votes, display results, and support multiple selection polls |
|
|
137
|
+
| 🎮 **Built-in Games** | 8 games: Blackjack, Slots, Dice, Coin Flip, Roulette, Mines, Trivia, Rock Paper Scissors |
|
|
138
|
+
| 📞 **VoIP Caller** | Answer incoming calls with audio playback using WASM VoIP engine |
|
|
139
|
+
| ⚡ **Pro Methods** | 34 convenience methods: Polls, Newsletter, Status, Chat, Groups, Profile |
|
|
259
140
|
|
|
260
141
|
---
|
|
261
142
|
|
|
262
|
-
## 📞 VoIP Caller
|
|
143
|
+
## 📞 VoIP Caller (Call Answer + Audio)
|
|
263
144
|
|
|
264
|
-
Answer incoming WhatsApp calls
|
|
145
|
+
Answer incoming WhatsApp calls and play audio automatically:
|
|
265
146
|
|
|
266
147
|
```javascript
|
|
267
|
-
const { makeWASocket, enableCallAutoAnswer
|
|
148
|
+
const { makeWASocket, enableCallAutoAnswer } = require('ishumdz-bail');
|
|
268
149
|
|
|
269
150
|
const sock = makeWASocket({ auth: state });
|
|
270
151
|
|
|
271
|
-
// Enable auto-answer
|
|
152
|
+
// Enable auto-answer with audio playback
|
|
272
153
|
sock.enableCallAutoAnswer({
|
|
273
|
-
audio: './welcome.wav',
|
|
274
|
-
autoAnswer: true,
|
|
275
|
-
answerDelayMs: 200,
|
|
276
|
-
durationMs: 60000,
|
|
277
|
-
loop: true,
|
|
278
|
-
onCall: (call) => {},
|
|
279
|
-
onAnswer: (call) => {},
|
|
280
|
-
onEnd: (call, reason) => {}
|
|
154
|
+
audio: './welcome.wav', // Audio file to play (MP3/WAV)
|
|
155
|
+
autoAnswer: true, // Auto-answer incoming calls
|
|
156
|
+
answerDelayMs: 200, // Delay before answering
|
|
157
|
+
durationMs: 60000, // Max call duration (60s)
|
|
158
|
+
loop: true, // Loop audio
|
|
159
|
+
onCall: (call) => {}, // Callback on incoming call
|
|
160
|
+
onAnswer: (call) => {}, // Callback when answered
|
|
161
|
+
onEnd: (call, reason) => {} // Callback when ended
|
|
281
162
|
});
|
|
282
163
|
```
|
|
283
164
|
|
|
284
|
-
|
|
285
|
-
|
|
165
|
+
**Manual call handling:**
|
|
286
166
|
```javascript
|
|
287
167
|
sock.ev.on('call', async ([call]) => {
|
|
288
168
|
if (call.status === 'offer') {
|
|
289
|
-
console.log(`📞 Incoming ${call.isVideo ? 'video' : 'voice'} call from ${call.from}`);
|
|
290
|
-
|
|
291
169
|
// Reject call
|
|
292
170
|
await sock.rejectCall(call.id, call.from);
|
|
293
171
|
|
|
294
172
|
// Or accept with VoIP client
|
|
295
173
|
const voipClient = getActiveVoipClient();
|
|
296
|
-
if (voipClient
|
|
297
|
-
voipClient.activeCall
|
|
174
|
+
if (voipClient) {
|
|
175
|
+
const activeCall = voipClient.activeCall;
|
|
176
|
+
activeCall.accept('./audio.wav');
|
|
298
177
|
}
|
|
299
178
|
}
|
|
300
179
|
});
|
|
@@ -304,7 +183,7 @@ sock.ev.on('call', async ([call]) => {
|
|
|
304
183
|
|
|
305
184
|
## ⚡ Pro Methods
|
|
306
185
|
|
|
307
|
-
34 convenience methods
|
|
186
|
+
34 convenience methods attached to socket via `attachProMethods()`:
|
|
308
187
|
|
|
309
188
|
```javascript
|
|
310
189
|
const { makeWASocket, attachProMethods } = require('ishumdz-bail');
|
|
@@ -313,9 +192,7 @@ const sock = makeWASocket({ auth: state });
|
|
|
313
192
|
attachProMethods(sock); // Attach all Pro methods
|
|
314
193
|
```
|
|
315
194
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
## 📊 Polls
|
|
195
|
+
### 📊 Polls Pro
|
|
319
196
|
|
|
320
197
|
```javascript
|
|
321
198
|
// Create a poll
|
|
@@ -332,12 +209,10 @@ await sock.sendPollVote(jid, pollMessage, ['Red']);
|
|
|
332
209
|
const votes = sock.getAggregatePollVotes(pollMessage);
|
|
333
210
|
```
|
|
334
211
|
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
## 📢 Newsletter/Channels
|
|
212
|
+
### 📢 Newsletter/Channel Pro
|
|
338
213
|
|
|
339
214
|
```javascript
|
|
340
|
-
// Smart channel poll vote (auto-resolves links)
|
|
215
|
+
// Smart channel poll vote (auto-resolves links, IDs)
|
|
341
216
|
await sock.channelVote('https://whatsapp.com/channel/xxx/123', 1);
|
|
342
217
|
|
|
343
218
|
// React to channel post
|
|
@@ -353,9 +228,7 @@ const results = await sock.newsletterSearch('technology');
|
|
|
353
228
|
const channels = await sock.newsletterList();
|
|
354
229
|
```
|
|
355
230
|
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
## 🟢 Status/Stories
|
|
231
|
+
### 🟢 Status/Stories Pro
|
|
359
232
|
|
|
360
233
|
```javascript
|
|
361
234
|
// Send text status
|
|
@@ -374,9 +247,7 @@ await sock.sendStatusMedia('./photo.jpg', {
|
|
|
374
247
|
await sock.reactStatus(statusKey, '❤️');
|
|
375
248
|
```
|
|
376
249
|
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
## 💬 Chat Actions
|
|
250
|
+
### 💬 Chat Pro
|
|
380
251
|
|
|
381
252
|
```javascript
|
|
382
253
|
// Edit a message
|
|
@@ -385,11 +256,8 @@ await sock.editMessage(jid, messageKey, 'Updated text!');
|
|
|
385
256
|
// Delete a message
|
|
386
257
|
await sock.deleteMessage(jid, messageKey);
|
|
387
258
|
|
|
388
|
-
// Pin a message (
|
|
389
|
-
await sock.pinMessage(jid, messageKey, 86400);
|
|
390
|
-
|
|
391
|
-
// Unpin a message
|
|
392
|
-
await sock.unpinMessage(jid, messageKey);
|
|
259
|
+
// Pin a message (24h, 7d, or 30d)
|
|
260
|
+
await sock.pinMessage(jid, messageKey, 86400); // 24 hours
|
|
393
261
|
|
|
394
262
|
// Star/unstar a message
|
|
395
263
|
await sock.starMessage(jid, messageKey, true);
|
|
@@ -404,9 +272,7 @@ await sock.sendPresence(jid, 'composing');
|
|
|
404
272
|
await sock.reply(jid, 'This is a reply!', quotedMessage);
|
|
405
273
|
```
|
|
406
274
|
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
## 👥 Group Management
|
|
275
|
+
### 👥 Groups Pro
|
|
410
276
|
|
|
411
277
|
```javascript
|
|
412
278
|
// Get group info from invite link
|
|
@@ -427,9 +293,7 @@ await sock.groupApproveParticipants(groupJid, [participant1, participant2]);
|
|
|
427
293
|
await sock.groupRejectParticipants(groupJid, [participant3]);
|
|
428
294
|
```
|
|
429
295
|
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
## 👤 Profile Management
|
|
296
|
+
### 👤 Profile Pro
|
|
433
297
|
|
|
434
298
|
```javascript
|
|
435
299
|
// Check if number exists on WhatsApp
|
|
@@ -451,174 +315,722 @@ await sock.removeProfilePicture(jid);
|
|
|
451
315
|
|
|
452
316
|
---
|
|
453
317
|
|
|
454
|
-
##
|
|
318
|
+
## 🎮 Built-in Games
|
|
455
319
|
|
|
456
|
-
|
|
320
|
+
8 fun games for your WhatsApp bot:
|
|
457
321
|
|
|
458
322
|
```javascript
|
|
459
|
-
const {
|
|
323
|
+
const { blackjack, slotMachine, diceGame, coinFlip, roulette, rps, trivia, createMines } = require('ishumdz-bail');
|
|
324
|
+
|
|
325
|
+
// Blackjack
|
|
326
|
+
const game = blackjack('start', [], [], 100); // Start with 100 bet
|
|
327
|
+
// game.playerHand, game.dealerHand, game.status
|
|
328
|
+
|
|
329
|
+
// Slots
|
|
330
|
+
const slots = slotMachine(100);
|
|
331
|
+
// slots.reels, slots.payout
|
|
332
|
+
|
|
333
|
+
// Dice
|
|
334
|
+
const dice = diceGame(100, 'high'); // Bet on high (7-12)
|
|
335
|
+
// dice.total, dice.dice1, dice.dice2
|
|
336
|
+
|
|
337
|
+
// Coin Flip
|
|
338
|
+
const flip = coinFlip(100, 'heads');
|
|
339
|
+
// flip.result, flip.payout
|
|
340
|
+
|
|
341
|
+
// Roulette
|
|
342
|
+
const spin = roulette(100, 'red');
|
|
343
|
+
// spin.number, spin.color, spin.payout
|
|
344
|
+
|
|
345
|
+
// Rock Paper Scissors
|
|
346
|
+
const game = rps('rock');
|
|
347
|
+
// game.playerChoice, game.botChoice, game.result
|
|
460
348
|
|
|
461
|
-
|
|
349
|
+
// Trivia
|
|
350
|
+
const question = trivia(100);
|
|
351
|
+
// question.question, question.options, question.answer
|
|
352
|
+
|
|
353
|
+
// Mines
|
|
354
|
+
const mines = createMines(5, 5, 5); // 5x5 grid, 5 mines
|
|
355
|
+
const tile = revealTile(mines, 0, 0); // Reveal tile at (0,0)
|
|
356
|
+
// tile.safe, tile.mine
|
|
357
|
+
const cashout = cashoutMines(mines, 100); // Cash out
|
|
358
|
+
// cashout.payout
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
## 💬 Rich Response (GenAI Bubble)
|
|
362
|
+
|
|
363
|
+
Send messages that render as Meta AI-style bubbles inside WhatsApp. Supports multiple primitives in a single message:
|
|
364
|
+
|
|
365
|
+
```javascript
|
|
366
|
+
// Markdown text
|
|
367
|
+
await sock.sendMessage(jid, {
|
|
368
|
+
richResponse: {
|
|
369
|
+
text: '**Hello** from *ishumdz-bail*',
|
|
370
|
+
responseId: 'optional-uuid'
|
|
371
|
+
}
|
|
372
|
+
})
|
|
373
|
+
|
|
374
|
+
// Code block
|
|
375
|
+
await sock.sendMessage(jid, {
|
|
376
|
+
richResponse: {
|
|
377
|
+
code: 'console.log("hello")',
|
|
378
|
+
language: 'javascript'
|
|
379
|
+
}
|
|
380
|
+
})
|
|
381
|
+
|
|
382
|
+
// Table
|
|
383
|
+
await sock.sendMessage(jid, {
|
|
384
|
+
richResponse: {
|
|
385
|
+
table: {
|
|
386
|
+
rows: [
|
|
387
|
+
['Name', 'Age'],
|
|
388
|
+
['Alice', '25'],
|
|
389
|
+
['Bob', '30']
|
|
390
|
+
]
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
})
|
|
394
|
+
|
|
395
|
+
// HTML (raw HTML rendered in client)
|
|
396
|
+
await sock.sendMessage(jid, {
|
|
397
|
+
richResponse: {
|
|
398
|
+
text: 'fallback',
|
|
399
|
+
html: '<b>bold</b> <a href="https://example.com">link</a>'
|
|
400
|
+
}
|
|
401
|
+
})
|
|
402
|
+
|
|
403
|
+
// LaTeX
|
|
404
|
+
await sock.sendMessage(jid, {
|
|
405
|
+
richResponse: {
|
|
406
|
+
latex: 'E = mc^2'
|
|
407
|
+
}
|
|
408
|
+
})
|
|
409
|
+
|
|
410
|
+
// Map / location
|
|
411
|
+
await sock.sendMessage(jid, {
|
|
412
|
+
richResponse: {
|
|
413
|
+
map: {
|
|
414
|
+
latitude: -6.2,
|
|
415
|
+
longitude: 106.8,
|
|
416
|
+
zoom: 15,
|
|
417
|
+
title: 'Jakarta',
|
|
418
|
+
annotations: []
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
})
|
|
422
|
+
|
|
423
|
+
// Inline image
|
|
424
|
+
await sock.sendMessage(jid, {
|
|
425
|
+
richResponse: {
|
|
426
|
+
imageUrl: 'https://example.com/photo.jpg'
|
|
427
|
+
}
|
|
428
|
+
})
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
**Shortcut methods** (all accept `quoted` and `options`):
|
|
432
|
+
|
|
433
|
+
```javascript
|
|
434
|
+
await sock.sendTable(jid, 'Title', ['H1','H2'], [['A','B']], quoted)
|
|
435
|
+
await sock.sendList(jid, 'Title', ['item1','item2'], quoted)
|
|
436
|
+
await sock.sendCodeBlock(jid, 'print("hello")', quoted, { language: 'python' })
|
|
437
|
+
await sock.sendLatex(jid, quoted, { latex: 'x^2 + y^2 = z^2' })
|
|
438
|
+
await sock.sendRichMessage(jid, submessages, quoted)
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
---
|
|
442
|
+
|
|
443
|
+
## 🖼️ Album Message
|
|
444
|
+
|
|
445
|
+
Send multiple images/videos grouped into a single WA album:
|
|
446
|
+
|
|
447
|
+
```javascript
|
|
448
|
+
await sock.sendMessage(jid, {
|
|
449
|
+
album: [
|
|
450
|
+
{ image: { url: 'https://example.com/a.jpg' } },
|
|
451
|
+
{ image: { url: 'https://example.com/b.jpg' }, caption: 'caption foto kedua' },
|
|
452
|
+
{ video: { url: 'https://example.com/c.mp4' }, gifPlayback: false }
|
|
453
|
+
],
|
|
454
|
+
caption: 'caption ini otomatis ke item pertama'
|
|
455
|
+
})
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
---
|
|
459
|
+
|
|
460
|
+
## 🚫 Ban Checker
|
|
461
|
+
|
|
462
|
+
4-factor ban detection against WhatsApp's own servers — no third-party API:
|
|
463
|
+
|
|
464
|
+
```javascript
|
|
465
|
+
const result = await sock.checkBanStatus('628123456789')
|
|
466
|
+
// or: sock.checkBanStatus('628123456789@s.whatsapp.net')
|
|
467
|
+
|
|
468
|
+
console.log(result)
|
|
462
469
|
// {
|
|
463
|
-
//
|
|
464
|
-
//
|
|
465
|
-
//
|
|
466
|
-
//
|
|
467
|
-
//
|
|
468
|
-
//
|
|
469
|
-
//
|
|
470
|
-
// ptv: '/newsletter/newsletter-ptv'
|
|
470
|
+
// status: 'ACTIVE' | 'PROFILE_HIDDEN' | 'LIKELY_ACTIVE' | 'BANNED' | 'OFF_WHATSAPP' | 'UNKNOWN',
|
|
471
|
+
// emoji: '🟢' | '🟡' | '🔴' | '❓',
|
|
472
|
+
// confidence: 0..1,
|
|
473
|
+
// deviceCount: number | null,
|
|
474
|
+
// registryExists: boolean | null,
|
|
475
|
+
// pageVisible: boolean | null,
|
|
476
|
+
// profileName: string | null
|
|
471
477
|
// }
|
|
472
478
|
```
|
|
473
479
|
|
|
480
|
+
**Four factors checked:**
|
|
481
|
+
- **Factor A** — Live registry (`sock.onWhatsApp`)
|
|
482
|
+
- **Factor B** — Public send-page title/image probe (`api.whatsapp.com`)
|
|
483
|
+
- **Factor C** — Identity-key device probe via USync (strongest: banned numbers have their keys destroyed)
|
|
484
|
+
- **Factor D** — Device-count signature (2+ = ACTIVE, 1 generic = likely BANNED, 0 = BANNED/OFF_WA)
|
|
485
|
+
|
|
486
|
+
---
|
|
487
|
+
|
|
488
|
+
## 🆔 Username Socket (w:mex)
|
|
489
|
+
|
|
490
|
+
Full WA `@username` API via WhatsApp's internal Pando/MEX GraphQL protocol, query IDs sourced from Java decompile of WA 2.26.17.2:
|
|
491
|
+
|
|
492
|
+
```javascript
|
|
493
|
+
// Check availability
|
|
494
|
+
const res = await sock.checkUsername('myusername')
|
|
495
|
+
// { available: true, username } or { available: false, suggestions: [...] }
|
|
496
|
+
|
|
497
|
+
// Set username
|
|
498
|
+
await sock.setUsername('myusername')
|
|
499
|
+
|
|
500
|
+
// Delete username
|
|
501
|
+
await sock.deleteUsername()
|
|
502
|
+
|
|
503
|
+
// Get your own username
|
|
504
|
+
const mine = await sock.getMyUsername()
|
|
505
|
+
|
|
506
|
+
// Pin/unpin username
|
|
507
|
+
await sock.setUsernamePin(true)
|
|
508
|
+
|
|
509
|
+
// Find user by username
|
|
510
|
+
const user = await sock.findUserByUsername('someuser', pin)
|
|
511
|
+
|
|
512
|
+
// Fetch usernames of your contacts in batch
|
|
513
|
+
const usernames = await sock.fetchContactUsernames('94xxxx@s.whatsapp.net', '628yyy@s.whatsapp.net')
|
|
514
|
+
|
|
515
|
+
// Get username suggestions
|
|
516
|
+
const suggestions = await sock.getUsernameRecommendations()
|
|
517
|
+
```
|
|
518
|
+
|
|
474
519
|
---
|
|
475
520
|
|
|
476
|
-
##
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
| `sendPoll(jid, data)` | Create poll |
|
|
509
|
-
| `sendPollVote(jid, key, options)` | Vote on poll |
|
|
510
|
-
| `editMessage(jid, key, text)` | Edit message |
|
|
511
|
-
| `deleteMessage(jid, key)` | Delete message |
|
|
512
|
-
| `pinMessage(jid, key, duration)` | Pin message |
|
|
513
|
-
| `unpinMessage(jid, key)` | Unpin message |
|
|
514
|
-
| `starMessage(jid, key, star)` | Star message |
|
|
515
|
-
| `reactMessage(jid, key, emoji)` | React to message |
|
|
516
|
-
| `sendPresence(jid, presence)` | Send presence |
|
|
517
|
-
| `reply(jid, text, quoted)` | Reply with quote |
|
|
518
|
-
| `checkNumber(phone)` | Check WhatsApp number |
|
|
519
|
-
| `setBio(text)` | Update bio |
|
|
520
|
-
| `updateProfileName(name)` | Update name |
|
|
521
|
-
| `setProfilePicture(jid, content)` | Set profile pic |
|
|
522
|
-
| `removeProfilePicture(jid)` | Remove profile pic |
|
|
523
|
-
| `sendStatusText(text, options)` | Send text status |
|
|
524
|
-
| `sendStatusMedia(media, options)` | Send media status |
|
|
525
|
-
| `readStatus(key)` | Mark status as read |
|
|
526
|
-
| `reactStatus(key, emoji)` | React to status |
|
|
527
|
-
| `channelVote(target, option)` | Smart channel vote |
|
|
528
|
-
| `newsletterReact(jid, id, reaction)` | React to channel |
|
|
529
|
-
| `newsletterGetMessages(jid, count)` | Get channel messages |
|
|
530
|
-
| `newsletterSearch(query)` | Search channels |
|
|
531
|
-
| `newsletterList()` | List followed channels |
|
|
532
|
-
| `groupGetInviteInfo(code)` | Get group info |
|
|
533
|
-
| `groupJoinViaInvite(code)` | Join via invite |
|
|
534
|
-
| `groupSetAnnouncement(jid, bool)` | Admin-only messages |
|
|
535
|
-
| `groupSetLocked(jid, bool)` | Admin-only edit |
|
|
536
|
-
| `groupRequestParticipantsList(jid)` | Pending requests |
|
|
537
|
-
| `groupApproveParticipants(jid, list)` | Approve requests |
|
|
538
|
-
| `groupRejectParticipants(jid, list)` | Reject requests |
|
|
539
|
-
| `rejectCall(callId, from)` | Reject call |
|
|
521
|
+
## 🏘️ Communities Socket
|
|
522
|
+
|
|
523
|
+
```javascript
|
|
524
|
+
// Create community
|
|
525
|
+
const community = await sock.communityCreate('Community Name', 'Description')
|
|
526
|
+
|
|
527
|
+
// Create group inside community
|
|
528
|
+
await sock.communityCreateGroup('Group Name', [jid1, jid2], communityJid)
|
|
529
|
+
|
|
530
|
+
// Link/unlink existing group
|
|
531
|
+
await sock.communityLinkGroup(groupJid, communityJid)
|
|
532
|
+
await sock.communityUnlinkGroup(groupJid, communityJid)
|
|
533
|
+
|
|
534
|
+
// Fetch linked groups
|
|
535
|
+
const groups = await sock.communityFetchLinkedGroups(communityJid)
|
|
536
|
+
|
|
537
|
+
// Manage participants
|
|
538
|
+
await sock.communityParticipantsUpdate(communityJid, [jid1], 'add') // 'add' | 'remove' | 'promote' | 'demote'
|
|
539
|
+
|
|
540
|
+
// Invite code
|
|
541
|
+
const code = await sock.communityInviteCode(communityJid)
|
|
542
|
+
await sock.communityRevokeInvite(communityJid)
|
|
543
|
+
await sock.communityAcceptInvite(code)
|
|
544
|
+
|
|
545
|
+
// Settings
|
|
546
|
+
await sock.communityToggleEphemeral(communityJid, 86400) // seconds
|
|
547
|
+
await sock.communityMemberAddMode(communityJid, 'admin_add')
|
|
548
|
+
await sock.communityJoinApprovalMode(communityJid, 'on')
|
|
549
|
+
await sock.communityUpdateSubject(communityJid, 'New Name')
|
|
550
|
+
await sock.communityUpdateDescription(communityJid, 'New Desc')
|
|
551
|
+
await sock.communityLeave(communityJid)
|
|
552
|
+
```
|
|
540
553
|
|
|
541
554
|
---
|
|
542
555
|
|
|
543
|
-
##
|
|
556
|
+
## 🔕 noSelfSync
|
|
544
557
|
|
|
545
|
-
|
|
558
|
+
Skip syncing outgoing messages to your own linked devices. Useful for high-volume bots where sync traffic is unnecessary:
|
|
546
559
|
|
|
547
560
|
```javascript
|
|
548
|
-
|
|
561
|
+
await sock.sendMessage(jid, { text: 'hello' }, { noSelfSync: true })
|
|
549
562
|
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
563
|
+
// Also supported in all shortcut methods:
|
|
564
|
+
await sock.sendTable(jid, title, headers, rows, quoted, { noSelfSync: true })
|
|
565
|
+
await sock.sendCodeBlock(jid, code, quoted, { noSelfSync: true })
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
> **Safe by design:** if `noSelfSync` would accidentally drop all recipients (e.g. messaging yourself), the guard kicks in and delivers normally. If the other party has zero resolved devices, it throws `Boom 421` instead of silently pretending the message was sent.
|
|
569
|
+
|
|
570
|
+
---
|
|
571
|
+
|
|
572
|
+
## 🔄 Stability & Disconnect Handling
|
|
573
|
+
|
|
574
|
+
ishumdz-bail ships `classifyDisconnect()` — maps every WA status code into an actionable result:
|
|
575
|
+
|
|
576
|
+
```javascript
|
|
577
|
+
import { classifyDisconnect } from 'ishumdz-bail'
|
|
578
|
+
|
|
579
|
+
sock.ev.on('connection.update', ({ connection, lastDisconnect }) => {
|
|
580
|
+
if (connection === 'close') {
|
|
581
|
+
const code = lastDisconnect?.error?.output?.statusCode
|
|
582
|
+
const info = classifyDisconnect(code)
|
|
583
|
+
|
|
584
|
+
console.log(info)
|
|
585
|
+
// {
|
|
586
|
+
// category: 'fatal' | 'recoverable' | 'rate-limited' | 'unknown',
|
|
587
|
+
// shouldReconnect: boolean,
|
|
588
|
+
// backoffMs: number, // ms to wait before reconnecting
|
|
589
|
+
// message: string,
|
|
590
|
+
// code: number
|
|
591
|
+
// }
|
|
592
|
+
|
|
593
|
+
if (info.shouldReconnect) {
|
|
594
|
+
setTimeout(() => reconnect(), info.backoffMs)
|
|
576
595
|
}
|
|
577
|
-
}
|
|
596
|
+
}
|
|
597
|
+
})
|
|
598
|
+
```
|
|
599
|
+
|
|
600
|
+
**Code map:**
|
|
601
|
+
|
|
602
|
+
| Code | Category | Reconnect | Backoff |
|
|
603
|
+
|---|---|---|---|
|
|
604
|
+
| 401, 440 | fatal | ❌ | — |
|
|
605
|
+
| 515 | recoverable | ✅ | 0 ms (immediate) |
|
|
606
|
+
| 405 | fatal | ❌ | — |
|
|
607
|
+
| 408 | recoverable | ✅ | 30 s |
|
|
608
|
+
| 503 | recoverable | ✅ | 5 min |
|
|
609
|
+
| 429 | rate-limited | ✅ | 60 s |
|
|
610
|
+
| 500 | recoverable | ✅ | 5 s |
|
|
611
|
+
| 503 | recoverable | ✅ | 10 s |
|
|
612
|
+
| Graceful close | recoverable | ✅ | 2 s |
|
|
613
|
+
| Unknown | unknown | ✅ | 15 s |
|
|
614
|
+
|
|
615
|
+
> **Important:** Code 515 (`restartRequired`) is WhatsApp's normal post-pairing signal. ishumdz-bail correctly treats it as recoverable with 0 ms backoff — other forks incorrectly mark it as fatal, causing bots to stop after first pair.
|
|
616
|
+
|
|
617
|
+
---
|
|
618
|
+
|
|
619
|
+
## ⏱️ Rate Limiter
|
|
620
|
+
|
|
621
|
+
Anti-ban pacing calculator — wire into your send path before each `sendMessage`:
|
|
622
|
+
|
|
623
|
+
```javascript
|
|
624
|
+
import { RateLimiter } from 'ishumdz-bail'
|
|
625
|
+
|
|
626
|
+
const limiter = new RateLimiter({
|
|
627
|
+
maxPerMinute: 8,
|
|
628
|
+
maxPerHour: 200,
|
|
629
|
+
maxPerDay: 1500,
|
|
630
|
+
minDelayMs: 1500,
|
|
631
|
+
maxDelayMs: 5000,
|
|
632
|
+
newChatDelayMs: 3000,
|
|
633
|
+
maxIdenticalMessages: 3,
|
|
634
|
+
burstAllowance: 3
|
|
635
|
+
})
|
|
636
|
+
|
|
637
|
+
async function safeSend(jid, content) {
|
|
638
|
+
const delay = await limiter.getDelay(jid, content)
|
|
639
|
+
if (delay === -1) throw new Error('Rate limit exceeded — blocked')
|
|
640
|
+
if (delay > 0) await new Promise(r => setTimeout(r, delay))
|
|
641
|
+
await sock.sendMessage(jid, content)
|
|
642
|
+
limiter.record(jid, content)
|
|
578
643
|
}
|
|
644
|
+
```
|
|
645
|
+
|
|
646
|
+
---
|
|
647
|
+
|
|
648
|
+
## 📦 Supported Message Types
|
|
649
|
+
|
|
650
|
+
Every WhatsApp message type is covered:
|
|
651
|
+
|
|
652
|
+
- Text, image, video, audio, document, sticker, GIF/video note (PTV)
|
|
653
|
+
- Location & live location
|
|
654
|
+
- Contact / vCard
|
|
655
|
+
- Poll (create, vote, add option, poll result)
|
|
656
|
+
- Button, list, template, interactive (native flow)
|
|
657
|
+
- Album (multiple media in one message)
|
|
658
|
+
- Event & event invite
|
|
659
|
+
- Group invite, group status, group mention
|
|
660
|
+
- Spoiler (blurred) messages
|
|
661
|
+
- Reaction & edited message
|
|
662
|
+
- View-once media
|
|
663
|
+
- Status/story mention & reply
|
|
664
|
+
- Newsletter / channel messages
|
|
665
|
+
- Payment & payment invite
|
|
666
|
+
- All WhatsApp Business types: product, catalog, order, invoice, business profile
|
|
667
|
+
|
|
668
|
+
<details>
|
|
669
|
+
<summary><b>Example: Album</b></summary>
|
|
670
|
+
|
|
671
|
+
```javascript
|
|
672
|
+
await sock.sendMessage(jid, {
|
|
673
|
+
album: [
|
|
674
|
+
{ image: { url: 'https://example.com/1.jpg' } },
|
|
675
|
+
{ video: { url: 'https://example.com/2.mp4' } }
|
|
676
|
+
],
|
|
677
|
+
caption: 'Album caption'
|
|
678
|
+
})
|
|
679
|
+
```
|
|
680
|
+
</details>
|
|
681
|
+
|
|
682
|
+
<details>
|
|
683
|
+
<summary><b>Example: Poll</b></summary>
|
|
684
|
+
|
|
685
|
+
```javascript
|
|
686
|
+
await sock.sendMessage(jid, {
|
|
687
|
+
poll: {
|
|
688
|
+
name: 'Poll Title',
|
|
689
|
+
values: ['Option A', 'Option B'],
|
|
690
|
+
selectableCount: 1
|
|
691
|
+
}
|
|
692
|
+
})
|
|
693
|
+
```
|
|
694
|
+
</details>
|
|
695
|
+
|
|
696
|
+
<details>
|
|
697
|
+
<summary><b>Example: Spoiler</b></summary>
|
|
698
|
+
|
|
699
|
+
```javascript
|
|
700
|
+
await sock.sendMessage(jid, {
|
|
701
|
+
text: 'Spoiler content',
|
|
702
|
+
spoiler: true
|
|
703
|
+
})
|
|
704
|
+
```
|
|
705
|
+
</details>
|
|
706
|
+
|
|
707
|
+
<details>
|
|
708
|
+
<summary><b>Example: Event</b></summary>
|
|
709
|
+
|
|
710
|
+
```javascript
|
|
711
|
+
await sock.sendMessage(jid, {
|
|
712
|
+
eventMessage: {
|
|
713
|
+
name: 'Meeting',
|
|
714
|
+
description: 'Weekly sync',
|
|
715
|
+
location: { degreesLatitude: -6.2, degreesLongitude: 106.8 },
|
|
716
|
+
startTime: Math.floor(Date.now() / 1000) + 3600
|
|
717
|
+
}
|
|
718
|
+
})
|
|
719
|
+
```
|
|
720
|
+
</details>
|
|
721
|
+
|
|
722
|
+
---
|
|
723
|
+
|
|
724
|
+
## 🛠️ Additional Methods
|
|
725
|
+
|
|
726
|
+
```javascript
|
|
727
|
+
// Parse incoming extended/special messages
|
|
728
|
+
sock.ev.on('messages.upsert', ({ messages }) => {
|
|
729
|
+
const extended = sock.parseExtendedMessageContent(messages[0].message)
|
|
730
|
+
if (extended) console.log(extended.type, extended.data)
|
|
731
|
+
})
|
|
732
|
+
|
|
733
|
+
// Business profile
|
|
734
|
+
const profile = await sock.getBusinessProfile(jid)
|
|
735
|
+
await sock.updateBusinessProfile({ description: 'Open 9-5', email: 'hi@example.com', category: 'Retail' })
|
|
736
|
+
|
|
737
|
+
// Get newsletter/channel JID from URL
|
|
738
|
+
await sock.newsletterId('https://whatsapp.com/channel/...')
|
|
739
|
+
|
|
740
|
+
// Refresh media URL for expired messages
|
|
741
|
+
await sock.updateMediaMessage(message)
|
|
742
|
+
```
|
|
743
|
+
|
|
744
|
+
---
|
|
745
|
+
|
|
746
|
+
## 🎮 Games
|
|
747
|
+
|
|
748
|
+
Built-in games for your WhatsApp bot! Import from `ishumdz-bail`:
|
|
749
|
+
|
|
750
|
+
```javascript
|
|
751
|
+
import {
|
|
752
|
+
blackjack, slotMachine, diceGame,
|
|
753
|
+
coinFlip, roulette, rps, trivia,
|
|
754
|
+
createMines, revealTile, cashoutMines
|
|
755
|
+
} from 'ishumdz-bail'
|
|
756
|
+
```
|
|
757
|
+
|
|
758
|
+
### 🃏 Blackjack
|
|
759
|
+
|
|
760
|
+
```javascript
|
|
761
|
+
// Start game
|
|
762
|
+
const game = blackjack('start', [], [], 1000)
|
|
763
|
+
await sock.sendMessage(jid, { text: game.message })
|
|
764
|
+
|
|
765
|
+
// Hit (after start)
|
|
766
|
+
const hit = blackjack('hit', game.playerHand, game.dealerHand, 1000)
|
|
767
|
+
|
|
768
|
+
// Stand
|
|
769
|
+
const stand = blackjack('stand', game)
|
|
770
|
+
|
|
771
|
+
// Double
|
|
772
|
+
const dbl = blackjack('double', game)
|
|
773
|
+
```
|
|
774
|
+
|
|
775
|
+
### 🎰 Slot Machine
|
|
776
|
+
|
|
777
|
+
```javascript
|
|
778
|
+
const slot = slotMachine(100)
|
|
779
|
+
await sock.sendMessage(jid, { text: slot.message })
|
|
780
|
+
// 🎰 [🍒] [🍋] [💎] - NO MATCH
|
|
781
|
+
```
|
|
782
|
+
|
|
783
|
+
### 🎲 Dice
|
|
784
|
+
|
|
785
|
+
```javascript
|
|
786
|
+
const dice = diceGame(100, 'high') // high, low, or seven
|
|
787
|
+
await sock.sendMessage(jid, { text: dice.message })
|
|
788
|
+
```
|
|
789
|
+
|
|
790
|
+
### 🪙 Coin Flip
|
|
791
|
+
|
|
792
|
+
```javascript
|
|
793
|
+
const coin = coinFlip(100, 'heads') // heads or tails
|
|
794
|
+
await sock.sendMessage(jid, { text: coin.message })
|
|
795
|
+
```
|
|
796
|
+
|
|
797
|
+
### 🎰 Roulette
|
|
579
798
|
|
|
580
|
-
|
|
799
|
+
```javascript
|
|
800
|
+
const rou = roulette(100, 'red') // red, black, odd, even, low, high
|
|
801
|
+
await sock.sendMessage(jid, { text: rou.message })
|
|
581
802
|
```
|
|
582
803
|
|
|
583
|
-
###
|
|
804
|
+
### ✊ Rock Paper Scissors
|
|
584
805
|
|
|
585
806
|
```javascript
|
|
586
|
-
const
|
|
807
|
+
const r = rps('rock') // rock, paper, scissors
|
|
808
|
+
await sock.sendMessage(jid, { text: r.message })
|
|
809
|
+
```
|
|
810
|
+
|
|
811
|
+
### 💣 Mines
|
|
812
|
+
|
|
813
|
+
```javascript
|
|
814
|
+
// Create game
|
|
815
|
+
const game = createMines(5, 5, 5) // rows, cols, mines
|
|
816
|
+
|
|
817
|
+
// Reveal tile
|
|
818
|
+
const result = revealTile(game, 0, 0) // row, col
|
|
819
|
+
await sock.sendMessage(jid, { text: result.message })
|
|
587
820
|
|
|
588
|
-
|
|
589
|
-
|
|
821
|
+
// Cashout
|
|
822
|
+
const cashout = cashoutMines(game, 100)
|
|
823
|
+
await sock.sendMessage(jid, { text: cashout.message })
|
|
824
|
+
```
|
|
825
|
+
|
|
826
|
+
### 🧠 Trivia
|
|
827
|
+
|
|
828
|
+
```javascript
|
|
829
|
+
const quiz = trivia(100)
|
|
830
|
+
await sock.sendMessage(jid, { text: quiz.message })
|
|
831
|
+
|
|
832
|
+
// Check answer (A, B, C, or D)
|
|
833
|
+
const answer = checkTriviaAnswer('B', quiz.answer, 100)
|
|
834
|
+
await sock.sendMessage(jid, { text: answer.message })
|
|
835
|
+
```
|
|
836
|
+
|
|
837
|
+
### 📱 Bot Command Example
|
|
838
|
+
|
|
839
|
+
```javascript
|
|
840
|
+
sock.ev.on('messages.upsert', async ({ messages }) => {
|
|
841
|
+
const msg = messages[0]
|
|
842
|
+
const text = msg.message?.conversation || ''
|
|
590
843
|
|
|
591
|
-
|
|
844
|
+
if (text === '.rps rock' || text === '.rps paper' || text === '.rps scissors') {
|
|
845
|
+
const choice = text.split(' ')[1]
|
|
846
|
+
const result = rps(choice)
|
|
847
|
+
await sock.sendMessage(msg.key.remoteJid, { text: result.message })
|
|
848
|
+
}
|
|
592
849
|
|
|
593
|
-
|
|
850
|
+
if (text.startsWith('.slot')) {
|
|
851
|
+
const bet = parseInt(text.split(' ')[1]) || 100
|
|
852
|
+
const result = slotMachine(bet)
|
|
853
|
+
await sock.sendMessage(msg.key.remoteJid, { text: result.message })
|
|
854
|
+
}
|
|
594
855
|
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
856
|
+
if (text.startsWith('.coinflip')) {
|
|
857
|
+
const choice = text.split(' ')[1] || 'heads'
|
|
858
|
+
const bet = parseInt(text.split(' ')[2]) || 100
|
|
859
|
+
const result = coinFlip(bet, choice)
|
|
860
|
+
await sock.sendMessage(msg.key.remoteJid, { text: result.message })
|
|
861
|
+
}
|
|
862
|
+
})
|
|
863
|
+
```
|
|
864
|
+
|
|
865
|
+
---
|
|
866
|
+
|
|
867
|
+
## 📊 Poll Voting
|
|
868
|
+
|
|
869
|
+
Create polls, track votes, and display results.
|
|
870
|
+
|
|
871
|
+
### 🗳️ Create Poll
|
|
872
|
+
|
|
873
|
+
```javascript
|
|
874
|
+
await sock.sendMessage(jid, {
|
|
875
|
+
poll: {
|
|
876
|
+
name: 'Best programming language?',
|
|
877
|
+
values: ['JavaScript', 'Python', 'Java', 'Go', 'Rust'],
|
|
878
|
+
selectableCount: 1
|
|
879
|
+
}
|
|
880
|
+
})
|
|
881
|
+
```
|
|
882
|
+
|
|
883
|
+
### 📊 Poll with Multiple Selections
|
|
884
|
+
|
|
885
|
+
```javascript
|
|
886
|
+
await sock.sendMessage(jid, {
|
|
887
|
+
poll: {
|
|
888
|
+
name: 'Which features do you want?',
|
|
889
|
+
values: ['Games', 'AI', 'Stickers', 'Download'],
|
|
890
|
+
selectableCount: 3 // Users can select up to 3 options
|
|
891
|
+
}
|
|
892
|
+
})
|
|
893
|
+
```
|
|
894
|
+
|
|
895
|
+
### 📢 Announcement Group Poll (Admin Only Voting)
|
|
896
|
+
|
|
897
|
+
```javascript
|
|
898
|
+
await sock.sendMessage(groupJid, {
|
|
899
|
+
poll: {
|
|
900
|
+
name: 'Admin Poll',
|
|
901
|
+
values: ['Option 1', 'Option 2'],
|
|
902
|
+
selectableCount: 1,
|
|
903
|
+
toAnnouncementGroup: true
|
|
904
|
+
}
|
|
905
|
+
})
|
|
906
|
+
```
|
|
907
|
+
|
|
908
|
+
### 🏆 Poll Result (Fake Results)
|
|
909
|
+
|
|
910
|
+
```javascript
|
|
911
|
+
await sock.sendMessage(jid, {
|
|
912
|
+
pollResult: {
|
|
913
|
+
name: 'Best framework?',
|
|
914
|
+
votes: [['React', 150], ['Vue', 120], ['Angular', 80]]
|
|
915
|
+
}
|
|
916
|
+
})
|
|
917
|
+
```
|
|
918
|
+
|
|
919
|
+
### 📈 Track Poll Votes
|
|
920
|
+
|
|
921
|
+
```javascript
|
|
922
|
+
import { getAggregateVotesInPollMessage } from 'ishumdz-bail'
|
|
923
|
+
|
|
924
|
+
// Store messages
|
|
925
|
+
const messageStore = new Map()
|
|
926
|
+
|
|
927
|
+
sock.ev.on('messages.upsert', async ({ messages }) => {
|
|
928
|
+
for (const msg of messages) {
|
|
929
|
+
const id = msg.key.remoteJid + ':' + msg.key.id
|
|
930
|
+
messageStore.set(id, msg)
|
|
931
|
+
}
|
|
932
|
+
})
|
|
933
|
+
|
|
934
|
+
// Listen for poll votes
|
|
935
|
+
sock.ev.on('messages.update', async (events) => {
|
|
936
|
+
for (const { key, update } of events) {
|
|
937
|
+
if (update.pollUpdates) {
|
|
938
|
+
const id = key.remoteJid + ':' + key.id
|
|
939
|
+
const pollCreation = messageStore.get(id)
|
|
940
|
+
|
|
941
|
+
if (pollCreation) {
|
|
942
|
+
const votes = getAggregateVotesInPollMessage({
|
|
943
|
+
message: pollCreation,
|
|
944
|
+
pollUpdates: update.pollUpdates
|
|
945
|
+
})
|
|
946
|
+
|
|
947
|
+
console.log('Poll votes:', votes)
|
|
948
|
+
// [{ name: 'Option 1', voters: ['123@s.whatsapp.net'] }, ...]
|
|
949
|
+
}
|
|
602
950
|
}
|
|
603
|
-
}
|
|
604
|
-
}
|
|
951
|
+
}
|
|
952
|
+
})
|
|
953
|
+
```
|
|
954
|
+
|
|
955
|
+
### 📱 Poll Bot Command Example
|
|
605
956
|
|
|
606
|
-
|
|
957
|
+
```javascript
|
|
958
|
+
sock.ev.on('messages.upsert', async ({ messages }) => {
|
|
959
|
+
const msg = messages[0]
|
|
960
|
+
const text = msg.message?.conversation || ''
|
|
961
|
+
|
|
962
|
+
// .poll Question | Option1 | Option2 | Option3
|
|
963
|
+
if (text.startsWith('.poll')) {
|
|
964
|
+
const args = text.slice(5).split('|').map(s => s.trim())
|
|
965
|
+
const question = args[0]
|
|
966
|
+
const options = args.slice(1)
|
|
967
|
+
|
|
968
|
+
if (question && options.length >= 2) {
|
|
969
|
+
await sock.sendMessage(msg.key.remoteJid, {
|
|
970
|
+
poll: {
|
|
971
|
+
name: question,
|
|
972
|
+
values: options,
|
|
973
|
+
selectableCount: 1
|
|
974
|
+
}
|
|
975
|
+
})
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
// .pollresult React | 150 | Vue | 120
|
|
980
|
+
if (text.startsWith('.pollresult')) {
|
|
981
|
+
const args = text.slice(12).split('|').map(s => s.trim())
|
|
982
|
+
const votes = []
|
|
983
|
+
for (let i = 0; i < args.length; i += 2) {
|
|
984
|
+
votes.push([args[i], parseInt(args[i + 1]) || 0])
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
await sock.sendMessage(msg.key.remoteJid, {
|
|
988
|
+
pollResult: {
|
|
989
|
+
name: 'Poll Results',
|
|
990
|
+
votes
|
|
991
|
+
}
|
|
992
|
+
})
|
|
993
|
+
}
|
|
994
|
+
})
|
|
607
995
|
```
|
|
608
996
|
|
|
609
997
|
---
|
|
610
998
|
|
|
611
|
-
##
|
|
999
|
+
## 🌐 Community & Support
|
|
1000
|
+
|
|
1001
|
+
<div align="center">
|
|
612
1002
|
|
|
613
|
-
|
|
1003
|
+
<table>
|
|
1004
|
+
<tr>
|
|
1005
|
+
<td align="center">
|
|
1006
|
+
<a href="https://ishanx-pro.site.je">
|
|
1007
|
+
🌐<br/><b>Website</b><br/>ishanx-pro.site.je
|
|
1008
|
+
</a>
|
|
1009
|
+
</td>
|
|
1010
|
+
<td align="center">
|
|
1011
|
+
<a href="https://shyracore.indevs.in">
|
|
1012
|
+
💬<br/><b>WhatsApp Channel</b><br/>shyracore.indevs.in
|
|
1013
|
+
</a>
|
|
1014
|
+
</td>
|
|
1015
|
+
</tr>
|
|
1016
|
+
</table>
|
|
1017
|
+
|
|
1018
|
+
**Developer:** Lovely
|
|
1019
|
+
|
|
1020
|
+
</div>
|
|
614
1021
|
|
|
615
1022
|
---
|
|
616
1023
|
|
|
617
1024
|
<div align="center">
|
|
618
1025
|
|
|
619
|
-
|
|
1026
|
+
### ⭐ If this project helped you, consider giving it a star!
|
|
620
1027
|
|
|
621
|
-
|
|
622
|
-
[](https://github.com/lovelyofficial/ishumdz-bail)
|
|
1028
|
+
Made with ❤️ by **Lovely**
|
|
623
1029
|
|
|
624
1030
|
</div>
|
|
1031
|
+
|
|
1032
|
+
---
|
|
1033
|
+
|
|
1034
|
+
## 📄 License
|
|
1035
|
+
|
|
1036
|
+
MIT
|