@badzz88/baileys 8.5.4 → 8.5.5

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 (107) hide show
  1. package/README.md +1 -1
  2. package/WAProto/WAProto.proto +75 -1256
  3. package/WAProto/index.d.ts +19729 -36122
  4. package/WAProto/index.js +132193 -178538
  5. package/engine-requirements.js +15 -7
  6. package/lib/Defaults/index.js +14 -22
  7. package/lib/Signal/Group/group_cipher.js +5 -5
  8. package/lib/Signal/Group/keyhelper.js +4 -4
  9. package/lib/Signal/Group/sender-chain-key.js +2 -2
  10. package/lib/Signal/Group/sender-key-distribution-message.js +1 -1
  11. package/lib/Signal/Group/sender-key-message.js +3 -3
  12. package/lib/Signal/Group/sender-key-record.js +1 -1
  13. package/lib/Signal/Group/sender-message-key.js +5 -5
  14. package/lib/Signal/libsignal.js +28 -39
  15. package/lib/Signal/lid-mapping.js +8 -28
  16. package/lib/Socket/aigroups.js +5 -5
  17. package/lib/Socket/business.js +11 -3
  18. package/lib/Socket/chats.js +319 -668
  19. package/lib/Socket/communities.js +89 -85
  20. package/lib/Socket/graphql.js +228 -435
  21. package/lib/Socket/groups.js +211 -132
  22. package/lib/Socket/index.js +7 -9
  23. package/lib/Socket/interactive-handler.js +60 -117
  24. package/lib/Socket/interop.js +175 -56
  25. package/lib/Socket/luxu.js +387 -0
  26. package/lib/Socket/managed-account.js +48 -79
  27. package/lib/Socket/messages-recv.js +340 -898
  28. package/lib/Socket/messages-send.js +160 -462
  29. package/lib/Socket/mex.js +53 -40
  30. package/lib/Socket/newsletter.js +295 -291
  31. package/lib/Socket/privacy.js +265 -77
  32. package/lib/Socket/registration.js +157 -164
  33. package/lib/Socket/socket.js +199 -181
  34. package/lib/Socket/text-router.js +83 -0
  35. package/lib/Socket/username.js +227 -144
  36. package/lib/Store/keyed-db.js +108 -0
  37. package/lib/Store/make-cache-manager-store.js +2 -2
  38. package/lib/Store/make-in-memory-store.js +141 -25
  39. package/lib/Types/Auth.js +3 -3
  40. package/lib/Types/Label.js +1 -1
  41. package/lib/Types/LabelAssociation.js +1 -1
  42. package/lib/Types/Mex.js +112 -0
  43. package/lib/Types/Newsletter.js +65 -96
  44. package/lib/Types/State.js +4 -4
  45. package/lib/Types/index.js +1 -1
  46. package/lib/Utils/auth-utils.js +57 -52
  47. package/lib/Utils/browser-utils.js +1 -1
  48. package/lib/Utils/business.js +6 -2
  49. package/lib/Utils/chat-utils.js +38 -102
  50. package/lib/Utils/command-loader.d.ts +31 -0
  51. package/lib/Utils/command-loader.js +100 -0
  52. package/lib/Utils/companion-reg-client-utils.js +42 -0
  53. package/lib/Utils/crypto.js +84 -54
  54. package/lib/Utils/curve25519-js.js +275 -0
  55. package/lib/Utils/decode-wa-message.js +83 -316
  56. package/lib/Utils/event-buffer.js +61 -37
  57. package/lib/Utils/generics.js +103 -157
  58. package/lib/Utils/group-history.js +12 -3
  59. package/lib/Utils/history.js +15 -15
  60. package/lib/Utils/index.js +5 -1
  61. package/lib/Utils/link-preview.js +8 -3
  62. package/lib/Utils/lt-hash.js +35 -2
  63. package/lib/Utils/make-mutex.js +1 -1
  64. package/lib/Utils/message-retry-manager.js +92 -27
  65. package/lib/Utils/messages-media.js +130 -159
  66. package/lib/Utils/messages.js +566 -144
  67. package/lib/Utils/meta-ai-msmsg.js +202 -62
  68. package/lib/Utils/native-bridge.js +82 -0
  69. package/lib/Utils/noise-handler.js +21 -19
  70. package/lib/Utils/offline-node-processor.js +8 -3
  71. package/lib/Utils/pre-key-manager.js +23 -13
  72. package/lib/Utils/process-message.js +106 -197
  73. package/lib/Utils/reporting-utils.js +2 -2
  74. package/lib/Utils/session-pool.d.ts +16 -0
  75. package/lib/Utils/session-pool.js +94 -0
  76. package/lib/Utils/signal.js +63 -28
  77. package/lib/Utils/stanza-ack.js +12 -39
  78. package/lib/Utils/sticker.d.ts +17 -0
  79. package/lib/Utils/sticker.js +145 -0
  80. package/lib/Utils/sync-action-utils.js +7 -4
  81. package/lib/Utils/tc-token-utils.js +25 -20
  82. package/lib/Utils/use-multi-file-auth-state.js +14 -30
  83. package/lib/Utils/validate-connection.js +19 -59
  84. package/lib/Utils/view-once-cache.d.ts +9 -0
  85. package/lib/Utils/view-once-cache.js +79 -0
  86. package/lib/WABinary/decode.js +16 -50
  87. package/lib/WABinary/encode.js +224 -54
  88. package/lib/WABinary/generic-utils.js +97 -7
  89. package/lib/WABinary/jid-utils.js +14 -27
  90. package/lib/WAM/encode.js +7 -7
  91. package/lib/WAUSync/Protocols/USyncBusinessProtocol.js +1 -58
  92. package/lib/WAUSync/Protocols/USyncContactProtocol.js +1 -7
  93. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +5 -13
  94. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +4 -1
  95. package/lib/WAUSync/Protocols/USyncFeatureProtocol.js +7 -20
  96. package/lib/WAUSync/Protocols/USyncPictureProtocol.js +1 -1
  97. package/lib/WAUSync/Protocols/USyncSidelistProtocol.js +2 -2
  98. package/lib/WAUSync/Protocols/USyncStatusProtocol.js +2 -7
  99. package/lib/WAUSync/Protocols/USyncTextStatusProtocol.js +1 -1
  100. package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +1 -2
  101. package/lib/WAUSync/Protocols/index.js +0 -1
  102. package/lib/WAUSync/USyncQuery.js +6 -77
  103. package/lib/WAUSync/USyncUser.js +8 -16
  104. package/lib/WAUSync/index.js +0 -1
  105. package/lib/antiban.js +854 -608
  106. package/lib/index.js +1 -1
  107. package/package.json +20 -16
@@ -41,9 +41,11 @@ exports.bindWaitForEvent = bindWaitForEvent
41
41
  exports.trimUndefined = trimUndefined
42
42
  exports.bytesToCrockford = bytesToCrockford
43
43
  exports.encodeNewsletterMessage = encodeNewsletterMessage
44
+ exports.generateIOSMessageID = void 0
45
+ exports.generateAndroMessageID = void 0
44
46
  const boom_1 = require('@hapi/boom')
45
47
  const crypto_1 = require('crypto')
46
- const rb = require('whatsapp-rust-bridge')
48
+ const Crypto_1 = require('./crypto')
47
49
  const DEFAULTS_1 = require('../Defaults')
48
50
  const index_js_1 = require('../../WAProto/index.js')
49
51
  const baileysVersion = DEFAULTS_1.VERSION
@@ -51,14 +53,14 @@ const Types_1 = require('../Types')
51
53
  const WABinary_1 = require('../WABinary')
52
54
  const crypto_2 = require('./crypto')
53
55
  exports.BufferJSON = {
54
-
56
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
55
57
  replacer: (k, value) => {
56
58
  if (Buffer.isBuffer(value) || value instanceof Uint8Array || value?.type === 'Buffer') {
57
59
  return { type: 'Buffer', data: Buffer.from(value?.data || value).toString('base64') }
58
60
  }
59
61
  return value
60
62
  },
61
-
63
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
62
64
  reviver: (_, value) => {
63
65
  if (typeof value === 'object' && value !== null && value.type === 'Buffer' && typeof value.data === 'string') {
64
66
  return Buffer.from(value.data, 'base64')
@@ -79,7 +81,7 @@ const getKeyAuthor = (key, meId = 'me') =>
79
81
  (key?.fromMe ? meId : key?.participantAlt || key?.remoteJidAlt || key?.participant || key?.remoteJid) || ''
80
82
  exports.getKeyAuthor = getKeyAuthor
81
83
  const isStringNullOrEmpty = value =>
82
-
84
+ // eslint-disable-next-line eqeqeq
83
85
  value == null || value === ''
84
86
  exports.isStringNullOrEmpty = isStringNullOrEmpty
85
87
  const writeRandomPadMax16 = msg => {
@@ -100,7 +102,7 @@ const unpadRandomMax16 = e => {
100
102
  return new Uint8Array(t.buffer, t.byteOffset, t.length - r)
101
103
  }
102
104
  exports.unpadRandomMax16 = unpadRandomMax16
103
-
105
+ // code is inspired by whatsmeow
104
106
  const generateParticipantHashV2 = participants => {
105
107
  participants.sort()
106
108
  const sha256Hash = (0, crypto_2.sha256)(Buffer.from(participants.join(''))).toString('base64')
@@ -125,7 +127,7 @@ const encodeBigEndian = (e, t = 4) => {
125
127
  exports.encodeBigEndian = encodeBigEndian
126
128
  const toNumber = t => (typeof t === 'object' && t ? ('toNumber' in t ? t.toNumber() : t.low) : t || 0)
127
129
  exports.toNumber = toNumber
128
-
130
+ /** unix timestamp of a date in seconds */
129
131
  const unixTimestampSeconds = (date = new Date()) => Math.floor(date.getTime() / 1000)
130
132
  exports.unixTimestampSeconds = unixTimestampSeconds
131
133
  const debouncedTimeout = (intervalMs = 1000, task) => {
@@ -175,7 +177,7 @@ async function promiseTimeout(ms, promise) {
175
177
  return new Promise(promise)
176
178
  }
177
179
  const stack = new Error().stack
178
-
180
+ // Create a promise that rejects in <ms> milliseconds
179
181
  const { delay, cancel } = (0, exports.delayCancellable)(ms)
180
182
  const p = new Promise((resolve, reject) => {
181
183
  delay
@@ -194,26 +196,38 @@ async function promiseTimeout(ms, promise) {
194
196
  }).finally(cancel)
195
197
  return p
196
198
  }
197
-
198
-
199
- const generateMessageIDV2 = userId => {
200
- const data = Buffer.alloc(8 + 20 + 16)
201
- data.writeBigUInt64BE(BigInt(Math.floor(Date.now() / 1000)))
202
- if (userId) {
203
- const id = (0, WABinary_1.jidDecode)(userId)
204
- if (id?.user) {
205
- data.write(id.user, 8)
206
- data.write('@c.us', 8 + id.user.length)
207
- }
208
- }
209
- const random = (0, crypto_1.randomBytes)(16)
210
- random.copy(data, 28)
211
- const hash = Buffer.from(rb.sha256(data))
212
- return '3EB0' + hash.toString('hex').toUpperCase().substring(0, 18)
213
- }
199
+ // inspired from whatsmeow code
200
+ // https://github.com/tulir/whatsmeow/blob/64bc969fbe78d31ae0dd443b8d4c80a5d026d07a/send.go#L42
201
+ const generateMessageIDV2 = (userId) => {
202
+ const data = Buffer.alloc(8 + 20 + 16);
203
+ data.writeBigUInt64BE(BigInt(Math.floor(Date.now() / 1000)));
204
+ if (userId) {
205
+ const id = (0, WABinary_1.jidDecode)(userId);
206
+ if (id?.user) {
207
+ data.write(id.user, 8);
208
+ data.write('@c.us', 8 + id.user.length);
209
+ }
210
+ }
211
+ const random = (0, crypto_1.randomBytes)(16);
212
+ random.copy(data, 28);
213
+ const hash = (0, crypto_1.createHash)('sha256').update(data).digest();
214
+ return 'XZCYYX-' + hash.toString('hex').toUpperCase().substring(0, 18);
215
+ };
214
216
  exports.generateMessageIDV2 = generateMessageIDV2
215
-
216
- const generateMessageID = () => '3EB0' + (0, crypto_1.randomBytes)(18).toString('hex').toUpperCase()
217
+ const generateIOSMessageID = () => {
218
+ const prefix = '3A';
219
+ const random = (0, crypto_1.randomBytes)(9.5); // 19 hex chars = 9.5 bytes
220
+ return (prefix + random.toString('hex')).toUpperCase().substring(0, 21);
221
+ };
222
+ exports.generateIOSMessageID = generateIOSMessageID
223
+ const generateAndroMessageID = () => {
224
+ const prefix = '3A';
225
+ const random = (0, crypto_1.randomBytes)(16); // 32 hex chars = 16 bytes
226
+ return (random.toString('hex')).toUpperCase().substring(0, 21);
227
+ };
228
+ exports.generateAndroMessageID = generateAndroMessageID
229
+ // generate a random ID to attach to a message
230
+ const generateMessageID = () => 'XZCYYX-' + (0, crypto_1.randomBytes)(18).toString('hex').toUpperCase()
217
231
  exports.generateMessageID = generateMessageID
218
232
  function bindWaitForEvent(ev, event) {
219
233
  return async (check, timeoutMs) => {
@@ -243,33 +257,30 @@ function bindWaitForEvent(ev, event) {
243
257
  }
244
258
  const bindWaitForConnectionUpdate = ev => bindWaitForEvent(ev, 'connection.update')
245
259
  exports.bindWaitForConnectionUpdate = bindWaitForConnectionUpdate
246
-
260
+ /**
261
+ * utility that fetches latest baileys version from the master branch.
262
+ * Use to ensure your WA connection is always on the latest version
263
+ */
247
264
  const fetchLatestBaileysVersion = async (options = {}) => {
248
265
  const URL = 'https://raw.githubusercontent.com/WhiskeySockets/Baileys/master/src/Defaults/index.ts'
249
266
  try {
250
-
251
-
252
- const controller = new AbortController()
253
- const timer = setTimeout(() => controller.abort(), options.timeout ?? 5000)
254
267
  const response = await fetch(URL, {
255
268
  dispatcher: options.dispatcher,
256
269
  method: 'GET',
257
- headers: options.headers,
258
- signal: controller.signal
270
+ headers: options.headers
259
271
  })
260
- clearTimeout(timer)
261
272
  if (!response.ok) {
262
273
  throw new boom_1.Boom(`Failed to fetch latest Baileys version: ${response.statusText}`, {
263
274
  statusCode: response.status
264
275
  })
265
276
  }
266
277
  const text = await response.text()
267
-
278
+ // Extract version from line 7 (const version = [...])
268
279
  const lines = text.split('\n')
269
- const versionLine = lines[6]
280
+ const versionLine = lines[6] // Line 7 (0-indexed)
270
281
  const versionMatch = versionLine.match(/const version = \[(\d+),\s*(\d+),\s*(\d+)\]/)
271
282
  if (versionMatch) {
272
- const version = [parseInt(versionMatch[1], 10), parseInt(versionMatch[2], 10), parseInt(versionMatch[3], 10)]
283
+ const version = [parseInt(versionMatch[1]), parseInt(versionMatch[2]), parseInt(versionMatch[3])]
273
284
  return {
274
285
  version,
275
286
  isLatest: true
@@ -286,25 +297,24 @@ const fetchLatestBaileysVersion = async (options = {}) => {
286
297
  }
287
298
  }
288
299
  exports.fetchLatestBaileysVersion = fetchLatestBaileysVersion
289
-
300
+ /**
301
+ * A utility that fetches the latest web version of whatsapp.
302
+ * Use to ensure your WA connection is always on the latest version
303
+ */
290
304
  const fetchLatestWaWebVersion = async (options = {}) => {
291
305
  try {
292
-
306
+ // Absolute minimal headers required to bypass anti-bot detection
293
307
  const defaultHeaders = {
294
308
  'sec-fetch-site': 'none',
295
309
  'user-agent':
296
310
  'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36'
297
311
  }
298
312
  const headers = { ...defaultHeaders, ...options.headers }
299
- const controller = new AbortController()
300
- const timer = setTimeout(() => controller.abort(), options.timeout ?? 5000)
301
313
  const response = await fetch('https://web.whatsapp.com/sw.js', {
302
314
  ...options,
303
315
  method: 'GET',
304
- headers,
305
- signal: controller.signal
316
+ headers
306
317
  })
307
- clearTimeout(timer)
308
318
  if (!response.ok) {
309
319
  throw new boom_1.Boom(`Failed to fetch sw.js: ${response.statusText}`, { statusCode: response.status })
310
320
  }
@@ -334,7 +344,7 @@ const fetchLatestWaWebVersion = async (options = {}) => {
334
344
  }
335
345
  }
336
346
  exports.fetchLatestWaWebVersion = fetchLatestWaWebVersion
337
-
347
+ /** unique message tag prefix for MD clients */
338
348
  const generateMdTagPrefix = () => {
339
349
  const bytes = (0, crypto_1.randomBytes)(4)
340
350
  return `${bytes.readUInt16BE()}.${bytes.readUInt16BE(2)}-`
@@ -343,11 +353,13 @@ exports.generateMdTagPrefix = generateMdTagPrefix
343
353
  const STATUS_MAP = {
344
354
  sender: index_js_1.proto.WebMessageInfo.Status.SERVER_ACK,
345
355
  played: index_js_1.proto.WebMessageInfo.Status.PLAYED,
346
- 'played-self': index_js_1.proto.WebMessageInfo.Status.PLAYED,
347
356
  read: index_js_1.proto.WebMessageInfo.Status.READ,
348
357
  'read-self': index_js_1.proto.WebMessageInfo.Status.READ
349
358
  }
350
-
359
+ /**
360
+ * Given a type of receipt, returns what the new status of the message should be
361
+ * @param type type from receipt
362
+ */
351
363
  const getStatusFromReceiptType = type => {
352
364
  const status = STATUS_MAP[type]
353
365
  if (typeof type === 'undefined') {
@@ -359,7 +371,10 @@ exports.getStatusFromReceiptType = getStatusFromReceiptType
359
371
  const CODE_MAP = {
360
372
  conflict: Types_1.DisconnectReason.connectionReplaced
361
373
  }
362
-
374
+ /**
375
+ * Stream errors generally provide a reason, map that to a baileys DisconnectReason
376
+ * @param reason the string reason given, eg. "conflict"
377
+ */
363
378
  const getErrorCodeFromStreamError = node => {
364
379
  const [reasonNode] = (0, WABinary_1.getAllBinaryNodeChildren)(node)
365
380
  let reason = reasonNode?.tag || 'unknown'
@@ -381,31 +396,11 @@ const getCallStatusFromNode = ({ tag, attrs }) => {
381
396
  status = 'offer'
382
397
  break
383
398
  case 'terminate':
384
-
385
- switch (attrs.reason) {
386
- case 'timeout':
387
- case 'Timeout':
388
- status = 'timeout'
389
- break
390
- case 'RejectDoNotDisturb':
391
- status = 'reject_do_not_disturb'
392
- break
393
- case 'MicPermissionDenied':
394
- status = 'mic_permission_denied'
395
- break
396
- case 'CameraPermissionDenied':
397
- status = 'camera_permission_denied'
398
- break
399
- case 'RemoteBusy':
400
- status = 'remote_busy'
401
- break
402
- case 'RemoteOffline':
403
- status = 'remote_offline'
404
- break
405
- default:
406
-
407
- status = 'terminate'
408
- break
399
+ if (attrs.reason === 'timeout') {
400
+ status = 'timeout'
401
+ } else {
402
+ //fired when accepted/rejected/timeout/caller hangs up
403
+ status = 'terminate'
409
404
  }
410
405
  break
411
406
  case 'reject':
@@ -414,76 +409,6 @@ const getCallStatusFromNode = ({ tag, attrs }) => {
414
409
  case 'accept':
415
410
  status = 'accept'
416
411
  break
417
- case 'preaccept':
418
- status = 'preaccept'
419
- break
420
- case 'accept_ack':
421
- status = 'accept_ack'
422
- break
423
- case 'enc-rekey':
424
- case 'enc_rekey':
425
- status = 'enc_rekey'
426
- break
427
- case 'peer_state':
428
- status = 'peer_state'
429
- break
430
- case 'group_info':
431
- status = 'group_info'
432
- break
433
- case 'video_state':
434
- status = 'video_state'
435
- break
436
- case 'video_state_ack':
437
- status = 'video_state_ack'
438
- break
439
- case 'flow_control':
440
- status = 'flow_control'
441
- break
442
- case 'relaylatency':
443
- status = 'relaylatency'
444
- break
445
- case 'mute_v2':
446
- status = 'mute'
447
- break
448
- case 'waiting_room_request':
449
- status = 'waiting_room_request'
450
- break
451
- case 'signal':
452
-
453
- switch (attrs.type) {
454
- case '13':
455
- status = 'preaccept'
456
- break
457
- case '15':
458
- status = 'video_state'
459
- break
460
- case '17':
461
- status = 'group_info'
462
- break
463
- case '20':
464
- status = 'video_state_ack'
465
- break
466
- case '21':
467
- status = 'flow_control'
468
- break
469
- case '23':
470
- status = 'accept_ack'
471
- break
472
- case '1002':
473
- case '1007':
474
- status = 'peer_state'
475
- break
476
- case '1008':
477
- status = 'enc_rekey'
478
- break
479
- case '12':
480
- status = 'mute'
481
- break
482
- default:
483
- status = 'ringing'
484
- break
485
- }
486
- break
487
412
  default:
488
413
  status = 'ringing'
489
414
  break
@@ -500,22 +425,25 @@ const getCodeFromWSError = error => {
500
425
  statusCode = code
501
426
  }
502
427
  } else if (
503
-
428
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
504
429
  error?.code?.startsWith('E') ||
505
430
  error?.message?.includes('timed out')
506
431
  ) {
507
-
432
+ // handle ETIMEOUT, ENOTFOUND etc
508
433
  statusCode = 408
509
434
  }
510
435
  return statusCode
511
436
  }
512
437
  exports.getCodeFromWSError = getCodeFromWSError
513
-
438
+ /**
439
+ * Is the given platform WA business
440
+ * @param platform AuthenticationCreds.platform
441
+ */
514
442
  const isWABusinessPlatform = platform => {
515
443
  return platform === 'smbi' || platform === 'smba'
516
444
  }
517
445
  exports.isWABusinessPlatform = isWABusinessPlatform
518
-
446
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
519
447
  function trimUndefined(obj) {
520
448
  for (const key in obj) {
521
449
  if (typeof obj[key] === 'undefined') {
@@ -546,40 +474,51 @@ function encodeNewsletterMessage(message) {
546
474
  return index_js_1.proto.Message.encode(message).finish()
547
475
  }
548
476
 
549
-
477
+ /**
478
+ * Add human-like jitter to a base delay
479
+ * @param baseMs base delay in milliseconds
480
+ * @param varianceFraction fraction of baseMs to use as variance (0–1), default 0.3
481
+ */
550
482
  const jitterDelay = (baseMs, varianceFraction = 0.3) => {
551
483
  const variance = baseMs * varianceFraction
552
484
  return baseMs + (Math.random() * 2 - 1) * variance
553
485
  }
554
486
  exports.jitterDelay = jitterDelay
555
487
 
556
-
488
+ /**
489
+ * Compute exponential backoff delay for a given attempt number (0-based)
490
+ * @param attempt attempt index (0 = first retry)
491
+ * @param baseMs starting delay in ms (default 500)
492
+ * @param maxMs maximum delay cap in ms (default 30000)
493
+ */
557
494
  const exponentialBackoff = (attempt, baseMs = 500, maxMs = 30000) => {
558
495
  return Math.min(baseMs * Math.pow(2, attempt), maxMs)
559
496
  }
560
497
  exports.exponentialBackoff = exponentialBackoff
561
498
 
562
-
499
+ /** Convert buffer/Uint8Array to hex string */
563
500
  const bytesToHex = buf => Buffer.from(buf).toString('hex')
564
501
  exports.bytesToHex = bytesToHex
565
502
 
566
-
503
+ /** Convert hex string to Buffer */
567
504
  const hexToBytes = hex => Buffer.from(hex, 'hex')
568
505
  exports.hexToBytes = hexToBytes
569
506
 
570
-
507
+ /** Convert buffer to base64url string */
571
508
  const bytesToBase64Url = buf => Buffer.from(buf).toString('base64url')
572
509
  exports.bytesToBase64Url = bytesToBase64Url
573
510
 
574
-
511
+ /** Compute SHA-256 hex digest of data */
575
512
  const sha256Hex = data => (0, crypto_1.createHash)('sha256').update(data).digest('hex')
576
513
  exports.sha256Hex = sha256Hex
577
514
 
578
-
515
+ /** Compute HMAC-SHA-256 of data with key, returns Buffer */
579
516
  const hmacSha256 = (data, key) => (0, crypto_1.createHmac)('sha256', key).update(data).digest()
580
517
  exports.hmacSha256 = hmacSha256
581
518
 
582
-
519
+ /**
520
+ * Normalize and deduplicate an array of JIDs
521
+ */
583
522
  const normalizeJidBatch = (jids, normalizer) => {
584
523
  const seen = new Set()
585
524
  const result = []
@@ -595,11 +534,18 @@ const normalizeJidBatch = (jids, normalizer) => {
595
534
  }
596
535
  exports.normalizeJidBatch = normalizeJidBatch
597
536
 
598
-
537
+ /**
538
+ * Sleep for a given number of milliseconds, returns a cancellable promise
539
+ */
599
540
  const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
600
541
  exports.sleep = sleep
601
542
 
602
-
543
+ /**
544
+ * Run an async function with retry using exponential backoff
545
+ * @param fn async function to retry
546
+ * @param maxAttempts maximum number of attempts
547
+ * @param baseDelayMs base delay between retries
548
+ */
603
549
  const withRetry = async (fn, maxAttempts = 3, baseDelayMs = 500) => {
604
550
  let lastErr
605
551
  for (let i = 0; i < maxAttempts; i++) {
@@ -4,7 +4,13 @@ exports.processGroupHistory = exports.decodeGroupHistory = void 0
4
4
  const zlib_1 = require('zlib')
5
5
  const index_js_1 = require('../../WAProto/index.js')
6
6
 
7
-
7
+ /**
8
+ * Decode a GroupHistory protobuf blob (community/group history container).
9
+ * @param buffer raw bytes, optionally zlib-compressed
10
+ * @param options.inflate try zlib.inflateSync first, falling back to raw bytes (default true)
11
+ * @param options.withMessageBytes decode the GroupHistoryWithMessageBytes variant,
12
+ * expanding each entry's messageBytes into a WebMessageInfo (default false)
13
+ */
8
14
  const decodeGroupHistory = (buffer, options = {}) => {
9
15
  const { inflate = true, withMessageBytes = false } = options
10
16
  if (!Buffer.isBuffer(buffer) && !(buffer instanceof Uint8Array)) {
@@ -15,7 +21,7 @@ const decodeGroupHistory = (buffer, options = {}) => {
15
21
  try {
16
22
  data = zlib_1.inflateSync(data)
17
23
  } catch {
18
-
24
+ // not zlib-compressed — use raw bytes
19
25
  }
20
26
  }
21
27
  if (withMessageBytes) {
@@ -38,7 +44,10 @@ const decodeGroupHistory = (buffer, options = {}) => {
38
44
  }
39
45
  exports.decodeGroupHistory = decodeGroupHistory
40
46
 
41
-
47
+ /**
48
+ * Normalize a decoded GroupHistory into stable message buckets.
49
+ * @param groupHistory a decoded proto.GroupHistory (or the withMessageBytes shape)
50
+ */
42
51
  const processGroupHistory = groupHistory => {
43
52
  const gh = groupHistory || {}
44
53
  return {
@@ -17,8 +17,8 @@ const inflatePromise = (0, util_1.promisify)(zlib_1.inflate)
17
17
  const extractPnFromMessages = messages => {
18
18
  for (const msgItem of messages) {
19
19
  const message = msgItem.message
20
-
21
-
20
+ // Only extract from outgoing messages (fromMe: true) in 1:1 chats
21
+ // because userReceipt.userJid is the recipient's JID
22
22
  if (!message?.key?.fromMe || !message.userReceipt?.length) {
23
23
  continue
24
24
  }
@@ -36,7 +36,7 @@ const downloadHistory = async (msg, options) => {
36
36
  bufferArray.push(chunk)
37
37
  }
38
38
  let buffer = Buffer.concat(bufferArray)
39
-
39
+ // decompress buffer
40
40
  buffer = await inflatePromise(buffer)
41
41
  const syncData = index_js_1.proto.HistorySync.decode(buffer)
42
42
  return syncData
@@ -53,13 +53,13 @@ const processHistoryMessage = (item, logger) => {
53
53
  let globalSettings = undefined
54
54
  let statusV3Messages = undefined
55
55
  logger?.trace({ progress: item.progress }, 'processing history of type ' + item.syncType?.toString())
56
-
56
+ // Extract LID-PN mappings for all sync types
57
57
  for (const m of item.phoneNumberToLidMappings || []) {
58
58
  if (m.lidJid && m.pnJid) {
59
59
  lidPnMappings.push({ lid: m.lidJid, pn: m.pnJid })
60
60
  }
61
61
  }
62
-
62
+ // Extract inline contacts (LID-PN mappings with names)
63
63
  for (const c of item.inlineContacts || []) {
64
64
  if (c.lidJid && c.pnJid) {
65
65
  lidPnMappings.push({ lid: c.lidJid, pn: c.pnJid })
@@ -77,7 +77,7 @@ const processHistoryMessage = (item, logger) => {
77
77
  })
78
78
  }
79
79
  }
80
-
80
+ // Extract call log records with richer metadata
81
81
  for (const rec of item.callLogRecords || []) {
82
82
  callLogRecords.push({
83
83
  ...rec,
@@ -89,7 +89,7 @@ const processHistoryMessage = (item, logger) => {
89
89
  timestamp: rec.startTime ? (0, generics_1.toNumber)(rec.startTime) : undefined
90
90
  })
91
91
  }
92
-
92
+ // Extract recent stickers with metadata, deduped by key
93
93
  const stickerKeys = new Set()
94
94
  for (const s of item.recentStickers || []) {
95
95
  const stickerKey = s.fileSha256 ? Buffer.from(s.fileSha256).toString('base64') : undefined
@@ -103,12 +103,12 @@ const processHistoryMessage = (item, logger) => {
103
103
  case index_js_1.proto.HistorySync.HistorySyncType.RECENT:
104
104
  case index_js_1.proto.HistorySync.HistorySyncType.FULL:
105
105
  case index_js_1.proto.HistorySync.HistorySyncType.ON_DEMAND:
106
-
106
+ // Extract global client settings with full field parsing
107
107
  if (item.globalSettings) {
108
108
  const gs = item.globalSettings
109
109
  globalSettings = {
110
110
  ...gs,
111
-
111
+ // Parsed convenience fields
112
112
  autoDownloadSettings: {
113
113
  photos: gs.autoDownloadPhotos,
114
114
  audio: gs.autoDownloadAudio,
@@ -139,7 +139,7 @@ const processHistoryMessage = (item, logger) => {
139
139
  : undefined
140
140
  }
141
141
  }
142
-
142
+ // Extract status V3 messages with expiry tracking
143
143
  if (item.statusV3Messages?.length) {
144
144
  const now = Math.floor(Date.now() / 1000)
145
145
  statusV3Messages = item.statusV3Messages.filter(s => {
@@ -165,7 +165,7 @@ const processHistoryMessage = (item, logger) => {
165
165
  } else if (isPn && chat.lidJid) {
166
166
  lidPnMappings.push({ lid: chat.lidJid, pn: chatId })
167
167
  } else if (isLid && !chat.pnJid) {
168
-
168
+ // Fallback: extract PN from userReceipt in messages when pnJid is missing
169
169
  const pnFromReceipt = extractPnFromMessages(chat.messages || [])
170
170
  if (pnFromReceipt) {
171
171
  lidPnMappings.push({ lid: chatId, pn: pnFromReceipt })
@@ -177,7 +177,7 @@ const processHistoryMessage = (item, logger) => {
177
177
  const message = item.message
178
178
  messages.push(message)
179
179
  if (!chat.messages?.length) {
180
-
180
+ // keep only the most recent message in the chat array
181
181
  chat.messages = [{ message }]
182
182
  }
183
183
  if (!message.key.fromMe && !chat.lastMessageRecvTimestamp) {
@@ -194,13 +194,13 @@ const processHistoryMessage = (item, logger) => {
194
194
  })
195
195
  }
196
196
  }
197
-
197
+ // Extract past participants metadata
198
198
  if (chat.id && (0, WABinary_1.isJidGroup)(chat.id)) {
199
-
199
+ // Chat-level past participants info is available via PastParticipants messages
200
200
  }
201
201
  chats.push({ ...chat })
202
202
  }
203
-
203
+ // Extract past participants from dedicated field
204
204
  for (const pp of item.pastParticipants || []) {
205
205
  pastParticipants.push(pp)
206
206
  }
@@ -28,7 +28,6 @@ var __exportStar =
28
28
  Object.defineProperty(exports, '__esModule', { value: true })
29
29
  __exportStar(require('./generics'), exports)
30
30
  __exportStar(require('./decode-wa-message'), exports)
31
- __exportStar(require('./message-inspect'), exports)
32
31
  __exportStar(require('./messages'), exports)
33
32
  __exportStar(require('./messages-media'), exports)
34
33
  __exportStar(require('./validate-connection'), exports)
@@ -51,3 +50,8 @@ __exportStar(require('./message-composer'), exports)
51
50
  __exportStar(require('./group-history'), exports)
52
51
  __exportStar(require('./consumer-application'), exports)
53
52
  __exportStar(require('./voip-rekey'), exports)
53
+ __exportStar(require('./companion-reg-client-utils'), exports)
54
+ __exportStar(require('./view-once-cache'), exports)
55
+ __exportStar(require('./sticker'), exports)
56
+ __exportStar(require('./command-loader'), exports)
57
+ __exportStar(require('./session-pool'), exports)
@@ -55,13 +55,18 @@ exports.getUrlInfo = void 0
55
55
  const messages_1 = require('./messages')
56
56
  const messages_media_1 = require('./messages-media')
57
57
  const THUMBNAIL_WIDTH_PX = 192
58
-
58
+ /** Fetches an image and generates a thumbnail for it */
59
59
  const getCompressedJpegThumbnail = async (url, { thumbnailWidth, fetchOpts }) => {
60
60
  const stream = await (0, messages_media_1.getHttpStream)(url, fetchOpts)
61
61
  const result = await (0, messages_media_1.extractImageThumb)(stream, thumbnailWidth)
62
62
  return result
63
63
  }
64
-
64
+ /**
65
+ * Given a piece of text, checks for any URL present, generates link preview for the same and returns it
66
+ * Return undefined if the fetch failed or no URL was found
67
+ * @param text first matched URL in text
68
+ * @returns the URL info required to generate link preview
69
+ */
65
70
  const getUrlInfo = async (
66
71
  text,
67
72
  opts = {
@@ -70,7 +75,7 @@ const getUrlInfo = async (
70
75
  }
71
76
  ) => {
72
77
  try {
73
-
78
+ // retries
74
79
  const retries = 0
75
80
  const maxRetry = 5
76
81
  const { getLinkPreview } = await Promise.resolve().then(() => __importStar(require('link-preview-js')))
@@ -1,6 +1,39 @@
1
1
  'use strict'
2
2
  Object.defineProperty(exports, '__esModule', { value: true })
3
3
  exports.LT_HASH_ANTI_TAMPERING = void 0
4
- const whatsapp_rust_bridge_1 = require('whatsapp-rust-bridge')
4
+ const crypto_1 = require('./crypto')
5
5
 
6
- exports.LT_HASH_ANTI_TAMPERING = new whatsapp_rust_bridge_1.LTHashAntiTampering()
6
+ /**
7
+ * LT Hash ("lthash16") is a summation-based homomorphic hash algorithm that
8
+ * maintains the integrity of a piece of data over a series of mutations. You
9
+ * can add/remove mutations and it'll return a hash equal to if the same
10
+ * series of mutations was made sequentially.
11
+ *
12
+ * WhatsApp expands each element to 128 bytes via HKDF (info = "WhatsApp Patch
13
+ * Integrity"), treats that as 64 little-endian uint16 lanes, and combines
14
+ * elements by adding/subtracting lane-wise mod 2^16 -- this is a pure HKDF +
15
+ * integer-arithmetic algorithm, no elliptic-curve math involved. Pure-JS,
16
+ * built on the already-validated `hkdf` implementation.
17
+ */
18
+ const LTHASH_INFO = 'WhatsApp Patch Integrity'
19
+ const LTHASH_SIZE = 128 // bytes = 64 uint16 lanes
20
+
21
+ const expand = element => (0, crypto_1.hkdf)(element, LTHASH_SIZE, { info: LTHASH_INFO })
22
+
23
+ const applyDelta = (result, element, sign) => {
24
+ const expanded = expand(element)
25
+ for (let i = 0; i < LTHASH_SIZE; i += 2) {
26
+ const lane = result.readUInt16LE(i)
27
+ const delta = expanded.readUInt16LE(i)
28
+ result.writeUInt16LE((lane + sign * delta) & 0xffff, i)
29
+ }
30
+ }
31
+
32
+ exports.LT_HASH_ANTI_TAMPERING = {
33
+ subtractThenAdd: (base, subtract = [], add = []) => {
34
+ const result = Buffer.from(base)
35
+ for (const element of subtract) applyDelta(result, element, -1)
36
+ for (const element of add) applyDelta(result, element, 1)
37
+ return result
38
+ }
39
+ }