@badzz88/baileys 8.5.2 → 8.5.4

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 (110) hide show
  1. package/README.md +1 -1
  2. package/WAProto/WAProto.proto +1256 -75
  3. package/WAProto/index.d.ts +36042 -19649
  4. package/WAProto/index.js +181990 -135645
  5. package/engine-requirements.js +7 -15
  6. package/lib/Defaults/index.js +22 -17
  7. package/lib/Signal/Group/group_cipher.js +5 -5
  8. package/lib/Signal/Group/keyhelper.js +4 -4
  9. package/lib/Signal/Group/sender-chain-key.js +2 -2
  10. package/lib/Signal/Group/sender-key-distribution-message.js +1 -1
  11. package/lib/Signal/Group/sender-key-message.js +3 -3
  12. package/lib/Signal/Group/sender-key-record.js +1 -1
  13. package/lib/Signal/Group/sender-message-key.js +5 -5
  14. package/lib/Signal/libsignal.js +39 -59
  15. package/lib/Signal/lid-mapping.js +28 -10
  16. package/lib/Socket/aigroups.js +5 -5
  17. package/lib/Socket/business.js +3 -11
  18. package/lib/Socket/chats.js +668 -319
  19. package/lib/Socket/communities.js +85 -89
  20. package/lib/Socket/graphql.js +435 -228
  21. package/lib/Socket/groups.js +132 -211
  22. package/lib/Socket/index.js +9 -7
  23. package/lib/Socket/interactive-handler.js +117 -60
  24. package/lib/Socket/interop.js +56 -175
  25. package/lib/Socket/managed-account.js +79 -48
  26. package/lib/Socket/messages-recv.js +898 -340
  27. package/lib/Socket/messages-send.js +462 -160
  28. package/lib/Socket/mex.js +40 -53
  29. package/lib/Socket/newsletter.js +291 -291
  30. package/lib/Socket/privacy.js +77 -265
  31. package/lib/Socket/registration.js +164 -157
  32. package/lib/Socket/socket.js +181 -199
  33. package/lib/Socket/username.js +144 -227
  34. package/lib/Store/make-cache-manager-store.js +2 -2
  35. package/lib/Store/make-in-memory-store.js +25 -141
  36. package/lib/Types/Auth.js +3 -3
  37. package/lib/Types/Label.js +1 -1
  38. package/lib/Types/LabelAssociation.js +1 -1
  39. package/lib/Types/Newsletter.js +96 -65
  40. package/lib/Types/State.js +4 -4
  41. package/lib/Types/index.js +1 -1
  42. package/lib/Utils/auth-utils.js +52 -57
  43. package/lib/Utils/browser-utils.js +1 -1
  44. package/lib/Utils/business.js +2 -6
  45. package/lib/Utils/chat-utils.js +102 -38
  46. package/lib/Utils/crypto.js +54 -84
  47. package/lib/Utils/decode-wa-message.js +316 -83
  48. package/lib/Utils/event-buffer.js +37 -61
  49. package/lib/Utils/generics.js +157 -103
  50. package/lib/Utils/group-history.js +3 -12
  51. package/lib/Utils/history.js +15 -15
  52. package/lib/Utils/index.js +1 -5
  53. package/lib/Utils/link-preview.js +3 -8
  54. package/lib/Utils/lt-hash.js +2 -35
  55. package/lib/Utils/make-mutex.js +1 -1
  56. package/lib/Utils/message-inspect.js +393 -0
  57. package/lib/Utils/message-retry-manager.js +27 -92
  58. package/lib/Utils/messages-media.js +159 -130
  59. package/lib/Utils/messages.js +144 -566
  60. package/lib/Utils/meta-ai-msmsg.js +62 -202
  61. package/lib/Utils/noise-handler.js +19 -21
  62. package/lib/Utils/offline-node-processor.js +3 -8
  63. package/lib/Utils/pre-key-manager.js +13 -23
  64. package/lib/Utils/process-message.js +197 -106
  65. package/lib/Utils/reporting-utils.js +2 -2
  66. package/lib/Utils/signal.js +28 -63
  67. package/lib/Utils/stanza-ack.js +39 -12
  68. package/lib/Utils/sync-action-utils.js +4 -7
  69. package/lib/Utils/tc-token-utils.js +20 -25
  70. package/lib/Utils/use-multi-file-auth-state.js +30 -14
  71. package/lib/Utils/validate-connection.js +59 -19
  72. package/lib/WABinary/decode.js +50 -16
  73. package/lib/WABinary/encode.js +54 -224
  74. package/lib/WABinary/generic-utils.js +7 -97
  75. package/lib/WABinary/jid-utils.js +27 -14
  76. package/lib/WAM/encode.js +7 -7
  77. package/lib/WAUSync/Protocols/USyncBusinessProtocol.js +58 -1
  78. package/lib/WAUSync/Protocols/USyncContactProtocol.js +7 -1
  79. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +13 -5
  80. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +1 -4
  81. package/lib/WAUSync/Protocols/USyncFeatureProtocol.js +20 -7
  82. package/lib/WAUSync/Protocols/USyncNewsletterProtocol.js +865 -0
  83. package/lib/WAUSync/Protocols/USyncPictureProtocol.js +1 -1
  84. package/lib/WAUSync/Protocols/USyncSidelistProtocol.js +2 -2
  85. package/lib/WAUSync/Protocols/USyncStatusProtocol.js +7 -2
  86. package/lib/WAUSync/Protocols/USyncTextStatusProtocol.js +1 -1
  87. package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +2 -1
  88. package/lib/WAUSync/Protocols/index.js +1 -0
  89. package/lib/WAUSync/USyncBackoff.js +26 -0
  90. package/lib/WAUSync/USyncQuery.js +77 -6
  91. package/lib/WAUSync/USyncUser.js +16 -8
  92. package/lib/WAUSync/index.js +1 -0
  93. package/lib/antiban.js +608 -854
  94. package/lib/index.js +3 -3
  95. package/package.json +16 -19
  96. package/lib/Socket/luxu.js +0 -387
  97. package/lib/Socket/text-router.js +0 -83
  98. package/lib/Store/keyed-db.js +0 -108
  99. package/lib/Types/Mex.js +0 -112
  100. package/lib/Utils/command-loader.d.ts +0 -31
  101. package/lib/Utils/command-loader.js +0 -100
  102. package/lib/Utils/companion-reg-client-utils.js +0 -42
  103. package/lib/Utils/curve25519-js.js +0 -275
  104. package/lib/Utils/native-bridge.js +0 -82
  105. package/lib/Utils/session-pool.d.ts +0 -16
  106. package/lib/Utils/session-pool.js +0 -94
  107. package/lib/Utils/sticker.d.ts +0 -17
  108. package/lib/Utils/sticker.js +0 -145
  109. package/lib/Utils/view-once-cache.d.ts +0 -9
  110. package/lib/Utils/view-once-cache.js +0 -79
@@ -25,7 +25,7 @@ const makeKeyedMutex = () => {
25
25
  return await entry.mutex.runExclusive(task)
26
26
  } finally {
27
27
  entry.refCount--
28
- // only delete it if this is still the current entry
28
+
29
29
  if (entry.refCount === 0 && map.get(key) === entry) {
30
30
  map.delete(key)
31
31
  }
@@ -0,0 +1,393 @@
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
+
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
+ const normalizeMessageContent = content => {
23
+ if (!content) {
24
+ return undefined
25
+ }
26
+
27
+ for (let i = 0; i < 5; i++) {
28
+ const inner = getFutureProofMessage(content)
29
+ if (!inner) {
30
+ break
31
+ }
32
+ content = inner.message
33
+ }
34
+ return content
35
+ function getFutureProofMessage(message) {
36
+ return (
37
+ message.ephemeralMessage ||
38
+ message.viewOnceMessage ||
39
+ message.documentWithCaptionMessage ||
40
+ message.viewOnceMessageV2 ||
41
+ message.viewOnceMessageV2Extension ||
42
+ message.editedMessage ||
43
+ message.groupMentionedMessage ||
44
+ message.botInvokeMessage ||
45
+ message.lottieStickerMessage ||
46
+ message.eventCoverImage ||
47
+ message.statusMentionMessage ||
48
+ message.pollCreationOptionImageMessage ||
49
+ message.associatedChildMessage ||
50
+ message.groupStatusMentionMessage ||
51
+ message.pollCreationMessageV4 ||
52
+ message.pollCreationMessageV5 ||
53
+ message.statusAddYours ||
54
+ message.groupStatusMessage ||
55
+ message.limitSharingMessage ||
56
+ message.botTaskMessage ||
57
+ message.questionMessage ||
58
+ message.groupStatusMessageV2 ||
59
+ message.botForwardedMessage ||
60
+ message.questionReplyMessage ||
61
+ message.newsletterAdminProfileMessage ||
62
+ message.newsletterAdminProfileMessageV2 ||
63
+ message.newsletterAdminProfileStatusMessage ||
64
+ message.spoilerMessage ||
65
+ message.groupStatusV3Message ||
66
+ message.pollCreationMessageV6
67
+ )
68
+ }
69
+ }
70
+ exports.normalizeMessageContent = normalizeMessageContent
71
+
72
+
73
+ const extractMessageContent = content => {
74
+ const extractFromTemplateMessage = msg => {
75
+ if (msg.imageMessage) {
76
+ return { imageMessage: msg.imageMessage }
77
+ } else if (msg.documentMessage) {
78
+ return { documentMessage: msg.documentMessage }
79
+ } else if (msg.videoMessage) {
80
+ return { videoMessage: msg.videoMessage }
81
+ } else if (msg.locationMessage) {
82
+ return { locationMessage: msg.locationMessage }
83
+ } else {
84
+ return {
85
+ conversation:
86
+ 'contentText' in msg ? msg.contentText : 'hydratedContentText' in msg ? msg.hydratedContentText : ''
87
+ }
88
+ }
89
+ }
90
+ content = normalizeMessageContent(content)
91
+ if (content?.buttonsMessage) {
92
+ return extractFromTemplateMessage(content.buttonsMessage)
93
+ }
94
+ if (content?.templateMessage?.hydratedFourRowTemplate) {
95
+ return extractFromTemplateMessage(content?.templateMessage?.hydratedFourRowTemplate)
96
+ }
97
+ if (content?.templateMessage?.hydratedTemplate) {
98
+ return extractFromTemplateMessage(content?.templateMessage?.hydratedTemplate)
99
+ }
100
+ if (content?.templateMessage?.fourRowTemplate) {
101
+ return extractFromTemplateMessage(content?.templateMessage?.fourRowTemplate)
102
+ }
103
+ return content
104
+ }
105
+ exports.extractMessageContent = extractMessageContent
106
+
107
+
108
+ const getDevice = id =>
109
+ /^3A.{18}$/.test(id)
110
+ ? 'ios'
111
+ : /^3E.{20}$/.test(id)
112
+ ? 'web'
113
+ : /^(.{21}|.{32})$/.test(id)
114
+ ? 'android'
115
+ : /^(3F|.{18}$)/.test(id)
116
+ ? 'desktop'
117
+ : 'api/baileys'
118
+ exports.getDevice = getDevice
119
+
120
+
121
+ const updateMessageWithReceipt = (msg, receipt) => {
122
+ msg.userReceipt = msg.userReceipt || []
123
+ const recp = msg.userReceipt.find(m => m.userJid === receipt.userJid)
124
+ if (recp) {
125
+ Object.assign(recp, receipt)
126
+ } else {
127
+ msg.userReceipt.push(receipt)
128
+ }
129
+ }
130
+ exports.updateMessageWithReceipt = updateMessageWithReceipt
131
+
132
+
133
+ const updateMessageWithReaction = (msg, reaction) => {
134
+ const authorID = (0, generics_1.getKeyAuthor)(reaction.key)
135
+ const reactions = (msg.reactions || []).filter(r => (0, generics_1.getKeyAuthor)(r.key) !== authorID)
136
+ reaction.text = reaction.text || ''
137
+ reactions.push(reaction)
138
+ msg.reactions = reactions
139
+ }
140
+ exports.updateMessageWithReaction = updateMessageWithReaction
141
+
142
+
143
+ const updateMessageWithPollUpdate = (msg, update) => {
144
+ const authorID = (0, generics_1.getKeyAuthor)(update.pollUpdateMessageKey)
145
+ const reactions = (msg.pollUpdates || []).filter(
146
+ r => (0, generics_1.getKeyAuthor)(r.pollUpdateMessageKey) !== authorID
147
+ )
148
+ if (update.vote?.selectedOptions?.length) {
149
+ reactions.push(update)
150
+ }
151
+ msg.pollUpdates = reactions
152
+ }
153
+ exports.updateMessageWithPollUpdate = updateMessageWithPollUpdate
154
+
155
+
156
+ const updateMessageWithEventResponse = (msg, update) => {
157
+ const authorID = (0, generics_1.getKeyAuthor)(update.eventResponseMessageKey)
158
+ const responses = (msg.eventResponses || []).filter(
159
+ r => (0, generics_1.getKeyAuthor)(r.eventResponseMessageKey) !== authorID
160
+ )
161
+ responses.push(update)
162
+ msg.eventResponses = responses
163
+ }
164
+ exports.updateMessageWithEventResponse = updateMessageWithEventResponse
165
+
166
+
167
+ function getAggregateVotesInPollMessage({ message, pollUpdates }, meId) {
168
+ const opts =
169
+ message?.pollCreationMessage?.options ||
170
+ message?.pollCreationMessageV2?.options ||
171
+ message?.pollCreationMessageV3?.options ||
172
+ message?.pollCreationMessageV5?.options ||
173
+ message?.pollCreationMessageV6?.options ||
174
+ message?.pollCreationMessageV4?.message?.pollCreationMessage?.options ||
175
+ message?.pollCreationMessageV4?.message?.pollCreationMessageV3?.options ||
176
+ []
177
+ const voteHashMap = opts.reduce((acc, opt) => {
178
+ const hash = (0, crypto_2.sha256)(Buffer.from(opt.optionName || '')).toString()
179
+ acc[hash] = {
180
+ name: opt.optionName || '',
181
+ voters: []
182
+ }
183
+ return acc
184
+ }, {})
185
+ for (const update of pollUpdates || []) {
186
+ const { vote } = update
187
+ if (!vote) {
188
+ continue
189
+ }
190
+ for (const option of vote.selectedOptions || []) {
191
+ const hash = option.toString()
192
+ let data = voteHashMap[hash]
193
+ if (!data) {
194
+ voteHashMap[hash] = {
195
+ name: 'Unknown',
196
+ voters: []
197
+ }
198
+ data = voteHashMap[hash]
199
+ }
200
+ voteHashMap[hash].voters.push((0, generics_1.getKeyAuthor)(update.pollUpdateMessageKey, meId))
201
+ }
202
+ }
203
+ return Object.values(voteHashMap)
204
+ }
205
+ exports.getAggregateVotesInPollMessage = getAggregateVotesInPollMessage
206
+
207
+
208
+ const aggregateMessageKeysNotFromMe = keys => {
209
+ const keyMap = {}
210
+ for (const { remoteJid, id, participant, fromMe, sts } of keys) {
211
+ if (!fromMe) {
212
+ const uqKey = `${remoteJid}:${participant || ''}`
213
+ if (!keyMap[uqKey]) {
214
+ keyMap[uqKey] = {
215
+ jid: remoteJid,
216
+ participant: participant,
217
+ messageIds: [],
218
+
219
+ sts: sts
220
+ }
221
+ } else if (keyMap[uqKey].sts !== sts) {
222
+
223
+ keyMap[uqKey].sts = undefined
224
+ }
225
+ keyMap[uqKey].messageIds.push(id)
226
+ }
227
+ }
228
+ return Object.values(keyMap)
229
+ }
230
+ exports.aggregateMessageKeysNotFromMe = aggregateMessageKeysNotFromMe
231
+
232
+
233
+ const isScheduledMessage = msg => !!msg?.scheduledMessageMetadata?.scheduledTime
234
+ exports.isScheduledMessage = isScheduledMessage
235
+
236
+
237
+ const getScheduledMessageTime = msg => {
238
+ const t = msg?.scheduledMessageMetadata?.scheduledTime
239
+ if (!t) return null
240
+ return new Date(Number(t) * 1000)
241
+ }
242
+ exports.getScheduledMessageTime = getScheduledMessageTime
243
+
244
+
245
+ const getMessagePaymentInfo = msg => msg?.paymentInfo || msg?.quotedPaymentInfo || null
246
+ exports.getMessagePaymentInfo = getMessagePaymentInfo
247
+
248
+
249
+ const getMessageCommentMetadata = msg => msg?.commentMetadata || null
250
+ exports.getMessageCommentMetadata = getMessageCommentMetadata
251
+
252
+
253
+ const getMessageAddOns = msg => msg?.messageAddOns || []
254
+ exports.getMessageAddOns = getMessageAddOns
255
+
256
+
257
+ const getPollCorrectAnswer = pollMsg => {
258
+ const poll =
259
+ pollMsg?.pollCreationMessage ||
260
+ pollMsg?.pollCreationMessageV2 ||
261
+ pollMsg?.pollCreationMessageV3 ||
262
+ pollMsg?.pollCreationMessageV5 ||
263
+ pollMsg?.pollCreationMessageV6
264
+ if (!poll) return null
265
+ const isQuiz = poll.pollType === proto.Message.PollType?.QUIZ || poll.pollType === 1
266
+ return isQuiz ? poll.correctAnswer?.optionName || null : null
267
+ }
268
+ exports.getPollCorrectAnswer = getPollCorrectAnswer
269
+
270
+
271
+ function getAggregateResponsesInEventMessage({ eventResponses }, meLid) {
272
+ const responseTypes = ['GOING', 'NOT_GOING', 'MAYBE']
273
+ const responseMap = {}
274
+
275
+ for (const type of responseTypes) {
276
+ responseMap[type] = {
277
+ response: type,
278
+ responders: []
279
+ }
280
+ }
281
+ for (const update of eventResponses) {
282
+ const { response } = update.response || {}
283
+ const responseType = proto.Message.EventResponseMessage.EventResponseType[response]
284
+ if (responseType !== 'UNKNOWN' && responseMap[responseType]) {
285
+ responseMap[responseType].responders.push(generics_1.getKeyAuthor(update.eventResponseMessageKey, meLid))
286
+ }
287
+ }
288
+
289
+ return Object.values(responseMap)
290
+ }
291
+ exports.getAggregateResponsesInEventMessage = getAggregateResponsesInEventMessage
292
+
293
+ const REUPLOAD_REQUIRED_STATUS = [410, 404]
294
+
295
+
296
+ const downloadMediaMessage = async (message, type, options, ctx) => {
297
+ const result = await downloadMsg().catch(async error => {
298
+
299
+
300
+
301
+ const errorStatus =
302
+ typeof error?.status === 'number'
303
+ ? error.status
304
+ : typeof error?.output?.statusCode === 'number'
305
+ ? error.output.statusCode
306
+ : undefined
307
+ if (ctx && typeof errorStatus === 'number' && REUPLOAD_REQUIRED_STATUS.includes(errorStatus)) {
308
+ ctx.logger.info({ key: message.key }, 'sending reupload media request...')
309
+ message = await ctx.reuploadRequest(message)
310
+ const result = await downloadMsg()
311
+ return result
312
+ }
313
+ throw error
314
+ })
315
+ return result
316
+ async function downloadMsg() {
317
+ const mContent = extractMessageContent(message.message)
318
+ if (!mContent) {
319
+ throw new boom_1.Boom('No message present', { statusCode: 400, data: message })
320
+ }
321
+ const contentType = getContentType(mContent)
322
+ let mediaType = contentType?.replace('Message', '')
323
+ const media = mContent[contentType]
324
+ if (!media || typeof media !== 'object' || (!('url' in media) && !('thumbnailDirectPath' in media))) {
325
+ throw new boom_1.Boom(`"${contentType}" message is not a media message`)
326
+ }
327
+ let download
328
+ if ('thumbnailDirectPath' in media && !('url' in media)) {
329
+ download = {
330
+ directPath: media.thumbnailDirectPath,
331
+ mediaKey: media.mediaKey
332
+ }
333
+ mediaType = 'thumbnail-link'
334
+ } else {
335
+ download = media
336
+ }
337
+ const stream = await (0, messages_media_1.downloadContentFromMessage)(download, mediaType, options)
338
+ if (type === 'buffer') {
339
+ const bufferArray = []
340
+ for await (const chunk of stream) {
341
+ bufferArray.push(chunk)
342
+ }
343
+ return Buffer.concat(bufferArray)
344
+ }
345
+ return stream
346
+ }
347
+ }
348
+ exports.downloadMediaMessage = downloadMediaMessage
349
+
350
+
351
+ const assertMediaContent = content => {
352
+ content = extractMessageContent(content)
353
+ const mediaContent =
354
+ content?.documentMessage ||
355
+ content?.imageMessage ||
356
+ content?.videoMessage ||
357
+ content?.audioMessage ||
358
+ content?.stickerMessage
359
+ if (!mediaContent) {
360
+ throw new boom_1.Boom('given message is not a media message', { statusCode: 400, data: content })
361
+ }
362
+ return mediaContent
363
+ }
364
+ exports.assertMediaContent = assertMediaContent
365
+
366
+
367
+ const toJid = id => {
368
+ if (!id) return ''
369
+ if (id.includes('@')) return id
370
+ return `${id}@s.whatsapp.net`
371
+ }
372
+ exports.toJid = toJid
373
+
374
+
375
+ const getSenderLid = message => {
376
+ const k = message.key
377
+ if (!k) {
378
+ return { jid: '', lid: '' }
379
+ }
380
+ const jid = k.participant || k.remoteJid || ''
381
+ if (jid.endsWith('@lid') || jid.endsWith('@hosted.lid')) {
382
+ return { jid, lid: jid }
383
+ }
384
+ if (k.lid && typeof k.lid === 'string') {
385
+ const lid = k.lid.includes('@') ? k.lid : (0, WABinary_1.jidEncode)(k.lid, 'lid')
386
+ return { jid, lid }
387
+ }
388
+ if (k.participantLid && (0, WABinary_1.isLidUser)(k.participantLid)) {
389
+ return { jid, lid: k.participantLid }
390
+ }
391
+ return { jid, lid: '' }
392
+ }
393
+ exports.getSenderLid = getSenderLid
@@ -2,24 +2,24 @@
2
2
  Object.defineProperty(exports, '__esModule', { value: true })
3
3
  exports.MessageRetryManager = exports.RetryReason = void 0
4
4
  const lru_cache_1 = require('lru-cache')
5
- /** Number of sent messages to cache in memory for handling retry receipts */
5
+
6
6
  const RECENT_MESSAGES_SIZE = 512
7
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
8
+
9
+ const RECREATE_SESSION_TIMEOUT = 60 * 60 * 1000
10
10
  const PHONE_REQUEST_DELAY = 3000
11
- // Retry reason codes matching WhatsApp Web's Signal error codes.
11
+
12
12
  var RetryReason
13
13
  ;(function (RetryReason) {
14
14
  RetryReason[(RetryReason['UnknownError'] = 0)] = 'UnknownError'
15
15
  RetryReason[(RetryReason['SignalErrorNoSession'] = 1)] = 'SignalErrorNoSession'
16
16
  RetryReason[(RetryReason['SignalErrorInvalidKey'] = 2)] = 'SignalErrorInvalidKey'
17
17
  RetryReason[(RetryReason['SignalErrorInvalidKeyId'] = 3)] = 'SignalErrorInvalidKeyId'
18
- /** MAC verification failed - most common cause of decryption failures */
18
+
19
19
  RetryReason[(RetryReason['SignalErrorInvalidMessage'] = 4)] = 'SignalErrorInvalidMessage'
20
20
  RetryReason[(RetryReason['SignalErrorInvalidSignature'] = 5)] = 'SignalErrorInvalidSignature'
21
21
  RetryReason[(RetryReason['SignalErrorFutureMessage'] = 6)] = 'SignalErrorFutureMessage'
22
- /** Explicit MAC failure - session is definitely out of sync */
22
+
23
23
  RetryReason[(RetryReason['SignalErrorBadMac'] = 7)] = 'SignalErrorBadMac'
24
24
  RetryReason[(RetryReason['SignalErrorInvalidSession'] = 8)] = 'SignalErrorInvalidSession'
25
25
  RetryReason[(RetryReason['SignalErrorInvalidMsgKey'] = 9)] = 'SignalErrorInvalidMsgKey'
@@ -28,7 +28,7 @@ var RetryReason
28
28
  RetryReason[(RetryReason['AdvFailure'] = 12)] = 'AdvFailure'
29
29
  RetryReason[(RetryReason['StatusRevokeDelay'] = 13)] = 'StatusRevokeDelay'
30
30
  })(RetryReason || (exports.RetryReason = RetryReason = {}))
31
- /** Error codes that indicate a MAC failure and require immediate session recreation */
31
+
32
32
  const MAC_ERROR_CODES = new Set([RetryReason.SignalErrorInvalidMessage, RetryReason.SignalErrorBadMac])
33
33
  class MessageRetryManager {
34
34
  constructor(logger, maxMsgRetryCount) {
@@ -54,12 +54,7 @@ class MessageRetryManager {
54
54
  ttl: 15 * 60 * 1000,
55
55
  ttlAutopurge: true,
56
56
  updateAgeOnGet: true
57
- }) // 15 minutes TTL
58
- this.baseKeys = new lru_cache_1.LRUCache({
59
- max: 1024,
60
- ttl: 15 * 60 * 1000,
61
- ttlAutopurge: true
62
- })
57
+ })
63
58
  this.pendingPhoneRequests = {}
64
59
  this.maxMsgRetryCount = 5
65
60
  this.statistics = {
@@ -72,13 +67,11 @@ class MessageRetryManager {
72
67
  }
73
68
  this.maxMsgRetryCount = maxMsgRetryCount
74
69
  }
75
- /**
76
- * Add a recent message to the cache for retry handling
77
- */
70
+
78
71
  addRecentMessage(to, id, message) {
79
72
  const key = { to, id }
80
73
  const keyStr = this.keyToString(key)
81
- // Add new message
74
+
82
75
  this.recentMessagesMap.set(keyStr, {
83
76
  message,
84
77
  timestamp: Date.now()
@@ -86,20 +79,15 @@ class MessageRetryManager {
86
79
  this.messageKeyIndex.set(id, keyStr)
87
80
  this.logger.debug(`Added message to retry cache: ${to}/${id}`)
88
81
  }
89
- /**
90
- * Get a recent message from the cache
91
- */
82
+
92
83
  getRecentMessage(to, id) {
93
84
  const key = { to, id }
94
85
  const keyStr = this.keyToString(key)
95
86
  return this.recentMessagesMap.get(keyStr)
96
87
  }
97
- /**
98
- * Check if a session should be recreated based on retry count, history, and error code.
99
- * MAC errors (codes 4 and 7) trigger immediate session recreation regardless of timeout.
100
- */
88
+
101
89
  shouldRecreateSession(jid, hasSession, errorCode) {
102
- // If we don't have a session, always recreate
90
+
103
91
  if (!hasSession) {
104
92
  this.sessionRecreateHistory.set(jid, Date.now())
105
93
  this.statistics.sessionRecreations++
@@ -108,7 +96,7 @@ class MessageRetryManager {
108
96
  recreate: true
109
97
  }
110
98
  }
111
- // IMMEDIATE recreation for MAC errors - session is definitely out of sync
99
+
112
100
  if (errorCode !== undefined && MAC_ERROR_CODES.has(errorCode)) {
113
101
  this.sessionRecreateHistory.set(jid, Date.now())
114
102
  this.statistics.sessionRecreations++
@@ -123,7 +111,7 @@ class MessageRetryManager {
123
111
  }
124
112
  const now = Date.now()
125
113
  const prevTime = this.sessionRecreateHistory.get(jid)
126
- // If no previous recreation or it's been more than an hour
114
+
127
115
  if (!prevTime || now - prevTime > RECREATE_SESSION_TIMEOUT) {
128
116
  this.sessionRecreateHistory.set(jid, now)
129
117
  this.statistics.sessionRecreations++
@@ -134,10 +122,7 @@ class MessageRetryManager {
134
122
  }
135
123
  return { reason: '', recreate: false }
136
124
  }
137
- /**
138
- * Parse error code from retry receipt's retry node.
139
- * Returns undefined if no error code is present.
140
- */
125
+
141
126
  parseRetryErrorCode(errorAttr) {
142
127
  if (errorAttr === undefined || errorAttr === '') {
143
128
  return undefined
@@ -146,62 +131,48 @@ class MessageRetryManager {
146
131
  if (Number.isNaN(code)) {
147
132
  return undefined
148
133
  }
149
- // Validate it's a known RetryReason
134
+
150
135
  if (code >= RetryReason.UnknownError && code <= RetryReason.StatusRevokeDelay) {
151
136
  return code
152
137
  }
153
138
  return RetryReason.UnknownError
154
139
  }
155
- /**
156
- * Check if an error code indicates a MAC failure
157
- */
140
+
158
141
  isMacError(errorCode) {
159
142
  return errorCode !== undefined && MAC_ERROR_CODES.has(errorCode)
160
143
  }
161
- /**
162
- * Increment retry counter for a message
163
- */
144
+
164
145
  incrementRetryCount(messageId) {
165
146
  this.retryCounters.set(messageId, (this.retryCounters.get(messageId) || 0) + 1)
166
147
  this.statistics.totalRetries++
167
148
  return this.retryCounters.get(messageId)
168
149
  }
169
- /**
170
- * Get retry count for a message
171
- */
150
+
172
151
  getRetryCount(messageId) {
173
152
  return this.retryCounters.get(messageId) || 0
174
153
  }
175
- /**
176
- * Check if message has exceeded maximum retry attempts
177
- */
154
+
178
155
  hasExceededMaxRetries(messageId) {
179
156
  return this.getRetryCount(messageId) >= this.maxMsgRetryCount
180
157
  }
181
- /**
182
- * Mark retry as successful
183
- */
158
+
184
159
  markRetrySuccess(messageId) {
185
160
  this.statistics.successfulRetries++
186
- // Clean up retry counter for successful message
161
+
187
162
  this.retryCounters.delete(messageId)
188
163
  this.cancelPendingPhoneRequest(messageId)
189
164
  this.removeRecentMessage(messageId)
190
165
  }
191
- /**
192
- * Mark retry as failed
193
- */
166
+
194
167
  markRetryFailed(messageId) {
195
168
  this.statistics.failedRetries++
196
169
  this.retryCounters.delete(messageId)
197
170
  this.cancelPendingPhoneRequest(messageId)
198
171
  this.removeRecentMessage(messageId)
199
172
  }
200
- /**
201
- * Schedule a phone request with delay
202
- */
173
+
203
174
  schedulePhoneRequest(messageId, callback, delay = PHONE_REQUEST_DELAY) {
204
- // Cancel any existing request for this message
175
+
205
176
  this.cancelPendingPhoneRequest(messageId)
206
177
  this.pendingPhoneRequests[messageId] = setTimeout(() => {
207
178
  delete this.pendingPhoneRequests[messageId]
@@ -210,9 +181,7 @@ class MessageRetryManager {
210
181
  }, delay)
211
182
  this.logger.debug(`Scheduled phone request for message ${messageId} with ${delay}ms delay`)
212
183
  }
213
- /**
214
- * Cancel pending phone request
215
- */
184
+
216
185
  cancelPendingPhoneRequest(messageId) {
217
186
  const timeout = this.pendingPhoneRequests[messageId]
218
187
  if (timeout) {
@@ -221,40 +190,6 @@ class MessageRetryManager {
221
190
  this.logger.debug(`Cancelled pending phone request for message ${messageId}`)
222
191
  }
223
192
  }
224
- clear() {
225
- this.recentMessagesMap.clear()
226
- this.messageKeyIndex.clear()
227
- this.sessionRecreateHistory.clear()
228
- this.retryCounters.clear()
229
- this.baseKeys.clear()
230
- for (const messageId of Object.keys(this.pendingPhoneRequests)) {
231
- this.cancelPendingPhoneRequest(messageId)
232
- }
233
- this.statistics = {
234
- totalRetries: 0,
235
- successfulRetries: 0,
236
- failedRetries: 0,
237
- mediaRetries: 0,
238
- sessionRecreations: 0,
239
- phoneRequests: 0
240
- }
241
- }
242
- saveBaseKey(addr, msgId, baseKey) {
243
- this.baseKeys.set(`${addr}:${msgId}`, baseKey)
244
- }
245
- hasSameBaseKey(addr, msgId, baseKey) {
246
- const stored = this.baseKeys.get(`${addr}:${msgId}`)
247
- if (!stored || stored.length !== baseKey.length) {
248
- return false
249
- }
250
- for (let i = 0; i < stored.length; i++) {
251
- if (stored[i] !== baseKey[i]) return false
252
- }
253
- return true
254
- }
255
- deleteBaseKey(addr, msgId) {
256
- this.baseKeys.delete(`${addr}:${msgId}`)
257
- }
258
193
  keyToString(key) {
259
194
  return `${key.to}${MESSAGE_KEY_SEPARATOR}${key.id}`
260
195
  }