@hansaka02/baileys 7.3.2 → 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 (210) hide show
  1. package/lib/Defaults/baileys-version.json +2 -2
  2. package/lib/Defaults/connection.js +51 -0
  3. package/lib/Defaults/constants.js +74 -0
  4. package/lib/Defaults/history.js +19 -0
  5. package/lib/Defaults/index.js +36 -142
  6. package/lib/Defaults/media.js +48 -0
  7. package/lib/Defaults/prefix.js +18 -0
  8. package/lib/Signal/Group/group-session-builder.js +10 -42
  9. package/lib/Signal/Group/group_cipher.js +9 -6
  10. package/lib/Signal/Group/index.js +39 -53
  11. package/lib/Signal/Group/keyhelper.js +8 -41
  12. package/lib/Signal/Group/sender-chain-key.js +5 -18
  13. package/lib/Signal/Group/sender-key-distribution-message.js +7 -7
  14. package/lib/Signal/Group/sender-key-message.js +12 -8
  15. package/lib/Signal/Group/sender-key-record.js +7 -16
  16. package/lib/Signal/Group/sender-key-state.js +15 -61
  17. package/lib/Signal/Group/sender-message-key.js +2 -2
  18. package/lib/Signal/libsignal.js +237 -177
  19. package/lib/Signal/lid-mapping.js +128 -71
  20. package/lib/Socket/Client/types.js +2 -2
  21. package/lib/Socket/Client/websocket.js +25 -16
  22. package/lib/Socket/business.js +46 -33
  23. package/lib/Socket/chats.js +286 -170
  24. package/lib/Socket/community.js +215 -77
  25. package/lib/Socket/groups.js +77 -61
  26. package/lib/Socket/index.js +4 -4
  27. package/lib/Socket/messages-recv.js +629 -457
  28. package/lib/Socket/messages-send.js +645 -656
  29. package/lib/Socket/mex.js +61 -0
  30. package/lib/Socket/newsletter.js +166 -245
  31. package/lib/Socket/socket.js +396 -170
  32. package/lib/Store/index.js +27 -11
  33. package/lib/Store/make-cache-manager-store.js +14 -15
  34. package/lib/Store/make-in-memory-store.js +28 -24
  35. package/lib/Types/LabelAssociation.js +2 -2
  36. package/lib/Types/Message.js +6 -6
  37. package/lib/Types/MexUpdates.js +5 -5
  38. package/lib/Types/Newsletter.js +32 -25
  39. package/lib/Types/State.js +4 -4
  40. package/lib/Types/index.js +28 -12
  41. package/lib/Utils/auth-utils.js +212 -375
  42. package/lib/Utils/baileys-event-stream.js +68 -69
  43. package/lib/Utils/browser-utils.js +43 -0
  44. package/lib/Utils/business.js +63 -53
  45. package/lib/Utils/chat-utils.js +241 -106
  46. package/lib/Utils/crypto.js +25 -45
  47. package/lib/Utils/decode-wa-message.js +361 -311
  48. package/lib/Utils/event-buffer.js +97 -42
  49. package/lib/Utils/generics.js +90 -207
  50. package/lib/Utils/history.js +29 -27
  51. package/lib/Utils/index.js +28 -14
  52. package/lib/Utils/link-preview.js +24 -62
  53. package/lib/Utils/logger.js +5 -5
  54. package/lib/Utils/lt-hash.js +29 -23
  55. package/lib/Utils/make-mutex.js +26 -28
  56. package/lib/Utils/message-retry-manager.js +55 -7
  57. package/lib/Utils/messages-media.js +434 -247
  58. package/lib/Utils/messages.js +963 -917
  59. package/lib/Utils/noise-handler.js +60 -20
  60. package/lib/Utils/pre-key-manager.js +126 -0
  61. package/lib/Utils/process-message.js +216 -141
  62. package/lib/Utils/signal.js +75 -37
  63. package/lib/Utils/use-multi-file-auth-state.js +18 -22
  64. package/lib/Utils/validate-connection.js +96 -66
  65. package/lib/WABinary/constants.js +1268 -1268
  66. package/lib/WABinary/decode.js +62 -34
  67. package/lib/WABinary/encode.js +57 -36
  68. package/lib/WABinary/generic-utils.js +4 -4
  69. package/lib/WABinary/index.js +27 -11
  70. package/lib/WABinary/jid-utils.js +58 -11
  71. package/lib/WAM/constants.js +19064 -11563
  72. package/lib/WAM/encode.js +71 -14
  73. package/lib/WAM/index.js +27 -11
  74. package/lib/WAUSync/Protocols/USyncBotProfileProtocol.js +20 -16
  75. package/lib/WAUSync/Protocols/USyncContactProtocol.js +2 -2
  76. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +7 -4
  77. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +2 -2
  78. package/lib/WAUSync/Protocols/USyncLIDProtocol.js +0 -2
  79. package/lib/WAUSync/Protocols/USyncStatusProtocol.js +2 -2
  80. package/lib/WAUSync/Protocols/index.js +27 -11
  81. package/lib/WAUSync/USyncQuery.js +51 -28
  82. package/lib/WAUSync/index.js +27 -11
  83. package/lib/index.js +60 -31
  84. package/package.json +12 -17
  85. package/WAProto/AICommon/AICommon.d.ts +0 -11702
  86. package/WAProto/Adv/Adv.d.ts +0 -643
  87. package/WAProto/BotMetadata/BotMetadata.d.ts +0 -5654
  88. package/WAProto/Cert/Cert.d.ts +0 -613
  89. package/WAProto/ChatLockSettings/ChatLockSettings.d.ts +0 -476
  90. package/WAProto/CompanionReg/CompanionReg.d.ts +0 -1361
  91. package/WAProto/DeviceCapabilities/DeviceCapabilities.d.ts +0 -577
  92. package/WAProto/E2E/E2E.d.ts +0 -41724
  93. package/WAProto/Ephemeral/Ephemeral.d.ts +0 -114
  94. package/WAProto/HistorySync/HistorySync.d.ts +0 -51700
  95. package/WAProto/LidMigrationSyncPayload/LidMigrationSyncPayload.d.ts +0 -229
  96. package/WAProto/MdStorageChatRowOpaqueData/MdStorageChatRowOpaqueData.d.ts +0 -583
  97. package/WAProto/MdStorageMsgRowOpaqueData/MdStorageMsgRowOpaqueData.d.ts +0 -42897
  98. package/WAProto/MmsRetry/MmsRetry.d.ts +0 -243
  99. package/WAProto/Protocol/Protocol.d.ts +0 -270
  100. package/WAProto/Reporting/Reporting.d.ts +0 -371
  101. package/WAProto/ServerSync/ServerSync.d.ts +0 -1285
  102. package/WAProto/SignalLocalStorageProtocol/SignalLocalStorageProtocol.d.ts +0 -1868
  103. package/WAProto/SignalWhisperTextProtocol/SignalWhisperTextProtocol.d.ts +0 -767
  104. package/WAProto/StatusAttributions/StatusAttributions.d.ts +0 -1027
  105. package/WAProto/SyncAction/SyncAction.d.ts +0 -11193
  106. package/WAProto/UserPassword/UserPassword.d.ts +0 -363
  107. package/WAProto/VnameCert/VnameCert.d.ts +0 -821
  108. package/WAProto/Wa6/Wa6.d.ts +0 -2128
  109. package/WAProto/Web/Web.d.ts +0 -46383
  110. package/WAProto/index.d.ts +0 -55
  111. package/lib/Defaults/index.d.ts +0 -77
  112. package/lib/Signal/Group/ciphertext-message.d.ts +0 -9
  113. package/lib/Signal/Group/group-session-builder.d.ts +0 -17
  114. package/lib/Signal/Group/group_cipher.d.ts +0 -19
  115. package/lib/Signal/Group/index.d.ts +0 -11
  116. package/lib/Signal/Group/keyhelper.d.ts +0 -16
  117. package/lib/Signal/Group/sender-chain-key.d.ts +0 -14
  118. package/lib/Signal/Group/sender-key-distribution-message.d.ts +0 -17
  119. package/lib/Signal/Group/sender-key-message.d.ts +0 -19
  120. package/lib/Signal/Group/sender-key-name.d.ts +0 -19
  121. package/lib/Signal/Group/sender-key-record.d.ts +0 -32
  122. package/lib/Signal/Group/sender-key-state.d.ts +0 -44
  123. package/lib/Signal/Group/sender-message-key.d.ts +0 -11
  124. package/lib/Signal/libsignal.d.ts +0 -8
  125. package/lib/Signal/lid-mapping.d.ts +0 -28
  126. package/lib/Socket/Client/index.d.ts +0 -2
  127. package/lib/Socket/Client/types.d.ts +0 -16
  128. package/lib/Socket/Client/websocket.d.ts +0 -13
  129. package/lib/Socket/business.d.ts +0 -187
  130. package/lib/Socket/chats.d.ts +0 -97
  131. package/lib/Socket/community.d.ts +0 -129
  132. package/lib/Socket/groups.d.ts +0 -129
  133. package/lib/Socket/index.d.ts +0 -191
  134. package/lib/Socket/messages-recv.d.ts +0 -174
  135. package/lib/Socket/messages-send.d.ts +0 -165
  136. package/lib/Socket/newsletter.d.ts +0 -145
  137. package/lib/Socket/socket.d.ts +0 -45
  138. package/lib/Socket/usync.d.ts +0 -37
  139. package/lib/Socket/usync.js +0 -83
  140. package/lib/Store/index.d.ts +0 -4
  141. package/lib/Store/make-cache-manager-store.d.ts +0 -14
  142. package/lib/Store/make-in-memory-store.d.ts +0 -123
  143. package/lib/Store/make-ordered-dictionary.d.ts +0 -12
  144. package/lib/Store/object-repository.d.ts +0 -10
  145. package/lib/Types/Auth.d.ts +0 -121
  146. package/lib/Types/Bussiness.d.ts +0 -28
  147. package/lib/Types/Call.d.ts +0 -14
  148. package/lib/Types/Chat.d.ts +0 -143
  149. package/lib/Types/Contact.d.ts +0 -23
  150. package/lib/Types/Events.d.ts +0 -226
  151. package/lib/Types/GroupMetadata.d.ts +0 -66
  152. package/lib/Types/Label.d.ts +0 -48
  153. package/lib/Types/LabelAssociation.d.ts +0 -35
  154. package/lib/Types/Message.d.ts +0 -484
  155. package/lib/Types/MexUpdates.d.ts +0 -9
  156. package/lib/Types/Newsletter.d.ts +0 -109
  157. package/lib/Types/Product.d.ts +0 -92
  158. package/lib/Types/Signal.d.ts +0 -98
  159. package/lib/Types/Socket.d.ts +0 -141
  160. package/lib/Types/State.d.ts +0 -41
  161. package/lib/Types/USync.d.ts +0 -26
  162. package/lib/Types/index.d.ts +0 -80
  163. package/lib/Utils/auth-utils.d.ts +0 -21
  164. package/lib/Utils/baileys-event-stream.d.ts +0 -18
  165. package/lib/Utils/business.d.ts +0 -29
  166. package/lib/Utils/chat-utils.d.ts +0 -82
  167. package/lib/Utils/crypto.d.ts +0 -56
  168. package/lib/Utils/decode-wa-message.d.ts +0 -53
  169. package/lib/Utils/event-buffer.d.ts +0 -39
  170. package/lib/Utils/generics.d.ts +0 -117
  171. package/lib/Utils/history.d.ts +0 -23
  172. package/lib/Utils/index.d.ts +0 -20
  173. package/lib/Utils/link-preview.d.ts +0 -23
  174. package/lib/Utils/logger.d.ts +0 -13
  175. package/lib/Utils/lt-hash.d.ts +0 -14
  176. package/lib/Utils/make-mutex.d.ts +0 -9
  177. package/lib/Utils/message-retry-manager.d.ts +0 -88
  178. package/lib/Utils/messages-media.d.ts +0 -135
  179. package/lib/Utils/messages.d.ts +0 -105
  180. package/lib/Utils/noise-handler.d.ts +0 -20
  181. package/lib/Utils/process-message.d.ts +0 -49
  182. package/lib/Utils/signal.d.ts +0 -42
  183. package/lib/Utils/use-mongo-file-auth-state.d.ts +0 -6
  184. package/lib/Utils/use-mongo-file-auth-state.js +0 -84
  185. package/lib/Utils/use-multi-file-auth-state.d.ts +0 -13
  186. package/lib/Utils/use-single-file-auth-state.d.ts +0 -13
  187. package/lib/Utils/use-single-file-auth-state.js +0 -80
  188. package/lib/Utils/validate-connection.d.ts +0 -13
  189. package/lib/WABinary/constants.d.ts +0 -30
  190. package/lib/WABinary/decode.d.ts +0 -9
  191. package/lib/WABinary/encode.d.ts +0 -3
  192. package/lib/WABinary/generic-utils.d.ts +0 -28
  193. package/lib/WABinary/index.d.ts +0 -5
  194. package/lib/WABinary/jid-utils.d.ts +0 -58
  195. package/lib/WABinary/types.d.ts +0 -22
  196. package/lib/WAM/BinaryInfo.d.ts +0 -16
  197. package/lib/WAM/constants.d.ts +0 -47
  198. package/lib/WAM/encode.d.ts +0 -3
  199. package/lib/WAM/index.d.ts +0 -3
  200. package/lib/WAUSync/Protocols/USyncBotProfileProtocol.d.ts +0 -28
  201. package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts +0 -10
  202. package/lib/WAUSync/Protocols/USyncDeviceProtocol.d.ts +0 -26
  203. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts +0 -14
  204. package/lib/WAUSync/Protocols/USyncLIDProtocol.d.ts +0 -10
  205. package/lib/WAUSync/Protocols/USyncStatusProtocol.d.ts +0 -14
  206. package/lib/WAUSync/Protocols/index.d.ts +0 -6
  207. package/lib/WAUSync/USyncQuery.d.ts +0 -31
  208. package/lib/WAUSync/USyncUser.d.ts +0 -12
  209. package/lib/WAUSync/index.d.ts +0 -3
  210. package/lib/index.d.ts +0 -13
@@ -1,76 +1,149 @@
1
1
  "use strict"
2
2
 
3
- var __importDefault = (this && this.__importDefault) || function (mod) {
4
- return (mod && mod.__esModule) ? mod : { "default": mod }
5
- }
6
-
7
3
  Object.defineProperty(exports, "__esModule", { value: true })
8
4
 
9
- const node_cache_1 = __importDefault(require("@cacheable/node-cache"))
10
- const boom_1 = require("@hapi/boom")
11
- const crypto_1 = require("crypto")
12
- const WAProto_1 = require("../../WAProto")
13
- const Defaults_1 = require("../Defaults")
14
- const Utils_1 = require("../Utils")
15
- const Types_1 = require("../Types")
16
- const WABinary_1 = require("../WABinary")
17
- const WAUSync_1 = require("../WAUSync")
18
- const newsletter_1 = require("./newsletter")
19
- const link_preview_1 = require("../Utils/link-preview")
20
- const make_keyed_mutex_1 = require("../Utils/make-mutex")
5
+ const { default: NodeCache } = require("@cacheable/node-cache")
6
+ const { Boom } = require("@hapi/boom")
7
+ const { randomBytes } = require("crypto")
8
+ const { proto } = require("../../WAProto")
9
+ const {
10
+ DEFAULT_CACHE_TTLS,
11
+ WA_DEFAULT_EPHEMERAL
12
+ } = require("../Defaults/constants")
13
+ const {
14
+ delay,
15
+ assertMediaContent,
16
+ bindWaitForEvent,
17
+ decryptMediaRetryData,
18
+ encodeNewsletterMessage,
19
+ encodeSignedDeviceIdentity,
20
+ encodeWAMessage,
21
+ encryptMediaRetryRequest,
22
+ extractDeviceJids,
23
+ generateMessageID,
24
+ generateParticipantHashV2,
25
+ generateWAMessage,
26
+ generateWAMessageFromContent,
27
+ getStatusCodeForMediaRetry,
28
+ getUrlFromDirectPath,
29
+ getWAUploadToServer,
30
+ MessageRetryManager,
31
+ normalizeMessageContent,
32
+ parseAndInjectE2ESessions,
33
+ unixTimestampSeconds,
34
+ prepareAlbumMessageContent,
35
+ aggregateMessageKeysNotFromMe
36
+ } = require("../Utils")
37
+ const { WAMessageAddressingMode } = require("../Types")
38
+ const {
39
+ areJidsSameUser,
40
+ getBinaryNodeChild,
41
+ getBinaryNodeChildren,
42
+ getBinaryFilteredBizBot,
43
+ getBinaryFilteredButtons,
44
+ isHostedLidUser,
45
+ isHostedPnUser,
46
+ isJidNewsletter,
47
+ isJidGroup,
48
+ isLidUser,
49
+ isPnUser,
50
+ jidDecode,
51
+ jidEncode,
52
+ jidNormalizedUser,
53
+ STORIES_JID,
54
+ S_WHATSAPP_NET
55
+ } = require("../WABinary")
56
+ const {
57
+ USyncUser,
58
+ USyncQuery
59
+ } = require("../WAUSync")
60
+ const { makeNewsletterSocket } = require("./newsletter")
61
+ const { getUrlInfo } = require("../Utils/link-preview")
62
+ const { makeKeyedMutex } = require("../Utils/make-mutex")
21
63
 
22
64
  const makeMessagesSocket = (config) => {
23
- const { logger, maxMsgRetryCount, linkPreviewImageThumbnailWidth, generateHighQualityLinkPreview, options: axiosOptions, patchMessageBeforeSending, cachedGroupMetadata, enableRecentMessageCache } = config
24
- const suki = newsletter_1.makeNewsletterSocket(config)
25
- const { ev, authState, processingMutex, signalRepository, upsertMessage, createCallLink, query, fetchPrivacySettings, sendNode, groupQuery, groupMetadata, groupToggleEphemeral, newsletterWMexQuery, executeUSyncQuery } = suki
26
-
27
- const userDevicesCache = config.userDevicesCache || new node_cache_1.default({
28
- stdTTL: Defaults_1.DEFAULT_CACHE_TTLS.USER_DEVICES,
65
+ const {
66
+ logger,
67
+ linkPreviewImageThumbnailWidth,
68
+ generateHighQualityLinkPreview,
69
+ options: httpRequestOptions,
70
+ patchMessageBeforeSending,
71
+ cachedGroupMetadata,
72
+ enableRecentMessageCache,
73
+ maxMsgRetryCount
74
+ } = config
75
+
76
+ const suki = makeNewsletterSocket(config)
77
+
78
+ const {
79
+ ev,
80
+ authState,
81
+ messageMutex,
82
+ signalRepository,
83
+ upsertMessage,
84
+ createCallLink,
85
+ query,
86
+ fetchPrivacySettings,
87
+ sendNode,
88
+ groupQuery,
89
+ groupMetadata,
90
+ groupToggleEphemeral,
91
+ executeUSyncQuery,
92
+ newsletterMetadata
93
+ } = suki
94
+
95
+ const userDevicesCache = config.userDevicesCache || new NodeCache({
96
+ stdTTL: DEFAULT_CACHE_TTLS.USER_DEVICES,
97
+ useClones: false
98
+ })
99
+
100
+ const peerSessionsCache = new NodeCache({
101
+ stdTTL: DEFAULT_CACHE_TTLS.USER_DEVICES,
29
102
  useClones: false
30
103
  })
31
104
 
32
105
  // Initialize message retry manager if enabled
33
- const messageRetryManager = enableRecentMessageCache ? new Utils_1.MessageRetryManager(logger, maxMsgRetryCount) : null
106
+ const messageRetryManager = enableRecentMessageCache ? new MessageRetryManager(logger, maxMsgRetryCount) : null
34
107
 
35
108
  // Prevent race conditions in Signal session encryption by user
36
- const encryptionMutex = make_keyed_mutex_1.makeKeyedMutex()
109
+ const encryptionMutex = makeKeyedMutex()
37
110
 
38
111
  let mediaConn
39
112
 
40
113
  const refreshMediaConn = async (forceGet = false) => {
41
114
  const media = await mediaConn
42
-
43
- if (!media || forceGet || (new Date().getTime() - media.fetchDate.getTime()) > media.ttl * 1000) {
115
+
116
+ if (!media || forceGet || new Date().getTime() - media.fetchDate.getTime() > media.ttl * 1000) {
44
117
  mediaConn = (async () => {
45
-
46
118
  const result = await query({
47
119
  tag: 'iq',
48
120
  attrs: {
49
121
  type: 'set',
50
122
  xmlns: 'w:m',
51
- to: WABinary_1.S_WHATSAPP_NET,
123
+ to: S_WHATSAPP_NET
52
124
  },
53
125
  content: [{ tag: 'media_conn', attrs: {} }]
54
126
  })
55
-
56
- const mediaConnNode = WABinary_1.getBinaryNodeChild(result, 'media_conn')
57
-
127
+
128
+ const mediaConnNode = getBinaryNodeChild(result, 'media_conn')
129
+
130
+ // TODO: explore full length of data that whatsapp provides
58
131
  const node = {
59
- hosts: WABinary_1.getBinaryNodeChildren(mediaConnNode, 'host').map(({ attrs }) => ({
132
+ hosts: getBinaryNodeChildren(mediaConnNode, 'host').map(({ attrs }) => ({
60
133
  hostname: attrs.hostname,
61
- maxContentLengthBytes: +attrs.maxContentLengthBytes,
134
+ maxContentLengthBytes: +attrs.maxContentLengthBytes
62
135
  })),
63
136
  auth: mediaConnNode.attrs.auth,
64
137
  ttl: +mediaConnNode.attrs.ttl,
65
138
  fetchDate: new Date()
66
139
  }
67
-
140
+
68
141
  logger.debug('fetched media conn')
69
-
142
+
70
143
  return node
71
144
  })()
72
145
  }
73
-
146
+
74
147
  return mediaConn
75
148
  }
76
149
 
@@ -79,37 +152,42 @@ const makeMessagesSocket = (config) => {
79
152
  * used for receipts of phone call, read, delivery etc.
80
153
  * */
81
154
  const sendReceipt = async (jid, participant, messageIds, type) => {
155
+ if (!messageIds || messageIds.length === 0) {
156
+ throw new Boom('missing ids in receipt')
157
+ }
158
+
82
159
  const node = {
83
160
  tag: 'receipt',
84
161
  attrs: {
85
- id: messageIds[0],
86
- },
162
+ id: messageIds[0]
163
+ }
87
164
  }
88
-
165
+
89
166
  const isReadReceipt = type === 'read' || type === 'read-self'
90
-
167
+
91
168
  if (isReadReceipt) {
92
- node.attrs.t = Utils_1.unixTimestampSeconds().toString()
169
+ node.attrs.t = unixTimestampSeconds().toString()
93
170
  }
94
-
95
- if (type === 'sender' && WABinary_1.isJidUser(jid)) {
171
+
172
+ if (type === 'sender' && (isPnUser(jid) || isLidUser(jid))) {
96
173
  node.attrs.recipient = jid
97
174
  node.attrs.to = participant
98
175
  }
99
-
176
+
100
177
  else {
101
178
  node.attrs.to = jid
179
+
102
180
  if (participant) {
103
181
  node.attrs.participant = participant
104
182
  }
105
183
  }
106
-
184
+
107
185
  if (type) {
108
- node.attrs.type = WABinary_1.isJidNewsletter(jid) ? 'read-self' : type
186
+ node.attrs.type = type
109
187
  }
110
-
188
+
111
189
  const remainingMessageIds = messageIds.slice(1)
112
-
190
+
113
191
  if (remainingMessageIds.length) {
114
192
  node.content = [
115
193
  {
@@ -122,15 +200,15 @@ const makeMessagesSocket = (config) => {
122
200
  }
123
201
  ]
124
202
  }
125
-
203
+
126
204
  logger.debug({ attrs: node.attrs, messageIds }, 'sending receipt for messages')
127
-
205
+
128
206
  await sendNode(node)
129
207
  }
130
208
 
131
209
  /** Correctly bulk send receipts to multiple chats, participants */
132
210
  const sendReceipts = async (keys, type) => {
133
- const recps = Utils_1.aggregateMessageKeysNotFromMe(keys)
211
+ const recps = aggregateMessageKeysNotFromMe(keys)
134
212
 
135
213
  for (const { jid, participant, messageIds } of recps) {
136
214
  await sendReceipt(jid, participant, messageIds, type)
@@ -147,84 +225,6 @@ const makeMessagesSocket = (config) => {
147
225
  await sendReceipts(keys, readType)
148
226
  }
149
227
 
150
- /**
151
- * Deduplicate JIDs when both LID and PN versions exist for same user
152
- * Prefers LID over PN to maintain single encryption layer
153
- */
154
- const deduplicateLidPnJids = (jids) => {
155
- const lidUsers = new Set()
156
- const filteredJids = []
157
-
158
- // Collect all LID users
159
- for (const jid of jids) {
160
- if (WABinary_1.isLidUser(jid)) {
161
- const user = WABinary_1.jidDecode(jid)?.user
162
- if (user)
163
- lidUsers.add(user)
164
- }
165
- }
166
-
167
- // Filter out PN versions when LID exists
168
- for (const jid of jids) {
169
- if (WABinary_1.isJidUser(jid)) {
170
- const user = WABinary_1.jidDecode(jid)?.user
171
- if (user && lidUsers.has(user)) {
172
- logger.debug({ jid }, 'Skipping PN - LID version exists')
173
- continue
174
- }
175
- }
176
- filteredJids.push(jid)
177
- }
178
- return filteredJids
179
- }
180
-
181
- /** Fetch image for groups, user, and newsletter **/
182
- const profilePictureUrl = async (jid) => {
183
- if (WABinary_1.isJidNewsletter(jid)) {
184
-
185
- let node = await newsletterWMexQuery(undefined, Types_1.QueryIds.METADATA, {
186
- input: {
187
- key: jid,
188
- type: 'JID',
189
- view_role: 'GUEST'
190
- },
191
- fetch_viewer_metadata: true,
192
- fetch_full_image: true,
193
- fetch_creation_time: true
194
- })
195
-
196
- let result = WABinary_1.getBinaryNodeChild(node, 'result')?.content?.toString()
197
-
198
- let metadata = JSON.parse(result).data[Types_1.XWAPaths.NEWSLETTER]
199
-
200
- return Utils_1.getUrlFromDirectPath(metadata.thread_metadata.picture?.direct_path || '')
201
-
202
- }
203
-
204
- else {
205
- const result = await query({
206
- tag: 'iq',
207
- attrs: {
208
- target: WABinary_1.jidNormalizedUser(jid),
209
- to: WABinary_1.S_WHATSAPP_NET,
210
- type: 'get',
211
- xmlns: 'w:profile:picture'
212
- },
213
- content: [{
214
- tag: 'picture',
215
- attrs: {
216
- type: 'image',
217
- query: 'url'
218
- }
219
- }]
220
- })
221
-
222
- const child = WABinary_1.getBinaryNodeChild(result, 'picture')
223
-
224
- return child?.attrs?.url || null
225
- }
226
- }
227
-
228
228
  /** Fetch all the devices we've to send a message to */
229
229
  const getUSyncDevices = async (jids, useCache, ignoreZeroDevices) => {
230
230
  const deviceResults = []
@@ -235,10 +235,9 @@ const makeMessagesSocket = (config) => {
235
235
 
236
236
  const toFetch = []
237
237
 
238
- jids = deduplicateLidPnJids(Array.from(new Set(jids)))
239
238
  const jidsWithUser = jids
240
239
  .map(jid => {
241
- const decoded = WABinary_1.jidDecode(jid)
240
+ const decoded = jidDecode(jid)
242
241
  const user = decoded?.user
243
242
  const device = decoded?.device
244
243
  const isExplicitDevice = typeof device === 'number' && device >= 0
@@ -247,20 +246,22 @@ const makeMessagesSocket = (config) => {
247
246
  deviceResults.push({
248
247
  user,
249
248
  device,
250
- wireJid: jid // again this makes no sense
251
- });
249
+ jid
250
+ })
251
+
252
252
  return null
253
253
  }
254
254
 
255
- jid = WABinary_1.jidNormalizedUser(jid)
255
+ jid = jidNormalizedUser(jid)
256
+
256
257
  return { jid, user }
257
- })
258
- .filter(jid => jid !== null)
259
-
258
+ }).filter(jid => jid !== null)
259
+
260
260
  let mgetDevices
261
261
 
262
262
  if (useCache && userDevicesCache.mget) {
263
263
  const usersToFetch = jidsWithUser.map(j => j?.user).filter(Boolean)
264
+
264
265
  mgetDevices = await userDevicesCache.mget(usersToFetch)
265
266
  }
266
267
 
@@ -270,19 +271,21 @@ const makeMessagesSocket = (config) => {
270
271
  (userDevicesCache.mget ? undefined : (await userDevicesCache.get(user)))
271
272
 
272
273
  if (devices) {
273
- const isLidJid = WABinary_1.isLidUser(jid)
274
- const devicesWithWire = devices.map(d => ({
274
+ const devicesWithJid = devices.map(d => ({
275
275
  ...d,
276
- wireJid: isLidJid ? WABinary_1.jidEncode(d.user, 'lid', d.device) : WABinary_1.jidEncode(d.user, 's.whatsapp.net', d.device)
276
+ jid: jidEncode(d.user, d.server, d.device)
277
277
  }))
278
278
 
279
- deviceResults.push(...devicesWithWire)
279
+ deviceResults.push(...devicesWithJid)
280
+
280
281
  logger.trace({ user }, 'using cache for devices')
281
282
  }
283
+
282
284
  else {
283
285
  toFetch.push(jid)
284
286
  }
285
287
  }
288
+
286
289
  else {
287
290
  toFetch.push(jid)
288
291
  }
@@ -293,23 +296,49 @@ const makeMessagesSocket = (config) => {
293
296
  }
294
297
 
295
298
  const requestedLidUsers = new Set()
299
+
296
300
  for (const jid of toFetch) {
297
- if (WABinary_1.isLidUser(jid)) {
298
- const user = WABinary_1.jidDecode(jid)?.user
301
+ if (isLidUser(jid) || isHostedLidUser(jid)) {
302
+ const user = jidDecode(jid)?.user
303
+
299
304
  if (user)
300
305
  requestedLidUsers.add(user)
301
306
  }
302
307
  }
303
308
 
304
- const query = new WAUSync_1.USyncQuery().withContext('message').withDeviceProtocol()
309
+ const query = new USyncQuery().withContext('message').withDeviceProtocol().withLIDProtocol()
310
+
305
311
  for (const jid of toFetch) {
306
- query.withUser(new WAUSync_1.USyncUser().withId(jid))
312
+ query.withUser(new USyncUser().withId(jid)) // todo: investigate - the idea here is that <user> should have an inline lid field with the lid being the pn equivalent
307
313
  }
308
314
 
309
315
  const result = await executeUSyncQuery(query)
310
316
 
311
317
  if (result) {
312
- const extracted = Utils_1.extractDeviceJids(result?.list, authState.creds.me.id, ignoreZeroDevices)
318
+ // TODO: LID MAP this stuff (lid protocol will now return lid with devices)
319
+ const lidResults = result.list.filter(a => !!a.lid)
320
+
321
+ if (lidResults.length > 0) {
322
+ logger.trace('Storing LID maps from device call')
323
+
324
+ await signalRepository.lidMapping.storeLIDPNMappings(lidResults.map(a => ({ lid: a.lid, pn: a.id })))
325
+
326
+ // Force-refresh sessions for newly mapped LIDs to align identity addressing
327
+ try {
328
+ const lids = lidResults.map(a => a.lid)
329
+
330
+ if (lids.length) {
331
+ await assertSessions(lids, true)
332
+ }
333
+ }
334
+
335
+ catch (e) {
336
+ logger.warn({ e, count: lidResults.length }, 'failed to assert sessions for newly mapped LIDs')
337
+ }
338
+ }
339
+
340
+ const extracted = extractDeviceJids(result?.list, authState.creds.me.id, authState.creds.me.lid, ignoreZeroDevices)
341
+
313
342
  const deviceMap = {}
314
343
 
315
344
  for (const item of extracted) {
@@ -319,22 +348,21 @@ const makeMessagesSocket = (config) => {
319
348
 
320
349
  // Process each user's devices as a group for bulk LID migration
321
350
  for (const [user, userDevices] of Object.entries(deviceMap)) {
322
- const isLidUser = requestedLidUsers.has(user)
323
-
351
+ const isLidUser = requestedLidUsers.has(user);
324
352
  // Process all devices for this user
325
353
  for (const item of userDevices) {
326
- const finalWireJid = isLidUser
327
- ? WABinary_1.jidEncode(user, 'lid', item.device)
328
- : WABinary_1.jidEncode(item.user, 's.whatsapp.net', item.device)
354
+ const finalJid = isLidUser
355
+ ? jidEncode(user, item.server, item.device)
356
+ : jidEncode(item.user, item.server, item.device)
329
357
  deviceResults.push({
330
358
  ...item,
331
- wireJid: finalWireJid
332
- });
359
+ jid: finalJid
360
+ })
333
361
 
334
362
  logger.debug({
335
363
  user: item.user,
336
364
  device: item.device,
337
- finalWireJid,
365
+ finalJid,
338
366
  usedLid: isLidUser
339
367
  }, 'Processed device with LID priority')
340
368
  }
@@ -352,331 +380,204 @@ const makeMessagesSocket = (config) => {
352
380
  }
353
381
  }
354
382
 
355
- }
356
- return deviceResults
357
- }
358
-
359
- const assertSessions = async (jids, force) => {
360
- let didFetchNewSession = false
361
- const jidsRequiringFetch = []
362
-
363
- // Apply same deduplication as in getUSyncDevices
364
- jids = deduplicateLidPnJids(jids)
365
-
366
- if (force) {
367
- // Check which sessions are missing (with LID migration check)
368
- const addrs = jids.map(jid => signalRepository.jidToSignalProtocolAddress(jid))
369
- const sessions = await authState.keys.get('session', addrs)
383
+ const userDeviceUpdates = {}
370
384
 
371
- const checkJidSession = (jid) => {
372
- const signalId = signalRepository.jidToSignalProtocolAddress(jid)
373
- const hasSession = !!sessions[signalId]
374
-
375
- // Add to fetch list if no session exists
376
- // Session type selection (LID vs PN) is handled in encryptMessage
377
- if (!hasSession) {
378
- if (jid.includes('@lid')) {
379
- logger.debug({ jid }, 'No LID session found, will create new LID session')
380
- }
381
- jidsRequiringFetch.push(jid)
385
+ for (const [userId, devices] of Object.entries(deviceMap)) {
386
+ if (devices && devices.length > 0) {
387
+ userDeviceUpdates[userId] = devices.map(d => d.device?.toString() || '0')
382
388
  }
383
389
  }
384
390
 
385
- // Process all JIDs
386
- for (const jid of jids) {
387
- checkJidSession(jid)
391
+ if (Object.keys(userDeviceUpdates).length > 0) {
392
+ try {
393
+ await authState.keys.set({ 'device-list': userDeviceUpdates })
394
+
395
+ logger.debug({ userCount: Object.keys(userDeviceUpdates).length }, 'stored user device lists for bulk migration')
396
+ }
397
+
398
+ catch (error) {
399
+ logger.warn({ error }, 'failed to store user device lists')
400
+ }
388
401
  }
389
402
  }
390
- else {
391
- const addrs = jids.map(jid => signalRepository.jidToSignalProtocolAddress(jid))
392
- const sessions = await authState.keys.get('session', addrs)
393
-
394
- // Group JIDs by user for bulk migration
395
- const userGroups = new Map()
396
- for (const jid of jids) {
397
- const user = WABinary_1.jidNormalizedUser(jid)
398
- if (!userGroups.has(user)) {
399
- userGroups.set(user, [])
403
+
404
+ return deviceResults
405
+ }
406
+
407
+ const updateMemberLabel = (jid, memberLabel) => {
408
+ if (!isJidGroup(jid)) {
409
+ throw new Error('Jid must a group!')
410
+ }
411
+
412
+ const protocolMessage = {
413
+ protocolMessage: {
414
+ type: proto.Message.ProtocolMessage.Type.GROUP_MEMBER_LABEL_CHANGE,
415
+ memberLabel: {
416
+ label: memberLabel?.slice(0, 30),
417
+ labelTimestamp: unixTimestampSeconds()
400
418
  }
401
- userGroups.get(user).push(jid)
402
419
  }
403
-
404
- // Helper to check LID mapping for a user
405
- const checkUserLidMapping = async (user, userJids) => {
406
- if (!userJids.some(jid => WABinary_1.isJidUser(jid))) {
407
- return { shouldMigrate: false, lidForPN: undefined }
408
- }
409
-
410
- try {
411
- // Convert user to proper PN JID format for getLIDForPN
412
- const pnJid = `${user}@s.whatsapp.net`
413
- const mapping = await signalRepository.lidMapping.getLIDForPN(pnJid)
414
-
415
- if (mapping?.includes('@lid')) {
416
- logger.debug({ user, lidForPN: mapping, deviceCount: userJids.length }, 'User has LID mapping - preparing bulk migration')
417
- return { shouldMigrate: true, lidForPN: mapping }
420
+ }
421
+
422
+ return relayMessage(jid, protocolMessage, {
423
+ additionalNodes: [
424
+ {
425
+ tag: 'meta',
426
+ attrs: {
427
+ tag_reason: 'user_update',
428
+ appdata: 'member_tag'
418
429
  }
419
430
  }
420
- catch (error) {
421
- logger.debug({ user, error }, 'Failed to check LID mapping for user')
431
+ ]
432
+ })
433
+ }
434
+
435
+ const assertSessions = async (jids, force) => {
436
+ let didFetchNewSession = false
437
+
438
+ const uniqueJids = [...new Set(jids)] // Deduplicate JIDs
439
+ const jidsRequiringFetch = []
440
+
441
+ logger.debug({ jids }, 'assertSessions call with jids')
442
+
443
+ // Check peerSessionsCache and validate sessions using libsignal loadSession
444
+ for (const jid of uniqueJids) {
445
+ const signalId = signalRepository.jidToSignalProtocolAddress(jid)
446
+ const cachedSession = peerSessionsCache.get(signalId)
447
+
448
+ if (cachedSession !== undefined) {
449
+ if (cachedSession && !force) {
450
+ continue // Session exists in cache
422
451
  }
423
-
424
- return { shouldMigrate: false, lidForPN: undefined }
425
452
  }
426
453
 
427
- // Process each user group for potential bulk LID migration
428
- for (const [user, userJids] of userGroups) {
429
- const mappingResult = await checkUserLidMapping(user, userJids)
430
- const shouldMigrateUser = mappingResult.shouldMigrate
431
- const lidForPN = mappingResult.lidForPN
454
+ else {
455
+ const sessionValidation = await signalRepository.validateSession(jid)
456
+ const hasSession = sessionValidation.exists
432
457
 
433
- // Migrate all devices for this user if LID mapping exists
434
- if (shouldMigrateUser && lidForPN) {
435
- // Bulk migrate all user devices in single transaction
436
- const migrationResult = await signalRepository.migrateSession(userJids, lidForPN)
437
-
438
- if (migrationResult.migrated > 0) {
439
- logger.info({
440
- user,
441
- lidMapping: lidForPN,
442
- migrated: migrationResult.migrated,
443
- skipped: migrationResult.skipped,
444
- total: migrationResult.total
445
- }, 'Completed bulk migration for user devices');
446
- }
447
- else {
448
- logger.debug({
449
- user,
450
- lidMapping: lidForPN,
451
- skipped: migrationResult.skipped,
452
- total: migrationResult.total
453
- }, 'All user device sessions already migrated');
454
- }
455
- }
458
+ peerSessionsCache.set(signalId, hasSession)
456
459
 
457
- // Direct bulk session check with LID single source of truth
458
- const addMissingSessionsToFetchList = (jid) => {
459
- const signalId = signalRepository.jidToSignalProtocolAddress(jid)
460
-
461
- if (sessions[signalId]) return
462
-
463
- // Determine correct JID to fetch (LID if mapping exists, otherwise original)
464
- if (jid.includes('@s.whatsapp.net') && shouldMigrateUser && lidForPN) {
465
- const decoded = WABinary_1.jidDecode(jid)
466
- const lidDeviceJid = decoded.device !== undefined ? `${WABinary_1.jidDecode(lidForPN).user}:${decoded.device}@lid` : lidForPN
467
-
468
- jidsRequiringFetch.push(lidDeviceJid)
469
- logger.debug({ pnJid: jid, lidJid: lidDeviceJid }, 'Adding LID JID to fetch list (conversion)')
470
- }
471
-
472
- else {
473
- jidsRequiringFetch.push(jid)
474
- logger.debug({ jid }, 'Adding JID to fetch list')
475
- }
460
+ if (hasSession && !force) {
461
+ continue
476
462
  }
477
-
478
- userJids.forEach(addMissingSessionsToFetchList)
479
463
  }
464
+
465
+ jidsRequiringFetch.push(jid)
480
466
  }
481
467
 
482
468
  if (jidsRequiringFetch.length) {
483
- logger.debug({ jidsRequiringFetch }, 'fetching sessions')
484
-
485
- // DEBUG: Check if there are PN versions of LID users being fetched
486
- const lidUsersBeingFetched = new Set()
487
- const pnUsersBeingFetched = new Set()
488
-
489
- for (const jid of jidsRequiringFetch) {
490
- const user = WABinary_1.jidDecode(jid)?.user
491
-
492
- if (user) {
493
- if (WABinary_1.isLidUser(jid)) {
494
- lidUsersBeingFetched.add(user)
495
- }
496
- else if (WABinary_1.isJidUser(jid)) {
497
- pnUsersBeingFetched.add(user)
498
- }
499
- }
500
- }
469
+ // LID if mapped, otherwise original
470
+ const wireJids = [
471
+ ...jidsRequiringFetch.filter(jid => !!isLidUser(jid) || !!isHostedLidUser(jid)),
472
+ ...((await signalRepository.lidMapping.getLIDsForPNs(jidsRequiringFetch.filter(jid => !!isPnUser(jid) || !!isHostedPnUser(jid)))) || []).map(a => a.lid)
473
+ ]
501
474
 
502
- // Find overlaps
503
- const overlapping = Array.from(pnUsersBeingFetched).filter(user => lidUsersBeingFetched.has(user))
504
- if (overlapping.length > 0) {
505
- logger.warn({
506
- overlapping,
507
- lidUsersBeingFetched: Array.from(lidUsersBeingFetched),
508
- pnUsersBeingFetched: Array.from(pnUsersBeingFetched)
509
- }, 'Fetching both LID and PN sessions for same users')
510
- }
475
+ logger.debug({ jidsRequiringFetch, wireJids }, 'fetching sessions')
511
476
 
512
477
  const result = await query({
513
478
  tag: 'iq',
514
479
  attrs: {
515
480
  xmlns: 'encrypt',
516
481
  type: 'get',
517
- to: WABinary_1.S_WHATSAPP_NET
482
+ to: S_WHATSAPP_NET
518
483
  },
519
484
  content: [
520
485
  {
521
486
  tag: 'key',
522
487
  attrs: {},
523
- content: jidsRequiringFetch.map(jid => ({
524
- tag: 'user',
525
- attrs: { jid }
526
- }))
488
+ content: wireJids.map(jid => {
489
+ const attrs = { jid }
490
+
491
+ if (force) attrs.reason = 'identity'
492
+
493
+ return { tag: 'user', attrs }
494
+ })
527
495
  }
528
496
  ]
529
497
  })
530
498
 
531
- await Utils_1.parseAndInjectE2ESessions(result, signalRepository)
499
+ await parseAndInjectE2ESessions(result, signalRepository)
500
+
532
501
  didFetchNewSession = true
502
+
503
+ // Cache fetched sessions using wire JIDs
504
+ for (const wireJid of wireJids) {
505
+ const signalId = signalRepository.jidToSignalProtocolAddress(wireJid)
506
+ peerSessionsCache.set(signalId, true)
507
+ }
533
508
  }
509
+
534
510
  return didFetchNewSession
535
511
  }
536
-
537
- /** Send Peer Operation */
512
+
538
513
  const sendPeerDataOperationMessage = async (pdoMessage) => {
539
514
  //TODO: for later, abstract the logic to send a Peer Message instead of just PDO - useful for App State Key Resync with phone
540
515
  if (!authState.creds.me?.id) {
541
- throw new boom_1.Boom('Not authenticated')
516
+ throw new Boom('Not authenticated')
542
517
  }
543
-
518
+
544
519
  const protocolMessage = {
545
520
  protocolMessage: {
546
521
  peerDataOperationRequestMessage: pdoMessage,
547
- type: WAProto_1.proto.Message.ProtocolMessage.Type.PEER_DATA_OPERATION_REQUEST_MESSAGE
522
+ type: proto.Message.ProtocolMessage.Type.PEER_DATA_OPERATION_REQUEST_MESSAGE
548
523
  }
549
524
  }
550
-
551
- const meJid = WABinary_1.jidNormalizedUser(authState.creds.me.id)
552
-
525
+
526
+ const meJid = jidNormalizedUser(authState.creds.me.id)
553
527
  const msgId = await relayMessage(meJid, protocolMessage, {
554
528
  additionalAttributes: {
555
529
  category: 'peer',
556
- // eslint-disable-next-line camelcase
557
- push_priority: 'high_force',
530
+ push_priority: 'high_force'
558
531
  },
532
+ additionalNodes: [
533
+ {
534
+ tag: 'meta',
535
+ attrs: { appdata: 'default' }
536
+ }
537
+ ]
559
538
  })
560
-
539
+
561
540
  return msgId
562
541
  }
563
542
 
564
- const createParticipantNodes = async (jids, message, extraAttrs, dsmMessage) => {
565
- let patched = await patchMessageBeforeSending(message, jids)
566
-
567
- if (!Array.isArray(patched)) {
568
- patched = jids ? jids.map(jid => ({ recipientJid: jid, ...patched })) : [patched]
543
+ const createParticipantNodes = async (recipientJids, message, extraAttrs, dsmMessage) => {
544
+ if (!recipientJids.length) {
545
+ return { nodes: [], shouldIncludeDeviceIdentity: false }
569
546
  }
570
547
 
548
+ const patched = await patchMessageBeforeSending(message, recipientJids)
549
+ const patchedMessages = Array.isArray(patched)
550
+ ? patched
551
+ : recipientJids.map(jid => ({ recipientJid: jid, message: patched }))
552
+
571
553
  let shouldIncludeDeviceIdentity = false
572
554
 
573
555
  const meId = authState.creds.me.id
574
556
  const meLid = authState.creds.me?.lid
575
- const meLidUser = meLid ? WABinary_1.jidDecode(meLid)?.user : null
576
- const devicesByUser = new Map()
577
-
578
- for (const patchedMessageWithJid of patched) {
579
- const { recipientJid: wireJid, ...patchedMessage } = patchedMessageWithJid
580
- if (!wireJid)
581
- continue
557
+ const meLidUser = meLid ? jidDecode(meLid)?.user : null
558
+ const encryptionPromises = patchedMessages.map(async ({ recipientJid: jid, message: patchedMessage }) => {
559
+ if (!jid) return null
582
560
 
583
- // Extract user from JID for grouping
584
- const decoded = WABinary_1.jidDecode(wireJid)
585
- const user = decoded?.user
561
+ let msgToEncrypt = patchedMessage
586
562
 
587
- if (!user)
588
- continue
563
+ if (dsmMessage) {
564
+ const { user: targetUser } = jidDecode(jid)
565
+ const { user: ownPnUser } = jidDecode(meId)
566
+ const ownLidUser = meLidUser
567
+ const isOwnUser = targetUser === ownPnUser || (ownLidUser && targetUser === ownLidUser)
568
+ const isExactSenderDevice = jid === meId || (meLid && jid === meLid)
589
569
 
590
- if (!devicesByUser.has(user)) {
591
- devicesByUser.set(user, []);
592
- }
593
-
594
- devicesByUser.get(user).push({ recipientJid: wireJid, patchedMessage })
595
- }
596
-
597
- // Process each user's devices sequentially, but different users in parallel
598
- const userEncryptionPromises = Array.from(devicesByUser.entries()).map(([user, userDevices]) => encryptionMutex.mutex(user, async () => {
599
- logger.debug({ user, deviceCount: userDevices.length }, 'Acquiring encryption lock for user devices');
600
- const userNodes = []
601
-
602
- // Helper to get encryption JID with LID migration
603
- const getEncryptionJid = async (wireJid) => {
604
- if (!WABinary_1.isJidUser(wireJid))
605
- return wireJid
606
-
607
- try {
608
- const lidForPN = await signalRepository.lidMapping.getLIDForPN(wireJid)
609
-
610
- if (!lidForPN?.includes('@lid'))
611
- return wireJid
612
-
613
- // Preserve device ID from original wire JID
614
- const wireDecoded = WABinary_1.jidDecode(wireJid)
615
- const deviceId = wireDecoded?.device || 0
616
- const lidDecoded = WABinary_1.jidDecode(lidForPN)
617
- const lidWithDevice = WABinary_1.jidEncode(lidDecoded?.user, 'lid', deviceId)
618
-
619
- // Migrate session to LID for unified encryption layer
620
- try {
621
- const migrationResult = await signalRepository.migrateSession([wireJid], lidWithDevice)
622
- const recipientUser = WABinary_1.jidNormalizedUser(wireJid)
623
- const ownPnUser = WABinary_1.jidNormalizedUser(meId)
624
- const isOwnDevice = recipientUser === ownPnUser
625
- logger.info({ wireJid, lidWithDevice, isOwnDevice }, 'Migrated to LID encryption')
626
-
627
- // Delete PN session after successful migration
628
- try {
629
- if (migrationResult.migrated) {
630
- await signalRepository.deleteSession([wireJid])
631
- logger.debug({ deletedPNSession: wireJid }, 'Deleted PN session')
632
- }
633
- }
634
- catch (deleteError) {
635
- logger.warn({ wireJid, error: deleteError }, 'Failed to delete PN session')
636
- }
637
- return lidWithDevice
638
- }
639
- catch (migrationError) {
640
- logger.warn({ wireJid, error: migrationError }, 'Failed to migrate session')
641
- return wireJid
642
- }
643
- }
644
- catch (error) {
645
- logger.debug({ wireJid, error }, 'Failed to check LID mapping')
646
- return wireJid
570
+ if (isOwnUser && !isExactSenderDevice) {
571
+ msgToEncrypt = dsmMessage
572
+ logger.debug({ jid, targetUser }, 'Using DSM for own device')
647
573
  }
648
574
  }
649
575
 
650
- // Encrypt to this user's devices sequentially to prevent session corruption
651
- for (const { recipientJid: wireJid, patchedMessage } of userDevices) {
652
- // DSM logic: Use DSM for own other devices (following whatsmeow implementation)
653
- let messageToEncrypt = patchedMessage
654
-
655
- if (dsmMessage) {
656
- const { user: targetUser } = WABinary_1.jidDecode(wireJid)
657
- const { user: ownPnUser } = WABinary_1.jidDecode(meId)
658
- const ownLidUser = meLidUser
659
-
660
- // Check if this is our device (same user, different device)
661
- const isOwnUser = targetUser === ownPnUser || (ownLidUser && targetUser === ownLidUser)
662
-
663
- // Exclude exact sender device (whatsmeow: if jid == ownJID || jid == ownLID { continue })
664
- const isExactSenderDevice = wireJid === meId || (authState.creds.me?.lid && wireJid === authState.creds.me.lid)
665
-
666
- if (isOwnUser && !isExactSenderDevice) {
667
- messageToEncrypt = dsmMessage
668
- logger.debug({ wireJid, targetUser }, 'Using DSM for own device')
669
- }
670
- }
671
-
672
- const bytes = Utils_1.encodeWAMessage(messageToEncrypt)
673
-
674
- // Get encryption JID with LID migration
675
- const encryptionJid = await getEncryptionJid(wireJid)
676
-
677
- // ENCRYPT: Use the determined encryption identity (prefers migrated LID)
576
+ const bytes = encodeWAMessage(msgToEncrypt)
577
+ const mutexKey = jid
578
+ const node = await encryptionMutex.mutex(mutexKey, async () => {
678
579
  const { type, ciphertext } = await signalRepository.encryptMessage({
679
- jid: encryptionJid, // Unified encryption layer (LID when available)
580
+ jid,
680
581
  data: bytes
681
582
  })
682
583
 
@@ -684,9 +585,9 @@ const makeMessagesSocket = (config) => {
684
585
  shouldIncludeDeviceIdentity = true
685
586
  }
686
587
 
687
- const node = {
588
+ return {
688
589
  tag: 'to',
689
- attrs: { jid: wireJid }, // Always use original wire identity in envelope
590
+ attrs: { jid },
690
591
  content: [
691
592
  {
692
593
  tag: 'enc',
@@ -698,53 +599,71 @@ const makeMessagesSocket = (config) => {
698
599
  content: ciphertext
699
600
  }
700
601
  ]
701
- }
702
- userNodes.push(node)
703
- }
704
- logger.debug({ user, nodesCreated: userNodes.length }, 'Releasing encryption lock for user devices');
705
- return userNodes
706
- }))
602
+ };
603
+ })
604
+
605
+ return node
606
+ })
607
+
608
+ const nodes = (await Promise.all(encryptionPromises)).filter(node => node !== null)
707
609
 
708
- // Wait for all users to complete (users are processed in parallel)
709
- const userNodesArrays = await Promise.all(userEncryptionPromises)
710
- const nodes = userNodesArrays.flat()
711
610
  return { nodes, shouldIncludeDeviceIdentity }
712
611
  }
612
+
613
+ /** Fetch image for groups, user, and newsletter **/
614
+ const profilePictureUrl = async (jid) => {
615
+ if (isJidNewsletter(jid)) {
616
+ const metadata = await suki.newsletterMetadata('JID', jid)
617
+
618
+ return getUrlFromDirectPath(metadata.thread_metadata.picture?.direct_path || '')
619
+
620
+ }
621
+
622
+ else {
623
+ const result = await query({
624
+ tag: 'iq',
625
+ attrs: {
626
+ target: jidNormalizedUser(jid),
627
+ to: S_WHATSAPP_NET,
628
+ type: 'get',
629
+ xmlns: 'w:profile:picture'
630
+ },
631
+ content: [{
632
+ tag: 'picture',
633
+ attrs: {
634
+ type: 'image',
635
+ query: 'url'
636
+ }
637
+ }]
638
+ })
639
+
640
+ const child = getBinaryNodeChild(result, 'picture')
641
+
642
+ return child?.attrs?.url || null
643
+ }
644
+ }
713
645
 
714
646
  const relayMessage = async (jid, message, { messageId: msgId, participant, additionalAttributes, useUserDevicesCache, useCachedGroupMetadata, statusJidList, additionalNodes, AI = false }) => {
715
647
  const meId = authState.creds.me.id
716
648
  const meLid = authState.creds.me?.lid
717
-
649
+ const isRetryResend = Boolean(participant?.jid)
650
+
651
+ let shouldIncludeDeviceIdentity = isRetryResend
718
652
  let didPushAdditional = false
719
- let shouldIncludeDeviceIdentity = false
720
-
721
- const { user, server } = WABinary_1.jidDecode(jid)
722
-
653
+
723
654
  const statusJid = 'status@broadcast'
655
+ const { user, server } = jidDecode(jid)
724
656
  const isGroup = server === 'g.us'
725
- const isPrivate = server === 's.whatsapp.net'
726
- const isNewsletter = server == 'newsletter'
727
657
  const isStatus = jid === statusJid
728
658
  const isLid = server === 'lid'
729
-
730
- // Keep user's original JID choice for envelope addressing
659
+ const isNewsletter = server === 'newsletter'
660
+ const isGroupOrStatus = isGroup || isStatus
731
661
  const finalJid = jid
732
662
 
733
- // ADDRESSING CONSISTENCY: Match own identity to conversation context
734
- let ownId = meId
735
-
736
- if (isLid && meLid) {
737
- ownId = meLid
738
- logger.debug({ to: jid, ownId }, 'Using LID identity for @lid conversation')
739
- }
740
- else {
741
- logger.debug({ to: jid, ownId }, 'Using PN identity for @s.whatsapp.net conversation')
742
- }
743
-
744
- msgId = msgId || Utils_1.generateMessageID(authState.creds.me.id)
745
- useUserDevicesCache = useUserDevicesCache !== false
663
+ msgId = msgId || generateMessageID(meId)
664
+ useUserDevicesCache = useUserDevicesCache !== false;
746
665
  useCachedGroupMetadata = useCachedGroupMetadata !== false && !isStatus
747
-
666
+
748
667
  const participants = []
749
668
  const destinationJid = !isStatus ? finalJid : statusJid
750
669
  const binaryNodeContent = []
@@ -755,33 +674,30 @@ const makeMessagesSocket = (config) => {
755
674
  destinationJid,
756
675
  message
757
676
  },
758
- messageContextInfo: message.messageContextInfo || {}
677
+ messageContextInfo: message.messageContextInfo
759
678
  }
760
679
 
761
680
  const extraAttrs = {}
762
681
 
763
682
  const regexGroupOld = /^(\d{1,15})-(\d+)@g\.us$/
764
683
 
765
- const messages = Utils_1.normalizeMessageContent(message)
684
+ const messages = normalizeMessageContent(message)
766
685
 
767
686
  const buttonType = getButtonType(messages)
768
687
  const pollMessage = messages.pollCreationMessage || messages.pollCreationMessageV2 || messages.pollCreationMessageV3
769
688
 
770
689
 
771
690
  if (participant) {
772
- // when the retry request is not for a group
773
- // only send to the specific device that asked for a retry
774
- // otherwise the message is sent out to every device that should be a recipient
775
691
  if (!isGroup && !isStatus) {
776
- additionalAttributes = { ...additionalAttributes, 'device_fanout': 'false' }
692
+ additionalAttributes = { ...additionalAttributes, device_fanout: 'false' }
777
693
  }
778
-
779
- const { user, device } = WABinary_1.jidDecode(participant.jid)
780
-
694
+
695
+ const { user, device } = jidDecode(participant.jid)
696
+
781
697
  devices.push({
782
698
  user,
783
699
  device,
784
- wireJid: participant.jid // Use the participant JID as wire JID
700
+ jid: participant.jid
785
701
  })
786
702
  }
787
703
 
@@ -791,6 +707,34 @@ const makeMessagesSocket = (config) => {
791
707
  if (mediaType) {
792
708
  extraAttrs['mediatype'] = mediaType
793
709
  }
710
+
711
+ if (isNewsletter) {
712
+ const patched = patchMessageBeforeSending ? await patchMessageBeforeSending(message, []) : message
713
+ const bytes = encodeNewsletterMessage(patched)
714
+
715
+ binaryNodeContent.push({
716
+ tag: 'plaintext',
717
+ attrs: {},
718
+ content: bytes
719
+ })
720
+
721
+ const stanza = {
722
+ tag: 'message',
723
+ attrs: {
724
+ to: jid,
725
+ id: msgId,
726
+ type: getTypeMessage(message),
727
+ ...(additionalAttributes || {})
728
+ },
729
+ content: binaryNodeContent
730
+ }
731
+
732
+ logger.debug({ msgId }, `sending newsletter message to ${jid}`)
733
+
734
+ await sendNode(stanza)
735
+
736
+ return
737
+ }
794
738
 
795
739
  if (messages.pinInChatMessage || messages.keepInChatMessage || message.reactionMessage || message.protocolMessage?.editedMessage) {
796
740
  extraAttrs['decrypt-fail'] = 'hide'
@@ -800,244 +744,273 @@ const makeMessagesSocket = (config) => {
800
744
  extraAttrs['native_flow_name'] = messages.interactiveResponseMessage.nativeFlowResponseMessage?.name || 'menu_options'
801
745
  }
802
746
 
803
- if (isGroup || isStatus) {
747
+ if (isGroupOrStatus && !isRetryResend) {
804
748
  const [groupData, senderKeyMap] = await Promise.all([
805
749
  (async () => {
806
- let groupData = useCachedGroupMetadata && cachedGroupMetadata ? await cachedGroupMetadata(jid) : undefined
807
-
750
+ let groupData = useCachedGroupMetadata && cachedGroupMetadata ? await cachedGroupMetadata(jid) : undefined // todo: should we rely on the cache specially if the cache is outdated and the metadata has new fields?
751
+
808
752
  if (groupData && Array.isArray(groupData?.participants)) {
809
753
  logger.trace({ jid, participants: groupData.participants.length }, 'using cached group metadata')
810
754
  }
811
-
755
+
812
756
  else if (!isStatus) {
813
- groupData = await groupMetadata(jid)
757
+ groupData = await groupMetadata(jid) // TODO: start storing group participant list + addr mode in Signal & stop relying on this
814
758
  }
815
-
759
+
816
760
  return groupData
817
761
  })(),
818
-
819
762
  (async () => {
820
763
  if (!participant && !isStatus) {
821
- const result = await authState.keys.get('sender-key-memory', [jid])
764
+ // what if sender memory is less accurate than the cached metadata
765
+ // on participant change in group, we should do sender memory manipulation
766
+ const result = await authState.keys.get('sender-key-memory', [jid]) // TODO: check out what if the sender key memory doesn't include the LID stuff now?
767
+
822
768
  return result[jid] || {}
823
769
  }
824
-
770
+
825
771
  return {}
826
-
827
772
  })()
828
773
  ])
829
-
830
- if (!participant) {
831
- const participantsList = (groupData && !isStatus) ? groupData.participants.map(p => p.id) : []
832
-
833
- if (isStatus && statusJidList) {
834
- participantsList.push(...statusJidList)
774
+
775
+ const participantsList = groupData ? groupData.participants.map(p => p.id) : []
776
+
777
+ if (groupData?.ephemeralDuration && groupData.ephemeralDuration > 0) {
778
+ additionalAttributes = {
779
+ ...additionalAttributes,
780
+ expiration: groupData.ephemeralDuration.toString()
835
781
  }
836
-
837
- if (!isStatus) {
838
- const groupAddressingMode = groupData?.addressingMode || (isLid ? Types_1.WAMessageAddressingMode.LID : Types_1.WAMessageAddressingMode.PN)
839
- additionalAttributes = {
840
- ...additionalAttributes,
841
- addressing_mode: groupAddressingMode
842
- }
782
+ }
783
+
784
+ if (isStatus && statusJidList) {
785
+ participantsList.push(...statusJidList)
786
+ }
787
+
788
+ const additionalDevices = await getUSyncDevices(participantsList, !!useUserDevicesCache, false)
789
+
790
+ devices.push(...additionalDevices)
791
+
792
+ if (isGroup) {
793
+ additionalAttributes = {
794
+ ...additionalAttributes,
795
+ addressing_mode: groupData?.addressingMode || 'lid'
843
796
  }
844
-
845
- const additionalDevices = await getUSyncDevices(participantsList, !!useUserDevicesCache, false)
846
- devices.push(...additionalDevices)
847
797
  }
848
-
849
- const patched = await patchMessageBeforeSending(message, devices.map(d => WABinary_1.jidEncode(d.user, isLid ? 'lid' : 's.whatsapp.net', d.device)))
850
- const bytes = Utils_1.encodeWAMessage(patched)
851
798
 
852
- // This should match the group's addressing mode and conversation context
853
- const groupAddressingMode = groupData?.addressingMode || (isLid ? 'lid' : 'pn')
799
+ const patched = await patchMessageBeforeSending(message)
800
+
801
+ if (Array.isArray(patched)) {
802
+ throw new Boom('Per-jid patching is not supported in groups')
803
+ }
804
+
805
+ const bytes = encodeWAMessage(patched)
806
+ const groupAddressingMode = additionalAttributes?.['addressing_mode'] || groupData?.addressingMode || 'lid'
854
807
  const groupSenderIdentity = groupAddressingMode === 'lid' && meLid ? meLid : meId
855
-
856
808
  const { ciphertext, senderKeyDistributionMessage } = await signalRepository.encryptGroupMessage({
857
809
  group: destinationJid,
858
810
  data: bytes,
859
811
  meId: groupSenderIdentity
860
812
  })
861
-
862
- const senderKeyJids = []
863
-
864
- // ensure a connection is established with every device
813
+
814
+ const senderKeyRecipients = []
815
+
865
816
  for (const device of devices) {
866
- // This preserves the LID migration results from getUSyncDevices
867
- const deviceJid = device.wireJid
817
+ const deviceJid = device.jid
868
818
  const hasKey = !!senderKeyMap[deviceJid]
869
- if (!hasKey || !!participant) {
870
- senderKeyJids.push(deviceJid)
871
- // store that this person has had the sender keys sent to them
819
+
820
+ if ((!hasKey || !!participant) &&
821
+ !isHostedLidUser(deviceJid) &&
822
+ !isHostedPnUser(deviceJid) &&
823
+ device.device !== 99) {
824
+ //todo: revamp all this logic
825
+ // the goal is to follow with what I said above for each group, and instead of a true false map of ids, we can set an array full of those the app has already sent pkmsgs
826
+ senderKeyRecipients.push(deviceJid)
872
827
  senderKeyMap[deviceJid] = true
873
828
  }
874
829
  }
875
-
876
- // if there are some participants with whom the session has not been established
877
- // if there are, we re-send the senderkey
878
- if (senderKeyJids.length) {
879
- logger.debug({ senderKeyJids }, 'sending new sender key')
830
+
831
+ if (senderKeyRecipients.length) {
832
+ logger.debug({ senderKeyJids: senderKeyRecipients }, 'sending new sender key')
833
+
880
834
  const senderKeyMsg = {
881
835
  senderKeyDistributionMessage: {
882
836
  axolotlSenderKeyDistributionMessage: senderKeyDistributionMessage,
883
837
  groupId: destinationJid
884
838
  }
885
839
  }
886
-
887
- await assertSessions(senderKeyJids, false)
888
-
889
- const result = await createParticipantNodes(senderKeyJids, senderKeyMsg, extraAttrs)
890
-
891
- shouldIncludeDeviceIdentity = shouldIncludeDeviceIdentity || result.shouldIncludeDeviceIdentity
892
-
840
+
841
+ const senderKeySessionTargets = senderKeyRecipients
842
+
843
+ await assertSessions(senderKeySessionTargets)
844
+
845
+ const result = await createParticipantNodes(senderKeyRecipients, senderKeyMsg, extraAttrs)
846
+
847
+ shouldIncludeDeviceIdentity = shouldIncludeDeviceIdentity || result.shouldIncludeDeviceIdentity;
893
848
  participants.push(...result.nodes)
894
849
  }
895
-
850
+
896
851
  binaryNodeContent.push({
897
852
  tag: 'enc',
898
- attrs: { v: '2', type: 'skmsg', ...extraAttrs },
853
+ attrs: { v: '2', type: 'skmsg', ...extraAttrs },
899
854
  content: ciphertext
900
855
  })
901
-
856
+
902
857
  await authState.keys.set({ 'sender-key-memory': { [jid]: senderKeyMap } })
903
858
  }
904
859
 
905
- else if (isNewsletter) {
906
- // Message edit
907
- if (message.protocolMessage?.editedMessage) {
908
- msgId = message.protocolMessage.key?.id
909
- message = message.protocolMessage.editedMessage
860
+ else {
861
+ // ADDRESSING CONSISTENCY: Match own identity to conversation context
862
+ // TODO: investigate if this is true
863
+ let ownId = meId
864
+
865
+ if (isLid && meLid) {
866
+ ownId = meLid;
867
+ logger.debug({ to: jid, ownId }, 'Using LID identity for @lid conversation')
910
868
  }
911
-
912
- // Message delete
913
- if (message.protocolMessage?.type === WAProto_1.proto.Message.ProtocolMessage.Type.REVOKE) {
914
- msgId = message.protocolMessage.key?.id
915
- message = {}
869
+
870
+ else {
871
+ logger.debug({ to: jid, ownId }, 'Using PN identity for @s.whatsapp.net conversation')
916
872
  }
917
-
918
- const patched = await patchMessageBeforeSending(message, [])
919
- const bytes = Utils_1.encodeNewsletterMessage(patched)
920
-
921
- binaryNodeContent.push({
922
- tag: 'plaintext',
923
- attrs: extraAttrs,
924
- content: bytes
925
- })
926
- }
927
-
928
- else {
929
- const { user: ownUser } = WABinary_1.jidDecode(ownId)
930
-
931
- if (!participant) {
873
+
874
+ const { user: ownUser } = jidDecode(ownId)
875
+
876
+ if (!isRetryResend) {
932
877
  const targetUserServer = isLid ? 'lid' : 's.whatsapp.net'
878
+
933
879
  devices.push({
934
880
  user,
935
881
  device: 0,
936
- wireJid: WABinary_1.jidEncode(user, targetUserServer, 0)
882
+ jid: jidEncode(user, targetUserServer, 0) // rajeh, todo: this entire logic is convoluted and weird.
937
883
  })
938
884
 
939
- // Own user matches conversation addressing mode
940
885
  if (user !== ownUser) {
941
- const ownUserServer = isLid ? 'lid' : 's.whatsapp.net';
942
- const ownUserForAddressing = isLid && meLid ? WABinary_1.jidDecode(meLid).user : WABinary_1.jidDecode(meId).user
886
+ const ownUserServer = isLid ? 'lid' : 's.whatsapp.net'
887
+ const ownUserForAddressing = isLid && meLid ? jidDecode(meLid).user : jidDecode(meId).user
888
+
943
889
  devices.push({
944
890
  user: ownUserForAddressing,
945
891
  device: 0,
946
- wireJid: WABinary_1.jidEncode(ownUserForAddressing, ownUserServer, 0)
892
+ jid: jidEncode(ownUserForAddressing, ownUserServer, 0)
947
893
  })
948
894
  }
949
-
895
+
950
896
  if (additionalAttributes?.['category'] !== 'peer') {
951
897
  // Clear placeholders and enumerate actual devices
952
898
  devices.length = 0
953
899
 
954
900
  // Use conversation-appropriate sender identity
955
901
  const senderIdentity = isLid && meLid
956
- ? WABinary_1.jidEncode(WABinary_1.jidDecode(meLid)?.user, 'lid', undefined)
957
- : WABinary_1.jidEncode(WABinary_1.jidDecode(meId)?.user, 's.whatsapp.net', undefined)
958
-
902
+ ? jidEncode(jidDecode(meLid)?.user, 'lid', undefined)
903
+ : jidEncode(jidDecode(meId)?.user, 's.whatsapp.net', undefined)
959
904
  // Enumerate devices for sender and target with consistent addressing
960
- const sessionDevices = await getUSyncDevices([senderIdentity, jid], false, false)
905
+ const sessionDevices = await getUSyncDevices([senderIdentity, jid], true, false)
906
+
961
907
  devices.push(...sessionDevices)
908
+
962
909
  logger.debug({
963
910
  deviceCount: devices.length,
964
- devices: devices.map(d => `${d.user}:${d.device}@${WABinary_1.jidDecode(d.wireJid)?.server}`)
911
+ devices: devices.map(d => `${d.user}:${d.device}@${jidDecode(d.jid)?.server}`)
965
912
  }, 'Device enumeration complete with unified addressing')
966
913
  }
967
914
  }
968
-
969
- const allJids = []
970
- const meJids = []
971
- const otherJids = []
972
915
 
973
- const { user: mePnUser } = WABinary_1.jidDecode(meId)
974
- const { user: meLidUser } = meLid ? WABinary_1.jidDecode(meLid) : { user: null }
975
-
976
- for (const { user, wireJid } of devices) {
977
- const isExactSenderDevice = wireJid === meId || (meLid && wireJid === meLid)
916
+ const allRecipients = []
917
+ const meRecipients = []
918
+ const otherRecipients = []
919
+
920
+ const { user: mePnUser } = jidDecode(meId)
921
+ const { user: meLidUser } = meLid ? jidDecode(meLid) : { user: null }
922
+
923
+ for (const { user, jid } of devices) {
924
+ const isExactSenderDevice = jid === meId || (meLid && jid === meLid)
925
+
978
926
  if (isExactSenderDevice) {
979
- logger.debug({ wireJid, meId, meLid }, 'Skipping exact sender device (whatsmeow pattern)')
927
+ logger.debug({ jid, meId, meLid }, 'Skipping exact sender device (whatsmeow pattern)')
980
928
  continue
981
929
  }
982
930
 
983
931
  // Check if this is our device (could match either PN or LID user)
984
- const isMe = user === mePnUser || (meLidUser && user === meLidUser)
985
- const jid = wireJid
986
-
932
+ const isMe = user === mePnUser || user === meLidUser
933
+
987
934
  if (isMe) {
988
- meJids.push(jid)
935
+ meRecipients.push(jid);
989
936
  }
990
-
937
+
991
938
  else {
992
- otherJids.push(jid)
939
+ otherRecipients.push(jid)
993
940
  }
994
-
995
- allJids.push(jid)
941
+
942
+ allRecipients.push(jid)
996
943
  }
997
-
998
- await assertSessions([...otherJids, ...meJids], false)
999
-
944
+
945
+ await assertSessions(allRecipients)
946
+
1000
947
  const [{ nodes: meNodes, shouldIncludeDeviceIdentity: s1 }, { nodes: otherNodes, shouldIncludeDeviceIdentity: s2 }] = await Promise.all([
1001
948
  // For own devices: use DSM if available (1:1 chats only)
1002
- createParticipantNodes(meJids, meMsg || message, extraAttrs),
1003
- createParticipantNodes(otherJids, message, extraAttrs, meMsg)
949
+ createParticipantNodes(meRecipients, meMsg || message, extraAttrs),
950
+ createParticipantNodes(otherRecipients, message, extraAttrs, meMsg)
1004
951
  ])
1005
-
952
+
1006
953
  participants.push(...meNodes)
1007
-
1008
954
  participants.push(...otherNodes)
1009
955
 
1010
- if (meJids.length > 0 || otherJids.length > 0) {
1011
- extraAttrs['phash'] = Utils_1.generateParticipantHashV2([...meJids, ...otherJids])
956
+ if (meRecipients.length > 0 || otherRecipients.length > 0) {
957
+ extraAttrs['phash'] = generateParticipantHashV2([...meRecipients, ...otherRecipients])
1012
958
  }
1013
-
959
+
1014
960
  shouldIncludeDeviceIdentity = shouldIncludeDeviceIdentity || s1 || s2
1015
961
  }
1016
-
962
+
963
+ if (isRetryResend) {
964
+ const isParticipantLid = isLidUser(participant.jid)
965
+ const isMe = areJidsSameUser(participant.jid, isParticipantLid ? meLid : meId)
966
+ const encodedMessageToSend = isMe
967
+ ? encodeWAMessage({
968
+ deviceSentMessage: {
969
+ destinationJid,
970
+ message
971
+ }
972
+ })
973
+ : encodeWAMessage(message)
974
+ const { type, ciphertext: encryptedContent } = await signalRepository.encryptMessage({
975
+ data: encodedMessageToSend,
976
+ jid: participant.jid
977
+ })
978
+
979
+ binaryNodeContent.push({
980
+ tag: 'enc',
981
+ attrs: {
982
+ v: '2',
983
+ type,
984
+ count: participant.count.toString()
985
+ },
986
+ content: encryptedContent
987
+ })
988
+ }
989
+
1017
990
  if (participants.length) {
1018
991
  if (additionalAttributes?.['category'] === 'peer') {
1019
992
  const peerNode = participants[0]?.content?.[0]
1020
-
993
+
1021
994
  if (peerNode) {
1022
995
  binaryNodeContent.push(peerNode) // push only enc
1023
996
  }
1024
997
  }
1025
-
998
+
1026
999
  else {
1027
1000
  binaryNodeContent.push({
1028
1001
  tag: 'participants',
1029
1002
  attrs: {},
1030
1003
  content: participants
1031
- })
1004
+ });
1032
1005
  }
1033
1006
  }
1034
-
1007
+
1035
1008
  const stanza = {
1036
1009
  tag: 'message',
1037
1010
  attrs: {
1011
+ id: msgId,
1038
1012
  to: destinationJid,
1039
- id: msgId,
1040
- type: getTypeMessage(message),
1013
+ type: getTypeMessage(message),
1041
1014
  ...(additionalAttributes || {})
1042
1015
  },
1043
1016
  content: binaryNodeContent
@@ -1047,34 +1020,45 @@ const makeMessagesSocket = (config) => {
1047
1020
  // ensure the message is only sent to that person
1048
1021
  // if a retry receipt is sent to everyone -- it'll fail decryption for everyone else who received the msg
1049
1022
  if (participant) {
1050
- if (WABinary_1.isJidGroup(destinationJid)) {
1023
+ if (isJidGroup(destinationJid)) {
1051
1024
  stanza.attrs.to = destinationJid
1052
1025
  stanza.attrs.participant = participant.jid
1053
1026
  }
1054
-
1055
- else if (WABinary_1.areJidsSameUser(participant.jid, meId)) {
1027
+
1028
+ else if (areJidsSameUser(participant.jid, meId)) {
1056
1029
  stanza.attrs.to = participant.jid
1057
1030
  stanza.attrs.recipient = destinationJid
1058
1031
  }
1059
-
1032
+
1060
1033
  else {
1061
1034
  stanza.attrs.to = participant.jid
1062
1035
  }
1063
1036
  }
1064
-
1037
+
1065
1038
  else {
1066
1039
  stanza.attrs.to = destinationJid
1067
1040
  }
1068
-
1041
+
1069
1042
  if (shouldIncludeDeviceIdentity) {
1070
1043
  stanza.content.push({
1071
1044
  tag: 'device-identity',
1072
1045
  attrs: {},
1073
- content: Utils_1.encodeSignedDeviceIdentity(authState.creds.account, true)
1046
+ content: encodeSignedDeviceIdentity(authState.creds.account, true)
1074
1047
  })
1075
-
1048
+
1076
1049
  logger.debug({ jid }, 'adding device identity')
1077
1050
  }
1051
+
1052
+ const contactTcTokenData = !isGroup && !isRetryResend && !isStatus ? await authState.keys.get('tctoken', [destinationJid]) : {}
1053
+ const tcTokenBuffer = contactTcTokenData[destinationJid]?.token
1054
+
1055
+ if (tcTokenBuffer) {
1056
+ stanza.content.push({
1057
+ tag: 'tctoken',
1058
+ attrs: {},
1059
+ content: tcTokenBuffer
1060
+ })
1061
+ }
1078
1062
 
1079
1063
  if (isGroup && regexGroupOld.test(jid) && !message.reactionMessage) {
1080
1064
  stanza.content.push({
@@ -1099,7 +1083,7 @@ const makeMessagesSocket = (config) => {
1099
1083
 
1100
1084
  if (!isNewsletter && buttonType) {
1101
1085
  const buttonsNode = getButtonArgs(messages)
1102
- const filteredButtons = WABinary_1.getBinaryFilteredButtons(additionalNodes ? additionalNodes : [])
1086
+ const filteredButtons = getBinaryFilteredButtons(additionalNodes ? additionalNodes : [])
1103
1087
 
1104
1088
  if (filteredButtons) {
1105
1089
  stanza.content.push(...additionalNodes)
@@ -1119,7 +1103,7 @@ const makeMessagesSocket = (config) => {
1119
1103
  }
1120
1104
  }
1121
1105
 
1122
- const filteredBizBot = WABinary_1.getBinaryFilteredBizBot(additionalNodes ? additionalNodes : [])
1106
+ const filteredBizBot = getBinaryFilteredBizBot(additionalNodes ? additionalNodes : [])
1123
1107
 
1124
1108
  if (filteredBizBot) {
1125
1109
  stanza.content.push(...additionalNodes)
@@ -1149,7 +1133,7 @@ const makeMessagesSocket = (config) => {
1149
1133
  }
1150
1134
 
1151
1135
  const getTypeMessage = (msg) => {
1152
- const message = Utils_1.normalizeMessageContent(msg)
1136
+ const message = normalizeMessageContent(msg)
1153
1137
  if (message.pollCreationMessage || message.pollCreationMessageV2 || message.pollCreationMessageV3) {
1154
1138
  return 'poll'
1155
1139
  }
@@ -1268,7 +1252,7 @@ const makeMessagesSocket = (config) => {
1268
1252
  attrs: {
1269
1253
  actual_actors: '2',
1270
1254
  host_storage: '2',
1271
- privacy_mode_ts: Utils_1.unixTimestampSeconds().toString()
1255
+ privacy_mode_ts: unixTimestampSeconds().toString()
1272
1256
  },
1273
1257
  content: [{
1274
1258
  tag: 'interactive',
@@ -1298,7 +1282,7 @@ const makeMessagesSocket = (config) => {
1298
1282
  attrs: {
1299
1283
  actual_actors: '2',
1300
1284
  host_storage: '2',
1301
- privacy_mode_ts: Utils_1.unixTimestampSeconds().toString()
1285
+ privacy_mode_ts: unixTimestampSeconds().toString()
1302
1286
  },
1303
1287
  content: [{
1304
1288
  tag: 'interactive',
@@ -1327,7 +1311,7 @@ const makeMessagesSocket = (config) => {
1327
1311
  attrs: {
1328
1312
  actual_actors: '2',
1329
1313
  host_storage: '2',
1330
- privacy_mode_ts: Utils_1.unixTimestampSeconds().toString()
1314
+ privacy_mode_ts: unixTimestampSeconds().toString()
1331
1315
  },
1332
1316
  content: [{
1333
1317
  tag: 'list',
@@ -1349,19 +1333,19 @@ const makeMessagesSocket = (config) => {
1349
1333
  attrs: {
1350
1334
  actual_actors: '2',
1351
1335
  host_storage: '2',
1352
- privacy_mode_ts: Utils_1.unixTimestampSeconds().toString()
1336
+ privacy_mode_ts: unixTimestampSeconds().toString()
1353
1337
  }
1354
1338
  }
1355
1339
  }
1356
1340
  }
1357
1341
 
1358
1342
  const getPrivacyTokens = async (jids) => {
1359
- const t = Utils_1.unixTimestampSeconds().toString()
1343
+ const t = unixTimestampSeconds().toString()
1360
1344
 
1361
1345
  const result = await query({
1362
1346
  tag: 'iq',
1363
1347
  attrs: {
1364
- to: WABinary_1.S_WHATSAPP_NET,
1348
+ to: S_WHATSAPP_NET,
1365
1349
  type: 'set',
1366
1350
  xmlns: 'privacy'
1367
1351
  },
@@ -1372,7 +1356,7 @@ const makeMessagesSocket = (config) => {
1372
1356
  content: jids.map(jid => ({
1373
1357
  tag: 'token',
1374
1358
  attrs: {
1375
- jid: WABinary_1.jidNormalizedUser(jid),
1359
+ jid: jidNormalizedUser(jid),
1376
1360
  t,
1377
1361
  type: 'trusted_contact'
1378
1362
  }
@@ -1385,7 +1369,7 @@ const makeMessagesSocket = (config) => {
1385
1369
  }
1386
1370
 
1387
1371
  const getEphemeralGroup = (jid) => {
1388
- if (!WABinary_1.isJidGroup(jid)) throw new TypeError("Jid should originate from a group!")
1372
+ if (!isJidGroup(jid)) throw new TypeError("Jid should originate from a group!")
1389
1373
 
1390
1374
  return groupQuery(jid, 'get', [{
1391
1375
  tag: 'query',
@@ -1393,23 +1377,23 @@ const makeMessagesSocket = (config) => {
1393
1377
  request: 'interactive'
1394
1378
  }
1395
1379
  }])
1396
- .then((groups) => WABinary_1.getBinaryNodeChild(groups, 'group'))
1397
- .then((metadata) => WABinary_1.getBinaryNodeChild(metadata, 'ephemeral')?.attrs?.expiration || 0)
1380
+ .then((groups) => getBinaryNodeChild(groups, 'group'))
1381
+ .then((metadata) => getBinaryNodeChild(metadata, 'ephemeral')?.attrs?.expiration || 0)
1398
1382
  }
1399
1383
 
1400
- const waUploadToServer = Utils_1.getWAUploadToServer(config, refreshMediaConn)
1384
+ const waUploadToServer = getWAUploadToServer(config, refreshMediaConn)
1401
1385
 
1402
- const waitForMsgMediaUpdate = Utils_1.bindWaitForEvent(ev, 'messages.media-update')
1386
+ const waitForMsgMediaUpdate = bindWaitForEvent(ev, 'messages.media-update')
1403
1387
 
1404
1388
  return {
1405
1389
  ...suki,
1406
1390
  getPrivacyTokens,
1407
1391
  assertSessions,
1392
+ profilePictureUrl,
1408
1393
  relayMessage,
1409
1394
  sendReceipt,
1410
1395
  sendReceipts,
1411
1396
  readMessages,
1412
- profilePictureUrl,
1413
1397
  getUSyncDevices,
1414
1398
  refreshMediaConn,
1415
1399
  waUploadToServer,
@@ -1418,78 +1402,80 @@ const makeMessagesSocket = (config) => {
1418
1402
  messageRetryManager,
1419
1403
  createParticipantNodes,
1420
1404
  sendPeerDataOperationMessage,
1405
+ updateMemberLabel,
1421
1406
  updateMediaMessage: async (message) => {
1422
- const content = Utils_1.assertMediaContent(message.message)
1407
+ const content = assertMediaContent(message.message)
1423
1408
  const mediaKey = content.mediaKey
1424
1409
  const meId = authState.creds.me.id
1425
- const node = await Utils_1.encryptMediaRetryRequest(message.key, mediaKey, meId)
1410
+ const node = await encryptMediaRetryRequest(message.key, mediaKey, meId)
1411
+
1426
1412
  let error = undefined
1427
-
1413
+
1428
1414
  await Promise.all([
1429
1415
  sendNode(node),
1430
1416
  waitForMsgMediaUpdate(async (update) => {
1431
1417
  const result = update.find(c => c.key.id === message.key.id)
1418
+
1432
1419
  if (result) {
1433
1420
  if (result.error) {
1434
1421
  error = result.error
1435
1422
  }
1436
-
1423
+
1437
1424
  else {
1438
1425
  try {
1439
- const media = await Utils_1.decryptMediaRetryData(result.media, mediaKey, result.key.id)
1440
-
1441
- if (media.result !== WAProto_1.proto.MediaRetryNotification.ResultType.SUCCESS) {
1442
- const resultStr = WAProto_1.proto.MediaRetryNotification.ResultType[media.result]
1443
-
1444
- throw new boom_1.Boom(`Media re-upload failed by device (${resultStr})`, { data: media, statusCode: Utils_1.getStatusCodeForMediaRetry(media.result) || 404 })
1426
+ const media = await decryptMediaRetryData(result.media, mediaKey, result.key.id)
1427
+
1428
+ if (media.result !== proto.MediaRetryNotification.ResultType.SUCCESS) {
1429
+ const resultStr = proto.MediaRetryNotification.ResultType[media.result]
1430
+
1431
+ throw new Boom(`Media re-upload failed by device (${resultStr})`, {
1432
+ data: media,
1433
+ statusCode: getStatusCodeForMediaRetry(media.result) || 404
1434
+ })
1445
1435
  }
1446
-
1436
+
1447
1437
  content.directPath = media.directPath
1448
-
1449
- content.url = Utils_1.getUrlFromDirectPath(content.directPath)
1450
-
1438
+ content.url = getUrlFromDirectPath(content.directPath)
1451
1439
  logger.debug({ directPath: media.directPath, key: result.key }, 'media update successful')
1452
1440
  }
1453
-
1441
+
1454
1442
  catch (err) {
1455
1443
  error = err
1456
1444
  }
1457
1445
  }
1458
-
1446
+
1459
1447
  return true
1460
1448
  }
1461
1449
  })
1462
1450
  ])
1463
-
1451
+
1464
1452
  if (error) {
1465
1453
  throw error
1466
1454
  }
1467
-
1468
- ev.emit('messages.update', [
1469
- { key: message.key, update: { message: message.message } }
1470
- ])
1471
-
1455
+
1456
+ ev.emit('messages.update', [{ key: message.key, update: { message: message.message } }])
1457
+
1472
1458
  return message
1473
1459
  },
1474
1460
  sendStatusMentions: async (content, jids = []) => {
1475
- const userJid = WABinary_1.jidNormalizedUser(authState.creds.me.id)
1461
+ const userJid = jidNormalizedUser(authState.creds.me.id)
1476
1462
  let allUsers = new Set()
1477
1463
  allUsers.add(userJid)
1478
1464
 
1479
1465
  for (const id of jids) {
1480
- const isGroup = WABinary_1.isJidGroup(id)
1481
- const isPrivate = WABinary_1.isJidUser(id)
1466
+ const isGroup = isJidGroup(id)
1467
+ const isPrivate = isPnUser(id)
1482
1468
 
1483
1469
  if (isGroup) {
1484
1470
  try {
1485
1471
  const metadata = await cachedGroupMetadata(id) || await groupMetadata(id)
1486
- const participants = metadata.participants.map(p => WABinary_1.jidNormalizedUser(p.id))
1472
+ const participants = metadata.participants.map(p => jidNormalizedUser(p.id))
1487
1473
  participants.forEach(jid => allUsers.add(jid))
1488
1474
  } catch (error) {
1489
1475
  logger.error(`Error getting metadata for group ${id}: ${error}`)
1490
1476
  }
1491
1477
  } else if (isPrivate) {
1492
- allUsers.add(WABinary_1.jidNormalizedUser(id))
1478
+ allUsers.add(jidNormalizedUser(id))
1493
1479
  }
1494
1480
  }
1495
1481
 
@@ -1529,12 +1515,15 @@ const makeMessagesSocket = (config) => {
1529
1515
  let msg
1530
1516
  let mediaHandle
1531
1517
  try {
1532
- msg = await Utils_1.generateWAMessage(WABinary_1.STORIES_JID, messageContent, {
1518
+ msg = await generateWAMessage(STORIES_JID, messageContent, {
1533
1519
  logger,
1534
1520
  userJid,
1535
- getUrlInfo: text => link_preview_1.getUrlInfo(text, {
1521
+ getUrlInfo: text => getUrlInfo(text, {
1536
1522
  thumbnailWidth: linkPreviewImageThumbnailWidth,
1537
- fetchOpts: { timeout: 3000, ...axiosOptions || {} },
1523
+ fetchOpts: {
1524
+ timeout: 3000,
1525
+ ...(httpRequestOptions || {})
1526
+ },
1538
1527
  logger,
1539
1528
  uploadImage: generateHighQualityLinkPreview ? waUploadToServer : undefined
1540
1529
  }),
@@ -1555,7 +1544,7 @@ const makeMessagesSocket = (config) => {
1555
1544
  throw error
1556
1545
  }
1557
1546
 
1558
- await relayMessage(WABinary_1.STORIES_JID, msg.message, {
1547
+ await relayMessage(STORIES_JID, msg.message, {
1559
1548
  messageId: msg.key.id,
1560
1549
  statusJidList: uniqueUsers,
1561
1550
  additionalNodes: [
@@ -1568,7 +1557,7 @@ const makeMessagesSocket = (config) => {
1568
1557
  attrs: {},
1569
1558
  content: jids.map(jid => ({
1570
1559
  tag: 'to',
1571
- attrs: { jid: WABinary_1.jidNormalizedUser(jid) }
1560
+ attrs: { jid: jidNormalizedUser(jid) }
1572
1561
  }))
1573
1562
  }]
1574
1563
  }]
@@ -1576,8 +1565,8 @@ const makeMessagesSocket = (config) => {
1576
1565
 
1577
1566
  for (const id of jids) {
1578
1567
  try {
1579
- const normalizedId = WABinary_1.jidNormalizedUser(id)
1580
- const isPrivate = WABinary_1.isJidUser(normalizedId)
1568
+ const normalizedId = jidNormalizedUser(id)
1569
+ const isPrivate = isPnUser(normalizedId)
1581
1570
  const type = isPrivate ? 'statusMentionMessage' : 'groupStatusMentionMessage'
1582
1571
 
1583
1572
  const protocolMessage = {
@@ -1590,11 +1579,11 @@ const makeMessagesSocket = (config) => {
1590
1579
  }
1591
1580
  },
1592
1581
  messageContextInfo: {
1593
- messageSecret: crypto_1.randomBytes(32)
1582
+ messageSecret: randomBytes(32)
1594
1583
  }
1595
1584
  }
1596
1585
 
1597
- const statusMsg = await Utils_1.generateWAMessageFromContent(normalizedId,
1586
+ const statusMsg = await generateWAMessageFromContent(normalizedId,
1598
1587
  protocolMessage,
1599
1588
  {}
1600
1589
  )
@@ -1612,7 +1601,7 @@ const makeMessagesSocket = (config) => {
1612
1601
  }
1613
1602
  )
1614
1603
 
1615
- await Utils_1.delay(2000)
1604
+ await delay(2000)
1616
1605
  } catch (error) {
1617
1606
  logger.error(`Error sending to ${id}: ${error}`)
1618
1607
  }
@@ -1625,7 +1614,7 @@ const makeMessagesSocket = (config) => {
1625
1614
  const additionalAttributes = {}
1626
1615
 
1627
1616
  if (!options.ephemeralExpiration) {
1628
- if (WABinary_1.isJidGroup(jid)) {
1617
+ if (isJidGroup(jid)) {
1629
1618
  const expiration = await getEphemeralGroup(jid)
1630
1619
  options.ephemeralExpiration = expiration
1631
1620
  }
@@ -1634,19 +1623,19 @@ const makeMessagesSocket = (config) => {
1634
1623
  if (typeof content === 'object' &&
1635
1624
  'disappearingMessagesInChat' in content &&
1636
1625
  typeof content['disappearingMessagesInChat'] !== 'undefined' &&
1637
- WABinary_1.isJidGroup(jid)) {
1626
+ isJidGroup(jid)) {
1638
1627
 
1639
1628
  const { disappearingMessagesInChat } = content
1640
1629
 
1641
1630
  const value = typeof disappearingMessagesInChat === 'boolean' ?
1642
- (disappearingMessagesInChat ? Defaults_1.WA_DEFAULT_EPHEMERAL : 0) :
1631
+ (disappearingMessagesInChat ? WA_DEFAULT_EPHEMERAL : 0) :
1643
1632
  disappearingMessagesInChat
1644
1633
 
1645
1634
  await groupToggleEphemeral(jid, value)
1646
1635
  }
1647
1636
 
1648
1637
  else if (typeof content === 'object' && 'album' in content && content.album) {
1649
- const albumMsg = await Utils_1.prepareAlbumMessageContent(jid, content.album, {
1638
+ const albumMsg = await prepareAlbumMessageContent(jid, content.album, {
1650
1639
  suki: {
1651
1640
  relayMessage,
1652
1641
  waUploadToServer
@@ -1656,7 +1645,7 @@ const makeMessagesSocket = (config) => {
1656
1645
  })
1657
1646
 
1658
1647
  for (const media of albumMsg) {
1659
- await Utils_1.delay(options.delay || 500)
1648
+ await delay(options.delay || 500)
1660
1649
  await relayMessage(jid, media.message, { messageId: media.key.id, useCachedGroupMetadata: options.useCachedGroupMetadata, additionalAttributes, statusJidList: options.statusJidList, additionalNodes: options.additionalNodes, AI: options.ai })
1661
1650
  }
1662
1651
 
@@ -1666,14 +1655,14 @@ const makeMessagesSocket = (config) => {
1666
1655
  else {
1667
1656
  let mediaHandle
1668
1657
 
1669
- const fullMsg = await Utils_1.generateWAMessage(jid, content, {
1658
+ const fullMsg = await generateWAMessage(jid, content, {
1670
1659
  logger,
1671
1660
  userJid,
1672
- getUrlInfo: text => link_preview_1.getUrlInfo(text, {
1661
+ getUrlInfo: text => getUrlInfo(text, {
1673
1662
  thumbnailWidth: linkPreviewImageThumbnailWidth,
1674
1663
  fetchOpts: {
1675
- timeout: 3000,
1676
- ...axiosOptions || {}
1664
+ timeout: 3000,
1665
+ ...(httpRequestOptions || {})
1677
1666
  },
1678
1667
  logger,
1679
1668
  uploadImage: generateHighQualityLinkPreview
@@ -1683,13 +1672,13 @@ const makeMessagesSocket = (config) => {
1683
1672
  getProfilePicUrl: profilePictureUrl,
1684
1673
  getCallLink: createCallLink,
1685
1674
  upload: async (encFilePath, opts) => {
1686
- const up = await waUploadToServer(encFilePath, { ...opts, newsletter: WABinary_1.isJidNewsletter(jid) })
1675
+ const up = await waUploadToServer(encFilePath, { ...opts, newsletter: isJidNewsletter(jid) })
1687
1676
  mediaHandle = up.handle
1688
1677
  return up
1689
1678
  },
1690
1679
  mediaCache: config.mediaCache,
1691
1680
  options: config.options,
1692
- messageId: Utils_1.generateMessageID(userJid),
1681
+ messageId: generateMessageID(userJid),
1693
1682
  ...options,
1694
1683
  })
1695
1684
 
@@ -1700,7 +1689,7 @@ const makeMessagesSocket = (config) => {
1700
1689
 
1701
1690
  if (isDelete || isKeep) {
1702
1691
  // if the chat is a group, and I am not the author, then delete the message as an admin
1703
- if (WABinary_1.isJidGroup(content.delete?.remoteJid) && !content.delete?.fromMe || WABinary_1.isJidNewsletter(jid)) {
1692
+ if (isJidGroup(content.delete?.remoteJid) && !content.delete?.fromMe || isJidNewsletter(jid)) {
1704
1693
  additionalAttributes.edit = '8'
1705
1694
  }
1706
1695
 
@@ -1710,7 +1699,7 @@ const makeMessagesSocket = (config) => {
1710
1699
  }
1711
1700
 
1712
1701
  else if (isEdit) {
1713
- additionalAttributes.edit = WABinary_1.isJidNewsletter(jid) ? '3' : '1'
1702
+ additionalAttributes.edit = isJidNewsletter(jid) ? '3' : '1'
1714
1703
  }
1715
1704
 
1716
1705
  else if (isPin) {
@@ -1728,8 +1717,8 @@ const makeMessagesSocket = (config) => {
1728
1717
  await relayMessage(jid, fullMsg.message, { messageId: fullMsg.key.id, useCachedGroupMetadata: options.useCachedGroupMetadata, additionalAttributes, statusJidList: options.statusJidList, additionalNodes: options.additionalNodes, AI: options.ai })
1729
1718
 
1730
1719
  if (config.emitOwnEvents) {
1731
- process.nextTick(() => {
1732
- processingMutex.mutex(() => (upsertMessage(fullMsg, 'append')))
1720
+ process.nextTick(async () => {
1721
+ await messageMutex.mutex(() => upsertMessage(fullMsg, 'append'))
1733
1722
  })
1734
1723
  }
1735
1724