@crysnovax/baileys 2.5.0 → 2.5.2
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.
- package/WAProto/index.js +14789 -3578
- package/lib/Defaults/index.js +19 -11
- package/lib/Signal/libsignal.js +42 -18
- package/lib/Socket/Client//342/234/230 +1 -0
- package/lib/Socket/chats.js +246 -91
- package/lib/Socket/messages-recv.js +618 -322
- package/lib/Socket/messages-send.js +174 -74
- package/lib/Socket/newsletter.js +2 -2
- package/lib/Socket/socket.js +12 -20
- package/lib/Socket//342/230/201/357/270/216 +1 -0
- package/lib/Types/Mex.js +39 -0
- package/lib/Types/index.js +1 -0
- package/lib/Types//342/234/206 +1 -0
- package/lib/Utils/index.js +1 -0
- package/lib/Utils/messages.js +148 -114
- package/lib/Utils/use-sqlite-auth-state.js +109 -0
- package/lib/Utils//342/232/211 +1 -0
- package/lib/WABinary/constants.js +99 -5
- package/lib/WABinary//342/216/231 +1 -0
- package/package.json +43 -9
- package/lib/Utils/event-buffer.js +0 -589
package/lib/Utils/messages.js
CHANGED
|
@@ -2,7 +2,6 @@ import { Boom } from '@hapi/boom';
|
|
|
2
2
|
import { randomBytes } from 'crypto';
|
|
3
3
|
import { zip } from 'fflate';
|
|
4
4
|
import { promises as fs } from 'fs';
|
|
5
|
-
import {} from 'stream';
|
|
6
5
|
import { proto } from '../../WAProto/index.js';
|
|
7
6
|
import { CALL_AUDIO_PREFIX, CALL_VIDEO_PREFIX, DONATE_URL, LIBRARY_NAME, MEDIA_KEYS, URL_REGEX, WA_DEFAULT_EPHEMERAL } from '../Defaults/index.js';
|
|
8
7
|
import { AssociationType, ButtonHeaderType, ButtonType, CarouselCardType, ListType, ProtocolType, WAMessageStatus, WAProto } from '../Types/index.js';
|
|
@@ -12,6 +11,7 @@ import { generateMessageIDV2, getKeyAuthor, unixTimestampSeconds } from './gener
|
|
|
12
11
|
import { downloadContentFromMessage, encryptedStream, generateThumbnail, getAudioDuration, getAudioWaveform, getImageProcessingLibrary, getRawMediaUploadData, getStream, toBuffer } from './messages-media.js';
|
|
13
12
|
import { prepareRichResponseMessage } from './rich-message-utils.js';
|
|
14
13
|
import { shouldIncludeReportingToken } from './reporting-utils.js';
|
|
14
|
+
const CONCURRENCY_LIMIT = 15;
|
|
15
15
|
const MIMETYPE_MAP = {
|
|
16
16
|
image: 'image/jpeg',
|
|
17
17
|
video: 'video/mp4',
|
|
@@ -36,7 +36,7 @@ const mediaAnnotation = [
|
|
|
36
36
|
{ x: 20.840980529785156, y: -47.80188751220703 }
|
|
37
37
|
],
|
|
38
38
|
newsletter: {
|
|
39
|
-
//
|
|
39
|
+
// crysnovax@Note 03-02-26 --- You can change jid, message id, and name via .env (≧▽≦)
|
|
40
40
|
newsletterJid: process.env.NEWSLETTER_ID ||
|
|
41
41
|
'120363402922206865@newsletter',
|
|
42
42
|
serverMessageId: process.env.NEWSLETTER_MESSAGE_ID ||
|
|
@@ -106,9 +106,9 @@ export const prepareWAMessageMedia = async (message, options) => {
|
|
|
106
106
|
'url' in uploadData.media &&
|
|
107
107
|
!!uploadData.media.url &&
|
|
108
108
|
!!options.mediaCache &&
|
|
109
|
-
mediaType + ':' + uploadData.media.url;
|
|
109
|
+
mediaType + ':' + uploadData.media.url.toString();
|
|
110
110
|
if (mediaType === 'document' && !uploadData.fileName) {
|
|
111
|
-
uploadData.fileName =
|
|
111
|
+
uploadData.fileName = 'file';
|
|
112
112
|
}
|
|
113
113
|
if (!uploadData.mimetype) {
|
|
114
114
|
uploadData.mimetype = MIMETYPE_MAP[mediaType];
|
|
@@ -123,13 +123,13 @@ export const prepareWAMessageMedia = async (message, options) => {
|
|
|
123
123
|
return obj;
|
|
124
124
|
}
|
|
125
125
|
}
|
|
126
|
-
const isNewsletter = isJidNewsletter(options.jid);
|
|
126
|
+
const isNewsletter = !!options.jid && isJidNewsletter(options.jid);
|
|
127
127
|
const requiresDurationComputation = mediaType === 'audio' && typeof uploadData.seconds === 'undefined';
|
|
128
128
|
const requiresThumbnailComputation = (mediaType === 'image' || mediaType === 'video') && typeof uploadData.jpegThumbnail === 'undefined';
|
|
129
129
|
const requiresWaveformProcessing = mediaType === 'audio' && uploadData.ptt === true && typeof uploadData.waveform === 'undefined';
|
|
130
130
|
const requiresAudioBackground = options.backgroundColor && mediaType === 'audio' && uploadData.ptt === true;
|
|
131
131
|
const requiresOriginalForSomeProcessing = requiresDurationComputation || requiresThumbnailComputation || requiresWaveformProcessing;
|
|
132
|
-
//
|
|
132
|
+
// crysnovax@Changes 06-02-26 --- Add few support for sending media to newsletter (≧▽≦)
|
|
133
133
|
if (isNewsletter) {
|
|
134
134
|
logger?.info({ key: cacheableKey }, 'Preparing raw media for newsletter');
|
|
135
135
|
const { filePath, fileSha256, fileLength } = await getRawMediaUploadData(uploadData.media, options.mediaTypeOverride || mediaType, logger);
|
|
@@ -285,36 +285,33 @@ export const prepareDisappearingMessageSettingContent = (ephemeralExpiration) =>
|
|
|
285
285
|
ephemeralMessage: {
|
|
286
286
|
message: {
|
|
287
287
|
protocolMessage: {
|
|
288
|
-
type:
|
|
288
|
+
type: WAProto.Message.ProtocolMessage.Type.EPHEMERAL_SETTING,
|
|
289
289
|
ephemeralExpiration
|
|
290
290
|
}
|
|
291
291
|
}
|
|
292
292
|
}
|
|
293
293
|
};
|
|
294
|
-
return content;
|
|
294
|
+
return WAProto.Message.fromObject(content);
|
|
295
295
|
};
|
|
296
|
-
//
|
|
296
|
+
// crysnovax@Changes 31-01-26 --- Extract product message into a standalone function so it can also be reused as the header for interactive messages
|
|
297
297
|
const prepareProductMessage = async (message, options) => {
|
|
298
298
|
if (!message.businessOwnerJid) {
|
|
299
299
|
throw new Boom('"businessOwnerJid" is missing from the content', { statusCode: 400 });
|
|
300
300
|
}
|
|
301
301
|
const { imageMessage } = await prepareWAMessageMedia({ image: message.image || message.product.productImage }, options);
|
|
302
|
-
//
|
|
303
|
-
const content =
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
productImage: imageMessage
|
|
311
|
-
}
|
|
302
|
+
// crysnovax@Changes 01-02-26 --- Add product message default value
|
|
303
|
+
const { image, ...content } = message;
|
|
304
|
+
content.product = {
|
|
305
|
+
currencyCode: 'IDR',
|
|
306
|
+
priceAmount1000: 1000,
|
|
307
|
+
title: LIBRARY_NAME,
|
|
308
|
+
...message.product,
|
|
309
|
+
productImage: imageMessage
|
|
312
310
|
};
|
|
313
|
-
delete content.image;
|
|
314
311
|
return content;
|
|
315
312
|
};
|
|
316
313
|
/**
|
|
317
|
-
*
|
|
314
|
+
* crysnovax@Note 30-01-26
|
|
318
315
|
* ---
|
|
319
316
|
* Credits: Work on ensuring stickerPackMessage fields are valid by @jlucaso1 (https://github.com/jlucaso1).
|
|
320
317
|
* based on https://github.com/WhiskeySockets/Baileys/pull/1561
|
|
@@ -330,7 +327,7 @@ const prepareStickerPackMessage = async (message, options) => {
|
|
|
330
327
|
if (!cover) {
|
|
331
328
|
throw new Boom('Sticker pack must contain a cover', { statusCode: 400 });
|
|
332
329
|
}
|
|
333
|
-
//
|
|
330
|
+
// crysnovax@Changes 01-02-26 --- Add caching for sticker pack (similiar to prepareWAMessageMedia)
|
|
334
331
|
const cacheableKey = Array.isArray(stickers) &&
|
|
335
332
|
stickers.length &&
|
|
336
333
|
!!options.mediaCache &&
|
|
@@ -529,18 +526,18 @@ const prepareStickerPackMessage = async (message, options) => {
|
|
|
529
526
|
}
|
|
530
527
|
return WAProto.Message.StickerPackMessage.fromObject(content);
|
|
531
528
|
};
|
|
532
|
-
//
|
|
529
|
+
// crysnovax@Changes 30-01-26 --- Add native flow button helper for interactive message
|
|
533
530
|
const prepareNativeFlowButtons = (message) => {
|
|
534
|
-
const buttons = message.nativeFlow
|
|
531
|
+
const buttons = message.nativeFlow;
|
|
535
532
|
const isButtonsFieldArray = Array.isArray(buttons);
|
|
536
533
|
const correctedField = isButtonsFieldArray ? buttons : buttons.buttons;
|
|
537
534
|
const messageParamsJson = {};
|
|
538
|
-
//
|
|
535
|
+
// crysnovax@Changes 31-01-26 --- Add offer and options inside interactive message
|
|
539
536
|
if (hasOptionalProperty(message, 'offerText') && !!message.offerText) {
|
|
540
537
|
Object.assign(messageParamsJson, {
|
|
541
538
|
limited_time_offer: {
|
|
542
539
|
text: message.offerText || LIBRARY_NAME,
|
|
543
|
-
url: message.offerUrl || DONATE_URL, //
|
|
540
|
+
url: message.offerUrl || DONATE_URL, // crysnovax@Note 02-02-26 --- Apologies if this feels cheeky, just a fallback
|
|
544
541
|
copy_code: message.offerCode,
|
|
545
542
|
expiration_time: message.offerExpiration
|
|
546
543
|
}
|
|
@@ -590,6 +587,7 @@ const prepareNativeFlowButtons = (message) => {
|
|
|
590
587
|
display_text: buttonText || '🌐 Visit',
|
|
591
588
|
url: button.url,
|
|
592
589
|
merchant_url: button.url,
|
|
590
|
+
webview_interaction: button.useWebview,
|
|
593
591
|
icon: buttonIcon
|
|
594
592
|
})
|
|
595
593
|
};
|
|
@@ -604,7 +602,7 @@ const prepareNativeFlowButtons = (message) => {
|
|
|
604
602
|
})
|
|
605
603
|
};
|
|
606
604
|
}
|
|
607
|
-
//
|
|
605
|
+
// crysnovax@Changes 12-03-26 --- Add "single_select" shortcut \(°o°)/
|
|
608
606
|
else if (hasOptionalProperty(button, 'sections') && !!button.sections) {
|
|
609
607
|
return {
|
|
610
608
|
name: 'single_select',
|
|
@@ -627,7 +625,7 @@ const prepareNativeFlowButtons = (message) => {
|
|
|
627
625
|
* @param options.forceForward will show the message as forwarded even if it is from you
|
|
628
626
|
*/
|
|
629
627
|
export const generateForwardMessageContent = (message, forceForward) => {
|
|
630
|
-
let content = message.message
|
|
628
|
+
let content = message.message;
|
|
631
629
|
if (!content) {
|
|
632
630
|
throw new Boom('no content in message', { statusCode: 400 });
|
|
633
631
|
}
|
|
@@ -675,36 +673,35 @@ export const hasOptionalProperty = (obj, key) => {
|
|
|
675
673
|
key in obj &&
|
|
676
674
|
obj[key] != null;
|
|
677
675
|
};
|
|
678
|
-
//
|
|
676
|
+
// crysnovax@Changes 06-02-26 --- Validate album message media to avoid bug 👀
|
|
679
677
|
export const hasValidAlbumMedia = (message) => {
|
|
680
|
-
return message.imageMessage ||
|
|
681
|
-
message.videoMessage;
|
|
678
|
+
return !!(message.imageMessage ||
|
|
679
|
+
message.videoMessage);
|
|
682
680
|
};
|
|
683
681
|
export const hasValidInteractiveHeader = (message) => {
|
|
684
|
-
return message.imageMessage ||
|
|
682
|
+
return !!(message.imageMessage ||
|
|
685
683
|
message.videoMessage ||
|
|
686
684
|
message.documentMessage ||
|
|
687
685
|
message.productMessage ||
|
|
688
|
-
message.locationMessage;
|
|
686
|
+
message.locationMessage);
|
|
689
687
|
};
|
|
690
|
-
//
|
|
688
|
+
// crysnovax@Changes 30-01-26 --- Validate carousel cards header to avoid bug 👀
|
|
691
689
|
export const hasValidCarouselHeader = (message) => {
|
|
692
|
-
return message.imageMessage ||
|
|
690
|
+
return !!(message.imageMessage ||
|
|
693
691
|
message.videoMessage ||
|
|
694
|
-
message.productMessage;
|
|
692
|
+
message.productMessage);
|
|
695
693
|
};
|
|
696
694
|
export const generateWAMessageContent = async (message, options) => {
|
|
697
695
|
var _a, _b;
|
|
698
696
|
let m = {};
|
|
699
|
-
//
|
|
697
|
+
// crysnovax@Changes 30-01-26 --- Add "raw" boolean to send raw messages directly via generateWAMessage()
|
|
700
698
|
if (hasNonNullishProperty(message, 'raw')) {
|
|
701
699
|
delete message.raw;
|
|
702
700
|
return message;
|
|
703
701
|
}
|
|
704
|
-
//
|
|
702
|
+
// crysnovax@Changes 09-04-26 --- Add support for code block and table with richResponseMessage
|
|
705
703
|
else if (hasNonNullishProperty(message, 'code') ||
|
|
706
|
-
hasNonNullishProperty(message, '
|
|
707
|
-
hasNonNullishProperty(message, 'items') ||
|
|
704
|
+
hasNonNullishProperty(message, 'links') ||
|
|
708
705
|
hasNonNullishProperty(message, 'table') ||
|
|
709
706
|
hasNonNullishProperty(message, 'richResponse')) {
|
|
710
707
|
m = prepareRichResponseMessage(message);
|
|
@@ -720,7 +717,8 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
720
717
|
extContent.jpegThumbnail = urlInfo.jpegThumbnail;
|
|
721
718
|
extContent.description = urlInfo.description;
|
|
722
719
|
extContent.title = urlInfo.title;
|
|
723
|
-
extContent.previewType = 0;
|
|
720
|
+
extContent.previewType = urlInfo.previewType ?? 0;
|
|
721
|
+
extContent.linkPreviewMetadata = urlInfo.linkPreviewMetadata;
|
|
724
722
|
const img = urlInfo.highQualityThumbnail;
|
|
725
723
|
if (img) {
|
|
726
724
|
extContent.thumbnailDirectPath = img.directPath;
|
|
@@ -732,6 +730,21 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
732
730
|
extContent.thumbnailEncSha256 = img.fileEncSha256;
|
|
733
731
|
}
|
|
734
732
|
}
|
|
733
|
+
const faviconData = message.favicon;
|
|
734
|
+
if (faviconData && typeof options.upload === 'function') {
|
|
735
|
+
const { imageMessage } = await prepareWAMessageMedia({
|
|
736
|
+
image: faviconData
|
|
737
|
+
}, options);
|
|
738
|
+
extContent.faviconMMSMetadata = {
|
|
739
|
+
thumbnailDirectPath: imageMessage.directPath,
|
|
740
|
+
mediaKey: imageMessage.mediaKey,
|
|
741
|
+
mediaKeyTimestamp: imageMessage.mediaKeyTimestamp,
|
|
742
|
+
thumbnailWidth: 32,
|
|
743
|
+
thumbnailHeight: 32,
|
|
744
|
+
thumbnailSha256: imageMessage.fileSha256,
|
|
745
|
+
thumbnailEncSha256: imageMessage.fileEncSha256
|
|
746
|
+
};
|
|
747
|
+
}
|
|
735
748
|
if (options.backgroundColor) {
|
|
736
749
|
extContent.backgroundArgb = await assertColor(options.backgroundColor);
|
|
737
750
|
}
|
|
@@ -746,25 +759,25 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
746
759
|
throw new Boom('require atleast 1 contact', { statusCode: 400 });
|
|
747
760
|
}
|
|
748
761
|
if (contactLen === 1) {
|
|
749
|
-
m.contactMessage = message.contacts.contacts[0];
|
|
762
|
+
m.contactMessage = WAProto.Message.ContactMessage.create(message.contacts.contacts[0]);
|
|
750
763
|
}
|
|
751
764
|
else {
|
|
752
|
-
m.contactsArrayMessage = message.contacts;
|
|
765
|
+
m.contactsArrayMessage = WAProto.Message.ContactsArrayMessage.create(message.contacts);
|
|
753
766
|
}
|
|
754
767
|
}
|
|
755
768
|
else if (hasNonNullishProperty(message, 'location')) {
|
|
756
|
-
m.locationMessage = message.location;
|
|
769
|
+
m.locationMessage = WAProto.Message.LocationMessage.create(message.location);
|
|
757
770
|
}
|
|
758
771
|
else if (hasNonNullishProperty(message, 'react')) {
|
|
759
772
|
if (!message.react.senderTimestampMs) {
|
|
760
773
|
message.react.senderTimestampMs = Date.now();
|
|
761
774
|
}
|
|
762
|
-
m.reactionMessage = message.react;
|
|
775
|
+
m.reactionMessage = WAProto.Message.ReactionMessage.create(message.react);
|
|
763
776
|
}
|
|
764
777
|
else if (hasNonNullishProperty(message, 'delete')) {
|
|
765
778
|
m.protocolMessage = {
|
|
766
779
|
key: message.delete,
|
|
767
|
-
type:
|
|
780
|
+
type: WAProto.Message.ProtocolMessage.Type.REVOKE
|
|
768
781
|
};
|
|
769
782
|
}
|
|
770
783
|
else if (hasNonNullishProperty(message, 'forward')) {
|
|
@@ -894,27 +907,26 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
894
907
|
statusCode: 400
|
|
895
908
|
});
|
|
896
909
|
}
|
|
897
|
-
m.messageContextInfo = {
|
|
898
|
-
// encKey
|
|
899
|
-
messageSecret: message.poll.messageSecret || randomBytes(32)
|
|
900
|
-
};
|
|
901
910
|
const pollCreationMessage = {
|
|
902
911
|
name: message.poll.name,
|
|
903
912
|
selectableOptionsCount: message.poll.selectableCount,
|
|
904
|
-
options: message.poll.values.map(optionName => ({ optionName }))
|
|
913
|
+
options: message.poll.values.map(optionName => ({ optionName })),
|
|
914
|
+
endTime: message.poll.endDate ? message.poll.endDate.getTime() : undefined,
|
|
915
|
+
hideParticipantName: message.poll.hideVoter ?? false,
|
|
916
|
+
allowAddOption: message.poll.canAddOption ?? false
|
|
905
917
|
};
|
|
906
918
|
if (message.poll.toAnnouncementGroup) {
|
|
907
919
|
// poll v2 is for community announcement groups (single select and multiple)
|
|
908
920
|
m.pollCreationMessageV2 = pollCreationMessage;
|
|
909
921
|
}
|
|
910
922
|
else {
|
|
911
|
-
//
|
|
912
|
-
if (message.poll.pollType
|
|
923
|
+
// crysnovax@Changes 08-02-26 --- Add quiz message support
|
|
924
|
+
if (message.poll.pollType === 1) {
|
|
913
925
|
if (!message.poll.correctAnswer) {
|
|
914
926
|
throw new Boom('No "correctAnswer" provided for quiz', { statusCode: 400 });
|
|
915
927
|
}
|
|
916
928
|
m.pollCreationMessageV5 = {
|
|
917
|
-
//
|
|
929
|
+
// crysnovax@Note 08-02-26 --- quiz for newsletter only
|
|
918
930
|
...pollCreationMessage,
|
|
919
931
|
correctAnswer: {
|
|
920
932
|
optionName: message.poll.correctAnswer.toString()
|
|
@@ -932,8 +944,12 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
932
944
|
m.pollCreationMessage = pollCreationMessage;
|
|
933
945
|
}
|
|
934
946
|
}
|
|
947
|
+
m.messageContextInfo = {
|
|
948
|
+
// encKey
|
|
949
|
+
messageSecret: message.poll.messageSecret || randomBytes(32)
|
|
950
|
+
};
|
|
935
951
|
}
|
|
936
|
-
//
|
|
952
|
+
// crysnovax@Changes 08-02-26 --- Add poll result snapshot message
|
|
937
953
|
else if (hasNonNullishProperty(message, 'pollResult')) {
|
|
938
954
|
const pollResultSnapshotMessage = {
|
|
939
955
|
name: message.pollResult.name,
|
|
@@ -942,7 +958,7 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
942
958
|
optionVoteCount: parseInt(vote.voteCount)
|
|
943
959
|
}))
|
|
944
960
|
};
|
|
945
|
-
if (message.pollResult.pollType
|
|
961
|
+
if (message.pollResult.pollType === 1) {
|
|
946
962
|
pollResultSnapshotMessage.pollType = proto.Message.PollType.QUIZ;
|
|
947
963
|
m.pollResultSnapshotMessageV3 = pollResultSnapshotMessage;
|
|
948
964
|
}
|
|
@@ -951,7 +967,7 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
951
967
|
m.pollResultSnapshotMessage = pollResultSnapshotMessage;
|
|
952
968
|
}
|
|
953
969
|
}
|
|
954
|
-
//
|
|
970
|
+
// crysnovax@Changes 08-02-26 --- Add poll update message
|
|
955
971
|
else if (hasNonNullishProperty(message, 'pollUpdate')) {
|
|
956
972
|
if (!message.pollUpdate.key) {
|
|
957
973
|
throw new Boom('Message key is required', { statusCode: 400 });
|
|
@@ -968,7 +984,7 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
968
984
|
}
|
|
969
985
|
else if (hasNonNullishProperty(message, 'sharePhoneNumber')) {
|
|
970
986
|
m.protocolMessage = {
|
|
971
|
-
type:
|
|
987
|
+
type: proto.Message.ProtocolMessage.Type.SHARE_PHONE_NUMBER
|
|
972
988
|
};
|
|
973
989
|
}
|
|
974
990
|
else if (hasNonNullishProperty(message, 'requestPhoneNumber')) {
|
|
@@ -976,7 +992,7 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
976
992
|
}
|
|
977
993
|
else if (hasNonNullishProperty(message, 'limitSharing')) {
|
|
978
994
|
m.protocolMessage = {
|
|
979
|
-
type:
|
|
995
|
+
type: proto.Message.ProtocolMessage.Type.LIMIT_SHARING,
|
|
980
996
|
limitSharing: {
|
|
981
997
|
sharingLimited: message.limitSharing === true,
|
|
982
998
|
trigger: 1,
|
|
@@ -985,14 +1001,14 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
985
1001
|
}
|
|
986
1002
|
};
|
|
987
1003
|
}
|
|
988
|
-
//
|
|
1004
|
+
// crysnovax@Changes 01-02-26 --- Add payment invite message
|
|
989
1005
|
else if (hasNonNullishProperty(message, 'paymentInviteServiceType')) {
|
|
990
1006
|
m.paymentInviteMessage = {
|
|
991
1007
|
expiryTimestamp: Date.now(),
|
|
992
1008
|
serviceType: message.paymentInviteServiceType
|
|
993
1009
|
};
|
|
994
1010
|
}
|
|
995
|
-
//
|
|
1011
|
+
// crysnovax@Changes 01-02-26 --- Add order message
|
|
996
1012
|
else if (hasNonNullishProperty(message, 'orderText')) {
|
|
997
1013
|
if (!Buffer.isBuffer(message.thumbnail)) {
|
|
998
1014
|
throw new Boom('Must provide thumbnail buffer in order message', { statusCode: 400 });
|
|
@@ -1011,19 +1027,21 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
1011
1027
|
};
|
|
1012
1028
|
delete m.orderMessage.orderText;
|
|
1013
1029
|
}
|
|
1014
|
-
//
|
|
1030
|
+
// crysnovax@Changes 31-01-26 --- Add support for album messages
|
|
1015
1031
|
else if (hasNonNullishProperty(message, 'album')) {
|
|
1016
1032
|
if (!Array.isArray(message.album)) {
|
|
1017
1033
|
throw new Boom('Invalid album type. Expected an array.', { statusCode: 400 });
|
|
1018
1034
|
}
|
|
1019
1035
|
let videoCount = 0;
|
|
1020
1036
|
for (let i = 0; i < message.album.length; i++) {
|
|
1021
|
-
if (message.album[i].video)
|
|
1022
|
-
|
|
1037
|
+
if (message.album[i].video)
|
|
1038
|
+
videoCount++;
|
|
1039
|
+
}
|
|
1023
1040
|
let imageCount = 0;
|
|
1024
1041
|
for (let i = 0; i < message.album.length; i++) {
|
|
1025
|
-
if (message.album[i].image)
|
|
1026
|
-
|
|
1042
|
+
if (message.album[i].image)
|
|
1043
|
+
imageCount++;
|
|
1044
|
+
}
|
|
1027
1045
|
if ((videoCount + imageCount) < 2) {
|
|
1028
1046
|
throw new Boom('Minimum provide 2 media to upload album message', { statusCode: 400 });
|
|
1029
1047
|
}
|
|
@@ -1035,11 +1053,11 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
1035
1053
|
else {
|
|
1036
1054
|
m = await prepareWAMessageMedia(message, options);
|
|
1037
1055
|
}
|
|
1038
|
-
//
|
|
1056
|
+
// crysnovax@Changes 30-01-26 --- Add interactive messages (buttonsMessage, listMessage, interactiveMessage, templateMessage, and carouselMessage)
|
|
1039
1057
|
if (hasNonNullishProperty(message, 'buttons')) {
|
|
1040
1058
|
const buttonsMessage = {
|
|
1041
1059
|
buttons: message.buttons.map(button => {
|
|
1042
|
-
//
|
|
1060
|
+
// crysnovax@Changes 12-03-26 --- Add "single_select" shortcut!
|
|
1043
1061
|
const buttonText = button.text || button.buttonText;
|
|
1044
1062
|
if (hasOptionalProperty(button, 'sections')) {
|
|
1045
1063
|
return {
|
|
@@ -1097,7 +1115,7 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
1097
1115
|
};
|
|
1098
1116
|
m = { listMessage };
|
|
1099
1117
|
}
|
|
1100
|
-
//
|
|
1118
|
+
// crysnovax@Note 03-02-26 --- This message type is shown on WhatsApp Web/Desktop and iOS (I guess 。◕‿◕。). On Android, it only appears in newsletter (so far ಥ‿ಥ)
|
|
1101
1119
|
else if (hasNonNullishProperty(message, 'templateButtons')) {
|
|
1102
1120
|
const hydratedTemplate = {
|
|
1103
1121
|
hydratedButtons: message.templateButtons.map((button, i) => {
|
|
@@ -1146,7 +1164,7 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
1146
1164
|
if (hasOptionalProperty(message, 'footer')) {
|
|
1147
1165
|
hydratedTemplate.hydratedFooterText = message.footer;
|
|
1148
1166
|
}
|
|
1149
|
-
hydratedTemplate.templateId = message.id || 'template-' + Date.now(); //
|
|
1167
|
+
hydratedTemplate.templateId = message.id || 'template-' + Date.now(); // crysnovax@Note 04-02-26 --- Minimal templateId to satisfy WhatsApp ( ꈍᴗꈍ)
|
|
1150
1168
|
m = {
|
|
1151
1169
|
templateMessage: {
|
|
1152
1170
|
hydratedFourRowTemplate: hydratedTemplate,
|
|
@@ -1218,9 +1236,9 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
1218
1236
|
else {
|
|
1219
1237
|
carouselHeader = await prepareWAMessageMedia(card, options).catch(() => ({ }));
|
|
1220
1238
|
}
|
|
1221
|
-
const isValidHeader = hasValidCarouselHeader(carouselHeader)
|
|
1239
|
+
const isValidHeader = hasValidCarouselHeader(carouselHeader);
|
|
1222
1240
|
if (!isValidHeader) {
|
|
1223
|
-
|
|
1241
|
+
throw new Boom('Invalid media type for carousel card', { statusCode: 400 });
|
|
1224
1242
|
}
|
|
1225
1243
|
const carouselCard = {
|
|
1226
1244
|
nativeFlowMessage: prepareNativeFlowButtons(card.nativeFlow ? card : [])
|
|
@@ -1243,11 +1261,11 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
1243
1261
|
Object.assign(carouselCard.header, carouselHeader);
|
|
1244
1262
|
}
|
|
1245
1263
|
if (hasOptionalProperty(card, 'audioFooter')) {
|
|
1246
|
-
const
|
|
1264
|
+
const { audioMessage } = await prepareWAMessageMedia({
|
|
1247
1265
|
audio: card.audioFooter
|
|
1248
1266
|
}, options);
|
|
1249
1267
|
carouselCard.footer = {
|
|
1250
|
-
audioMessage
|
|
1268
|
+
audioMessage,
|
|
1251
1269
|
hasMediaAttachment: true
|
|
1252
1270
|
};
|
|
1253
1271
|
}
|
|
@@ -1268,7 +1286,7 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
1268
1286
|
}
|
|
1269
1287
|
m = { interactiveMessage };
|
|
1270
1288
|
}
|
|
1271
|
-
//
|
|
1289
|
+
// crysnovax@Changes 01-02-26 --- Add request payment message
|
|
1272
1290
|
else if (hasNonNullishProperty(message, 'requestPaymentFrom')) {
|
|
1273
1291
|
const requestPaymentMessage = {
|
|
1274
1292
|
amount: {
|
|
@@ -1292,7 +1310,7 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
1292
1310
|
}
|
|
1293
1311
|
m = { requestPaymentMessage };
|
|
1294
1312
|
}
|
|
1295
|
-
//
|
|
1313
|
+
// crysnovax@Changes 01-02-26 --- Add invoice message
|
|
1296
1314
|
else if (hasNonNullishProperty(message, 'invoiceNote')) {
|
|
1297
1315
|
const attachment = m.imageMessage || m.documentMessage;
|
|
1298
1316
|
const type = Object.keys(m)[0].replace('Message', '').toUpperCase();
|
|
@@ -1318,7 +1336,7 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
1318
1336
|
}
|
|
1319
1337
|
m = { invoiceMessage };
|
|
1320
1338
|
}
|
|
1321
|
-
//
|
|
1339
|
+
// crysnovax@Changes 31-01-26 --- Add direct externalAdReply access (no need to create contextInfo first)
|
|
1322
1340
|
if (hasOptionalProperty(message, 'externalAdReply') && !!message.externalAdReply) {
|
|
1323
1341
|
const messageType = Object.keys(m)[0];
|
|
1324
1342
|
const key = m[messageType];
|
|
@@ -1327,7 +1345,7 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
1327
1345
|
throw new Boom('Thumbnail must in buffer type', { statusCode: 400 });
|
|
1328
1346
|
}
|
|
1329
1347
|
if (!content.url || typeof content.url !== 'string') {
|
|
1330
|
-
content.url = DONATE_URL; //
|
|
1348
|
+
content.url = DONATE_URL; // crysnovax@Note 02-02-26 --- Apologies if this feels cheeky, just a fallback
|
|
1331
1349
|
}
|
|
1332
1350
|
const externalAdReply = {
|
|
1333
1351
|
...content,
|
|
@@ -1335,9 +1353,9 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
1335
1353
|
mediaType: content.mediaType || 1,
|
|
1336
1354
|
mediaUrl: content.url,
|
|
1337
1355
|
renderLargerThumbnail: content.largeThumbnail,
|
|
1338
|
-
sourceUrl: content.url
|
|
1356
|
+
sourceUrl: content.url,
|
|
1339
1357
|
thumbnail: content.thumbnail,
|
|
1340
|
-
thumbnailUrl: content.url,
|
|
1358
|
+
thumbnailUrl: content.url + '?update=' + Date.now(),
|
|
1341
1359
|
title: content.title || LIBRARY_NAME
|
|
1342
1360
|
};
|
|
1343
1361
|
delete externalAdReply.subTitle;
|
|
@@ -1354,18 +1372,21 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
1354
1372
|
(hasOptionalProperty(message, 'mentionAll') && message.mentionAll)) {
|
|
1355
1373
|
const messageType = Object.keys(m)[0];
|
|
1356
1374
|
const key = m[messageType];
|
|
1357
|
-
if ('contextInfo' in key
|
|
1358
|
-
key.contextInfo
|
|
1375
|
+
if (key && 'contextInfo' in key) {
|
|
1376
|
+
key.contextInfo = key.contextInfo || {};
|
|
1377
|
+
if (message.mentions?.length) {
|
|
1378
|
+
key.contextInfo.mentionedJid = message.mentions;
|
|
1379
|
+
}
|
|
1380
|
+
if (message.mentionAll) {
|
|
1381
|
+
key.contextInfo.nonJidMentions = 1;
|
|
1382
|
+
}
|
|
1359
1383
|
}
|
|
1360
1384
|
else if (key) {
|
|
1361
1385
|
key.contextInfo = {
|
|
1362
|
-
mentionedJid: message.mentions
|
|
1386
|
+
mentionedJid: message.mentions,
|
|
1387
|
+
nonJidMentions: message.mentionAll ? 1 : 0
|
|
1363
1388
|
};
|
|
1364
1389
|
}
|
|
1365
|
-
if (message.mentionAll) {
|
|
1366
|
-
key.contextInfo.mentionedJid = [];
|
|
1367
|
-
key.contextInfo.nonJidMentions = 1;
|
|
1368
|
-
}
|
|
1369
1390
|
}
|
|
1370
1391
|
if (hasOptionalProperty(message, 'contextInfo') && !!message.contextInfo) {
|
|
1371
1392
|
const messageType = Object.keys(m)[0];
|
|
@@ -1377,7 +1398,7 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
1377
1398
|
key.contextInfo = message.contextInfo;
|
|
1378
1399
|
}
|
|
1379
1400
|
}
|
|
1380
|
-
//
|
|
1401
|
+
// crysnovax@Changes 31-01-26 --- Add "groupStatus" boolean to set contextInfo.isGroupStatus and wrap message into groupStatusMessageV2
|
|
1381
1402
|
if (hasOptionalProperty(message, 'groupStatus') && !!message.groupStatus) {
|
|
1382
1403
|
const messageType = Object.keys(m)[0];
|
|
1383
1404
|
const key = m[messageType];
|
|
@@ -1392,20 +1413,35 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
1392
1413
|
m = { groupStatusMessageV2: { message: m } };
|
|
1393
1414
|
delete message.groupStatus;
|
|
1394
1415
|
}
|
|
1395
|
-
//
|
|
1416
|
+
// crysnovax@Changes 06-05-26 --- Add "spoiler" boolean to set contextInfo.isSpoiler and wrap message into spoilerMessage
|
|
1417
|
+
if (hasOptionalProperty(message, 'spoiler') && !!message.spoiler) {
|
|
1418
|
+
const messageType = Object.keys(m)[0];
|
|
1419
|
+
const key = m[messageType];
|
|
1420
|
+
if ('contextInfo' in key && !!key.contextInfo) {
|
|
1421
|
+
key.contextInfo.isSpoiler = message.spoiler;
|
|
1422
|
+
}
|
|
1423
|
+
else if (key) {
|
|
1424
|
+
key.contextInfo = {
|
|
1425
|
+
isSpoiler: message.spoiler
|
|
1426
|
+
};
|
|
1427
|
+
}
|
|
1428
|
+
m = { spoilerMessage: { message: m } };
|
|
1429
|
+
delete message.spoiler;
|
|
1430
|
+
}
|
|
1431
|
+
// crysnovax@Changes 02-02-26 --- Add "interactiveAsTemplate" boolean to wrap interactiveMessage into templateMessage
|
|
1396
1432
|
else if (hasOptionalProperty(message, 'interactiveAsTemplate') && !!message.interactiveAsTemplate) {
|
|
1397
1433
|
if (!m.interactiveMessage) {
|
|
1398
|
-
throw new Boom('Invalid message type for template', { statusCode: 400 }); //
|
|
1434
|
+
throw new Boom('Invalid message type for template', { statusCode: 400 }); // crysnovax@Note 02-02-26 --- To avoid bug 👀
|
|
1399
1435
|
}
|
|
1400
1436
|
m = {
|
|
1401
1437
|
templateMessage: {
|
|
1402
1438
|
interactiveMessageTemplate: m.interactiveMessage,
|
|
1403
|
-
templateId: message.id || 'template-' + Date.now() //
|
|
1439
|
+
templateId: message.id || 'template-' + Date.now() // crysnovax@Note 04-02-26 --- Minimal templateId to satisfy WhatsApp ( ꈍᴗꈍ)
|
|
1404
1440
|
}
|
|
1405
1441
|
};
|
|
1406
1442
|
delete message.interactiveAsTemplate;
|
|
1407
1443
|
}
|
|
1408
|
-
//
|
|
1444
|
+
// crysnovax@Changes 30-01-26 --- Add "ephemeral" boolean to wrap message into ephemeralMessage like "viewOnce"
|
|
1409
1445
|
if (hasOptionalProperty(message, 'ephemeral') && !!message.ephemeral) {
|
|
1410
1446
|
m = { ephemeralMessage: { message: m } };
|
|
1411
1447
|
delete message.ephemeral;
|
|
@@ -1413,12 +1449,12 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
1413
1449
|
else if (hasOptionalProperty(message, 'viewOnce') && !!message.viewOnce) {
|
|
1414
1450
|
m = { viewOnceMessage: { message: m } };
|
|
1415
1451
|
}
|
|
1416
|
-
//
|
|
1452
|
+
// crysnovax@Changes 03-02-26 --- Add "viewOnceV2" boolean to wrap message into viewOnceMessageV2 like "viewOnce"
|
|
1417
1453
|
else if (hasOptionalProperty(message, 'viewOnceV2') && !!message.viewOnceV2) {
|
|
1418
1454
|
m = { viewOnceMessageV2: { message: m } };
|
|
1419
1455
|
delete message.viewOnceV2;
|
|
1420
1456
|
}
|
|
1421
|
-
//
|
|
1457
|
+
// crysnovax@Changes 03-02-26 --- Add "viewOnceV2Extension" boolean to wrap message into viewOnceMessageV2Extension like "viewOnce"
|
|
1422
1458
|
else if (hasOptionalProperty(message, 'viewOnceV2Extension') && !!message.viewOnceV2Extension) {
|
|
1423
1459
|
m = { viewOnceMessageV2Extension: { message: m } };
|
|
1424
1460
|
delete message.viewOnceV2Extension;
|
|
@@ -1429,7 +1465,7 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
1429
1465
|
key: message.edit,
|
|
1430
1466
|
editedMessage: m,
|
|
1431
1467
|
timestampMs: Date.now(),
|
|
1432
|
-
type:
|
|
1468
|
+
type: WAProto.Message.ProtocolMessage.Type.MESSAGE_EDIT
|
|
1433
1469
|
}
|
|
1434
1470
|
}
|
|
1435
1471
|
}
|
|
@@ -1439,13 +1475,13 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
1439
1475
|
m.messageContextInfo.messageSecret = randomBytes(32);
|
|
1440
1476
|
}
|
|
1441
1477
|
}
|
|
1442
|
-
return
|
|
1478
|
+
return WAProto.Message.create(m);
|
|
1443
1479
|
};
|
|
1444
1480
|
export const generateWAMessageFromContent = (jid, message, options) => {
|
|
1445
1481
|
// set timestamp to now
|
|
1446
1482
|
// if not specified
|
|
1447
1483
|
if (!options.timestamp) {
|
|
1448
|
-
options.timestamp = Date
|
|
1484
|
+
options.timestamp = new Date();
|
|
1449
1485
|
}
|
|
1450
1486
|
const messageContextInfo = message.messageContextInfo
|
|
1451
1487
|
const innerMessage = normalizeMessageContent(message);
|
|
@@ -1495,7 +1531,7 @@ export const generateWAMessageFromContent = (jid, message, options) => {
|
|
|
1495
1531
|
//ephemeralSettingTimestamp: options.ephemeralOptions.eph_setting_ts?.toString()
|
|
1496
1532
|
};
|
|
1497
1533
|
}
|
|
1498
|
-
//
|
|
1534
|
+
// crysnovax@Changes 30-01-26 --- Add deviceListMetadata inside messageContextInfo for private chat
|
|
1499
1535
|
if (messageContextInfo?.messageSecret && (isPnUser(jid) || isLidUser(jid))) {
|
|
1500
1536
|
messageContextInfo.deviceListMetadata = {
|
|
1501
1537
|
recipientKeyHash: randomBytes(10),
|
|
@@ -1503,7 +1539,7 @@ export const generateWAMessageFromContent = (jid, message, options) => {
|
|
|
1503
1539
|
};
|
|
1504
1540
|
messageContextInfo.deviceListMetadataVersion = 2
|
|
1505
1541
|
}
|
|
1506
|
-
message =
|
|
1542
|
+
message = WAProto.Message.create(message);
|
|
1507
1543
|
const messageJSON = {
|
|
1508
1544
|
key: {
|
|
1509
1545
|
remoteJid: jid,
|
|
@@ -1518,11 +1554,11 @@ export const generateWAMessageFromContent = (jid, message, options) => {
|
|
|
1518
1554
|
};
|
|
1519
1555
|
return WAProto.WebMessageInfo.fromObject(messageJSON);
|
|
1520
1556
|
};
|
|
1521
|
-
export const generateWAMessage = async (jid, content, options
|
|
1557
|
+
export const generateWAMessage = async (jid, content, options) => {
|
|
1522
1558
|
// ensure msg ID is with every log
|
|
1523
1559
|
options.logger = options?.logger?.child({ msgId: options.messageId });
|
|
1524
1560
|
// Pass jid in the options to generateWAMessageContent
|
|
1525
|
-
if (jid
|
|
1561
|
+
if (jid) {
|
|
1526
1562
|
options.jid = jid;
|
|
1527
1563
|
}
|
|
1528
1564
|
return generateWAMessageFromContent(jid, await generateWAMessageContent(content, options), options);
|
|
@@ -1554,7 +1590,7 @@ export const normalizeMessageContent = (content) => {
|
|
|
1554
1590
|
content = inner.message;
|
|
1555
1591
|
}
|
|
1556
1592
|
return content;
|
|
1557
|
-
//
|
|
1593
|
+
// crysnovax@Changes 03-02-26 --- Add all futureProofMessage into getFutureProofMessage()
|
|
1558
1594
|
function getFutureProofMessage(message) {
|
|
1559
1595
|
return (
|
|
1560
1596
|
message?.associatedChildMessage ||
|
|
@@ -1571,10 +1607,14 @@ export const normalizeMessageContent = (content) => {
|
|
|
1571
1607
|
message?.groupStatusMessageV2 ||
|
|
1572
1608
|
message?.limitSharingMessage ||
|
|
1573
1609
|
message?.lottieStickerMessage ||
|
|
1610
|
+
message?.newsletterAdminProfileMessage ||
|
|
1611
|
+
message?.newsletterAdminProfileMessageV2 ||
|
|
1612
|
+
message?.newsletterAdminProfileStatusMessage ||
|
|
1574
1613
|
message?.pollCreationMessageV4 ||
|
|
1575
1614
|
message?.pollCreationOptionImageMessage ||
|
|
1576
1615
|
message?.questionMessage ||
|
|
1577
1616
|
message?.questionReplyMessage ||
|
|
1617
|
+
message?.spoilerMessage ||
|
|
1578
1618
|
message?.statusAddYours ||
|
|
1579
1619
|
message?.statusMentionMessage ||
|
|
1580
1620
|
message?.viewOnceMessage ||
|
|
@@ -1872,20 +1912,14 @@ const isWebPBuffer = (buffer) => {
|
|
|
1872
1912
|
);
|
|
1873
1913
|
};
|
|
1874
1914
|
/**
|
|
1875
|
-
*
|
|
1915
|
+
* crysnovax@Changes 30-01-26
|
|
1876
1916
|
* ---
|
|
1877
1917
|
* Determines whether a message should include a Biz Binary Node.
|
|
1878
1918
|
* A Biz Binary Node is added only for interactive messages
|
|
1879
1919
|
* such as buttons or other supported interactive types.
|
|
1880
1920
|
*/
|
|
1881
|
-
export const shouldIncludeBizBinaryNode = (message) =>
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
!message.interactiveMessage.shopStorefrontMessage;
|
|
1887
|
-
return (message.buttonsMessage ||
|
|
1888
|
-
message.interactiveMessage ||
|
|
1889
|
-
message.listMessage ||
|
|
1890
|
-
hasValidInteractive);
|
|
1891
|
-
};
|
|
1921
|
+
export const shouldIncludeBizBinaryNode = (message) => !!(message.buttonsMessage ||
|
|
1922
|
+
message.listMessage ||
|
|
1923
|
+
message.templateMessage ||
|
|
1924
|
+
(message.interactiveMessage &&
|
|
1925
|
+
message.interactiveMessage.nativeFlowMessage));
|