@badzz88/baileys 8.4.7 → 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 (240) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1055 -337
  3. package/WAProto/WAProto.proto +347 -6
  4. package/WAProto/fix-import.js +38 -0
  5. package/WAProto/fix-imports.js +86 -85
  6. package/WAProto/index.d.ts +4913 -25
  7. package/WAProto/index.js +14074 -98
  8. package/package.json +50 -90
  9. package/src/Defaults/index.js +201 -0
  10. package/src/Defaults/phonenumber-mcc.json +223 -0
  11. package/src/Signal/Group/ciphertext-message.js +15 -0
  12. package/src/Signal/Group/group-session-builder.js +92 -0
  13. package/src/Signal/Group/group_cipher.js +89 -0
  14. package/src/Signal/Group/index.js +136 -0
  15. package/src/Signal/Group/keyhelper.js +73 -0
  16. package/src/Signal/Group/sender-chain-key.js +32 -0
  17. package/src/Signal/Group/sender-key-distribution-message.js +66 -0
  18. package/src/Signal/Group/sender-key-message.js +69 -0
  19. package/src/Signal/Group/sender-key-name.js +50 -0
  20. package/src/Signal/Group/sender-key-record.js +44 -0
  21. package/src/Signal/Group/sender-key-state.js +97 -0
  22. package/src/Signal/Group/sender-message-key.js +30 -0
  23. package/src/Signal/libsignal.js +470 -0
  24. package/src/Signal/lid-mapping.js +262 -0
  25. package/src/Socket/Client/index.js +30 -0
  26. package/src/Socket/Client/types.js +13 -0
  27. package/src/Socket/Client/websocket.js +62 -0
  28. package/src/Socket/aigroups.js +240 -0
  29. package/src/Socket/business.js +422 -0
  30. package/src/Socket/chats.js +2374 -0
  31. package/src/Socket/communities.js +580 -0
  32. package/src/Socket/graphql.js +915 -0
  33. package/src/Socket/groups.js +812 -0
  34. package/src/Socket/index.js +37 -0
  35. package/src/Socket/interactive-handler.js +579 -0
  36. package/src/Socket/interop.js +566 -0
  37. package/src/Socket/managed-account.js +214 -0
  38. package/src/Socket/messages-recv.js +3012 -0
  39. package/src/Socket/messages-send.js +2163 -0
  40. package/{lib → src}/Socket/mex.js +11 -5
  41. package/src/Socket/newsletter.js +1057 -0
  42. package/src/Socket/privacy.js +452 -0
  43. package/src/Socket/registration.js +434 -0
  44. package/src/Socket/socket.js +1079 -0
  45. package/src/Socket/text-router.js +67 -0
  46. package/src/Socket/username.js +234 -0
  47. package/src/Store/index.js +36 -0
  48. package/src/Store/make-cache-manager-store.js +90 -0
  49. package/src/Store/make-in-memory-store.js +506 -0
  50. package/src/Store/make-ordered-dictionary.js +81 -0
  51. package/src/Store/object-repository.js +29 -0
  52. package/src/Types/Auth.js +38 -0
  53. package/src/Types/Bussines.js +2 -0
  54. package/src/Types/Call.js +2 -0
  55. package/src/Types/Chat.js +4 -0
  56. package/src/Types/Contact.js +2 -0
  57. package/src/Types/Events.js +2 -0
  58. package/src/Types/GroupMetadata.js +2 -0
  59. package/src/Types/Label.js +27 -0
  60. package/src/Types/LabelAssociation.js +9 -0
  61. package/src/Types/Message.js +95 -0
  62. package/src/Types/Newsletter.js +152 -0
  63. package/src/Types/Product.js +2 -0
  64. package/src/Types/Signal.js +2 -0
  65. package/src/Types/Socket.js +2 -0
  66. package/src/Types/State.js +70 -0
  67. package/src/Types/USync.js +2 -0
  68. package/src/Types/index.js +54 -0
  69. package/src/Utils/auth-utils.js +306 -0
  70. package/src/Utils/browser-utils.js +114 -0
  71. package/src/Utils/business.js +247 -0
  72. package/src/Utils/chat-utils.js +1272 -0
  73. package/src/Utils/consumer-application.js +107 -0
  74. package/src/Utils/crypto.js +125 -0
  75. package/src/Utils/decode-wa-message.js +808 -0
  76. package/src/Utils/event-buffer.js +586 -0
  77. package/src/Utils/generics.js +640 -0
  78. package/src/Utils/group-history.js +60 -0
  79. package/src/Utils/history.js +244 -0
  80. package/src/Utils/identity-change-handler.js +52 -0
  81. package/src/Utils/index.js +53 -0
  82. package/src/Utils/jid-display-normalization.js +218 -0
  83. package/src/Utils/link-preview.js +143 -0
  84. package/src/Utils/logger.js +9 -0
  85. package/src/Utils/lt-hash.js +10 -0
  86. package/src/Utils/make-mutex.js +36 -0
  87. package/src/Utils/message-composer.js +479 -0
  88. package/src/Utils/message-inspect.js +400 -0
  89. package/src/Utils/message-retry-manager.js +231 -0
  90. package/src/Utils/messages-media.js +943 -0
  91. package/src/Utils/messages.js +2490 -0
  92. package/src/Utils/meta-ai-msmsg.js +133 -0
  93. package/src/Utils/noise-handler.js +194 -0
  94. package/src/Utils/offline-node-processor.js +42 -0
  95. package/src/Utils/pre-key-manager.js +107 -0
  96. package/src/Utils/process-message.js +1047 -0
  97. package/src/Utils/reporting-utils.js +262 -0
  98. package/src/Utils/signal.js +192 -0
  99. package/src/Utils/stanza-ack.js +74 -0
  100. package/src/Utils/sync-action-utils.js +54 -0
  101. package/src/Utils/tc-token-utils.js +161 -0
  102. package/src/Utils/use-multi-file-auth-state.js +121 -0
  103. package/src/Utils/validate-connection.js +248 -0
  104. package/src/Utils/voip-rekey.js +22 -0
  105. package/src/WABinary/constants.js +1304 -0
  106. package/src/WABinary/decode.js +377 -0
  107. package/src/WABinary/encode.js +58 -0
  108. package/src/WABinary/generic-utils.js +148 -0
  109. package/src/WABinary/index.js +33 -0
  110. package/src/WABinary/jid-utils.js +374 -0
  111. package/src/WABinary/types.js +2 -0
  112. package/src/WAM/BinaryInfo.js +13 -0
  113. package/src/WAM/constants.js +39486 -0
  114. package/src/WAM/encode.js +142 -0
  115. package/src/WAM/index.js +31 -0
  116. package/src/WAUSync/Protocols/USyncBotProfileProtocol.js +55 -0
  117. package/src/WAUSync/Protocols/USyncBusinessProtocol.js +100 -0
  118. package/src/WAUSync/Protocols/USyncContactProtocol.js +60 -0
  119. package/src/WAUSync/Protocols/USyncDeviceProtocol.js +65 -0
  120. package/src/WAUSync/Protocols/USyncDisappearingModeProtocol.js +27 -0
  121. package/src/WAUSync/Protocols/USyncFeatureProtocol.js +74 -0
  122. package/src/WAUSync/Protocols/USyncLIDProtocol.js +31 -0
  123. package/src/WAUSync/Protocols/USyncPictureProtocol.js +32 -0
  124. package/src/WAUSync/Protocols/USyncSidelistProtocol.js +29 -0
  125. package/src/WAUSync/Protocols/USyncStatusProtocol.js +44 -0
  126. package/src/WAUSync/Protocols/USyncTextStatusProtocol.js +38 -0
  127. package/src/WAUSync/Protocols/USyncUsernameProtocol.js +28 -0
  128. package/src/WAUSync/Protocols/index.js +40 -0
  129. package/src/WAUSync/USyncBackoff.js +31 -0
  130. package/src/WAUSync/USyncQuery.js +204 -0
  131. package/src/WAUSync/USyncUser.js +58 -0
  132. package/src/WAUSync/index.js +32 -0
  133. package/src/antiban.js +4726 -0
  134. package/{lib → src}/index.js +48 -15
  135. package/lib/Defaults/index.js +0 -130
  136. package/lib/Signal/Group/ciphertext-message.js +0 -12
  137. package/lib/Signal/Group/group-session-builder.js +0 -30
  138. package/lib/Signal/Group/group_cipher.js +0 -82
  139. package/lib/Signal/Group/index.js +0 -12
  140. package/lib/Signal/Group/keyhelper.js +0 -18
  141. package/lib/Signal/Group/sender-chain-key.js +0 -26
  142. package/lib/Signal/Group/sender-key-distribution-message.js +0 -63
  143. package/lib/Signal/Group/sender-key-message.js +0 -66
  144. package/lib/Signal/Group/sender-key-name.js +0 -48
  145. package/lib/Signal/Group/sender-key-record.js +0 -41
  146. package/lib/Signal/Group/sender-key-state.js +0 -84
  147. package/lib/Signal/Group/sender-message-key.js +0 -26
  148. package/lib/Signal/libsignal.js +0 -431
  149. package/lib/Signal/lid-mapping.js +0 -277
  150. package/lib/Socket/Client/index.js +0 -3
  151. package/lib/Socket/Client/types.js +0 -11
  152. package/lib/Socket/Client/websocket.js +0 -54
  153. package/lib/Socket/business.js +0 -379
  154. package/lib/Socket/chats.js +0 -1193
  155. package/lib/Socket/communities.js +0 -431
  156. package/lib/Socket/groups.js +0 -374
  157. package/lib/Socket/index.js +0 -12
  158. package/lib/Socket/luxu.js +0 -386
  159. package/lib/Socket/messages-recv.js +0 -1916
  160. package/lib/Socket/messages-send.js +0 -1453
  161. package/lib/Socket/newsletter.js +0 -251
  162. package/lib/Socket/socket.js +0 -980
  163. package/lib/Socket/username.js +0 -146
  164. package/lib/Store/index.js +0 -10
  165. package/lib/Store/keyed-db.js +0 -108
  166. package/lib/Store/make-cache-manager-store.js +0 -85
  167. package/lib/Store/make-in-memory-store.js +0 -198
  168. package/lib/Store/make-ordered-dictionary.js +0 -75
  169. package/lib/Store/object-repository.js +0 -32
  170. package/lib/Types/Auth.js +0 -2
  171. package/lib/Types/Bussines.js +0 -2
  172. package/lib/Types/Call.js +0 -2
  173. package/lib/Types/Chat.js +0 -8
  174. package/lib/Types/Contact.js +0 -2
  175. package/lib/Types/Events.js +0 -2
  176. package/lib/Types/GroupMetadata.js +0 -2
  177. package/lib/Types/Label.js +0 -25
  178. package/lib/Types/LabelAssociation.js +0 -7
  179. package/lib/Types/Message.js +0 -11
  180. package/lib/Types/Mex.js +0 -37
  181. package/lib/Types/Product.js +0 -2
  182. package/lib/Types/Signal.js +0 -2
  183. package/lib/Types/Socket.js +0 -3
  184. package/lib/Types/State.js +0 -56
  185. package/lib/Types/USync.js +0 -2
  186. package/lib/Types/index.js +0 -26
  187. package/lib/Utils/auth-utils.js +0 -302
  188. package/lib/Utils/browser-utils.js +0 -49
  189. package/lib/Utils/business.js +0 -231
  190. package/lib/Utils/chat-utils.js +0 -872
  191. package/lib/Utils/companion-reg-client-utils.js +0 -35
  192. package/lib/Utils/crypto.js +0 -118
  193. package/lib/Utils/decode-wa-message.js +0 -350
  194. package/lib/Utils/event-buffer.js +0 -622
  195. package/lib/Utils/generics.js +0 -403
  196. package/lib/Utils/history.js +0 -134
  197. package/lib/Utils/identity-change-handler.js +0 -50
  198. package/lib/Utils/index.js +0 -23
  199. package/lib/Utils/link-preview.js +0 -85
  200. package/lib/Utils/logger.js +0 -3
  201. package/lib/Utils/lt-hash.js +0 -8
  202. package/lib/Utils/make-mutex.js +0 -33
  203. package/lib/Utils/message-composer.js +0 -273
  204. package/lib/Utils/message-retry-manager.js +0 -265
  205. package/lib/Utils/messages-media.js +0 -788
  206. package/lib/Utils/messages.js +0 -1260
  207. package/lib/Utils/noise-handler.js +0 -201
  208. package/lib/Utils/offline-node-processor.js +0 -40
  209. package/lib/Utils/pre-key-manager.js +0 -106
  210. package/lib/Utils/process-message.js +0 -630
  211. package/lib/Utils/reporting-utils.js +0 -258
  212. package/lib/Utils/signal.js +0 -201
  213. package/lib/Utils/stanza-ack.js +0 -38
  214. package/lib/Utils/sync-action-utils.js +0 -49
  215. package/lib/Utils/tc-token-utils.js +0 -163
  216. package/lib/Utils/use-multi-file-auth-state.js +0 -121
  217. package/lib/Utils/validate-connection.js +0 -203
  218. package/lib/WABinary/constants.js +0 -1301
  219. package/lib/WABinary/decode.js +0 -262
  220. package/lib/WABinary/encode.js +0 -220
  221. package/lib/WABinary/generic-utils.js +0 -204
  222. package/lib/WABinary/index.js +0 -6
  223. package/lib/WABinary/jid-utils.js +0 -98
  224. package/lib/WABinary/types.js +0 -2
  225. package/lib/WAM/BinaryInfo.js +0 -10
  226. package/lib/WAM/constants.js +0 -22853
  227. package/lib/WAM/encode.js +0 -150
  228. package/lib/WAM/index.js +0 -4
  229. package/lib/WAUSync/Protocols/USyncContactProtocol.js +0 -52
  230. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +0 -54
  231. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +0 -27
  232. package/lib/WAUSync/Protocols/USyncNewsletterProtocol.js +0 -263
  233. package/lib/WAUSync/Protocols/USyncStatusProtocol.js +0 -38
  234. package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +0 -25
  235. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +0 -51
  236. package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +0 -29
  237. package/lib/WAUSync/Protocols/index.js +0 -6
  238. package/lib/WAUSync/USyncQuery.js +0 -98
  239. package/lib/WAUSync/USyncUser.js +0 -31
  240. 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
+ }