baileys-joss 1.0.3 → 2.0.0

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