@periskope/baileys 7.0.0-alpha-5 → 7.0.0-beta-2

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 (146) hide show
  1. package/README.md +0 -6
  2. package/lib/Defaults/index.d.ts +1 -7
  3. package/lib/Defaults/index.d.ts.map +1 -1
  4. package/lib/Defaults/index.js +4 -11
  5. package/lib/Defaults/index.js.map +1 -1
  6. package/lib/Signal/Group/group_cipher.d.ts +1 -0
  7. package/lib/Signal/Group/group_cipher.d.ts.map +1 -1
  8. package/lib/Signal/Group/group_cipher.js +37 -28
  9. package/lib/Signal/Group/group_cipher.js.map +1 -1
  10. package/lib/Signal/Group/keyhelper.d.ts.map +1 -1
  11. package/lib/Signal/Group/keyhelper.js +1 -0
  12. package/lib/Signal/Group/keyhelper.js.map +1 -1
  13. package/lib/Signal/Group/sender-chain-key.d.ts +1 -1
  14. package/lib/Signal/Group/sender-chain-key.d.ts.map +1 -1
  15. package/lib/Signal/Group/sender-chain-key.js +3 -9
  16. package/lib/Signal/Group/sender-chain-key.js.map +1 -1
  17. package/lib/Signal/Group/sender-key-message.d.ts.map +1 -1
  18. package/lib/Signal/Group/sender-key-message.js +1 -0
  19. package/lib/Signal/Group/sender-key-message.js.map +1 -1
  20. package/lib/Signal/Group/sender-key-state.d.ts +4 -4
  21. package/lib/Signal/Group/sender-key-state.d.ts.map +1 -1
  22. package/lib/Signal/Group/sender-key-state.js +19 -47
  23. package/lib/Signal/Group/sender-key-state.js.map +1 -1
  24. package/lib/Signal/Group/sender-message-key.d.ts.map +1 -1
  25. package/lib/Signal/Group/sender-message-key.js +1 -0
  26. package/lib/Signal/Group/sender-message-key.js.map +1 -1
  27. package/lib/Signal/libsignal.d.ts +2 -6
  28. package/lib/Signal/libsignal.d.ts.map +1 -1
  29. package/lib/Signal/libsignal.js +41 -224
  30. package/lib/Signal/libsignal.js.map +1 -1
  31. package/lib/Signal/lid-mapping.d.ts +2 -11
  32. package/lib/Signal/lid-mapping.d.ts.map +1 -1
  33. package/lib/Signal/lid-mapping.js +34 -91
  34. package/lib/Signal/lid-mapping.js.map +1 -1
  35. package/lib/Socket/business.d.ts +14 -26
  36. package/lib/Socket/business.d.ts.map +1 -1
  37. package/lib/Socket/business.js +1 -122
  38. package/lib/Socket/business.js.map +1 -1
  39. package/lib/Socket/chats.d.ts +9 -15
  40. package/lib/Socket/chats.d.ts.map +1 -1
  41. package/lib/Socket/chats.js +20 -53
  42. package/lib/Socket/chats.js.map +1 -1
  43. package/lib/Socket/communities.d.ts +11 -25
  44. package/lib/Socket/communities.d.ts.map +1 -1
  45. package/lib/Socket/communities.js +0 -44
  46. package/lib/Socket/communities.js.map +1 -1
  47. package/lib/Socket/groups.d.ts +9 -14
  48. package/lib/Socket/groups.d.ts.map +1 -1
  49. package/lib/Socket/groups.js +10 -12
  50. package/lib/Socket/groups.js.map +1 -1
  51. package/lib/Socket/index.d.ts +11 -25
  52. package/lib/Socket/index.d.ts.map +1 -1
  53. package/lib/Socket/messages-recv.d.ts +11 -19
  54. package/lib/Socket/messages-recv.d.ts.map +1 -1
  55. package/lib/Socket/messages-recv.js +230 -396
  56. package/lib/Socket/messages-recv.js.map +1 -1
  57. package/lib/Socket/messages-send.d.ts +11 -20
  58. package/lib/Socket/messages-send.d.ts.map +1 -1
  59. package/lib/Socket/messages-send.js +71 -443
  60. package/lib/Socket/messages-send.js.map +1 -1
  61. package/lib/Socket/newsletter.d.ts +12 -16
  62. package/lib/Socket/newsletter.d.ts.map +1 -1
  63. package/lib/Socket/newsletter.js +1 -3
  64. package/lib/Socket/newsletter.js.map +1 -1
  65. package/lib/Socket/socket.d.ts +3 -10
  66. package/lib/Socket/socket.d.ts.map +1 -1
  67. package/lib/Socket/socket.js +69 -264
  68. package/lib/Socket/socket.js.map +1 -1
  69. package/lib/Types/Auth.d.ts +1 -2
  70. package/lib/Types/Auth.d.ts.map +1 -1
  71. package/lib/Types/Chat.d.ts +0 -5
  72. package/lib/Types/Chat.d.ts.map +1 -1
  73. package/lib/Types/Chat.js.map +1 -1
  74. package/lib/Types/Contact.d.ts +4 -4
  75. package/lib/Types/Contact.d.ts.map +1 -1
  76. package/lib/Types/Events.d.ts +2 -2
  77. package/lib/Types/Events.d.ts.map +1 -1
  78. package/lib/Types/GroupMetadata.d.ts +4 -6
  79. package/lib/Types/GroupMetadata.d.ts.map +1 -1
  80. package/lib/Types/Message.d.ts +7 -28
  81. package/lib/Types/Message.d.ts.map +1 -1
  82. package/lib/Types/Message.js +1 -5
  83. package/lib/Types/Message.js.map +1 -1
  84. package/lib/Types/Signal.d.ts +0 -28
  85. package/lib/Types/Signal.d.ts.map +1 -1
  86. package/lib/Types/Socket.d.ts +7 -23
  87. package/lib/Types/Socket.d.ts.map +1 -1
  88. package/lib/Utils/auth-utils.d.ts.map +1 -1
  89. package/lib/Utils/auth-utils.js +79 -363
  90. package/lib/Utils/auth-utils.js.map +1 -1
  91. package/lib/Utils/chat-utils.d.ts +2 -2
  92. package/lib/Utils/chat-utils.d.ts.map +1 -1
  93. package/lib/Utils/chat-utils.js +2 -19
  94. package/lib/Utils/chat-utils.js.map +1 -1
  95. package/lib/Utils/crypto.d.ts +3 -3
  96. package/lib/Utils/crypto.d.ts.map +1 -1
  97. package/lib/Utils/crypto.js +12 -16
  98. package/lib/Utils/crypto.js.map +1 -1
  99. package/lib/Utils/decode-wa-message.d.ts +2 -13
  100. package/lib/Utils/decode-wa-message.d.ts.map +1 -1
  101. package/lib/Utils/decode-wa-message.js +13 -84
  102. package/lib/Utils/decode-wa-message.js.map +1 -1
  103. package/lib/Utils/event-buffer.d.ts +1 -0
  104. package/lib/Utils/event-buffer.d.ts.map +1 -1
  105. package/lib/Utils/event-buffer.js +4 -48
  106. package/lib/Utils/event-buffer.js.map +1 -1
  107. package/lib/Utils/generics.d.ts +0 -1
  108. package/lib/Utils/generics.d.ts.map +1 -1
  109. package/lib/Utils/generics.js +8 -24
  110. package/lib/Utils/generics.js.map +1 -1
  111. package/lib/Utils/history.d.ts.map +1 -1
  112. package/lib/Utils/history.js +2 -1
  113. package/lib/Utils/history.js.map +1 -1
  114. package/lib/Utils/index.d.ts +0 -1
  115. package/lib/Utils/index.d.ts.map +1 -1
  116. package/lib/Utils/index.js +0 -1
  117. package/lib/Utils/index.js.map +1 -1
  118. package/lib/Utils/messages-media.d.ts +2 -3
  119. package/lib/Utils/messages-media.d.ts.map +1 -1
  120. package/lib/Utils/messages-media.js +1 -4
  121. package/lib/Utils/messages-media.js.map +1 -1
  122. package/lib/Utils/messages.d.ts.map +1 -1
  123. package/lib/Utils/messages.js +4 -24
  124. package/lib/Utils/messages.js.map +1 -1
  125. package/lib/Utils/process-message.d.ts +2 -3
  126. package/lib/Utils/process-message.d.ts.map +1 -1
  127. package/lib/Utils/process-message.js +3 -13
  128. package/lib/Utils/process-message.js.map +1 -1
  129. package/lib/Utils/signal.d.ts +2 -2
  130. package/lib/Utils/signal.d.ts.map +1 -1
  131. package/lib/Utils/signal.js.map +1 -1
  132. package/lib/Utils/validate-connection.d.ts.map +1 -1
  133. package/lib/Utils/validate-connection.js +2 -3
  134. package/lib/Utils/validate-connection.js.map +1 -1
  135. package/lib/WABinary/jid-utils.d.ts +5 -6
  136. package/lib/WABinary/jid-utils.d.ts.map +1 -1
  137. package/lib/WABinary/jid-utils.js +5 -11
  138. package/lib/WABinary/jid-utils.js.map +1 -1
  139. package/lib/WAM/encode.d.ts.map +1 -1
  140. package/lib/WAM/encode.js +1 -0
  141. package/lib/WAM/encode.js.map +1 -1
  142. package/lib/WAUSync/Protocols/UsyncLIDProtocol.d.ts +1 -2
  143. package/lib/WAUSync/Protocols/UsyncLIDProtocol.d.ts.map +1 -1
  144. package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +2 -10
  145. package/lib/WAUSync/Protocols/UsyncLIDProtocol.js.map +1 -1
  146. package/package.json +8 -12
@@ -2,26 +2,21 @@ 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 { WAMessageAddressingMode } from '../Types/index.js';
6
- import { aggregateMessageKeysNotFromMe, assertMediaContent, bindWaitForEvent, decryptMediaRetryData, encodeNewsletterMessage, encodeSignedDeviceIdentity, encodeWAMessage, encryptMediaRetryRequest, extractDeviceJids, generateMessageIDV2, generateParticipantHashV2, generateWAMessage, getStatusCodeForMediaRetry, getUrlFromDirectPath, getWAUploadToServer, MessageRetryManager, normalizeMessageContent, parseAndInjectE2ESessions, unixTimestampSeconds } from '../Utils/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';
7
6
  import { getUrlInfo } from '../Utils/link-preview.js';
8
- import { makeKeyedMutex } from '../Utils/make-mutex.js';
9
- import { areJidsSameUser, getBinaryNodeChild, getBinaryNodeChildren, isJidGroup, isPnUser, jidDecode, jidEncode, jidNormalizedUser, S_WHATSAPP_NET } from '../WABinary/index.js';
7
+ import { areJidsSameUser, getBinaryNodeChild, getBinaryNodeChildren, isJidGroup, isJidUser, jidDecode, jidEncode, jidNormalizedUser, S_WHATSAPP_NET } from '../WABinary/index.js';
10
8
  import { USyncQuery, USyncUser } from '../WAUSync/index.js';
9
+ import { makeGroupsSocket } from './groups.js';
11
10
  import { makeNewsletterSocket } from './newsletter.js';
12
11
  export const makeMessagesSocket = (config) => {
13
- const { logger, linkPreviewImageThumbnailWidth, generateHighQualityLinkPreview, options: axiosOptions, patchMessageBeforeSending, cachedGroupMetadata, enableRecentMessageCache, maxMsgRetryCount } = config;
14
- const sock = makeNewsletterSocket(config);
12
+ const { logger, linkPreviewImageThumbnailWidth, generateHighQualityLinkPreview, options: axiosOptions, patchMessageBeforeSending, cachedGroupMetadata } = config;
13
+ const sock = makeNewsletterSocket(makeGroupsSocket(config));
15
14
  const { ev, authState, processingMutex, signalRepository, upsertMessage, query, fetchPrivacySettings, sendNode, groupMetadata, groupToggleEphemeral } = sock;
16
15
  const userDevicesCache = config.userDevicesCache ||
17
16
  new NodeCache({
18
17
  stdTTL: DEFAULT_CACHE_TTLS.USER_DEVICES, // 5 minutes
19
18
  useClones: false
20
19
  });
21
- // Initialize message retry manager if enabled
22
- const messageRetryManager = enableRecentMessageCache ? new MessageRetryManager(logger, maxMsgRetryCount) : null;
23
- // Prevent race conditions in Signal session encryption by user
24
- const encryptionMutex = makeKeyedMutex();
25
20
  let mediaConn;
26
21
  const refreshMediaConn = async (forceGet = false) => {
27
22
  const media = await mediaConn;
@@ -70,7 +65,7 @@ export const makeMessagesSocket = (config) => {
70
65
  if (isReadReceipt) {
71
66
  node.attrs.t = unixTimestampSeconds().toString();
72
67
  }
73
- if (type === 'sender' && isPnUser(jid)) {
68
+ if (type === 'sender' && isJidUser(jid)) {
74
69
  node.attrs.recipient = jid;
75
70
  node.attrs.to = participant;
76
71
  }
@@ -113,34 +108,6 @@ export const makeMessagesSocket = (config) => {
113
108
  const readType = privacySettings.readreceipts === 'all' ? 'read' : 'read-self';
114
109
  await sendReceipts(keys, readType);
115
110
  };
116
- /**
117
- * Deduplicate JIDs when both LID and PN versions exist for same user
118
- * Prefers LID over PN to maintain single encryption layer
119
- */
120
- const deduplicateLidPnJids = (jids) => {
121
- const lidUsers = new Set();
122
- const filteredJids = [];
123
- // Collect all LID users
124
- for (const jid of jids) {
125
- if (jid.includes('@lid')) {
126
- const user = jidDecode(jid)?.user;
127
- if (user)
128
- lidUsers.add(user);
129
- }
130
- }
131
- // Filter out PN versions when LID exists
132
- for (const jid of jids) {
133
- if (jid.includes('@s.whatsapp.net')) {
134
- const user = jidDecode(jid)?.user;
135
- if (user && lidUsers.has(user)) {
136
- logger.debug({ jid }, 'Skipping PN - LID version exists');
137
- continue;
138
- }
139
- }
140
- filteredJids.push(jid);
141
- }
142
- return filteredJids;
143
- };
144
111
  /** Fetch all the devices we've to send a message to */
145
112
  const getUSyncDevices = async (jids, useCache, ignoreZeroDevices) => {
146
113
  const deviceResults = [];
@@ -148,41 +115,14 @@ export const makeMessagesSocket = (config) => {
148
115
  logger.debug('not using cache for devices');
149
116
  }
150
117
  const toFetch = [];
151
- jids = deduplicateLidPnJids(Array.from(new Set(jids)));
152
- const jidsWithUser = jids
153
- .map(jid => {
154
- const decoded = jidDecode(jid);
155
- const user = decoded?.user;
156
- const device = decoded?.device;
157
- const isExplicitDevice = typeof device === 'number' && device >= 0;
158
- if (isExplicitDevice && user) {
159
- deviceResults.push({
160
- user,
161
- device,
162
- wireJid: jid // again this makes no sense
163
- });
164
- return null;
165
- }
118
+ jids = Array.from(new Set(jids));
119
+ for (let jid of jids) {
120
+ const user = jidDecode(jid)?.user;
166
121
  jid = jidNormalizedUser(jid);
167
- return { jid, user };
168
- })
169
- .filter(jid => jid !== null);
170
- let mgetDevices;
171
- if (useCache && userDevicesCache.mget) {
172
- const usersToFetch = jidsWithUser.map(j => j?.user).filter(Boolean);
173
- mgetDevices = await userDevicesCache.mget(usersToFetch);
174
- }
175
- for (const { jid, user } of jidsWithUser) {
176
122
  if (useCache) {
177
- const devices = mgetDevices?.[user] ||
178
- (userDevicesCache.mget ? undefined : (await userDevicesCache.get(user)));
123
+ const devices = userDevicesCache.get(user);
179
124
  if (devices) {
180
- const isLidJid = jid.includes('@lid');
181
- const devicesWithWire = devices.map(d => ({
182
- ...d,
183
- wireJid: isLidJid ? jidEncode(d.user, 'lid', d.device) : jidEncode(d.user, 's.whatsapp.net', d.device)
184
- }));
185
- deviceResults.push(...devicesWithWire);
125
+ deviceResults.push(...devices);
186
126
  logger.trace({ user }, 'using cache for devices');
187
127
  }
188
128
  else {
@@ -196,17 +136,9 @@ export const makeMessagesSocket = (config) => {
196
136
  if (!toFetch.length) {
197
137
  return deviceResults;
198
138
  }
199
- const requestedLidUsers = new Set();
200
- for (const jid of toFetch) {
201
- if (jid.includes('@lid')) {
202
- const user = jidDecode(jid)?.user;
203
- if (user)
204
- requestedLidUsers.add(user);
205
- }
206
- }
207
139
  const query = new USyncQuery().withContext('message').withDeviceProtocol();
208
140
  for (const jid of toFetch) {
209
- 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
141
+ query.withUser(new USyncUser().withId(jid));
210
142
  }
211
143
  const result = await sock.executeUSyncQuery(query);
212
144
  if (result) {
@@ -215,170 +147,32 @@ export const makeMessagesSocket = (config) => {
215
147
  for (const item of extracted) {
216
148
  deviceMap[item.user] = deviceMap[item.user] || [];
217
149
  deviceMap[item.user]?.push(item);
150
+ deviceResults.push(item);
218
151
  }
219
- // Process each user's devices as a group for bulk LID migration
220
- for (const [user, userDevices] of Object.entries(deviceMap)) {
221
- const isLidUser = requestedLidUsers.has(user);
222
- // Process all devices for this user
223
- for (const item of userDevices) {
224
- const finalWireJid = isLidUser
225
- ? jidEncode(user, 'lid', item.device)
226
- : jidEncode(item.user, 's.whatsapp.net', item.device);
227
- deviceResults.push({
228
- ...item,
229
- wireJid: finalWireJid
230
- });
231
- logger.debug({
232
- user: item.user,
233
- device: item.device,
234
- finalWireJid,
235
- usedLid: isLidUser
236
- }, 'Processed device with LID priority');
237
- }
238
- }
239
- if (userDevicesCache.mset) {
240
- // if the cache supports mset, we can set all devices in one go
241
- await userDevicesCache.mset(Object.entries(deviceMap).map(([key, value]) => ({ key, value })));
242
- }
243
- else {
244
- for (const key in deviceMap) {
245
- if (deviceMap[key])
246
- await userDevicesCache.set(key, deviceMap[key]);
247
- }
152
+ for (const key in deviceMap) {
153
+ userDevicesCache.set(key, deviceMap[key]);
248
154
  }
249
155
  }
250
156
  return deviceResults;
251
157
  };
252
158
  const assertSessions = async (jids, force) => {
253
159
  let didFetchNewSession = false;
254
- const jidsRequiringFetch = [];
255
- // Apply same deduplication as in getUSyncDevices
256
- jids = deduplicateLidPnJids(jids);
160
+ let jidsRequiringFetch = [];
257
161
  if (force) {
258
- // Check which sessions are missing (with LID migration check)
259
- const addrs = jids.map(jid => signalRepository.jidToSignalProtocolAddress(jid));
260
- const sessions = await authState.keys.get('session', addrs);
261
- // Simplified: Check session existence directly
262
- const checkJidSession = (jid) => {
263
- const signalId = signalRepository.jidToSignalProtocolAddress(jid);
264
- const hasSession = !!sessions[signalId];
265
- // Add to fetch list if no session exists
266
- // Session type selection (LID vs PN) is handled in encryptMessage
267
- if (!hasSession) {
268
- if (jid.includes('@lid')) {
269
- logger.debug({ jid }, 'No LID session found, will create new LID session');
270
- }
271
- jidsRequiringFetch.push(jid);
272
- }
273
- };
274
- // Process all JIDs
275
- for (const jid of jids) {
276
- checkJidSession(jid);
277
- }
162
+ jidsRequiringFetch = jids;
278
163
  }
279
164
  else {
280
165
  const addrs = jids.map(jid => signalRepository.jidToSignalProtocolAddress(jid));
281
166
  const sessions = await authState.keys.get('session', addrs);
282
- // Group JIDs by user for bulk migration
283
- const userGroups = new Map();
284
167
  for (const jid of jids) {
285
- const user = jidNormalizedUser(jid);
286
- if (!userGroups.has(user)) {
287
- userGroups.set(user, []);
288
- }
289
- userGroups.get(user).push(jid);
290
- }
291
- // Helper to check LID mapping for a user
292
- const checkUserLidMapping = async (user, userJids) => {
293
- if (!userJids.some(jid => jid.includes('@s.whatsapp.net'))) {
294
- return { shouldMigrate: false, lidForPN: undefined };
295
- }
296
- try {
297
- // Convert user to proper PN JID format for getLIDForPN
298
- const pnJid = `${user}@s.whatsapp.net`;
299
- const mapping = await signalRepository.lidMapping.getLIDForPN(pnJid);
300
- if (mapping?.includes('@lid')) {
301
- logger.debug({ user, lidForPN: mapping, deviceCount: userJids.length }, 'User has LID mapping - preparing bulk migration');
302
- return { shouldMigrate: true, lidForPN: mapping };
303
- }
304
- }
305
- catch (error) {
306
- logger.debug({ user, error }, 'Failed to check LID mapping for user');
307
- }
308
- return { shouldMigrate: false, lidForPN: undefined };
309
- };
310
- // Process each user group for potential bulk LID migration
311
- for (const [user, userJids] of userGroups) {
312
- const mappingResult = await checkUserLidMapping(user, userJids);
313
- const shouldMigrateUser = mappingResult.shouldMigrate;
314
- const lidForPN = mappingResult.lidForPN;
315
- // Migrate all devices for this user if LID mapping exists
316
- if (shouldMigrateUser && lidForPN) {
317
- // Bulk migrate all user devices in single transaction
318
- const migrationResult = await signalRepository.migrateSession(userJids, lidForPN);
319
- if (migrationResult.migrated > 0) {
320
- logger.info({
321
- user,
322
- lidMapping: lidForPN,
323
- migrated: migrationResult.migrated,
324
- skipped: migrationResult.skipped,
325
- total: migrationResult.total
326
- }, 'Completed bulk migration for user devices');
327
- }
328
- else {
329
- logger.debug({
330
- user,
331
- lidMapping: lidForPN,
332
- skipped: migrationResult.skipped,
333
- total: migrationResult.total
334
- }, 'All user device sessions already migrated');
335
- }
168
+ const signalId = signalRepository.jidToSignalProtocolAddress(jid);
169
+ if (!sessions[signalId]) {
170
+ jidsRequiringFetch.push(jid);
336
171
  }
337
- // Direct bulk session check with LID single source of truth
338
- const addMissingSessionsToFetchList = (jid) => {
339
- const signalId = signalRepository.jidToSignalProtocolAddress(jid);
340
- if (sessions[signalId])
341
- return;
342
- // Determine correct JID to fetch (LID if mapping exists, otherwise original)
343
- if (jid.includes('@s.whatsapp.net') && shouldMigrateUser && lidForPN) {
344
- const decoded = jidDecode(jid);
345
- const lidDeviceJid = decoded.device !== undefined ? `${jidDecode(lidForPN).user}:${decoded.device}@lid` : lidForPN;
346
- jidsRequiringFetch.push(lidDeviceJid);
347
- logger.debug({ pnJid: jid, lidJid: lidDeviceJid }, 'Adding LID JID to fetch list (conversion)');
348
- }
349
- else {
350
- jidsRequiringFetch.push(jid);
351
- logger.debug({ jid }, 'Adding JID to fetch list');
352
- }
353
- };
354
- userJids.forEach(addMissingSessionsToFetchList);
355
172
  }
356
173
  }
357
174
  if (jidsRequiringFetch.length) {
358
175
  logger.debug({ jidsRequiringFetch }, 'fetching sessions');
359
- // DEBUG: Check if there are PN versions of LID users being fetched
360
- const lidUsersBeingFetched = new Set();
361
- const pnUsersBeingFetched = new Set();
362
- for (const jid of jidsRequiringFetch) {
363
- const user = jidDecode(jid)?.user;
364
- if (user) {
365
- if (jid.includes('@lid')) {
366
- lidUsersBeingFetched.add(user);
367
- }
368
- else if (jid.includes('@s.whatsapp.net')) {
369
- pnUsersBeingFetched.add(user);
370
- }
371
- }
372
- }
373
- // Find overlaps
374
- const overlapping = Array.from(pnUsersBeingFetched).filter(user => lidUsersBeingFetched.has(user));
375
- if (overlapping.length > 0) {
376
- logger.warn({
377
- overlapping,
378
- lidUsersBeingFetched: Array.from(lidUsersBeingFetched),
379
- pnUsersBeingFetched: Array.from(pnUsersBeingFetched)
380
- }, 'Fetching both LID and PN sessions for same users');
381
- }
382
176
  const result = await query({
383
177
  tag: 'iq',
384
178
  attrs: {
@@ -422,133 +216,43 @@ export const makeMessagesSocket = (config) => {
422
216
  });
423
217
  return msgId;
424
218
  };
425
- const createParticipantNodes = async (jids, message, extraAttrs, dsmMessage) => {
219
+ const createParticipantNodes = async (jids, message, extraAttrs) => {
426
220
  let patched = await patchMessageBeforeSending(message, jids);
427
221
  if (!Array.isArray(patched)) {
428
222
  patched = jids ? jids.map(jid => ({ recipientJid: jid, ...patched })) : [patched];
429
223
  }
430
224
  let shouldIncludeDeviceIdentity = false;
431
- const meId = authState.creds.me.id;
432
- const meLid = authState.creds.me?.lid;
433
- const meLidUser = meLid ? jidDecode(meLid)?.user : null;
434
- const devicesByUser = new Map();
435
- for (const patchedMessageWithJid of patched) {
436
- const { recipientJid: wireJid, ...patchedMessage } = patchedMessageWithJid;
437
- if (!wireJid)
438
- continue;
439
- // Extract user from JID for grouping
440
- const decoded = jidDecode(wireJid);
441
- const user = decoded?.user;
442
- if (!user)
443
- continue;
444
- if (!devicesByUser.has(user)) {
445
- devicesByUser.set(user, []);
446
- }
447
- devicesByUser.get(user).push({ recipientJid: wireJid, patchedMessage });
448
- }
449
- // Process each user's devices sequentially, but different users in parallel
450
- const userEncryptionPromises = Array.from(devicesByUser.entries()).map(([user, userDevices]) => encryptionMutex.mutex(user, async () => {
451
- logger.debug({ user, deviceCount: userDevices.length }, 'Acquiring encryption lock for user devices');
452
- const userNodes = [];
453
- // Helper to get encryption JID with LID migration
454
- const getEncryptionJid = async (wireJid) => {
455
- if (!wireJid.includes('@s.whatsapp.net'))
456
- return wireJid;
457
- try {
458
- const lidForPN = await signalRepository.lidMapping.getLIDForPN(wireJid);
459
- if (!lidForPN?.includes('@lid'))
460
- return wireJid;
461
- // Preserve device ID from original wire JID
462
- const wireDecoded = jidDecode(wireJid);
463
- const deviceId = wireDecoded?.device || 0;
464
- const lidDecoded = jidDecode(lidForPN);
465
- const lidWithDevice = jidEncode(lidDecoded?.user, 'lid', deviceId);
466
- // Migrate session to LID for unified encryption layer
467
- try {
468
- const migrationResult = await signalRepository.migrateSession([wireJid], lidWithDevice);
469
- const recipientUser = jidNormalizedUser(wireJid);
470
- const ownPnUser = jidNormalizedUser(meId);
471
- const isOwnDevice = recipientUser === ownPnUser;
472
- logger.info({ wireJid, lidWithDevice, isOwnDevice }, 'Migrated to LID encryption');
473
- // Delete PN session after successful migration
474
- try {
475
- if (migrationResult.migrated) {
476
- await signalRepository.deleteSession([wireJid]);
477
- logger.debug({ deletedPNSession: wireJid }, 'Deleted PN session');
478
- }
479
- }
480
- catch (deleteError) {
481
- logger.warn({ wireJid, error: deleteError }, 'Failed to delete PN session');
482
- }
483
- return lidWithDevice;
484
- }
485
- catch (migrationError) {
486
- logger.warn({ wireJid, error: migrationError }, 'Failed to migrate session');
487
- return wireJid;
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
488
247
  }
489
- }
490
- catch (error) {
491
- logger.debug({ wireJid, error }, 'Failed to check LID mapping');
492
- return wireJid;
493
- }
248
+ ]
494
249
  };
495
- // Encrypt to this user's devices sequentially to prevent session corruption
496
- for (const { recipientJid: wireJid, patchedMessage } of userDevices) {
497
- // DSM logic: Use DSM for own other devices (following whatsmeow implementation)
498
- let messageToEncrypt = patchedMessage;
499
- if (dsmMessage) {
500
- const { user: targetUser } = jidDecode(wireJid);
501
- const { user: ownPnUser } = jidDecode(meId);
502
- const ownLidUser = meLidUser;
503
- // Check if this is our device (same user, different device)
504
- const isOwnUser = targetUser === ownPnUser || (ownLidUser && targetUser === ownLidUser);
505
- // Exclude exact sender device (whatsmeow: if jid == ownJID || jid == ownLID { continue })
506
- const isExactSenderDevice = wireJid === meId || (authState.creds.me?.lid && wireJid === authState.creds.me.lid);
507
- if (isOwnUser && !isExactSenderDevice) {
508
- messageToEncrypt = dsmMessage;
509
- logger.debug({ wireJid, targetUser }, 'Using DSM for own device');
510
- }
511
- }
512
- const bytes = encodeWAMessage(messageToEncrypt);
513
- // Get encryption JID with LID migration
514
- const encryptionJid = await getEncryptionJid(wireJid);
515
- // ENCRYPT: Use the determined encryption identity (prefers migrated LID)
516
- const { type, ciphertext } = await signalRepository.encryptMessage({
517
- jid: encryptionJid, // Unified encryption layer (LID when available)
518
- data: bytes
519
- });
520
- if (type === 'pkmsg') {
521
- shouldIncludeDeviceIdentity = true;
522
- }
523
- const node = {
524
- tag: 'to',
525
- attrs: { jid: wireJid }, // Always use original wire identity in envelope
526
- content: [
527
- {
528
- tag: 'enc',
529
- attrs: {
530
- v: '2',
531
- type,
532
- ...(extraAttrs || {})
533
- },
534
- content: ciphertext
535
- }
536
- ]
537
- };
538
- userNodes.push(node);
539
- }
540
- logger.debug({ user, nodesCreated: userNodes.length }, 'Releasing encryption lock for user devices');
541
- return userNodes;
250
+ return node;
542
251
  }));
543
- // Wait for all users to complete (users are processed in parallel)
544
- const userNodesArrays = await Promise.all(userEncryptionPromises);
545
- const nodes = userNodesArrays.flat();
546
252
  return { nodes, shouldIncludeDeviceIdentity };
547
253
  };
548
254
  const relayMessage = async (jid, message, { messageId: msgId, participant, additionalAttributes, additionalNodes, useUserDevicesCache, useCachedGroupMetadata, statusJidList }) => {
549
255
  const meId = authState.creds.me.id;
550
- const meLid = authState.creds.me?.lid;
551
- // ADDRESSING CONSISTENCY: Keep envelope addressing as user provided, handle LID migration in encryption
552
256
  let shouldIncludeDeviceIdentity = false;
553
257
  const { user, server } = jidDecode(jid);
554
258
  const statusJid = 'status@broadcast';
@@ -556,23 +260,11 @@ export const makeMessagesSocket = (config) => {
556
260
  const isStatus = jid === statusJid;
557
261
  const isLid = server === 'lid';
558
262
  const isNewsletter = server === 'newsletter';
559
- // Keep user's original JID choice for envelope addressing
560
- const finalJid = jid;
561
- // ADDRESSING CONSISTENCY: Match own identity to conversation context
562
- // TODO: investigate if this is true
563
- let ownId = meId;
564
- if (isLid && meLid) {
565
- ownId = meLid;
566
- logger.debug({ to: jid, ownId }, 'Using LID identity for @lid conversation');
567
- }
568
- else {
569
- logger.debug({ to: jid, ownId }, 'Using PN identity for @s.whatsapp.net conversation');
570
- }
571
263
  msgId = msgId || generateMessageIDV2(sock.user?.id);
572
264
  useUserDevicesCache = useUserDevicesCache !== false;
573
265
  useCachedGroupMetadata = useCachedGroupMetadata !== false && !isStatus;
574
266
  const participants = [];
575
- const destinationJid = !isStatus ? finalJid : statusJid;
267
+ const destinationJid = !isStatus ? jidEncode(user, isLid ? 'lid' : isGroup ? 'g.us' : 's.whatsapp.net') : statusJid;
576
268
  const binaryNodeContent = [];
577
269
  const devices = [];
578
270
  const meMsg = {
@@ -590,12 +282,8 @@ export const makeMessagesSocket = (config) => {
590
282
  if (!isGroup && !isStatus) {
591
283
  additionalAttributes = { ...additionalAttributes, device_fanout: 'false' };
592
284
  }
593
- const { user, device } = jidDecode(participant.jid); // rajeh: how does this even make sense TODO check out
594
- devices.push({
595
- user,
596
- device,
597
- wireJid: participant.jid // Use the participant JID as wire JID
598
- });
285
+ const { user, device } = jidDecode(participant.jid);
286
+ devices.push({ user, device });
599
287
  }
600
288
  await authState.keys.transaction(async () => {
601
289
  const mediaType = getMediaType(message);
@@ -626,12 +314,12 @@ export const makeMessagesSocket = (config) => {
626
314
  return;
627
315
  }
628
316
  if (normalizeMessageContent(message)?.pinInChatMessage) {
629
- extraAttrs['decrypt-fail'] = 'hide'; // todo: expand for reactions and other types
317
+ extraAttrs['decrypt-fail'] = 'hide';
630
318
  }
631
319
  if (isGroup || isStatus) {
632
320
  const [groupData, senderKeyMap] = await Promise.all([
633
321
  (async () => {
634
- 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?
322
+ let groupData = useCachedGroupMetadata && cachedGroupMetadata ? await cachedGroupMetadata(jid) : undefined;
635
323
  if (groupData && Array.isArray(groupData?.participants)) {
636
324
  logger.trace({ jid, participants: groupData.participants.length }, 'using cached group metadata');
637
325
  }
@@ -642,7 +330,7 @@ export const makeMessagesSocket = (config) => {
642
330
  })(),
643
331
  (async () => {
644
332
  if (!participant && !isStatus) {
645
- 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?
333
+ const result = await authState.keys.get('sender-key-memory', [jid]);
646
334
  return result[jid] || {};
647
335
  }
648
336
  return {};
@@ -654,10 +342,9 @@ export const makeMessagesSocket = (config) => {
654
342
  participantsList.push(...statusJidList);
655
343
  }
656
344
  if (!isStatus) {
657
- const groupAddressingMode = groupData?.addressingMode || (isLid ? WAMessageAddressingMode.LID : WAMessageAddressingMode.PN);
658
345
  additionalAttributes = {
659
346
  ...additionalAttributes,
660
- addressing_mode: groupAddressingMode
347
+ addressing_mode: groupData?.addressingMode || 'pn'
661
348
  };
662
349
  }
663
350
  const additionalDevices = await getUSyncDevices(participantsList, !!useUserDevicesCache, false);
@@ -668,24 +355,19 @@ export const makeMessagesSocket = (config) => {
668
355
  throw new Boom('Per-jid patching is not supported in groups');
669
356
  }
670
357
  const bytes = encodeWAMessage(patched);
671
- // This should match the group's addressing mode and conversation context
672
- const groupAddressingMode = groupData?.addressingMode || (isLid ? 'lid' : 'pn');
673
- const groupSenderIdentity = groupAddressingMode === 'lid' && meLid ? meLid : meId;
674
358
  const { ciphertext, senderKeyDistributionMessage } = await signalRepository.encryptGroupMessage({
675
359
  group: destinationJid,
676
360
  data: bytes,
677
- meId: groupSenderIdentity
361
+ meId
678
362
  });
679
363
  const senderKeyJids = [];
680
364
  // ensure a connection is established with every device
681
- for (const device of devices) {
682
- // This preserves the LID migration results from getUSyncDevices
683
- const deviceJid = device.wireJid;
684
- const hasKey = !!senderKeyMap[deviceJid];
685
- if (!hasKey || !!participant) {
686
- senderKeyJids.push(deviceJid);
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);
687
369
  // store that this person has had the sender keys sent to them
688
- senderKeyMap[deviceJid] = true;
370
+ senderKeyMap[jid] = true;
689
371
  }
690
372
  }
691
373
  // if there are some participants with whom the session has not been established
@@ -711,54 +393,23 @@ export const makeMessagesSocket = (config) => {
711
393
  await authState.keys.set({ 'sender-key-memory': { [jid]: senderKeyMap } });
712
394
  }
713
395
  else {
714
- const { user: ownUser } = jidDecode(ownId);
396
+ const { user: meUser } = jidDecode(meId);
715
397
  if (!participant) {
716
- const targetUserServer = isLid ? 'lid' : 's.whatsapp.net';
717
- devices.push({
718
- user,
719
- device: 0,
720
- wireJid: jidEncode(user, targetUserServer, 0)
721
- });
722
- // Own user matches conversation addressing mode
723
- if (user !== ownUser) {
724
- const ownUserServer = isLid ? 'lid' : 's.whatsapp.net';
725
- const ownUserForAddressing = isLid && meLid ? jidDecode(meLid).user : jidDecode(meId).user;
726
- devices.push({
727
- user: ownUserForAddressing,
728
- device: 0,
729
- wireJid: jidEncode(ownUserForAddressing, ownUserServer, 0)
730
- });
398
+ devices.push({ user });
399
+ if (user !== meUser) {
400
+ devices.push({ user: meUser });
731
401
  }
732
402
  if (additionalAttributes?.['category'] !== 'peer') {
733
- // Clear placeholders and enumerate actual devices
734
- devices.length = 0;
735
- // Use conversation-appropriate sender identity
736
- const senderIdentity = isLid && meLid
737
- ? jidEncode(jidDecode(meLid)?.user, 'lid', undefined)
738
- : jidEncode(jidDecode(meId)?.user, 's.whatsapp.net', undefined);
739
- // Enumerate devices for sender and target with consistent addressing
740
- const sessionDevices = await getUSyncDevices([senderIdentity, jid], false, false);
741
- devices.push(...sessionDevices);
742
- logger.debug({
743
- deviceCount: devices.length,
744
- devices: devices.map(d => `${d.user}:${d.device}@${jidDecode(d.wireJid)?.server}`)
745
- }, 'Device enumeration complete with unified addressing');
403
+ const additionalDevices = await getUSyncDevices([meId, jid], !!useUserDevicesCache, true);
404
+ devices.push(...additionalDevices);
746
405
  }
747
406
  }
748
407
  const allJids = [];
749
408
  const meJids = [];
750
409
  const otherJids = [];
751
- const { user: mePnUser } = jidDecode(meId);
752
- const { user: meLidUser } = meLid ? jidDecode(meLid) : { user: null };
753
- for (const { user, wireJid } of devices) {
754
- const isExactSenderDevice = wireJid === meId || (meLid && wireJid === meLid);
755
- if (isExactSenderDevice) {
756
- logger.debug({ wireJid, meId, meLid }, 'Skipping exact sender device (whatsmeow pattern)');
757
- continue;
758
- }
759
- // Check if this is our device (could match either PN or LID user)
760
- const isMe = user === mePnUser || (meLidUser && user === meLidUser);
761
- const jid = wireJid;
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);
762
413
  if (isMe) {
763
414
  meJids.push(jid);
764
415
  }
@@ -767,17 +418,13 @@ export const makeMessagesSocket = (config) => {
767
418
  }
768
419
  allJids.push(jid);
769
420
  }
770
- await assertSessions([...otherJids, ...meJids], false);
421
+ await assertSessions(allJids, false);
771
422
  const [{ nodes: meNodes, shouldIncludeDeviceIdentity: s1 }, { nodes: otherNodes, shouldIncludeDeviceIdentity: s2 }] = await Promise.all([
772
- // For own devices: use DSM if available (1:1 chats only)
773
- createParticipantNodes(meJids, meMsg || message, extraAttrs),
774
- createParticipantNodes(otherJids, message, extraAttrs, meMsg)
423
+ createParticipantNodes(meJids, meMsg, extraAttrs),
424
+ createParticipantNodes(otherJids, message, extraAttrs)
775
425
  ]);
776
426
  participants.push(...meNodes);
777
427
  participants.push(...otherNodes);
778
- if (meJids.length > 0 || otherJids.length > 0) {
779
- extraAttrs['phash'] = generateParticipantHashV2([...meJids, ...otherJids]);
780
- }
781
428
  shouldIncludeDeviceIdentity = shouldIncludeDeviceIdentity || s1 || s2;
782
429
  }
783
430
  if (participants.length) {
@@ -799,7 +446,6 @@ export const makeMessagesSocket = (config) => {
799
446
  tag: 'message',
800
447
  attrs: {
801
448
  id: msgId,
802
- to: destinationJid,
803
449
  type: getMessageType(message),
804
450
  ...(additionalAttributes || {})
805
451
  },
@@ -839,20 +485,13 @@ export const makeMessagesSocket = (config) => {
839
485
  }
840
486
  logger.debug({ msgId }, `sending message to ${participants.length} devices`);
841
487
  await sendNode(stanza);
842
- // Add message to retry cache if enabled
843
- if (messageRetryManager && !participant) {
844
- messageRetryManager.addRecentMessage(destinationJid, msgId, message);
845
- }
846
- }, meId);
488
+ });
847
489
  return msgId;
848
490
  };
849
491
  const getMessageType = (message) => {
850
492
  if (message.pollCreationMessage || message.pollCreationMessageV2 || message.pollCreationMessageV3) {
851
493
  return 'poll';
852
494
  }
853
- if (message.eventMessage) {
854
- return 'event';
855
- }
856
495
  return 'text';
857
496
  };
858
497
  const getMediaType = (message) => {
@@ -944,7 +583,6 @@ export const makeMessagesSocket = (config) => {
944
583
  sendPeerDataOperationMessage,
945
584
  createParticipantNodes,
946
585
  getUSyncDevices,
947
- messageRetryManager,
948
586
  updateMediaMessage: async (message) => {
949
587
  const content = assertMediaContent(message.message);
950
588
  const mediaKey = content.mediaKey;
@@ -1016,14 +654,12 @@ export const makeMessagesSocket = (config) => {
1016
654
  }),
1017
655
  //TODO: CACHE
1018
656
  getProfilePicUrl: sock.profilePictureUrl,
1019
- getCallLink: sock.createCallLink,
1020
657
  upload: waUploadToServer,
1021
658
  mediaCache: config.mediaCache,
1022
659
  options: config.options,
1023
660
  messageId: generateMessageIDV2(sock.user?.id),
1024
661
  ...options
1025
662
  });
1026
- const isEventMsg = 'event' in content && !!content.event;
1027
663
  const isDeleteMsg = 'delete' in content && !!content.delete;
1028
664
  const isEditMsg = 'edit' in content && !!content.edit;
1029
665
  const isPinMsg = 'pin' in content && !!content.pin;
@@ -1054,14 +690,6 @@ export const makeMessagesSocket = (config) => {
1054
690
  }
1055
691
  });
1056
692
  }
1057
- else if (isEventMsg) {
1058
- additionalNodes.push({
1059
- tag: 'meta',
1060
- attrs: {
1061
- event_type: 'creation'
1062
- }
1063
- });
1064
- }
1065
693
  if ('cachedGroupMetadata' in options) {
1066
694
  console.warn('cachedGroupMetadata in sendMessage are deprecated, now cachedGroupMetadata is part of the socket config.');
1067
695
  }