@badzz88/baileys 8.5.2 → 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.
Files changed (110) hide show
  1. package/README.md +1 -1
  2. package/WAProto/WAProto.proto +1256 -75
  3. package/WAProto/index.d.ts +36042 -19649
  4. package/WAProto/index.js +181990 -135645
  5. package/engine-requirements.js +7 -15
  6. package/lib/Defaults/index.js +22 -17
  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 +39 -59
  15. package/lib/Signal/lid-mapping.js +28 -10
  16. package/lib/Socket/aigroups.js +5 -5
  17. package/lib/Socket/business.js +3 -11
  18. package/lib/Socket/chats.js +668 -319
  19. package/lib/Socket/communities.js +85 -89
  20. package/lib/Socket/graphql.js +435 -228
  21. package/lib/Socket/groups.js +132 -211
  22. package/lib/Socket/index.js +9 -7
  23. package/lib/Socket/interactive-handler.js +117 -60
  24. package/lib/Socket/interop.js +56 -175
  25. package/lib/Socket/managed-account.js +79 -48
  26. package/lib/Socket/messages-recv.js +898 -340
  27. package/lib/Socket/messages-send.js +462 -160
  28. package/lib/Socket/mex.js +40 -53
  29. package/lib/Socket/newsletter.js +291 -291
  30. package/lib/Socket/privacy.js +77 -265
  31. package/lib/Socket/registration.js +164 -157
  32. package/lib/Socket/socket.js +181 -199
  33. package/lib/Socket/username.js +144 -227
  34. package/lib/Store/make-cache-manager-store.js +2 -2
  35. package/lib/Store/make-in-memory-store.js +25 -141
  36. package/lib/Types/Auth.js +3 -3
  37. package/lib/Types/Label.js +1 -1
  38. package/lib/Types/LabelAssociation.js +1 -1
  39. package/lib/Types/Newsletter.js +96 -65
  40. package/lib/Types/State.js +4 -4
  41. package/lib/Types/index.js +1 -1
  42. package/lib/Utils/auth-utils.js +52 -57
  43. package/lib/Utils/browser-utils.js +1 -1
  44. package/lib/Utils/business.js +2 -6
  45. package/lib/Utils/chat-utils.js +102 -38
  46. package/lib/Utils/crypto.js +54 -84
  47. package/lib/Utils/decode-wa-message.js +316 -83
  48. package/lib/Utils/event-buffer.js +37 -61
  49. package/lib/Utils/generics.js +157 -103
  50. package/lib/Utils/group-history.js +3 -12
  51. package/lib/Utils/history.js +15 -15
  52. package/lib/Utils/index.js +1 -5
  53. package/lib/Utils/link-preview.js +3 -8
  54. package/lib/Utils/lt-hash.js +2 -35
  55. package/lib/Utils/make-mutex.js +1 -1
  56. package/lib/Utils/message-inspect.js +393 -0
  57. package/lib/Utils/message-retry-manager.js +27 -92
  58. package/lib/Utils/messages-media.js +159 -130
  59. package/lib/Utils/messages.js +144 -566
  60. package/lib/Utils/meta-ai-msmsg.js +62 -202
  61. package/lib/Utils/noise-handler.js +19 -21
  62. package/lib/Utils/offline-node-processor.js +3 -8
  63. package/lib/Utils/pre-key-manager.js +13 -23
  64. package/lib/Utils/process-message.js +197 -106
  65. package/lib/Utils/reporting-utils.js +2 -2
  66. package/lib/Utils/signal.js +28 -63
  67. package/lib/Utils/stanza-ack.js +39 -12
  68. package/lib/Utils/sync-action-utils.js +4 -7
  69. package/lib/Utils/tc-token-utils.js +20 -25
  70. package/lib/Utils/use-multi-file-auth-state.js +30 -14
  71. package/lib/Utils/validate-connection.js +59 -19
  72. package/lib/WABinary/decode.js +50 -16
  73. package/lib/WABinary/encode.js +54 -224
  74. package/lib/WABinary/generic-utils.js +7 -97
  75. package/lib/WABinary/jid-utils.js +27 -14
  76. package/lib/WAM/encode.js +7 -7
  77. package/lib/WAUSync/Protocols/USyncBusinessProtocol.js +58 -1
  78. package/lib/WAUSync/Protocols/USyncContactProtocol.js +7 -1
  79. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +13 -5
  80. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +1 -4
  81. package/lib/WAUSync/Protocols/USyncFeatureProtocol.js +20 -7
  82. package/lib/WAUSync/Protocols/USyncNewsletterProtocol.js +865 -0
  83. package/lib/WAUSync/Protocols/USyncPictureProtocol.js +1 -1
  84. package/lib/WAUSync/Protocols/USyncSidelistProtocol.js +2 -2
  85. package/lib/WAUSync/Protocols/USyncStatusProtocol.js +7 -2
  86. package/lib/WAUSync/Protocols/USyncTextStatusProtocol.js +1 -1
  87. package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +2 -1
  88. package/lib/WAUSync/Protocols/index.js +1 -0
  89. package/lib/WAUSync/USyncBackoff.js +26 -0
  90. package/lib/WAUSync/USyncQuery.js +77 -6
  91. package/lib/WAUSync/USyncUser.js +16 -8
  92. package/lib/WAUSync/index.js +1 -0
  93. package/lib/antiban.js +608 -854
  94. package/lib/index.js +3 -3
  95. package/package.json +16 -19
  96. package/lib/Socket/luxu.js +0 -387
  97. package/lib/Socket/text-router.js +0 -83
  98. package/lib/Store/keyed-db.js +0 -108
  99. package/lib/Types/Mex.js +0 -112
  100. package/lib/Utils/command-loader.d.ts +0 -31
  101. package/lib/Utils/command-loader.js +0 -100
  102. package/lib/Utils/companion-reg-client-utils.js +0 -42
  103. package/lib/Utils/curve25519-js.js +0 -275
  104. package/lib/Utils/native-bridge.js +0 -82
  105. package/lib/Utils/session-pool.d.ts +0 -16
  106. package/lib/Utils/session-pool.js +0 -94
  107. package/lib/Utils/sticker.d.ts +0 -17
  108. package/lib/Utils/sticker.js +0 -145
  109. package/lib/Utils/view-once-cache.d.ts +0 -9
  110. package/lib/Utils/view-once-cache.js +0 -79
@@ -48,26 +48,47 @@ const makeMessagesSocket = config => {
48
48
  trustInteropContact
49
49
  } = sock
50
50
  const getLIDForPN = signalRepository.lidMapping.getLIDForPN.bind(signalRepository.lidMapping)
51
- /**
52
- * Set of tctoken storage JIDs with a fire-and-forget issuePrivacyTokens IQ in flight.
53
- * Prevents duplicate IQs from rapid back-to-back sends before senderTimestamp persists.
54
- */
51
+
52
+
53
+ const resolveStatusAudience = async (groupJids, includeMe = false) => {
54
+ const myJid = authState.creds.me?.id
55
+ const seen = new Set()
56
+ const allUsers = []
57
+ for (const gjid of groupJids) {
58
+ let meta
59
+ try {
60
+ meta = cachedGroupMetadata ? await cachedGroupMetadata(gjid) : null
61
+ if (!meta) meta = await groupMetadata(gjid)
62
+ } catch {
63
+ continue
64
+ }
65
+ for (const p of meta?.participants || []) {
66
+ const id = p.id
67
+ if (!id || seen.has(id)) continue
68
+ if (!includeMe && id === myJid) continue
69
+ seen.add(id)
70
+ allUsers.push(id)
71
+ }
72
+ }
73
+ return { allUsers }
74
+ }
75
+
55
76
  const inFlightTcTokenIssuance = new Set()
56
77
  const userDevicesCache =
57
78
  config.userDevicesCache ||
58
79
  new node_cache_1.default({
59
- stdTTL: Defaults_1.DEFAULT_CACHE_TTLS.USER_DEVICES, // 5 minutes
80
+ stdTTL: Defaults_1.DEFAULT_CACHE_TTLS.USER_DEVICES,
60
81
  useClones: false
61
82
  })
62
83
  const peerSessionsCache = new node_cache_1.default({
63
84
  stdTTL: Defaults_1.DEFAULT_CACHE_TTLS.USER_DEVICES,
64
85
  useClones: false
65
86
  })
66
- // Initialize message retry manager if enabled
87
+
67
88
  const messageRetryManager = enableRecentMessageCache
68
89
  ? new Utils_1.MessageRetryManager(logger, maxMsgRetryCount)
69
90
  : null
70
- // Prevent race conditions in Signal session encryption by user
91
+
71
92
  const encryptionMutex = (0, make_mutex_1.makeKeyedMutex)()
72
93
  let mediaConn
73
94
  const refreshMediaConn = async (forceGet = false) => {
@@ -84,7 +105,7 @@ const makeMessagesSocket = config => {
84
105
  content: [{ tag: 'media_conn', attrs: {} }]
85
106
  })
86
107
  const mediaConnNode = (0, WABinary_1.getBinaryNodeChild)(result, 'media_conn')
87
- // TODO: explore full length of data that whatsapp provides
108
+
88
109
  const node = {
89
110
  hosts: (0, WABinary_1.getBinaryNodeChildren)(mediaConnNode, 'host').map(({ attrs }) => ({
90
111
  hostname: attrs.hostname,
@@ -100,10 +121,7 @@ const makeMessagesSocket = config => {
100
121
  }
101
122
  return mediaConn
102
123
  }
103
- /**
104
- * generic send receipt function
105
- * used for receipts of phone call, read, delivery etc.
106
- * */
124
+
107
125
  const sendReceipt = async (jid, participant, messageIds, type, sts) => {
108
126
  if (!messageIds || messageIds.length === 0) {
109
127
  throw new boom_1.Boom('missing ids in receipt')
@@ -123,7 +141,7 @@ const makeMessagesSocket = config => {
123
141
  node.attrs.recipient = jid
124
142
  node.attrs.to = participant
125
143
  } else if (isInterop && !type) {
126
- // Delivery receipt to interop contact: WA sends to device-qualified JID (user:0@interop)
144
+
127
145
  const { user } = (0, WABinary_1.jidDecode)(jid)
128
146
  node.attrs.to = `${user}:0@interop`
129
147
  } else {
@@ -135,7 +153,7 @@ const makeMessagesSocket = config => {
135
153
  if (type) {
136
154
  node.attrs.type = type
137
155
  }
138
- // Interop bridge requires sts (microsecond stanza timestamp) from the original message
156
+
139
157
  if (isInterop && sts) {
140
158
  node.attrs.sts = sts
141
159
  }
@@ -155,21 +173,21 @@ const makeMessagesSocket = config => {
155
173
  logger.debug({ attrs: node.attrs, messageIds }, 'sending receipt for messages')
156
174
  await sendNode(node)
157
175
  }
158
- /** Correctly bulk send receipts to multiple chats, participants */
176
+
159
177
  const sendReceipts = async (keys, type) => {
160
178
  const recps = (0, Utils_1.aggregateMessageKeysNotFromMe)(keys)
161
179
  for (const { jid, participant, messageIds, sts } of recps) {
162
180
  await sendReceipt(jid, participant, messageIds, type, sts)
163
181
  }
164
182
  }
165
- /** Bulk read messages. Keys can be from different chats & participants */
183
+
166
184
  const readMessages = async keys => {
167
185
  const privacySettings = await fetchPrivacySettings()
168
- // based on privacy settings, we have to change the read type
186
+
169
187
  const readType = privacySettings.readreceipts === 'all' ? 'read' : 'read-self'
170
188
  await sendReceipts(keys, readType)
171
189
  }
172
- /** Fetch all the devices we've to send a message to */
190
+
173
191
  const getUSyncDevices = async (jids, useCache, ignoreZeroDevices) => {
174
192
  const deviceResults = []
175
193
  if (!useCache) {
@@ -227,17 +245,26 @@ const makeMessagesSocket = config => {
227
245
  }
228
246
  }
229
247
  const query = new WAUSync_1.USyncQuery().withContext('message').withDeviceProtocol().withLIDProtocol()
248
+
249
+
250
+ const pnJidsToFetch = toFetch.filter(jid => (0, WABinary_1.isPnUser)(jid) || (0, WABinary_1.isHostedPnUser)(jid))
251
+ const cachedLidPairs = pnJidsToFetch.length
252
+ ? (await signalRepository.lidMapping.getLIDsForPNs(pnJidsToFetch)) || []
253
+ : []
254
+ const cachedLidByPn = new Map(cachedLidPairs.map(({ pn, lid }) => [pn, lid]))
230
255
  for (const jid of toFetch) {
231
- query.withUser(new WAUSync_1.USyncUser().withId(jid)) // todo: investigate - the idea here is that <user> should have an inline lid field with the lid being the pn equivalent
256
+ const syncUser = new WAUSync_1.USyncUser().withId(jid)
257
+ const cachedLid = cachedLidByPn.get(jid)
258
+ if (cachedLid) syncUser.withLid(cachedLid)
259
+ query.withUser(syncUser)
232
260
  }
233
261
  const result = await sock.executeUSyncQuery(query)
234
262
  if (result) {
235
- // TODO: LID MAP this stuff (lid protocol will now return lid with devices)
236
263
  const lidResults = result.list.filter(a => !!a.lid)
237
264
  if (lidResults.length > 0) {
238
265
  logger.trace('Storing LID maps from device call')
239
266
  await signalRepository.lidMapping.storeLIDPNMappings(lidResults.map(a => ({ lid: a.lid, pn: a.id })))
240
- // Force-refresh sessions for newly mapped LIDs to align identity addressing
267
+
241
268
  try {
242
269
  const lids = lidResults.map(a => a.lid)
243
270
  if (lids.length) {
@@ -258,10 +285,10 @@ const makeMessagesSocket = config => {
258
285
  deviceMap[item.user] = deviceMap[item.user] || []
259
286
  deviceMap[item.user]?.push(item)
260
287
  }
261
- // Process each user's devices as a group for bulk LID migration
288
+
262
289
  for (const [user, userDevices] of Object.entries(deviceMap)) {
263
290
  const isLidUser = requestedLidUsers.has(user)
264
- // Process all devices for this user
291
+
265
292
  for (const item of userDevices) {
266
293
  const finalJid = isLidUser
267
294
  ? (0, WABinary_1.jidEncode)(user, item.server, item.device)
@@ -282,7 +309,7 @@ const makeMessagesSocket = config => {
282
309
  }
283
310
  }
284
311
  if (userDevicesCache.mset) {
285
- // if the cache supports mset, we can set all devices in one go
312
+
286
313
  await userDevicesCache.mset(Object.entries(deviceMap).map(([key, value]) => ({ key, value })))
287
314
  } else {
288
315
  for (const key in deviceMap) {
@@ -309,9 +336,7 @@ const makeMessagesSocket = config => {
309
336
  }
310
337
  return deviceResults
311
338
  }
312
- /**
313
- * Update Member Label
314
- */
339
+
315
340
  const updateMemberLabel = (jid, memberLabel) => {
316
341
  return relayMessage(
317
342
  jid,
@@ -340,16 +365,16 @@ const makeMessagesSocket = config => {
340
365
  }
341
366
  const assertSessions = async (jids, force) => {
342
367
  let didFetchNewSession = false
343
- const uniqueJids = [...new Set(jids)] // Deduplicate JIDs
368
+ const uniqueJids = [...new Set(jids)]
344
369
  const jidsRequiringFetch = []
345
370
  logger.debug({ jids }, 'assertSessions call with jids')
346
- // Check peerSessionsCache and validate sessions using libsignal loadSession
371
+
347
372
  for (const jid of uniqueJids) {
348
373
  const signalId = signalRepository.jidToSignalProtocolAddress(jid)
349
374
  const cachedSession = peerSessionsCache.get(signalId)
350
375
  if (cachedSession !== undefined) {
351
376
  if (cachedSession && !force) {
352
- continue // Session exists in cache
377
+ continue
353
378
  }
354
379
  } else {
355
380
  const sessionValidation = await signalRepository.validateSession(jid)
@@ -362,7 +387,7 @@ const makeMessagesSocket = config => {
362
387
  jidsRequiringFetch.push(jid)
363
388
  }
364
389
  if (jidsRequiringFetch.length) {
365
- // LID if mapped, otherwise original; interop JIDs pass through as-is
390
+
366
391
  const wireJids = [
367
392
  ...jidsRequiringFetch.filter(jid => !!(0, WABinary_1.isLidUser)(jid) || !!(0, WABinary_1.isHostedLidUser)(jid)),
368
393
  ...(
@@ -405,7 +430,7 @@ const makeMessagesSocket = config => {
405
430
  }
406
431
  await (0, Utils_1.parseAndInjectE2ESessions)(result, signalRepository)
407
432
  didFetchNewSession = true
408
- // Cache fetched sessions using wire JIDs
433
+
409
434
  for (const wireJid of wireJids) {
410
435
  const signalId = signalRepository.jidToSignalProtocolAddress(wireJid)
411
436
  peerSessionsCache.set(signalId, true)
@@ -414,7 +439,7 @@ const makeMessagesSocket = config => {
414
439
  return didFetchNewSession
415
440
  }
416
441
  const sendPeerDataOperationMessage = async pdoMessage => {
417
- //TODO: for later, abstract the logic to send a Peer Message instead of just PDO - useful for App State Key Resync with phone
442
+
418
443
  if (!authState.creds.me?.id) {
419
444
  throw new boom_1.Boom('Not authenticated')
420
445
  }
@@ -507,7 +532,9 @@ const makeMessagesSocket = config => {
507
532
  additionalNodes,
508
533
  useUserDevicesCache,
509
534
  useCachedGroupMetadata,
510
- statusJidList
535
+ statusJidList,
536
+ statusPrivacy,
537
+ AI = false
511
538
  }
512
539
  ) => {
513
540
  const meId = authState.creds.me.id
@@ -523,8 +550,7 @@ const makeMessagesSocket = config => {
523
550
  const isInterop = (0, WABinary_1.isInteropUser)(jid)
524
551
  const isGroupOrStatus = isGroup || isStatus
525
552
  const finalJid = jid
526
- const iosBros = config.browser[0] === "iOS" || config.browser[1] === "Safari";
527
- msgId = iosBros ? Utils_1.generateIOSMessageID() : msgId ?? (0, Utils_1.generateMessageIDV2)(meId)
553
+ msgId = msgId || (0, Utils_1.generateMessageIDV2)(meId)
528
554
  useUserDevicesCache = useUserDevicesCache !== false
529
555
  useCachedGroupMetadata = useCachedGroupMetadata !== false && !isStatus
530
556
  const participants = []
@@ -547,6 +573,18 @@ const makeMessagesSocket = config => {
547
573
 
548
574
  const buttonType = getButtonType(messages)
549
575
  const pollMessage = messages.pollCreationMessage || messages.pollCreationMessageV2 || messages.pollCreationMessageV3
576
+
577
+ if (participant) {
578
+ if (!isGroup && !isStatus) {
579
+ additionalAttributes = { ...additionalAttributes, device_fanout: 'false' }
580
+ }
581
+ const { user, device } = (0, WABinary_1.jidDecode)(participant.jid)
582
+ devices.push({
583
+ user,
584
+ device,
585
+ jid: participant.jid
586
+ })
587
+ }
550
588
  await authState.keys.transaction(async () => {
551
589
  const mediaType = getMediaType(message)
552
590
  if (mediaType) {
@@ -578,35 +616,24 @@ const makeMessagesSocket = config => {
578
616
  (0, Utils_1.normalizeMessageContent)(message)?.pinInChatMessage ||
579
617
  (0, Utils_1.normalizeMessageContent)(message)?.reactionMessage
580
618
  ) {
581
- extraAttrs['decrypt-fail'] = 'hide' // todo: expand for reactions and other types
619
+ extraAttrs['decrypt-fail'] = 'hide'
582
620
  }
583
621
  if (isGroupOrStatus && !isRetryResend) {
584
622
  const [groupData, senderKeyMap] = await Promise.all([
585
623
  (async () => {
586
- let groupData = useCachedGroupMetadata && cachedGroupMetadata ? await cachedGroupMetadata(jid) : undefined
587
- const looksStale =
588
- groupData &&
589
- typeof groupData.size === 'number' &&
590
- Array.isArray(groupData.participants) &&
591
- groupData.participants.length < groupData.size
592
- if (groupData && Array.isArray(groupData?.participants) && !looksStale) {
624
+ let groupData = useCachedGroupMetadata && cachedGroupMetadata ? await cachedGroupMetadata(jid) : undefined
625
+ if (groupData && Array.isArray(groupData?.participants)) {
593
626
  logger.trace({ jid, participants: groupData.participants.length }, 'using cached group metadata')
594
627
  } else if (!isStatus) {
595
- if (looksStale) {
596
- logger.debug(
597
- { jid, cached: groupData.participants.length, expected: groupData.size },
598
- 'cached group metadata looks stale, re-fetching'
599
- )
600
- }
601
- groupData = await groupMetadata(jid) // TODO: start storing group participant list + addr mode in Signal & stop relying on this
628
+ groupData = await groupMetadata(jid)
602
629
  }
603
630
  return groupData
604
631
  })(),
605
632
  (async () => {
606
633
  if (!participant && !isStatus) {
607
- // what if sender memory is less accurate than the cached metadata
608
- // on participant change in group, we should do sender memory manipulation
609
- const result = await authState.keys.get('sender-key-memory', [jid]) // TODO: check out what if the sender key memory doesn't include the LID stuff now?
634
+
635
+
636
+ const result = await authState.keys.get('sender-key-memory', [jid])
610
637
  return result[jid] || {}
611
638
  }
612
639
  return {}
@@ -790,8 +817,8 @@ const makeMessagesSocket = config => {
790
817
  !(0, WABinary_1.isHostedPnUser)(deviceJid) &&
791
818
  device.device !== 99
792
819
  ) {
793
- //todo: revamp all this logic
794
- // the goal is to follow with what I said above for each group, and instead of a true false map of ids, we can set an array full of those the app has already sent pkmsgs
820
+
821
+
795
822
  senderKeyRecipients.push(deviceJid)
796
823
  senderKeyMap[deviceJid] = true
797
824
  }
@@ -817,8 +844,8 @@ const makeMessagesSocket = config => {
817
844
  })
818
845
  await authState.keys.set({ 'sender-key-memory': { [jid]: senderKeyMap } })
819
846
  } else {
820
- // ADDRESSING CONSISTENCY: Match own identity to conversation context
821
- // TODO: investigate if this is true
847
+
848
+
822
849
  let ownId = meId
823
850
  if (isLid && meLid) {
824
851
  ownId = meLid
@@ -838,9 +865,9 @@ const makeMessagesSocket = config => {
838
865
  devices.push({
839
866
  user,
840
867
  device: 0,
841
- jid: (0, WABinary_1.jidEncode)(user, targetUserServer, 0) // rajeh, todo: this entire logic is convoluted and weird.
868
+ jid: (0, WABinary_1.jidEncode)(user, targetUserServer, 0)
842
869
  })
843
- // Interop contacts don't receive a copy to own devices — native WA sends only one flat <enc>
870
+
844
871
  if (user !== ownUser && !isInterop) {
845
872
  const ownUserServer = isLid ? 'lid' : 's.whatsapp.net'
846
873
  const ownUserForAddressing =
@@ -852,14 +879,14 @@ const makeMessagesSocket = config => {
852
879
  })
853
880
  }
854
881
  if (additionalAttributes?.['category'] !== 'peer' && !isInterop) {
855
- // Clear placeholders and enumerate actual devices
882
+
856
883
  devices.length = 0
857
- // Use conversation-appropriate sender identity
884
+
858
885
  const senderIdentity =
859
886
  isLid && meLid
860
887
  ? (0, WABinary_1.jidEncode)((0, WABinary_1.jidDecode)(meLid)?.user, 'lid', undefined)
861
888
  : (0, WABinary_1.jidEncode)((0, WABinary_1.jidDecode)(meId)?.user, 's.whatsapp.net', undefined)
862
- // Enumerate devices for sender and target with consistent addressing
889
+
863
890
  const sessionDevices = await getUSyncDevices([senderIdentity, jid], true, false)
864
891
  devices.push(...sessionDevices)
865
892
  logger.debug(
@@ -877,25 +904,26 @@ const makeMessagesSocket = config => {
877
904
  const { user: mePnUser } = (0, WABinary_1.jidDecode)(meId)
878
905
  const { user: meLidUser } = meLid ? (0, WABinary_1.jidDecode)(meLid) : { user: null }
879
906
  for (const { user, jid } of devices) {
880
- const isExactSenderDevice = jid === meId || (meLid && jid === meLid);
881
- if (isExactSenderDevice) continue;
882
- const isMe = user === mePnUser || user === meLidUser;
883
- let ptcp = false;
884
- if (participant) {
885
- if (!(!isMe)) ptcp = true;
886
- }
887
- if (!ptcp) {
888
- if (isMe) meRecipients.push(jid);
889
- else otherRecipients.push(jid);
890
- allRecipients.push(jid);
891
- }
892
- }
907
+ const isExactSenderDevice = jid === meId || (meLid && jid === meLid)
908
+ if (isExactSenderDevice) {
909
+ logger.debug({ jid, meId, meLid }, 'Skipping exact sender device (whatsmeow pattern)')
910
+ continue
911
+ }
912
+
913
+ const isMe = user === mePnUser || user === meLidUser
914
+ if (isMe) {
915
+ meRecipients.push(jid)
916
+ } else {
917
+ otherRecipients.push(jid)
918
+ }
919
+ allRecipients.push(jid)
920
+ }
893
921
  await assertSessions(allRecipients)
894
922
  const [
895
923
  { nodes: meNodes, shouldIncludeDeviceIdentity: s1 },
896
924
  { nodes: otherNodes, shouldIncludeDeviceIdentity: s2 }
897
925
  ] = await Promise.all([
898
- // For own devices: use DSM if available (1:1 chats only)
926
+
899
927
  createParticipantNodes(meRecipients, meMsg || message, extraAttrs),
900
928
  createParticipantNodes(otherRecipients, message, extraAttrs, meMsg)
901
929
  ])
@@ -906,15 +934,40 @@ const makeMessagesSocket = config => {
906
934
  }
907
935
  shouldIncludeDeviceIdentity = shouldIncludeDeviceIdentity || s1 || s2
908
936
  }
937
+ if (isRetryResend) {
938
+ const isParticipantLid = (0, WABinary_1.isLidUser)(participant.jid)
939
+ const isMe = (0, WABinary_1.areJidsSameUser)(participant.jid, isParticipantLid ? meLid : meId)
940
+ const encodedMessageToSend = isMe
941
+ ? (0, Utils_1.encodeWAMessage)({
942
+ deviceSentMessage: {
943
+ destinationJid,
944
+ message
945
+ }
946
+ })
947
+ : (0, Utils_1.encodeWAMessage)(message)
948
+ const { type, ciphertext: encryptedContent } = await signalRepository.encryptMessage({
949
+ data: encodedMessageToSend,
950
+ jid: participant.jid
951
+ })
952
+ binaryNodeContent.push({
953
+ tag: 'enc',
954
+ attrs: {
955
+ v: '2',
956
+ type,
957
+ count: (participant.count ?? 0).toString()
958
+ },
959
+ content: encryptedContent
960
+ })
961
+ }
909
962
  if (participants.length) {
910
963
  if (additionalAttributes?.['category'] === 'peer') {
911
964
  const peerNode = participants[0]?.content?.[0]
912
965
  if (peerNode) {
913
- binaryNodeContent.push(peerNode) // push only enc
966
+ binaryNodeContent.push(peerNode)
914
967
  }
915
968
  } else if (isInterop) {
916
- // Flat <enc> directly on <message> — no <participants> wrapper (native WA behavior).
917
- // Find the enc for the actual interop recipient, not own-device DSM copy.
969
+
970
+
918
971
  const recipientNode = participants.find(p => (0, WABinary_1.isInteropUser)(p?.attrs?.jid))
919
972
  const encNode = (recipientNode ?? participants[0])?.content?.[0]
920
973
  if (encNode) {
@@ -938,6 +991,22 @@ const makeMessagesSocket = config => {
938
991
  },
939
992
  content: binaryNodeContent
940
993
  }
994
+
995
+
996
+
997
+ if (participant) {
998
+ if ((0, WABinary_1.isJidGroup)(destinationJid)) {
999
+ stanza.attrs.to = destinationJid
1000
+ stanza.attrs.participant = participant.jid
1001
+ } else if ((0, WABinary_1.areJidsSameUser)(participant.jid, meId)) {
1002
+ stanza.attrs.to = participant.jid
1003
+ stanza.attrs.recipient = destinationJid
1004
+ } else {
1005
+ stanza.attrs.to = participant.jid
1006
+ }
1007
+ } else {
1008
+ stanza.attrs.to = destinationJid
1009
+ }
941
1010
  if (shouldIncludeDeviceIdentity) {
942
1011
  stanza.content.push({
943
1012
  tag: 'device-identity',
@@ -954,6 +1023,14 @@ const makeMessagesSocket = config => {
954
1023
  })
955
1024
  }
956
1025
 
1026
+
1027
+ if (isStatus && statusPrivacy && !additionalAttributes?.edit) {
1028
+ stanza.content.push({
1029
+ tag: 'meta',
1030
+ attrs: { status_setting: statusPrivacy, session_scope: 'status' }
1031
+ })
1032
+ }
1033
+
957
1034
  if (pollMessage || messages.eventMessage) {
958
1035
  stanza.content.push({
959
1036
  tag: 'meta',
@@ -1011,30 +1088,30 @@ const makeMessagesSocket = config => {
1011
1088
  stanza.content.push(buttonsNode)
1012
1089
  }
1013
1090
  }
1014
- if (!config.aiLabel && (0, WABinary_1.isPnUser)(destinationJid)) {
1091
+ if (!AI && (0, WABinary_1.isPnUser)(destinationJid)) {
1015
1092
  const alreadyHasBizBot =
1016
1093
  WABinary_1.getBinaryFilteredBizBot(additionalNodes || []) ||
1017
1094
  WABinary_1.getBinaryFilteredBizBot(stanza.content)
1018
1095
  if (!alreadyHasBizBot) {
1019
1096
  stanza.content.push({ tag: 'bot', attrs: { biz_bot: '1' } })
1020
1097
  }
1021
- } else if (config.aiLabel && !isGroup && !isStatus && !isNewsletter) {
1098
+ } else if (AI && !isGroup && !isStatus && !isNewsletter) {
1022
1099
  const existingBizBot = WABinary_1.getBinaryFilteredBizBot(additionalNodes || [])
1023
1100
  if (!existingBizBot) {
1024
1101
  stanza.content.push({ tag: 'bot', attrs: { biz_bot: '1' } })
1025
1102
  }
1026
1103
  }
1027
- // WA Web never attaches tctoken to peer (AppStateSync) messages — server rejects with 479
1104
+
1028
1105
  const isPeerMessage = additionalAttributes?.['category'] === 'peer'
1029
1106
  const is1on1Send = !isGroup && !isRetryResend && !isStatus && !isNewsletter && !isPeerMessage
1030
- // Resolve destination to LID for tctoken storage — matches Signal session key pattern
1107
+
1031
1108
  const tcTokenJid = is1on1Send
1032
1109
  ? await (0, tc_token_utils_1.resolveTcTokenJid)(destinationJid, getLIDForPN)
1033
1110
  : destinationJid
1034
1111
  const contactTcTokenData = is1on1Send ? await authState.keys.get('tctoken', [tcTokenJid]) : {}
1035
1112
  const existingTokenEntry = contactTcTokenData[tcTokenJid]
1036
1113
  let tcTokenBuffer = existingTokenEntry?.token
1037
- // Treat expired tokens the same as missing — clear from cache
1114
+
1038
1115
  if (tcTokenBuffer?.length && (0, tc_token_utils_1.isTcTokenExpired)(existingTokenEntry?.timestamp)) {
1039
1116
  logger.debug({ jid: destinationJid, timestamp: existingTokenEntry?.timestamp }, 'tctoken expired, clearing')
1040
1117
  tcTokenBuffer = undefined
@@ -1055,17 +1132,38 @@ const makeMessagesSocket = config => {
1055
1132
  content: tcTokenBuffer
1056
1133
  })
1057
1134
  }
1135
+
1136
+ if (is1on1Send && !tcTokenBuffer?.length) {
1137
+ try {
1138
+ const saltStore = await authState.keys.get('nct-salt', ['default'])
1139
+ const nctSalt = saltStore?.['default']
1140
+ if (nctSalt?.length) {
1141
+ const recipientLid = await getLIDForPN(destinationJid)
1142
+ if (recipientLid) {
1143
+ const { createHmac } = require('crypto')
1144
+ const lidStr = (0, WABinary_1.isLidUser)(recipientLid)
1145
+ ? recipientLid
1146
+ : `${recipientLid.split('@')[0]}@lid`
1147
+ const cs = createHmac('sha256', nctSalt).update(lidStr, 'utf8').digest()
1148
+ stanza.content.push({ tag: 'cstoken', attrs: {}, content: cs })
1149
+ logger.debug({ jid: destinationJid, lid: lidStr }, 'nct: attached cstoken')
1150
+ }
1151
+ }
1152
+ } catch (err) {
1153
+ logger.debug({ jid: destinationJid, err: err?.message }, 'nct: cstoken attach failed')
1154
+ }
1155
+ }
1058
1156
  if (additionalNodes && additionalNodes.length > 0 && !didPushAdditional) {
1059
1157
  stanza.content.push(...additionalNodes)
1060
1158
  }
1061
1159
  logger.debug({ msgId }, `sending message to ${participants.length} devices`)
1062
1160
  await sendNode(stanza)
1063
- // Register messageSecret immediately at send time so msmsg replies can be
1064
- // decrypted even if they arrive before our own message echo comes back.
1161
+
1162
+
1065
1163
  if (message.messageContextInfo?.messageSecret) {
1066
1164
  setBotMessageSecret(msgId, message.messageContextInfo.messageSecret, destinationJid)
1067
1165
  }
1068
- // Fire-and-forget: issue our token to the contact AFTER message send.
1166
+
1069
1167
  const isProtocolMsg = !!(0, Utils_1.normalizeMessageContent)(message)?.protocolMessage
1070
1168
  const isBotOrPSA =
1071
1169
  destinationJid === WABinary_1.PSA_WID ||
@@ -1116,7 +1214,7 @@ const makeMessagesSocket = config => {
1116
1214
  inFlightTcTokenIssuance.delete(tcTokenJid)
1117
1215
  })
1118
1216
  }
1119
- // Add message to retry cache if enabled
1217
+
1120
1218
  if (messageRetryManager && !participant) {
1121
1219
  messageRetryManager.addRecentMessage(destinationJid, msgId, message)
1122
1220
  }
@@ -1238,7 +1336,7 @@ const makeMessagesSocket = config => {
1238
1336
  }
1239
1337
  }
1240
1338
  } else if (nativeFlow && nativeFlowSpecials.includes(firstButtonName)) {
1241
- // Only works for WhatsApp Original, not WhatsApp Business
1339
+
1242
1340
  return {
1243
1341
  tag: 'biz',
1244
1342
  attrs: {
@@ -1272,7 +1370,7 @@ const makeMessagesSocket = config => {
1272
1370
  ]
1273
1371
  }
1274
1372
  } else if (nativeFlow || message.buttonsMessage) {
1275
- // It works for whatsapp original and whatsapp business
1373
+
1276
1374
  return {
1277
1375
  tag: 'biz',
1278
1376
  attrs: {
@@ -1368,7 +1466,7 @@ const makeMessagesSocket = config => {
1368
1466
  }
1369
1467
  const getPrivacyTokens = issuePrivacyTokens
1370
1468
  const waUploadToServer = (0, Utils_1.getWAUploadToServer)(config, refreshMediaConn)
1371
- const interactiveHandler = new interactive_handler_1.InteractiveMessageHandler(waUploadToServer, relayMessage, config, sock)
1469
+ const badzzne2 = new interactive_handler_1.badzz88(waUploadToServer, relayMessage, config, sock)
1372
1470
  const waitForMsgMediaUpdate = (0, Utils_1.bindWaitForEvent)(ev, 'messages.media-update')
1373
1471
  return {
1374
1472
  ...sock,
@@ -1521,6 +1619,7 @@ const makeMessagesSocket = config => {
1521
1619
  mediaHandle = up.handle
1522
1620
  return up
1523
1621
  },
1622
+ mediaAbProps: authState.creds.mediaAbProps,
1524
1623
  ...options
1525
1624
  }
1526
1625
  )
@@ -1542,6 +1641,7 @@ const makeMessagesSocket = config => {
1542
1641
  mediaHandle = up.handle
1543
1642
  return up
1544
1643
  },
1644
+ mediaAbProps: authState.creds.mediaAbProps,
1545
1645
  ...options
1546
1646
  }
1547
1647
  )
@@ -1561,7 +1661,7 @@ const makeMessagesSocket = config => {
1561
1661
  },
1562
1662
 
1563
1663
  sendStatusMention: async (content, jids = []) => {
1564
- return await interactiveHandler.sendStatusWhatsApp(content, jids)
1664
+ return await badzzne2.sendStatusWhatsApp(content, jids)
1565
1665
  },
1566
1666
  sendTable: async (jid, title, headers, rows, quoted, options = {}) => {
1567
1667
  const { message, messageId } = message_composer_1.generateTableContent(title, headers, rows, quoted, options)
@@ -1616,9 +1716,7 @@ const makeMessagesSocket = config => {
1616
1716
  },
1617
1717
  sendMessage: async (jid, content, options = {}) => {
1618
1718
  const userJid = authState.creds.me.id
1619
- const iosBros = config.browser[0] === "iOS" || config.browser[1] === "Safari";
1620
- const mId = iosBros ? Utils_1.generateIOSMessageID() : msgId ?? (0, Utils_1.generateMessageIDV2)(userJid)
1621
- // ── Normalize: buttons[].nativeFlowInfo -> interactiveButtons ──────
1719
+
1622
1720
  if (
1623
1721
  typeof content === 'object' &&
1624
1722
  Array.isArray(content.buttons) &&
@@ -1643,6 +1741,181 @@ const makeMessagesSocket = config => {
1643
1741
  const { buttons, headerType, viewOnce, ...rest } = content
1644
1742
  content = { ...rest, interactiveButtons }
1645
1743
  }
1744
+ if (
1745
+ typeof content === 'object' &&
1746
+ Array.isArray(content.interactiveButtons) &&
1747
+ content.interactiveButtons.length > 0
1748
+ ) {
1749
+ const {
1750
+ text = '',
1751
+ caption = '',
1752
+ title = '',
1753
+ footer = '',
1754
+ interactiveButtons,
1755
+ hasMediaAttachment = false,
1756
+ image = null,
1757
+ video = null,
1758
+ document = null,
1759
+ mimetype = null,
1760
+ jpegThumbnail = null,
1761
+ location = null,
1762
+ product = null,
1763
+ businessOwnerJid = null,
1764
+ externalAdReply = null
1765
+ } = content
1766
+
1767
+ const processedButtons = []
1768
+ for (let i = 0; i < interactiveButtons.length; i++) {
1769
+ const btn = interactiveButtons[i]
1770
+ if (!btn || typeof btn !== 'object') throw new Error(`interactiveButtons[${i}] must be an object`)
1771
+ if (btn.name && btn.buttonParamsJson) {
1772
+ processedButtons.push(btn)
1773
+ continue
1774
+ }
1775
+ if (btn.id || btn.text || btn.displayText) {
1776
+ processedButtons.push({
1777
+ name: 'quick_reply',
1778
+ buttonParamsJson: JSON.stringify({
1779
+ display_text: btn.text || btn.displayText || `Button ${i + 1}`,
1780
+ id: btn.id || `quick_${i + 1}`
1781
+ })
1782
+ })
1783
+ continue
1784
+ }
1785
+ if (btn.buttonId && btn.buttonText?.displayText) {
1786
+ processedButtons.push({
1787
+ name: 'quick_reply',
1788
+ buttonParamsJson: JSON.stringify({ display_text: btn.buttonText.displayText, id: btn.buttonId })
1789
+ })
1790
+ continue
1791
+ }
1792
+ throw new Error(`interactiveButtons[${i}] has invalid shape`)
1793
+ }
1794
+ let messageContent = {}
1795
+ if (image) {
1796
+ const mi = Buffer.isBuffer(image)
1797
+ ? { image }
1798
+ : { image: { url: typeof image === 'object' ? image.url : image } }
1799
+ const pm = await (0, Utils_1.prepareWAMessageMedia)(mi, { upload: waUploadToServer })
1800
+ messageContent.header = { title: title || '', hasMediaAttachment: true, imageMessage: pm.imageMessage }
1801
+ } else if (video) {
1802
+ const mi = Buffer.isBuffer(video)
1803
+ ? { video }
1804
+ : { video: { url: typeof video === 'object' ? video.url : video } }
1805
+ const pm = await (0, Utils_1.prepareWAMessageMedia)(mi, { upload: waUploadToServer })
1806
+ messageContent.header = { title: title || '', hasMediaAttachment: true, videoMessage: pm.videoMessage }
1807
+ } else if (document) {
1808
+ const mi = Buffer.isBuffer(document)
1809
+ ? { document }
1810
+ : { document: { url: typeof document === 'object' ? document.url : document } }
1811
+ if (mimetype && typeof mi.document === 'object') mi.document.mimetype = mimetype
1812
+ if (jpegThumbnail) {
1813
+ const thumb = Buffer.isBuffer(jpegThumbnail)
1814
+ ? jpegThumbnail
1815
+ : await (async () => {
1816
+ try {
1817
+ const r = await fetch(jpegThumbnail)
1818
+ return Buffer.from(await r.arrayBuffer())
1819
+ } catch {
1820
+ return undefined
1821
+ }
1822
+ })()
1823
+ if (thumb) mi.document.jpegThumbnail = thumb
1824
+ }
1825
+ const pm = await (0, Utils_1.prepareWAMessageMedia)(mi, { upload: waUploadToServer })
1826
+ messageContent.header = { title: title || '', hasMediaAttachment: true, documentMessage: pm.documentMessage }
1827
+ } else if (location && typeof location === 'object') {
1828
+ messageContent.header = {
1829
+ title: title || location.name || 'Location',
1830
+ hasMediaAttachment: false,
1831
+ locationMessage: {
1832
+ degreesLatitude: location.degreesLatitude || location.degressLatitude || 0,
1833
+ degreesLongitude: location.degreesLongitude || location.degressLongitude || 0,
1834
+ name: location.name || '',
1835
+ address: location.address || ''
1836
+ }
1837
+ }
1838
+ } else if (product && typeof product === 'object') {
1839
+ let productImageMessage = null
1840
+ if (product.productImage) {
1841
+ const mi = Buffer.isBuffer(product.productImage)
1842
+ ? { image: product.productImage }
1843
+ : {
1844
+ image: {
1845
+ url: typeof product.productImage === 'object' ? product.productImage.url : product.productImage
1846
+ }
1847
+ }
1848
+ const pm = await (0, Utils_1.prepareWAMessageMedia)(mi, { upload: waUploadToServer })
1849
+ productImageMessage = pm.imageMessage
1850
+ }
1851
+ messageContent.header = {
1852
+ title: title || product.title || 'Product',
1853
+ hasMediaAttachment: false,
1854
+ productMessage: {
1855
+ product: {
1856
+ productImage: productImageMessage,
1857
+ productId: product.productId || '',
1858
+ title: product.title || '',
1859
+ description: product.description || '',
1860
+ currencyCode: product.currencyCode || 'USD',
1861
+ priceAmount1000: parseInt(product.priceAmount1000, 10) || 0,
1862
+ retailerId: product.retailerId || '',
1863
+ url: product.url || '',
1864
+ productImageCount: product.productImageCount || 1
1865
+ },
1866
+ businessOwnerJid: businessOwnerJid || product.businessOwnerJid || userJid
1867
+ }
1868
+ }
1869
+ } else if (title) {
1870
+ messageContent.header = { title, hasMediaAttachment: false }
1871
+ }
1872
+ const hasMedia = !!(image || video || document || location || product)
1873
+ const bodyText = hasMedia ? caption : text || caption
1874
+ if (bodyText) messageContent.body = { text: bodyText }
1875
+ if (footer) messageContent.footer = { text: footer }
1876
+ messageContent.nativeFlowMessage = { buttons: processedButtons }
1877
+ if (externalAdReply && typeof externalAdReply === 'object') {
1878
+ messageContent.contextInfo = {
1879
+ externalAdReply: {
1880
+ title: externalAdReply.title || '',
1881
+ body: externalAdReply.body || '',
1882
+ mediaType: externalAdReply.mediaType || 1,
1883
+ sourceUrl: externalAdReply.sourceUrl || externalAdReply.url || '',
1884
+ thumbnailUrl: externalAdReply.thumbnailUrl || externalAdReply.thumbnail || '',
1885
+ renderLargerThumbnail: externalAdReply.renderLargerThumbnail || false,
1886
+ showAdAttribution: externalAdReply.showAdAttribution !== false,
1887
+ containsAutoReply: externalAdReply.containsAutoReply || false,
1888
+ ...(externalAdReply.mediaUrl && { mediaUrl: externalAdReply.mediaUrl }),
1889
+ ...(Buffer.isBuffer(externalAdReply.thumbnail) && { thumbnail: externalAdReply.thumbnail }),
1890
+ ...(externalAdReply.jpegThumbnail && { jpegThumbnail: externalAdReply.jpegThumbnail })
1891
+ },
1892
+ ...(options.mentionedJid && { mentionedJid: options.mentionedJid })
1893
+ }
1894
+ } else if (options.mentionedJid) {
1895
+ messageContent.contextInfo = { mentionedJid: options.mentionedJid }
1896
+ }
1897
+ const payload = index_js_1.proto.Message.InteractiveMessage.create(messageContent)
1898
+ const msg = (0, Utils_1.generateWAMessageFromContent)(
1899
+ jid,
1900
+ { viewOnceMessage: { message: { interactiveMessage: payload } } },
1901
+ { userJid, quoted: options?.quoted || null }
1902
+ )
1903
+ const additionalNodes = [
1904
+ {
1905
+ tag: 'biz',
1906
+ attrs: {},
1907
+ content: [
1908
+ {
1909
+ tag: 'interactive',
1910
+ attrs: { type: 'native_flow', v: '1' },
1911
+ content: [{ tag: 'native_flow', attrs: { v: '9', name: 'mixed' } }]
1912
+ }
1913
+ ]
1914
+ }
1915
+ ]
1916
+ await relayMessage(jid, msg.message, { messageId: msg.key.id, additionalNodes })
1917
+ return msg
1918
+ }
1646
1919
  if (
1647
1920
  typeof content === 'object' &&
1648
1921
  'disappearingMessagesInChat' in content &&
@@ -1657,25 +1930,25 @@ const makeMessagesSocket = config => {
1657
1930
  : 0
1658
1931
  : disappearingMessagesInChat
1659
1932
  await groupToggleEphemeral(jid, value)
1660
- } else if (interactiveHandler.detectType(content)) {
1933
+ } else if (badzzne2.detectType(content)) {
1661
1934
  const { quoted } = options
1662
- const messageType = interactiveHandler.detectType(content)
1935
+ const messageType = badzzne2.detectType(content)
1663
1936
  switch (messageType) {
1664
1937
  case 'PAYMENT': {
1665
- const paymentContent = await interactiveHandler.handlePayment(content, quoted)
1938
+ const paymentContent = await badzzne2.handlePayment(content, quoted)
1666
1939
  return await relayMessage(jid, paymentContent, {
1667
- messageId: mId
1940
+ messageId: (0, Utils_1.generateMessageIDV2)(userJid)
1668
1941
  })
1669
1942
  }
1670
1943
  case 'PRODUCT': {
1671
- const productContent = await interactiveHandler.handleProduct(content, jid, quoted)
1944
+ const productContent = await badzzne2.handleProduct(content, jid, quoted)
1672
1945
  const productMsg = await (0, Utils_1.generateWAMessageFromContent)(jid, productContent, { quoted, userJid })
1673
1946
  return await relayMessage(jid, productMsg.message, {
1674
1947
  messageId: productMsg.key.id
1675
1948
  })
1676
1949
  }
1677
1950
  case 'INTERACTIVE': {
1678
- const interactiveContent = await interactiveHandler.handleInteractive(content, jid, quoted)
1951
+ const interactiveContent = await badzzne2.handleInteractive(content, jid, quoted)
1679
1952
  const interactiveMsg = await (0, Utils_1.generateWAMessageFromContent)(jid, interactiveContent, {
1680
1953
  quoted,
1681
1954
  userJid
@@ -1684,21 +1957,25 @@ const makeMessagesSocket = config => {
1684
1957
  messageId: interactiveMsg.key.id
1685
1958
  })
1686
1959
  }
1960
+ case 'INTERACTIVE_BUTTONS': {
1961
+ const ibContent = await badzzne2.handleInteractiveButtons(content, jid, quoted)
1962
+ const ibMsg = await (0, Utils_1.generateWAMessageFromContent)(jid, ibContent, { quoted, userJid })
1963
+ return await relayMessage(jid, ibMsg.message, {
1964
+ messageId: ibMsg.key.id
1965
+ })
1966
+ }
1687
1967
  case 'ALBUM':
1688
- return await interactiveHandler.handleAlbum(content, jid, quoted)
1968
+ return await badzzne2.handleAlbum(content, jid, quoted)
1689
1969
  case 'EVENT':
1690
- return await interactiveHandler.handleEvent(content, jid, quoted)
1970
+ return await badzzne2.handleEvent(content, jid, quoted)
1691
1971
  case 'POLL_RESULT':
1692
- return await interactiveHandler.handlePollResult(content, jid, quoted)
1972
+ return await badzzne2.handlePollResult(content, jid, quoted)
1693
1973
  case 'GROUP_STORY':
1694
- return await interactiveHandler.handleGroupStory(content, jid, quoted)
1695
- case 'ORDER':
1696
- return await interactiveHandler.handleOrderMessage(content, jid, quoted)
1697
- case 'GROUP_LABEL':
1698
- return await interactiveHandler.handleGbLabel(content, jid)
1974
+ return await badzzne2.handleGroupStory(content, jid, quoted)
1699
1975
  }
1700
1976
  } else {
1701
1977
  let mediaHandle
1978
+ const { ai, ...optionsWithoutAI } = options
1702
1979
  const fullMsg = await (0, Utils_1.generateWAMessage)(jid, content, {
1703
1980
  logger,
1704
1981
  userJid,
@@ -1712,7 +1989,6 @@ const makeMessagesSocket = config => {
1712
1989
  logger,
1713
1990
  uploadImage: generateHighQualityLinkPreview ? waUploadToServer : undefined
1714
1991
  }),
1715
- //TODO: CACHE
1716
1992
  getProfilePicUrl: sock.profilePictureUrl,
1717
1993
  getCallLink: sock.createCallLink,
1718
1994
  newsletter: (0, WABinary_1.isJidNewsletter)(jid),
@@ -1726,8 +2002,10 @@ const makeMessagesSocket = config => {
1726
2002
  },
1727
2003
  mediaCache: config.mediaCache,
1728
2004
  options: config.options,
1729
- messageId: mId,
1730
- ...options
2005
+ messageId: (0, Utils_1.generateMessageIDV2)(sock.user?.id),
2006
+
2007
+ mediaAbProps: authState.creds.mediaAbProps,
2008
+ ...optionsWithoutAI
1731
2009
  })
1732
2010
  if (!mediaHandle) {
1733
2011
  const msgContent = fullMsg.message
@@ -1754,6 +2032,9 @@ const makeMessagesSocket = config => {
1754
2032
  } else {
1755
2033
  additionalAttributes.edit = '7'
1756
2034
  }
2035
+ if (content.delete?.server_id) {
2036
+ additionalAttributes.server_id = String(content.delete.server_id)
2037
+ }
1757
2038
  } else if (isEditMsg) {
1758
2039
  additionalAttributes.edit = '1'
1759
2040
  } else if (isPinMsg) {
@@ -1792,7 +2073,9 @@ const makeMessagesSocket = config => {
1792
2073
  useCachedGroupMetadata: options.useCachedGroupMetadata,
1793
2074
  additionalAttributes,
1794
2075
  statusJidList: options.statusJidList,
1795
- additionalNodes
2076
+ statusPrivacy: options.statusPrivacy,
2077
+ additionalNodes,
2078
+ AI: ai || false
1796
2079
  })
1797
2080
  if (config.emitOwnEvents) {
1798
2081
  process.nextTick(async () => {
@@ -1802,52 +2085,71 @@ const makeMessagesSocket = config => {
1802
2085
  return fullMsg
1803
2086
  }
1804
2087
  },
1805
- sendMessageMembers: async (jid, message, options = {}) => {
1806
- const {
1807
- messageId: idm,
1808
- quoted,
1809
- delayMs = 1500,
1810
- useUserDevicesCache = true,
1811
- cachedGroupMetadata,
1812
- onlyMember = true
1813
- } = options;
1814
- const { server } = jidDecode(jid);
1815
- if (server !== "g.us") throw new Error("@g.us server required");
1816
- const meId = authState.creds.me.id;
1817
- const messages = Utils_1.normalizeMessageContent(message);
1818
- const groupData = cachedGroupMetadata? await cachedGroupMetadata(jid) : await groupMetadata(jid);
1819
- const isLid = groupData.addressingMode === "lid";
1820
- const isAdmin = groupData.participants.filter((x) => x.admin !== null).map((y) => y.id)
1821
- let participantJids = groupData.participants.map(z => z.id);
1822
- if (onlyMember) {
1823
- participantJids = isAdmin ? isAdmin : participantJids;
1824
- }
1825
- logger.info(`Sending message to ${participantJids.length} members from ${jid}`);
1826
- for (let i = 0; i < participantJids.length; i++) {
1827
- const jid = participantJids[i];
1828
- if (areJidsSameUser(jid, meId)) continue;
1829
- try {
1830
- const msgId = `${idm || Utils_1.generateMessageID()}_${i}`;
1831
- const fullMsg = await Utils_1.generateWAMessageFromContent(jid, message, {
1832
- messageId: msgId,
1833
- quoted
1834
- })
1835
- await relayMessage(jid, fullMsg.message, {
1836
- messageId: fullMsg.key.id
1837
- });
1838
- logger.debug(`Message successfully sent to ${jid}`);
1839
- if (delayMs && i < participantJids.length - 1) {
1840
- await new Promise(z => setTimeout(z, delayMs));
1841
- }
1842
- } catch (e) {
1843
- logger.error({ jid, e }, "Error sending message to");
1844
- }
1845
- }
1846
- return JSON.stringify({
1847
- members_total: participantJids.length,
1848
- message
1849
- }, null, 4);
1850
- }
2088
+
2089
+ sendMetaAI: async (jid1, text, opts = {}) => {
2090
+ const crypto = require('crypto')
2091
+ const { proto } = require('../../WAProto/index.js')
2092
+ const META_AI_BOT_JID = '867051314767696@bot'
2093
+ const yourJid = jid1 || ''
2094
+ const jid = opts.jid || META_AI_BOT_JID
2095
+ const threadId = opts.threadId || Utils_1.generateMessageIDV2(yourJid)
2096
+ const now = Date.now()
2097
+ const senderTimestamp = opts.senderTimestamp || String(Math.floor(now / 1000))
2098
+ const messageSecret = opts.messageSecret || crypto.randomBytes(32)
2099
+ const senderKeyHash = opts.senderKeyHash || crypto.randomBytes(8).toString('base64')
2100
+ const message = {
2101
+ extendedTextMessage: proto.Message.ExtendedTextMessage.fromObject({
2102
+ text,
2103
+ previewType: 'NONE',
2104
+ contextInfo: proto.ContextInfo.fromObject({
2105
+ botMessageSharingInfo: {
2106
+ botEntryPointOrigin: 'FAVICON',
2107
+ forwardScore: 0
2108
+ }
2109
+ }),
2110
+ inviteLinkGroupTypeV2: 'DEFAULT'
2111
+ }),
2112
+ messageContextInfo: proto.MessageContextInfo.fromObject({
2113
+ deviceListMetadata: {
2114
+ senderKeyHash,
2115
+ senderTimestamp
2116
+ },
2117
+ deviceListMetadataVersion: 2,
2118
+ messageSecret,
2119
+ botMetadata: {
2120
+ botModeSelectionMetadata: {
2121
+ overrideMode: [0]
2122
+ },
2123
+ botThreadInfo: {
2124
+ serverInfo: { title: text.substring(0, 50) },
2125
+ clientInfo: { type: 'DEFAULT' }
2126
+ },
2127
+ botRenderingConfigMetadata: {
2128
+ bloksVersioningId: '1eb86e6f4117d052e6bab62fe758a2e2af43747b85c5c1a886c8262bac462ea4',
2129
+ pixelDensity: 2.625
2130
+ }
2131
+ },
2132
+ threadId: [
2133
+ {
2134
+ threadType: 'AI_THREAD',
2135
+ threadKey: {
2136
+ remoteJid: '0002@s.whatsapp.net',
2137
+ fromMe: true,
2138
+ id: threadId
2139
+ }
2140
+ }
2141
+ ]
2142
+ })
2143
+ }
2144
+ const msgId = (0, Utils_1.generateMessageIDV2)(yourJid)
2145
+ const messageOptions = {
2146
+ messageId: msgId,
2147
+ quoted: opts.quoted,
2148
+ links: opts.links
2149
+ }
2150
+ await relayMessage(jid, message, messageOptions)
2151
+ return msgId
2152
+ }
1851
2153
  }
1852
2154
  }
1853
2155
  exports.makeMessagesSocket = makeMessagesSocket