baileys-joss 1.0.3 → 2.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 +1052 -2534
- package/WAProto/fix-imports.js +22 -18
- package/WAProto/index.js +22 -18
- package/lib/Defaults/index.d.ts +15 -6
- package/lib/Defaults/index.d.ts.map +1 -1
- package/lib/Defaults/index.js +16 -7
- package/lib/Defaults/index.js.map +1 -1
- package/lib/Signal/libsignal.d.ts.map +1 -1
- package/lib/Signal/libsignal.js +105 -16
- package/lib/Signal/libsignal.js.map +1 -1
- package/lib/Signal/lid-mapping.d.ts +8 -9
- package/lib/Signal/lid-mapping.d.ts.map +1 -1
- package/lib/Signal/lid-mapping.js +88 -31
- package/lib/Signal/lid-mapping.js.map +1 -1
- package/lib/Socket/business.d.ts +21 -4
- package/lib/Socket/business.d.ts.map +1 -1
- package/lib/Socket/chats.d.ts +18 -2
- package/lib/Socket/chats.d.ts.map +1 -1
- package/lib/Socket/chats.js +263 -43
- package/lib/Socket/chats.js.map +1 -1
- package/lib/Socket/communities.d.ts +21 -4
- package/lib/Socket/communities.d.ts.map +1 -1
- package/lib/Socket/groups.d.ts +15 -2
- package/lib/Socket/groups.d.ts.map +1 -1
- package/lib/Socket/groups.js +20 -0
- package/lib/Socket/groups.js.map +1 -1
- package/lib/Socket/index.d.ts +21 -4
- package/lib/Socket/index.d.ts.map +1 -1
- package/lib/Socket/messages-recv.d.ts +25 -7
- package/lib/Socket/messages-recv.d.ts.map +1 -1
- package/lib/Socket/messages-recv.js +810 -332
- package/lib/Socket/messages-recv.js.map +1 -1
- package/lib/Socket/messages-send.d.ts +20 -2
- package/lib/Socket/messages-send.d.ts.map +1 -1
- package/lib/Socket/messages-send.js +149 -47
- package/lib/Socket/messages-send.js.map +1 -1
- package/lib/Socket/newsletter.d.ts +13 -1
- package/lib/Socket/newsletter.d.ts.map +1 -1
- package/lib/Socket/newsletter.js +2 -2
- package/lib/Socket/newsletter.js.map +1 -1
- package/lib/Socket/socket.d.ts +8 -2
- package/lib/Socket/socket.d.ts.map +1 -1
- package/lib/Socket/socket.js +109 -26
- package/lib/Socket/socket.js.map +1 -1
- package/lib/Types/Auth.d.ts +2 -0
- package/lib/Types/Auth.d.ts.map +1 -1
- package/lib/Types/Call.d.ts +2 -1
- package/lib/Types/Call.d.ts.map +1 -1
- package/lib/Types/Chat.d.ts +1 -0
- package/lib/Types/Chat.d.ts.map +1 -1
- package/lib/Types/Contact.d.ts +2 -0
- package/lib/Types/Contact.d.ts.map +1 -1
- package/lib/Types/Events.d.ts +21 -1
- package/lib/Types/Events.d.ts.map +1 -1
- package/lib/Types/GroupMetadata.d.ts +4 -0
- package/lib/Types/GroupMetadata.d.ts.map +1 -1
- package/lib/Types/Message.d.ts +20 -5
- package/lib/Types/Message.d.ts.map +1 -1
- package/lib/Types/Message.js.map +1 -1
- package/lib/Types/{Newsletter.d.ts → Mex.d.ts} +11 -5
- package/lib/Types/Mex.d.ts.map +1 -0
- package/lib/Types/{Newsletter.js → Mex.js} +9 -3
- package/lib/Types/Mex.js.map +1 -0
- package/lib/Types/Signal.d.ts +12 -1
- package/lib/Types/Signal.d.ts.map +1 -1
- package/lib/Types/Socket.d.ts +3 -0
- package/lib/Types/Socket.d.ts.map +1 -1
- package/lib/Types/State.d.ts +58 -0
- package/lib/Types/State.d.ts.map +1 -1
- package/lib/Types/State.js +43 -0
- package/lib/Types/State.js.map +1 -1
- package/lib/Types/index.d.ts +2 -1
- package/lib/Types/index.d.ts.map +1 -1
- package/lib/Types/index.js +1 -1
- package/lib/Types/index.js.map +1 -1
- package/lib/Utils/auth-utils.d.ts +5 -0
- package/lib/Utils/auth-utils.d.ts.map +1 -1
- package/lib/Utils/auth-utils.js +12 -0
- package/lib/Utils/auth-utils.js.map +1 -1
- package/lib/Utils/browser-utils.d.ts.map +1 -1
- package/lib/Utils/browser-utils.js +1 -0
- package/lib/Utils/browser-utils.js.map +1 -1
- package/lib/Utils/chat-export.js +30 -30
- package/lib/Utils/chat-utils.d.ts +31 -1
- package/lib/Utils/chat-utils.d.ts.map +1 -1
- package/lib/Utils/chat-utils.js +123 -63
- package/lib/Utils/chat-utils.js.map +1 -1
- package/lib/Utils/companion-reg-client-utils.d.ts +17 -0
- package/lib/Utils/companion-reg-client-utils.d.ts.map +1 -0
- package/lib/Utils/companion-reg-client-utils.js +35 -0
- package/lib/Utils/companion-reg-client-utils.js.map +1 -0
- package/lib/Utils/crypto.d.ts +4 -8
- package/lib/Utils/crypto.d.ts.map +1 -1
- package/lib/Utils/crypto.js +2 -26
- package/lib/Utils/crypto.js.map +1 -1
- package/lib/Utils/decode-wa-message.d.ts +18 -0
- package/lib/Utils/decode-wa-message.d.ts.map +1 -1
- package/lib/Utils/decode-wa-message.js +34 -0
- package/lib/Utils/decode-wa-message.js.map +1 -1
- package/lib/Utils/event-buffer.d.ts +2 -0
- package/lib/Utils/event-buffer.d.ts.map +1 -1
- package/lib/Utils/event-buffer.js +49 -1
- package/lib/Utils/event-buffer.js.map +1 -1
- package/lib/Utils/generics.d.ts +1 -0
- package/lib/Utils/generics.d.ts.map +1 -1
- package/lib/Utils/generics.js +10 -1
- package/lib/Utils/generics.js.map +1 -1
- package/lib/Utils/history.d.ts +2 -0
- package/lib/Utils/history.d.ts.map +1 -1
- package/lib/Utils/history.js +12 -9
- package/lib/Utils/history.js.map +1 -1
- package/lib/Utils/identity-change-handler.d.ts +7 -0
- package/lib/Utils/identity-change-handler.d.ts.map +1 -1
- package/lib/Utils/identity-change-handler.js +1 -0
- package/lib/Utils/identity-change-handler.js.map +1 -1
- package/lib/Utils/index.d.ts +27 -48
- package/lib/Utils/index.d.ts.map +1 -1
- package/lib/Utils/index.js +27 -77
- package/lib/Utils/index.js.map +1 -1
- package/lib/Utils/link-preview.js +2 -2
- package/lib/Utils/link-preview.js.map +1 -1
- package/lib/Utils/lt-hash.d.ts +7 -12
- package/lib/Utils/lt-hash.d.ts.map +1 -1
- package/lib/Utils/lt-hash.js +2 -42
- package/lib/Utils/lt-hash.js.map +1 -1
- package/lib/Utils/meme-generator.js +33 -33
- package/lib/Utils/message-retry-manager.d.ts +35 -2
- package/lib/Utils/message-retry-manager.d.ts.map +1 -1
- package/lib/Utils/message-retry-manager.js +99 -2
- package/lib/Utils/message-retry-manager.js.map +1 -1
- package/lib/Utils/messages-media.d.ts +6 -3
- package/lib/Utils/messages-media.d.ts.map +1 -1
- package/lib/Utils/messages-media.js +25 -11
- package/lib/Utils/messages-media.js.map +1 -1
- package/lib/Utils/messages.d.ts.map +1 -1
- package/lib/Utils/messages.js +28 -5
- package/lib/Utils/messages.js.map +1 -1
- package/lib/Utils/mini-games.js +7 -7
- package/lib/Utils/noise-handler.d.ts +7 -7
- package/lib/Utils/noise-handler.d.ts.map +1 -1
- package/lib/Utils/noise-handler.js +33 -27
- package/lib/Utils/noise-handler.js.map +1 -1
- package/lib/Utils/offline-node-processor.d.ts +17 -0
- package/lib/Utils/offline-node-processor.d.ts.map +1 -0
- package/lib/Utils/offline-node-processor.js +40 -0
- package/lib/Utils/offline-node-processor.js.map +1 -0
- package/lib/Utils/process-message.d.ts.map +1 -1
- package/lib/Utils/process-message.js +140 -14
- package/lib/Utils/process-message.js.map +1 -1
- package/lib/Utils/qr-generator.js +16 -16
- package/lib/Utils/reporting-utils.js +2 -2
- package/lib/Utils/reporting-utils.js.map +1 -1
- package/lib/Utils/signal.d.ts +13 -0
- package/lib/Utils/signal.d.ts.map +1 -1
- package/lib/Utils/signal.js +42 -0
- package/lib/Utils/signal.js.map +1 -1
- package/lib/Utils/stanza-ack.d.ts +11 -0
- package/lib/Utils/stanza-ack.d.ts.map +1 -0
- package/lib/Utils/stanza-ack.js +38 -0
- package/lib/Utils/stanza-ack.js.map +1 -0
- package/lib/Utils/sync-action-utils.d.ts.map +1 -1
- package/lib/Utils/sync-action-utils.js +1 -0
- package/lib/Utils/sync-action-utils.js.map +1 -1
- package/lib/Utils/tc-token-utils.d.ts +26 -1
- package/lib/Utils/tc-token-utils.d.ts.map +1 -1
- package/lib/Utils/tc-token-utils.js +151 -5
- package/lib/Utils/tc-token-utils.js.map +1 -1
- package/lib/Utils/templates.js +104 -104
- package/lib/Utils/validate-connection.d.ts.map +1 -1
- package/lib/Utils/validate-connection.js +12 -2
- package/lib/Utils/validate-connection.js.map +1 -1
- package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts.map +1 -1
- package/lib/WAUSync/Protocols/USyncContactProtocol.js +26 -3
- package/lib/WAUSync/Protocols/USyncContactProtocol.js.map +1 -1
- package/lib/WAUSync/Protocols/USyncUsernameProtocol.d.ts +10 -0
- package/lib/WAUSync/Protocols/USyncUsernameProtocol.d.ts.map +1 -0
- package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +25 -0
- package/lib/WAUSync/Protocols/USyncUsernameProtocol.js.map +1 -0
- package/lib/WAUSync/Protocols/index.d.ts +1 -0
- package/lib/WAUSync/Protocols/index.d.ts.map +1 -1
- package/lib/WAUSync/Protocols/index.js +1 -0
- package/lib/WAUSync/Protocols/index.js.map +1 -1
- package/lib/WAUSync/USyncQuery.d.ts +1 -0
- package/lib/WAUSync/USyncQuery.d.ts.map +1 -1
- package/lib/WAUSync/USyncQuery.js +6 -2
- package/lib/WAUSync/USyncQuery.js.map +1 -1
- package/lib/WAUSync/USyncUser.d.ts +4 -0
- package/lib/WAUSync/USyncUser.d.ts.map +1 -1
- package/lib/WAUSync/USyncUser.js +8 -0
- package/lib/WAUSync/USyncUser.js.map +1 -1
- package/package.json +41 -12
- package/lib/Types/Newsletter.d.ts.map +0 -1
- package/lib/Types/Newsletter.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,2794 +1,1312 @@
|
|
|
1
|
-
<
|
|
2
|
-
<img src="https://raw.githubusercontent.com/firdausmntp/Baileys-Joss/main/Media/logo.png" alt="Baileys-Joss" width="200"/>
|
|
3
|
-
</p>
|
|
4
|
-
|
|
5
|
-
<h1 align="center">🚀 Baileys-Joss</h1>
|
|
6
|
-
|
|
7
|
-
<p align="center">
|
|
8
|
-
<b>WhatsApp Web API Library dengan Fitur Ekstra Premium</b><br>
|
|
9
|
-
Fork dari <a href="https://github.com/WhiskeySockets/Baileys">Baileys</a> dengan penambahan fitur Interactive Button, Albums, AI Message, LID Plotting, dan lainnya.
|
|
10
|
-
</p>
|
|
11
|
-
|
|
12
|
-
<p align="center">
|
|
13
|
-
<a href="https://www.npmjs.com/package/baileys-joss"><img src="https://img.shields.io/npm/v/baileys-joss?color=brightgreen&label=npm&style=for-the-badge&logo=npm" alt="npm version"/></a>
|
|
14
|
-
<a href="https://www.npmjs.com/package/baileys-joss"><img src="https://img.shields.io/npm/dm/baileys-joss?color=blue&style=for-the-badge&logo=npm" alt="npm downloads"/></a>
|
|
15
|
-
<a href="https://www.npmjs.com/package/baileys-joss"><img src="https://img.shields.io/npm/dt/baileys-joss?color=blue&style=for-the-badge" alt="npm total downloads"/></a>
|
|
16
|
-
</p>
|
|
17
|
-
|
|
18
|
-
<p align="center">
|
|
19
|
-
<a href="https://github.com/firdausmntp/Baileys-Joss/blob/main/LICENSE"><img src="https://img.shields.io/github/license/firdausmntp/Baileys-Joss?style=for-the-badge&logo=opensourceinitiative&logoColor=white" alt="license"/></a>
|
|
20
|
-
<a href="https://github.com/firdausmntp/Baileys-Joss/stargazers"><img src="https://img.shields.io/github/stars/firdausmntp/Baileys-Joss?style=for-the-badge&logo=github&color=gold" alt="stars"/></a>
|
|
21
|
-
<a href="https://github.com/firdausmntp/Baileys-Joss/network/members"><img src="https://img.shields.io/github/forks/firdausmntp/Baileys-Joss?style=for-the-badge&logo=github&color=purple" alt="forks"/></a>
|
|
22
|
-
<a href="https://github.com/firdausmntp/Baileys-Joss/issues"><img src="https://img.shields.io/github/issues/firdausmntp/Baileys-Joss?style=for-the-badge&logo=github&color=red" alt="issues"/></a>
|
|
23
|
-
</p>
|
|
24
|
-
|
|
25
|
-
<p align="center">
|
|
26
|
-
<a href="#-installation">📦 Installation</a> •
|
|
27
|
-
<a href="#-features">✨ Features</a> •
|
|
28
|
-
<a href="#-quick-start">🚀 Quick Start</a> •
|
|
29
|
-
<a href="#-use-case-examples">💡 Examples</a> •
|
|
30
|
-
<a href="#-api-reference">📋 API</a> •
|
|
31
|
-
<a href="#-contributing">🤝 Contributing</a>
|
|
32
|
-
</p>
|
|
33
|
-
|
|
34
|
-
<p align="center">
|
|
35
|
-
<b>📖 Documentation:</b>
|
|
36
|
-
<a href="./README.md">🇮🇩 Indonesia</a> |
|
|
37
|
-
<a href="./docs/README.en.md">🇺🇸 English</a>
|
|
38
|
-
</p>
|
|
39
|
-
|
|
40
|
-
<p align="center">
|
|
41
|
-
<b>🎮 Full Demo:</b>
|
|
42
|
-
<a href="./Example/wa-baileys-joss-complete.js">📁 Local Example File</a>
|
|
43
|
-
</p>
|
|
44
|
-
|
|
45
|
-
---
|
|
46
|
-
|
|
47
|
-
## ✨ Kenapa Baileys-Joss?
|
|
48
|
-
|
|
49
|
-
<table>
|
|
50
|
-
<tr>
|
|
51
|
-
<th align="center">🎯 Feature</th>
|
|
52
|
-
<th align="center">Baileys Original</th>
|
|
53
|
-
<th align="center">Baileys-Joss</th>
|
|
54
|
-
</tr>
|
|
55
|
-
<tr>
|
|
56
|
-
<td>🖱️ Interactive Buttons</td>
|
|
57
|
-
<td align="center">❌</td>
|
|
58
|
-
<td align="center">✅</td>
|
|
59
|
-
</tr>
|
|
60
|
-
<tr>
|
|
61
|
-
<td>📋 List Messages</td>
|
|
62
|
-
<td align="center">❌</td>
|
|
63
|
-
<td align="center">✅</td>
|
|
64
|
-
</tr>
|
|
65
|
-
<tr>
|
|
66
|
-
<td>📋 Copy Code Button</td>
|
|
67
|
-
<td align="center">❌</td>
|
|
68
|
-
<td align="center">✅</td>
|
|
69
|
-
</tr>
|
|
70
|
-
<tr>
|
|
71
|
-
<td>🔗 URL Buttons</td>
|
|
72
|
-
<td align="center">❌</td>
|
|
73
|
-
<td align="center">✅</td>
|
|
74
|
-
</tr>
|
|
75
|
-
<tr>
|
|
76
|
-
<td>🔄 Combined Button Types</td>
|
|
77
|
-
<td align="center">❌</td>
|
|
78
|
-
<td align="center">✅</td>
|
|
79
|
-
</tr>
|
|
80
|
-
<tr>
|
|
81
|
-
<td>🎨 Native Flow Messages</td>
|
|
82
|
-
<td align="center">❌</td>
|
|
83
|
-
<td align="center">✅</td>
|
|
84
|
-
</tr>
|
|
85
|
-
<tr>
|
|
86
|
-
<td>👤 LID/SenderPn Plotting</td>
|
|
87
|
-
<td align="center">❌</td>
|
|
88
|
-
<td align="center">✅</td>
|
|
89
|
-
</tr>
|
|
90
|
-
<tr>
|
|
91
|
-
<td>🖼️ Album Messages</td>
|
|
92
|
-
<td align="center">❌</td>
|
|
93
|
-
<td align="center">✅</td>
|
|
94
|
-
</tr>
|
|
95
|
-
<tr>
|
|
96
|
-
<td>🤖 AI Message Style</td>
|
|
97
|
-
<td align="center">❌</td>
|
|
98
|
-
<td align="center">✅</td>
|
|
99
|
-
</tr>
|
|
100
|
-
<tr>
|
|
101
|
-
<td>📊 Poll Creation</td>
|
|
102
|
-
<td align="center">✅</td>
|
|
103
|
-
<td align="center">✅ Enhanced</td>
|
|
104
|
-
</tr>
|
|
105
|
-
<tr>
|
|
106
|
-
<td>📢 Newsletter/Channel Control</td>
|
|
107
|
-
<td align="center">✅</td>
|
|
108
|
-
<td align="center">✅ Enhanced</td>
|
|
109
|
-
</tr>
|
|
110
|
-
<tr>
|
|
111
|
-
<td>🔐 Custom Pairing Code</td>
|
|
112
|
-
<td align="center">❌</td>
|
|
113
|
-
<td align="center">✅</td>
|
|
114
|
-
</tr>
|
|
115
|
-
<tr>
|
|
116
|
-
<td>📷 HD Profile Pictures</td>
|
|
117
|
-
<td align="center">✅</td>
|
|
118
|
-
<td align="center">✅</td>
|
|
119
|
-
</tr>
|
|
120
|
-
<tr>
|
|
121
|
-
<td>🔧 Fixed Button Delivery</td>
|
|
122
|
-
<td align="center">❌</td>
|
|
123
|
-
<td align="center">✅</td>
|
|
124
|
-
</tr>
|
|
125
|
-
<tr>
|
|
126
|
-
<td>📸 HD Images (Uncompressed)</td>
|
|
127
|
-
<td align="center">❌</td>
|
|
128
|
-
<td align="center">✅</td>
|
|
129
|
-
</tr>
|
|
130
|
-
<tr>
|
|
131
|
-
<td>🎬 HD Videos (Uncompressed)</td>
|
|
132
|
-
<td align="center">❌</td>
|
|
133
|
-
<td align="center">✅</td>
|
|
134
|
-
</tr>
|
|
135
|
-
<tr>
|
|
136
|
-
<td>🌄 Panorama Profile Picture</td>
|
|
137
|
-
<td align="center">❌</td>
|
|
138
|
-
<td align="center">✅</td>
|
|
139
|
-
</tr>
|
|
140
|
-
<tr>
|
|
141
|
-
<td>📅 Message Scheduling</td>
|
|
142
|
-
<td align="center">❌</td>
|
|
143
|
-
<td align="center">✅</td>
|
|
144
|
-
</tr>
|
|
145
|
-
<tr>
|
|
146
|
-
<td>📨 Bulk Messaging</td>
|
|
147
|
-
<td align="center">❌</td>
|
|
148
|
-
<td align="center">✅</td>
|
|
149
|
-
</tr>
|
|
150
|
-
<tr>
|
|
151
|
-
<td>🔄 Auto Reply System</td>
|
|
152
|
-
<td align="center">❌</td>
|
|
153
|
-
<td align="center">✅</td>
|
|
154
|
-
</tr>
|
|
155
|
-
<tr>
|
|
156
|
-
<td>📇 Contact Card (vCard)</td>
|
|
157
|
-
<td align="center">⚠️ Basic</td>
|
|
158
|
-
<td align="center">✅ Enhanced</td>
|
|
159
|
-
</tr>
|
|
160
|
-
<tr>
|
|
161
|
-
<td>📺 Status/Story Posting</td>
|
|
162
|
-
<td align="center">⚠️ Basic</td>
|
|
163
|
-
<td align="center">✅ Enhanced</td>
|
|
164
|
-
</tr>
|
|
165
|
-
<tr>
|
|
166
|
-
<td>📋 Message Templates</td>
|
|
167
|
-
<td align="center">❌</td>
|
|
168
|
-
<td align="center">✅</td>
|
|
169
|
-
</tr>
|
|
170
|
-
<tr>
|
|
171
|
-
<td>📡 Broadcast Manager</td>
|
|
172
|
-
<td align="center">❌</td>
|
|
173
|
-
<td align="center">✅</td>
|
|
174
|
-
</tr>
|
|
175
|
-
<tr>
|
|
176
|
-
<td>⌨️ Typing Indicator</td>
|
|
177
|
-
<td align="center">⚠️ Basic</td>
|
|
178
|
-
<td align="center">✅ Enhanced</td>
|
|
179
|
-
</tr>
|
|
180
|
-
<tr>
|
|
181
|
-
<td>✅ Read Receipt Control</td>
|
|
182
|
-
<td align="center">⚠️ Basic</td>
|
|
183
|
-
<td align="center">✅ Enhanced</td>
|
|
184
|
-
</tr>
|
|
185
|
-
<tr>
|
|
186
|
-
<td>🔍 Message Search</td>
|
|
187
|
-
<td align="center">❌</td>
|
|
188
|
-
<td align="center">✅</td>
|
|
189
|
-
</tr>
|
|
190
|
-
<tr>
|
|
191
|
-
<td>📊 Chat Analytics</td>
|
|
192
|
-
<td align="center">❌</td>
|
|
193
|
-
<td align="center">✅</td>
|
|
194
|
-
</tr>
|
|
195
|
-
<tr>
|
|
196
|
-
<td>💾 Chat Export</td>
|
|
197
|
-
<td align="center">❌</td>
|
|
198
|
-
<td align="center">✅</td>
|
|
199
|
-
</tr>
|
|
200
|
-
<tr>
|
|
201
|
-
<td>🔗 QR Code Generator</td>
|
|
202
|
-
<td align="center">⚠️ Basic</td>
|
|
203
|
-
<td align="center">✅ Enhanced</td>
|
|
204
|
-
</tr>
|
|
205
|
-
<tr>
|
|
206
|
-
<td>📁 Media Downloader</td>
|
|
207
|
-
<td align="center">❌</td>
|
|
208
|
-
<td align="center">✅</td>
|
|
209
|
-
</tr>
|
|
210
|
-
<tr>
|
|
211
|
-
<td>🎮 Mini Games</td>
|
|
212
|
-
<td align="center">❌</td>
|
|
213
|
-
<td align="center">✅ Tested</td>
|
|
214
|
-
</tr>
|
|
215
|
-
<tr>
|
|
216
|
-
<td>🔍 Content Detector</td>
|
|
217
|
-
<td align="center">❌</td>
|
|
218
|
-
<td align="center">✅ Tested</td>
|
|
219
|
-
</tr>
|
|
220
|
-
<tr>
|
|
221
|
-
<td>🛡️ Anti-Spam System</td>
|
|
222
|
-
<td align="center">❌</td>
|
|
223
|
-
<td align="center">✅ Tested</td>
|
|
224
|
-
</tr>
|
|
225
|
-
<tr>
|
|
226
|
-
<td>🔗 Link Scanner</td>
|
|
227
|
-
<td align="center">❌</td>
|
|
228
|
-
<td align="center">✅ Tested</td>
|
|
229
|
-
</tr>
|
|
230
|
-
<tr>
|
|
231
|
-
<td>📝 Activity Logger</td>
|
|
232
|
-
<td align="center">❌</td>
|
|
233
|
-
<td align="center">✅ Tested</td>
|
|
234
|
-
</tr>
|
|
235
|
-
<tr>
|
|
236
|
-
<td>🎭 Meme Generator</td>
|
|
237
|
-
<td align="center">❌</td>
|
|
238
|
-
<td align="center">✅ Tested</td>
|
|
239
|
-
</tr>
|
|
240
|
-
<tr>
|
|
241
|
-
<td>🍅 Pomodoro Timer</td>
|
|
242
|
-
<td align="center">❌</td>
|
|
243
|
-
<td align="center">✅ Tested</td>
|
|
244
|
-
</tr>
|
|
245
|
-
<tr>
|
|
246
|
-
<td>💬 Quote Generator</td>
|
|
247
|
-
<td align="center">❌</td>
|
|
248
|
-
<td align="center">✅ Tested</td>
|
|
249
|
-
</tr>
|
|
250
|
-
<tr>
|
|
251
|
-
<td>🌤️ Weather Bot</td>
|
|
252
|
-
<td align="center">❌</td>
|
|
253
|
-
<td align="center">✅ Tested</td>
|
|
254
|
-
</tr>
|
|
255
|
-
</table>
|
|
256
|
-
|
|
257
|
-
---
|
|
258
|
-
|
|
259
|
-
## 📦 Installation
|
|
260
|
-
|
|
261
|
-
```bash
|
|
262
|
-
# Menggunakan npm
|
|
263
|
-
npm install baileys-joss
|
|
264
|
-
|
|
265
|
-
# Menggunakan yarn
|
|
266
|
-
yarn add baileys-joss
|
|
267
|
-
|
|
268
|
-
# Menggunakan pnpm
|
|
269
|
-
pnpm add baileys-joss
|
|
270
|
-
```
|
|
271
|
-
|
|
272
|
-
<details>
|
|
273
|
-
<summary><b>📦 Via package.json (Fork Override)</b></summary>
|
|
274
|
-
|
|
275
|
-
```json
|
|
276
|
-
// Untuk mengganti @whiskeysockets/baileys
|
|
277
|
-
{
|
|
278
|
-
"dependencies": {
|
|
279
|
-
"@whiskeysockets/baileys": "npm:baileys-joss"
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
// Untuk mengganti @adiwajshing/baileys
|
|
284
|
-
{
|
|
285
|
-
"dependencies": {
|
|
286
|
-
"@adiwajshing/baileys": "npm:baileys-joss"
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
```
|
|
290
|
-
|
|
291
|
-
</details>
|
|
292
|
-
|
|
293
|
-
---
|
|
294
|
-
|
|
295
|
-
## 🎯 Features
|
|
1
|
+
<h1 align='center'><img alt="Baileys logo" src="https://raw.githubusercontent.com/WhiskeySockets/Baileys/refs/heads/master/Media/logo.png" height="75"/></h1>
|
|
296
2
|
|
|
297
|
-
<
|
|
298
|
-
<summary><h3>🖱️ Interactive Messages & Buttons</h3></summary>
|
|
3
|
+
<div align='center'>Baileys is a WebSockets-based TypeScript library for interacting with the WhatsApp Web API.</div>
|
|
299
4
|
|
|
300
|
-
Fitur button interactive yang lebih lengkap dan mudah digunakan:
|
|
301
5
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
generateCopyCodeButton,
|
|
309
|
-
generateUrlButtonMessage,
|
|
310
|
-
generateQuickReplyButtons
|
|
311
|
-
} from 'baileys-joss'
|
|
6
|
+
> [!CAUTION]
|
|
7
|
+
> NOTICE OF BREAKING CHANGE.
|
|
8
|
+
>
|
|
9
|
+
> As of 7.0.0, multiple breaking changes were introduced into the library.
|
|
10
|
+
>
|
|
11
|
+
> Please check out https://whiskey.so/migrate-latest for more information.
|
|
312
12
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
'Pilih opsi di bawah ini:',
|
|
316
|
-
[
|
|
317
|
-
{ id: 'btn-1', displayText: '✅ Setuju' },
|
|
318
|
-
{ id: 'btn-2', displayText: '❌ Tolak' },
|
|
319
|
-
{ id: 'btn-3', displayText: '📞 Hubungi CS' }
|
|
320
|
-
],
|
|
321
|
-
{ footer: 'Powered by Baileys-Joss' }
|
|
322
|
-
)
|
|
13
|
+
# Important Note
|
|
14
|
+
This is a temporary README.md, the new guide is in development and will this file will be replaced with .github/README.md (already a default on GitHub).
|
|
323
15
|
|
|
324
|
-
|
|
16
|
+
New guide link: https://baileys.wiki
|
|
325
17
|
|
|
326
|
-
|
|
327
|
-
const urlButton = generateUrlButtonMessage(
|
|
328
|
-
'Kunjungi website kami untuk info lebih lanjut',
|
|
329
|
-
[{ displayText: '🌐 Buka Website', url: 'https://example.com' }],
|
|
330
|
-
{ title: 'Info Produk', footer: 'Click untuk membuka' }
|
|
331
|
-
)
|
|
18
|
+
# Get Support
|
|
332
19
|
|
|
333
|
-
|
|
20
|
+
If you'd like business to enterprise-level support from Rajeh, the current maintainer of Baileys, you can book a video chat. Book a 1 hour time slot by contacting him on Discord or pre-ordering [here](https://purpshell.dev/book). The earlier you pre-order the better, as his time slots usually fill up very quickly. He offers immense value per hour and will answer all your questions before the time runs out.
|
|
334
21
|
|
|
335
|
-
|
|
336
|
-
const copyButton = generateCopyCodeButton(
|
|
337
|
-
'Kode OTP Anda adalah:',
|
|
338
|
-
'123456',
|
|
339
|
-
'📋 Copy Kode'
|
|
340
|
-
)
|
|
22
|
+
If you are a business, we encourage you to contribute back to the high development costs of the project and to feed the maintainers who dump tens of hours a week on this. You can do so by booking meetings or sponsoring below. All support, even in bona fide / contribution hours, is welcome by businesses of all sizes. This is not condoning or endorsing businesses to use the library. See the Disclaimer below.
|
|
341
23
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
// Combined Buttons (mix URL, Reply, Copy, Call)
|
|
345
|
-
const combinedButtons = generateCombinedButtons(
|
|
346
|
-
'Pilih aksi:',
|
|
347
|
-
[
|
|
348
|
-
{ type: 'reply', displayText: '🛒 Pesan Sekarang', id: 'order' },
|
|
349
|
-
{ type: 'url', displayText: '🌐 Website', url: 'https://example.com' },
|
|
350
|
-
{ type: 'call', displayText: '📞 Telepon', phoneNumber: '+6281234567890' },
|
|
351
|
-
{ type: 'copy', displayText: '📋 Copy Promo', copyCode: 'PROMO2024' }
|
|
352
|
-
],
|
|
353
|
-
{ title: 'Menu Utama', footer: 'Baileys-Joss' }
|
|
354
|
-
)
|
|
24
|
+
# Sponsor
|
|
25
|
+
If you'd like to financially support this project, you can do so by supporting the current maintainer [here](https://purpshell.dev/sponsor).
|
|
355
26
|
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
const listMessage = generateInteractiveListMessage({
|
|
360
|
-
title: '📋 Menu Produk',
|
|
361
|
-
buttonText: 'Lihat Menu',
|
|
362
|
-
description: 'Silahkan pilih produk yang diinginkan',
|
|
363
|
-
footer: 'Ketik nomor untuk memesan',
|
|
364
|
-
sections: [
|
|
365
|
-
{
|
|
366
|
-
title: 'Makanan',
|
|
367
|
-
rows: [
|
|
368
|
-
{ rowId: 'nasi-goreng', title: 'Nasi Goreng', description: 'Rp 25.000' },
|
|
369
|
-
{ rowId: 'mie-goreng', title: 'Mie Goreng', description: 'Rp 22.000' }
|
|
370
|
-
]
|
|
371
|
-
},
|
|
372
|
-
{
|
|
373
|
-
title: 'Minuman',
|
|
374
|
-
rows: [
|
|
375
|
-
{ rowId: 'es-teh', title: 'Es Teh', description: 'Rp 5.000' },
|
|
376
|
-
{ rowId: 'kopi', title: 'Kopi', description: 'Rp 10.000' }
|
|
377
|
-
]
|
|
378
|
-
}
|
|
379
|
-
]
|
|
380
|
-
})
|
|
27
|
+
# Disclaimer
|
|
28
|
+
This project is not affiliated, associated, authorized, endorsed by, or in any way officially connected with WhatsApp or any of its subsidiaries or its affiliates.
|
|
29
|
+
The official WhatsApp website can be found at whatsapp.com. "WhatsApp" as well as related names, marks, emblems and images are registered trademarks of their respective owners.
|
|
381
30
|
|
|
382
|
-
|
|
383
|
-
|
|
31
|
+
The maintainers of Baileys do not in any way condone the use of this application in practices that violate the Terms of Service of WhatsApp. The maintainers of this application call upon the personal responsibility of its users to use this application in a fair way, as it is intended to be used.
|
|
32
|
+
Use at your own discretion. Do not spam people with this. We discourage any stalkerware, bulk or automated messaging usage.
|
|
384
33
|
|
|
385
|
-
|
|
34
|
+
##
|
|
386
35
|
|
|
387
|
-
|
|
388
|
-
|
|
36
|
+
- Baileys does not require Selenium or any other browser to be interface with WhatsApp Web, it does so directly using a **WebSocket**.
|
|
37
|
+
- Not running Selenium or Chromium saves you like **half a gig** of ram :/
|
|
38
|
+
- Baileys supports interacting with the multi-device & web versions of WhatsApp.
|
|
39
|
+
- Thank you to [@pokearaujo](https://github.com/pokearaujo/multidevice) for writing his observations on the workings of WhatsApp Multi-Device. Also, thank you to [@Sigalor](https://github.com/sigalor/whatsapp-web-reveng) for writing his observations on the workings of WhatsApp Web and thanks to [@Rhymen](https://github.com/Rhymen/go-whatsapp/) for the __go__ implementation.
|
|
389
40
|
|
|
390
|
-
|
|
41
|
+
> [!IMPORTANT]
|
|
42
|
+
> The original repository had to be removed by the original author - we now continue development in this repository here.
|
|
43
|
+
This is the only official repository and is maintained by the community.
|
|
44
|
+
> **Join the Discord [here](https://discord.gg/WeJM5FP9GG)**
|
|
391
45
|
|
|
392
|
-
|
|
393
|
-
// Send Album (grouped images/videos)
|
|
394
|
-
const albumMedia = [
|
|
395
|
-
{ image: { url: 'https://example.com/pic1.jpg' }, caption: 'Photo 1' },
|
|
396
|
-
{ image: { url: 'https://example.com/pic2.jpg' }, caption: 'Photo 2' },
|
|
397
|
-
{ video: { url: 'https://example.com/video.mp4' }, caption: 'Video' }
|
|
398
|
-
]
|
|
46
|
+
## Example
|
|
399
47
|
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
48
|
+
Do check out & run [example.ts](Example/example.ts) to see an example usage of the library.
|
|
49
|
+
The script covers most common use cases.
|
|
50
|
+
To run the example script, download or clone the repo and then type the following in a terminal:
|
|
51
|
+
1. ``` cd path/to/Baileys ```
|
|
52
|
+
2. ``` yarn ```
|
|
53
|
+
3. ``` yarn example ```
|
|
404
54
|
|
|
405
|
-
|
|
406
|
-
const localAlbum = [
|
|
407
|
-
{ image: fs.readFileSync('./image1.jpg') },
|
|
408
|
-
{ image: fs.readFileSync('./image2.jpg') },
|
|
409
|
-
{ video: fs.readFileSync('./video.mp4'), gifPlayback: true }
|
|
410
|
-
]
|
|
55
|
+
## Install
|
|
411
56
|
|
|
412
|
-
|
|
57
|
+
Use the stable version:
|
|
413
58
|
```
|
|
414
|
-
|
|
415
|
-
</details>
|
|
416
|
-
|
|
417
|
-
<details>
|
|
418
|
-
<summary><h3>🤖 AI Message Style</h3></summary>
|
|
419
|
-
|
|
420
|
-
Tambahkan ikon AI stylish pada pesan:
|
|
421
|
-
|
|
422
|
-
```typescript
|
|
423
|
-
// Kirim pesan dengan AI icon
|
|
424
|
-
await sock.sendMessage(jid, {
|
|
425
|
-
text: 'Halo! Saya adalah asisten AI Anda 🤖',
|
|
426
|
-
ai: true // Menampilkan ikon AI pada pesan
|
|
427
|
-
})
|
|
428
|
-
|
|
429
|
-
// AI dengan media
|
|
430
|
-
await sock.sendMessage(jid, {
|
|
431
|
-
image: { url: 'https://example.com/ai-generated.jpg' },
|
|
432
|
-
caption: 'Generated by AI',
|
|
433
|
-
ai: true
|
|
434
|
-
})
|
|
59
|
+
yarn add @whiskeysockets/baileys
|
|
435
60
|
```
|
|
436
61
|
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
<details>
|
|
440
|
-
<summary><h3>📸 HD Images & Videos (Uncompressed)</h3></summary>
|
|
441
|
-
|
|
442
|
-
Kirim gambar dan video tanpa kompresi dalam kualitas HD:
|
|
443
|
-
|
|
444
|
-
```typescript
|
|
445
|
-
// Kirim gambar HD (kualitas tinggi, tidak dikompres)
|
|
446
|
-
await sock.sendMessage(jid, {
|
|
447
|
-
image: { url: './photo-hd.jpg' },
|
|
448
|
-
caption: 'Foto HD 📸',
|
|
449
|
-
hd: true // Kirim tanpa kompresi
|
|
450
|
-
})
|
|
451
|
-
|
|
452
|
-
// Kirim video HD
|
|
453
|
-
await sock.sendMessage(jid, {
|
|
454
|
-
video: { url: './video-4k.mp4' },
|
|
455
|
-
caption: 'Video 4K 🎬',
|
|
456
|
-
hd: true // Kualitas asli
|
|
457
|
-
})
|
|
458
|
-
|
|
459
|
-
// HD dengan media dari URL
|
|
460
|
-
await sock.sendMessage(jid, {
|
|
461
|
-
image: { url: 'https://example.com/high-res-photo.jpg' },
|
|
462
|
-
hd: true,
|
|
463
|
-
caption: 'High Resolution Photo'
|
|
464
|
-
})
|
|
62
|
+
Use the edge version (no guarantee of stability, but latest fixes + features)
|
|
465
63
|
```
|
|
466
|
-
|
|
467
|
-
</details>
|
|
468
|
-
|
|
469
|
-
<details>
|
|
470
|
-
<summary><h3>🌄 Panorama Profile Picture</h3></summary>
|
|
471
|
-
|
|
472
|
-
Set foto profil panorama (wide) tanpa cropping:
|
|
473
|
-
|
|
474
|
-
```typescript
|
|
475
|
-
// Set panorama profile picture (tidak di-crop square)
|
|
476
|
-
await sock.updatePanoramaProfilePicture(myJid, { url: './panorama.jpg' })
|
|
477
|
-
|
|
478
|
-
// Dengan opsi kustom
|
|
479
|
-
await sock.updatePanoramaProfilePicture(myJid, { url: './wide-photo.jpg' }, {
|
|
480
|
-
maxWidth: 1080, // Maximum width
|
|
481
|
-
quality: 90 // JPEG quality (1-100)
|
|
482
|
-
})
|
|
483
|
-
|
|
484
|
-
// Set panorama untuk grup
|
|
485
|
-
await sock.updatePanoramaProfilePicture(groupJid, { url: './group-banner.jpg' })
|
|
486
|
-
|
|
487
|
-
// Atau gunakan profile picture biasa (square crop)
|
|
488
|
-
await sock.updateProfilePicture(myJid, { url: './square-photo.jpg' })
|
|
64
|
+
yarn add github:WhiskeySockets/Baileys
|
|
489
65
|
```
|
|
490
66
|
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
<summary><h3>📊 Poll Creation</h3></summary>
|
|
495
|
-
|
|
496
|
-
Buat polling dengan mudah:
|
|
497
|
-
|
|
498
|
-
```typescript
|
|
499
|
-
// Create a Poll
|
|
500
|
-
const pollMessage = {
|
|
501
|
-
name: '🎨 Warna Favorit?',
|
|
502
|
-
values: ['🔴 Merah', '🔵 Biru', '🟢 Hijau', '🟡 Kuning'],
|
|
503
|
-
selectableCount: 1 // Jumlah pilihan yang bisa dipilih
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
await sock.sendMessage(jid, { poll: pollMessage })
|
|
507
|
-
|
|
508
|
-
// Multi-select Poll
|
|
509
|
-
const multiPoll = {
|
|
510
|
-
name: '🍕 Topping Pizza Favorit?',
|
|
511
|
-
values: ['Pepperoni', 'Mushroom', 'Cheese', 'Olive', 'Bacon'],
|
|
512
|
-
selectableCount: 3 // Bisa pilih hingga 3 opsi
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
await sock.sendMessage(jid, { poll: multiPoll })
|
|
67
|
+
Then import your code using:
|
|
68
|
+
```ts
|
|
69
|
+
import makeWASocket from '@whiskeysockets/baileys'
|
|
516
70
|
```
|
|
517
71
|
|
|
518
|
-
|
|
72
|
+
# Links
|
|
73
|
+
|
|
74
|
+
- [Discord](https://discord.gg/WeJM5FP9GG)
|
|
75
|
+
- [Docs](https://baileys.wiki/docs/intro/)
|
|
76
|
+
|
|
77
|
+
# Index
|
|
78
|
+
|
|
79
|
+
- [Connecting Account](#connecting-account)
|
|
80
|
+
- [Connect with QR-CODE](#starting-socket-with-qr-code)
|
|
81
|
+
- [Connect with Pairing Code](#starting-socket-with-pairing-code)
|
|
82
|
+
- [Receive Full History](#receive-full-history)
|
|
83
|
+
- [Important Notes About Socket Config](#important-notes-about-socket-config)
|
|
84
|
+
- [Caching Group Metadata (Recommended)](#caching-group-metadata-recommended)
|
|
85
|
+
- [Improve Retry System & Decrypt Poll Votes](#improve-retry-system--decrypt-poll-votes)
|
|
86
|
+
- [Receive Notifications in Whatsapp App](#receive-notifications-in-whatsapp-app)
|
|
87
|
+
|
|
88
|
+
- [Save Auth Info](#saving--restoring-sessions)
|
|
89
|
+
- [Handling Events](#handling-events)
|
|
90
|
+
- [Example to Start](#example-to-start)
|
|
91
|
+
- [Decrypt Poll Votes](#decrypt-poll-votes)
|
|
92
|
+
- [Summary of Events on First Connection](#summary-of-events-on-first-connection)
|
|
93
|
+
- [Implementing a Data Store](#implementing-a-data-store)
|
|
94
|
+
- [Whatsapp IDs Explain](#whatsapp-ids-explain)
|
|
95
|
+
- [Utility Functions](#utility-functions)
|
|
96
|
+
- [Sending Messages](#sending-messages)
|
|
97
|
+
- [Non-Media Messages](#non-media-messages)
|
|
98
|
+
- [Text Message](#text-message)
|
|
99
|
+
- [Quote Message](#quote-message-works-with-all-types)
|
|
100
|
+
- [Mention User](#mention-user-works-with-most-types)
|
|
101
|
+
- [Forward Messages](#forward-messages)
|
|
102
|
+
- [Location Message](#location-message)
|
|
103
|
+
- [Contact Message](#contact-message)
|
|
104
|
+
- [Reaction Message](#reaction-message)
|
|
105
|
+
- [Pin Message](#pin-message)
|
|
106
|
+
- [Poll Message](#poll-message)
|
|
107
|
+
- [Sending with Link Preview](#sending-messages-with-link-previews)
|
|
108
|
+
- [Media Messages](#media-messages)
|
|
109
|
+
- [Gif Message](#gif-message)
|
|
110
|
+
- [Video Message](#video-message)
|
|
111
|
+
- [Audio Message](#audio-message)
|
|
112
|
+
- [Image Message](#image-message)
|
|
113
|
+
- [ViewOnce Message](#view-once-message)
|
|
114
|
+
- [Modify Messages](#modify-messages)
|
|
115
|
+
- [Delete Messages (for everyone)](#deleting-messages-for-everyone)
|
|
116
|
+
- [Edit Messages](#editing-messages)
|
|
117
|
+
- [Manipulating Media Messages](#manipulating-media-messages)
|
|
118
|
+
- [Thumbnail in Media Messages](#thumbnail-in-media-messages)
|
|
119
|
+
- [Downloading Media Messages](#downloading-media-messages)
|
|
120
|
+
- [Re-upload Media Message to Whatsapp](#re-upload-media-message-to-whatsapp)
|
|
121
|
+
- [Reject Call](#reject-call)
|
|
122
|
+
- [Send States in Chat](#send-states-in-chat)
|
|
123
|
+
- [Reading Messages](#reading-messages)
|
|
124
|
+
- [Update Presence](#update-presence)
|
|
125
|
+
- [Modifying Chats](#modifying-chats)
|
|
126
|
+
- [Archive a Chat](#archive-a-chat)
|
|
127
|
+
- [Mute/Unmute a Chat](#muteunmute-a-chat)
|
|
128
|
+
- [Mark a Chat Read/Unread](#mark-a-chat-readunread)
|
|
129
|
+
- [Delete a Message for Me](#delete-a-message-for-me)
|
|
130
|
+
- [Delete a Chat](#delete-a-chat)
|
|
131
|
+
- [Star/Unstar a Message](#starunstar-a-message)
|
|
132
|
+
- [Disappearing Messages](#disappearing-messages)
|
|
133
|
+
- [User Querys](#user-querys)
|
|
134
|
+
- [Check If ID Exists in Whatsapp](#check-if-id-exists-in-whatsapp)
|
|
135
|
+
- [Query Chat History (groups too)](#query-chat-history-groups-too)
|
|
136
|
+
- [Fetch Status](#fetch-status)
|
|
137
|
+
- [Fetch Profile Picture (groups too)](#fetch-profile-picture-groups-too)
|
|
138
|
+
- [Fetch Bussines Profile (such as description or category)](#fetch-bussines-profile-such-as-description-or-category)
|
|
139
|
+
- [Fetch Someone's Presence (if they're typing or online)](#fetch-someones-presence-if-theyre-typing-or-online)
|
|
140
|
+
- [Change Profile](#change-profile)
|
|
141
|
+
- [Change Profile Status](#change-profile-status)
|
|
142
|
+
- [Change Profile Name](#change-profile-name)
|
|
143
|
+
- [Change Display Picture (groups too)](#change-display-picture-groups-too)
|
|
144
|
+
- [Remove display picture (groups too)](#remove-display-picture-groups-too)
|
|
145
|
+
- [Groups](#groups)
|
|
146
|
+
- [Create a Group](#create-a-group)
|
|
147
|
+
- [Add/Remove or Demote/Promote](#addremove-or-demotepromote)
|
|
148
|
+
- [Change Subject (name)](#change-subject-name)
|
|
149
|
+
- [Change Description](#change-description)
|
|
150
|
+
- [Change Settings](#change-settings)
|
|
151
|
+
- [Leave a Group](#leave-a-group)
|
|
152
|
+
- [Get Invite Code](#get-invite-code)
|
|
153
|
+
- [Revoke Invite Code](#revoke-invite-code)
|
|
154
|
+
- [Join Using Invitation Code](#join-using-invitation-code)
|
|
155
|
+
- [Get Group Info by Invite Code](#get-group-info-by-invite-code)
|
|
156
|
+
- [Query Metadata (participants, name, description...)](#query-metadata-participants-name-description)
|
|
157
|
+
- [Join using groupInviteMessage](#join-using-groupinvitemessage)
|
|
158
|
+
- [Get Request Join List](#get-request-join-list)
|
|
159
|
+
- [Approve/Reject Request Join](#approvereject-request-join)
|
|
160
|
+
- [Get All Participating Groups Metadata](#get-all-participating-groups-metadata)
|
|
161
|
+
- [Toggle Ephemeral](#toggle-ephemeral)
|
|
162
|
+
- [Change Add Mode](#change-add-mode)
|
|
163
|
+
- [Privacy](#privacy)
|
|
164
|
+
- [Block/Unblock User](#blockunblock-user)
|
|
165
|
+
- [Get Privacy Settings](#get-privacy-settings)
|
|
166
|
+
- [Get BlockList](#get-blocklist)
|
|
167
|
+
- [Update LastSeen Privacy](#update-lastseen-privacy)
|
|
168
|
+
- [Update Online Privacy](#update-online-privacy)
|
|
169
|
+
- [Update Profile Picture Privacy](#update-profile-picture-privacy)
|
|
170
|
+
- [Update Status Privacy](#update-status-privacy)
|
|
171
|
+
- [Update Read Receipts Privacy](#update-read-receipts-privacy)
|
|
172
|
+
- [Update Groups Add Privacy](#update-groups-add-privacy)
|
|
173
|
+
- [Update Default Disappearing Mode](#update-default-disappearing-mode)
|
|
174
|
+
- [Broadcast Lists & Stories](#broadcast-lists--stories)
|
|
175
|
+
- [Send Broadcast & Stories](#send-broadcast--stories)
|
|
176
|
+
- [Query a Broadcast List's Recipients & Name](#query-a-broadcast-lists-recipients--name)
|
|
177
|
+
- [Writing Custom Functionality](#writing-custom-functionality)
|
|
178
|
+
- [Enabling Debug Level in Baileys Logs](#enabling-debug-level-in-baileys-logs)
|
|
179
|
+
- [How Whatsapp Communicate With Us](#how-whatsapp-communicate-with-us)
|
|
180
|
+
- [Register a Callback for Websocket Events](#register-a-callback-for-websocket-events)
|
|
181
|
+
|
|
182
|
+
## Connecting Account
|
|
183
|
+
|
|
184
|
+
WhatsApp provides a multi-device API that allows Baileys to be authenticated as a second WhatsApp client by scanning a **QR code** or **Pairing Code** with WhatsApp on your phone.
|
|
185
|
+
|
|
186
|
+
> [!NOTE]
|
|
187
|
+
> **[Here](#example-to-start) is a simple example of event handling**
|
|
188
|
+
|
|
189
|
+
> [!TIP]
|
|
190
|
+
> **You can see all supported socket configs in the [SocketConfig type alias](https://baileys.wiki/docs/api/type-aliases/SocketConfig/) (Recommended)**
|
|
191
|
+
|
|
192
|
+
### Starting socket with **QR-CODE**
|
|
193
|
+
|
|
194
|
+
> [!TIP]
|
|
195
|
+
> You can customize browser name if you connect with **QR-CODE**, with `Browser` constant, we have some browsers config, **see the [BrowsersMap type alias](https://baileys.wiki/docs/api/type-aliases/BrowsersMap/)**
|
|
196
|
+
|
|
197
|
+
```ts
|
|
198
|
+
import makeWASocket from '@whiskeysockets/baileys'
|
|
519
199
|
|
|
520
|
-
|
|
521
|
-
|
|
200
|
+
const sock = makeWASocket({
|
|
201
|
+
// can provide additional config here
|
|
202
|
+
browser: Browsers.ubuntu('My App'),
|
|
203
|
+
printQRInTerminal: true
|
|
204
|
+
})
|
|
205
|
+
```
|
|
522
206
|
|
|
523
|
-
|
|
207
|
+
If the connection is successful, you will see a QR code printed on your terminal screen, scan it with WhatsApp on your phone and you'll be logged in!
|
|
524
208
|
|
|
525
|
-
|
|
526
|
-
// Create Newsletter/Channel
|
|
527
|
-
await sock.newsletterCreate('My Channel', 'Channel description')
|
|
209
|
+
### Starting socket with **Pairing Code**
|
|
528
210
|
|
|
529
|
-
// Update channel info
|
|
530
|
-
await sock.newsletterUpdateName(channelJid, 'New Channel Name')
|
|
531
|
-
await sock.newsletterUpdateDescription(channelJid, 'Updated description')
|
|
532
|
-
await sock.newsletterUpdatePicture(channelJid, { url: 'https://example.com/pic.jpg' })
|
|
533
211
|
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
await sock.newsletterUnfollow(channelJid)
|
|
212
|
+
> [!IMPORTANT]
|
|
213
|
+
> Pairing Code isn't Mobile API, it's a method to connect Whatsapp Web without QR-CODE, you can connect only with one device, see [here](https://faq.whatsapp.com/1324084875126592/?cms_platform=web)
|
|
537
214
|
|
|
538
|
-
|
|
539
|
-
await sock.newsletterMute(channelJid)
|
|
540
|
-
await sock.newsletterUnmute(channelJid)
|
|
215
|
+
The phone number can't have `+` or `()` or `-`, only numbers, you must provide country code
|
|
541
216
|
|
|
542
|
-
|
|
543
|
-
|
|
217
|
+
```ts
|
|
218
|
+
import makeWASocket from '@whiskeysockets/baileys'
|
|
544
219
|
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
220
|
+
const sock = makeWASocket({
|
|
221
|
+
// can provide additional config here
|
|
222
|
+
printQRInTerminal: false //need to be false
|
|
223
|
+
})
|
|
548
224
|
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
await sock.
|
|
552
|
-
|
|
225
|
+
if (!sock.authState.creds.registered) {
|
|
226
|
+
const number = 'XXXXXXXXXXX'
|
|
227
|
+
const code = await sock.requestPairingCode(number)
|
|
228
|
+
console.log(code)
|
|
229
|
+
}
|
|
553
230
|
```
|
|
554
231
|
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
<details>
|
|
558
|
-
<summary><h3>🔐 Custom Pairing Code</h3></summary>
|
|
232
|
+
### Receive Full History
|
|
559
233
|
|
|
560
|
-
|
|
234
|
+
1. Set `syncFullHistory` as `true`
|
|
235
|
+
2. Baileys, by default, use chrome browser config
|
|
236
|
+
- If you'd like to emulate a desktop connection (and receive more message history), this browser setting to your Socket config:
|
|
561
237
|
|
|
562
|
-
```
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
console.log('Your Custom Code:', customCode)
|
|
238
|
+
```ts
|
|
239
|
+
const sock = makeWASocket({
|
|
240
|
+
...otherOpts,
|
|
241
|
+
// can use Windows, Ubuntu here too
|
|
242
|
+
browser: Browsers.macOS('Desktop'),
|
|
243
|
+
syncFullHistory: true
|
|
244
|
+
})
|
|
570
245
|
```
|
|
571
246
|
|
|
572
|
-
|
|
247
|
+
## Important Notes About Socket Config
|
|
573
248
|
|
|
574
|
-
|
|
575
|
-
|
|
249
|
+
### Caching Group Metadata (Recommended)
|
|
250
|
+
- If you use baileys for groups, we recommend you to set `cachedGroupMetadata` in socket config, you need to implement a cache like this:
|
|
576
251
|
|
|
577
|
-
|
|
252
|
+
```ts
|
|
253
|
+
const groupCache = new NodeCache({stdTTL: 5 * 60, useClones: false})
|
|
578
254
|
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
getSenderPn,
|
|
583
|
-
getCurrentSenderInfo,
|
|
584
|
-
isSelf,
|
|
585
|
-
plotJid,
|
|
586
|
-
normalizePhoneToJid,
|
|
587
|
-
extractPhoneNumber,
|
|
588
|
-
formatJidDisplay,
|
|
589
|
-
isSameUser,
|
|
590
|
-
getJidVariants,
|
|
591
|
-
getRemoteJidFromMessage,
|
|
592
|
-
createJidPlotter
|
|
593
|
-
} from 'baileys-joss'
|
|
594
|
-
|
|
595
|
-
// Get info tentang current session (senderPn)
|
|
596
|
-
const senderInfo = getCurrentSenderInfo(sock.authState)
|
|
597
|
-
console.log('Phone:', senderInfo.phoneNumber)
|
|
598
|
-
console.log('Phone JID:', senderInfo.phoneJid)
|
|
599
|
-
console.log('LID:', senderInfo.lid)
|
|
600
|
-
console.log('Device ID:', senderInfo.deviceId)
|
|
601
|
-
console.log('Name:', senderInfo.pushName)
|
|
602
|
-
|
|
603
|
-
// Parse JID untuk info lengkap
|
|
604
|
-
const jidInfo = parseJid('6281234567890@s.whatsapp.net')
|
|
605
|
-
console.log('User:', jidInfo.user)
|
|
606
|
-
console.log('Is LID:', jidInfo.isLid)
|
|
607
|
-
console.log('Is PN:', jidInfo.isPn)
|
|
608
|
-
console.log('Device:', jidInfo.device)
|
|
255
|
+
const sock = makeWASocket({
|
|
256
|
+
cachedGroupMetadata: async (jid) => groupCache.get(jid)
|
|
257
|
+
})
|
|
609
258
|
|
|
610
|
-
|
|
611
|
-
const
|
|
259
|
+
sock.ev.on('groups.update', async ([event]) => {
|
|
260
|
+
const metadata = await sock.groupMetadata(event.id)
|
|
261
|
+
groupCache.set(event.id, metadata)
|
|
262
|
+
})
|
|
612
263
|
|
|
613
|
-
|
|
614
|
-
const
|
|
264
|
+
sock.ev.on('group-participants.update', async (event) => {
|
|
265
|
+
const metadata = await sock.groupMetadata(event.id)
|
|
266
|
+
groupCache.set(event.id, metadata)
|
|
267
|
+
})
|
|
268
|
+
```
|
|
615
269
|
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
}) // -> 6281234567890:1 (PN)
|
|
624
|
-
|
|
625
|
-
// Compare dua JID
|
|
626
|
-
const same = isSameUser('6281234567890@s.whatsapp.net', '6281234567890:1@s.whatsapp.net') // true
|
|
627
|
-
|
|
628
|
-
// Get sender dari message
|
|
629
|
-
sock.ev.on('messages.upsert', async ({ messages }) => {
|
|
630
|
-
for (const msg of messages) {
|
|
631
|
-
const { chatJid, senderJid } = getRemoteJidFromMessage(msg)
|
|
632
|
-
console.log('Chat:', chatJid)
|
|
633
|
-
console.log('Sender:', senderJid)
|
|
634
|
-
}
|
|
635
|
-
})
|
|
270
|
+
### Improve Retry System & Decrypt Poll Votes
|
|
271
|
+
- If you want to improve sending message, retrying when error occurs and decrypt poll votes, you need to have a store and set `getMessage` config in socket like this:
|
|
272
|
+
```ts
|
|
273
|
+
const sock = makeWASocket({
|
|
274
|
+
getMessage: async (key) => await getMessageFromStore(key)
|
|
275
|
+
})
|
|
276
|
+
```
|
|
636
277
|
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
sock
|
|
641
|
-
|
|
278
|
+
### Receive Notifications in Whatsapp App
|
|
279
|
+
- If you want to receive notifications in whatsapp app, set `markOnlineOnConnect` to `false`
|
|
280
|
+
```ts
|
|
281
|
+
const sock = makeWASocket({
|
|
282
|
+
markOnlineOnConnect: false
|
|
283
|
+
})
|
|
284
|
+
```
|
|
285
|
+
## Saving & Restoring Sessions
|
|
642
286
|
|
|
643
|
-
|
|
644
|
-
console.log('Phone:', plotted.pn)
|
|
645
|
-
console.log('LID:', plotted.lid)
|
|
646
|
-
```
|
|
287
|
+
You obviously don't want to keep scanning the QR code every time you want to connect.
|
|
647
288
|
|
|
648
|
-
|
|
289
|
+
So, you can load the credentials to log back in:
|
|
290
|
+
```ts
|
|
291
|
+
import makeWASocket, { useMultiFileAuthState } from '@whiskeysockets/baileys'
|
|
649
292
|
|
|
650
|
-
|
|
651
|
-
<summary><h3>📍 Location Sharing</h3></summary>
|
|
293
|
+
const { state, saveCreds } = await useMultiFileAuthState('auth_info_baileys')
|
|
652
294
|
|
|
653
|
-
|
|
295
|
+
// will use the given state to connect
|
|
296
|
+
// so if valid credentials are available -- it'll connect without QR
|
|
297
|
+
const sock = makeWASocket({ auth: state })
|
|
654
298
|
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
await sock.sendMessage(jid, {
|
|
658
|
-
location: {
|
|
659
|
-
degreesLatitude: -6.2088,
|
|
660
|
-
degreesLongitude: 106.8456,
|
|
661
|
-
name: 'Jakarta, Indonesia',
|
|
662
|
-
address: 'Jl. Sudirman, Jakarta Pusat'
|
|
663
|
-
}
|
|
664
|
-
})
|
|
299
|
+
// this will be called as soon as the credentials are updated
|
|
300
|
+
sock.ev.on('creds.update', saveCreds)
|
|
665
301
|
```
|
|
666
302
|
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
<details>
|
|
670
|
-
<summary><h3>👥 Group Management</h3></summary>
|
|
303
|
+
> [!IMPORTANT]
|
|
304
|
+
> `useMultiFileAuthState` is a utility function to help save the auth state in a single folder, this function serves as a good guide to help write auth & key states for SQL/no-SQL databases, which I would recommend in any production grade system.
|
|
671
305
|
|
|
672
|
-
|
|
306
|
+
> [!NOTE]
|
|
307
|
+
> When a message is received/sent, due to signal sessions needing updating, the auth keys (`authState.keys`) will update. Whenever that happens, you must save the updated keys (`authState.keys.set()` is called). Not doing so will prevent your messages from reaching the recipient & cause other unexpected consequences. The `useMultiFileAuthState` function automatically takes care of that, but for any other serious implementation -- you will need to be very careful with the key state management.
|
|
673
308
|
|
|
674
|
-
|
|
675
|
-
// Create group
|
|
676
|
-
const group = await sock.groupCreate('My Group', ['6281234567890@s.whatsapp.net'])
|
|
309
|
+
## Handling Events
|
|
677
310
|
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
await sock.groupUpdateDescription(groupJid, 'New description')
|
|
311
|
+
- Baileys uses the EventEmitter syntax for events.
|
|
312
|
+
They're all nicely typed up, so you shouldn't have any issues with an Intellisense editor like VS Code.
|
|
681
313
|
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
await sock.groupParticipantsUpdate(groupJid, ['6281234567890@s.whatsapp.net'], 'remove')
|
|
685
|
-
await sock.groupParticipantsUpdate(groupJid, ['6281234567890@s.whatsapp.net'], 'promote')
|
|
686
|
-
await sock.groupParticipantsUpdate(groupJid, ['6281234567890@s.whatsapp.net'], 'demote')
|
|
314
|
+
> [!IMPORTANT]
|
|
315
|
+
> **The events are in the [BaileysEventMap type alias](https://baileys.wiki/docs/api/type-aliases/BaileysEventMap/)**, it's important you see all events
|
|
687
316
|
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
await sock.groupSettingUpdate(groupJid, 'announcement') // Only admins can send
|
|
695
|
-
await sock.groupSettingUpdate(groupJid, 'not_announcement') // Everyone can send
|
|
696
|
-
await sock.groupSettingUpdate(groupJid, 'locked') // Only admins can edit info
|
|
697
|
-
await sock.groupSettingUpdate(groupJid, 'unlocked') // Everyone can edit info
|
|
698
|
-
|
|
699
|
-
// Leave group
|
|
700
|
-
await sock.groupLeave(groupJid)
|
|
317
|
+
You can listen to these events like this:
|
|
318
|
+
```ts
|
|
319
|
+
const sock = makeWASocket()
|
|
320
|
+
sock.ev.on('messages.upsert', ({ messages }) => {
|
|
321
|
+
console.log('got messages', messages)
|
|
322
|
+
})
|
|
701
323
|
```
|
|
702
324
|
|
|
703
|
-
|
|
325
|
+
### Example to Start
|
|
704
326
|
|
|
705
|
-
|
|
327
|
+
> [!NOTE]
|
|
328
|
+
> This example includes basic auth storage too
|
|
706
329
|
|
|
707
|
-
|
|
330
|
+
> [!NOTE]
|
|
331
|
+
> For reliable serialization of the authentication state, especially when storing as JSON, always use the BufferJSON utility.
|
|
708
332
|
|
|
709
|
-
```
|
|
710
|
-
import makeWASocket, {
|
|
711
|
-
|
|
712
|
-
DisconnectReason,
|
|
713
|
-
// Interactive Message features
|
|
714
|
-
generateQuickReplyButtons,
|
|
715
|
-
generateInteractiveListMessage,
|
|
716
|
-
generateCombinedButtons,
|
|
717
|
-
// JID Plotting features
|
|
718
|
-
getCurrentSenderInfo,
|
|
719
|
-
parseJid,
|
|
720
|
-
isSelf
|
|
721
|
-
} from 'baileys-joss'
|
|
333
|
+
```ts
|
|
334
|
+
import makeWASocket, { DisconnectReason, useMultiFileAuthState } from '@whiskeysockets/baileys'
|
|
335
|
+
import { Boom } from '@hapi/boom'
|
|
722
336
|
|
|
723
|
-
async function
|
|
724
|
-
const { state, saveCreds } = await useMultiFileAuthState('
|
|
725
|
-
|
|
337
|
+
async function connectToWhatsApp () {
|
|
338
|
+
const { state, saveCreds } = await useMultiFileAuthState('auth_info_baileys')
|
|
726
339
|
const sock = makeWASocket({
|
|
340
|
+
// can provide additional config here
|
|
727
341
|
auth: state,
|
|
728
342
|
printQRInTerminal: true
|
|
729
343
|
})
|
|
730
|
-
|
|
731
|
-
sock.ev.on('creds.update', saveCreds)
|
|
732
|
-
|
|
733
344
|
sock.ev.on('connection.update', (update) => {
|
|
734
345
|
const { connection, lastDisconnect } = update
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
if
|
|
739
|
-
|
|
346
|
+
if(connection === 'close') {
|
|
347
|
+
const shouldReconnect = (lastDisconnect.error as Boom)?.output?.statusCode !== DisconnectReason.loggedOut
|
|
348
|
+
console.log('connection closed due to ', lastDisconnect.error, ', reconnecting ', shouldReconnect)
|
|
349
|
+
// reconnect if not logged out
|
|
350
|
+
if(shouldReconnect) {
|
|
351
|
+
connectToWhatsApp()
|
|
740
352
|
}
|
|
741
|
-
} else if
|
|
742
|
-
console.log('
|
|
743
|
-
|
|
744
|
-
// Get sender info
|
|
745
|
-
const sender = getCurrentSenderInfo(sock.authState)
|
|
746
|
-
console.log('📱 Logged in as:', sender?.phoneNumber)
|
|
353
|
+
} else if(connection === 'open') {
|
|
354
|
+
console.log('opened connection')
|
|
747
355
|
}
|
|
748
356
|
})
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
msg.message.extendedTextMessage?.text || ''
|
|
756
|
-
|
|
757
|
-
if (text === '/menu') {
|
|
758
|
-
// Kirim interactive buttons
|
|
759
|
-
const buttons = generateQuickReplyButtons(
|
|
760
|
-
'🤖 Bot Menu\n\nPilih opsi:',
|
|
761
|
-
[
|
|
762
|
-
{ id: 'help', displayText: '❓ Bantuan' },
|
|
763
|
-
{ id: 'info', displayText: 'ℹ️ Info' },
|
|
764
|
-
{ id: 'order', displayText: '🛒 Order' }
|
|
765
|
-
],
|
|
766
|
-
{ footer: 'Baileys-Joss Bot' }
|
|
767
|
-
)
|
|
768
|
-
|
|
769
|
-
await sock.sendMessage(msg.key.remoteJid!, buttons)
|
|
770
|
-
}
|
|
771
|
-
|
|
772
|
-
if (text === '/poll') {
|
|
773
|
-
// Kirim poll
|
|
774
|
-
await sock.sendMessage(msg.key.remoteJid!, {
|
|
775
|
-
poll: {
|
|
776
|
-
name: '🗳️ Vote sekarang!',
|
|
777
|
-
values: ['Option A', 'Option B', 'Option C'],
|
|
778
|
-
selectableCount: 1
|
|
779
|
-
}
|
|
780
|
-
})
|
|
781
|
-
}
|
|
782
|
-
|
|
783
|
-
if (text === '/ai') {
|
|
784
|
-
// Kirim pesan dengan AI style
|
|
785
|
-
await sock.sendMessage(msg.key.remoteJid!, {
|
|
786
|
-
text: 'Halo! Saya asisten AI Anda 🤖',
|
|
787
|
-
ai: true
|
|
788
|
-
})
|
|
357
|
+
sock.ev.on('messages.upsert', event => {
|
|
358
|
+
for (const m of event.messages) {
|
|
359
|
+
console.log(JSON.stringify(m, undefined, 2))
|
|
360
|
+
|
|
361
|
+
console.log('replying to', m.key.remoteJid)
|
|
362
|
+
await sock.sendMessage(m.key.remoteJid!, { text: 'Hello Word' })
|
|
789
363
|
}
|
|
790
364
|
})
|
|
365
|
+
|
|
366
|
+
// to storage creds (session info) when it updates
|
|
367
|
+
sock.ev.on('creds.update', saveCreds)
|
|
791
368
|
}
|
|
369
|
+
// run in main file
|
|
370
|
+
connectToWhatsApp()
|
|
371
|
+
```
|
|
792
372
|
|
|
793
|
-
|
|
373
|
+
> [!IMPORTANT]
|
|
374
|
+
> In `messages.upsert` it's recommended to use a loop like `for (const message of event.messages)` to handle all messages in array
|
|
375
|
+
|
|
376
|
+
### Decrypt Poll Votes
|
|
377
|
+
|
|
378
|
+
- By default poll votes are encrypted and handled in `messages.update`
|
|
379
|
+
- That's a simple example
|
|
380
|
+
```ts
|
|
381
|
+
sock.ev.on('messages.update', event => {
|
|
382
|
+
for(const { key, update } of event) {
|
|
383
|
+
if(update.pollUpdates) {
|
|
384
|
+
const pollCreation = await getMessage(key)
|
|
385
|
+
if(pollCreation) {
|
|
386
|
+
console.log(
|
|
387
|
+
'got poll update, aggregation: ',
|
|
388
|
+
getAggregateVotesInPollMessage({
|
|
389
|
+
message: pollCreation,
|
|
390
|
+
pollUpdates: update.pollUpdates,
|
|
391
|
+
})
|
|
392
|
+
)
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
})
|
|
794
397
|
```
|
|
795
398
|
|
|
796
|
-
|
|
399
|
+
- `getMessage` is a [store](#implementing-a-data-store) implementation (in your end)
|
|
797
400
|
|
|
798
|
-
|
|
401
|
+
### Summary of Events on First Connection
|
|
799
402
|
|
|
800
|
-
|
|
801
|
-
|
|
403
|
+
1. When you connect first time, `connection.update` will be fired requesting you to restart sock
|
|
404
|
+
2. Then, history messages will be received in `messaging.history-set`
|
|
802
405
|
|
|
803
|
-
|
|
804
|
-
// Create a newsletter
|
|
805
|
-
await sock.newsletterCreate('My Updates Channel', 'Stay updated!')
|
|
406
|
+
## Implementing a Data Store
|
|
806
407
|
|
|
807
|
-
|
|
808
|
-
await sock.newsletterUpdateDescription(channelJid, 'Fresh updates weekly 🔥')
|
|
408
|
+
- Baileys does not come with a defacto storage for chats, contacts, or messages. However, a simple in-memory implementation has been provided. The store listens for chat updates, new messages, message updates, etc., to always have an up-to-date version of the data.
|
|
809
409
|
|
|
810
|
-
|
|
811
|
-
|
|
410
|
+
> [!IMPORTANT]
|
|
411
|
+
> I highly recommend building your own data store, as storing someone's entire chat history in memory is a terrible waste of RAM.
|
|
812
412
|
|
|
813
|
-
|
|
814
|
-
const messages = await sock.newsletterFetchMessages('jid', channelJid, 10)
|
|
815
|
-
```
|
|
413
|
+
It can be used as follows:
|
|
816
414
|
|
|
817
|
-
|
|
415
|
+
```ts
|
|
416
|
+
import makeWASocket, { makeInMemoryStore } from '@whiskeysockets/baileys'
|
|
417
|
+
// the store maintains the data of the WA connection in memory
|
|
418
|
+
// can be written out to a file & read from it
|
|
419
|
+
const store = makeInMemoryStore({ })
|
|
420
|
+
// can be read from a file
|
|
421
|
+
store.readFromFile('./baileys_store.json')
|
|
422
|
+
// saves the state to a file every 10s
|
|
423
|
+
setInterval(() => {
|
|
424
|
+
store.writeToFile('./baileys_store.json')
|
|
425
|
+
}, 10_000)
|
|
818
426
|
|
|
819
|
-
|
|
820
|
-
|
|
427
|
+
const sock = makeWASocket({ })
|
|
428
|
+
// will listen from this socket
|
|
429
|
+
// the store can listen from a new socket once the current socket outlives its lifetime
|
|
430
|
+
store.bind(sock.ev)
|
|
821
431
|
|
|
822
|
-
|
|
823
|
-
//
|
|
824
|
-
|
|
825
|
-
'
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
],
|
|
832
|
-
{ title: 'Welcome!', footer: 'Powered by Baileys-Joss' }
|
|
833
|
-
)
|
|
432
|
+
sock.ev.on('chats.upsert', () => {
|
|
433
|
+
// can use 'store.chats' however you want, even after the socket dies out
|
|
434
|
+
// 'chats' => a KeyedDB instance
|
|
435
|
+
console.log('got chats', store.chats.all())
|
|
436
|
+
})
|
|
437
|
+
|
|
438
|
+
sock.ev.on('contacts.upsert', () => {
|
|
439
|
+
console.log('got contacts', Object.values(store.contacts))
|
|
440
|
+
})
|
|
834
441
|
|
|
835
|
-
await sock.sendMessage(jid, buttons)
|
|
836
442
|
```
|
|
837
443
|
|
|
838
|
-
|
|
444
|
+
The store also provides some simple functions such as `loadMessages` that utilize the store to speed up data retrieval.
|
|
839
445
|
|
|
840
|
-
|
|
841
|
-
<summary><b>🖼️ Send Album</b></summary>
|
|
446
|
+
## Whatsapp IDs Explain
|
|
842
447
|
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
448
|
+
- `id` is the WhatsApp ID, called `jid` too, of the person or group you're sending the message to.
|
|
449
|
+
- It must be in the format ```[country code][phone number]@s.whatsapp.net```
|
|
450
|
+
- Example for people: ```+19999999999@s.whatsapp.net```.
|
|
451
|
+
- For groups, it must be in the format ``` 123456789-123345@g.us ```.
|
|
452
|
+
- For broadcast lists, it's `[timestamp of creation]@broadcast`.
|
|
453
|
+
- For stories, the ID is `status@broadcast`.
|
|
849
454
|
|
|
850
|
-
|
|
851
|
-
album: media,
|
|
852
|
-
caption: 'My Vacation Memories 🌴'
|
|
853
|
-
})
|
|
854
|
-
```
|
|
455
|
+
## Utility Functions
|
|
855
456
|
|
|
856
|
-
|
|
457
|
+
- `getContentType`, returns the content type for any message
|
|
458
|
+
- `getDevice`, returns the device from message
|
|
459
|
+
- `makeCacheableSignalKeyStore`, make auth store more fast
|
|
460
|
+
- `downloadContentFromMessage`, download content from any message
|
|
857
461
|
|
|
858
|
-
|
|
859
|
-
<summary><b>🔐 Pairing with Custom Code</b></summary>
|
|
462
|
+
## Sending Messages
|
|
860
463
|
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
console.log('Your Pairing Code:', code)
|
|
464
|
+
- Send all types of messages with a single function
|
|
465
|
+
- **In the [AnyMessageContent type alias](https://baileys.wiki/docs/api/type-aliases/AnyMessageContent/) you can see all message contents supported, like text message**
|
|
466
|
+
- **In the [MiscMessageGenerationOptions type alias](https://baileys.wiki/docs/api/type-aliases/MiscMessageGenerationOptions/) you can see all options supported, like quote message**
|
|
865
467
|
|
|
866
|
-
|
|
867
|
-
const
|
|
868
|
-
|
|
869
|
-
|
|
468
|
+
```ts
|
|
469
|
+
const jid: string
|
|
470
|
+
const content: AnyMessageContent
|
|
471
|
+
const options: MiscMessageGenerationOptions
|
|
870
472
|
|
|
871
|
-
|
|
473
|
+
sock.sendMessage(jid, content, options)
|
|
474
|
+
```
|
|
872
475
|
|
|
873
|
-
|
|
874
|
-
<summary><b>📊 Poll Creation</b></summary>
|
|
476
|
+
### Non-Media Messages
|
|
875
477
|
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
values: [
|
|
880
|
-
'🦸 Superhero Movie',
|
|
881
|
-
'😂 Comedy',
|
|
882
|
-
'😱 Horror',
|
|
883
|
-
'💑 Romance'
|
|
884
|
-
],
|
|
885
|
-
selectableCount: 1
|
|
886
|
-
}
|
|
887
|
-
|
|
888
|
-
await sock.sendMessage(jid, { poll: pollMessage })
|
|
478
|
+
#### Text Message
|
|
479
|
+
```ts
|
|
480
|
+
await sock.sendMessage(jid, { text: 'hello word' })
|
|
889
481
|
```
|
|
890
482
|
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
483
|
+
#### Quote Message (works with all types)
|
|
484
|
+
```ts
|
|
485
|
+
await sock.sendMessage(jid, { text: 'hello word' }, { quoted: message })
|
|
486
|
+
```
|
|
895
487
|
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
488
|
+
#### Mention User (works with most types)
|
|
489
|
+
- @number is to mention in text, it's optional
|
|
490
|
+
```ts
|
|
491
|
+
await sock.sendMessage(
|
|
492
|
+
jid,
|
|
493
|
+
{
|
|
494
|
+
text: '@12345678901',
|
|
495
|
+
mentions: ['12345678901@s.whatsapp.net']
|
|
903
496
|
}
|
|
904
|
-
|
|
497
|
+
)
|
|
905
498
|
```
|
|
906
499
|
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
```typescript
|
|
913
|
-
// Create group
|
|
914
|
-
const group = await sock.groupCreate('My Awesome Group', [
|
|
915
|
-
'6281234567890@s.whatsapp.net',
|
|
916
|
-
'6281234567891@s.whatsapp.net'
|
|
917
|
-
])
|
|
918
|
-
|
|
919
|
-
console.log('Group created:', group.id)
|
|
920
|
-
|
|
921
|
-
// Update group settings
|
|
922
|
-
await sock.groupUpdateSubject(group.id, 'Updated Group Name')
|
|
923
|
-
await sock.groupSettingUpdate(group.id, 'announcement')
|
|
924
|
-
|
|
925
|
-
// Add members
|
|
926
|
-
await sock.groupParticipantsUpdate(group.id, [
|
|
927
|
-
'6281234567892@s.whatsapp.net'
|
|
928
|
-
], 'add')
|
|
500
|
+
#### Forward Messages
|
|
501
|
+
- You need to have message object, can be retrieved from [store](#implementing-a-data-store) or use a [message](https://baileys.wiki/docs/api/type-aliases/WAMessage/) object
|
|
502
|
+
```ts
|
|
503
|
+
const msg = getMessageFromStore() // implement this on your end
|
|
504
|
+
await sock.sendMessage(jid, { forward: msg }) // WA forward the message!
|
|
929
505
|
```
|
|
930
506
|
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
## 🆕 Baileys-Joss v1.0.3 New Features
|
|
936
|
-
|
|
937
|
-
<details>
|
|
938
|
-
<summary><h3>📅 Message Scheduling</h3></summary>
|
|
939
|
-
|
|
940
|
-
Jadwalkan pesan untuk dikirim otomatis di waktu tertentu:
|
|
941
|
-
|
|
942
|
-
```typescript
|
|
943
|
-
import { createMessageScheduler } from 'baileys-joss'
|
|
944
|
-
|
|
945
|
-
// Buat scheduler
|
|
946
|
-
const scheduler = createMessageScheduler(
|
|
947
|
-
(jid, content) => sock.sendMessage(jid, content),
|
|
507
|
+
#### Location Message
|
|
508
|
+
```ts
|
|
509
|
+
await sock.sendMessage(
|
|
510
|
+
jid,
|
|
948
511
|
{
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
onFailed: (scheduled, error) => {
|
|
953
|
-
console.log(`Gagal kirim: ${error.message}`)
|
|
512
|
+
location: {
|
|
513
|
+
degreesLatitude: 24.121231,
|
|
514
|
+
degreesLongitude: 55.1121221
|
|
954
515
|
}
|
|
955
516
|
}
|
|
956
517
|
)
|
|
957
|
-
|
|
958
|
-
// Jadwalkan pesan untuk waktu tertentu
|
|
959
|
-
const scheduled = scheduler.schedule(
|
|
960
|
-
'6281234567890@s.whatsapp.net',
|
|
961
|
-
{ text: 'Selamat Ulang Tahun! 🎂' },
|
|
962
|
-
new Date('2024-12-25 09:00:00')
|
|
963
|
-
)
|
|
964
|
-
|
|
965
|
-
// Jadwalkan dengan delay (30 menit dari sekarang)
|
|
966
|
-
scheduler.scheduleDelay(jid, { text: 'Reminder!' }, 30 * 60 * 1000)
|
|
967
|
-
|
|
968
|
-
// Cancel scheduled message
|
|
969
|
-
scheduler.cancel(scheduled.id)
|
|
970
|
-
|
|
971
|
-
// Get all pending messages
|
|
972
|
-
const pending = scheduler.getPending()
|
|
973
|
-
|
|
974
|
-
// Stop scheduler
|
|
975
|
-
scheduler.stop()
|
|
976
518
|
```
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
// Method 1: Create bulk sender instance
|
|
989
|
-
const bulkSender = createBulkSender(
|
|
990
|
-
(jid, content) => sock.sendMessage(jid, content),
|
|
519
|
+
#### Contact Message
|
|
520
|
+
```ts
|
|
521
|
+
const vcard = 'BEGIN:VCARD\n' // metadata of the contact card
|
|
522
|
+
+ 'VERSION:3.0\n'
|
|
523
|
+
+ 'FN:Jeff Singh\n' // full name
|
|
524
|
+
+ 'ORG:Ashoka Uni;\n' // the organization of the contact
|
|
525
|
+
+ 'TEL;type=CELL;type=VOICE;waid=911234567890:+91 12345 67890\n' // WhatsApp ID + phone number
|
|
526
|
+
+ 'END:VCARD'
|
|
527
|
+
|
|
528
|
+
await sock.sendMessage(
|
|
529
|
+
id,
|
|
991
530
|
{
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
onProgress: (progress) => {
|
|
996
|
-
console.log(`Progress: ${progress.sent}/${progress.total} (${progress.percentage}%)`)
|
|
997
|
-
},
|
|
998
|
-
onComplete: (results) => {
|
|
999
|
-
const success = results.filter(r => r.success).length
|
|
1000
|
-
console.log(`Selesai: ${success}/${results.length} berhasil`)
|
|
531
|
+
contacts: {
|
|
532
|
+
displayName: 'Jeff',
|
|
533
|
+
contacts: [{ vcard }]
|
|
1001
534
|
}
|
|
1002
535
|
}
|
|
1003
536
|
)
|
|
1004
|
-
|
|
1005
|
-
// Kirim pesan yang sama ke banyak JID
|
|
1006
|
-
const jids = [
|
|
1007
|
-
'6281234567890@s.whatsapp.net',
|
|
1008
|
-
'6281234567891@s.whatsapp.net',
|
|
1009
|
-
'6281234567892@s.whatsapp.net'
|
|
1010
|
-
]
|
|
1011
|
-
|
|
1012
|
-
const results = await bulkSender.sendToMany(jids, { text: 'Hello everyone!' })
|
|
1013
|
-
|
|
1014
|
-
// Kirim pesan berbeda ke JID berbeda
|
|
1015
|
-
const messages = [
|
|
1016
|
-
{ jid: '6281...@s.whatsapp.net', content: { text: 'Hi John!' } },
|
|
1017
|
-
{ jid: '6282...@s.whatsapp.net', content: { text: 'Hi Jane!' } }
|
|
1018
|
-
]
|
|
1019
|
-
await bulkSender.send(messages)
|
|
1020
|
-
|
|
1021
|
-
// Method 2: Quick helper
|
|
1022
|
-
await sendBulkMessages(
|
|
1023
|
-
(jid, content) => sock.sendMessage(jid, content),
|
|
1024
|
-
jids,
|
|
1025
|
-
{ text: 'Broadcast message' }
|
|
1026
|
-
)
|
|
1027
537
|
```
|
|
1028
538
|
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
Sistem balasan otomatis berdasarkan keyword/pattern:
|
|
1035
|
-
|
|
1036
|
-
```typescript
|
|
1037
|
-
import { createAutoReply } from 'baileys-joss'
|
|
1038
|
-
|
|
1039
|
-
// Buat auto-reply handler
|
|
1040
|
-
const autoReply = createAutoReply(
|
|
1041
|
-
(jid, content, options) => sock.sendMessage(jid, content, options),
|
|
1042
|
-
(jid, presence) => sock.sendPresenceUpdate(presence, jid),
|
|
539
|
+
#### Reaction Message
|
|
540
|
+
- You need to pass the key of message, you can retrieve from [store](#implementing-a-data-store) or use a [key](https://baileys.wiki/docs/api/type-aliases/WAMessageKey/) object
|
|
541
|
+
```ts
|
|
542
|
+
await sock.sendMessage(
|
|
543
|
+
jid,
|
|
1043
544
|
{
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
545
|
+
react: {
|
|
546
|
+
text: '💖', // use an empty string to remove the reaction
|
|
547
|
+
key: message.key
|
|
548
|
+
}
|
|
1047
549
|
}
|
|
1048
550
|
)
|
|
551
|
+
```
|
|
1049
552
|
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
keywords: ['harga', 'price', 'biaya'],
|
|
1053
|
-
response: { text: 'Silakan cek katalog kami di example.com' },
|
|
1054
|
-
cooldown: 60000, // 1 menit cooldown per user
|
|
1055
|
-
quoted: true // Reply dengan quote
|
|
1056
|
-
})
|
|
1057
|
-
|
|
1058
|
-
// Rule dengan regex pattern
|
|
1059
|
-
autoReply.addRule({
|
|
1060
|
-
pattern: /^(hi|hello|halo|hay)/i,
|
|
1061
|
-
response: { text: 'Hai! Ada yang bisa dibantu? 😊' },
|
|
1062
|
-
privateOnly: true // Hanya di private chat
|
|
1063
|
-
})
|
|
553
|
+
#### Pin Message
|
|
554
|
+
- You need to pass the key of message, you can retrieve from [store](#implementing-a-data-store) or use a [key](https://baileys.wiki/docs/api/type-aliases/WAMessageKey/) object
|
|
1064
555
|
|
|
1065
|
-
|
|
1066
|
-
autoReply.addRule({
|
|
1067
|
-
keywords: ['order'],
|
|
1068
|
-
response: async (message, match) => {
|
|
1069
|
-
const sender = message.key.remoteJid
|
|
1070
|
-
return { text: `Terima kasih sudah order! ID: ${Date.now()}` }
|
|
1071
|
-
}
|
|
1072
|
-
})
|
|
556
|
+
- Time can be:
|
|
1073
557
|
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
})
|
|
558
|
+
| Time | Seconds |
|
|
559
|
+
|-------|----------------|
|
|
560
|
+
| 24h | 86.400 |
|
|
561
|
+
| 7d | 604.800 |
|
|
562
|
+
| 30d | 2.592.000 |
|
|
1080
563
|
|
|
1081
|
-
|
|
1082
|
-
sock.
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
564
|
+
```ts
|
|
565
|
+
await sock.sendMessage(
|
|
566
|
+
jid,
|
|
567
|
+
{
|
|
568
|
+
pin: {
|
|
569
|
+
type: 1, // 0 to remove
|
|
570
|
+
time: 86400
|
|
571
|
+
key: message.key
|
|
1086
572
|
}
|
|
1087
573
|
}
|
|
1088
|
-
|
|
574
|
+
)
|
|
1089
575
|
```
|
|
1090
576
|
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
} from 'baileys-joss'
|
|
1105
|
-
|
|
1106
|
-
// Quick contact (simple)
|
|
1107
|
-
const simple = quickContact('John Doe', '+628123456789', {
|
|
1108
|
-
organization: 'PT Example',
|
|
1109
|
-
email: 'john@example.com'
|
|
1110
|
-
})
|
|
1111
|
-
await sock.sendMessage(jid, createContactCard(simple))
|
|
1112
|
-
|
|
1113
|
-
// Full vCard with all details
|
|
1114
|
-
const fullContact = {
|
|
1115
|
-
fullName: 'Dr. John Doe',
|
|
1116
|
-
displayName: 'John D.',
|
|
1117
|
-
organization: 'Hospital ABC',
|
|
1118
|
-
title: 'Senior Doctor',
|
|
1119
|
-
phones: [
|
|
1120
|
-
{ number: '+628123456789', type: 'CELL' },
|
|
1121
|
-
{ number: '+622112345678', type: 'WORK' }
|
|
1122
|
-
],
|
|
1123
|
-
emails: [
|
|
1124
|
-
{ email: 'john@hospital.com', type: 'WORK' },
|
|
1125
|
-
{ email: 'john.personal@gmail.com', type: 'HOME' }
|
|
1126
|
-
],
|
|
1127
|
-
urls: [
|
|
1128
|
-
{ url: 'https://linkedin.com/in/johndoe', type: 'WORK' }
|
|
1129
|
-
],
|
|
1130
|
-
addresses: [{
|
|
1131
|
-
street: 'Jl. Sudirman No. 123',
|
|
1132
|
-
city: 'Jakarta',
|
|
1133
|
-
state: 'DKI Jakarta',
|
|
1134
|
-
postalCode: '12345',
|
|
1135
|
-
country: 'Indonesia',
|
|
1136
|
-
type: 'WORK'
|
|
1137
|
-
}],
|
|
1138
|
-
birthday: '1990-05-15',
|
|
1139
|
-
note: 'Met at conference 2024'
|
|
1140
|
-
}
|
|
1141
|
-
|
|
1142
|
-
await sock.sendMessage(jid, createContactCard(fullContact))
|
|
1143
|
-
|
|
1144
|
-
// Send multiple contacts
|
|
1145
|
-
const contacts = [
|
|
1146
|
-
quickContact('Alice', '+628111111111'),
|
|
1147
|
-
quickContact('Bob', '+628222222222'),
|
|
1148
|
-
quickContact('Charlie', '+628333333333')
|
|
1149
|
-
]
|
|
1150
|
-
await sock.sendMessage(jid, createContactCards(contacts))
|
|
1151
|
-
|
|
1152
|
-
// Generate raw vCard string
|
|
1153
|
-
const vcardString = generateVCard(fullContact)
|
|
1154
|
-
console.log(vcardString)
|
|
577
|
+
#### Poll Message
|
|
578
|
+
```ts
|
|
579
|
+
await sock.sendMessage(
|
|
580
|
+
jid,
|
|
581
|
+
{
|
|
582
|
+
poll: {
|
|
583
|
+
name: 'My Poll',
|
|
584
|
+
values: ['Option 1', 'Option 2', ...],
|
|
585
|
+
selectableCount: 1,
|
|
586
|
+
toAnnouncementGroup: false // or true
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
)
|
|
1155
590
|
```
|
|
1156
591
|
|
|
1157
|
-
|
|
592
|
+
### Sending Messages with Link Previews
|
|
1158
593
|
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
} from 'baileys-joss'
|
|
1171
|
-
|
|
1172
|
-
const statusJid = STATUS_BROADCAST_JID // 'status@broadcast'
|
|
1173
|
-
|
|
1174
|
-
// Post text status
|
|
1175
|
-
await sock.sendMessage(statusJid, StatusHelper.text(
|
|
1176
|
-
'Hello World! 🌍',
|
|
1177
|
-
STATUS_BACKGROUNDS.solid.green
|
|
1178
|
-
))
|
|
1179
|
-
|
|
1180
|
-
// Post image status
|
|
1181
|
-
const imageBuffer = fs.readFileSync('./my-photo.jpg')
|
|
1182
|
-
await sock.sendMessage(statusJid, StatusHelper.image(
|
|
1183
|
-
imageBuffer,
|
|
1184
|
-
'Beautiful day! ☀️'
|
|
1185
|
-
))
|
|
1186
|
-
|
|
1187
|
-
// Post video status
|
|
1188
|
-
const videoBuffer = fs.readFileSync('./my-video.mp4')
|
|
1189
|
-
await sock.sendMessage(statusJid, StatusHelper.video(
|
|
1190
|
-
videoBuffer,
|
|
1191
|
-
'Check this out! 🎬'
|
|
1192
|
-
))
|
|
1193
|
-
|
|
1194
|
-
// Post GIF status
|
|
1195
|
-
await sock.sendMessage(statusJid, StatusHelper.gif(
|
|
1196
|
-
gifBuffer,
|
|
1197
|
-
'Animated! 🎭'
|
|
1198
|
-
))
|
|
1199
|
-
|
|
1200
|
-
// Custom text status with font
|
|
1201
|
-
import { createTextStatus } from 'baileys-joss'
|
|
1202
|
-
|
|
1203
|
-
await sock.sendMessage(statusJid, createTextStatus({
|
|
1204
|
-
text: 'Custom styled status!',
|
|
1205
|
-
backgroundColor: STATUS_BACKGROUNDS.solid.purple,
|
|
1206
|
-
font: STATUS_FONTS.DANCING,
|
|
1207
|
-
textColor: '#FFFFFF'
|
|
1208
|
-
}))
|
|
594
|
+
1. By default, wa does not have link generation when sent from the web
|
|
595
|
+
2. Baileys has a function to generate the content for these link previews
|
|
596
|
+
3. To enable this function's usage, add `link-preview-js` as a dependency to your project with `yarn add link-preview-js`
|
|
597
|
+
4. Send a link:
|
|
598
|
+
```ts
|
|
599
|
+
await sock.sendMessage(
|
|
600
|
+
jid,
|
|
601
|
+
{
|
|
602
|
+
text: 'Hi, this was sent using https://github.com/whiskeysockets/baileys'
|
|
603
|
+
}
|
|
604
|
+
)
|
|
1209
605
|
```
|
|
1210
606
|
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
<details>
|
|
1214
|
-
<summary><h3>📋 Message Templates</h3></summary>
|
|
1215
|
-
|
|
1216
|
-
Template pesan siap pakai untuk berbagai keperluan:
|
|
607
|
+
### Media Messages
|
|
1217
608
|
|
|
1218
|
-
|
|
1219
|
-
import { createTemplateManager, renderTemplate, PRESET_TEMPLATES } from 'baileys-joss'
|
|
609
|
+
Sending media (video, stickers, images) is easier & more efficient than ever.
|
|
1220
610
|
|
|
1221
|
-
|
|
1222
|
-
|
|
611
|
+
> [!NOTE]
|
|
612
|
+
> In media messages, you can pass `{ stream: Stream }` or `{ url: Url }` or `Buffer` directly, you can see more in the [WAMediaUpload type alias](https://baileys.wiki/docs/api/type-aliases/WAMediaUpload/)
|
|
1223
613
|
|
|
1224
|
-
|
|
1225
|
-
const orderConfirmation = templates.render('order_confirmation', {
|
|
1226
|
-
orderId: 'ORD-12345',
|
|
1227
|
-
customerName: 'John Doe',
|
|
1228
|
-
orderDate: '2024-01-15',
|
|
1229
|
-
items: '1x Product A\n2x Product B',
|
|
1230
|
-
total: '150,000'
|
|
1231
|
-
})
|
|
1232
|
-
|
|
1233
|
-
await sock.sendMessage(jid, { text: orderConfirmation })
|
|
1234
|
-
|
|
1235
|
-
// Create custom template
|
|
1236
|
-
templates.create({
|
|
1237
|
-
name: 'Welcome Message',
|
|
1238
|
-
content: `Halo {{name}}! 👋
|
|
1239
|
-
|
|
1240
|
-
Selamat datang di {{company}}!
|
|
1241
|
-
|
|
1242
|
-
Berikut layanan kami:
|
|
1243
|
-
{{services}}
|
|
1244
|
-
|
|
1245
|
-
Contact: {{phone:021-12345678}}`,
|
|
1246
|
-
category: 'greeting'
|
|
1247
|
-
})
|
|
614
|
+
- When specifying a media url, Baileys never loads the entire buffer into memory; it even encrypts the media as a readable stream.
|
|
1248
615
|
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
name: 'Budi',
|
|
1252
|
-
company: 'PT Example',
|
|
1253
|
-
services: '- Layanan A\n- Layanan B\n- Layanan C'
|
|
1254
|
-
})
|
|
616
|
+
> [!TIP]
|
|
617
|
+
> It's recommended to use Stream or Url to save memory
|
|
1255
618
|
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
619
|
+
#### Gif Message
|
|
620
|
+
- Whatsapp doesn't support `.gif` files, that's why we send gifs as common `.mp4` video with `gifPlayback` flag
|
|
621
|
+
```ts
|
|
622
|
+
await sock.sendMessage(
|
|
623
|
+
jid,
|
|
624
|
+
{
|
|
625
|
+
video: fs.readFileSync('Media/ma_gif.mp4'),
|
|
626
|
+
caption: 'hello word',
|
|
627
|
+
gifPlayback: true
|
|
628
|
+
}
|
|
1260
629
|
)
|
|
1261
|
-
|
|
1262
|
-
// List available templates
|
|
1263
|
-
const allTemplates = templates.getAll()
|
|
1264
|
-
const invoiceTemplates = templates.getByCategory('invoice')
|
|
1265
|
-
|
|
1266
|
-
// Export/Import templates
|
|
1267
|
-
const exportJson = templates.export()
|
|
1268
|
-
templates.import(exportJson, true) // true = overwrite existing
|
|
1269
630
|
```
|
|
1270
631
|
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
(jid, content) => sock.sendMessage(jid, content)
|
|
632
|
+
#### Video Message
|
|
633
|
+
```ts
|
|
634
|
+
await sock.sendMessage(
|
|
635
|
+
id,
|
|
636
|
+
{
|
|
637
|
+
video: {
|
|
638
|
+
url: './Media/ma_gif.mp4'
|
|
639
|
+
},
|
|
640
|
+
caption: 'hello word',
|
|
641
|
+
ptv: false // if set to true, will send as a `video note`
|
|
642
|
+
}
|
|
1283
643
|
)
|
|
644
|
+
```
|
|
1284
645
|
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
// Send to broadcast list
|
|
1301
|
-
const result = await broadcast.broadcast(
|
|
1302
|
-
customerList.id,
|
|
1303
|
-
{ text: '🎉 Special promo for VIP customers!' },
|
|
646
|
+
#### Audio Message
|
|
647
|
+
- To audio message work in all devices you need to convert with some tool like `ffmpeg` with this flags:
|
|
648
|
+
```bash
|
|
649
|
+
codec: libopus //ogg file
|
|
650
|
+
ac: 1 //one channel
|
|
651
|
+
avoid_negative_ts
|
|
652
|
+
make_zero
|
|
653
|
+
```
|
|
654
|
+
- Example:
|
|
655
|
+
```bash
|
|
656
|
+
ffmpeg -i input.mp4 -avoid_negative_ts make_zero -ac 1 output.ogg
|
|
657
|
+
```
|
|
658
|
+
```ts
|
|
659
|
+
await sock.sendMessage(
|
|
660
|
+
jid,
|
|
1304
661
|
{
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
662
|
+
audio: {
|
|
663
|
+
url: './Media/audio.mp3'
|
|
664
|
+
},
|
|
665
|
+
mimetype: 'audio/mp4'
|
|
1309
666
|
}
|
|
1310
667
|
)
|
|
1311
|
-
|
|
1312
|
-
console.log(`Sent: ${result.sent}, Failed: ${result.failed}`)
|
|
1313
|
-
|
|
1314
|
-
// Get statistics
|
|
1315
|
-
const stats = broadcast.getStats()
|
|
1316
|
-
console.log(`Total lists: ${stats.totalLists}, Recipients: ${stats.totalRecipients}`)
|
|
1317
|
-
|
|
1318
|
-
// Export/Import lists
|
|
1319
|
-
const json = broadcast.export()
|
|
1320
|
-
broadcast.import(json)
|
|
1321
668
|
```
|
|
1322
669
|
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
const typing = createTypingIndicator(
|
|
1334
|
-
(jid, presence) => sock.sendPresenceUpdate(presence, jid)
|
|
670
|
+
#### Image Message
|
|
671
|
+
```ts
|
|
672
|
+
await sock.sendMessage(
|
|
673
|
+
id,
|
|
674
|
+
{
|
|
675
|
+
image: {
|
|
676
|
+
url: './Media/ma_img.png'
|
|
677
|
+
},
|
|
678
|
+
caption: 'hello word'
|
|
679
|
+
}
|
|
1335
680
|
)
|
|
1336
|
-
|
|
1337
|
-
// Start typing
|
|
1338
|
-
await typing.startTyping(jid, {
|
|
1339
|
-
duration: 5000, // Auto pause after 5 seconds
|
|
1340
|
-
autoPause: true
|
|
1341
|
-
})
|
|
1342
|
-
|
|
1343
|
-
// Start recording (for voice notes)
|
|
1344
|
-
await typing.startRecording(jid, { duration: 3000 })
|
|
1345
|
-
|
|
1346
|
-
// Stop typing
|
|
1347
|
-
await typing.stopTyping(jid)
|
|
1348
|
-
|
|
1349
|
-
// Simulate typing then send
|
|
1350
|
-
await typing.simulateTyping(jid, 2000, async () => {
|
|
1351
|
-
return sock.sendMessage(jid, { text: 'Hello!' })
|
|
1352
|
-
})
|
|
1353
|
-
|
|
1354
|
-
// Stop all typing indicators
|
|
1355
|
-
await typing.stopAll()
|
|
1356
681
|
```
|
|
1357
682
|
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
<details>
|
|
1361
|
-
<summary><h3>✅ Read Receipt Control</h3></summary>
|
|
683
|
+
#### View Once Message
|
|
1362
684
|
|
|
1363
|
-
|
|
685
|
+
- You can send all messages above as `viewOnce`, you only need to pass `viewOnce: true` in content object
|
|
1364
686
|
|
|
1365
|
-
```
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
const readReceipts = createReadReceiptController(
|
|
1369
|
-
(jid, participant, messageIds) => sock.readMessages([{ remoteJid: jid, id: messageIds[0] }]),
|
|
687
|
+
```ts
|
|
688
|
+
await sock.sendMessage(
|
|
689
|
+
id,
|
|
1370
690
|
{
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
691
|
+
image: {
|
|
692
|
+
url: './Media/ma_img.png'
|
|
693
|
+
},
|
|
694
|
+
viewOnce: true, //works with video, audio too
|
|
695
|
+
caption: 'hello word'
|
|
1374
696
|
}
|
|
1375
697
|
)
|
|
1376
|
-
|
|
1377
|
-
// Toggle read receipts
|
|
1378
|
-
readReceipts.disable() // Stop sending read receipts
|
|
1379
|
-
readReceipts.enable() // Resume
|
|
1380
|
-
|
|
1381
|
-
// Check status
|
|
1382
|
-
console.log(readReceipts.isEnabled())
|
|
1383
|
-
|
|
1384
|
-
// Manual read (respects config)
|
|
1385
|
-
await readReceipts.markRead(jid, participant, ['messageId123'])
|
|
1386
|
-
|
|
1387
|
-
// Force read (ignores config)
|
|
1388
|
-
await readReceipts.forceMarkRead(jid, participant, ['messageId123'])
|
|
1389
|
-
|
|
1390
|
-
// Update config
|
|
1391
|
-
readReceipts.setConfig({
|
|
1392
|
-
enabled: true,
|
|
1393
|
-
readDelay: 2000
|
|
1394
|
-
})
|
|
1395
698
|
```
|
|
1396
699
|
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
<details>
|
|
1400
|
-
<summary><h3>🔍 Message Search</h3></summary>
|
|
1401
|
-
|
|
1402
|
-
Cari pesan dalam chat:
|
|
1403
|
-
|
|
1404
|
-
```typescript
|
|
1405
|
-
import { createMessageSearch, searchMessages } from 'baileys-joss'
|
|
1406
|
-
|
|
1407
|
-
// Create search manager
|
|
1408
|
-
const search = createMessageSearch()
|
|
700
|
+
## Modify Messages
|
|
1409
701
|
|
|
1410
|
-
|
|
1411
|
-
search.addMessages(chatMessages)
|
|
702
|
+
### Deleting Messages (for everyone)
|
|
1412
703
|
|
|
1413
|
-
|
|
1414
|
-
const
|
|
1415
|
-
|
|
1416
|
-
limit: 20,
|
|
1417
|
-
messageTypes: ['text', 'image'], // Include captions
|
|
1418
|
-
fromDate: new Date('2024-01-01')
|
|
1419
|
-
})
|
|
1420
|
-
|
|
1421
|
-
for (const result of results) {
|
|
1422
|
-
console.log(`Found: "${result.matchedText}"`)
|
|
1423
|
-
console.log(`Score: ${result.relevanceScore}`)
|
|
1424
|
-
console.log(`Message ID: ${result.message.key.id}`)
|
|
1425
|
-
}
|
|
1426
|
-
|
|
1427
|
-
// Search with regex
|
|
1428
|
-
const regexResults = search.searchRegex(/order\s*#?\d+/i)
|
|
1429
|
-
|
|
1430
|
-
// Get messages by type
|
|
1431
|
-
const images = search.getByType('image')
|
|
1432
|
-
const videos = search.getByType('video')
|
|
1433
|
-
|
|
1434
|
-
// Get messages by sender
|
|
1435
|
-
const fromSender = search.getBySender('6281234567890@s.whatsapp.net')
|
|
1436
|
-
|
|
1437
|
-
// Quick search (without manager)
|
|
1438
|
-
const quickResults = searchMessages(messages, 'keyword', {
|
|
1439
|
-
jid: specificChatJid,
|
|
1440
|
-
fromMe: false
|
|
1441
|
-
})
|
|
704
|
+
```ts
|
|
705
|
+
const msg = await sock.sendMessage(jid, { text: 'hello word' })
|
|
706
|
+
await sock.sendMessage(jid, { delete: msg.key })
|
|
1442
707
|
```
|
|
1443
708
|
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
<details>
|
|
1447
|
-
<summary><h3>📊 Chat Analytics</h3></summary>
|
|
1448
|
-
|
|
1449
|
-
Statistik dan analitik chat:
|
|
1450
|
-
|
|
1451
|
-
```typescript
|
|
1452
|
-
import { createChatAnalytics } from 'baileys-joss'
|
|
1453
|
-
|
|
1454
|
-
const analytics = createChatAnalytics()
|
|
1455
|
-
|
|
1456
|
-
// Add messages for analysis
|
|
1457
|
-
analytics.addMessages(allMessages)
|
|
1458
|
-
|
|
1459
|
-
// Get stats for specific chat
|
|
1460
|
-
const chatStats = analytics.getChatStats('6281234567890@s.whatsapp.net')
|
|
709
|
+
**Note:** deleting for oneself is supported via `chatModify`, see in [this section](#modifying-chats)
|
|
1461
710
|
|
|
1462
|
-
|
|
1463
|
-
console.log(`From me: ${chatStats.messagesFromMe}`)
|
|
1464
|
-
console.log(`Media count: ${chatStats.mediaCount}`)
|
|
1465
|
-
console.log(`Links shared: ${chatStats.linkCount}`)
|
|
1466
|
-
console.log(`Emojis used: ${chatStats.emojiCount}`)
|
|
1467
|
-
console.log(`Most active hour: ${chatStats.mostActiveHour}:00`)
|
|
1468
|
-
console.log(`Most active day: ${chatStats.mostActiveDay}`)
|
|
1469
|
-
console.log(`Avg messages/day: ${chatStats.averageMessagesPerDay}`)
|
|
711
|
+
### Editing Messages
|
|
1470
712
|
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
console.log(`Total messages: ${globalStats.totalMessages}`)
|
|
1479
|
-
console.log(`Most active chat: ${globalStats.mostActiveChat?.jid}`)
|
|
1480
|
-
|
|
1481
|
-
// Activity analysis
|
|
1482
|
-
const hourlyActivity = analytics.getActivityByHour(jid) // Array[24]
|
|
1483
|
-
const dailyActivity = analytics.getActivityByDay(jid) // { Sunday: 10, Monday: 25, ... }
|
|
713
|
+
- You can pass all editable contents here
|
|
714
|
+
```ts
|
|
715
|
+
await sock.sendMessage(jid, {
|
|
716
|
+
text: 'updated text goes here',
|
|
717
|
+
edit: response.key,
|
|
718
|
+
});
|
|
719
|
+
```
|
|
1484
720
|
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
721
|
+
## Manipulating Media Messages
|
|
722
|
+
|
|
723
|
+
### Thumbnail in Media Messages
|
|
724
|
+
- For media messages, the thumbnail can be generated automatically for images & stickers provided you add `jimp` or `sharp` as a dependency in your project using `yarn add jimp` or `yarn add sharp`.
|
|
725
|
+
- Thumbnails for videos can also be generated automatically, though, you need to have `ffmpeg` installed on your system.
|
|
726
|
+
|
|
727
|
+
### Downloading Media Messages
|
|
728
|
+
|
|
729
|
+
If you want to save the media you received
|
|
730
|
+
```ts
|
|
731
|
+
import { createWriteStream } from 'fs'
|
|
732
|
+
import { downloadMediaMessage, getContentType } from '@whiskeysockets/baileys'
|
|
733
|
+
|
|
734
|
+
sock.ev.on('messages.upsert', async ({ [m] }) => {
|
|
735
|
+
if (!m.message) return // if there is no text or media message
|
|
736
|
+
const messageType = getContentType(m) // get what type of message it is (text, image, video...)
|
|
737
|
+
|
|
738
|
+
// if the message is an image
|
|
739
|
+
if (messageType === 'imageMessage') {
|
|
740
|
+
// download the message
|
|
741
|
+
const stream = await downloadMediaMessage(
|
|
742
|
+
m,
|
|
743
|
+
'stream', // can be 'buffer' too
|
|
744
|
+
{ },
|
|
745
|
+
{
|
|
746
|
+
logger,
|
|
747
|
+
// pass this so that baileys can request a reupload of media
|
|
748
|
+
// that has been deleted
|
|
749
|
+
reuploadRequest: sock.updateMediaMessage
|
|
750
|
+
}
|
|
751
|
+
)
|
|
752
|
+
// save to file
|
|
753
|
+
const writeStream = createWriteStream('./my-download.jpeg')
|
|
754
|
+
stream.pipe(writeStream)
|
|
755
|
+
}
|
|
1489
756
|
}
|
|
1490
757
|
```
|
|
1491
758
|
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
<details>
|
|
1495
|
-
<summary><h3>💾 Chat Export</h3></summary>
|
|
1496
|
-
|
|
1497
|
-
Export chat ke JSON, HTML, TXT, atau CSV:
|
|
1498
|
-
|
|
1499
|
-
```typescript
|
|
1500
|
-
import { createChatExporter, exportChat } from 'baileys-joss'
|
|
1501
|
-
|
|
1502
|
-
const exporter = createChatExporter()
|
|
1503
|
-
|
|
1504
|
-
// Add messages
|
|
1505
|
-
exporter.addMessages(jid, chatMessages)
|
|
1506
|
-
|
|
1507
|
-
// Export to JSON
|
|
1508
|
-
const jsonExport = exporter.export(jid, {
|
|
1509
|
-
format: 'json',
|
|
1510
|
-
includeMediaInfo: true,
|
|
1511
|
-
includeMetadata: true
|
|
1512
|
-
})
|
|
1513
|
-
|
|
1514
|
-
fs.writeFileSync(jsonExport.filename, jsonExport.content)
|
|
759
|
+
### Re-upload Media Message to Whatsapp
|
|
1515
760
|
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
dateFormat: 'YYYY-MM-DD HH:mm'
|
|
1521
|
-
})
|
|
1522
|
-
|
|
1523
|
-
fs.writeFileSync(htmlExport.filename, htmlExport.content)
|
|
1524
|
-
|
|
1525
|
-
// Export to TXT (simple text)
|
|
1526
|
-
const txtExport = exporter.export(jid, {
|
|
1527
|
-
format: 'txt',
|
|
1528
|
-
dateRange: {
|
|
1529
|
-
start: new Date('2024-01-01'),
|
|
1530
|
-
end: new Date('2024-12-31')
|
|
1531
|
-
}
|
|
1532
|
-
})
|
|
761
|
+
- WhatsApp automatically removes old media from their servers. For the device to access said media -- a re-upload is required by another device that has it. This can be accomplished using:
|
|
762
|
+
```ts
|
|
763
|
+
await sock.updateMediaMessage(msg)
|
|
764
|
+
```
|
|
1533
765
|
|
|
1534
|
-
|
|
1535
|
-
const csvExport = exporter.export(jid, {
|
|
1536
|
-
format: 'csv',
|
|
1537
|
-
includeMetadata: true
|
|
1538
|
-
})
|
|
766
|
+
## Reject Call
|
|
1539
767
|
|
|
1540
|
-
|
|
1541
|
-
const result = exportChat(messages, jid, { format: 'json' })
|
|
1542
|
-
console.log(`Exported ${result.messageCount} messages`)
|
|
768
|
+
- You can obtain `callId` and `callFrom` from `call` event
|
|
1543
769
|
|
|
1544
|
-
|
|
1545
|
-
|
|
770
|
+
```ts
|
|
771
|
+
await sock.rejectCall(callId, callFrom)
|
|
1546
772
|
```
|
|
1547
773
|
|
|
1548
|
-
|
|
774
|
+
## Send States in Chat
|
|
1549
775
|
|
|
1550
|
-
|
|
1551
|
-
|
|
776
|
+
### Reading Messages
|
|
777
|
+
- A set of message [keys](https://baileys.wiki/docs/api/type-aliases/WAMessageKey/) must be explicitly marked read now.
|
|
778
|
+
- You cannot mark an entire 'chat' read as it were with Baileys Web.
|
|
779
|
+
This means you have to keep track of unread messages.
|
|
1552
780
|
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
createTicTacToeGame,
|
|
1559
|
-
createQuiz
|
|
1560
|
-
} from 'baileys-joss'
|
|
781
|
+
```ts
|
|
782
|
+
const key: WAMessageKey
|
|
783
|
+
// can pass multiple keys to read multiple messages as well
|
|
784
|
+
await sock.readMessages([key])
|
|
785
|
+
```
|
|
1561
786
|
|
|
1562
|
-
|
|
1563
|
-
|
|
787
|
+
The message ID is the unique identifier of the message that you are marking as read.
|
|
788
|
+
On a `WAMessage`, the `messageID` can be accessed using ```messageID = message.key.id```.
|
|
1564
789
|
|
|
1565
|
-
|
|
1566
|
-
const guessSession = games.startGuessNumber('6281234567890@s.whatsapp.net', {
|
|
1567
|
-
minNumber: 1,
|
|
1568
|
-
maxNumber: 100,
|
|
1569
|
-
maxAttempts: 7
|
|
1570
|
-
})
|
|
790
|
+
### Update Presence
|
|
1571
791
|
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
await sock.sendMessage(jid, { text: `🎉 Correct! The number was ${result.answer}` })
|
|
1576
|
-
} else {
|
|
1577
|
-
await sock.sendMessage(jid, { text: `${result.hint} (${result.remaining} attempts left)` })
|
|
1578
|
-
}
|
|
792
|
+
- ``` presence ``` can be one of the values in the [WAPresence type alias](https://baileys.wiki/docs/api/type-aliases/WAPresence/)
|
|
793
|
+
- The presence expires after about 10 seconds.
|
|
794
|
+
- This lets the person/group with `jid` know whether you're online, offline, typing etc.
|
|
1579
795
|
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
{
|
|
1584
|
-
question: 'Apa ibukota Indonesia?',
|
|
1585
|
-
options: ['Jakarta', 'Bandung', 'Surabaya', 'Medan'],
|
|
1586
|
-
correctIndex: 0,
|
|
1587
|
-
explanation: 'Jakarta adalah ibukota Indonesia sejak 1945'
|
|
1588
|
-
}
|
|
1589
|
-
],
|
|
1590
|
-
category: 'geography'
|
|
1591
|
-
})
|
|
1592
|
-
await sock.sendMessage(jid, {
|
|
1593
|
-
text: `📝 Quiz:\n${quizSession.data.currentQuestion}\n\n${quizSession.data.options.map((o, i) => `${i+1}. ${o}`).join('\n')}`
|
|
1594
|
-
})
|
|
796
|
+
```ts
|
|
797
|
+
await sock.sendPresenceUpdate('available', jid)
|
|
798
|
+
```
|
|
1595
799
|
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
const moveResult = games.handleMove(tttSession.id, player1Jid, 4) // Center position
|
|
800
|
+
> [!NOTE]
|
|
801
|
+
> If a desktop client is active, WA doesn't send push notifications to the device. If you would like to receive said notifications -- mark your Baileys client offline using `sock.sendPresenceUpdate('unavailable')`
|
|
1599
802
|
|
|
1600
|
-
|
|
1601
|
-
text: `${games.renderBoard(tttSession)}\n\n${moveResult.message}`
|
|
1602
|
-
})
|
|
803
|
+
## Modifying Chats
|
|
1603
804
|
|
|
1604
|
-
|
|
1605
|
-
const dice = games.rollDice() // { value: 1-6, emoji: '🎲' }
|
|
1606
|
-
const coin = games.flipCoin() // { result: 'heads'|'tails', emoji: '🪙' }
|
|
1607
|
-
const rps = games.playRockPaperScissors('rock', 'scissors') // { winner: 'player1', ... }
|
|
1608
|
-
|
|
1609
|
-
// 🏆 Leaderboard
|
|
1610
|
-
const leaderboard = games.getLeaderboard(10)
|
|
1611
|
-
```
|
|
1612
|
-
|
|
1613
|
-
</details>
|
|
1614
|
-
|
|
1615
|
-
<details>
|
|
1616
|
-
<summary><h3>🔍 Content Detector (UNTESTED ⚠️)</h3></summary>
|
|
1617
|
-
|
|
1618
|
-
Deteksi otomatis berbagai jenis konten dalam pesan:
|
|
1619
|
-
|
|
1620
|
-
```typescript
|
|
1621
|
-
import {
|
|
1622
|
-
ContentDetector,
|
|
1623
|
-
ContentFilter,
|
|
1624
|
-
hasLinks,
|
|
1625
|
-
hasPhoneNumbers,
|
|
1626
|
-
hasEmails,
|
|
1627
|
-
hasMediaContent
|
|
1628
|
-
} from 'baileys-joss'
|
|
1629
|
-
|
|
1630
|
-
// Create detector
|
|
1631
|
-
const detector = new ContentDetector()
|
|
1632
|
-
|
|
1633
|
-
// Full analysis
|
|
1634
|
-
const result = detector.analyze(message)
|
|
1635
|
-
console.log('Has media:', result.hasMedia)
|
|
1636
|
-
console.log('Media type:', result.mediaType)
|
|
1637
|
-
console.log('Links found:', result.links)
|
|
1638
|
-
console.log('Phone numbers:', result.phoneNumbers)
|
|
1639
|
-
console.log('Emails:', result.emails)
|
|
1640
|
-
console.log('Mentions:', result.mentions)
|
|
1641
|
-
console.log('Hashtags:', result.hashtags)
|
|
1642
|
-
console.log('Word count:', result.wordCount)
|
|
1643
|
-
|
|
1644
|
-
// Quick checks
|
|
1645
|
-
if (hasLinks(message)) {
|
|
1646
|
-
console.log('Message contains links!')
|
|
1647
|
-
}
|
|
1648
|
-
if (hasPhoneNumbers(message)) {
|
|
1649
|
-
console.log('Message contains phone numbers!')
|
|
1650
|
-
}
|
|
1651
|
-
if (hasMediaContent(message)) {
|
|
1652
|
-
console.log('Message has media attachment!')
|
|
1653
|
-
}
|
|
805
|
+
WA uses an encrypted form of communication to send chat/app updates. This has been implemented mostly and you can send the following updates:
|
|
1654
806
|
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
blockLinks: true,
|
|
1658
|
-
blockedDomains: ['spam.com', 'malware.xyz'],
|
|
1659
|
-
blockPhoneNumbers: false,
|
|
1660
|
-
sensitiveKeywords: ['spam', 'promo', 'click here'],
|
|
1661
|
-
maxMessageLength: 1000
|
|
1662
|
-
})
|
|
807
|
+
> [!IMPORTANT]
|
|
808
|
+
> If you mess up one of your updates, WA can log you out of all your devices and you'll have to log in again.
|
|
1663
809
|
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
})
|
|
1669
|
-
}
|
|
810
|
+
### Archive a Chat
|
|
811
|
+
```ts
|
|
812
|
+
const lastMsgInChat = await getLastMessageInChat(jid) // implement this on your end
|
|
813
|
+
await sock.chatModify({ archive: true, lastMessages: [lastMsgInChat] }, jid)
|
|
1670
814
|
```
|
|
815
|
+
### Mute/Unmute a Chat
|
|
1671
816
|
|
|
1672
|
-
|
|
817
|
+
- Supported times:
|
|
1673
818
|
|
|
1674
|
-
|
|
1675
|
-
|
|
819
|
+
| Time | Miliseconds |
|
|
820
|
+
|-------|-----------------|
|
|
821
|
+
| Remove | null |
|
|
822
|
+
| 8h | 86.400.000 |
|
|
823
|
+
| 7d | 604.800.000 |
|
|
1676
824
|
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
825
|
+
```ts
|
|
826
|
+
// mute for 8 hours
|
|
827
|
+
await sock.chatModify({ mute: 8 * 60 * 60 * 1000 }, jid)
|
|
828
|
+
// unmute
|
|
829
|
+
await sock.chatModify({ mute: null }, jid)
|
|
830
|
+
```
|
|
831
|
+
### Mark a Chat Read/Unread
|
|
832
|
+
```ts
|
|
833
|
+
const lastMsgInChat = await getLastMessageInChat(jid) // implement this on your end
|
|
834
|
+
// mark it unread
|
|
835
|
+
await sock.chatModify({ markRead: false, lastMessages: [lastMsgInChat] }, jid)
|
|
836
|
+
```
|
|
1681
837
|
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
838
|
+
### Delete a Message for Me
|
|
839
|
+
```ts
|
|
840
|
+
await sock.chatModify(
|
|
841
|
+
{
|
|
842
|
+
clear: {
|
|
843
|
+
messages: [
|
|
844
|
+
{
|
|
845
|
+
id: 'ATWYHDNNWU81732J',
|
|
846
|
+
fromMe: true,
|
|
847
|
+
timestamp: '1654823909'
|
|
848
|
+
}
|
|
849
|
+
]
|
|
1693
850
|
}
|
|
1694
|
-
}
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
// Add custom spam pattern
|
|
1698
|
-
antispam.addRule({
|
|
1699
|
-
id: 'promo_spam',
|
|
1700
|
-
name: 'Promotional Spam',
|
|
1701
|
-
type: 'pattern',
|
|
1702
|
-
enabled: true,
|
|
1703
|
-
config: { patterns: [/FREE\s+\d+\s+TOKEN/i, /CLICK\s+HERE.*WIN/i] },
|
|
1704
|
-
action: 'delete'
|
|
1705
|
-
})
|
|
851
|
+
},
|
|
852
|
+
jid
|
|
853
|
+
)
|
|
1706
854
|
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
await sock.sendMessage(msg.key.remoteJid, { delete: msg.key })
|
|
1718
|
-
} else if (result.action === 'warn') {
|
|
1719
|
-
await sock.sendMessage(msg.key.remoteJid, {
|
|
1720
|
-
text: `⚠️ Warning: ${result.reason}`
|
|
1721
|
-
})
|
|
855
|
+
```
|
|
856
|
+
### Delete a Chat
|
|
857
|
+
```ts
|
|
858
|
+
const lastMsgInChat = await getLastMessageInChat(jid) // implement this on your end
|
|
859
|
+
await sock.chatModify({
|
|
860
|
+
delete: true,
|
|
861
|
+
lastMessages: [
|
|
862
|
+
{
|
|
863
|
+
key: lastMsgInChat.key,
|
|
864
|
+
messageTimestamp: lastMsgInChat.messageTimestamp
|
|
1722
865
|
}
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
}
|
|
1728
|
-
})
|
|
1729
|
-
|
|
1730
|
-
// Whitelist trusted users
|
|
1731
|
-
antispam.whitelist('trusteduser@s.whatsapp.net')
|
|
1732
|
-
|
|
1733
|
-
// Mute spammer temporarily
|
|
1734
|
-
antispam.muteUser('spammer@s.whatsapp.net', 3600) // 1 hour
|
|
1735
|
-
|
|
1736
|
-
// Ban repeat offender
|
|
1737
|
-
antispam.banUser('baduser@s.whatsapp.net')
|
|
1738
|
-
|
|
1739
|
-
// Get spam statistics
|
|
1740
|
-
const stats = antispam.getStats()
|
|
1741
|
-
console.log('Total spam blocked:', stats.totalBlocked)
|
|
866
|
+
]
|
|
867
|
+
},
|
|
868
|
+
jid
|
|
869
|
+
)
|
|
1742
870
|
```
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
```typescript
|
|
1752
|
-
import { LinkScanner, scanUrls, isUrlSafe } from 'baileys-joss'
|
|
1753
|
-
|
|
1754
|
-
// Create scanner
|
|
1755
|
-
const scanner = new LinkScanner({
|
|
1756
|
-
followRedirects: true,
|
|
1757
|
-
maxRedirects: 5,
|
|
1758
|
-
timeout: 5000,
|
|
1759
|
-
enablePhishingDetection: true
|
|
1760
|
-
})
|
|
1761
|
-
|
|
1762
|
-
// Scan single URL
|
|
1763
|
-
const result = await scanner.scanUrl('https://suspicious-link.xyz/login')
|
|
1764
|
-
console.log('Safe:', result.safe)
|
|
1765
|
-
console.log('Risk level:', result.riskLevel) // 'safe' | 'low' | 'medium' | 'high' | 'critical'
|
|
1766
|
-
console.log('Threats:', result.threats)
|
|
1767
|
-
console.log('Details:', result.details)
|
|
1768
|
-
|
|
1769
|
-
// Scan all URLs in a message
|
|
1770
|
-
const messageResults = await scanner.scanMessage(message)
|
|
1771
|
-
for (const urlResult of messageResults) {
|
|
1772
|
-
if (!urlResult.safe) {
|
|
1773
|
-
await sock.sendMessage(jid, {
|
|
1774
|
-
text: `⚠️ Warning! Suspicious link detected:\n${urlResult.url}\n\nRisk: ${urlResult.riskLevel}\nThreats: ${urlResult.threats.join(', ')}`
|
|
1775
|
-
})
|
|
1776
|
-
}
|
|
1777
|
-
}
|
|
1778
|
-
|
|
1779
|
-
// Quick safety check
|
|
1780
|
-
const isSafe = await scanner.isUrlSafe('https://example.com')
|
|
1781
|
-
|
|
1782
|
-
// Add custom patterns
|
|
1783
|
-
scanner.addPhishingPattern(/banking.*verify.*account/i)
|
|
1784
|
-
scanner.addTrustedDomain('mytrusted.com')
|
|
1785
|
-
scanner.addMaliciousDomain('known-scam.xyz')
|
|
1786
|
-
|
|
1787
|
-
// Auto-scan in message handler
|
|
1788
|
-
sock.ev.on('messages.upsert', async ({ messages }) => {
|
|
1789
|
-
for (const msg of messages) {
|
|
1790
|
-
const scanResults = await scanner.scanMessage(msg)
|
|
1791
|
-
const dangerous = scanResults.filter(r => r.riskLevel === 'high' || r.riskLevel === 'critical')
|
|
1792
|
-
|
|
1793
|
-
if (dangerous.length > 0) {
|
|
1794
|
-
await sock.sendMessage(msg.key.remoteJid, {
|
|
1795
|
-
text: `🚨 Dangerous link(s) detected! ${dangerous.length} threat(s) found.`
|
|
1796
|
-
}, { quoted: msg })
|
|
1797
|
-
}
|
|
1798
|
-
}
|
|
1799
|
-
})
|
|
871
|
+
### Pin/Unpin a Chat
|
|
872
|
+
```ts
|
|
873
|
+
await sock.chatModify({
|
|
874
|
+
pin: true // or `false` to unpin
|
|
875
|
+
},
|
|
876
|
+
jid
|
|
877
|
+
)
|
|
1800
878
|
```
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
// Create logger
|
|
1813
|
-
const logger = new ActivityLogger({
|
|
1814
|
-
fileLogging: true,
|
|
1815
|
-
logFilePath: './logs/bot-activity.log',
|
|
1816
|
-
maxMemoryEntries: 1000,
|
|
1817
|
-
maxFileSize: 10 * 1024 * 1024, // 10MB
|
|
1818
|
-
minLevel: 'info',
|
|
1819
|
-
categories: ['message', 'user', 'group', 'bot'],
|
|
1820
|
-
onLog: (entry) => {
|
|
1821
|
-
if (entry.level === 'error') {
|
|
1822
|
-
// Send alert to admin
|
|
1823
|
-
console.error(`[ALERT] ${entry.action}: ${entry.details.message}`)
|
|
879
|
+
### Star/Unstar a Message
|
|
880
|
+
```ts
|
|
881
|
+
await sock.chatModify({
|
|
882
|
+
star: {
|
|
883
|
+
messages: [
|
|
884
|
+
{
|
|
885
|
+
id: 'messageID',
|
|
886
|
+
fromMe: true // or `false`
|
|
887
|
+
}
|
|
888
|
+
],
|
|
889
|
+
star: true // - true: Star Message; false: Unstar Message
|
|
1824
890
|
}
|
|
1825
|
-
}
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
// Log message activity
|
|
1829
|
-
logger.logMessage(message, 'received', {
|
|
1830
|
-
processed: true,
|
|
1831
|
-
responseTime: 150
|
|
1832
|
-
})
|
|
1833
|
-
|
|
1834
|
-
// Log user action
|
|
1835
|
-
logger.logUserAction('6281234567890@s.whatsapp.net', 'command_executed', {
|
|
1836
|
-
command: '/help',
|
|
1837
|
-
success: true
|
|
1838
|
-
})
|
|
1839
|
-
|
|
1840
|
-
// Log group action
|
|
1841
|
-
logger.logGroupAction('groupjid@g.us', 'member_added', {
|
|
1842
|
-
addedBy: 'admin@s.whatsapp.net',
|
|
1843
|
-
newMember: 'newuser@s.whatsapp.net'
|
|
1844
|
-
})
|
|
1845
|
-
|
|
1846
|
-
// Log custom activity
|
|
1847
|
-
logger.log({
|
|
1848
|
-
level: 'info',
|
|
1849
|
-
category: 'bot',
|
|
1850
|
-
action: 'scheduled_task',
|
|
1851
|
-
actor: 'system',
|
|
1852
|
-
details: { task: 'daily_backup', status: 'completed' }
|
|
1853
|
-
})
|
|
1854
|
-
|
|
1855
|
-
// Query logs
|
|
1856
|
-
const recentErrors = logger.query({
|
|
1857
|
-
level: 'error',
|
|
1858
|
-
fromDate: new Date(Date.now() - 24 * 60 * 60 * 1000), // Last 24 hours
|
|
1859
|
-
limit: 50
|
|
1860
|
-
})
|
|
1861
|
-
|
|
1862
|
-
// Get statistics
|
|
1863
|
-
const stats = logger.getStats()
|
|
1864
|
-
console.log('Total entries:', stats.totalEntries)
|
|
1865
|
-
console.log('By level:', stats.byLevel)
|
|
1866
|
-
console.log('Top actors:', stats.topActors)
|
|
1867
|
-
|
|
1868
|
-
// Export logs
|
|
1869
|
-
const jsonLogs = logger.export('json')
|
|
1870
|
-
const csvLogs = logger.export('csv')
|
|
891
|
+
},
|
|
892
|
+
jid
|
|
893
|
+
)
|
|
1871
894
|
```
|
|
1872
895
|
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
<details>
|
|
1876
|
-
<summary><h3>🎭 Meme Generator (UNTESTED ⚠️)</h3></summary>
|
|
896
|
+
### Disappearing Messages
|
|
1877
897
|
|
|
1878
|
-
|
|
898
|
+
- Ephemeral can be:
|
|
1879
899
|
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
thisIsFineMeme
|
|
1887
|
-
} from 'baileys-joss'
|
|
900
|
+
| Time | Seconds |
|
|
901
|
+
|-------|----------------|
|
|
902
|
+
| Remove | 0 |
|
|
903
|
+
| 24h | 86.400 |
|
|
904
|
+
| 7d | 604.800 |
|
|
905
|
+
| 90d | 7.776.000 |
|
|
1888
906
|
|
|
1889
|
-
|
|
1890
|
-
const meme = new MemeGenerator()
|
|
907
|
+
- You need to pass in **Seconds**, default is 7 days
|
|
1891
908
|
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
//
|
|
1897
|
-
|
|
1898
|
-
'Debugging code manually', // Rejected
|
|
1899
|
-
'Using console.log everywhere' // Approved
|
|
909
|
+
```ts
|
|
910
|
+
// turn on disappearing messages
|
|
911
|
+
await sock.sendMessage(
|
|
912
|
+
jid,
|
|
913
|
+
// this is 1 week in seconds -- how long you want messages to appear for
|
|
914
|
+
{ disappearingMessagesInChat: WA_DEFAULT_EPHEMERAL }
|
|
1900
915
|
)
|
|
1901
|
-
await sock.sendMessage(jid, { text: drake.htmlContent })
|
|
1902
|
-
|
|
1903
|
-
// Generate Expanding Brain meme
|
|
1904
|
-
const brain = expandingBrainMeme([
|
|
1905
|
-
'Using var',
|
|
1906
|
-
'Using let',
|
|
1907
|
-
'Using const',
|
|
1908
|
-
'Using TypeScript'
|
|
1909
|
-
])
|
|
1910
|
-
await sock.sendMessage(jid, { text: brain.htmlContent })
|
|
1911
|
-
|
|
1912
|
-
// Generate "This is Fine" meme
|
|
1913
|
-
const fine = thisIsFineMeme('Production is on fire but it\'s fine')
|
|
1914
|
-
await sock.sendMessage(jid, { text: fine.htmlContent })
|
|
1915
|
-
|
|
1916
|
-
// Custom meme with template
|
|
1917
|
-
const custom = meme.generateTextMeme({
|
|
1918
|
-
template: 'distracted',
|
|
1919
|
-
texts: {
|
|
1920
|
-
boyfriend: 'Me',
|
|
1921
|
-
girlfriend: 'My deadlines',
|
|
1922
|
-
other: 'New side project'
|
|
1923
|
-
},
|
|
1924
|
-
fontSize: 24,
|
|
1925
|
-
fontColor: '#ffffff'
|
|
1926
|
-
})
|
|
1927
916
|
|
|
1928
|
-
//
|
|
1929
|
-
|
|
1930
|
-
template: 'two_buttons',
|
|
1931
|
-
texts: {
|
|
1932
|
-
button1: 'Sleep early',
|
|
1933
|
-
button2: 'One more episode'
|
|
1934
|
-
}
|
|
1935
|
-
})
|
|
917
|
+
// will send as a disappearing message
|
|
918
|
+
await sock.sendMessage(jid, { text: 'hello' }, { ephemeralExpiration: WA_DEFAULT_EPHEMERAL })
|
|
1936
919
|
|
|
1937
|
-
//
|
|
1938
|
-
await sock.sendMessage(
|
|
1939
|
-
|
|
1940
|
-
}
|
|
920
|
+
// turn off disappearing messages
|
|
921
|
+
await sock.sendMessage(
|
|
922
|
+
jid,
|
|
923
|
+
{ disappearingMessagesInChat: false }
|
|
924
|
+
)
|
|
1941
925
|
```
|
|
1942
926
|
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
<details>
|
|
1946
|
-
<summary><h3>🍅 Pomodoro Timer (UNTESTED ⚠️)</h3></summary>
|
|
1947
|
-
|
|
1948
|
-
Timer produktivitas dengan teknik Pomodoro:
|
|
1949
|
-
|
|
1950
|
-
```typescript
|
|
1951
|
-
import { PomodoroManager, DEFAULT_POMODORO_CONFIG } from 'baileys-joss'
|
|
1952
|
-
|
|
1953
|
-
// Create pomodoro manager
|
|
1954
|
-
const pomodoro = new PomodoroManager()
|
|
1955
|
-
|
|
1956
|
-
// Register event handler
|
|
1957
|
-
pomodoro.onEvent(async (event) => {
|
|
1958
|
-
const jid = event.session.jid
|
|
1959
|
-
|
|
1960
|
-
switch (event.type) {
|
|
1961
|
-
case 'work_start':
|
|
1962
|
-
await sock.sendMessage(jid, {
|
|
1963
|
-
text: `🍅 *WORK SESSION STARTED*\n\n⏱️ Duration: 25 minutes\n🎯 Session: ${event.session.currentSession}/${event.session.totalSessions}\n\n💪 Stay focused!`
|
|
1964
|
-
})
|
|
1965
|
-
break
|
|
1966
|
-
case 'work_end':
|
|
1967
|
-
await sock.sendMessage(jid, {
|
|
1968
|
-
text: `✅ *WORK SESSION COMPLETE!*\n\n🎉 Great job! Time for a break.\n\nType /break to start break timer.`
|
|
1969
|
-
})
|
|
1970
|
-
break
|
|
1971
|
-
case 'break_start':
|
|
1972
|
-
await sock.sendMessage(jid, {
|
|
1973
|
-
text: `☕ *BREAK TIME*\n\n⏱️ Duration: 5 minutes\n\n🧘 Relax and recharge!`
|
|
1974
|
-
})
|
|
1975
|
-
break
|
|
1976
|
-
case 'break_end':
|
|
1977
|
-
await sock.sendMessage(jid, {
|
|
1978
|
-
text: `⏰ *BREAK OVER!*\n\nReady for next session?\nType /work to continue.`
|
|
1979
|
-
})
|
|
1980
|
-
break
|
|
1981
|
-
}
|
|
1982
|
-
})
|
|
927
|
+
## User Querys
|
|
1983
928
|
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
sessionsBeforeLongBreak: 4,
|
|
1990
|
-
autoStartBreaks: true
|
|
1991
|
-
})
|
|
929
|
+
### Check If ID Exists in Whatsapp
|
|
930
|
+
```ts
|
|
931
|
+
const [result] = await sock.onWhatsApp(jid)
|
|
932
|
+
if (result.exists) console.log (`${jid} exists on WhatsApp, as jid: ${result.jid}`)
|
|
933
|
+
```
|
|
1992
934
|
|
|
1993
|
-
|
|
1994
|
-
pomodoro.pause(jid)
|
|
1995
|
-
pomodoro.resume(jid)
|
|
935
|
+
### Query Chat History (groups too)
|
|
1996
936
|
|
|
1997
|
-
|
|
1998
|
-
|
|
937
|
+
- You need to have oldest message in chat
|
|
938
|
+
```ts
|
|
939
|
+
const msg = await getOldestMessageInChat(jid) // implement this on your end
|
|
940
|
+
await sock.fetchMessageHistory(
|
|
941
|
+
50, //quantity (max: 50 per query)
|
|
942
|
+
msg.key,
|
|
943
|
+
msg.messageTimestamp
|
|
944
|
+
)
|
|
945
|
+
```
|
|
946
|
+
- Messages will be received in `messaging.history-set` event
|
|
1999
947
|
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
console.log('
|
|
2004
|
-
|
|
948
|
+
### Fetch Status
|
|
949
|
+
```ts
|
|
950
|
+
const status = await sock.fetchStatus(jid)
|
|
951
|
+
console.log('status: ' + status)
|
|
952
|
+
```
|
|
2005
953
|
|
|
2006
|
-
|
|
2007
|
-
|
|
954
|
+
### Fetch Profile Picture (groups too)
|
|
955
|
+
- To get the display picture of some person/group
|
|
956
|
+
```ts
|
|
957
|
+
// for low res picture
|
|
958
|
+
const ppUrl = await sock.profilePictureUrl(jid)
|
|
959
|
+
console.log(ppUrl)
|
|
2008
960
|
|
|
2009
|
-
//
|
|
2010
|
-
const
|
|
2011
|
-
console.log('Total work sessions:', stats.totalWorkSessions)
|
|
2012
|
-
console.log('Total work minutes:', stats.totalWorkMinutes)
|
|
2013
|
-
console.log('Current streak:', stats.currentStreak)
|
|
961
|
+
// for high res picture
|
|
962
|
+
const ppUrl = await sock.profilePictureUrl(jid, 'image')
|
|
2014
963
|
```
|
|
2015
964
|
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
965
|
+
### Fetch Bussines Profile (such as description or category)
|
|
966
|
+
```ts
|
|
967
|
+
const profile = await sock.getBusinessProfile(jid)
|
|
968
|
+
console.log('business description: ' + profile.description + ', category: ' + profile.category)
|
|
969
|
+
```
|
|
2020
970
|
|
|
2021
|
-
|
|
971
|
+
### Fetch Someone's Presence (if they're typing or online)
|
|
972
|
+
```ts
|
|
973
|
+
// the presence update is fetched and called here
|
|
974
|
+
sock.ev.on('presence.update', console.log)
|
|
2022
975
|
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
getRandomQuote,
|
|
2027
|
-
getQuoteOfTheDay,
|
|
2028
|
-
getMotivationalQuote,
|
|
2029
|
-
getIslamicQuote,
|
|
2030
|
-
getFunnyQuote,
|
|
2031
|
-
quoteCommand,
|
|
2032
|
-
QUOTES
|
|
2033
|
-
} from 'baileys-joss'
|
|
976
|
+
// request updates for a chat
|
|
977
|
+
await sock.presenceSubscribe(jid)
|
|
978
|
+
```
|
|
2034
979
|
|
|
2035
|
-
|
|
2036
|
-
const random = getRandomQuote()
|
|
2037
|
-
await sock.sendMessage(jid, {
|
|
2038
|
-
text: `💬 *Quote*\n\n"${random.text}"\n\n— ${random.author}`
|
|
2039
|
-
})
|
|
980
|
+
## Change Profile
|
|
2040
981
|
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
await sock.
|
|
2044
|
-
|
|
2045
|
-
|
|
982
|
+
### Change Profile Status
|
|
983
|
+
```ts
|
|
984
|
+
await sock.updateProfileStatus('Hello World!')
|
|
985
|
+
```
|
|
986
|
+
### Change Profile Name
|
|
987
|
+
```ts
|
|
988
|
+
await sock.updateProfileName('My name')
|
|
989
|
+
```
|
|
990
|
+
### Change Display Picture (groups too)
|
|
991
|
+
- To change your display picture or a group's
|
|
2046
992
|
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
const islamic = getIslamicQuote()
|
|
2050
|
-
const funny = getFunnyQuote()
|
|
993
|
+
> [!NOTE]
|
|
994
|
+
> Like media messages, you can pass `{ stream: Stream }` or `{ url: Url }` or `Buffer` directly, you can see more in the [WAMediaUpload type alias](https://baileys.wiki/docs/api/type-aliases/WAMediaUpload/)
|
|
2051
995
|
|
|
2052
|
-
|
|
2053
|
-
|
|
996
|
+
```ts
|
|
997
|
+
await sock.updateProfilePicture(jid, { url: './new-profile-picture.jpeg' })
|
|
998
|
+
```
|
|
999
|
+
### Remove display picture (groups too)
|
|
1000
|
+
```ts
|
|
1001
|
+
await sock.removeProfilePicture(jid)
|
|
1002
|
+
```
|
|
2054
1003
|
|
|
2055
|
-
|
|
2056
|
-
const loveQuote = quoteManager.getByCategory('love')
|
|
2057
|
-
const wisdomQuote = quoteManager.getByCategory('wisdom')
|
|
1004
|
+
## Groups
|
|
2058
1005
|
|
|
2059
|
-
|
|
2060
|
-
const indonesianQuote = quoteManager.getByLanguage('id')
|
|
2061
|
-
const englishQuote = quoteManager.getByLanguage('en')
|
|
1006
|
+
- To change group properties you need to be admin
|
|
2062
1007
|
|
|
2063
|
-
|
|
2064
|
-
|
|
1008
|
+
### Create a Group
|
|
1009
|
+
```ts
|
|
1010
|
+
// title & participants
|
|
1011
|
+
const group = await sock.groupCreate('My Fab Group', ['1234@s.whatsapp.net', '4564@s.whatsapp.net'])
|
|
1012
|
+
console.log('created group with id: ' + group.gid)
|
|
1013
|
+
await sock.sendMessage(group.id, { text: 'hello there' }) // say hello to everyone on the group
|
|
1014
|
+
```
|
|
1015
|
+
### Add/Remove or Demote/Promote
|
|
1016
|
+
```ts
|
|
1017
|
+
// id & people to add to the group (will throw error if it fails)
|
|
1018
|
+
await sock.groupParticipantsUpdate(
|
|
1019
|
+
jid,
|
|
1020
|
+
['abcd@s.whatsapp.net', 'efgh@s.whatsapp.net'],
|
|
1021
|
+
'add' // replace this parameter with 'remove' or 'demote' or 'promote'
|
|
1022
|
+
)
|
|
1023
|
+
```
|
|
1024
|
+
### Change Subject (name)
|
|
1025
|
+
```ts
|
|
1026
|
+
await sock.groupUpdateSubject(jid, 'New Subject!')
|
|
1027
|
+
```
|
|
1028
|
+
### Change Description
|
|
1029
|
+
```ts
|
|
1030
|
+
await sock.groupUpdateDescription(jid, 'New Description!')
|
|
1031
|
+
```
|
|
1032
|
+
### Change Settings
|
|
1033
|
+
```ts
|
|
1034
|
+
// only allow admins to send messages
|
|
1035
|
+
await sock.groupSettingUpdate(jid, 'announcement')
|
|
1036
|
+
// allow everyone to send messages
|
|
1037
|
+
await sock.groupSettingUpdate(jid, 'not_announcement')
|
|
1038
|
+
// allow everyone to modify the group's settings -- like display picture etc.
|
|
1039
|
+
await sock.groupSettingUpdate(jid, 'unlocked')
|
|
1040
|
+
// only allow admins to modify the group's settings
|
|
1041
|
+
await sock.groupSettingUpdate(jid, 'locked')
|
|
1042
|
+
```
|
|
1043
|
+
### Leave a Group
|
|
1044
|
+
```ts
|
|
1045
|
+
// will throw error if it fails
|
|
1046
|
+
await sock.groupLeave(jid)
|
|
1047
|
+
```
|
|
1048
|
+
### Get Invite Code
|
|
1049
|
+
- To create link with code use `'https://chat.whatsapp.com/' + code`
|
|
1050
|
+
```ts
|
|
1051
|
+
const code = await sock.groupInviteCode(jid)
|
|
1052
|
+
console.log('group code: ' + code)
|
|
1053
|
+
```
|
|
1054
|
+
### Revoke Invite Code
|
|
1055
|
+
```ts
|
|
1056
|
+
const code = await sock.groupRevokeInvite(jid)
|
|
1057
|
+
console.log('New group code: ' + code)
|
|
1058
|
+
```
|
|
1059
|
+
### Join Using Invitation Code
|
|
1060
|
+
- Code can't have `https://chat.whatsapp.com/`, only code
|
|
1061
|
+
```ts
|
|
1062
|
+
const response = await sock.groupAcceptInvite(code)
|
|
1063
|
+
console.log('joined to: ' + response)
|
|
1064
|
+
```
|
|
1065
|
+
### Get Group Info by Invite Code
|
|
1066
|
+
```ts
|
|
1067
|
+
const response = await sock.groupGetInviteInfo(code)
|
|
1068
|
+
console.log('group information: ' + response)
|
|
1069
|
+
```
|
|
1070
|
+
### Query Metadata (participants, name, description...)
|
|
1071
|
+
```ts
|
|
1072
|
+
const metadata = await sock.groupMetadata(jid)
|
|
1073
|
+
console.log(metadata.id + ', title: ' + metadata.subject + ', description: ' + metadata.desc)
|
|
1074
|
+
```
|
|
1075
|
+
### Join using `groupInviteMessage`
|
|
1076
|
+
```ts
|
|
1077
|
+
const response = await sock.groupAcceptInviteV4(jid, groupInviteMessage)
|
|
1078
|
+
console.log('joined to: ' + response)
|
|
1079
|
+
```
|
|
1080
|
+
### Get Request Join List
|
|
1081
|
+
```ts
|
|
1082
|
+
const response = await sock.groupRequestParticipantsList(jid)
|
|
1083
|
+
console.log(response)
|
|
1084
|
+
```
|
|
1085
|
+
### Approve/Reject Request Join
|
|
1086
|
+
```ts
|
|
1087
|
+
const response = await sock.groupRequestParticipantsUpdate(
|
|
1088
|
+
jid, // group id
|
|
1089
|
+
['abcd@s.whatsapp.net', 'efgh@s.whatsapp.net'],
|
|
1090
|
+
'approve' // or 'reject'
|
|
1091
|
+
)
|
|
1092
|
+
console.log(response)
|
|
1093
|
+
```
|
|
1094
|
+
### Get All Participating Groups Metadata
|
|
1095
|
+
```ts
|
|
1096
|
+
const response = await sock.groupFetchAllParticipating()
|
|
1097
|
+
console.log(response)
|
|
1098
|
+
```
|
|
1099
|
+
### Toggle Ephemeral
|
|
2065
1100
|
|
|
2066
|
-
|
|
2067
|
-
quoteManager.addQuote({
|
|
2068
|
-
id: 'custom1',
|
|
2069
|
-
text: 'My custom inspirational quote',
|
|
2070
|
-
author: 'Me',
|
|
2071
|
-
category: 'inspirational',
|
|
2072
|
-
language: 'en'
|
|
2073
|
-
})
|
|
1101
|
+
- Ephemeral can be:
|
|
2074
1102
|
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
1103
|
+
| Time | Seconds |
|
|
1104
|
+
|-------|----------------|
|
|
1105
|
+
| Remove | 0 |
|
|
1106
|
+
| 24h | 86.400 |
|
|
1107
|
+
| 7d | 604.800 |
|
|
1108
|
+
| 90d | 7.776.000 |
|
|
2079
1109
|
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
style: 'fancy', // 'simple' | 'fancy' | 'minimal'
|
|
2083
|
-
includeCategory: true
|
|
2084
|
-
})
|
|
2085
|
-
await sock.sendMessage(jid, { text: formatted })
|
|
1110
|
+
```ts
|
|
1111
|
+
await sock.groupToggleEphemeral(jid, 86400)
|
|
2086
1112
|
```
|
|
2087
1113
|
|
|
2088
|
-
|
|
1114
|
+
### Change Add Mode
|
|
1115
|
+
```ts
|
|
1116
|
+
await sock.groupMemberAddMode(
|
|
1117
|
+
jid,
|
|
1118
|
+
'all_member_add' // or 'admin_add'
|
|
1119
|
+
)
|
|
1120
|
+
```
|
|
2089
1121
|
|
|
2090
|
-
|
|
2091
|
-
<summary><h3>🌤️ Weather Bot (UNTESTED ⚠️)</h3></summary>
|
|
1122
|
+
## Privacy
|
|
2092
1123
|
|
|
2093
|
-
|
|
1124
|
+
### Block/Unblock User
|
|
1125
|
+
```ts
|
|
1126
|
+
await sock.updateBlockStatus(jid, 'block') // Block user
|
|
1127
|
+
await sock.updateBlockStatus(jid, 'unblock') // Unblock user
|
|
1128
|
+
```
|
|
1129
|
+
### Get Privacy Settings
|
|
1130
|
+
```ts
|
|
1131
|
+
const privacySettings = await sock.fetchPrivacySettings(true)
|
|
1132
|
+
console.log('privacy settings: ' + privacySettings)
|
|
1133
|
+
```
|
|
1134
|
+
### Get BlockList
|
|
1135
|
+
```ts
|
|
1136
|
+
const response = await sock.fetchBlocklist()
|
|
1137
|
+
console.log(response)
|
|
1138
|
+
```
|
|
1139
|
+
### Update LastSeen Privacy
|
|
1140
|
+
```ts
|
|
1141
|
+
const value = 'all' // 'contacts' | 'contact_blacklist' | 'none'
|
|
1142
|
+
await sock.updateLastSeenPrivacy(value)
|
|
1143
|
+
```
|
|
1144
|
+
### Update Online Privacy
|
|
1145
|
+
```ts
|
|
1146
|
+
const value = 'all' // 'match_last_seen'
|
|
1147
|
+
await sock.updateOnlinePrivacy(value)
|
|
1148
|
+
```
|
|
1149
|
+
### Update Profile Picture Privacy
|
|
1150
|
+
```ts
|
|
1151
|
+
const value = 'all' // 'contacts' | 'contact_blacklist' | 'none'
|
|
1152
|
+
await sock.updateProfilePicturePrivacy(value)
|
|
1153
|
+
```
|
|
1154
|
+
### Update Status Privacy
|
|
1155
|
+
```ts
|
|
1156
|
+
const value = 'all' // 'contacts' | 'contact_blacklist' | 'none'
|
|
1157
|
+
await sock.updateStatusPrivacy(value)
|
|
1158
|
+
```
|
|
1159
|
+
### Update Read Receipts Privacy
|
|
1160
|
+
```ts
|
|
1161
|
+
const value = 'all' // 'none'
|
|
1162
|
+
await sock.updateReadReceiptsPrivacy(value)
|
|
1163
|
+
```
|
|
1164
|
+
### Update Groups Add Privacy
|
|
1165
|
+
```ts
|
|
1166
|
+
const value = 'all' // 'contacts' | 'contact_blacklist'
|
|
1167
|
+
await sock.updateGroupsAddPrivacy(value)
|
|
1168
|
+
```
|
|
1169
|
+
### Update Default Disappearing Mode
|
|
2094
1170
|
|
|
2095
|
-
|
|
2096
|
-
import {
|
|
2097
|
-
WeatherBot,
|
|
2098
|
-
getWeather,
|
|
2099
|
-
getSimpleWeather,
|
|
2100
|
-
weatherCommand
|
|
2101
|
-
} from 'baileys-joss'
|
|
1171
|
+
- Like [this](#disappearing-messages), ephemeral can be:
|
|
2102
1172
|
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
})
|
|
1173
|
+
| Time | Seconds |
|
|
1174
|
+
|-------|----------------|
|
|
1175
|
+
| Remove | 0 |
|
|
1176
|
+
| 24h | 86.400 |
|
|
1177
|
+
| 7d | 604.800 |
|
|
1178
|
+
| 90d | 7.776.000 |
|
|
2110
1179
|
|
|
2111
|
-
|
|
2112
|
-
const
|
|
2113
|
-
await sock.
|
|
2114
|
-
|
|
2115
|
-
})
|
|
1180
|
+
```ts
|
|
1181
|
+
const ephemeral = 86400
|
|
1182
|
+
await sock.updateDefaultDisappearingMode(ephemeral)
|
|
1183
|
+
```
|
|
2116
1184
|
|
|
2117
|
-
|
|
2118
|
-
const simpleWeather = await getSimpleWeather('Tokyo')
|
|
2119
|
-
await sock.sendMessage(jid, { text: simpleWeather })
|
|
1185
|
+
## Broadcast Lists & Stories
|
|
2120
1186
|
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
1187
|
+
### Send Broadcast & Stories
|
|
1188
|
+
- Messages can be sent to broadcasts & stories. You need to add the following message options in sendMessage, like this:
|
|
1189
|
+
```ts
|
|
1190
|
+
await sock.sendMessage(
|
|
1191
|
+
jid,
|
|
1192
|
+
{
|
|
1193
|
+
image: {
|
|
1194
|
+
url: url
|
|
1195
|
+
},
|
|
1196
|
+
caption: caption
|
|
1197
|
+
},
|
|
1198
|
+
{
|
|
1199
|
+
backgroundColor: backgroundColor,
|
|
1200
|
+
font: font,
|
|
1201
|
+
statusJidList: statusJidList,
|
|
1202
|
+
broadcast: true
|
|
2136
1203
|
}
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
1204
|
+
)
|
|
1205
|
+
```
|
|
1206
|
+
- Message body can be a `extendedTextMessage` or `imageMessage` or `videoMessage` or `voiceMessage`, see the [AnyRegularMessageContent type alias](https://baileys.wiki/docs/api/type-aliases/AnyRegularMessageContent/)
|
|
1207
|
+
- You can add `backgroundColor` and other options in the message options, see the [MiscMessageGenerationOptions type alias](https://baileys.wiki/docs/api/type-aliases/MiscMessageGenerationOptions/)
|
|
1208
|
+
- `broadcast: true` enables broadcast mode
|
|
1209
|
+
- `statusJidList`: a list of people that you can get which you need to provide, which are the people who will get this status message.
|
|
1210
|
+
|
|
1211
|
+
- You can send messages to broadcast lists the same way you send messages to groups & individual chats.
|
|
1212
|
+
- Right now, WA Web does not support creating broadcast lists, but you can still delete them.
|
|
1213
|
+
- Broadcast IDs are in the format `12345678@broadcast`
|
|
1214
|
+
### Query a Broadcast List's Recipients & Name
|
|
1215
|
+
```ts
|
|
1216
|
+
const bList = await sock.getBroadcastListInfo('1234@broadcast')
|
|
1217
|
+
console.log (`list name: ${bList.name}, recps: ${bList.recipients}`)
|
|
2151
1218
|
```
|
|
2152
1219
|
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
<details>
|
|
2156
|
-
<summary><h3>🔗 QR Code Generator</h3></summary>
|
|
2157
|
-
|
|
2158
|
-
Generate QR code custom untuk pairing:
|
|
2159
|
-
|
|
2160
|
-
```typescript
|
|
2161
|
-
import {
|
|
2162
|
-
createQRGenerator,
|
|
2163
|
-
QRHelper,
|
|
2164
|
-
createQRHandler,
|
|
2165
|
-
createWhatsAppQR
|
|
2166
|
-
} from 'baileys-joss'
|
|
2167
|
-
|
|
2168
|
-
// Quick QR generation
|
|
2169
|
-
const terminalQR = await QRHelper.terminal(pairingCode)
|
|
2170
|
-
console.log(terminalQR)
|
|
2171
|
-
|
|
2172
|
-
// Generate SVG QR
|
|
2173
|
-
const svgQR = await QRHelper.svg(pairingCode, {
|
|
2174
|
-
size: 300,
|
|
2175
|
-
foregroundColor: '#128C7E', // WhatsApp green
|
|
2176
|
-
backgroundColor: '#FFFFFF'
|
|
2177
|
-
})
|
|
2178
|
-
|
|
2179
|
-
// Generate base64 QR (for web)
|
|
2180
|
-
const base64QR = await QRHelper.base64(pairingCode)
|
|
2181
|
-
|
|
2182
|
-
// Generate PNG buffer
|
|
2183
|
-
const pngBuffer = await QRHelper.buffer(pairingCode)
|
|
2184
|
-
fs.writeFileSync('qr.png', pngBuffer)
|
|
2185
|
-
|
|
2186
|
-
// Custom generator
|
|
2187
|
-
const generator = createQRGenerator({
|
|
2188
|
-
size: 256,
|
|
2189
|
-
errorCorrectionLevel: 'H',
|
|
2190
|
-
foregroundColor: '#000000',
|
|
2191
|
-
margin: 4
|
|
2192
|
-
})
|
|
2193
|
-
|
|
2194
|
-
const qr = await generator.generate(data)
|
|
2195
|
-
|
|
2196
|
-
// WhatsApp-styled QR
|
|
2197
|
-
const waQR = await createWhatsAppQR(pairingCode)
|
|
1220
|
+
## Writing Custom Functionality
|
|
1221
|
+
Baileys is written with custom functionality in mind. Instead of forking the project & re-writing the internals, you can simply write your own extensions.
|
|
2198
1222
|
|
|
2199
|
-
|
|
1223
|
+
### Enabling Debug Level in Baileys Logs
|
|
1224
|
+
First, enable the logging of unhandled messages from WhatsApp by setting:
|
|
1225
|
+
```ts
|
|
2200
1226
|
const sock = makeWASocket({
|
|
2201
|
-
|
|
2202
|
-
printQRInTerminal: false
|
|
2203
|
-
})
|
|
2204
|
-
|
|
2205
|
-
sock.ev.on('connection.update', async ({ qr }) => {
|
|
2206
|
-
if (qr) {
|
|
2207
|
-
const qrHandler = createQRHandler({
|
|
2208
|
-
maxAttempts: 5,
|
|
2209
|
-
onQR: (rendered, raw, attempt) => {
|
|
2210
|
-
console.log(`\nScan QR (${attempt}/5):\n`)
|
|
2211
|
-
console.log(rendered)
|
|
2212
|
-
}
|
|
2213
|
-
})
|
|
2214
|
-
await qrHandler(qr)
|
|
2215
|
-
}
|
|
1227
|
+
logger: P({ level: 'debug' }),
|
|
2216
1228
|
})
|
|
2217
1229
|
```
|
|
1230
|
+
This will enable you to see all sorts of messages WhatsApp sends in the console.
|
|
2218
1231
|
|
|
2219
|
-
|
|
1232
|
+
### How Whatsapp Communicate With Us
|
|
2220
1233
|
|
|
2221
|
-
|
|
2222
|
-
|
|
1234
|
+
> [!TIP]
|
|
1235
|
+
> If you want to learn whatsapp protocol, we recommend to study about Libsignal Protocol and Noise Protocol
|
|
2223
1236
|
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
```typescript
|
|
2227
|
-
import { createMediaDownloader, downloadAllMedia } from 'baileys-joss'
|
|
2228
|
-
|
|
2229
|
-
const downloader = createMediaDownloader(
|
|
2230
|
-
async (key) => store.loadMessage(key.remoteJid, key.id)
|
|
2231
|
-
)
|
|
2232
|
-
|
|
2233
|
-
// Download all media from chat
|
|
2234
|
-
const summary = await downloader.downloadFromChat(
|
|
2235
|
-
'6281234567890@s.whatsapp.net',
|
|
2236
|
-
chatMessages,
|
|
1237
|
+
- **Example:** Functionality to track the battery percentage of your phone. You enable logging and you'll see a message about your battery pop up in the console:
|
|
1238
|
+
```
|
|
2237
1239
|
{
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
1240
|
+
"level": 10,
|
|
1241
|
+
"fromMe": false,
|
|
1242
|
+
"frame": {
|
|
1243
|
+
"tag": "ib",
|
|
1244
|
+
"attrs": {
|
|
1245
|
+
"from": "@s.whatsapp.net"
|
|
1246
|
+
},
|
|
1247
|
+
"content": [
|
|
1248
|
+
{
|
|
1249
|
+
"tag": "edge_routing",
|
|
1250
|
+
"attrs": {},
|
|
1251
|
+
"content": [
|
|
1252
|
+
{
|
|
1253
|
+
"tag": "routing_info",
|
|
1254
|
+
"attrs": {},
|
|
1255
|
+
"content": {
|
|
1256
|
+
"type": "Buffer",
|
|
1257
|
+
"data": [8,2,8,5]
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
]
|
|
1261
|
+
}
|
|
1262
|
+
]
|
|
2246
1263
|
},
|
|
2247
|
-
|
|
2248
|
-
console.log(`Failed: ${error.message}`)
|
|
2249
|
-
}
|
|
1264
|
+
"msg":"communication"
|
|
2250
1265
|
}
|
|
2251
|
-
|
|
1266
|
+
```
|
|
2252
1267
|
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
1268
|
+
The `'frame'` is what the message received is, it has three components:
|
|
1269
|
+
- `tag` -- what this frame is about (eg. message will have 'message')
|
|
1270
|
+
- `attrs` -- a string key-value pair with some metadata (contains ID of the message usually)
|
|
1271
|
+
- `content` -- the actual data (eg. a message node will have the actual message content in it)
|
|
1272
|
+
- read more about this format [here](/src/WABinary/readme.md)
|
|
2256
1273
|
|
|
2257
|
-
|
|
2258
|
-
const singleResult = await downloader.downloadSingle(
|
|
2259
|
-
mediaMessage,
|
|
2260
|
-
'./downloads',
|
|
2261
|
-
{ filenameTemplate: '{type}_{date}_{id}{ext}' }
|
|
2262
|
-
)
|
|
1274
|
+
### Register a Callback for Websocket Events
|
|
2263
1275
|
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
1276
|
+
> [!TIP]
|
|
1277
|
+
> Recommended to see `onMessageReceived` function in `socket.ts` file to understand how websockets events are fired
|
|
1278
|
+
|
|
1279
|
+
```ts
|
|
1280
|
+
// for any message with tag 'edge_routing'
|
|
1281
|
+
sock.ws.on('CB:edge_routing', (node: BinaryNode) => { })
|
|
2270
1282
|
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
---
|
|
2274
|
-
|
|
2275
|
-
## 📋 API Reference
|
|
2276
|
-
|
|
2277
|
-
<details>
|
|
2278
|
-
<summary><b>🖱️ Interactive Messages</b></summary>
|
|
2279
|
-
|
|
2280
|
-
| Function | Description |
|
|
2281
|
-
|----------|-------------|
|
|
2282
|
-
| `generateInteractiveButtonMessage()` | Buat button message dengan media header |
|
|
2283
|
-
| `generateInteractiveListMessage()` | Buat list message dengan sections |
|
|
2284
|
-
| `generateTemplateMessage()` | Buat template message (Quick Reply, URL, Call) |
|
|
2285
|
-
| `generateNativeFlowMessage()` | Buat native flow message (format terbaru) |
|
|
2286
|
-
| `generateCopyCodeButton()` | Button untuk copy code |
|
|
2287
|
-
| `generateUrlButtonMessage()` | Button dengan URL |
|
|
2288
|
-
| `generateQuickReplyButtons()` | Quick reply buttons |
|
|
2289
|
-
| `generateCombinedButtons()` | Gabungan berbagai jenis button |
|
|
2290
|
-
|
|
2291
|
-
</details>
|
|
2292
|
-
|
|
2293
|
-
<details>
|
|
2294
|
-
<summary><b>📍 JID Plotting</b></summary>
|
|
2295
|
-
|
|
2296
|
-
| Function | Description |
|
|
2297
|
-
|----------|-------------|
|
|
2298
|
-
| `parseJid()` | Parse JID dan extract info lengkap |
|
|
2299
|
-
| `getSenderPn()` | Get senderPn dari AuthenticationCreds |
|
|
2300
|
-
| `getCurrentSenderInfo()` | Get current sender info dari authState |
|
|
2301
|
-
| `isSelf()` | Check apakah JID adalah diri sendiri |
|
|
2302
|
-
| `plotJid()` | Plot JID (basic, tanpa LID mapping) |
|
|
2303
|
-
| `normalizePhoneToJid()` | Normalize nomor ke JID |
|
|
2304
|
-
| `extractPhoneNumber()` | Extract phone number dari JID |
|
|
2305
|
-
| `formatJidDisplay()` | Format JID untuk display |
|
|
2306
|
-
| `isSameUser()` | Compare dua JID |
|
|
2307
|
-
| `getJidVariants()` | Get semua variant JID dari nomor |
|
|
2308
|
-
| `constructJidWithDevice()` | Construct JID dengan device ID |
|
|
2309
|
-
| `getRemoteJidFromMessage()` | Get remoteJid dari message |
|
|
2310
|
-
| `createJidPlotter()` | Create plotter dengan LID mapping support |
|
|
2311
|
-
|
|
2312
|
-
</details>
|
|
2313
|
-
|
|
2314
|
-
<details>
|
|
2315
|
-
<summary><b>📢 Newsletter/Channel</b></summary>
|
|
2316
|
-
|
|
2317
|
-
| Function | Description |
|
|
2318
|
-
|----------|-------------|
|
|
2319
|
-
| `newsletterCreate()` | Buat channel baru |
|
|
2320
|
-
| `newsletterUpdateName()` | Update nama channel |
|
|
2321
|
-
| `newsletterUpdateDescription()` | Update deskripsi channel |
|
|
2322
|
-
| `newsletterUpdatePicture()` | Update foto channel |
|
|
2323
|
-
| `newsletterFollow()` | Follow channel |
|
|
2324
|
-
| `newsletterUnfollow()` | Unfollow channel |
|
|
2325
|
-
| `newsletterMute()` | Mute notifikasi channel |
|
|
2326
|
-
| `newsletterUnmute()` | Unmute notifikasi channel |
|
|
2327
|
-
| `newsletterReactMessage()` | React ke pesan channel |
|
|
2328
|
-
| `newsletterMetadata()` | Get metadata channel |
|
|
2329
|
-
| `newsletterAdminCount()` | Get jumlah admin |
|
|
2330
|
-
| `newsletterChangeOwner()` | Ganti owner channel |
|
|
2331
|
-
| `newsletterDemote()` | Demote admin channel |
|
|
2332
|
-
| `newsletterDelete()` | Hapus channel |
|
|
2333
|
-
|
|
2334
|
-
</details>
|
|
2335
|
-
|
|
2336
|
-
<details>
|
|
2337
|
-
<summary><b>👥 Group Management</b></summary>
|
|
2338
|
-
|
|
2339
|
-
| Function | Description |
|
|
2340
|
-
|----------|-------------|
|
|
2341
|
-
| `groupCreate()` | Buat grup baru |
|
|
2342
|
-
| `groupUpdateSubject()` | Update nama grup |
|
|
2343
|
-
| `groupUpdateDescription()` | Update deskripsi grup |
|
|
2344
|
-
| `groupParticipantsUpdate()` | Add/remove/promote/demote member |
|
|
2345
|
-
| `groupSettingUpdate()` | Update pengaturan grup |
|
|
2346
|
-
| `groupMetadata()` | Get metadata grup |
|
|
2347
|
-
| `groupLeave()` | Keluar dari grup |
|
|
2348
|
-
| `groupInviteCode()` | Get kode invite grup |
|
|
2349
|
-
| `groupAcceptInvite()` | Join grup via invite code |
|
|
2350
|
-
|
|
2351
|
-
</details>
|
|
2352
|
-
|
|
2353
|
-
<details>
|
|
2354
|
-
<summary><b>💬 Message Types</b></summary>
|
|
2355
|
-
|
|
2356
|
-
| Type | Description |
|
|
2357
|
-
|------|-------------|
|
|
2358
|
-
| `text` | Pesan teks biasa |
|
|
2359
|
-
| `image` | Kirim gambar (dengan opsi `hd: true` untuk kualitas HD) |
|
|
2360
|
-
| `video` | Kirim video (dengan opsi `hd: true` untuk kualitas HD) |
|
|
2361
|
-
| `audio` | Kirim audio |
|
|
2362
|
-
| `document` | Kirim dokumen |
|
|
2363
|
-
| `sticker` | Kirim sticker |
|
|
2364
|
-
| `location` | Kirim lokasi |
|
|
2365
|
-
| `contacts` | Kirim kontak |
|
|
2366
|
-
| `poll` | Buat polling |
|
|
2367
|
-
| `album` | Kirim album (multiple media) |
|
|
2368
|
-
| `react` | React ke pesan |
|
|
2369
|
-
| `edit` | Edit pesan |
|
|
2370
|
-
| `delete` | Hapus pesan |
|
|
2371
|
-
|
|
2372
|
-
</details>
|
|
2373
|
-
|
|
2374
|
-
<details>
|
|
2375
|
-
<summary><b>📷 Profile Picture</b></summary>
|
|
2376
|
-
|
|
2377
|
-
| Function | Description |
|
|
2378
|
-
|----------|-------------|
|
|
2379
|
-
| `updateProfilePicture()` | Update foto profil (square crop) |
|
|
2380
|
-
| `updatePanoramaProfilePicture()` | Update foto profil panorama (wide, tidak di-crop) |
|
|
2381
|
-
| `removeProfilePicture()` | Hapus foto profil |
|
|
2382
|
-
| `profilePictureUrl()` | Get URL foto profil |
|
|
2383
|
-
|
|
2384
|
-
</details>
|
|
2385
|
-
|
|
2386
|
-
<details>
|
|
2387
|
-
<summary><b>🎮 Mini Games (UNTESTED ⚠️)</b></summary>
|
|
2388
|
-
|
|
2389
|
-
| Function | Description |
|
|
2390
|
-
|----------|-------------|
|
|
2391
|
-
| `MiniGamesManager` | Main class untuk manage semua games |
|
|
2392
|
-
| `games.startGuessNumber()` | Start guess number game |
|
|
2393
|
-
| `games.startQuiz()` | Start quiz game |
|
|
2394
|
-
| `games.startTicTacToe()` | Start TicTacToe (vs bot/player) |
|
|
2395
|
-
| `games.playRockPaperScissors()` | Play RPS game |
|
|
2396
|
-
| `games.rollDice()` | Roll dice (1-6) |
|
|
2397
|
-
| `games.flipCoin()` | Flip a coin |
|
|
2398
|
-
| `games.handleGuess()` | Handle guess input |
|
|
2399
|
-
| `games.handleMove()` | Handle TicTacToe move |
|
|
2400
|
-
| `games.getLeaderboard()` | Get player leaderboard |
|
|
2401
|
-
|
|
2402
|
-
</details>
|
|
2403
|
-
|
|
2404
|
-
<details>
|
|
2405
|
-
<summary><b>🔍 Content Detector (UNTESTED ⚠️)</b></summary>
|
|
2406
|
-
|
|
2407
|
-
| Function | Description |
|
|
2408
|
-
|----------|-------------|
|
|
2409
|
-
| `ContentDetector` | Main class untuk detect content |
|
|
2410
|
-
| `detector.analyze()` | Full content analysis |
|
|
2411
|
-
| `hasLinks()` | Quick check for URLs |
|
|
2412
|
-
| `hasPhoneNumbers()` | Quick check for phone numbers |
|
|
2413
|
-
| `hasEmails()` | Quick check for emails |
|
|
2414
|
-
| `hasMediaContent()` | Check if message has media |
|
|
2415
|
-
| `isForwarded()` | Check if message is forwarded |
|
|
2416
|
-
| `ContentFilter` | Filter messages by criteria |
|
|
2417
|
-
|
|
2418
|
-
</details>
|
|
2419
|
-
|
|
2420
|
-
<details>
|
|
2421
|
-
<summary><b>🛡️ Anti-Spam (UNTESTED ⚠️)</b></summary>
|
|
2422
|
-
|
|
2423
|
-
| Function | Description |
|
|
2424
|
-
|----------|-------------|
|
|
2425
|
-
| `AntiSpamManager` | Main anti-spam class |
|
|
2426
|
-
| `antispam.checkMessage()` | Check if message is spam |
|
|
2427
|
-
| `antispam.addRule()` | Add custom spam rule |
|
|
2428
|
-
| `antispam.muteUser()` | Mute user temporarily |
|
|
2429
|
-
| `antispam.banUser()` | Ban user permanently |
|
|
2430
|
-
| `antispam.whitelist()` | Add user to whitelist |
|
|
2431
|
-
| `antispam.getStats()` | Get spam statistics |
|
|
2432
|
-
|
|
2433
|
-
</details>
|
|
2434
|
-
|
|
2435
|
-
<details>
|
|
2436
|
-
<summary><b>🔗 Link Scanner (UNTESTED ⚠️)</b></summary>
|
|
2437
|
-
|
|
2438
|
-
| Function | Description |
|
|
2439
|
-
|----------|-------------|
|
|
2440
|
-
| `LinkScanner` | Main URL security scanner |
|
|
2441
|
-
| `scanner.scanUrl()` | Scan single URL |
|
|
2442
|
-
| `scanner.scanMessage()` | Scan all URLs in message |
|
|
2443
|
-
| `scanner.isUrlSafe()` | Quick safety check |
|
|
2444
|
-
| `scanner.addPhishingPattern()` | Add custom phishing pattern |
|
|
2445
|
-
| `scanner.addTrustedDomain()` | Add trusted domain |
|
|
2446
|
-
|
|
2447
|
-
</details>
|
|
2448
|
-
|
|
2449
|
-
<details>
|
|
2450
|
-
<summary><b>📝 Activity Logger (UNTESTED ⚠️)</b></summary>
|
|
2451
|
-
|
|
2452
|
-
| Function | Description |
|
|
2453
|
-
|----------|-------------|
|
|
2454
|
-
| `ActivityLogger` | Main logging class |
|
|
2455
|
-
| `logger.log()` | Log custom activity |
|
|
2456
|
-
| `logger.logMessage()` | Log message activity |
|
|
2457
|
-
| `logger.logUserAction()` | Log user action |
|
|
2458
|
-
| `logger.logGroupAction()` | Log group action |
|
|
2459
|
-
| `logger.query()` | Query logs with filters |
|
|
2460
|
-
| `logger.getStats()` | Get activity statistics |
|
|
2461
|
-
|
|
2462
|
-
</details>
|
|
2463
|
-
|
|
2464
|
-
<details>
|
|
2465
|
-
<summary><b>🎭 Meme Generator (UNTESTED ⚠️)</b></summary>
|
|
2466
|
-
|
|
2467
|
-
| Function | Description |
|
|
2468
|
-
|----------|-------------|
|
|
2469
|
-
| `MemeGenerator` | Main meme class |
|
|
2470
|
-
| `meme.generateTextMeme()` | Generate ASCII text meme |
|
|
2471
|
-
| `meme.generateSvgMeme()` | Generate SVG meme |
|
|
2472
|
-
| `meme.getTemplates()` | List available templates |
|
|
2473
|
-
| `drakeMeme()` | Quick Drake meme |
|
|
2474
|
-
| `expandingBrainMeme()` | Quick Expanding Brain meme |
|
|
2475
|
-
| `thisIsFineMeme()` | Quick "This is Fine" meme |
|
|
2476
|
-
|
|
2477
|
-
</details>
|
|
2478
|
-
|
|
2479
|
-
<details>
|
|
2480
|
-
<summary><b>🍅 Pomodoro Timer (UNTESTED ⚠️)</b></summary>
|
|
2481
|
-
|
|
2482
|
-
| Function | Description |
|
|
2483
|
-
|----------|-------------|
|
|
2484
|
-
| `PomodoroManager` | Main timer class |
|
|
2485
|
-
| `pomodoro.start()` | Start work session |
|
|
2486
|
-
| `pomodoro.break()` | Start break |
|
|
2487
|
-
| `pomodoro.pause()` | Pause timer |
|
|
2488
|
-
| `pomodoro.resume()` | Resume timer |
|
|
2489
|
-
| `pomodoro.stop()` | Stop and reset |
|
|
2490
|
-
| `pomodoro.status()` | Get current status |
|
|
2491
|
-
| `pomodoro.stats()` | Get statistics |
|
|
2492
|
-
|
|
2493
|
-
</details>
|
|
2494
|
-
|
|
2495
|
-
<details>
|
|
2496
|
-
<summary><b>💬 Quote Generator (UNTESTED ⚠️)</b></summary>
|
|
2497
|
-
|
|
2498
|
-
| Function | Description |
|
|
2499
|
-
|----------|-------------|
|
|
2500
|
-
| `QuoteManager` | Main quote class |
|
|
2501
|
-
| `getRandomQuote()` | Get random quote |
|
|
2502
|
-
| `getQuoteOfTheDay()` | Get daily quote |
|
|
2503
|
-
| `getMotivationalQuote()` | Get motivational quote |
|
|
2504
|
-
| `getIslamicQuote()` | Get Islamic quote |
|
|
2505
|
-
| `getFunnyQuote()` | Get funny quote |
|
|
2506
|
-
| `quoteCommand()` | Parse quote command |
|
|
2507
|
-
|
|
2508
|
-
</details>
|
|
2509
|
-
|
|
2510
|
-
<details>
|
|
2511
|
-
<summary><b>🌤️ Weather Bot (UNTESTED ⚠️)</b></summary>
|
|
2512
|
-
|
|
2513
|
-
| Function | Description |
|
|
2514
|
-
|----------|-------------|
|
|
2515
|
-
| `WeatherBot` | Main weather class |
|
|
2516
|
-
| `weather.getWeather()` | Get weather for city |
|
|
2517
|
-
| `weather.setApiKey()` | Set OpenWeatherMap API key |
|
|
2518
|
-
| `getWeather()` | Quick weather helper |
|
|
2519
|
-
| `getSimpleWeather()` | Get simplified weather |
|
|
2520
|
-
| `weatherCommand()` | Parse weather command |
|
|
2521
|
-
|
|
2522
|
-
</details>
|
|
2523
|
-
|
|
2524
|
-
---
|
|
2525
|
-
|
|
2526
|
-
## 🔄 Changelog
|
|
2527
|
-
|
|
2528
|
-
<details open>
|
|
2529
|
-
<summary><b>v1.0.3</b> - Latest (BIG UPDATE! 🎉)</summary>
|
|
2530
|
-
|
|
2531
|
-
### 🆕 New Features
|
|
2532
|
-
|
|
2533
|
-
**🎮 Mini Games**
|
|
2534
|
-
- Guess Number game with hints
|
|
2535
|
-
- Quiz with multiple categories
|
|
2536
|
-
- TicTacToe (vs Bot or 2 players)
|
|
2537
|
-
- Rock Paper Scissors
|
|
2538
|
-
- Dice Roll & Coin Flip
|
|
2539
|
-
- Score tracking and leaderboards
|
|
2540
|
-
|
|
2541
|
-
**🔍 Content Detector**
|
|
2542
|
-
- URL/Link detection with extraction
|
|
2543
|
-
- Phone number detection
|
|
2544
|
-
- Email detection
|
|
2545
|
-
- Media type detection (image, video, audio, document, sticker)
|
|
2546
|
-
- Mention and hashtag extraction
|
|
2547
|
-
- Emoji analysis
|
|
2548
|
-
- Sensitive content filtering
|
|
2549
|
-
- Forwarded message detection
|
|
2550
|
-
|
|
2551
|
-
**🛡️ Anti-Spam System**
|
|
2552
|
-
- Rate limiting per user
|
|
2553
|
-
- Duplicate message detection
|
|
2554
|
-
- Flood protection
|
|
2555
|
-
- Pattern-based spam detection
|
|
2556
|
-
- User mute/ban functionality
|
|
2557
|
-
- Whitelist support
|
|
2558
|
-
- Customizable rules and thresholds
|
|
2559
|
-
|
|
2560
|
-
**🔗 Link Scanner**
|
|
2561
|
-
- URL security analysis
|
|
2562
|
-
- Phishing detection with pattern matching
|
|
2563
|
-
- URL shortener expansion
|
|
2564
|
-
- Suspicious TLD detection
|
|
2565
|
-
- Domain reputation checking
|
|
2566
|
-
- Risk level scoring (safe/low/medium/high/critical)
|
|
2567
|
-
- Redirect following for shortened URLs
|
|
2568
|
-
|
|
2569
|
-
**📝 Activity Logger**
|
|
2570
|
-
- Audit trail logging
|
|
2571
|
-
- Multiple log levels (debug, info, warn, error, critical)
|
|
2572
|
-
- Category-based logging (message, user, group, bot, security)
|
|
2573
|
-
- File logging with rotation support
|
|
2574
|
-
- Query and search logs
|
|
2575
|
-
- Statistics and analytics
|
|
2576
|
-
- Memory and file output options
|
|
2577
|
-
|
|
2578
|
-
**🎭 Meme Generator**
|
|
2579
|
-
- Text-based meme templates
|
|
2580
|
-
- Popular meme formats (Drake, Expanding Brain, Two Buttons, etc.)
|
|
2581
|
-
- SVG/HTML output generation
|
|
2582
|
-
- Custom template support
|
|
2583
|
-
- Quick meme helpers
|
|
2584
|
-
|
|
2585
|
-
**🍅 Pomodoro Timer**
|
|
2586
|
-
- Productivity timer with Pomodoro technique
|
|
2587
|
-
- Configurable work/break durations
|
|
2588
|
-
- Session tracking and statistics
|
|
2589
|
-
- Pause/resume functionality
|
|
2590
|
-
- Auto-start options
|
|
2591
|
-
- Streak tracking
|
|
2592
|
-
|
|
2593
|
-
**💬 Quote Generator**
|
|
2594
|
-
- 40+ built-in quotes (English & Indonesian)
|
|
2595
|
-
- Multiple categories (motivational, inspirational, love, life, success, wisdom, funny, islamic, philosophy)
|
|
2596
|
-
- Quote of the day feature
|
|
2597
|
-
- Search quotes by text or author
|
|
2598
|
-
- Custom quote support
|
|
2599
|
-
- Formatted output styles
|
|
2600
|
-
|
|
2601
|
-
**🌤️ Weather Bot**
|
|
2602
|
-
- Real-time weather information
|
|
2603
|
-
- OpenWeatherMap API integration
|
|
2604
|
-
- Mock data for offline use
|
|
2605
|
-
- Detailed weather display (temp, humidity, wind, etc.)
|
|
2606
|
-
- Weather advice based on conditions
|
|
2607
|
-
- Multiple city support
|
|
2608
|
-
- Caching for performance
|
|
2609
|
-
|
|
2610
|
-
**📅 Message Scheduling**
|
|
2611
|
-
- Schedule messages for future delivery
|
|
2612
|
-
- Delay-based scheduling
|
|
2613
|
-
- Cancel/manage scheduled messages
|
|
2614
|
-
|
|
2615
|
-
**📨 Bulk Messaging**
|
|
2616
|
-
- Send to multiple recipients with rate limiting
|
|
2617
|
-
- Progress tracking and callbacks
|
|
2618
|
-
- Retry mechanism with error handling
|
|
2619
|
-
|
|
2620
|
-
**🔄 Auto Reply System**
|
|
2621
|
-
- Keyword-based auto replies
|
|
2622
|
-
- Regex pattern matching
|
|
2623
|
-
- Cooldown per user/rule
|
|
2624
|
-
- Group/private chat filters
|
|
2625
|
-
|
|
2626
|
-
**📇 Contact Card (vCard)**
|
|
2627
|
-
- Full vCard generation with all fields
|
|
2628
|
-
- Multi-contact support
|
|
2629
|
-
- Quick contact helper
|
|
2630
|
-
|
|
2631
|
-
**📺 Status/Story Posting**
|
|
2632
|
-
- Text status with backgrounds & fonts
|
|
2633
|
-
- Image/video status
|
|
2634
|
-
- Pre-defined backgrounds & styles
|
|
2635
|
-
|
|
2636
|
-
**📋 Message Templates**
|
|
2637
|
-
- Pre-built templates (order, invoice, etc.)
|
|
2638
|
-
- Variable substitution
|
|
2639
|
-
- Export/import templates
|
|
2640
|
-
|
|
2641
|
-
**📡 Broadcast Manager**
|
|
2642
|
-
- Create and manage broadcast lists
|
|
2643
|
-
- Send to multiple lists
|
|
2644
|
-
- Statistics and tracking
|
|
2645
|
-
|
|
2646
|
-
**⌨️ Typing Indicator**
|
|
2647
|
-
- Start/stop typing simulation
|
|
2648
|
-
- Recording indicator for voice notes
|
|
2649
|
-
- Auto-pause functionality
|
|
2650
|
-
|
|
2651
|
-
**✅ Read Receipt Control**
|
|
2652
|
-
- Enable/disable read receipts
|
|
2653
|
-
- Delay before marking read
|
|
2654
|
-
- Exclude specific JIDs
|
|
2655
|
-
|
|
2656
|
-
**🔍 Message Search**
|
|
2657
|
-
- Full-text search in messages
|
|
2658
|
-
- Regex support
|
|
2659
|
-
- Filter by type, date, sender
|
|
2660
|
-
|
|
2661
|
-
**📊 Chat Analytics**
|
|
2662
|
-
- Message statistics
|
|
2663
|
-
- Activity by hour/day
|
|
2664
|
-
- Top participants
|
|
2665
|
-
- Media/link/emoji counts
|
|
2666
|
-
|
|
2667
|
-
**💾 Chat Export**
|
|
2668
|
-
- Export to JSON, HTML, TXT, CSV
|
|
2669
|
-
- Customizable templates
|
|
2670
|
-
- Date range filtering
|
|
2671
|
-
|
|
2672
|
-
**🔗 QR Code Generator**
|
|
2673
|
-
- Multiple output formats (terminal, SVG, PNG, base64)
|
|
2674
|
-
- Customizable colors and styles
|
|
2675
|
-
- WhatsApp-styled QR
|
|
2676
|
-
|
|
2677
|
-
**📁 Media Downloader**
|
|
2678
|
-
- Batch download media from chats
|
|
2679
|
-
- Progress tracking
|
|
2680
|
-
- Type filtering and size limits
|
|
2681
|
-
|
|
2682
|
-
### ✨ Improvements
|
|
2683
|
-
- ✨ **HD Images & Videos** - Send uncompressed media with `hd: true`
|
|
2684
|
-
- ✨ **Panorama Profile Picture** - Set wide/panoramic profile pictures without cropping
|
|
2685
|
-
- ✨ Higher quality thumbnails for HD mode
|
|
2686
|
-
- 📸 Better image quality preservation
|
|
2687
|
-
- 🎬 Video quality improvements
|
|
2688
|
-
- 📝 Added complete demo code example
|
|
2689
|
-
- 🎨 Improved documentation structure
|
|
2690
|
-
- 🐛 Bug fixes and performance improvements
|
|
2691
|
-
|
|
2692
|
-
</details>
|
|
2693
|
-
|
|
2694
|
-
<details>
|
|
2695
|
-
<summary><b>v1.0.1</b></summary>
|
|
2696
|
-
|
|
2697
|
-
- ✨ Added Album Messages support (carousel format)
|
|
2698
|
-
- ✨ Added AI Message Style (`ai: true`) - shows AI indicator on messages
|
|
2699
|
-
- ✨ Added Custom Pairing Code support
|
|
2700
|
-
- ✨ Enhanced Newsletter/Channel control
|
|
2701
|
-
- ✨ Enhanced Poll creation
|
|
2702
|
-
- 🔧 **Fixed Interactive Buttons** - Added `biz` node for proper button rendering
|
|
2703
|
-
- 🔧 Fixed List Messages delivery
|
|
2704
|
-
- 🎨 Improved documentation with collapsible sections
|
|
2705
|
-
- 🐛 Bug fixes and stability improvements
|
|
2706
|
-
|
|
2707
|
-
</details>
|
|
2708
|
-
|
|
2709
|
-
<details>
|
|
2710
|
-
<summary><b>v1.0.0</b></summary>
|
|
2711
|
-
|
|
2712
|
-
- 🎉 Initial release
|
|
2713
|
-
- ✨ Interactive Buttons support
|
|
2714
|
-
- ✨ List Messages support
|
|
2715
|
-
- ✨ Copy Code Button
|
|
2716
|
-
- ✨ URL Buttons
|
|
2717
|
-
- ✨ Combined Button Types
|
|
2718
|
-
- ✨ Native Flow Messages
|
|
2719
|
-
- ✨ LID/SenderPn Plotting utilities
|
|
2720
|
-
|
|
2721
|
-
</details>
|
|
2722
|
-
|
|
2723
|
-
---
|
|
2724
|
-
|
|
2725
|
-
## 🤝 Contributing
|
|
2726
|
-
|
|
2727
|
-
Kontribusi sangat diterima! Silahkan:
|
|
2728
|
-
|
|
2729
|
-
1. 🍴 Fork repository ini
|
|
2730
|
-
2. 🌿 Buat branch fitur (`git checkout -b feature/AmazingFeature`)
|
|
2731
|
-
3. 💾 Commit changes (`git commit -m 'Add some AmazingFeature'`)
|
|
2732
|
-
4. 📤 Push ke branch (`git push origin feature/AmazingFeature`)
|
|
2733
|
-
5. 🔃 Buka Pull Request
|
|
2734
|
-
|
|
2735
|
-
---
|
|
2736
|
-
|
|
2737
|
-
## 💖 Support
|
|
2738
|
-
|
|
2739
|
-
Jika project ini membantu, berikan ⭐ di [GitHub](https://github.com/firdausmntp/Baileys-Joss)!
|
|
2740
|
-
|
|
2741
|
-
<p align="center">
|
|
2742
|
-
<a href="https://github.com/firdausmntp/Baileys-Joss/stargazers">
|
|
2743
|
-
<img src="https://img.shields.io/github/stars/firdausmntp/Baileys-Joss?style=social" alt="GitHub Stars"/>
|
|
2744
|
-
</a>
|
|
2745
|
-
</p>
|
|
2746
|
-
|
|
2747
|
-
---
|
|
2748
|
-
|
|
2749
|
-
## ⚠️ Disclaimer
|
|
2750
|
-
|
|
2751
|
-
> **Peringatan:** Proyek ini tidak berafiliasi dengan WhatsApp atau Meta. Gunakan dengan tanggung jawab dan sesuai dengan Terms of Service WhatsApp.
|
|
2752
|
-
>
|
|
2753
|
-
> ❌ **Jangan spam!**
|
|
2754
|
-
> ❌ **Jangan abuse API!**
|
|
2755
|
-
> ✅ **Gunakan untuk keperluan yang baik!**
|
|
2756
|
-
|
|
2757
|
-
---
|
|
2758
|
-
|
|
2759
|
-
## 📄 License
|
|
2760
|
-
|
|
2761
|
-
MIT License - Lihat file [LICENSE](LICENSE) untuk detail.
|
|
2762
|
-
|
|
2763
|
-
---
|
|
2764
|
-
|
|
2765
|
-
## 🙏 Credits
|
|
2766
|
-
|
|
2767
|
-
<table>
|
|
2768
|
-
<tr>
|
|
2769
|
-
<td align="center">
|
|
2770
|
-
<a href="https://github.com/WhiskeySockets/Baileys">
|
|
2771
|
-
<b>Baileys Original</b>
|
|
2772
|
-
</a>
|
|
2773
|
-
<br>Base library
|
|
2774
|
-
</td>
|
|
2775
|
-
<td align="center">
|
|
2776
|
-
<a href="https://github.com/WhiskeySockets">
|
|
2777
|
-
<b>WhiskeySockets</b>
|
|
2778
|
-
</a>
|
|
2779
|
-
<br>Maintainer Baileys
|
|
2780
|
-
</td>
|
|
2781
|
-
</tr>
|
|
2782
|
-
</table>
|
|
2783
|
-
|
|
2784
|
-
---
|
|
1283
|
+
// for any message with tag 'edge_routing' and id attribute = abcd
|
|
1284
|
+
sock.ws.on('CB:edge_routing,id:abcd', (node: BinaryNode) => { })
|
|
2785
1285
|
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
1286
|
+
// for any message with tag 'edge_routing', id attribute = abcd & first content node routing_info
|
|
1287
|
+
sock.ws.on('CB:edge_routing,id:abcd,routing_info', (node: BinaryNode) => { })
|
|
1288
|
+
```
|
|
2789
1289
|
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
1290
|
+
# License
|
|
1291
|
+
Copyright (c) 2025 Rajeh Taher/WhiskeySockets
|
|
1292
|
+
|
|
1293
|
+
Licensed under the MIT License:
|
|
1294
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
1295
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
1296
|
+
in the Software without restriction, including without limitation the rights
|
|
1297
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
1298
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
1299
|
+
furnished to do so, subject to the following conditions:
|
|
1300
|
+
|
|
1301
|
+
The above copyright notice and this permission notice shall be included in all
|
|
1302
|
+
copies or substantial portions of the Software.
|
|
1303
|
+
|
|
1304
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
1305
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
1306
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
1307
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
1308
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
1309
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
1310
|
+
SOFTWARE.
|
|
1311
|
+
|
|
1312
|
+
Thus, the maintainers of the project can't be held liable for any potential misuse of this project.
|