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 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
  [![Node.js Version](https://img.shields.io/node/v/baileys-antiban.svg)](https://nodejs.org/)
5
5
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
6
 
7
- Anti-ban middleware for [Baileys](https://github.com/WhiskeySockets/Baileys) — protect your WhatsApp number with human-like messaging patterns.
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
- Requires Node.js ≥16 and Baileys ≥6.0.0.
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
- * Usage:
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
- * Usage:
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 connection events for health monitoring
29
- sock.ev.on('connection.update', (update) => {
30
- if (update.connection === 'close') {
31
- const reason = update.lastDisconnect?.error?.output?.statusCode || 'unknown';
32
- antiban.onDisconnect(reason);
33
- antiban.destroy(); // Clean up all timers
34
- }
35
- if (update.connection === 'open') {
36
- antiban.onReconnect();
37
- }
38
- // Reachout timelock detection
39
- if (update.reachoutTimeLock) {
40
- antiban.timelock.onTimelockUpdate({
41
- isActive: update.reachoutTimeLock.isActive,
42
- timeEnforcementEnds: update.reachoutTimeLock.timeEnforcementEnds,
43
- enforcementType: update.reachoutTimeLock.enforcementType,
44
- });
45
- }
46
- });
47
- // Catch 463 errors from message updates
48
- sock.ev.on('messages.update', (updates) => {
49
- for (const update of updates) {
50
- if (update?.update?.messageStubParameters) {
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
- // Register known chats from incoming messages + handle reply suggestions
59
- sock.ev.on('messages.upsert', ({ messages }) => {
60
- for (const msg of messages || []) {
61
- const jid = msg.key?.remoteJid;
62
- if (!jid)
63
- continue;
64
- // Register known chat
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
- catch (error) {
87
- // Silently fail — auto-reply is best-effort
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
- }, replyDelay);
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.3.0",
4
- "description": "Anti-ban middleware for Baileys — human-like messaging patterns to protect your WhatsApp number",
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.6",
69
+ "ts-jest": "^29.4.9",
59
70
  "tsx": "^4.21.0",
60
71
  "typescript": "^5.0.0"
61
72
  }