@neykoor/baileys 7.0.4-rc15 → 7.0.7-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 (88) hide show
  1. package/lib/Defaults/index.d.ts +0 -4
  2. package/lib/Defaults/index.d.ts.map +1 -1
  3. package/lib/Defaults/index.js +7 -11
  4. package/lib/Defaults/index.js.map +1 -1
  5. package/lib/Signal/lid-mapping.d.ts.map +1 -1
  6. package/lib/Signal/lid-mapping.js.map +1 -1
  7. package/lib/Socket/business.d.ts +35 -0
  8. package/lib/Socket/business.d.ts.map +1 -1
  9. package/lib/Socket/chats.d.ts +3 -1
  10. package/lib/Socket/chats.d.ts.map +1 -1
  11. package/lib/Socket/chats.js +32 -3
  12. package/lib/Socket/chats.js.map +1 -1
  13. package/lib/Socket/communities.d.ts +35 -0
  14. package/lib/Socket/communities.d.ts.map +1 -1
  15. package/lib/Socket/groups.d.ts +2 -0
  16. package/lib/Socket/groups.d.ts.map +1 -1
  17. package/lib/Socket/groups.js +7 -2
  18. package/lib/Socket/groups.js.map +1 -1
  19. package/lib/Socket/index.d.ts +35 -0
  20. package/lib/Socket/index.d.ts.map +1 -1
  21. package/lib/Socket/messages-recv.d.ts +35 -0
  22. package/lib/Socket/messages-recv.d.ts.map +1 -1
  23. package/lib/Socket/messages-send.d.ts +36 -1
  24. package/lib/Socket/messages-send.d.ts.map +1 -1
  25. package/lib/Socket/messages-send.js +139 -65
  26. package/lib/Socket/messages-send.js.map +1 -1
  27. package/lib/Socket/newsletter.d.ts +2 -0
  28. package/lib/Socket/newsletter.d.ts.map +1 -1
  29. package/lib/Socket/smgss.d.ts +203 -0
  30. package/lib/Socket/smgss.d.ts.map +1 -0
  31. package/lib/Socket/smgss.js +461 -0
  32. package/lib/Socket/smgss.js.map +1 -0
  33. package/lib/Store/make-in-memory-store.d.ts.map +1 -1
  34. package/lib/Store/make-in-memory-store.js +12 -10
  35. package/lib/Store/make-in-memory-store.js.map +1 -1
  36. package/lib/Types/Message.d.ts +94 -2
  37. package/lib/Types/Message.d.ts.map +1 -1
  38. package/lib/Types/Message.js +4 -0
  39. package/lib/Types/Message.js.map +1 -1
  40. package/lib/Utils/connection-watchdog.d.ts +30 -0
  41. package/lib/Utils/connection-watchdog.d.ts.map +1 -0
  42. package/lib/Utils/connection-watchdog.js +66 -0
  43. package/lib/Utils/connection-watchdog.js.map +1 -0
  44. package/lib/Utils/generics.d.ts +0 -8
  45. package/lib/Utils/generics.d.ts.map +1 -1
  46. package/lib/Utils/generics.js +2 -15
  47. package/lib/Utils/generics.js.map +1 -1
  48. package/lib/Utils/group-status-detection.d.ts +7 -0
  49. package/lib/Utils/group-status-detection.d.ts.map +1 -0
  50. package/lib/Utils/group-status-detection.js +72 -0
  51. package/lib/Utils/group-status-detection.js.map +1 -0
  52. package/lib/Utils/index.d.ts +3 -0
  53. package/lib/Utils/index.d.ts.map +1 -1
  54. package/lib/Utils/index.js +3 -0
  55. package/lib/Utils/index.js.map +1 -1
  56. package/lib/Utils/message-composer.d.ts +2 -2
  57. package/lib/Utils/message-composer.d.ts.map +1 -1
  58. package/lib/Utils/message-composer.js.map +1 -1
  59. package/lib/Utils/message-retry-manager.d.ts.map +1 -1
  60. package/lib/Utils/message-retry-manager.js.map +1 -1
  61. package/lib/Utils/messages-media.d.ts +1 -0
  62. package/lib/Utils/messages-media.d.ts.map +1 -1
  63. package/lib/Utils/messages-media.js +92 -0
  64. package/lib/Utils/messages-media.js.map +1 -1
  65. package/lib/Utils/messages-newsletter.d.ts +34 -0
  66. package/lib/Utils/messages-newsletter.d.ts.map +1 -1
  67. package/lib/Utils/messages-newsletter.js +67 -0
  68. package/lib/Utils/messages-newsletter.js.map +1 -1
  69. package/lib/Utils/messages.d.ts +3 -46
  70. package/lib/Utils/messages.d.ts.map +1 -1
  71. package/lib/Utils/messages.js +290 -84
  72. package/lib/Utils/messages.js.map +1 -1
  73. package/lib/Utils/scheduling.d.ts +46 -0
  74. package/lib/Utils/scheduling.d.ts.map +1 -0
  75. package/lib/Utils/scheduling.js +117 -0
  76. package/lib/Utils/scheduling.js.map +1 -0
  77. package/lib/Utils/signal.d.ts +0 -4
  78. package/lib/Utils/signal.d.ts.map +1 -1
  79. package/lib/Utils/signal.js +7 -14
  80. package/lib/Utils/signal.js.map +1 -1
  81. package/lib/Utils/use-sqlite-auth-state.d.ts +1 -0
  82. package/lib/Utils/use-sqlite-auth-state.d.ts.map +1 -1
  83. package/lib/Utils/use-sqlite-auth-state.js +18 -3
  84. package/lib/Utils/use-sqlite-auth-state.js.map +1 -1
  85. package/lib/Utils/validate-connection.d.ts.map +1 -1
  86. package/lib/Utils/validate-connection.js +1 -4
  87. package/lib/Utils/validate-connection.js.map +1 -1
  88. 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 { ButtonHeaderType, ButtonType, 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,253 @@ 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 buttonsMessage = {
498
+ buttons: message.buttons.map((button) => {
499
+ const buttonText = button.text || button.buttonText;
500
+ if (button.nativeFlowInfo) {
501
+ return {
502
+ buttonId: button.id || button.buttonId,
503
+ buttonText: typeof buttonText === 'string' ? { displayText: buttonText } : buttonText,
504
+ nativeFlowInfo: button.nativeFlowInfo,
505
+ type: ButtonType.NATIVE_FLOW
506
+ };
507
+ }
508
+ else if (button.sections) {
509
+ return {
510
+ nativeFlowInfo: {
511
+ name: 'single_select',
512
+ paramsJson: JSON.stringify({ title: buttonText, sections: button.sections })
513
+ },
514
+ type: ButtonType.NATIVE_FLOW
515
+ };
516
+ }
517
+ else if (button.name) {
518
+ return {
519
+ nativeFlowInfo: { name: button.name, paramsJson: button.paramsJson },
520
+ type: ButtonType.NATIVE_FLOW
521
+ };
522
+ }
523
+ return {
524
+ buttonId: button.id || button.buttonId,
525
+ buttonText: typeof buttonText === 'string' ? { displayText: buttonText } : buttonText,
526
+ type: button.type || ButtonType.RESPONSE
527
+ };
528
+ })
529
+ };
530
+ if (message.text) {
531
+ buttonsMessage.contentText = message.text;
532
+ buttonsMessage.headerType = ButtonHeaderType.EMPTY;
533
+ }
534
+ else {
535
+ const media = await prepareWAMessageMedia(message, options);
536
+ if (message.caption) {
537
+ buttonsMessage.contentText = message.caption;
538
+ }
539
+ const mediaKey = Object.keys(media)[0];
540
+ if (!mediaKey) {
541
+ throw new Boom('buttons message needs either "text" or a media field (image/video/document) as header', {
542
+ statusCode: 400
543
+ });
544
+ }
545
+ const type = mediaKey.replace('Message', '').toUpperCase();
546
+ buttonsMessage.headerType = ButtonHeaderType[type];
547
+ Object.assign(buttonsMessage, media);
548
+ }
549
+ if (message.footer) {
550
+ buttonsMessage.footerText = message.footer;
551
+ }
552
+ m.buttonsMessage = buttonsMessage;
553
+ }
554
+ else if (hasNonNullishProperty(message, 'sections')) {
555
+ m.listMessage = {
556
+ sections: message.sections,
557
+ buttonText: message.buttonText,
558
+ title: message.title,
559
+ footerText: message.footer,
560
+ description: message.description,
561
+ listType: ListType.SINGLE_SELECT
562
+ };
563
+ }
564
+ else if (hasNonNullishProperty(message, 'templateButtons')) {
565
+ const hydratedTemplate = {
566
+ hydratedButtons: message.templateButtons.map((button, i) => {
567
+ const buttonText = button.text || button.buttonText;
568
+ if (button.id) {
569
+ return { index: i, quickReplyButton: { displayText: buttonText || 'Click', id: button.id } };
570
+ }
571
+ else if (button.url) {
572
+ return { index: i, urlButton: { displayText: buttonText || 'Visit', url: button.url } };
573
+ }
574
+ else if (button.call) {
575
+ return { index: i, callButton: { displayText: buttonText || 'Call', phoneNumber: button.call } };
576
+ }
577
+ button.index = button.index || i;
578
+ return button;
579
+ })
580
+ };
581
+ if (message.text) {
582
+ hydratedTemplate.hydratedContentText = message.text;
583
+ }
584
+ else {
585
+ const media = await prepareWAMessageMedia(message, options);
586
+ if (message.caption) {
587
+ hydratedTemplate.hydratedTitleText = message.title;
588
+ hydratedTemplate.hydratedContentText = message.caption;
589
+ }
590
+ Object.assign(hydratedTemplate, media);
591
+ }
592
+ if (message.footer) {
593
+ hydratedTemplate.hydratedFooterText = message.footer;
594
+ }
595
+ hydratedTemplate.templateId = message.id || `template-${Date.now()}`;
596
+ m.templateMessage = {
597
+ hydratedFourRowTemplate: hydratedTemplate,
598
+ hydratedTemplate
599
+ };
600
+ }
601
+ else if (hasNonNullishProperty(message, 'nativeFlow')) {
602
+ const interactiveMessage = {
603
+ nativeFlowMessage: prepareNativeFlowButtons(message)
604
+ };
605
+ if (message.text) {
606
+ interactiveMessage.body = { text: message.text };
607
+ }
608
+ else {
609
+ const media = await prepareWAMessageMedia(message, options);
610
+ if (message.caption) {
611
+ const isValidHeader = hasValidInteractiveHeader(media);
612
+ if (!isValidHeader) {
613
+ throw new Boom('Invalid media type for interactive message header', { statusCode: 400 });
614
+ }
615
+ interactiveMessage.header = {
616
+ title: message.title || '',
617
+ subtitle: message.subtitle || '',
618
+ hasMediaAttachment: isValidHeader
619
+ };
620
+ interactiveMessage.body = { text: message.caption };
621
+ }
622
+ Object.assign(interactiveMessage.header || (interactiveMessage.header = {}), media);
623
+ }
624
+ if (message.audioFooter) {
625
+ const { audioMessage } = await prepareWAMessageMedia({ audio: message.audioFooter }, options);
626
+ interactiveMessage.footer = { audioMessage, hasMediaAttachment: true };
627
+ }
628
+ else if (message.footer) {
629
+ interactiveMessage.footer = { text: message.footer };
630
+ }
631
+ m.interactiveMessage = interactiveMessage;
632
+ }
633
+ else if (hasNonNullishProperty(message, 'cards')) {
634
+ const interactiveMessage = {
635
+ carouselMessage: {
636
+ cards: await Promise.all(message.cards.map(async (card) => {
637
+ const carouselHeader = await prepareWAMessageMedia(card, options).catch(() => ({}));
638
+ const isValidHeader = hasValidCarouselHeader(carouselHeader);
639
+ if (!isValidHeader) {
640
+ throw new Boom('Invalid media type for carousel card', { statusCode: 400 });
641
+ }
642
+ const carouselCard = {
643
+ nativeFlowMessage: prepareNativeFlowButtons({ nativeFlow: card.nativeFlow || [] })
644
+ };
645
+ if (card.text) {
646
+ carouselCard.body = { text: card.text };
647
+ }
648
+ else if (card.caption) {
649
+ carouselCard.header = {
650
+ title: card.title || '',
651
+ subtitle: card.subtitle || '',
652
+ hasMediaAttachment: isValidHeader,
653
+ ...carouselHeader
654
+ };
655
+ carouselCard.body = { text: card.caption };
656
+ }
657
+ if (card.audioFooter) {
658
+ const { audioMessage } = await prepareWAMessageMedia({ audio: card.audioFooter }, options);
659
+ carouselCard.footer = { audioMessage, hasMediaAttachment: true };
660
+ }
661
+ else if (card.footer) {
662
+ carouselCard.footer = { text: card.footer };
663
+ }
664
+ if (card.contextInfo) {
665
+ carouselCard.contextInfo = card.contextInfo;
666
+ }
667
+ return carouselCard;
668
+ })),
669
+ carouselCardType: CarouselCardType.UNKNOWN,
670
+ messageVersion: 1
671
+ }
672
+ };
673
+ if (message.footer) {
674
+ interactiveMessage.footer = { text: message.footer };
675
+ }
676
+ m.interactiveMessage = interactiveMessage;
677
+ }
678
+ else if (hasNonNullishProperty(message, 'text')) {
435
679
  const extContent = { text: message.text };
436
680
  let urlInfo = message.linkPreview;
437
681
  if (typeof urlInfo === 'undefined') {
@@ -507,8 +751,6 @@ export const generateWAMessageContent = async (message, options) => {
507
751
  m.groupInviteMessage.caption = message.groupInvite.text;
508
752
  m.groupInviteMessage.groupJid = message.groupInvite.jid;
509
753
  m.groupInviteMessage.groupName = message.groupInvite.subject;
510
- //TODO: use built-in interface and get disappearing mode info etc.
511
- //TODO: cache / use store!?
512
754
  if (options.getProfilePicUrl) {
513
755
  const pfpUrl = await options.getProfilePicUrl(message.groupInvite.jid, 'preview');
514
756
  if (pfpUrl) {
@@ -553,7 +795,6 @@ export const generateWAMessageContent = async (message, options) => {
553
795
  m.eventMessage.joinLink = (message.event.call === 'audio' ? CALL_AUDIO_PREFIX : CALL_VIDEO_PREFIX) + token;
554
796
  }
555
797
  m.messageContextInfo = {
556
- // encKey
557
798
  messageSecret: message.event.messageSecret || randomBytes(32)
558
799
  };
559
800
  m.eventMessage.name = message.event.name;
@@ -565,6 +806,24 @@ export const generateWAMessageContent = async (message, options) => {
565
806
  m.eventMessage.isScheduleCall = message.event.isScheduleCall ?? false;
566
807
  m.eventMessage.location = message.event.location;
567
808
  }
809
+ else if (hasNonNullishProperty(message, 'buttonReply')) {
810
+ switch (message.type) {
811
+ case 'template':
812
+ m.templateButtonReplyMessage = {
813
+ selectedDisplayText: message.buttonReply.displayText,
814
+ selectedId: message.buttonReply.id,
815
+ selectedIndex: message.buttonReply.index
816
+ };
817
+ break;
818
+ case 'plain':
819
+ m.buttonsResponseMessage = {
820
+ selectedButtonId: message.buttonReply.id,
821
+ selectedDisplayText: message.buttonReply.displayText,
822
+ type: proto.Message.ButtonsResponseMessage.Type.DISPLAY_TEXT
823
+ };
824
+ break;
825
+ }
826
+ }
568
827
  else if (hasNonNullishProperty(message, 'poll')) {
569
828
  (_a = message.poll).selectableCount || (_a.selectableCount = 0);
570
829
  (_b = message.poll).toAnnouncementGroup || (_b.toAnnouncementGroup = false);
@@ -577,7 +836,6 @@ export const generateWAMessageContent = async (message, options) => {
577
836
  });
578
837
  }
579
838
  m.messageContextInfo = {
580
- // encKey
581
839
  messageSecret: message.poll.messageSecret || randomBytes(32)
582
840
  };
583
841
  const pollCreationMessage = {
@@ -586,16 +844,13 @@ export const generateWAMessageContent = async (message, options) => {
586
844
  options: message.poll.values.map(optionName => ({ optionName }))
587
845
  };
588
846
  if (message.poll.toAnnouncementGroup) {
589
- // poll v2 is for community announcement groups (single select and multiple)
590
847
  m.pollCreationMessageV2 = pollCreationMessage;
591
848
  }
592
849
  else {
593
850
  if (message.poll.selectableCount === 1) {
594
- //poll v3 is for single select polls
595
851
  m.pollCreationMessageV3 = pollCreationMessage;
596
852
  }
597
853
  else {
598
- // poll for multiple choice polls
599
854
  m.pollCreationMessage = pollCreationMessage;
600
855
  }
601
856
  }
@@ -705,8 +960,6 @@ export const generateWAMessageContent = async (message, options) => {
705
960
  return WAProto.Message.create(m);
706
961
  };
707
962
  export const generateWAMessageFromContent = (jid, message, options) => {
708
- // set timestamp to now
709
- // if not specified
710
963
  if (!options.timestamp) {
711
964
  options.timestamp = new Date();
712
965
  }
@@ -716,11 +969,10 @@ export const generateWAMessageFromContent = (jid, message, options) => {
716
969
  const { quoted, userJid } = options;
717
970
  if (quoted && !isJidNewsletter(jid)) {
718
971
  const participant = quoted.key.fromMe
719
- ? userJid // TODO: Add support for LIDs
972
+ ? userJid
720
973
  : quoted.participant || quoted.key.participant || quoted.key.remoteJid;
721
974
  let quotedMsg = normalizeMessageContent(quoted.message);
722
975
  const msgType = getContentType(quotedMsg);
723
- // strip any redundant properties
724
976
  quotedMsg = proto.Message.create({ [msgType]: quotedMsg[msgType] });
725
977
  const quotedContent = quotedMsg[msgType];
726
978
  if (typeof quotedContent === 'object' && quotedContent && 'contextInfo' in quotedContent) {
@@ -730,30 +982,23 @@ export const generateWAMessageFromContent = (jid, message, options) => {
730
982
  contextInfo.participant = jidNormalizedUser(participant);
731
983
  contextInfo.stanzaId = quoted.key.id;
732
984
  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
985
  if (jid !== quoted.key.remoteJid) {
736
986
  contextInfo.remoteJid = quoted.key.remoteJid;
737
987
  }
738
988
  if (contextInfo && innerMessage[key]) {
739
- /* @ts-ignore */
989
+ ;
740
990
  innerMessage[key].contextInfo = contextInfo;
741
991
  }
742
992
  }
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
993
+ if (!!options?.ephemeralExpiration &&
747
994
  key !== 'protocolMessage' &&
748
- // already not converted to disappearing message
749
995
  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()
996
+ !isJidNewsletter(jid) &&
997
+ innerMessage[key]) {
998
+ const target = innerMessage[key];
999
+ target.contextInfo = {
1000
+ ...(target.contextInfo || {}),
1001
+ expiration: Number(options.ephemeralExpiration) || WA_DEFAULT_EPHEMERAL
757
1002
  };
758
1003
  }
759
1004
  message = WAProto.Message.create(message);
@@ -766,18 +1011,15 @@ export const generateWAMessageFromContent = (jid, message, options) => {
766
1011
  message: message,
767
1012
  messageTimestamp: timestamp,
768
1013
  messageStubParameters: [],
769
- participant: isJidGroup(jid) || isJidStatusBroadcast(jid) ? userJid : undefined, // TODO: Add support for LIDs
1014
+ participant: isJidGroup(jid) || isJidStatusBroadcast(jid) ? userJid : undefined,
770
1015
  status: WAMessageStatus.PENDING
771
1016
  };
772
1017
  return WAProto.WebMessageInfo.fromObject(messageJSON);
773
1018
  };
774
1019
  export const generateWAMessage = async (jid, content, options) => {
775
- // ensure msg ID is with every log
776
1020
  options.logger = options?.logger?.child({ msgId: options.messageId });
777
- // Pass jid in the options to generateWAMessageContent
778
1021
  return generateWAMessageFromContent(jid, await generateWAMessageContent(content, { ...options, jid }), options);
779
1022
  };
780
- /** Get the key to access the true type of content */
781
1023
  export const getContentType = (content) => {
782
1024
  if (content) {
783
1025
  const keys = Object.keys(content);
@@ -785,17 +1027,10 @@ export const getContentType = (content) => {
785
1027
  return key;
786
1028
  }
787
1029
  };
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
1030
  export const normalizeMessageContent = (content) => {
795
1031
  if (!content) {
796
1032
  return undefined;
797
1033
  }
798
- // set max iterations to prevent an infinite loop
799
1034
  for (let i = 0; i < 5; i++) {
800
1035
  const inner = getFutureProofMessage(content);
801
1036
  if (!inner) {
@@ -817,10 +1052,6 @@ export const normalizeMessageContent = (content) => {
817
1052
  message?.lottieStickerMessage);
818
1053
  }
819
1054
  };
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
1055
  export const extractMessageContent = (content) => {
825
1056
  const extractFromTemplateMessage = (msg) => {
826
1057
  if (msg.imageMessage) {
@@ -856,9 +1087,6 @@ export const extractMessageContent = (content) => {
856
1087
  }
857
1088
  return content;
858
1089
  };
859
- /**
860
- * Returns the device predicted by message ID
861
- */
862
1090
  export const getDevice = (id) => /^3A.{18}$/.test(id)
863
1091
  ? 'ios'
864
1092
  : /^3E.{20}$/.test(id)
@@ -868,7 +1096,6 @@ export const getDevice = (id) => /^3A.{18}$/.test(id)
868
1096
  : /^(3F|.{18}$)/.test(id)
869
1097
  ? 'desktop'
870
1098
  : 'unknown';
871
- /** Upserts a receipt in the message */
872
1099
  export const updateMessageWithReceipt = (msg, receipt) => {
873
1100
  msg.userReceipt = msg.userReceipt || [];
874
1101
  const recp = msg.userReceipt.find(m => m.userJid === receipt.userJid);
@@ -879,7 +1106,6 @@ export const updateMessageWithReceipt = (msg, receipt) => {
879
1106
  msg.userReceipt.push(receipt);
880
1107
  }
881
1108
  };
882
- /** Update the message with a new reaction */
883
1109
  export const updateMessageWithReaction = (msg, reaction) => {
884
1110
  const authorID = getKeyAuthor(reaction.key);
885
1111
  const reactions = (msg.reactions || []).filter(r => getKeyAuthor(r.key) !== authorID);
@@ -887,7 +1113,6 @@ export const updateMessageWithReaction = (msg, reaction) => {
887
1113
  reactions.push(reaction);
888
1114
  msg.reactions = reactions;
889
1115
  };
890
- /** Update the message with a new poll update */
891
1116
  export const updateMessageWithPollUpdate = (msg, update) => {
892
1117
  const authorID = getKeyAuthor(update.pollUpdateMessageKey);
893
1118
  const reactions = (msg.pollUpdates || []).filter(r => getKeyAuthor(r.pollUpdateMessageKey) !== authorID);
@@ -896,19 +1121,12 @@ export const updateMessageWithPollUpdate = (msg, update) => {
896
1121
  }
897
1122
  msg.pollUpdates = reactions;
898
1123
  };
899
- /** Update the message with a new event response */
900
1124
  export const updateMessageWithEventResponse = (msg, update) => {
901
1125
  const authorID = getKeyAuthor(update.eventResponseMessageKey);
902
1126
  const responses = (msg.eventResponses || []).filter(r => getKeyAuthor(r.eventResponseMessageKey) !== authorID);
903
1127
  responses.push(update);
904
1128
  msg.eventResponses = responses;
905
1129
  };
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
1130
  export function getAggregateVotesInPollMessage({ message, pollUpdates }, meId) {
913
1131
  const opts = message?.pollCreationMessage?.options ||
914
1132
  message?.pollCreationMessageV2?.options ||
@@ -942,12 +1160,6 @@ export function getAggregateVotesInPollMessage({ message, pollUpdates }, meId) {
942
1160
  }
943
1161
  return Object.values(voteHashMap);
944
1162
  }
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
1163
  export function getAggregateResponsesInEventMessage({ eventResponses }, meId) {
952
1164
  const responseTypes = ['GOING', 'NOT_GOING', 'MAYBE'];
953
1165
  const responseMap = {};
@@ -965,7 +1177,6 @@ export function getAggregateResponsesInEventMessage({ eventResponses }, meId) {
965
1177
  }
966
1178
  return Object.values(responseMap);
967
1179
  }
968
- /** Given a list of message keys, aggregates them by chat & sender. Useful for sending read receipts in bulk */
969
1180
  export const aggregateMessageKeysNotFromMe = (keys) => {
970
1181
  const keyMap = {};
971
1182
  for (const { remoteJid, id, participant, fromMe } of keys) {
@@ -984,16 +1195,12 @@ export const aggregateMessageKeysNotFromMe = (keys) => {
984
1195
  return Object.values(keyMap);
985
1196
  };
986
1197
  const REUPLOAD_REQUIRED_STATUS = [410, 404];
987
- /**
988
- * Downloads the given message. Throws an error if it's not a media message
989
- */
990
1198
  export const downloadMediaMessage = async (message, type, options, ctx) => {
991
1199
  const result = await downloadMsg().catch(async (error) => {
992
1200
  if (ctx &&
993
- typeof error?.status === 'number' && // treat errors with status as HTTP failures requiring reupload
1201
+ typeof error?.status === 'number' &&
994
1202
  REUPLOAD_REQUIRED_STATUS.includes(error.status)) {
995
1203
  ctx.logger.info({ key: message.key }, 'sending reupload media request...');
996
- // request reupload
997
1204
  message = await ctx.reuploadRequest(message);
998
1205
  const result = await downloadMsg();
999
1206
  return result;
@@ -1034,7 +1241,6 @@ export const downloadMediaMessage = async (message, type, options, ctx) => {
1034
1241
  return stream;
1035
1242
  }
1036
1243
  };
1037
- /** Checks whether the given message is a media message; if it is returns the inner content */
1038
1244
  export const assertMediaContent = (content) => {
1039
1245
  content = extractMessageContent(content);
1040
1246
  const mediaContent = content?.documentMessage ||