@prototypevip/baileys 0.0.5 → 0.0.7

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 (54) hide show
  1. package/lib/AntiBan/antiban.js +922 -0
  2. package/lib/AntiBan/banRecoveryOrchestrator.js +284 -0
  3. package/lib/AntiBan/contactGraph.js +236 -0
  4. package/lib/AntiBan/contentVariator.js +150 -0
  5. package/lib/AntiBan/credsSnapshot.js +121 -0
  6. package/lib/AntiBan/deliveryTracker.js +107 -0
  7. package/lib/AntiBan/deviceFingerprint.js +106 -0
  8. package/lib/AntiBan/fleetEventStore.js +157 -0
  9. package/lib/AntiBan/groupOperationGuard.js +116 -0
  10. package/lib/AntiBan/health.js +207 -0
  11. package/lib/AntiBan/humanEntropy.js +337 -0
  12. package/lib/AntiBan/index.js +77 -0
  13. package/lib/AntiBan/instanceCoordinator.js +175 -0
  14. package/lib/AntiBan/jidCanonicalizer.js +256 -0
  15. package/lib/AntiBan/jidCircuitBreaker.js +186 -0
  16. package/lib/AntiBan/legitimacySignalInjector.js +231 -0
  17. package/lib/AntiBan/lidFirstResolver.js +174 -0
  18. package/lib/AntiBan/lidResolver.js +324 -0
  19. package/lib/AntiBan/messageQueue.js +187 -0
  20. package/lib/AntiBan/messageRecovery.js +283 -0
  21. package/lib/AntiBan/messageTypeRegistry.js +369 -0
  22. package/lib/AntiBan/observability.js +145 -0
  23. package/lib/AntiBan/patch.js +302 -0
  24. package/lib/AntiBan/persist.js +87 -0
  25. package/lib/AntiBan/presenceChoreographer.js +430 -0
  26. package/lib/AntiBan/presets.js +105 -0
  27. package/lib/AntiBan/profiles.js +31 -0
  28. package/lib/AntiBan/proxyRotator.js +306 -0
  29. package/lib/AntiBan/rateLimiter.js +261 -0
  30. package/lib/AntiBan/readReceiptVariance.js +88 -0
  31. package/lib/AntiBan/reconnectThrottle.js +180 -0
  32. package/lib/AntiBan/replyRatio.js +161 -0
  33. package/lib/AntiBan/reputationVoucher.js +373 -0
  34. package/lib/AntiBan/retryReason.js +91 -0
  35. package/lib/AntiBan/retryTracker.js +172 -0
  36. package/lib/AntiBan/scheduler.js +111 -0
  37. package/lib/AntiBan/sessionFingerprint.js +248 -0
  38. package/lib/AntiBan/sessionStability.js +330 -0
  39. package/lib/AntiBan/stateAdapter.js +73 -0
  40. package/lib/AntiBan/stateExport.js +152 -0
  41. package/lib/AntiBan/stealthConnect.js +130 -0
  42. package/lib/AntiBan/timelockGuard.js +181 -0
  43. package/lib/AntiBan/topologyThrottler.js +339 -0
  44. package/lib/AntiBan/warmup.js +140 -0
  45. package/lib/AntiBan/webhooks.js +80 -0
  46. package/lib/AntiBan/wrapper.js +456 -0
  47. package/lib/Socket/chats.js +29 -4
  48. package/lib/Socket/groups.js +7 -2
  49. package/lib/Socket/index.js +68 -3
  50. package/lib/Socket/messages-send.js +44 -8
  51. package/lib/Socket/socket.js +2 -2
  52. package/lib/Store/prototype-store.js +10 -39
  53. package/lib/index.js +5 -0
  54. package/package.json +7 -3
@@ -0,0 +1,207 @@
1
+ /**
2
+ * Health Monitor — Detect ban warning signs early
3
+ *
4
+ * Tracks connection patterns to identify when WhatsApp is
5
+ * getting suspicious. Gives you time to back off before a ban.
6
+ *
7
+ * Warning signs:
8
+ * - Frequent disconnections (connection.update → close)
9
+ * - 403 Forbidden errors
10
+ * - 401 Logged Out (possible temp ban)
11
+ * - Messages failing silently (sent but not delivered)
12
+ * - QR re-request loops
13
+ * - Rate limit responses (429-like behavior)
14
+ */
15
+ const DEFAULT_CONFIG = {
16
+ disconnectWarningThreshold: 3,
17
+ disconnectCriticalThreshold: 5,
18
+ failedMessageThreshold: 5,
19
+ autoPauseAt: 'high',
20
+ };
21
+ export class HealthMonitor {
22
+ config;
23
+ events = [];
24
+ startTime = Date.now();
25
+ paused = false;
26
+ lastRisk = 'low';
27
+ lastBadEventTime = Date.now();
28
+ lastEventWasSevere = false;
29
+ constructor(config = {}) {
30
+ this.config = { ...DEFAULT_CONFIG, ...config };
31
+ }
32
+ /**
33
+ * Record a disconnection event
34
+ */
35
+ recordDisconnect(reason) {
36
+ const reasonStr = String(reason);
37
+ if (reasonStr === '403' || reasonStr === 'forbidden') {
38
+ this.events.push({ type: 'forbidden', timestamp: Date.now(), detail: reasonStr });
39
+ this.lastBadEventTime = Date.now();
40
+ this.lastEventWasSevere = true;
41
+ }
42
+ else if (reasonStr === '401' || reasonStr === 'loggedOut') {
43
+ this.events.push({ type: 'loggedOut', timestamp: Date.now(), detail: reasonStr });
44
+ this.lastBadEventTime = Date.now();
45
+ this.lastEventWasSevere = true;
46
+ }
47
+ else {
48
+ this.events.push({ type: 'disconnect', timestamp: Date.now(), detail: reasonStr });
49
+ this.lastBadEventTime = Date.now();
50
+ this.lastEventWasSevere = false;
51
+ }
52
+ this.checkAndNotify();
53
+ }
54
+ /**
55
+ * Record a successful reconnection
56
+ */
57
+ recordReconnect() {
58
+ this.events.push({ type: 'reconnect', timestamp: Date.now() });
59
+ }
60
+ /**
61
+ * Record a failed message send
62
+ */
63
+ recordMessageFailed(error) {
64
+ this.events.push({ type: 'messageFailed', timestamp: Date.now(), detail: error });
65
+ this.lastBadEventTime = Date.now();
66
+ this.lastEventWasSevere = false;
67
+ this.checkAndNotify();
68
+ }
69
+ /**
70
+ * Record a 463 reachout timelock error
71
+ */
72
+ recordReachoutTimelock(detail) {
73
+ this.events.push({ type: 'reachoutTimelocked', timestamp: Date.now(), detail });
74
+ this.lastBadEventTime = Date.now();
75
+ this.lastEventWasSevere = false;
76
+ this.checkAndNotify();
77
+ }
78
+ /**
79
+ * Get current health status
80
+ */
81
+ getStatus() {
82
+ const now = Date.now();
83
+ this.cleanup(now);
84
+ const hourEvents = this.events.filter(e => now - e.timestamp < 3600000);
85
+ const disconnects = hourEvents.filter(e => e.type === 'disconnect').length;
86
+ const forbidden = hourEvents.filter(e => e.type === 'forbidden').length;
87
+ const loggedOut = hourEvents.filter(e => e.type === 'loggedOut').length;
88
+ const failedMessages = hourEvents.filter(e => e.type === 'messageFailed').length;
89
+ let score = 0;
90
+ const reasons = [];
91
+ // Forbidden errors are serious
92
+ if (forbidden > 0) {
93
+ score += 40 * forbidden;
94
+ reasons.push(`${forbidden} forbidden (403) error${forbidden > 1 ? 's' : ''} in last hour`);
95
+ }
96
+ // Logged out is very serious
97
+ if (loggedOut > 0) {
98
+ score += 60;
99
+ reasons.push('Logged out by WhatsApp — possible temporary ban');
100
+ }
101
+ // Reachout timelocked (463)
102
+ const timelocked = hourEvents.filter(e => e.type === 'reachoutTimelocked').length;
103
+ if (timelocked > 0) {
104
+ score += 25;
105
+ reasons.push(`${timelocked} reachout timelock (463) error${timelocked > 1 ? 's' : ''} in last hour`);
106
+ }
107
+ // Frequent disconnects
108
+ if (disconnects >= this.config.disconnectCriticalThreshold) {
109
+ score += 30;
110
+ reasons.push(`${disconnects} disconnects in last hour (critical threshold)`);
111
+ }
112
+ else if (disconnects >= this.config.disconnectWarningThreshold) {
113
+ score += 30;
114
+ reasons.push(`${disconnects} disconnects in last hour`);
115
+ }
116
+ // Failed messages
117
+ if (failedMessages >= this.config.failedMessageThreshold) {
118
+ score += 20;
119
+ reasons.push(`${failedMessages} failed messages in last hour`);
120
+ }
121
+ // Determine risk level
122
+ score = Math.min(100, score);
123
+ // Tiered decay: recover based on time since last bad event
124
+ // Severe (403/401): 2pts/min — ~50min to clear 100pts
125
+ // Normal: 5pts/min — ~20min to clear 100pts
126
+ const minutesSinceLastBad = (now - this.lastBadEventTime) / 60000;
127
+ const decayRate = this.lastEventWasSevere ? 2 : 5;
128
+ score = Math.max(0, score - Math.floor(minutesSinceLastBad * decayRate));
129
+ let risk;
130
+ if (score >= 80)
131
+ risk = 'critical';
132
+ else if (score >= 40)
133
+ risk = 'high';
134
+ else if (score >= 15)
135
+ risk = 'medium';
136
+ else
137
+ risk = 'low';
138
+ // Determine recommendation
139
+ let recommendation;
140
+ switch (risk) {
141
+ case 'critical':
142
+ recommendation = 'STOP ALL MESSAGING IMMEDIATELY. Disconnect and wait 24-48 hours before reconnecting.';
143
+ break;
144
+ case 'high':
145
+ recommendation = 'Reduce messaging rate by 80%. Consider pausing for 1-2 hours.';
146
+ break;
147
+ case 'medium':
148
+ recommendation = 'Reduce messaging rate by 50%. Increase delays between messages.';
149
+ break;
150
+ default:
151
+ recommendation = 'Operating normally. Continue monitoring.';
152
+ }
153
+ const lastDisconnect = [...this.events].reverse().find(e => e.type === 'disconnect' || e.type === 'forbidden' || e.type === 'loggedOut');
154
+ return {
155
+ risk,
156
+ score,
157
+ reasons: reasons.length ? reasons : ['No issues detected'],
158
+ recommendation,
159
+ stats: {
160
+ disconnectsLastHour: disconnects,
161
+ failedMessagesLastHour: failedMessages,
162
+ forbiddenErrors: forbidden,
163
+ timelockErrors: timelocked,
164
+ uptimeMs: now - this.startTime,
165
+ lastDisconnectReason: lastDisconnect?.detail,
166
+ },
167
+ };
168
+ }
169
+ /**
170
+ * Check if sending should be paused
171
+ */
172
+ isPaused() {
173
+ if (this.paused)
174
+ return true;
175
+ const status = this.getStatus();
176
+ const riskOrder = ['low', 'medium', 'high', 'critical'];
177
+ return riskOrder.indexOf(status.risk) >= riskOrder.indexOf(this.config.autoPauseAt);
178
+ }
179
+ /**
180
+ * Manually pause/resume
181
+ */
182
+ setPaused(paused) {
183
+ this.paused = paused;
184
+ }
185
+ /**
186
+ * Reset all tracked events
187
+ */
188
+ reset() {
189
+ this.events = [];
190
+ this.startTime = Date.now();
191
+ this.paused = false;
192
+ this.lastRisk = 'low';
193
+ this.lastBadEventTime = Date.now();
194
+ this.lastEventWasSevere = false;
195
+ }
196
+ cleanup(now) {
197
+ // Keep last 6 hours of events
198
+ this.events = this.events.filter(e => now - e.timestamp < 21600000);
199
+ }
200
+ checkAndNotify() {
201
+ const status = this.getStatus();
202
+ if (status.risk !== this.lastRisk) {
203
+ this.lastRisk = status.risk;
204
+ this.config.onRiskChange?.(status);
205
+ }
206
+ }
207
+ }
@@ -0,0 +1,337 @@
1
+ /**
2
+ * HumanEntropyService — Background noise for WA sessions
3
+ *
4
+ * Runs periodic human-like actions to make idle sessions appear more realistic:
5
+ * - Random typing presence to recent contacts
6
+ * - Delayed read receipts
7
+ * - Availability status toggles
8
+ *
9
+ * Design:
10
+ * - Works ONLY with WaSP's public API (no direct socket access)
11
+ * - Fail-silent (never crashes wa-pa)
12
+ * - Configurable intervals and probabilities
13
+ * - Only interacts with contacts who messaged first (never strangers)
14
+ */
15
+ const DEFAULT_CONFIG = {
16
+ enabled: true,
17
+ minIntervalMs: 2 * 60 * 60 * 1000, // 2 hours
18
+ maxIntervalMs: 6 * 60 * 60 * 1000, // 6 hours
19
+ maxRecentContacts: 30,
20
+ typingProbability: 0.3,
21
+ typingMinMs: 3000,
22
+ typingMaxMs: 8000,
23
+ readReceiptProbability: 0.2,
24
+ readReceiptMinDelayMs: 10 * 60 * 1000, // 10 min
25
+ readReceiptMaxDelayMs: 60 * 60 * 1000, // 60 min
26
+ presenceToggleProbability: 0.15,
27
+ presenceToggleMinMs: 30 * 1000, // 30 sec
28
+ presenceToggleMaxMs: 2 * 60 * 1000, // 2 min
29
+ };
30
+ /**
31
+ * Human entropy service
32
+ *
33
+ * Adds realistic background noise to WhatsApp sessions by performing
34
+ * random human-like actions periodically.
35
+ */
36
+ export class HumanEntropyService {
37
+ config;
38
+ wasp; // WaSP instance
39
+ sessionId;
40
+ recentContacts = [];
41
+ unreadMessages = [];
42
+ cycleTimer = null;
43
+ isRunning = false;
44
+ stats = {
45
+ cyclesExecuted: 0,
46
+ typingActionsPerformed: 0,
47
+ readReceiptsMarked: 0,
48
+ presenceToggles: 0,
49
+ errors: 0,
50
+ lastCycleAt: null,
51
+ nextCycleAt: null,
52
+ };
53
+ constructor(wasp, sessionId, config = {}) {
54
+ this.wasp = wasp;
55
+ this.sessionId = sessionId;
56
+ this.config = { ...DEFAULT_CONFIG, ...config };
57
+ // Listen to MESSAGE_RECEIVED events to track recent contacts
58
+ this.wasp.on('MESSAGE_RECEIVED', (event) => {
59
+ if (event.sessionId === this.sessionId) {
60
+ this.trackIncomingMessage(event.data);
61
+ }
62
+ });
63
+ this.log('info', 'HumanEntropyService initialized', {
64
+ enabled: this.config.enabled,
65
+ minInterval: this.config.minIntervalMs,
66
+ maxInterval: this.config.maxIntervalMs,
67
+ });
68
+ }
69
+ /**
70
+ * Start the entropy service
71
+ */
72
+ start() {
73
+ if (!this.config.enabled) {
74
+ this.log('info', 'Entropy service disabled, not starting');
75
+ return;
76
+ }
77
+ if (this.isRunning) {
78
+ this.log('warn', 'Entropy service already running');
79
+ return;
80
+ }
81
+ this.isRunning = true;
82
+ this.scheduleNextCycle();
83
+ this.log('info', 'Entropy service started');
84
+ }
85
+ /**
86
+ * Stop the entropy service
87
+ */
88
+ stop() {
89
+ this.isRunning = false;
90
+ if (this.cycleTimer) {
91
+ clearTimeout(this.cycleTimer);
92
+ this.cycleTimer = null;
93
+ }
94
+ this.stats.nextCycleAt = null;
95
+ this.log('info', 'Entropy service stopped');
96
+ }
97
+ /**
98
+ * Get current statistics
99
+ */
100
+ getStats() {
101
+ return { ...this.stats };
102
+ }
103
+ /**
104
+ * Track incoming message to build recent contacts list
105
+ */
106
+ trackIncomingMessage(message) {
107
+ try {
108
+ // Skip outgoing messages
109
+ if (message.fromMe)
110
+ return;
111
+ const jid = message.from || message.chatId;
112
+ if (!jid)
113
+ return;
114
+ // Update or add to recent contacts
115
+ const existingIndex = this.recentContacts.findIndex(c => c.jid === jid);
116
+ if (existingIndex >= 0) {
117
+ this.recentContacts[existingIndex].lastMessageAt = new Date();
118
+ }
119
+ else {
120
+ this.recentContacts.push({
121
+ jid,
122
+ lastMessageAt: new Date(),
123
+ isGroup: message.isGroup ?? false,
124
+ });
125
+ }
126
+ // Trim to max size (keep most recent)
127
+ if (this.recentContacts.length > this.config.maxRecentContacts) {
128
+ this.recentContacts.sort((a, b) => b.lastMessageAt.getTime() - a.lastMessageAt.getTime());
129
+ this.recentContacts = this.recentContacts.slice(0, this.config.maxRecentContacts);
130
+ }
131
+ // Track for potential read receipt
132
+ if (message.id && message.key) {
133
+ this.unreadMessages.push({
134
+ jid,
135
+ messageKey: message.key,
136
+ receivedAt: new Date(),
137
+ });
138
+ // Trim old unread messages (keep last 50)
139
+ if (this.unreadMessages.length > 50) {
140
+ this.unreadMessages = this.unreadMessages.slice(-50);
141
+ }
142
+ }
143
+ }
144
+ catch (error) {
145
+ this.log('error', 'Error tracking incoming message', { error: error.message });
146
+ }
147
+ }
148
+ /**
149
+ * Schedule next entropy cycle
150
+ */
151
+ scheduleNextCycle() {
152
+ if (!this.isRunning)
153
+ return;
154
+ const delay = this.randomBetween(this.config.minIntervalMs, this.config.maxIntervalMs);
155
+ this.stats.nextCycleAt = new Date(Date.now() + delay);
156
+ this.cycleTimer = setTimeout(() => {
157
+ this.executeCycle().catch(error => {
158
+ this.log('error', 'Entropy cycle failed', { error: error.message });
159
+ this.stats.errors++;
160
+ }).finally(() => {
161
+ this.scheduleNextCycle();
162
+ });
163
+ }, delay);
164
+ this.log('debug', `Next entropy cycle in ${Math.floor(delay / 1000)}s`);
165
+ }
166
+ /**
167
+ * Execute one entropy cycle
168
+ */
169
+ async executeCycle() {
170
+ if (!this.isRunning || this.recentContacts.length === 0) {
171
+ return;
172
+ }
173
+ this.log('info', 'Starting entropy cycle', {
174
+ recentContactsCount: this.recentContacts.length,
175
+ unreadMessagesCount: this.unreadMessages.length,
176
+ });
177
+ this.stats.cyclesExecuted++;
178
+ this.stats.lastCycleAt = new Date();
179
+ const actions = [];
180
+ // Action 1: Random typing presence
181
+ if (Math.random() < this.config.typingProbability) {
182
+ actions.push(this.performTypingPresence());
183
+ }
184
+ // Action 2: Mark random message as read
185
+ if (Math.random() < this.config.readReceiptProbability && this.unreadMessages.length > 0) {
186
+ actions.push(this.performReadReceipt());
187
+ }
188
+ // Action 3: Toggle presence status
189
+ if (Math.random() < this.config.presenceToggleProbability) {
190
+ actions.push(this.performPresenceToggle());
191
+ }
192
+ // Execute all actions in parallel
193
+ await Promise.allSettled(actions);
194
+ }
195
+ /**
196
+ * Send typing presence to a random recent contact
197
+ */
198
+ async performTypingPresence() {
199
+ try {
200
+ // Pick a random non-group contact
201
+ const eligibleContacts = this.recentContacts.filter(c => !c.isGroup);
202
+ if (eligibleContacts.length === 0) {
203
+ this.log('debug', 'No eligible contacts for typing presence');
204
+ return;
205
+ }
206
+ const contact = eligibleContacts[Math.floor(Math.random() * eligibleContacts.length)];
207
+ const duration = this.randomBetween(this.config.typingMinMs, this.config.typingMaxMs);
208
+ this.log('info', `Entropy action: typing to ${this.maskJid(contact.jid)} for ${duration}ms`);
209
+ // Get provider to access socket
210
+ const provider = this.wasp.getProvider(this.sessionId);
211
+ if (!provider || !provider.socket) {
212
+ throw new Error('Provider or socket not available');
213
+ }
214
+ // Send composing presence
215
+ await provider.socket.sendPresenceUpdate('composing', contact.jid);
216
+ // Wait for duration
217
+ await this.sleep(duration);
218
+ // Send paused presence
219
+ await provider.socket.sendPresenceUpdate('paused', contact.jid);
220
+ this.stats.typingActionsPerformed++;
221
+ }
222
+ catch (error) {
223
+ this.log('error', 'Error performing typing presence', { error: error.message });
224
+ this.stats.errors++;
225
+ }
226
+ }
227
+ /**
228
+ * Mark a random recent message as read with delay
229
+ */
230
+ async performReadReceipt() {
231
+ try {
232
+ const message = this.unreadMessages[Math.floor(Math.random() * this.unreadMessages.length)];
233
+ if (!message)
234
+ return;
235
+ const delay = this.randomBetween(this.config.readReceiptMinDelayMs, this.config.readReceiptMaxDelayMs);
236
+ this.log('info', `Entropy action: mark read ${this.maskJid(message.jid)} after ${Math.floor(delay / 1000)}s`);
237
+ // Wait for delay
238
+ await this.sleep(delay);
239
+ // Get provider to access socket
240
+ const provider = this.wasp.getProvider(this.sessionId);
241
+ if (!provider || !provider.socket) {
242
+ throw new Error('Provider or socket not available');
243
+ }
244
+ // Mark as read
245
+ await provider.socket.readMessages([message.messageKey]);
246
+ // Remove from unread list
247
+ this.unreadMessages = this.unreadMessages.filter(m => m !== message);
248
+ this.stats.readReceiptsMarked++;
249
+ }
250
+ catch (error) {
251
+ this.log('error', 'Error performing read receipt', { error: error.message });
252
+ this.stats.errors++;
253
+ }
254
+ }
255
+ /**
256
+ * Toggle presence status (available → unavailable)
257
+ */
258
+ async performPresenceToggle() {
259
+ try {
260
+ const duration = this.randomBetween(this.config.presenceToggleMinMs, this.config.presenceToggleMaxMs);
261
+ this.log('info', `Entropy action: presence toggle for ${Math.floor(duration / 1000)}s`);
262
+ // Get provider to access socket
263
+ const provider = this.wasp.getProvider(this.sessionId);
264
+ if (!provider || !provider.socket) {
265
+ throw new Error('Provider or socket not available');
266
+ }
267
+ // Set available
268
+ await provider.socket.sendPresenceUpdate('available');
269
+ // Wait for duration
270
+ await this.sleep(duration);
271
+ // Set unavailable
272
+ await provider.socket.sendPresenceUpdate('unavailable');
273
+ this.stats.presenceToggles++;
274
+ }
275
+ catch (error) {
276
+ this.log('error', 'Error performing presence toggle', { error: error.message });
277
+ this.stats.errors++;
278
+ }
279
+ }
280
+ /**
281
+ * Random value between min and max (inclusive)
282
+ */
283
+ randomBetween(min, max) {
284
+ return Math.floor(Math.random() * (max - min + 1)) + min;
285
+ }
286
+ /**
287
+ * Sleep for specified milliseconds
288
+ */
289
+ sleep(ms) {
290
+ return new Promise(resolve => setTimeout(resolve, ms));
291
+ }
292
+ /**
293
+ * Mask JID for logging (privacy)
294
+ */
295
+ maskJid(jid) {
296
+ if (jid.length < 8)
297
+ return '***';
298
+ return jid.substring(0, 4) + '***' + jid.substring(jid.length - 4);
299
+ }
300
+ /**
301
+ * Log message
302
+ */
303
+ log(level, message, meta) {
304
+ const prefix = '[entropy]';
305
+ const logData = meta ? `${message} ${JSON.stringify(meta)}` : message;
306
+ switch (level) {
307
+ case 'info':
308
+ console.log(`${prefix} ${logData}`);
309
+ break;
310
+ case 'warn':
311
+ console.warn(`${prefix} ${logData}`);
312
+ break;
313
+ case 'error':
314
+ console.error(`${prefix} ${logData}`);
315
+ break;
316
+ case 'debug':
317
+ // Skip debug logs in production
318
+ break;
319
+ }
320
+ }
321
+ }
322
+ /**
323
+ * Factory function to create HumanEntropyService
324
+ *
325
+ * @param wasp WaSP instance
326
+ * @param sessionId Session ID
327
+ * @param config Optional configuration
328
+ * @returns HumanEntropyService instance with start() and stop() methods
329
+ */
330
+ export function createHumanEntropyService(wasp, sessionId, config) {
331
+ const service = new HumanEntropyService(wasp, sessionId, config);
332
+ return {
333
+ start: () => service.start(),
334
+ stop: () => service.stop(),
335
+ getStats: () => service.getStats(),
336
+ };
337
+ }
@@ -0,0 +1,77 @@
1
+ /**
2
+ * baileys-antiban — Anti-ban middleware for Baileys
3
+ *
4
+ * Wraps a Baileys socket with human-like messaging patterns
5
+ * to minimize the risk of WhatsApp banning your number.
6
+ *
7
+ * @author Kobus Wentzel <kobie@pop.co.za>
8
+ * @license MIT
9
+ */
10
+ // Core
11
+ export { AntiBan } from './antiban.js';
12
+ export { RateLimiter } from './rateLimiter.js';
13
+ export { WarmUp } from './warmup.js';
14
+ export { HealthMonitor } from './health.js';
15
+ export { TimelockGuard } from './timelockGuard.js';
16
+ // v1.3 new modules
17
+ export { ReplyRatioGuard } from './replyRatio.js';
18
+ export { ContactGraphWarmer } from './contactGraph.js';
19
+ export { PresenceChoreographer, getCircadianMultiplier, } from './presenceChoreographer.js';
20
+ // v1.5 new modules
21
+ export { RetryReasonTracker } from './retryTracker.js';
22
+ export { PostReconnectThrottle } from './reconnectThrottle.js';
23
+ // v1.6 new modules
24
+ export { LidResolver } from './lidResolver.js';
25
+ export { JidCanonicalizer } from './jidCanonicalizer.js';
26
+ // v2.0 new modules
27
+ export { SessionHealthMonitor, wrapWithSessionStability, classifyDisconnect, DeafSessionDetector, } from './sessionStability.js';
28
+ // v2.1 new modules
29
+ export { LidFirstResolver, createLidFirstResolver, } from './lidFirstResolver.js';
30
+ export { MessageRetryReason, MAC_ERROR_CODES, parseRetryReason, isMacError, getRetryReasonDescription, } from './retryReason.js';
31
+ // Socket wrapper
32
+ export { wrapSocket, wrapSocketWithFingerprint } from './wrapper.js';
33
+ // Optional features
34
+ export { MessageQueue } from './messageQueue.js';
35
+ export { ContentVariator } from './contentVariator.js';
36
+ export { WebhookAlerts } from './webhooks.js';
37
+ export { Scheduler } from './scheduler.js';
38
+ // State persistence
39
+ export { FileStateAdapter } from './stateAdapter.js';
40
+ // v3.0 new modules
41
+ export { resolveConfig, PRESETS } from './presets.js';
42
+ export { StateManager } from './persist.js';
43
+ export { isGroup, isNewsletter, isBroadcast, shouldUseGroupProfile, applyGroupMultiplier } from './profiles.js';
44
+ // v3.1 new modules
45
+ export { messageRecovery } from './messageRecovery.js';
46
+ // v3.2 new modules
47
+ export { generateFingerprint, applyFingerprint, } from './deviceFingerprint.js';
48
+ export { credsSnapshot, } from './credsSnapshot.js';
49
+ export { readReceiptVariance, } from './readReceiptVariance.js';
50
+ // v3.5 new modules
51
+ export { proxyRotator, } from './proxyRotator.js';
52
+ // v3.6 new modules (Obscura-inspired)
53
+ export { generateSessionFingerprint, applySessionFingerprint, getMessageSendJitter, getTypingJitter, getRetryJitter, getVoiceNoteMetadata, getBatteryState, createStealthFingerprint, } from './sessionFingerprint.js';
54
+ // v3.8 new modules
55
+ export { getStealthSocketConfig, rampPresenceAfterConnect, STEALTH_BROWSER_POOL, AbortError, } from './stealthConnect.js';
56
+ // v4.0 new modules
57
+ export { GroupOperationGuard, classifyGroupOpError, extractPrivacyBlock, GROUP_OP_ERRORS, } from './groupOperationGuard.js';
58
+ // v4.1 new modules
59
+ export { LegitimacySignalInjector, } from './legitimacySignalInjector.js';
60
+ // v4.2 new modules
61
+ export { BanRecoveryOrchestrator, } from './banRecoveryOrchestrator.js';
62
+ // v4.3 new modules
63
+ export { DeliveryTracker } from './deliveryTracker.js';
64
+ // v4.4 new modules
65
+ export { InstanceCoordinator } from './instanceCoordinator.js';
66
+ // v4.7 new modules
67
+ export { JidCircuitBreaker, createJidCircuitBreaker } from './jidCircuitBreaker.js';
68
+ export { createFleetEventStore, createMySQLEventStoreBackend, createInMemoryEventStoreBackend } from './fleetEventStore.js';
69
+ export { HumanEntropyService, createHumanEntropyService } from './humanEntropy.js';
70
+ // v4.8 new modules
71
+ export { MessageTypeRegistry } from './messageTypeRegistry.js';
72
+ export { exportAntibanState, importAntibanState } from './stateExport.js';
73
+ export { TopologyThrottler } from './topologyThrottler.js';
74
+ // v4.9 new modules
75
+ export { ReputationVoucher } from './reputationVoucher.js';
76
+ // Observability
77
+ export { createConsoleLogger, exportPrometheusMetrics, createMetricsHandler, createPeriodicExporter, } from './observability.js';