@badzz88/baileys 8.5.3 → 8.5.4
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/README.md +1 -1
- package/WAProto/WAProto.proto +1256 -75
- package/WAProto/index.d.ts +36042 -19649
- package/WAProto/index.js +181990 -135645
- package/engine-requirements.js +7 -15
- package/lib/Defaults/index.js +22 -17
- package/lib/Signal/Group/group_cipher.js +5 -5
- package/lib/Signal/Group/keyhelper.js +4 -4
- package/lib/Signal/Group/sender-chain-key.js +2 -2
- package/lib/Signal/Group/sender-key-distribution-message.js +1 -1
- package/lib/Signal/Group/sender-key-message.js +3 -3
- package/lib/Signal/Group/sender-key-record.js +1 -1
- package/lib/Signal/Group/sender-message-key.js +5 -5
- package/lib/Signal/libsignal.js +39 -59
- package/lib/Signal/lid-mapping.js +28 -10
- package/lib/Socket/aigroups.js +5 -5
- package/lib/Socket/business.js +3 -11
- package/lib/Socket/chats.js +668 -319
- package/lib/Socket/communities.js +85 -89
- package/lib/Socket/graphql.js +435 -228
- package/lib/Socket/groups.js +132 -211
- package/lib/Socket/index.js +9 -7
- package/lib/Socket/interactive-handler.js +117 -60
- package/lib/Socket/interop.js +56 -175
- package/lib/Socket/managed-account.js +79 -48
- package/lib/Socket/messages-recv.js +898 -340
- package/lib/Socket/messages-send.js +462 -160
- package/lib/Socket/mex.js +40 -53
- package/lib/Socket/newsletter.js +291 -295
- package/lib/Socket/privacy.js +77 -265
- package/lib/Socket/registration.js +164 -157
- package/lib/Socket/socket.js +181 -199
- package/lib/Socket/username.js +144 -227
- package/lib/Store/make-cache-manager-store.js +2 -2
- package/lib/Store/make-in-memory-store.js +25 -141
- package/lib/Types/Auth.js +3 -3
- package/lib/Types/Label.js +1 -1
- package/lib/Types/LabelAssociation.js +1 -1
- package/lib/Types/Newsletter.js +96 -65
- package/lib/Types/State.js +4 -4
- package/lib/Types/index.js +1 -1
- package/lib/Utils/auth-utils.js +52 -57
- package/lib/Utils/browser-utils.js +1 -1
- package/lib/Utils/business.js +2 -6
- package/lib/Utils/chat-utils.js +102 -38
- package/lib/Utils/crypto.js +54 -84
- package/lib/Utils/decode-wa-message.js +316 -83
- package/lib/Utils/event-buffer.js +37 -61
- package/lib/Utils/generics.js +157 -103
- package/lib/Utils/group-history.js +3 -12
- package/lib/Utils/history.js +15 -15
- package/lib/Utils/index.js +1 -5
- package/lib/Utils/link-preview.js +3 -8
- package/lib/Utils/lt-hash.js +2 -35
- package/lib/Utils/make-mutex.js +1 -1
- package/lib/Utils/message-inspect.js +393 -0
- package/lib/Utils/message-retry-manager.js +27 -92
- package/lib/Utils/messages-media.js +159 -130
- package/lib/Utils/messages.js +144 -566
- package/lib/Utils/meta-ai-msmsg.js +62 -202
- package/lib/Utils/noise-handler.js +19 -21
- package/lib/Utils/offline-node-processor.js +3 -8
- package/lib/Utils/pre-key-manager.js +13 -23
- package/lib/Utils/process-message.js +197 -106
- package/lib/Utils/reporting-utils.js +2 -2
- package/lib/Utils/signal.js +28 -63
- package/lib/Utils/stanza-ack.js +39 -12
- package/lib/Utils/sync-action-utils.js +4 -7
- package/lib/Utils/tc-token-utils.js +20 -25
- package/lib/Utils/use-multi-file-auth-state.js +30 -14
- package/lib/Utils/validate-connection.js +59 -19
- package/lib/WABinary/decode.js +50 -16
- package/lib/WABinary/encode.js +54 -224
- package/lib/WABinary/generic-utils.js +7 -97
- package/lib/WABinary/jid-utils.js +27 -14
- package/lib/WAM/encode.js +7 -7
- package/lib/WAUSync/Protocols/USyncBusinessProtocol.js +58 -1
- package/lib/WAUSync/Protocols/USyncContactProtocol.js +7 -1
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +13 -5
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +1 -4
- package/lib/WAUSync/Protocols/USyncFeatureProtocol.js +20 -7
- package/lib/WAUSync/Protocols/USyncNewsletterProtocol.js +865 -0
- package/lib/WAUSync/Protocols/USyncPictureProtocol.js +1 -1
- package/lib/WAUSync/Protocols/USyncSidelistProtocol.js +2 -2
- package/lib/WAUSync/Protocols/USyncStatusProtocol.js +7 -2
- package/lib/WAUSync/Protocols/USyncTextStatusProtocol.js +1 -1
- package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +2 -1
- package/lib/WAUSync/Protocols/index.js +1 -0
- package/lib/WAUSync/USyncBackoff.js +26 -0
- package/lib/WAUSync/USyncQuery.js +77 -6
- package/lib/WAUSync/USyncUser.js +16 -8
- package/lib/WAUSync/index.js +1 -0
- package/lib/antiban.js +608 -854
- package/lib/index.js +1 -1
- package/package.json +16 -20
- package/lib/Socket/luxu.js +0 -387
- package/lib/Socket/text-router.js +0 -83
- package/lib/Store/keyed-db.js +0 -108
- package/lib/Types/Mex.js +0 -112
- package/lib/Utils/command-loader.d.ts +0 -31
- package/lib/Utils/command-loader.js +0 -100
- package/lib/Utils/companion-reg-client-utils.js +0 -42
- package/lib/Utils/curve25519-js.js +0 -275
- package/lib/Utils/native-bridge.js +0 -82
- package/lib/Utils/session-pool.d.ts +0 -16
- package/lib/Utils/session-pool.js +0 -94
- package/lib/Utils/sticker.d.ts +0 -17
- package/lib/Utils/sticker.js +0 -145
- package/lib/Utils/view-once-cache.d.ts +0 -9
- package/lib/Utils/view-once-cache.js +0 -79
package/lib/antiban.js
CHANGED
|
@@ -23,17 +23,17 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
23
23
|
var __toESM = (mod, isNodeMode, target) => (
|
|
24
24
|
(target = mod != null ? __create(__getProtoOf(mod)) : {}),
|
|
25
25
|
__copyProps(
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
30
|
isNodeMode || !mod || !mod.__esModule ? __defProp(target, 'default', { value: mod, enumerable: true }) : target,
|
|
31
31
|
mod
|
|
32
32
|
)
|
|
33
33
|
)
|
|
34
34
|
var __toCommonJS = mod => __copyProps(__defProp({}, '__esModule', { value: true }), mod)
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
|
|
37
37
|
var index_exports = {}
|
|
38
38
|
__export(index_exports, {
|
|
39
39
|
AntiBan: () => AntiBan,
|
|
@@ -61,6 +61,7 @@ __export(index_exports, {
|
|
|
61
61
|
WebhookAlerts: () => WebhookAlerts,
|
|
62
62
|
applyFingerprint: () => applyFingerprint,
|
|
63
63
|
applyGroupMultiplier: () => applyGroupMultiplier,
|
|
64
|
+
buildContentSignature: () => buildContentSignature,
|
|
64
65
|
classifyDisconnect: () => classifyDisconnect,
|
|
65
66
|
createLidFirstResolver: () => createLidFirstResolver,
|
|
66
67
|
credsSnapshot: () => credsSnapshot,
|
|
@@ -82,46 +83,44 @@ __export(index_exports, {
|
|
|
82
83
|
})
|
|
83
84
|
module.exports = __toCommonJS(index_exports)
|
|
84
85
|
|
|
85
|
-
|
|
86
|
+
|
|
86
87
|
var TIME_CONSTANTS = {
|
|
87
88
|
MS_PER_SECOND: 1e3,
|
|
88
89
|
MS_PER_MINUTE: 6e4,
|
|
89
90
|
MS_PER_HOUR: 36e5,
|
|
90
91
|
MS_PER_DAY: 864e5,
|
|
91
92
|
BURST_RESET_MS: 3e4,
|
|
92
|
-
IDENTICAL_WINDOW_MS:
|
|
93
|
-
|
|
93
|
+
IDENTICAL_WINDOW_MS: 18e5
|
|
94
|
+
|
|
94
95
|
}
|
|
95
96
|
var DEFAULT_CONFIG = {
|
|
96
|
-
maxPerMinute:
|
|
97
|
-
maxPerHour:
|
|
98
|
-
maxPerDay:
|
|
99
|
-
minDelayMs:
|
|
100
|
-
maxDelayMs:
|
|
101
|
-
newChatDelayMs:
|
|
102
|
-
maxIdenticalMessages:
|
|
103
|
-
burstAllowance:
|
|
97
|
+
maxPerMinute: 12,
|
|
98
|
+
maxPerHour: 400,
|
|
99
|
+
maxPerDay: 2500,
|
|
100
|
+
minDelayMs: 1200,
|
|
101
|
+
maxDelayMs: 4e3,
|
|
102
|
+
newChatDelayMs: 2e3,
|
|
103
|
+
maxIdenticalMessages: 10,
|
|
104
|
+
burstAllowance: 5,
|
|
104
105
|
identicalMessageWindowMs: TIME_CONSTANTS.IDENTICAL_WINDOW_MS
|
|
105
106
|
}
|
|
106
107
|
var RateLimiter = class {
|
|
107
108
|
config
|
|
108
109
|
messages = []
|
|
109
|
-
identicalCount =
|
|
110
|
-
knownChats =
|
|
110
|
+
identicalCount = new Map()
|
|
111
|
+
knownChats = new Set()
|
|
111
112
|
burstCount = 0
|
|
112
113
|
lastMessageTime = 0
|
|
114
|
+
statsCacheTime = 0
|
|
115
|
+
statsCache = null
|
|
113
116
|
constructor(config = {}) {
|
|
114
117
|
this.config = { ...DEFAULT_CONFIG, ...config }
|
|
115
118
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
* Returns 0 if message can be sent immediately.
|
|
119
|
-
* Returns -1 if message should be blocked entirely.
|
|
120
|
-
*/
|
|
121
|
-
async getDelay(recipient, content) {
|
|
119
|
+
|
|
120
|
+
async getDelay(recipient, content, dedupKey) {
|
|
122
121
|
const now = Date.now()
|
|
123
122
|
this.cleanup(now)
|
|
124
|
-
const contentHash = this.hashContent(content)
|
|
123
|
+
const contentHash = this.hashContent(dedupKey !== undefined ? dedupKey : content)
|
|
125
124
|
const dayMessages = this.messages.filter(m => now - m.timestamp < TIME_CONSTANTS.MS_PER_DAY)
|
|
126
125
|
if (dayMessages.length >= this.config.maxPerDay) {
|
|
127
126
|
return -1
|
|
@@ -167,16 +166,14 @@ var RateLimiter = class {
|
|
|
167
166
|
if (timeSinceLast < this.config.minDelayMs) {
|
|
168
167
|
delay = Math.max(delay, this.config.minDelayMs - timeSinceLast)
|
|
169
168
|
}
|
|
170
|
-
const typingDelay = Math.min(content
|
|
169
|
+
const typingDelay = Math.min((content?.length || 0) * 15, 2e3)
|
|
171
170
|
delay += this.jitter(typingDelay * 0.5, typingDelay)
|
|
172
171
|
return Math.round(delay)
|
|
173
172
|
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
*/
|
|
177
|
-
record(recipient, content) {
|
|
173
|
+
|
|
174
|
+
record(recipient, content, dedupKey) {
|
|
178
175
|
const now = Date.now()
|
|
179
|
-
const contentHash = this.hashContent(content)
|
|
176
|
+
const contentHash = this.hashContent(dedupKey !== undefined ? dedupKey : content)
|
|
180
177
|
const timeSinceLast = now - this.lastMessageTime
|
|
181
178
|
if (timeSinceLast > TIME_CONSTANTS.BURST_RESET_MS) {
|
|
182
179
|
this.burstCount = 0
|
|
@@ -196,16 +193,26 @@ var RateLimiter = class {
|
|
|
196
193
|
this.identicalCount.set(contentHash, { count: 1, firstSeen: now, lastSeen: now })
|
|
197
194
|
}
|
|
198
195
|
}
|
|
199
|
-
|
|
200
|
-
* Get current usage stats
|
|
201
|
-
*/
|
|
196
|
+
|
|
202
197
|
getStats() {
|
|
203
198
|
const now = Date.now()
|
|
199
|
+
if (this.statsCache && now - this.statsCacheTime < 100) {
|
|
200
|
+
return this.statsCache
|
|
201
|
+
}
|
|
204
202
|
this.cleanup(now)
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
203
|
+
let lastMinute = 0
|
|
204
|
+
let lastHour = 0
|
|
205
|
+
let lastDay = 0
|
|
206
|
+
for (const m of this.messages) {
|
|
207
|
+
const age = now - m.timestamp
|
|
208
|
+
if (age < TIME_CONSTANTS.MS_PER_MINUTE) lastMinute++
|
|
209
|
+
if (age < TIME_CONSTANTS.MS_PER_HOUR) lastHour++
|
|
210
|
+
if (age < TIME_CONSTANTS.MS_PER_DAY) lastDay++
|
|
211
|
+
}
|
|
212
|
+
this.statsCache = {
|
|
213
|
+
lastMinute,
|
|
214
|
+
lastHour,
|
|
215
|
+
lastDay,
|
|
209
216
|
limits: {
|
|
210
217
|
perMinute: this.config.maxPerMinute,
|
|
211
218
|
perHour: this.config.maxPerHour,
|
|
@@ -213,12 +220,14 @@ var RateLimiter = class {
|
|
|
213
220
|
},
|
|
214
221
|
knownChats: this.knownChats.size
|
|
215
222
|
}
|
|
223
|
+
this.statsCacheTime = now
|
|
224
|
+
return this.statsCache
|
|
216
225
|
}
|
|
217
|
-
|
|
226
|
+
|
|
218
227
|
getKnownChats() {
|
|
219
228
|
return this.knownChats
|
|
220
229
|
}
|
|
221
|
-
|
|
230
|
+
|
|
222
231
|
restoreKnownChats(chats) {
|
|
223
232
|
for (const jid of chats) {
|
|
224
233
|
this.knownChats.add(jid)
|
|
@@ -232,7 +241,7 @@ var RateLimiter = class {
|
|
|
232
241
|
}
|
|
233
242
|
}
|
|
234
243
|
}
|
|
235
|
-
|
|
244
|
+
|
|
236
245
|
jitter(min, max) {
|
|
237
246
|
const u1 = Math.random()
|
|
238
247
|
const u2 = Math.random()
|
|
@@ -241,7 +250,7 @@ var RateLimiter = class {
|
|
|
241
250
|
const clamped = Math.max(0, Math.min(1, normalized))
|
|
242
251
|
return Math.round(min + clamped * (max - min))
|
|
243
252
|
}
|
|
244
|
-
|
|
253
|
+
|
|
245
254
|
hashContent(content) {
|
|
246
255
|
let hash = 0
|
|
247
256
|
for (let i = 0; i < content.length; i++) {
|
|
@@ -253,12 +262,12 @@ var RateLimiter = class {
|
|
|
253
262
|
}
|
|
254
263
|
}
|
|
255
264
|
|
|
256
|
-
|
|
265
|
+
|
|
257
266
|
var DEFAULT_CONFIG2 = {
|
|
258
|
-
warmUpDays:
|
|
259
|
-
day1Limit:
|
|
267
|
+
warmUpDays: 5,
|
|
268
|
+
day1Limit: 30,
|
|
260
269
|
growthFactor: 1.8,
|
|
261
|
-
inactivityThresholdHours:
|
|
270
|
+
inactivityThresholdHours: 168
|
|
262
271
|
}
|
|
263
272
|
var WarmUp = class {
|
|
264
273
|
config
|
|
@@ -267,9 +276,7 @@ var WarmUp = class {
|
|
|
267
276
|
this.config = { ...DEFAULT_CONFIG2, ...config }
|
|
268
277
|
this.state = existingState || this.freshState()
|
|
269
278
|
}
|
|
270
|
-
|
|
271
|
-
* Get the current daily message limit based on warm-up phase
|
|
272
|
-
*/
|
|
279
|
+
|
|
273
280
|
getDailyLimit() {
|
|
274
281
|
if (this.state.graduated) return Infinity
|
|
275
282
|
const day = this.getCurrentDay()
|
|
@@ -279,9 +286,7 @@ var WarmUp = class {
|
|
|
279
286
|
}
|
|
280
287
|
return Math.round(this.config.day1Limit * Math.pow(this.config.growthFactor, day))
|
|
281
288
|
}
|
|
282
|
-
|
|
283
|
-
* Check if a message can be sent (within warm-up limits)
|
|
284
|
-
*/
|
|
289
|
+
|
|
285
290
|
canSend() {
|
|
286
291
|
this.checkInactivity()
|
|
287
292
|
if (this.state.graduated) return true
|
|
@@ -289,9 +294,7 @@ var WarmUp = class {
|
|
|
289
294
|
const todayCount = this.state.dailyCounts[day] || 0
|
|
290
295
|
return todayCount < this.getDailyLimit()
|
|
291
296
|
}
|
|
292
|
-
|
|
293
|
-
* Record a sent message
|
|
294
|
-
*/
|
|
297
|
+
|
|
295
298
|
record() {
|
|
296
299
|
const now = Date.now()
|
|
297
300
|
const day = this.getCurrentDay()
|
|
@@ -301,9 +304,7 @@ var WarmUp = class {
|
|
|
301
304
|
this.state.dailyCounts[day]++
|
|
302
305
|
this.state.lastActiveAt = now
|
|
303
306
|
}
|
|
304
|
-
|
|
305
|
-
* Get current warm-up status
|
|
306
|
-
*/
|
|
307
|
+
|
|
307
308
|
getStatus() {
|
|
308
309
|
const day = this.getCurrentDay()
|
|
309
310
|
const todaySent = this.state.dailyCounts[day] || 0
|
|
@@ -317,15 +318,11 @@ var WarmUp = class {
|
|
|
317
318
|
progress: this.state.graduated ? 100 : Math.round((day / this.config.warmUpDays) * 100)
|
|
318
319
|
}
|
|
319
320
|
}
|
|
320
|
-
|
|
321
|
-
* Export state for persistence
|
|
322
|
-
*/
|
|
321
|
+
|
|
323
322
|
exportState() {
|
|
324
323
|
return { ...this.state }
|
|
325
324
|
}
|
|
326
|
-
|
|
327
|
-
* Reset warm-up (e.g., after detected ban risk)
|
|
328
|
-
*/
|
|
325
|
+
|
|
329
326
|
reset() {
|
|
330
327
|
this.state = this.freshState()
|
|
331
328
|
}
|
|
@@ -350,7 +347,7 @@ var WarmUp = class {
|
|
|
350
347
|
}
|
|
351
348
|
}
|
|
352
349
|
|
|
353
|
-
|
|
350
|
+
|
|
354
351
|
var DEFAULT_CONFIG3 = {
|
|
355
352
|
disconnectWarningThreshold: 3,
|
|
356
353
|
disconnectCriticalThreshold: 5,
|
|
@@ -368,9 +365,7 @@ var HealthMonitor = class {
|
|
|
368
365
|
constructor(config = {}) {
|
|
369
366
|
this.config = { ...DEFAULT_CONFIG3, ...config }
|
|
370
367
|
}
|
|
371
|
-
|
|
372
|
-
* Record a disconnection event
|
|
373
|
-
*/
|
|
368
|
+
|
|
374
369
|
recordDisconnect(reason) {
|
|
375
370
|
const reasonStr = String(reason)
|
|
376
371
|
if (reasonStr === '403' || reasonStr === 'forbidden') {
|
|
@@ -392,33 +387,25 @@ var HealthMonitor = class {
|
|
|
392
387
|
}
|
|
393
388
|
this.checkAndNotify()
|
|
394
389
|
}
|
|
395
|
-
|
|
396
|
-
* Record a successful reconnection
|
|
397
|
-
*/
|
|
390
|
+
|
|
398
391
|
recordReconnect() {
|
|
399
392
|
this.events.push({ type: 'reconnect', timestamp: Date.now() })
|
|
400
393
|
}
|
|
401
|
-
|
|
402
|
-
* Record a failed message send
|
|
403
|
-
*/
|
|
394
|
+
|
|
404
395
|
recordMessageFailed(error) {
|
|
405
396
|
this.events.push({ type: 'messageFailed', timestamp: Date.now(), detail: error })
|
|
406
397
|
this.lastBadEventTime = Date.now()
|
|
407
398
|
this.lastEventWasSevere = false
|
|
408
399
|
this.checkAndNotify()
|
|
409
400
|
}
|
|
410
|
-
|
|
411
|
-
* Record a 463 reachout timelock error
|
|
412
|
-
*/
|
|
401
|
+
|
|
413
402
|
recordReachoutTimelock(detail) {
|
|
414
403
|
this.events.push({ type: 'reachoutTimelocked', timestamp: Date.now(), detail })
|
|
415
404
|
this.lastBadEventTime = Date.now()
|
|
416
405
|
this.lastEventWasSevere = false
|
|
417
406
|
this.checkAndNotify()
|
|
418
407
|
}
|
|
419
|
-
|
|
420
|
-
* Get current health status
|
|
421
|
-
*/
|
|
408
|
+
|
|
422
409
|
getStatus() {
|
|
423
410
|
const now = Date.now()
|
|
424
411
|
this.cleanup(now)
|
|
@@ -494,24 +481,18 @@ var HealthMonitor = class {
|
|
|
494
481
|
}
|
|
495
482
|
}
|
|
496
483
|
}
|
|
497
|
-
|
|
498
|
-
* Check if sending should be paused
|
|
499
|
-
*/
|
|
484
|
+
|
|
500
485
|
isPaused() {
|
|
501
486
|
if (this.paused) return true
|
|
502
487
|
const status = this.getStatus()
|
|
503
488
|
const riskOrder = ['low', 'medium', 'high', 'critical']
|
|
504
489
|
return riskOrder.indexOf(status.risk) >= riskOrder.indexOf(this.config.autoPauseAt)
|
|
505
490
|
}
|
|
506
|
-
|
|
507
|
-
* Manually pause/resume
|
|
508
|
-
*/
|
|
491
|
+
|
|
509
492
|
setPaused(paused) {
|
|
510
493
|
this.paused = paused
|
|
511
494
|
}
|
|
512
|
-
|
|
513
|
-
* Reset all tracked events
|
|
514
|
-
*/
|
|
495
|
+
|
|
515
496
|
reset() {
|
|
516
497
|
this.events = []
|
|
517
498
|
this.startTime = Date.now()
|
|
@@ -532,7 +513,7 @@ var HealthMonitor = class {
|
|
|
532
513
|
}
|
|
533
514
|
}
|
|
534
515
|
|
|
535
|
-
|
|
516
|
+
|
|
536
517
|
var DEFAULT_CONFIG4 = {
|
|
537
518
|
resumeBufferMs: 1e4
|
|
538
519
|
}
|
|
@@ -542,23 +523,21 @@ var TimelockGuard = class {
|
|
|
542
523
|
isActive: false,
|
|
543
524
|
errorCount: 0
|
|
544
525
|
}
|
|
545
|
-
knownChats =
|
|
526
|
+
knownChats = new Set()
|
|
546
527
|
resumeTimer = null
|
|
547
528
|
timerGeneration = 0
|
|
548
|
-
|
|
529
|
+
|
|
549
530
|
constructor(config = {}) {
|
|
550
531
|
this.config = { ...DEFAULT_CONFIG4, ...config }
|
|
551
532
|
}
|
|
552
|
-
|
|
553
|
-
* Update timelock state from Baileys connection.update event
|
|
554
|
-
*/
|
|
533
|
+
|
|
555
534
|
onTimelockUpdate(data) {
|
|
556
535
|
const wasActive = this.state.isActive
|
|
557
536
|
this.state.isActive = !!data.isActive
|
|
558
537
|
this.state.enforcementType = data.enforcementType
|
|
559
538
|
this.state.expiresAt = data.timeEnforcementEnds
|
|
560
539
|
if (this.state.isActive && !wasActive) {
|
|
561
|
-
this.state.detectedAt =
|
|
540
|
+
this.state.detectedAt = new Date()
|
|
562
541
|
this.state.errorCount = 0
|
|
563
542
|
this.config.onTimelockDetected?.(this.getState())
|
|
564
543
|
this.scheduleResume()
|
|
@@ -570,36 +549,28 @@ var TimelockGuard = class {
|
|
|
570
549
|
this.config.onTimelockLifted?.(this.getState())
|
|
571
550
|
}
|
|
572
551
|
}
|
|
573
|
-
|
|
574
|
-
* Record a 463 error from a failed send
|
|
575
|
-
*/
|
|
552
|
+
|
|
576
553
|
record463Error() {
|
|
577
554
|
this.state.errorCount++
|
|
578
555
|
if (!this.state.isActive) {
|
|
579
556
|
this.state.isActive = true
|
|
580
|
-
this.state.detectedAt =
|
|
557
|
+
this.state.detectedAt = new Date()
|
|
581
558
|
this.state.expiresAt = new Date(Date.now() + 6e4)
|
|
582
559
|
this.config.onTimelockDetected?.(this.getState())
|
|
583
560
|
this.scheduleResume()
|
|
584
561
|
}
|
|
585
562
|
}
|
|
586
|
-
|
|
587
|
-
* Register a JID as a known/existing chat (has tctoken / prior history)
|
|
588
|
-
*/
|
|
563
|
+
|
|
589
564
|
registerKnownChat(jid) {
|
|
590
565
|
this.knownChats.add(jid)
|
|
591
566
|
}
|
|
592
|
-
|
|
593
|
-
* Register multiple known chats at once (e.g. from chat list on connect)
|
|
594
|
-
*/
|
|
567
|
+
|
|
595
568
|
registerKnownChats(jids) {
|
|
596
569
|
for (const jid of jids) {
|
|
597
570
|
this.knownChats.add(jid)
|
|
598
571
|
}
|
|
599
572
|
}
|
|
600
|
-
|
|
601
|
-
* Check if a message to this recipient should be allowed
|
|
602
|
-
*/
|
|
573
|
+
|
|
603
574
|
canSend(jid) {
|
|
604
575
|
if (!this.state.isActive) {
|
|
605
576
|
return { allowed: true }
|
|
@@ -623,15 +594,11 @@ var TimelockGuard = class {
|
|
|
623
594
|
reason: `Reachout timelocked (${this.state.enforcementType || 'unknown'}). New contacts blocked. Expires in ${Math.ceil(expiresIn / 1e3)}s.`
|
|
624
595
|
}
|
|
625
596
|
}
|
|
626
|
-
|
|
627
|
-
* Get current timelock state
|
|
628
|
-
*/
|
|
597
|
+
|
|
629
598
|
getState() {
|
|
630
599
|
return { ...this.state }
|
|
631
600
|
}
|
|
632
|
-
|
|
633
|
-
* Check if currently timelocked
|
|
634
|
-
*/
|
|
601
|
+
|
|
635
602
|
isTimelocked() {
|
|
636
603
|
if (!this.state.isActive) return false
|
|
637
604
|
if (this.state.expiresAt) {
|
|
@@ -643,15 +610,11 @@ var TimelockGuard = class {
|
|
|
643
610
|
}
|
|
644
611
|
return true
|
|
645
612
|
}
|
|
646
|
-
|
|
647
|
-
* Get the set of known chat JIDs
|
|
648
|
-
*/
|
|
613
|
+
|
|
649
614
|
getKnownChats() {
|
|
650
615
|
return new Set(this.knownChats)
|
|
651
616
|
}
|
|
652
|
-
|
|
653
|
-
* Manually lift the timelock
|
|
654
|
-
*/
|
|
617
|
+
|
|
655
618
|
lift() {
|
|
656
619
|
if (this.state.isActive) {
|
|
657
620
|
this.state.isActive = false
|
|
@@ -659,9 +622,7 @@ var TimelockGuard = class {
|
|
|
659
622
|
this.config.onTimelockLifted?.(this.getState())
|
|
660
623
|
}
|
|
661
624
|
}
|
|
662
|
-
|
|
663
|
-
* Reset all state
|
|
664
|
-
*/
|
|
625
|
+
|
|
665
626
|
reset() {
|
|
666
627
|
this.state = { isActive: false, errorCount: 0 }
|
|
667
628
|
this.knownChats.clear()
|
|
@@ -691,7 +652,7 @@ var TimelockGuard = class {
|
|
|
691
652
|
}
|
|
692
653
|
}
|
|
693
654
|
|
|
694
|
-
|
|
655
|
+
|
|
695
656
|
var DEFAULT_CONFIG5 = {
|
|
696
657
|
enabled: false,
|
|
697
658
|
minRatio: 0.1,
|
|
@@ -703,14 +664,11 @@ var DEFAULT_CONFIG5 = {
|
|
|
703
664
|
}
|
|
704
665
|
var ReplyRatioGuard = class {
|
|
705
666
|
config
|
|
706
|
-
contacts =
|
|
667
|
+
contacts = new Map()
|
|
707
668
|
constructor(config = {}) {
|
|
708
669
|
this.config = { ...DEFAULT_CONFIG5, ...config }
|
|
709
670
|
}
|
|
710
|
-
|
|
711
|
-
* Check if message can be sent to this contact based on reply ratio.
|
|
712
|
-
* Call before sending.
|
|
713
|
-
*/
|
|
671
|
+
|
|
714
672
|
beforeSend(jid) {
|
|
715
673
|
if (!this.config.enabled) {
|
|
716
674
|
return { allowed: true }
|
|
@@ -741,18 +699,14 @@ var ReplyRatioGuard = class {
|
|
|
741
699
|
}
|
|
742
700
|
return { allowed: true }
|
|
743
701
|
}
|
|
744
|
-
|
|
745
|
-
* Record an outbound message sent to this contact.
|
|
746
|
-
*/
|
|
702
|
+
|
|
747
703
|
recordSent(jid) {
|
|
748
704
|
if (!this.config.enabled) return
|
|
749
705
|
const record = this.contacts.get(jid) || { sent: 0, received: 0 }
|
|
750
706
|
record.sent++
|
|
751
707
|
this.contacts.set(jid, record)
|
|
752
708
|
}
|
|
753
|
-
|
|
754
|
-
* Record an inbound message received from this contact.
|
|
755
|
-
*/
|
|
709
|
+
|
|
756
710
|
recordReceived(jid) {
|
|
757
711
|
if (!this.config.enabled) return
|
|
758
712
|
const record = this.contacts.get(jid) || { sent: 0, received: 0 }
|
|
@@ -760,11 +714,7 @@ var ReplyRatioGuard = class {
|
|
|
760
714
|
delete record.cooledUntil
|
|
761
715
|
this.contacts.set(jid, record)
|
|
762
716
|
}
|
|
763
|
-
|
|
764
|
-
* Suggest whether to send an auto-reply to this incoming message.
|
|
765
|
-
* Returns { shouldReply: true, suggestedText: '👍' } if probability check passes.
|
|
766
|
-
* Caller is responsible for actually sending the message.
|
|
767
|
-
*/
|
|
717
|
+
|
|
768
718
|
suggestReply(jid, _msgText) {
|
|
769
719
|
if (!this.config.enabled) {
|
|
770
720
|
return { shouldReply: false }
|
|
@@ -779,9 +729,7 @@ var ReplyRatioGuard = class {
|
|
|
779
729
|
}
|
|
780
730
|
return { shouldReply: false }
|
|
781
731
|
}
|
|
782
|
-
|
|
783
|
-
* Get statistics for all contacts and global metrics.
|
|
784
|
-
*/
|
|
732
|
+
|
|
785
733
|
getStats() {
|
|
786
734
|
const perContact = Array.from(this.contacts.entries()).map(([jid, record]) => ({
|
|
787
735
|
jid,
|
|
@@ -802,60 +750,49 @@ var ReplyRatioGuard = class {
|
|
|
802
750
|
contactsOnCooldown
|
|
803
751
|
}
|
|
804
752
|
}
|
|
805
|
-
|
|
806
|
-
* Reset all counters.
|
|
807
|
-
*/
|
|
753
|
+
|
|
808
754
|
reset() {
|
|
809
755
|
this.contacts.clear()
|
|
810
756
|
}
|
|
811
|
-
|
|
812
|
-
* Export state for persistence.
|
|
813
|
-
*/
|
|
757
|
+
|
|
814
758
|
exportState() {
|
|
815
759
|
return {
|
|
816
760
|
contacts: Array.from(this.contacts.entries())
|
|
817
761
|
}
|
|
818
762
|
}
|
|
819
|
-
|
|
820
|
-
* Restore state from persistence.
|
|
821
|
-
*/
|
|
763
|
+
|
|
822
764
|
restoreState(state) {
|
|
823
765
|
if (state?.contacts && Array.isArray(state.contacts)) {
|
|
824
766
|
this.contacts = new Map(state.contacts)
|
|
825
767
|
}
|
|
826
768
|
}
|
|
827
|
-
|
|
828
|
-
* Check if JID is a group.
|
|
829
|
-
*/
|
|
769
|
+
|
|
830
770
|
isGroup(jid) {
|
|
831
771
|
return jid.endsWith('@g.us')
|
|
832
772
|
}
|
|
833
773
|
}
|
|
834
774
|
|
|
835
|
-
|
|
775
|
+
|
|
836
776
|
var DEFAULT_CONFIG6 = {
|
|
837
777
|
enabled: false,
|
|
838
778
|
requireHandshakeBeforeGroupSend: true,
|
|
839
779
|
handshakeMinDelayMs: 36e5,
|
|
840
|
-
|
|
780
|
+
|
|
841
781
|
groupLurkPeriodMs: 432e5,
|
|
842
|
-
|
|
782
|
+
|
|
843
783
|
maxStrangerMessagesPerDay: 5,
|
|
844
784
|
autoRegisterOnIncoming: true
|
|
845
785
|
}
|
|
846
786
|
var ContactGraphWarmer = class {
|
|
847
787
|
config
|
|
848
|
-
contacts =
|
|
849
|
-
groups =
|
|
788
|
+
contacts = new Map()
|
|
789
|
+
groups = new Map()
|
|
850
790
|
strangerMessagesToday = 0
|
|
851
791
|
lastStrangerResetDay = this.getCurrentDay()
|
|
852
792
|
constructor(config = {}) {
|
|
853
793
|
this.config = { ...DEFAULT_CONFIG6, ...config }
|
|
854
794
|
}
|
|
855
|
-
|
|
856
|
-
* Check if message can be sent to this contact/group.
|
|
857
|
-
* Returns { allowed: false, needsHandshake: true } if handshake required.
|
|
858
|
-
*/
|
|
795
|
+
|
|
859
796
|
canMessage(jid) {
|
|
860
797
|
if (!this.config.enabled) {
|
|
861
798
|
return { allowed: true }
|
|
@@ -870,9 +807,7 @@ var ContactGraphWarmer = class {
|
|
|
870
807
|
}
|
|
871
808
|
return this.checkIndividualMessage(jid)
|
|
872
809
|
}
|
|
873
|
-
|
|
874
|
-
* Mark handshake as sent to this contact.
|
|
875
|
-
*/
|
|
810
|
+
|
|
876
811
|
markHandshakeSent(jid) {
|
|
877
812
|
if (!this.config.enabled) return
|
|
878
813
|
if (this.isGroup(jid)) return
|
|
@@ -881,9 +816,7 @@ var ContactGraphWarmer = class {
|
|
|
881
816
|
record.handshakeSentAt = Date.now()
|
|
882
817
|
this.contacts.set(jid, record)
|
|
883
818
|
}
|
|
884
|
-
|
|
885
|
-
* Mark handshake as complete with this contact.
|
|
886
|
-
*/
|
|
819
|
+
|
|
887
820
|
markHandshakeComplete(jid) {
|
|
888
821
|
if (!this.config.enabled) return
|
|
889
822
|
if (this.isGroup(jid)) return
|
|
@@ -891,9 +824,7 @@ var ContactGraphWarmer = class {
|
|
|
891
824
|
record.state = 'handshake_complete'
|
|
892
825
|
this.contacts.set(jid, record)
|
|
893
826
|
}
|
|
894
|
-
|
|
895
|
-
* Register a contact as known (skip handshake requirement).
|
|
896
|
-
*/
|
|
827
|
+
|
|
897
828
|
registerKnownContact(jid) {
|
|
898
829
|
if (!this.config.enabled) return
|
|
899
830
|
if (this.isGroup(jid)) return
|
|
@@ -901,24 +832,18 @@ var ContactGraphWarmer = class {
|
|
|
901
832
|
record.state = 'known'
|
|
902
833
|
this.contacts.set(jid, record)
|
|
903
834
|
}
|
|
904
|
-
|
|
905
|
-
* Register a group join event.
|
|
906
|
-
*/
|
|
835
|
+
|
|
907
836
|
registerGroupJoin(groupJid) {
|
|
908
837
|
if (!this.config.enabled) return
|
|
909
838
|
if (!this.isGroup(groupJid)) return
|
|
910
839
|
this.groups.set(groupJid, { joinedAt: Date.now() })
|
|
911
840
|
}
|
|
912
|
-
|
|
913
|
-
* Get contact state.
|
|
914
|
-
*/
|
|
841
|
+
|
|
915
842
|
getContactState(jid) {
|
|
916
843
|
if (this.isGroup(jid)) return 'known'
|
|
917
844
|
return this.contacts.get(jid)?.state || 'stranger'
|
|
918
845
|
}
|
|
919
|
-
|
|
920
|
-
* Handle incoming message — auto-register if enabled.
|
|
921
|
-
*/
|
|
846
|
+
|
|
922
847
|
onIncomingMessage(jid) {
|
|
923
848
|
if (!this.config.enabled) return
|
|
924
849
|
if (this.isGroup(jid)) return
|
|
@@ -926,9 +851,7 @@ var ContactGraphWarmer = class {
|
|
|
926
851
|
this.registerKnownContact(jid)
|
|
927
852
|
}
|
|
928
853
|
}
|
|
929
|
-
|
|
930
|
-
* Get statistics.
|
|
931
|
-
*/
|
|
854
|
+
|
|
932
855
|
getStats() {
|
|
933
856
|
const knownContacts = Array.from(this.contacts.values()).filter(c => c.state === 'known').length
|
|
934
857
|
const pendingHandshakes = Array.from(this.contacts.values()).filter(c => c.state === 'handshake_sent').length
|
|
@@ -944,18 +867,14 @@ var ContactGraphWarmer = class {
|
|
|
944
867
|
groupsJoined
|
|
945
868
|
}
|
|
946
869
|
}
|
|
947
|
-
|
|
948
|
-
* Reset all state.
|
|
949
|
-
*/
|
|
870
|
+
|
|
950
871
|
reset() {
|
|
951
872
|
this.contacts.clear()
|
|
952
873
|
this.groups.clear()
|
|
953
874
|
this.strangerMessagesToday = 0
|
|
954
875
|
this.lastStrangerResetDay = this.getCurrentDay()
|
|
955
876
|
}
|
|
956
|
-
|
|
957
|
-
* Export state for persistence.
|
|
958
|
-
*/
|
|
877
|
+
|
|
959
878
|
exportState() {
|
|
960
879
|
return {
|
|
961
880
|
contacts: Array.from(this.contacts.entries()),
|
|
@@ -964,9 +883,7 @@ var ContactGraphWarmer = class {
|
|
|
964
883
|
lastStrangerResetDay: this.lastStrangerResetDay
|
|
965
884
|
}
|
|
966
885
|
}
|
|
967
|
-
|
|
968
|
-
* Restore state from persistence.
|
|
969
|
-
*/
|
|
886
|
+
|
|
970
887
|
restoreState(state) {
|
|
971
888
|
if (state?.contacts && Array.isArray(state.contacts)) {
|
|
972
889
|
this.contacts = new Map(state.contacts)
|
|
@@ -981,7 +898,7 @@ var ContactGraphWarmer = class {
|
|
|
981
898
|
this.lastStrangerResetDay = state.lastStrangerResetDay
|
|
982
899
|
}
|
|
983
900
|
}
|
|
984
|
-
|
|
901
|
+
|
|
985
902
|
isGroup(jid) {
|
|
986
903
|
return jid.endsWith('@g.us')
|
|
987
904
|
}
|
|
@@ -1035,7 +952,7 @@ var ContactGraphWarmer = class {
|
|
|
1035
952
|
}
|
|
1036
953
|
}
|
|
1037
954
|
|
|
1038
|
-
|
|
955
|
+
|
|
1039
956
|
var DEFAULT_CONFIG7 = {
|
|
1040
957
|
enabled: false,
|
|
1041
958
|
enableCircadianRhythm: true,
|
|
@@ -1068,60 +985,60 @@ var DEFAULT_CONFIG7 = {
|
|
|
1068
985
|
var ACTIVITY_CURVES = {
|
|
1069
986
|
office: [
|
|
1070
987
|
0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1,
|
|
1071
|
-
|
|
988
|
+
|
|
1072
989
|
0.5, 0.5,
|
|
1073
|
-
|
|
990
|
+
|
|
1074
991
|
0.95, 0.95,
|
|
1075
|
-
|
|
992
|
+
|
|
1076
993
|
0.6,
|
|
1077
|
-
|
|
994
|
+
|
|
1078
995
|
0.9, 0.9, 0.9, 0.9,
|
|
1079
|
-
|
|
996
|
+
|
|
1080
997
|
0.6, 0.6,
|
|
1081
|
-
|
|
998
|
+
|
|
1082
999
|
0.4, 0.4,
|
|
1083
|
-
|
|
1000
|
+
|
|
1084
1001
|
0.2, 0.2, 0.2, 0.2
|
|
1085
|
-
|
|
1002
|
+
|
|
1086
1003
|
],
|
|
1087
1004
|
social: [
|
|
1088
1005
|
0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1,
|
|
1089
|
-
|
|
1006
|
+
|
|
1090
1007
|
0.3, 0.4,
|
|
1091
|
-
|
|
1008
|
+
|
|
1092
1009
|
0.7, 0.8,
|
|
1093
|
-
|
|
1010
|
+
|
|
1094
1011
|
0.5,
|
|
1095
|
-
|
|
1012
|
+
|
|
1096
1013
|
0.7, 0.7,
|
|
1097
|
-
|
|
1014
|
+
|
|
1098
1015
|
0.4,
|
|
1099
|
-
|
|
1016
|
+
|
|
1100
1017
|
0.8, 0.9, 0.9,
|
|
1101
|
-
|
|
1018
|
+
|
|
1102
1019
|
0.6,
|
|
1103
|
-
|
|
1020
|
+
|
|
1104
1021
|
0.8, 0.85, 0.9, 0.95, 1
|
|
1105
|
-
|
|
1022
|
+
|
|
1106
1023
|
],
|
|
1107
1024
|
global: [
|
|
1108
1025
|
0.5, 0.5, 0.5, 0.5, 0.5, 0.5,
|
|
1109
|
-
|
|
1026
|
+
|
|
1110
1027
|
0.4, 0.4,
|
|
1111
|
-
|
|
1028
|
+
|
|
1112
1029
|
0.6, 0.7, 0.8, 0.8,
|
|
1113
|
-
|
|
1030
|
+
|
|
1114
1031
|
0.6,
|
|
1115
|
-
|
|
1032
|
+
|
|
1116
1033
|
0.8, 0.8, 0.8, 0.8,
|
|
1117
|
-
|
|
1034
|
+
|
|
1118
1035
|
0.7, 0.7,
|
|
1119
|
-
|
|
1036
|
+
|
|
1120
1037
|
0.6, 0.5, 0.5, 0.5, 0.5, 0.5
|
|
1121
|
-
|
|
1038
|
+
|
|
1122
1039
|
]
|
|
1123
1040
|
}
|
|
1124
|
-
function getCircadianMultiplier(date =
|
|
1041
|
+
function getCircadianMultiplier(date = new Date(), profile = 'default', timezone) {
|
|
1125
1042
|
if (profile === 'always_on') {
|
|
1126
1043
|
return 1
|
|
1127
1044
|
}
|
|
@@ -1186,11 +1103,7 @@ var PresenceChoreographer = class {
|
|
|
1186
1103
|
}
|
|
1187
1104
|
}
|
|
1188
1105
|
}
|
|
1189
|
-
|
|
1190
|
-
* Get current activity factor (0.1 to 1.0).
|
|
1191
|
-
* Higher = more active = shorter delays.
|
|
1192
|
-
* If circadian disabled, returns 1.0.
|
|
1193
|
-
*/
|
|
1106
|
+
|
|
1194
1107
|
getCurrentActivityFactor() {
|
|
1195
1108
|
if (!this.config.enabled || !this.config.enableCircadianRhythm) {
|
|
1196
1109
|
return 1
|
|
@@ -1199,10 +1112,7 @@ var PresenceChoreographer = class {
|
|
|
1199
1112
|
const curve = ACTIVITY_CURVES[this.config.activityCurve]
|
|
1200
1113
|
return curve[hour] || 0.5
|
|
1201
1114
|
}
|
|
1202
|
-
|
|
1203
|
-
* Check if should pause for distraction.
|
|
1204
|
-
* Returns { pause: true, durationMs: 600000 } if probability check passes.
|
|
1205
|
-
*/
|
|
1115
|
+
|
|
1206
1116
|
shouldPauseForDistraction() {
|
|
1207
1117
|
if (!this.config.enabled) {
|
|
1208
1118
|
return { pause: false, durationMs: 0 }
|
|
@@ -1214,10 +1124,7 @@ var PresenceChoreographer = class {
|
|
|
1214
1124
|
}
|
|
1215
1125
|
return { pause: false, durationMs: 0 }
|
|
1216
1126
|
}
|
|
1217
|
-
|
|
1218
|
-
* Check if should take offline gap.
|
|
1219
|
-
* Returns { offline: true, durationMs: 600000 } if probability check passes.
|
|
1220
|
-
*/
|
|
1127
|
+
|
|
1221
1128
|
shouldTakeOfflineGap() {
|
|
1222
1129
|
if (!this.config.enabled) {
|
|
1223
1130
|
return { offline: false, durationMs: 0 }
|
|
@@ -1229,12 +1136,7 @@ var PresenceChoreographer = class {
|
|
|
1229
1136
|
}
|
|
1230
1137
|
return { offline: false, durationMs: 0 }
|
|
1231
1138
|
}
|
|
1232
|
-
|
|
1233
|
-
* Check if should mark message as read.
|
|
1234
|
-
* Returns { mark: false } if skip probability hit.
|
|
1235
|
-
* Returns { mark: true, delayMs: 5000 } otherwise.
|
|
1236
|
-
* Applies circadian multiplier to delay.
|
|
1237
|
-
*/
|
|
1139
|
+
|
|
1238
1140
|
shouldMarkRead() {
|
|
1239
1141
|
if (!this.config.enabled) {
|
|
1240
1142
|
return { mark: true, delayMs: 0 }
|
|
@@ -1247,7 +1149,7 @@ var PresenceChoreographer = class {
|
|
|
1247
1149
|
let delayMs = baseDelayMs
|
|
1248
1150
|
if (this.config.circadian.enabled) {
|
|
1249
1151
|
const circadianMultiplier = getCircadianMultiplier(
|
|
1250
|
-
|
|
1152
|
+
new Date(),
|
|
1251
1153
|
this.config.circadian.profile,
|
|
1252
1154
|
this.config.circadian.timezone
|
|
1253
1155
|
)
|
|
@@ -1256,18 +1158,7 @@ var PresenceChoreographer = class {
|
|
|
1256
1158
|
this.stats.readReceiptsDelayed++
|
|
1257
1159
|
return { mark: true, delayMs }
|
|
1258
1160
|
}
|
|
1259
|
-
|
|
1260
|
-
* Compute realistic typing duration for a message of given length.
|
|
1261
|
-
* Includes Gaussian WPM variance + think-pause injection + circadian timing multiplier.
|
|
1262
|
-
* Returns a "typing plan": array of { state, durationMs } steps the caller should execute sequentially.
|
|
1263
|
-
*
|
|
1264
|
-
* plan = [
|
|
1265
|
-
* { state: 'composing', durationMs: 4200 },
|
|
1266
|
-
* { state: 'paused', durationMs: 950 }, // think pause
|
|
1267
|
-
* { state: 'composing', durationMs: 6800 },
|
|
1268
|
-
* { state: 'paused', durationMs: 600 }, // brief stop before send
|
|
1269
|
-
* ]
|
|
1270
|
-
*/
|
|
1161
|
+
|
|
1271
1162
|
computeTypingPlan(messageLength) {
|
|
1272
1163
|
if (!this.config.enabled || !this.config.enableTypingModel) {
|
|
1273
1164
|
return [{ state: 'composing', durationMs: this.config.typingMinMs }]
|
|
@@ -1282,7 +1173,7 @@ var PresenceChoreographer = class {
|
|
|
1282
1173
|
let circadianMultiplier = 1
|
|
1283
1174
|
if (this.config.circadian.enabled) {
|
|
1284
1175
|
circadianMultiplier = getCircadianMultiplier(
|
|
1285
|
-
|
|
1176
|
+
new Date(),
|
|
1286
1177
|
this.config.circadian.profile,
|
|
1287
1178
|
this.config.circadian.timezone
|
|
1288
1179
|
)
|
|
@@ -1325,13 +1216,7 @@ var PresenceChoreographer = class {
|
|
|
1325
1216
|
}
|
|
1326
1217
|
return plan
|
|
1327
1218
|
}
|
|
1328
|
-
|
|
1329
|
-
* Execute a typing plan against a Baileys-shaped sock with sendPresenceUpdate(state, jid).
|
|
1330
|
-
* Awaits each step's duration. Updates stats.
|
|
1331
|
-
*
|
|
1332
|
-
* await choreo.executeTypingPlan(sock, jid, plan);
|
|
1333
|
-
* await sock.sendMessage(jid, content);
|
|
1334
|
-
*/
|
|
1219
|
+
|
|
1335
1220
|
async executeTypingPlan(sock, jid, plan, options) {
|
|
1336
1221
|
this.stats.typingPlansExecuted++
|
|
1337
1222
|
for (const step of plan) {
|
|
@@ -1344,9 +1229,7 @@ var PresenceChoreographer = class {
|
|
|
1344
1229
|
this.stats.totalTypingTimeMs += step.durationMs
|
|
1345
1230
|
}
|
|
1346
1231
|
}
|
|
1347
|
-
|
|
1348
|
-
* Get statistics.
|
|
1349
|
-
*/
|
|
1232
|
+
|
|
1350
1233
|
getStats() {
|
|
1351
1234
|
return {
|
|
1352
1235
|
currentActivityFactor: this.getCurrentActivityFactor(),
|
|
@@ -1360,9 +1243,7 @@ var PresenceChoreographer = class {
|
|
|
1360
1243
|
totalTypingTimeMs: this.stats.totalTypingTimeMs
|
|
1361
1244
|
}
|
|
1362
1245
|
}
|
|
1363
|
-
|
|
1364
|
-
* Reset statistics.
|
|
1365
|
-
*/
|
|
1246
|
+
|
|
1366
1247
|
reset() {
|
|
1367
1248
|
this.stats = {
|
|
1368
1249
|
distractionPausesInjected: 0,
|
|
@@ -1374,7 +1255,7 @@ var PresenceChoreographer = class {
|
|
|
1374
1255
|
totalTypingTimeMs: 0
|
|
1375
1256
|
}
|
|
1376
1257
|
}
|
|
1377
|
-
|
|
1258
|
+
|
|
1378
1259
|
getLocalHour() {
|
|
1379
1260
|
try {
|
|
1380
1261
|
const formatter = new Intl.DateTimeFormat('en-US', {
|
|
@@ -1382,13 +1263,13 @@ var PresenceChoreographer = class {
|
|
|
1382
1263
|
hour: 'numeric',
|
|
1383
1264
|
hour12: false
|
|
1384
1265
|
})
|
|
1385
|
-
const parts = formatter.formatToParts(
|
|
1266
|
+
const parts = formatter.formatToParts( new Date())
|
|
1386
1267
|
const hourPart = parts.find(p => p.type === 'hour')
|
|
1387
1268
|
if (hourPart) {
|
|
1388
1269
|
return parseInt(hourPart.value, 10)
|
|
1389
1270
|
}
|
|
1390
1271
|
} catch (error) {}
|
|
1391
|
-
return
|
|
1272
|
+
return new Date().getUTCHours()
|
|
1392
1273
|
}
|
|
1393
1274
|
randomBetween(min, max) {
|
|
1394
1275
|
return Math.floor(Math.random() * (max - min + 1)) + min
|
|
@@ -1396,10 +1277,7 @@ var PresenceChoreographer = class {
|
|
|
1396
1277
|
clamp(value, min, max) {
|
|
1397
1278
|
return Math.max(min, Math.min(max, value))
|
|
1398
1279
|
}
|
|
1399
|
-
|
|
1400
|
-
* Generate Gaussian sample using Box-Muller transform.
|
|
1401
|
-
* Returns a sample from N(mean, stdDev).
|
|
1402
|
-
*/
|
|
1280
|
+
|
|
1403
1281
|
gaussianSample(mean, stdDev) {
|
|
1404
1282
|
const u1 = Math.random()
|
|
1405
1283
|
const u2 = Math.random()
|
|
@@ -1411,7 +1289,7 @@ var PresenceChoreographer = class {
|
|
|
1411
1289
|
}
|
|
1412
1290
|
}
|
|
1413
1291
|
|
|
1414
|
-
|
|
1292
|
+
|
|
1415
1293
|
var DEFAULT_CONFIG8 = {
|
|
1416
1294
|
enabled: false,
|
|
1417
1295
|
maxRetries: 5,
|
|
@@ -1420,7 +1298,7 @@ var DEFAULT_CONFIG8 = {
|
|
|
1420
1298
|
}
|
|
1421
1299
|
var RetryReasonTracker = class {
|
|
1422
1300
|
config
|
|
1423
|
-
retries =
|
|
1301
|
+
retries = new Map()
|
|
1424
1302
|
totalRetries = 0
|
|
1425
1303
|
reasonCounts = {
|
|
1426
1304
|
no_session: 0,
|
|
@@ -1438,10 +1316,7 @@ var RetryReasonTracker = class {
|
|
|
1438
1316
|
constructor(config) {
|
|
1439
1317
|
this.config = { ...DEFAULT_CONFIG8, ...config }
|
|
1440
1318
|
}
|
|
1441
|
-
|
|
1442
|
-
* Call when a messages.update event arrives with a status/error.
|
|
1443
|
-
* Classifies and records the retry.
|
|
1444
|
-
*/
|
|
1319
|
+
|
|
1445
1320
|
onMessageUpdate(update) {
|
|
1446
1321
|
if (!this.config.enabled) return
|
|
1447
1322
|
const msgId = update.key?.id
|
|
@@ -1450,9 +1325,7 @@ var RetryReasonTracker = class {
|
|
|
1450
1325
|
const reason = this.classify(update.error || update)
|
|
1451
1326
|
this.recordRetry(msgId, reason)
|
|
1452
1327
|
}
|
|
1453
|
-
|
|
1454
|
-
* Classify an arbitrary error object into a RetryReason
|
|
1455
|
-
*/
|
|
1328
|
+
|
|
1456
1329
|
classify(err) {
|
|
1457
1330
|
if (!err) return 'unknown'
|
|
1458
1331
|
const statusCode = err.output?.statusCode || err.statusCode || err.status
|
|
@@ -1469,9 +1342,7 @@ var RetryReasonTracker = class {
|
|
|
1469
1342
|
if (errorMsg.includes('malformed') || errorMsg.includes('invalid node')) return 'node_malformed'
|
|
1470
1343
|
return 'unknown'
|
|
1471
1344
|
}
|
|
1472
|
-
|
|
1473
|
-
* Record a retry for a message
|
|
1474
|
-
*/
|
|
1345
|
+
|
|
1475
1346
|
recordRetry(msgId, reason) {
|
|
1476
1347
|
const now = Date.now()
|
|
1477
1348
|
let record = this.retries.get(msgId)
|
|
@@ -1495,22 +1366,16 @@ var RetryReasonTracker = class {
|
|
|
1495
1366
|
this.config.onSpiral(msgId, reason)
|
|
1496
1367
|
}
|
|
1497
1368
|
}
|
|
1498
|
-
|
|
1499
|
-
* Should we warn the user this message is spiraling?
|
|
1500
|
-
*/
|
|
1369
|
+
|
|
1501
1370
|
isSpiraling(msgId) {
|
|
1502
1371
|
const record = this.retries.get(msgId)
|
|
1503
1372
|
return record ? record.count >= this.config.spiralThreshold : false
|
|
1504
1373
|
}
|
|
1505
|
-
|
|
1506
|
-
* Reset counters for a specific message (call on successful delivery)
|
|
1507
|
-
*/
|
|
1374
|
+
|
|
1508
1375
|
clear(msgId) {
|
|
1509
1376
|
this.retries.delete(msgId)
|
|
1510
1377
|
}
|
|
1511
|
-
|
|
1512
|
-
* Get current stats
|
|
1513
|
-
*/
|
|
1378
|
+
|
|
1514
1379
|
getStats() {
|
|
1515
1380
|
return {
|
|
1516
1381
|
totalRetries: this.totalRetries,
|
|
@@ -1519,9 +1384,7 @@ var RetryReasonTracker = class {
|
|
|
1519
1384
|
activeRetries: this.retries.size
|
|
1520
1385
|
}
|
|
1521
1386
|
}
|
|
1522
|
-
|
|
1523
|
-
* Clean up old retry records (>5 minutes old)
|
|
1524
|
-
*/
|
|
1387
|
+
|
|
1525
1388
|
cleanup() {
|
|
1526
1389
|
const now = Date.now()
|
|
1527
1390
|
const maxAge = 5 * 60 * 1e3
|
|
@@ -1531,16 +1394,14 @@ var RetryReasonTracker = class {
|
|
|
1531
1394
|
}
|
|
1532
1395
|
}
|
|
1533
1396
|
}
|
|
1534
|
-
|
|
1535
|
-
* Destroy and clean up
|
|
1536
|
-
*/
|
|
1397
|
+
|
|
1537
1398
|
destroy() {
|
|
1538
1399
|
this.retries.clear()
|
|
1539
1400
|
this.cleanup()
|
|
1540
1401
|
}
|
|
1541
1402
|
}
|
|
1542
1403
|
|
|
1543
|
-
|
|
1404
|
+
|
|
1544
1405
|
var DEFAULT_CONFIG9 = {
|
|
1545
1406
|
enabled: false,
|
|
1546
1407
|
rampDurationMs: 6e4,
|
|
@@ -1555,11 +1416,11 @@ var PostReconnectThrottle = class {
|
|
|
1555
1416
|
lifetimeReconnects = 0
|
|
1556
1417
|
rampTimer = null
|
|
1557
1418
|
currentStep = 0
|
|
1558
|
-
|
|
1419
|
+
|
|
1559
1420
|
sendsInCurrentWindow = 0
|
|
1560
1421
|
currentWindowStart = 0
|
|
1561
1422
|
WINDOW_DURATION_MS = 6e4
|
|
1562
|
-
|
|
1423
|
+
|
|
1563
1424
|
constructor(config) {
|
|
1564
1425
|
this.config = {
|
|
1565
1426
|
...DEFAULT_CONFIG9,
|
|
@@ -1567,9 +1428,7 @@ var PostReconnectThrottle = class {
|
|
|
1567
1428
|
baselineRatePerMinute: config?.baselineRatePerMinute || null
|
|
1568
1429
|
}
|
|
1569
1430
|
}
|
|
1570
|
-
|
|
1571
|
-
* Call when connection is re-established. Starts throttle window.
|
|
1572
|
-
*/
|
|
1431
|
+
|
|
1573
1432
|
onReconnect() {
|
|
1574
1433
|
if (!this.config.enabled) return
|
|
1575
1434
|
this.throttledSince = Date.now()
|
|
@@ -1583,13 +1442,9 @@ var PostReconnectThrottle = class {
|
|
|
1583
1442
|
}
|
|
1584
1443
|
this.scheduleNextRampStep()
|
|
1585
1444
|
}
|
|
1586
|
-
|
|
1587
|
-
* Call when connection drops (optional — reset state).
|
|
1588
|
-
*/
|
|
1445
|
+
|
|
1589
1446
|
onDisconnect() {}
|
|
1590
|
-
|
|
1591
|
-
* Schedule the next ramp step
|
|
1592
|
-
*/
|
|
1447
|
+
|
|
1593
1448
|
scheduleNextRampStep() {
|
|
1594
1449
|
if (this.currentStep >= this.config.rampSteps) {
|
|
1595
1450
|
this.throttledSince = null
|
|
@@ -1602,9 +1457,7 @@ var PostReconnectThrottle = class {
|
|
|
1602
1457
|
this.scheduleNextRampStep()
|
|
1603
1458
|
}, stepDuration)
|
|
1604
1459
|
}
|
|
1605
|
-
|
|
1606
|
-
* Returns current rate multiplier (1.0 = no throttle)
|
|
1607
|
-
*/
|
|
1460
|
+
|
|
1608
1461
|
getCurrentMultiplier() {
|
|
1609
1462
|
if (!this.config.enabled || !this.throttledSince) {
|
|
1610
1463
|
return 1
|
|
@@ -1617,9 +1470,7 @@ var PostReconnectThrottle = class {
|
|
|
1617
1470
|
const multiplier = this.config.initialRateMultiplier + (1 - this.config.initialRateMultiplier) * progress
|
|
1618
1471
|
return Math.min(1, multiplier)
|
|
1619
1472
|
}
|
|
1620
|
-
|
|
1621
|
-
* Checks if a send should be gated. Returns {allowed, reason, retryAfterMs?}
|
|
1622
|
-
*/
|
|
1473
|
+
|
|
1623
1474
|
beforeSend() {
|
|
1624
1475
|
if (!this.config.enabled || !this.throttledSince) {
|
|
1625
1476
|
return { allowed: true }
|
|
@@ -1648,9 +1499,7 @@ var PostReconnectThrottle = class {
|
|
|
1648
1499
|
this.throttledSendCount++
|
|
1649
1500
|
return { allowed: true }
|
|
1650
1501
|
}
|
|
1651
|
-
|
|
1652
|
-
* Get current stats
|
|
1653
|
-
*/
|
|
1502
|
+
|
|
1654
1503
|
getStats() {
|
|
1655
1504
|
const multiplier = this.getCurrentMultiplier()
|
|
1656
1505
|
const isThrottled = this.throttledSince !== null && multiplier < 1
|
|
@@ -1667,9 +1516,7 @@ var PostReconnectThrottle = class {
|
|
|
1667
1516
|
lifetimeReconnects: this.lifetimeReconnects
|
|
1668
1517
|
}
|
|
1669
1518
|
}
|
|
1670
|
-
|
|
1671
|
-
* Destroy and clean up timers
|
|
1672
|
-
*/
|
|
1519
|
+
|
|
1673
1520
|
destroy() {
|
|
1674
1521
|
if (this.rampTimer) {
|
|
1675
1522
|
clearTimeout(this.rampTimer)
|
|
@@ -1679,7 +1526,7 @@ var PostReconnectThrottle = class {
|
|
|
1679
1526
|
}
|
|
1680
1527
|
}
|
|
1681
1528
|
|
|
1682
|
-
|
|
1529
|
+
|
|
1683
1530
|
var DEFAULT_CONFIG10 = {
|
|
1684
1531
|
canonical: 'pn',
|
|
1685
1532
|
maxEntries: 1e4
|
|
@@ -1687,10 +1534,10 @@ var DEFAULT_CONFIG10 = {
|
|
|
1687
1534
|
var LidResolver = class {
|
|
1688
1535
|
config
|
|
1689
1536
|
persistence
|
|
1690
|
-
|
|
1691
|
-
lidToPn =
|
|
1692
|
-
pnToLid =
|
|
1693
|
-
|
|
1537
|
+
|
|
1538
|
+
lidToPn = new Map()
|
|
1539
|
+
pnToLid = new Map()
|
|
1540
|
+
|
|
1694
1541
|
stats = {
|
|
1695
1542
|
learnedFromEvents: 0,
|
|
1696
1543
|
lookupsServed: 0,
|
|
@@ -1703,10 +1550,7 @@ var LidResolver = class {
|
|
|
1703
1550
|
void this.hydrate()
|
|
1704
1551
|
}
|
|
1705
1552
|
}
|
|
1706
|
-
|
|
1707
|
-
* Learn from a message event. Idempotent.
|
|
1708
|
-
* Accepts partial mappings — will use whatever fields are available.
|
|
1709
|
-
*/
|
|
1553
|
+
|
|
1710
1554
|
learn(mapping) {
|
|
1711
1555
|
let lid = mapping.lid ? this.normalizeJid(mapping.lid) : void 0
|
|
1712
1556
|
let pn = mapping.pn ? this.normalizeJid(mapping.pn) : void 0
|
|
@@ -1744,10 +1588,7 @@ var LidResolver = class {
|
|
|
1744
1588
|
void this.flush()
|
|
1745
1589
|
}
|
|
1746
1590
|
}
|
|
1747
|
-
|
|
1748
|
-
* Given any form (LID or PN), return the canonical form.
|
|
1749
|
-
* Falls back to input if unknown (no throw).
|
|
1750
|
-
*/
|
|
1591
|
+
|
|
1751
1592
|
resolveCanonical(jid) {
|
|
1752
1593
|
const normalized = this.normalizeJid(jid)
|
|
1753
1594
|
if (this.config.canonical === 'pn') {
|
|
@@ -1781,9 +1622,7 @@ var LidResolver = class {
|
|
|
1781
1622
|
return normalized
|
|
1782
1623
|
}
|
|
1783
1624
|
}
|
|
1784
|
-
|
|
1785
|
-
* Lookup partner form. Returns null if unknown.
|
|
1786
|
-
*/
|
|
1625
|
+
|
|
1787
1626
|
getLid(pn) {
|
|
1788
1627
|
const normalized = this.normalizeJid(pn)
|
|
1789
1628
|
const lid = this.pnToLid.get(normalized)
|
|
@@ -1804,9 +1643,7 @@ var LidResolver = class {
|
|
|
1804
1643
|
}
|
|
1805
1644
|
return null
|
|
1806
1645
|
}
|
|
1807
|
-
|
|
1808
|
-
* Full mapping for inspection
|
|
1809
|
-
*/
|
|
1646
|
+
|
|
1810
1647
|
getMapping(jid) {
|
|
1811
1648
|
const normalized = this.normalizeJid(jid)
|
|
1812
1649
|
const byLid = this.lidToPn.get(normalized)
|
|
@@ -1824,9 +1661,7 @@ var LidResolver = class {
|
|
|
1824
1661
|
}
|
|
1825
1662
|
return null
|
|
1826
1663
|
}
|
|
1827
|
-
|
|
1828
|
-
* Seed from persistence (called automatically in constructor if persistence provided)
|
|
1829
|
-
*/
|
|
1664
|
+
|
|
1830
1665
|
async hydrate() {
|
|
1831
1666
|
if (!this.persistence?.load) return
|
|
1832
1667
|
try {
|
|
@@ -1853,9 +1688,7 @@ var LidResolver = class {
|
|
|
1853
1688
|
}
|
|
1854
1689
|
} catch (error) {}
|
|
1855
1690
|
}
|
|
1856
|
-
|
|
1857
|
-
* Flush current map to persistence
|
|
1858
|
-
*/
|
|
1691
|
+
|
|
1859
1692
|
async flush() {
|
|
1860
1693
|
if (!this.persistence?.save) return
|
|
1861
1694
|
try {
|
|
@@ -1875,9 +1708,7 @@ var LidResolver = class {
|
|
|
1875
1708
|
canonicalForm: this.config.canonical
|
|
1876
1709
|
}
|
|
1877
1710
|
}
|
|
1878
|
-
|
|
1879
|
-
* Clear everything
|
|
1880
|
-
*/
|
|
1711
|
+
|
|
1881
1712
|
reset() {
|
|
1882
1713
|
this.lidToPn.clear()
|
|
1883
1714
|
this.pnToLid.clear()
|
|
@@ -1893,16 +1724,12 @@ var LidResolver = class {
|
|
|
1893
1724
|
void this.flush()
|
|
1894
1725
|
}
|
|
1895
1726
|
}
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
* Normalize JID: strip device suffix `:N`
|
|
1899
|
-
*/
|
|
1727
|
+
|
|
1728
|
+
|
|
1900
1729
|
normalizeJid(jid) {
|
|
1901
1730
|
return jid.replace(/:\d+@/, '@')
|
|
1902
1731
|
}
|
|
1903
|
-
|
|
1904
|
-
* Evict least recently accessed mapping (LRU)
|
|
1905
|
-
*/
|
|
1732
|
+
|
|
1906
1733
|
evictLRU() {
|
|
1907
1734
|
let oldestLid = null
|
|
1908
1735
|
let oldestTime = Infinity
|
|
@@ -1922,7 +1749,7 @@ var LidResolver = class {
|
|
|
1922
1749
|
}
|
|
1923
1750
|
}
|
|
1924
1751
|
|
|
1925
|
-
|
|
1752
|
+
|
|
1926
1753
|
var DEFAULT_CONFIG11 = {
|
|
1927
1754
|
enabled: false,
|
|
1928
1755
|
canonicalizeOutbound: true,
|
|
@@ -1932,7 +1759,7 @@ var JidCanonicalizer = class {
|
|
|
1932
1759
|
config
|
|
1933
1760
|
lidResolver
|
|
1934
1761
|
ownsResolver
|
|
1935
|
-
|
|
1762
|
+
|
|
1936
1763
|
stats = {
|
|
1937
1764
|
outboundCanonicalized: 0,
|
|
1938
1765
|
outboundPassthrough: 0,
|
|
@@ -1950,15 +1777,11 @@ var JidCanonicalizer = class {
|
|
|
1950
1777
|
this.ownsResolver = true
|
|
1951
1778
|
}
|
|
1952
1779
|
}
|
|
1953
|
-
|
|
1954
|
-
* Access the underlying resolver (for cross-module sharing)
|
|
1955
|
-
*/
|
|
1780
|
+
|
|
1956
1781
|
get resolver() {
|
|
1957
1782
|
return this.lidResolver
|
|
1958
1783
|
}
|
|
1959
|
-
|
|
1960
|
-
* Called by wrapper on every outbound send. Returns canonical JID.
|
|
1961
|
-
*/
|
|
1784
|
+
|
|
1962
1785
|
canonicalizeTarget(jid) {
|
|
1963
1786
|
if (!this.config.enabled || !this.config.canonicalizeOutbound) {
|
|
1964
1787
|
return jid
|
|
@@ -1971,22 +1794,7 @@ var JidCanonicalizer = class {
|
|
|
1971
1794
|
}
|
|
1972
1795
|
return canonical
|
|
1973
1796
|
}
|
|
1974
|
-
|
|
1975
|
-
* Returns a stable, canonical thread key for storage / DB indexing.
|
|
1976
|
-
*
|
|
1977
|
-
* Different from `canonicalizeTarget()` (which picks the right send target):
|
|
1978
|
-
* - canonicalizeTarget('1234@lid') → '+27...@s.whatsapp.net' (best send target)
|
|
1979
|
-
* - canonicalKey('1234@lid') → 'thread:27...' (stable thread identifier)
|
|
1980
|
-
*
|
|
1981
|
-
* If LID has known PN mapping → use phone-number form
|
|
1982
|
-
* If only LID known → use LID stripped of suffix
|
|
1983
|
-
* Always lowercase, no @-suffix, prefixed with `thread:`
|
|
1984
|
-
*
|
|
1985
|
-
* Apps using this as their DB key won't double-thread on LID/PN drift.
|
|
1986
|
-
*
|
|
1987
|
-
* @param jid - WhatsApp JID (can be PN, LID, group, or broadcast)
|
|
1988
|
-
* @returns Stable thread key for DB indexing
|
|
1989
|
-
*/
|
|
1797
|
+
|
|
1990
1798
|
canonicalKey(jid) {
|
|
1991
1799
|
if (!jid || typeof jid !== 'string' || jid.trim() === '') {
|
|
1992
1800
|
return 'thread:invalid'
|
|
@@ -2024,9 +1832,7 @@ var JidCanonicalizer = class {
|
|
|
2024
1832
|
}
|
|
2025
1833
|
return `thread:${domain}:${user}`
|
|
2026
1834
|
}
|
|
2027
|
-
|
|
2028
|
-
* Called by wrapper on messages.upsert event. Learns mappings.
|
|
2029
|
-
*/
|
|
1835
|
+
|
|
2030
1836
|
onIncomingEvent(upsert) {
|
|
2031
1837
|
if (!this.config.enabled || !this.config.learnFromEvents) {
|
|
2032
1838
|
return
|
|
@@ -2035,9 +1841,7 @@ var JidCanonicalizer = class {
|
|
|
2035
1841
|
this.learnFromMessage(msg)
|
|
2036
1842
|
}
|
|
2037
1843
|
}
|
|
2038
|
-
|
|
2039
|
-
* Called by wrapper on messages.update event. Learns from sent-message refs.
|
|
2040
|
-
*/
|
|
1844
|
+
|
|
2041
1845
|
onMessageUpdate(updates) {
|
|
2042
1846
|
if (!this.config.enabled || !this.config.learnFromEvents) {
|
|
2043
1847
|
return
|
|
@@ -2063,10 +1867,8 @@ var JidCanonicalizer = class {
|
|
|
2063
1867
|
this.lidResolver.destroy()
|
|
2064
1868
|
}
|
|
2065
1869
|
}
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
* Extract LID↔PN mappings from a message object
|
|
2069
|
-
*/
|
|
1870
|
+
|
|
1871
|
+
|
|
2070
1872
|
learnFromMessage(msg) {
|
|
2071
1873
|
if (!msg.key) return
|
|
2072
1874
|
this.learnFromMessageKey(msg.key)
|
|
@@ -2078,9 +1880,7 @@ var JidCanonicalizer = class {
|
|
|
2078
1880
|
this.stats.inboundLearned++
|
|
2079
1881
|
}
|
|
2080
1882
|
}
|
|
2081
|
-
|
|
2082
|
-
* Extract mappings from message.key
|
|
2083
|
-
*/
|
|
1883
|
+
|
|
2084
1884
|
learnFromMessageKey(key) {
|
|
2085
1885
|
if (!key) return
|
|
2086
1886
|
if (key.participant && key.participantPn) {
|
|
@@ -2113,7 +1913,7 @@ var JidCanonicalizer = class {
|
|
|
2113
1913
|
}
|
|
2114
1914
|
}
|
|
2115
1915
|
|
|
2116
|
-
|
|
1916
|
+
|
|
2117
1917
|
function classifyDisconnect(statusCode) {
|
|
2118
1918
|
if (statusCode === 401 || statusCode === 440) {
|
|
2119
1919
|
return {
|
|
@@ -2152,7 +1952,7 @@ function classifyDisconnect(statusCode) {
|
|
|
2152
1952
|
category: 'recoverable',
|
|
2153
1953
|
shouldReconnect: true,
|
|
2154
1954
|
backoffMs: 3e4,
|
|
2155
|
-
|
|
1955
|
+
|
|
2156
1956
|
message: 'Precondition failed \u2014 auth state mismatch, retry after delay',
|
|
2157
1957
|
code: statusCode
|
|
2158
1958
|
}
|
|
@@ -2162,7 +1962,7 @@ function classifyDisconnect(statusCode) {
|
|
|
2162
1962
|
category: 'rate-limited',
|
|
2163
1963
|
shouldReconnect: true,
|
|
2164
1964
|
backoffMs: 3e5,
|
|
2165
|
-
|
|
1965
|
+
|
|
2166
1966
|
message: 'Rate limited by WhatsApp \u2014 cool-off period required',
|
|
2167
1967
|
code: statusCode
|
|
2168
1968
|
}
|
|
@@ -2172,7 +1972,7 @@ function classifyDisconnect(statusCode) {
|
|
|
2172
1972
|
category: 'rate-limited',
|
|
2173
1973
|
shouldReconnect: true,
|
|
2174
1974
|
backoffMs: 6e4,
|
|
2175
|
-
|
|
1975
|
+
|
|
2176
1976
|
message: 'WhatsApp service unavailable \u2014 temporary outage',
|
|
2177
1977
|
code: statusCode
|
|
2178
1978
|
}
|
|
@@ -2182,7 +1982,7 @@ function classifyDisconnect(statusCode) {
|
|
|
2182
1982
|
category: 'recoverable',
|
|
2183
1983
|
shouldReconnect: true,
|
|
2184
1984
|
backoffMs: 5e3,
|
|
2185
|
-
|
|
1985
|
+
|
|
2186
1986
|
message: 'Connection timeout \u2014 network issue, safe to retry',
|
|
2187
1987
|
code: statusCode
|
|
2188
1988
|
}
|
|
@@ -2192,7 +1992,7 @@ function classifyDisconnect(statusCode) {
|
|
|
2192
1992
|
category: 'recoverable',
|
|
2193
1993
|
shouldReconnect: true,
|
|
2194
1994
|
backoffMs: 1e4,
|
|
2195
|
-
|
|
1995
|
+
|
|
2196
1996
|
message: 'WhatsApp internal error \u2014 temporary server issue',
|
|
2197
1997
|
code: statusCode
|
|
2198
1998
|
}
|
|
@@ -2202,7 +2002,7 @@ function classifyDisconnect(statusCode) {
|
|
|
2202
2002
|
category: 'recoverable',
|
|
2203
2003
|
shouldReconnect: true,
|
|
2204
2004
|
backoffMs: 2e3,
|
|
2205
|
-
|
|
2005
|
+
|
|
2206
2006
|
message: 'Connection closed gracefully \u2014 safe to reconnect',
|
|
2207
2007
|
code: statusCode
|
|
2208
2008
|
}
|
|
@@ -2211,7 +2011,7 @@ function classifyDisconnect(statusCode) {
|
|
|
2211
2011
|
category: 'unknown',
|
|
2212
2012
|
shouldReconnect: true,
|
|
2213
2013
|
backoffMs: 15e3,
|
|
2214
|
-
|
|
2014
|
+
|
|
2215
2015
|
message: `Unknown disconnect reason (code ${statusCode}) \u2014 reconnect with caution`,
|
|
2216
2016
|
code: statusCode
|
|
2217
2017
|
}
|
|
@@ -2236,16 +2036,12 @@ var SessionHealthMonitor = class {
|
|
|
2236
2036
|
this.onDegraded = config.onDegraded
|
|
2237
2037
|
this.onRecovered = config.onRecovered
|
|
2238
2038
|
}
|
|
2239
|
-
|
|
2240
|
-
* Record successful decrypt
|
|
2241
|
-
*/
|
|
2039
|
+
|
|
2242
2040
|
recordDecryptSuccess() {
|
|
2243
2041
|
this.stats.decryptSuccess++
|
|
2244
2042
|
this.checkRecovery()
|
|
2245
2043
|
}
|
|
2246
|
-
|
|
2247
|
-
* Record failed decrypt (Bad MAC or similar)
|
|
2248
|
-
*/
|
|
2044
|
+
|
|
2249
2045
|
recordDecryptFail(isBadMac = false) {
|
|
2250
2046
|
this.stats.decryptFail++
|
|
2251
2047
|
if (isBadMac) {
|
|
@@ -2262,9 +2058,7 @@ var SessionHealthMonitor = class {
|
|
|
2262
2058
|
}
|
|
2263
2059
|
}
|
|
2264
2060
|
}
|
|
2265
|
-
|
|
2266
|
-
* Check if session has recovered from degraded state
|
|
2267
|
-
*/
|
|
2061
|
+
|
|
2268
2062
|
checkRecovery() {
|
|
2269
2063
|
if (!this.stats.isDegraded) return
|
|
2270
2064
|
const now = Date.now()
|
|
@@ -2276,15 +2070,11 @@ var SessionHealthMonitor = class {
|
|
|
2276
2070
|
this.onRecovered?.(this.getStats())
|
|
2277
2071
|
}
|
|
2278
2072
|
}
|
|
2279
|
-
|
|
2280
|
-
* Get current health stats
|
|
2281
|
-
*/
|
|
2073
|
+
|
|
2282
2074
|
getStats() {
|
|
2283
2075
|
return { ...this.stats }
|
|
2284
2076
|
}
|
|
2285
|
-
|
|
2286
|
-
* Reset all counters
|
|
2287
|
-
*/
|
|
2077
|
+
|
|
2288
2078
|
reset() {
|
|
2289
2079
|
this.stats = {
|
|
2290
2080
|
decryptSuccess: 0,
|
|
@@ -2317,51 +2107,51 @@ function wrapWithSessionStability(sock, config = {}) {
|
|
|
2317
2107
|
})
|
|
2318
2108
|
}
|
|
2319
2109
|
|
|
2320
|
-
|
|
2110
|
+
|
|
2321
2111
|
var PRESETS = {
|
|
2322
2112
|
conservative: {
|
|
2323
|
-
maxPerMinute:
|
|
2324
|
-
maxPerHour:
|
|
2325
|
-
maxPerDay:
|
|
2326
|
-
minDelayMs:
|
|
2327
|
-
maxDelayMs:
|
|
2328
|
-
newChatDelayMs:
|
|
2329
|
-
warmupDays:
|
|
2330
|
-
day1Limit:
|
|
2113
|
+
maxPerMinute: 6,
|
|
2114
|
+
maxPerHour: 150,
|
|
2115
|
+
maxPerDay: 1000,
|
|
2116
|
+
minDelayMs: 2000,
|
|
2117
|
+
maxDelayMs: 6e3,
|
|
2118
|
+
newChatDelayMs: 3e3,
|
|
2119
|
+
warmupDays: 7,
|
|
2120
|
+
day1Limit: 20,
|
|
2331
2121
|
growthFactor: 1.8,
|
|
2332
|
-
inactivityThresholdHours:
|
|
2333
|
-
autoPauseAt: '
|
|
2122
|
+
inactivityThresholdHours: 120,
|
|
2123
|
+
autoPauseAt: 'high',
|
|
2334
2124
|
groupMultiplier: 0.5,
|
|
2335
2125
|
groupProfiles: false,
|
|
2336
2126
|
logging: true
|
|
2337
2127
|
},
|
|
2338
2128
|
moderate: {
|
|
2339
|
-
maxPerMinute:
|
|
2340
|
-
maxPerHour:
|
|
2341
|
-
maxPerDay:
|
|
2342
|
-
minDelayMs:
|
|
2343
|
-
maxDelayMs:
|
|
2344
|
-
newChatDelayMs:
|
|
2345
|
-
warmupDays:
|
|
2346
|
-
day1Limit:
|
|
2129
|
+
maxPerMinute: 15,
|
|
2130
|
+
maxPerHour: 500,
|
|
2131
|
+
maxPerDay: 3e3,
|
|
2132
|
+
minDelayMs: 1e3,
|
|
2133
|
+
maxDelayMs: 4e3,
|
|
2134
|
+
newChatDelayMs: 2e3,
|
|
2135
|
+
warmupDays: 5,
|
|
2136
|
+
day1Limit: 30,
|
|
2347
2137
|
growthFactor: 1.8,
|
|
2348
|
-
inactivityThresholdHours:
|
|
2349
|
-
autoPauseAt: '
|
|
2138
|
+
inactivityThresholdHours: 168,
|
|
2139
|
+
autoPauseAt: 'critical',
|
|
2350
2140
|
groupMultiplier: 0.7,
|
|
2351
2141
|
groupProfiles: false,
|
|
2352
2142
|
logging: true
|
|
2353
2143
|
},
|
|
2354
2144
|
aggressive: {
|
|
2355
|
-
maxPerMinute:
|
|
2356
|
-
maxPerHour:
|
|
2357
|
-
maxPerDay:
|
|
2358
|
-
minDelayMs:
|
|
2359
|
-
maxDelayMs:
|
|
2360
|
-
newChatDelayMs:
|
|
2361
|
-
warmupDays:
|
|
2362
|
-
day1Limit:
|
|
2145
|
+
maxPerMinute: 25,
|
|
2146
|
+
maxPerHour: 1200,
|
|
2147
|
+
maxPerDay: 6e3,
|
|
2148
|
+
minDelayMs: 600,
|
|
2149
|
+
maxDelayMs: 2500,
|
|
2150
|
+
newChatDelayMs: 1500,
|
|
2151
|
+
warmupDays: 3,
|
|
2152
|
+
day1Limit: 50,
|
|
2363
2153
|
growthFactor: 2,
|
|
2364
|
-
inactivityThresholdHours:
|
|
2154
|
+
inactivityThresholdHours: 96,
|
|
2365
2155
|
autoPauseAt: 'critical',
|
|
2366
2156
|
groupMultiplier: 0.9,
|
|
2367
2157
|
groupProfiles: false,
|
|
@@ -2370,7 +2160,7 @@ var PRESETS = {
|
|
|
2370
2160
|
}
|
|
2371
2161
|
function resolveConfig(input) {
|
|
2372
2162
|
if (input === void 0) {
|
|
2373
|
-
return { ...PRESETS.
|
|
2163
|
+
return { ...PRESETS.moderate }
|
|
2374
2164
|
}
|
|
2375
2165
|
if (typeof input === 'string') {
|
|
2376
2166
|
if (!(input in PRESETS)) {
|
|
@@ -2378,14 +2168,14 @@ function resolveConfig(input) {
|
|
|
2378
2168
|
}
|
|
2379
2169
|
return { ...PRESETS[input] }
|
|
2380
2170
|
}
|
|
2381
|
-
const { preset = '
|
|
2171
|
+
const { preset = 'moderate', ...overrides } = input
|
|
2382
2172
|
if (!(preset in PRESETS)) {
|
|
2383
2173
|
throw new Error(`Unknown preset "${preset}". Valid: ${Object.keys(PRESETS).join(', ')}`)
|
|
2384
2174
|
}
|
|
2385
2175
|
return { ...PRESETS[preset], ...overrides }
|
|
2386
2176
|
}
|
|
2387
2177
|
|
|
2388
|
-
|
|
2178
|
+
|
|
2389
2179
|
var fs = __toESM(require('fs'), 1)
|
|
2390
2180
|
var KNOWN_CHATS_MAX = 1e3
|
|
2391
2181
|
var DEBOUNCE_MS = 5e3
|
|
@@ -2411,7 +2201,7 @@ var StateManager = class {
|
|
|
2411
2201
|
return null
|
|
2412
2202
|
}
|
|
2413
2203
|
}
|
|
2414
|
-
|
|
2204
|
+
|
|
2415
2205
|
saveDebounced(state) {
|
|
2416
2206
|
if (this.debounceTimer) {
|
|
2417
2207
|
clearTimeout(this.debounceTimer)
|
|
@@ -2421,7 +2211,7 @@ var StateManager = class {
|
|
|
2421
2211
|
this.debounceTimer = null
|
|
2422
2212
|
}, DEBOUNCE_MS)
|
|
2423
2213
|
}
|
|
2424
|
-
|
|
2214
|
+
|
|
2425
2215
|
saveImmediate(state) {
|
|
2426
2216
|
if (this.debounceTimer) {
|
|
2427
2217
|
clearTimeout(this.debounceTimer)
|
|
@@ -2429,7 +2219,7 @@ var StateManager = class {
|
|
|
2429
2219
|
}
|
|
2430
2220
|
this.writeFile(state)
|
|
2431
2221
|
}
|
|
2432
|
-
|
|
2222
|
+
|
|
2433
2223
|
flush() {
|
|
2434
2224
|
if (this.debounceTimer) {
|
|
2435
2225
|
clearTimeout(this.debounceTimer)
|
|
@@ -2443,7 +2233,7 @@ var StateManager = class {
|
|
|
2443
2233
|
const toSave = {
|
|
2444
2234
|
...state,
|
|
2445
2235
|
savedAt: Date.now(),
|
|
2446
|
-
|
|
2236
|
+
|
|
2447
2237
|
knownChats:
|
|
2448
2238
|
state.knownChats.length > KNOWN_CHATS_MAX ? state.knownChats.slice(-KNOWN_CHATS_MAX) : state.knownChats
|
|
2449
2239
|
}
|
|
@@ -2455,7 +2245,7 @@ var StateManager = class {
|
|
|
2455
2245
|
}
|
|
2456
2246
|
}
|
|
2457
2247
|
|
|
2458
|
-
|
|
2248
|
+
|
|
2459
2249
|
function isGroup(jid) {
|
|
2460
2250
|
return jid.endsWith('@g.us')
|
|
2461
2251
|
}
|
|
@@ -2476,26 +2266,23 @@ function applyGroupMultiplier(limits, multiplier) {
|
|
|
2476
2266
|
}
|
|
2477
2267
|
}
|
|
2478
2268
|
|
|
2479
|
-
|
|
2480
|
-
|
|
2269
|
+
|
|
2270
|
+
|
|
2271
|
+
|
|
2272
|
+
|
|
2273
|
+
|
|
2274
|
+
|
|
2275
|
+
|
|
2276
|
+
|
|
2277
|
+
const CORE_LEGACY_KEYS = ['rateLimiter', 'warmUp']
|
|
2278
|
+
function hasLegacyCoreNesting(cfg) {
|
|
2481
2279
|
if (typeof cfg !== 'object' || cfg === null) return false
|
|
2482
|
-
return (
|
|
2483
|
-
'rateLimiter' in cfg ||
|
|
2484
|
-
'warmUp' in cfg ||
|
|
2485
|
-
'health' in cfg ||
|
|
2486
|
-
'timelock' in cfg ||
|
|
2487
|
-
'replyRatio' in cfg ||
|
|
2488
|
-
'contactGraph' in cfg ||
|
|
2489
|
-
'presence' in cfg ||
|
|
2490
|
-
'retryTracker' in cfg ||
|
|
2491
|
-
'reconnectThrottle' in cfg ||
|
|
2492
|
-
'lidResolver' in cfg ||
|
|
2493
|
-
'jidCanonicalizer' in cfg ||
|
|
2494
|
-
'sessionStability' in cfg
|
|
2495
|
-
)
|
|
2280
|
+
return CORE_LEGACY_KEYS.some(key => key in cfg)
|
|
2496
2281
|
}
|
|
2497
2282
|
function mapLegacyToFlat(legacy) {
|
|
2498
|
-
process.stderr.write(
|
|
2283
|
+
process.stderr.write(
|
|
2284
|
+
'[baileys-antiban] DEPRECATED: nested { rateLimiter, warmUp } config detected. Migrate to flat fields: new AntiBan({ maxPerMinute: 8, warmupDays: 5 }). Flat top-level fields you also pass always take precedence.\n'
|
|
2285
|
+
)
|
|
2499
2286
|
const flat = {}
|
|
2500
2287
|
if (legacy.rateLimiter?.maxPerMinute !== void 0) flat.maxPerMinute = legacy.rateLimiter.maxPerMinute
|
|
2501
2288
|
if (legacy.rateLimiter?.maxPerHour !== void 0) flat.maxPerHour = legacy.rateLimiter.maxPerHour
|
|
@@ -2506,7 +2293,6 @@ function mapLegacyToFlat(legacy) {
|
|
|
2506
2293
|
if (legacy.warmUp?.warmUpDays !== void 0) flat.warmupDays = legacy.warmUp.warmUpDays
|
|
2507
2294
|
if (legacy.warmUp?.day1Limit !== void 0) flat.day1Limit = legacy.warmUp.day1Limit
|
|
2508
2295
|
if (legacy.warmUp?.growthFactor !== void 0) flat.growthFactor = legacy.warmUp.growthFactor
|
|
2509
|
-
if (legacy.logging !== void 0) flat.logging = legacy.logging
|
|
2510
2296
|
return flat
|
|
2511
2297
|
}
|
|
2512
2298
|
var AntiBan = class {
|
|
@@ -2531,18 +2317,29 @@ var AntiBan = class {
|
|
|
2531
2317
|
totalDelayMs: 0
|
|
2532
2318
|
}
|
|
2533
2319
|
constructor(input, warmUpStateArg) {
|
|
2534
|
-
let flatConfig
|
|
2535
|
-
let legacyPassthrough = null
|
|
2536
2320
|
let warmUpState = warmUpStateArg
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
const
|
|
2321
|
+
|
|
2322
|
+
|
|
2323
|
+
|
|
2324
|
+
|
|
2325
|
+
const rawInput = typeof input === 'object' && input !== null ? input : {}
|
|
2326
|
+
const legacyNested = hasLegacyCoreNesting(rawInput)
|
|
2327
|
+
|
|
2328
|
+
const flatMerged = legacyNested ? { ...mapLegacyToFlat(rawInput), ...rawInput } : rawInput
|
|
2329
|
+
const cfg = typeof input === 'string' ? resolveConfig(input) : resolveConfig(flatMerged)
|
|
2545
2330
|
this.resolvedConfig = cfg
|
|
2331
|
+
const rateLimiterOverrides = rawInput.rateLimiter || {}
|
|
2332
|
+
const warmUpOverrides = rawInput.warmUp || {}
|
|
2333
|
+
const healthOverrides = rawInput.health || {}
|
|
2334
|
+
const timelockOverrides = rawInput.timelock || {}
|
|
2335
|
+
const replyRatioCfg = rawInput.replyRatio
|
|
2336
|
+
const contactGraphCfg = rawInput.contactGraph
|
|
2337
|
+
const presenceCfg = rawInput.presence
|
|
2338
|
+
const retryTrackerCfg = rawInput.retryTracker
|
|
2339
|
+
const reconnectThrottleCfg = rawInput.reconnectThrottle
|
|
2340
|
+
const lidResolverCfg = rawInput.lidResolver
|
|
2341
|
+
const jidCanonicalizerCfg = rawInput.jidCanonicalizer
|
|
2342
|
+
const sessionStabilityCfg = rawInput.sessionStability
|
|
2546
2343
|
let savedState = null
|
|
2547
2344
|
if (cfg.persist) {
|
|
2548
2345
|
this.stateManager = new StateManager(cfg.persist)
|
|
@@ -2552,7 +2349,9 @@ var AntiBan = class {
|
|
|
2552
2349
|
}
|
|
2553
2350
|
}
|
|
2554
2351
|
this.logging = cfg.logging ?? true
|
|
2555
|
-
this._log =
|
|
2352
|
+
this._log = msg => {
|
|
2353
|
+
if (this.logging) process.stdout.write(`[baileys-antiban] ${msg}\n`)
|
|
2354
|
+
}
|
|
2556
2355
|
this.rateLimiter = new RateLimiter({
|
|
2557
2356
|
maxPerMinute: cfg.maxPerMinute,
|
|
2558
2357
|
maxPerHour: cfg.maxPerHour,
|
|
@@ -2560,7 +2359,7 @@ var AntiBan = class {
|
|
|
2560
2359
|
minDelayMs: cfg.minDelayMs,
|
|
2561
2360
|
maxDelayMs: cfg.maxDelayMs,
|
|
2562
2361
|
newChatDelayMs: cfg.newChatDelayMs,
|
|
2563
|
-
...
|
|
2362
|
+
...rateLimiterOverrides
|
|
2564
2363
|
})
|
|
2565
2364
|
if (savedState?.knownChats) {
|
|
2566
2365
|
this.rateLimiter.restoreKnownChats(savedState.knownChats)
|
|
@@ -2571,69 +2370,73 @@ var AntiBan = class {
|
|
|
2571
2370
|
day1Limit: cfg.day1Limit,
|
|
2572
2371
|
growthFactor: cfg.growthFactor,
|
|
2573
2372
|
inactivityThresholdHours: cfg.inactivityThresholdHours,
|
|
2574
|
-
...
|
|
2373
|
+
...warmUpOverrides
|
|
2575
2374
|
},
|
|
2576
2375
|
warmUpState
|
|
2577
2376
|
)
|
|
2578
2377
|
this.health = new HealthMonitor({
|
|
2579
2378
|
autoPauseAt: cfg.autoPauseAt,
|
|
2580
|
-
...
|
|
2379
|
+
...healthOverrides,
|
|
2581
2380
|
onRiskChange: status => {
|
|
2582
2381
|
const emoji = { low: '\u{1F7E2}', medium: '\u{1F7E1}', high: '\u{1F7E0}', critical: '\u{1F534}' }
|
|
2583
2382
|
this._log(`${emoji[status.risk]} Risk level: ${status.risk.toUpperCase()} (score: ${status.score})`)
|
|
2584
2383
|
this._log(status.recommendation)
|
|
2585
2384
|
status.reasons.forEach(r => this._log(` \u2192 ${r}`))
|
|
2586
|
-
|
|
2385
|
+
healthOverrides.onRiskChange?.(status)
|
|
2587
2386
|
}
|
|
2588
2387
|
})
|
|
2589
2388
|
this.timelockGuard = new TimelockGuard({
|
|
2590
|
-
...
|
|
2389
|
+
...timelockOverrides,
|
|
2591
2390
|
onTimelockDetected: state => {
|
|
2592
2391
|
this.health.recordReachoutTimelock(state.enforcementType)
|
|
2593
|
-
this._log(
|
|
2594
|
-
|
|
2392
|
+
this._log(
|
|
2393
|
+
`REACHOUT TIMELOCKED \u2014 ${state.enforcementType || 'unknown'}, expires ${state.expiresAt?.toISOString() || 'unknown'}`
|
|
2394
|
+
)
|
|
2395
|
+
timelockOverrides.onTimelockDetected?.(state)
|
|
2595
2396
|
},
|
|
2596
2397
|
onTimelockLifted: state => {
|
|
2597
2398
|
this._log('Timelock lifted \u2014 resuming new contact messages')
|
|
2598
|
-
|
|
2399
|
+
timelockOverrides.onTimelockLifted?.(state)
|
|
2599
2400
|
}
|
|
2600
2401
|
})
|
|
2601
|
-
this.replyRatioGuard = new ReplyRatioGuard(
|
|
2602
|
-
this.contactGraphWarmer = new ContactGraphWarmer(
|
|
2603
|
-
this.presenceChoreographer = new PresenceChoreographer(
|
|
2402
|
+
this.replyRatioGuard = new ReplyRatioGuard(replyRatioCfg)
|
|
2403
|
+
this.contactGraphWarmer = new ContactGraphWarmer(contactGraphCfg)
|
|
2404
|
+
this.presenceChoreographer = new PresenceChoreographer(presenceCfg)
|
|
2604
2405
|
this.retryTrackerModule = new RetryReasonTracker({
|
|
2605
|
-
...(
|
|
2406
|
+
...(retryTrackerCfg || {}),
|
|
2606
2407
|
onSpiral: (msgId, reason) => {
|
|
2607
2408
|
this._log(`\u26A0\uFE0F Message ${msgId} stuck in retry spiral (${reason})`)
|
|
2608
|
-
|
|
2409
|
+
retryTrackerCfg?.onSpiral?.(msgId, reason)
|
|
2609
2410
|
}
|
|
2610
2411
|
})
|
|
2611
2412
|
this.reconnectThrottleModule = new PostReconnectThrottle({
|
|
2612
|
-
...(
|
|
2413
|
+
...(reconnectThrottleCfg || {}),
|
|
2613
2414
|
baselineRatePerMinute: () => this.rateLimiter.getStats().limits.perMinute
|
|
2614
2415
|
})
|
|
2615
|
-
if (
|
|
2616
|
-
if (
|
|
2617
|
-
this.jidCanonicalizerModule = new JidCanonicalizer(
|
|
2618
|
-
this.lidResolverModule =
|
|
2416
|
+
if (jidCanonicalizerCfg?.enabled) {
|
|
2417
|
+
if (jidCanonicalizerCfg.resolver) {
|
|
2418
|
+
this.jidCanonicalizerModule = new JidCanonicalizer(jidCanonicalizerCfg)
|
|
2419
|
+
this.lidResolverModule = jidCanonicalizerCfg.resolver
|
|
2619
2420
|
} else {
|
|
2620
|
-
const resolverConfig =
|
|
2421
|
+
const resolverConfig = lidResolverCfg || jidCanonicalizerCfg.resolverConfig
|
|
2621
2422
|
const resolver = new LidResolver(resolverConfig)
|
|
2622
2423
|
this.lidResolverModule = resolver
|
|
2623
2424
|
this.jidCanonicalizerModule = new JidCanonicalizer({
|
|
2624
|
-
...
|
|
2425
|
+
...jidCanonicalizerCfg,
|
|
2625
2426
|
resolver
|
|
2626
2427
|
})
|
|
2627
2428
|
}
|
|
2628
|
-
} else if (
|
|
2629
|
-
this.lidResolverModule = new LidResolver(
|
|
2429
|
+
} else if (lidResolverCfg) {
|
|
2430
|
+
this.lidResolverModule = new LidResolver(lidResolverCfg)
|
|
2630
2431
|
}
|
|
2631
|
-
if (
|
|
2432
|
+
if (sessionStabilityCfg?.enabled) {
|
|
2632
2433
|
const healthConfig = {
|
|
2633
|
-
badMacThreshold:
|
|
2634
|
-
badMacWindowMs:
|
|
2434
|
+
badMacThreshold: sessionStabilityCfg.badMacThreshold,
|
|
2435
|
+
badMacWindowMs: sessionStabilityCfg.badMacWindowMs,
|
|
2635
2436
|
onDegraded: stats => {
|
|
2636
|
-
this._log(
|
|
2437
|
+
this._log(
|
|
2438
|
+
`\u{1F534} SESSION DEGRADED \u2014 Bad MAC rate: ${stats.badMacCount} in last ${sessionStabilityCfg.badMacWindowMs || 6e4}ms`
|
|
2439
|
+
)
|
|
2637
2440
|
this._log('Consider restarting session or switching to LID-based canonical form')
|
|
2638
2441
|
},
|
|
2639
2442
|
onRecovered: () => {
|
|
@@ -2643,11 +2446,8 @@ var AntiBan = class {
|
|
|
2643
2446
|
this.sessionStabilityMonitor = new SessionHealthMonitor(healthConfig)
|
|
2644
2447
|
}
|
|
2645
2448
|
}
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
* Call this BEFORE every sendMessage().
|
|
2649
|
-
*/
|
|
2650
|
-
async beforeSend(recipient, content) {
|
|
2449
|
+
|
|
2450
|
+
async beforeSend(recipient, content, dedupKey) {
|
|
2651
2451
|
const healthStatus = this.health.getStatus()
|
|
2652
2452
|
if (this.health.isPaused()) {
|
|
2653
2453
|
this.stats.messagesBlocked++
|
|
@@ -2673,7 +2473,9 @@ var AntiBan = class {
|
|
|
2673
2473
|
if (!this.warmUp.canSend()) {
|
|
2674
2474
|
this.stats.messagesBlocked++
|
|
2675
2475
|
const warmUpStatus = this.warmUp.getStatus()
|
|
2676
|
-
this._log(
|
|
2476
|
+
this._log(
|
|
2477
|
+
`\u23F3 BLOCKED \u2014 warm-up day ${warmUpStatus.day}/${warmUpStatus.totalDays}, limit reached (${warmUpStatus.todaySent}/${warmUpStatus.todayLimit})`
|
|
2478
|
+
)
|
|
2677
2479
|
return {
|
|
2678
2480
|
allowed: false,
|
|
2679
2481
|
delayMs: 0,
|
|
@@ -2735,7 +2537,7 @@ var AntiBan = class {
|
|
|
2735
2537
|
return { allowed: false, delayMs: 0, reason: 'Group rate limit exceeded', health: healthStatus }
|
|
2736
2538
|
}
|
|
2737
2539
|
}
|
|
2738
|
-
let delay = await this.rateLimiter.getDelay(recipient, content)
|
|
2540
|
+
let delay = await this.rateLimiter.getDelay(recipient, content, dedupKey)
|
|
2739
2541
|
if (delay === -1) {
|
|
2740
2542
|
this.stats.messagesBlocked++
|
|
2741
2543
|
this._log(`\u{1F6AB} BLOCKED \u2014 rate limit or identical message spam`)
|
|
@@ -2768,26 +2570,19 @@ var AntiBan = class {
|
|
|
2768
2570
|
health: healthStatus
|
|
2769
2571
|
}
|
|
2770
2572
|
}
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
*/
|
|
2775
|
-
afterSend(recipient, content) {
|
|
2776
|
-
this.rateLimiter.record(recipient, content)
|
|
2573
|
+
|
|
2574
|
+
afterSend(recipient, content, dedupKey) {
|
|
2575
|
+
this.rateLimiter.record(recipient, content, dedupKey)
|
|
2777
2576
|
this.warmUp.record()
|
|
2778
2577
|
this.replyRatioGuard.recordSent(recipient)
|
|
2779
2578
|
this.stats.messagesAllowed++
|
|
2780
2579
|
this.persistStateDebounced()
|
|
2781
2580
|
}
|
|
2782
|
-
|
|
2783
|
-
* Record a failed message send
|
|
2784
|
-
*/
|
|
2581
|
+
|
|
2785
2582
|
afterSendFailed(error) {
|
|
2786
2583
|
this.health.recordMessageFailed(error)
|
|
2787
2584
|
}
|
|
2788
|
-
|
|
2789
|
-
* Record a disconnection (call from connection.update handler)
|
|
2790
|
-
*/
|
|
2585
|
+
|
|
2791
2586
|
onDisconnect(reason) {
|
|
2792
2587
|
this.health.recordDisconnect(reason)
|
|
2793
2588
|
this.reconnectThrottleModule.onDisconnect()
|
|
@@ -2796,25 +2591,18 @@ var AntiBan = class {
|
|
|
2796
2591
|
this.persistStateImmediate()
|
|
2797
2592
|
}
|
|
2798
2593
|
}
|
|
2799
|
-
|
|
2800
|
-
* Record a successful reconnection
|
|
2801
|
-
*/
|
|
2594
|
+
|
|
2802
2595
|
onReconnect() {
|
|
2803
2596
|
this.health.recordReconnect()
|
|
2804
2597
|
this.reconnectThrottleModule.onReconnect()
|
|
2805
2598
|
}
|
|
2806
|
-
|
|
2807
|
-
* Handle incoming message — record in reply ratio + contact graph.
|
|
2808
|
-
* Returns suggested reply if reply ratio suggests auto-reply.
|
|
2809
|
-
*/
|
|
2599
|
+
|
|
2810
2600
|
onIncomingMessage(jid, msgText) {
|
|
2811
2601
|
this.replyRatioGuard.recordReceived(jid)
|
|
2812
2602
|
this.contactGraphWarmer.onIncomingMessage(jid)
|
|
2813
2603
|
return this.replyRatioGuard.suggestReply(jid, msgText)
|
|
2814
2604
|
}
|
|
2815
|
-
|
|
2816
|
-
* Get comprehensive stats
|
|
2817
|
-
*/
|
|
2605
|
+
|
|
2818
2606
|
getStats() {
|
|
2819
2607
|
const stats = {
|
|
2820
2608
|
...this.stats,
|
|
@@ -2848,65 +2636,57 @@ var AntiBan = class {
|
|
|
2848
2636
|
}
|
|
2849
2637
|
return stats
|
|
2850
2638
|
}
|
|
2851
|
-
|
|
2639
|
+
|
|
2852
2640
|
get timelock() {
|
|
2853
2641
|
return this.timelockGuard
|
|
2854
2642
|
}
|
|
2855
|
-
|
|
2643
|
+
|
|
2856
2644
|
get replyRatio() {
|
|
2857
2645
|
return this.replyRatioGuard
|
|
2858
2646
|
}
|
|
2859
|
-
|
|
2647
|
+
|
|
2860
2648
|
get contactGraph() {
|
|
2861
2649
|
return this.contactGraphWarmer
|
|
2862
2650
|
}
|
|
2863
|
-
|
|
2651
|
+
|
|
2864
2652
|
get presence() {
|
|
2865
2653
|
return this.presenceChoreographer
|
|
2866
2654
|
}
|
|
2867
|
-
|
|
2655
|
+
|
|
2868
2656
|
get retryTracker() {
|
|
2869
2657
|
return this.retryTrackerModule
|
|
2870
2658
|
}
|
|
2871
|
-
|
|
2659
|
+
|
|
2872
2660
|
get reconnectThrottle() {
|
|
2873
2661
|
return this.reconnectThrottleModule
|
|
2874
2662
|
}
|
|
2875
|
-
|
|
2663
|
+
|
|
2876
2664
|
get lidResolver() {
|
|
2877
2665
|
return this.lidResolverModule
|
|
2878
2666
|
}
|
|
2879
|
-
|
|
2667
|
+
|
|
2880
2668
|
get jidCanonicalizer() {
|
|
2881
2669
|
return this.jidCanonicalizerModule
|
|
2882
2670
|
}
|
|
2883
|
-
|
|
2671
|
+
|
|
2884
2672
|
get sessionStability() {
|
|
2885
2673
|
return this.sessionStabilityMonitor
|
|
2886
2674
|
}
|
|
2887
|
-
|
|
2888
|
-
* Export warm-up state for persistence between restarts
|
|
2889
|
-
*/
|
|
2675
|
+
|
|
2890
2676
|
exportWarmUpState() {
|
|
2891
2677
|
return this.warmUp.exportState()
|
|
2892
2678
|
}
|
|
2893
|
-
|
|
2894
|
-
* Force pause all sending
|
|
2895
|
-
*/
|
|
2679
|
+
|
|
2896
2680
|
pause() {
|
|
2897
2681
|
this.health.setPaused(true)
|
|
2898
2682
|
this._log('\u23F8\uFE0F Sending paused manually')
|
|
2899
2683
|
}
|
|
2900
|
-
|
|
2901
|
-
* Resume sending
|
|
2902
|
-
*/
|
|
2684
|
+
|
|
2903
2685
|
resume() {
|
|
2904
2686
|
this.health.setPaused(false)
|
|
2905
2687
|
this._log('\u25B6\uFE0F Sending resumed')
|
|
2906
2688
|
}
|
|
2907
|
-
|
|
2908
|
-
* Reset everything (use after a ban period)
|
|
2909
|
-
*/
|
|
2689
|
+
|
|
2910
2690
|
reset() {
|
|
2911
2691
|
this.timelockGuard.reset()
|
|
2912
2692
|
this.health.reset()
|
|
@@ -2939,10 +2719,7 @@ var AntiBan = class {
|
|
|
2939
2719
|
}
|
|
2940
2720
|
this.stateManager.saveImmediate(state)
|
|
2941
2721
|
}
|
|
2942
|
-
|
|
2943
|
-
* Clean up all timers and resources.
|
|
2944
|
-
* Call this when disposing of the AntiBan instance or when the socket closes.
|
|
2945
|
-
*/
|
|
2722
|
+
|
|
2946
2723
|
destroy() {
|
|
2947
2724
|
this.stateManager?.destroy()
|
|
2948
2725
|
this.timelockGuard.reset()
|
|
@@ -2958,17 +2735,14 @@ var AntiBan = class {
|
|
|
2958
2735
|
}
|
|
2959
2736
|
}
|
|
2960
2737
|
|
|
2961
|
-
|
|
2738
|
+
|
|
2962
2739
|
var fs2 = __toESM(require('fs'), 1)
|
|
2963
2740
|
var path = __toESM(require('path'), 1)
|
|
2964
2741
|
var LidFirstResolver = class {
|
|
2965
|
-
lidToPhone =
|
|
2966
|
-
phoneToLid =
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
* Load mappings from Baileys auth state directory.
|
|
2970
|
-
* Looks for lid-mapping-*_reverse.json files.
|
|
2971
|
-
*/
|
|
2742
|
+
lidToPhone = new Map()
|
|
2743
|
+
phoneToLid = new Map()
|
|
2744
|
+
|
|
2745
|
+
|
|
2972
2746
|
loadFromAuthDir(authDir) {
|
|
2973
2747
|
try {
|
|
2974
2748
|
if (!fs2.existsSync(authDir)) {
|
|
@@ -2998,10 +2772,7 @@ var LidFirstResolver = class {
|
|
|
2998
2772
|
}
|
|
2999
2773
|
} catch (error) {}
|
|
3000
2774
|
}
|
|
3001
|
-
|
|
3002
|
-
* Learn a new mapping from a Baileys event (messages, contacts, etc.).
|
|
3003
|
-
* Accepts partial data — will extract what it can.
|
|
3004
|
-
*/
|
|
2775
|
+
|
|
3005
2776
|
learnFromEvent(event) {
|
|
3006
2777
|
try {
|
|
3007
2778
|
if (event.key?.remoteJid) {
|
|
@@ -3020,28 +2791,19 @@ var LidFirstResolver = class {
|
|
|
3020
2791
|
}
|
|
3021
2792
|
} catch (error) {}
|
|
3022
2793
|
}
|
|
3023
|
-
|
|
3024
|
-
* Resolve phone number or phone JID to LID JID.
|
|
3025
|
-
* Returns null if not known.
|
|
3026
|
-
*/
|
|
2794
|
+
|
|
3027
2795
|
resolveToLID(phoneOrJid) {
|
|
3028
2796
|
const phone = this.extractPhone(phoneOrJid)
|
|
3029
2797
|
if (!phone) return null
|
|
3030
2798
|
return this.phoneToLid.get(phone) || null
|
|
3031
2799
|
}
|
|
3032
|
-
|
|
3033
|
-
* Resolve LID JID to phone number.
|
|
3034
|
-
* Returns null if not known.
|
|
3035
|
-
*/
|
|
2800
|
+
|
|
3036
2801
|
resolveToPhone(lid) {
|
|
3037
2802
|
const normalized = this.normalizeLid(lid)
|
|
3038
2803
|
const mapping = this.lidToPhone.get(normalized)
|
|
3039
2804
|
return mapping ? mapping.phone : null
|
|
3040
2805
|
}
|
|
3041
|
-
|
|
3042
|
-
* Get full mapping for a given JID (either LID or phone).
|
|
3043
|
-
* Returns null if not known.
|
|
3044
|
-
*/
|
|
2806
|
+
|
|
3045
2807
|
getMapping(jid) {
|
|
3046
2808
|
const normalized = this.normalizeLid(jid)
|
|
3047
2809
|
const byLid = this.lidToPhone.get(normalized)
|
|
@@ -3053,20 +2815,16 @@ var LidFirstResolver = class {
|
|
|
3053
2815
|
}
|
|
3054
2816
|
return null
|
|
3055
2817
|
}
|
|
3056
|
-
|
|
3057
|
-
* Get total number of known mappings.
|
|
3058
|
-
*/
|
|
2818
|
+
|
|
3059
2819
|
size() {
|
|
3060
2820
|
return this.lidToPhone.size
|
|
3061
2821
|
}
|
|
3062
|
-
|
|
3063
|
-
* Clear all mappings.
|
|
3064
|
-
*/
|
|
2822
|
+
|
|
3065
2823
|
clear() {
|
|
3066
2824
|
this.lidToPhone.clear()
|
|
3067
2825
|
this.phoneToLid.clear()
|
|
3068
2826
|
}
|
|
3069
|
-
|
|
2827
|
+
|
|
3070
2828
|
learnJid(_jid, _source) {}
|
|
3071
2829
|
extractPhone(jid) {
|
|
3072
2830
|
if (!jid) return null
|
|
@@ -3085,7 +2843,7 @@ function createLidFirstResolver() {
|
|
|
3085
2843
|
return new LidFirstResolver()
|
|
3086
2844
|
}
|
|
3087
2845
|
|
|
3088
|
-
|
|
2846
|
+
|
|
3089
2847
|
var MessageRetryReason
|
|
3090
2848
|
;(function (MessageRetryReason2) {
|
|
3091
2849
|
MessageRetryReason2[(MessageRetryReason2['UnknownError'] = 0)] = 'UnknownError'
|
|
@@ -3097,7 +2855,7 @@ var MessageRetryReason
|
|
|
3097
2855
|
MessageRetryReason2[(MessageRetryReason2['MessageExpired'] = 8)] = 'MessageExpired'
|
|
3098
2856
|
MessageRetryReason2[(MessageRetryReason2['DecryptionError'] = 9)] = 'DecryptionError'
|
|
3099
2857
|
})(MessageRetryReason || (MessageRetryReason = {}))
|
|
3100
|
-
var MAC_ERROR_CODES =
|
|
2858
|
+
var MAC_ERROR_CODES = new Set([
|
|
3101
2859
|
MessageRetryReason.SignalErrorBadMac,
|
|
3102
2860
|
MessageRetryReason.SignalErrorInvalidMessage,
|
|
3103
2861
|
MessageRetryReason.SignalErrorNoSession,
|
|
@@ -3142,133 +2900,171 @@ function getRetryReasonDescription(reason) {
|
|
|
3142
2900
|
}
|
|
3143
2901
|
}
|
|
3144
2902
|
|
|
3145
|
-
|
|
2903
|
+
|
|
2904
|
+
|
|
2905
|
+
function mediaFingerprint(media) {
|
|
2906
|
+
if (Buffer.isBuffer(media)) {
|
|
2907
|
+
const len = media.length
|
|
2908
|
+
const head = media.subarray(0, Math.min(24, len)).toString('hex')
|
|
2909
|
+
const tail = len > 24 ? media.subarray(Math.max(24, len - 24)).toString('hex') : ''
|
|
2910
|
+
return `buf:${len}:${head}:${tail}`
|
|
2911
|
+
}
|
|
2912
|
+
if (media && typeof media === 'object' && typeof media.url === 'string') {
|
|
2913
|
+
return `url:${media.url}`
|
|
2914
|
+
}
|
|
2915
|
+
if (typeof media === 'string') {
|
|
2916
|
+
return `str:${media}`
|
|
2917
|
+
}
|
|
2918
|
+
if (media && typeof media === 'object') {
|
|
2919
|
+
|
|
2920
|
+
|
|
2921
|
+
|
|
2922
|
+
return `unresolvable:${Math.random().toString(36)}`
|
|
2923
|
+
}
|
|
2924
|
+
return 'none'
|
|
2925
|
+
}
|
|
2926
|
+
|
|
2927
|
+
function buildContentSignature(content) {
|
|
2928
|
+
if (!content || typeof content !== 'object') return String(content ?? '')
|
|
2929
|
+
const parts = []
|
|
2930
|
+
const text =
|
|
2931
|
+
content.text ||
|
|
2932
|
+
content.caption ||
|
|
2933
|
+
content.image?.caption ||
|
|
2934
|
+
content.video?.caption ||
|
|
2935
|
+
content.document?.caption ||
|
|
2936
|
+
''
|
|
2937
|
+
if (text) parts.push(`text:${text}`)
|
|
2938
|
+
if (content.image !== undefined) parts.push(`image:${mediaFingerprint(content.image)}`)
|
|
2939
|
+
if (content.video !== undefined) parts.push(`video:${mediaFingerprint(content.video)}`)
|
|
2940
|
+
if (content.audio !== undefined) parts.push(`audio:${mediaFingerprint(content.audio)}`)
|
|
2941
|
+
if (content.sticker !== undefined) parts.push(`sticker:${mediaFingerprint(content.sticker)}`)
|
|
2942
|
+
if (content.document !== undefined) {
|
|
2943
|
+
parts.push(`document:${mediaFingerprint(content.document)}:${content.fileName || ''}`)
|
|
2944
|
+
}
|
|
2945
|
+
if (content.location) {
|
|
2946
|
+
parts.push(`location:${content.location.degreesLatitude}:${content.location.degreesLongitude}`)
|
|
2947
|
+
}
|
|
2948
|
+
if (content.contacts) {
|
|
2949
|
+
const vcards = content.contacts.contacts?.map(c => c.vcard).join('|') || JSON.stringify(content.contacts)
|
|
2950
|
+
parts.push(`contacts:${vcards}`)
|
|
2951
|
+
}
|
|
2952
|
+
if (content.poll) {
|
|
2953
|
+
parts.push(`poll:${content.poll.name}:${(content.poll.values || []).join(',')}`)
|
|
2954
|
+
}
|
|
2955
|
+
if (content.buttons) parts.push(`buttons:${JSON.stringify(content.buttons)}`)
|
|
2956
|
+
if (content.templateButtons) parts.push(`template:${JSON.stringify(content.templateButtons)}`)
|
|
2957
|
+
if (content.sections) parts.push(`sections:${JSON.stringify(content.sections)}`)
|
|
2958
|
+
if (content.react) parts.push(`react:${content.react.text}:${content.react.key?.id || ''}`)
|
|
2959
|
+
if (!parts.length) {
|
|
2960
|
+
|
|
2961
|
+
parts.push(`shape:${Object.keys(content).sort().join(',')}`)
|
|
2962
|
+
}
|
|
2963
|
+
return parts.join('|')
|
|
2964
|
+
}
|
|
3146
2965
|
function wrapSocket(sock, config, warmUpState, wrapOptions) {
|
|
3147
2966
|
const antiban = new AntiBan(config, warmUpState)
|
|
3148
2967
|
const options = {
|
|
3149
2968
|
autoRespondToIncoming: false,
|
|
3150
2969
|
...wrapOptions
|
|
3151
2970
|
}
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
}
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3177
|
-
|
|
3178
|
-
|
|
3179
|
-
|
|
3180
|
-
|
|
2971
|
+
|
|
2972
|
+
|
|
2973
|
+
|
|
2974
|
+
|
|
2975
|
+
const pendingAutoReplyTimers = new Set()
|
|
2976
|
+
const scheduleAutoReply = (jid, suggestedText) => {
|
|
2977
|
+
const replyDelay = Math.floor(Math.random() * 12e3) + 3e3
|
|
2978
|
+
const timer = setTimeout(async () => {
|
|
2979
|
+
pendingAutoReplyTimers.delete(timer)
|
|
2980
|
+
try {
|
|
2981
|
+
await sock.sendMessage(jid, { text: suggestedText })
|
|
2982
|
+
} catch (error) {}
|
|
2983
|
+
}, replyDelay)
|
|
2984
|
+
pendingAutoReplyTimers.add(timer)
|
|
2985
|
+
}
|
|
2986
|
+
const handleConnectionUpdate = update => {
|
|
2987
|
+
if (update.connection === 'close') {
|
|
2988
|
+
const reason = update.lastDisconnect?.error?.output?.statusCode || 'unknown'
|
|
2989
|
+
antiban.onDisconnect(reason)
|
|
2990
|
+
}
|
|
2991
|
+
if (update.connection === 'open') {
|
|
2992
|
+
antiban.onReconnect()
|
|
2993
|
+
}
|
|
2994
|
+
if (update.reachoutTimeLock) {
|
|
2995
|
+
antiban.timelock.onTimelockUpdate({
|
|
2996
|
+
isActive: update.reachoutTimeLock.isActive,
|
|
2997
|
+
timeEnforcementEnds: update.reachoutTimeLock.timeEnforcementEnds,
|
|
2998
|
+
enforcementType: update.reachoutTimeLock.enforcementType
|
|
2999
|
+
})
|
|
3000
|
+
}
|
|
3001
|
+
}
|
|
3002
|
+
const handleMessagesUpdate = updates => {
|
|
3003
|
+
for (const update of updates) {
|
|
3004
|
+
if (update?.update?.messageStubParameters) {
|
|
3005
|
+
const params = update.update.messageStubParameters
|
|
3006
|
+
if (params.includes(463) || params.includes('463')) {
|
|
3007
|
+
antiban.timelock.record463Error()
|
|
3181
3008
|
}
|
|
3182
|
-
antiban.jidCanonicalizer?.onMessageUpdate(updates)
|
|
3183
3009
|
}
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
|
|
3196
|
-
|
|
3197
|
-
|
|
3198
|
-
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
|
|
3206
|
-
}, replyDelay)
|
|
3207
|
-
}
|
|
3208
|
-
}
|
|
3010
|
+
antiban.retryTracker.onMessageUpdate(update)
|
|
3011
|
+
}
|
|
3012
|
+
antiban.jidCanonicalizer?.onMessageUpdate(updates)
|
|
3013
|
+
}
|
|
3014
|
+
const handleMessagesUpsert = upsert => {
|
|
3015
|
+
const { messages } = upsert
|
|
3016
|
+
antiban.jidCanonicalizer?.onIncomingEvent(upsert)
|
|
3017
|
+
for (const msg of messages || []) {
|
|
3018
|
+
const jid = msg.key?.remoteJid
|
|
3019
|
+
if (!jid) continue
|
|
3020
|
+
antiban.timelock.registerKnownChat(jid)
|
|
3021
|
+
const isSelf = msg.key?.fromMe || false
|
|
3022
|
+
if (isSelf) continue
|
|
3023
|
+
const msgText =
|
|
3024
|
+
msg.message?.conversation ||
|
|
3025
|
+
msg.message?.extendedTextMessage?.text ||
|
|
3026
|
+
msg.message?.imageMessage?.caption ||
|
|
3027
|
+
msg.message?.videoMessage?.caption ||
|
|
3028
|
+
''
|
|
3029
|
+
const replySuggestion = antiban.onIncomingMessage(jid, msgText)
|
|
3030
|
+
if (options.autoRespondToIncoming && replySuggestion.shouldReply && replySuggestion.suggestedText) {
|
|
3031
|
+
scheduleAutoReply(jid, replySuggestion.suggestedText)
|
|
3209
3032
|
}
|
|
3210
|
-
}
|
|
3033
|
+
}
|
|
3034
|
+
}
|
|
3035
|
+
let stopEventBridge = () => {}
|
|
3036
|
+
if (typeof sock.ev.process === 'function') {
|
|
3037
|
+
const processListener = async events => {
|
|
3038
|
+
if (events['connection.update']) handleConnectionUpdate(events['connection.update'])
|
|
3039
|
+
if (events['messages.update']) handleMessagesUpdate(events['messages.update'])
|
|
3040
|
+
if (events['messages.upsert']) handleMessagesUpsert(events['messages.upsert'])
|
|
3041
|
+
}
|
|
3042
|
+
const maybeUnsubscribe = sock.ev.process(processListener)
|
|
3043
|
+
if (typeof maybeUnsubscribe === 'function') {
|
|
3044
|
+
stopEventBridge = maybeUnsubscribe
|
|
3045
|
+
}
|
|
3211
3046
|
} else {
|
|
3212
|
-
sock.ev.on('connection.update',
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
|
|
3219
|
-
|
|
3220
|
-
if (update.reachoutTimeLock) {
|
|
3221
|
-
antiban.timelock.onTimelockUpdate({
|
|
3222
|
-
isActive: update.reachoutTimeLock.isActive,
|
|
3223
|
-
timeEnforcementEnds: update.reachoutTimeLock.timeEnforcementEnds,
|
|
3224
|
-
enforcementType: update.reachoutTimeLock.enforcementType
|
|
3225
|
-
})
|
|
3226
|
-
}
|
|
3227
|
-
})
|
|
3228
|
-
sock.ev.on('messages.update', updates => {
|
|
3229
|
-
for (const update of updates) {
|
|
3230
|
-
if (update?.update?.messageStubParameters) {
|
|
3231
|
-
const params = update.update.messageStubParameters
|
|
3232
|
-
if (params.includes(463) || params.includes('463')) {
|
|
3233
|
-
antiban.timelock.record463Error()
|
|
3234
|
-
}
|
|
3235
|
-
}
|
|
3236
|
-
antiban.retryTracker.onMessageUpdate(update)
|
|
3237
|
-
}
|
|
3238
|
-
antiban.jidCanonicalizer?.onMessageUpdate(updates)
|
|
3239
|
-
})
|
|
3240
|
-
sock.ev.on('messages.upsert', upsert => {
|
|
3241
|
-
const { messages } = upsert
|
|
3242
|
-
antiban.jidCanonicalizer?.onIncomingEvent(upsert)
|
|
3243
|
-
for (const msg of messages || []) {
|
|
3244
|
-
const jid = msg.key?.remoteJid
|
|
3245
|
-
if (!jid) continue
|
|
3246
|
-
antiban.timelock.registerKnownChat(jid)
|
|
3247
|
-
const isSelf = msg.key?.fromMe || false
|
|
3248
|
-
if (isSelf) continue
|
|
3249
|
-
const msgText =
|
|
3250
|
-
msg.message?.conversation ||
|
|
3251
|
-
msg.message?.extendedTextMessage?.text ||
|
|
3252
|
-
msg.message?.imageMessage?.caption ||
|
|
3253
|
-
msg.message?.videoMessage?.caption ||
|
|
3254
|
-
''
|
|
3255
|
-
const replySuggestion = antiban.onIncomingMessage(jid, msgText)
|
|
3256
|
-
if (options.autoRespondToIncoming && replySuggestion.shouldReply && replySuggestion.suggestedText) {
|
|
3257
|
-
const replyDelay = Math.floor(Math.random() * 12e3) + 3e3
|
|
3258
|
-
setTimeout(async () => {
|
|
3259
|
-
try {
|
|
3260
|
-
await sock.sendMessage(jid, { text: replySuggestion.suggestedText })
|
|
3261
|
-
} catch (error) {}
|
|
3262
|
-
}, replyDelay)
|
|
3263
|
-
}
|
|
3264
|
-
}
|
|
3265
|
-
})
|
|
3047
|
+
sock.ev.on('connection.update', handleConnectionUpdate)
|
|
3048
|
+
sock.ev.on('messages.update', handleMessagesUpdate)
|
|
3049
|
+
sock.ev.on('messages.upsert', handleMessagesUpsert)
|
|
3050
|
+
stopEventBridge = () => {
|
|
3051
|
+
sock.ev.off('connection.update', handleConnectionUpdate)
|
|
3052
|
+
sock.ev.off('messages.update', handleMessagesUpdate)
|
|
3053
|
+
sock.ev.off('messages.upsert', handleMessagesUpsert)
|
|
3054
|
+
}
|
|
3266
3055
|
}
|
|
3267
3056
|
const originalSendMessage = sock.sendMessage.bind(sock)
|
|
3268
3057
|
const wrappedSendMessage = async (jid, content, options2) => {
|
|
3269
3058
|
const canonicalJid = antiban.jidCanonicalizer?.canonicalizeTarget(jid) || jid
|
|
3270
|
-
const text =
|
|
3271
|
-
|
|
3059
|
+
const text =
|
|
3060
|
+
content?.text ||
|
|
3061
|
+
content?.caption ||
|
|
3062
|
+
content?.image?.caption ||
|
|
3063
|
+
content?.video?.caption ||
|
|
3064
|
+
content?.document?.caption ||
|
|
3065
|
+
''
|
|
3066
|
+
const dedupKey = buildContentSignature(content)
|
|
3067
|
+
const decision = await antiban.beforeSend(canonicalJid, text, dedupKey)
|
|
3272
3068
|
if (!decision.allowed) {
|
|
3273
3069
|
throw new Error(`[baileys-antiban] Message blocked: ${decision.reason}`)
|
|
3274
3070
|
}
|
|
@@ -3277,7 +3073,7 @@ function wrapSocket(sock, config, warmUpState, wrapOptions) {
|
|
|
3277
3073
|
}
|
|
3278
3074
|
try {
|
|
3279
3075
|
const result = await originalSendMessage(canonicalJid, content, options2)
|
|
3280
|
-
antiban.afterSend(canonicalJid, text)
|
|
3076
|
+
antiban.afterSend(canonicalJid, text, dedupKey)
|
|
3281
3077
|
antiban.timelock.registerKnownChat(canonicalJid)
|
|
3282
3078
|
if (result?.key?.id) {
|
|
3283
3079
|
antiban.retryTracker.clear(result.key.id)
|
|
@@ -3291,11 +3087,17 @@ function wrapSocket(sock, config, warmUpState, wrapOptions) {
|
|
|
3291
3087
|
const wrapped = Object.create(sock)
|
|
3292
3088
|
wrapped.sendMessage = wrappedSendMessage
|
|
3293
3089
|
wrapped.antiban = antiban
|
|
3294
|
-
|
|
3090
|
+
const originalDestroy = antiban.destroy.bind(antiban)
|
|
3091
|
+
wrapped.antiban.destroy = () => {
|
|
3092
|
+
stopEventBridge()
|
|
3093
|
+
for (const timer of pendingAutoReplyTimers) clearTimeout(timer)
|
|
3094
|
+
pendingAutoReplyTimers.clear()
|
|
3095
|
+
originalDestroy()
|
|
3096
|
+
}
|
|
3295
3097
|
return wrapped
|
|
3296
3098
|
}
|
|
3297
3099
|
|
|
3298
|
-
|
|
3100
|
+
|
|
3299
3101
|
var import_events = require('events')
|
|
3300
3102
|
var DEFAULT_CONFIG12 = {
|
|
3301
3103
|
maxAttempts: 3,
|
|
@@ -3314,16 +3116,11 @@ var MessageQueue = class extends import_events.EventEmitter {
|
|
|
3314
3116
|
super()
|
|
3315
3117
|
this.config = { ...DEFAULT_CONFIG12, ...config }
|
|
3316
3118
|
}
|
|
3317
|
-
|
|
3318
|
-
* Set the send function (called for each message when drained)
|
|
3319
|
-
* This should be the anti-ban wrapped sendMessage
|
|
3320
|
-
*/
|
|
3119
|
+
|
|
3321
3120
|
setSendFunction(fn) {
|
|
3322
3121
|
this.sendFn = fn
|
|
3323
3122
|
}
|
|
3324
|
-
|
|
3325
|
-
* Add a message to the queue
|
|
3326
|
-
*/
|
|
3123
|
+
|
|
3327
3124
|
add(recipient, content, options) {
|
|
3328
3125
|
if (this.queue.length >= this.config.maxQueueSize) {
|
|
3329
3126
|
throw new Error(`Queue full (${this.config.maxQueueSize} messages)`)
|
|
@@ -3345,23 +3142,17 @@ var MessageQueue = class extends import_events.EventEmitter {
|
|
|
3345
3142
|
this.emit('added', message)
|
|
3346
3143
|
return id
|
|
3347
3144
|
}
|
|
3348
|
-
|
|
3349
|
-
* Add multiple messages (e.g., broadcast to many recipients)
|
|
3350
|
-
*/
|
|
3145
|
+
|
|
3351
3146
|
addBulk(recipients, content, options) {
|
|
3352
3147
|
return recipients.map(r => this.add(r, content, options))
|
|
3353
3148
|
}
|
|
3354
|
-
|
|
3355
|
-
* Start processing the queue
|
|
3356
|
-
*/
|
|
3149
|
+
|
|
3357
3150
|
start(intervalMs = 1e3) {
|
|
3358
3151
|
if (this.drainTimer) return
|
|
3359
3152
|
this.drainTimer = setInterval(() => this.processNext(), intervalMs)
|
|
3360
3153
|
this.emit('started')
|
|
3361
3154
|
}
|
|
3362
|
-
|
|
3363
|
-
* Stop processing
|
|
3364
|
-
*/
|
|
3155
|
+
|
|
3365
3156
|
stop() {
|
|
3366
3157
|
if (this.drainTimer) {
|
|
3367
3158
|
clearInterval(this.drainTimer)
|
|
@@ -3369,16 +3160,11 @@ var MessageQueue = class extends import_events.EventEmitter {
|
|
|
3369
3160
|
}
|
|
3370
3161
|
this.emit('stopped')
|
|
3371
3162
|
}
|
|
3372
|
-
|
|
3373
|
-
* Clean up all timers and resources.
|
|
3374
|
-
* Call this when disposing of the queue.
|
|
3375
|
-
*/
|
|
3163
|
+
|
|
3376
3164
|
destroy() {
|
|
3377
3165
|
this.stop()
|
|
3378
3166
|
}
|
|
3379
|
-
|
|
3380
|
-
* Process the next message in the queue
|
|
3381
|
-
*/
|
|
3167
|
+
|
|
3382
3168
|
async processNext() {
|
|
3383
3169
|
if (this.processing || !this.sendFn) return
|
|
3384
3170
|
const now = Date.now()
|
|
@@ -3407,9 +3193,7 @@ var MessageQueue = class extends import_events.EventEmitter {
|
|
|
3407
3193
|
this.processing = false
|
|
3408
3194
|
}
|
|
3409
3195
|
}
|
|
3410
|
-
|
|
3411
|
-
* Get queue stats
|
|
3412
|
-
*/
|
|
3196
|
+
|
|
3413
3197
|
getStats() {
|
|
3414
3198
|
const now = Date.now()
|
|
3415
3199
|
return {
|
|
@@ -3425,31 +3209,23 @@ var MessageQueue = class extends import_events.EventEmitter {
|
|
|
3425
3209
|
isRunning: this.drainTimer !== null
|
|
3426
3210
|
}
|
|
3427
3211
|
}
|
|
3428
|
-
|
|
3429
|
-
* Clear all messages
|
|
3430
|
-
*/
|
|
3212
|
+
|
|
3431
3213
|
clear() {
|
|
3432
3214
|
const count = this.queue.length
|
|
3433
3215
|
this.queue = []
|
|
3434
3216
|
this.emit('cleared', count)
|
|
3435
3217
|
}
|
|
3436
|
-
|
|
3437
|
-
* Remove a specific message
|
|
3438
|
-
*/
|
|
3218
|
+
|
|
3439
3219
|
remove(id) {
|
|
3440
3220
|
const before = this.queue.length
|
|
3441
3221
|
this.queue = this.queue.filter(m => m.id !== id)
|
|
3442
3222
|
return this.queue.length < before
|
|
3443
3223
|
}
|
|
3444
|
-
|
|
3445
|
-
* Export queue for persistence
|
|
3446
|
-
*/
|
|
3224
|
+
|
|
3447
3225
|
export() {
|
|
3448
3226
|
return [...this.queue]
|
|
3449
3227
|
}
|
|
3450
|
-
|
|
3451
|
-
* Import queue (e.g., after restart)
|
|
3452
|
-
*/
|
|
3228
|
+
|
|
3453
3229
|
import(messages) {
|
|
3454
3230
|
this.queue = [...messages]
|
|
3455
3231
|
this.sortQueue()
|
|
@@ -3465,7 +3241,7 @@ var MessageQueue = class extends import_events.EventEmitter {
|
|
|
3465
3241
|
}
|
|
3466
3242
|
}
|
|
3467
3243
|
|
|
3468
|
-
|
|
3244
|
+
|
|
3469
3245
|
var DEFAULT_CONFIG13 = {
|
|
3470
3246
|
zeroWidthChars: true,
|
|
3471
3247
|
punctuationVariation: true,
|
|
@@ -3474,13 +3250,13 @@ var DEFAULT_CONFIG13 = {
|
|
|
3474
3250
|
}
|
|
3475
3251
|
var ZERO_WIDTH = [
|
|
3476
3252
|
'\u200B',
|
|
3477
|
-
|
|
3253
|
+
|
|
3478
3254
|
'\u200C',
|
|
3479
|
-
|
|
3255
|
+
|
|
3480
3256
|
'\u200D',
|
|
3481
|
-
|
|
3257
|
+
|
|
3482
3258
|
'\uFEFF'
|
|
3483
|
-
|
|
3259
|
+
|
|
3484
3260
|
]
|
|
3485
3261
|
var SYNONYMS = {
|
|
3486
3262
|
hello: ['hi', 'hey', 'howdy'],
|
|
@@ -3507,10 +3283,7 @@ var ContentVariator = class {
|
|
|
3507
3283
|
constructor(config = {}) {
|
|
3508
3284
|
this.config = { ...DEFAULT_CONFIG13, ...config }
|
|
3509
3285
|
}
|
|
3510
|
-
|
|
3511
|
-
* Create a unique variation of a message
|
|
3512
|
-
* Each call produces a slightly different version
|
|
3513
|
-
*/
|
|
3286
|
+
|
|
3514
3287
|
vary(text) {
|
|
3515
3288
|
let result = text
|
|
3516
3289
|
this.counter++
|
|
@@ -3531,22 +3304,15 @@ var ContentVariator = class {
|
|
|
3531
3304
|
}
|
|
3532
3305
|
return result
|
|
3533
3306
|
}
|
|
3534
|
-
|
|
3535
|
-
* Create N unique variations of a message
|
|
3536
|
-
*/
|
|
3307
|
+
|
|
3537
3308
|
varyBulk(text, count) {
|
|
3538
3309
|
const results = []
|
|
3539
|
-
const
|
|
3310
|
+
const startCounter = this.counter
|
|
3540
3311
|
for (let i = 0; i < count; i++) {
|
|
3541
|
-
|
|
3542
|
-
|
|
3543
|
-
while (seen.has(variation) && attempts < 10) {
|
|
3544
|
-
variation = this.vary(text)
|
|
3545
|
-
attempts++
|
|
3546
|
-
}
|
|
3547
|
-
seen.add(variation)
|
|
3548
|
-
results.push(variation)
|
|
3312
|
+
this.counter = startCounter + i
|
|
3313
|
+
results.push(this.vary(text))
|
|
3549
3314
|
}
|
|
3315
|
+
this.counter = startCounter + count
|
|
3550
3316
|
return results
|
|
3551
3317
|
}
|
|
3552
3318
|
addZeroWidth(text) {
|
|
@@ -3565,14 +3331,14 @@ var ContentVariator = class {
|
|
|
3565
3331
|
}
|
|
3566
3332
|
varyPunctuation(text) {
|
|
3567
3333
|
const variations = [
|
|
3568
|
-
|
|
3334
|
+
|
|
3569
3335
|
() => text + ' ',
|
|
3570
3336
|
() => text + ' ',
|
|
3571
|
-
|
|
3337
|
+
|
|
3572
3338
|
() => (text.endsWith('.') ? text.slice(0, -1) : text + '.'),
|
|
3573
|
-
|
|
3339
|
+
|
|
3574
3340
|
() => text,
|
|
3575
|
-
|
|
3341
|
+
|
|
3576
3342
|
() => (text.charAt(0) === text.charAt(0).toUpperCase() ? text.charAt(0).toLowerCase() + text.slice(1) : text)
|
|
3577
3343
|
]
|
|
3578
3344
|
return variations[this.counter % variations.length]()
|
|
@@ -3582,21 +3348,18 @@ var ContentVariator = class {
|
|
|
3582
3348
|
return text + emojis[this.counter % emojis.length]
|
|
3583
3349
|
}
|
|
3584
3350
|
applySynonyms(text) {
|
|
3585
|
-
const
|
|
3586
|
-
|
|
3587
|
-
|
|
3588
|
-
|
|
3589
|
-
|
|
3590
|
-
|
|
3591
|
-
|
|
3592
|
-
|
|
3593
|
-
|
|
3594
|
-
|
|
3595
|
-
|
|
3596
|
-
|
|
3597
|
-
return word
|
|
3598
|
-
})
|
|
3599
|
-
.join('')
|
|
3351
|
+
const lower = text.toLowerCase()
|
|
3352
|
+
for (const key of Object.keys(SYNONYMS)) {
|
|
3353
|
+
const idx = lower.indexOf(key)
|
|
3354
|
+
if (idx === -1) continue
|
|
3355
|
+
const word = text.substring(idx, idx + key.length)
|
|
3356
|
+
if (!SYNONYMS[key] || Math.random() > 0.5) continue
|
|
3357
|
+
const synonym = SYNONYMS[key][Math.floor(Math.random() * SYNONYMS[key].length)]
|
|
3358
|
+
const replacement =
|
|
3359
|
+
word[0] === word[0].toUpperCase() ? synonym.charAt(0).toUpperCase() + synonym.slice(1) : synonym
|
|
3360
|
+
return text.substring(0, idx) + replacement + text.substring(idx + key.length)
|
|
3361
|
+
}
|
|
3362
|
+
return text
|
|
3600
3363
|
}
|
|
3601
3364
|
randomPositions(max, count) {
|
|
3602
3365
|
const positions = []
|
|
@@ -3608,7 +3371,7 @@ var ContentVariator = class {
|
|
|
3608
3371
|
}
|
|
3609
3372
|
}
|
|
3610
3373
|
|
|
3611
|
-
|
|
3374
|
+
|
|
3612
3375
|
var DEFAULT_CONFIG14 = {
|
|
3613
3376
|
urls: [],
|
|
3614
3377
|
minRiskLevel: 'medium',
|
|
@@ -3621,9 +3384,7 @@ var WebhookAlerts = class {
|
|
|
3621
3384
|
constructor(config = {}) {
|
|
3622
3385
|
this.config = { ...DEFAULT_CONFIG14, ...config }
|
|
3623
3386
|
}
|
|
3624
|
-
|
|
3625
|
-
* Send alert if risk level warrants it
|
|
3626
|
-
*/
|
|
3387
|
+
|
|
3627
3388
|
async alert(data) {
|
|
3628
3389
|
const riskOrder = ['low', 'medium', 'high', 'critical']
|
|
3629
3390
|
if (riskOrder.indexOf(data.risk) < riskOrder.indexOf(this.config.minRiskLevel)) {
|
|
@@ -3636,7 +3397,7 @@ var WebhookAlerts = class {
|
|
|
3636
3397
|
this.lastAlertTime = now
|
|
3637
3398
|
const payload = {
|
|
3638
3399
|
source: 'baileys-antiban',
|
|
3639
|
-
timestamp:
|
|
3400
|
+
timestamp: new Date().toISOString(),
|
|
3640
3401
|
...data
|
|
3641
3402
|
}
|
|
3642
3403
|
for (const url of this.config.urls) {
|
|
@@ -3671,7 +3432,7 @@ ${data.reasons.map(r => `\u2022 ${r}`).join('\n')}`
|
|
|
3671
3432
|
{ name: 'Recommendation', value: data.recommendation },
|
|
3672
3433
|
{ name: 'Reasons', value: data.reasons.join('\n') }
|
|
3673
3434
|
],
|
|
3674
|
-
timestamp:
|
|
3435
|
+
timestamp: new Date().toISOString()
|
|
3675
3436
|
}
|
|
3676
3437
|
]
|
|
3677
3438
|
}).catch(() => {})
|
|
@@ -3696,7 +3457,7 @@ ${data.reasons.map(r => `\u2022 ${r}`).join('\n')}`
|
|
|
3696
3457
|
}
|
|
3697
3458
|
}
|
|
3698
3459
|
|
|
3699
|
-
|
|
3460
|
+
|
|
3700
3461
|
var DEFAULT_CONFIG15 = {
|
|
3701
3462
|
timezone: 'UTC',
|
|
3702
3463
|
activeHours: [8, 21],
|
|
@@ -3711,18 +3472,13 @@ var Scheduler = class {
|
|
|
3711
3472
|
constructor(config = {}) {
|
|
3712
3473
|
this.config = { ...DEFAULT_CONFIG15, ...config }
|
|
3713
3474
|
}
|
|
3714
|
-
|
|
3715
|
-
* Check if now is within active hours
|
|
3716
|
-
*/
|
|
3475
|
+
|
|
3717
3476
|
isActiveTime() {
|
|
3718
3477
|
const hour = this.getCurrentHour()
|
|
3719
3478
|
const [start, end] = this.config.activeHours
|
|
3720
3479
|
return hour >= start && hour < end
|
|
3721
3480
|
}
|
|
3722
|
-
|
|
3723
|
-
* Get the speed multiplier for current time
|
|
3724
|
-
* > 1 = faster, < 1 = slower, 0 = don't send
|
|
3725
|
-
*/
|
|
3481
|
+
|
|
3726
3482
|
getSpeedFactor() {
|
|
3727
3483
|
if (!this.isActiveTime()) return 0
|
|
3728
3484
|
const hour = this.getCurrentHour()
|
|
@@ -3741,12 +3497,10 @@ var Scheduler = class {
|
|
|
3741
3497
|
}
|
|
3742
3498
|
return factor
|
|
3743
3499
|
}
|
|
3744
|
-
|
|
3745
|
-
* Get ms until next active window
|
|
3746
|
-
*/
|
|
3500
|
+
|
|
3747
3501
|
msUntilActive() {
|
|
3748
3502
|
if (this.isActiveTime()) return 0
|
|
3749
|
-
const now =
|
|
3503
|
+
const now = new Date()
|
|
3750
3504
|
const hour = now.getHours()
|
|
3751
3505
|
const [start] = this.config.activeHours
|
|
3752
3506
|
let nextActive
|
|
@@ -3760,17 +3514,13 @@ var Scheduler = class {
|
|
|
3760
3514
|
}
|
|
3761
3515
|
return nextActive.getTime() - now.getTime()
|
|
3762
3516
|
}
|
|
3763
|
-
|
|
3764
|
-
* Adjust a delay based on current time factors
|
|
3765
|
-
*/
|
|
3517
|
+
|
|
3766
3518
|
adjustDelay(baseDelayMs) {
|
|
3767
3519
|
const factor = this.getSpeedFactor()
|
|
3768
3520
|
if (factor === 0) return -1
|
|
3769
3521
|
return Math.round(baseDelayMs / factor)
|
|
3770
3522
|
}
|
|
3771
|
-
|
|
3772
|
-
* Get current schedule status
|
|
3773
|
-
*/
|
|
3523
|
+
|
|
3774
3524
|
getStatus() {
|
|
3775
3525
|
const hour = this.getCurrentHour()
|
|
3776
3526
|
const day = this.getCurrentDay()
|
|
@@ -3786,14 +3536,14 @@ var Scheduler = class {
|
|
|
3786
3536
|
}
|
|
3787
3537
|
}
|
|
3788
3538
|
getCurrentHour() {
|
|
3789
|
-
return
|
|
3539
|
+
return new Date().getHours()
|
|
3790
3540
|
}
|
|
3791
3541
|
getCurrentDay() {
|
|
3792
|
-
return
|
|
3542
|
+
return new Date().getDay()
|
|
3793
3543
|
}
|
|
3794
3544
|
}
|
|
3795
3545
|
|
|
3796
|
-
|
|
3546
|
+
|
|
3797
3547
|
var _fsPromises = require('fs/promises')
|
|
3798
3548
|
var _fsSync = require('fs')
|
|
3799
3549
|
var _path3 = require('path')
|
|
@@ -3836,11 +3586,11 @@ var FileStateAdapter = class {
|
|
|
3836
3586
|
}
|
|
3837
3587
|
}
|
|
3838
3588
|
|
|
3839
|
-
|
|
3589
|
+
|
|
3840
3590
|
var DEFAULT_CONFIG16 = {
|
|
3841
3591
|
maxTrackedChats: 1e3,
|
|
3842
3592
|
maxGapMs: 30 * 6e4,
|
|
3843
|
-
|
|
3593
|
+
|
|
3844
3594
|
persistDebounceMs: 2e3,
|
|
3845
3595
|
onGapFilled: () => {},
|
|
3846
3596
|
logger: {
|
|
@@ -3852,7 +3602,7 @@ var DEFAULT_CONFIG16 = {
|
|
|
3852
3602
|
function messageRecovery(sock, config) {
|
|
3853
3603
|
const cfg = { ...DEFAULT_CONFIG16, ...config }
|
|
3854
3604
|
const logger = cfg.logger
|
|
3855
|
-
const lastSeen =
|
|
3605
|
+
const lastSeen = new Map()
|
|
3856
3606
|
let disconnectedAt = null
|
|
3857
3607
|
let totalRecovered = 0
|
|
3858
3608
|
let lastReconnectAt = null
|
|
@@ -3952,7 +3702,7 @@ function messageRecovery(sock, config) {
|
|
|
3952
3702
|
loggedFetchWarning = true
|
|
3953
3703
|
}
|
|
3954
3704
|
disconnectedAt = null
|
|
3955
|
-
lastReconnectAt =
|
|
3705
|
+
lastReconnectAt = new Date()
|
|
3956
3706
|
lastGapMs = gapMs
|
|
3957
3707
|
await cfg.onRecoveryComplete?.({
|
|
3958
3708
|
chats: 0,
|
|
@@ -3965,7 +3715,7 @@ function messageRecovery(sock, config) {
|
|
|
3965
3715
|
try {
|
|
3966
3716
|
const messages = await sock.fetchMessageHistory(jid, 50, {
|
|
3967
3717
|
before: void 0
|
|
3968
|
-
|
|
3718
|
+
|
|
3969
3719
|
})
|
|
3970
3720
|
if (!messages || !Array.isArray(messages)) continue
|
|
3971
3721
|
const gapMessages = messages.filter(msg => {
|
|
@@ -3998,7 +3748,7 @@ function messageRecovery(sock, config) {
|
|
|
3998
3748
|
}
|
|
3999
3749
|
}
|
|
4000
3750
|
totalRecovered += recovered
|
|
4001
|
-
lastReconnectAt =
|
|
3751
|
+
lastReconnectAt = new Date()
|
|
4002
3752
|
lastGapMs = gapMs
|
|
4003
3753
|
disconnectedAt = null
|
|
4004
3754
|
logger.info?.(
|
|
@@ -4085,29 +3835,33 @@ function messageRecovery(sock, config) {
|
|
|
4085
3835
|
}
|
|
4086
3836
|
}
|
|
4087
3837
|
|
|
4088
|
-
|
|
3838
|
+
|
|
4089
3839
|
var DEFAULT_APP_VERSION_POOL = [
|
|
4090
|
-
[2,
|
|
4091
|
-
[2,
|
|
4092
|
-
[2,
|
|
4093
|
-
[2,
|
|
4094
|
-
[2,
|
|
4095
|
-
[2,
|
|
3840
|
+
[2, 25, 10, 67],
|
|
3841
|
+
[2, 25, 10, 68],
|
|
3842
|
+
[2, 25, 9, 96],
|
|
3843
|
+
[2, 25, 8, 77],
|
|
3844
|
+
[2, 25, 7, 85],
|
|
3845
|
+
[2, 25, 6, 98],
|
|
3846
|
+
[2, 24, 22, 78],
|
|
3847
|
+
[2, 24, 20, 86]
|
|
4096
3848
|
]
|
|
4097
|
-
var DEFAULT_OS_VERSION_POOL = ['
|
|
3849
|
+
var DEFAULT_OS_VERSION_POOL = ['11', '12', '13', '14', '15']
|
|
4098
3850
|
var DEFAULT_DEVICE_MODEL_POOL = [
|
|
4099
|
-
'Pixel
|
|
3851
|
+
'Pixel 8',
|
|
3852
|
+
'Pixel 9',
|
|
4100
3853
|
'Pixel 7',
|
|
4101
|
-
'Galaxy
|
|
3854
|
+
'Galaxy S24',
|
|
4102
3855
|
'Galaxy S23',
|
|
3856
|
+
'Galaxy S22',
|
|
3857
|
+
'Xiaomi 14',
|
|
4103
3858
|
'Xiaomi 13',
|
|
4104
|
-
'
|
|
3859
|
+
'OnePlus 12',
|
|
4105
3860
|
'OnePlus 11',
|
|
4106
3861
|
'Moto G84',
|
|
4107
|
-
'
|
|
4108
|
-
'
|
|
4109
|
-
'
|
|
4110
|
-
'Oppo Find X6'
|
|
3862
|
+
'Realme 12',
|
|
3863
|
+
'Vivo V30',
|
|
3864
|
+
'Oppo Find X7'
|
|
4111
3865
|
]
|
|
4112
3866
|
var SeededRandom = class {
|
|
4113
3867
|
state
|
|
@@ -4147,7 +3901,7 @@ function generateFingerprint(config = {}, sessionId) {
|
|
|
4147
3901
|
const deviceModel = enabled && randomizeDeviceModel ? rng.pick(deviceModelPool) : deviceModelPool[0]
|
|
4148
3902
|
return {
|
|
4149
3903
|
appVersion: [...appVersion],
|
|
4150
|
-
|
|
3904
|
+
|
|
4151
3905
|
osVersion,
|
|
4152
3906
|
deviceModel,
|
|
4153
3907
|
sessionId: finalSessionId
|
|
@@ -4164,7 +3918,7 @@ function applyFingerprint(socketConfig, fp) {
|
|
|
4164
3918
|
return config
|
|
4165
3919
|
}
|
|
4166
3920
|
|
|
4167
|
-
|
|
3921
|
+
|
|
4168
3922
|
var import_fs = require('fs')
|
|
4169
3923
|
var path2 = __toESM(require('path'), 1)
|
|
4170
3924
|
var noop = () => {}
|
|
@@ -4184,7 +3938,7 @@ function credsSnapshot(config) {
|
|
|
4184
3938
|
return null
|
|
4185
3939
|
}
|
|
4186
3940
|
await import_fs.promises.mkdir(snapshotDir, { recursive: true })
|
|
4187
|
-
const timestamp =
|
|
3941
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-')
|
|
4188
3942
|
const snapshotPath = path2.join(snapshotDir, `creds-${timestamp}.json`)
|
|
4189
3943
|
const tmpPath = `${snapshotPath}.tmp`
|
|
4190
3944
|
await import_fs.promises.copyFile(credsPath, tmpPath)
|
|
@@ -4265,7 +4019,7 @@ function credsSnapshot(config) {
|
|
|
4265
4019
|
}
|
|
4266
4020
|
}
|
|
4267
4021
|
|
|
4268
|
-
|
|
4022
|
+
|
|
4269
4023
|
function gaussianRandom() {
|
|
4270
4024
|
let u = 0
|
|
4271
4025
|
let v = 0
|
|
@@ -4275,7 +4029,7 @@ function gaussianRandom() {
|
|
|
4275
4029
|
}
|
|
4276
4030
|
function readReceiptVariance(config = {}) {
|
|
4277
4031
|
const { meanMs = 1500, stdDevMs = 800, minMs = 200, maxMs = 8e3, skipIfOlderThanMs = 6e4 } = config
|
|
4278
|
-
const pendingTimers =
|
|
4032
|
+
const pendingTimers = new Set()
|
|
4279
4033
|
function delayMs() {
|
|
4280
4034
|
const gaussian = gaussianRandom()
|
|
4281
4035
|
const value = meanMs + gaussian * stdDevMs
|
|
@@ -4332,7 +4086,7 @@ function readReceiptVariance(config = {}) {
|
|
|
4332
4086
|
}
|
|
4333
4087
|
}
|
|
4334
4088
|
|
|
4335
|
-
|
|
4089
|
+
|
|
4336
4090
|
var import_node_module = require('node:module')
|
|
4337
4091
|
var require2 = (0, import_node_module.createRequire)(__importMetaUrl)
|
|
4338
4092
|
var NoopLogger = {
|
|
@@ -4348,7 +4102,7 @@ function proxyRotator(config) {
|
|
|
4348
4102
|
scheduledIntervalMs = 0,
|
|
4349
4103
|
maxFailures = 3,
|
|
4350
4104
|
deadCooldownMs = 6e5,
|
|
4351
|
-
|
|
4105
|
+
|
|
4352
4106
|
logger = NoopLogger
|
|
4353
4107
|
} = config
|
|
4354
4108
|
if (!pool || pool.length === 0) {
|
|
@@ -4370,7 +4124,7 @@ function proxyRotator(config) {
|
|
|
4370
4124
|
let totalRotations = 0
|
|
4371
4125
|
const rotationsByTrigger = {}
|
|
4372
4126
|
let scheduledTimer = null
|
|
4373
|
-
const agentCache =
|
|
4127
|
+
const agentCache = new Map()
|
|
4374
4128
|
const moduleCache = {}
|
|
4375
4129
|
function buildProxyUrl(endpoint) {
|
|
4376
4130
|
const { type, host, port, username, password } = endpoint
|
|
@@ -4509,7 +4263,7 @@ function proxyRotator(config) {
|
|
|
4509
4263
|
} else {
|
|
4510
4264
|
currentIndex = nextIdx
|
|
4511
4265
|
}
|
|
4512
|
-
states[currentIndex].lastUsedAt =
|
|
4266
|
+
states[currentIndex].lastUsedAt = new Date()
|
|
4513
4267
|
totalRotations++
|
|
4514
4268
|
rotationsByTrigger[reason] = (rotationsByTrigger[reason] || 0) + 1
|
|
4515
4269
|
const label = states[currentIndex].endpoint.label || states[currentIndex].endpoint.host
|
|
@@ -4577,7 +4331,7 @@ function proxyRotator(config) {
|
|
|
4577
4331
|
}, scheduledIntervalMs)
|
|
4578
4332
|
logger.info?.(`Scheduled rotation enabled (every ${scheduledIntervalMs}ms)`)
|
|
4579
4333
|
}
|
|
4580
|
-
states[0].lastUsedAt =
|
|
4334
|
+
states[0].lastUsedAt = new Date()
|
|
4581
4335
|
return {
|
|
4582
4336
|
currentAgent: currentAgentImpl,
|
|
4583
4337
|
current: currentImpl,
|
|
@@ -4588,7 +4342,7 @@ function proxyRotator(config) {
|
|
|
4588
4342
|
getStats: getStatsImpl
|
|
4589
4343
|
}
|
|
4590
4344
|
}
|
|
4591
|
-
|
|
4345
|
+
|
|
4592
4346
|
0 &&
|
|
4593
4347
|
(module.exports = {
|
|
4594
4348
|
AntiBan,
|