@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
@@ -48,47 +48,26 @@ const makeMessagesSocket = config => {
48
48
  trustInteropContact
49
49
  } = sock
50
50
  const getLIDForPN = signalRepository.lidMapping.getLIDForPN.bind(signalRepository.lidMapping)
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
-
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
+ */
76
55
  const inFlightTcTokenIssuance = new Set()
77
56
  const userDevicesCache =
78
57
  config.userDevicesCache ||
79
58
  new node_cache_1.default({
80
- stdTTL: Defaults_1.DEFAULT_CACHE_TTLS.USER_DEVICES,
59
+ stdTTL: Defaults_1.DEFAULT_CACHE_TTLS.USER_DEVICES, // 5 minutes
81
60
  useClones: false
82
61
  })
83
62
  const peerSessionsCache = new node_cache_1.default({
84
63
  stdTTL: Defaults_1.DEFAULT_CACHE_TTLS.USER_DEVICES,
85
64
  useClones: false
86
65
  })
87
-
66
+ // Initialize message retry manager if enabled
88
67
  const messageRetryManager = enableRecentMessageCache
89
68
  ? new Utils_1.MessageRetryManager(logger, maxMsgRetryCount)
90
69
  : null
91
-
70
+ // Prevent race conditions in Signal session encryption by user
92
71
  const encryptionMutex = (0, make_mutex_1.makeKeyedMutex)()
93
72
  let mediaConn
94
73
  const refreshMediaConn = async (forceGet = false) => {
@@ -105,7 +84,7 @@ const makeMessagesSocket = config => {
105
84
  content: [{ tag: 'media_conn', attrs: {} }]
106
85
  })
107
86
  const mediaConnNode = (0, WABinary_1.getBinaryNodeChild)(result, 'media_conn')
108
-
87
+ // TODO: explore full length of data that whatsapp provides
109
88
  const node = {
110
89
  hosts: (0, WABinary_1.getBinaryNodeChildren)(mediaConnNode, 'host').map(({ attrs }) => ({
111
90
  hostname: attrs.hostname,
@@ -121,7 +100,10 @@ const makeMessagesSocket = config => {
121
100
  }
122
101
  return mediaConn
123
102
  }
124
-
103
+ /**
104
+ * generic send receipt function
105
+ * used for receipts of phone call, read, delivery etc.
106
+ * */
125
107
  const sendReceipt = async (jid, participant, messageIds, type, sts) => {
126
108
  if (!messageIds || messageIds.length === 0) {
127
109
  throw new boom_1.Boom('missing ids in receipt')
@@ -141,7 +123,7 @@ const makeMessagesSocket = config => {
141
123
  node.attrs.recipient = jid
142
124
  node.attrs.to = participant
143
125
  } else if (isInterop && !type) {
144
-
126
+ // Delivery receipt to interop contact: WA sends to device-qualified JID (user:0@interop)
145
127
  const { user } = (0, WABinary_1.jidDecode)(jid)
146
128
  node.attrs.to = `${user}:0@interop`
147
129
  } else {
@@ -153,7 +135,7 @@ const makeMessagesSocket = config => {
153
135
  if (type) {
154
136
  node.attrs.type = type
155
137
  }
156
-
138
+ // Interop bridge requires sts (microsecond stanza timestamp) from the original message
157
139
  if (isInterop && sts) {
158
140
  node.attrs.sts = sts
159
141
  }
@@ -173,21 +155,21 @@ const makeMessagesSocket = config => {
173
155
  logger.debug({ attrs: node.attrs, messageIds }, 'sending receipt for messages')
174
156
  await sendNode(node)
175
157
  }
176
-
158
+ /** Correctly bulk send receipts to multiple chats, participants */
177
159
  const sendReceipts = async (keys, type) => {
178
160
  const recps = (0, Utils_1.aggregateMessageKeysNotFromMe)(keys)
179
161
  for (const { jid, participant, messageIds, sts } of recps) {
180
162
  await sendReceipt(jid, participant, messageIds, type, sts)
181
163
  }
182
164
  }
183
-
165
+ /** Bulk read messages. Keys can be from different chats & participants */
184
166
  const readMessages = async keys => {
185
167
  const privacySettings = await fetchPrivacySettings()
186
-
168
+ // based on privacy settings, we have to change the read type
187
169
  const readType = privacySettings.readreceipts === 'all' ? 'read' : 'read-self'
188
170
  await sendReceipts(keys, readType)
189
171
  }
190
-
172
+ /** Fetch all the devices we've to send a message to */
191
173
  const getUSyncDevices = async (jids, useCache, ignoreZeroDevices) => {
192
174
  const deviceResults = []
193
175
  if (!useCache) {
@@ -245,26 +227,17 @@ const makeMessagesSocket = config => {
245
227
  }
246
228
  }
247
229
  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]))
255
230
  for (const jid of toFetch) {
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)
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
260
232
  }
261
233
  const result = await sock.executeUSyncQuery(query)
262
234
  if (result) {
235
+ // TODO: LID MAP this stuff (lid protocol will now return lid with devices)
263
236
  const lidResults = result.list.filter(a => !!a.lid)
264
237
  if (lidResults.length > 0) {
265
238
  logger.trace('Storing LID maps from device call')
266
239
  await signalRepository.lidMapping.storeLIDPNMappings(lidResults.map(a => ({ lid: a.lid, pn: a.id })))
267
-
240
+ // Force-refresh sessions for newly mapped LIDs to align identity addressing
268
241
  try {
269
242
  const lids = lidResults.map(a => a.lid)
270
243
  if (lids.length) {
@@ -285,10 +258,10 @@ const makeMessagesSocket = config => {
285
258
  deviceMap[item.user] = deviceMap[item.user] || []
286
259
  deviceMap[item.user]?.push(item)
287
260
  }
288
-
261
+ // Process each user's devices as a group for bulk LID migration
289
262
  for (const [user, userDevices] of Object.entries(deviceMap)) {
290
263
  const isLidUser = requestedLidUsers.has(user)
291
-
264
+ // Process all devices for this user
292
265
  for (const item of userDevices) {
293
266
  const finalJid = isLidUser
294
267
  ? (0, WABinary_1.jidEncode)(user, item.server, item.device)
@@ -309,7 +282,7 @@ const makeMessagesSocket = config => {
309
282
  }
310
283
  }
311
284
  if (userDevicesCache.mset) {
312
-
285
+ // if the cache supports mset, we can set all devices in one go
313
286
  await userDevicesCache.mset(Object.entries(deviceMap).map(([key, value]) => ({ key, value })))
314
287
  } else {
315
288
  for (const key in deviceMap) {
@@ -336,7 +309,9 @@ const makeMessagesSocket = config => {
336
309
  }
337
310
  return deviceResults
338
311
  }
339
-
312
+ /**
313
+ * Update Member Label
314
+ */
340
315
  const updateMemberLabel = (jid, memberLabel) => {
341
316
  return relayMessage(
342
317
  jid,
@@ -365,16 +340,16 @@ const makeMessagesSocket = config => {
365
340
  }
366
341
  const assertSessions = async (jids, force) => {
367
342
  let didFetchNewSession = false
368
- const uniqueJids = [...new Set(jids)]
343
+ const uniqueJids = [...new Set(jids)] // Deduplicate JIDs
369
344
  const jidsRequiringFetch = []
370
345
  logger.debug({ jids }, 'assertSessions call with jids')
371
-
346
+ // Check peerSessionsCache and validate sessions using libsignal loadSession
372
347
  for (const jid of uniqueJids) {
373
348
  const signalId = signalRepository.jidToSignalProtocolAddress(jid)
374
349
  const cachedSession = peerSessionsCache.get(signalId)
375
350
  if (cachedSession !== undefined) {
376
351
  if (cachedSession && !force) {
377
- continue
352
+ continue // Session exists in cache
378
353
  }
379
354
  } else {
380
355
  const sessionValidation = await signalRepository.validateSession(jid)
@@ -387,7 +362,7 @@ const makeMessagesSocket = config => {
387
362
  jidsRequiringFetch.push(jid)
388
363
  }
389
364
  if (jidsRequiringFetch.length) {
390
-
365
+ // LID if mapped, otherwise original; interop JIDs pass through as-is
391
366
  const wireJids = [
392
367
  ...jidsRequiringFetch.filter(jid => !!(0, WABinary_1.isLidUser)(jid) || !!(0, WABinary_1.isHostedLidUser)(jid)),
393
368
  ...(
@@ -430,7 +405,7 @@ const makeMessagesSocket = config => {
430
405
  }
431
406
  await (0, Utils_1.parseAndInjectE2ESessions)(result, signalRepository)
432
407
  didFetchNewSession = true
433
-
408
+ // Cache fetched sessions using wire JIDs
434
409
  for (const wireJid of wireJids) {
435
410
  const signalId = signalRepository.jidToSignalProtocolAddress(wireJid)
436
411
  peerSessionsCache.set(signalId, true)
@@ -439,7 +414,7 @@ const makeMessagesSocket = config => {
439
414
  return didFetchNewSession
440
415
  }
441
416
  const sendPeerDataOperationMessage = async pdoMessage => {
442
-
417
+ //TODO: for later, abstract the logic to send a Peer Message instead of just PDO - useful for App State Key Resync with phone
443
418
  if (!authState.creds.me?.id) {
444
419
  throw new boom_1.Boom('Not authenticated')
445
420
  }
@@ -532,9 +507,7 @@ const makeMessagesSocket = config => {
532
507
  additionalNodes,
533
508
  useUserDevicesCache,
534
509
  useCachedGroupMetadata,
535
- statusJidList,
536
- statusPrivacy,
537
- AI = false
510
+ statusJidList
538
511
  }
539
512
  ) => {
540
513
  const meId = authState.creds.me.id
@@ -550,7 +523,8 @@ const makeMessagesSocket = config => {
550
523
  const isInterop = (0, WABinary_1.isInteropUser)(jid)
551
524
  const isGroupOrStatus = isGroup || isStatus
552
525
  const finalJid = jid
553
- 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)
554
528
  useUserDevicesCache = useUserDevicesCache !== false
555
529
  useCachedGroupMetadata = useCachedGroupMetadata !== false && !isStatus
556
530
  const participants = []
@@ -573,18 +547,6 @@ const makeMessagesSocket = config => {
573
547
 
574
548
  const buttonType = getButtonType(messages)
575
549
  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
- }
588
550
  await authState.keys.transaction(async () => {
589
551
  const mediaType = getMediaType(message)
590
552
  if (mediaType) {
@@ -616,24 +578,35 @@ const makeMessagesSocket = config => {
616
578
  (0, Utils_1.normalizeMessageContent)(message)?.pinInChatMessage ||
617
579
  (0, Utils_1.normalizeMessageContent)(message)?.reactionMessage
618
580
  ) {
619
- extraAttrs['decrypt-fail'] = 'hide'
581
+ extraAttrs['decrypt-fail'] = 'hide' // todo: expand for reactions and other types
620
582
  }
621
583
  if (isGroupOrStatus && !isRetryResend) {
622
584
  const [groupData, senderKeyMap] = await Promise.all([
623
585
  (async () => {
624
- let groupData = useCachedGroupMetadata && cachedGroupMetadata ? await cachedGroupMetadata(jid) : undefined
625
- 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) {
626
593
  logger.trace({ jid, participants: groupData.participants.length }, 'using cached group metadata')
627
594
  } else if (!isStatus) {
628
- groupData = await groupMetadata(jid)
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
629
602
  }
630
603
  return groupData
631
604
  })(),
632
605
  (async () => {
633
606
  if (!participant && !isStatus) {
634
-
635
-
636
- const result = await authState.keys.get('sender-key-memory', [jid])
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?
637
610
  return result[jid] || {}
638
611
  }
639
612
  return {}
@@ -817,8 +790,8 @@ const makeMessagesSocket = config => {
817
790
  !(0, WABinary_1.isHostedPnUser)(deviceJid) &&
818
791
  device.device !== 99
819
792
  ) {
820
-
821
-
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
822
795
  senderKeyRecipients.push(deviceJid)
823
796
  senderKeyMap[deviceJid] = true
824
797
  }
@@ -844,8 +817,8 @@ const makeMessagesSocket = config => {
844
817
  })
845
818
  await authState.keys.set({ 'sender-key-memory': { [jid]: senderKeyMap } })
846
819
  } else {
847
-
848
-
820
+ // ADDRESSING CONSISTENCY: Match own identity to conversation context
821
+ // TODO: investigate if this is true
849
822
  let ownId = meId
850
823
  if (isLid && meLid) {
851
824
  ownId = meLid
@@ -865,9 +838,9 @@ const makeMessagesSocket = config => {
865
838
  devices.push({
866
839
  user,
867
840
  device: 0,
868
- jid: (0, WABinary_1.jidEncode)(user, targetUserServer, 0)
841
+ jid: (0, WABinary_1.jidEncode)(user, targetUserServer, 0) // rajeh, todo: this entire logic is convoluted and weird.
869
842
  })
870
-
843
+ // Interop contacts don't receive a copy to own devices — native WA sends only one flat <enc>
871
844
  if (user !== ownUser && !isInterop) {
872
845
  const ownUserServer = isLid ? 'lid' : 's.whatsapp.net'
873
846
  const ownUserForAddressing =
@@ -879,14 +852,14 @@ const makeMessagesSocket = config => {
879
852
  })
880
853
  }
881
854
  if (additionalAttributes?.['category'] !== 'peer' && !isInterop) {
882
-
855
+ // Clear placeholders and enumerate actual devices
883
856
  devices.length = 0
884
-
857
+ // Use conversation-appropriate sender identity
885
858
  const senderIdentity =
886
859
  isLid && meLid
887
860
  ? (0, WABinary_1.jidEncode)((0, WABinary_1.jidDecode)(meLid)?.user, 'lid', undefined)
888
861
  : (0, WABinary_1.jidEncode)((0, WABinary_1.jidDecode)(meId)?.user, 's.whatsapp.net', undefined)
889
-
862
+ // Enumerate devices for sender and target with consistent addressing
890
863
  const sessionDevices = await getUSyncDevices([senderIdentity, jid], true, false)
891
864
  devices.push(...sessionDevices)
892
865
  logger.debug(
@@ -904,26 +877,25 @@ const makeMessagesSocket = config => {
904
877
  const { user: mePnUser } = (0, WABinary_1.jidDecode)(meId)
905
878
  const { user: meLidUser } = meLid ? (0, WABinary_1.jidDecode)(meLid) : { user: null }
906
879
  for (const { user, jid } of devices) {
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
- }
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
+ }
921
893
  await assertSessions(allRecipients)
922
894
  const [
923
895
  { nodes: meNodes, shouldIncludeDeviceIdentity: s1 },
924
896
  { nodes: otherNodes, shouldIncludeDeviceIdentity: s2 }
925
897
  ] = await Promise.all([
926
-
898
+ // For own devices: use DSM if available (1:1 chats only)
927
899
  createParticipantNodes(meRecipients, meMsg || message, extraAttrs),
928
900
  createParticipantNodes(otherRecipients, message, extraAttrs, meMsg)
929
901
  ])
@@ -934,40 +906,15 @@ const makeMessagesSocket = config => {
934
906
  }
935
907
  shouldIncludeDeviceIdentity = shouldIncludeDeviceIdentity || s1 || s2
936
908
  }
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
- }
962
909
  if (participants.length) {
963
910
  if (additionalAttributes?.['category'] === 'peer') {
964
911
  const peerNode = participants[0]?.content?.[0]
965
912
  if (peerNode) {
966
- binaryNodeContent.push(peerNode)
913
+ binaryNodeContent.push(peerNode) // push only enc
967
914
  }
968
915
  } else if (isInterop) {
969
-
970
-
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.
971
918
  const recipientNode = participants.find(p => (0, WABinary_1.isInteropUser)(p?.attrs?.jid))
972
919
  const encNode = (recipientNode ?? participants[0])?.content?.[0]
973
920
  if (encNode) {
@@ -991,22 +938,6 @@ const makeMessagesSocket = config => {
991
938
  },
992
939
  content: binaryNodeContent
993
940
  }
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
- }
1010
941
  if (shouldIncludeDeviceIdentity) {
1011
942
  stanza.content.push({
1012
943
  tag: 'device-identity',
@@ -1023,14 +954,6 @@ const makeMessagesSocket = config => {
1023
954
  })
1024
955
  }
1025
956
 
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
-
1034
957
  if (pollMessage || messages.eventMessage) {
1035
958
  stanza.content.push({
1036
959
  tag: 'meta',
@@ -1088,30 +1011,30 @@ const makeMessagesSocket = config => {
1088
1011
  stanza.content.push(buttonsNode)
1089
1012
  }
1090
1013
  }
1091
- if (!AI && (0, WABinary_1.isPnUser)(destinationJid)) {
1014
+ if (!config.aiLabel && (0, WABinary_1.isPnUser)(destinationJid)) {
1092
1015
  const alreadyHasBizBot =
1093
1016
  WABinary_1.getBinaryFilteredBizBot(additionalNodes || []) ||
1094
1017
  WABinary_1.getBinaryFilteredBizBot(stanza.content)
1095
1018
  if (!alreadyHasBizBot) {
1096
1019
  stanza.content.push({ tag: 'bot', attrs: { biz_bot: '1' } })
1097
1020
  }
1098
- } else if (AI && !isGroup && !isStatus && !isNewsletter) {
1021
+ } else if (config.aiLabel && !isGroup && !isStatus && !isNewsletter) {
1099
1022
  const existingBizBot = WABinary_1.getBinaryFilteredBizBot(additionalNodes || [])
1100
1023
  if (!existingBizBot) {
1101
1024
  stanza.content.push({ tag: 'bot', attrs: { biz_bot: '1' } })
1102
1025
  }
1103
1026
  }
1104
-
1027
+ // WA Web never attaches tctoken to peer (AppStateSync) messages — server rejects with 479
1105
1028
  const isPeerMessage = additionalAttributes?.['category'] === 'peer'
1106
1029
  const is1on1Send = !isGroup && !isRetryResend && !isStatus && !isNewsletter && !isPeerMessage
1107
-
1030
+ // Resolve destination to LID for tctoken storage — matches Signal session key pattern
1108
1031
  const tcTokenJid = is1on1Send
1109
1032
  ? await (0, tc_token_utils_1.resolveTcTokenJid)(destinationJid, getLIDForPN)
1110
1033
  : destinationJid
1111
1034
  const contactTcTokenData = is1on1Send ? await authState.keys.get('tctoken', [tcTokenJid]) : {}
1112
1035
  const existingTokenEntry = contactTcTokenData[tcTokenJid]
1113
1036
  let tcTokenBuffer = existingTokenEntry?.token
1114
-
1037
+ // Treat expired tokens the same as missing — clear from cache
1115
1038
  if (tcTokenBuffer?.length && (0, tc_token_utils_1.isTcTokenExpired)(existingTokenEntry?.timestamp)) {
1116
1039
  logger.debug({ jid: destinationJid, timestamp: existingTokenEntry?.timestamp }, 'tctoken expired, clearing')
1117
1040
  tcTokenBuffer = undefined
@@ -1132,38 +1055,17 @@ const makeMessagesSocket = config => {
1132
1055
  content: tcTokenBuffer
1133
1056
  })
1134
1057
  }
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
- }
1156
1058
  if (additionalNodes && additionalNodes.length > 0 && !didPushAdditional) {
1157
1059
  stanza.content.push(...additionalNodes)
1158
1060
  }
1159
1061
  logger.debug({ msgId }, `sending message to ${participants.length} devices`)
1160
1062
  await sendNode(stanza)
1161
-
1162
-
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.
1163
1065
  if (message.messageContextInfo?.messageSecret) {
1164
1066
  setBotMessageSecret(msgId, message.messageContextInfo.messageSecret, destinationJid)
1165
1067
  }
1166
-
1068
+ // Fire-and-forget: issue our token to the contact AFTER message send.
1167
1069
  const isProtocolMsg = !!(0, Utils_1.normalizeMessageContent)(message)?.protocolMessage
1168
1070
  const isBotOrPSA =
1169
1071
  destinationJid === WABinary_1.PSA_WID ||
@@ -1214,7 +1116,7 @@ const makeMessagesSocket = config => {
1214
1116
  inFlightTcTokenIssuance.delete(tcTokenJid)
1215
1117
  })
1216
1118
  }
1217
-
1119
+ // Add message to retry cache if enabled
1218
1120
  if (messageRetryManager && !participant) {
1219
1121
  messageRetryManager.addRecentMessage(destinationJid, msgId, message)
1220
1122
  }
@@ -1336,7 +1238,7 @@ const makeMessagesSocket = config => {
1336
1238
  }
1337
1239
  }
1338
1240
  } else if (nativeFlow && nativeFlowSpecials.includes(firstButtonName)) {
1339
-
1241
+ // Only works for WhatsApp Original, not WhatsApp Business
1340
1242
  return {
1341
1243
  tag: 'biz',
1342
1244
  attrs: {
@@ -1370,7 +1272,7 @@ const makeMessagesSocket = config => {
1370
1272
  ]
1371
1273
  }
1372
1274
  } else if (nativeFlow || message.buttonsMessage) {
1373
-
1275
+ // It works for whatsapp original and whatsapp business
1374
1276
  return {
1375
1277
  tag: 'biz',
1376
1278
  attrs: {
@@ -1466,7 +1368,7 @@ const makeMessagesSocket = config => {
1466
1368
  }
1467
1369
  const getPrivacyTokens = issuePrivacyTokens
1468
1370
  const waUploadToServer = (0, Utils_1.getWAUploadToServer)(config, refreshMediaConn)
1469
- const badzzne2 = new interactive_handler_1.badzz88(waUploadToServer, relayMessage, config, sock)
1371
+ const interactiveHandler = new interactive_handler_1.InteractiveMessageHandler(waUploadToServer, relayMessage, config, sock)
1470
1372
  const waitForMsgMediaUpdate = (0, Utils_1.bindWaitForEvent)(ev, 'messages.media-update')
1471
1373
  return {
1472
1374
  ...sock,
@@ -1619,7 +1521,6 @@ const makeMessagesSocket = config => {
1619
1521
  mediaHandle = up.handle
1620
1522
  return up
1621
1523
  },
1622
- mediaAbProps: authState.creds.mediaAbProps,
1623
1524
  ...options
1624
1525
  }
1625
1526
  )
@@ -1641,7 +1542,6 @@ const makeMessagesSocket = config => {
1641
1542
  mediaHandle = up.handle
1642
1543
  return up
1643
1544
  },
1644
- mediaAbProps: authState.creds.mediaAbProps,
1645
1545
  ...options
1646
1546
  }
1647
1547
  )
@@ -1661,7 +1561,7 @@ const makeMessagesSocket = config => {
1661
1561
  },
1662
1562
 
1663
1563
  sendStatusMention: async (content, jids = []) => {
1664
- return await badzzne2.sendStatusWhatsApp(content, jids)
1564
+ return await interactiveHandler.sendStatusWhatsApp(content, jids)
1665
1565
  },
1666
1566
  sendTable: async (jid, title, headers, rows, quoted, options = {}) => {
1667
1567
  const { message, messageId } = message_composer_1.generateTableContent(title, headers, rows, quoted, options)
@@ -1716,7 +1616,9 @@ const makeMessagesSocket = config => {
1716
1616
  },
1717
1617
  sendMessage: async (jid, content, options = {}) => {
1718
1618
  const userJid = authState.creds.me.id
1719
-
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 ──────
1720
1622
  if (
1721
1623
  typeof content === 'object' &&
1722
1624
  Array.isArray(content.buttons) &&
@@ -1741,181 +1643,6 @@ const makeMessagesSocket = config => {
1741
1643
  const { buttons, headerType, viewOnce, ...rest } = content
1742
1644
  content = { ...rest, interactiveButtons }
1743
1645
  }
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
- }
1919
1646
  if (
1920
1647
  typeof content === 'object' &&
1921
1648
  'disappearingMessagesInChat' in content &&
@@ -1930,25 +1657,25 @@ const makeMessagesSocket = config => {
1930
1657
  : 0
1931
1658
  : disappearingMessagesInChat
1932
1659
  await groupToggleEphemeral(jid, value)
1933
- } else if (badzzne2.detectType(content)) {
1660
+ } else if (interactiveHandler.detectType(content)) {
1934
1661
  const { quoted } = options
1935
- const messageType = badzzne2.detectType(content)
1662
+ const messageType = interactiveHandler.detectType(content)
1936
1663
  switch (messageType) {
1937
1664
  case 'PAYMENT': {
1938
- const paymentContent = await badzzne2.handlePayment(content, quoted)
1665
+ const paymentContent = await interactiveHandler.handlePayment(content, quoted)
1939
1666
  return await relayMessage(jid, paymentContent, {
1940
- messageId: (0, Utils_1.generateMessageIDV2)(userJid)
1667
+ messageId: mId
1941
1668
  })
1942
1669
  }
1943
1670
  case 'PRODUCT': {
1944
- const productContent = await badzzne2.handleProduct(content, jid, quoted)
1671
+ const productContent = await interactiveHandler.handleProduct(content, jid, quoted)
1945
1672
  const productMsg = await (0, Utils_1.generateWAMessageFromContent)(jid, productContent, { quoted, userJid })
1946
1673
  return await relayMessage(jid, productMsg.message, {
1947
1674
  messageId: productMsg.key.id
1948
1675
  })
1949
1676
  }
1950
1677
  case 'INTERACTIVE': {
1951
- const interactiveContent = await badzzne2.handleInteractive(content, jid, quoted)
1678
+ const interactiveContent = await interactiveHandler.handleInteractive(content, jid, quoted)
1952
1679
  const interactiveMsg = await (0, Utils_1.generateWAMessageFromContent)(jid, interactiveContent, {
1953
1680
  quoted,
1954
1681
  userJid
@@ -1957,25 +1684,21 @@ const makeMessagesSocket = config => {
1957
1684
  messageId: interactiveMsg.key.id
1958
1685
  })
1959
1686
  }
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
- }
1967
1687
  case 'ALBUM':
1968
- return await badzzne2.handleAlbum(content, jid, quoted)
1688
+ return await interactiveHandler.handleAlbum(content, jid, quoted)
1969
1689
  case 'EVENT':
1970
- return await badzzne2.handleEvent(content, jid, quoted)
1690
+ return await interactiveHandler.handleEvent(content, jid, quoted)
1971
1691
  case 'POLL_RESULT':
1972
- return await badzzne2.handlePollResult(content, jid, quoted)
1692
+ return await interactiveHandler.handlePollResult(content, jid, quoted)
1973
1693
  case 'GROUP_STORY':
1974
- 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)
1975
1699
  }
1976
1700
  } else {
1977
1701
  let mediaHandle
1978
- const { ai, ...optionsWithoutAI } = options
1979
1702
  const fullMsg = await (0, Utils_1.generateWAMessage)(jid, content, {
1980
1703
  logger,
1981
1704
  userJid,
@@ -1989,6 +1712,7 @@ const makeMessagesSocket = config => {
1989
1712
  logger,
1990
1713
  uploadImage: generateHighQualityLinkPreview ? waUploadToServer : undefined
1991
1714
  }),
1715
+ //TODO: CACHE
1992
1716
  getProfilePicUrl: sock.profilePictureUrl,
1993
1717
  getCallLink: sock.createCallLink,
1994
1718
  newsletter: (0, WABinary_1.isJidNewsletter)(jid),
@@ -2002,10 +1726,8 @@ const makeMessagesSocket = config => {
2002
1726
  },
2003
1727
  mediaCache: config.mediaCache,
2004
1728
  options: config.options,
2005
- messageId: (0, Utils_1.generateMessageIDV2)(sock.user?.id),
2006
-
2007
- mediaAbProps: authState.creds.mediaAbProps,
2008
- ...optionsWithoutAI
1729
+ messageId: mId,
1730
+ ...options
2009
1731
  })
2010
1732
  if (!mediaHandle) {
2011
1733
  const msgContent = fullMsg.message
@@ -2032,9 +1754,6 @@ const makeMessagesSocket = config => {
2032
1754
  } else {
2033
1755
  additionalAttributes.edit = '7'
2034
1756
  }
2035
- if (content.delete?.server_id) {
2036
- additionalAttributes.server_id = String(content.delete.server_id)
2037
- }
2038
1757
  } else if (isEditMsg) {
2039
1758
  additionalAttributes.edit = '1'
2040
1759
  } else if (isPinMsg) {
@@ -2073,9 +1792,7 @@ const makeMessagesSocket = config => {
2073
1792
  useCachedGroupMetadata: options.useCachedGroupMetadata,
2074
1793
  additionalAttributes,
2075
1794
  statusJidList: options.statusJidList,
2076
- statusPrivacy: options.statusPrivacy,
2077
- additionalNodes,
2078
- AI: ai || false
1795
+ additionalNodes
2079
1796
  })
2080
1797
  if (config.emitOwnEvents) {
2081
1798
  process.nextTick(async () => {
@@ -2085,71 +1802,52 @@ const makeMessagesSocket = config => {
2085
1802
  return fullMsg
2086
1803
  }
2087
1804
  },
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
- }
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
+ }
2153
1851
  }
2154
1852
  }
2155
1853
  exports.makeMessagesSocket = makeMessagesSocket