@hansaka02/baileys 7.3.4 → 7.3.6

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 (50) hide show
  1. package/README.md +203 -247
  2. package/lib/Defaults/baileys-version.json +2 -2
  3. package/lib/Defaults/connection.js +1 -1
  4. package/lib/Defaults/constants.js +13 -1
  5. package/lib/Defaults/history.js +3 -1
  6. package/lib/Signal/Group/sender-chain-key.js +1 -14
  7. package/lib/Signal/Group/sender-key-distribution-message.js +2 -2
  8. package/lib/Signal/Group/sender-key-record.js +2 -11
  9. package/lib/Signal/Group/sender-key-state.js +11 -57
  10. package/lib/Signal/libsignal.js +200 -116
  11. package/lib/Signal/lid-mapping.js +121 -68
  12. package/lib/Socket/Client/websocket.js +9 -2
  13. package/lib/Socket/business.js +5 -1
  14. package/lib/Socket/chats.js +180 -89
  15. package/lib/Socket/community.js +169 -41
  16. package/lib/Socket/groups.js +25 -21
  17. package/lib/Socket/messages-recv.js +458 -333
  18. package/lib/Socket/messages-send.js +517 -572
  19. package/lib/Socket/mex.js +61 -0
  20. package/lib/Socket/newsletter.js +159 -252
  21. package/lib/Socket/socket.js +283 -100
  22. package/lib/Types/Newsletter.js +32 -25
  23. package/lib/Utils/auth-utils.js +189 -354
  24. package/lib/Utils/browser-utils.js +43 -0
  25. package/lib/Utils/chat-utils.js +166 -41
  26. package/lib/Utils/decode-wa-message.js +77 -35
  27. package/lib/Utils/event-buffer.js +80 -24
  28. package/lib/Utils/generics.js +28 -128
  29. package/lib/Utils/history.js +10 -8
  30. package/lib/Utils/index.js +1 -1
  31. package/lib/Utils/link-preview.js +17 -32
  32. package/lib/Utils/lt-hash.js +28 -22
  33. package/lib/Utils/make-mutex.js +26 -28
  34. package/lib/Utils/message-retry-manager.js +51 -3
  35. package/lib/Utils/messages-media.js +343 -151
  36. package/lib/Utils/messages.js +806 -792
  37. package/lib/Utils/noise-handler.js +33 -2
  38. package/lib/Utils/pre-key-manager.js +126 -0
  39. package/lib/Utils/process-message.js +115 -55
  40. package/lib/Utils/signal.js +45 -18
  41. package/lib/Utils/validate-connection.js +52 -29
  42. package/lib/WABinary/constants.js +1268 -1268
  43. package/lib/WABinary/decode.js +58 -4
  44. package/lib/WABinary/encode.js +54 -7
  45. package/lib/WABinary/jid-utils.js +58 -11
  46. package/lib/WAM/constants.js +19064 -11563
  47. package/lib/WAM/encode.js +57 -8
  48. package/lib/WAUSync/USyncQuery.js +35 -19
  49. package/package.json +9 -8
  50. package/lib/Socket/usync.js +0 -83
@@ -5,15 +5,16 @@ Object.defineProperty(exports, "__esModule", { value: true })
5
5
  const { Boom } = require("@hapi/boom")
6
6
  const { proto } = require("../../WAProto")
7
7
  const {
8
- isJidUser,
9
- isLidUser,
8
+ areJidsSameUser,
9
+ isHostedLidUser,
10
+ isHostedPnUser,
11
+ isJidBroadcast,
10
12
  isJidGroup,
11
13
  isJidMetaAI,
12
- isJidBroadcast,
13
14
  isJidNewsletter,
14
- transferDevice,
15
- areJidsSameUser,
16
- isJidStatusBroadcast
15
+ isJidStatusBroadcast,
16
+ isLidUser,
17
+ isPnUser
17
18
  } = require("../WABinary")
18
19
  const { unpadRandomMax16 } = require("./generics")
19
20
  const { getDevice } = require("./messages")
@@ -52,25 +53,23 @@ const extractAddressingContext = (stanza) => {
52
53
  const sender = stanza.attrs.participant || stanza.attrs.from
53
54
  const addressingMode = stanza.attrs.addressing_mode || (sender?.endsWith('lid') ? 'lid' : 'pn')
54
55
 
55
- if (isLidUser(sender)) {
56
+ if (addressingMode === 'lid') {
56
57
  // Message is LID-addressed: sender is LID, extract corresponding PN
57
58
  // without device data
58
59
  senderAlt = stanza.attrs.participant_pn || stanza.attrs.sender_pn || stanza.attrs.peer_recipient_pn
59
60
  recipientAlt = stanza.attrs.recipient_pn
60
61
  // with device data
61
- if (sender && senderAlt)
62
- senderAlt = transferDevice(sender, senderAlt)
62
+ //if (sender && senderAlt) senderAlt = transferDevice(sender, senderAlt)
63
63
  }
64
-
65
- else if (isJidUser(sender)) {
64
+ else {
66
65
  // Message is PN-addressed: sender is PN, extract corresponding LID
67
66
  // without device data
68
67
  senderAlt = stanza.attrs.participant_lid || stanza.attrs.sender_lid || stanza.attrs.peer_recipient_lid
69
68
  recipientAlt = stanza.attrs.recipient_lid
70
69
  //with device data
71
- if (sender && senderAlt)
72
- senderAlt = transferDevice(sender, senderAlt)
70
+ //if (sender && senderAlt) senderAlt = transferDevice(sender, senderAlt)
73
71
  }
72
+
74
73
  return {
75
74
  addressingMode,
76
75
  senderAlt,
@@ -79,18 +78,21 @@ const extractAddressingContext = (stanza) => {
79
78
  }
80
79
 
81
80
  const getDecryptionJid = async (sender, repository) => {
82
- if (!sender.includes('@s.whatsapp.net')) {
81
+ if (isLidUser(sender) || isHostedLidUser(sender)) {
83
82
  return sender
84
83
  }
85
- return (await repository.lidMapping.getLIDForPN(sender))
84
+ const mapped = await repository.lidMapping.getLIDForPN(sender)
85
+ return mapped || sender
86
86
  }
87
87
 
88
- const storeMappingFromEnvelope = async (stanza, sender, decryptionJid, repository, logger) => {
88
+ const storeMappingFromEnvelope = async (stanza, sender, repository, decryptionJid, logger) => {
89
+ // TODO: Handle hosted IDs
89
90
  const { senderAlt } = extractAddressingContext(stanza)
90
91
 
91
- if (senderAlt && isLidUser(senderAlt) && isJidUser(sender) && decryptionJid === sender) {
92
+ if (senderAlt && isLidUser(senderAlt) && isPnUser(sender) && decryptionJid === sender) {
92
93
  try {
93
94
  await repository.lidMapping.storeLIDPNMappings([{ lid: senderAlt, pn: sender }])
95
+ await repository.migrateSession(sender, senderAlt)
94
96
  logger.debug({ sender, senderAlt }, 'Stored LID mapping from envelope')
95
97
  }
96
98
  catch (error) {
@@ -103,73 +105,90 @@ const storeMappingFromEnvelope = async (stanza, sender, decryptionJid, repositor
103
105
  * Decode the received node as a message.
104
106
  * @note this will only parse the message, not decrypt it
105
107
  */
106
- function decodeMessageNode(stanza, meId, meLid) {
108
+ function decodeMessageNode(stanza, meId, meLid) {
107
109
  let msgType
108
110
  let chatId
109
111
  let author
110
112
  let fromMe = false
113
+
111
114
  const msgId = stanza.attrs.id
112
115
  const from = stanza.attrs.from
113
116
  const participant = stanza.attrs.participant
114
117
  const recipient = stanza.attrs.recipient
115
- const addressingContext = extractAddressingContext(stanza)
118
+ const addressingContext = extractAddressingContext(stanza)
116
119
  const isMe = (jid) => areJidsSameUser(jid, meId)
117
120
  const isMeLid = (jid) => areJidsSameUser(jid, meLid)
118
- if (isJidUser(from) || isLidUser(from)) {
121
+
122
+ if (isPnUser(from) || isLidUser(from) || isHostedLidUser(from) || isHostedPnUser(from)) {
119
123
  if (recipient && !isJidMetaAI(recipient)) {
120
124
  if (!isMe(from) && !isMeLid(from)) {
121
125
  throw new Boom('receipient present, but msg not from me', { data: stanza })
122
126
  }
127
+
123
128
  if (isMe(from) || isMeLid(from)) {
124
129
  fromMe = true
125
130
  }
131
+
126
132
  chatId = recipient
127
133
  }
128
134
  else {
129
135
  chatId = from
130
136
  }
137
+
131
138
  msgType = 'chat'
132
139
  author = from
133
140
  }
141
+
134
142
  else if (isJidGroup(from)) {
135
143
  if (!participant) {
136
144
  throw new Boom('No participant in group message')
137
145
  }
146
+
138
147
  if (isMe(participant) || isMeLid(participant)) {
139
- fromMe = true;
148
+ fromMe = true
140
149
  }
150
+
141
151
  msgType = 'group'
142
152
  author = participant
143
153
  chatId = from
144
154
  }
155
+
145
156
  else if (isJidBroadcast(from)) {
146
157
  if (!participant) {
147
158
  throw new Boom('No participant in group message')
148
159
  }
160
+
149
161
  const isParticipantMe = isMe(participant)
162
+
150
163
  if (isJidStatusBroadcast(from)) {
151
164
  msgType = isParticipantMe ? 'direct_peer_status' : 'other_status'
152
165
  }
166
+
153
167
  else {
154
168
  msgType = isParticipantMe ? 'peer_broadcast' : 'other_broadcast'
155
169
  }
170
+
156
171
  fromMe = isParticipantMe
157
172
  chatId = from
158
173
  author = participant
159
174
  }
175
+
160
176
  else if (isJidNewsletter(from)) {
161
177
  msgType = 'newsletter'
162
178
  chatId = from
163
179
  author = from
180
+
164
181
  if (isMe(from) || isMeLid(from)) {
165
- fromMe = true;
182
+ fromMe = true
166
183
  }
167
184
  }
185
+
168
186
  else {
169
187
  throw new Boom('Unknown message type', { data: stanza })
170
188
  }
171
189
 
172
190
  const pushname = stanza?.attrs?.notify
191
+
173
192
  const key = {
174
193
  remoteJid: chatId,
175
194
  remoteJidAlt: !isJidGroup(chatId) ? addressingContext.senderAlt : undefined,
@@ -177,21 +196,24 @@ function decodeMessageNode(stanza, meId, meLid) {
177
196
  id: msgId,
178
197
  participant,
179
198
  participantAlt: isJidGroup(chatId) ? addressingContext.senderAlt : undefined,
199
+ addressingMode: addressingContext.addressingMode,
200
+ ...(msgType === 'newsletter' && stanza.attrs.server_id ? { server_id: stanza.attrs.server_id } : {})
180
201
  }
202
+
181
203
  const fullMessage = {
182
204
  key,
205
+ category: stanza.attrs.category,
183
206
  messageTimestamp: +stanza.attrs.t,
184
207
  pushName: pushname,
208
+ platform: getDevice(key.id),
185
209
  broadcast: isJidBroadcast(from),
186
- newsletter: isJidNewsletter(from),
187
- platform: getDevice(key.id)
188
- }
189
- if (msgType === 'newsletter') {
190
- fullMessage.newsletter_server_id = +stanza.attrs?.server_id
210
+ newsletter: isJidNewsletter(from)
191
211
  }
212
+
192
213
  if (key.fromMe) {
193
214
  fullMessage.status = proto.WebMessageInfo.Status.SERVER_ACK
194
215
  }
216
+
195
217
  return {
196
218
  fullMessage,
197
219
  author,
@@ -207,30 +229,43 @@ const decryptMessageNode = (stanza, meId, meLid, repository, logger) => {
207
229
  author,
208
230
  async decrypt() {
209
231
  let decryptables = 0
232
+
210
233
  if (Array.isArray(stanza.content)) {
211
234
  for (const { tag, attrs, content } of stanza.content) {
212
235
  if (tag === 'verified_name' && content instanceof Uint8Array) {
213
236
  const cert = proto.VerifiedNameCertificate.decode(content)
214
237
  const details = proto.VerifiedNameCertificate.Details.decode(cert.details)
238
+
215
239
  fullMessage.verifiedBizName = details.verifiedName
216
240
  }
241
+
217
242
  if (tag === 'unavailable' && attrs.type === 'view_once') {
218
- fullMessage.key.isViewOnce = true; // TODO: remove from here and add a STUB TYPE
243
+ fullMessage.key.isViewOnce = true // TODO: remove from here and add a STUB TYPE
219
244
  }
245
+
246
+ if (attrs.count && tag === 'enc') {
247
+ fullMessage.retryCount = Number(attrs.count)
248
+ }
249
+
220
250
  if (tag !== 'enc' && tag !== 'plaintext') {
221
251
  continue
222
252
  }
253
+
223
254
  if (!(content instanceof Uint8Array)) {
224
255
  continue
225
256
  }
257
+
226
258
  decryptables += 1
259
+
227
260
  let msgBuffer
228
- const user = isJidUser(sender) ? sender : author // TODO: flaky logic
229
- const decryptionJid = await getDecryptionJid(user, repository)
261
+
262
+ const decryptionJid = await getDecryptionJid(author, repository)
230
263
 
231
264
  if (tag !== 'plaintext') {
232
- await storeMappingFromEnvelope(stanza, user, decryptionJid, repository, logger)
265
+ // TODO: Handle hosted devices
266
+ await storeMappingFromEnvelope(stanza, author, repository, decryptionJid, logger)
233
267
  }
268
+
234
269
  try {
235
270
  const e2eType = tag === 'plaintext' ? 'plaintext' : attrs.type
236
271
  switch (e2eType) {
@@ -255,27 +290,33 @@ const decryptMessageNode = (stanza, meId, meLid, repository, logger) => {
255
290
  default:
256
291
  throw new Error(`Unknown e2e type: ${e2eType}`)
257
292
  }
293
+
258
294
  let msg = proto.Message.decode(e2eType !== 'plaintext' ? unpadRandomMax16(msgBuffer) : msgBuffer)
295
+
259
296
  msg = msg.deviceSentMessage?.message || msg
297
+
260
298
  if (msg.senderKeyDistributionMessage) {
261
- //eslint-disable-next-line max-depth
262
299
  try {
263
300
  await repository.processSenderKeyDistributionMessage({
264
301
  authorJid: author,
265
302
  item: msg.senderKeyDistributionMessage
266
303
  })
267
304
  }
305
+
268
306
  catch (err) {
269
- logger.error({ key: fullMessage.key, err }, 'failed to decrypt message')
307
+ logger.error({ key: fullMessage.key, err }, 'failed to process sender key distribution message')
270
308
  }
271
309
  }
310
+
272
311
  if (fullMessage.message) {
273
312
  Object.assign(fullMessage.message, msg)
274
313
  }
314
+
275
315
  else {
276
316
  fullMessage.message = msg
277
317
  }
278
318
  }
319
+
279
320
  catch (err) {
280
321
  const errorContext = {
281
322
  key: fullMessage.key,
@@ -285,7 +326,8 @@ const decryptMessageNode = (stanza, meId, meLid, repository, logger) => {
285
326
  author,
286
327
  isSessionRecordError: isSessionRecordError(err)
287
328
  }
288
- logger.error(errorContext, 'failed to process sender key distribution message')
329
+
330
+ logger.error(errorContext, 'failed to decrypt message')
289
331
  fullMessage.messageStubType = proto.WebMessageInfo.StubType.CIPHERTEXT
290
332
  fullMessage.messageStubParameters = [err.message.toString()]
291
333
  }
@@ -293,7 +335,7 @@ const decryptMessageNode = (stanza, meId, meLid, repository, logger) => {
293
335
  }
294
336
 
295
337
  // if nothing was found to decrypt
296
- if (!decryptables) {
338
+ if (!decryptables && !fullMessage.key?.isViewOnce) {
297
339
  fullMessage.messageStubType = proto.WebMessageInfo.StubType.CIPHERTEXT
298
340
  fullMessage.messageStubParameters = [NO_MESSAGE_FOUND_ERROR_TEXT]
299
341
  }
@@ -2,7 +2,7 @@
2
2
 
3
3
  Object.defineProperty(exports, "__esModule", { value: true })
4
4
 
5
- const Events = require("events")
5
+ const EventEmitter = require("events")
6
6
  const { WAMessageStatus } = require("../Types")
7
7
  const { trimUndefined } = require("./generics")
8
8
  const {
@@ -34,7 +34,7 @@ const BUFFERABLE_EVENT_SET = new Set(BUFFERABLE_EVENT)
34
34
  * making the data processing more efficient.
35
35
  */
36
36
  const makeEventBuffer = (logger) => {
37
- const ev = new Events()
37
+ const ev = new EventEmitter()
38
38
  const historyCache = new Set()
39
39
  let data = makeBufferData()
40
40
  let isBuffering = false
@@ -121,10 +121,37 @@ const makeEventBuffer = (logger) => {
121
121
  }
122
122
  },
123
123
  emit(event, evData) {
124
+ // Check if this is a messages.upsert with a different type than what's buffered
125
+ // If so, flush the buffered messages first to avoid type overshadowing
126
+ if (event === 'messages.upsert') {
127
+ const { type } = evData
128
+ const existingUpserts = Object.values(data.messageUpserts)
129
+
130
+ if (existingUpserts.length > 0) {
131
+ const bufferedType = existingUpserts[0].type
132
+
133
+ if (bufferedType !== type) {
134
+ logger.debug({ bufferedType, newType: type }, 'messages.upsert type mismatch, emitting buffered messages')
135
+
136
+ // Emit the buffered messages with their correct type
137
+ ev.emit('event', {
138
+ 'messages.upsert': {
139
+ messages: existingUpserts.map(m => m.message),
140
+ type: bufferedType
141
+ }
142
+ })
143
+
144
+ // Clear the message upserts from the buffer
145
+ data.messageUpserts = {}
146
+ }
147
+ }
148
+ }
149
+
124
150
  if (isBuffering && BUFFERABLE_EVENT_SET.has(event)) {
125
151
  append(data, historyCache, event, evData, logger)
126
152
  return true
127
153
  }
154
+
128
155
  return ev.emit('event', { [event]: evData })
129
156
  },
130
157
  isBuffering() {
@@ -192,42 +219,50 @@ const makeBufferData = () => {
192
219
  }
193
220
 
194
221
  function append(data, historyCache, event, eventData, logger) {
195
- var _a, _b, _c
196
222
  switch (event) {
197
223
  case 'messaging-history.set':
198
224
  for (const chat of eventData.chats) {
199
- const existingChat = data.historySets.chats[chat.id]
225
+ const id = chat.id || ''
226
+ const existingChat = data.historySets.chats[id]
227
+
200
228
  if (existingChat) {
201
229
  existingChat.endOfHistoryTransferType = chat.endOfHistoryTransferType
202
230
  }
203
- if (!existingChat && !historyCache.has(chat.id)) {
204
- data.historySets.chats[chat.id] = chat
205
- historyCache.add(chat.id)
231
+
232
+ if (!existingChat && !historyCache.has(id)) {
233
+ data.historySets.chats[id] = chat
234
+ historyCache.add(id)
206
235
  absorbingChatUpdate(chat)
207
236
  }
208
237
  }
238
+
209
239
  for (const contact of eventData.contacts) {
210
240
  const existingContact = data.historySets.contacts[contact.id]
241
+
211
242
  if (existingContact) {
212
243
  Object.assign(existingContact, trimUndefined(contact))
213
244
  }
214
245
  else {
215
246
  const historyContactId = `c:${contact.id}`
216
247
  const hasAnyName = contact.notify || contact.name || contact.verifiedName
248
+
217
249
  if (!historyCache.has(historyContactId) || hasAnyName) {
218
250
  data.historySets.contacts[contact.id] = contact
219
251
  historyCache.add(historyContactId)
220
252
  }
221
253
  }
222
254
  }
255
+
223
256
  for (const message of eventData.messages) {
224
257
  const key = stringifyMessageKey(message.key)
225
258
  const existingMsg = data.historySets.messages[key]
259
+
226
260
  if (!existingMsg && !historyCache.has(key)) {
227
261
  data.historySets.messages[key] = message
228
262
  historyCache.add(key)
229
263
  }
230
264
  }
265
+
231
266
  data.historySets.empty = false
232
267
  data.historySets.syncType = eventData.syncType
233
268
  data.historySets.progress = eventData.progress
@@ -236,23 +271,30 @@ function append(data, historyCache, event, eventData, logger) {
236
271
  break
237
272
  case 'chats.upsert':
238
273
  for (const chat of eventData) {
239
- let upsert = data.chatUpserts[chat.id]
240
- if (!upsert) {
241
- upsert = data.historySets[chat.id]
274
+ const id = chat.id || ''
275
+
276
+ let upsert = data.chatUpserts[id]
277
+
278
+ if (id && !upsert) {
279
+ upsert = data.historySets.chats[id]
280
+
242
281
  if (upsert) {
243
- logger.debug({ chatId: chat.id }, 'absorbed chat upsert in chat set')
282
+ logger.debug({ chatId: id }, 'absorbed chat upsert in chat set')
244
283
  }
245
284
  }
285
+
246
286
  if (upsert) {
247
287
  upsert = concatChats(upsert, chat)
248
288
  }
249
289
  else {
250
290
  upsert = chat
251
- data.chatUpserts[chat.id] = upsert
291
+ data.chatUpserts[id] = upsert
252
292
  }
293
+
253
294
  absorbingChatUpdate(upsert)
254
- if (data.chatDeletes.has(chat.id)) {
255
- data.chatDeletes.delete(chat.id)
295
+
296
+ if (data.chatDeletes.has(id)) {
297
+ data.chatDeletes.delete(id)
256
298
  }
257
299
  }
258
300
  break
@@ -342,43 +384,51 @@ function append(data, historyCache, event, eventData, logger) {
342
384
  break
343
385
  case 'messages.upsert':
344
386
  const { messages, type } = eventData
387
+
345
388
  for (const message of messages) {
346
389
  const key = stringifyMessageKey(message.key)
347
- let existing = (_a = data.messageUpserts[key]) === null || _a === void 0 ? void 0 : _a.message
390
+
391
+ let existing = data.messageUpserts[key]?.message
392
+
348
393
  if (!existing) {
349
394
  existing = data.historySets.messages[key]
395
+
350
396
  if (existing) {
351
397
  logger.debug({ messageId: key }, 'absorbed message upsert in message set')
352
398
  }
353
399
  }
400
+
354
401
  if (existing) {
355
402
  message.messageTimestamp = existing.messageTimestamp
356
403
  }
404
+
357
405
  if (data.messageUpdates[key]) {
358
406
  logger.debug('absorbed prior message update in message upsert')
359
407
  Object.assign(message, data.messageUpdates[key].update)
360
408
  delete data.messageUpdates[key]
361
409
  }
410
+
362
411
  if (data.historySets.messages[key]) {
363
412
  data.historySets.messages[key] = message
364
413
  }
365
414
  else {
366
415
  data.messageUpserts[key] = {
367
416
  message,
368
- type: type === 'notify' || ((_b = data.messageUpserts[key]) === null || _b === void 0 ? void 0 : _b.type) === 'notify'
369
- ? 'notify'
370
- : type
417
+ type: type === 'notify' || data.messageUpserts[key]?.type === 'notify' ? 'notify' : type
371
418
  }
372
419
  }
373
420
  }
374
421
  break
375
422
  case 'messages.update':
376
423
  const msgUpdates = eventData
424
+
377
425
  for (const { key, update } of msgUpdates) {
378
426
  const keyStr = stringifyMessageKey(key)
379
- const existing = data.historySets.messages[keyStr] || ((_c = data.messageUpserts[keyStr]) === null || _c === void 0 ? void 0 : _c.message)
427
+ const existing = data.historySets.messages[keyStr] || data.messageUpserts[keyStr]?.message
428
+
380
429
  if (existing) {
381
430
  Object.assign(existing, update)
431
+
382
432
  // if the message was received & read by us
383
433
  // the chat counter must have been incremented
384
434
  // so we need to decrement it
@@ -471,11 +521,14 @@ function append(data, historyCache, event, eventData, logger) {
471
521
  default:
472
522
  throw new Error(`"${event}" cannot be buffered`)
473
523
  }
524
+
474
525
  function absorbingChatUpdate(existing) {
475
- const chatId = existing.id
526
+ const chatId = existing.id || ''
476
527
  const update = data.chatUpdates[chatId]
528
+
477
529
  if (update) {
478
530
  const conditionMatches = update.conditional ? update.conditional(data) : true
531
+
479
532
  if (conditionMatches) {
480
533
  delete update.conditional
481
534
  logger.debug({ chatId }, 'absorbed chat update in existing chat')
@@ -488,17 +541,20 @@ function append(data, historyCache, event, eventData, logger) {
488
541
  }
489
542
  }
490
543
  }
544
+
491
545
  function decrementChatReadCounterIfMsgDidUnread(message) {
492
546
  // decrement chat unread counter
493
547
  // if the message has already been marked read by us
494
548
  const chatId = message.key.remoteJid
495
549
  const chat = data.chatUpdates[chatId] || data.chatUpserts[chatId]
496
- if (isRealMessage(message, '')
497
- && shouldIncrementChatUnread(message)
498
- && typeof (chat?.unreadCount) === 'number'
499
- && chat.unreadCount > 0) {
550
+
551
+ if (isRealMessage(message) &&
552
+ shouldIncrementChatUnread(message) &&
553
+ typeof chat?.unreadCount === 'number' &&
554
+ chat.unreadCount > 0) {
500
555
  logger.debug({ chatId: chat.id }, 'decrementing chat counter')
501
556
  chat.unreadCount -= 1
557
+
502
558
  if (chat.unreadCount === 0) {
503
559
  delete chat.unreadCount
504
560
  }