@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,400 @@
1
+ 'use strict'
2
+ Object.defineProperty(exports, '__esModule', { value: true })
3
+
4
+ const boom_1 = require('@hapi/boom')
5
+ const { proto } = require('../../WAProto/index.js')
6
+ const WABinary_1 = require('../WABinary')
7
+ const crypto_2 = require('./crypto')
8
+ const generics_1 = require('./generics')
9
+ const messages_media_1 = require('./messages-media')
10
+
11
+ /** Get the key to access the true type of content */
12
+ const getContentType = content => {
13
+ if (content) {
14
+ const keys = Object.keys(content)
15
+ const key = keys.find(k => (k === 'conversation' || k.includes('Message')) && k !== 'senderKeyDistributionMessage')
16
+ return key
17
+ }
18
+ }
19
+ exports.getContentType = getContentType
20
+
21
+ /**
22
+ * Normalizes ephemeral, view once messages to regular message content
23
+ * Eg. image messages in ephemeral messages, in view once messages etc.
24
+ */
25
+ const normalizeMessageContent = content => {
26
+ if (!content) {
27
+ return undefined
28
+ }
29
+ // set max iterations to prevent an infinite loop
30
+ for (let i = 0; i < 5; i++) {
31
+ const inner = getFutureProofMessage(content)
32
+ if (!inner) {
33
+ break
34
+ }
35
+ content = inner.message
36
+ }
37
+ return content
38
+ function getFutureProofMessage(message) {
39
+ return (
40
+ message.ephemeralMessage ||
41
+ message.viewOnceMessage ||
42
+ message.documentWithCaptionMessage ||
43
+ message.viewOnceMessageV2 ||
44
+ message.viewOnceMessageV2Extension ||
45
+ message.editedMessage ||
46
+ message.groupMentionedMessage ||
47
+ message.botInvokeMessage ||
48
+ message.lottieStickerMessage ||
49
+ message.eventCoverImage ||
50
+ message.statusMentionMessage ||
51
+ message.pollCreationOptionImageMessage ||
52
+ message.associatedChildMessage ||
53
+ message.groupStatusMentionMessage ||
54
+ message.pollCreationMessageV4 ||
55
+ message.pollCreationMessageV5 ||
56
+ message.statusAddYours ||
57
+ message.groupStatusMessage ||
58
+ message.limitSharingMessage ||
59
+ message.botTaskMessage ||
60
+ message.questionMessage ||
61
+ message.groupStatusMessageV2 ||
62
+ message.botForwardedMessage ||
63
+ message.questionReplyMessage ||
64
+ message.newsletterAdminProfileMessage ||
65
+ message.newsletterAdminProfileMessageV2 ||
66
+ message.newsletterAdminProfileStatusMessage ||
67
+ message.spoilerMessage ||
68
+ message.groupStatusV3Message ||
69
+ message.pollCreationMessageV6
70
+ )
71
+ }
72
+ }
73
+ exports.normalizeMessageContent = normalizeMessageContent
74
+
75
+ /**
76
+ * Extract the true message content from a message
77
+ * Eg. extracts the inner message from a disappearing message/view once message
78
+ */
79
+ const extractMessageContent = content => {
80
+ const extractFromTemplateMessage = msg => {
81
+ if (msg.imageMessage) {
82
+ return { imageMessage: msg.imageMessage }
83
+ } else if (msg.documentMessage) {
84
+ return { documentMessage: msg.documentMessage }
85
+ } else if (msg.videoMessage) {
86
+ return { videoMessage: msg.videoMessage }
87
+ } else if (msg.locationMessage) {
88
+ return { locationMessage: msg.locationMessage }
89
+ } else {
90
+ return {
91
+ conversation:
92
+ 'contentText' in msg ? msg.contentText : 'hydratedContentText' in msg ? msg.hydratedContentText : ''
93
+ }
94
+ }
95
+ }
96
+ content = normalizeMessageContent(content)
97
+ if (content?.buttonsMessage) {
98
+ return extractFromTemplateMessage(content.buttonsMessage)
99
+ }
100
+ if (content?.templateMessage?.hydratedFourRowTemplate) {
101
+ return extractFromTemplateMessage(content?.templateMessage?.hydratedFourRowTemplate)
102
+ }
103
+ if (content?.templateMessage?.hydratedTemplate) {
104
+ return extractFromTemplateMessage(content?.templateMessage?.hydratedTemplate)
105
+ }
106
+ if (content?.templateMessage?.fourRowTemplate) {
107
+ return extractFromTemplateMessage(content?.templateMessage?.fourRowTemplate)
108
+ }
109
+ return content
110
+ }
111
+ exports.extractMessageContent = extractMessageContent
112
+
113
+ /** Returns the device predicted by message ID */
114
+ const getDevice = id =>
115
+ /^3A.{18}$/.test(id)
116
+ ? 'ios'
117
+ : /^3E.{20}$/.test(id)
118
+ ? 'web'
119
+ : /^(.{21}|.{32})$/.test(id)
120
+ ? 'android'
121
+ : /^(3F|.{18}$)/.test(id)
122
+ ? 'desktop'
123
+ : 'api/baileys'
124
+ exports.getDevice = getDevice
125
+
126
+ /** Upserts a receipt in the message */
127
+ const updateMessageWithReceipt = (msg, receipt) => {
128
+ msg.userReceipt = msg.userReceipt || []
129
+ const recp = msg.userReceipt.find(m => m.userJid === receipt.userJid)
130
+ if (recp) {
131
+ Object.assign(recp, receipt)
132
+ } else {
133
+ msg.userReceipt.push(receipt)
134
+ }
135
+ }
136
+ exports.updateMessageWithReceipt = updateMessageWithReceipt
137
+
138
+ /** Update the message with a new reaction */
139
+ const updateMessageWithReaction = (msg, reaction) => {
140
+ const authorID = (0, generics_1.getKeyAuthor)(reaction.key)
141
+ const reactions = (msg.reactions || []).filter(r => (0, generics_1.getKeyAuthor)(r.key) !== authorID)
142
+ reaction.text = reaction.text || ''
143
+ reactions.push(reaction)
144
+ msg.reactions = reactions
145
+ }
146
+ exports.updateMessageWithReaction = updateMessageWithReaction
147
+
148
+ /** Update the message with a new poll update */
149
+ const updateMessageWithPollUpdate = (msg, update) => {
150
+ const authorID = (0, generics_1.getKeyAuthor)(update.pollUpdateMessageKey)
151
+ const reactions = (msg.pollUpdates || []).filter(
152
+ r => (0, generics_1.getKeyAuthor)(r.pollUpdateMessageKey) !== authorID
153
+ )
154
+ if (update.vote?.selectedOptions?.length) {
155
+ reactions.push(update)
156
+ }
157
+ msg.pollUpdates = reactions
158
+ }
159
+ exports.updateMessageWithPollUpdate = updateMessageWithPollUpdate
160
+
161
+ /** Update the message with a new event response */
162
+ const updateMessageWithEventResponse = (msg, update) => {
163
+ const authorID = (0, generics_1.getKeyAuthor)(update.eventResponseMessageKey)
164
+ const responses = (msg.eventResponses || []).filter(
165
+ r => (0, generics_1.getKeyAuthor)(r.eventResponseMessageKey) !== authorID
166
+ )
167
+ responses.push(update)
168
+ msg.eventResponses = responses
169
+ }
170
+ exports.updateMessageWithEventResponse = updateMessageWithEventResponse
171
+
172
+ /**
173
+ * Aggregates all poll updates in a poll.
174
+ * @param msg the poll creation message
175
+ * @param meId your jid
176
+ * @returns A list of options & their voters
177
+ */
178
+ function getAggregateVotesInPollMessage({ message, pollUpdates }, meId) {
179
+ const opts =
180
+ message?.pollCreationMessage?.options ||
181
+ message?.pollCreationMessageV2?.options ||
182
+ message?.pollCreationMessageV3?.options ||
183
+ message?.pollCreationMessageV5?.options ||
184
+ message?.pollCreationMessageV6?.options ||
185
+ message?.pollCreationMessageV4?.message?.pollCreationMessage?.options ||
186
+ message?.pollCreationMessageV4?.message?.pollCreationMessageV3?.options ||
187
+ []
188
+ const voteHashMap = opts.reduce((acc, opt) => {
189
+ const hash = (0, crypto_2.sha256)(Buffer.from(opt.optionName || '')).toString()
190
+ acc[hash] = {
191
+ name: opt.optionName || '',
192
+ voters: []
193
+ }
194
+ return acc
195
+ }, {})
196
+ for (const update of pollUpdates || []) {
197
+ const { vote } = update
198
+ if (!vote) {
199
+ continue
200
+ }
201
+ for (const option of vote.selectedOptions || []) {
202
+ const hash = option.toString()
203
+ let data = voteHashMap[hash]
204
+ if (!data) {
205
+ voteHashMap[hash] = {
206
+ name: 'Unknown',
207
+ voters: []
208
+ }
209
+ data = voteHashMap[hash]
210
+ }
211
+ voteHashMap[hash].voters.push((0, generics_1.getKeyAuthor)(update.pollUpdateMessageKey, meId))
212
+ }
213
+ }
214
+ return Object.values(voteHashMap)
215
+ }
216
+ exports.getAggregateVotesInPollMessage = getAggregateVotesInPollMessage
217
+
218
+ /** Given a list of message keys, aggregates them by chat & sender. Useful for sending read receipts in bulk */
219
+ const aggregateMessageKeysNotFromMe = keys => {
220
+ const keyMap = {}
221
+ for (const { remoteJid, id, participant, fromMe, sts } of keys) {
222
+ if (!fromMe) {
223
+ const uqKey = `${remoteJid}:${participant || ''}`
224
+ if (!keyMap[uqKey]) {
225
+ keyMap[uqKey] = {
226
+ jid: remoteJid,
227
+ participant: participant,
228
+ messageIds: [],
229
+ // sts is per-message; kept only for single-message interop receipts
230
+ sts: sts
231
+ }
232
+ } else if (keyMap[uqKey].sts !== sts) {
233
+ // Multiple messages with different sts — can't aggregate a single sts
234
+ keyMap[uqKey].sts = undefined
235
+ }
236
+ keyMap[uqKey].messageIds.push(id)
237
+ }
238
+ }
239
+ return Object.values(keyMap)
240
+ }
241
+ exports.aggregateMessageKeysNotFromMe = aggregateMessageKeysNotFromMe
242
+
243
+ /** Check if a WebMessageInfo has a scheduled reveal time (ConditionalRevealMessage) */
244
+ const isScheduledMessage = msg => !!msg?.scheduledMessageMetadata?.scheduledTime
245
+ exports.isScheduledMessage = isScheduledMessage
246
+
247
+ /** Get scheduled reveal time of a message as a Date, or null */
248
+ const getScheduledMessageTime = msg => {
249
+ const t = msg?.scheduledMessageMetadata?.scheduledTime
250
+ if (!t) return null
251
+ return new Date(Number(t) * 1000)
252
+ }
253
+ exports.getScheduledMessageTime = getScheduledMessageTime
254
+
255
+ /** Extract PaymentInfo from a WebMessageInfo (the payment status field, not the message content) */
256
+ const getMessagePaymentInfo = msg => msg?.paymentInfo || msg?.quotedPaymentInfo || null
257
+ exports.getMessagePaymentInfo = getMessagePaymentInfo
258
+
259
+ /** Get all comment metadata from a WebMessageInfo */
260
+ const getMessageCommentMetadata = msg => msg?.commentMetadata || null
261
+ exports.getMessageCommentMetadata = getMessageCommentMetadata
262
+
263
+ /** Get all message add-ons (reactions, poll updates, pins) from a WebMessageInfo */
264
+ const getMessageAddOns = msg => msg?.messageAddOns || []
265
+ exports.getMessageAddOns = getMessageAddOns
266
+
267
+ /** Get the quiz correct answer from a poll creation message, if it's a quiz */
268
+ const getPollCorrectAnswer = pollMsg => {
269
+ const poll =
270
+ pollMsg?.pollCreationMessage ||
271
+ pollMsg?.pollCreationMessageV2 ||
272
+ pollMsg?.pollCreationMessageV3 ||
273
+ pollMsg?.pollCreationMessageV5 ||
274
+ pollMsg?.pollCreationMessageV6
275
+ if (!poll) return null
276
+ const isQuiz = poll.pollType === proto.Message.PollType?.QUIZ || poll.pollType === 1
277
+ return isQuiz ? poll.correctAnswer?.optionName || null : null
278
+ }
279
+ exports.getPollCorrectAnswer = getPollCorrectAnswer
280
+
281
+ /**
282
+ * Aggregates all event responses in an event message.
283
+ * @param msg the event creation message
284
+ * @param meLid your lid
285
+ * @returns A list of response types & their responders
286
+ */
287
+ function getAggregateResponsesInEventMessage({ eventResponses }, meLid) {
288
+ const responseTypes = ['GOING', 'NOT_GOING', 'MAYBE']
289
+ const responseMap = {}
290
+
291
+ for (const type of responseTypes) {
292
+ responseMap[type] = {
293
+ response: type,
294
+ responders: []
295
+ }
296
+ }
297
+ for (const update of eventResponses) {
298
+ const { response } = update.response || {}
299
+ const responseType = proto.Message.EventResponseMessage.EventResponseType[response]
300
+ if (responseType !== 'UNKNOWN' && responseMap[responseType]) {
301
+ responseMap[responseType].responders.push(generics_1.getKeyAuthor(update.eventResponseMessageKey, meLid))
302
+ }
303
+ }
304
+
305
+ return Object.values(responseMap)
306
+ }
307
+ exports.getAggregateResponsesInEventMessage = getAggregateResponsesInEventMessage
308
+
309
+ const REUPLOAD_REQUIRED_STATUS = [410, 404]
310
+
311
+ /** Downloads the given message. Throws an error if it's not a media message */
312
+ const downloadMediaMessage = async (message, type, options, ctx) => {
313
+ const result = await downloadMsg().catch(async error => {
314
+ if (ctx && typeof error?.status === 'number' && REUPLOAD_REQUIRED_STATUS.includes(error.status)) {
315
+ ctx.logger.info({ key: message.key }, 'sending reupload media request...')
316
+ message = await ctx.reuploadRequest(message)
317
+ const result = await downloadMsg()
318
+ return result
319
+ }
320
+ throw error
321
+ })
322
+ return result
323
+ async function downloadMsg() {
324
+ const mContent = extractMessageContent(message.message)
325
+ if (!mContent) {
326
+ throw new boom_1.Boom('No message present', { statusCode: 400, data: message })
327
+ }
328
+ const contentType = getContentType(mContent)
329
+ let mediaType = contentType?.replace('Message', '')
330
+ const media = mContent[contentType]
331
+ if (!media || typeof media !== 'object' || (!('url' in media) && !('thumbnailDirectPath' in media))) {
332
+ throw new boom_1.Boom(`"${contentType}" message is not a media message`)
333
+ }
334
+ let download
335
+ if ('thumbnailDirectPath' in media && !('url' in media)) {
336
+ download = {
337
+ directPath: media.thumbnailDirectPath,
338
+ mediaKey: media.mediaKey
339
+ }
340
+ mediaType = 'thumbnail-link'
341
+ } else {
342
+ download = media
343
+ }
344
+ const stream = await (0, messages_media_1.downloadContentFromMessage)(download, mediaType, options)
345
+ if (type === 'buffer') {
346
+ const bufferArray = []
347
+ for await (const chunk of stream) {
348
+ bufferArray.push(chunk)
349
+ }
350
+ return Buffer.concat(bufferArray)
351
+ }
352
+ return stream
353
+ }
354
+ }
355
+ exports.downloadMediaMessage = downloadMediaMessage
356
+
357
+ /** Checks whether the given message is a media message; if it is returns the inner content */
358
+ const assertMediaContent = content => {
359
+ content = extractMessageContent(content)
360
+ const mediaContent =
361
+ content?.documentMessage ||
362
+ content?.imageMessage ||
363
+ content?.videoMessage ||
364
+ content?.audioMessage ||
365
+ content?.stickerMessage
366
+ if (!mediaContent) {
367
+ throw new boom_1.Boom('given message is not a media message', { statusCode: 400, data: content })
368
+ }
369
+ return mediaContent
370
+ }
371
+ exports.assertMediaContent = assertMediaContent
372
+
373
+ /** Normalizes a bare user id to @s.whatsapp.net. Does not convert LID↔PN; use lidMapping / PN in key.remoteJidAlt when needed. */
374
+ const toJid = id => {
375
+ if (!id) return ''
376
+ if (id.includes('@')) return id
377
+ return `${id}@s.whatsapp.net`
378
+ }
379
+ exports.toJid = toJid
380
+
381
+ /** Returns the peer LID JID when the key is LID-primary (decode sets remoteJid/participant to @lid when WA sends LID). */
382
+ const getSenderLid = message => {
383
+ const k = message.key
384
+ if (!k) {
385
+ return { jid: '', lid: '' }
386
+ }
387
+ const jid = k.participant || k.remoteJid || ''
388
+ if (jid.endsWith('@lid') || jid.endsWith('@hosted.lid')) {
389
+ return { jid, lid: jid }
390
+ }
391
+ if (k.lid && typeof k.lid === 'string') {
392
+ const lid = k.lid.includes('@') ? k.lid : (0, WABinary_1.jidEncode)(k.lid, 'lid')
393
+ return { jid, lid }
394
+ }
395
+ if (k.participantLid && (0, WABinary_1.isLidUser)(k.participantLid)) {
396
+ return { jid, lid: k.participantLid }
397
+ }
398
+ return { jid, lid: '' }
399
+ }
400
+ exports.getSenderLid = getSenderLid
@@ -0,0 +1,231 @@
1
+ 'use strict'
2
+ Object.defineProperty(exports, '__esModule', { value: true })
3
+ exports.MessageRetryManager = exports.RetryReason = void 0
4
+ const lru_cache_1 = require('lru-cache')
5
+ /** Number of sent messages to cache in memory for handling retry receipts */
6
+ const RECENT_MESSAGES_SIZE = 512
7
+ const MESSAGE_KEY_SEPARATOR = '\u0000'
8
+ /** Timeout for session recreation - 1 hour */
9
+ const RECREATE_SESSION_TIMEOUT = 60 * 60 * 1000 // 1 hour in milliseconds
10
+ const PHONE_REQUEST_DELAY = 3000
11
+ // Retry reason codes matching WhatsApp Web's Signal error codes.
12
+ var RetryReason
13
+ ;(function (RetryReason) {
14
+ RetryReason[(RetryReason['UnknownError'] = 0)] = 'UnknownError'
15
+ RetryReason[(RetryReason['SignalErrorNoSession'] = 1)] = 'SignalErrorNoSession'
16
+ RetryReason[(RetryReason['SignalErrorInvalidKey'] = 2)] = 'SignalErrorInvalidKey'
17
+ RetryReason[(RetryReason['SignalErrorInvalidKeyId'] = 3)] = 'SignalErrorInvalidKeyId'
18
+ /** MAC verification failed - most common cause of decryption failures */
19
+ RetryReason[(RetryReason['SignalErrorInvalidMessage'] = 4)] = 'SignalErrorInvalidMessage'
20
+ RetryReason[(RetryReason['SignalErrorInvalidSignature'] = 5)] = 'SignalErrorInvalidSignature'
21
+ RetryReason[(RetryReason['SignalErrorFutureMessage'] = 6)] = 'SignalErrorFutureMessage'
22
+ /** Explicit MAC failure - session is definitely out of sync */
23
+ RetryReason[(RetryReason['SignalErrorBadMac'] = 7)] = 'SignalErrorBadMac'
24
+ RetryReason[(RetryReason['SignalErrorInvalidSession'] = 8)] = 'SignalErrorInvalidSession'
25
+ RetryReason[(RetryReason['SignalErrorInvalidMsgKey'] = 9)] = 'SignalErrorInvalidMsgKey'
26
+ RetryReason[(RetryReason['BadBroadcastEphemeralSetting'] = 10)] = 'BadBroadcastEphemeralSetting'
27
+ RetryReason[(RetryReason['UnknownCompanionNoPrekey'] = 11)] = 'UnknownCompanionNoPrekey'
28
+ RetryReason[(RetryReason['AdvFailure'] = 12)] = 'AdvFailure'
29
+ RetryReason[(RetryReason['StatusRevokeDelay'] = 13)] = 'StatusRevokeDelay'
30
+ })(RetryReason || (exports.RetryReason = RetryReason = {}))
31
+ /** Error codes that indicate a MAC failure and require immediate session recreation */
32
+ const MAC_ERROR_CODES = new Set([RetryReason.SignalErrorInvalidMessage, RetryReason.SignalErrorBadMac])
33
+ class MessageRetryManager {
34
+ constructor(logger, maxMsgRetryCount) {
35
+ this.logger = logger
36
+ this.recentMessagesMap = new lru_cache_1.LRUCache({
37
+ max: RECENT_MESSAGES_SIZE,
38
+ ttl: 5 * 60 * 1000,
39
+ ttlAutopurge: true,
40
+ dispose: (_value, key) => {
41
+ const separatorIndex = key.lastIndexOf(MESSAGE_KEY_SEPARATOR)
42
+ if (separatorIndex > -1) {
43
+ const messageId = key.slice(separatorIndex + MESSAGE_KEY_SEPARATOR.length)
44
+ this.messageKeyIndex.delete(messageId)
45
+ }
46
+ }
47
+ })
48
+ this.messageKeyIndex = new Map()
49
+ this.sessionRecreateHistory = new lru_cache_1.LRUCache({
50
+ ttl: RECREATE_SESSION_TIMEOUT * 2,
51
+ ttlAutopurge: true
52
+ })
53
+ this.retryCounters = new lru_cache_1.LRUCache({
54
+ ttl: 15 * 60 * 1000,
55
+ ttlAutopurge: true,
56
+ updateAgeOnGet: true
57
+ }) // 15 minutes TTL
58
+ this.pendingPhoneRequests = {}
59
+ this.maxMsgRetryCount = 5
60
+ this.statistics = {
61
+ totalRetries: 0,
62
+ successfulRetries: 0,
63
+ failedRetries: 0,
64
+ mediaRetries: 0,
65
+ sessionRecreations: 0,
66
+ phoneRequests: 0
67
+ }
68
+ this.maxMsgRetryCount = maxMsgRetryCount
69
+ }
70
+ /**
71
+ * Add a recent message to the cache for retry handling
72
+ */
73
+ addRecentMessage(to, id, message) {
74
+ const key = { to, id }
75
+ const keyStr = this.keyToString(key)
76
+ // Add new message
77
+ this.recentMessagesMap.set(keyStr, {
78
+ message,
79
+ timestamp: Date.now()
80
+ })
81
+ this.messageKeyIndex.set(id, keyStr)
82
+ this.logger.debug(`Added message to retry cache: ${to}/${id}`)
83
+ }
84
+ /**
85
+ * Get a recent message from the cache
86
+ */
87
+ getRecentMessage(to, id) {
88
+ const key = { to, id }
89
+ const keyStr = this.keyToString(key)
90
+ return this.recentMessagesMap.get(keyStr)
91
+ }
92
+ /**
93
+ * Check if a session should be recreated based on retry count, history, and error code.
94
+ * MAC errors (codes 4 and 7) trigger immediate session recreation regardless of timeout.
95
+ */
96
+ shouldRecreateSession(jid, hasSession, errorCode) {
97
+ // If we don't have a session, always recreate
98
+ if (!hasSession) {
99
+ this.sessionRecreateHistory.set(jid, Date.now())
100
+ this.statistics.sessionRecreations++
101
+ return {
102
+ reason: "we don't have a Signal session with them",
103
+ recreate: true
104
+ }
105
+ }
106
+ // IMMEDIATE recreation for MAC errors - session is definitely out of sync
107
+ if (errorCode !== undefined && MAC_ERROR_CODES.has(errorCode)) {
108
+ this.sessionRecreateHistory.set(jid, Date.now())
109
+ this.statistics.sessionRecreations++
110
+ this.logger.warn(
111
+ { jid, errorCode: RetryReason[errorCode] },
112
+ 'MAC error detected, forcing immediate session recreation'
113
+ )
114
+ return {
115
+ reason: `MAC error (code ${errorCode}: ${RetryReason[errorCode]}), immediate session recreation`,
116
+ recreate: true
117
+ }
118
+ }
119
+ const now = Date.now()
120
+ const prevTime = this.sessionRecreateHistory.get(jid)
121
+ // If no previous recreation or it's been more than an hour
122
+ if (!prevTime || now - prevTime > RECREATE_SESSION_TIMEOUT) {
123
+ this.sessionRecreateHistory.set(jid, now)
124
+ this.statistics.sessionRecreations++
125
+ return {
126
+ reason: 'retry count > 1 and over an hour since last recreation',
127
+ recreate: true
128
+ }
129
+ }
130
+ return { reason: '', recreate: false }
131
+ }
132
+ /**
133
+ * Parse error code from retry receipt's retry node.
134
+ * Returns undefined if no error code is present.
135
+ */
136
+ parseRetryErrorCode(errorAttr) {
137
+ if (errorAttr === undefined || errorAttr === '') {
138
+ return undefined
139
+ }
140
+ const code = parseInt(errorAttr, 10)
141
+ if (Number.isNaN(code)) {
142
+ return undefined
143
+ }
144
+ // Validate it's a known RetryReason
145
+ if (code >= RetryReason.UnknownError && code <= RetryReason.StatusRevokeDelay) {
146
+ return code
147
+ }
148
+ return RetryReason.UnknownError
149
+ }
150
+ /**
151
+ * Check if an error code indicates a MAC failure
152
+ */
153
+ isMacError(errorCode) {
154
+ return errorCode !== undefined && MAC_ERROR_CODES.has(errorCode)
155
+ }
156
+ /**
157
+ * Increment retry counter for a message
158
+ */
159
+ incrementRetryCount(messageId) {
160
+ this.retryCounters.set(messageId, (this.retryCounters.get(messageId) || 0) + 1)
161
+ this.statistics.totalRetries++
162
+ return this.retryCounters.get(messageId)
163
+ }
164
+ /**
165
+ * Get retry count for a message
166
+ */
167
+ getRetryCount(messageId) {
168
+ return this.retryCounters.get(messageId) || 0
169
+ }
170
+ /**
171
+ * Check if message has exceeded maximum retry attempts
172
+ */
173
+ hasExceededMaxRetries(messageId) {
174
+ return this.getRetryCount(messageId) >= this.maxMsgRetryCount
175
+ }
176
+ /**
177
+ * Mark retry as successful
178
+ */
179
+ markRetrySuccess(messageId) {
180
+ this.statistics.successfulRetries++
181
+ // Clean up retry counter for successful message
182
+ this.retryCounters.delete(messageId)
183
+ this.cancelPendingPhoneRequest(messageId)
184
+ this.removeRecentMessage(messageId)
185
+ }
186
+ /**
187
+ * Mark retry as failed
188
+ */
189
+ markRetryFailed(messageId) {
190
+ this.statistics.failedRetries++
191
+ this.retryCounters.delete(messageId)
192
+ this.cancelPendingPhoneRequest(messageId)
193
+ this.removeRecentMessage(messageId)
194
+ }
195
+ /**
196
+ * Schedule a phone request with delay
197
+ */
198
+ schedulePhoneRequest(messageId, callback, delay = PHONE_REQUEST_DELAY) {
199
+ // Cancel any existing request for this message
200
+ this.cancelPendingPhoneRequest(messageId)
201
+ this.pendingPhoneRequests[messageId] = setTimeout(() => {
202
+ delete this.pendingPhoneRequests[messageId]
203
+ this.statistics.phoneRequests++
204
+ callback()
205
+ }, delay)
206
+ this.logger.debug(`Scheduled phone request for message ${messageId} with ${delay}ms delay`)
207
+ }
208
+ /**
209
+ * Cancel pending phone request
210
+ */
211
+ cancelPendingPhoneRequest(messageId) {
212
+ const timeout = this.pendingPhoneRequests[messageId]
213
+ if (timeout) {
214
+ clearTimeout(timeout)
215
+ delete this.pendingPhoneRequests[messageId]
216
+ this.logger.debug(`Cancelled pending phone request for message ${messageId}`)
217
+ }
218
+ }
219
+ keyToString(key) {
220
+ return `${key.to}${MESSAGE_KEY_SEPARATOR}${key.id}`
221
+ }
222
+ removeRecentMessage(messageId) {
223
+ const keyStr = this.messageKeyIndex.get(messageId)
224
+ if (!keyStr) {
225
+ return
226
+ }
227
+ this.recentMessagesMap.delete(keyStr)
228
+ this.messageKeyIndex.delete(messageId)
229
+ }
230
+ }
231
+ exports.MessageRetryManager = MessageRetryManager