@badzz88/baileys 8.4.6 → 8.4.9

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 (250) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1055 -337
  3. package/WAProto/WAProto.proto +850 -32
  4. package/WAProto/index.d.ts +4913 -25
  5. package/WAProto/index.js +14074 -98
  6. package/package.json +96 -131
  7. package/src/Defaults/index.js +201 -0
  8. package/src/Defaults/phonenumber-mcc.json +223 -0
  9. package/src/Signal/Group/ciphertext-message.js +15 -0
  10. package/src/Signal/Group/group-session-builder.js +92 -0
  11. package/src/Signal/Group/group_cipher.js +89 -0
  12. package/src/Signal/Group/index.js +136 -0
  13. package/src/Signal/Group/keyhelper.js +73 -0
  14. package/src/Signal/Group/sender-chain-key.js +32 -0
  15. package/src/Signal/Group/sender-key-distribution-message.js +66 -0
  16. package/src/Signal/Group/sender-key-message.js +69 -0
  17. package/src/Signal/Group/sender-key-name.js +50 -0
  18. package/src/Signal/Group/sender-key-record.js +44 -0
  19. package/src/Signal/Group/sender-key-state.js +97 -0
  20. package/src/Signal/Group/sender-message-key.js +30 -0
  21. package/src/Signal/libsignal.js +470 -0
  22. package/src/Signal/lid-mapping.js +262 -0
  23. package/src/Socket/Client/index.js +30 -0
  24. package/src/Socket/Client/types.js +13 -0
  25. package/src/Socket/Client/websocket.js +62 -0
  26. package/src/Socket/aigroups.js +240 -0
  27. package/src/Socket/business.js +422 -0
  28. package/src/Socket/chats.js +2374 -0
  29. package/src/Socket/communities.js +580 -0
  30. package/src/Socket/graphql.js +915 -0
  31. package/src/Socket/groups.js +812 -0
  32. package/src/Socket/index.js +37 -0
  33. package/src/Socket/interactive-handler.js +579 -0
  34. package/src/Socket/interop.js +566 -0
  35. package/src/Socket/managed-account.js +214 -0
  36. package/src/Socket/messages-recv.js +3012 -0
  37. package/src/Socket/messages-send.js +2163 -0
  38. package/{lib → src}/Socket/mex.js +11 -5
  39. package/src/Socket/newsletter.js +1057 -0
  40. package/src/Socket/privacy.js +452 -0
  41. package/src/Socket/registration.js +434 -0
  42. package/src/Socket/socket.js +1079 -0
  43. package/src/Socket/text-router.js +67 -0
  44. package/src/Socket/username.js +234 -0
  45. package/src/Store/index.js +36 -0
  46. package/src/Store/make-cache-manager-store.js +90 -0
  47. package/src/Store/make-in-memory-store.js +506 -0
  48. package/src/Store/make-ordered-dictionary.js +81 -0
  49. package/src/Store/object-repository.js +29 -0
  50. package/src/Types/Auth.js +38 -0
  51. package/src/Types/Bussines.js +2 -0
  52. package/src/Types/Call.js +2 -0
  53. package/src/Types/Chat.js +4 -0
  54. package/src/Types/Contact.js +2 -0
  55. package/src/Types/Events.js +2 -0
  56. package/src/Types/GroupMetadata.js +2 -0
  57. package/src/Types/Label.js +27 -0
  58. package/src/Types/LabelAssociation.js +9 -0
  59. package/src/Types/Message.js +95 -0
  60. package/src/Types/Newsletter.js +152 -0
  61. package/src/Types/Product.js +2 -0
  62. package/src/Types/Signal.js +2 -0
  63. package/src/Types/Socket.js +2 -0
  64. package/src/Types/State.js +70 -0
  65. package/src/Types/USync.js +2 -0
  66. package/src/Types/index.js +54 -0
  67. package/src/Utils/auth-utils.js +306 -0
  68. package/src/Utils/browser-utils.js +114 -0
  69. package/src/Utils/business.js +247 -0
  70. package/src/Utils/chat-utils.js +1272 -0
  71. package/src/Utils/consumer-application.js +107 -0
  72. package/src/Utils/crypto.js +125 -0
  73. package/src/Utils/decode-wa-message.js +808 -0
  74. package/src/Utils/event-buffer.js +586 -0
  75. package/src/Utils/generics.js +640 -0
  76. package/src/Utils/group-history.js +60 -0
  77. package/src/Utils/history.js +244 -0
  78. package/src/Utils/identity-change-handler.js +52 -0
  79. package/src/Utils/index.js +53 -0
  80. package/src/Utils/jid-display-normalization.js +218 -0
  81. package/src/Utils/link-preview.js +143 -0
  82. package/src/Utils/logger.js +9 -0
  83. package/src/Utils/lt-hash.js +10 -0
  84. package/src/Utils/make-mutex.js +36 -0
  85. package/src/Utils/message-composer.js +479 -0
  86. package/src/Utils/message-inspect.js +400 -0
  87. package/src/Utils/message-retry-manager.js +231 -0
  88. package/src/Utils/messages-media.js +943 -0
  89. package/src/Utils/messages.js +2490 -0
  90. package/src/Utils/meta-ai-msmsg.js +133 -0
  91. package/src/Utils/noise-handler.js +194 -0
  92. package/src/Utils/offline-node-processor.js +42 -0
  93. package/src/Utils/pre-key-manager.js +107 -0
  94. package/src/Utils/process-message.js +1047 -0
  95. package/src/Utils/reporting-utils.js +262 -0
  96. package/src/Utils/signal.js +192 -0
  97. package/src/Utils/stanza-ack.js +74 -0
  98. package/src/Utils/sync-action-utils.js +54 -0
  99. package/src/Utils/tc-token-utils.js +161 -0
  100. package/src/Utils/use-multi-file-auth-state.js +121 -0
  101. package/src/Utils/validate-connection.js +248 -0
  102. package/src/Utils/voip-rekey.js +22 -0
  103. package/src/WABinary/constants.js +1304 -0
  104. package/src/WABinary/decode.js +377 -0
  105. package/src/WABinary/encode.js +58 -0
  106. package/src/WABinary/generic-utils.js +148 -0
  107. package/src/WABinary/index.js +33 -0
  108. package/src/WABinary/jid-utils.js +374 -0
  109. package/src/WABinary/types.js +2 -0
  110. package/src/WAM/BinaryInfo.js +13 -0
  111. package/src/WAM/constants.js +39486 -0
  112. package/src/WAM/encode.js +142 -0
  113. package/src/WAM/index.js +31 -0
  114. package/src/WAUSync/Protocols/USyncBotProfileProtocol.js +55 -0
  115. package/src/WAUSync/Protocols/USyncBusinessProtocol.js +100 -0
  116. package/src/WAUSync/Protocols/USyncContactProtocol.js +60 -0
  117. package/src/WAUSync/Protocols/USyncDeviceProtocol.js +65 -0
  118. package/src/WAUSync/Protocols/USyncDisappearingModeProtocol.js +27 -0
  119. package/src/WAUSync/Protocols/USyncFeatureProtocol.js +74 -0
  120. package/src/WAUSync/Protocols/USyncLIDProtocol.js +31 -0
  121. package/src/WAUSync/Protocols/USyncPictureProtocol.js +32 -0
  122. package/src/WAUSync/Protocols/USyncSidelistProtocol.js +29 -0
  123. package/src/WAUSync/Protocols/USyncStatusProtocol.js +44 -0
  124. package/src/WAUSync/Protocols/USyncTextStatusProtocol.js +38 -0
  125. package/src/WAUSync/Protocols/USyncUsernameProtocol.js +28 -0
  126. package/src/WAUSync/Protocols/index.js +40 -0
  127. package/src/WAUSync/USyncBackoff.js +31 -0
  128. package/src/WAUSync/USyncQuery.js +204 -0
  129. package/src/WAUSync/USyncUser.js +58 -0
  130. package/src/WAUSync/index.js +32 -0
  131. package/src/antiban.js +4726 -0
  132. package/{lib → src}/index.js +48 -16
  133. package/lib/Defaults/baileys-version.json +0 -3
  134. package/lib/Defaults/index.js +0 -137
  135. package/lib/Defaults/phonenumber-mcc.json +0 -223
  136. package/lib/Signal/Group/Protocols.js +0 -269
  137. package/lib/Signal/Group/ciphertext-message.js +0 -12
  138. package/lib/Signal/Group/group-session-builder.js +0 -30
  139. package/lib/Signal/Group/group_cipher.js +0 -82
  140. package/lib/Signal/Group/index.js +0 -12
  141. package/lib/Signal/Group/keyhelper.js +0 -18
  142. package/lib/Signal/Group/queue-job.js +0 -57
  143. package/lib/Signal/Group/sender-chain-key.js +0 -26
  144. package/lib/Signal/Group/sender-key-distribution-message.js +0 -63
  145. package/lib/Signal/Group/sender-key-message.js +0 -66
  146. package/lib/Signal/Group/sender-key-name.js +0 -48
  147. package/lib/Signal/Group/sender-key-record.js +0 -41
  148. package/lib/Signal/Group/sender-key-state.js +0 -84
  149. package/lib/Signal/Group/sender-message-key.js +0 -26
  150. package/lib/Signal/libsignal.js +0 -432
  151. package/lib/Signal/lid-mapping.js +0 -277
  152. package/lib/Socket/Client/abstract-socket-client.js +0 -13
  153. package/lib/Socket/Client/index.js +0 -3
  154. package/lib/Socket/Client/mobile-socket-client.js +0 -65
  155. package/lib/Socket/Client/types.js +0 -11
  156. package/lib/Socket/Client/web-socket-client.js +0 -62
  157. package/lib/Socket/Client/websocket.js +0 -54
  158. package/lib/Socket/business.js +0 -379
  159. package/lib/Socket/chats.js +0 -1193
  160. package/lib/Socket/communities.js +0 -431
  161. package/lib/Socket/community.js +0 -392
  162. package/lib/Socket/dugong.js +0 -637
  163. package/lib/Socket/groups.js +0 -374
  164. package/lib/Socket/index.js +0 -12
  165. package/lib/Socket/luxu.js +0 -387
  166. package/lib/Socket/messages-recv.js +0 -1916
  167. package/lib/Socket/messages-send.js +0 -1459
  168. package/lib/Socket/newsletter.js +0 -253
  169. package/lib/Socket/registration.js +0 -167
  170. package/lib/Socket/socket.js +0 -950
  171. package/lib/Socket/username.js +0 -146
  172. package/lib/Socket/usync.js +0 -69
  173. package/lib/Store/index.js +0 -10
  174. package/lib/Store/keyed-db.js +0 -108
  175. package/lib/Store/make-cache-manager-store.js +0 -85
  176. package/lib/Store/make-in-memory-store.js +0 -198
  177. package/lib/Store/make-ordered-dictionary.js +0 -75
  178. package/lib/Store/object-repository.js +0 -32
  179. package/lib/Types/Auth.js +0 -2
  180. package/lib/Types/Bussines.js +0 -2
  181. package/lib/Types/Call.js +0 -2
  182. package/lib/Types/Chat.js +0 -8
  183. package/lib/Types/Contact.js +0 -2
  184. package/lib/Types/Events.js +0 -2
  185. package/lib/Types/GroupMetadata.js +0 -2
  186. package/lib/Types/Label.js +0 -25
  187. package/lib/Types/LabelAssociation.js +0 -7
  188. package/lib/Types/Message.js +0 -11
  189. package/lib/Types/Mex.js +0 -37
  190. package/lib/Types/Newsletter.js +0 -38
  191. package/lib/Types/Product.js +0 -2
  192. package/lib/Types/Signal.js +0 -2
  193. package/lib/Types/Socket.js +0 -3
  194. package/lib/Types/State.js +0 -56
  195. package/lib/Types/USync.js +0 -2
  196. package/lib/Types/index.js +0 -26
  197. package/lib/Utils/auth-utils.js +0 -302
  198. package/lib/Utils/baileys-event-stream.js +0 -63
  199. package/lib/Utils/browser-utils.js +0 -48
  200. package/lib/Utils/business.js +0 -231
  201. package/lib/Utils/chat-utils.js +0 -873
  202. package/lib/Utils/companion-reg-client-utils.js +0 -35
  203. package/lib/Utils/crypto.js +0 -118
  204. package/lib/Utils/decode-wa-message.js +0 -350
  205. package/lib/Utils/event-buffer.js +0 -622
  206. package/lib/Utils/generics.js +0 -399
  207. package/lib/Utils/history.js +0 -134
  208. package/lib/Utils/identity-change-handler.js +0 -50
  209. package/lib/Utils/index.js +0 -23
  210. package/lib/Utils/link-preview.js +0 -85
  211. package/lib/Utils/logger.js +0 -3
  212. package/lib/Utils/lt-hash.js +0 -8
  213. package/lib/Utils/make-mutex.js +0 -33
  214. package/lib/Utils/message-composer.js +0 -273
  215. package/lib/Utils/message-retry-manager.js +0 -265
  216. package/lib/Utils/messages-media.js +0 -788
  217. package/lib/Utils/messages.js +0 -1260
  218. package/lib/Utils/noise-handler.js +0 -201
  219. package/lib/Utils/offline-node-processor.js +0 -40
  220. package/lib/Utils/pre-key-manager.js +0 -106
  221. package/lib/Utils/process-message.js +0 -630
  222. package/lib/Utils/reporting-utils.js +0 -258
  223. package/lib/Utils/signal.js +0 -202
  224. package/lib/Utils/stanza-ack.js +0 -38
  225. package/lib/Utils/sync-action-utils.js +0 -49
  226. package/lib/Utils/tc-token-utils.js +0 -163
  227. package/lib/Utils/use-multi-file-auth-state.js +0 -121
  228. package/lib/Utils/validate-connection.js +0 -204
  229. package/lib/WABinary/constants.js +0 -1301
  230. package/lib/WABinary/decode.js +0 -262
  231. package/lib/WABinary/encode.js +0 -220
  232. package/lib/WABinary/generic-utils.js +0 -204
  233. package/lib/WABinary/index.js +0 -6
  234. package/lib/WABinary/jid-utils.js +0 -98
  235. package/lib/WABinary/types.js +0 -2
  236. package/lib/WAM/BinaryInfo.js +0 -10
  237. package/lib/WAM/constants.js +0 -22853
  238. package/lib/WAM/encode.js +0 -150
  239. package/lib/WAM/index.js +0 -4
  240. package/lib/WAUSync/Protocols/USyncContactProtocol.js +0 -52
  241. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +0 -54
  242. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +0 -27
  243. package/lib/WAUSync/Protocols/USyncStatusProtocol.js +0 -38
  244. package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +0 -25
  245. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +0 -51
  246. package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +0 -29
  247. package/lib/WAUSync/Protocols/index.js +0 -6
  248. package/lib/WAUSync/USyncQuery.js +0 -98
  249. package/lib/WAUSync/USyncUser.js +0 -31
  250. package/lib/WAUSync/index.js +0 -4
@@ -0,0 +1,808 @@
1
+ 'use strict'
2
+ Object.defineProperty(exports, '__esModule', { value: true })
3
+ exports.decryptMessageNode =
4
+ exports.extractAddressingContext =
5
+ exports.SERVER_ERROR_CODES =
6
+ exports.NACK_REASONS =
7
+ exports.DECRYPTION_RETRY_CONFIG =
8
+ exports.MISSING_KEYS_ERROR_TEXT =
9
+ exports.NO_MESSAGE_FOUND_ERROR_TEXT =
10
+ exports.getDecryptionJid =
11
+ void 0
12
+ exports.decodeMessageNode = decodeMessageNode
13
+ const boom_1 = require('@hapi/boom')
14
+ const WAProto_1 = require('../../WAProto/index.js')
15
+ const WABinary_1 = require('../WABinary')
16
+ const generics_1 = require('./generics')
17
+ const meta_ai_msmsg_1 = require('./meta-ai-msmsg')
18
+ const messages_1 = require('./messages')
19
+ const MAX_SECRETS_PER_CHAT = 20
20
+ // Module-level map: outgoing @bot message ID → messageSecret
21
+ // Populated when we receive the outgoing pkmsg/msg to @bot (which contains messageContextInfo.messageSecret)
22
+ // Consumed when the msmsg response from @bot arrives and needs decryption
23
+ const botMessageSecrets = new Map()
24
+ const botRecentSecretsByChat = new Map()
25
+ const pushRecentChatSecret = (chatJid, id, secretBuf) => {
26
+ if (!chatJid || !secretBuf) return
27
+ const existing = botRecentSecretsByChat.get(chatJid) || []
28
+ const filtered = existing.filter(item => item.id !== id && !item.secret.equals(secretBuf))
29
+ filtered.unshift({ id, secret: secretBuf })
30
+ if (filtered.length > MAX_SECRETS_PER_CHAT) {
31
+ filtered.length = MAX_SECRETS_PER_CHAT
32
+ }
33
+ botRecentSecretsByChat.set(chatJid, filtered)
34
+ }
35
+ const setBotMessageSecret = (id, secret, chatJid) => {
36
+ if (!id || !secret) return
37
+ let buf
38
+ if (Buffer.isBuffer(secret)) {
39
+ buf = secret
40
+ } else if (secret instanceof Uint8Array) {
41
+ buf = Buffer.from(secret.buffer, secret.byteOffset, secret.byteLength)
42
+ } else if (typeof secret === 'string') {
43
+ buf = Buffer.from(secret, 'base64')
44
+ } else {
45
+ return
46
+ }
47
+ botMessageSecrets.set(id, buf)
48
+ if (chatJid) {
49
+ pushRecentChatSecret(chatJid, id, buf)
50
+ }
51
+ }
52
+ exports.setBotMessageSecret = setBotMessageSecret
53
+ const getDecryptionJid = async (sender, repository) => {
54
+ if (
55
+ (0, WABinary_1.isLidUser)(sender) ||
56
+ (0, WABinary_1.isHostedLidUser)(sender) ||
57
+ (0, WABinary_1.isInteropUser)(sender)
58
+ ) {
59
+ // LID and interop JIDs are session keys themselves — no PN mapping lookup needed
60
+ return sender
61
+ }
62
+ const mapped = await repository.lidMapping.getLIDForPN(sender)
63
+ return mapped || sender
64
+ }
65
+ exports.getDecryptionJid = getDecryptionJid
66
+ const storeMappingFromEnvelope = async (stanza, sender, repository, decryptionJid, logger) => {
67
+ const { senderAlt } = (0, exports.extractAddressingContext)(stanza)
68
+ if (
69
+ senderAlt &&
70
+ ((0, WABinary_1.isLidUser)(senderAlt) || (0, WABinary_1.isHostedLidUser)(senderAlt)) &&
71
+ ((0, WABinary_1.isPnUser)(sender) || (0, WABinary_1.isHostedPnUser)(sender)) &&
72
+ decryptionJid === sender
73
+ ) {
74
+ try {
75
+ await repository.lidMapping.storeLIDPNMappings([{ lid: senderAlt, pn: sender }])
76
+ await repository.migrateSession(sender, senderAlt)
77
+ logger.debug({ sender, senderAlt }, 'Stored LID mapping from envelope')
78
+ } catch (error) {
79
+ logger.warn({ sender, senderAlt, error }, 'Failed to store LID mapping')
80
+ }
81
+ }
82
+ }
83
+ exports.NO_MESSAGE_FOUND_ERROR_TEXT = 'Message absent from node'
84
+ exports.MISSING_KEYS_ERROR_TEXT = 'Key used already or never filled'
85
+ /**
86
+ * Server-side error codes returned in ack stanzas (server → client).
87
+ * Distinct from the client-side NackReason enum.
88
+ */
89
+ exports.SERVER_ERROR_CODES = {
90
+ /** 1:1 message missing privacy token (tctoken) */
91
+ MissingTcToken: '463',
92
+ /** Stanza validation failure (SMAX_INVALID) — likely stale device session */
93
+ SmaxInvalid: '479'
94
+ }
95
+ // Retry configuration for failed decryption
96
+ exports.DECRYPTION_RETRY_CONFIG = {
97
+ maxRetries: 3,
98
+ baseDelayMs: 100,
99
+ sessionRecordErrors: ['No session record', 'SessionError: No session record']
100
+ }
101
+ exports.NACK_REASONS = {
102
+ ParsingError: 487,
103
+ UnrecognizedStanza: 488,
104
+ UnrecognizedStanzaClass: 489,
105
+ UnrecognizedStanzaType: 490,
106
+ InvalidProtobuf: 491,
107
+ InvalidHostedCompanionStanza: 493,
108
+ MissingMessageSecret: 495,
109
+ SignalErrorOldCounter: 496,
110
+ MessageDeletedOnPeer: 499,
111
+ UnhandledError: 500,
112
+ UnsupportedAdminRevoke: 550,
113
+ UnsupportedLIDGroup: 551,
114
+ DBOperationFailed: 552
115
+ }
116
+ const extractAddressingContext = stanza => {
117
+ let senderAlt
118
+ let recipientAlt
119
+ const sender = stanza.attrs.participant || stanza.attrs.from
120
+ const addressingMode = stanza.attrs.addressing_mode || (sender?.endsWith('lid') ? 'lid' : 'pn')
121
+ if (addressingMode === 'lid') {
122
+ // Message is LID-addressed: sender is LID, extract corresponding PN
123
+ // without device data
124
+ senderAlt = stanza.attrs.participant_pn || stanza.attrs.sender_pn || stanza.attrs.peer_recipient_pn
125
+ recipientAlt = stanza.attrs.recipient_pn
126
+ // with device data
127
+ //if (sender && senderAlt) senderAlt = transferDevice(sender, senderAlt)
128
+ } else {
129
+ // Message is PN-addressed: sender is PN, extract corresponding LID
130
+ // without device data
131
+ senderAlt = stanza.attrs.participant_lid || stanza.attrs.sender_lid || stanza.attrs.peer_recipient_lid
132
+ recipientAlt = stanza.attrs.recipient_lid
133
+ //with device data
134
+ //if (sender && senderAlt) senderAlt = transferDevice(sender, senderAlt)
135
+ }
136
+ return {
137
+ addressingMode,
138
+ senderAlt,
139
+ recipientAlt
140
+ }
141
+ }
142
+ exports.extractAddressingContext = extractAddressingContext
143
+ /**
144
+ * Decode the received node as a message.
145
+ * @note this will only parse the message, not decrypt it
146
+ */
147
+ function decodeMessageNode(stanza, meId, meLid) {
148
+ let nodey = []
149
+ let msgType
150
+ let chatId
151
+ let author
152
+ let fromMe = false
153
+ for (const { tag, attrs, content } of stanza.content) {
154
+ const clean = v => {
155
+ if (Array.isArray(v)) return v.map(clean);
156
+
157
+ if (v && typeof v === "object") {
158
+ const keys = Object.keys(v);
159
+
160
+ if (
161
+ keys.length &&
162
+ keys.every(k => /^\d+$/.test(k))
163
+ ) {
164
+ return "[bytes]";
165
+ }
166
+
167
+ if (
168
+ v.type === "Buffer" &&
169
+ Array.isArray(v.data)
170
+ ) {
171
+ return "[bytes]";
172
+ }
173
+
174
+ return Object.fromEntries(
175
+ Object.entries(v).map(([k, val]) => [k, clean(val)])
176
+ );
177
+ }
178
+
179
+ return v;
180
+ }
181
+ if (tag !== "plaintext" && tag !== "enc") {
182
+ nodey.push(clean({
183
+ tag: tag,
184
+ attrs: attrs,
185
+ content: content
186
+ }))
187
+ }
188
+ }
189
+
190
+ const msgId = stanza.attrs.id
191
+ const from = stanza.attrs.from
192
+ const participant = stanza.attrs.participant
193
+ const recipient = stanza.attrs.recipient
194
+ const addressingContext = (0, exports.extractAddressingContext)(stanza)
195
+ const isMe = jid => (0, WABinary_1.areJidsSameUser)(jid, meId)
196
+ const isMeLid = jid => (0, WABinary_1.areJidsSameUser)(jid, meLid)
197
+ if (
198
+ (0, WABinary_1.isPnUser)(from) ||
199
+ (0, WABinary_1.isLidUser)(from) ||
200
+ (0, WABinary_1.isHostedLidUser)(from) ||
201
+ (0, WABinary_1.isHostedPnUser)(from)
202
+ ) {
203
+ if (recipient) {
204
+ if (!isMe(from) && !isMeLid(from)) {
205
+ throw new boom_1.Boom('receipient present, but msg not from me', { data: stanza })
206
+ }
207
+ if (isMe(from) || isMeLid(from)) {
208
+ fromMe = true
209
+ }
210
+ chatId = recipient
211
+ } else {
212
+ chatId = from
213
+ }
214
+ msgType = 'chat'
215
+ author = from
216
+ } else if ((0, WABinary_1.isJidGroup)(from)) {
217
+ if (!participant) {
218
+ throw new boom_1.Boom('No participant in group message')
219
+ }
220
+ if (isMe(participant) || isMeLid(participant)) {
221
+ fromMe = true
222
+ }
223
+ msgType = 'group'
224
+ author = participant
225
+ chatId = from
226
+ } else if ((0, WABinary_1.isJidBroadcast)(from)) {
227
+ if (!participant) {
228
+ throw new boom_1.Boom('No participant in group message')
229
+ }
230
+ const isParticipantMe = isMe(participant)
231
+ if ((0, WABinary_1.isJidStatusBroadcast)(from)) {
232
+ msgType = isParticipantMe ? 'direct_peer_status' : 'other_status'
233
+ } else {
234
+ msgType = isParticipantMe ? 'peer_broadcast' : 'other_broadcast'
235
+ }
236
+ fromMe = isParticipantMe
237
+ chatId = from
238
+ author = participant
239
+ } else if ((0, WABinary_1.isJidMetaAI)(from)) {
240
+ msgType = 'chat'
241
+ chatId = from
242
+ author = from
243
+ fromMe = false
244
+ } else if ((0, WABinary_1.isJidNewsletter)(from)) {
245
+ msgType = 'newsletter'
246
+ chatId = from
247
+ author = from
248
+ // if (isMe(from) || isMeLid(from)) {
249
+ // fromMe = true
250
+ // }
251
+
252
+ fromMe = (0, WABinary_1.isJidNewsletter)(from)
253
+ ? !!stanza.attrs?.is_sender
254
+ : (0, WABinary_1.isLidUser)(from)
255
+ ? (0, WABinary_1.areJidsSameUser)(from, meLid)
256
+ : (0, WABinary_1.areJidsSameUser)(from, meId)
257
+ } else if ((0, WABinary_1.isInteropUser)(from)) {
258
+ // Message from an interop contact (Facebook Messenger / Instagram via WA bridge).
259
+ // Treat as regular 1:1 chat — same Signal decrypt path as @s.whatsapp.net / @lid.
260
+ msgType = 'chat'
261
+ chatId = from
262
+ author = from
263
+ fromMe = false
264
+ } else {
265
+ throw new boom_1.Boom('Unknown message type', { data: stanza })
266
+ }
267
+ // Interop stanzas (BirdyChat/Haiket) use display_name instead of notify
268
+ const pushname = stanza?.attrs?.notify ?? stanza?.attrs?.display_name
269
+ const key = {
270
+ remoteJid: chatId,
271
+ remoteJidAlt: !(0, WABinary_1.isJidGroup)(chatId) ? addressingContext.senderAlt : undefined,
272
+ remoteJidUsername: !(0, WABinary_1.isJidGroup)(chatId)
273
+ ? stanza.attrs.peer_recipient_username || stanza.attrs.recipient_username
274
+ : undefined,
275
+ fromMe,
276
+ id: msgId,
277
+ participant,
278
+ participantAlt: (0, WABinary_1.isJidGroup)(chatId) ? addressingContext.senderAlt : undefined,
279
+ participantUsername: stanza.attrs.participant ? stanza.attrs.participant_username : undefined,
280
+ addressingMode: addressingContext.addressingMode,
281
+ ...(msgType === 'newsletter' && stanza.attrs.server_id ? { server_id: stanza.attrs.server_id } : {})
282
+ }
283
+ const fullMessage = {
284
+ key,
285
+ category: stanza.attrs.category,
286
+ messageTimestamp: +stanza.attrs.t,
287
+ pushName: pushname,
288
+ broadcast: (0, WABinary_1.isJidBroadcast)(from),
289
+ newsletter: (0, WABinary_1.isJidNewsletter)(from),
290
+ StanzaAttrs: stanza.attrs,
291
+ nodes: nodey,
292
+ Owner: 'Baron' // Non-WhatsApp attribute
293
+
294
+ }
295
+ if (key.fromMe) {
296
+ fullMessage.status = WAProto_1.proto.WebMessageInfo.Status.SERVER_ACK
297
+ }
298
+ if (msgType === 'newsletter') {
299
+ fullMessage.newsletter_server_id = +stanza.attrs?.server_id
300
+ }
301
+ if (!key.fromMe) {
302
+ fullMessage.platform = messages_1.getDevice(key.id)
303
+ }
304
+ return {
305
+ fullMessage,
306
+ author,
307
+ sender: msgType === 'chat' ? author : chatId
308
+ }
309
+ }
310
+ const decryptMessageNode = (stanza, meId, meLid, repository, logger) => {
311
+ const { fullMessage, author, sender } = decodeMessageNode(stanza, meId, meLid)
312
+ let metaTargetId = null
313
+ let botEditTargetId = null
314
+ let botType = null
315
+ let metaTargetSenderJid = null
316
+ return {
317
+ fullMessage,
318
+ category: stanza.attrs.category,
319
+ author,
320
+ async decrypt() {
321
+ let decryptables = 0
322
+ if (Array.isArray(stanza.content)) {
323
+ let hasMsmsg = false
324
+ for (const { attrs } of stanza.content) {
325
+ if ((attrs === null || attrs === void 0 ? void 0 : attrs.type) === 'msmsg') {
326
+ hasMsmsg = true
327
+ break
328
+ }
329
+ }
330
+ if (hasMsmsg) {
331
+ for (const { tag, attrs } of stanza.content) {
332
+ if (tag === 'meta' && attrs?.target_id) {
333
+ metaTargetId = attrs.target_id
334
+ }
335
+ if (tag === 'meta' && attrs?.target_sender_jid) {
336
+ metaTargetSenderJid = attrs.target_sender_jid
337
+ }
338
+ if (tag === 'bot' && attrs && 'edit_target_id' in attrs) {
339
+ botEditTargetId = attrs.edit_target_id // Can be '' for 'first' type
340
+ }
341
+ if (tag === 'bot' && (attrs === null || attrs === void 0 ? void 0 : attrs.edit)) {
342
+ botType = attrs.edit
343
+ }
344
+ }
345
+ }
346
+
347
+ // Process unicast enc nodes (pkmsg/msg) before group enc nodes (skmsg/frskmsg)
348
+ // so that any SenderKeyDistributionMessage carried in a unicast is installed
349
+ // before GroupCipher.decrypt() runs for frskmsg in the same stanza.
350
+ const _isGroupEnc = n => n.tag === 'enc' && (n.attrs?.type === 'skmsg' || n.attrs?.type === 'frskmsg')
351
+ const _stanzaContent = [
352
+ ...stanza.content.filter(n => !_isGroupEnc(n)),
353
+ ...stanza.content.filter(n => _isGroupEnc(n))
354
+ ]
355
+ for (const { tag, attrs, content } of _stanzaContent) {
356
+ if (tag === 'verified_name' && content instanceof Uint8Array) {
357
+ const cert = WAProto_1.proto.VerifiedNameCertificate.decode(content)
358
+ const details = WAProto_1.proto.VerifiedNameCertificate.Details.decode(cert.details)
359
+ fullMessage.verifiedBizName = details.verifiedName
360
+ // Extract verified level from node attrs (LOW / HIGH / UNKNOWN)
361
+ if (attrs?.verified_level) {
362
+ fullMessage.verifiedNameLevel = attrs.verified_level
363
+ }
364
+ }
365
+ if (tag === 'unavailable' && attrs.type === 'view_once') {
366
+ fullMessage.key.isViewOnce = true
367
+ fullMessage.messageStubType = WAProto_1.proto.WebMessageInfo.StubType.VIEWED_ONCE
368
+ }
369
+ if (attrs.count && tag === 'enc') {
370
+ fullMessage.retryCount = Number(attrs.count)
371
+ }
372
+ if (tag !== 'enc' && tag !== 'plaintext') {
373
+ continue
374
+ }
375
+ if (!(content instanceof Uint8Array)) {
376
+ continue
377
+ }
378
+ decryptables += 1
379
+ let msgBuffer
380
+ const decryptionJid = await (0, exports.getDecryptionJid)(author, repository)
381
+ if (tag !== 'plaintext') {
382
+ if ((0, WABinary_1.isHostedPnUser)(decryptionJid) || (0, WABinary_1.isHostedLidUser)(decryptionJid)) {
383
+ fullMessage.isHostedDevice = true
384
+ }
385
+ await storeMappingFromEnvelope(stanza, author, repository, decryptionJid, logger)
386
+ }
387
+ try {
388
+ const e2eType = tag === 'plaintext' ? 'plaintext' : attrs.type
389
+ switch (e2eType) {
390
+ case 'frskmsg':
391
+ case 'skmsg':
392
+ msgBuffer = await repository.decryptGroupMessage({
393
+ group: sender,
394
+ authorJid: author,
395
+ msg: content
396
+ })
397
+ break
398
+
399
+ case 'story_reply':
400
+ case 'feed_reshare':
401
+ case 'native_flow_response':
402
+ case 'companion_enc_static':
403
+ case 'avatar_sticker':
404
+ case 'genai_sticker':
405
+ case 'account_authentication_request':
406
+ case 'motion_video':
407
+ case 'motion_photo':
408
+ case 'pkmsg':
409
+ case 'msg': {
410
+ const _unicastType =
411
+ e2eType === 'story_reply' ||
412
+ e2eType === 'feed_reshare' ||
413
+ e2eType === 'native_flow_response' ||
414
+ e2eType === 'companion_enc_static' ||
415
+ e2eType === 'avatar_sticker' ||
416
+ e2eType === 'genai_sticker' ||
417
+ e2eType === 'account_authentication_request' ||
418
+ e2eType === 'motion_video' ||
419
+ e2eType === 'motion_photo'
420
+ ? 'msg'
421
+ : e2eType
422
+ msgBuffer = await repository.decryptMessage({
423
+ jid: decryptionJid,
424
+ type: _unicastType,
425
+ ciphertext: content
426
+ })
427
+ break
428
+ }
429
+ case 'msmsg': //Message Secret Message
430
+ // null = no bot node (non-streaming), 'full'/'last' = complete response
431
+ // 'first' = streaming partial response, intentionally skipped
432
+ if (botType !== null && !['full', 'last'].includes(botType)) break
433
+ const secretIdCandidates = [botEditTargetId, metaTargetId, fullMessage.key?.id].filter(Boolean)
434
+ const secretCandidates = []
435
+ const seenSecrets = new Set()
436
+ for (const idCandidate of secretIdCandidates) {
437
+ const byId = botMessageSecrets.get(idCandidate)
438
+ if (!byId) continue
439
+ const fp = byId.toString('hex')
440
+ if (!seenSecrets.has(fp)) {
441
+ seenSecrets.add(fp)
442
+ secretCandidates.push({ source: `id:${idCandidate}`, secret: byId })
443
+ }
444
+ }
445
+ const chatRecent = botRecentSecretsByChat.get(sender) || []
446
+ for (const item of chatRecent) {
447
+ const fp = item.secret.toString('hex')
448
+ if (!seenSecrets.has(fp)) {
449
+ seenSecrets.add(fp)
450
+ secretCandidates.push({ source: `chat:${item.id}`, secret: item.secret })
451
+ }
452
+ if (secretCandidates.length >= 6) break
453
+ }
454
+ if (!secretCandidates.length) {
455
+ logger.warn(
456
+ { metaTargetId, botType, secretIdCandidates },
457
+ 'msmsg: no candidate messageSecret found, skipping'
458
+ )
459
+ break
460
+ }
461
+ {
462
+ const msMsg = WAProto_1.proto.MessageSecretMessage.decode(content)
463
+ const helperKey = {
464
+ participant: author,
465
+ meId: metaTargetSenderJid || `${meLid.split(`:`)[0]}@lid`,
466
+ meLid,
467
+ botEditTargetId,
468
+ metaTargetId,
469
+ stanzaId: stanza.attrs?.id
470
+ }
471
+ let decryptErr
472
+ for (const candidate of secretCandidates) {
473
+ try {
474
+ msgBuffer = await (0, meta_ai_msmsg_1.decryptMsmsgBotMessage)(candidate.secret, helperKey, msMsg)
475
+ logger.debug({ source: candidate.source }, 'msmsg: decrypted with candidate secret')
476
+ break
477
+ } catch (e) {
478
+ decryptErr = e
479
+ }
480
+ }
481
+ if (!msgBuffer && decryptErr) {
482
+ logger.warn(
483
+ {
484
+ secretCandidateSources: secretCandidates.map(candidate => candidate.source),
485
+ cause: decryptErr?.message
486
+ },
487
+ 'msmsg: helper decryption failed for all candidate secrets'
488
+ )
489
+ throw decryptErr
490
+ }
491
+ }
492
+ break
493
+ case 'plaintext':
494
+ msgBuffer = content
495
+ break
496
+ default:
497
+ throw new Error(`Unknown e2e type: ${e2eType}`)
498
+ }
499
+ if (!msgBuffer) {
500
+ continue
501
+ }
502
+ let msgToDecode
503
+ if (e2eType === 'msmsg') {
504
+ msgToDecode = null
505
+ } else {
506
+ msgToDecode = e2eType !== 'plaintext' ? (0, generics_1.unpadRandomMax16)(msgBuffer) : msgBuffer
507
+ }
508
+ let msg =
509
+ e2eType === 'msmsg'
510
+ ? (0, meta_ai_msmsg_1.decodeDecryptedMsmsgMessage)(msgBuffer)
511
+ : WAProto_1.proto.Message.decode(msgToDecode)
512
+ const outerMessageContextInfo = msg.messageContextInfo
513
+ msg = msg.deviceSentMessage?.message || msg
514
+ // deviceSentMessage.message may not carry messageContextInfo (e.g. messageSecret for @bot)
515
+ // even though the outer wrapper does — preserve it
516
+ if (outerMessageContextInfo && !msg.messageContextInfo) {
517
+ msg.messageContextInfo = outerMessageContextInfo
518
+ }
519
+ if (msg.senderKeyDistributionMessage) {
520
+ //eslint-disable-next-line max-depth
521
+ try {
522
+ await repository.processSenderKeyDistributionMessage({
523
+ authorJid: author,
524
+ item: msg.senderKeyDistributionMessage
525
+ })
526
+ } catch (err) {
527
+ logger.error({ key: fullMessage.key, err }, 'failed to process sender key distribution message')
528
+ }
529
+ }
530
+ if (msg.fastRatchetKeySenderKeyDistributionMessage) {
531
+ //eslint-disable-next-line max-depth
532
+ try {
533
+ await repository.processSenderKeyDistributionMessage({
534
+ authorJid: author,
535
+ item: msg.fastRatchetKeySenderKeyDistributionMessage
536
+ })
537
+ } catch (err) {
538
+ logger.error(
539
+ { key: fullMessage.key, err },
540
+ 'failed to process fast ratchet sender key distribution message'
541
+ )
542
+ }
543
+ }
544
+ if (fullMessage.message) {
545
+ Object.assign(fullMessage.message, msg)
546
+ } else {
547
+ fullMessage.message = msg
548
+ }
549
+ // --- story_reply metadata ---
550
+ if (e2eType === 'story_reply') {
551
+ fullMessage.storyReply = true
552
+ // Secondary check: quoted status JID in the decoded message
553
+ const quotedJid = msg.extendedTextMessage?.contextInfo?.remoteJid
554
+ if (quotedJid && (0, WABinary_1.isJidStatusBroadcast)(quotedJid)) {
555
+ fullMessage.storyReply = true
556
+ }
557
+ }
558
+ // --- feed_reshare metadata ---
559
+ if (e2eType === 'feed_reshare') {
560
+ fullMessage.feedReshare = true
561
+ }
562
+ // --- view_once type from enc attributes ---
563
+ if (attrs.view_once === 'read' || attrs.view_once === 'write') {
564
+ fullMessage.viewOnceType = attrs.view_once
565
+ }
566
+ // --- XMA message ---
567
+ if (msg.xmaMessage) {
568
+ fullMessage.xma = msg.xmaMessage
569
+ fullMessage.messageType = 'xma'
570
+ }
571
+ // --- native_flow_response ---
572
+ if (e2eType === 'native_flow_response' || msg.nativeFlowResponseMessage) {
573
+ fullMessage.messageType = 'native_flow_response'
574
+ if (msg.nativeFlowResponseMessage) {
575
+ fullMessage.nativeFlowResponse = msg.nativeFlowResponseMessage
576
+ // SMB quick reply is a business-specific native flow variant
577
+ if (msg.nativeFlowResponseMessage.name === 'md_smb_quick_reply') {
578
+ fullMessage.smbQuickReply = true
579
+ }
580
+ }
581
+ }
582
+ // --- call_permission_request ---
583
+ if (msg.callPermissionRequestMessage) {
584
+ fullMessage.messageType = 'call_permission_request'
585
+ fullMessage.callPermissionRequest = msg.callPermissionRequestMessage
586
+ }
587
+ // --- Product / Order / Catalog types ---
588
+ if (msg.productMessage) {
589
+ fullMessage.messageType = 'product'
590
+ } else if (msg.orderMessage) {
591
+ fullMessage.messageType = 'order'
592
+ } else if (msg.catalogMessage || msg.listMessage?.catalogType) {
593
+ fullMessage.messageType = 'catalog'
594
+ }
595
+ // --- Payment types ---
596
+ if (msg.paymentMessage) {
597
+ fullMessage.messageType = 'payment'
598
+ const pm = msg.paymentMessage
599
+ fullMessage.paymentInfo = {
600
+ amount: pm.amount1000 ? pm.amount1000 / 1000 : null,
601
+ currency: pm.currencyCodeIso4217 || null,
602
+ status: pm.status || null,
603
+ transactionTimestamp: pm.transactionTimestamp
604
+ ? pm.transactionTimestamp.toNumber?.() || pm.transactionTimestamp
605
+ : null,
606
+ type: pm.type || null,
607
+ method: pm.paymentMethod || null,
608
+ futureProofed: pm.futureProofed || false
609
+ }
610
+ }
611
+ if (msg.requestPaymentMessage) {
612
+ fullMessage.messageType = 'request_payment'
613
+ fullMessage.paymentRequest = {
614
+ amount: msg.requestPaymentMessage.amount || null,
615
+ currency: msg.requestPaymentMessage.currencyCodeIso4217 || null,
616
+ expiry: msg.requestPaymentMessage.expiryTimestamp || null
617
+ }
618
+ }
619
+ if (msg.sendPaymentMessage) {
620
+ fullMessage.messageType = 'send_payment'
621
+ }
622
+ if (msg.cancelPaymentRequestMessage) {
623
+ fullMessage.messageType = 'cancel_payment'
624
+ }
625
+ // --- Sticker flags ---
626
+ if (msg.stickerMessage) {
627
+ if (msg.stickerMessage.isAvatar) {
628
+ fullMessage.isAvatarSticker = true
629
+ }
630
+ if (msg.stickerMessage.isAiSticker || msg.stickerMessage.isGenAI) {
631
+ fullMessage.isAiSticker = true
632
+ }
633
+ }
634
+ // --- StickerPackMessage ---
635
+ if (msg.stickerPackMessage) {
636
+ fullMessage.messageType = 'sticker_pack'
637
+ const sp = msg.stickerPackMessage
638
+ fullMessage.stickerPack = {
639
+ id: sp.stickerPackId,
640
+ name: sp.name,
641
+ // 0 = FIRST_PARTY, 1 = THIRD_PARTY
642
+ origin: sp.stickerPackOrigin,
643
+ size: sp.stickerPackSize,
644
+ stickers: sp.stickers || []
645
+ }
646
+ }
647
+ // --- AI media collection metadata from bot context ---
648
+ if (msg.messageContextInfo?.botMetadata?.aiMediaCollectionMetadata) {
649
+ fullMessage.aiMediaCollectionMetadata = {
650
+ collectionId: msg.messageContextInfo.botMetadata.aiMediaCollectionMetadata.collectionId,
651
+ uploadOrderIndex: msg.messageContextInfo.botMetadata.aiMediaCollectionMetadata.uploadOrderIndex
652
+ }
653
+ }
654
+ // --- ProtocolMessage: AI media collection coordination ---
655
+ if (msg.protocolMessage?.aiMediaCollectionMessage) {
656
+ fullMessage.messageType = 'ai_media_collection'
657
+ const amc = msg.protocolMessage.aiMediaCollectionMessage
658
+ fullMessage.aiMediaCollection = {
659
+ collectionId: amc.collectionId,
660
+ expectedMediaCount: amc.expectedMediaCount
661
+ }
662
+ }
663
+ // --- SplitPaymentMessage ---
664
+ if (msg.splitPaymentMessage) {
665
+ fullMessage.messageType = 'split_payment'
666
+ const sp = msg.splitPaymentMessage
667
+ fullMessage.splitPayment = {
668
+ splitId: sp.splitId,
669
+ totalAmount: sp.totalAmount,
670
+ description: sp.description,
671
+ requesterJid: sp.requesterJid,
672
+ participants: (sp.participants || []).map(p => ({
673
+ jid: p.jid,
674
+ amount: p.amount,
675
+ // 0 = PENDING, 1 = PAID
676
+ status: p.status
677
+ })),
678
+ createdAtMs: sp.createdAtMs ? sp.createdAtMs.toNumber?.() || sp.createdAtMs : null
679
+ }
680
+ }
681
+ // --- PaymentInviteMessage (FBPAY / UPI / NOVI) ---
682
+ if (msg.paymentInviteMessage) {
683
+ fullMessage.messageType = 'payment_invite'
684
+ const SERVICE_TYPE = { 0: 'UNKNOWN', 1: 'FBPAY', 2: 'NOVI', 3: 'UPI' }
685
+ fullMessage.paymentInvite = {
686
+ serviceType: SERVICE_TYPE[msg.paymentInviteMessage.serviceType] || 'UNKNOWN',
687
+ expiry: msg.paymentInviteMessage.expiryTimestamp
688
+ ? msg.paymentInviteMessage.expiryTimestamp.toNumber?.() || msg.paymentInviteMessage.expiryTimestamp
689
+ : null,
690
+ incentiveEligible: msg.paymentInviteMessage.incentiveEligible || false
691
+ }
692
+ }
693
+ // --- PaymentReminderMessage ---
694
+ if (msg.paymentReminderMessage) {
695
+ fullMessage.messageType = 'payment_reminder'
696
+ }
697
+ // --- companion_enc_static ---
698
+ if (e2eType === 'companion_enc_static') {
699
+ fullMessage.companionEncStatic = true
700
+ }
701
+ // --- avatar_sticker / genai_sticker enc type ---
702
+ if (e2eType === 'avatar_sticker' || e2eType === 'genai_sticker') {
703
+ fullMessage.stickerType = e2eType
704
+ }
705
+ // --- account_authentication_request ---
706
+ if (e2eType === 'account_authentication_request' || msg.accountAuthRequestMessage) {
707
+ fullMessage.messageType = 'account_auth_request'
708
+ }
709
+ // --- motion_video ---
710
+ if (e2eType === 'motion_video' || (msg.videoMessage && msg.videoMessage.motionVideo)) {
711
+ fullMessage.messageType = 'motion_video'
712
+ fullMessage.motionVideo = true
713
+ }
714
+ // --- motion_photo ---
715
+ if (e2eType === 'motion_photo' || (msg.imageMessage && msg.imageMessage.motionPhoto)) {
716
+ fullMessage.messageType = 'motion_photo'
717
+ fullMessage.motionPhoto = true
718
+ }
719
+ // --- non-E2EE plaintext (newsletter / system channel messages) ---
720
+ if (e2eType === 'plaintext') {
721
+ fullMessage.isNonE2EE = true
722
+ }
723
+ // Auto-decode richResponseMessage text so m.msg.text is populated
724
+ {
725
+ const rich = fullMessage.message?.richResponseMessage
726
+ if (rich && !rich.text) {
727
+ const decoded = decodeRichResponseMessage(rich)
728
+ if (decoded) rich.text = decoded
729
+ }
730
+ const editedRich = fullMessage.message?.protocolMessage?.editedMessage?.richResponseMessage
731
+ if (editedRich && !editedRich.text) {
732
+ const decoded = decodeRichResponseMessage(editedRich)
733
+ if (decoded) editedRich.text = decoded
734
+ }
735
+ }
736
+ // Save messageSecret for any message (AI group server may set it on any message)
737
+ {
738
+ const secret = msg.messageContextInfo?.messageSecret
739
+ if (secret) {
740
+ const secretBuf = Buffer.isBuffer(secret)
741
+ ? secret
742
+ : Buffer.from(secret.buffer, secret.byteOffset, secret.byteLength)
743
+ setBotMessageSecret(fullMessage.key.id, secretBuf, fullMessage.key.remoteJid)
744
+ }
745
+ }
746
+ } catch (err) {
747
+ const errorContext = {
748
+ key: fullMessage.key,
749
+ err,
750
+ messageType: tag === 'plaintext' ? 'plaintext' : attrs.type,
751
+ sender,
752
+ author,
753
+ isSessionRecordError: isSessionRecordError(err)
754
+ }
755
+ logger.error(errorContext, 'failed to decrypt message')
756
+ fullMessage.messageStubType = WAProto_1.proto.WebMessageInfo.StubType.CIPHERTEXT
757
+ fullMessage.messageStubParameters = [err.message.toString()]
758
+ }
759
+ }
760
+ }
761
+ // if nothing was found to decrypt
762
+ if (!decryptables && !fullMessage.key?.isViewOnce) {
763
+ fullMessage.messageStubType = WAProto_1.proto.WebMessageInfo.StubType.CIPHERTEXT
764
+ fullMessage.messageStubParameters = [exports.NO_MESSAGE_FOUND_ERROR_TEXT]
765
+ }
766
+ }
767
+ }
768
+ }
769
+ exports.decryptMessageNode = decryptMessageNode
770
+ /**
771
+ * Decode text content from a richResponseMessage (Meta AI).
772
+ * Tries submessages first, then parses base64 JSON from unifiedResponse.data.
773
+ * Returns the extracted text string or '' on failure.
774
+ */
775
+ function decodeRichResponseMessage(richMsg) {
776
+ try {
777
+ if (!richMsg) return ''
778
+ if (Array.isArray(richMsg.submessages) && richMsg.submessages.length > 0) {
779
+ const sub = richMsg.submessages
780
+ .map(s => s.messageText)
781
+ .filter(Boolean)
782
+ .join('\n')
783
+ if (sub) return sub
784
+ }
785
+ const data = richMsg.unifiedResponse?.data
786
+ if (!data) return ''
787
+ const json = JSON.parse(Buffer.from(data, 'base64').toString('utf8'))
788
+ const texts = []
789
+ for (const section of json.sections || []) {
790
+ const prim = section?.view_model?.primitive
791
+ if (prim?.text) texts.push(prim.text)
792
+ if (prim?.header) texts.push(prim.header)
793
+ for (const sub of section?.view_model?.items || []) {
794
+ if (sub?.primitive?.text) texts.push(sub.primitive.text)
795
+ }
796
+ }
797
+ return texts.join('\n')
798
+ } catch {
799
+ return ''
800
+ }
801
+ }
802
+ /**
803
+ * Utility function to check if an error is related to missing session record
804
+ */
805
+ function isSessionRecordError(error) {
806
+ const errorMessage = error?.message || error?.toString() || ''
807
+ return exports.DECRYPTION_RETRY_CONFIG.sessionRecordErrors.some(errorPattern => errorMessage.includes(errorPattern))
808
+ }