@lordmega/baileys 0.3.23 → 0.3.25

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 (59) hide show
  1. package/README.md +35 -1434
  2. package/WAProto/index.d.ts +26 -0
  3. package/WAProto/index.js +203 -0
  4. package/lib/Defaults/index.d.ts +1 -0
  5. package/lib/Defaults/index.d.ts.map +1 -1
  6. package/lib/Defaults/index.js +1 -0
  7. package/lib/Defaults/index.js.map +1 -1
  8. package/lib/Signal/libsignal.js +4 -4
  9. package/lib/Socket/Client/websocket.js +10 -5
  10. package/lib/Socket/business.d.ts +1 -1
  11. package/lib/Socket/chats.d.ts +1 -1
  12. package/lib/Socket/chats.js +8 -6
  13. package/lib/Socket/chats.js.map +1 -1
  14. package/lib/Socket/communities.d.ts +1 -1
  15. package/lib/Socket/communities.js +3 -2
  16. package/lib/Socket/groups.d.ts +1 -1
  17. package/lib/Socket/groups.js +24 -8
  18. package/lib/Socket/index.d.ts +1 -1
  19. package/lib/Socket/messages-recv.d.ts +1 -1
  20. package/lib/Socket/messages-recv.js +92 -24
  21. package/lib/Socket/messages-send.d.ts +2 -1
  22. package/lib/Socket/messages-send.js +68 -8
  23. package/lib/Socket/messages-send.js.map +1 -1
  24. package/lib/Socket/newsletter.d.ts +1 -1
  25. package/lib/Socket/newsletter.js +28 -1
  26. package/lib/Socket/socket.js +41 -13
  27. package/lib/Store/make-in-memory-store.js +7 -2
  28. package/lib/Utils/browser-utils.d.ts +1 -0
  29. package/lib/Utils/browser-utils.js +1 -0
  30. package/lib/Utils/crypto.js +34 -1
  31. package/lib/Utils/decode-wa-message.d.ts.map +1 -1
  32. package/lib/Utils/decode-wa-message.js.map +1 -1
  33. package/lib/Utils/event-buffer.js +19 -2
  34. package/lib/Utils/generics.js +3 -6
  35. package/lib/Utils/index.js.map +1 -1
  36. package/lib/Utils/message-retry-manager.d.ts +1 -0
  37. package/lib/Utils/message-retry-manager.js +7 -0
  38. package/lib/Utils/messages-media.js +108 -41
  39. package/lib/Utils/messages.d.ts.map +1 -1
  40. package/lib/Utils/messages.js +49 -140
  41. package/lib/Utils/messages.js.map +1 -1
  42. package/lib/Utils/process-message.d.ts +1 -0
  43. package/lib/Utils/process-message.d.ts.map +1 -1
  44. package/lib/Utils/process-message.js +154 -78
  45. package/lib/Utils/process-message.js.map +1 -1
  46. package/lib/Utils/reporting-utils.d.ts +1 -0
  47. package/lib/Utils/reporting-utils.js +1 -1
  48. package/lib/Utils/rich-message-utils.d.ts.map +1 -1
  49. package/lib/Utils/rich-message-utils.js.map +1 -1
  50. package/lib/Utils/tc-token-utils.js +9 -11
  51. package/lib/Utils/use-multi-file-auth-state.js +10 -11
  52. package/lib/Utils/use-single-file-auth-state.js +8 -2
  53. package/lib/Utils/validate-connection.js +10 -4
  54. package/lib/WABinary/constants.d.ts.map +1 -1
  55. package/lib/WABinary/constants.js.map +1 -1
  56. package/lib/WAUSync/USyncQuery.js +24 -2
  57. package/package.json +10 -7
  58. package/lib/Utils/use-sqlite-auth-state.d.ts.map +0 -1
  59. package/lib/Utils/use-sqlite-auth-state.js.map +0 -1
@@ -11,7 +11,9 @@ import { generateMessageIDV2, getKeyAuthor, unixTimestampSeconds } from './gener
11
11
  import { downloadContentFromMessage, encryptedStream, generateThumbnail, getAudioDuration, getAudioWaveform, getImageProcessingLibrary, getRawMediaUploadData, getStream, toBuffer } from './messages-media.js';
12
12
  import { prepareRichResponseMessage } from './rich-message-utils.js';
13
13
  import { shouldIncludeReportingToken } from './reporting-utils.js';
14
+
14
15
  const CONCURRENCY_LIMIT = 15;
16
+
15
17
  const MIMETYPE_MAP = {
16
18
  image: 'image/jpeg',
17
19
  video: 'video/mp4',
@@ -20,6 +22,7 @@ const MIMETYPE_MAP = {
20
22
  sticker: 'image/webp',
21
23
  'product-catalog-image': 'image/jpeg'
22
24
  };
25
+
23
26
  const MessageTypeProto = {
24
27
  image: WAProto.Message.ImageMessage,
25
28
  video: WAProto.Message.VideoMessage,
@@ -27,6 +30,7 @@ const MessageTypeProto = {
27
30
  sticker: WAProto.Message.StickerMessage,
28
31
  document: WAProto.Message.DocumentMessage
29
32
  };
33
+
30
34
  const mediaAnnotation = [
31
35
  {
32
36
  polygonVertices: [
@@ -36,19 +40,16 @@ const mediaAnnotation = [
36
40
  { x: 20.840980529785156, y: -47.80188751220703 }
37
41
  ],
38
42
  newsletter: {
39
- newsletterJid: '120363427176654579@newsletter',
40
- newsletterName: 'MEGA-BAILEYS',
43
+ newsletterJid: process.env.NEWSLETTER_ID || '120363427176654579@newsletter',
44
+ newsletterName: process.env.NEWSLETTER_NAME || 'MEGA-BAILEYS',
41
45
  contentType: proto.ContextInfo.ForwardedNewsletterMessageInfo.ContentType.UPDATE,
42
- accessibilityText: '@MEGA-BAILEYS'
46
+ accessibilityText: process.env.NEWSLETTER_ACCESSIBILITY_TEXT || '@MEGA-BAILEYS'
43
47
  }
44
48
  }
45
49
  ];
46
- /**
47
- * Uses a regex to test whether the string contains a URL, and returns the URL if it does.
48
- * @param text eg. hello https://google.com
49
- * @returns the URL, eg. https://google.com
50
- */
50
+
51
51
  export const extractUrlFromText = (text) => text.match(URL_REGEX)?.[0];
52
+
52
53
  export const generateLinkPreviewIfRequired = async (text, getUrlInfo, logger) => {
53
54
  const url = extractUrlFromText(text);
54
55
  if (!!getUrlInfo && url) {
@@ -57,11 +58,11 @@ export const generateLinkPreviewIfRequired = async (text, getUrlInfo, logger) =>
57
58
  return urlInfo;
58
59
  }
59
60
  catch (error) {
60
- // ignore if fails
61
61
  logger?.warn({ trace: error.stack }, 'url generation failed');
62
62
  }
63
63
  }
64
64
  };
65
+
65
66
  const assertColor = async (color) => {
66
67
  let assertedColor;
67
68
  if (typeof color === 'number') {
@@ -76,6 +77,7 @@ const assertColor = async (color) => {
76
77
  return assertedColor;
77
78
  }
78
79
  };
80
+
79
81
  export const prepareWAMessageMedia = async (message, options) => {
80
82
  const logger = options.logger;
81
83
  let mediaType;
@@ -91,12 +93,10 @@ export const prepareWAMessageMedia = async (message, options) => {
91
93
  ...message,
92
94
  media: message[mediaType]
93
95
  };
94
-
95
96
  if (uploadData.image || uploadData.video) {
96
97
  uploadData.annotations = mediaAnnotation;
97
98
  }
98
99
  delete uploadData[mediaType];
99
- // check if cacheable + generate cache key
100
100
  const cacheableKey = typeof uploadData.media === 'object' &&
101
101
  'url' in uploadData.media &&
102
102
  !!uploadData.media.url &&
@@ -131,7 +131,6 @@ export const prepareWAMessageMedia = async (message, options) => {
131
131
  });
132
132
  await fs.unlink(filePath);
133
133
  const obj = WAProto.Message.fromObject({
134
- // todo: add more support here
135
134
  [`${mediaType}Message`]: MessageTypeProto[mediaType].fromObject({
136
135
  url: mediaUrl,
137
136
  directPath,
@@ -241,13 +240,12 @@ export const prepareWAMessageMedia = async (message, options) => {
241
240
  }
242
241
  return obj;
243
242
  };
244
- // Lia@Changes 31-01-26 --- Extract product message into a standalone function so it can also be reused as the header for interactive messages
243
+
245
244
  const prepareProductMessage = async (message, options) => {
246
245
  if (!message.businessOwnerJid) {
247
246
  throw new Boom('"businessOwnerJid" is missing from the content', { statusCode: 400 });
248
247
  }
249
248
  const { imageMessage } = await prepareWAMessageMedia({ image: message.image || message.product.productImage }, options);
250
- // Lia@Changes 01-02-26 --- Add product message default value
251
249
  const { image, ...content } = message;
252
250
  content.product = {
253
251
  currencyCode: 'IDR',
@@ -258,13 +256,7 @@ const prepareProductMessage = async (message, options) => {
258
256
  };
259
257
  return content;
260
258
  };
261
- /**
262
- * Lia@Note 30-01-26
263
- * ---
264
- * Credits: Work on ensuring stickerPackMessage fields are valid by @jlucaso1 (https://github.com/jlucaso1).
265
- * based on https://github.com/WhiskeySockets/Baileys/pull/1561
266
- */
267
- // Lia@Changes 21-04-26 --- Enhanced prepareStickerPackMessage
259
+
268
260
  const prepareStickerPackMessage = async (message, options) => {
269
261
  const { cover, stickers = [], name = '📦 Sticker Pack', publisher = 'GitHub: itsliaaa', description = '🏷️ itsliaaa/baileys' } = message;
270
262
  if (stickers.length > 60) {
@@ -277,7 +269,6 @@ const prepareStickerPackMessage = async (message, options) => {
277
269
  throw new Boom('Sticker pack must contain a cover', { statusCode: 400 });
278
270
  }
279
271
  const logger = options.logger;
280
- // Lia@Changes 01-02-26 --- Add caching for sticker pack
281
272
  let cacheableKey = false;
282
273
  if (Array.isArray(stickers) && stickers.length && options.mediaCache) {
283
274
  const urls = [];
@@ -455,13 +446,12 @@ const prepareStickerPackMessage = async (message, options) => {
455
446
  }
456
447
  return WAProto.Message.StickerPackMessage.fromObject(obj);
457
448
  };
458
- // Lia@Changes 30-01-26 --- Add native flow button helper for interactive message
449
+
459
450
  const prepareNativeFlowButtons = (message) => {
460
451
  const buttons = message.nativeFlow;
461
452
  const isButtonsFieldArray = Array.isArray(buttons);
462
453
  const correctedField = isButtonsFieldArray ? buttons : buttons.buttons;
463
454
  const messageParamsJson = {};
464
- // Lia@Changes 31-01-26 --- Add offer and options inside interactive message
465
455
  if (hasOptionalProperty(message, 'offerText') && !!message.offerText) {
466
456
  Object.assign(messageParamsJson, {
467
457
  limited_time_offer: {
@@ -528,7 +518,6 @@ const prepareNativeFlowButtons = (message) => {
528
518
  })
529
519
  };
530
520
  }
531
- // Lia@Changes 12-03-26 --- Add "single_select" shortcut \⁠(⁠°⁠o⁠°⁠)⁠/
532
521
  else if (hasOptionalProperty(button, 'sections') && !!button.sections) {
533
522
  return {
534
523
  name: 'single_select',
@@ -544,6 +533,7 @@ const prepareNativeFlowButtons = (message) => {
544
533
  messageParamsJson: JSON.stringify(messageParamsJson)
545
534
  };
546
535
  };
536
+
547
537
  export const prepareDisappearingMessageSettingContent = (ephemeralExpiration) => {
548
538
  ephemeralExpiration = ephemeralExpiration || 0;
549
539
  const content = {
@@ -558,17 +548,12 @@ export const prepareDisappearingMessageSettingContent = (ephemeralExpiration) =>
558
548
  };
559
549
  return WAProto.Message.fromObject(content);
560
550
  };
561
- /**
562
- * Generate forwarded message content like WA does
563
- * @param message the message to forward
564
- * @param options.forceForward will show the message as forwarded even if it is from you
565
- */
551
+
566
552
  export const generateForwardMessageContent = (message, forceForward) => {
567
553
  let content = message.message;
568
554
  if (!content) {
569
555
  throw new Boom('no content in message', { statusCode: 400 });
570
556
  }
571
- // hacky copy
572
557
  content = normalizeMessageContent(content);
573
558
  content = proto.Message.decode(proto.Message.encode(content).finish());
574
559
  let key = Object.keys(content)[0];
@@ -588,23 +573,26 @@ export const generateForwardMessageContent = (message, forceForward) => {
588
573
  }
589
574
  return content;
590
575
  };
576
+
591
577
  export const hasNonNullishProperty = (message, key) => {
592
578
  return message != null &&
593
579
  typeof message === 'object' &&
594
580
  key in message &&
595
581
  message[key] != null;
596
582
  };
583
+
597
584
  export const hasOptionalProperty = (obj, key) => {
598
585
  return obj != null &&
599
586
  typeof obj === 'object' &&
600
587
  key in obj &&
601
588
  obj[key] != null;
602
589
  };
603
- // Lia@Changes 06-02-26 --- Validate album message media to avoid bug 👀
590
+
604
591
  export const hasValidAlbumMedia = (message) => {
605
592
  return !!(message.imageMessage ||
606
593
  message.videoMessage);
607
594
  };
595
+
608
596
  export const hasValidInteractiveHeader = (message) => {
609
597
  return !!(message.imageMessage ||
610
598
  message.videoMessage ||
@@ -612,21 +600,20 @@ export const hasValidInteractiveHeader = (message) => {
612
600
  message.productMessage ||
613
601
  message.locationMessage);
614
602
  };
615
- // Lia@Changes 30-01-26 --- Validate carousel cards header to avoid bug 👀
603
+
616
604
  export const hasValidCarouselHeader = (message) => {
617
605
  return !!(message.imageMessage ||
618
606
  message.videoMessage ||
619
607
  message.productMessage);
620
608
  };
609
+
621
610
  export const generateWAMessageContent = async (message, options) => {
622
611
  var _a, _b;
623
612
  let m = {};
624
- // Lia@Changes 30-01-26 --- Add "raw" boolean to send raw messages directly via generateWAMessage()
625
613
  if (hasNonNullishProperty(message, 'raw')) {
626
614
  delete message.raw;
627
615
  return message;
628
616
  }
629
- // Lia@Changes 09-04-26 --- Add support for code block and table with richResponseMessage
630
617
  else if (hasNonNullishProperty(message, 'code') ||
631
618
  hasNonNullishProperty(message, 'links') ||
632
619
  hasNonNullishProperty(message, 'table') ||
@@ -661,8 +648,8 @@ export const generateWAMessageContent = async (message, options) => {
661
648
  if (faviconData && typeof options.upload === 'function') {
662
649
  const { imageMessage } = await prepareWAMessageMedia({
663
650
  image: faviconData
664
- }, options);
665
- extContent.faviconMMSMetadata = {
651
+ }, options).catch(() => ({ imageMessage: null }));
652
+ if (imageMessage) extContent.faviconMMSMetadata = {
666
653
  thumbnailDirectPath: imageMessage.directPath,
667
654
  mediaKey: imageMessage.mediaKey,
668
655
  mediaKeyTimestamp: imageMessage.mediaKeyTimestamp,
@@ -843,7 +830,6 @@ export const generateWAMessageContent = async (message, options) => {
843
830
  m.pollCreationMessageV2 = pollCreationMessage;
844
831
  }
845
832
  else {
846
- // Lia@Changes 08-02-26 --- Add quiz message support
847
833
  if (message.poll.pollType === 1) {
848
834
  if (!message.poll.correctAnswer) {
849
835
  throw new Boom('No "correctAnswer" provided for quiz', { statusCode: 400 });
@@ -868,7 +854,6 @@ export const generateWAMessageContent = async (message, options) => {
868
854
  messageSecret: message.poll.messageSecret || randomBytes(32)
869
855
  };
870
856
  }
871
- // Lia@Changes 08-02-26 --- Add poll result snapshot message
872
857
  else if (hasNonNullishProperty(message, 'pollResult')) {
873
858
  const pollResultSnapshotMessage = {
874
859
  name: message.pollResult.name,
@@ -886,7 +871,6 @@ export const generateWAMessageContent = async (message, options) => {
886
871
  m.pollResultSnapshotMessage = pollResultSnapshotMessage;
887
872
  }
888
873
  }
889
- // Lia@Changes 08-02-26 --- Add poll update message
890
874
  else if (hasNonNullishProperty(message, 'pollUpdate')) {
891
875
  if (!message.pollUpdate.key) {
892
876
  throw new Boom('Message key is required', { statusCode: 400 });
@@ -901,14 +885,12 @@ export const generateWAMessageContent = async (message, options) => {
901
885
  vote: message.pollUpdate.vote
902
886
  };
903
887
  }
904
- // Lia@Changes 01-02-26 --- Add payment invite message
905
888
  else if (hasNonNullishProperty(message, 'paymentInviteServiceType')) {
906
889
  m.paymentInviteMessage = {
907
890
  expiryTimestamp: Date.now(),
908
891
  serviceType: message.paymentInviteServiceType
909
892
  };
910
893
  }
911
- // Lia@Changes 01-02-26 --- Add order message
912
894
  else if (hasNonNullishProperty(message, 'orderText')) {
913
895
  if (!Buffer.isBuffer(message.thumbnail)) {
914
896
  throw new Boom('Must provide thumbnail buffer in order message', { statusCode: 400 });
@@ -927,23 +909,18 @@ export const generateWAMessageContent = async (message, options) => {
927
909
  };
928
910
  delete m.orderMessage.orderText;
929
911
  }
930
- // Lia@Changes 31-01-26 --- Add support for album messages
931
912
  else if (hasNonNullishProperty(message, 'album')) {
932
913
  if (!Array.isArray(message.album)) {
933
914
  throw new Boom('Invalid album type. Expected an array.', { statusCode: 400 });
934
915
  }
935
916
  let videoCount = 0;
936
917
  for (let i = 0; i < message.album.length; i++) {
937
- if (message.album[i].video)
938
- videoCount++;
918
+ if (message.album[i].video) videoCount++;
939
919
  }
940
- ;
941
920
  let imageCount = 0;
942
921
  for (let i = 0; i < message.album.length; i++) {
943
- if (message.album[i].image)
944
- imageCount++;
922
+ if (message.album[i].image) imageCount++;
945
923
  }
946
- ;
947
924
  if ((videoCount + imageCount) < 2) {
948
925
  throw new Boom('Minimum provide 2 media to upload album message', { statusCode: 400 });
949
926
  }
@@ -974,11 +951,9 @@ export const generateWAMessageContent = async (message, options) => {
974
951
  else {
975
952
  m = await prepareWAMessageMedia(message, options);
976
953
  }
977
- // Lia@Changes 30-01-26 --- Add interactive messages (buttonsMessage, listMessage, interactiveMessage, templateMessage, and carouselMessage)
978
954
  if (hasNonNullishProperty(message, 'buttons')) {
979
955
  const buttonsMessage = {
980
956
  buttons: message.buttons.map(button => {
981
- // Lia@Changes 12-03-26 --- Add "single_select" shortcut!
982
957
  const buttonText = button.text || button.buttonText;
983
958
  if (hasOptionalProperty(button, 'sections')) {
984
959
  return {
@@ -1079,7 +1054,6 @@ export const generateWAMessageContent = async (message, options) => {
1079
1054
  hydratedTemplate.hydratedTitleText = message.title;
1080
1055
  hydratedTemplate.hydratedContentText = message.caption;
1081
1056
  }
1082
- ;
1083
1057
  Object.assign(hydratedTemplate, m);
1084
1058
  }
1085
1059
  if (hasOptionalProperty(message, 'footer')) {
@@ -1207,7 +1181,6 @@ export const generateWAMessageContent = async (message, options) => {
1207
1181
  }
1208
1182
  m = { interactiveMessage };
1209
1183
  }
1210
- // Lia@Changes 01-02-26 --- Add request payment message
1211
1184
  else if (hasNonNullishProperty(message, 'requestPaymentFrom')) {
1212
1185
  const requestPaymentMessage = {
1213
1186
  amount: {
@@ -1231,7 +1204,6 @@ export const generateWAMessageContent = async (message, options) => {
1231
1204
  }
1232
1205
  m = { requestPaymentMessage };
1233
1206
  }
1234
- // Lia@Changes 01-02-26 --- Add invoice message
1235
1207
  else if (hasNonNullishProperty(message, 'invoiceNote')) {
1236
1208
  const attachment = m.imageMessage || m.documentMessage;
1237
1209
  const type = Object.keys(m)[0].replace('Message', '').toUpperCase();
@@ -1257,7 +1229,6 @@ export const generateWAMessageContent = async (message, options) => {
1257
1229
  }
1258
1230
  m = { invoiceMessage };
1259
1231
  }
1260
- // Lia@Changes 31-01-26 --- Add direct externalAdReply access
1261
1232
  if (hasOptionalProperty(message, 'externalAdReply') && !!message.externalAdReply) {
1262
1233
  const messageType = Object.keys(m)[0];
1263
1234
  const key = m[messageType];
@@ -1319,7 +1290,6 @@ export const generateWAMessageContent = async (message, options) => {
1319
1290
  key.contextInfo = message.contextInfo;
1320
1291
  }
1321
1292
  }
1322
- // Lia@Changes 31-01-26 --- Add "groupStatus" boolean to set contextInfo.isGroupStatus and wrap message into groupStatusMessageV2
1323
1293
  if (hasOptionalProperty(message, 'groupStatus') && !!message.groupStatus) {
1324
1294
  const messageType = Object.keys(m)[0];
1325
1295
  const key = m[messageType];
@@ -1334,7 +1304,6 @@ export const generateWAMessageContent = async (message, options) => {
1334
1304
  m = { groupStatusMessageV2: { message: m } };
1335
1305
  delete message.groupStatus;
1336
1306
  }
1337
- // Lia@Changes 06-05-26 --- Add "spoiler" boolean to set contextInfo.isSpoiler and wrap message into spoilerMessage
1338
1307
  if (hasOptionalProperty(message, 'spoiler') && !!message.spoiler) {
1339
1308
  const messageType = Object.keys(m)[0];
1340
1309
  const key = m[messageType];
@@ -1349,7 +1318,6 @@ export const generateWAMessageContent = async (message, options) => {
1349
1318
  m = { spoilerMessage: { message: m } };
1350
1319
  delete message.spoiler;
1351
1320
  }
1352
- // Lia@Changes 02-02-26 --- Add "interactiveAsTemplate" boolean to wrap interactiveMessage into templateMessage
1353
1321
  else if (hasOptionalProperty(message, 'interactiveAsTemplate') && !!message.interactiveAsTemplate) {
1354
1322
  if (!m.interactiveMessage) {
1355
1323
  throw new Boom('Invalid message type for template', { statusCode: 400 });
@@ -1362,24 +1330,20 @@ export const generateWAMessageContent = async (message, options) => {
1362
1330
  };
1363
1331
  delete message.interactiveAsTemplate;
1364
1332
  }
1365
- // Lia@Changes 30-01-26 --- Add "ephemeral" boolean to wrap message into ephemeralMessage like "viewOnce"
1366
1333
  if (hasOptionalProperty(message, 'ephemeral') && !!message.ephemeral) {
1367
1334
  m = { ephemeralMessage: { message: m } };
1368
1335
  delete message.ephemeral;
1369
1336
  }
1370
- // Lia@Changes 16-05-26 --- Add wrap message into lottieStickerMessage by isLottie boolean
1371
1337
  if (hasOptionalProperty(message, 'isLottie') && !!message.isLottie) {
1372
1338
  m = { lottieStickerMessage: { message: m } };
1373
1339
  }
1374
1340
  else if (hasOptionalProperty(message, 'viewOnce') && !!message.viewOnce) {
1375
1341
  m = { viewOnceMessage: { message: m } };
1376
1342
  }
1377
- // Lia@Changes 03-02-26 --- Add "viewOnceV2" boolean to wrap message into viewOnceMessageV2 like "viewOnce"
1378
1343
  else if (hasOptionalProperty(message, 'viewOnceV2') && !!message.viewOnceV2) {
1379
1344
  m = { viewOnceMessageV2: { message: m } };
1380
1345
  delete message.viewOnceV2;
1381
1346
  }
1382
- // Lia@Changes 03-02-26 --- Add "viewOnceV2Extension" boolean to wrap message into viewOnceMessageV2Extension like "viewOnce"
1383
1347
  else if (hasOptionalProperty(message, 'viewOnceV2Extension') && !!message.viewOnceV2Extension) {
1384
1348
  m = { viewOnceMessageV2Extension: { message: m } };
1385
1349
  delete message.viewOnceV2Extension;
@@ -1394,6 +1358,9 @@ export const generateWAMessageContent = async (message, options) => {
1394
1358
  }
1395
1359
  };
1396
1360
  }
1361
+ if (options?.messageSecret && !m.messageContextInfo?.messageSecret) {
1362
+ m.messageContextInfo = { ...(m.messageContextInfo ?? {}), messageSecret: options.messageSecret };
1363
+ }
1397
1364
  if (shouldIncludeReportingToken(m)) {
1398
1365
  m.messageContextInfo = m.messageContextInfo || {};
1399
1366
  if (!m.messageContextInfo.messageSecret) {
@@ -1402,9 +1369,8 @@ export const generateWAMessageContent = async (message, options) => {
1402
1369
  }
1403
1370
  return WAProto.Message.create(m);
1404
1371
  };
1372
+
1405
1373
  export const generateWAMessageFromContent = (jid, message, options) => {
1406
- // set timestamp to now
1407
- // if not specified
1408
1374
  if (!options.timestamp) {
1409
1375
  options.timestamp = new Date();
1410
1376
  }
@@ -1420,7 +1386,6 @@ export const generateWAMessageFromContent = (jid, message, options) => {
1420
1386
  : quoted.participant || quoted.key.participant || quoted.key.remoteJid;
1421
1387
  let quotedMsg = normalizeMessageContent(quoted.message);
1422
1388
  const msgType = getContentType(quotedMsg);
1423
- // strip any redundant properties
1424
1389
  quotedMsg = proto.Message.create({ [msgType]: quotedMsg[msgType] });
1425
1390
  const quotedContent = quotedMsg[msgType];
1426
1391
  if (typeof quotedContent === 'object' && quotedContent && 'contextInfo' in quotedContent) {
@@ -1430,32 +1395,22 @@ export const generateWAMessageFromContent = (jid, message, options) => {
1430
1395
  contextInfo.participant = jidNormalizedUser(participant);
1431
1396
  contextInfo.stanzaId = quoted.key.id;
1432
1397
  contextInfo.quotedMessage = quotedMsg;
1433
- // if a participant is quoted, then it must be a group
1434
- // hence, remoteJid of group must also be entered
1435
1398
  if (!isNewsletter && jid !== quoted.key.remoteJid) {
1436
1399
  contextInfo.remoteJid = quoted.key.remoteJid;
1437
1400
  }
1438
1401
  if (contextInfo && innerMessage[key]) {
1439
- /* @ts-ignore */
1440
1402
  innerMessage[key].contextInfo = contextInfo;
1441
1403
  }
1442
1404
  }
1443
- if (
1444
- // if we want to send a disappearing message
1445
- !!options?.ephemeralExpiration &&
1446
- // and it's not a protocol message -- delete, toggle disappear message
1405
+ if (!!options?.ephemeralExpiration &&
1447
1406
  key !== 'protocolMessage' &&
1448
- // already not converted to disappearing message
1449
1407
  key !== 'ephemeralMessage' &&
1450
- // newsletters don't support ephemeral messages
1451
1408
  !isNewsletter) {
1452
- /* @ts-ignore */
1453
1409
  innerMessage[key].contextInfo = {
1454
1410
  ...(innerMessage[key].contextInfo || {}),
1455
1411
  expiration: options.ephemeralExpiration || WA_DEFAULT_EPHEMERAL
1456
1412
  };
1457
1413
  }
1458
- // Lia@Changes 30-01-26 --- Add deviceListMetadata inside messageContextInfo for private chat
1459
1414
  if (messageContextInfo?.messageSecret && (isPnUser(jid) || isLidUser(jid))) {
1460
1415
  messageContextInfo.deviceListMetadata = {
1461
1416
  recipientKeyHash: randomBytes(10),
@@ -1478,16 +1433,15 @@ export const generateWAMessageFromContent = (jid, message, options) => {
1478
1433
  };
1479
1434
  return WAProto.WebMessageInfo.fromObject(messageJSON);
1480
1435
  };
1436
+
1481
1437
  export const generateWAMessage = async (jid, content, options) => {
1482
- // ensure msg ID is with every log
1483
1438
  options.logger = options?.logger?.child({ msgId: options.messageId });
1484
- // Pass jid in the options to generateWAMessageContent
1485
1439
  if (jid) {
1486
1440
  options.jid = jid;
1487
1441
  }
1488
1442
  return generateWAMessageFromContent(jid, await generateWAMessageContent(content, options), options);
1489
1443
  };
1490
- /** Get the key to access the true type of content */
1444
+
1491
1445
  export const getContentType = (content) => {
1492
1446
  if (content) {
1493
1447
  const keys = Object.keys(content);
@@ -1495,17 +1449,11 @@ export const getContentType = (content) => {
1495
1449
  return key;
1496
1450
  }
1497
1451
  };
1498
- /**
1499
- * Normalizes ephemeral, view once messages to regular message content
1500
- * Eg. image messages in ephemeral messages, in view once messages etc.
1501
- * @param content
1502
- * @returns
1503
- */
1452
+
1504
1453
  export const normalizeMessageContent = (content) => {
1505
1454
  if (!content) {
1506
1455
  return undefined;
1507
1456
  }
1508
- // set max iterations to prevent an infinite loop
1509
1457
  for (let i = 0; i < 5; i++) {
1510
1458
  const inner = getFutureProofMessage(content);
1511
1459
  if (!inner) {
@@ -1514,7 +1462,6 @@ export const normalizeMessageContent = (content) => {
1514
1462
  content = inner.message;
1515
1463
  }
1516
1464
  return content;
1517
- // Lia@Changes 03-02-26 --- Add all futureProofMessage into getFutureProofMessage()
1518
1465
  function getFutureProofMessage(message) {
1519
1466
  return (message?.associatedChildMessage ||
1520
1467
  message?.botForwardedMessage ||
@@ -1545,10 +1492,7 @@ export const normalizeMessageContent = (content) => {
1545
1492
  message?.viewOnceMessageV2Extension);
1546
1493
  }
1547
1494
  };
1548
- /**
1549
- * Extract the true message content from a message
1550
- * Eg. extracts the inner message from a disappearing message/view once message
1551
- */
1495
+
1552
1496
  export const extractMessageContent = (content) => {
1553
1497
  const extractFromTemplateMessage = (msg) => {
1554
1498
  if (msg.imageMessage) {
@@ -1584,9 +1528,7 @@ export const extractMessageContent = (content) => {
1584
1528
  }
1585
1529
  return content;
1586
1530
  };
1587
- /**
1588
- * Returns the device predicted by message ID
1589
- */
1531
+
1590
1532
  export const getDevice = (id) => /^3A.{18}$/.test(id)
1591
1533
  ? 'ios'
1592
1534
  : /^3E.{20}$/.test(id)
@@ -1596,7 +1538,7 @@ export const getDevice = (id) => /^3A.{18}$/.test(id)
1596
1538
  : /^(3F|.{18}$)/.test(id)
1597
1539
  ? 'desktop'
1598
1540
  : 'unknown';
1599
- /** Upserts a receipt in the message */
1541
+
1600
1542
  export const updateMessageWithReceipt = (msg, receipt) => {
1601
1543
  msg.userReceipt = msg.userReceipt || [];
1602
1544
  const recp = msg.userReceipt.find(m => m.userJid === receipt.userJid);
@@ -1607,7 +1549,7 @@ export const updateMessageWithReceipt = (msg, receipt) => {
1607
1549
  msg.userReceipt.push(receipt);
1608
1550
  }
1609
1551
  };
1610
- /** Update the message with a new reaction */
1552
+
1611
1553
  export const updateMessageWithReaction = (msg, reaction) => {
1612
1554
  const authorID = getKeyAuthor(reaction.key);
1613
1555
  const reactions = (msg.reactions || []).filter(r => getKeyAuthor(r.key) !== authorID);
@@ -1615,7 +1557,7 @@ export const updateMessageWithReaction = (msg, reaction) => {
1615
1557
  reactions.push(reaction);
1616
1558
  msg.reactions = reactions;
1617
1559
  };
1618
- /** Update the message with a new poll update */
1560
+
1619
1561
  export const updateMessageWithPollUpdate = (msg, update) => {
1620
1562
  const authorID = getKeyAuthor(update.pollUpdateMessageKey);
1621
1563
  const reactions = (msg.pollUpdates || []).filter(r => getKeyAuthor(r.pollUpdateMessageKey) !== authorID);
@@ -1624,19 +1566,14 @@ export const updateMessageWithPollUpdate = (msg, update) => {
1624
1566
  }
1625
1567
  msg.pollUpdates = reactions;
1626
1568
  };
1627
- /** Update the message with a new event response */
1569
+
1628
1570
  export const updateMessageWithEventResponse = (msg, update) => {
1629
1571
  const authorID = getKeyAuthor(update.eventResponseMessageKey);
1630
1572
  const responses = (msg.eventResponses || []).filter(r => getKeyAuthor(r.eventResponseMessageKey) !== authorID);
1631
1573
  responses.push(update);
1632
1574
  msg.eventResponses = responses;
1633
1575
  };
1634
- /**
1635
- * Aggregates all poll updates in a poll.
1636
- * @param msg the poll creation message
1637
- * @param meId your jid
1638
- * @returns A list of options & their voters
1639
- */
1576
+
1640
1577
  export function getAggregateVotesInPollMessage({ message, pollUpdates }, meId) {
1641
1578
  const opts = message?.pollCreationMessage?.options ||
1642
1579
  message?.pollCreationMessageV2?.options ||
@@ -1670,12 +1607,7 @@ export function getAggregateVotesInPollMessage({ message, pollUpdates }, meId) {
1670
1607
  }
1671
1608
  return Object.values(voteHashMap);
1672
1609
  }
1673
- /**
1674
- * Aggregates all event responses in an event message.
1675
- * @param msg the event creation message
1676
- * @param meId your jid
1677
- * @returns A list of response types & their responders
1678
- */
1610
+
1679
1611
  export function getAggregateResponsesInEventMessage({ eventResponses }, meId) {
1680
1612
  const responseTypes = ['GOING', 'NOT_GOING', 'MAYBE'];
1681
1613
  const responseMap = {};
@@ -1693,7 +1625,7 @@ export function getAggregateResponsesInEventMessage({ eventResponses }, meId) {
1693
1625
  }
1694
1626
  return Object.values(responseMap);
1695
1627
  }
1696
- /** Given a list of message keys, aggregates them by chat & sender. Useful for sending read receipts in bulk */
1628
+
1697
1629
  export const aggregateMessageKeysNotFromMe = (keys) => {
1698
1630
  const keyMap = {};
1699
1631
  for (const { remoteJid, id, participant, fromMe } of keys) {
@@ -1711,17 +1643,15 @@ export const aggregateMessageKeysNotFromMe = (keys) => {
1711
1643
  }
1712
1644
  return Object.values(keyMap);
1713
1645
  };
1646
+
1714
1647
  const REUPLOAD_REQUIRED_STATUS = [410, 404];
1715
- /**
1716
- * Downloads the given message. Throws an error if it's not a media message
1717
- */
1648
+
1718
1649
  export const downloadMediaMessage = async (message, type, options, ctx) => {
1719
1650
  const result = await downloadMsg().catch(async (error) => {
1720
1651
  if (ctx &&
1721
1652
  typeof error?.status === 'number' &&
1722
1653
  REUPLOAD_REQUIRED_STATUS.includes(error.status)) {
1723
1654
  ctx.logger.info({ key: message.key }, 'sending reupload media request...');
1724
- // request reupload
1725
1655
  message = await ctx.reuploadRequest(message);
1726
1656
  const result = await downloadMsg();
1727
1657
  return result;
@@ -1762,7 +1692,7 @@ export const downloadMediaMessage = async (message, type, options, ctx) => {
1762
1692
  return stream;
1763
1693
  }
1764
1694
  };
1765
- /** Checks whether the given message is a media message; if it is returns the inner content */
1695
+
1766
1696
  export const assertMediaContent = (content) => {
1767
1697
  content = extractMessageContent(content);
1768
1698
  const mediaContent = content?.documentMessage ||
@@ -1775,12 +1705,8 @@ export const assertMediaContent = (content) => {
1775
1705
  }
1776
1706
  return mediaContent;
1777
1707
  };
1778
- /**
1779
- * Checks if a WebP buffer is animated by looking for VP8X chunk with animation flag
1780
- * or ANIM/ANMF chunks
1781
- */
1708
+
1782
1709
  const isAnimatedWebP = (buffer) => {
1783
- // WebP must start with RIFF....WEBP
1784
1710
  if (buffer.length < 12 ||
1785
1711
  buffer[0] !== 0x52 ||
1786
1712
  buffer[1] !== 0x49 ||
@@ -1792,38 +1718,27 @@ const isAnimatedWebP = (buffer) => {
1792
1718
  buffer[11] !== 0x50) {
1793
1719
  return false;
1794
1720
  }
1795
- ;
1796
- // Parse chunks starting after RIFF header (12 bytes)
1797
1721
  let offset = 12;
1798
1722
  while (offset < buffer.length - 8) {
1799
1723
  const chunkFourCC = buffer.toString('ascii', offset, offset + 4);
1800
1724
  const chunkSize = buffer.readUInt32LE(offset + 4);
1801
1725
  if (chunkFourCC === 'VP8X') {
1802
- // VP8X extended header, check animation flag (bit 1 at offset+8)
1803
1726
  const flagsOffset = offset + 8;
1804
1727
  if (flagsOffset < buffer.length) {
1805
1728
  const flags = buffer[flagsOffset];
1806
1729
  if (flags & 0x02) {
1807
1730
  return true;
1808
1731
  }
1809
- ;
1810
1732
  }
1811
- ;
1812
1733
  }
1813
1734
  else if (chunkFourCC === 'ANIM' || chunkFourCC === 'ANMF') {
1814
- // ANIM or ANMF chunks indicate animation
1815
1735
  return true;
1816
1736
  }
1817
- ;
1818
- // Move to next chunk (chunk size + 8 bytes header, padded to even)
1819
1737
  offset += 8 + chunkSize + (chunkSize % 2);
1820
1738
  }
1821
- ;
1822
1739
  return false;
1823
1740
  };
1824
- /**
1825
- * Checks if a buffer is a WebP file
1826
- */
1741
+
1827
1742
  const isWebPBuffer = (buffer) => {
1828
1743
  return (buffer.length >= 12 &&
1829
1744
  buffer[0] === 0x52 &&
@@ -1835,13 +1750,7 @@ const isWebPBuffer = (buffer) => {
1835
1750
  buffer[10] === 0x42 &&
1836
1751
  buffer[11] === 0x50);
1837
1752
  };
1838
- /**
1839
- * Lia@Changes 30-01-26
1840
- * ---
1841
- * Determines whether a message should include a Biz Binary Node.
1842
- * A Biz Binary Node is added only for interactive messages
1843
- * such as buttons or other supported interactive types.
1844
- */
1753
+
1845
1754
  export const shouldIncludeBizBinaryNode = (message) => !!(message.buttonsMessage ||
1846
1755
  message.listMessage ||
1847
1756
  message.templateMessage ||