@neykoor/baileys 7.0.5-rc15 → 7.0.8-rc15

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 (77) hide show
  1. package/lib/Defaults/index.js +6 -6
  2. package/lib/Defaults/index.js.map +1 -1
  3. package/lib/Signal/lid-mapping.d.ts.map +1 -1
  4. package/lib/Signal/lid-mapping.js.map +1 -1
  5. package/lib/Socket/business.d.ts +33 -0
  6. package/lib/Socket/business.d.ts.map +1 -1
  7. package/lib/Socket/chats.d.ts.map +1 -1
  8. package/lib/Socket/chats.js +9 -2
  9. package/lib/Socket/chats.js.map +1 -1
  10. package/lib/Socket/communities.d.ts +33 -0
  11. package/lib/Socket/communities.d.ts.map +1 -1
  12. package/lib/Socket/groups.d.ts.map +1 -1
  13. package/lib/Socket/groups.js +7 -2
  14. package/lib/Socket/groups.js.map +1 -1
  15. package/lib/Socket/index.d.ts +33 -0
  16. package/lib/Socket/index.d.ts.map +1 -1
  17. package/lib/Socket/messages-recv.d.ts +33 -0
  18. package/lib/Socket/messages-recv.d.ts.map +1 -1
  19. package/lib/Socket/messages-send.d.ts +34 -1
  20. package/lib/Socket/messages-send.d.ts.map +1 -1
  21. package/lib/Socket/messages-send.js +139 -65
  22. package/lib/Socket/messages-send.js.map +1 -1
  23. package/lib/Socket/newsletter.d.ts.map +1 -1
  24. package/lib/Socket/smgss.d.ts +203 -0
  25. package/lib/Socket/smgss.d.ts.map +1 -0
  26. package/lib/Socket/smgss.js +461 -0
  27. package/lib/Socket/smgss.js.map +1 -0
  28. package/lib/Store/make-in-memory-store.d.ts.map +1 -1
  29. package/lib/Store/make-in-memory-store.js +12 -10
  30. package/lib/Store/make-in-memory-store.js.map +1 -1
  31. package/lib/Types/Message.d.ts +94 -2
  32. package/lib/Types/Message.d.ts.map +1 -1
  33. package/lib/Types/Message.js +4 -0
  34. package/lib/Types/Message.js.map +1 -1
  35. package/lib/Utils/connection-watchdog.d.ts +30 -0
  36. package/lib/Utils/connection-watchdog.d.ts.map +1 -0
  37. package/lib/Utils/connection-watchdog.js +66 -0
  38. package/lib/Utils/connection-watchdog.js.map +1 -0
  39. package/lib/Utils/generics.js +1 -1
  40. package/lib/Utils/group-status-detection.d.ts +7 -0
  41. package/lib/Utils/group-status-detection.d.ts.map +1 -0
  42. package/lib/Utils/group-status-detection.js +72 -0
  43. package/lib/Utils/group-status-detection.js.map +1 -0
  44. package/lib/Utils/index.d.ts +3 -0
  45. package/lib/Utils/index.d.ts.map +1 -1
  46. package/lib/Utils/index.js +3 -0
  47. package/lib/Utils/index.js.map +1 -1
  48. package/lib/Utils/message-retry-manager.d.ts.map +1 -1
  49. package/lib/Utils/message-retry-manager.js.map +1 -1
  50. package/lib/Utils/messages-media.d.ts +1 -0
  51. package/lib/Utils/messages-media.d.ts.map +1 -1
  52. package/lib/Utils/messages-media.js +92 -0
  53. package/lib/Utils/messages-media.js.map +1 -1
  54. package/lib/Utils/messages-newsletter.d.ts +34 -0
  55. package/lib/Utils/messages-newsletter.d.ts.map +1 -1
  56. package/lib/Utils/messages-newsletter.js +67 -0
  57. package/lib/Utils/messages-newsletter.js.map +1 -1
  58. package/lib/Utils/messages.d.ts +3 -46
  59. package/lib/Utils/messages.d.ts.map +1 -1
  60. package/lib/Utils/messages.js +306 -84
  61. package/lib/Utils/messages.js.map +1 -1
  62. package/lib/Utils/scheduling.d.ts +46 -0
  63. package/lib/Utils/scheduling.d.ts.map +1 -0
  64. package/lib/Utils/scheduling.js +117 -0
  65. package/lib/Utils/scheduling.js.map +1 -0
  66. package/lib/Utils/signal.d.ts +0 -4
  67. package/lib/Utils/signal.d.ts.map +1 -1
  68. package/lib/Utils/signal.js +7 -14
  69. package/lib/Utils/signal.js.map +1 -1
  70. package/lib/Utils/use-sqlite-auth-state.d.ts +1 -0
  71. package/lib/Utils/use-sqlite-auth-state.d.ts.map +1 -1
  72. package/lib/Utils/use-sqlite-auth-state.js +18 -3
  73. package/lib/Utils/use-sqlite-auth-state.js.map +1 -1
  74. package/lib/Utils/validate-connection.d.ts.map +1 -1
  75. package/lib/Utils/validate-connection.js +1 -4
  76. package/lib/Utils/validate-connection.js.map +1 -1
  77. package/package.json +1 -1
@@ -6,11 +6,11 @@ import { join } from 'path';
6
6
  import {} from 'stream';
7
7
  import { proto } from '../../WAProto/index.js';
8
8
  import { CALL_AUDIO_PREFIX, CALL_VIDEO_PREFIX, MEDIA_KEYS, URL_REGEX, WA_DEFAULT_EPHEMERAL } from '../Defaults/index.js';
9
- import { WAMessageStatus, WAProto } from '../Types/index.js';
9
+ import { CarouselCardType, ListType, WAMessageStatus, WAProto } from '../Types/index.js';
10
10
  import { isJidGroup, isJidNewsletter, isJidStatusBroadcast, jidNormalizedUser } from '../WABinary/index.js';
11
11
  import { sha256 } from './crypto.js';
12
12
  import { generateMessageIDV2, getKeyAuthor, unixTimestampSeconds } from './generics.js';
13
- import { downloadContentFromMessage, encryptedStream, generateThumbnail, getAudioDuration, getAudioWaveform, getMediaKeys, getRawMediaUploadData, getStream, toBuffer } from './messages-media.js';
13
+ import { downloadContentFromMessage, encryptedStream, generateThumbnail, getAudioDuration, getAudioWaveform, getMediaKeys, getRawMediaUploadData, getStream, toBuffer, transcodeAudioToOpus } from './messages-media.js';
14
14
  import { shouldIncludeReportingToken } from './reporting-utils.js';
15
15
  const MIMETYPE_MAP = {
16
16
  image: 'image/jpeg',
@@ -27,11 +27,6 @@ const MessageTypeProto = {
27
27
  sticker: WAProto.Message.StickerMessage,
28
28
  document: WAProto.Message.DocumentMessage
29
29
  };
30
- /**
31
- * Uses a regex to test whether the string contains a URL, and returns the URL if it does.
32
- * @param text eg. hello https://google.com
33
- * @returns the URL, eg. https://google.com
34
- */
35
30
  export const extractUrlFromText = (text) => text.match(URL_REGEX)?.[0];
36
31
  export const generateLinkPreviewIfRequired = async (text, getUrlInfo, logger) => {
37
32
  const url = extractUrlFromText(text);
@@ -41,7 +36,6 @@ export const generateLinkPreviewIfRequired = async (text, getUrlInfo, logger) =>
41
36
  return urlInfo;
42
37
  }
43
38
  catch (error) {
44
- // ignore if fails
45
39
  logger?.warn({ trace: error.stack }, 'url generation failed');
46
40
  }
47
41
  }
@@ -232,7 +226,6 @@ export const prepareWAMessageMedia = async (message, options) => {
232
226
  media: message[mediaType]
233
227
  };
234
228
  delete uploadData[mediaType];
235
- // check if cacheable + generate cache key
236
229
  const cacheableKey = typeof uploadData.media === 'object' &&
237
230
  'url' in uploadData.media &&
238
231
  !!uploadData.media.url &&
@@ -244,6 +237,18 @@ export const prepareWAMessageMedia = async (message, options) => {
244
237
  if (!uploadData.mimetype) {
245
238
  uploadData.mimetype = MIMETYPE_MAP[mediaType];
246
239
  }
240
+ let pttTranscodedPath;
241
+ if (mediaType === 'audio' && uploadData.ptt === true) {
242
+ const media = uploadData.media;
243
+ const mediaUrl = typeof media === 'string' ? media : media?.url?.toString?.() || '';
244
+ const sourceLooksLikeOpus = /\.(opus|ogg)(\?|$)/i.test(mediaUrl);
245
+ if (!sourceLooksLikeOpus) {
246
+ const sourceForTranscode = Buffer.isBuffer(media) ? media : typeof media === 'string' ? media : mediaUrl;
247
+ pttTranscodedPath = await transcodeAudioToOpus(sourceForTranscode);
248
+ uploadData.media = { url: pttTranscodedPath };
249
+ }
250
+ uploadData.mimetype = 'audio/ogg; codecs=opus';
251
+ }
247
252
  if (cacheableKey) {
248
253
  const mediaBuff = await options.mediaCache.get(cacheableKey);
249
254
  if (mediaBuff) {
@@ -266,7 +271,6 @@ export const prepareWAMessageMedia = async (message, options) => {
266
271
  });
267
272
  await fs.unlink(filePath);
268
273
  const obj = WAProto.Message.fromObject({
269
- // todo: add more support here
270
274
  [`${mediaType}Message`]: MessageTypeProto[mediaType].fromObject({
271
275
  url: mediaUrl,
272
276
  directPath,
@@ -345,6 +349,9 @@ export const prepareWAMessageMedia = async (message, options) => {
345
349
  if (originalFilePath) {
346
350
  await fs.unlink(originalFilePath);
347
351
  }
352
+ if (pttTranscodedPath) {
353
+ await fs.unlink(pttTranscodedPath);
354
+ }
348
355
  logger?.debug('removed tmp files');
349
356
  }
350
357
  catch (error) {
@@ -388,17 +395,11 @@ export const prepareDisappearingMessageSettingContent = (ephemeralExpiration) =>
388
395
  };
389
396
  return WAProto.Message.fromObject(content);
390
397
  };
391
- /**
392
- * Generate forwarded message content like WA does
393
- * @param message the message to forward
394
- * @param options.forceForward will show the message as forwarded even if it is from you
395
- */
396
398
  export const generateForwardMessageContent = (message, forceForward) => {
397
399
  let content = message.message;
398
400
  if (!content) {
399
401
  throw new Boom('no content in message', { statusCode: 400 });
400
402
  }
401
- // hacky copy
402
403
  content = normalizeMessageContent(content);
403
404
  content = proto.Message.decode(proto.Message.encode(content).finish());
404
405
  let key = Object.keys(content)[0];
@@ -428,10 +429,269 @@ export const hasNonNullishProperty = (message, key) => {
428
429
  function hasOptionalProperty(obj, key) {
429
430
  return typeof obj === 'object' && obj !== null && key in obj && obj[key] !== null;
430
431
  }
432
+ const prepareNativeFlowButtons = (message) => {
433
+ const buttons = message.nativeFlow;
434
+ const correctedField = Array.isArray(buttons) ? buttons : buttons.buttons;
435
+ return {
436
+ buttons: correctedField.map((button) => {
437
+ const buttonText = button.text || button.buttonText;
438
+ const icon = button.icon?.toUpperCase();
439
+ if (button.id) {
440
+ return {
441
+ name: 'quick_reply',
442
+ buttonParamsJson: JSON.stringify({ display_text: buttonText || 'Click', id: button.id, icon })
443
+ };
444
+ }
445
+ else if (button.copy) {
446
+ return {
447
+ name: 'cta_copy',
448
+ buttonParamsJson: JSON.stringify({ display_text: buttonText || 'Copy', copy_code: button.copy, icon })
449
+ };
450
+ }
451
+ else if (button.url) {
452
+ return {
453
+ name: 'cta_url',
454
+ buttonParamsJson: JSON.stringify({
455
+ display_text: buttonText || 'Visit',
456
+ url: button.url,
457
+ merchant_url: button.url,
458
+ webview_interaction: button.useWebview,
459
+ icon
460
+ })
461
+ };
462
+ }
463
+ else if (button.call) {
464
+ return {
465
+ name: 'cta_call',
466
+ buttonParamsJson: JSON.stringify({ display_text: buttonText || 'Call', phone_number: button.call, icon })
467
+ };
468
+ }
469
+ else if (button.sections) {
470
+ return {
471
+ name: 'single_select',
472
+ buttonParamsJson: JSON.stringify({ title: buttonText || 'Select', sections: button.sections, icon })
473
+ };
474
+ }
475
+ return { name: button.name, buttonParamsJson: button.paramsJson };
476
+ })
477
+ };
478
+ };
479
+ export const hasValidInteractiveHeader = (message) => {
480
+ return !!(message.imageMessage ||
481
+ message.videoMessage ||
482
+ message.documentMessage ||
483
+ message.productMessage ||
484
+ message.locationMessage);
485
+ };
486
+ export const hasValidCarouselHeader = (message) => {
487
+ return !!(message.imageMessage || message.videoMessage || message.productMessage);
488
+ };
431
489
  export const generateWAMessageContent = async (message, options) => {
432
490
  var _a, _b;
433
491
  let m = {};
434
- if (hasNonNullishProperty(message, 'text')) {
492
+ if (hasNonNullishProperty(message, 'raw')) {
493
+ delete message.raw;
494
+ return message;
495
+ }
496
+ else if (hasNonNullishProperty(message, 'buttons')) {
497
+ const nativeButtons = message.buttons.map((button) => {
498
+ if (button.nativeFlowInfo) {
499
+ return { name: button.nativeFlowInfo.name, buttonParamsJson: button.nativeFlowInfo.paramsJson };
500
+ }
501
+ if (button.name && (button.buttonParamsJson || button.paramsJson)) {
502
+ return { name: button.name, buttonParamsJson: button.buttonParamsJson || button.paramsJson };
503
+ }
504
+ const buttonText = button.text || (typeof button.buttonText === 'string' ? button.buttonText : button.buttonText?.displayText);
505
+ const id = button.id || button.buttonId || buttonText;
506
+ const icon = button.icon?.toUpperCase();
507
+ if (button.sections) {
508
+ return {
509
+ name: 'single_select',
510
+ buttonParamsJson: JSON.stringify({ title: buttonText || 'Select', sections: button.sections, icon })
511
+ };
512
+ }
513
+ else if (button.url) {
514
+ return {
515
+ name: 'cta_url',
516
+ buttonParamsJson: JSON.stringify({
517
+ display_text: buttonText || 'Visit',
518
+ url: button.url,
519
+ merchant_url: button.url,
520
+ webview_interaction: button.useWebview,
521
+ icon
522
+ })
523
+ };
524
+ }
525
+ else if (button.call) {
526
+ return {
527
+ name: 'cta_call',
528
+ buttonParamsJson: JSON.stringify({ display_text: buttonText || 'Call', phone_number: button.call, icon })
529
+ };
530
+ }
531
+ else if (button.copy) {
532
+ return {
533
+ name: 'cta_copy',
534
+ buttonParamsJson: JSON.stringify({ display_text: buttonText || 'Copy', copy_code: button.copy, icon })
535
+ };
536
+ }
537
+ return {
538
+ name: 'quick_reply',
539
+ buttonParamsJson: JSON.stringify({ display_text: buttonText || 'Click', id, icon })
540
+ };
541
+ });
542
+ const interactiveMessage = {
543
+ nativeFlowMessage: { buttons: nativeButtons, messageParamsJson: '{}' }
544
+ };
545
+ if (message.text) {
546
+ interactiveMessage.body = { text: message.text };
547
+ interactiveMessage.header = { title: '', subtitle: '', hasMediaAttachment: false };
548
+ }
549
+ else {
550
+ const media = await prepareWAMessageMedia(message, options);
551
+ const mediaKey = Object.keys(media)[0];
552
+ if (!mediaKey) {
553
+ throw new Boom('buttons message needs either "text" or a media field (image/video/document) as header', {
554
+ statusCode: 400
555
+ });
556
+ }
557
+ interactiveMessage.body = { text: message.caption || '' };
558
+ interactiveMessage.header = {
559
+ title: '',
560
+ subtitle: '',
561
+ hasMediaAttachment: true,
562
+ ...media
563
+ };
564
+ }
565
+ if (message.footer) {
566
+ interactiveMessage.footer = { text: message.footer };
567
+ }
568
+ m.interactiveMessage = interactiveMessage;
569
+ }
570
+ else if (hasNonNullishProperty(message, 'sections')) {
571
+ m.listMessage = {
572
+ sections: message.sections,
573
+ buttonText: message.buttonText,
574
+ title: message.title,
575
+ footerText: message.footer,
576
+ description: message.description,
577
+ listType: ListType.SINGLE_SELECT
578
+ };
579
+ }
580
+ else if (hasNonNullishProperty(message, 'templateButtons')) {
581
+ const hydratedTemplate = {
582
+ hydratedButtons: message.templateButtons.map((button, i) => {
583
+ const buttonText = button.text || button.buttonText;
584
+ if (button.id) {
585
+ return { index: i, quickReplyButton: { displayText: buttonText || 'Click', id: button.id } };
586
+ }
587
+ else if (button.url) {
588
+ return { index: i, urlButton: { displayText: buttonText || 'Visit', url: button.url } };
589
+ }
590
+ else if (button.call) {
591
+ return { index: i, callButton: { displayText: buttonText || 'Call', phoneNumber: button.call } };
592
+ }
593
+ button.index = button.index || i;
594
+ return button;
595
+ })
596
+ };
597
+ if (message.text) {
598
+ hydratedTemplate.hydratedContentText = message.text;
599
+ }
600
+ else {
601
+ const media = await prepareWAMessageMedia(message, options);
602
+ if (message.caption) {
603
+ hydratedTemplate.hydratedTitleText = message.title;
604
+ hydratedTemplate.hydratedContentText = message.caption;
605
+ }
606
+ Object.assign(hydratedTemplate, media);
607
+ }
608
+ if (message.footer) {
609
+ hydratedTemplate.hydratedFooterText = message.footer;
610
+ }
611
+ hydratedTemplate.templateId = message.id || `template-${Date.now()}`;
612
+ m.templateMessage = {
613
+ hydratedFourRowTemplate: hydratedTemplate,
614
+ hydratedTemplate
615
+ };
616
+ }
617
+ else if (hasNonNullishProperty(message, 'nativeFlow')) {
618
+ const interactiveMessage = {
619
+ nativeFlowMessage: prepareNativeFlowButtons(message)
620
+ };
621
+ if (message.text) {
622
+ interactiveMessage.body = { text: message.text };
623
+ }
624
+ else {
625
+ const media = await prepareWAMessageMedia(message, options);
626
+ if (message.caption) {
627
+ const isValidHeader = hasValidInteractiveHeader(media);
628
+ if (!isValidHeader) {
629
+ throw new Boom('Invalid media type for interactive message header', { statusCode: 400 });
630
+ }
631
+ interactiveMessage.header = {
632
+ title: message.title || '',
633
+ subtitle: message.subtitle || '',
634
+ hasMediaAttachment: isValidHeader
635
+ };
636
+ interactiveMessage.body = { text: message.caption };
637
+ }
638
+ Object.assign(interactiveMessage.header || (interactiveMessage.header = {}), media);
639
+ }
640
+ if (message.audioFooter) {
641
+ const { audioMessage } = await prepareWAMessageMedia({ audio: message.audioFooter }, options);
642
+ interactiveMessage.footer = { audioMessage, hasMediaAttachment: true };
643
+ }
644
+ else if (message.footer) {
645
+ interactiveMessage.footer = { text: message.footer };
646
+ }
647
+ m.interactiveMessage = interactiveMessage;
648
+ }
649
+ else if (hasNonNullishProperty(message, 'cards')) {
650
+ const interactiveMessage = {
651
+ carouselMessage: {
652
+ cards: await Promise.all(message.cards.map(async (card) => {
653
+ const carouselHeader = await prepareWAMessageMedia(card, options).catch(() => ({}));
654
+ const isValidHeader = hasValidCarouselHeader(carouselHeader);
655
+ if (!isValidHeader) {
656
+ throw new Boom('Invalid media type for carousel card', { statusCode: 400 });
657
+ }
658
+ const carouselCard = {
659
+ nativeFlowMessage: prepareNativeFlowButtons({ nativeFlow: card.nativeFlow || [] })
660
+ };
661
+ if (card.text) {
662
+ carouselCard.body = { text: card.text };
663
+ }
664
+ else if (card.caption) {
665
+ carouselCard.header = {
666
+ title: card.title || '',
667
+ subtitle: card.subtitle || '',
668
+ hasMediaAttachment: isValidHeader,
669
+ ...carouselHeader
670
+ };
671
+ carouselCard.body = { text: card.caption };
672
+ }
673
+ if (card.audioFooter) {
674
+ const { audioMessage } = await prepareWAMessageMedia({ audio: card.audioFooter }, options);
675
+ carouselCard.footer = { audioMessage, hasMediaAttachment: true };
676
+ }
677
+ else if (card.footer) {
678
+ carouselCard.footer = { text: card.footer };
679
+ }
680
+ if (card.contextInfo) {
681
+ carouselCard.contextInfo = card.contextInfo;
682
+ }
683
+ return carouselCard;
684
+ })),
685
+ carouselCardType: CarouselCardType.UNKNOWN,
686
+ messageVersion: 1
687
+ }
688
+ };
689
+ if (message.footer) {
690
+ interactiveMessage.footer = { text: message.footer };
691
+ }
692
+ m.interactiveMessage = interactiveMessage;
693
+ }
694
+ else if (hasNonNullishProperty(message, 'text')) {
435
695
  const extContent = { text: message.text };
436
696
  let urlInfo = message.linkPreview;
437
697
  if (typeof urlInfo === 'undefined') {
@@ -507,8 +767,6 @@ export const generateWAMessageContent = async (message, options) => {
507
767
  m.groupInviteMessage.caption = message.groupInvite.text;
508
768
  m.groupInviteMessage.groupJid = message.groupInvite.jid;
509
769
  m.groupInviteMessage.groupName = message.groupInvite.subject;
510
- //TODO: use built-in interface and get disappearing mode info etc.
511
- //TODO: cache / use store!?
512
770
  if (options.getProfilePicUrl) {
513
771
  const pfpUrl = await options.getProfilePicUrl(message.groupInvite.jid, 'preview');
514
772
  if (pfpUrl) {
@@ -553,7 +811,6 @@ export const generateWAMessageContent = async (message, options) => {
553
811
  m.eventMessage.joinLink = (message.event.call === 'audio' ? CALL_AUDIO_PREFIX : CALL_VIDEO_PREFIX) + token;
554
812
  }
555
813
  m.messageContextInfo = {
556
- // encKey
557
814
  messageSecret: message.event.messageSecret || randomBytes(32)
558
815
  };
559
816
  m.eventMessage.name = message.event.name;
@@ -565,6 +822,24 @@ export const generateWAMessageContent = async (message, options) => {
565
822
  m.eventMessage.isScheduleCall = message.event.isScheduleCall ?? false;
566
823
  m.eventMessage.location = message.event.location;
567
824
  }
825
+ else if (hasNonNullishProperty(message, 'buttonReply')) {
826
+ switch (message.type) {
827
+ case 'template':
828
+ m.templateButtonReplyMessage = {
829
+ selectedDisplayText: message.buttonReply.displayText,
830
+ selectedId: message.buttonReply.id,
831
+ selectedIndex: message.buttonReply.index
832
+ };
833
+ break;
834
+ case 'plain':
835
+ m.buttonsResponseMessage = {
836
+ selectedButtonId: message.buttonReply.id,
837
+ selectedDisplayText: message.buttonReply.displayText,
838
+ type: proto.Message.ButtonsResponseMessage.Type.DISPLAY_TEXT
839
+ };
840
+ break;
841
+ }
842
+ }
568
843
  else if (hasNonNullishProperty(message, 'poll')) {
569
844
  (_a = message.poll).selectableCount || (_a.selectableCount = 0);
570
845
  (_b = message.poll).toAnnouncementGroup || (_b.toAnnouncementGroup = false);
@@ -577,7 +852,6 @@ export const generateWAMessageContent = async (message, options) => {
577
852
  });
578
853
  }
579
854
  m.messageContextInfo = {
580
- // encKey
581
855
  messageSecret: message.poll.messageSecret || randomBytes(32)
582
856
  };
583
857
  const pollCreationMessage = {
@@ -586,16 +860,13 @@ export const generateWAMessageContent = async (message, options) => {
586
860
  options: message.poll.values.map(optionName => ({ optionName }))
587
861
  };
588
862
  if (message.poll.toAnnouncementGroup) {
589
- // poll v2 is for community announcement groups (single select and multiple)
590
863
  m.pollCreationMessageV2 = pollCreationMessage;
591
864
  }
592
865
  else {
593
866
  if (message.poll.selectableCount === 1) {
594
- //poll v3 is for single select polls
595
867
  m.pollCreationMessageV3 = pollCreationMessage;
596
868
  }
597
869
  else {
598
- // poll for multiple choice polls
599
870
  m.pollCreationMessage = pollCreationMessage;
600
871
  }
601
872
  }
@@ -705,8 +976,6 @@ export const generateWAMessageContent = async (message, options) => {
705
976
  return WAProto.Message.create(m);
706
977
  };
707
978
  export const generateWAMessageFromContent = (jid, message, options) => {
708
- // set timestamp to now
709
- // if not specified
710
979
  if (!options.timestamp) {
711
980
  options.timestamp = new Date();
712
981
  }
@@ -716,11 +985,10 @@ export const generateWAMessageFromContent = (jid, message, options) => {
716
985
  const { quoted, userJid } = options;
717
986
  if (quoted && !isJidNewsletter(jid)) {
718
987
  const participant = quoted.key.fromMe
719
- ? userJid // TODO: Add support for LIDs
988
+ ? userJid
720
989
  : quoted.participant || quoted.key.participant || quoted.key.remoteJid;
721
990
  let quotedMsg = normalizeMessageContent(quoted.message);
722
991
  const msgType = getContentType(quotedMsg);
723
- // strip any redundant properties
724
992
  quotedMsg = proto.Message.create({ [msgType]: quotedMsg[msgType] });
725
993
  const quotedContent = quotedMsg[msgType];
726
994
  if (typeof quotedContent === 'object' && quotedContent && 'contextInfo' in quotedContent) {
@@ -730,30 +998,23 @@ export const generateWAMessageFromContent = (jid, message, options) => {
730
998
  contextInfo.participant = jidNormalizedUser(participant);
731
999
  contextInfo.stanzaId = quoted.key.id;
732
1000
  contextInfo.quotedMessage = quotedMsg;
733
- // if a participant is quoted, then it must be a group
734
- // hence, remoteJid of group must also be entered
735
1001
  if (jid !== quoted.key.remoteJid) {
736
1002
  contextInfo.remoteJid = quoted.key.remoteJid;
737
1003
  }
738
1004
  if (contextInfo && innerMessage[key]) {
739
- /* @ts-ignore */
1005
+ ;
740
1006
  innerMessage[key].contextInfo = contextInfo;
741
1007
  }
742
1008
  }
743
- if (
744
- // if we want to send a disappearing message
745
- !!options?.ephemeralExpiration &&
746
- // and it's not a protocol message -- delete, toggle disappear message
1009
+ if (!!options?.ephemeralExpiration &&
747
1010
  key !== 'protocolMessage' &&
748
- // already not converted to disappearing message
749
1011
  key !== 'ephemeralMessage' &&
750
- // newsletters don't support ephemeral messages
751
- !isJidNewsletter(jid)) {
752
- /* @ts-ignore */
753
- innerMessage[key].contextInfo = {
754
- ...(innerMessage[key].contextInfo || {}),
755
- expiration: options.ephemeralExpiration || WA_DEFAULT_EPHEMERAL
756
- //ephemeralSettingTimestamp: options.ephemeralOptions.eph_setting_ts?.toString()
1012
+ !isJidNewsletter(jid) &&
1013
+ innerMessage[key]) {
1014
+ const target = innerMessage[key];
1015
+ target.contextInfo = {
1016
+ ...(target.contextInfo || {}),
1017
+ expiration: Number(options.ephemeralExpiration) || WA_DEFAULT_EPHEMERAL
757
1018
  };
758
1019
  }
759
1020
  message = WAProto.Message.create(message);
@@ -766,18 +1027,15 @@ export const generateWAMessageFromContent = (jid, message, options) => {
766
1027
  message: message,
767
1028
  messageTimestamp: timestamp,
768
1029
  messageStubParameters: [],
769
- participant: isJidGroup(jid) || isJidStatusBroadcast(jid) ? userJid : undefined, // TODO: Add support for LIDs
1030
+ participant: isJidGroup(jid) || isJidStatusBroadcast(jid) ? userJid : undefined,
770
1031
  status: WAMessageStatus.PENDING
771
1032
  };
772
1033
  return WAProto.WebMessageInfo.fromObject(messageJSON);
773
1034
  };
774
1035
  export const generateWAMessage = async (jid, content, options) => {
775
- // ensure msg ID is with every log
776
1036
  options.logger = options?.logger?.child({ msgId: options.messageId });
777
- // Pass jid in the options to generateWAMessageContent
778
1037
  return generateWAMessageFromContent(jid, await generateWAMessageContent(content, { ...options, jid }), options);
779
1038
  };
780
- /** Get the key to access the true type of content */
781
1039
  export const getContentType = (content) => {
782
1040
  if (content) {
783
1041
  const keys = Object.keys(content);
@@ -785,17 +1043,10 @@ export const getContentType = (content) => {
785
1043
  return key;
786
1044
  }
787
1045
  };
788
- /**
789
- * Normalizes ephemeral, view once messages to regular message content
790
- * Eg. image messages in ephemeral messages, in view once messages etc.
791
- * @param content
792
- * @returns
793
- */
794
1046
  export const normalizeMessageContent = (content) => {
795
1047
  if (!content) {
796
1048
  return undefined;
797
1049
  }
798
- // set max iterations to prevent an infinite loop
799
1050
  for (let i = 0; i < 5; i++) {
800
1051
  const inner = getFutureProofMessage(content);
801
1052
  if (!inner) {
@@ -817,10 +1068,6 @@ export const normalizeMessageContent = (content) => {
817
1068
  message?.lottieStickerMessage);
818
1069
  }
819
1070
  };
820
- /**
821
- * Extract the true message content from a message
822
- * Eg. extracts the inner message from a disappearing message/view once message
823
- */
824
1071
  export const extractMessageContent = (content) => {
825
1072
  const extractFromTemplateMessage = (msg) => {
826
1073
  if (msg.imageMessage) {
@@ -856,9 +1103,6 @@ export const extractMessageContent = (content) => {
856
1103
  }
857
1104
  return content;
858
1105
  };
859
- /**
860
- * Returns the device predicted by message ID
861
- */
862
1106
  export const getDevice = (id) => /^3A.{18}$/.test(id)
863
1107
  ? 'ios'
864
1108
  : /^3E.{20}$/.test(id)
@@ -868,7 +1112,6 @@ export const getDevice = (id) => /^3A.{18}$/.test(id)
868
1112
  : /^(3F|.{18}$)/.test(id)
869
1113
  ? 'desktop'
870
1114
  : 'unknown';
871
- /** Upserts a receipt in the message */
872
1115
  export const updateMessageWithReceipt = (msg, receipt) => {
873
1116
  msg.userReceipt = msg.userReceipt || [];
874
1117
  const recp = msg.userReceipt.find(m => m.userJid === receipt.userJid);
@@ -879,7 +1122,6 @@ export const updateMessageWithReceipt = (msg, receipt) => {
879
1122
  msg.userReceipt.push(receipt);
880
1123
  }
881
1124
  };
882
- /** Update the message with a new reaction */
883
1125
  export const updateMessageWithReaction = (msg, reaction) => {
884
1126
  const authorID = getKeyAuthor(reaction.key);
885
1127
  const reactions = (msg.reactions || []).filter(r => getKeyAuthor(r.key) !== authorID);
@@ -887,7 +1129,6 @@ export const updateMessageWithReaction = (msg, reaction) => {
887
1129
  reactions.push(reaction);
888
1130
  msg.reactions = reactions;
889
1131
  };
890
- /** Update the message with a new poll update */
891
1132
  export const updateMessageWithPollUpdate = (msg, update) => {
892
1133
  const authorID = getKeyAuthor(update.pollUpdateMessageKey);
893
1134
  const reactions = (msg.pollUpdates || []).filter(r => getKeyAuthor(r.pollUpdateMessageKey) !== authorID);
@@ -896,19 +1137,12 @@ export const updateMessageWithPollUpdate = (msg, update) => {
896
1137
  }
897
1138
  msg.pollUpdates = reactions;
898
1139
  };
899
- /** Update the message with a new event response */
900
1140
  export const updateMessageWithEventResponse = (msg, update) => {
901
1141
  const authorID = getKeyAuthor(update.eventResponseMessageKey);
902
1142
  const responses = (msg.eventResponses || []).filter(r => getKeyAuthor(r.eventResponseMessageKey) !== authorID);
903
1143
  responses.push(update);
904
1144
  msg.eventResponses = responses;
905
1145
  };
906
- /**
907
- * Aggregates all poll updates in a poll.
908
- * @param msg the poll creation message
909
- * @param meId your jid
910
- * @returns A list of options & their voters
911
- */
912
1146
  export function getAggregateVotesInPollMessage({ message, pollUpdates }, meId) {
913
1147
  const opts = message?.pollCreationMessage?.options ||
914
1148
  message?.pollCreationMessageV2?.options ||
@@ -942,12 +1176,6 @@ export function getAggregateVotesInPollMessage({ message, pollUpdates }, meId) {
942
1176
  }
943
1177
  return Object.values(voteHashMap);
944
1178
  }
945
- /**
946
- * Aggregates all event responses in an event message.
947
- * @param msg the event creation message
948
- * @param meId your jid
949
- * @returns A list of response types & their responders
950
- */
951
1179
  export function getAggregateResponsesInEventMessage({ eventResponses }, meId) {
952
1180
  const responseTypes = ['GOING', 'NOT_GOING', 'MAYBE'];
953
1181
  const responseMap = {};
@@ -965,7 +1193,6 @@ export function getAggregateResponsesInEventMessage({ eventResponses }, meId) {
965
1193
  }
966
1194
  return Object.values(responseMap);
967
1195
  }
968
- /** Given a list of message keys, aggregates them by chat & sender. Useful for sending read receipts in bulk */
969
1196
  export const aggregateMessageKeysNotFromMe = (keys) => {
970
1197
  const keyMap = {};
971
1198
  for (const { remoteJid, id, participant, fromMe } of keys) {
@@ -984,16 +1211,12 @@ export const aggregateMessageKeysNotFromMe = (keys) => {
984
1211
  return Object.values(keyMap);
985
1212
  };
986
1213
  const REUPLOAD_REQUIRED_STATUS = [410, 404];
987
- /**
988
- * Downloads the given message. Throws an error if it's not a media message
989
- */
990
1214
  export const downloadMediaMessage = async (message, type, options, ctx) => {
991
1215
  const result = await downloadMsg().catch(async (error) => {
992
1216
  if (ctx &&
993
- typeof error?.status === 'number' && // treat errors with status as HTTP failures requiring reupload
1217
+ typeof error?.status === 'number' &&
994
1218
  REUPLOAD_REQUIRED_STATUS.includes(error.status)) {
995
1219
  ctx.logger.info({ key: message.key }, 'sending reupload media request...');
996
- // request reupload
997
1220
  message = await ctx.reuploadRequest(message);
998
1221
  const result = await downloadMsg();
999
1222
  return result;
@@ -1034,7 +1257,6 @@ export const downloadMediaMessage = async (message, type, options, ctx) => {
1034
1257
  return stream;
1035
1258
  }
1036
1259
  };
1037
- /** Checks whether the given message is a media message; if it is returns the inner content */
1038
1260
  export const assertMediaContent = (content) => {
1039
1261
  content = extractMessageContent(content);
1040
1262
  const mediaContent = content?.documentMessage ||