baileys-joss 1.0.2 → 2.0.0

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