@fer2809fl/baileys 7.0.2 → 7.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (222) hide show
  1. package/README.md +100 -20
  2. package/lib/Defaults/index.js +2 -1
  3. package/lib/Signal/libsignal.js +19 -0
  4. package/lib/Socket/business.d.ts +213 -532
  5. package/lib/Socket/business.js +359 -401
  6. package/lib/Socket/chats.d.ts +16 -2
  7. package/lib/Socket/chats.js +247 -40
  8. package/lib/Socket/groups.d.ts +16 -0
  9. package/lib/Socket/groups.js +101 -18
  10. package/lib/Socket/messages-recv.js +18 -1
  11. package/lib/Socket/newsletter.js +3 -3
  12. package/lib/Socket/socket.js +50 -6
  13. package/lib/Types/Newsletter.d.ts +13 -4
  14. package/lib/Types/Newsletter.js +12 -2
  15. package/lib/Utils/chat-utils.d.ts +34 -4
  16. package/lib/Utils/chat-utils.js +80 -20
  17. package/lib/Utils/companion-reg-client-utils.d.ts +17 -0
  18. package/lib/Utils/companion-reg-client-utils.js +35 -0
  19. package/lib/Utils/event-buffer.js +49 -1
  20. package/lib/Utils/index.js +1 -0
  21. package/lib/Utils/message-retry-manager.js +40 -0
  22. package/lib/WAUSync/Protocols/USyncUsernameProtocol.d.ts +10 -0
  23. package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +25 -0
  24. package/lib/WAUSync/Protocols/index.js +1 -0
  25. package/lib/WAUSync/USyncQuery.js +5 -1
  26. package/package.json +6 -6
  27. package/lib/Defaults/index.d.ts.map +0 -1
  28. package/lib/Defaults/index.js.map +0 -1
  29. package/lib/Signal/Group/ciphertext-message.d.ts.map +0 -1
  30. package/lib/Signal/Group/ciphertext-message.js.map +0 -1
  31. package/lib/Signal/Group/group-session-builder.d.ts.map +0 -1
  32. package/lib/Signal/Group/group-session-builder.js.map +0 -1
  33. package/lib/Signal/Group/group_cipher.d.ts.map +0 -1
  34. package/lib/Signal/Group/group_cipher.js.map +0 -1
  35. package/lib/Signal/Group/index.d.ts.map +0 -1
  36. package/lib/Signal/Group/index.js.map +0 -1
  37. package/lib/Signal/Group/keyhelper.d.ts.map +0 -1
  38. package/lib/Signal/Group/keyhelper.js.map +0 -1
  39. package/lib/Signal/Group/sender-chain-key.d.ts.map +0 -1
  40. package/lib/Signal/Group/sender-chain-key.js.map +0 -1
  41. package/lib/Signal/Group/sender-key-distribution-message.d.ts.map +0 -1
  42. package/lib/Signal/Group/sender-key-distribution-message.js.map +0 -1
  43. package/lib/Signal/Group/sender-key-message.d.ts.map +0 -1
  44. package/lib/Signal/Group/sender-key-message.js.map +0 -1
  45. package/lib/Signal/Group/sender-key-name.d.ts.map +0 -1
  46. package/lib/Signal/Group/sender-key-name.js.map +0 -1
  47. package/lib/Signal/Group/sender-key-record.d.ts.map +0 -1
  48. package/lib/Signal/Group/sender-key-record.js.map +0 -1
  49. package/lib/Signal/Group/sender-key-state.d.ts.map +0 -1
  50. package/lib/Signal/Group/sender-key-state.js.map +0 -1
  51. package/lib/Signal/Group/sender-message-key.d.ts.map +0 -1
  52. package/lib/Signal/Group/sender-message-key.js.map +0 -1
  53. package/lib/Signal/libsignal.d.ts.map +0 -1
  54. package/lib/Signal/libsignal.js.map +0 -1
  55. package/lib/Signal/lid-mapping.d.ts.map +0 -1
  56. package/lib/Signal/lid-mapping.js.map +0 -1
  57. package/lib/Socket/Client/index.d.ts.map +0 -1
  58. package/lib/Socket/Client/index.js.map +0 -1
  59. package/lib/Socket/Client/types.d.ts.map +0 -1
  60. package/lib/Socket/Client/types.js.map +0 -1
  61. package/lib/Socket/Client/websocket.d.ts.map +0 -1
  62. package/lib/Socket/Client/websocket.js.map +0 -1
  63. package/lib/Socket/business.d.ts.map +0 -1
  64. package/lib/Socket/business.js.map +0 -1
  65. package/lib/Socket/chats.d.ts.map +0 -1
  66. package/lib/Socket/chats.js.map +0 -1
  67. package/lib/Socket/communities.d.ts.map +0 -1
  68. package/lib/Socket/communities.js.map +0 -1
  69. package/lib/Socket/dugong.d.ts.map +0 -1
  70. package/lib/Socket/dugong.js.map +0 -1
  71. package/lib/Socket/groups.d.ts.map +0 -1
  72. package/lib/Socket/groups.js.map +0 -1
  73. package/lib/Socket/index.d.ts.map +0 -1
  74. package/lib/Socket/index.js.map +0 -1
  75. package/lib/Socket/messages-recv.d.ts.map +0 -1
  76. package/lib/Socket/messages-recv.js.map +0 -1
  77. package/lib/Socket/messages-send.d.ts.map +0 -1
  78. package/lib/Socket/messages-send.js.map +0 -1
  79. package/lib/Socket/mex.d.ts.map +0 -1
  80. package/lib/Socket/mex.js.map +0 -1
  81. package/lib/Socket/newsletter.d.ts.map +0 -1
  82. package/lib/Socket/newsletter.js.map +0 -1
  83. package/lib/Socket/socket.d.ts.map +0 -1
  84. package/lib/Socket/socket.js.map +0 -1
  85. package/lib/Types/Auth.d.ts.map +0 -1
  86. package/lib/Types/Auth.js.map +0 -1
  87. package/lib/Types/Bussines.d.ts.map +0 -1
  88. package/lib/Types/Bussines.js.map +0 -1
  89. package/lib/Types/Call.d.ts.map +0 -1
  90. package/lib/Types/Call.js.map +0 -1
  91. package/lib/Types/Chat.d.ts.map +0 -1
  92. package/lib/Types/Chat.js.map +0 -1
  93. package/lib/Types/Contact.d.ts.map +0 -1
  94. package/lib/Types/Contact.js.map +0 -1
  95. package/lib/Types/Events.d.ts.map +0 -1
  96. package/lib/Types/Events.js.map +0 -1
  97. package/lib/Types/GroupMetadata.d.ts.map +0 -1
  98. package/lib/Types/GroupMetadata.js.map +0 -1
  99. package/lib/Types/Label.d.ts.map +0 -1
  100. package/lib/Types/Label.js.map +0 -1
  101. package/lib/Types/LabelAssociation.d.ts.map +0 -1
  102. package/lib/Types/LabelAssociation.js.map +0 -1
  103. package/lib/Types/Message.d.ts.map +0 -1
  104. package/lib/Types/Message.js.map +0 -1
  105. package/lib/Types/Newsletter.d.ts.map +0 -1
  106. package/lib/Types/Newsletter.js.map +0 -1
  107. package/lib/Types/Product.d.ts.map +0 -1
  108. package/lib/Types/Product.js.map +0 -1
  109. package/lib/Types/Signal.d.ts.map +0 -1
  110. package/lib/Types/Signal.js.map +0 -1
  111. package/lib/Types/Socket.d.ts.map +0 -1
  112. package/lib/Types/Socket.js.map +0 -1
  113. package/lib/Types/State.d.ts.map +0 -1
  114. package/lib/Types/State.js.map +0 -1
  115. package/lib/Types/USync.d.ts.map +0 -1
  116. package/lib/Types/USync.js.map +0 -1
  117. package/lib/Types/index.d.ts.map +0 -1
  118. package/lib/Types/index.js.map +0 -1
  119. package/lib/Utils/auth-utils.d.ts.map +0 -1
  120. package/lib/Utils/auth-utils.js.map +0 -1
  121. package/lib/Utils/browser-utils.d.ts.map +0 -1
  122. package/lib/Utils/browser-utils.js.map +0 -1
  123. package/lib/Utils/business.d.ts.map +0 -1
  124. package/lib/Utils/business.js.map +0 -1
  125. package/lib/Utils/chat-utils.d.ts.map +0 -1
  126. package/lib/Utils/chat-utils.js.map +0 -1
  127. package/lib/Utils/crypto.d.ts.map +0 -1
  128. package/lib/Utils/crypto.js.map +0 -1
  129. package/lib/Utils/decode-wa-message.d.ts.map +0 -1
  130. package/lib/Utils/decode-wa-message.js.map +0 -1
  131. package/lib/Utils/event-buffer.d.ts.map +0 -1
  132. package/lib/Utils/event-buffer.js.map +0 -1
  133. package/lib/Utils/generics.d.ts.map +0 -1
  134. package/lib/Utils/generics.js.map +0 -1
  135. package/lib/Utils/history.d.ts.map +0 -1
  136. package/lib/Utils/history.js.map +0 -1
  137. package/lib/Utils/identity-change-handler.d.ts.map +0 -1
  138. package/lib/Utils/identity-change-handler.js.map +0 -1
  139. package/lib/Utils/index.d.ts.map +0 -1
  140. package/lib/Utils/index.js.map +0 -1
  141. package/lib/Utils/link-preview.d.ts.map +0 -1
  142. package/lib/Utils/link-preview.js.map +0 -1
  143. package/lib/Utils/logger.d.ts.map +0 -1
  144. package/lib/Utils/logger.js.map +0 -1
  145. package/lib/Utils/lt-hash.d.ts.map +0 -1
  146. package/lib/Utils/lt-hash.js.map +0 -1
  147. package/lib/Utils/make-mutex.d.ts.map +0 -1
  148. package/lib/Utils/make-mutex.js.map +0 -1
  149. package/lib/Utils/message-retry-manager.d.ts.map +0 -1
  150. package/lib/Utils/message-retry-manager.js.map +0 -1
  151. package/lib/Utils/messages-media.d.ts.map +0 -1
  152. package/lib/Utils/messages-media.js.map +0 -1
  153. package/lib/Utils/messages.d.ts.map +0 -1
  154. package/lib/Utils/messages.js.map +0 -1
  155. package/lib/Utils/noise-handler.d.ts.map +0 -1
  156. package/lib/Utils/noise-handler.js.map +0 -1
  157. package/lib/Utils/offline-node-processor.d.ts.map +0 -1
  158. package/lib/Utils/offline-node-processor.js.map +0 -1
  159. package/lib/Utils/pre-key-manager.d.ts.map +0 -1
  160. package/lib/Utils/pre-key-manager.js.map +0 -1
  161. package/lib/Utils/process-message.d.ts.map +0 -1
  162. package/lib/Utils/process-message.js.map +0 -1
  163. package/lib/Utils/reporting-utils.d.ts.map +0 -1
  164. package/lib/Utils/reporting-utils.js.map +0 -1
  165. package/lib/Utils/rich-messages.d.ts.map +0 -1
  166. package/lib/Utils/rich-messages.js.map +0 -1
  167. package/lib/Utils/signal.d.ts.map +0 -1
  168. package/lib/Utils/signal.js.map +0 -1
  169. package/lib/Utils/stanza-ack.d.ts.map +0 -1
  170. package/lib/Utils/stanza-ack.js.map +0 -1
  171. package/lib/Utils/sync-action-utils.d.ts.map +0 -1
  172. package/lib/Utils/sync-action-utils.js.map +0 -1
  173. package/lib/Utils/tc-token-utils.d.ts.map +0 -1
  174. package/lib/Utils/tc-token-utils.js.map +0 -1
  175. package/lib/Utils/use-multi-file-auth-state.d.ts.map +0 -1
  176. package/lib/Utils/use-multi-file-auth-state.js.map +0 -1
  177. package/lib/Utils/validate-connection.d.ts.map +0 -1
  178. package/lib/Utils/validate-connection.js.map +0 -1
  179. package/lib/WABinary/constants.d.ts.map +0 -1
  180. package/lib/WABinary/constants.js.map +0 -1
  181. package/lib/WABinary/decode.d.ts.map +0 -1
  182. package/lib/WABinary/decode.js.map +0 -1
  183. package/lib/WABinary/encode.d.ts.map +0 -1
  184. package/lib/WABinary/encode.js.map +0 -1
  185. package/lib/WABinary/generic-utils.d.ts.map +0 -1
  186. package/lib/WABinary/generic-utils.js.map +0 -1
  187. package/lib/WABinary/index.d.ts.map +0 -1
  188. package/lib/WABinary/index.js.map +0 -1
  189. package/lib/WABinary/jid-utils.d.ts.map +0 -1
  190. package/lib/WABinary/jid-utils.js.map +0 -1
  191. package/lib/WABinary/types.d.ts.map +0 -1
  192. package/lib/WABinary/types.js.map +0 -1
  193. package/lib/WAM/BinaryInfo.d.ts.map +0 -1
  194. package/lib/WAM/BinaryInfo.js.map +0 -1
  195. package/lib/WAM/constants.d.ts.map +0 -1
  196. package/lib/WAM/constants.js.map +0 -1
  197. package/lib/WAM/encode.d.ts.map +0 -1
  198. package/lib/WAM/encode.js.map +0 -1
  199. package/lib/WAM/index.d.ts.map +0 -1
  200. package/lib/WAM/index.js.map +0 -1
  201. package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts.map +0 -1
  202. package/lib/WAUSync/Protocols/USyncContactProtocol.js.map +0 -1
  203. package/lib/WAUSync/Protocols/USyncDeviceProtocol.d.ts.map +0 -1
  204. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js.map +0 -1
  205. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts.map +0 -1
  206. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js.map +0 -1
  207. package/lib/WAUSync/Protocols/USyncStatusProtocol.d.ts.map +0 -1
  208. package/lib/WAUSync/Protocols/USyncStatusProtocol.js.map +0 -1
  209. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.d.ts.map +0 -1
  210. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js.map +0 -1
  211. package/lib/WAUSync/Protocols/UsyncLIDProtocol.d.ts.map +0 -1
  212. package/lib/WAUSync/Protocols/UsyncLIDProtocol.js.map +0 -1
  213. package/lib/WAUSync/Protocols/index.d.ts.map +0 -1
  214. package/lib/WAUSync/Protocols/index.js.map +0 -1
  215. package/lib/WAUSync/USyncQuery.d.ts.map +0 -1
  216. package/lib/WAUSync/USyncQuery.js.map +0 -1
  217. package/lib/WAUSync/USyncUser.d.ts.map +0 -1
  218. package/lib/WAUSync/USyncUser.js.map +0 -1
  219. package/lib/WAUSync/index.d.ts.map +0 -1
  220. package/lib/WAUSync/index.js.map +0 -1
  221. package/lib/index.d.ts.map +0 -1
  222. package/lib/index.js.map +0 -1
@@ -1,11 +1,13 @@
1
+ import { Boom } from '@hapi/boom';
1
2
  import { proto } from '../../WAProto/index.js';
2
3
  import { WAMessageAddressingMode, WAMessageStubType } from '../Types/index.js';
3
4
  import { generateMessageIDV2, unixTimestampSeconds } from '../Utils/index.js';
4
5
  import { getBinaryNodeChild, getBinaryNodeChildren, getBinaryNodeChildString, isLidUser, isPnUser, jidEncode, jidNormalizedUser } from '../WABinary/index.js';
5
6
  import { makeChatsSocket } from './chats.js';
7
+ const GROUP_METADATA_CACHE_TTL_MS = 30_000;
6
8
  export const makeGroupsSocket = (config) => {
7
9
  const sock = makeChatsSocket(config);
8
- const { authState, ev, query, upsertMessage } = sock;
10
+ const { authState, ev, query, upsertMessage, signalRepository, logger } = sock;
9
11
  const groupQuery = async (jid, type, content) => query({
10
12
  tag: 'iq',
11
13
  attrs: {
@@ -19,6 +21,82 @@ export const makeGroupsSocket = (config) => {
19
21
  const result = await groupQuery(jid, 'get', [{ tag: 'query', attrs: { request: 'interactive' } }]);
20
22
  return extractGroupMetadata(result);
21
23
  };
24
+ const groupMetadataCache = new Map();
25
+ const invalidateGroupMetadataCache = (jid) => {
26
+ if (jid)
27
+ groupMetadataCache.delete(jid);
28
+ else
29
+ groupMetadataCache.clear();
30
+ };
31
+ ev.on('group-participants.update', ({ id }) => invalidateGroupMetadataCache(id));
32
+ ev.on('groups.update', updates => {
33
+ for (const update of updates) {
34
+ if (update?.id)
35
+ invalidateGroupMetadataCache(update.id);
36
+ }
37
+ });
38
+ /**
39
+ * groupMetadata con cache corto (30s) para evitar golpear WhatsApp en checks repetidos
40
+ * (ej. isGroupAdmin llamado por cada mensaje). Se invalida automáticamente ante cualquier
41
+ * cambio real de participantes.
42
+ */
43
+ const groupMetadataCached = async (jid) => {
44
+ const cached = groupMetadataCache.get(jid);
45
+ if (cached && cached.expiresAt > Date.now()) {
46
+ return cached.data;
47
+ }
48
+ const data = await groupMetadata(jid);
49
+ groupMetadataCache.set(jid, { data, expiresAt: Date.now() + GROUP_METADATA_CACHE_TTL_MS });
50
+ return data;
51
+ };
52
+ /**
53
+ * Resuelve un jid (que puede venir como @lid) a su jid de número de teléfono real.
54
+ */
55
+ const resolveParticipantJid = async (jidOrChatId, targetJid) => {
56
+ if (!targetJid)
57
+ return targetJid;
58
+ const normalized = jidNormalizedUser(targetJid);
59
+ if (!isLidUser(normalized))
60
+ return normalized;
61
+ const participants = Array.isArray(jidOrChatId) ? jidOrChatId : (await groupMetadataCached(jidOrChatId)).participants;
62
+ const match = participants.find(p => jidNormalizedUser(p.id) === normalized || (p.lid && jidNormalizedUser(p.lid) === normalized));
63
+ if (match?.phoneNumber)
64
+ return jidNormalizedUser(match.phoneNumber);
65
+ if (match?.jid && !isLidUser(match.jid))
66
+ return jidNormalizedUser(match.jid);
67
+ try {
68
+ const pn = await signalRepository.lidMapping.getPNForLID(normalized);
69
+ if (pn)
70
+ return jidNormalizedUser(pn);
71
+ }
72
+ catch (err) {
73
+ logger.trace({ err, jid: normalized }, 'no se pudo resolver LID a PN via signalRepository');
74
+ }
75
+ return normalized;
76
+ };
77
+ /** true si el jid (número o @lid) es admin/superadmin del grupo. */
78
+ const isGroupAdmin = async (jid, participantJid) => {
79
+ if (!participantJid)
80
+ return false;
81
+ const normalized = jidNormalizedUser(participantJid);
82
+ const meta = await groupMetadataCached(jid);
83
+ const participant = meta.participants.find(p => {
84
+ const pid = jidNormalizedUser(p.id);
85
+ return (pid === normalized ||
86
+ (p.lid && jidNormalizedUser(p.lid) === normalized) ||
87
+ (p.phoneNumber && jidNormalizedUser(p.phoneNumber) === normalized));
88
+ });
89
+ return participant?.admin === 'admin' || participant?.admin === 'superadmin';
90
+ };
91
+ /** Lista de admins del grupo ya resueltos a jid de número de teléfono (no @lid). */
92
+ const getGroupAdmins = async (jid) => {
93
+ const meta = await groupMetadataCached(jid);
94
+ const admins = meta.participants.filter(p => p.admin === 'admin' || p.admin === 'superadmin');
95
+ return Promise.all(admins.map(async (p) => ({
96
+ jid: await resolveParticipantJid(meta.participants, p.id),
97
+ admin: p.admin
98
+ })));
99
+ };
22
100
  const groupFetchAllParticipating = async () => {
23
101
  const result = await query({
24
102
  tag: 'iq',
@@ -66,6 +144,10 @@ export const makeGroupsSocket = (config) => {
66
144
  return {
67
145
  ...sock,
68
146
  groupMetadata,
147
+ groupMetadataCached,
148
+ resolveParticipantJid,
149
+ isGroupAdmin,
150
+ getGroupAdmins,
69
151
  groupCreate: async (subject, participants) => {
70
152
  const key = generateMessageIDV2();
71
153
  const result = await groupQuery('@g.us', 'set', [
@@ -182,23 +264,12 @@ export const makeGroupsSocket = (config) => {
182
264
  const result = getBinaryNodeChild(results, 'group');
183
265
  return result?.attrs.jid;
184
266
  },
185
- /**
186
- * revoke a v4 invite for someone
187
- * @param groupJid group jid
188
- * @param invitedJid jid of person you invited
189
- * @returns true if successful
190
- */
191
267
  groupRevokeInviteV4: async (groupJid, invitedJid) => {
192
268
  const result = await groupQuery(groupJid, 'set', [
193
269
  { tag: 'revoke', attrs: {}, content: [{ tag: 'participant', attrs: { jid: invitedJid } }] }
194
270
  ]);
195
271
  return !!result;
196
272
  },
197
- /**
198
- * accept a GroupInviteMessage
199
- * @param key the key of the invite message, or optionally only provide the jid of the person who sent the invite
200
- * @param inviteMessage the message to accept
201
- */
202
273
  groupAcceptInviteV4: ev.createBufferedFunction(async (key, inviteMessage) => {
203
274
  key = typeof key === 'string' ? { remoteJid: key } : key;
204
275
  const results = await groupQuery(inviteMessage.groupJid, 'set', [
@@ -211,10 +282,7 @@ export const makeGroupsSocket = (config) => {
211
282
  }
212
283
  }
213
284
  ]);
214
- // if we have the full message key
215
- // update the invite message to be expired
216
285
  if (key.id) {
217
- // create new invite message that is expired
218
286
  inviteMessage = proto.Message.GroupInviteMessage.fromObject(inviteMessage);
219
287
  inviteMessage.inviteExpiration = 0;
220
288
  inviteMessage.inviteCode = '';
@@ -229,7 +297,6 @@ export const makeGroupsSocket = (config) => {
229
297
  }
230
298
  ]);
231
299
  }
232
- // generate the group add message
233
300
  await upsertMessage({
234
301
  key: {
235
302
  remoteJid: inviteMessage.groupJid,
@@ -270,16 +337,30 @@ export const makeGroupsSocket = (config) => {
270
337
  };
271
338
  export const extractGroupMetadata = (result) => {
272
339
  const group = getBinaryNodeChild(result, 'group');
340
+ if (!group) {
341
+ const errorNode = getBinaryNodeChild(result, 'error');
342
+ if (errorNode) {
343
+ const code = errorNode.attrs.code ? +errorNode.attrs.code : 500;
344
+ const text = errorNode.attrs.text || 'group metadata query failed';
345
+ throw new Boom(text, { statusCode: code, data: errorNode });
346
+ }
347
+ throw new Boom('Invalid group metadata response: missing <group> node', { data: result });
348
+ }
349
+ if (!group.attrs.id) {
350
+ throw new Boom('Invalid group metadata response: missing group id', { data: group });
351
+ }
273
352
  const descChild = getBinaryNodeChild(group, 'description');
274
353
  let desc;
275
354
  let descId;
276
355
  let descOwner;
277
356
  let descOwnerPn;
357
+ let descOwnerUsername;
278
358
  let descTime;
279
359
  if (descChild) {
280
360
  desc = getBinaryNodeChildString(descChild, 'body');
281
361
  descOwner = descChild.attrs.participant ? jidNormalizedUser(descChild.attrs.participant) : undefined;
282
362
  descOwnerPn = descChild.attrs.participant_pn ? jidNormalizedUser(descChild.attrs.participant_pn) : undefined;
363
+ descOwnerUsername = descChild.attrs.participant_username || undefined;
283
364
  descTime = +descChild.attrs.t;
284
365
  descId = descChild.attrs.id;
285
366
  }
@@ -293,16 +374,19 @@ export const extractGroupMetadata = (result) => {
293
374
  subject: group.attrs.subject,
294
375
  subjectOwner: group.attrs.s_o,
295
376
  subjectOwnerPn: group.attrs.s_o_pn,
377
+ subjectOwnerUsername: group.attrs.s_o_username,
296
378
  subjectTime: +group.attrs.s_t,
297
379
  size: group.attrs.size ? +group.attrs.size : getBinaryNodeChildren(group, 'participant').length,
298
380
  creation: +group.attrs.creation,
299
381
  owner: group.attrs.creator ? jidNormalizedUser(group.attrs.creator) : undefined,
300
382
  ownerPn: group.attrs.creator_pn ? jidNormalizedUser(group.attrs.creator_pn) : undefined,
383
+ ownerUsername: group.attrs.creator_username || undefined,
301
384
  owner_country_code: group.attrs.creator_country_code,
302
385
  desc,
303
386
  descId,
304
387
  descOwner,
305
388
  descOwnerPn,
389
+ descOwnerUsername,
306
390
  descTime,
307
391
  linkedParent: getBinaryNodeChild(group, 'linked_parent')?.attrs.jid || undefined,
308
392
  restrict: !!getBinaryNodeChild(group, 'locked'),
@@ -314,9 +398,9 @@ export const extractGroupMetadata = (result) => {
314
398
  participants: getBinaryNodeChildren(group, 'participant').map(({ attrs }) => {
315
399
  return {
316
400
  id: attrs.jid,
317
- jid: attrs.phone_number || attrs.jid,
318
401
  phoneNumber: isLidUser(attrs.jid) && isPnUser(attrs.phone_number) ? attrs.phone_number : undefined,
319
402
  lid: isPnUser(attrs.jid) && isLidUser(attrs.lid) ? attrs.lid : undefined,
403
+ username: attrs.participant_username || attrs.username || undefined,
320
404
  admin: (attrs.type || null)
321
405
  };
322
406
  }),
@@ -324,4 +408,3 @@ export const extractGroupMetadata = (result) => {
324
408
  };
325
409
  return metadata;
326
410
  };
327
- //# sourceMappingURL=groups.js.map
@@ -764,9 +764,26 @@ export const makeMessagesRecvSocket = (config) => {
764
764
  // Check if we should recreate session for this retry
765
765
  let shouldRecreateSession = false;
766
766
  let recreateReason = '';
767
+ const sessionId = signalRepository.jidToSignalProtocolAddress(participant);
768
+ const BASE_KEY_CHECK_RETRY = 2;
769
+ const primaryMsgId = ids[0];
770
+ if (primaryMsgId && messageRetryManager) {
771
+ const baseKeyInfo = await signalRepository.getSessionInfo(participant);
772
+ if (baseKeyInfo) {
773
+ if (retryCount === BASE_KEY_CHECK_RETRY) {
774
+ messageRetryManager.saveBaseKey(sessionId, primaryMsgId, baseKeyInfo.baseKey);
775
+ }
776
+ else if (retryCount > BASE_KEY_CHECK_RETRY) {
777
+ if (messageRetryManager.hasSameBaseKey(sessionId, primaryMsgId, baseKeyInfo.baseKey)) {
778
+ logger.warn({ participant, retryCount }, 'base key collision on retry, forcing fresh session');
779
+ await authState.keys.set({ session: { [sessionId]: null } });
780
+ }
781
+ messageRetryManager.deleteBaseKey(sessionId, primaryMsgId);
782
+ }
783
+ }
784
+ }
767
785
  if (enableAutoSessionRecreation && messageRetryManager && retryCount > 1) {
768
786
  try {
769
- const sessionId = signalRepository.jidToSignalProtocolAddress(participant);
770
787
  const hasSession = await signalRepository.validateSession(participant);
771
788
  const result = messageRetryManager.shouldRecreateSession(participant, hasSession.exists);
772
789
  shouldRecreateSession = result.recreate;
@@ -200,7 +200,7 @@ export const makeNewsletterSocket = (config) => {
200
200
  await executeWMexQuery(
201
201
  { newsletter_id: id },
202
202
  QueryIds.FOLLOW,
203
- XWAPaths.xwa2_newsletter_follow,
203
+ XWAPaths.xwa2_newsletter_join_v2,
204
204
  );
205
205
  await new Promise((resolve) => setTimeout(resolve, 550));
206
206
  }
@@ -297,14 +297,14 @@ export const makeNewsletterSocket = (config) => {
297
297
  return executeWMexQuery(
298
298
  { newsletter_id: jid },
299
299
  QueryIds.FOLLOW,
300
- XWAPaths.xwa2_newsletter_follow,
300
+ XWAPaths.xwa2_newsletter_join_v2,
301
301
  );
302
302
  },
303
303
  newsletterUnfollow: (jid) => {
304
304
  return executeWMexQuery(
305
305
  { newsletter_id: jid },
306
306
  QueryIds.UNFOLLOW,
307
- XWAPaths.xwa2_newsletter_unfollow,
307
+ XWAPaths.xwa2_newsletter_leave_v2,
308
308
  );
309
309
  },
310
310
  newsletterMute: (jid) => {
@@ -4,13 +4,14 @@ import { URL } from 'url';
4
4
  import { promisify } from 'util';
5
5
  import { proto } from '../../WAProto/index.js';
6
6
  import { DEF_CALLBACK_PREFIX, DEF_TAG_PREFIX, INITIAL_PREKEY_COUNT, MIN_PREKEY_COUNT, MIN_UPLOAD_INTERVAL, NOISE_WA_HEADER, PROCESSABLE_HISTORY_TYPES, TimeMs, UPLOAD_TIMEOUT } from '../Defaults/index.js';
7
- import { DisconnectReason } from '../Types/index.js';
8
- import { addTransactionCapability, aesEncryptCTR, bindWaitForConnectionUpdate, bytesToCrockford, configureSuccessfulPairing, Curve, derivePairingCodeKey, generateLoginNode, generateMdTagPrefix, generateRegistrationNode, getCodeFromWSError, getErrorCodeFromStreamError, getNextPreKeysNode, makeEventBuffer, makeNoiseHandler, promiseTimeout, signedKeyPair, xmppSignedPreKey } from '../Utils/index.js';
9
- import { getPlatformId } from '../Utils/browser-utils.js';
7
+ import { QueryIds, ReachoutTimelockEnforcementType } from '../Types/index.js';
8
+ import { DisconnectReason, XWAPaths } from '../Types/index.js';
9
+ import { addTransactionCapability, aesEncryptCTR, bindWaitForConnectionUpdate, buildPairingQRData, bytesToCrockford, configureSuccessfulPairing, Curve, derivePairingCodeKey, generateLoginNode, generateMdTagPrefix, generateRegistrationNode, getCodeFromWSError, getCompanionPlatformId, getErrorCodeFromStreamError, getNextPreKeysNode, makeEventBuffer, makeNoiseHandler, promiseTimeout, signedKeyPair, xmppSignedPreKey } from '../Utils/index.js';
10
10
  import { assertNodeErrorFree, binaryNodeToString, encodeBinaryNode, getAllBinaryNodeChildren, getBinaryNodeChild, getBinaryNodeChildren, isLidUser, jidDecode, jidEncode, S_WHATSAPP_NET } from '../WABinary/index.js';
11
11
  import { BinaryInfo } from '../WAM/BinaryInfo.js';
12
12
  import { USyncQuery, USyncUser } from '../WAUSync/index.js';
13
13
  import { WebSocketClient } from './Client/index.js';
14
+ import { executeWMexQuery } from './mex.js';
14
15
  /**
15
16
  * Connects to WA servers and performs:
16
17
  * - simple queries (no retry mechanism, wait for connection establishment)
@@ -26,6 +27,9 @@ export const makeSocket = (config) => {
26
27
  if (printQRInTerminal) {
27
28
  logger.warn({}, '⚠️ The printQRInTerminal option has been deprecated. You will no longer receive QR codes in the terminal automatically. Please listen to the connection.update event yourself and handle the QR your way. You can remove this message by removing this opttion. This message will be removed in a future version.');
28
29
  }
30
+ if (browser[1].toLocaleLowerCase().includes('android')) {
31
+ logger.warn('⚠️ Using the Android browser is experimental and may lead to unexpected behavior. Use at your own risk.');
32
+ }
29
33
  const syncDisabled = PROCESSABLE_HISTORY_TYPES.map(syncType => config.shouldSyncHistoryMessage({ syncType })).filter(x => x === false)
30
34
  .length === PROCESSABLE_HISTORY_TYPES.length;
31
35
  if (syncDisabled) {
@@ -270,6 +274,7 @@ export const makeSocket = (config) => {
270
274
  let keepAliveReq;
271
275
  let qrTimer;
272
276
  let closed = false;
277
+ const socketEndHandlers = [];
273
278
  /** log & process any unexpected errors */
274
279
  const onUnexpectedError = (err, msg) => {
275
280
  logger.error({ err }, `unexpected error in '${msg}'`);
@@ -411,6 +416,32 @@ export const makeSocket = (config) => {
411
416
  const exists = !!preKeys[currentPreKeyId.toString()];
412
417
  return { exists, currentPreKeyId };
413
418
  };
419
+ const registerSocketEndHandler = (handler) => {
420
+ socketEndHandlers.push(handler);
421
+ };
422
+ /**
423
+ * Fetches your account's standing when it comes to restrictions.
424
+ * @returns Returns the state of the restrictions.
425
+ */
426
+ const fetchAccountReachoutTimelock = async () => {
427
+ const queryResult = await executeWMexQuery({}, QueryIds.REACHOUT_TIMELOCK, XWAPaths.xwa2_fetch_account_reachout_timelock, query, generateMessageTag);
428
+ const result = {
429
+ isActive: !!queryResult?.is_active,
430
+ timeEnforcementEnds: queryResult?.time_enforcement_ends && queryResult?.time_enforcement_ends !== '0'
431
+ ? new Date(parseInt(queryResult.time_enforcement_ends, 10) * 1000)
432
+ : undefined,
433
+ enforcementType: queryResult?.enforcement_type ?? ReachoutTimelockEnforcementType.DEFAULT
434
+ };
435
+ ev.emit('connection.update', { reachoutTimeLock: result });
436
+ return result;
437
+ };
438
+ /**
439
+ * Fetches your account's new chat limits.
440
+ * @returns Returns the quota and the usage.
441
+ */
442
+ const fetchNewChatMessageCap = async () => {
443
+ return executeWMexQuery({ input: { type: 'INDIVIDUAL_NEW_CHAT_MSG' } }, QueryIds.MESSAGE_CAPPING_INFO, XWAPaths.xwa2_message_capping_info, query, generateMessageTag);
444
+ };
414
445
  const uploadPreKeysToServerIfRequired = async () => {
415
446
  try {
416
447
  let count = 0;
@@ -486,12 +517,21 @@ export const makeSocket = (config) => {
486
517
  ws.removeAllListeners('close');
487
518
  ws.removeAllListeners('open');
488
519
  ws.removeAllListeners('message');
520
+ signalRepository.close?.();
489
521
  if (!ws.isClosed && !ws.isClosing) {
490
522
  try {
491
523
  await ws.close();
492
524
  }
493
525
  catch { }
494
526
  }
527
+ for (const handler of socketEndHandlers) {
528
+ try {
529
+ await handler(error);
530
+ }
531
+ catch (err) {
532
+ logger.error({ err }, 'error in socket end handler');
533
+ }
534
+ }
495
535
  ev.emit('connection.update', {
496
536
  connection: 'close',
497
537
  lastDisconnect: {
@@ -500,6 +540,7 @@ export const makeSocket = (config) => {
500
540
  }
501
541
  });
502
542
  ev.removeAllListeners('connection.update');
543
+ ev.destroy();
503
544
  };
504
545
  const waitForSocketOpen = async () => {
505
546
  if (ws.isOpen) {
@@ -629,7 +670,7 @@ export const makeSocket = (config) => {
629
670
  {
630
671
  tag: 'companion_platform_id',
631
672
  attrs: {},
632
- content: getPlatformId(browser[1])
673
+ content: getCompanionPlatformId(browser)
633
674
  },
634
675
  {
635
676
  tag: 'companion_platform_display',
@@ -712,7 +753,7 @@ export const makeSocket = (config) => {
712
753
  return;
713
754
  }
714
755
  const ref = refNode.content.toString('utf-8');
715
- const qr = [ref, noiseKeyB64, identityKeyB64, advB64].join(',');
756
+ const qr = buildPairingQRData(ref, noiseKeyB64, identityKeyB64, advB64, browser);
716
757
  ev.emit('connection.update', { qr });
717
758
  qrTimer = setTimeout(genPairQR, qrMs);
718
759
  qrMs = qrTimeout || 20000; // shorter subsequent qrs
@@ -921,7 +962,10 @@ export const makeSocket = (config) => {
921
962
  waitForConnectionUpdate: bindWaitForConnectionUpdate(ev),
922
963
  sendWAMBuffer,
923
964
  executeUSyncQuery,
924
- onWhatsApp
965
+ registerSocketEndHandler,
966
+ onWhatsApp,
967
+ fetchAccountReachoutTimelock,
968
+ fetchNewChatMessageCap
925
969
  };
926
970
  };
927
971
  /**
@@ -8,23 +8,32 @@ export declare enum XWAPaths {
8
8
  xwa2_newsletter_unmute_v2 = "xwa2_newsletter_unmute_v2",
9
9
  xwa2_newsletter_follow = "xwa2_newsletter_follow",
10
10
  xwa2_newsletter_unfollow = "xwa2_newsletter_unfollow",
11
+ xwa2_newsletter_join_v2 = "xwa2_newsletter_join_v2",
12
+ xwa2_newsletter_leave_v2 = "xwa2_newsletter_leave_v2",
11
13
  xwa2_newsletter_change_owner = "xwa2_newsletter_change_owner",
12
14
  xwa2_newsletter_demote = "xwa2_newsletter_demote",
13
- xwa2_newsletter_delete_v2 = "xwa2_newsletter_delete_v2"
15
+ xwa2_newsletter_delete_v2 = "xwa2_newsletter_delete_v2",
16
+ xwa2_fetch_account_reachout_timelock = "xwa2_fetch_account_reachout_timelock",
17
+ xwa2_message_capping_info = "xwa2_message_capping_info"
18
+ }
19
+ export declare enum ReachoutTimelockEnforcementType {
20
+ DEFAULT = "DEFAULT"
14
21
  }
15
22
  export declare enum QueryIds {
16
23
  CREATE = "8823471724422422",
17
24
  UPDATE_METADATA = "24250201037901610",
18
25
  METADATA = "6563316087068696",
19
26
  SUBSCRIBERS = "9783111038412085",
20
- FOLLOW = "7871414976211147",
21
- UNFOLLOW = "7238632346214362",
27
+ FOLLOW = "24404358912487870",
28
+ UNFOLLOW = "9767147403369991",
22
29
  MUTE = "29766401636284406",
23
30
  UNMUTE = "9864994326891137",
24
31
  ADMIN_COUNT = "7130823597031706",
25
32
  CHANGE_OWNER = "7341777602580933",
26
33
  DEMOTE = "6551828931592903",
27
- DELETE = "30062808666639665"
34
+ DELETE = "30062808666639665",
35
+ REACHOUT_TIMELOCK = "23983697327930364",
36
+ MESSAGE_CAPPING_INFO = "24503548349331633"
28
37
  }
29
38
  export type NewsletterUpdate = {
30
39
  name?: string;
@@ -9,23 +9,33 @@ export var XWAPaths;
9
9
  XWAPaths["xwa2_newsletter_unmute_v2"] = "xwa2_newsletter_unmute_v2";
10
10
  XWAPaths["xwa2_newsletter_follow"] = "xwa2_newsletter_follow";
11
11
  XWAPaths["xwa2_newsletter_unfollow"] = "xwa2_newsletter_unfollow";
12
+ XWAPaths["xwa2_newsletter_join_v2"] = "xwa2_newsletter_join_v2";
13
+ XWAPaths["xwa2_newsletter_leave_v2"] = "xwa2_newsletter_leave_v2";
12
14
  XWAPaths["xwa2_newsletter_change_owner"] = "xwa2_newsletter_change_owner";
13
15
  XWAPaths["xwa2_newsletter_demote"] = "xwa2_newsletter_demote";
14
16
  XWAPaths["xwa2_newsletter_delete_v2"] = "xwa2_newsletter_delete_v2";
17
+ XWAPaths["xwa2_fetch_account_reachout_timelock"] = "xwa2_fetch_account_reachout_timelock";
18
+ XWAPaths["xwa2_message_capping_info"] = "xwa2_message_capping_info";
15
19
  })(XWAPaths || (XWAPaths = {}));
20
+ export var ReachoutTimelockEnforcementType;
21
+ (function (ReachoutTimelockEnforcementType) {
22
+ ReachoutTimelockEnforcementType["DEFAULT"] = "DEFAULT";
23
+ })(ReachoutTimelockEnforcementType || (ReachoutTimelockEnforcementType = {}));
16
24
  export var QueryIds;
17
25
  (function (QueryIds) {
18
26
  QueryIds["CREATE"] = "8823471724422422";
19
27
  QueryIds["UPDATE_METADATA"] = "24250201037901610";
20
28
  QueryIds["METADATA"] = "6563316087068696";
21
29
  QueryIds["SUBSCRIBERS"] = "9783111038412085";
22
- QueryIds["FOLLOW"] = "7871414976211147";
23
- QueryIds["UNFOLLOW"] = "7238632346214362";
30
+ QueryIds["FOLLOW"] = "24404358912487870";
31
+ QueryIds["UNFOLLOW"] = "9767147403369991";
24
32
  QueryIds["MUTE"] = "29766401636284406";
25
33
  QueryIds["UNMUTE"] = "9864994326891137";
26
34
  QueryIds["ADMIN_COUNT"] = "7130823597031706";
27
35
  QueryIds["CHANGE_OWNER"] = "7341777602580933";
28
36
  QueryIds["DEMOTE"] = "6551828931592903";
29
37
  QueryIds["DELETE"] = "30062808666639665";
38
+ QueryIds["REACHOUT_TIMELOCK"] = "23983697327930364";
39
+ QueryIds["MESSAGE_CAPPING_INFO"] = "24503548349331633";
30
40
  })(QueryIds || (QueryIds = {}));
31
41
  //# sourceMappingURL=Newsletter.js.map
@@ -6,13 +6,43 @@ type FetchAppStateSyncKey = (keyId: string) => Promise<proto.Message.IAppStateSy
6
6
  export type ChatMutationMap = {
7
7
  [index: string]: ChatMutation;
8
8
  };
9
+ type Mac = {
10
+ indexMac: Uint8Array;
11
+ valueMac: Uint8Array;
12
+ operation: proto.SyncdMutation.SyncdOperation;
13
+ };
14
+ export declare const makeLtHashGenerator: ({ indexValueMap, hash }: Pick<LTHashState, "hash" | "indexValueMap">) => {
15
+ mix: ({ indexMac, valueMac, operation }: Mac) => void;
16
+ finish: () => {
17
+ hash: Buffer<ArrayBuffer>;
18
+ indexValueMap: {
19
+ [indexMacBase64: string]: {
20
+ valueMac: Uint8Array | Buffer;
21
+ };
22
+ };
23
+ };
24
+ };
9
25
  export declare const newLTHashState: () => LTHashState;
26
+ export declare const ensureLTHashStateVersion: (state: LTHashState) => LTHashState;
27
+ export declare const MAX_SYNC_ATTEMPTS = 2;
28
+ /**
29
+ * Check if an error is a missing app state sync key.
30
+ * WA Web treats these as "Blocked" (waits for key arrival), not fatal.
31
+ * In Baileys we retry with a snapshot which may use a different key.
32
+ */
33
+ export declare const isMissingKeyError: (error: any) => boolean;
34
+ /**
35
+ * Determines if an app state sync error is unrecoverable.
36
+ * TypeError indicates a WASM crash; otherwise we give up after MAX_SYNC_ATTEMPTS.
37
+ * Missing keys are NOT checked here — they are handled separately as "Blocked".
38
+ */
39
+ export declare const isAppStateSyncIrrecoverable: (error: any, attempts: number) => boolean;
10
40
  export declare const encodeSyncdPatch: ({ type, index, syncAction, apiVersion, operation }: WAPatchCreate, myAppStateKeyId: string, state: LTHashState, getAppStateSyncKey: FetchAppStateSyncKey) => Promise<{
11
41
  patch: proto.ISyncdPatch;
12
42
  state: LTHashState;
13
43
  }>;
14
44
  export declare const decodeSyncdMutations: (msgMutations: (proto.ISyncdMutation | proto.ISyncdRecord)[], initialState: LTHashState, getAppStateSyncKey: FetchAppStateSyncKey, onMutation: (mutation: ChatMutation) => void, validateMacs: boolean) => Promise<{
15
- hash: Buffer;
45
+ hash: Buffer<ArrayBuffer>;
16
46
  indexValueMap: {
17
47
  [indexMacBase64: string]: {
18
48
  valueMac: Uint8Array | Buffer;
@@ -20,7 +50,7 @@ export declare const decodeSyncdMutations: (msgMutations: (proto.ISyncdMutation
20
50
  };
21
51
  }>;
22
52
  export declare const decodeSyncdPatch: (msg: proto.ISyncdPatch, name: WAPatchName, initialState: LTHashState, getAppStateSyncKey: FetchAppStateSyncKey, onMutation: (mutation: ChatMutation) => void, validateMacs: boolean) => Promise<{
23
- hash: Buffer;
53
+ hash: Buffer<ArrayBuffer>;
24
54
  indexValueMap: {
25
55
  [indexMacBase64: string]: {
26
56
  valueMac: Uint8Array | Buffer;
@@ -54,9 +84,9 @@ export declare const extractSyncdPatches: (result: BinaryNode, options: RequestI
54
84
  snapshot?: proto.ISyncdSnapshot;
55
85
  };
56
86
  }>;
57
- export declare const downloadExternalBlob: (blob: proto.IExternalBlobReference, options: RequestInit) => Promise<Buffer>;
87
+ export declare const downloadExternalBlob: (blob: proto.IExternalBlobReference, options: RequestInit) => Promise<Buffer<ArrayBuffer>>;
58
88
  export declare const downloadExternalPatch: (blob: proto.IExternalBlobReference, options: RequestInit) => Promise<proto.SyncdMutations>;
59
- export declare const decodeSyncdSnapshot: (name: WAPatchName, snapshot: proto.ISyncdSnapshot, getAppStateSyncKey: FetchAppStateSyncKey, minimumVersionNumber: number | undefined, validateMacs?: boolean) => Promise<{
89
+ export declare const decodeSyncdSnapshot: (name: WAPatchName, snapshot: proto.ISyncdSnapshot, getAppStateSyncKey: FetchAppStateSyncKey, minimumVersionNumber: number | undefined, validateMacs?: boolean, logger?: ILogger) => Promise<{
60
90
  state: LTHashState;
61
91
  mutationMap: ChatMutationMap;
62
92
  }>;