violetics 7.0.6-alpha → 7.0.7-alpha
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/.github/workflows/publish.yml +75 -0
- package/.pnp.cjs +8572 -0
- package/.pnp.loader.mjs +2126 -0
- package/.yarn/install-state.gz +0 -0
- package/WAProto/index.js +1542 -179
- package/lib/Defaults/index.js +7 -8
- package/lib/Socket/Client/websocket.js +1 -10
- package/lib/Socket/chats.js +4 -5
- package/lib/Socket/messages-recv.js +85 -26
- package/lib/Socket/messages-send.js +47 -52
- package/lib/Socket/newsletter.js +2 -10
- package/lib/Socket/socket.js +13 -23
- package/lib/Types/Message.js +1 -1
- package/lib/Utils/event-buffer.js +2 -2
- package/lib/Utils/generics.js +1 -2
- package/lib/Utils/index.js +1 -0
- package/lib/Utils/message-retry-manager.js +1 -1
- package/lib/Utils/messages-media.js +18 -12
- package/lib/Utils/messages.js +86 -85
- package/lib/Utils/noise-handler.js +0 -6
- package/lib/Utils/use-single-file-auth-state.js +96 -0
- package/lib/WABinary/generic-utils.js +58 -41
- package/lib/WABinary/jid-utils.js +1 -1
- package/package.json +3 -22
package/lib/Utils/messages.js
CHANGED
|
@@ -2,7 +2,7 @@ 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 {
|
|
5
|
+
import {} from 'stream';
|
|
6
6
|
import { proto } from '../../WAProto/index.js';
|
|
7
7
|
import { CALL_AUDIO_PREFIX, CALL_VIDEO_PREFIX, DONATE_URL, LIBRARY_NAME, MEDIA_KEYS, URL_REGEX, WA_DEFAULT_EPHEMERAL } from '../Defaults/index.js';
|
|
8
8
|
import { AssociationType, ButtonHeaderType, ButtonType, CarouselCardType, ListType, ProtocolType, WAMessageStatus, WAProto } from '../Types/index.js';
|
|
@@ -44,7 +44,7 @@ const mediaAnnotation = [
|
|
|
44
44
|
Buffer.from('f09d96b2f09d978df09d96baf09d978bf09d96bff09d96baf09d9785f09d9785', 'hex').toString(),
|
|
45
45
|
contentType: proto.ContextInfo.ForwardedNewsletterMessageInfo.ContentType.UPDATE,
|
|
46
46
|
accessibilityText: process.env.NEWSLETTER_ACCESSIBILITY_TEXT ||
|
|
47
|
-
'
|
|
47
|
+
'@itsliaaa/baileys'
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
];
|
|
@@ -122,18 +122,18 @@ export const prepareWAMessageMedia = async (message, options) => {
|
|
|
122
122
|
return obj;
|
|
123
123
|
}
|
|
124
124
|
}
|
|
125
|
-
const isNewsletter =
|
|
125
|
+
const isNewsletter = isJidNewsletter(options.jid);
|
|
126
126
|
const requiresDurationComputation = mediaType === 'audio' && typeof uploadData.seconds === 'undefined';
|
|
127
|
-
const requiresThumbnailComputation = (mediaType === 'image' || mediaType === 'video') && typeof uploadData
|
|
128
|
-
const requiresWaveformProcessing = mediaType === 'audio' && uploadData.ptt === true;
|
|
127
|
+
const requiresThumbnailComputation = (mediaType === 'image' || mediaType === 'video') && typeof uploadData.jpegThumbnail === 'undefined';
|
|
128
|
+
const requiresWaveformProcessing = mediaType === 'audio' && uploadData.ptt === true && typeof uploadData.waveform === 'undefined';
|
|
129
129
|
const requiresAudioBackground = options.backgroundColor && mediaType === 'audio' && uploadData.ptt === true;
|
|
130
130
|
const requiresOriginalForSomeProcessing = requiresDurationComputation || requiresThumbnailComputation || requiresWaveformProcessing;
|
|
131
|
-
//
|
|
131
|
+
// Lia@Changes 06-02-26 --- Add few support for sending media to newsletter (≧▽≦)
|
|
132
132
|
if (isNewsletter) {
|
|
133
133
|
logger?.info({ key: cacheableKey }, 'Preparing raw media for newsletter');
|
|
134
134
|
const { filePath, fileSha256, fileLength } = await getRawMediaUploadData(uploadData.media, options.mediaTypeOverride || mediaType, logger);
|
|
135
135
|
const fileSha256B64 = fileSha256.toString('base64');
|
|
136
|
-
const [{ mediaUrl, directPath }] = await Promise.all([
|
|
136
|
+
const [{ mediaUrl, directPath, thumbnailDirectPath, thumbnailSha256 }] = await Promise.all([
|
|
137
137
|
(async () => {
|
|
138
138
|
const result = options.upload(filePath, {
|
|
139
139
|
fileEncSha256B64: fileSha256B64,
|
|
@@ -177,6 +177,8 @@ export const prepareWAMessageMedia = async (message, options) => {
|
|
|
177
177
|
directPath,
|
|
178
178
|
fileSha256,
|
|
179
179
|
fileLength,
|
|
180
|
+
thumbnailDirectPath,
|
|
181
|
+
thumbnailSha256,
|
|
180
182
|
...uploadData
|
|
181
183
|
})
|
|
182
184
|
});
|
|
@@ -290,13 +292,13 @@ export const prepareDisappearingMessageSettingContent = (ephemeralExpiration) =>
|
|
|
290
292
|
};
|
|
291
293
|
return content;
|
|
292
294
|
};
|
|
293
|
-
//
|
|
295
|
+
// Lia@Changes 31-01-26 --- Extract product message into a standalone function so it can also be reused as the header for interactive messages
|
|
294
296
|
const prepareProductMessage = async (message, options) => {
|
|
295
297
|
if (!message.businessOwnerJid) {
|
|
296
298
|
throw new Boom('"businessOwnerJid" is missing from the content', { statusCode: 400 });
|
|
297
299
|
}
|
|
298
300
|
const { imageMessage } = await prepareWAMessageMedia({ image: message.image || message.product.productImage }, options);
|
|
299
|
-
//
|
|
301
|
+
// Lia@Changes 01-02-26 --- Add product message default value
|
|
300
302
|
const content = {
|
|
301
303
|
...message,
|
|
302
304
|
product: {
|
|
@@ -327,7 +329,7 @@ const prepareStickerPackMessage = async (message, options) => {
|
|
|
327
329
|
if (!cover) {
|
|
328
330
|
throw new Boom('Sticker pack must contain a cover', { statusCode: 400 });
|
|
329
331
|
}
|
|
330
|
-
//
|
|
332
|
+
// Lia@Changes 01-02-26 --- Add caching for sticker pack (similiar to prepareWAMessageMedia)
|
|
331
333
|
const cacheableKey = Array.isArray(stickers) &&
|
|
332
334
|
stickers.length &&
|
|
333
335
|
!!options.mediaCache &&
|
|
@@ -386,7 +388,7 @@ const prepareStickerPackMessage = async (message, options) => {
|
|
|
386
388
|
throw new Boom('No image processing library (sharp or @napi-rs/image) available for converting sticker to WebP. Either install sharp or @napi-rs/image or provide stickers in WebP format.');
|
|
387
389
|
}
|
|
388
390
|
if (webpBuffer.length > 1024 * 1024) {
|
|
389
|
-
|
|
391
|
+
throw new Boom(`Sticker at index ${i} exceeds the 1MB size limit`, { statusCode: 400 });
|
|
390
392
|
}
|
|
391
393
|
const hash = sha256(webpBuffer).toString('base64').replace(/\//g, '-');
|
|
392
394
|
const fileName = hash + '.webp';
|
|
@@ -526,13 +528,13 @@ const prepareStickerPackMessage = async (message, options) => {
|
|
|
526
528
|
}
|
|
527
529
|
return WAProto.Message.StickerPackMessage.fromObject(content);
|
|
528
530
|
};
|
|
529
|
-
//
|
|
531
|
+
// Lia@Changes 30-01-26 --- Add native flow button helper for interactive message
|
|
530
532
|
const prepareNativeFlowButtons = (message) => {
|
|
531
533
|
const buttons = message.nativeFlow
|
|
532
534
|
const isButtonsFieldArray = Array.isArray(buttons);
|
|
533
535
|
const correctedField = isButtonsFieldArray ? buttons : buttons.buttons;
|
|
534
536
|
const messageParamsJson = {};
|
|
535
|
-
//
|
|
537
|
+
// Lia@Changes 31-01-26 --- Add coupon and options inside interactive message
|
|
536
538
|
if (hasOptionalProperty(message, 'couponCode') && !!message.couponCode) {
|
|
537
539
|
Object.assign(messageParamsJson, {
|
|
538
540
|
limited_time_offer: {
|
|
@@ -596,7 +598,7 @@ const prepareNativeFlowButtons = (message) => {
|
|
|
596
598
|
})
|
|
597
599
|
};
|
|
598
600
|
}
|
|
599
|
-
//
|
|
601
|
+
// Lia@Changes 12-03-26 --- Add "single_select" shortcut \(°o°)/
|
|
600
602
|
else if (hasOptionalProperty(button, 'sections') && !!button.sections) {
|
|
601
603
|
return {
|
|
602
604
|
name: 'single_select',
|
|
@@ -655,40 +657,39 @@ export const generateForwardMessageContent = (message, forceForward) => {
|
|
|
655
657
|
return content;
|
|
656
658
|
};
|
|
657
659
|
export const hasNonNullishProperty = (message, key) => {
|
|
658
|
-
return
|
|
659
|
-
message
|
|
660
|
+
return message != null &&
|
|
661
|
+
typeof message === 'object' &&
|
|
660
662
|
key in message &&
|
|
661
|
-
message[key]
|
|
662
|
-
message[key] !== undefined);
|
|
663
|
+
message[key] != null;
|
|
663
664
|
};
|
|
664
665
|
export const hasOptionalProperty = (obj, key) => {
|
|
665
|
-
return
|
|
666
|
-
obj
|
|
666
|
+
return obj != null &&
|
|
667
|
+
typeof obj === 'object' &&
|
|
667
668
|
key in obj &&
|
|
668
|
-
obj[key]
|
|
669
|
+
obj[key] != null;
|
|
669
670
|
};
|
|
670
|
-
//
|
|
671
|
+
// Lia@Changes 06-02-26 --- Validate album message media to avoid bug 👀
|
|
671
672
|
export const hasValidAlbumMedia = (message) => {
|
|
672
|
-
return
|
|
673
|
-
message.videoMessage
|
|
673
|
+
return message.imageMessage ||
|
|
674
|
+
message.videoMessage;
|
|
674
675
|
};
|
|
675
676
|
export const hasValidInteractiveHeader = (message) => {
|
|
676
|
-
return
|
|
677
|
+
return message.imageMessage ||
|
|
677
678
|
message.videoMessage ||
|
|
678
679
|
message.documentMessage ||
|
|
679
680
|
message.productMessage ||
|
|
680
|
-
message.locationMessage
|
|
681
|
+
message.locationMessage;
|
|
681
682
|
};
|
|
682
|
-
//
|
|
683
|
+
// Lia@Changes 30-01-26 --- Validate carousel cards header to avoid bug 👀
|
|
683
684
|
export const hasValidCarouselHeader = (message) => {
|
|
684
|
-
return
|
|
685
|
+
return message.imageMessage ||
|
|
685
686
|
message.videoMessage ||
|
|
686
|
-
message.productMessage
|
|
687
|
+
message.productMessage;
|
|
687
688
|
};
|
|
688
689
|
export const generateWAMessageContent = async (message, options) => {
|
|
689
690
|
var _a, _b;
|
|
690
691
|
let m = {};
|
|
691
|
-
//
|
|
692
|
+
// Lia@Changes 30-01-26 --- Add "raw" boolean to send raw messages directly via generateWAMessage()
|
|
692
693
|
if (hasNonNullishProperty(message, 'raw')) {
|
|
693
694
|
delete message.raw;
|
|
694
695
|
return proto.Message.create(message);
|
|
@@ -725,7 +726,7 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
725
726
|
m.extendedTextMessage = extContent;
|
|
726
727
|
}
|
|
727
728
|
else if (hasNonNullishProperty(message, 'contacts')) {
|
|
728
|
-
const { contacts } = message; //
|
|
729
|
+
const { contacts } = message; // Lia@Changes 04-02-26 --- Destructured for readability & cleaner access (✷‿✷)
|
|
729
730
|
const contactLen = contacts.contacts.length;
|
|
730
731
|
if (!contactLen) {
|
|
731
732
|
throw new Boom('require atleast 1 contact', { statusCode: 400 });
|
|
@@ -741,7 +742,7 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
741
742
|
m.locationMessage = message.location;
|
|
742
743
|
}
|
|
743
744
|
else if (hasNonNullishProperty(message, 'react')) {
|
|
744
|
-
const { react } = message; //
|
|
745
|
+
const { react } = message; // Lia@Changes 04-02-26 --- Destructured for readability & cleaner access (✷‿✷)
|
|
745
746
|
if (!react.senderTimestampMs) {
|
|
746
747
|
react.senderTimestampMs = Date.now();
|
|
747
748
|
}
|
|
@@ -757,7 +758,7 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
757
758
|
m = generateForwardMessageContent(message.forward, message.force);
|
|
758
759
|
}
|
|
759
760
|
else if (hasNonNullishProperty(message, 'disappearingMessagesInChat')) {
|
|
760
|
-
const { disappearingMessagesInChat } = message; //
|
|
761
|
+
const { disappearingMessagesInChat } = message; // Lia@Changes 04-02-26 --- Destructured for readability & cleaner access (✷‿✷)
|
|
761
762
|
const exp = typeof disappearingMessagesInChat === 'boolean'
|
|
762
763
|
? disappearingMessagesInChat
|
|
763
764
|
? WA_DEFAULT_EPHEMERAL
|
|
@@ -766,7 +767,7 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
766
767
|
m = prepareDisappearingMessageSettingContent(exp);
|
|
767
768
|
}
|
|
768
769
|
else if (hasNonNullishProperty(message, 'groupInvite')) {
|
|
769
|
-
const { groupInvite } = message; //
|
|
770
|
+
const { groupInvite } = message; // Lia@Changes 04-02-26 --- Destructured for readability & cleaner access (✷‿✷)
|
|
770
771
|
m.groupInviteMessage = {};
|
|
771
772
|
m.groupInviteMessage.inviteCode = groupInvite.inviteCode;
|
|
772
773
|
m.groupInviteMessage.inviteExpiration = groupInvite.inviteExpiration;
|
|
@@ -804,7 +805,7 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
804
805
|
m.keepInChatMessage.timestampMs = Date.now();
|
|
805
806
|
}
|
|
806
807
|
else if (hasNonNullishProperty(message, 'flowReply')) {
|
|
807
|
-
const { flowReply } = message; //
|
|
808
|
+
const { flowReply } = message; // Lia@Changes 04-02-26 --- Destructured for readability & cleaner access (✷‿✷)
|
|
808
809
|
m.interactiveResponseMessage = {
|
|
809
810
|
body: {
|
|
810
811
|
format: flowReply.format || proto.Message.InteractiveResponseMessage.Body.Format.DEFAULT,
|
|
@@ -818,7 +819,7 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
818
819
|
};
|
|
819
820
|
}
|
|
820
821
|
else if (hasNonNullishProperty(message, 'buttonReply')) {
|
|
821
|
-
const { buttonReply } = message; //
|
|
822
|
+
const { buttonReply } = message; // Lia@Changes 04-02-26 --- Destructured for readability & cleaner access (✷‿✷)
|
|
822
823
|
switch (message.type) {
|
|
823
824
|
case 'template':
|
|
824
825
|
m.templateButtonReplyMessage = {
|
|
@@ -837,7 +838,7 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
837
838
|
}
|
|
838
839
|
}
|
|
839
840
|
else if (hasNonNullishProperty(message, 'listReply')) {
|
|
840
|
-
const { listReply } = message; //
|
|
841
|
+
const { listReply } = message; // Lia@Changes 04-02-26 --- Destructured for readability & cleaner access (✷‿✷)
|
|
841
842
|
m.listResponseMessage = {
|
|
842
843
|
description: listReply.description,
|
|
843
844
|
listType: proto.Message.ListResponseMessage.ListType.SINGLE_SELECT,
|
|
@@ -855,7 +856,7 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
855
856
|
m.productMessage = await prepareProductMessage(message, options);
|
|
856
857
|
}
|
|
857
858
|
else if (hasNonNullishProperty(message, 'event')) {
|
|
858
|
-
const { event } = message; //
|
|
859
|
+
const { event } = message; // Lia@Changes 04-02-26 --- Destructured for readability & cleaner access (✷‿✷)
|
|
859
860
|
m.eventMessage = {};
|
|
860
861
|
const startTime = Math.floor(event.startDate.getTime() / 1000);
|
|
861
862
|
if (event.call && options.getCallLink) {
|
|
@@ -876,7 +877,7 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
876
877
|
m.eventMessage.location = event.location;
|
|
877
878
|
}
|
|
878
879
|
else if (hasNonNullishProperty(message, 'poll')) {
|
|
879
|
-
const { poll } = message; //
|
|
880
|
+
const { poll } = message; // Lia@Changes 04-02-26 --- Destructured for readability & cleaner access (✷‿✷)
|
|
880
881
|
(_a = poll).selectableCount || (_a.selectableCount = 0);
|
|
881
882
|
(_b = poll).toAnnouncementGroup || (_b.toAnnouncementGroup = false);
|
|
882
883
|
if (!Array.isArray(poll.values)) {
|
|
@@ -901,7 +902,7 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
901
902
|
m.pollCreationMessageV2 = pollCreationMessage;
|
|
902
903
|
}
|
|
903
904
|
else {
|
|
904
|
-
//
|
|
905
|
+
// Lia@Changes 08-02-26 --- Add quiz message support
|
|
905
906
|
if (poll.pollType === 1) {
|
|
906
907
|
if (!poll.correctAnswer) {
|
|
907
908
|
throw new Boom('No "correctAnswer" provided for quiz', { statusCode: 400 });
|
|
@@ -926,7 +927,7 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
926
927
|
}
|
|
927
928
|
}
|
|
928
929
|
}
|
|
929
|
-
//
|
|
930
|
+
// Lia@Changes 08-02-26 --- Add poll result snapshot message
|
|
930
931
|
else if (hasNonNullishProperty(message, 'pollResult')) {
|
|
931
932
|
const { pollResult } = message;
|
|
932
933
|
const pollResultSnapshotMessage = {
|
|
@@ -945,7 +946,7 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
945
946
|
m.pollResultSnapshotMessage = pollResultSnapshotMessage;
|
|
946
947
|
}
|
|
947
948
|
}
|
|
948
|
-
//
|
|
949
|
+
// Lia@Changes 08-02-26 --- Add poll update message
|
|
949
950
|
else if (hasNonNullishProperty(message, 'pollUpdate')) {
|
|
950
951
|
const { pollUpdate } = message;
|
|
951
952
|
if (!pollUpdate.key) {
|
|
@@ -980,14 +981,14 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
980
981
|
}
|
|
981
982
|
};
|
|
982
983
|
}
|
|
983
|
-
//
|
|
984
|
+
// Lia@Changes 01-02-26 --- Add payment invite message
|
|
984
985
|
else if (hasNonNullishProperty(message, 'paymentInviteServiceType')) {
|
|
985
986
|
m.paymentInviteMessage = {
|
|
986
987
|
expiryTimestamp: Date.now(),
|
|
987
988
|
serviceType: message.paymentInviteServiceType
|
|
988
989
|
};
|
|
989
990
|
}
|
|
990
|
-
//
|
|
991
|
+
// Lia@Changes 01-02-26 --- Add order message
|
|
991
992
|
else if (hasNonNullishProperty(message, 'orderText')) {
|
|
992
993
|
if (!Buffer.isBuffer(message.thumbnail)) {
|
|
993
994
|
throw new Boom('Must provide thumbnail buffer in order message', { statusCode: 400 });
|
|
@@ -1006,7 +1007,7 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
1006
1007
|
};
|
|
1007
1008
|
delete m.orderMessage.orderText;
|
|
1008
1009
|
}
|
|
1009
|
-
//
|
|
1010
|
+
// Lia@Changes 31-01-26 --- Add support for album messages
|
|
1010
1011
|
else if (hasNonNullishProperty(message, 'album')) {
|
|
1011
1012
|
const { album } = message;
|
|
1012
1013
|
if (!Array.isArray(album)) {
|
|
@@ -1031,20 +1032,20 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
1031
1032
|
else {
|
|
1032
1033
|
m = await prepareWAMessageMedia(message, options);
|
|
1033
1034
|
}
|
|
1034
|
-
//
|
|
1035
|
+
// Lia@Changes 30-01-26 --- Add interactive messages (buttonsMessage, listMessage, interactiveMessage, templateMessage, and carouselMessage)
|
|
1035
1036
|
if (hasNonNullishProperty(message, 'buttons')) {
|
|
1036
1037
|
const buttonsMessage = {
|
|
1037
1038
|
buttons: message.buttons.map(button => {
|
|
1038
|
-
//
|
|
1039
|
+
// Lia@Changes 12-03-26 --- Add "single_select" shortcut!
|
|
1039
1040
|
const buttonText = button.text || button.buttonText
|
|
1040
1041
|
if (hasOptionalProperty(button, 'sections')) {
|
|
1041
1042
|
return {
|
|
1042
1043
|
nativeFlowInfo: {
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1044
|
+
name: 'single_select',
|
|
1045
|
+
paramsJson: JSON.stringify({
|
|
1046
|
+
title: buttonText,
|
|
1047
|
+
sections: button.sections
|
|
1048
|
+
})
|
|
1048
1049
|
},
|
|
1049
1050
|
type: ButtonType.NATIVE_FLOW
|
|
1050
1051
|
};
|
|
@@ -1052,8 +1053,8 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
1052
1053
|
else if (hasOptionalProperty(button, 'name')) {
|
|
1053
1054
|
return {
|
|
1054
1055
|
nativeFlowInfo: {
|
|
1055
|
-
|
|
1056
|
-
|
|
1056
|
+
name: button.name,
|
|
1057
|
+
paramsJson: button.paramsJson
|
|
1057
1058
|
},
|
|
1058
1059
|
type: ButtonType.NATIVE_FLOW
|
|
1059
1060
|
};
|
|
@@ -1174,7 +1175,7 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
1174
1175
|
if (hasOptionalProperty(message, 'caption')) {
|
|
1175
1176
|
const isValidHeader = hasValidInteractiveHeader(m)
|
|
1176
1177
|
if (!isValidHeader) {
|
|
1177
|
-
|
|
1178
|
+
throw new Boom('Invalid media type for interactive message header', { statusCode: 400 });
|
|
1178
1179
|
}
|
|
1179
1180
|
interactiveMessage.header = {
|
|
1180
1181
|
title: message.title || '',
|
|
@@ -1211,11 +1212,11 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
1211
1212
|
carouselHeader.productMessage = await prepareProductMessage(card, options);
|
|
1212
1213
|
}
|
|
1213
1214
|
else {
|
|
1214
|
-
carouselHeader = await prepareWAMessageMedia(card, options).catch(() => ({}));
|
|
1215
|
+
carouselHeader = await prepareWAMessageMedia(card, options).catch(() => ({ }));
|
|
1215
1216
|
}
|
|
1216
1217
|
const isValidHeader = hasValidCarouselHeader(carouselHeader)
|
|
1217
1218
|
if (!isValidHeader) {
|
|
1218
|
-
|
|
1219
|
+
throw new Boom('Invalid media type for carousel card', { statusCode: 400 });
|
|
1219
1220
|
}
|
|
1220
1221
|
const carouselCard = {
|
|
1221
1222
|
nativeFlowMessage: prepareNativeFlowButtons(card.nativeFlow ? card : [])
|
|
@@ -1263,13 +1264,13 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
1263
1264
|
}
|
|
1264
1265
|
m = { interactiveMessage };
|
|
1265
1266
|
}
|
|
1266
|
-
//
|
|
1267
|
+
// Lia@Changes 01-02-26 --- Add request payment message
|
|
1267
1268
|
else if (hasNonNullishProperty(message, 'requestPaymentFrom')) {
|
|
1268
1269
|
const requestPaymentMessage = {
|
|
1269
1270
|
amount: {
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1271
|
+
currencyCode: 'IDR',
|
|
1272
|
+
offset: 1000,
|
|
1273
|
+
value: 1000
|
|
1273
1274
|
},
|
|
1274
1275
|
amount1000: 1000,
|
|
1275
1276
|
currencyCodeIso4217: 'IDR',
|
|
@@ -1287,7 +1288,7 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
1287
1288
|
}
|
|
1288
1289
|
m = { requestPaymentMessage };
|
|
1289
1290
|
}
|
|
1290
|
-
//
|
|
1291
|
+
// Lia@Changes 01-02-26 --- Add invoice message
|
|
1291
1292
|
else if (hasNonNullishProperty(message, 'invoiceNote')) {
|
|
1292
1293
|
const attachment = m.imageMessage || m.documentMessage;
|
|
1293
1294
|
const type = Object.keys(m)[0].replace('Message', '').toUpperCase();
|
|
@@ -1313,7 +1314,7 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
1313
1314
|
}
|
|
1314
1315
|
m = { invoiceMessage };
|
|
1315
1316
|
}
|
|
1316
|
-
//
|
|
1317
|
+
// Lia@Changes 31-01-26 --- Add direct externalAdReply access (no need to create contextInfo first)
|
|
1317
1318
|
if (hasOptionalProperty(message, 'externalAdReply') && !!message.externalAdReply) {
|
|
1318
1319
|
const messageType = Object.keys(m)[0];
|
|
1319
1320
|
const key = m[messageType];
|
|
@@ -1344,10 +1345,8 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
1344
1345
|
key.contextInfo = { externalAdReply };
|
|
1345
1346
|
}
|
|
1346
1347
|
}
|
|
1347
|
-
if (
|
|
1348
|
-
(hasOptionalProperty(message, '
|
|
1349
|
-
(hasOptionalProperty(message, 'mentionAll') && message.mentionAll)
|
|
1350
|
-
) {
|
|
1348
|
+
if ((hasOptionalProperty(message, 'mentions') && message.mentions?.length) ||
|
|
1349
|
+
(hasOptionalProperty(message, 'mentionAll') && message.mentionAll)) {
|
|
1351
1350
|
const messageType = Object.keys(m)[0];
|
|
1352
1351
|
const key = m[messageType];
|
|
1353
1352
|
if ('contextInfo' in key && !!key.contextInfo) {
|
|
@@ -1373,7 +1372,7 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
1373
1372
|
key.contextInfo = message.contextInfo;
|
|
1374
1373
|
}
|
|
1375
1374
|
}
|
|
1376
|
-
//
|
|
1375
|
+
// Lia@Changes 31-01-26 --- Add "groupStatus" boolean to set contextInfo.isGroupStatus and wrap message into groupStatusMessageV2
|
|
1377
1376
|
if (hasOptionalProperty(message, 'groupStatus') && !!message.groupStatus) {
|
|
1378
1377
|
const messageType = Object.keys(m)[0];
|
|
1379
1378
|
const key = m[messageType];
|
|
@@ -1388,7 +1387,7 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
1388
1387
|
m = { groupStatusMessageV2: { message: m } };
|
|
1389
1388
|
delete message.groupStatus;
|
|
1390
1389
|
}
|
|
1391
|
-
//
|
|
1390
|
+
// Lia@Changes 02-02-26 --- Add "interactiveAsTemplate" boolean to wrap interactiveMessage into templateMessage
|
|
1392
1391
|
else if (hasOptionalProperty(message, 'interactiveAsTemplate') && !!message.interactiveAsTemplate) {
|
|
1393
1392
|
if (!m.interactiveMessage) {
|
|
1394
1393
|
throw new Boom('Invalid message type for template', { statusCode: 400 }); // Lia@Note 02-02-26 --- To avoid bug 👀
|
|
@@ -1401,7 +1400,7 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
1401
1400
|
};
|
|
1402
1401
|
delete message.interactiveAsTemplate;
|
|
1403
1402
|
}
|
|
1404
|
-
//
|
|
1403
|
+
// Lia@Changes 30-01-26 --- Add "ephemeral" boolean to wrap message into ephemeralMessage like "viewOnce"
|
|
1405
1404
|
if (hasOptionalProperty(message, 'ephemeral') && !!message.ephemeral) {
|
|
1406
1405
|
m = { ephemeralMessage: { message: m } };
|
|
1407
1406
|
delete message.ephemeral;
|
|
@@ -1409,12 +1408,12 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
1409
1408
|
else if (hasOptionalProperty(message, 'viewOnce') && !!message.viewOnce) {
|
|
1410
1409
|
m = { viewOnceMessage: { message: m } };
|
|
1411
1410
|
}
|
|
1412
|
-
//
|
|
1411
|
+
// Lia@Changes 03-02-26 --- Add "viewOnceV2" boolean to wrap message into viewOnceMessageV2 like "viewOnce"
|
|
1413
1412
|
else if (hasOptionalProperty(message, 'viewOnceV2') && !!message.viewOnceV2) {
|
|
1414
1413
|
m = { viewOnceMessageV2: { message: m } };
|
|
1415
1414
|
delete message.viewOnceV2;
|
|
1416
1415
|
}
|
|
1417
|
-
//
|
|
1416
|
+
// Lia@Changes 03-02-26 --- Add "viewOnceV2Extension" boolean to wrap message into viewOnceMessageV2Extension like "viewOnce"
|
|
1418
1417
|
else if (hasOptionalProperty(message, 'viewOnceV2Extension') && !!message.viewOnceV2Extension) {
|
|
1419
1418
|
m = { viewOnceMessageV2Extension: { message: m } };
|
|
1420
1419
|
delete message.viewOnceV2Extension;
|
|
@@ -1476,8 +1475,8 @@ export const generateWAMessageFromContent = (jid, message, options) => {
|
|
|
1476
1475
|
}
|
|
1477
1476
|
}
|
|
1478
1477
|
if (
|
|
1479
|
-
|
|
1480
|
-
|
|
1478
|
+
// if we want to send a disappearing message
|
|
1479
|
+
!!options?.ephemeralExpiration &&
|
|
1481
1480
|
// and it's not a protocol message -- delete, toggle disappear message
|
|
1482
1481
|
key !== 'protocolMessage' &&
|
|
1483
1482
|
// already not converted to disappearing message
|
|
@@ -1491,8 +1490,8 @@ export const generateWAMessageFromContent = (jid, message, options) => {
|
|
|
1491
1490
|
//ephemeralSettingTimestamp: options.ephemeralOptions.eph_setting_ts?.toString()
|
|
1492
1491
|
};
|
|
1493
1492
|
}
|
|
1494
|
-
//
|
|
1495
|
-
|
|
1493
|
+
// Lia@Changes 30-01-26 --- Add deviceListMetadata inside messageContextInfo for private chat
|
|
1494
|
+
if (messageContextInfo?.messageSecret && (isPnUser(jid) || isLidUser(jid))) {
|
|
1496
1495
|
messageContextInfo.deviceListMetadata = {
|
|
1497
1496
|
recipientKeyHash: randomBytes(10),
|
|
1498
1497
|
recipientTimestamp: unixTimestampSeconds()
|
|
@@ -1550,7 +1549,7 @@ export const normalizeMessageContent = (content) => {
|
|
|
1550
1549
|
content = inner.message;
|
|
1551
1550
|
}
|
|
1552
1551
|
return content;
|
|
1553
|
-
//
|
|
1552
|
+
// Lia@Changes 03-02-26 --- Add all futureProofMessage into getFutureProofMessage()
|
|
1554
1553
|
function getFutureProofMessage(message) {
|
|
1555
1554
|
return (
|
|
1556
1555
|
message?.associatedChildMessage ||
|
|
@@ -1868,18 +1867,20 @@ const isWebPBuffer = (buffer) => {
|
|
|
1868
1867
|
);
|
|
1869
1868
|
};
|
|
1870
1869
|
/**
|
|
1871
|
-
*
|
|
1870
|
+
* Lia@Changes 30-01-26
|
|
1872
1871
|
* ---
|
|
1873
1872
|
* Determines whether a message should include a Biz Binary Node.
|
|
1874
1873
|
* A Biz Binary Node is added only for interactive messages
|
|
1875
1874
|
* such as buttons or other supported interactive types.
|
|
1876
1875
|
*/
|
|
1877
1876
|
export const shouldIncludeBizBinaryNode = (message) => {
|
|
1878
|
-
const
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1877
|
+
const hasValidInteractive =
|
|
1878
|
+
message.interactiveMessage &&
|
|
1879
|
+
!message.interactiveMessage.carouselMessage &&
|
|
1880
|
+
!message.interactiveMessage.collectionMessage &&
|
|
1881
|
+
!message.interactiveMessage.shopStorefrontMessage;
|
|
1882
|
+
return (message.buttonsMessage ||
|
|
1883
|
+
message.interactiveMessage ||
|
|
1884
|
+
message.listMessage ||
|
|
1885
|
+
hasValidInteractive);
|
|
1885
1886
|
};
|
|
@@ -195,12 +195,6 @@ export const makeNoiseHandler = ({ keyPair: { private: privateKey, public: publi
|
|
|
195
195
|
inBytes = Buffer.concat([inBytes, newData]);
|
|
196
196
|
}
|
|
197
197
|
await processData(onFrame);
|
|
198
|
-
},
|
|
199
|
-
/** Clean up internal buffers to prevent memory leaks on connection close */
|
|
200
|
-
destroy() {
|
|
201
|
-
inBytes = Buffer.alloc(0);
|
|
202
|
-
transport = null;
|
|
203
|
-
pendingOnFrame = null;
|
|
204
198
|
}
|
|
205
199
|
};
|
|
206
200
|
};
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { readFile, rename, stat, writeFile } from 'fs/promises';
|
|
2
|
+
import { DEFAULT_CACHE_TTLS } from '../Defaults/index.js';
|
|
3
|
+
import { proto } from '../../WAProto/index.js';
|
|
4
|
+
import { initAuthCreds } from './auth-utils.js';
|
|
5
|
+
import { BufferJSON } from './generics.js';
|
|
6
|
+
// Lia@Changes 25-03-26 --- Add useSingleFileAuthState with integrated cache
|
|
7
|
+
const FLUSH_TIMEOUT_MS = 3000;
|
|
8
|
+
export const useSingleFileAuthState = async (fileName) => {
|
|
9
|
+
const cache = new Map();
|
|
10
|
+
let isLoaded,
|
|
11
|
+
isWriting,
|
|
12
|
+
isNeedWrite,
|
|
13
|
+
flushTimeout,
|
|
14
|
+
loadPromise;
|
|
15
|
+
const loadKey = () => {
|
|
16
|
+
if (isLoaded) return;
|
|
17
|
+
if (loadPromise) return loadPromise;
|
|
18
|
+
loadPromise = (async () => {
|
|
19
|
+
try {
|
|
20
|
+
const data = JSON.parse(await readFile(fileName, 'utf-8'), BufferJSON.reviver);
|
|
21
|
+
for (const [keyName, value] of Object.entries(data)) {
|
|
22
|
+
cache.set(keyName, value);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
catch { }
|
|
26
|
+
isLoaded = true;
|
|
27
|
+
loadPromise = null;
|
|
28
|
+
})();
|
|
29
|
+
return loadPromise;
|
|
30
|
+
};
|
|
31
|
+
const flushKey = () => {
|
|
32
|
+
if (flushTimeout) return;
|
|
33
|
+
flushTimeout = setTimeout(async () => {
|
|
34
|
+
flushTimeout = null;
|
|
35
|
+
if (isWriting) {
|
|
36
|
+
isNeedWrite = true;
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
isWriting = true;
|
|
40
|
+
do {
|
|
41
|
+
isNeedWrite = false;
|
|
42
|
+
const tempFile = fileName + '.temp';
|
|
43
|
+
const value = Object.fromEntries(cache);
|
|
44
|
+
await writeFile(tempFile, JSON.stringify(value, BufferJSON.replacer));
|
|
45
|
+
await rename(tempFile, fileName);
|
|
46
|
+
}
|
|
47
|
+
while (isNeedWrite);
|
|
48
|
+
isWriting = false;
|
|
49
|
+
}, FLUSH_TIMEOUT_MS);
|
|
50
|
+
};
|
|
51
|
+
const writeKey = (keyName, value) => {
|
|
52
|
+
cache.set(keyName, value);
|
|
53
|
+
flushKey();
|
|
54
|
+
};
|
|
55
|
+
const removeKey = (keyName) => {
|
|
56
|
+
cache.delete(keyName);
|
|
57
|
+
flushKey();
|
|
58
|
+
};
|
|
59
|
+
const fileInfo = await stat(fileName).catch(() => null);
|
|
60
|
+
if (!fileInfo) {
|
|
61
|
+
await writeFile(fileName, '{}');
|
|
62
|
+
}
|
|
63
|
+
else if (!fileInfo.isFile()) {
|
|
64
|
+
throw new Error(`found something that is not a file at ${fileName}, either delete it or specify a different location`);
|
|
65
|
+
}
|
|
66
|
+
await loadKey();
|
|
67
|
+
const creds = cache.get('creds') || initAuthCreds();
|
|
68
|
+
return {
|
|
69
|
+
state: {
|
|
70
|
+
creds,
|
|
71
|
+
keys: {
|
|
72
|
+
get: (type, ids) => {
|
|
73
|
+
const data = {};
|
|
74
|
+
for (const id of ids) {
|
|
75
|
+
let value = cache.get(type + id);
|
|
76
|
+
if (type === 'app-state-sync-key' && value) {
|
|
77
|
+
value = proto.Message.AppStateSyncKeyData.fromObject(value);
|
|
78
|
+
}
|
|
79
|
+
data[id] = value;
|
|
80
|
+
}
|
|
81
|
+
return data;
|
|
82
|
+
},
|
|
83
|
+
set: (data) => {
|
|
84
|
+
for (const category in data) {
|
|
85
|
+
for (const id in data[category]) {
|
|
86
|
+
const keyName = category + id;
|
|
87
|
+
const value = data[category][id];
|
|
88
|
+
value ? writeKey(keyName, value) : removeKey(keyName);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
saveCreds: () => writeKey('creds', creds)
|
|
95
|
+
};
|
|
96
|
+
};
|