@znan/wabot 0.2.0-beta.0 → 0.2.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/publish.yaml +27 -0
- package/README.md +596 -93
- package/lib/database/index.js +1 -80
- package/lib/database/local.js +1 -1
- package/lib/database/mongo.js +1 -1
- package/lib/database/mysql.js +1 -1
- package/lib/database/postgre.js +1 -1
- package/lib/database/sqlite.js +1 -1
- package/lib/socket/connection.js +1 -1
- package/lib/socket/events/call.js +1 -1
- package/lib/socket/events/chats.update.js +1 -1
- package/lib/socket/events/contacts.update.js +1 -1
- package/lib/socket/events/group-participants.update.js +1 -1
- package/lib/socket/events/group.join-request.js +1 -1
- package/lib/socket/events/groups.update.js +1 -1
- package/lib/socket/events/index.js +1 -33
- package/lib/socket/events/lid-mapping.update.js +1 -1
- package/lib/socket/events/message-receipt.update.js +1 -1
- package/lib/socket/events/messages.reaction.js +1 -1
- package/lib/socket/events/messages.update.js +1 -1
- package/lib/socket/events/messages.upsert.js +1 -1
- package/lib/socket/events/presence.update.js +1 -1
- package/lib/socket/message.js +1 -1
- package/lib/socket/serialize.js +1 -1
- package/lib/socket/store.js +1 -1
- package/lib/system/converter.js +1 -1
- package/lib/system/exif.js +1 -1
- package/lib/system/function.js +1 -1
- package/lib/system/scraper.js +1 -1
- package/lib/utils/cache.js +1 -1
- package/lib/utils/cooldown.js +1 -1
- package/lib/utils/getcommand.js +1 -1
- package/lib/utils/logger.js +1 -1
- package/lib/utils/parsecommand.js +1 -1
- package/lib/utils/plugins.js +1 -1
- package/lib/utils/session.js +1 -1
- package/lib/utils/spam.js +1 -1
- package/package.json +1 -1
- package/lib/socket/builder.js +0 -1
- package/lib/socket/builder.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,138 +1,641 @@
|
|
|
1
|
-
# @
|
|
1
|
+
# @znan/wabot
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@znan/wabot)
|
|
4
4
|
[](https://www.npmjs.com/package/@znan/wabot)
|
|
5
5
|
[](https://opensource.org/licenses/MIT)
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Socket-based WhatsApp bot module built on [@whiskeysockets/baileys](https://github.com/WhiskeySockets/Baileys) v7. Handles LID migration, session management, and event processing out of the box.
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
## ✨ Key Features
|
|
12
|
-
|
|
13
|
-
* **Simplified Baileys Integration**: Leverage the power of Baileys with a more user-friendly interface.
|
|
14
|
-
* **Flexible Configuration**: Extensive options to tailor your bot's behavior.
|
|
15
|
-
* **Efficient Session Management**: Robust handling of connection sessions.
|
|
16
|
-
* **Comprehensive Event Handling**: Supports various Baileys events for bot responsiveness.
|
|
17
|
-
* **Developer-Centric Design**: Built with ease of use and learning in mind.
|
|
9
|
+
---
|
|
18
10
|
|
|
19
|
-
##
|
|
11
|
+
## Table of Contents
|
|
12
|
+
|
|
13
|
+
- [Installation](#installation)
|
|
14
|
+
- [Quick Start](#quick-start)
|
|
15
|
+
- [Connection](#connection)
|
|
16
|
+
- [Events](#events)
|
|
17
|
+
- [Custom Events](#custom-events)
|
|
18
|
+
- [Raw Events](#raw-events)
|
|
19
|
+
- [Payload Details](#payload-details)
|
|
20
|
+
- [Plugin System](#plugin-system)
|
|
21
|
+
- [Session Management](#session-management)
|
|
22
|
+
- [Database](#database)
|
|
23
|
+
- [Migration Guide](#migration-guide)
|
|
24
|
+
- [Error Handling](#error-handling)
|
|
25
|
+
- [Advanced Examples](#advanced-examples)
|
|
26
|
+
- [License](#license)
|
|
20
27
|
|
|
21
|
-
|
|
28
|
+
---
|
|
22
29
|
|
|
23
|
-
|
|
30
|
+
## Installation
|
|
24
31
|
|
|
25
32
|
```bash
|
|
26
33
|
npm install @znan/wabot
|
|
27
34
|
```
|
|
28
35
|
|
|
29
|
-
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Quick Start
|
|
30
39
|
|
|
31
|
-
```
|
|
32
|
-
|
|
40
|
+
```javascript
|
|
41
|
+
const { Connection } = require('@znan/wabot')
|
|
42
|
+
|
|
43
|
+
const conn = new Connection({
|
|
44
|
+
plugins_dir: 'plugins',
|
|
45
|
+
session_dir: './session',
|
|
46
|
+
online: true,
|
|
47
|
+
presence: true,
|
|
48
|
+
bypass_ephemeral: true,
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
conn.on('connect', x => console.log(x.message))
|
|
52
|
+
conn.on('prepare', x => console.log(x.message))
|
|
53
|
+
conn.on('error', x => console.error(x.message))
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Connection
|
|
59
|
+
|
|
60
|
+
### Constructor
|
|
61
|
+
|
|
62
|
+
```javascript
|
|
63
|
+
new Connection(options, extra?)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Options
|
|
67
|
+
|
|
68
|
+
| Option | Type | Default | Description |
|
|
69
|
+
|---|---|---|---|
|
|
70
|
+
| `plugins_dir` | `string` | `'plugins'` | Plugin directory path |
|
|
71
|
+
| `session_dir` | `string` | `'./session'` | Session storage path |
|
|
72
|
+
| `online` | `boolean` | `false` | Maintain online presence |
|
|
73
|
+
| `presence` | `boolean` | `false` | Emit presence updates |
|
|
74
|
+
| `bypass_ephemeral` | `boolean` | `false` | Ignore ephemeral message settings |
|
|
75
|
+
| `pairing.state` | `boolean` | `false` | Enable pairing code mode (instead of QR) |
|
|
76
|
+
| `pairing.number` | `string` | `''` | Phone number for pairing code |
|
|
77
|
+
| `pairing.code` | `string` | `''` | Custom 8-character pairing code |
|
|
78
|
+
|
|
79
|
+
### Extra Options
|
|
80
|
+
|
|
81
|
+
Passed directly to Baileys `makeWASocket`. Common options:
|
|
82
|
+
|
|
83
|
+
```javascript
|
|
84
|
+
const conn = new Connection(options, {
|
|
85
|
+
browser: ['Ubuntu', 'Firefox', '20.0.00'],
|
|
86
|
+
version: [2, 3000, 1029030078], // Baileys version override
|
|
87
|
+
shouldIgnoreJid: jid => /(newsletter|bot)/.test(jid), // Ignore specific JIDs
|
|
88
|
+
getMessage: async key => { /* custom message retrieval */ },
|
|
89
|
+
groupMetadata: async jid => { /* custom group cache */ },
|
|
90
|
+
// ... any Baileys SocketConfig option
|
|
91
|
+
})
|
|
33
92
|
```
|
|
34
93
|
|
|
35
|
-
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## Events
|
|
36
97
|
|
|
37
|
-
|
|
98
|
+
Events are split into two categories: **Custom Events** (processed, LID-resolved) and **Raw Events** (passthrough from Baileys with `baileys:` prefix).
|
|
99
|
+
|
|
100
|
+
### Custom Events
|
|
101
|
+
|
|
102
|
+
#### Connection Lifecycle
|
|
103
|
+
|
|
104
|
+
| Event | Listener Count | Description |
|
|
105
|
+
|---|---|---|
|
|
106
|
+
| `connect` | `on` | Fires on every connection attempt (includes reconnects) |
|
|
107
|
+
| `prepare` | `once` | Bot is ready — session loaded, plugins watching |
|
|
108
|
+
| `error` | `on` | Connection or runtime error |
|
|
38
109
|
|
|
39
110
|
```javascript
|
|
40
|
-
|
|
41
|
-
|
|
111
|
+
conn.on('connect', ({ display, message }) => console.log(display, message))
|
|
112
|
+
conn.on('prepare', ({ display, message }) => {
|
|
113
|
+
console.log(display, message)
|
|
114
|
+
// Bot is ready — start your services here
|
|
115
|
+
})
|
|
116
|
+
conn.on('error', ({ display, message }) => console.error(display, message))
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
#### Messages
|
|
42
120
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
121
|
+
| Event | Description |
|
|
122
|
+
|---|---|
|
|
123
|
+
| `import` | Message received, serialized, and parsed (includes command parsing) |
|
|
124
|
+
| `poll` | Poll vote detected and decrypted |
|
|
125
|
+
| `stories` | Status broadcast received |
|
|
126
|
+
| `messages.update` | Raw message update (emit passthrough) |
|
|
127
|
+
| `message.delete` | Message deleted or revoked |
|
|
128
|
+
| `message.receipt` | Message receipt update (read status) |
|
|
129
|
+
|
|
130
|
+
```javascript
|
|
131
|
+
conn.on('import', x => {
|
|
132
|
+
// x.m — serialized message with sender, body, command, args, etc.
|
|
133
|
+
// x.isCommand — boolean if message matches prefix
|
|
134
|
+
// x.command — command name (e.g. 'menu', 'help')
|
|
135
|
+
// x.args — array of arguments
|
|
136
|
+
// x.text — full text after command
|
|
137
|
+
// x.prefix — detected prefix
|
|
138
|
+
// x.prefixes — all active prefixes
|
|
139
|
+
// x.store — global store reference
|
|
140
|
+
if (x.isCommand) {
|
|
141
|
+
console.log(`Command: ${x.command} from ${x.m.sender}`)
|
|
142
|
+
}
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
conn.on('poll', x => {
|
|
146
|
+
console.log(`Poll vote: ${x.selected} by ${x.sender}`)
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
conn.on('message.delete', x => {
|
|
150
|
+
if (x) console.log(`Message deleted in ${x.jid}`)
|
|
151
|
+
})
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
#### Groups
|
|
155
|
+
|
|
156
|
+
| Event | Description |
|
|
157
|
+
|---|---|
|
|
158
|
+
| `group.add` | Participant added to group |
|
|
159
|
+
| `group.remove` | Participant removed from group |
|
|
160
|
+
| `group.promote` | Participant promoted to admin |
|
|
161
|
+
| `group.demote` | Participant demoted from admin |
|
|
162
|
+
| `group.subject` | Group name changed |
|
|
163
|
+
| `group.desc` | Group description changed |
|
|
164
|
+
| `group.announce` | Group opened or closed |
|
|
165
|
+
| `group.restrict` | Edit info permission changed |
|
|
166
|
+
| `group.memberAddMode` | Member add mode toggled |
|
|
167
|
+
| `group.joinApprovalMode` | Join approval mode toggled |
|
|
168
|
+
| `group.request` | Join request created, approved, or rejected |
|
|
169
|
+
| `groups.update` | Legacy — any group metadata change |
|
|
170
|
+
|
|
171
|
+
```javascript
|
|
172
|
+
conn.on('group.add', x => {
|
|
173
|
+
// x.jid — group ID
|
|
174
|
+
// x.author — who added (resolved to PN)
|
|
175
|
+
// x.member — who was added (resolved to PN)
|
|
176
|
+
// x.subject — group name
|
|
177
|
+
// x.groupMetadata — full group metadata
|
|
178
|
+
console.log(`${x.member} added to ${x.subject} by ${x.author}`)
|
|
179
|
+
})
|
|
180
|
+
|
|
181
|
+
conn.on('group.remove', x => {
|
|
182
|
+
console.log(`${x.member} removed from ${x.subject}`)
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
conn.on('group.request', x => {
|
|
186
|
+
if (x.action === 'created') {
|
|
187
|
+
console.log(`Join request from ${x.participant}`)
|
|
188
|
+
} else if (x.action === 'approved') {
|
|
189
|
+
console.log(`Request approved by ${x.author}`)
|
|
190
|
+
} else if (x.action === 'rejected') {
|
|
191
|
+
console.log(`Request rejected by ${x.author}`)
|
|
54
192
|
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
193
|
+
})
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
#### Other
|
|
197
|
+
|
|
198
|
+
| Event | Description |
|
|
199
|
+
|---|---|
|
|
200
|
+
| `presence.update` | User presence changed (resolved to PN) |
|
|
201
|
+
| `call` | Incoming call event |
|
|
202
|
+
| `lid-mapping.update` | New LID→PN mapping received |
|
|
203
|
+
|
|
204
|
+
```javascript
|
|
205
|
+
conn.on('presence.update', ({ id, presences }) => {
|
|
206
|
+
for (const [jid, data] of Object.entries(presences)) {
|
|
207
|
+
if (data.lastKnownPresence === 'composing') {
|
|
208
|
+
console.log(`${jid} is typing in ${id}`)
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
})
|
|
212
|
+
|
|
213
|
+
conn.on('call', async calls => {
|
|
214
|
+
for (const call of calls) {
|
|
215
|
+
if (call.status === 'offer') {
|
|
216
|
+
await conn.sock.rejectCall(call.id, call.from)
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
})
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### Raw Events
|
|
223
|
+
|
|
224
|
+
All Baileys native events are forwarded with `baileys:` prefix. This gives you access to every event Baileys emits, even ones not covered by custom events:
|
|
225
|
+
|
|
226
|
+
```javascript
|
|
227
|
+
conn.on('baileys:connection.update', state => { ... })
|
|
228
|
+
conn.on('baileys:messaging-history.set', data => { ... })
|
|
229
|
+
conn.on('baileys:messaging-history.status', status => { ... })
|
|
230
|
+
conn.on('baileys:chats.upsert', chats => { ... })
|
|
231
|
+
conn.on('baileys:chats.update', updates => { ... })
|
|
232
|
+
conn.on('baileys:chats.delete', ids => { ... })
|
|
233
|
+
conn.on('baileys:chats.lock', data => { ... })
|
|
234
|
+
conn.on('baileys:contacts.upsert', contacts => { ... })
|
|
235
|
+
conn.on('baileys:contacts.update', updates => { ... })
|
|
236
|
+
conn.on('baileys:messages.upsert', data => { ... })
|
|
237
|
+
conn.on('baileys:messages.update', updates => { ... })
|
|
238
|
+
conn.on('baileys:messages.delete', data => { ... })
|
|
239
|
+
conn.on('baileys:messages.media-update', updates => { ... })
|
|
240
|
+
conn.on('baileys:messages.reaction', reactions => { ... })
|
|
241
|
+
conn.on('baileys:message-receipt.update', receipts => { ... })
|
|
242
|
+
conn.on('baileys:groups.upsert', groups => { ... })
|
|
243
|
+
conn.on('baileys:groups.update', updates => { ... })
|
|
244
|
+
conn.on('baileys:group-participants.update', update => { ... })
|
|
245
|
+
conn.on('baileys:group.join-request', request => { ... })
|
|
246
|
+
conn.on('baileys:group.member-tag.update', update => { ... })
|
|
247
|
+
conn.on('baileys:blocklist.set', data => { ... })
|
|
248
|
+
conn.on('baileys:blocklist.update', data => { ... })
|
|
249
|
+
conn.on('baileys:labels.edit', label => { ... })
|
|
250
|
+
conn.on('baileys:labels.association', data => { ... })
|
|
251
|
+
conn.on('baileys:newsletter.reaction', data => { ... })
|
|
252
|
+
conn.on('baileys:newsletter.view', data => { ... })
|
|
253
|
+
conn.on('baileys:newsletter-participants.update', data => { ... })
|
|
254
|
+
conn.on('baileys:newsletter-settings.update', data => { ... })
|
|
255
|
+
conn.on('baileys:message-capping.update', data => { ... })
|
|
256
|
+
conn.on('baileys:settings.update', data => { ... })
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
Events **not** forwarded as raw (managed internally):
|
|
260
|
+
- `connection.update` — handled by connection lifecycle
|
|
261
|
+
- `creds.update` — handled by session persistence
|
|
262
|
+
- `contacts.upsert` — handled by contact store
|
|
263
|
+
|
|
264
|
+
### Payload Details
|
|
265
|
+
|
|
266
|
+
#### `import` — Full Message Object
|
|
267
|
+
|
|
268
|
+
After serialization, `x.m` includes:
|
|
269
|
+
|
|
270
|
+
| Property | Type | Description |
|
|
271
|
+
|---|---|---|
|
|
272
|
+
| `m.id` | `string` | Unique message ID |
|
|
273
|
+
| `m.chat` | `string` | Chat JID |
|
|
274
|
+
| `m.sender` | `string` | Sender JID (resolved to PN) |
|
|
275
|
+
| `m.fromMe` | `boolean` | Sent by self |
|
|
276
|
+
| `m.isGroup` | `boolean` | Is group chat |
|
|
277
|
+
| `m.mtype` | `string` | Message type (e.g. `extendedTextMessage`, `imageMessage`) |
|
|
278
|
+
| `m.msg` | `object` | Message content (text, caption, media metadata) |
|
|
279
|
+
| `m.text` | `string` | Extracted text content |
|
|
280
|
+
| `m.mentionedJid` | `string[]` | Mentioned JIDs (resolved to PN) |
|
|
281
|
+
| `m.isMedia` | `boolean` | Has media attachment |
|
|
282
|
+
| `m.isBot` | `boolean` | Sent by bot |
|
|
283
|
+
| `m.device` | `string` | Sender device (`web`, `android`, `ios`, `desktop`) |
|
|
284
|
+
| `m.quoted` | `object` | Quoted/replied message (if any) |
|
|
285
|
+
| `m.quoted.sender` | `string` | Quoted sender (resolved to PN) |
|
|
286
|
+
| `m.quoted.mentionedJid` | `string[]` | Quoted mentions (resolved to PN) |
|
|
287
|
+
| `m.key` | `object` | Raw Baileys message key |
|
|
288
|
+
| `m.reply(text, opts?)` | `function` | Quick reply helper |
|
|
289
|
+
| `m.react(emoji, key?)` | `function` | Quick reaction helper |
|
|
290
|
+
| `m.download()` | `function` | Download media |
|
|
291
|
+
|
|
292
|
+
#### `group.*` — Group Events
|
|
293
|
+
|
|
294
|
+
```javascript
|
|
295
|
+
conn.on('group.add', {
|
|
296
|
+
action: 'add', // 'add' | 'remove' | 'promote' | 'demote'
|
|
297
|
+
jid: '...@g.us', // Group JID
|
|
298
|
+
author: '...@s.whatsapp.net', // Who performed the action (resolved)
|
|
299
|
+
subject: 'Group Name', // Group subject
|
|
300
|
+
member: '...@s.whatsapp.net', // Target member (resolved)
|
|
301
|
+
groupMetadata: { ... } // Full GroupMetadata object
|
|
302
|
+
})
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
#### `group.request`
|
|
306
|
+
|
|
307
|
+
```javascript
|
|
308
|
+
conn.on('group.request', {
|
|
309
|
+
id: '...@g.us',
|
|
310
|
+
author: '...@s.whatsapp.net', // Admin who approved/rejected (null on 'created')
|
|
311
|
+
participant: '...@s.whatsapp.net', // User who requested
|
|
312
|
+
action: 'created', // 'created' | 'approved' | 'rejected'
|
|
313
|
+
method: 'invite_link' // Request method
|
|
314
|
+
})
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
---
|
|
318
|
+
|
|
319
|
+
## Plugin System
|
|
320
|
+
|
|
321
|
+
### Structure
|
|
322
|
+
|
|
323
|
+
```
|
|
324
|
+
plugins/
|
|
325
|
+
├── menu.js
|
|
326
|
+
├── group.js
|
|
327
|
+
├── owner/
|
|
328
|
+
│ ├── ban.js
|
|
329
|
+
│ └── eval.js
|
|
330
|
+
└── ...
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
### Plugin Format
|
|
334
|
+
|
|
335
|
+
Each plugin file exports an object:
|
|
336
|
+
|
|
337
|
+
```javascript
|
|
338
|
+
module.exports = {
|
|
339
|
+
command: 'menu',
|
|
340
|
+
alias: ['help', 'h'],
|
|
341
|
+
category: 'main',
|
|
342
|
+
description: 'Show bot menu',
|
|
343
|
+
loading: true,
|
|
344
|
+
async run(m, { sock, Func, config, db, plugins }) {
|
|
345
|
+
// m — serialized message
|
|
346
|
+
// sock — Baileys socket
|
|
347
|
+
// Func — utility functions
|
|
348
|
+
// config — environment config
|
|
349
|
+
// db — global database
|
|
350
|
+
// plugins — all loaded plugins
|
|
351
|
+
m.reply('Hello from menu plugin!')
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
### Plugin Properties
|
|
357
|
+
|
|
358
|
+
| Property | Type | Default | Description |
|
|
359
|
+
|---|---|---|---|
|
|
360
|
+
| `command` | `string` | required | Command name (without prefix) |
|
|
361
|
+
| `alias` | `string[]` | `[]` | Alternative names |
|
|
362
|
+
| `category` | `string` | `'main'` | Grouping category |
|
|
363
|
+
| `description` | `string` | `''` | Help text |
|
|
364
|
+
| `loading` | `boolean` | `true` | Show typing indicator |
|
|
365
|
+
| `run` | `function` | required | Command handler |
|
|
366
|
+
|
|
367
|
+
### Event Plugins
|
|
368
|
+
|
|
369
|
+
```javascript
|
|
370
|
+
module.exports = {
|
|
371
|
+
command: 'antilink',
|
|
372
|
+
event: 'group.add', // Listen to a custom event instead of commands
|
|
373
|
+
async run(x, { sock, db }) {
|
|
374
|
+
// x — event payload
|
|
375
|
+
// Runs automatically when 'group.add' fires
|
|
60
376
|
}
|
|
61
|
-
}
|
|
377
|
+
}
|
|
62
378
|
```
|
|
63
379
|
|
|
64
|
-
|
|
380
|
+
---
|
|
381
|
+
|
|
382
|
+
## Session Management
|
|
65
383
|
|
|
66
|
-
|
|
384
|
+
### File-Based Session (Default)
|
|
67
385
|
|
|
68
386
|
```javascript
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
});
|
|
387
|
+
const conn = new Connection({
|
|
388
|
+
session_dir: './session' // Multi-file auth state stored here
|
|
389
|
+
})
|
|
390
|
+
```
|
|
74
391
|
|
|
75
|
-
|
|
76
|
-
Conn.on('error', (error) => {
|
|
77
|
-
console.error('Connection error:', error);
|
|
78
|
-
});
|
|
392
|
+
### Custom Session Provider
|
|
79
393
|
|
|
80
|
-
|
|
81
|
-
Conn.on('prepare', () => {
|
|
82
|
-
console.log('Bot is preparing...');
|
|
83
|
-
});
|
|
394
|
+
Pass an async object implementing the auth state interface:
|
|
84
395
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
396
|
+
```javascript
|
|
397
|
+
const { Connection } = require('@znan/wabot')
|
|
398
|
+
const customSession = {
|
|
399
|
+
state: { creds: {}, keys: {} },
|
|
400
|
+
saveCreds: () => {},
|
|
401
|
+
deleteCreds: () => {},
|
|
402
|
+
restoreCreds: async () => {},
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
const conn = new Connection({
|
|
406
|
+
session_dir: customSession // Custom session provider
|
|
407
|
+
})
|
|
408
|
+
```
|
|
90
409
|
|
|
91
|
-
|
|
92
|
-
Conn.on('messages.reaction', (reaction) => {
|
|
93
|
-
console.log('Message reaction:', reaction);
|
|
94
|
-
});
|
|
410
|
+
### Auto-Backup & Restore
|
|
95
411
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
412
|
+
Module automatically:
|
|
413
|
+
- Backs up session when connected
|
|
414
|
+
- Detects session corruption on `badSession` disconnect
|
|
415
|
+
- Restores from backup if available
|
|
416
|
+
- Reconnects with restored session
|
|
100
417
|
|
|
101
|
-
|
|
102
|
-
Conn.on('messages.delete', (deletedMessage) => {
|
|
103
|
-
console.log('Message deleted:', deletedMessage);
|
|
104
|
-
});
|
|
418
|
+
### Session Cleanup
|
|
105
419
|
|
|
106
|
-
|
|
107
|
-
Conn.on('presence.update', (presenceUpdate) => {
|
|
108
|
-
// console.log('Presence update:', presenceUpdate);
|
|
109
|
-
});
|
|
420
|
+
Auto-delete old session files (midnight cron):
|
|
110
421
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
422
|
+
```javascript
|
|
423
|
+
const conn = new Connection({
|
|
424
|
+
session_dir: './session',
|
|
425
|
+
// Auto-delete old data at midnight
|
|
426
|
+
})
|
|
427
|
+
```
|
|
115
428
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
429
|
+
---
|
|
430
|
+
|
|
431
|
+
## Database
|
|
432
|
+
|
|
433
|
+
The module supports multiple database backends via `Database.create()`:
|
|
434
|
+
|
|
435
|
+
### Supported Drivers
|
|
436
|
+
|
|
437
|
+
| Driver | Connection String |
|
|
438
|
+
|---|---|
|
|
439
|
+
| **MongoDB** | `mongodb://user:pass@host:port/db` |
|
|
440
|
+
| **MySQL** | `mysql://user:pass@host:port/db` |
|
|
441
|
+
| **PostgreSQL** | `postgresql://user:pass@host:port/db` |
|
|
442
|
+
| **SQLite** | File path (e.g. `./database.db`) |
|
|
443
|
+
| **JSON** | File path (e.g. `./database.json`) |
|
|
120
444
|
|
|
121
|
-
|
|
122
|
-
Conn.on('groups.update', (groupInfoUpdate) => {
|
|
123
|
-
console.log('Group info updated:', groupInfoUpdate);
|
|
124
|
-
});
|
|
445
|
+
### Usage
|
|
125
446
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
447
|
+
```javascript
|
|
448
|
+
const { Connection, Database } = require('@znan/wabot')
|
|
449
|
+
|
|
450
|
+
const start = async () => {
|
|
451
|
+
const db = Database.create(process.env.DATABASE_URL, {
|
|
452
|
+
type: 'json', // or 'mongodb', 'mysql', 'postgresql', 'sqlite'
|
|
453
|
+
dir: './db'
|
|
454
|
+
})
|
|
455
|
+
|
|
456
|
+
const conn = new Connection({
|
|
457
|
+
plugins_dir: 'plugins',
|
|
458
|
+
session_dir: db.session || './session',
|
|
459
|
+
})
|
|
460
|
+
|
|
461
|
+
conn.on('connect', async () => {
|
|
462
|
+
global.db = { users: {}, groups: {}, setting: {}, ...(await db.fetch() || {}) }
|
|
463
|
+
await db.save(global.db)
|
|
464
|
+
})
|
|
465
|
+
|
|
466
|
+
// Auto-save every 30 seconds
|
|
467
|
+
setInterval(() => {
|
|
468
|
+
if (global.db) db.save(global.db)
|
|
469
|
+
}, 30000)
|
|
470
|
+
}
|
|
130
471
|
```
|
|
131
472
|
|
|
132
|
-
|
|
473
|
+
---
|
|
474
|
+
|
|
475
|
+
## Migration Guide
|
|
476
|
+
|
|
477
|
+
### From v0.x to v1.x (Baileys v7 LID)
|
|
133
478
|
|
|
134
|
-
|
|
479
|
+
#### Breaking Changes
|
|
480
|
+
|
|
481
|
+
1. **Event name changes**
|
|
482
|
+
|
|
483
|
+
| Old | New | Reason |
|
|
484
|
+
|---|---|---|
|
|
485
|
+
| `group-participants.update` | `group.add` / `.remove` / `.promote` / `.demote` | Split per action |
|
|
486
|
+
| `groups.update` | `group.subject` / `.desc` / `.announce` / `.restrict` / `.memberAddMode` / `.joinApprovalMode` | Split per field |
|
|
487
|
+
| — | `group.request` | New Baileys v7 event |
|
|
488
|
+
| — | `poll` | New — poll decryption added |
|
|
489
|
+
| — | `baileys:<event>` | Raw event forwarding (new) |
|
|
490
|
+
|
|
491
|
+
2. **`getRealJid` is now async**
|
|
492
|
+
|
|
493
|
+
```javascript
|
|
494
|
+
// Old
|
|
495
|
+
const jid = conn.getRealJid(lid)
|
|
496
|
+
|
|
497
|
+
// New
|
|
498
|
+
const jid = await conn.getRealJid(lid)
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
3. **`conn.user.lid`** — may be undefined in v7. Use `conn.user.id` instead.
|
|
502
|
+
|
|
503
|
+
4. **`getUserId`** — no longer returns `lid` field:
|
|
504
|
+
|
|
505
|
+
```javascript
|
|
506
|
+
// Old
|
|
507
|
+
const { jid, lid } = await conn.getUserId('62812...')
|
|
508
|
+
|
|
509
|
+
// New
|
|
510
|
+
const { jid } = await conn.getUserId('62812...')
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
5. **`onWhatsApp`** — no longer returns LID in results. Use `signalRepository.lidMapping.getPNForLID()` for reverse lookups.
|
|
514
|
+
|
|
515
|
+
#### What Changed Internally
|
|
516
|
+
|
|
517
|
+
- Custom XMPP node parsing for LID mapping (`CB:message` listener) removed — Baileys v7 handles this internally via `signalRepository.lidMapping`
|
|
518
|
+
- `lid_map` storage removed — mapping persisted in auth state automatically
|
|
519
|
+
- `lidMap` cache removed — group participant data already includes `phoneNumber`
|
|
520
|
+
- All sender/participant resolution uses Baileys built-in `Alt` fields + `getPNForLID()`
|
|
135
521
|
|
|
136
522
|
---
|
|
137
523
|
|
|
138
|
-
|
|
524
|
+
## Error Handling
|
|
525
|
+
|
|
526
|
+
### Disconnect Reasons
|
|
527
|
+
|
|
528
|
+
The module automatically handles all Baileys disconnect reasons:
|
|
529
|
+
|
|
530
|
+
| Reason | Behavior |
|
|
531
|
+
|---|---|
|
|
532
|
+
| `connectionClosed` | Auto-reconnect |
|
|
533
|
+
| `connectionLost` | Auto-reconnect |
|
|
534
|
+
| `connectionReplaced` | Exit (session active elsewhere) |
|
|
535
|
+
| `timedOut` | Auto-reconnect |
|
|
536
|
+
| `loggedOut` | Clear session, exit |
|
|
537
|
+
| `badSession` | Restore from backup, reconnect |
|
|
538
|
+
| `restartRequired` | Auto-reconnect |
|
|
539
|
+
| `multideviceMismatch` | Clear session, reconnect |
|
|
540
|
+
| `forbidden` (403) | Clear session, exit (banned) |
|
|
541
|
+
|
|
542
|
+
### Custom Error Handling
|
|
543
|
+
|
|
544
|
+
```javascript
|
|
545
|
+
conn.on('error', x => {
|
|
546
|
+
console.error(x.message)
|
|
547
|
+
// Log to file, send notification, etc.
|
|
548
|
+
})
|
|
549
|
+
```
|
|
550
|
+
|
|
551
|
+
### Session Corruption Recovery
|
|
552
|
+
|
|
553
|
+
When `badSession` is detected, the module:
|
|
554
|
+
1. Checks for session backup
|
|
555
|
+
2. Restores from backup if available
|
|
556
|
+
3. Clears corrupted session
|
|
557
|
+
4. Reconnects automatically
|
|
558
|
+
|
|
559
|
+
---
|
|
560
|
+
|
|
561
|
+
## Advanced Examples
|
|
562
|
+
|
|
563
|
+
### AI Bot Reply
|
|
564
|
+
|
|
565
|
+
```javascript
|
|
566
|
+
// Requires AI module integration
|
|
567
|
+
conn.on('import', async x => {
|
|
568
|
+
if (!x.isCommand && !x.m.fromMe) {
|
|
569
|
+
const reply = await generateAIResponse(x.m.text)
|
|
570
|
+
x.m.reply(reply)
|
|
571
|
+
}
|
|
572
|
+
})
|
|
573
|
+
```
|
|
574
|
+
|
|
575
|
+
### Anti-Delete
|
|
576
|
+
|
|
577
|
+
```javascript
|
|
578
|
+
conn.on('message.delete', x => {
|
|
579
|
+
if (x && !x.msg.key.fromMe && !x.msg.isBot) {
|
|
580
|
+
const groupSet = global.db.groups[x.jid]
|
|
581
|
+
if (groupSet?.antidelete) {
|
|
582
|
+
conn.sock.copyNForward(x.jid, x.msg)
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
})
|
|
586
|
+
```
|
|
587
|
+
|
|
588
|
+
### Auto-React to Stories
|
|
589
|
+
|
|
590
|
+
```javascript
|
|
591
|
+
conn.on('stories', x => {
|
|
592
|
+
conn.sock.sendMessage('status@broadcast', {
|
|
593
|
+
react: { text: '👍', key: x.key }
|
|
594
|
+
}, { statusJidList: [x.sender] })
|
|
595
|
+
})
|
|
596
|
+
```
|
|
597
|
+
|
|
598
|
+
### Welcome Card with Canvas
|
|
599
|
+
|
|
600
|
+
```javascript
|
|
601
|
+
conn.on('group.add', async x => {
|
|
602
|
+
const avatar = await conn.sock.profilePictureUrl(x.member, 'image')
|
|
603
|
+
const card = await welcomeCard(avatar, x.member.split('@')[0], x.subject)
|
|
604
|
+
conn.sock.sendFile(x.jid, card, 'welcome.jpg', `Welcome @${x.member.split('@')[0]}!`, null)
|
|
605
|
+
})
|
|
606
|
+
```
|
|
607
|
+
|
|
608
|
+
### AFK Detection via Presence
|
|
609
|
+
|
|
610
|
+
```javascript
|
|
611
|
+
conn.on('presence.update', ({ id, presences }) => {
|
|
612
|
+
for (const [jid, data] of Object.entries(presences)) {
|
|
613
|
+
if (data.lastKnownPresence === 'composing') {
|
|
614
|
+
const groupSet = global.db.groups[id]
|
|
615
|
+
const member = groupSet?.member?.[jid]
|
|
616
|
+
if (member && member.afk > -1) {
|
|
617
|
+
conn.sock.reply(id, `@${jid.split('@')[0]} back from AFK (${member.afkReason})`, null)
|
|
618
|
+
member.afk = -1
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
})
|
|
623
|
+
```
|
|
624
|
+
|
|
625
|
+
### Using Raw Events for Newsletter Tracking
|
|
626
|
+
|
|
627
|
+
```javascript
|
|
628
|
+
conn.on('baileys:newsletter.reaction', data => {
|
|
629
|
+
console.log(`Newsletter ${data.id} got reaction:`, data.reaction)
|
|
630
|
+
})
|
|
631
|
+
|
|
632
|
+
conn.on('baileys:newsletter.view', data => {
|
|
633
|
+
console.log(`Newsletter ${data.id} has ${data.count} views`)
|
|
634
|
+
})
|
|
635
|
+
```
|
|
636
|
+
|
|
637
|
+
---
|
|
638
|
+
|
|
639
|
+
## License
|
|
640
|
+
|
|
641
|
+
MIT
|