@badzz88/baileys 8.4.9 → 8.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (153) hide show
  1. package/WAProto/WAProto.proto +6 -347
  2. package/WAProto/fix-imports.js +85 -86
  3. package/WAProto/index.d.ts +25 -4913
  4. package/WAProto/index.js +93 -14069
  5. package/{src → lib}/Defaults/index.js +2 -13
  6. package/{src → lib}/Signal/Group/group_cipher.js +5 -5
  7. package/{src → lib}/Signal/Group/keyhelper.js +4 -4
  8. package/{src → lib}/Signal/Group/sender-chain-key.js +2 -2
  9. package/{src → lib}/Signal/Group/sender-key-distribution-message.js +1 -1
  10. package/{src → lib}/Signal/Group/sender-key-message.js +3 -3
  11. package/{src → lib}/Signal/Group/sender-key-record.js +1 -1
  12. package/{src → lib}/Signal/Group/sender-message-key.js +2 -2
  13. package/{src → lib}/Signal/libsignal.js +26 -6
  14. package/{src → lib}/Socket/chats.js +58 -616
  15. package/{src → lib}/Socket/communities.js +28 -59
  16. package/{src → lib}/Socket/graphql.js +103 -362
  17. package/{src → lib}/Socket/groups.js +29 -77
  18. package/{src → lib}/Socket/index.js +5 -3
  19. package/{src → lib}/Socket/interactive-handler.js +60 -117
  20. package/{src → lib}/Socket/interop.js +19 -36
  21. package/lib/Socket/luxu.js +387 -0
  22. package/{src → lib}/Socket/managed-account.js +27 -58
  23. package/{src → lib}/Socket/messages-recv.js +143 -715
  24. package/{src → lib}/Socket/messages-send.js +102 -412
  25. package/lib/Socket/mex.js +60 -0
  26. package/{src → lib}/Socket/newsletter.js +23 -266
  27. package/{src → lib}/Socket/privacy.js +38 -41
  28. package/{src → lib}/Socket/registration.js +106 -113
  29. package/{src → lib}/Socket/socket.js +101 -88
  30. package/{src → lib}/Socket/text-router.js +17 -1
  31. package/lib/Socket/username.js +243 -0
  32. package/lib/Store/keyed-db.js +108 -0
  33. package/{src → lib}/Store/make-in-memory-store.js +104 -6
  34. package/lib/Types/Mex.js +112 -0
  35. package/{src → lib}/Types/Newsletter.js +41 -72
  36. package/{src → lib}/Types/index.js +1 -0
  37. package/{src → lib}/Utils/chat-utils.js +9 -73
  38. package/lib/Utils/command-loader.d.ts +31 -0
  39. package/lib/Utils/command-loader.js +100 -0
  40. package/lib/Utils/companion-reg-client-utils.js +42 -0
  41. package/lib/Utils/crypto.js +155 -0
  42. package/lib/Utils/curve25519-js.js +275 -0
  43. package/{src → lib}/Utils/decode-wa-message.js +36 -284
  44. package/{src → lib}/Utils/event-buffer.js +27 -6
  45. package/{src → lib}/Utils/generics.js +37 -114
  46. package/{src → lib}/Utils/index.js +5 -1
  47. package/lib/Utils/lt-hash.js +39 -0
  48. package/{src → lib}/Utils/message-retry-manager.js +39 -0
  49. package/{src → lib}/Utils/messages-media.js +58 -105
  50. package/{src → lib}/Utils/messages.js +529 -115
  51. package/lib/Utils/meta-ai-msmsg.js +262 -0
  52. package/lib/Utils/native-bridge.js +82 -0
  53. package/{src → lib}/Utils/noise-handler.js +15 -13
  54. package/{src → lib}/Utils/process-message.js +55 -54
  55. package/{src → lib}/Utils/reporting-utils.js +2 -2
  56. package/lib/Utils/session-pool.d.ts +16 -0
  57. package/lib/Utils/session-pool.js +94 -0
  58. package/{src → lib}/Utils/signal.js +51 -19
  59. package/{src → lib}/Utils/stanza-ack.js +2 -36
  60. package/lib/Utils/sticker.d.ts +17 -0
  61. package/lib/Utils/sticker.js +145 -0
  62. package/{src → lib}/Utils/tc-token-utils.js +1 -1
  63. package/{src → lib}/Utils/validate-connection.js +11 -40
  64. package/lib/Utils/view-once-cache.d.ts +9 -0
  65. package/lib/Utils/view-once-cache.js +79 -0
  66. package/{src → lib}/WABinary/decode.js +4 -38
  67. package/lib/WABinary/encode.js +228 -0
  68. package/{src → lib}/WABinary/generic-utils.js +93 -1
  69. package/{src → lib}/WABinary/jid-utils.js +3 -16
  70. package/{src → lib}/WAM/encode.js +1 -1
  71. package/lib/WAUSync/Protocols/USyncBusinessProtocol.js +43 -0
  72. package/{src → lib}/WAUSync/Protocols/USyncContactProtocol.js +1 -7
  73. package/{src → lib}/WAUSync/Protocols/USyncDeviceProtocol.js +5 -13
  74. package/{src → lib}/WAUSync/Protocols/USyncDisappearingModeProtocol.js +4 -1
  75. package/{src → lib}/WAUSync/Protocols/USyncFeatureProtocol.js +2 -17
  76. package/{src → lib}/WAUSync/Protocols/USyncStatusProtocol.js +2 -7
  77. package/{src → lib}/WAUSync/Protocols/USyncUsernameProtocol.js +1 -2
  78. package/{src → lib}/WAUSync/Protocols/index.js +0 -1
  79. package/{src → lib}/WAUSync/USyncQuery.js +6 -77
  80. package/{src → lib}/WAUSync/USyncUser.js +8 -16
  81. package/{src → lib}/WAUSync/index.js +0 -1
  82. package/{src → lib}/antiban.js +266 -355
  83. package/{src → lib}/index.js +2 -2
  84. package/package.json +18 -15
  85. package/WAProto/fix-import.js +0 -38
  86. package/src/Socket/mex.js +0 -47
  87. package/src/Socket/username.js +0 -234
  88. package/src/Utils/crypto.js +0 -125
  89. package/src/Utils/lt-hash.js +0 -10
  90. package/src/Utils/message-inspect.js +0 -400
  91. package/src/Utils/meta-ai-msmsg.js +0 -133
  92. package/src/WABinary/encode.js +0 -58
  93. package/src/WAUSync/Protocols/USyncBusinessProtocol.js +0 -100
  94. package/src/WAUSync/USyncBackoff.js +0 -31
  95. /package/{src → lib}/Defaults/phonenumber-mcc.json +0 -0
  96. /package/{src → lib}/Signal/Group/ciphertext-message.js +0 -0
  97. /package/{src → lib}/Signal/Group/group-session-builder.js +0 -0
  98. /package/{src → lib}/Signal/Group/index.js +0 -0
  99. /package/{src → lib}/Signal/Group/sender-key-name.js +0 -0
  100. /package/{src → lib}/Signal/Group/sender-key-state.js +0 -0
  101. /package/{src → lib}/Signal/lid-mapping.js +0 -0
  102. /package/{src → lib}/Socket/Client/index.js +0 -0
  103. /package/{src → lib}/Socket/Client/types.js +0 -0
  104. /package/{src → lib}/Socket/Client/websocket.js +0 -0
  105. /package/{src → lib}/Socket/aigroups.js +0 -0
  106. /package/{src → lib}/Socket/business.js +0 -0
  107. /package/{src → lib}/Store/index.js +0 -0
  108. /package/{src → lib}/Store/make-cache-manager-store.js +0 -0
  109. /package/{src → lib}/Store/make-ordered-dictionary.js +0 -0
  110. /package/{src → lib}/Store/object-repository.js +0 -0
  111. /package/{src → lib}/Types/Auth.js +0 -0
  112. /package/{src → lib}/Types/Bussines.js +0 -0
  113. /package/{src → lib}/Types/Call.js +0 -0
  114. /package/{src → lib}/Types/Chat.js +0 -0
  115. /package/{src → lib}/Types/Contact.js +0 -0
  116. /package/{src → lib}/Types/Events.js +0 -0
  117. /package/{src → lib}/Types/GroupMetadata.js +0 -0
  118. /package/{src → lib}/Types/Label.js +0 -0
  119. /package/{src → lib}/Types/LabelAssociation.js +0 -0
  120. /package/{src → lib}/Types/Message.js +0 -0
  121. /package/{src → lib}/Types/Product.js +0 -0
  122. /package/{src → lib}/Types/Signal.js +0 -0
  123. /package/{src → lib}/Types/Socket.js +0 -0
  124. /package/{src → lib}/Types/State.js +0 -0
  125. /package/{src → lib}/Types/USync.js +0 -0
  126. /package/{src → lib}/Utils/auth-utils.js +0 -0
  127. /package/{src → lib}/Utils/browser-utils.js +0 -0
  128. /package/{src → lib}/Utils/business.js +0 -0
  129. /package/{src → lib}/Utils/consumer-application.js +0 -0
  130. /package/{src → lib}/Utils/group-history.js +0 -0
  131. /package/{src → lib}/Utils/history.js +0 -0
  132. /package/{src → lib}/Utils/identity-change-handler.js +0 -0
  133. /package/{src → lib}/Utils/jid-display-normalization.js +0 -0
  134. /package/{src → lib}/Utils/link-preview.js +0 -0
  135. /package/{src → lib}/Utils/logger.js +0 -0
  136. /package/{src → lib}/Utils/make-mutex.js +0 -0
  137. /package/{src → lib}/Utils/message-composer.js +0 -0
  138. /package/{src → lib}/Utils/offline-node-processor.js +0 -0
  139. /package/{src → lib}/Utils/pre-key-manager.js +0 -0
  140. /package/{src → lib}/Utils/sync-action-utils.js +0 -0
  141. /package/{src → lib}/Utils/use-multi-file-auth-state.js +0 -0
  142. /package/{src → lib}/Utils/voip-rekey.js +0 -0
  143. /package/{src → lib}/WABinary/constants.js +0 -0
  144. /package/{src → lib}/WABinary/index.js +0 -0
  145. /package/{src → lib}/WABinary/types.js +0 -0
  146. /package/{src → lib}/WAM/BinaryInfo.js +0 -0
  147. /package/{src → lib}/WAM/constants.js +0 -0
  148. /package/{src → lib}/WAM/index.js +0 -0
  149. /package/{src → lib}/WAUSync/Protocols/USyncBotProfileProtocol.js +0 -0
  150. /package/{src → lib}/WAUSync/Protocols/USyncLIDProtocol.js +0 -0
  151. /package/{src → lib}/WAUSync/Protocols/USyncPictureProtocol.js +0 -0
  152. /package/{src → lib}/WAUSync/Protocols/USyncSidelistProtocol.js +0 -0
  153. /package/{src → lib}/WAUSync/Protocols/USyncTextStatusProtocol.js +0 -0
@@ -61,7 +61,6 @@ __export(index_exports, {
61
61
  WebhookAlerts: () => WebhookAlerts,
62
62
  applyFingerprint: () => applyFingerprint,
63
63
  applyGroupMultiplier: () => applyGroupMultiplier,
64
- buildContentSignature: () => buildContentSignature,
65
64
  classifyDisconnect: () => classifyDisconnect,
66
65
  createLidFirstResolver: () => createLidFirstResolver,
67
66
  credsSnapshot: () => credsSnapshot,
@@ -90,18 +89,18 @@ var TIME_CONSTANTS = {
90
89
  MS_PER_HOUR: 36e5,
91
90
  MS_PER_DAY: 864e5,
92
91
  BURST_RESET_MS: 3e4,
93
- IDENTICAL_WINDOW_MS: 18e5
94
- // 30 minutes (was 1 hour — shorter window is less punishing for broadcast use cases)
92
+ IDENTICAL_WINDOW_MS: 36e5
93
+ // 1 hour
95
94
  }
96
95
  var DEFAULT_CONFIG = {
97
- maxPerMinute: 12,
98
- maxPerHour: 400,
99
- maxPerDay: 2500,
100
- minDelayMs: 1200,
101
- maxDelayMs: 4e3,
102
- newChatDelayMs: 2e3,
103
- maxIdenticalMessages: 10,
104
- burstAllowance: 5,
96
+ maxPerMinute: 8,
97
+ maxPerHour: 200,
98
+ maxPerDay: 1500,
99
+ minDelayMs: 1500,
100
+ maxDelayMs: 5e3,
101
+ newChatDelayMs: 3e3,
102
+ maxIdenticalMessages: 3,
103
+ burstAllowance: 3,
105
104
  identicalMessageWindowMs: TIME_CONSTANTS.IDENTICAL_WINDOW_MS
106
105
  }
107
106
  var RateLimiter = class {
@@ -111,8 +110,6 @@ var RateLimiter = class {
111
110
  knownChats = /* @__PURE__ */ new Set()
112
111
  burstCount = 0
113
112
  lastMessageTime = 0
114
- statsCacheTime = 0
115
- statsCache = null
116
113
  constructor(config = {}) {
117
114
  this.config = { ...DEFAULT_CONFIG, ...config }
118
115
  }
@@ -120,15 +117,11 @@ var RateLimiter = class {
120
117
  * Calculate delay before next message can be sent.
121
118
  * Returns 0 if message can be sent immediately.
122
119
  * Returns -1 if message should be blocked entirely.
123
- *
124
- * @param dedupKey - optional signature used for identical-message detection instead
125
- * of `content`. Callers that only pass extracted text (e.g. no-caption media)
126
- * should supply a richer dedupKey so unrelated messages don't collide on ''.
127
120
  */
128
- async getDelay(recipient, content, dedupKey) {
121
+ async getDelay(recipient, content) {
129
122
  const now = Date.now()
130
123
  this.cleanup(now)
131
- const contentHash = this.hashContent(dedupKey !== undefined ? dedupKey : content)
124
+ const contentHash = this.hashContent(content)
132
125
  const dayMessages = this.messages.filter(m => now - m.timestamp < TIME_CONSTANTS.MS_PER_DAY)
133
126
  if (dayMessages.length >= this.config.maxPerDay) {
134
127
  return -1
@@ -174,16 +167,16 @@ var RateLimiter = class {
174
167
  if (timeSinceLast < this.config.minDelayMs) {
175
168
  delay = Math.max(delay, this.config.minDelayMs - timeSinceLast)
176
169
  }
177
- const typingDelay = Math.min((content?.length || 0) * 15, 2e3)
170
+ const typingDelay = Math.min(content.length * 30, 3e3)
178
171
  delay += this.jitter(typingDelay * 0.5, typingDelay)
179
172
  return Math.round(delay)
180
173
  }
181
174
  /**
182
175
  * Record a sent message
183
176
  */
184
- record(recipient, content, dedupKey) {
177
+ record(recipient, content) {
185
178
  const now = Date.now()
186
- const contentHash = this.hashContent(dedupKey !== undefined ? dedupKey : content)
179
+ const contentHash = this.hashContent(content)
187
180
  const timeSinceLast = now - this.lastMessageTime
188
181
  if (timeSinceLast > TIME_CONSTANTS.BURST_RESET_MS) {
189
182
  this.burstCount = 0
@@ -204,27 +197,15 @@ var RateLimiter = class {
204
197
  }
205
198
  }
206
199
  /**
207
- * Get current usage stats (cached for 100ms)
200
+ * Get current usage stats
208
201
  */
209
202
  getStats() {
210
203
  const now = Date.now()
211
- if (this.statsCache && now - this.statsCacheTime < 100) {
212
- return this.statsCache
213
- }
214
204
  this.cleanup(now)
215
- let lastMinute = 0
216
- let lastHour = 0
217
- let lastDay = 0
218
- for (const m of this.messages) {
219
- const age = now - m.timestamp
220
- if (age < TIME_CONSTANTS.MS_PER_MINUTE) lastMinute++
221
- if (age < TIME_CONSTANTS.MS_PER_HOUR) lastHour++
222
- if (age < TIME_CONSTANTS.MS_PER_DAY) lastDay++
223
- }
224
- this.statsCache = {
225
- lastMinute,
226
- lastHour,
227
- lastDay,
205
+ return {
206
+ lastMinute: this.messages.filter(m => now - m.timestamp < TIME_CONSTANTS.MS_PER_MINUTE).length,
207
+ lastHour: this.messages.filter(m => now - m.timestamp < TIME_CONSTANTS.MS_PER_HOUR).length,
208
+ lastDay: this.messages.filter(m => now - m.timestamp < TIME_CONSTANTS.MS_PER_DAY).length,
228
209
  limits: {
229
210
  perMinute: this.config.maxPerMinute,
230
211
  perHour: this.config.maxPerHour,
@@ -232,8 +213,6 @@ var RateLimiter = class {
232
213
  },
233
214
  knownChats: this.knownChats.size
234
215
  }
235
- this.statsCacheTime = now
236
- return this.statsCache
237
216
  }
238
217
  /** Get the set of known chat JIDs (for state persistence) */
239
218
  getKnownChats() {
@@ -276,10 +255,10 @@ var RateLimiter = class {
276
255
 
277
256
  // warmup.js
278
257
  var DEFAULT_CONFIG2 = {
279
- warmUpDays: 5,
280
- day1Limit: 30,
258
+ warmUpDays: 7,
259
+ day1Limit: 20,
281
260
  growthFactor: 1.8,
282
- inactivityThresholdHours: 168
261
+ inactivityThresholdHours: 72
283
262
  }
284
263
  var WarmUp = class {
285
264
  config
@@ -2341,48 +2320,48 @@ function wrapWithSessionStability(sock, config = {}) {
2341
2320
  // presets.js
2342
2321
  var PRESETS = {
2343
2322
  conservative: {
2344
- maxPerMinute: 6,
2345
- maxPerHour: 150,
2346
- maxPerDay: 1000,
2347
- minDelayMs: 2000,
2348
- maxDelayMs: 6e3,
2349
- newChatDelayMs: 3e3,
2350
- warmupDays: 7,
2351
- day1Limit: 20,
2323
+ maxPerMinute: 5,
2324
+ maxPerHour: 100,
2325
+ maxPerDay: 800,
2326
+ minDelayMs: 2500,
2327
+ maxDelayMs: 7e3,
2328
+ newChatDelayMs: 4e3,
2329
+ warmupDays: 10,
2330
+ day1Limit: 15,
2352
2331
  growthFactor: 1.8,
2353
- inactivityThresholdHours: 120,
2354
- autoPauseAt: 'high',
2332
+ inactivityThresholdHours: 72,
2333
+ autoPauseAt: 'medium',
2355
2334
  groupMultiplier: 0.5,
2356
2335
  groupProfiles: false,
2357
2336
  logging: true
2358
2337
  },
2359
2338
  moderate: {
2360
- maxPerMinute: 15,
2361
- maxPerHour: 500,
2362
- maxPerDay: 3e3,
2363
- minDelayMs: 1e3,
2364
- maxDelayMs: 4e3,
2365
- newChatDelayMs: 2e3,
2366
- warmupDays: 5,
2367
- day1Limit: 30,
2339
+ maxPerMinute: 10,
2340
+ maxPerHour: 300,
2341
+ maxPerDay: 1500,
2342
+ minDelayMs: 1500,
2343
+ maxDelayMs: 5e3,
2344
+ newChatDelayMs: 3e3,
2345
+ warmupDays: 7,
2346
+ day1Limit: 20,
2368
2347
  growthFactor: 1.8,
2369
- inactivityThresholdHours: 168,
2370
- autoPauseAt: 'critical',
2348
+ inactivityThresholdHours: 72,
2349
+ autoPauseAt: 'high',
2371
2350
  groupMultiplier: 0.7,
2372
2351
  groupProfiles: false,
2373
2352
  logging: true
2374
2353
  },
2375
2354
  aggressive: {
2376
- maxPerMinute: 25,
2377
- maxPerHour: 1200,
2378
- maxPerDay: 6e3,
2379
- minDelayMs: 600,
2380
- maxDelayMs: 2500,
2381
- newChatDelayMs: 1500,
2382
- warmupDays: 3,
2383
- day1Limit: 50,
2355
+ maxPerMinute: 20,
2356
+ maxPerHour: 800,
2357
+ maxPerDay: 4e3,
2358
+ minDelayMs: 800,
2359
+ maxDelayMs: 3e3,
2360
+ newChatDelayMs: 2e3,
2361
+ warmupDays: 4,
2362
+ day1Limit: 35,
2384
2363
  growthFactor: 2,
2385
- inactivityThresholdHours: 96,
2364
+ inactivityThresholdHours: 48,
2386
2365
  autoPauseAt: 'critical',
2387
2366
  groupMultiplier: 0.9,
2388
2367
  groupProfiles: false,
@@ -2391,7 +2370,7 @@ var PRESETS = {
2391
2370
  }
2392
2371
  function resolveConfig(input) {
2393
2372
  if (input === void 0) {
2394
- return { ...PRESETS.moderate }
2373
+ return { ...PRESETS.conservative }
2395
2374
  }
2396
2375
  if (typeof input === 'string') {
2397
2376
  if (!(input in PRESETS)) {
@@ -2399,7 +2378,7 @@ function resolveConfig(input) {
2399
2378
  }
2400
2379
  return { ...PRESETS[input] }
2401
2380
  }
2402
- const { preset = 'moderate', ...overrides } = input
2381
+ const { preset = 'conservative', ...overrides } = input
2403
2382
  if (!(preset in PRESETS)) {
2404
2383
  throw new Error(`Unknown preset "${preset}". Valid: ${Object.keys(PRESETS).join(', ')}`)
2405
2384
  }
@@ -2498,22 +2477,25 @@ function applyGroupMultiplier(limits, multiplier) {
2498
2477
  }
2499
2478
 
2500
2479
  // antiban.js
2501
- // Only rateLimiter/warmUp are true legacy duplicates — every field they carry has a
2502
- // 1:1 flat equivalent (maxPerMinute, warmupDays, ...), so nesting them is pure v2-style
2503
- // baggage worth migrating away from. health/timelock/replyRatio/contactGraph/presence/
2504
- // retryTracker/reconnectThrottle/lidResolver/jidCanonicalizer/sessionStability are NOT
2505
- // legacy: they configure guards with no flat equivalent (many sub-fields, callback hooks),
2506
- // so nesting is their normal, permanent, supported shape — read directly off whatever
2507
- // input object the caller passes, regardless of whether a preset/flat override is also present.
2508
- const CORE_LEGACY_KEYS = ['rateLimiter', 'warmUp']
2509
- function hasLegacyCoreNesting(cfg) {
2480
+ function isLegacyConfig(cfg) {
2510
2481
  if (typeof cfg !== 'object' || cfg === null) return false
2511
- return CORE_LEGACY_KEYS.some(key => key in cfg)
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
+ )
2512
2496
  }
2513
2497
  function mapLegacyToFlat(legacy) {
2514
- process.stderr.write(
2515
- '[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'
2516
- )
2498
+ process.stderr.write('[baileys-antiban] DEPRECATED: Nested config (v2 style) detected. Migrate to flat config: new AntiBan({ maxPerMinute: 8 }).\n')
2517
2499
  const flat = {}
2518
2500
  if (legacy.rateLimiter?.maxPerMinute !== void 0) flat.maxPerMinute = legacy.rateLimiter.maxPerMinute
2519
2501
  if (legacy.rateLimiter?.maxPerHour !== void 0) flat.maxPerHour = legacy.rateLimiter.maxPerHour
@@ -2524,6 +2506,7 @@ function mapLegacyToFlat(legacy) {
2524
2506
  if (legacy.warmUp?.warmUpDays !== void 0) flat.warmupDays = legacy.warmUp.warmUpDays
2525
2507
  if (legacy.warmUp?.day1Limit !== void 0) flat.day1Limit = legacy.warmUp.day1Limit
2526
2508
  if (legacy.warmUp?.growthFactor !== void 0) flat.growthFactor = legacy.warmUp.growthFactor
2509
+ if (legacy.logging !== void 0) flat.logging = legacy.logging
2527
2510
  return flat
2528
2511
  }
2529
2512
  var AntiBan = class {
@@ -2548,29 +2531,18 @@ var AntiBan = class {
2548
2531
  totalDelayMs: 0
2549
2532
  }
2550
2533
  constructor(input, warmUpStateArg) {
2534
+ let flatConfig
2535
+ let legacyPassthrough = null
2551
2536
  let warmUpState = warmUpStateArg
2552
- // rawInput is whatever object the caller passed (preset string input has no
2553
- // guard-block config, so it resolves to {}) — every guard-specific override
2554
- // block below (rateLimiter, warmUp, health, timelock, replyRatio, ...) is read
2555
- // straight from it, regardless of preset/flat fields being present alongside.
2556
- const rawInput = typeof input === 'object' && input !== null ? input : {}
2557
- const legacyNested = hasLegacyCoreNesting(rawInput)
2558
- // Explicit top-level flat fields always win over values mapped from legacy nesting.
2559
- const flatMerged = legacyNested ? { ...mapLegacyToFlat(rawInput), ...rawInput } : rawInput
2560
- const cfg = typeof input === 'string' ? resolveConfig(input) : resolveConfig(flatMerged)
2537
+ if (isLegacyConfig(input)) {
2538
+ legacyPassthrough = input
2539
+ flatConfig = mapLegacyToFlat(legacyPassthrough)
2540
+ } else {
2541
+ flatConfig = {}
2542
+ legacyPassthrough = null
2543
+ }
2544
+ const cfg = isLegacyConfig(input) ? resolveConfig(flatConfig) : resolveConfig(input)
2561
2545
  this.resolvedConfig = cfg
2562
- const rateLimiterOverrides = rawInput.rateLimiter || {}
2563
- const warmUpOverrides = rawInput.warmUp || {}
2564
- const healthOverrides = rawInput.health || {}
2565
- const timelockOverrides = rawInput.timelock || {}
2566
- const replyRatioCfg = rawInput.replyRatio
2567
- const contactGraphCfg = rawInput.contactGraph
2568
- const presenceCfg = rawInput.presence
2569
- const retryTrackerCfg = rawInput.retryTracker
2570
- const reconnectThrottleCfg = rawInput.reconnectThrottle
2571
- const lidResolverCfg = rawInput.lidResolver
2572
- const jidCanonicalizerCfg = rawInput.jidCanonicalizer
2573
- const sessionStabilityCfg = rawInput.sessionStability
2574
2546
  let savedState = null
2575
2547
  if (cfg.persist) {
2576
2548
  this.stateManager = new StateManager(cfg.persist)
@@ -2580,9 +2552,7 @@ var AntiBan = class {
2580
2552
  }
2581
2553
  }
2582
2554
  this.logging = cfg.logging ?? true
2583
- this._log = msg => {
2584
- if (this.logging) process.stdout.write(`[baileys-antiban] ${msg}\n`)
2585
- }
2555
+ this._log = (msg) => { if (this.logging) process.stdout.write(`[antiban] ${msg}\n`) }
2586
2556
  this.rateLimiter = new RateLimiter({
2587
2557
  maxPerMinute: cfg.maxPerMinute,
2588
2558
  maxPerHour: cfg.maxPerHour,
@@ -2590,7 +2560,7 @@ var AntiBan = class {
2590
2560
  minDelayMs: cfg.minDelayMs,
2591
2561
  maxDelayMs: cfg.maxDelayMs,
2592
2562
  newChatDelayMs: cfg.newChatDelayMs,
2593
- ...rateLimiterOverrides
2563
+ ...(legacyPassthrough?.rateLimiter || {})
2594
2564
  })
2595
2565
  if (savedState?.knownChats) {
2596
2566
  this.rateLimiter.restoreKnownChats(savedState.knownChats)
@@ -2601,73 +2571,69 @@ var AntiBan = class {
2601
2571
  day1Limit: cfg.day1Limit,
2602
2572
  growthFactor: cfg.growthFactor,
2603
2573
  inactivityThresholdHours: cfg.inactivityThresholdHours,
2604
- ...warmUpOverrides
2574
+ ...(legacyPassthrough?.warmUp || {})
2605
2575
  },
2606
2576
  warmUpState
2607
2577
  )
2608
2578
  this.health = new HealthMonitor({
2609
2579
  autoPauseAt: cfg.autoPauseAt,
2610
- ...healthOverrides,
2580
+ ...(legacyPassthrough?.health || {}),
2611
2581
  onRiskChange: status => {
2612
2582
  const emoji = { low: '\u{1F7E2}', medium: '\u{1F7E1}', high: '\u{1F7E0}', critical: '\u{1F534}' }
2613
2583
  this._log(`${emoji[status.risk]} Risk level: ${status.risk.toUpperCase()} (score: ${status.score})`)
2614
2584
  this._log(status.recommendation)
2615
2585
  status.reasons.forEach(r => this._log(` \u2192 ${r}`))
2616
- healthOverrides.onRiskChange?.(status)
2586
+ legacyPassthrough?.health?.onRiskChange?.(status)
2617
2587
  }
2618
2588
  })
2619
2589
  this.timelockGuard = new TimelockGuard({
2620
- ...timelockOverrides,
2590
+ ...(legacyPassthrough?.timelock || {}),
2621
2591
  onTimelockDetected: state => {
2622
2592
  this.health.recordReachoutTimelock(state.enforcementType)
2623
- this._log(
2624
- `REACHOUT TIMELOCKED \u2014 ${state.enforcementType || 'unknown'}, expires ${state.expiresAt?.toISOString() || 'unknown'}`
2625
- )
2626
- timelockOverrides.onTimelockDetected?.(state)
2593
+ this._log(`REACHOUT TIMELOCKED \u2014 ${state.enforcementType || 'unknown'}, expires ${state.expiresAt?.toISOString() || 'unknown'}`)
2594
+ legacyPassthrough?.timelock?.onTimelockDetected?.(state)
2627
2595
  },
2628
2596
  onTimelockLifted: state => {
2629
2597
  this._log('Timelock lifted \u2014 resuming new contact messages')
2630
- timelockOverrides.onTimelockLifted?.(state)
2598
+ legacyPassthrough?.timelock?.onTimelockLifted?.(state)
2631
2599
  }
2632
2600
  })
2633
- this.replyRatioGuard = new ReplyRatioGuard(replyRatioCfg)
2634
- this.contactGraphWarmer = new ContactGraphWarmer(contactGraphCfg)
2635
- this.presenceChoreographer = new PresenceChoreographer(presenceCfg)
2601
+ this.replyRatioGuard = new ReplyRatioGuard(legacyPassthrough?.replyRatio)
2602
+ this.contactGraphWarmer = new ContactGraphWarmer(legacyPassthrough?.contactGraph)
2603
+ this.presenceChoreographer = new PresenceChoreographer(legacyPassthrough?.presence)
2636
2604
  this.retryTrackerModule = new RetryReasonTracker({
2637
- ...(retryTrackerCfg || {}),
2605
+ ...(legacyPassthrough?.retryTracker || {}),
2638
2606
  onSpiral: (msgId, reason) => {
2639
2607
  this._log(`\u26A0\uFE0F Message ${msgId} stuck in retry spiral (${reason})`)
2640
- retryTrackerCfg?.onSpiral?.(msgId, reason)
2608
+ legacyPassthrough?.retryTracker?.onSpiral?.(msgId, reason)
2641
2609
  }
2642
2610
  })
2643
2611
  this.reconnectThrottleModule = new PostReconnectThrottle({
2644
- ...(reconnectThrottleCfg || {}),
2612
+ ...(legacyPassthrough?.reconnectThrottle || {}),
2645
2613
  baselineRatePerMinute: () => this.rateLimiter.getStats().limits.perMinute
2646
2614
  })
2647
- if (jidCanonicalizerCfg?.enabled) {
2648
- if (jidCanonicalizerCfg.resolver) {
2649
- this.jidCanonicalizerModule = new JidCanonicalizer(jidCanonicalizerCfg)
2650
- this.lidResolverModule = jidCanonicalizerCfg.resolver
2615
+ if (legacyPassthrough?.jidCanonicalizer?.enabled) {
2616
+ if (legacyPassthrough.jidCanonicalizer.resolver) {
2617
+ this.jidCanonicalizerModule = new JidCanonicalizer(legacyPassthrough.jidCanonicalizer)
2618
+ this.lidResolverModule = legacyPassthrough.jidCanonicalizer.resolver
2651
2619
  } else {
2652
- const resolverConfig = lidResolverCfg || jidCanonicalizerCfg.resolverConfig
2620
+ const resolverConfig = legacyPassthrough.lidResolver || legacyPassthrough.jidCanonicalizer.resolverConfig
2653
2621
  const resolver = new LidResolver(resolverConfig)
2654
2622
  this.lidResolverModule = resolver
2655
2623
  this.jidCanonicalizerModule = new JidCanonicalizer({
2656
- ...jidCanonicalizerCfg,
2624
+ ...legacyPassthrough.jidCanonicalizer,
2657
2625
  resolver
2658
2626
  })
2659
2627
  }
2660
- } else if (lidResolverCfg) {
2661
- this.lidResolverModule = new LidResolver(lidResolverCfg)
2628
+ } else if (legacyPassthrough?.lidResolver) {
2629
+ this.lidResolverModule = new LidResolver(legacyPassthrough.lidResolver)
2662
2630
  }
2663
- if (sessionStabilityCfg?.enabled) {
2631
+ if (legacyPassthrough?.sessionStability?.enabled) {
2664
2632
  const healthConfig = {
2665
- badMacThreshold: sessionStabilityCfg.badMacThreshold,
2666
- badMacWindowMs: sessionStabilityCfg.badMacWindowMs,
2633
+ badMacThreshold: legacyPassthrough.sessionStability.badMacThreshold,
2634
+ badMacWindowMs: legacyPassthrough.sessionStability.badMacWindowMs,
2667
2635
  onDegraded: stats => {
2668
- this._log(
2669
- `\u{1F534} SESSION DEGRADED \u2014 Bad MAC rate: ${stats.badMacCount} in last ${sessionStabilityCfg.badMacWindowMs || 6e4}ms`
2670
- )
2636
+ this._log(`\u{1F534} SESSION DEGRADED \u2014 Bad MAC rate: ${stats.badMacCount} in last ${legacyPassthrough?.sessionStability?.badMacWindowMs || 6e4}ms`)
2671
2637
  this._log('Consider restarting session or switching to LID-based canonical form')
2672
2638
  },
2673
2639
  onRecovered: () => {
@@ -2680,11 +2646,8 @@ var AntiBan = class {
2680
2646
  /**
2681
2647
  * Check if a message can be sent and get required delay.
2682
2648
  * Call this BEFORE every sendMessage().
2683
- *
2684
- * @param dedupKey - optional richer signature for identical-message detection
2685
- * (see RateLimiter.getDelay). Falls back to hashing `content` if omitted.
2686
2649
  */
2687
- async beforeSend(recipient, content, dedupKey) {
2650
+ async beforeSend(recipient, content) {
2688
2651
  const healthStatus = this.health.getStatus()
2689
2652
  if (this.health.isPaused()) {
2690
2653
  this.stats.messagesBlocked++
@@ -2710,9 +2673,7 @@ var AntiBan = class {
2710
2673
  if (!this.warmUp.canSend()) {
2711
2674
  this.stats.messagesBlocked++
2712
2675
  const warmUpStatus = this.warmUp.getStatus()
2713
- this._log(
2714
- `\u23F3 BLOCKED \u2014 warm-up day ${warmUpStatus.day}/${warmUpStatus.totalDays}, limit reached (${warmUpStatus.todaySent}/${warmUpStatus.todayLimit})`
2715
- )
2676
+ this._log(`\u23F3 BLOCKED \u2014 warm-up day ${warmUpStatus.day}/${warmUpStatus.totalDays}, limit reached (${warmUpStatus.todaySent}/${warmUpStatus.todayLimit})`)
2716
2677
  return {
2717
2678
  allowed: false,
2718
2679
  delayMs: 0,
@@ -2774,7 +2735,7 @@ var AntiBan = class {
2774
2735
  return { allowed: false, delayMs: 0, reason: 'Group rate limit exceeded', health: healthStatus }
2775
2736
  }
2776
2737
  }
2777
- let delay = await this.rateLimiter.getDelay(recipient, content, dedupKey)
2738
+ let delay = await this.rateLimiter.getDelay(recipient, content)
2778
2739
  if (delay === -1) {
2779
2740
  this.stats.messagesBlocked++
2780
2741
  this._log(`\u{1F6AB} BLOCKED \u2014 rate limit or identical message spam`)
@@ -2811,8 +2772,8 @@ var AntiBan = class {
2811
2772
  * Record a successfully sent message.
2812
2773
  * Call this AFTER every successful sendMessage().
2813
2774
  */
2814
- afterSend(recipient, content, dedupKey) {
2815
- this.rateLimiter.record(recipient, content, dedupKey)
2775
+ afterSend(recipient, content) {
2776
+ this.rateLimiter.record(recipient, content)
2816
2777
  this.warmUp.record()
2817
2778
  this.replyRatioGuard.recordSent(recipient)
2818
2779
  this.stats.messagesAllowed++
@@ -3182,180 +3143,132 @@ function getRetryReasonDescription(reason) {
3182
3143
  }
3183
3144
 
3184
3145
  // wrapper.js
3185
- /**
3186
- * Cheap, stable-ish fingerprint for a media payload. Used only for identical-message
3187
- * spam detection, not for integrity — collisions are acceptable, false "different"
3188
- * results are not (they just mean a real repeat isn't deduped, which is safe).
3189
- */
3190
- function mediaFingerprint(media) {
3191
- if (Buffer.isBuffer(media)) {
3192
- const len = media.length
3193
- const head = media.subarray(0, Math.min(24, len)).toString('hex')
3194
- const tail = len > 24 ? media.subarray(Math.max(24, len - 24)).toString('hex') : ''
3195
- return `buf:${len}:${head}:${tail}`
3196
- }
3197
- if (media && typeof media === 'object' && typeof media.url === 'string') {
3198
- return `url:${media.url}`
3199
- }
3200
- if (typeof media === 'string') {
3201
- return `str:${media}`
3202
- }
3203
- if (media && typeof media === 'object') {
3204
- // Stream or other unresolvable wrapper — no cheap stable fingerprint available.
3205
- // A per-call unique token means it's never deduped, which is the safe failure mode
3206
- // (a real repeat slips past the spam guard) rather than colliding unrelated media.
3207
- return `unresolvable:${Math.random().toString(36)}`
3208
- }
3209
- return 'none'
3210
- }
3211
- /**
3212
- * Build a signature covering the full range of Baileys message content shapes for
3213
- * identical-message spam detection. Plain text/caption extraction alone collapses
3214
- * every captionless image/video/document/sticker/location/contact/poll onto the
3215
- * same '' hash, which falsely flags bulk media sends as spam repeats. This folds
3216
- * in a type discriminator plus a cheap content fingerprint per shape instead.
3217
- */
3218
- function buildContentSignature(content) {
3219
- if (!content || typeof content !== 'object') return String(content ?? '')
3220
- const parts = []
3221
- const text =
3222
- content.text ||
3223
- content.caption ||
3224
- content.image?.caption ||
3225
- content.video?.caption ||
3226
- content.document?.caption ||
3227
- ''
3228
- if (text) parts.push(`text:${text}`)
3229
- if (content.image !== undefined) parts.push(`image:${mediaFingerprint(content.image)}`)
3230
- if (content.video !== undefined) parts.push(`video:${mediaFingerprint(content.video)}`)
3231
- if (content.audio !== undefined) parts.push(`audio:${mediaFingerprint(content.audio)}`)
3232
- if (content.sticker !== undefined) parts.push(`sticker:${mediaFingerprint(content.sticker)}`)
3233
- if (content.document !== undefined) {
3234
- parts.push(`document:${mediaFingerprint(content.document)}:${content.fileName || ''}`)
3235
- }
3236
- if (content.location) {
3237
- parts.push(`location:${content.location.degreesLatitude}:${content.location.degreesLongitude}`)
3238
- }
3239
- if (content.contacts) {
3240
- const vcards = content.contacts.contacts?.map(c => c.vcard).join('|') || JSON.stringify(content.contacts)
3241
- parts.push(`contacts:${vcards}`)
3242
- }
3243
- if (content.poll) {
3244
- parts.push(`poll:${content.poll.name}:${(content.poll.values || []).join(',')}`)
3245
- }
3246
- if (content.buttons) parts.push(`buttons:${JSON.stringify(content.buttons)}`)
3247
- if (content.templateButtons) parts.push(`template:${JSON.stringify(content.templateButtons)}`)
3248
- if (content.sections) parts.push(`sections:${JSON.stringify(content.sections)}`)
3249
- if (content.react) parts.push(`react:${content.react.text}:${content.react.key?.id || ''}`)
3250
- if (!parts.length) {
3251
- // Unknown/unmodeled content shape — don't silently collapse it onto '' either.
3252
- parts.push(`shape:${Object.keys(content).sort().join(',')}`)
3253
- }
3254
- return parts.join('|')
3255
- }
3256
3146
  function wrapSocket(sock, config, warmUpState, wrapOptions) {
3257
3147
  const antiban = new AntiBan(config, warmUpState)
3258
3148
  const options = {
3259
3149
  autoRespondToIncoming: false,
3260
3150
  ...wrapOptions
3261
3151
  }
3262
- // Auto-reply timers and event-bridge listeners both outlive a single sendMessage
3263
- // call, so both need explicit teardown on antiban.destroy() — otherwise a
3264
- // reconnect that re-wraps the socket leaks listeners, and a destroyed socket can
3265
- // still fire a queued auto-reply send.
3266
- const pendingAutoReplyTimers = new Set()
3267
- const scheduleAutoReply = (jid, suggestedText) => {
3268
- const replyDelay = Math.floor(Math.random() * 12e3) + 3e3
3269
- const timer = setTimeout(async () => {
3270
- pendingAutoReplyTimers.delete(timer)
3271
- try {
3272
- await sock.sendMessage(jid, { text: suggestedText })
3273
- } catch (error) {}
3274
- }, replyDelay)
3275
- pendingAutoReplyTimers.add(timer)
3276
- }
3277
- const handleConnectionUpdate = update => {
3278
- if (update.connection === 'close') {
3279
- const reason = update.lastDisconnect?.error?.output?.statusCode || 'unknown'
3280
- antiban.onDisconnect(reason)
3281
- }
3282
- if (update.connection === 'open') {
3283
- antiban.onReconnect()
3284
- }
3285
- if (update.reachoutTimeLock) {
3286
- antiban.timelock.onTimelockUpdate({
3287
- isActive: update.reachoutTimeLock.isActive,
3288
- timeEnforcementEnds: update.reachoutTimeLock.timeEnforcementEnds,
3289
- enforcementType: update.reachoutTimeLock.enforcementType
3290
- })
3291
- }
3292
- }
3293
- const handleMessagesUpdate = updates => {
3294
- for (const update of updates) {
3295
- if (update?.update?.messageStubParameters) {
3296
- const params = update.update.messageStubParameters
3297
- if (params.includes(463) || params.includes('463')) {
3298
- antiban.timelock.record463Error()
3152
+ if (typeof sock.ev.process === 'function') {
3153
+ sock.ev.process(async events => {
3154
+ if (events['connection.update']) {
3155
+ const update = events['connection.update']
3156
+ if (update.connection === 'close') {
3157
+ const reason = update.lastDisconnect?.error?.output?.statusCode || 'unknown'
3158
+ antiban.onDisconnect(reason)
3159
+ }
3160
+ if (update.connection === 'open') {
3161
+ antiban.onReconnect()
3162
+ }
3163
+ if (update.reachoutTimeLock) {
3164
+ antiban.timelock.onTimelockUpdate({
3165
+ isActive: update.reachoutTimeLock.isActive,
3166
+ timeEnforcementEnds: update.reachoutTimeLock.timeEnforcementEnds,
3167
+ enforcementType: update.reachoutTimeLock.enforcementType
3168
+ })
3299
3169
  }
3300
3170
  }
3301
- antiban.retryTracker.onMessageUpdate(update)
3302
- }
3303
- antiban.jidCanonicalizer?.onMessageUpdate(updates)
3304
- }
3305
- const handleMessagesUpsert = upsert => {
3306
- const { messages } = upsert
3307
- antiban.jidCanonicalizer?.onIncomingEvent(upsert)
3308
- for (const msg of messages || []) {
3309
- const jid = msg.key?.remoteJid
3310
- if (!jid) continue
3311
- antiban.timelock.registerKnownChat(jid)
3312
- const isSelf = msg.key?.fromMe || false
3313
- if (isSelf) continue
3314
- const msgText =
3315
- msg.message?.conversation ||
3316
- msg.message?.extendedTextMessage?.text ||
3317
- msg.message?.imageMessage?.caption ||
3318
- msg.message?.videoMessage?.caption ||
3319
- ''
3320
- const replySuggestion = antiban.onIncomingMessage(jid, msgText)
3321
- if (options.autoRespondToIncoming && replySuggestion.shouldReply && replySuggestion.suggestedText) {
3322
- scheduleAutoReply(jid, replySuggestion.suggestedText)
3171
+ if (events['messages.update']) {
3172
+ const updates = events['messages.update']
3173
+ for (const update of updates) {
3174
+ if (update?.update?.messageStubParameters) {
3175
+ const params = update.update.messageStubParameters
3176
+ if (params.includes(463) || params.includes('463')) {
3177
+ antiban.timelock.record463Error()
3178
+ }
3179
+ }
3180
+ antiban.retryTracker.onMessageUpdate(update)
3181
+ }
3182
+ antiban.jidCanonicalizer?.onMessageUpdate(updates)
3323
3183
  }
3324
- }
3325
- }
3326
- let stopEventBridge = () => {}
3327
- if (typeof sock.ev.process === 'function') {
3328
- const processListener = async events => {
3329
- if (events['connection.update']) handleConnectionUpdate(events['connection.update'])
3330
- if (events['messages.update']) handleMessagesUpdate(events['messages.update'])
3331
- if (events['messages.upsert']) handleMessagesUpsert(events['messages.upsert'])
3332
- }
3333
- const maybeUnsubscribe = sock.ev.process(processListener)
3334
- if (typeof maybeUnsubscribe === 'function') {
3335
- stopEventBridge = maybeUnsubscribe
3336
- }
3184
+ if (events['messages.upsert']) {
3185
+ const { messages } = events['messages.upsert']
3186
+ antiban.jidCanonicalizer?.onIncomingEvent(events['messages.upsert'])
3187
+ for (const msg of messages || []) {
3188
+ const jid = msg.key?.remoteJid
3189
+ if (!jid) continue
3190
+ antiban.timelock.registerKnownChat(jid)
3191
+ const isSelf = msg.key?.fromMe || false
3192
+ if (isSelf) continue
3193
+ const msgText =
3194
+ msg.message?.conversation ||
3195
+ msg.message?.extendedTextMessage?.text ||
3196
+ msg.message?.imageMessage?.caption ||
3197
+ msg.message?.videoMessage?.caption ||
3198
+ ''
3199
+ const replySuggestion = antiban.onIncomingMessage(jid, msgText)
3200
+ if (options.autoRespondToIncoming && replySuggestion.shouldReply && replySuggestion.suggestedText) {
3201
+ const replyDelay = Math.floor(Math.random() * 12e3) + 3e3
3202
+ setTimeout(async () => {
3203
+ try {
3204
+ await sock.sendMessage(jid, { text: replySuggestion.suggestedText })
3205
+ } catch (error) {}
3206
+ }, replyDelay)
3207
+ }
3208
+ }
3209
+ }
3210
+ })
3337
3211
  } else {
3338
- sock.ev.on('connection.update', handleConnectionUpdate)
3339
- sock.ev.on('messages.update', handleMessagesUpdate)
3340
- sock.ev.on('messages.upsert', handleMessagesUpsert)
3341
- stopEventBridge = () => {
3342
- sock.ev.off('connection.update', handleConnectionUpdate)
3343
- sock.ev.off('messages.update', handleMessagesUpdate)
3344
- sock.ev.off('messages.upsert', handleMessagesUpsert)
3345
- }
3212
+ sock.ev.on('connection.update', update => {
3213
+ if (update.connection === 'close') {
3214
+ const reason = update.lastDisconnect?.error?.output?.statusCode || 'unknown'
3215
+ antiban.onDisconnect(reason)
3216
+ }
3217
+ if (update.connection === 'open') {
3218
+ antiban.onReconnect()
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
+ })
3346
3266
  }
3347
3267
  const originalSendMessage = sock.sendMessage.bind(sock)
3348
3268
  const wrappedSendMessage = async (jid, content, options2) => {
3349
3269
  const canonicalJid = antiban.jidCanonicalizer?.canonicalizeTarget(jid) || jid
3350
- const text =
3351
- content?.text ||
3352
- content?.caption ||
3353
- content?.image?.caption ||
3354
- content?.video?.caption ||
3355
- content?.document?.caption ||
3356
- ''
3357
- const dedupKey = buildContentSignature(content)
3358
- const decision = await antiban.beforeSend(canonicalJid, text, dedupKey)
3270
+ const text = content?.text || content?.caption || content?.image?.caption || ''
3271
+ const decision = await antiban.beforeSend(canonicalJid, text)
3359
3272
  if (!decision.allowed) {
3360
3273
  throw new Error(`[baileys-antiban] Message blocked: ${decision.reason}`)
3361
3274
  }
@@ -3364,7 +3277,7 @@ function wrapSocket(sock, config, warmUpState, wrapOptions) {
3364
3277
  }
3365
3278
  try {
3366
3279
  const result = await originalSendMessage(canonicalJid, content, options2)
3367
- antiban.afterSend(canonicalJid, text, dedupKey)
3280
+ antiban.afterSend(canonicalJid, text)
3368
3281
  antiban.timelock.registerKnownChat(canonicalJid)
3369
3282
  if (result?.key?.id) {
3370
3283
  antiban.retryTracker.clear(result.key.id)
@@ -3378,13 +3291,7 @@ function wrapSocket(sock, config, warmUpState, wrapOptions) {
3378
3291
  const wrapped = Object.create(sock)
3379
3292
  wrapped.sendMessage = wrappedSendMessage
3380
3293
  wrapped.antiban = antiban
3381
- const originalDestroy = antiban.destroy.bind(antiban)
3382
- wrapped.antiban.destroy = () => {
3383
- stopEventBridge()
3384
- for (const timer of pendingAutoReplyTimers) clearTimeout(timer)
3385
- pendingAutoReplyTimers.clear()
3386
- originalDestroy()
3387
- }
3294
+ wrapped.antiban.destroy = antiban.destroy.bind(antiban)
3388
3295
  return wrapped
3389
3296
  }
3390
3297
 
@@ -3625,16 +3532,21 @@ var ContentVariator = class {
3625
3532
  return result
3626
3533
  }
3627
3534
  /**
3628
- * Create N unique variations of a message (deterministic via counter)
3535
+ * Create N unique variations of a message
3629
3536
  */
3630
3537
  varyBulk(text, count) {
3631
3538
  const results = []
3632
- const startCounter = this.counter
3539
+ const seen = /* @__PURE__ */ new Set()
3633
3540
  for (let i = 0; i < count; i++) {
3634
- this.counter = startCounter + i
3635
- results.push(this.vary(text))
3541
+ let variation = this.vary(text)
3542
+ let attempts = 0
3543
+ while (seen.has(variation) && attempts < 10) {
3544
+ variation = this.vary(text)
3545
+ attempts++
3546
+ }
3547
+ seen.add(variation)
3548
+ results.push(variation)
3636
3549
  }
3637
- this.counter = startCounter + count
3638
3550
  return results
3639
3551
  }
3640
3552
  addZeroWidth(text) {
@@ -3670,18 +3582,21 @@ var ContentVariator = class {
3670
3582
  return text + emojis[this.counter % emojis.length]
3671
3583
  }
3672
3584
  applySynonyms(text) {
3673
- const lower = text.toLowerCase()
3674
- for (const key of Object.keys(SYNONYMS)) {
3675
- const idx = lower.indexOf(key)
3676
- if (idx === -1) continue
3677
- const word = text.substring(idx, idx + key.length)
3678
- if (!SYNONYMS[key] || Math.random() > 0.5) continue
3679
- const synonym = SYNONYMS[key][Math.floor(Math.random() * SYNONYMS[key].length)]
3680
- const replacement =
3681
- word[0] === word[0].toUpperCase() ? synonym.charAt(0).toUpperCase() + synonym.slice(1) : synonym
3682
- return text.substring(0, idx) + replacement + text.substring(idx + key.length)
3683
- }
3684
- return text
3585
+ const words = text.split(/\b/)
3586
+ let replaced = false
3587
+ return words
3588
+ .map(word => {
3589
+ if (replaced) return word
3590
+ const lower = word.toLowerCase()
3591
+ const synonymList = SYNONYMS[lower]
3592
+ if (synonymList && Math.random() > 0.5) {
3593
+ replaced = true
3594
+ const synonym = synonymList[Math.floor(Math.random() * synonymList.length)]
3595
+ return word[0] === word[0].toUpperCase() ? synonym.charAt(0).toUpperCase() + synonym.slice(1) : synonym
3596
+ }
3597
+ return word
3598
+ })
3599
+ .join('')
3685
3600
  }
3686
3601
  randomPositions(max, count) {
3687
3602
  const positions = []
@@ -4172,31 +4087,27 @@ function messageRecovery(sock, config) {
4172
4087
 
4173
4088
  // deviceFingerprint.js
4174
4089
  var DEFAULT_APP_VERSION_POOL = [
4175
- [2, 25, 10, 67],
4176
- [2, 25, 10, 68],
4177
- [2, 25, 9, 96],
4178
- [2, 25, 8, 77],
4179
- [2, 25, 7, 85],
4180
- [2, 25, 6, 98],
4181
- [2, 24, 22, 78],
4182
- [2, 24, 20, 86]
4090
+ [2, 24, 5, 18],
4091
+ [2, 24, 5, 17],
4092
+ [2, 24, 4, 77],
4093
+ [2, 24, 5, 15],
4094
+ [2, 24, 3, 91],
4095
+ [2, 24, 5, 20]
4183
4096
  ]
4184
- var DEFAULT_OS_VERSION_POOL = ['11', '12', '13', '14', '15']
4097
+ var DEFAULT_OS_VERSION_POOL = ['10', '11', '12', '13', '14']
4185
4098
  var DEFAULT_DEVICE_MODEL_POOL = [
4186
- 'Pixel 8',
4187
- 'Pixel 9',
4099
+ 'Pixel 6',
4188
4100
  'Pixel 7',
4189
- 'Galaxy S24',
4190
- 'Galaxy S23',
4191
4101
  'Galaxy S22',
4192
- 'Xiaomi 14',
4102
+ 'Galaxy S23',
4193
4103
  'Xiaomi 13',
4194
- 'OnePlus 12',
4104
+ 'Xiaomi 12',
4195
4105
  'OnePlus 11',
4196
4106
  'Moto G84',
4197
- 'Realme 12',
4198
- 'Vivo V30',
4199
- 'Oppo Find X7'
4107
+ 'Moto G54',
4108
+ 'Realme 11',
4109
+ 'Vivo V29',
4110
+ 'Oppo Find X6'
4200
4111
  ]
4201
4112
  var SeededRandom = class {
4202
4113
  state