@baileys-md/baileys 11.2.4 → 12.0.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.
Files changed (74) hide show
  1. package/README.md +113 -2
  2. package/WAProto/GenerateStatics.sh +4 -0
  3. package/WAProto/WAProto.proto +4775 -0
  4. package/WAProto/index.js +14270 -302
  5. package/lib/Defaults/index.js +50 -54
  6. package/lib/Defaults/wileys-version.json +3 -0
  7. package/lib/Signal/Group/ciphertext-message.js +15 -0
  8. package/lib/Signal/Group/group-session-builder.js +64 -0
  9. package/lib/Signal/Group/group_cipher.js +96 -0
  10. package/lib/Signal/Group/index.js +57 -0
  11. package/lib/Signal/Group/keyhelper.js +55 -0
  12. package/lib/Signal/Group/queue-job.js +57 -0
  13. package/lib/Signal/Group/sender-chain-key.js +34 -0
  14. package/lib/Signal/Group/sender-key-distribution-message.js +66 -0
  15. package/lib/Signal/Group/sender-key-message.js +69 -0
  16. package/lib/Signal/Group/sender-key-name.js +51 -0
  17. package/lib/Signal/Group/sender-key-record.js +53 -0
  18. package/lib/Signal/Group/sender-key-state.js +99 -0
  19. package/{WASignalGroup/sender_message_key.js → lib/Signal/Group/sender-message-key.js} +6 -16
  20. package/lib/Signal/libsignal.js +33 -20
  21. package/lib/Socket/Client/index.js +2 -3
  22. package/lib/Socket/Client/{web-socket-client.js → websocket.js} +54 -5
  23. package/lib/Socket/chats.js +136 -92
  24. package/lib/Socket/groups.js +16 -11
  25. package/lib/Socket/index.js +2 -2
  26. package/lib/Socket/messages-recv.js +26 -15
  27. package/lib/Socket/messages-send.js +122 -86
  28. package/lib/Socket/newsletter.js +23 -21
  29. package/lib/Socket/socket.js +29 -15
  30. package/lib/Store/make-in-memory-store.js +23 -15
  31. package/lib/Utils/auth-utils.js +0 -7
  32. package/lib/Utils/browser-utils.js +35 -0
  33. package/lib/Utils/chat-utils.js +2 -2
  34. package/lib/Utils/crypto.js +71 -29
  35. package/lib/Utils/decode-wa-message.js +15 -7
  36. package/lib/Utils/event-buffer.js +6 -8
  37. package/lib/Utils/generics.js +38 -16
  38. package/lib/Utils/history.js +1 -1
  39. package/lib/Utils/index.js +3 -1
  40. package/lib/Utils/message-retry-manager.js +128 -0
  41. package/lib/Utils/messages-media.js +212 -57
  42. package/lib/Utils/messages.js +38 -7
  43. package/lib/Utils/noise-handler.js +5 -10
  44. package/lib/Utils/process-message.js +34 -2
  45. package/lib/Utils/signal.js +26 -16
  46. package/lib/Utils/validate-connection.js +88 -66
  47. package/lib/Utils/{baileys-event-stream.js → wileys-event-stream.js} +1 -1
  48. package/lib/WABinary/constants.js +1276 -13
  49. package/lib/WABinary/jid-utils.js +20 -4
  50. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +1 -1
  51. package/lib/WAUSync/Protocols/USyncStatusProtocol.js +3 -3
  52. package/lib/index.js +17 -6
  53. package/package.json +22 -17
  54. package/WASignalGroup/GroupProtocol.js +0 -1697
  55. package/WASignalGroup/ciphertext_message.js +0 -16
  56. package/WASignalGroup/group_cipher.js +0 -120
  57. package/WASignalGroup/group_session_builder.js +0 -46
  58. package/WASignalGroup/index.js +0 -5
  59. package/WASignalGroup/keyhelper.js +0 -21
  60. package/WASignalGroup/protobufs.js +0 -3
  61. package/WASignalGroup/queue_job.js +0 -69
  62. package/WASignalGroup/sender_chain_key.js +0 -50
  63. package/WASignalGroup/sender_key_distribution_message.js +0 -78
  64. package/WASignalGroup/sender_key_message.js +0 -92
  65. package/WASignalGroup/sender_key_name.js +0 -70
  66. package/WASignalGroup/sender_key_record.js +0 -56
  67. package/WASignalGroup/sender_key_state.js +0 -129
  68. package/lib/Defaults/baileys-version.json +0 -3
  69. package/lib/Defaults/phonenumber-mcc.json +0 -223
  70. package/lib/Socket/Client/mobile-socket-client.js +0 -65
  71. package/lib/Socket/registration.js +0 -166
  72. package/lib/Store/make-cache-manager-store.js +0 -83
  73. package/lib/Store/make-mongo-store.js +0 -567
  74. /package/lib/Socket/Client/{abstract-socket-client.js → types.js} +0 -0
@@ -18,7 +18,7 @@ const messages_send_1 = require("./messages-send");
18
18
  const makeMessagesRecvSocket = (config) => {
19
19
  const { logger, retryRequestDelayMs, maxMsgRetryCount, getMessage, shouldIgnoreJid } = config;
20
20
  const sock = (0, messages_send_1.makeMessagesSocket)(config);
21
- const { ev, authState, ws, processingMutex, signalRepository, query, upsertMessage, resyncAppState, onUnexpectedError, assertSessions, sendNode, relayMessage, sendReceipt, uploadPreKeys, createParticipantNodes, getUSyncDevices, sendPeerDataOperationMessage, } = sock;
21
+ const { ev, authState, ws, processingMutex, signalRepository, query, upsertMessage, resyncAppState, groupMetadata, onUnexpectedError, assertSessions, sendNode, relayMessage, sendReceipt, uploadPreKeys, createParticipantNodes, getUSyncDevices, sendPeerDataOperationMessage, } = sock;
22
22
  /** this mutex ensures that each retryRequest will wait for the previous one to finish */
23
23
  const retryMutex = (0, make_mutex_1.makeMutex)();
24
24
  const msgRetryCache = config.msgRetryCounterCache || new node_cache_1.default({
@@ -332,28 +332,28 @@ const makeMessagesRecvSocket = (config) => {
332
332
  break;
333
333
  break;
334
334
  default:
335
- // console.log("BAILEYS-DEBUG:", JSON.stringify({ ...child, content: Buffer.isBuffer(child.content) ? child.content.toString() : child.content, participant }, null, 2))
335
+ // console.log("WILEYS-DEBUG:", JSON.stringify({ ...child, content: Buffer.isBuffer(child.content) ? child.content.toString() : child.content, participant }, null, 2))
336
336
  }
337
337
  };
338
338
  const handleNewsletterNotification = (id, node) => {
339
339
  const messages = (0, WABinary_1.getBinaryNodeChild)(node, 'messages');
340
340
  const message = (0, WABinary_1.getBinaryNodeChild)(messages, 'message');
341
- const server_id = message.attrs.server_id;
341
+ const serverId = message.attrs.server_id;
342
342
  const reactionsList = (0, WABinary_1.getBinaryNodeChild)(message, 'reactions');
343
343
  const viewsList = (0, WABinary_1.getBinaryNodeChildren)(message, 'views_count');
344
344
  if (reactionsList) {
345
345
  const reactions = (0, WABinary_1.getBinaryNodeChildren)(reactionsList, 'reaction');
346
346
  if (reactions.length === 0) {
347
- ev.emit('newsletter.reaction', { id, server_id, reaction: { removed: true } });
347
+ ev.emit('newsletter.reaction', { id, 'server_id': serverId, reaction: { removed: true } });
348
348
  }
349
349
  reactions.forEach(item => {
350
350
  var _a, _b;
351
- ev.emit('newsletter.reaction', { id, server_id, reaction: { code: (_a = item.attrs) === null || _a === void 0 ? void 0 : _a.code, count: +((_b = item.attrs) === null || _b === void 0 ? void 0 : _b.count) } });
351
+ ev.emit('newsletter.reaction', { id, 'server_id': serverId, reaction: { code: (_a = item.attrs) === null || _a === void 0 ? void 0 : _a.code, count: +((_b = item.attrs) === null || _b === void 0 ? void 0 : _b.count) } });
352
352
  });
353
353
  }
354
354
  if (viewsList.length) {
355
355
  viewsList.forEach(item => {
356
- ev.emit('newsletter.view', { id, server_id, count: +item.attrs.count });
356
+ ev.emit('newsletter.view', { id, 'server_id': serverId, count: +item.attrs.count });
357
357
  });
358
358
  }
359
359
  };
@@ -574,8 +574,7 @@ const makeMessagesRecvSocket = (config) => {
574
574
  await authState.keys.set({ 'sender-key-memory': { [remoteJid]: null } });
575
575
  }
576
576
  logger.debug({ participant, sendToAll }, 'forced new session for retry recp');
577
- for (let i = 0; i < msgs.length; i++) {
578
- const msg = msgs[i];
577
+ for (const [i, msg] of msgs.entries()) {
579
578
  if (msg) {
580
579
  updateSendMessageAgainCount(ids[i], participant);
581
580
  const msgRelayOpts = { messageId: ids[i] };
@@ -601,7 +600,7 @@ const makeMessagesRecvSocket = (config) => {
601
600
  const isLid = attrs.from.includes('lid');
602
601
  const isNodeFromMe = (0, WABinary_1.areJidsSameUser)(attrs.participant || attrs.from, isLid ? (_a = authState.creds.me) === null || _a === void 0 ? void 0 : _a.lid : (_b = authState.creds.me) === null || _b === void 0 ? void 0 : _b.id);
603
602
  const remoteJid = !isNodeFromMe || (0, WABinary_1.isJidGroup)(attrs.from) ? attrs.from : attrs.recipient;
604
- const fromMe = !attrs.recipient || (attrs.type === 'retry' && isNodeFromMe);
603
+ const fromMe = !attrs.recipient || ((attrs.type === 'retry' || attrs.type === 'sender') && isNodeFromMe);
605
604
  const key = {
606
605
  remoteJid,
607
606
  id: '',
@@ -742,15 +741,13 @@ const makeMessagesRecvSocket = (config) => {
742
741
  if (response && ((_a = msg === null || msg === void 0 ? void 0 : msg.messageStubParameters) === null || _a === void 0 ? void 0 : _a[0]) === Utils_1.NO_MESSAGE_FOUND_ERROR_TEXT) {
743
742
  msg.messageStubParameters = [Utils_1.NO_MESSAGE_FOUND_ERROR_TEXT, response];
744
743
  }
745
- if (((_c = (_b = msg.message) === null || _b === void 0 ? void 0 : _b.protocolMessage) === null || _c === void 0 ? void 0 : _c.type) === WAProto_1.proto.Message.ProtocolMessage.Type.SHARE_PHONE_NUMBER) {
746
- if (node.attrs.sender_pn) {
747
- ev.emit('chats.phoneNumberShare', { lid: node.attrs.from, jid: node.attrs.sender_pn });
748
- }
744
+ if (((_c = (_b = msg.message) === null || _b === void 0 ? void 0 : _b.protocolMessage) === null || _c === void 0 ? void 0 : _c.type) === WAProto_1.proto.Message.ProtocolMessage.Type.SHARE_PHONE_NUMBER && node.attrs.sender_pn) {
745
+ ev.emit('chats.phoneNumberShare', { lid: node.attrs.from, jid: node.attrs.sender_pn });
749
746
  }
750
747
  try {
751
748
  await Promise.all([
752
749
  processingMutex.mutex(async () => {
753
- var _a;
750
+ var _a, _b, _c, _d, _e, _f;
754
751
  await decrypt();
755
752
  // message failed to decrypt
756
753
  if (msg.messageStubType === WAProto_1.proto.WebMessageInfo.StubType.CIPHERTEXT) {
@@ -776,6 +773,20 @@ const makeMessagesRecvSocket = (config) => {
776
773
  else {
777
774
  // no type in the receipt => message delivered
778
775
  let type = undefined;
776
+ if ((_b = msg.key.participant) === null || _b === void 0 ? void 0 : _b.endsWith('@lid')) {
777
+ msg.key.participant = node.attrs.participant_pn || authState.creds.me.id;
778
+ }
779
+ if ((0, WABinary_1.isJidGroup)(msg.key.remoteJid) && ((_f = (_e = (_d = (_c = msg.message) === null || _c === void 0 ? void 0 : _c.extendedTextMessage) === null || _d === void 0 ? void 0 : _d.contextInfo) === null || _e === void 0 ? void 0 : _e.participant) === null || _f === void 0 ? void 0 : _f.endsWith('@lid'))) {
780
+ if (msg.message.extendedTextMessage.contextInfo) {
781
+ const metadata = await groupMetadata(msg.key.remoteJid);
782
+ const sender = msg.message.extendedTextMessage.contextInfo.participant;
783
+ const found = metadata.participants.find(p => p.id === sender);
784
+ msg.message.extendedTextMessage.contextInfo.participant = (found === null || found === void 0 ? void 0 : found.jid) || sender;
785
+ }
786
+ }
787
+ if (!(0, WABinary_1.isJidGroup)(msg.key.remoteJid) && (0, WABinary_1.isLidUser)(msg.key.remoteJid)) {
788
+ msg.key.remoteJid = node.attrs.sender_pn || node.attrs.peer_recipient_pn;
789
+ }
779
790
  let participant = msg.key.participant;
780
791
  if (category === 'peer') { // special peer message
781
792
  type = 'peer_msg';
@@ -890,7 +901,7 @@ const makeMessagesRecvSocket = (config) => {
890
901
  await sendMessageAck(node);
891
902
  };
892
903
  const handleBadAck = async ({ attrs }) => {
893
- const key = { remoteJid: attrs.from, fromMe: true, id: attrs.id, server_id: attrs === null || attrs === void 0 ? void 0 : attrs.server_id };
904
+ const key = { remoteJid: attrs.from, fromMe: true, id: attrs.id, 'server_id': attrs === null || attrs === void 0 ? void 0 : attrs.server_id };
894
905
  // current hypothesis is that if pash is sent in the ack
895
906
  // it means -- the message hasn't reached all devices yet
896
907
  // we'll retry sending the message here
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.makeMessagesSocket = void 0;
7
7
  const boom_1 = require("@hapi/boom");
8
8
  const node_cache_1 = __importDefault(require("@cacheable/node-cache"));
9
+ const crypto_1 = require("crypto");
9
10
  const WAProto_1 = require("../../WAProto");
10
11
  const Defaults_1 = require("../Defaults");
11
12
  const Utils_1 = require("../Utils");
@@ -13,7 +14,6 @@ const link_preview_1 = require("../Utils/link-preview");
13
14
  const WABinary_1 = require("../WABinary");
14
15
  const WAUSync_1 = require("../WAUSync");
15
16
  const newsletter_1 = require("./newsletter");
16
- var ListType = WAProto_1.proto.Message.ListMessage.ListType;
17
17
  const makeMessagesSocket = (config) => {
18
18
  const { logger, linkPreviewImageThumbnailWidth, generateHighQualityLinkPreview, options: axiosOptions, patchMessageBeforeSending, cachedGroupMetadata, } = config;
19
19
  const sock = (0, newsletter_1.makeNewsletterSocket)(config);
@@ -266,7 +266,7 @@ const makeMessagesSocket = (config) => {
266
266
  const { user, server } = (0, WABinary_1.jidDecode)(jid);
267
267
  const statusJid = 'status@broadcast';
268
268
  const isGroup = server === 'g.us';
269
- const isNewsletter = server == 'newsletter';
269
+ const isNewsletter = server === 'newsletter';
270
270
  const isStatus = jid === statusJid;
271
271
  const isLid = server === 'lid';
272
272
  msgId = msgId || (0, Utils_1.generateMessageIDV2)((_a = sock.user) === null || _a === void 0 ? void 0 : _a.id);
@@ -280,7 +280,8 @@ const makeMessagesSocket = (config) => {
280
280
  deviceSentMessage: {
281
281
  destinationJid,
282
282
  message
283
- }
283
+ },
284
+ messageContextInfo: message.messageContextInfo
284
285
  };
285
286
  const extraAttrs = {};
286
287
  if (participant) {
@@ -402,14 +403,13 @@ const makeMessagesSocket = (config) => {
402
403
  });
403
404
  }
404
405
  else {
405
- const { user: meUser, device: meDevice } = (0, WABinary_1.jidDecode)(meId);
406
+ const { user: meUser } = (0, WABinary_1.jidDecode)(meId);
406
407
  if (!participant) {
407
408
  devices.push({ user });
408
- // do not send message to self if the device is 0 (mobile)
409
- if (!((additionalAttributes === null || additionalAttributes === void 0 ? void 0 : additionalAttributes['category']) === 'peer' && user === meUser)) {
410
- if (meDevice !== undefined && meDevice !== 0) {
411
- devices.push({ user: meUser });
412
- }
409
+ if (user !== meUser) {
410
+ devices.push({ user: meUser });
411
+ }
412
+ if ((additionalAttributes === null || additionalAttributes === void 0 ? void 0 : additionalAttributes['category']) !== 'peer') {
413
413
  const additionalDevices = await getUSyncDevices([meId, jid], !!useUserDevicesCache, true);
414
414
  devices.push(...additionalDevices);
415
415
  }
@@ -456,7 +456,7 @@ const makeMessagesSocket = (config) => {
456
456
  tag: 'message',
457
457
  attrs: {
458
458
  id: msgId,
459
- type: isNewsletter ? getTypeMessage(message) : 'text',//getTypeMessage(message),
459
+ type: isNewsletter ? getTypeMessage(message) : 'text',
460
460
  ...(additionalAttributes || {})
461
461
  },
462
462
  content: binaryNodeContent
@@ -488,53 +488,45 @@ const makeMessagesSocket = (config) => {
488
488
  });
489
489
  logger.debug({ jid }, 'adding device identity');
490
490
  }
491
- const buttonType = getButtonType(message);
492
- if (buttonType) {
493
- stanza.content.push({
494
- tag: 'biz',
495
- attrs: {},
496
- content: [
497
- {
498
- tag: buttonType,
499
- attrs: getButtonArgs(message),
500
- }
501
- ]
502
- });
503
- logger.debug({ jid }, 'adding business node');
504
- }
505
491
  if (additionalNodes && additionalNodes.length > 0) {
506
492
  stanza.content.push(...additionalNodes);
507
493
  }
508
- else {
509
- if (((0, WABinary_1.isJidGroup)(jid) || (0, WABinary_1.isJidUser)(jid)) && (((_l = (_k = message === null || message === void 0 ? void 0 : message.viewOnceMessage) === null || _k === void 0 ? void 0 : _k.message) === null || _l === void 0 ? void 0 : _l.interactiveMessage) || ((_o = (_m = message === null || message === void 0 ? void 0 : message.viewOnceMessageV2) === null || _m === void 0 ? void 0 : _m.message) === null || _o === void 0 ? void 0 : _o.interactiveMessage) || ((_q = (_p = message === null || message === void 0 ? void 0 : message.viewOnceMessageV2Extension) === null || _p === void 0 ? void 0 : _p.message) === null || _q === void 0 ? void 0 : _q.interactiveMessage) || (message === null || message === void 0 ? void 0 : message.interactiveMessage)) || (((_s = (_r = message === null || message === void 0 ? void 0 : message.viewOnceMessage) === null || _r === void 0 ? void 0 : _r.message) === null || _s === void 0 ? void 0 : _s.buttonsMessage) || ((_u = (_t = message === null || message === void 0 ? void 0 : message.viewOnceMessageV2) === null || _t === void 0 ? void 0 : _t.message) === null || _u === void 0 ? void 0 : _u.buttonsMessage) || ((_w = (_v = message === null || message === void 0 ? void 0 : message.viewOnceMessageV2Extension) === null || _v === void 0 ? void 0 : _v.message) === null || _w === void 0 ? void 0 : _w.buttonsMessage) || (message === null || message === void 0 ? void 0 : message.buttonsMessage))) {
510
- stanza.content.push({
511
- tag: 'biz',
512
- attrs: {},
513
- content: [{
514
- tag: 'interactive',
515
- attrs: {
516
- type: 'native_flow',
517
- v: '1'
518
- },
519
- content: [{
520
- tag: 'native_flow',
521
- attrs: { name: 'quick_reply' }
522
- }]
523
- }]
524
- });
494
+ const content = (0, Utils_1.normalizeMessageContent)(message);
495
+ const contentType = (0, Utils_1.getContentType)(content);
496
+ if (((0, WABinary_1.isJidGroup)(jid) || (0, WABinary_1.isJidUser)(jid)) && (contentType === 'interactiveMessage' ||
497
+ contentType === 'buttonsMessage' ||
498
+ contentType === 'listMessage')) {
499
+ const bizNode = { tag: 'biz', attrs: {} };
500
+ if ((((_l = (_k = message === null || message === void 0 ? void 0 : message.viewOnceMessage) === null || _k === void 0 ? void 0 : _k.message) === null || _l === void 0 ? void 0 : _l.interactiveMessage) || ((_o = (_m = message === null || message === void 0 ? void 0 : message.viewOnceMessageV2) === null || _m === void 0 ? void 0 : _m.message) === null || _o === void 0 ? void 0 : _o.interactiveMessage) || ((_q = (_p = message === null || message === void 0 ? void 0 : message.viewOnceMessageV2Extension) === null || _p === void 0 ? void 0 : _p.message) === null || _q === void 0 ? void 0 : _q.interactiveMessage) || (message === null || message === void 0 ? void 0 : message.interactiveMessage)) || (((_s = (_r = message === null || message === void 0 ? void 0 : message.viewOnceMessage) === null || _r === void 0 ? void 0 : _r.message) === null || _s === void 0 ? void 0 : _s.buttonsMessage) || ((_u = (_t = message === null || message === void 0 ? void 0 : message.viewOnceMessageV2) === null || _t === void 0 ? void 0 : _t.message) === null || _u === void 0 ? void 0 : _u.buttonsMessage) || ((_w = (_v = message === null || message === void 0 ? void 0 : message.viewOnceMessageV2Extension) === null || _v === void 0 ? void 0 : _v.message) === null || _w === void 0 ? void 0 : _w.buttonsMessage) || (message === null || message === void 0 ? void 0 : message.buttonsMessage))) {
501
+ bizNode.content = [{
502
+ tag: 'interactive',
503
+ attrs: {
504
+ type: 'native_flow',
505
+ v: '1'
506
+ },
507
+ content: [{
508
+ tag: 'native_flow',
509
+ attrs: { v: '9', name: 'mixed' }
510
+ }]
511
+ }];
512
+ }
513
+ else if (message === null || message === void 0 ? void 0 : message.listMessage) {
514
+ // list message only support in private chat
515
+ bizNode.content = [{
516
+ tag: 'list',
517
+ attrs: {
518
+ type: 'product_list',
519
+ v: '2'
520
+ }
521
+ }];
525
522
  }
523
+ stanza.content.push(bizNode);
526
524
  }
527
525
  logger.debug({ msgId }, `sending message to ${participants.length} devices`);
528
526
  await sendNode(stanza);
529
527
  });
530
528
  return msgId;
531
529
  };
532
- /*const getMessageType = (message) => {
533
- if (message.pollCreationMessage || message.pollCreationMessageV2 || message.pollCreationMessageV3 || message.pollUpdateMessage) {
534
- return 'poll';
535
- }
536
- return 'text';
537
- };*/
538
530
  const getTypeMessage = (msg) => {
539
531
  if (msg.viewOnceMessage) {
540
532
  return getTypeMessage(msg.viewOnceMessage.message);
@@ -553,9 +545,9 @@ const makeMessagesSocket = (config) => {
553
545
  }
554
546
  else if (msg.reactionMessage) {
555
547
  return 'reaction';
556
- }
548
+ }
557
549
  else if (msg.pollCreationMessage || msg.pollCreationMessageV2 || msg.pollCreationMessageV3 || msg.pollUpdateMessage) {
558
- return 'reaction';
550
+ return 'poll';
559
551
  }
560
552
  else if (getMediaType(msg)) {
561
553
  return 'media';
@@ -611,39 +603,6 @@ const makeMessagesSocket = (config) => {
611
603
  return 'url';
612
604
  }
613
605
  };
614
- const getButtonType = (message) => {
615
- if (message.buttonsMessage) {
616
- return 'buttons';
617
- }
618
- else if (message.buttonsResponseMessage) {
619
- return 'buttons_response';
620
- }
621
- else if (message.interactiveResponseMessage) {
622
- return 'interactive_response';
623
- }
624
- else if (message.listMessage) {
625
- return 'list';
626
- }
627
- else if (message.listResponseMessage) {
628
- return 'list_response';
629
- }
630
- };
631
- const getButtonArgs = (message) => {
632
- if (message.templateMessage) {
633
- // TODO: Add attributes
634
- return {};
635
- }
636
- else if (message.listMessage) {
637
- const type = message.listMessage.listType;
638
- if (!type) {
639
- throw new boom_1.Boom('Expected list type inside message');
640
- }
641
- return { v: '2', type: ListType[type].toLowerCase() };
642
- }
643
- else {
644
- return {};
645
- }
646
- };
647
606
  const getPrivacyTokens = async (jids) => {
648
607
  const t = (0, Utils_1.unixTimestampSeconds)().toString();
649
608
  const result = await query({
@@ -679,7 +638,6 @@ const makeMessagesSocket = (config) => {
679
638
  relayMessage,
680
639
  sendReceipt,
681
640
  sendReceipts,
682
- getButtonArgs,
683
641
  readMessages,
684
642
  refreshMediaConn,
685
643
  waUploadToServer,
@@ -731,6 +689,19 @@ const makeMessagesSocket = (config) => {
731
689
  sendMessage: async (jid, content, options = {}) => {
732
690
  var _a, _b, _c;
733
691
  const userJid = authState.creds.me.id;
692
+ if (!options.ephemeralExpiration) {
693
+ if ((0, WABinary_1.isJidGroup)(jid)) {
694
+ const groups = await sock.groupQuery(jid, 'get', [{
695
+ tag: 'query',
696
+ attrs: {
697
+ request: 'interactive'
698
+ }
699
+ }]);
700
+ const metadata = (0, WABinary_1.getBinaryNodeChild)(groups, 'group');
701
+ const expiration = ((_b = (_a = (0, WABinary_1.getBinaryNodeChild)(metadata, 'ephemeral')) === null || _a === void 0 ? void 0 : _a.attrs) === null || _b === void 0 ? void 0 : _b.expiration) || 0;
702
+ options.ephemeralExpiration = expiration;
703
+ }
704
+ }
734
705
  if (typeof content === 'object' &&
735
706
  'disappearingMessagesInChat' in content &&
736
707
  typeof content['disappearingMessagesInChat'] !== 'undefined' &&
@@ -741,6 +712,71 @@ const makeMessagesSocket = (config) => {
741
712
  disappearingMessagesInChat;
742
713
  await groupToggleEphemeral(jid, value);
743
714
  }
715
+ if (typeof content === 'object' && 'album' in content && content.album) {
716
+ const { album, caption } = content;
717
+ if (caption && !album[0].caption) {
718
+ album[0].caption = caption;
719
+ }
720
+ let mediaHandle;
721
+ let mediaMsg;
722
+ const albumMsg = (0, Utils_1.generateWAMessageFromContent)(jid, {
723
+ albumMessage: {
724
+ expectedImageCount: album.filter(item => 'image' in item).length,
725
+ expectedVideoCount: album.filter(item => 'video' in item).length
726
+ }
727
+ }, { userJid, ...options });
728
+ await relayMessage(jid, albumMsg.message, {
729
+ messageId: albumMsg.key.id
730
+ });
731
+ for (const i in album) {
732
+ const media = album[i];
733
+ if ('image' in media) {
734
+ mediaMsg = await (0, Utils_1.generateWAMessage)(jid, {
735
+ image: media.image,
736
+ ...(media.caption ? { caption: media.caption } : {}),
737
+ ...options
738
+ }, {
739
+ userJid,
740
+ upload: async (readStream, opts) => {
741
+ const up = await waUploadToServer(readStream, { ...opts, newsletter: (0, WABinary_1.isJidNewsletter)(jid) });
742
+ mediaHandle = up.handle;
743
+ return up;
744
+ },
745
+ ...options,
746
+ });
747
+ }
748
+ else if ('video' in media) {
749
+ mediaMsg = await (0, Utils_1.generateWAMessage)(jid, {
750
+ video: media.video,
751
+ ...(media.caption ? { caption: media.caption } : {}),
752
+ ...(media.gifPlayback !== undefined ? { gifPlayback: media.gifPlayback } : {}),
753
+ ...options
754
+ }, {
755
+ userJid,
756
+ upload: async (readStream, opts) => {
757
+ const up = await waUploadToServer(readStream, { ...opts, newsletter: (0, WABinary_1.isJidNewsletter)(jid) });
758
+ mediaHandle = up.handle;
759
+ return up;
760
+ },
761
+ ...options,
762
+ });
763
+ }
764
+ if (mediaMsg) {
765
+ mediaMsg.message.messageContextInfo = {
766
+ messageSecret: (0, crypto_1.randomBytes)(32),
767
+ messageAssociation: {
768
+ associationType: 1,
769
+ parentMessageKey: albumMsg.key
770
+ }
771
+ };
772
+ }
773
+ await relayMessage(jid, mediaMsg.message, {
774
+ messageId: mediaMsg.key.id
775
+ });
776
+ await new Promise(resolve => setTimeout(resolve, 800));
777
+ }
778
+ return albumMsg;
779
+ }
744
780
  else {
745
781
  let mediaHandle;
746
782
  const fullMsg = await (0, Utils_1.generateWAMessage)(jid, content, {
@@ -765,7 +801,7 @@ const makeMessagesSocket = (config) => {
765
801
  },
766
802
  mediaCache: config.mediaCache,
767
803
  options: config.options,
768
- messageId: (0, Utils_1.generateMessageIDV2)((_a = sock.user) === null || _a === void 0 ? void 0 : _a.id),
804
+ messageId: (0, Utils_1.generateMessageIDV2)((_c = sock.user) === null || _c === void 0 ? void 0 : _c.id),
769
805
  ...options,
770
806
  });
771
807
  const isDeleteMsg = 'delete' in content && !!content.delete;
@@ -779,7 +815,7 @@ const makeMessagesSocket = (config) => {
779
815
  // required for delete
780
816
  if (isDeleteMsg) {
781
817
  // if the chat is a group, and I am not the author, then delete the message as an admin
782
- if (((0, WABinary_1.isJidGroup)((_b = content.delete) === null || _b === void 0 ? void 0 : _b.remoteJid) && !((_c = content.delete) === null || _c === void 0 ? void 0 : _c.fromMe)) || (0, WABinary_1.isJidNewsletter)(jid)) {
818
+ if (((0, WABinary_1.isJidGroup)(content.delete.remoteJid) && !content.delete.fromMe) || (0, WABinary_1.isJidNewsletter)(jid)) {
783
819
  additionalAttributes.edit = '8';
784
820
  }
785
821
  else {
@@ -833,4 +869,4 @@ const makeMessagesSocket = (config) => {
833
869
  }
834
870
  };
835
871
  };
836
- exports.makeMessagesSocket = makeMessagesSocket;
872
+ exports.makeMessagesSocket = makeMessagesSocket;
@@ -45,7 +45,12 @@ const makeNewsletterSocket = (config) => {
45
45
  {
46
46
  tag: 'query',
47
47
  attrs: { query_id },
48
- content: encoder.encode(JSON.stringify({ variables: { newsletter_id: jid, ...content } }))
48
+ content: encoder.encode(JSON.stringify({
49
+ variables: {
50
+ 'newsletter_id': jid,
51
+ ...content
52
+ }
53
+ }))
49
54
  }
50
55
  ]
51
56
  }));
@@ -60,30 +65,21 @@ const makeNewsletterSocket = (config) => {
60
65
  return await Promise.all((0, WABinary_1.getAllBinaryNodeChildren)(child).map(async (messageNode) => {
61
66
  var _a, _b;
62
67
  messageNode.attrs.from = child === null || child === void 0 ? void 0 : child.attrs.jid;
63
- const views = (_b = (_a = (0, WABinary_1.getBinaryNodeChild)(messageNode, 'views_count')) === null || _a === void 0 ? void 0 : _a.attrs) === null || _b === void 0 ? void 0 : _b.count;
68
+ const views = parseInt(((_b = (_a = (0, WABinary_1.getBinaryNodeChild)(messageNode, 'views_count')) === null || _a === void 0 ? void 0 : _a.attrs) === null || _b === void 0 ? void 0 : _b.count) || '0');
64
69
  const reactionNode = (0, WABinary_1.getBinaryNodeChild)(messageNode, 'reactions');
65
70
  const reactions = (0, WABinary_1.getBinaryNodeChildren)(reactionNode, 'reaction')
66
71
  .map(({ attrs }) => ({ count: +attrs.count, code: attrs.code }));
67
- let data;
72
+ const data = {
73
+ 'server_id': messageNode.attrs.server_id,
74
+ views,
75
+ reactions
76
+ };
68
77
  if (type === 'messages') {
69
78
  const { fullMessage: message, decrypt } = await (0, Utils_1.decryptMessageNode)(messageNode, authState.creds.me.id, authState.creds.me.lid || '', signalRepository, config.logger);
70
79
  await decrypt();
71
- data = {
72
- server_id: messageNode.attrs.server_id,
73
- views: views ? +views : undefined,
74
- reactions,
75
- message
76
- };
77
- return data;
78
- }
79
- else {
80
- data = {
81
- server_id: messageNode.attrs.server_id,
82
- views: views ? +views : undefined,
83
- reactions
84
- };
85
- return data;
80
+ data.message = message;
86
81
  }
82
+ return data;
87
83
  }));
88
84
  };
89
85
  return {
@@ -131,7 +127,7 @@ const makeNewsletterSocket = (config) => {
131
127
  newsletterMute: async (jid) => {
132
128
  await newsletterWMexQuery(jid, QueryIds.MUTE);
133
129
  },
134
- newsletterCreate: async (name, description) => {
130
+ newsletterCreate: async (name, description, picture) => {
135
131
  await query({
136
132
  tag: 'iq',
137
133
  attrs: {
@@ -152,7 +148,12 @@ const makeNewsletterSocket = (config) => {
152
148
  ]
153
149
  });
154
150
  const result = await newsletterWMexQuery(undefined, QueryIds.CREATE, {
155
- input: { name, description }
151
+ input: {
152
+ name,
153
+ description: description !== null && description !== void 0 ? description : null,
154
+ picture: picture ? (await (0, Utils_1.generateProfilePicture)(picture)).img.toString('base64') : null,
155
+ settings: null
156
+ }
156
157
  });
157
158
  return (0, exports.extractNewsletterMetadata)(result, true);
158
159
  },
@@ -202,10 +203,11 @@ const makeNewsletterSocket = (config) => {
202
203
  });
203
204
  },
204
205
  newsletterFetchMessages: async (type, key, count, after) => {
206
+ const afterStr = after === null || after === void 0 ? void 0 : after.toString();
205
207
  const result = await newsletterQuery(WABinary_1.S_WHATSAPP_NET, 'get', [
206
208
  {
207
209
  tag: 'messages',
208
- attrs: { type, ...(type === 'invite' ? { key } : { jid: key }), count: count.toString(), after: (after === null || after === void 0 ? void 0 : after.toString()) || '100' }
210
+ attrs: { type, ...(type === 'invite' ? { key } : { jid: key }), count: count.toString(), after: afterStr || '100' }
209
211
  }
210
212
  ]);
211
213
  return await parseFetchedUpdates(result, 'messages');
@@ -20,15 +20,14 @@ const Client_1 = require("./Client");
20
20
  const makeSocket = (config) => {
21
21
  var _a, _b;
22
22
  const { waWebSocketUrl, connectTimeoutMs, logger, keepAliveIntervalMs, browser, auth: authState, printQRInTerminal, defaultQueryTimeoutMs, transactionOpts, qrTimeout, makeSignalRepository, } = config;
23
- let url = typeof waWebSocketUrl === 'string' ? new url_1.URL(waWebSocketUrl) : waWebSocketUrl;
24
- config.mobile = config.mobile || url.protocol === 'tcp:';
25
- if (config.mobile && url.protocol !== 'tcp:') {
26
- url = new url_1.URL(`tcp://${Defaults_1.MOBILE_ENDPOINT}:${Defaults_1.MOBILE_PORT}`);
23
+ const url = typeof waWebSocketUrl === 'string' ? new url_1.URL(waWebSocketUrl) : waWebSocketUrl;
24
+ if (config.mobile || url.protocol === 'tcp:') {
25
+ throw new boom_1.Boom('Mobile API is not supported anymore', { statusCode: Types_1.DisconnectReason.loggedOut });
27
26
  }
28
- if (!config.mobile && url.protocol === 'wss' && ((_a = authState === null || authState === void 0 ? void 0 : authState.creds) === null || _a === void 0 ? void 0 : _a.routingInfo)) {
27
+ if (url.protocol === 'wss' && ((_a = authState === null || authState === void 0 ? void 0 : authState.creds) === null || _a === void 0 ? void 0 : _a.routingInfo)) {
29
28
  url.searchParams.append('ED', authState.creds.routingInfo.toString('base64url'));
30
29
  }
31
- const ws = config.socket ? config.socket : config.mobile ? new Client_1.MobileSocketClient(url, config) : new Client_1.WebSocketClient(url, config);
30
+ const ws = new Client_1.WebSocketClient(url, config);
32
31
  ws.connect();
33
32
  const ev = (0, Utils_1.makeEventBuffer)(logger);
34
33
  /** ephemeral key pair used to encrypt/decrypt communication. Unique for each connection */
@@ -36,8 +35,7 @@ const makeSocket = (config) => {
36
35
  /** WA noise protocol wrapper */
37
36
  const noise = (0, Utils_1.makeNoiseHandler)({
38
37
  keyPair: ephemeralKeyPair,
39
- NOISE_HEADER: config.mobile ? Defaults_1.MOBILE_NOISE_HEADER : Defaults_1.NOISE_WA_HEADER,
40
- mobile: config.mobile,
38
+ NOISE_HEADER: Defaults_1.NOISE_WA_HEADER,
41
39
  logger,
42
40
  routingInfo: (_b = authState === null || authState === void 0 ? void 0 : authState.creds) === null || _b === void 0 ? void 0 : _b.routingInfo
43
41
  });
@@ -80,6 +78,25 @@ const makeSocket = (config) => {
80
78
  /** log & process any unexpected errors */
81
79
  const onUnexpectedError = (err, msg) => {
82
80
  logger.error({ err }, `unexpected error in '${msg}'`);
81
+ const message = (err && ((err.stack || err.message) || String(err))).toLowerCase();
82
+ // auto recover from cryptographic desyncs by re-uploading prekeys
83
+ if (message.includes('bad mac') || (message.includes('mac') && message.includes('invalid'))) {
84
+ try {
85
+ uploadPreKeysToServerIfRequired(true)
86
+ .catch(e => logger.warn({ e }, 'failed to re-upload prekeys after bad mac'));
87
+ }
88
+ catch (_e) {
89
+ // ignore
90
+ }
91
+ }
92
+ // gently back off when encountering rate limits (429)
93
+ if (message.includes('429') || message.includes('rate limit')) {
94
+ const wait = Math.min(30000, (config.backoffDelayMs || 5000));
95
+ logger.info({ wait }, 'backing off due to rate limit');
96
+ setTimeout(() => {
97
+ // intentionally empty; wait to delay further sends
98
+ }, wait);
99
+ }
83
100
  };
84
101
  /** await the next incoming message */
85
102
  const awaitNextMessage = async (sendMsg) => {
@@ -161,10 +178,7 @@ const makeSocket = (config) => {
161
178
  logger.trace({ handshake }, 'handshake recv from WA');
162
179
  const keyEnc = await noise.processHandshake(handshake, creds.noiseKey);
163
180
  let node;
164
- if (config.mobile) {
165
- node = (0, Utils_1.generateMobileNode)(config);
166
- }
167
- else if (!creds.me) {
181
+ if (!creds.me) {
168
182
  node = (0, Utils_1.generateRegistrationNode)(creds, config);
169
183
  logger.info({ node }, 'not logged in, attempting registration...');
170
184
  }
@@ -234,11 +248,11 @@ const makeSocket = (config) => {
234
248
  const l0 = frame.tag;
235
249
  const l1 = frame.attrs || {};
236
250
  const l2 = Array.isArray(frame.content) ? (_a = frame.content[0]) === null || _a === void 0 ? void 0 : _a.tag : '';
237
- Object.keys(l1).forEach(key => {
251
+ for (const key of Object.keys(l1)) {
238
252
  anyTriggered = ws.emit(`${Defaults_1.DEF_CALLBACK_PREFIX}${l0},${key}:${l1[key]},${l2}`, frame) || anyTriggered;
239
253
  anyTriggered = ws.emit(`${Defaults_1.DEF_CALLBACK_PREFIX}${l0},${key}:${l1[key]}`, frame) || anyTriggered;
240
254
  anyTriggered = ws.emit(`${Defaults_1.DEF_CALLBACK_PREFIX}${l0},${key}`, frame) || anyTriggered;
241
- });
255
+ }
242
256
  anyTriggered = ws.emit(`${Defaults_1.DEF_CALLBACK_PREFIX}${l0},,${l2}`, frame) || anyTriggered;
243
257
  anyTriggered = ws.emit(`${Defaults_1.DEF_CALLBACK_PREFIX}${l0}`, frame) || anyTriggered;
244
258
  if (!anyTriggered && logger.level === 'debug') {
@@ -368,7 +382,7 @@ const makeSocket = (config) => {
368
382
  end(new boom_1.Boom(msg || 'Intentional Logout', { statusCode: Types_1.DisconnectReason.loggedOut }));
369
383
  };
370
384
  const requestPairingCode = async (phoneNumber, pairCode) => {
371
- await new Promise(resolve => setTimeout(resolve, 3000));
385
+ await new Promise(resolve => setTimeout(resolve, 3000));
372
386
  if (pairCode) {
373
387
  authState.creds.pairingCode = pairCode.substring(0, 8).toUpperCase();
374
388
  }