@d0v3riz/baileys 6.7.25 → 7.0.0-rc.8

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 (218) hide show
  1. package/README.md +53 -50
  2. package/WAProto/GenerateStatics.sh +2 -2
  3. package/WAProto/WAProto.proto +1339 -493
  4. package/WAProto/fix-imports.js +1 -1
  5. package/WAProto/index.d.ts +4585 -44041
  6. package/WAProto/index.js +80831 -148208
  7. package/lib/Defaults/index.d.ts +13 -3
  8. package/lib/Defaults/index.d.ts.map +1 -1
  9. package/lib/Defaults/index.js +27 -13
  10. package/lib/Defaults/index.js.map +1 -1
  11. package/lib/Signal/Group/group_cipher.d.ts +1 -2
  12. package/lib/Signal/Group/group_cipher.d.ts.map +1 -1
  13. package/lib/Signal/Group/group_cipher.js +29 -41
  14. package/lib/Signal/Group/group_cipher.js.map +1 -1
  15. package/lib/Signal/Group/keyhelper.d.ts.map +1 -1
  16. package/lib/Signal/Group/keyhelper.js +0 -1
  17. package/lib/Signal/Group/keyhelper.js.map +1 -1
  18. package/lib/Signal/Group/sender-chain-key.d.ts +1 -1
  19. package/lib/Signal/Group/sender-chain-key.d.ts.map +1 -1
  20. package/lib/Signal/Group/sender-chain-key.js +1 -7
  21. package/lib/Signal/Group/sender-chain-key.js.map +1 -1
  22. package/lib/Signal/Group/sender-key-distribution-message.js +2 -2
  23. package/lib/Signal/Group/sender-key-distribution-message.js.map +1 -1
  24. package/lib/Signal/Group/sender-key-message.d.ts.map +1 -1
  25. package/lib/Signal/Group/sender-key-message.js +0 -1
  26. package/lib/Signal/Group/sender-key-message.js.map +1 -1
  27. package/lib/Signal/Group/sender-key-record.d.ts +1 -1
  28. package/lib/Signal/Group/sender-key-record.d.ts.map +1 -1
  29. package/lib/Signal/Group/sender-key-record.js +2 -11
  30. package/lib/Signal/Group/sender-key-record.js.map +1 -1
  31. package/lib/Signal/Group/sender-key-state.d.ts +4 -4
  32. package/lib/Signal/Group/sender-key-state.d.ts.map +1 -1
  33. package/lib/Signal/Group/sender-key-state.js +21 -33
  34. package/lib/Signal/Group/sender-key-state.js.map +1 -1
  35. package/lib/Signal/Group/sender-message-key.d.ts.map +1 -1
  36. package/lib/Signal/Group/sender-message-key.js +0 -1
  37. package/lib/Signal/Group/sender-message-key.js.map +1 -1
  38. package/lib/Signal/libsignal.d.ts +4 -3
  39. package/lib/Signal/libsignal.d.ts.map +1 -1
  40. package/lib/Signal/libsignal.js +243 -42
  41. package/lib/Signal/libsignal.js.map +1 -1
  42. package/lib/Signal/lid-mapping.d.ts +23 -0
  43. package/lib/Signal/lid-mapping.d.ts.map +1 -0
  44. package/lib/Signal/lid-mapping.js +171 -0
  45. package/lib/Signal/lid-mapping.js.map +1 -0
  46. package/lib/Socket/Client/types.d.ts +2 -2
  47. package/lib/Socket/Client/types.d.ts.map +1 -1
  48. package/lib/Socket/Client/websocket.d.ts +2 -2
  49. package/lib/Socket/Client/websocket.d.ts.map +1 -1
  50. package/lib/Socket/Client/websocket.js +2 -2
  51. package/lib/Socket/Client/websocket.js.map +1 -1
  52. package/lib/Socket/business.d.ts +31 -17
  53. package/lib/Socket/business.d.ts.map +1 -1
  54. package/lib/Socket/business.js +122 -1
  55. package/lib/Socket/business.js.map +1 -1
  56. package/lib/Socket/chats.d.ts +17 -9
  57. package/lib/Socket/chats.d.ts.map +1 -1
  58. package/lib/Socket/chats.js +54 -23
  59. package/lib/Socket/chats.js.map +1 -1
  60. package/lib/Socket/communities.d.ts +41 -14
  61. package/lib/Socket/communities.d.ts.map +1 -1
  62. package/lib/Socket/communities.js +83 -3
  63. package/lib/Socket/communities.js.map +1 -1
  64. package/lib/Socket/groups.d.ts +16 -9
  65. package/lib/Socket/groups.d.ts.map +1 -1
  66. package/lib/Socket/groups.js +14 -11
  67. package/lib/Socket/groups.js.map +1 -1
  68. package/lib/Socket/index.d.ts +41 -14
  69. package/lib/Socket/index.d.ts.map +1 -1
  70. package/lib/Socket/index.js +1 -0
  71. package/lib/Socket/index.js.map +1 -1
  72. package/lib/Socket/messages-recv.d.ts +26 -16
  73. package/lib/Socket/messages-recv.d.ts.map +1 -1
  74. package/lib/Socket/messages-recv.js +512 -311
  75. package/lib/Socket/messages-recv.js.map +1 -1
  76. package/lib/Socket/messages-send.d.ts +27 -16
  77. package/lib/Socket/messages-send.d.ts.map +1 -1
  78. package/lib/Socket/messages-send.js +394 -133
  79. package/lib/Socket/messages-send.js.map +1 -1
  80. package/lib/Socket/newsletter.d.ts +18 -12
  81. package/lib/Socket/newsletter.d.ts.map +1 -1
  82. package/lib/Socket/newsletter.js +3 -1
  83. package/lib/Socket/newsletter.js.map +1 -1
  84. package/lib/Socket/socket.d.ts +13 -3
  85. package/lib/Socket/socket.d.ts.map +1 -1
  86. package/lib/Socket/socket.js +353 -78
  87. package/lib/Socket/socket.js.map +1 -1
  88. package/lib/Types/Auth.d.ts +12 -1
  89. package/lib/Types/Auth.d.ts.map +1 -1
  90. package/lib/Types/Bussines.d.ts +25 -0
  91. package/lib/Types/Bussines.d.ts.map +1 -0
  92. package/lib/Types/Bussines.js +2 -0
  93. package/lib/Types/Bussines.js.map +1 -0
  94. package/lib/Types/Chat.d.ts +5 -0
  95. package/lib/Types/Chat.d.ts.map +1 -1
  96. package/lib/Types/Chat.js.map +1 -1
  97. package/lib/Types/Contact.d.ts +4 -4
  98. package/lib/Types/Contact.d.ts.map +1 -1
  99. package/lib/Types/Events.d.ts +8 -5
  100. package/lib/Types/Events.d.ts.map +1 -1
  101. package/lib/Types/GroupMetadata.d.ts +7 -4
  102. package/lib/Types/GroupMetadata.d.ts.map +1 -1
  103. package/lib/Types/Message.d.ts +38 -12
  104. package/lib/Types/Message.d.ts.map +1 -1
  105. package/lib/Types/Message.js +5 -1
  106. package/lib/Types/Message.js.map +1 -1
  107. package/lib/Types/Signal.d.ts +18 -0
  108. package/lib/Types/Signal.d.ts.map +1 -1
  109. package/lib/Types/Socket.d.ts +24 -13
  110. package/lib/Types/Socket.d.ts.map +1 -1
  111. package/lib/Types/Socket.js.map +1 -1
  112. package/lib/Utils/auth-utils.d.ts +2 -2
  113. package/lib/Utils/auth-utils.d.ts.map +1 -1
  114. package/lib/Utils/auth-utils.js +178 -111
  115. package/lib/Utils/auth-utils.js.map +1 -1
  116. package/lib/Utils/browser-utils.d.ts +4 -0
  117. package/lib/Utils/browser-utils.d.ts.map +1 -0
  118. package/lib/Utils/browser-utils.js +28 -0
  119. package/lib/Utils/browser-utils.js.map +1 -0
  120. package/lib/Utils/chat-utils.d.ts +6 -7
  121. package/lib/Utils/chat-utils.d.ts.map +1 -1
  122. package/lib/Utils/chat-utils.js +19 -2
  123. package/lib/Utils/chat-utils.js.map +1 -1
  124. package/lib/Utils/crypto.d.ts +6 -6
  125. package/lib/Utils/crypto.d.ts.map +1 -1
  126. package/lib/Utils/crypto.js +16 -12
  127. package/lib/Utils/crypto.js.map +1 -1
  128. package/lib/Utils/decode-wa-message.d.ts +14 -2
  129. package/lib/Utils/decode-wa-message.d.ts.map +1 -1
  130. package/lib/Utils/decode-wa-message.js +104 -15
  131. package/lib/Utils/decode-wa-message.js.map +1 -1
  132. package/lib/Utils/event-buffer.d.ts +0 -1
  133. package/lib/Utils/event-buffer.d.ts.map +1 -1
  134. package/lib/Utils/event-buffer.js +65 -20
  135. package/lib/Utils/event-buffer.js.map +1 -1
  136. package/lib/Utils/generics.d.ts +5 -7
  137. package/lib/Utils/generics.d.ts.map +1 -1
  138. package/lib/Utils/generics.js +59 -51
  139. package/lib/Utils/generics.js.map +1 -1
  140. package/lib/Utils/history.d.ts +8 -9
  141. package/lib/Utils/history.d.ts.map +1 -1
  142. package/lib/Utils/history.js +8 -3
  143. package/lib/Utils/history.js.map +1 -1
  144. package/lib/Utils/index.d.ts +2 -1
  145. package/lib/Utils/index.d.ts.map +1 -1
  146. package/lib/Utils/index.js +2 -1
  147. package/lib/Utils/index.js.map +1 -1
  148. package/lib/Utils/link-preview.d.ts +1 -2
  149. package/lib/Utils/link-preview.d.ts.map +1 -1
  150. package/lib/Utils/link-preview.js +1 -1
  151. package/lib/Utils/link-preview.js.map +1 -1
  152. package/lib/Utils/message-retry-manager.d.ts +82 -0
  153. package/lib/Utils/message-retry-manager.d.ts.map +1 -0
  154. package/lib/Utils/message-retry-manager.js +172 -0
  155. package/lib/Utils/message-retry-manager.js.map +1 -0
  156. package/lib/Utils/messages-media.d.ts +14 -12
  157. package/lib/Utils/messages-media.d.ts.map +1 -1
  158. package/lib/Utils/messages-media.js +48 -24
  159. package/lib/Utils/messages-media.js.map +1 -1
  160. package/lib/Utils/messages.d.ts +17 -4
  161. package/lib/Utils/messages.d.ts.map +1 -1
  162. package/lib/Utils/messages.js +85 -21
  163. package/lib/Utils/messages.js.map +1 -1
  164. package/lib/Utils/noise-handler.js +2 -1
  165. package/lib/Utils/noise-handler.js.map +1 -1
  166. package/lib/Utils/pre-key-manager.d.ts +28 -0
  167. package/lib/Utils/pre-key-manager.d.ts.map +1 -0
  168. package/lib/Utils/pre-key-manager.js +106 -0
  169. package/lib/Utils/pre-key-manager.js.map +1 -0
  170. package/lib/Utils/process-message.d.ts +26 -8
  171. package/lib/Utils/process-message.d.ts.map +1 -1
  172. package/lib/Utils/process-message.js +141 -24
  173. package/lib/Utils/process-message.js.map +1 -1
  174. package/lib/Utils/signal.d.ts +4 -4
  175. package/lib/Utils/signal.d.ts.map +1 -1
  176. package/lib/Utils/signal.js +21 -12
  177. package/lib/Utils/signal.js.map +1 -1
  178. package/lib/Utils/validate-connection.d.ts.map +1 -1
  179. package/lib/Utils/validate-connection.js +50 -14
  180. package/lib/Utils/validate-connection.js.map +1 -1
  181. package/lib/WABinary/decode.d.ts.map +1 -1
  182. package/lib/WABinary/decode.js +12 -2
  183. package/lib/WABinary/decode.js.map +1 -1
  184. package/lib/WABinary/generic-utils.js +1 -1
  185. package/lib/WABinary/generic-utils.js.map +1 -1
  186. package/lib/WABinary/jid-utils.d.ts +18 -6
  187. package/lib/WABinary/jid-utils.d.ts.map +1 -1
  188. package/lib/WABinary/jid-utils.js +52 -8
  189. package/lib/WABinary/jid-utils.js.map +1 -1
  190. package/lib/WAM/constants.d.ts +1 -1
  191. package/lib/WAM/constants.d.ts.map +1 -1
  192. package/lib/WAM/constants.js +18516 -10904
  193. package/lib/WAM/constants.js.map +1 -1
  194. package/lib/WAM/encode.d.ts.map +1 -1
  195. package/lib/WAM/encode.js +0 -1
  196. package/lib/WAM/encode.js.map +1 -1
  197. package/lib/WAUSync/Protocols/UsyncLIDProtocol.d.ts +2 -1
  198. package/lib/WAUSync/Protocols/UsyncLIDProtocol.d.ts.map +1 -1
  199. package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +10 -2
  200. package/lib/WAUSync/Protocols/UsyncLIDProtocol.js.map +1 -1
  201. package/lib/WAUSync/USyncQuery.d.ts +1 -1
  202. package/lib/WAUSync/USyncQuery.d.ts.map +1 -1
  203. package/lib/WAUSync/USyncQuery.js +23 -20
  204. package/lib/WAUSync/USyncQuery.js.map +1 -1
  205. package/package.json +16 -11
  206. package/lib/Defaults/baileys-version.json +0 -3
  207. package/lib/Signal/Group/queue-job.d.ts +0 -2
  208. package/lib/Signal/Group/queue-job.d.ts.map +0 -1
  209. package/lib/Signal/Group/queue-job.js +0 -54
  210. package/lib/Signal/Group/queue-job.js.map +0 -1
  211. package/lib/Socket/usync.d.ts +0 -37
  212. package/lib/Socket/usync.d.ts.map +0 -1
  213. package/lib/Socket/usync.js +0 -63
  214. package/lib/Socket/usync.js.map +0 -1
  215. package/lib/Utils/baileys-event-stream.d.ts +0 -17
  216. package/lib/Utils/baileys-event-stream.d.ts.map +0 -1
  217. package/lib/Utils/baileys-event-stream.js +0 -56
  218. package/lib/Utils/baileys-event-stream.js.map +0 -1
@@ -2,21 +2,29 @@ import NodeCache from '@cacheable/node-cache';
2
2
  import { Boom } from '@hapi/boom';
3
3
  import { proto } from '../../WAProto/index.js';
4
4
  import { DEFAULT_CACHE_TTLS, WA_DEFAULT_EPHEMERAL } from '../Defaults/index.js';
5
- import { aggregateMessageKeysNotFromMe, assertMediaContent, bindWaitForEvent, decryptMediaRetryData, encodeNewsletterMessage, encodeSignedDeviceIdentity, encodeWAMessage, encryptMediaRetryRequest, extractDeviceJids, generateMessageIDV2, generateWAMessage, getStatusCodeForMediaRetry, getUrlFromDirectPath, getWAUploadToServer, normalizeMessageContent, parseAndInjectE2ESessions, unixTimestampSeconds } from '../Utils/index.js';
5
+ import { aggregateMessageKeysNotFromMe, assertMediaContent, bindWaitForEvent, decryptMediaRetryData, encodeNewsletterMessage, encodeSignedDeviceIdentity, encodeWAMessage, encryptMediaRetryRequest, extractDeviceJids, generateMessageIDV2, generateParticipantHashV2, generateWAMessage, getStatusCodeForMediaRetry, getUrlFromDirectPath, getWAUploadToServer, MessageRetryManager, normalizeMessageContent, parseAndInjectE2ESessions, unixTimestampSeconds } from '../Utils/index.js';
6
6
  import { getUrlInfo } from '../Utils/link-preview.js';
7
- import { areJidsSameUser, getBinaryNodeChild, getBinaryNodeChildren, isJidGroup, isJidUser, jidDecode, jidEncode, jidNormalizedUser, S_WHATSAPP_NET } from '../WABinary/index.js';
7
+ import { makeKeyedMutex } from '../Utils/make-mutex.js';
8
+ import { areJidsSameUser, getBinaryNodeChild, getBinaryNodeChildren, isHostedLidUser, isHostedPnUser, isJidGroup, isLidUser, isPnUser, jidDecode, jidEncode, jidNormalizedUser, S_WHATSAPP_NET } from '../WABinary/index.js';
8
9
  import { USyncQuery, USyncUser } from '../WAUSync/index.js';
9
- import { makeGroupsSocket } from './groups.js';
10
10
  import { makeNewsletterSocket } from './newsletter.js';
11
11
  export const makeMessagesSocket = (config) => {
12
- const { logger, linkPreviewImageThumbnailWidth, generateHighQualityLinkPreview, options: axiosOptions, patchMessageBeforeSending, cachedGroupMetadata } = config;
13
- const sock = makeNewsletterSocket(makeGroupsSocket(config));
12
+ const { logger, linkPreviewImageThumbnailWidth, generateHighQualityLinkPreview, options: httpRequestOptions, patchMessageBeforeSending, cachedGroupMetadata, enableRecentMessageCache, maxMsgRetryCount } = config;
13
+ const sock = makeNewsletterSocket(config);
14
14
  const { ev, authState, processingMutex, signalRepository, upsertMessage, query, fetchPrivacySettings, sendNode, groupMetadata, groupToggleEphemeral } = sock;
15
15
  const userDevicesCache = config.userDevicesCache ||
16
16
  new NodeCache({
17
17
  stdTTL: DEFAULT_CACHE_TTLS.USER_DEVICES, // 5 minutes
18
18
  useClones: false
19
19
  });
20
+ const peerSessionsCache = new NodeCache({
21
+ stdTTL: DEFAULT_CACHE_TTLS.USER_DEVICES,
22
+ useClones: false
23
+ });
24
+ // Initialize message retry manager if enabled
25
+ const messageRetryManager = enableRecentMessageCache ? new MessageRetryManager(logger, maxMsgRetryCount) : null;
26
+ // Prevent race conditions in Signal session encryption by user
27
+ const encryptionMutex = makeKeyedMutex();
20
28
  let mediaConn;
21
29
  const refreshMediaConn = async (forceGet = false) => {
22
30
  const media = await mediaConn;
@@ -32,6 +40,7 @@ export const makeMessagesSocket = (config) => {
32
40
  content: [{ tag: 'media_conn', attrs: {} }]
33
41
  });
34
42
  const mediaConnNode = getBinaryNodeChild(result, 'media_conn');
43
+ // TODO: explore full length of data that whatsapp provides
35
44
  const node = {
36
45
  hosts: getBinaryNodeChildren(mediaConnNode, 'host').map(({ attrs }) => ({
37
46
  hostname: attrs.hostname,
@@ -65,7 +74,7 @@ export const makeMessagesSocket = (config) => {
65
74
  if (isReadReceipt) {
66
75
  node.attrs.t = unixTimestampSeconds().toString();
67
76
  }
68
- if (type === 'sender' && isJidUser(jid)) {
77
+ if (type === 'sender' && (isPnUser(jid) || isLidUser(jid))) {
69
78
  node.attrs.recipient = jid;
70
79
  node.attrs.to = participant;
71
80
  }
@@ -115,14 +124,39 @@ export const makeMessagesSocket = (config) => {
115
124
  logger.debug('not using cache for devices');
116
125
  }
117
126
  const toFetch = [];
118
- jids = Array.from(new Set(jids));
119
- for (let jid of jids) {
120
- const user = jidDecode(jid)?.user;
127
+ const jidsWithUser = jids
128
+ .map(jid => {
129
+ const decoded = jidDecode(jid);
130
+ const user = decoded?.user;
131
+ const device = decoded?.device;
132
+ const isExplicitDevice = typeof device === 'number' && device >= 0;
133
+ if (isExplicitDevice && user) {
134
+ deviceResults.push({
135
+ user,
136
+ device,
137
+ jid
138
+ });
139
+ return null;
140
+ }
121
141
  jid = jidNormalizedUser(jid);
142
+ return { jid, user };
143
+ })
144
+ .filter(jid => jid !== null);
145
+ let mgetDevices;
146
+ if (useCache && userDevicesCache.mget) {
147
+ const usersToFetch = jidsWithUser.map(j => j?.user).filter(Boolean);
148
+ mgetDevices = await userDevicesCache.mget(usersToFetch);
149
+ }
150
+ for (const { jid, user } of jidsWithUser) {
122
151
  if (useCache) {
123
- const devices = userDevicesCache.get(user);
152
+ const devices = mgetDevices?.[user] ||
153
+ (userDevicesCache.mget ? undefined : (await userDevicesCache.get(user)));
124
154
  if (devices) {
125
- deviceResults.push(...devices);
155
+ const devicesWithJid = devices.map(d => ({
156
+ ...d,
157
+ jid: jidEncode(d.user, d.server, d.device)
158
+ }));
159
+ deviceResults.push(...devicesWithJid);
126
160
  logger.trace({ user }, 'using cache for devices');
127
161
  }
128
162
  else {
@@ -136,43 +170,121 @@ export const makeMessagesSocket = (config) => {
136
170
  if (!toFetch.length) {
137
171
  return deviceResults;
138
172
  }
139
- const query = new USyncQuery().withContext('message').withDeviceProtocol();
173
+ const requestedLidUsers = new Set();
174
+ for (const jid of toFetch) {
175
+ if (isLidUser(jid) || isHostedLidUser(jid)) {
176
+ const user = jidDecode(jid)?.user;
177
+ if (user)
178
+ requestedLidUsers.add(user);
179
+ }
180
+ }
181
+ const query = new USyncQuery().withContext('message').withDeviceProtocol().withLIDProtocol();
140
182
  for (const jid of toFetch) {
141
- query.withUser(new USyncUser().withId(jid));
183
+ 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
142
184
  }
143
185
  const result = await sock.executeUSyncQuery(query);
144
186
  if (result) {
145
- const extracted = extractDeviceJids(result?.list, authState.creds.me.id, ignoreZeroDevices);
187
+ // TODO: LID MAP this stuff (lid protocol will now return lid with devices)
188
+ const lidResults = result.list.filter(a => !!a.lid);
189
+ if (lidResults.length > 0) {
190
+ logger.trace('Storing LID maps from device call');
191
+ await signalRepository.lidMapping.storeLIDPNMappings(lidResults.map(a => ({ lid: a.lid, pn: a.id })));
192
+ // Force-refresh sessions for newly mapped LIDs to align identity addressing
193
+ try {
194
+ const lids = lidResults.map(a => a.lid);
195
+ if (lids.length) {
196
+ await assertSessions(lids, true);
197
+ }
198
+ }
199
+ catch (e) {
200
+ logger.warn({ e, count: lidResults.length }, 'failed to assert sessions for newly mapped LIDs');
201
+ }
202
+ }
203
+ const extracted = extractDeviceJids(result?.list, authState.creds.me.id, authState.creds.me.lid, ignoreZeroDevices);
146
204
  const deviceMap = {};
147
205
  for (const item of extracted) {
148
206
  deviceMap[item.user] = deviceMap[item.user] || [];
149
207
  deviceMap[item.user]?.push(item);
150
- deviceResults.push(item);
151
208
  }
152
- for (const key in deviceMap) {
153
- userDevicesCache.set(key, deviceMap[key]);
209
+ // Process each user's devices as a group for bulk LID migration
210
+ for (const [user, userDevices] of Object.entries(deviceMap)) {
211
+ const isLidUser = requestedLidUsers.has(user);
212
+ // Process all devices for this user
213
+ for (const item of userDevices) {
214
+ const finalJid = isLidUser
215
+ ? jidEncode(user, item.server, item.device)
216
+ : jidEncode(item.user, item.server, item.device);
217
+ deviceResults.push({
218
+ ...item,
219
+ jid: finalJid
220
+ });
221
+ logger.debug({
222
+ user: item.user,
223
+ device: item.device,
224
+ finalJid,
225
+ usedLid: isLidUser
226
+ }, 'Processed device with LID priority');
227
+ }
228
+ }
229
+ if (userDevicesCache.mset) {
230
+ // if the cache supports mset, we can set all devices in one go
231
+ await userDevicesCache.mset(Object.entries(deviceMap).map(([key, value]) => ({ key, value })));
232
+ }
233
+ else {
234
+ for (const key in deviceMap) {
235
+ if (deviceMap[key])
236
+ await userDevicesCache.set(key, deviceMap[key]);
237
+ }
238
+ }
239
+ const userDeviceUpdates = {};
240
+ for (const [userId, devices] of Object.entries(deviceMap)) {
241
+ if (devices && devices.length > 0) {
242
+ userDeviceUpdates[userId] = devices.map(d => d.device?.toString() || '0');
243
+ }
244
+ }
245
+ if (Object.keys(userDeviceUpdates).length > 0) {
246
+ try {
247
+ await authState.keys.set({ 'device-list': userDeviceUpdates });
248
+ logger.debug({ userCount: Object.keys(userDeviceUpdates).length }, 'stored user device lists for bulk migration');
249
+ }
250
+ catch (error) {
251
+ logger.warn({ error }, 'failed to store user device lists');
252
+ }
154
253
  }
155
254
  }
156
255
  return deviceResults;
157
256
  };
158
257
  const assertSessions = async (jids, force) => {
159
258
  let didFetchNewSession = false;
160
- let jidsRequiringFetch = [];
161
- if (force) {
162
- jidsRequiringFetch = jids;
163
- }
164
- else {
165
- const addrs = jids.map(jid => signalRepository.jidToSignalProtocolAddress(jid));
166
- const sessions = await authState.keys.get('session', addrs);
167
- for (const jid of jids) {
168
- const signalId = signalRepository.jidToSignalProtocolAddress(jid);
169
- if (!sessions[signalId]) {
170
- jidsRequiringFetch.push(jid);
259
+ const uniqueJids = [...new Set(jids)]; // Deduplicate JIDs
260
+ const jidsRequiringFetch = [];
261
+ logger.debug({ jids }, 'assertSessions call with jids');
262
+ // Check peerSessionsCache and validate sessions using libsignal loadSession
263
+ for (const jid of uniqueJids) {
264
+ const signalId = signalRepository.jidToSignalProtocolAddress(jid);
265
+ const cachedSession = peerSessionsCache.get(signalId);
266
+ if (cachedSession !== undefined) {
267
+ if (cachedSession && !force) {
268
+ continue; // Session exists in cache
171
269
  }
172
270
  }
271
+ else {
272
+ const sessionValidation = await signalRepository.validateSession(jid);
273
+ const hasSession = sessionValidation.exists;
274
+ peerSessionsCache.set(signalId, hasSession);
275
+ if (hasSession && !force) {
276
+ continue;
277
+ }
278
+ }
279
+ jidsRequiringFetch.push(jid);
173
280
  }
174
281
  if (jidsRequiringFetch.length) {
175
- logger.debug({ jidsRequiringFetch }, 'fetching sessions');
282
+ // LID if mapped, otherwise original
283
+ const wireJids = [
284
+ ...jidsRequiringFetch.filter(jid => !!isLidUser(jid) || !!isHostedLidUser(jid)),
285
+ ...((await signalRepository.lidMapping.getLIDsForPNs(jidsRequiringFetch.filter(jid => !!isPnUser(jid) || !!isHostedPnUser(jid)))) || []).map(a => a.lid)
286
+ ];
287
+ logger.debug({ jidsRequiringFetch, wireJids }, 'fetching sessions');
176
288
  const result = await query({
177
289
  tag: 'iq',
178
290
  attrs: {
@@ -184,15 +296,22 @@ export const makeMessagesSocket = (config) => {
184
296
  {
185
297
  tag: 'key',
186
298
  attrs: {},
187
- content: jidsRequiringFetch.map(jid => ({
188
- tag: 'user',
189
- attrs: { jid }
190
- }))
299
+ content: wireJids.map(jid => {
300
+ const attrs = { jid };
301
+ if (force)
302
+ attrs.reason = 'identity';
303
+ return { tag: 'user', attrs };
304
+ })
191
305
  }
192
306
  ]
193
307
  });
194
308
  await parseAndInjectE2ESessions(result, signalRepository);
195
309
  didFetchNewSession = true;
310
+ // Cache fetched sessions using wire JIDs
311
+ for (const wireJid of wireJids) {
312
+ const signalId = signalRepository.jidToSignalProtocolAddress(wireJid);
313
+ peerSessionsCache.set(signalId, true);
314
+ }
196
315
  }
197
316
  return didFetchNewSession;
198
317
  };
@@ -212,59 +331,92 @@ export const makeMessagesSocket = (config) => {
212
331
  additionalAttributes: {
213
332
  category: 'peer',
214
333
  push_priority: 'high_force'
215
- }
334
+ },
335
+ additionalNodes: [
336
+ {
337
+ tag: 'meta',
338
+ attrs: { appdata: 'default' }
339
+ }
340
+ ]
216
341
  });
217
342
  return msgId;
218
343
  };
219
- const createParticipantNodes = async (jids, message, extraAttrs) => {
220
- let patched = await patchMessageBeforeSending(message, jids);
221
- if (!Array.isArray(patched)) {
222
- patched = jids ? jids.map(jid => ({ recipientJid: jid, ...patched })) : [patched];
223
- }
344
+ const createParticipantNodes = async (recipientJids, message, extraAttrs, dsmMessage) => {
345
+ if (!recipientJids.length) {
346
+ return { nodes: [], shouldIncludeDeviceIdentity: false };
347
+ }
348
+ const patched = await patchMessageBeforeSending(message, recipientJids);
349
+ const patchedMessages = Array.isArray(patched)
350
+ ? patched
351
+ : recipientJids.map(jid => ({ recipientJid: jid, message: patched }));
224
352
  let shouldIncludeDeviceIdentity = false;
225
- const nodes = await Promise.all(patched.map(async (patchedMessageWithJid) => {
226
- const { recipientJid: jid, ...patchedMessage } = patchedMessageWithJid;
227
- if (!jid) {
228
- return {};
229
- }
230
- const bytes = encodeWAMessage(patchedMessage);
231
- const { type, ciphertext } = await signalRepository.encryptMessage({ jid, data: bytes });
232
- if (type === 'pkmsg') {
233
- shouldIncludeDeviceIdentity = true;
234
- }
235
- const node = {
236
- tag: 'to',
237
- attrs: { jid },
238
- content: [
239
- {
240
- tag: 'enc',
241
- attrs: {
242
- v: '2',
243
- type,
244
- ...(extraAttrs || {})
245
- },
246
- content: ciphertext
247
- }
248
- ]
249
- };
353
+ const meId = authState.creds.me.id;
354
+ const meLid = authState.creds.me?.lid;
355
+ const meLidUser = meLid ? jidDecode(meLid)?.user : null;
356
+ const encryptionPromises = patchedMessages.map(async ({ recipientJid: jid, message: patchedMessage }) => {
357
+ if (!jid)
358
+ return null;
359
+ let msgToEncrypt = patchedMessage;
360
+ if (dsmMessage) {
361
+ const { user: targetUser } = jidDecode(jid);
362
+ const { user: ownPnUser } = jidDecode(meId);
363
+ const ownLidUser = meLidUser;
364
+ const isOwnUser = targetUser === ownPnUser || (ownLidUser && targetUser === ownLidUser);
365
+ const isExactSenderDevice = jid === meId || (meLid && jid === meLid);
366
+ if (isOwnUser && !isExactSenderDevice) {
367
+ msgToEncrypt = dsmMessage;
368
+ logger.debug({ jid, targetUser }, 'Using DSM for own device');
369
+ }
370
+ }
371
+ const bytes = encodeWAMessage(msgToEncrypt);
372
+ const mutexKey = jid;
373
+ const node = await encryptionMutex.mutex(mutexKey, async () => {
374
+ const { type, ciphertext } = await signalRepository.encryptMessage({
375
+ jid,
376
+ data: bytes
377
+ });
378
+ if (type === 'pkmsg') {
379
+ shouldIncludeDeviceIdentity = true;
380
+ }
381
+ return {
382
+ tag: 'to',
383
+ attrs: { jid },
384
+ content: [
385
+ {
386
+ tag: 'enc',
387
+ attrs: {
388
+ v: '2',
389
+ type,
390
+ ...(extraAttrs || {})
391
+ },
392
+ content: ciphertext
393
+ }
394
+ ]
395
+ };
396
+ });
250
397
  return node;
251
- }));
398
+ });
399
+ const nodes = (await Promise.all(encryptionPromises)).filter(node => node !== null);
252
400
  return { nodes, shouldIncludeDeviceIdentity };
253
401
  };
254
402
  const relayMessage = async (jid, message, { messageId: msgId, participant, additionalAttributes, additionalNodes, useUserDevicesCache, useCachedGroupMetadata, statusJidList }) => {
255
403
  const meId = authState.creds.me.id;
256
- let shouldIncludeDeviceIdentity = false;
257
- const { user, server } = jidDecode(jid);
404
+ const meLid = authState.creds.me?.lid;
405
+ const isRetryResend = Boolean(participant?.jid);
406
+ let shouldIncludeDeviceIdentity = isRetryResend;
258
407
  const statusJid = 'status@broadcast';
408
+ const { user, server } = jidDecode(jid);
259
409
  const isGroup = server === 'g.us';
260
410
  const isStatus = jid === statusJid;
261
411
  const isLid = server === 'lid';
262
412
  const isNewsletter = server === 'newsletter';
263
- msgId = msgId || generateMessageIDV2(sock.user?.id);
413
+ const isGroupOrStatus = isGroup || isStatus;
414
+ const finalJid = jid;
415
+ msgId = msgId || generateMessageIDV2(meId);
264
416
  useUserDevicesCache = useUserDevicesCache !== false;
265
417
  useCachedGroupMetadata = useCachedGroupMetadata !== false && !isStatus;
266
418
  const participants = [];
267
- const destinationJid = !isStatus ? jidEncode(user, isLid ? 'lid' : isGroup ? 'g.us' : 's.whatsapp.net') : statusJid;
419
+ const destinationJid = !isStatus ? finalJid : statusJid;
268
420
  const binaryNodeContent = [];
269
421
  const devices = [];
270
422
  const meMsg = {
@@ -276,14 +428,15 @@ export const makeMessagesSocket = (config) => {
276
428
  };
277
429
  const extraAttrs = {};
278
430
  if (participant) {
279
- // when the retry request is not for a group
280
- // only send to the specific device that asked for a retry
281
- // otherwise the message is sent out to every device that should be a recipient
282
431
  if (!isGroup && !isStatus) {
283
432
  additionalAttributes = { ...additionalAttributes, device_fanout: 'false' };
284
433
  }
285
434
  const { user, device } = jidDecode(participant.jid);
286
- devices.push({ user, device });
435
+ devices.push({
436
+ user,
437
+ device,
438
+ jid: participant.jid
439
+ });
287
440
  }
288
441
  await authState.keys.transaction(async () => {
289
442
  const mediaType = getMediaType(message);
@@ -291,7 +444,6 @@ export const makeMessagesSocket = (config) => {
291
444
  extraAttrs['mediatype'] = mediaType;
292
445
  }
293
446
  if (isNewsletter) {
294
- // Patch message if needed, then encode as plaintext
295
447
  const patched = patchMessageBeforeSending ? await patchMessageBeforeSending(message, []) : message;
296
448
  const bytes = encodeNewsletterMessage(patched);
297
449
  binaryNodeContent.push({
@@ -314,119 +466,198 @@ export const makeMessagesSocket = (config) => {
314
466
  return;
315
467
  }
316
468
  if (normalizeMessageContent(message)?.pinInChatMessage) {
317
- extraAttrs['decrypt-fail'] = 'hide';
469
+ extraAttrs['decrypt-fail'] = 'hide'; // todo: expand for reactions and other types
318
470
  }
319
- if (isGroup || isStatus) {
471
+ if (isGroupOrStatus && !isRetryResend) {
320
472
  const [groupData, senderKeyMap] = await Promise.all([
321
473
  (async () => {
322
- let groupData = useCachedGroupMetadata && cachedGroupMetadata ? await cachedGroupMetadata(jid) : undefined;
474
+ 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?
323
475
  if (groupData && Array.isArray(groupData?.participants)) {
324
476
  logger.trace({ jid, participants: groupData.participants.length }, 'using cached group metadata');
325
477
  }
326
478
  else if (!isStatus) {
327
- groupData = await groupMetadata(jid);
479
+ groupData = await groupMetadata(jid); // TODO: start storing group participant list + addr mode in Signal & stop relying on this
328
480
  }
329
481
  return groupData;
330
482
  })(),
331
483
  (async () => {
332
484
  if (!participant && !isStatus) {
333
- const result = await authState.keys.get('sender-key-memory', [jid]);
485
+ // what if sender memory is less accurate than the cached metadata
486
+ // on participant change in group, we should do sender memory manipulation
487
+ 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?
334
488
  return result[jid] || {};
335
489
  }
336
490
  return {};
337
491
  })()
338
492
  ]);
339
- if (!participant) {
340
- const participantsList = groupData && !isStatus ? groupData.participants.map(p => p.id) : [];
341
- if (isStatus && statusJidList) {
342
- participantsList.push(...statusJidList);
343
- }
344
- if (!isStatus) {
345
- additionalAttributes = {
346
- ...additionalAttributes,
347
- addressing_mode: groupData?.addressingMode || 'pn'
348
- };
349
- }
350
- const additionalDevices = await getUSyncDevices(participantsList, !!useUserDevicesCache, false);
351
- devices.push(...additionalDevices);
493
+ const participantsList = groupData ? groupData.participants.map(p => p.id) : [];
494
+ if (groupData?.ephemeralDuration && groupData.ephemeralDuration > 0) {
495
+ additionalAttributes = {
496
+ ...additionalAttributes,
497
+ expiration: groupData.ephemeralDuration.toString()
498
+ };
499
+ }
500
+ if (isStatus && statusJidList) {
501
+ participantsList.push(...statusJidList);
502
+ }
503
+ const additionalDevices = await getUSyncDevices(participantsList, !!useUserDevicesCache, false);
504
+ devices.push(...additionalDevices);
505
+ if (isGroup) {
506
+ additionalAttributes = {
507
+ ...additionalAttributes,
508
+ addressing_mode: groupData?.addressingMode || 'lid'
509
+ };
352
510
  }
353
511
  const patched = await patchMessageBeforeSending(message);
354
512
  if (Array.isArray(patched)) {
355
513
  throw new Boom('Per-jid patching is not supported in groups');
356
514
  }
357
515
  const bytes = encodeWAMessage(patched);
516
+ const groupAddressingMode = additionalAttributes?.['addressing_mode'] || groupData?.addressingMode || 'lid';
517
+ const groupSenderIdentity = groupAddressingMode === 'lid' && meLid ? meLid : meId;
358
518
  const { ciphertext, senderKeyDistributionMessage } = await signalRepository.encryptGroupMessage({
359
519
  group: destinationJid,
360
520
  data: bytes,
361
- meId
521
+ meId: groupSenderIdentity
362
522
  });
363
- const senderKeyJids = [];
364
- // ensure a connection is established with every device
365
- for (const { user, device } of devices) {
366
- const jid = jidEncode(user, groupData?.addressingMode === 'lid' ? 'lid' : 's.whatsapp.net', device);
367
- if (!senderKeyMap[jid] || !!participant) {
368
- senderKeyJids.push(jid);
369
- // store that this person has had the sender keys sent to them
370
- senderKeyMap[jid] = true;
523
+ const senderKeyRecipients = [];
524
+ for (const device of devices) {
525
+ const deviceJid = device.jid;
526
+ const hasKey = !!senderKeyMap[deviceJid];
527
+ if ((!hasKey || !!participant) &&
528
+ !isHostedLidUser(deviceJid) &&
529
+ !isHostedPnUser(deviceJid) &&
530
+ device.device !== 99) {
531
+ //todo: revamp all this logic
532
+ // 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
533
+ senderKeyRecipients.push(deviceJid);
534
+ senderKeyMap[deviceJid] = true;
371
535
  }
372
536
  }
373
- // if there are some participants with whom the session has not been established
374
- // if there are, we re-send the senderkey
375
- if (senderKeyJids.length) {
376
- logger.debug({ senderKeyJids }, 'sending new sender key');
537
+ if (senderKeyRecipients.length) {
538
+ logger.debug({ senderKeyJids: senderKeyRecipients }, 'sending new sender key');
377
539
  const senderKeyMsg = {
378
540
  senderKeyDistributionMessage: {
379
541
  axolotlSenderKeyDistributionMessage: senderKeyDistributionMessage,
380
542
  groupId: destinationJid
381
543
  }
382
544
  };
383
- await assertSessions(senderKeyJids, false);
384
- const result = await createParticipantNodes(senderKeyJids, senderKeyMsg, extraAttrs);
545
+ const senderKeySessionTargets = senderKeyRecipients;
546
+ await assertSessions(senderKeySessionTargets);
547
+ const result = await createParticipantNodes(senderKeyRecipients, senderKeyMsg, extraAttrs);
385
548
  shouldIncludeDeviceIdentity = shouldIncludeDeviceIdentity || result.shouldIncludeDeviceIdentity;
386
549
  participants.push(...result.nodes);
387
550
  }
388
551
  binaryNodeContent.push({
389
552
  tag: 'enc',
390
- attrs: { v: '2', type: 'skmsg' },
553
+ attrs: { v: '2', type: 'skmsg', ...extraAttrs },
391
554
  content: ciphertext
392
555
  });
393
556
  await authState.keys.set({ 'sender-key-memory': { [jid]: senderKeyMap } });
394
557
  }
395
558
  else {
396
- const { user: meUser } = jidDecode(meId);
397
- if (!participant) {
398
- devices.push({ user });
399
- if (user !== meUser) {
400
- devices.push({ user: meUser });
559
+ // ADDRESSING CONSISTENCY: Match own identity to conversation context
560
+ // TODO: investigate if this is true
561
+ let ownId = meId;
562
+ if (isLid && meLid) {
563
+ ownId = meLid;
564
+ logger.debug({ to: jid, ownId }, 'Using LID identity for @lid conversation');
565
+ }
566
+ else {
567
+ logger.debug({ to: jid, ownId }, 'Using PN identity for @s.whatsapp.net conversation');
568
+ }
569
+ const { user: ownUser } = jidDecode(ownId);
570
+ if (!isRetryResend) {
571
+ const targetUserServer = isLid ? 'lid' : 's.whatsapp.net';
572
+ devices.push({
573
+ user,
574
+ device: 0,
575
+ jid: jidEncode(user, targetUserServer, 0) // rajeh, todo: this entire logic is convoluted and weird.
576
+ });
577
+ if (user !== ownUser) {
578
+ const ownUserServer = isLid ? 'lid' : 's.whatsapp.net';
579
+ const ownUserForAddressing = isLid && meLid ? jidDecode(meLid).user : jidDecode(meId).user;
580
+ devices.push({
581
+ user: ownUserForAddressing,
582
+ device: 0,
583
+ jid: jidEncode(ownUserForAddressing, ownUserServer, 0)
584
+ });
401
585
  }
402
586
  if (additionalAttributes?.['category'] !== 'peer') {
403
- const additionalDevices = await getUSyncDevices([meId, jid], !!useUserDevicesCache, true);
404
- devices.push(...additionalDevices);
587
+ // Clear placeholders and enumerate actual devices
588
+ devices.length = 0;
589
+ // Use conversation-appropriate sender identity
590
+ const senderIdentity = isLid && meLid
591
+ ? jidEncode(jidDecode(meLid)?.user, 'lid', undefined)
592
+ : jidEncode(jidDecode(meId)?.user, 's.whatsapp.net', undefined);
593
+ // Enumerate devices for sender and target with consistent addressing
594
+ const sessionDevices = await getUSyncDevices([senderIdentity, jid], true, false);
595
+ devices.push(...sessionDevices);
596
+ logger.debug({
597
+ deviceCount: devices.length,
598
+ devices: devices.map(d => `${d.user}:${d.device}@${jidDecode(d.jid)?.server}`)
599
+ }, 'Device enumeration complete with unified addressing');
405
600
  }
406
601
  }
407
- const allJids = [];
408
- const meJids = [];
409
- const otherJids = [];
410
- for (const { user, device } of devices) {
411
- const isMe = user === meUser;
412
- const jid = jidEncode(isMe && isLid ? authState.creds?.me?.lid.split(':')[0] || user : user, isLid ? 'lid' : 's.whatsapp.net', device);
602
+ const allRecipients = [];
603
+ const meRecipients = [];
604
+ const otherRecipients = [];
605
+ const { user: mePnUser } = jidDecode(meId);
606
+ const { user: meLidUser } = meLid ? jidDecode(meLid) : { user: null };
607
+ for (const { user, jid } of devices) {
608
+ const isExactSenderDevice = jid === meId || (meLid && jid === meLid);
609
+ if (isExactSenderDevice) {
610
+ logger.debug({ jid, meId, meLid }, 'Skipping exact sender device (whatsmeow pattern)');
611
+ continue;
612
+ }
613
+ // Check if this is our device (could match either PN or LID user)
614
+ const isMe = user === mePnUser || user === meLidUser;
413
615
  if (isMe) {
414
- meJids.push(jid);
616
+ meRecipients.push(jid);
415
617
  }
416
618
  else {
417
- otherJids.push(jid);
619
+ otherRecipients.push(jid);
418
620
  }
419
- allJids.push(jid);
621
+ allRecipients.push(jid);
420
622
  }
421
- await assertSessions(allJids, false);
623
+ await assertSessions(allRecipients);
422
624
  const [{ nodes: meNodes, shouldIncludeDeviceIdentity: s1 }, { nodes: otherNodes, shouldIncludeDeviceIdentity: s2 }] = await Promise.all([
423
- createParticipantNodes(meJids, meMsg, extraAttrs),
424
- createParticipantNodes(otherJids, message, extraAttrs)
625
+ // For own devices: use DSM if available (1:1 chats only)
626
+ createParticipantNodes(meRecipients, meMsg || message, extraAttrs),
627
+ createParticipantNodes(otherRecipients, message, extraAttrs, meMsg)
425
628
  ]);
426
629
  participants.push(...meNodes);
427
630
  participants.push(...otherNodes);
631
+ if (meRecipients.length > 0 || otherRecipients.length > 0) {
632
+ extraAttrs['phash'] = generateParticipantHashV2([...meRecipients, ...otherRecipients]);
633
+ }
428
634
  shouldIncludeDeviceIdentity = shouldIncludeDeviceIdentity || s1 || s2;
429
635
  }
636
+ if (isRetryResend) {
637
+ const isParticipantLid = isLidUser(participant.jid);
638
+ const isMe = areJidsSameUser(participant.jid, isParticipantLid ? meLid : meId);
639
+ const encodedMessageToSend = isMe
640
+ ? encodeWAMessage({
641
+ deviceSentMessage: {
642
+ destinationJid,
643
+ message
644
+ }
645
+ })
646
+ : encodeWAMessage(message);
647
+ const { type, ciphertext: encryptedContent } = await signalRepository.encryptMessage({
648
+ data: encodedMessageToSend,
649
+ jid: participant.jid
650
+ });
651
+ binaryNodeContent.push({
652
+ tag: 'enc',
653
+ attrs: {
654
+ v: '2',
655
+ type,
656
+ count: participant.count.toString()
657
+ },
658
+ content: encryptedContent
659
+ });
660
+ }
430
661
  if (participants.length) {
431
662
  if (additionalAttributes?.['category'] === 'peer') {
432
663
  const peerNode = participants[0]?.content?.[0];
@@ -446,6 +677,7 @@ export const makeMessagesSocket = (config) => {
446
677
  tag: 'message',
447
678
  attrs: {
448
679
  id: msgId,
680
+ to: destinationJid,
449
681
  type: getMessageType(message),
450
682
  ...(additionalAttributes || {})
451
683
  },
@@ -479,19 +711,39 @@ export const makeMessagesSocket = (config) => {
479
711
  });
480
712
  logger.debug({ jid }, 'adding device identity');
481
713
  }
714
+ const contactTcTokenData = !isGroup && !isRetryResend && !isStatus ? await authState.keys.get('tctoken', [destinationJid]) : {};
715
+ const tcTokenBuffer = contactTcTokenData[destinationJid]?.token;
716
+ if (tcTokenBuffer) {
717
+ ;
718
+ stanza.content.push({
719
+ tag: 'tctoken',
720
+ attrs: {},
721
+ content: tcTokenBuffer
722
+ });
723
+ }
482
724
  if (additionalNodes && additionalNodes.length > 0) {
483
725
  ;
484
726
  stanza.content.push(...additionalNodes);
485
727
  }
486
728
  logger.debug({ msgId }, `sending message to ${participants.length} devices`);
487
729
  await sendNode(stanza);
488
- });
730
+ // Add message to retry cache if enabled
731
+ if (messageRetryManager && !participant) {
732
+ messageRetryManager.addRecentMessage(destinationJid, msgId, message);
733
+ }
734
+ }, meId);
489
735
  return msgId;
490
736
  };
491
737
  const getMessageType = (message) => {
492
738
  if (message.pollCreationMessage || message.pollCreationMessageV2 || message.pollCreationMessageV3) {
493
739
  return 'poll';
494
740
  }
741
+ if (message.eventMessage) {
742
+ return 'event';
743
+ }
744
+ if (getMediaType(message) !== '') {
745
+ return 'media';
746
+ }
495
747
  return 'text';
496
748
  };
497
749
  const getMediaType = (message) => {
@@ -540,6 +792,7 @@ export const makeMessagesSocket = (config) => {
540
792
  else if (message.groupInviteMessage) {
541
793
  return 'url';
542
794
  }
795
+ return '';
543
796
  };
544
797
  const getPrivacyTokens = async (jids) => {
545
798
  const t = unixTimestampSeconds().toString();
@@ -583,6 +836,7 @@ export const makeMessagesSocket = (config) => {
583
836
  sendPeerDataOperationMessage,
584
837
  createParticipantNodes,
585
838
  getUSyncDevices,
839
+ messageRetryManager,
586
840
  updateMediaMessage: async (message) => {
587
841
  const content = assertMediaContent(message.message);
588
842
  const mediaKey = content.mediaKey;
@@ -647,19 +901,21 @@ export const makeMessagesSocket = (config) => {
647
901
  thumbnailWidth: linkPreviewImageThumbnailWidth,
648
902
  fetchOpts: {
649
903
  timeout: 3000,
650
- ...(axiosOptions || {})
904
+ ...(httpRequestOptions || {})
651
905
  },
652
906
  logger,
653
907
  uploadImage: generateHighQualityLinkPreview ? waUploadToServer : undefined
654
908
  }),
655
909
  //TODO: CACHE
656
910
  getProfilePicUrl: sock.profilePictureUrl,
911
+ getCallLink: sock.createCallLink,
657
912
  upload: waUploadToServer,
658
913
  mediaCache: config.mediaCache,
659
914
  options: config.options,
660
915
  messageId: options.messageId || generateMessageIDV2(sock.user?.id),
661
916
  ...options
662
917
  });
918
+ const isEventMsg = 'event' in content && !!content.event;
663
919
  const isDeleteMsg = 'delete' in content && !!content.delete;
664
920
  const isEditMsg = 'edit' in content && !!content.edit;
665
921
  const isPinMsg = 'pin' in content && !!content.pin;
@@ -690,8 +946,13 @@ export const makeMessagesSocket = (config) => {
690
946
  }
691
947
  });
692
948
  }
693
- if ('cachedGroupMetadata' in options) {
694
- console.warn('cachedGroupMetadata in sendMessage are deprecated, now cachedGroupMetadata is part of the socket config.');
949
+ else if (isEventMsg) {
950
+ additionalNodes.push({
951
+ tag: 'meta',
952
+ attrs: {
953
+ event_type: 'creation'
954
+ }
955
+ });
695
956
  }
696
957
  await relayMessage(jid, fullMsg.message, {
697
958
  messageId: fullMsg.key.id,
@@ -701,8 +962,8 @@ export const makeMessagesSocket = (config) => {
701
962
  additionalNodes
702
963
  });
703
964
  if (config.emitOwnEvents) {
704
- process.nextTick(() => {
705
- processingMutex.mutex(() => upsertMessage(fullMsg, 'append'));
965
+ process.nextTick(async () => {
966
+ await processingMutex.mutex(() => upsertMessage(fullMsg, 'append'));
706
967
  });
707
968
  }
708
969
  return fullMsg;