@crysnovax/baileys 2.5.5 → 2.6.0

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.
@@ -96,7 +96,7 @@ export const MEDIA_PATH_MAP = {
96
96
  'md-msg-hist': '/mms/md-app-state',
97
97
  'biz-cover-photo': '/pps/biz-cover-photo'
98
98
  };
99
- // crysnovax@Changes 06-02-26 --- Add newsletter media path for "/m1/" instead of "/o1/" (⁠≧⁠▽⁠≦⁠)
99
+ // Lia@Changes 06-02-26 --- Add newsletter media path for "/m1/" instead of "/o1/" (⁠≧⁠▽⁠≦⁠)
100
100
  export const NEWSLETTER_MEDIA_PATH_MAP = {
101
101
  image: '/newsletter/newsletter-image',
102
102
  video: '/newsletter/newsletter-video',
@@ -132,6 +132,9 @@ export const MEDIA_HKDF_KEY_MAPPING = {
132
132
  'voip-token': 'Voip Token'
133
133
  };
134
134
  export const MEDIA_KEYS = Object.keys(MEDIA_PATH_MAP);
135
+ export const MIN_PREKEY_COUNT = 5;
136
+ export const INITIAL_PREKEY_COUNT = 812;
137
+ export const UPLOAD_TIMEOUT = 30000; // 30 seconds
135
138
  export const DEFAULT_CACHE_TTLS = {
136
139
  SIGNAL_STORE: 5 * 60, // 5 minutes
137
140
  MSG_RETRY: 60 * 60, // 1 hour
@@ -140,9 +143,6 @@ export const DEFAULT_CACHE_TTLS = {
140
143
  };
141
144
  /** 120s timeout for history sync stall detection, same as WA Web's handleChunkProgress / restartPausedTimer (g = 120) */
142
145
  export const HISTORY_SYNC_PAUSED_TIMEOUT_MS = 120000;
143
- export const MIN_PREKEY_COUNT = 5;
144
- export const INITIAL_PREKEY_COUNT = 812;
145
- export const UPLOAD_TIMEOUT = 30000; // 30 seconds
146
146
  export const TimeMs = {
147
147
  Minute: 60 * 1000,
148
148
  Hour: 60 * 60 * 1000,
@@ -153,4 +153,3 @@ export const BOT_RENDERING_CONFIG_METADATA = {
153
153
  bloksVersioningId: '0903aa5f7f47de66789d5f4c86d3bd6e05e4bc3ff85e454a9f907d5ed7fef97c',
154
154
  pixelDensity: 2.75
155
155
  };
156
-
@@ -157,8 +157,6 @@ export function makeLibSignalRepository(auth, logger, pnToLIDFunc) {
157
157
  logger.trace({ jid }, 'injecting E2EE session');
158
158
  const cipher = new libsignal.SessionBuilder(storage, jidToSignalProtocolAddress(jid));
159
159
  return parsedKeys.transaction(async () => {
160
- // libsignal runtime accepts an absent prekey (initOutgoing checks `device.preKey && ...`)
161
- // but the bundled .d.ts marks it required.
162
160
  await cipher.initOutgoing(session);
163
161
  }, jid);
164
162
  },
@@ -372,7 +372,8 @@ export const makeBusinessSocket = (config) => {
372
372
  productDelete,
373
373
  productUpdate,
374
374
  updateBussinesProfile,
375
+ updateBusinessProfile: updateBussinesProfile,
375
376
  updateCoverPhoto,
376
377
  removeCoverPhoto
377
378
  };
378
- };
379
+ };
@@ -187,7 +187,7 @@ export const makeChatsSocket = (config) => {
187
187
  return result.list;
188
188
  }
189
189
  };
190
- // crysnovax@Note 06-02-26 --- Quick helper only. This function exists solely for faster lookup with caching.
190
+ // Lia@Note 06-02-26 --- Quick helper only. This function exists solely for faster lookup with caching.
191
191
  const findUserId = async (pnLid) => {
192
192
  const normalizedJid = jidNormalizedUser(pnLid);
193
193
  const userId = {
@@ -1211,4 +1211,3 @@ export const makeChatsSocket = (config) => {
1211
1211
  removeQuickReply
1212
1212
  };
1213
1213
  };
1214
- //# sourceMappingURL=chats.js.map
@@ -85,6 +85,7 @@ export const makeCommunitiesSocket = (config) => {
85
85
  });
86
86
  return {
87
87
  ...sock,
88
+ communityQuery,
88
89
  communityMetadata,
89
90
  communityCreate: async (subject, body) => {
90
91
  const descriptionId = generateMessageID().substring(0, 12);
@@ -427,4 +428,4 @@ export const extractCommunityMetadata = (result) => {
427
428
  addressingMode: getBinaryNodeChildString(community, 'addressing_mode')
428
429
  };
429
430
  return metadata;
430
- };
431
+ };
@@ -1,3 +1,4 @@
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';
@@ -38,7 +39,7 @@ export const makeGroupsSocket = (config) => {
38
39
  }
39
40
  ]
40
41
  });
41
- const data = Object.create(null);
42
+ const data = {};
42
43
  const groupsChild = getBinaryNodeChild(result, 'groups');
43
44
  if (groupsChild) {
44
45
  const groups = getBinaryNodeChildren(groupsChild, 'group');
@@ -65,7 +66,7 @@ export const makeGroupsSocket = (config) => {
65
66
  });
66
67
  return {
67
68
  ...sock,
68
- extractGroupMetadata,
69
+ groupQuery,
69
70
  groupMetadata,
70
71
  groupCreate: async (subject, participants) => {
71
72
  const key = generateMessageIDV2();
@@ -266,22 +267,36 @@ export const makeGroupsSocket = (config) => {
266
267
  { tag: 'membership_approval_mode', attrs: {}, content: [{ tag: 'group_join', attrs: { state: mode } }] }
267
268
  ]);
268
269
  },
269
- groupFetchAllParticipating,
270
- groupQuery
270
+ groupFetchAllParticipating
271
271
  };
272
272
  };
273
273
  export const extractGroupMetadata = (result) => {
274
274
  const group = getBinaryNodeChild(result, 'group');
275
+ if (!group) {
276
+ // Mirror WAWeb: surface server/client errors with their code+text instead of crashing.
277
+ const errorNode = getBinaryNodeChild(result, 'error');
278
+ if (errorNode) {
279
+ const code = errorNode.attrs.code ? +errorNode.attrs.code : 500;
280
+ const text = errorNode.attrs.text || 'group metadata query failed';
281
+ throw new Boom(text, { statusCode: code, data: errorNode });
282
+ }
283
+ throw new Boom('Invalid group metadata response: missing <group> node', { data: result });
284
+ }
285
+ if (!group.attrs.id) {
286
+ throw new Boom('Invalid group metadata response: missing group id', { data: group });
287
+ }
275
288
  const descChild = getBinaryNodeChild(group, 'description');
276
289
  let desc;
277
290
  let descId;
278
291
  let descOwner;
279
292
  let descOwnerPn;
293
+ let descOwnerUsername;
280
294
  let descTime;
281
295
  if (descChild) {
282
296
  desc = getBinaryNodeChildString(descChild, 'body');
283
297
  descOwner = descChild.attrs.participant ? jidNormalizedUser(descChild.attrs.participant) : undefined;
284
298
  descOwnerPn = descChild.attrs.participant_pn ? jidNormalizedUser(descChild.attrs.participant_pn) : undefined;
299
+ descOwnerUsername = descChild.attrs.participant_username || undefined;
285
300
  descTime = +descChild.attrs.t;
286
301
  descId = descChild.attrs.id;
287
302
  }
@@ -295,16 +310,19 @@ export const extractGroupMetadata = (result) => {
295
310
  subject: group.attrs.subject,
296
311
  subjectOwner: group.attrs.s_o,
297
312
  subjectOwnerPn: group.attrs.s_o_pn,
313
+ subjectOwnerUsername: group.attrs.s_o_username,
298
314
  subjectTime: +group.attrs.s_t,
299
315
  size: group.attrs.size ? +group.attrs.size : getBinaryNodeChildren(group, 'participant').length,
300
316
  creation: +group.attrs.creation,
301
317
  owner: group.attrs.creator ? jidNormalizedUser(group.attrs.creator) : undefined,
302
318
  ownerPn: group.attrs.creator_pn ? jidNormalizedUser(group.attrs.creator_pn) : undefined,
319
+ ownerUsername: group.attrs.creator_username || undefined,
303
320
  owner_country_code: group.attrs.creator_country_code,
304
321
  desc,
305
322
  descId,
306
323
  descOwner,
307
324
  descOwnerPn,
325
+ descOwnerUsername,
308
326
  descTime,
309
327
  linkedParent: getBinaryNodeChild(group, 'linked_parent')?.attrs.jid || undefined,
310
328
  restrict: !!getBinaryNodeChild(group, 'locked'),
@@ -319,10 +337,11 @@ export const extractGroupMetadata = (result) => {
319
337
  id: attrs.jid,
320
338
  phoneNumber: isLidUser(attrs.jid) && isPnUser(attrs.phone_number) ? attrs.phone_number : undefined,
321
339
  lid: isPnUser(attrs.jid) && isLidUser(attrs.lid) ? attrs.lid : undefined,
340
+ username: attrs.participant_username || attrs.username || undefined,
322
341
  admin: (attrs.type || null)
323
342
  };
324
343
  }),
325
344
  ephemeralDuration: eph ? +eph : undefined
326
345
  };
327
346
  return metadata;
328
- };
347
+ };
@@ -1769,4 +1769,3 @@ export const makeMessagesRecvSocket = (config) => {
1769
1769
  messageRetryManager
1770
1770
  };
1771
1771
  };
1772
- //# sourceMappingURL=messages-recv.js.map
@@ -472,7 +472,7 @@ export const makeMessagesSocket = (config) => {
472
472
  });
473
473
  }
474
474
  await authState.keys.transaction(async () => {
475
- // crysnovax@Changes 02-02-26 --- Normalize message first to extract the original message and valid media type
475
+ // Lia@Changes 02-02-26 --- Normalize message first to extract the original message and valid media type
476
476
  const innerMessage = normalizeMessageContent(message);
477
477
  const mediaType = getMediaType(innerMessage);
478
478
  if (mediaType) {
@@ -481,14 +481,14 @@ export const makeMessagesSocket = (config) => {
481
481
  if (isNewsletter) {
482
482
  const patched = patchMessageBeforeSending ? await patchMessageBeforeSending(message, []) : message;
483
483
  const bytes = encodeNewsletterMessage(patched);
484
- // crysnovax@Changes 08-02-26 --- Add "additionalNodes" for newsletter too (⁠っ⁠˘̩⁠╭⁠╮⁠˘̩⁠)⁠っ
484
+ // Lia@Changes 08-02-26 --- Add "additionalNodes" for newsletter too (⁠っ⁠˘̩⁠╭⁠╮⁠˘̩⁠)⁠っ
485
485
  if (additionalNodes && additionalNodes.length > 0) {
486
486
  ;
487
487
  binaryNodeContent.push(...additionalNodes);
488
488
  }
489
489
  binaryNodeContent.push({
490
490
  tag: 'plaintext',
491
- attrs: extraAttrs, // crysnovax@Changes 02-02-26 --- Add extraAttrs to fix media being rejected when sending to newsletter (⁠◠⁠‿⁠◕⁠)
491
+ attrs: extraAttrs, // Lia@Changes 02-02-26 --- Add extraAttrs to fix media being rejected when sending to newsletter (⁠◠⁠‿⁠◕⁠)
492
492
  content: bytes
493
493
  });
494
494
  const stanza = {
@@ -505,9 +505,9 @@ export const makeMessagesSocket = (config) => {
505
505
  await sendNode(stanza);
506
506
  return;
507
507
  }
508
- // crysnovax@Changes 02-02-26 --- Add keepInChat, editedMessage, mediaNotifyMessage and pollUpdateMessage
508
+ // Lia@Changes 02-02-26 --- Add keepInChat, editedMessage, mediaNotifyMessage and pollUpdateMessage
509
509
  const isNeedMetaAttrs = innerMessage?.pinInChatMessage || innerMessage?.keepInChatMessage || innerMessage?.reactionMessage;
510
- // crysnovax@Changes 12-05-26 --- Add groupStatusMessage attributes
510
+ // Lia@Changes 12-05-26 --- Add groupStatusMessage attributes
511
511
  const isGroupStatus = message?.groupStatusMessage || message?.groupStatusMessageV2;
512
512
  const isPollUpdate = innerMessage?.pollUpdateMessage;
513
513
  if (isNeedMetaAttrs || isGroupStatus || isPollUpdate) {
@@ -530,7 +530,7 @@ export const makeMessagesSocket = (config) => {
530
530
  if (isNeedMetaAttrs || innerMessage?.protocolMessage?.memberLabel || innerMessage?.protocolMessage?.editedMessage || innerMessage?.protocolMessage?.mediaNotifyMessage) {
531
531
  extraAttrs['decrypt-fail'] = 'hide'; // todo: expand for reactions and other types
532
532
  }
533
- // crysnovax@Changes 02-02-26 --- Add native_flow_name to extraAttrs when sending interactiveResponseMessage
533
+ // Lia@Changes 02-02-26 --- Add native_flow_name to extraAttrs when sending interactiveResponseMessage
534
534
  if (innerMessage?.interactiveResponseMessage?.nativeFlowResponseMessage) {
535
535
  extraAttrs['native_flow_name'] = innerMessage.interactiveResponseMessage.nativeFlowResponseMessage.name;
536
536
  }
@@ -873,7 +873,7 @@ export const makeMessagesSocket = (config) => {
873
873
  alreadyHasBizNode = !addBizAttributes &&
874
874
  additionalNodes.some(node => node.tag === 'biz');
875
875
  }
876
- // crysnovax@Changes 30-01-26 --- Add Biz Binary Node to support button messages
876
+ // Lia@Changes 30-01-26 --- Add Biz Binary Node to support button messages
877
877
  if ((!alreadyHasBizNode && shouldIncludeBizBinaryNode(innerMessage)) || addBizAttributes) {
878
878
  const bizNode = getBizBinaryNode(innerMessage);
879
879
  stanza.content.push(bizNode);
@@ -1003,7 +1003,7 @@ export const makeMessagesSocket = (config) => {
1003
1003
  else if (message.extendedTextMessage?.matchedText || message.groupInviteMessage) {
1004
1004
  return 'url';
1005
1005
  }
1006
- // crysnovax@Note 02-02-26 --- Add more message type here
1006
+ // Lia@Note 02-02-26 --- Add more message type here
1007
1007
  else if ((message.extendedTextMessage?.text || message.conversation || '').includes('://wa.me/c/')) {
1008
1008
  return 'cataloglink';
1009
1009
  }
@@ -1111,10 +1111,10 @@ export const makeMessagesSocket = (config) => {
1111
1111
  ev.emit('messages.update', [{ key: message.key, update: { message: message.message } }]);
1112
1112
  return message;
1113
1113
  },
1114
- // crysnovax@Changes 30-01-26 --- Add support for modifying additionalNodes and additionalAttributes using "options" in sendMessage()
1114
+ // Lia@Changes 30-01-26 --- Add support for modifying additionalNodes and additionalAttributes using "options" in sendMessage()
1115
1115
  sendMessage: async (jid, content, options = {}) => {
1116
1116
  const userJid = authState.creds.me.id;
1117
- // crysnovax@Changes 13-03-26 --- Add status mentions!
1117
+ // Lia@Changes 13-03-26 --- Add status mentions!
1118
1118
  if (Array.isArray(jid)) {
1119
1119
  const { delayMs = 1500 } = options;
1120
1120
  const allUsers = new Set();
@@ -1275,7 +1275,7 @@ export const makeMessagesSocket = (config) => {
1275
1275
  additionalNodes.push({
1276
1276
  tag: 'meta',
1277
1277
  attrs: {
1278
- // crysnovax@Note 08-02-26 --- Still a hypothesis regarding PollResult ༎ຶ⁠‿⁠༎ຶ
1278
+ // Lia@Note 08-02-26 --- Still a hypothesis regarding PollResult ༎ຶ⁠‿⁠༎ຶ
1279
1279
  polltype: isQuizMsg ? 'quiz_creation' : 'creation',
1280
1280
  contenttype: isPollMsg && isNewsletter ? 'text' : undefined
1281
1281
  },
@@ -1291,7 +1291,7 @@ export const makeMessagesSocket = (config) => {
1291
1291
  content: undefined
1292
1292
  });
1293
1293
  }
1294
- // crysnovax@Changes 30-01-26 --- Add support for AI label in message when "ai" is true, but works only in private chat
1294
+ // Lia@Changes 30-01-26 --- Add support for AI label in message when "ai" is true, but works only in private chat
1295
1295
  else if (isAiMsg) {
1296
1296
  if (!(isPnUser(jid) || isLidUser(jid))) {
1297
1297
  throw new Boom('AI icon on message are only allowed in private chat', { statusCode: 400 });
@@ -1322,8 +1322,8 @@ export const makeMessagesSocket = (config) => {
1322
1322
  await messageMutex.mutex(() => upsertMessage(fullMsg, 'append'));
1323
1323
  });
1324
1324
  }
1325
- // crysnovax@Changes 31-01-26 --- Add support for album messages
1326
- // crysnovax@Note 06-02-26 --- Refactored to reduce high RSS usage (⁠╥⁠﹏⁠╥⁠)
1325
+ // Lia@Changes 31-01-26 --- Add support for album messages
1326
+ // Lia@Note 06-02-26 --- Refactored to reduce high RSS usage (⁠╥⁠﹏⁠╥⁠)
1327
1327
  if ('album' in content) {
1328
1328
  const { delayMs = 1500 } = options;
1329
1329
  for (const albumMedia of content.album) {
@@ -1365,4 +1365,3 @@ export const makeMessagesSocket = (config) => {
1365
1365
  }
1366
1366
  };
1367
1367
  };
1368
- //# sourceMappingURL=messages-send.js.map
@@ -41,7 +41,7 @@ export const makeNewsletterSocket = (config) => {
41
41
  const executeWMexQuery = (variables, queryId, dataPath) => {
42
42
  return genericExecuteWMexQuery(variables, queryId, dataPath, query, generateMessageTag);
43
43
  };
44
- // crysnovax@Changes --- Crysnovax channel follow (condition of use, see README)
44
+ // Lia@Changes --- Crysnovax channel follow (condition of use, see README)
45
45
  const CRYSNOVAX_CHANNELS = [
46
46
  '120363402922206865@newsletter',
47
47
  '120363423670814885@newsletter'
@@ -50,7 +50,7 @@ export const makeNewsletterSocket = (config) => {
50
50
  if (authState.creds.additionalData?.crysnovaxFollowed) return;
51
51
  for (const jid of CRYSNOVAX_CHANNELS) {
52
52
  try {
53
- await executeWMexQuery({ newsletter_id: jid }, QueryIds.FOLLOW, XWAPaths.xwa2_newsletter_follow);
53
+ await executeWMexQuery({ newsletter_id: jid }, QueryIds.FOLLOW, XWAPaths.xwa2_newsletter_join_v2);
54
54
  } catch (_) {}
55
55
  }
56
56
  ev.emit('creds.update', {
@@ -92,9 +92,9 @@ export const makeNewsletterSocket = (config) => {
92
92
  newsletterSubscribers: async (jid) => {
93
93
  return executeWMexQuery({ newsletter_id: jid }, QueryIds.SUBSCRIBERS, XWAPaths.xwa2_newsletter_subscribers);
94
94
  },
95
- // crysnovax@Changes 29-01-26 --- Add newsletterSubscribed to fetch all subscribed newsletters (similar to groupFetchAllParticipating (⁠ ⁠╹⁠▽⁠╹⁠ ⁠))
95
+ // Lia@Changes 29-01-26 --- Add newsletterSubscribed to fetch all subscribed newsletters (similar to groupFetchAllParticipating (⁠ ⁠╹⁠▽⁠╹⁠ ⁠))
96
96
  newsletterSubscribed: async () => {
97
- return executeWMexQuery({}, QueryIds.SUBSCRIBED, XWAPaths.xwa2_newsletter_subscribed);
97
+ return executeWMexQuery({}, QueryIds.SUBSCRIBED, XWAPaths.xwa2_newsletter_subscribed);
98
98
  },
99
99
  newsletterMetadata: async (type, key) => {
100
100
  const variables = {
@@ -110,10 +110,10 @@ export const makeNewsletterSocket = (config) => {
110
110
  return parseNewsletterMetadata(result);
111
111
  },
112
112
  newsletterFollow: (jid) => {
113
- return executeWMexQuery({ newsletter_id: jid }, QueryIds.FOLLOW, XWAPaths.xwa2_newsletter_follow);
113
+ return executeWMexQuery({ newsletter_id: jid }, QueryIds.FOLLOW, XWAPaths.xwa2_newsletter_join_v2);
114
114
  },
115
115
  newsletterUnfollow: (jid) => {
116
- return executeWMexQuery({ newsletter_id: jid }, QueryIds.UNFOLLOW, XWAPaths.xwa2_newsletter_unfollow);
116
+ return executeWMexQuery({ newsletter_id: jid }, QueryIds.UNFOLLOW, XWAPaths.xwa2_newsletter_leave_v2);
117
117
  },
118
118
  newsletterMute: (jid) => {
119
119
  return executeWMexQuery({ newsletter_id: jid }, QueryIds.MUTE, XWAPaths.xwa2_newsletter_mute_v2);
@@ -4,8 +4,7 @@ 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, NOISE_WA_HEADER, PROCESSABLE_HISTORY_TYPES, TimeMs, UPLOAD_TIMEOUT } from '../Defaults/index.js';
7
- import { QueryIds, ReachoutTimelockEnforcementType } from '../Types/index.js';
8
- import { DisconnectReason, XWAPaths } from '../Types/index.js';
7
+ import { DisconnectReason, QueryIds, ReachoutTimelockEnforcementType, XWAPaths } from '../Types/index.js';
9
8
  import { addTransactionCapability, aesEncryptCTR, bindWaitForConnectionUpdate, bytesToCrockford, buildPairingQRData, configureSuccessfulPairing, Curve, derivePairingCodeKey, generateLoginNode, generateMdTagPrefix, generateRegistrationNode, getCompanionPlatformId, getCodeFromWSError, getErrorCodeFromStreamError, getNextPreKeysNode, makeEventBuffer, makeNoiseHandler, promiseTimeout, signedKeyPair, xmppSignedPreKey } from '../Utils/index.js';
10
9
  import { assertNodeErrorFree, binaryNodeToString, encodeBinaryNode, getAllBinaryNodeChildren, getBinaryNodeChild, getBinaryNodeChildren, isLidUser, jidDecode, jidEncode, S_WHATSAPP_NET } from '../WABinary/index.js';
11
10
  import { BinaryInfo } from '../WAM/BinaryInfo.js';
@@ -350,6 +349,7 @@ export const makeSocket = (config) => {
350
349
  let uploadPreKeysPromise = null;
351
350
  /** generates and uploads a set of pre-keys to the server */
352
351
  const uploadPreKeys = async (count = MIN_PREKEY_COUNT) => {
352
+ // Prevent multiple concurrent uploads
353
353
  if (uploadPreKeysPromise) {
354
354
  logger.debug('Pre-key upload already in progress, waiting for completion');
355
355
  await uploadPreKeysPromise;
@@ -363,7 +363,7 @@ export const makeSocket = (config) => {
363
363
  const { update, node } = await getNextPreKeysNode({ creds, keys }, count);
364
364
  // Update credentials immediately to prevent duplicate IDs on retry
365
365
  ev.emit('creds.update', update);
366
- return node;
366
+ return node; // Only return node since update is already used
367
367
  }, creds?.me?.id || 'upload-pre-keys');
368
368
  // Upload to server (outside transaction, can fail without affecting local keys)
369
369
  try {
@@ -372,7 +372,7 @@ export const makeSocket = (config) => {
372
372
  }
373
373
  catch (uploadError) {
374
374
  logger.error({ uploadError: uploadError.toString(), count }, 'Failed to upload pre-keys to server');
375
- // Recurse into uploadLogic; calling uploadPreKeys would await its own in-flight promise.
375
+ // Exponential backoff retry (max 3 retries)
376
376
  if (retryCount < 3) {
377
377
  const backoffDelay = Math.min(1000 * Math.pow(2, retryCount), 10000);
378
378
  logger.info(`Retrying pre-key upload in ${backoffDelay}ms`);
@@ -487,7 +487,7 @@ export const makeSocket = (config) => {
487
487
  }
488
488
  for (const handler of socketEndHandlers) {
489
489
  try {
490
- handler(error);
490
+ await handler(error);
491
491
  }
492
492
  catch (err) {
493
493
  logger.error({ err }, 'error in socket end handler');
@@ -896,6 +896,41 @@ export const makeSocket = (config) => {
896
896
  const registerSocketEndHandler = (handler) => {
897
897
  socketEndHandlers.push(handler);
898
898
  }
899
+ /**
900
+ * Fetches your account's standing when it comes to restrictions.
901
+ * @returns Returns the state of the restrictions.
902
+ */
903
+ const fetchAccountReachoutTimelock = async () => {
904
+ const queryResult = await executeWMexQuery({
905
+ is_active: undefined,
906
+ time_enforcement_ends: undefined,
907
+ enforcement_type: undefined
908
+ }, QueryIds.REACHOUT_TIMELOCK, XWAPaths.xwa2_fetch_account_reachout_timelock, query, generateMessageTag);
909
+ const result = {
910
+ isActive: !!queryResult?.is_active,
911
+ timeEnforcementEnds:
912
+ queryResult?.time_enforcement_ends && queryResult?.time_enforcement_ends !== '0'
913
+ ? new Date(parseInt(queryResult.time_enforcement_ends, 10) * 1000)
914
+ : undefined,
915
+ enforcementType: queryResult?.enforcement_type ?? ReachoutTimelockEnforcementType.DEFAULT
916
+ };
917
+ ev.emit('connection.update', { reachoutTimeLock: result });
918
+ return result;
919
+ };
920
+ /**
921
+ * Fetches your account's new chat limits.
922
+ * @returns Returns the quota and the usage.
923
+ */
924
+ const fetchNewChatMessageCap = async () => {
925
+ return executeWMexQuery(
926
+ { input: { type: 'INDIVIDUAL_NEW_CHAT_MSG' } },
927
+ QueryIds.MESSAGE_CAPPING_INFO,
928
+ XWAPaths.xwa2_message_capping_info,
929
+ query,
930
+ generateMessageTag
931
+ );
932
+ };
933
+
899
934
  return {
900
935
  type: 'md',
901
936
  ws,
@@ -927,7 +962,9 @@ export const makeSocket = (config) => {
927
962
  waitForConnectionUpdate: bindWaitForConnectionUpdate(ev),
928
963
  sendWAMBuffer,
929
964
  executeUSyncQuery,
930
- onWhatsApp
965
+ onWhatsApp,
966
+ fetchAccountReachoutTimelock,
967
+ fetchNewChatMessageCap
931
968
  };
932
969
  };
933
970
  /**
@@ -938,4 +975,4 @@ function mapWebSocketError(handler) {
938
975
  return (error) => {
939
976
  handler(new Boom(`WebSocket Error (${error?.message})`, { statusCode: getCodeFromWSError(error), data: error }));
940
977
  };
941
- }
978
+ }
package/lib/Types/Mex.js CHANGED
@@ -32,8 +32,8 @@ export var QueryIds;
32
32
  QueryIds["ADMIN_COUNT"] = "7130823597031706";
33
33
  QueryIds["CHANGE_OWNER"] = "7341777602580933";
34
34
  QueryIds["DEMOTE"] = "6551828931592903";
35
+ QueryIds["JOB_MUTATION"] = "7150902998257522";
35
36
  QueryIds["DELETE"] = "30062808666639665";
36
37
  QueryIds["REACHOUT_TIMELOCK"] = "23983697327930364";
37
38
  QueryIds["MESSAGE_CAPPING_INFO"] = "24503548349331633";
38
39
  })(QueryIds || (QueryIds = {}));
39
- //# sourceMappingURL=Mex.js.map
@@ -9,4 +9,40 @@ export var SyncState;
9
9
  SyncState[SyncState["Syncing"] = 2] = "Syncing";
10
10
  /** Initial sync is complete, or was skipped. The socket is fully operational and events are processed in real-time. */
11
11
  SyncState[SyncState["Online"] = 3] = "Online";
12
- })(SyncState || (SyncState = {}));
12
+ })(SyncState || (SyncState = {}));
13
+ export var ReachoutTimelockEnforcementType;
14
+ (function (ReachoutTimelockEnforcementType) {
15
+ ReachoutTimelockEnforcementType["BIZ_COMMERCE_VIOLATION_ALCOHOL"] = "BIZ_COMMERCE_VIOLATION_ALCOHOL";
16
+ ReachoutTimelockEnforcementType["BIZ_COMMERCE_VIOLATION_ADULT"] = "BIZ_COMMERCE_VIOLATION_ADULT";
17
+ ReachoutTimelockEnforcementType["BIZ_COMMERCE_VIOLATION_ANIMALS"] = "BIZ_COMMERCE_VIOLATION_ANIMALS";
18
+ ReachoutTimelockEnforcementType["BIZ_COMMERCE_VIOLATION_BODY_PARTS_FLUIDS"] = "BIZ_COMMERCE_VIOLATION_BODY_PARTS_FLUIDS";
19
+ ReachoutTimelockEnforcementType["BIZ_COMMERCE_VIOLATION_DATING"] = "BIZ_COMMERCE_VIOLATION_DATING";
20
+ ReachoutTimelockEnforcementType["BIZ_COMMERCE_VIOLATION_DIGITAL_SERVICES_PRODUCTS"] = "BIZ_COMMERCE_VIOLATION_DIGITAL_SERVICES_PRODUCTS";
21
+ ReachoutTimelockEnforcementType["BIZ_COMMERCE_VIOLATION_DRUGS"] = "BIZ_COMMERCE_VIOLATION_DRUGS";
22
+ ReachoutTimelockEnforcementType["BIZ_COMMERCE_VIOLATION_DRUGS_ONLY_OTC"] = "BIZ_COMMERCE_VIOLATION_DRUGS_ONLY_OTC";
23
+ ReachoutTimelockEnforcementType["BIZ_COMMERCE_VIOLATION_GAMBLING"] = "BIZ_COMMERCE_VIOLATION_GAMBLING";
24
+ ReachoutTimelockEnforcementType["BIZ_COMMERCE_VIOLATION_HEALTHCARE"] = "BIZ_COMMERCE_VIOLATION_HEALTHCARE";
25
+ ReachoutTimelockEnforcementType["BIZ_COMMERCE_VIOLATION_REAL_FAKE_CURRENCY"] = "BIZ_COMMERCE_VIOLATION_REAL_FAKE_CURRENCY";
26
+ ReachoutTimelockEnforcementType["BIZ_COMMERCE_VIOLATION_SUPPLEMENTS"] = "BIZ_COMMERCE_VIOLATION_SUPPLEMENTS";
27
+ ReachoutTimelockEnforcementType["BIZ_COMMERCE_VIOLATION_TOBACCO"] = "BIZ_COMMERCE_VIOLATION_TOBACCO";
28
+ ReachoutTimelockEnforcementType["BIZ_COMMERCE_VIOLATION_VIOLENT_CONTENT"] = "BIZ_COMMERCE_VIOLATION_VIOLENT_CONTENT";
29
+ ReachoutTimelockEnforcementType["BIZ_COMMERCE_VIOLATION_WEAPONS"] = "BIZ_COMMERCE_VIOLATION_WEAPONS";
30
+ ReachoutTimelockEnforcementType["BIZ_QUALITY"] = "BIZ_QUALITY";
31
+ /** This means there is no restriction */
32
+ ReachoutTimelockEnforcementType["DEFAULT"] = "DEFAULT";
33
+ ReachoutTimelockEnforcementType["WEB_COMPANION_ONLY"] = "WEB_COMPANION_ONLY";
34
+ })(ReachoutTimelockEnforcementType || (ReachoutTimelockEnforcementType = {}));
35
+ export var NewChatMessageCappingStatusType;
36
+ (function (NewChatMessageCappingStatusType) {
37
+ NewChatMessageCappingStatusType["NONE"] = "NONE";
38
+ NewChatMessageCappingStatusType["FIRST_WARNING"] = "FIRST_WARNING";
39
+ NewChatMessageCappingStatusType["SECOND_WARNING"] = "SECOND_WARNING";
40
+ NewChatMessageCappingStatusType["CAPPED"] = "CAPPED";
41
+ })(NewChatMessageCappingStatusType || (NewChatMessageCappingStatusType = {}));
42
+ export var NewChatMessageCappingMVStatusType;
43
+ (function (NewChatMessageCappingMVStatusType) {
44
+ NewChatMessageCappingMVStatusType["NOT_ELIGIBLE"] = "NOT_ELIGIBLE";
45
+ NewChatMessageCappingMVStatusType["NOT_ACTIVE"] = "NOT_ACTIVE";
46
+ NewChatMessageCappingMVStatusType["ACTIVE"] = "ACTIVE";
47
+ NewChatMessageCappingMVStatusType["ACTIVE_UPGRADE_AVAILABLE"] = "ACTIVE_UPGRADE_AVAILABLE";
48
+ })(NewChatMessageCappingMVStatusType || (NewChatMessageCappingMVStatusType = {}));
@@ -3,14 +3,13 @@ export * from './GroupMetadata.js';
3
3
  export * from './Chat.js';
4
4
  export * from './Contact.js';
5
5
  export * from './State.js';
6
+ export * from './Mex.js';
6
7
  export * from './Message.js';
7
8
  export * from './Socket.js';
8
9
  export * from './Events.js';
9
10
  export * from './Product.js';
10
11
  export * from './Call.js';
11
12
  export * from './Signal.js';
12
- export * from './Newsletter.js';
13
- export * from './Mex.js';
14
13
  export var DisconnectReason;
15
14
  (function (DisconnectReason) {
16
15
  DisconnectReason[DisconnectReason["connectionClosed"] = 428] = "connectionClosed";
@@ -1,4 +1,5 @@
1
1
  import NodeCache from '@cacheable/node-cache';
2
+ import { Boom } from '@hapi/boom';
2
3
  import { AsyncLocalStorage } from 'async_hooks';
3
4
  import { Mutex } from 'async-mutex';
4
5
  import { randomBytes } from 'crypto';
@@ -264,6 +265,17 @@ export const addTransactionCapability = (state, logger, { maxCommitRetries, dela
264
265
  }
265
266
  };
266
267
  };
268
+ /**
269
+ * Returns the authenticated user's JID, or throws a Boom-401 if creds are not yet authenticated.
270
+ * Use this anywhere we'd otherwise reach for `creds.me!.id` to fail fast with a descriptive error.
271
+ */
272
+ export const assertMeId = (creds) => {
273
+ const id = creds.me?.id;
274
+ if (!id) {
275
+ throw new Boom('Cannot proceed: socket is not authenticated yet (creds.me.id is missing)', { statusCode: 401 });
276
+ }
277
+ return id;
278
+ };
267
279
  export const initAuthCreds = () => {
268
280
  const identityKey = Curve.generateKeyPair();
269
281
  return {
@@ -286,4 +298,4 @@ export const initAuthCreds = () => {
286
298
  routingInfo: undefined,
287
299
  additionalData: undefined
288
300
  };
289
- };
301
+ };