@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
@@ -11,12 +11,16 @@ exports.decryptMessageNode =
11
11
  void 0
12
12
  exports.decodeMessageNode = decodeMessageNode
13
13
  const boom_1 = require('@hapi/boom')
14
+ const index_js_1 = require('../../WAProto/index.js')
14
15
  const WAProto_1 = require('../../WAProto/index.js')
15
16
  const WABinary_1 = require('../WABinary')
16
17
  const generics_1 = require('./generics')
17
18
  const meta_ai_msmsg_1 = require('./meta-ai-msmsg')
18
19
  const messages_1 = require('./messages')
19
20
  const MAX_SECRETS_PER_CHAT = 20
21
+ // Module-level map: outgoing @bot message ID → messageSecret
22
+ // Populated when we receive the outgoing pkmsg/msg to @bot (which contains messageContextInfo.messageSecret)
23
+ // Consumed when the msmsg response from @bot arrives and needs decryption
20
24
  const botMessageSecrets = new Map()
21
25
  const botRecentSecretsByChat = new Map()
22
26
  const pushRecentChatSecret = (chatJid, id, secretBuf) => {
@@ -53,7 +57,7 @@ const getDecryptionJid = async (sender, repository) => {
53
57
  (0, WABinary_1.isHostedLidUser)(sender) ||
54
58
  (0, WABinary_1.isInteropUser)(sender)
55
59
  ) {
56
-
60
+ // LID and interop JIDs are session keys themselves — no PN mapping lookup needed
57
61
  return sender
58
62
  }
59
63
  const mapped = await repository.lidMapping.getLIDForPN(sender)
@@ -61,11 +65,12 @@ const getDecryptionJid = async (sender, repository) => {
61
65
  }
62
66
  exports.getDecryptionJid = getDecryptionJid
63
67
  const storeMappingFromEnvelope = async (stanza, sender, repository, decryptionJid, logger) => {
68
+ // TODO: Handle hosted IDs
64
69
  const { senderAlt } = (0, exports.extractAddressingContext)(stanza)
65
70
  if (
66
71
  senderAlt &&
67
- ((0, WABinary_1.isLidUser)(senderAlt) || (0, WABinary_1.isHostedLidUser)(senderAlt)) &&
68
- ((0, WABinary_1.isPnUser)(sender) || (0, WABinary_1.isHostedPnUser)(sender)) &&
72
+ (0, WABinary_1.isLidUser)(senderAlt) &&
73
+ (0, WABinary_1.isPnUser)(sender) &&
69
74
  decryptionJid === sender
70
75
  ) {
71
76
  try {
@@ -79,14 +84,17 @@ const storeMappingFromEnvelope = async (stanza, sender, repository, decryptionJi
79
84
  }
80
85
  exports.NO_MESSAGE_FOUND_ERROR_TEXT = 'Message absent from node'
81
86
  exports.MISSING_KEYS_ERROR_TEXT = 'Key used already or never filled'
82
-
87
+ /**
88
+ * Server-side error codes returned in ack stanzas (server → client).
89
+ * Distinct from the client-side NackReason enum.
90
+ */
83
91
  exports.SERVER_ERROR_CODES = {
84
-
92
+ /** 1:1 message missing privacy token (tctoken) */
85
93
  MissingTcToken: '463',
86
-
94
+ /** Stanza validation failure (SMAX_INVALID) — likely stale device session */
87
95
  SmaxInvalid: '479'
88
96
  }
89
-
97
+ // Retry configuration for failed decryption
90
98
  exports.DECRYPTION_RETRY_CONFIG = {
91
99
  maxRetries: 3,
92
100
  baseDelayMs: 100,
@@ -113,19 +121,19 @@ const extractAddressingContext = stanza => {
113
121
  const sender = stanza.attrs.participant || stanza.attrs.from
114
122
  const addressingMode = stanza.attrs.addressing_mode || (sender?.endsWith('lid') ? 'lid' : 'pn')
115
123
  if (addressingMode === 'lid') {
116
-
117
-
124
+ // Message is LID-addressed: sender is LID, extract corresponding PN
125
+ // without device data
118
126
  senderAlt = stanza.attrs.participant_pn || stanza.attrs.sender_pn || stanza.attrs.peer_recipient_pn
119
127
  recipientAlt = stanza.attrs.recipient_pn
120
-
121
-
128
+ // with device data
129
+ //if (sender && senderAlt) senderAlt = transferDevice(sender, senderAlt)
122
130
  } else {
123
-
124
-
131
+ // Message is PN-addressed: sender is PN, extract corresponding LID
132
+ // without device data
125
133
  senderAlt = stanza.attrs.participant_lid || stanza.attrs.sender_lid || stanza.attrs.peer_recipient_lid
126
134
  recipientAlt = stanza.attrs.recipient_lid
127
-
128
-
135
+ //with device data
136
+ //if (sender && senderAlt) senderAlt = transferDevice(sender, senderAlt)
129
137
  }
130
138
  return {
131
139
  addressingMode,
@@ -134,50 +142,15 @@ const extractAddressingContext = stanza => {
134
142
  }
135
143
  }
136
144
  exports.extractAddressingContext = extractAddressingContext
137
-
145
+ /**
146
+ * Decode the received node as a message.
147
+ * @note this will only parse the message, not decrypt it
148
+ */
138
149
  function decodeMessageNode(stanza, meId, meLid) {
139
- let nodey = []
140
150
  let msgType
141
151
  let chatId
142
152
  let author
143
153
  let fromMe = false
144
- for (const { tag, attrs, content } of stanza.content) {
145
- const clean = v => {
146
- if (Array.isArray(v)) return v.map(clean);
147
-
148
- if (v && typeof v === "object") {
149
- const keys = Object.keys(v);
150
-
151
- if (
152
- keys.length &&
153
- keys.every(k => /^\d+$/.test(k))
154
- ) {
155
- return "[bytes]";
156
- }
157
-
158
- if (
159
- v.type === "Buffer" &&
160
- Array.isArray(v.data)
161
- ) {
162
- return "[bytes]";
163
- }
164
-
165
- return Object.fromEntries(
166
- Object.entries(v).map(([k, val]) => [k, clean(val)])
167
- );
168
- }
169
-
170
- return v;
171
- }
172
- if (tag !== "plaintext" && tag !== "enc") {
173
- nodey.push(clean({
174
- tag: tag,
175
- attrs: attrs,
176
- content: content
177
- }))
178
- }
179
- }
180
-
181
154
  const msgId = stanza.attrs.id
182
155
  const from = stanza.attrs.from
183
156
  const participant = stanza.attrs.participant
@@ -236,9 +209,9 @@ content: content
236
209
  msgType = 'newsletter'
237
210
  chatId = from
238
211
  author = from
239
-
240
-
241
-
212
+ // if (isMe(from) || isMeLid(from)) {
213
+ // fromMe = true
214
+ // }
242
215
 
243
216
  fromMe = (0, WABinary_1.isJidNewsletter)(from)
244
217
  ? !!stanza.attrs?.is_sender
@@ -246,8 +219,8 @@ content: content
246
219
  ? (0, WABinary_1.areJidsSameUser)(from, meLid)
247
220
  : (0, WABinary_1.areJidsSameUser)(from, meId)
248
221
  } else if ((0, WABinary_1.isInteropUser)(from)) {
249
-
250
-
222
+ // Message from an interop contact (Facebook Messenger / Instagram via WA bridge).
223
+ // Treat as regular 1:1 chat — same Signal decrypt path as @s.whatsapp.net / @lid.
251
224
  msgType = 'chat'
252
225
  chatId = from
253
226
  author = from
@@ -255,7 +228,7 @@ content: content
255
228
  } else {
256
229
  throw new boom_1.Boom('Unknown message type', { data: stanza })
257
230
  }
258
-
231
+ // Interop stanzas (BirdyChat/Haiket) use display_name instead of notify
259
232
  const pushname = stanza?.attrs?.notify ?? stanza?.attrs?.display_name
260
233
  const key = {
261
234
  remoteJid: chatId,
@@ -279,12 +252,10 @@ content: content
279
252
  broadcast: (0, WABinary_1.isJidBroadcast)(from),
280
253
  newsletter: (0, WABinary_1.isJidNewsletter)(from),
281
254
  StanzaAttrs: stanza.attrs,
282
- nodes: nodey,
283
- Owner: 'badzz88'
284
-
255
+ Owner: 'xazbails' // Non-WhatsApp attribute
285
256
  }
286
257
  if (key.fromMe) {
287
- fullMessage.status = WAProto_1.proto.WebMessageInfo.Status.SERVER_ACK
258
+ fullMessage.status = index_js_1.proto.WebMessageInfo.Status.SERVER_ACK
288
259
  }
289
260
  if (msgType === 'newsletter') {
290
261
  fullMessage.newsletter_server_id = +stanza.attrs?.server_id
@@ -327,7 +298,7 @@ const decryptMessageNode = (stanza, meId, meLid, repository, logger) => {
327
298
  metaTargetSenderJid = attrs.target_sender_jid
328
299
  }
329
300
  if (tag === 'bot' && attrs && 'edit_target_id' in attrs) {
330
- botEditTargetId = attrs.edit_target_id
301
+ botEditTargetId = attrs.edit_target_id // Can be '' for 'first' type
331
302
  }
332
303
  if (tag === 'bot' && (attrs === null || attrs === void 0 ? void 0 : attrs.edit)) {
333
304
  botType = attrs.edit
@@ -335,27 +306,14 @@ const decryptMessageNode = (stanza, meId, meLid, repository, logger) => {
335
306
  }
336
307
  }
337
308
 
338
-
339
-
340
-
341
- const _isGroupEnc = n => n.tag === 'enc' && (n.attrs?.type === 'skmsg' || n.attrs?.type === 'frskmsg')
342
- const _stanzaContent = [
343
- ...stanza.content.filter(n => !_isGroupEnc(n)),
344
- ...stanza.content.filter(n => _isGroupEnc(n))
345
- ]
346
- for (const { tag, attrs, content } of _stanzaContent) {
309
+ for (const { tag, attrs, content } of stanza.content) {
347
310
  if (tag === 'verified_name' && content instanceof Uint8Array) {
348
- const cert = WAProto_1.proto.VerifiedNameCertificate.decode(content)
349
- const details = WAProto_1.proto.VerifiedNameCertificate.Details.decode(cert.details)
311
+ const cert = index_js_1.proto.VerifiedNameCertificate.decode(content)
312
+ const details = index_js_1.proto.VerifiedNameCertificate.Details.decode(cert.details)
350
313
  fullMessage.verifiedBizName = details.verifiedName
351
-
352
- if (attrs?.verified_level) {
353
- fullMessage.verifiedNameLevel = attrs.verified_level
354
- }
355
314
  }
356
315
  if (tag === 'unavailable' && attrs.type === 'view_once') {
357
- fullMessage.key.isViewOnce = true
358
- fullMessage.messageStubType = WAProto_1.proto.WebMessageInfo.StubType.VIEWED_ONCE
316
+ fullMessage.key.isViewOnce = true // TODO: remove from here and add a STUB TYPE
359
317
  }
360
318
  if (attrs.count && tag === 'enc') {
361
319
  fullMessage.retryCount = Number(attrs.count)
@@ -370,15 +328,12 @@ const decryptMessageNode = (stanza, meId, meLid, repository, logger) => {
370
328
  let msgBuffer
371
329
  const decryptionJid = await (0, exports.getDecryptionJid)(author, repository)
372
330
  if (tag !== 'plaintext') {
373
- if ((0, WABinary_1.isHostedPnUser)(decryptionJid) || (0, WABinary_1.isHostedLidUser)(decryptionJid)) {
374
- fullMessage.isHostedDevice = true
375
- }
331
+ // TODO: Handle hosted devices
376
332
  await storeMappingFromEnvelope(stanza, author, repository, decryptionJid, logger)
377
333
  }
378
334
  try {
379
335
  const e2eType = tag === 'plaintext' ? 'plaintext' : attrs.type
380
336
  switch (e2eType) {
381
- case 'frskmsg':
382
337
  case 'skmsg':
383
338
  msgBuffer = await repository.decryptGroupMessage({
384
339
  group: sender,
@@ -387,39 +342,17 @@ const decryptMessageNode = (stanza, meId, meLid, repository, logger) => {
387
342
  })
388
343
  break
389
344
 
390
- case 'story_reply':
391
- case 'feed_reshare':
392
- case 'native_flow_response':
393
- case 'companion_enc_static':
394
- case 'avatar_sticker':
395
- case 'genai_sticker':
396
- case 'account_authentication_request':
397
- case 'motion_video':
398
- case 'motion_photo':
399
345
  case 'pkmsg':
400
- case 'msg': {
401
- const _unicastType =
402
- e2eType === 'story_reply' ||
403
- e2eType === 'feed_reshare' ||
404
- e2eType === 'native_flow_response' ||
405
- e2eType === 'companion_enc_static' ||
406
- e2eType === 'avatar_sticker' ||
407
- e2eType === 'genai_sticker' ||
408
- e2eType === 'account_authentication_request' ||
409
- e2eType === 'motion_video' ||
410
- e2eType === 'motion_photo'
411
- ? 'msg'
412
- : e2eType
346
+ case 'msg':
413
347
  msgBuffer = await repository.decryptMessage({
414
348
  jid: decryptionJid,
415
- type: _unicastType,
349
+ type: e2eType,
416
350
  ciphertext: content
417
351
  })
418
352
  break
419
- }
420
- case 'msmsg':
421
-
422
-
353
+ case 'msmsg': //Message Secret Message
354
+ // null = no bot node (non-streaming), 'full'/'last' = complete response
355
+ // 'first' = streaming partial response, intentionally skipped
423
356
  if (botType !== null && !['full', 'last'].includes(botType)) break
424
357
  const secretIdCandidates = [botEditTargetId, metaTargetId, fullMessage.key?.id].filter(Boolean)
425
358
  const secretCandidates = []
@@ -455,11 +388,17 @@ const decryptMessageNode = (stanza, meId, meLid, repository, logger) => {
455
388
  participant: author,
456
389
  meId: metaTargetSenderJid || `${meLid.split(`:`)[0]}@lid`,
457
390
  meLid,
391
+ conversationJid: sender,
392
+ senderJid: metaTargetSenderJid,
393
+ botType,
458
394
  botEditTargetId,
459
395
  metaTargetId,
460
- stanzaId: stanza.attrs?.id
396
+ stanzaId: stanza.attrs?.id,
397
+ targetId: botEditTargetId || metaTargetId || stanza.attrs?.id,
398
+ targetIdCandidates: secretIdCandidates
461
399
  }
462
400
  let decryptErr
401
+ const candidateAttemptSummaries = []
463
402
  for (const candidate of secretCandidates) {
464
403
  try {
465
404
  msgBuffer = await (0, meta_ai_msmsg_1.decryptMsmsgBotMessage)(candidate.secret, helperKey, msMsg)
@@ -467,16 +406,24 @@ const decryptMessageNode = (stanza, meId, meLid, repository, logger) => {
467
406
  break
468
407
  } catch (e) {
469
408
  decryptErr = e
409
+ if (Array.isArray(e?.attemptedStrategies) && e.attemptedStrategies.length) {
410
+ candidateAttemptSummaries.push({
411
+ secretSource: candidate.source,
412
+ attemptedStrategies: e.attemptedStrategies
413
+ })
414
+ }
470
415
  }
471
416
  }
472
- if (!msgBuffer && decryptErr) {
417
+ if (!msgBuffer && candidateAttemptSummaries.length) {
473
418
  logger.warn(
474
419
  {
475
420
  secretCandidateSources: secretCandidates.map(candidate => candidate.source),
476
- cause: decryptErr?.message
421
+ attemptsBySecret: candidateAttemptSummaries
477
422
  },
478
423
  'msmsg: helper decryption failed for all candidate secrets'
479
424
  )
425
+ }
426
+ if (!msgBuffer && decryptErr) {
480
427
  throw decryptErr
481
428
  }
482
429
  }
@@ -499,16 +446,18 @@ const decryptMessageNode = (stanza, meId, meLid, repository, logger) => {
499
446
  let msg =
500
447
  e2eType === 'msmsg'
501
448
  ? (0, meta_ai_msmsg_1.decodeDecryptedMsmsgMessage)(msgBuffer)
502
- : WAProto_1.proto.Message.decode(msgToDecode)
449
+ : index_js_1.proto.Message.decode(msgToDecode)
450
+ if (false) {
451
+ }
503
452
  const outerMessageContextInfo = msg.messageContextInfo
504
453
  msg = msg.deviceSentMessage?.message || msg
505
-
506
-
454
+ // deviceSentMessage.message may not carry messageContextInfo (e.g. messageSecret for @bot)
455
+ // even though the outer wrapper does — preserve it
507
456
  if (outerMessageContextInfo && !msg.messageContextInfo) {
508
457
  msg.messageContextInfo = outerMessageContextInfo
509
458
  }
510
459
  if (msg.senderKeyDistributionMessage) {
511
-
460
+ //eslint-disable-next-line max-depth
512
461
  try {
513
462
  await repository.processSenderKeyDistributionMessage({
514
463
  authorJid: author,
@@ -518,200 +467,12 @@ const decryptMessageNode = (stanza, meId, meLid, repository, logger) => {
518
467
  logger.error({ key: fullMessage.key, err }, 'failed to process sender key distribution message')
519
468
  }
520
469
  }
521
- if (msg.fastRatchetKeySenderKeyDistributionMessage) {
522
-
523
- try {
524
- await repository.processSenderKeyDistributionMessage({
525
- authorJid: author,
526
- item: msg.fastRatchetKeySenderKeyDistributionMessage
527
- })
528
- } catch (err) {
529
- logger.error(
530
- { key: fullMessage.key, err },
531
- 'failed to process fast ratchet sender key distribution message'
532
- )
533
- }
534
- }
535
470
  if (fullMessage.message) {
536
471
  Object.assign(fullMessage.message, msg)
537
472
  } else {
538
473
  fullMessage.message = msg
539
474
  }
540
-
541
- if (e2eType === 'story_reply') {
542
- fullMessage.storyReply = true
543
-
544
- const quotedJid = msg.extendedTextMessage?.contextInfo?.remoteJid
545
- if (quotedJid && (0, WABinary_1.isJidStatusBroadcast)(quotedJid)) {
546
- fullMessage.storyReply = true
547
- }
548
- }
549
-
550
- if (e2eType === 'feed_reshare') {
551
- fullMessage.feedReshare = true
552
- }
553
-
554
- if (attrs.view_once === 'read' || attrs.view_once === 'write') {
555
- fullMessage.viewOnceType = attrs.view_once
556
- }
557
-
558
- if (msg.xmaMessage) {
559
- fullMessage.xma = msg.xmaMessage
560
- fullMessage.messageType = 'xma'
561
- }
562
-
563
- if (e2eType === 'native_flow_response' || msg.nativeFlowResponseMessage) {
564
- fullMessage.messageType = 'native_flow_response'
565
- if (msg.nativeFlowResponseMessage) {
566
- fullMessage.nativeFlowResponse = msg.nativeFlowResponseMessage
567
-
568
- if (msg.nativeFlowResponseMessage.name === 'md_smb_quick_reply') {
569
- fullMessage.smbQuickReply = true
570
- }
571
- }
572
- }
573
-
574
- if (msg.callPermissionRequestMessage) {
575
- fullMessage.messageType = 'call_permission_request'
576
- fullMessage.callPermissionRequest = msg.callPermissionRequestMessage
577
- }
578
-
579
- if (msg.productMessage) {
580
- fullMessage.messageType = 'product'
581
- } else if (msg.orderMessage) {
582
- fullMessage.messageType = 'order'
583
- } else if (msg.catalogMessage || msg.listMessage?.catalogType) {
584
- fullMessage.messageType = 'catalog'
585
- }
586
-
587
- if (msg.paymentMessage) {
588
- fullMessage.messageType = 'payment'
589
- const pm = msg.paymentMessage
590
- fullMessage.paymentInfo = {
591
- amount: pm.amount1000 ? pm.amount1000 / 1000 : null,
592
- currency: pm.currencyCodeIso4217 || null,
593
- status: pm.status || null,
594
- transactionTimestamp: pm.transactionTimestamp
595
- ? pm.transactionTimestamp.toNumber?.() || pm.transactionTimestamp
596
- : null,
597
- type: pm.type || null,
598
- method: pm.paymentMethod || null,
599
- futureProofed: pm.futureProofed || false
600
- }
601
- }
602
- if (msg.requestPaymentMessage) {
603
- fullMessage.messageType = 'request_payment'
604
- fullMessage.paymentRequest = {
605
- amount: msg.requestPaymentMessage.amount || null,
606
- currency: msg.requestPaymentMessage.currencyCodeIso4217 || null,
607
- expiry: msg.requestPaymentMessage.expiryTimestamp || null
608
- }
609
- }
610
- if (msg.sendPaymentMessage) {
611
- fullMessage.messageType = 'send_payment'
612
- }
613
- if (msg.cancelPaymentRequestMessage) {
614
- fullMessage.messageType = 'cancel_payment'
615
- }
616
-
617
- if (msg.stickerMessage) {
618
- if (msg.stickerMessage.isAvatar) {
619
- fullMessage.isAvatarSticker = true
620
- }
621
- if (msg.stickerMessage.isAiSticker || msg.stickerMessage.isGenAI) {
622
- fullMessage.isAiSticker = true
623
- }
624
- }
625
-
626
- if (msg.stickerPackMessage) {
627
- fullMessage.messageType = 'sticker_pack'
628
- const sp = msg.stickerPackMessage
629
- fullMessage.stickerPack = {
630
- id: sp.stickerPackId,
631
- name: sp.name,
632
-
633
- origin: sp.stickerPackOrigin,
634
- size: sp.stickerPackSize,
635
- stickers: sp.stickers || []
636
- }
637
- }
638
-
639
- if (msg.messageContextInfo?.botMetadata?.aiMediaCollectionMetadata) {
640
- fullMessage.aiMediaCollectionMetadata = {
641
- collectionId: msg.messageContextInfo.botMetadata.aiMediaCollectionMetadata.collectionId,
642
- uploadOrderIndex: msg.messageContextInfo.botMetadata.aiMediaCollectionMetadata.uploadOrderIndex
643
- }
644
- }
645
-
646
- if (msg.protocolMessage?.aiMediaCollectionMessage) {
647
- fullMessage.messageType = 'ai_media_collection'
648
- const amc = msg.protocolMessage.aiMediaCollectionMessage
649
- fullMessage.aiMediaCollection = {
650
- collectionId: amc.collectionId,
651
- expectedMediaCount: amc.expectedMediaCount
652
- }
653
- }
654
-
655
- if (msg.splitPaymentMessage) {
656
- fullMessage.messageType = 'split_payment'
657
- const sp = msg.splitPaymentMessage
658
- fullMessage.splitPayment = {
659
- splitId: sp.splitId,
660
- totalAmount: sp.totalAmount,
661
- description: sp.description,
662
- requesterJid: sp.requesterJid,
663
- participants: (sp.participants || []).map(p => ({
664
- jid: p.jid,
665
- amount: p.amount,
666
-
667
- status: p.status
668
- })),
669
- createdAtMs: sp.createdAtMs ? sp.createdAtMs.toNumber?.() || sp.createdAtMs : null
670
- }
671
- }
672
-
673
- if (msg.paymentInviteMessage) {
674
- fullMessage.messageType = 'payment_invite'
675
- const SERVICE_TYPE = { 0: 'UNKNOWN', 1: 'FBPAY', 2: 'NOVI', 3: 'UPI' }
676
- fullMessage.paymentInvite = {
677
- serviceType: SERVICE_TYPE[msg.paymentInviteMessage.serviceType] || 'UNKNOWN',
678
- expiry: msg.paymentInviteMessage.expiryTimestamp
679
- ? msg.paymentInviteMessage.expiryTimestamp.toNumber?.() || msg.paymentInviteMessage.expiryTimestamp
680
- : null,
681
- incentiveEligible: msg.paymentInviteMessage.incentiveEligible || false
682
- }
683
- }
684
-
685
- if (msg.paymentReminderMessage) {
686
- fullMessage.messageType = 'payment_reminder'
687
- }
688
-
689
- if (e2eType === 'companion_enc_static') {
690
- fullMessage.companionEncStatic = true
691
- }
692
-
693
- if (e2eType === 'avatar_sticker' || e2eType === 'genai_sticker') {
694
- fullMessage.stickerType = e2eType
695
- }
696
-
697
- if (e2eType === 'account_authentication_request' || msg.accountAuthRequestMessage) {
698
- fullMessage.messageType = 'account_auth_request'
699
- }
700
-
701
- if (e2eType === 'motion_video' || (msg.videoMessage && msg.videoMessage.motionVideo)) {
702
- fullMessage.messageType = 'motion_video'
703
- fullMessage.motionVideo = true
704
- }
705
-
706
- if (e2eType === 'motion_photo' || (msg.imageMessage && msg.imageMessage.motionPhoto)) {
707
- fullMessage.messageType = 'motion_photo'
708
- fullMessage.motionPhoto = true
709
- }
710
-
711
- if (e2eType === 'plaintext') {
712
- fullMessage.isNonE2EE = true
713
- }
714
-
475
+ // Auto-decode richResponseMessage text so m.msg.text is populated
715
476
  {
716
477
  const rich = fullMessage.message?.richResponseMessage
717
478
  if (rich && !rich.text) {
@@ -724,7 +485,7 @@ const decryptMessageNode = (stanza, meId, meLid, repository, logger) => {
724
485
  if (decoded) editedRich.text = decoded
725
486
  }
726
487
  }
727
-
488
+ // Save messageSecret for any message (AI group server may set it on any message)
728
489
  {
729
490
  const secret = msg.messageContextInfo?.messageSecret
730
491
  if (secret) {
@@ -744,21 +505,25 @@ const decryptMessageNode = (stanza, meId, meLid, repository, logger) => {
744
505
  isSessionRecordError: isSessionRecordError(err)
745
506
  }
746
507
  logger.error(errorContext, 'failed to decrypt message')
747
- fullMessage.messageStubType = WAProto_1.proto.WebMessageInfo.StubType.CIPHERTEXT
508
+ fullMessage.messageStubType = index_js_1.proto.WebMessageInfo.StubType.CIPHERTEXT
748
509
  fullMessage.messageStubParameters = [err.message.toString()]
749
510
  }
750
511
  }
751
512
  }
752
-
513
+ // if nothing was found to decrypt
753
514
  if (!decryptables && !fullMessage.key?.isViewOnce) {
754
- fullMessage.messageStubType = WAProto_1.proto.WebMessageInfo.StubType.CIPHERTEXT
515
+ fullMessage.messageStubType = index_js_1.proto.WebMessageInfo.StubType.CIPHERTEXT
755
516
  fullMessage.messageStubParameters = [exports.NO_MESSAGE_FOUND_ERROR_TEXT]
756
517
  }
757
518
  }
758
519
  }
759
520
  }
760
521
  exports.decryptMessageNode = decryptMessageNode
761
-
522
+ /**
523
+ * Decode text content from a richResponseMessage (Meta AI).
524
+ * Tries submessages first, then parses base64 JSON from unifiedResponse.data.
525
+ * Returns the extracted text string or '' on failure.
526
+ */
762
527
  function decodeRichResponseMessage(richMsg) {
763
528
  try {
764
529
  if (!richMsg) return ''
@@ -782,11 +547,13 @@ function decodeRichResponseMessage(richMsg) {
782
547
  }
783
548
  }
784
549
  return texts.join('\n')
785
- } catch {
550
+ } catch (e) {
786
551
  return ''
787
552
  }
788
553
  }
789
-
554
+ /**
555
+ * Utility function to check if an error is related to missing session record
556
+ */
790
557
  function isSessionRecordError(error) {
791
558
  const errorMessage = error?.message || error?.toString() || ''
792
559
  return exports.DECRYPTION_RETRY_CONFIG.sessionRecordErrors.some(errorPattern => errorMessage.includes(errorPattern))