baileys-antiban 1.3.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +26 -0
- package/README.md +26 -3
- package/dist/wrapper.d.ts +14 -1
- package/dist/wrapper.js +151 -61
- package/package.json +15 -4
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,32 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.4.0] - 2026-04-18
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- **Transport-agnostic support** — works with both `baileys` and `@oxidezap/baileyrs` (Rust/WASM WhatsApp library)
|
|
12
|
+
- Both transports now listed as optional peer dependencies
|
|
13
|
+
- GitHub Actions CI workflow with dual-transport matrix testing (Node 18.x + 20.x × baileys + baileyrs)
|
|
14
|
+
- New test suite: `tests/transport-agnostic.test.ts` for duck-typed socket validation
|
|
15
|
+
- Updated JSDoc examples showing usage with both transports
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
- `peerDependencies` now includes both `baileys` and `@oxidezap/baileyrs` as optional
|
|
19
|
+
- Package description updated to mention transport-agnostic support
|
|
20
|
+
- Wrapper comments clarify baileyrs timelock behavior (no `reachoutTimeLock` events in v0.0.8 — operates in detection-only mode)
|
|
21
|
+
|
|
22
|
+
### Why
|
|
23
|
+
Positions baileys-antiban as "Switzerland" of WhatsApp anti-ban — works with any Baileys-compatible transport layer. No breaking changes for existing baileys users.
|
|
24
|
+
|
|
25
|
+
## [1.3.1] - 2026-04-16
|
|
26
|
+
|
|
27
|
+
### Changed
|
|
28
|
+
- Refactor wrapper to use Baileys' `ev.process()` API — single batched event handler reduces listener leaks and cleans up the integration surface
|
|
29
|
+
- Graceful fallback to `ev.on()` for older Baileys versions
|
|
30
|
+
|
|
31
|
+
### Why
|
|
32
|
+
Scattered `ev.on()` registrations are a known leak vector. Consolidating into `process()` shrinks the attack surface for listener-lifecycle bugs and future-proofs for backend-agnostic support.
|
|
33
|
+
|
|
8
34
|
## [1.3.0] - 2026-04-16
|
|
9
35
|
|
|
10
36
|
### Added
|
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
[](https://nodejs.org/)
|
|
5
5
|
[](https://opensource.org/licenses/MIT)
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
**Transport-agnostic** anti-ban middleware — protect your WhatsApp number with human-like messaging patterns. Works with both [Baileys](https://github.com/WhiskeySockets/Baileys) and [@oxidezap/baileyrs](https://github.com/oxidezap/baileyrs) (Rust/WASM).
|
|
8
8
|
|
|
9
9
|
## v1.3 New Features
|
|
10
10
|
|
|
@@ -93,20 +93,43 @@ WhatsApp bans numbers that behave like bots. This library makes your Baileys bot
|
|
|
93
93
|
- **Contact graph enforcement** (v1.3) — requires handshakes before bulk/group sends
|
|
94
94
|
- **Circadian rhythm** (v1.3) — realistic time-of-day activity patterns
|
|
95
95
|
|
|
96
|
+
## Supported Transports
|
|
97
|
+
|
|
98
|
+
**v1.4+** is transport-agnostic and works with any Baileys-compatible WhatsApp library:
|
|
99
|
+
|
|
100
|
+
- **[Baileys](https://github.com/WhiskeySockets/Baileys)** (Node.js, JavaScript/TypeScript)
|
|
101
|
+
- **[@oxidezap/baileyrs](https://github.com/oxidezap/baileyrs)** (Rust/WASM, Baileys-compatible API)
|
|
102
|
+
|
|
103
|
+
Both use the same `wrapSocket()` integration. Zero code changes needed.
|
|
104
|
+
|
|
96
105
|
## Installation
|
|
97
106
|
|
|
107
|
+
### With Baileys (Node.js)
|
|
108
|
+
|
|
98
109
|
```bash
|
|
99
|
-
npm install baileys-antiban
|
|
110
|
+
npm install baileys baileys-antiban
|
|
100
111
|
```
|
|
101
112
|
|
|
102
|
-
|
|
113
|
+
### With baileyrs (Rust/WASM)
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
npm install @oxidezap/baileyrs baileys-antiban
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Requires Node.js ≥16.
|
|
103
120
|
|
|
104
121
|
## Quick Start
|
|
105
122
|
|
|
106
123
|
### Option 1: Wrap Your Socket (Easiest)
|
|
107
124
|
|
|
125
|
+
Works with both baileys and baileyrs — same code:
|
|
126
|
+
|
|
108
127
|
```typescript
|
|
128
|
+
// With baileys:
|
|
109
129
|
import makeWASocket from 'baileys';
|
|
130
|
+
// OR with baileyrs:
|
|
131
|
+
// import { makeWASocket } from '@oxidezap/baileyrs';
|
|
132
|
+
|
|
110
133
|
import { wrapSocket } from 'baileys-antiban';
|
|
111
134
|
|
|
112
135
|
const sock = makeWASocket({ /* your config */ });
|
package/dist/wrapper.d.ts
CHANGED
|
@@ -1,18 +1,31 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Socket Wrapper — Drop-in replacement that wraps sendMessage with anti-ban protection
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Works with both baileys and @oxidezap/baileyrs transports.
|
|
5
|
+
*
|
|
6
|
+
* Usage with baileys:
|
|
5
7
|
* import makeWASocket from 'baileys';
|
|
6
8
|
* import { wrapSocket } from 'baileys-antiban';
|
|
7
9
|
*
|
|
8
10
|
* const sock = makeWASocket({ ... });
|
|
9
11
|
* const safeSock = wrapSocket(sock);
|
|
10
12
|
*
|
|
13
|
+
* Usage with baileyrs:
|
|
14
|
+
* import { makeWASocket } from '@oxidezap/baileyrs';
|
|
15
|
+
* import { wrapSocket } from 'baileys-antiban';
|
|
16
|
+
*
|
|
17
|
+
* const sock = makeWASocket({ ... });
|
|
18
|
+
* const safeSock = wrapSocket(sock);
|
|
19
|
+
*
|
|
11
20
|
* // Use safeSock.sendMessage() — automatically rate-limited and monitored
|
|
12
21
|
* await safeSock.sendMessage(jid, { text: 'Hello!' });
|
|
13
22
|
*
|
|
14
23
|
* // Check health anytime
|
|
15
24
|
* console.log(safeSock.antiban.getStats());
|
|
25
|
+
*
|
|
26
|
+
* Note: reachoutTimeLock timelock module silently noops on baileyrs until upstream
|
|
27
|
+
* emits reachoutTimeLock events — confirmed NOT present in baileyrs v0.0.8.
|
|
28
|
+
* Timelock guard will operate in detection-only mode (relies on 463 errors only).
|
|
16
29
|
*/
|
|
17
30
|
import { AntiBan, type AntiBanConfig } from './antiban.js';
|
|
18
31
|
import type { WarmUpState } from './warmup.js';
|
package/dist/wrapper.js
CHANGED
|
@@ -1,18 +1,31 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Socket Wrapper — Drop-in replacement that wraps sendMessage with anti-ban protection
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Works with both baileys and @oxidezap/baileyrs transports.
|
|
5
|
+
*
|
|
6
|
+
* Usage with baileys:
|
|
5
7
|
* import makeWASocket from 'baileys';
|
|
6
8
|
* import { wrapSocket } from 'baileys-antiban';
|
|
7
9
|
*
|
|
8
10
|
* const sock = makeWASocket({ ... });
|
|
9
11
|
* const safeSock = wrapSocket(sock);
|
|
10
12
|
*
|
|
13
|
+
* Usage with baileyrs:
|
|
14
|
+
* import { makeWASocket } from '@oxidezap/baileyrs';
|
|
15
|
+
* import { wrapSocket } from 'baileys-antiban';
|
|
16
|
+
*
|
|
17
|
+
* const sock = makeWASocket({ ... });
|
|
18
|
+
* const safeSock = wrapSocket(sock);
|
|
19
|
+
*
|
|
11
20
|
* // Use safeSock.sendMessage() — automatically rate-limited and monitored
|
|
12
21
|
* await safeSock.sendMessage(jid, { text: 'Hello!' });
|
|
13
22
|
*
|
|
14
23
|
* // Check health anytime
|
|
15
24
|
* console.log(safeSock.antiban.getStats());
|
|
25
|
+
*
|
|
26
|
+
* Note: reachoutTimeLock timelock module silently noops on baileyrs until upstream
|
|
27
|
+
* emits reachoutTimeLock events — confirmed NOT present in baileyrs v0.0.8.
|
|
28
|
+
* Timelock guard will operate in detection-only mode (relies on 463 errors only).
|
|
16
29
|
*/
|
|
17
30
|
import { AntiBan } from './antiban.js';
|
|
18
31
|
/**
|
|
@@ -25,71 +38,148 @@ export function wrapSocket(sock, config, warmUpState, wrapOptions) {
|
|
|
25
38
|
autoRespondToIncoming: false,
|
|
26
39
|
...wrapOptions,
|
|
27
40
|
};
|
|
28
|
-
// Hook into
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
const params = update.update.messageStubParameters;
|
|
52
|
-
if (params.includes(463) || params.includes('463')) {
|
|
53
|
-
antiban.timelock.record463Error();
|
|
41
|
+
// Hook into Baileys events for health monitoring
|
|
42
|
+
// Prefer ev.process() (Baileys ≥ late 2022) for batched event handling
|
|
43
|
+
// Fall back to ev.on() for older versions
|
|
44
|
+
if (typeof sock.ev.process === 'function') {
|
|
45
|
+
sock.ev.process(async (events) => {
|
|
46
|
+
// Handle connection updates
|
|
47
|
+
if (events['connection.update']) {
|
|
48
|
+
const update = events['connection.update'];
|
|
49
|
+
if (update.connection === 'close') {
|
|
50
|
+
const reason = update.lastDisconnect?.error?.output?.statusCode || 'unknown';
|
|
51
|
+
antiban.onDisconnect(reason);
|
|
52
|
+
antiban.destroy(); // Clean up all timers
|
|
53
|
+
}
|
|
54
|
+
if (update.connection === 'open') {
|
|
55
|
+
antiban.onReconnect();
|
|
56
|
+
}
|
|
57
|
+
// Reachout timelock detection
|
|
58
|
+
if (update.reachoutTimeLock) {
|
|
59
|
+
antiban.timelock.onTimelockUpdate({
|
|
60
|
+
isActive: update.reachoutTimeLock.isActive,
|
|
61
|
+
timeEnforcementEnds: update.reachoutTimeLock.timeEnforcementEnds,
|
|
62
|
+
enforcementType: update.reachoutTimeLock.enforcementType,
|
|
63
|
+
});
|
|
54
64
|
}
|
|
55
65
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
antiban.timelock.registerKnownChat(jid);
|
|
66
|
-
// Skip self messages
|
|
67
|
-
const isSelf = msg.key?.fromMe || false;
|
|
68
|
-
if (isSelf)
|
|
69
|
-
continue;
|
|
70
|
-
// Extract message text
|
|
71
|
-
const msgText = msg.message?.conversation ||
|
|
72
|
-
msg.message?.extendedTextMessage?.text ||
|
|
73
|
-
msg.message?.imageMessage?.caption ||
|
|
74
|
-
msg.message?.videoMessage?.caption ||
|
|
75
|
-
'';
|
|
76
|
-
// Handle incoming message (updates reply ratio + contact graph)
|
|
77
|
-
const replySuggestion = antiban.onIncomingMessage(jid, msgText);
|
|
78
|
-
// Auto-respond if enabled and suggested
|
|
79
|
-
if (options.autoRespondToIncoming && replySuggestion.shouldReply && replySuggestion.suggestedText) {
|
|
80
|
-
// Random delay 3-15s
|
|
81
|
-
const replyDelay = Math.floor(Math.random() * 12000) + 3000;
|
|
82
|
-
setTimeout(async () => {
|
|
83
|
-
try {
|
|
84
|
-
await sock.sendMessage(jid, { text: replySuggestion.suggestedText });
|
|
66
|
+
// Catch 463 errors from message updates
|
|
67
|
+
if (events['messages.update']) {
|
|
68
|
+
const updates = events['messages.update'];
|
|
69
|
+
for (const update of updates) {
|
|
70
|
+
if (update?.update?.messageStubParameters) {
|
|
71
|
+
const params = update.update.messageStubParameters;
|
|
72
|
+
if (params.includes(463) || params.includes('463')) {
|
|
73
|
+
antiban.timelock.record463Error();
|
|
74
|
+
}
|
|
85
75
|
}
|
|
86
|
-
|
|
87
|
-
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
// Register known chats from incoming messages + handle reply suggestions
|
|
79
|
+
if (events['messages.upsert']) {
|
|
80
|
+
const { messages } = events['messages.upsert'];
|
|
81
|
+
for (const msg of messages || []) {
|
|
82
|
+
const jid = msg.key?.remoteJid;
|
|
83
|
+
if (!jid)
|
|
84
|
+
continue;
|
|
85
|
+
// Register known chat
|
|
86
|
+
antiban.timelock.registerKnownChat(jid);
|
|
87
|
+
// Skip self messages
|
|
88
|
+
const isSelf = msg.key?.fromMe || false;
|
|
89
|
+
if (isSelf)
|
|
90
|
+
continue;
|
|
91
|
+
// Extract message text
|
|
92
|
+
const msgText = msg.message?.conversation ||
|
|
93
|
+
msg.message?.extendedTextMessage?.text ||
|
|
94
|
+
msg.message?.imageMessage?.caption ||
|
|
95
|
+
msg.message?.videoMessage?.caption ||
|
|
96
|
+
'';
|
|
97
|
+
// Handle incoming message (updates reply ratio + contact graph)
|
|
98
|
+
const replySuggestion = antiban.onIncomingMessage(jid, msgText);
|
|
99
|
+
// Auto-respond if enabled and suggested
|
|
100
|
+
if (options.autoRespondToIncoming && replySuggestion.shouldReply && replySuggestion.suggestedText) {
|
|
101
|
+
// Random delay 3-15s
|
|
102
|
+
const replyDelay = Math.floor(Math.random() * 12000) + 3000;
|
|
103
|
+
setTimeout(async () => {
|
|
104
|
+
try {
|
|
105
|
+
await sock.sendMessage(jid, { text: replySuggestion.suggestedText });
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
// Silently fail — auto-reply is best-effort
|
|
109
|
+
}
|
|
110
|
+
}, replyDelay);
|
|
88
111
|
}
|
|
89
|
-
}
|
|
112
|
+
}
|
|
90
113
|
}
|
|
91
|
-
}
|
|
92
|
-
}
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
// Fallback to ev.on() for older Baileys versions
|
|
118
|
+
sock.ev.on('connection.update', (update) => {
|
|
119
|
+
if (update.connection === 'close') {
|
|
120
|
+
const reason = update.lastDisconnect?.error?.output?.statusCode || 'unknown';
|
|
121
|
+
antiban.onDisconnect(reason);
|
|
122
|
+
antiban.destroy(); // Clean up all timers
|
|
123
|
+
}
|
|
124
|
+
if (update.connection === 'open') {
|
|
125
|
+
antiban.onReconnect();
|
|
126
|
+
}
|
|
127
|
+
// Reachout timelock detection
|
|
128
|
+
if (update.reachoutTimeLock) {
|
|
129
|
+
antiban.timelock.onTimelockUpdate({
|
|
130
|
+
isActive: update.reachoutTimeLock.isActive,
|
|
131
|
+
timeEnforcementEnds: update.reachoutTimeLock.timeEnforcementEnds,
|
|
132
|
+
enforcementType: update.reachoutTimeLock.enforcementType,
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
// Catch 463 errors from message updates
|
|
137
|
+
sock.ev.on('messages.update', (updates) => {
|
|
138
|
+
for (const update of updates) {
|
|
139
|
+
if (update?.update?.messageStubParameters) {
|
|
140
|
+
const params = update.update.messageStubParameters;
|
|
141
|
+
if (params.includes(463) || params.includes('463')) {
|
|
142
|
+
antiban.timelock.record463Error();
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
// Register known chats from incoming messages + handle reply suggestions
|
|
148
|
+
sock.ev.on('messages.upsert', ({ messages }) => {
|
|
149
|
+
for (const msg of messages || []) {
|
|
150
|
+
const jid = msg.key?.remoteJid;
|
|
151
|
+
if (!jid)
|
|
152
|
+
continue;
|
|
153
|
+
// Register known chat
|
|
154
|
+
antiban.timelock.registerKnownChat(jid);
|
|
155
|
+
// Skip self messages
|
|
156
|
+
const isSelf = msg.key?.fromMe || false;
|
|
157
|
+
if (isSelf)
|
|
158
|
+
continue;
|
|
159
|
+
// Extract message text
|
|
160
|
+
const msgText = msg.message?.conversation ||
|
|
161
|
+
msg.message?.extendedTextMessage?.text ||
|
|
162
|
+
msg.message?.imageMessage?.caption ||
|
|
163
|
+
msg.message?.videoMessage?.caption ||
|
|
164
|
+
'';
|
|
165
|
+
// Handle incoming message (updates reply ratio + contact graph)
|
|
166
|
+
const replySuggestion = antiban.onIncomingMessage(jid, msgText);
|
|
167
|
+
// Auto-respond if enabled and suggested
|
|
168
|
+
if (options.autoRespondToIncoming && replySuggestion.shouldReply && replySuggestion.suggestedText) {
|
|
169
|
+
// Random delay 3-15s
|
|
170
|
+
const replyDelay = Math.floor(Math.random() * 12000) + 3000;
|
|
171
|
+
setTimeout(async () => {
|
|
172
|
+
try {
|
|
173
|
+
await sock.sendMessage(jid, { text: replySuggestion.suggestedText });
|
|
174
|
+
}
|
|
175
|
+
catch (error) {
|
|
176
|
+
// Silently fail — auto-reply is best-effort
|
|
177
|
+
}
|
|
178
|
+
}, replyDelay);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
}
|
|
93
183
|
// Create proxy that intercepts sendMessage
|
|
94
184
|
const originalSendMessage = sock.sendMessage.bind(sock);
|
|
95
185
|
const wrappedSendMessage = async (jid, content, options) => {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "baileys-antiban",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.4.0",
|
|
4
|
+
"description": "Transport-agnostic anti-ban middleware for Baileys and baileyrs — human-like messaging patterns to protect your WhatsApp number",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"type": "module",
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
},
|
|
30
30
|
"keywords": [
|
|
31
31
|
"baileys",
|
|
32
|
+
"baileyrs",
|
|
32
33
|
"whatsapp",
|
|
33
34
|
"anti-ban",
|
|
34
35
|
"rate-limit",
|
|
@@ -36,7 +37,8 @@
|
|
|
36
37
|
"whatsapp-bot",
|
|
37
38
|
"bot-protection",
|
|
38
39
|
"whatsapp-api",
|
|
39
|
-
"nodejs"
|
|
40
|
+
"nodejs",
|
|
41
|
+
"transport-agnostic"
|
|
40
42
|
],
|
|
41
43
|
"author": "Kobus Wentzel <kobie@pop.co.za>",
|
|
42
44
|
"license": "MIT",
|
|
@@ -49,13 +51,22 @@
|
|
|
49
51
|
},
|
|
50
52
|
"homepage": "https://github.com/kobie3717/baileys-antiban#readme",
|
|
51
53
|
"peerDependencies": {
|
|
54
|
+
"@oxidezap/baileyrs": ">=0.0.8",
|
|
52
55
|
"baileys": ">=6.0.0"
|
|
53
56
|
},
|
|
57
|
+
"peerDependenciesMeta": {
|
|
58
|
+
"baileys": {
|
|
59
|
+
"optional": true
|
|
60
|
+
},
|
|
61
|
+
"@oxidezap/baileyrs": {
|
|
62
|
+
"optional": true
|
|
63
|
+
}
|
|
64
|
+
},
|
|
54
65
|
"devDependencies": {
|
|
55
66
|
"@types/jest": "^29.5.14",
|
|
56
67
|
"@types/node": "^20.0.0",
|
|
57
68
|
"jest": "^29.7.0",
|
|
58
|
-
"ts-jest": "^29.4.
|
|
69
|
+
"ts-jest": "^29.4.9",
|
|
59
70
|
"tsx": "^4.21.0",
|
|
60
71
|
"typescript": "^5.0.0"
|
|
61
72
|
}
|