@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
@@ -48,30 +48,6 @@ const makeMessagesSocket = config => {
48
48
  trustInteropContact
49
49
  } = sock
50
50
  const getLIDForPN = signalRepository.lidMapping.getLIDForPN.bind(signalRepository.lidMapping)
51
- // Resolve all participant JIDs across the given group JIDs for status targeting.
52
- // includeMe = false skips the bot's own JID (avoids self-send loops).
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
51
  /**
76
52
  * Set of tctoken storage JIDs with a fire-and-forget issuePrivacyTokens IQ in flight.
77
53
  * Prevents duplicate IQs from rapid back-to-back sends before senderTimestamp persists.
@@ -251,21 +227,12 @@ const makeMessagesSocket = config => {
251
227
  }
252
228
  }
253
229
  const query = new WAUSync_1.USyncQuery().withContext('message').withDeviceProtocol().withLIDProtocol()
254
- // Attach any already-known LID inline on the <user> node for PN jids, so the
255
- // LID/contact protocols can use it directly instead of round-tripping.
256
- const pnJidsToFetch = toFetch.filter(jid => (0, WABinary_1.isPnUser)(jid) || (0, WABinary_1.isHostedPnUser)(jid))
257
- const cachedLidPairs = pnJidsToFetch.length
258
- ? (await signalRepository.lidMapping.getLIDsForPNs(pnJidsToFetch)) || []
259
- : []
260
- const cachedLidByPn = new Map(cachedLidPairs.map(({ pn, lid }) => [pn, lid]))
261
230
  for (const jid of toFetch) {
262
- const syncUser = new WAUSync_1.USyncUser().withId(jid)
263
- const cachedLid = cachedLidByPn.get(jid)
264
- if (cachedLid) syncUser.withLid(cachedLid)
265
- query.withUser(syncUser)
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
266
232
  }
267
233
  const result = await sock.executeUSyncQuery(query)
268
234
  if (result) {
235
+ // TODO: LID MAP this stuff (lid protocol will now return lid with devices)
269
236
  const lidResults = result.list.filter(a => !!a.lid)
270
237
  if (lidResults.length > 0) {
271
238
  logger.trace('Storing LID maps from device call')
@@ -540,9 +507,7 @@ const makeMessagesSocket = config => {
540
507
  additionalNodes,
541
508
  useUserDevicesCache,
542
509
  useCachedGroupMetadata,
543
- statusJidList,
544
- statusPrivacy,
545
- AI = false
510
+ statusJidList
546
511
  }
547
512
  ) => {
548
513
  const meId = authState.creds.me.id
@@ -558,7 +523,8 @@ const makeMessagesSocket = config => {
558
523
  const isInterop = (0, WABinary_1.isInteropUser)(jid)
559
524
  const isGroupOrStatus = isGroup || isStatus
560
525
  const finalJid = jid
561
- msgId = msgId || (0, Utils_1.generateMessageIDV2)(meId)
526
+ const iosBros = config.browser[0] === "iOS" || config.browser[1] === "Safari";
527
+ msgId = iosBros ? Utils_1.generateIOSMessageID() : msgId ?? (0, Utils_1.generateMessageIDV2)(meId)
562
528
  useUserDevicesCache = useUserDevicesCache !== false
563
529
  useCachedGroupMetadata = useCachedGroupMetadata !== false && !isStatus
564
530
  const participants = []
@@ -581,18 +547,6 @@ const makeMessagesSocket = config => {
581
547
 
582
548
  const buttonType = getButtonType(messages)
583
549
  const pollMessage = messages.pollCreationMessage || messages.pollCreationMessageV2 || messages.pollCreationMessageV3
584
-
585
- if (participant) {
586
- if (!isGroup && !isStatus) {
587
- additionalAttributes = { ...additionalAttributes, device_fanout: 'false' }
588
- }
589
- const { user, device } = (0, WABinary_1.jidDecode)(participant.jid)
590
- devices.push({
591
- user,
592
- device,
593
- jid: participant.jid
594
- })
595
- }
596
550
  await authState.keys.transaction(async () => {
597
551
  const mediaType = getMediaType(message)
598
552
  if (mediaType) {
@@ -624,15 +578,26 @@ const makeMessagesSocket = config => {
624
578
  (0, Utils_1.normalizeMessageContent)(message)?.pinInChatMessage ||
625
579
  (0, Utils_1.normalizeMessageContent)(message)?.reactionMessage
626
580
  ) {
627
- extraAttrs['decrypt-fail'] = 'hide'
581
+ extraAttrs['decrypt-fail'] = 'hide' // todo: expand for reactions and other types
628
582
  }
629
583
  if (isGroupOrStatus && !isRetryResend) {
630
584
  const [groupData, senderKeyMap] = await Promise.all([
631
585
  (async () => {
632
- let groupData = useCachedGroupMetadata && cachedGroupMetadata ? await cachedGroupMetadata(jid) : undefined // todo: should we rely on the cache specially if the cache is outdated and the metadata has new fields?
633
- if (groupData && Array.isArray(groupData?.participants)) {
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) {
634
593
  logger.trace({ jid, participants: groupData.participants.length }, 'using cached group metadata')
635
594
  } 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
+ }
636
601
  groupData = await groupMetadata(jid) // TODO: start storing group participant list + addr mode in Signal & stop relying on this
637
602
  }
638
603
  return groupData
@@ -912,20 +877,19 @@ const makeMessagesSocket = config => {
912
877
  const { user: mePnUser } = (0, WABinary_1.jidDecode)(meId)
913
878
  const { user: meLidUser } = meLid ? (0, WABinary_1.jidDecode)(meLid) : { user: null }
914
879
  for (const { user, jid } of devices) {
915
- const isExactSenderDevice = jid === meId || (meLid && jid === meLid)
916
- if (isExactSenderDevice) {
917
- logger.debug({ jid, meId, meLid }, 'Skipping exact sender device (whatsmeow pattern)')
918
- continue
919
- }
920
- // Check if this is our device (could match either PN or LID user)
921
- const isMe = user === mePnUser || user === meLidUser
922
- if (isMe) {
923
- meRecipients.push(jid)
924
- } else {
925
- otherRecipients.push(jid)
926
- }
927
- allRecipients.push(jid)
928
- }
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
+ }
929
893
  await assertSessions(allRecipients)
930
894
  const [
931
895
  { nodes: meNodes, shouldIncludeDeviceIdentity: s1 },
@@ -942,31 +906,6 @@ const makeMessagesSocket = config => {
942
906
  }
943
907
  shouldIncludeDeviceIdentity = shouldIncludeDeviceIdentity || s1 || s2
944
908
  }
945
- if (isRetryResend) {
946
- const isParticipantLid = (0, WABinary_1.isLidUser)(participant.jid)
947
- const isMe = (0, WABinary_1.areJidsSameUser)(participant.jid, isParticipantLid ? meLid : meId)
948
- const encodedMessageToSend = isMe
949
- ? (0, Utils_1.encodeWAMessage)({
950
- deviceSentMessage: {
951
- destinationJid,
952
- message
953
- }
954
- })
955
- : (0, Utils_1.encodeWAMessage)(message)
956
- const { type, ciphertext: encryptedContent } = await signalRepository.encryptMessage({
957
- data: encodedMessageToSend,
958
- jid: participant.jid
959
- })
960
- binaryNodeContent.push({
961
- tag: 'enc',
962
- attrs: {
963
- v: '2',
964
- type,
965
- count: (participant.count ?? 0).toString()
966
- },
967
- content: encryptedContent
968
- })
969
- }
970
909
  if (participants.length) {
971
910
  if (additionalAttributes?.['category'] === 'peer') {
972
911
  const peerNode = participants[0]?.content?.[0]
@@ -999,22 +938,6 @@ const makeMessagesSocket = config => {
999
938
  },
1000
939
  content: binaryNodeContent
1001
940
  }
1002
- // if the participant to send to is explicitly specified (generally retry recp)
1003
- // ensure the message is only sent to that person
1004
- // if a retry receipt is sent to everyone -- it'll fail decryption for everyone else who received the msg
1005
- if (participant) {
1006
- if ((0, WABinary_1.isJidGroup)(destinationJid)) {
1007
- stanza.attrs.to = destinationJid
1008
- stanza.attrs.participant = participant.jid
1009
- } else if ((0, WABinary_1.areJidsSameUser)(participant.jid, meId)) {
1010
- stanza.attrs.to = participant.jid
1011
- stanza.attrs.recipient = destinationJid
1012
- } else {
1013
- stanza.attrs.to = participant.jid
1014
- }
1015
- } else {
1016
- stanza.attrs.to = destinationJid
1017
- }
1018
941
  if (shouldIncludeDeviceIdentity) {
1019
942
  stanza.content.push({
1020
943
  tag: 'device-identity',
@@ -1031,14 +954,6 @@ const makeMessagesSocket = config => {
1031
954
  })
1032
955
  }
1033
956
 
1034
- // Status audience privacy: add <meta status_setting="..."> for all non-revoke sends
1035
- if (isStatus && statusPrivacy && !additionalAttributes?.edit) {
1036
- stanza.content.push({
1037
- tag: 'meta',
1038
- attrs: { status_setting: statusPrivacy, session_scope: 'status' }
1039
- })
1040
- }
1041
-
1042
957
  if (pollMessage || messages.eventMessage) {
1043
958
  stanza.content.push({
1044
959
  tag: 'meta',
@@ -1096,14 +1011,14 @@ const makeMessagesSocket = config => {
1096
1011
  stanza.content.push(buttonsNode)
1097
1012
  }
1098
1013
  }
1099
- if (!AI && (0, WABinary_1.isPnUser)(destinationJid)) {
1014
+ if (!config.aiLabel && (0, WABinary_1.isPnUser)(destinationJid)) {
1100
1015
  const alreadyHasBizBot =
1101
1016
  WABinary_1.getBinaryFilteredBizBot(additionalNodes || []) ||
1102
1017
  WABinary_1.getBinaryFilteredBizBot(stanza.content)
1103
1018
  if (!alreadyHasBizBot) {
1104
1019
  stanza.content.push({ tag: 'bot', attrs: { biz_bot: '1' } })
1105
1020
  }
1106
- } else if (AI && !isGroup && !isStatus && !isNewsletter) {
1021
+ } else if (config.aiLabel && !isGroup && !isStatus && !isNewsletter) {
1107
1022
  const existingBizBot = WABinary_1.getBinaryFilteredBizBot(additionalNodes || [])
1108
1023
  if (!existingBizBot) {
1109
1024
  stanza.content.push({ tag: 'bot', attrs: { biz_bot: '1' } })
@@ -1140,27 +1055,6 @@ const makeMessagesSocket = config => {
1140
1055
  content: tcTokenBuffer
1141
1056
  })
1142
1057
  }
1143
- // CSToken: HMAC-SHA256(nctSalt, utf8("<user>@lid")) — cold-contact fallback when no tctoken
1144
- if (is1on1Send && !tcTokenBuffer?.length) {
1145
- try {
1146
- const saltStore = await authState.keys.get('nct-salt', ['default'])
1147
- const nctSalt = saltStore?.['default']
1148
- if (nctSalt?.length) {
1149
- const recipientLid = await getLIDForPN(destinationJid)
1150
- if (recipientLid) {
1151
- const { createHmac } = require('crypto')
1152
- const lidStr = (0, WABinary_1.isLidUser)(recipientLid)
1153
- ? recipientLid
1154
- : `${recipientLid.split('@')[0]}@lid`
1155
- const cs = createHmac('sha256', nctSalt).update(lidStr, 'utf8').digest()
1156
- stanza.content.push({ tag: 'cstoken', attrs: {}, content: cs })
1157
- logger.debug({ jid: destinationJid, lid: lidStr }, 'nct: attached cstoken')
1158
- }
1159
- }
1160
- } catch (err) {
1161
- logger.debug({ jid: destinationJid, err: err?.message }, 'nct: cstoken attach failed')
1162
- }
1163
- }
1164
1058
  if (additionalNodes && additionalNodes.length > 0 && !didPushAdditional) {
1165
1059
  stanza.content.push(...additionalNodes)
1166
1060
  }
@@ -1474,7 +1368,7 @@ const makeMessagesSocket = config => {
1474
1368
  }
1475
1369
  const getPrivacyTokens = issuePrivacyTokens
1476
1370
  const waUploadToServer = (0, Utils_1.getWAUploadToServer)(config, refreshMediaConn)
1477
- const badzzne2 = new interactive_handler_1.Badzz88Handler(waUploadToServer, relayMessage, config, sock)
1371
+ const interactiveHandler = new interactive_handler_1.InteractiveMessageHandler(waUploadToServer, relayMessage, config, sock)
1478
1372
  const waitForMsgMediaUpdate = (0, Utils_1.bindWaitForEvent)(ev, 'messages.media-update')
1479
1373
  return {
1480
1374
  ...sock,
@@ -1627,7 +1521,6 @@ const makeMessagesSocket = config => {
1627
1521
  mediaHandle = up.handle
1628
1522
  return up
1629
1523
  },
1630
- mediaAbProps: authState.creds.mediaAbProps,
1631
1524
  ...options
1632
1525
  }
1633
1526
  )
@@ -1649,7 +1542,6 @@ const makeMessagesSocket = config => {
1649
1542
  mediaHandle = up.handle
1650
1543
  return up
1651
1544
  },
1652
- mediaAbProps: authState.creds.mediaAbProps,
1653
1545
  ...options
1654
1546
  }
1655
1547
  )
@@ -1669,7 +1561,7 @@ const makeMessagesSocket = config => {
1669
1561
  },
1670
1562
 
1671
1563
  sendStatusMention: async (content, jids = []) => {
1672
- return await badzzne2.sendStatusWhatsApp(content, jids)
1564
+ return await interactiveHandler.sendStatusWhatsApp(content, jids)
1673
1565
  },
1674
1566
  sendTable: async (jid, title, headers, rows, quoted, options = {}) => {
1675
1567
  const { message, messageId } = message_composer_1.generateTableContent(title, headers, rows, quoted, options)
@@ -1724,6 +1616,8 @@ const makeMessagesSocket = config => {
1724
1616
  },
1725
1617
  sendMessage: async (jid, content, options = {}) => {
1726
1618
  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)
1727
1621
  // ── Normalize: buttons[].nativeFlowInfo -> interactiveButtons ──────
1728
1622
  if (
1729
1623
  typeof content === 'object' &&
@@ -1749,181 +1643,6 @@ const makeMessagesSocket = config => {
1749
1643
  const { buttons, headerType, viewOnce, ...rest } = content
1750
1644
  content = { ...rest, interactiveButtons }
1751
1645
  }
1752
- if (
1753
- typeof content === 'object' &&
1754
- Array.isArray(content.interactiveButtons) &&
1755
- content.interactiveButtons.length > 0
1756
- ) {
1757
- const {
1758
- text = '',
1759
- caption = '',
1760
- title = '',
1761
- footer = '',
1762
- interactiveButtons,
1763
- hasMediaAttachment = false,
1764
- image = null,
1765
- video = null,
1766
- document = null,
1767
- mimetype = null,
1768
- jpegThumbnail = null,
1769
- location = null,
1770
- product = null,
1771
- businessOwnerJid = null,
1772
- externalAdReply = null
1773
- } = content
1774
- // Normalize buttons
1775
- const processedButtons = []
1776
- for (let i = 0; i < interactiveButtons.length; i++) {
1777
- const btn = interactiveButtons[i]
1778
- if (!btn || typeof btn !== 'object') throw new Error(`interactiveButtons[${i}] must be an object`)
1779
- if (btn.name && btn.buttonParamsJson) {
1780
- processedButtons.push(btn)
1781
- continue
1782
- }
1783
- if (btn.id || btn.text || btn.displayText) {
1784
- processedButtons.push({
1785
- name: 'quick_reply',
1786
- buttonParamsJson: JSON.stringify({
1787
- display_text: btn.text || btn.displayText || `Button ${i + 1}`,
1788
- id: btn.id || `quick_${i + 1}`
1789
- })
1790
- })
1791
- continue
1792
- }
1793
- if (btn.buttonId && btn.buttonText?.displayText) {
1794
- processedButtons.push({
1795
- name: 'quick_reply',
1796
- buttonParamsJson: JSON.stringify({ display_text: btn.buttonText.displayText, id: btn.buttonId })
1797
- })
1798
- continue
1799
- }
1800
- throw new Error(`interactiveButtons[${i}] has invalid shape`)
1801
- }
1802
- let messageContent = {}
1803
- if (image) {
1804
- const mi = Buffer.isBuffer(image)
1805
- ? { image }
1806
- : { image: { url: typeof image === 'object' ? image.url : image } }
1807
- const pm = await (0, Utils_1.prepareWAMessageMedia)(mi, { upload: waUploadToServer })
1808
- messageContent.header = { title: title || '', hasMediaAttachment: true, imageMessage: pm.imageMessage }
1809
- } else if (video) {
1810
- const mi = Buffer.isBuffer(video)
1811
- ? { video }
1812
- : { video: { url: typeof video === 'object' ? video.url : video } }
1813
- const pm = await (0, Utils_1.prepareWAMessageMedia)(mi, { upload: waUploadToServer })
1814
- messageContent.header = { title: title || '', hasMediaAttachment: true, videoMessage: pm.videoMessage }
1815
- } else if (document) {
1816
- const mi = Buffer.isBuffer(document)
1817
- ? { document }
1818
- : { document: { url: typeof document === 'object' ? document.url : document } }
1819
- if (mimetype && typeof mi.document === 'object') mi.document.mimetype = mimetype
1820
- if (jpegThumbnail) {
1821
- const thumb = Buffer.isBuffer(jpegThumbnail)
1822
- ? jpegThumbnail
1823
- : await (async () => {
1824
- try {
1825
- const r = await fetch(jpegThumbnail)
1826
- return Buffer.from(await r.arrayBuffer())
1827
- } catch {
1828
- return undefined
1829
- }
1830
- })()
1831
- if (thumb) mi.document.jpegThumbnail = thumb
1832
- }
1833
- const pm = await (0, Utils_1.prepareWAMessageMedia)(mi, { upload: waUploadToServer })
1834
- messageContent.header = { title: title || '', hasMediaAttachment: true, documentMessage: pm.documentMessage }
1835
- } else if (location && typeof location === 'object') {
1836
- messageContent.header = {
1837
- title: title || location.name || 'Location',
1838
- hasMediaAttachment: false,
1839
- locationMessage: {
1840
- degreesLatitude: location.degreesLatitude || location.degressLatitude || 0,
1841
- degreesLongitude: location.degreesLongitude || location.degressLongitude || 0,
1842
- name: location.name || '',
1843
- address: location.address || ''
1844
- }
1845
- }
1846
- } else if (product && typeof product === 'object') {
1847
- let productImageMessage = null
1848
- if (product.productImage) {
1849
- const mi = Buffer.isBuffer(product.productImage)
1850
- ? { image: product.productImage }
1851
- : {
1852
- image: {
1853
- url: typeof product.productImage === 'object' ? product.productImage.url : product.productImage
1854
- }
1855
- }
1856
- const pm = await (0, Utils_1.prepareWAMessageMedia)(mi, { upload: waUploadToServer })
1857
- productImageMessage = pm.imageMessage
1858
- }
1859
- messageContent.header = {
1860
- title: title || product.title || 'Product',
1861
- hasMediaAttachment: false,
1862
- productMessage: {
1863
- product: {
1864
- productImage: productImageMessage,
1865
- productId: product.productId || '',
1866
- title: product.title || '',
1867
- description: product.description || '',
1868
- currencyCode: product.currencyCode || 'USD',
1869
- priceAmount1000: parseInt(product.priceAmount1000, 10) || 0,
1870
- retailerId: product.retailerId || '',
1871
- url: product.url || '',
1872
- productImageCount: product.productImageCount || 1
1873
- },
1874
- businessOwnerJid: businessOwnerJid || product.businessOwnerJid || userJid
1875
- }
1876
- }
1877
- } else if (title) {
1878
- messageContent.header = { title, hasMediaAttachment: false }
1879
- }
1880
- const hasMedia = !!(image || video || document || location || product)
1881
- const bodyText = hasMedia ? caption : text || caption
1882
- if (bodyText) messageContent.body = { text: bodyText }
1883
- if (footer) messageContent.footer = { text: footer }
1884
- messageContent.nativeFlowMessage = { buttons: processedButtons }
1885
- if (externalAdReply && typeof externalAdReply === 'object') {
1886
- messageContent.contextInfo = {
1887
- externalAdReply: {
1888
- title: externalAdReply.title || '',
1889
- body: externalAdReply.body || '',
1890
- mediaType: externalAdReply.mediaType || 1,
1891
- sourceUrl: externalAdReply.sourceUrl || externalAdReply.url || '',
1892
- thumbnailUrl: externalAdReply.thumbnailUrl || externalAdReply.thumbnail || '',
1893
- renderLargerThumbnail: externalAdReply.renderLargerThumbnail || false,
1894
- showAdAttribution: externalAdReply.showAdAttribution !== false,
1895
- containsAutoReply: externalAdReply.containsAutoReply || false,
1896
- ...(externalAdReply.mediaUrl && { mediaUrl: externalAdReply.mediaUrl }),
1897
- ...(Buffer.isBuffer(externalAdReply.thumbnail) && { thumbnail: externalAdReply.thumbnail }),
1898
- ...(externalAdReply.jpegThumbnail && { jpegThumbnail: externalAdReply.jpegThumbnail })
1899
- },
1900
- ...(options.mentionedJid && { mentionedJid: options.mentionedJid })
1901
- }
1902
- } else if (options.mentionedJid) {
1903
- messageContent.contextInfo = { mentionedJid: options.mentionedJid }
1904
- }
1905
- const payload = index_js_1.proto.Message.InteractiveMessage.create(messageContent)
1906
- const msg = (0, Utils_1.generateWAMessageFromContent)(
1907
- jid,
1908
- { viewOnceMessage: { message: { interactiveMessage: payload } } },
1909
- { userJid, quoted: options?.quoted || null }
1910
- )
1911
- const additionalNodes = [
1912
- {
1913
- tag: 'biz',
1914
- attrs: {},
1915
- content: [
1916
- {
1917
- tag: 'interactive',
1918
- attrs: { type: 'native_flow', v: '1' },
1919
- content: [{ tag: 'native_flow', attrs: { v: '9', name: 'mixed' } }]
1920
- }
1921
- ]
1922
- }
1923
- ]
1924
- await relayMessage(jid, msg.message, { messageId: msg.key.id, additionalNodes })
1925
- return msg
1926
- }
1927
1646
  if (
1928
1647
  typeof content === 'object' &&
1929
1648
  'disappearingMessagesInChat' in content &&
@@ -1938,25 +1657,25 @@ const makeMessagesSocket = config => {
1938
1657
  : 0
1939
1658
  : disappearingMessagesInChat
1940
1659
  await groupToggleEphemeral(jid, value)
1941
- } else if (badzzne2.detectType(content)) {
1660
+ } else if (interactiveHandler.detectType(content)) {
1942
1661
  const { quoted } = options
1943
- const messageType = badzzne2.detectType(content)
1662
+ const messageType = interactiveHandler.detectType(content)
1944
1663
  switch (messageType) {
1945
1664
  case 'PAYMENT': {
1946
- const paymentContent = await badzzne2.handlePayment(content, quoted)
1665
+ const paymentContent = await interactiveHandler.handlePayment(content, quoted)
1947
1666
  return await relayMessage(jid, paymentContent, {
1948
- messageId: (0, Utils_1.generateMessageIDV2)(userJid)
1667
+ messageId: mId
1949
1668
  })
1950
1669
  }
1951
1670
  case 'PRODUCT': {
1952
- const productContent = await badzzne2.handleProduct(content, jid, quoted)
1671
+ const productContent = await interactiveHandler.handleProduct(content, jid, quoted)
1953
1672
  const productMsg = await (0, Utils_1.generateWAMessageFromContent)(jid, productContent, { quoted, userJid })
1954
1673
  return await relayMessage(jid, productMsg.message, {
1955
1674
  messageId: productMsg.key.id
1956
1675
  })
1957
1676
  }
1958
1677
  case 'INTERACTIVE': {
1959
- const interactiveContent = await badzzne2.handleInteractive(content, jid, quoted)
1678
+ const interactiveContent = await interactiveHandler.handleInteractive(content, jid, quoted)
1960
1679
  const interactiveMsg = await (0, Utils_1.generateWAMessageFromContent)(jid, interactiveContent, {
1961
1680
  quoted,
1962
1681
  userJid
@@ -1965,25 +1684,21 @@ const makeMessagesSocket = config => {
1965
1684
  messageId: interactiveMsg.key.id
1966
1685
  })
1967
1686
  }
1968
- case 'INTERACTIVE_BUTTONS': {
1969
- const ibContent = await badzzne2.handleInteractiveButtons(content, jid, quoted)
1970
- const ibMsg = await (0, Utils_1.generateWAMessageFromContent)(jid, ibContent, { quoted, userJid })
1971
- return await relayMessage(jid, ibMsg.message, {
1972
- messageId: ibMsg.key.id
1973
- })
1974
- }
1975
1687
  case 'ALBUM':
1976
- return await badzzne2.handleAlbum(content, jid, quoted)
1688
+ return await interactiveHandler.handleAlbum(content, jid, quoted)
1977
1689
  case 'EVENT':
1978
- return await badzzne2.handleEvent(content, jid, quoted)
1690
+ return await interactiveHandler.handleEvent(content, jid, quoted)
1979
1691
  case 'POLL_RESULT':
1980
- return await badzzne2.handlePollResult(content, jid, quoted)
1692
+ return await interactiveHandler.handlePollResult(content, jid, quoted)
1981
1693
  case 'GROUP_STORY':
1982
- return await badzzne2.handleGroupStory(content, jid, quoted)
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)
1983
1699
  }
1984
1700
  } else {
1985
1701
  let mediaHandle
1986
- const { ai, ...optionsWithoutAI } = options
1987
1702
  const fullMsg = await (0, Utils_1.generateWAMessage)(jid, content, {
1988
1703
  logger,
1989
1704
  userJid,
@@ -1997,6 +1712,7 @@ const makeMessagesSocket = config => {
1997
1712
  logger,
1998
1713
  uploadImage: generateHighQualityLinkPreview ? waUploadToServer : undefined
1999
1714
  }),
1715
+ //TODO: CACHE
2000
1716
  getProfilePicUrl: sock.profilePictureUrl,
2001
1717
  getCallLink: sock.createCallLink,
2002
1718
  newsletter: (0, WABinary_1.isJidNewsletter)(jid),
@@ -2010,10 +1726,8 @@ const makeMessagesSocket = config => {
2010
1726
  },
2011
1727
  mediaCache: config.mediaCache,
2012
1728
  options: config.options,
2013
- messageId: (0, Utils_1.generateMessageIDV2)(sock.user?.id),
2014
- // Pass persisted media AB props so feature-flagged upload/download paths work.
2015
- mediaAbProps: authState.creds.mediaAbProps,
2016
- ...optionsWithoutAI
1729
+ messageId: mId,
1730
+ ...options
2017
1731
  })
2018
1732
  if (!mediaHandle) {
2019
1733
  const msgContent = fullMsg.message
@@ -2040,9 +1754,6 @@ const makeMessagesSocket = config => {
2040
1754
  } else {
2041
1755
  additionalAttributes.edit = '7'
2042
1756
  }
2043
- if (content.delete?.server_id) {
2044
- additionalAttributes.server_id = String(content.delete.server_id)
2045
- }
2046
1757
  } else if (isEditMsg) {
2047
1758
  additionalAttributes.edit = '1'
2048
1759
  } else if (isPinMsg) {
@@ -2081,9 +1792,7 @@ const makeMessagesSocket = config => {
2081
1792
  useCachedGroupMetadata: options.useCachedGroupMetadata,
2082
1793
  additionalAttributes,
2083
1794
  statusJidList: options.statusJidList,
2084
- statusPrivacy: options.statusPrivacy,
2085
- additionalNodes,
2086
- AI: ai || false
1795
+ additionalNodes
2087
1796
  })
2088
1797
  if (config.emitOwnEvents) {
2089
1798
  process.nextTick(async () => {
@@ -2093,71 +1802,52 @@ const makeMessagesSocket = config => {
2093
1802
  return fullMsg
2094
1803
  }
2095
1804
  },
2096
-
2097
- sendMetaAI: async (jid1, text, opts = {}) => {
2098
- const crypto = require('crypto')
2099
- const { proto } = require('../../WAProto/index.js')
2100
- const META_AI_BOT_JID = '867051314767696@bot'
2101
- const yourJid = jid1 || ''
2102
- const jid = opts.jid || META_AI_BOT_JID
2103
- const threadId = opts.threadId || Utils_1.generateMessageIDV2(yourJid)
2104
- const now = Date.now()
2105
- const senderTimestamp = opts.senderTimestamp || String(Math.floor(now / 1000))
2106
- const messageSecret = opts.messageSecret || crypto.randomBytes(32)
2107
- const senderKeyHash = opts.senderKeyHash || crypto.randomBytes(8).toString('base64')
2108
- const message = {
2109
- extendedTextMessage: proto.Message.ExtendedTextMessage.fromObject({
2110
- text,
2111
- previewType: 'NONE',
2112
- contextInfo: proto.ContextInfo.fromObject({
2113
- botMessageSharingInfo: {
2114
- botEntryPointOrigin: 'FAVICON',
2115
- forwardScore: 0
2116
- }
2117
- }),
2118
- inviteLinkGroupTypeV2: 'DEFAULT'
2119
- }),
2120
- messageContextInfo: proto.MessageContextInfo.fromObject({
2121
- deviceListMetadata: {
2122
- senderKeyHash,
2123
- senderTimestamp
2124
- },
2125
- deviceListMetadataVersion: 2,
2126
- messageSecret,
2127
- botMetadata: {
2128
- botModeSelectionMetadata: {
2129
- overrideMode: [0]
2130
- },
2131
- botThreadInfo: {
2132
- serverInfo: { title: text.substring(0, 50) },
2133
- clientInfo: { type: 'DEFAULT' }
2134
- },
2135
- botRenderingConfigMetadata: {
2136
- bloksVersioningId: '1eb86e6f4117d052e6bab62fe758a2e2af43747b85c5c1a886c8262bac462ea4',
2137
- pixelDensity: 2.625
2138
- }
2139
- },
2140
- threadId: [
2141
- {
2142
- threadType: 'AI_THREAD',
2143
- threadKey: {
2144
- remoteJid: '0002@s.whatsapp.net',
2145
- fromMe: true,
2146
- id: threadId
2147
- }
2148
- }
2149
- ]
2150
- })
2151
- }
2152
- const msgId = (0, Utils_1.generateMessageIDV2)(yourJid)
2153
- const messageOptions = {
2154
- messageId: msgId,
2155
- quoted: opts.quoted,
2156
- links: opts.links
2157
- }
2158
- await relayMessage(jid, message, messageOptions)
2159
- return msgId
2160
- }
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
+ }
2161
1851
  }
2162
1852
  }
2163
1853
  exports.makeMessagesSocket = makeMessagesSocket