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