@vanzxy/baileys 1.4.2 → 1.4.4
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/cjs/lib/Socket/index.js +11 -0
- package/cjs/lib/Utils/MessageBuilder.js +472 -23
- package/cjs/lib/Utils/chat-utils.js +4 -1
- package/cjs/lib/Utils/crypto.js +7 -1
- package/cjs/lib/Utils/lt-hash.js +3 -1
- package/cjs/lib/Utils/messages.js +5 -0
- package/lib/Socket/index.js +17 -0
- package/lib/Utils/MessageBuilder.d.ts +202 -0
- package/lib/Utils/MessageBuilder.js +909 -25
- package/lib/Utils/messages.js +7 -0
- package/package.json +1 -1
|
@@ -58,10 +58,10 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
58
58
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
59
59
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
60
60
|
};
|
|
61
|
-
var _a, _Button_client, _Button_validateAgainstSchema, _ButtonV2_client, _Carousel_client, _AIRich_client;
|
|
61
|
+
var _a, _Button_client, _Button_validateAgainstSchema, _ButtonV2_client, _Carousel_client, _Poll_client, _AIRich_client;
|
|
62
62
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
63
|
-
exports.Toolkit = exports.AIRich = exports.Carousel = exports.ButtonV2 = exports.Button = exports.MESSAGE_BUILDER_VERSION = void 0;
|
|
64
|
-
const MESSAGE_BUILDER_VERSION = '4.
|
|
63
|
+
exports.Toolkit = exports.VanzxyRich = exports.VanzxyAI = exports.LeafRich = exports.AIVanzxy = exports.AIRich = exports.Poll = exports.Carousel = exports.ButtonV2 = exports.Button = exports.MESSAGE_BUILDER_VERSION = void 0;
|
|
64
|
+
const MESSAGE_BUILDER_VERSION = '4.7';
|
|
65
65
|
exports.MESSAGE_BUILDER_VERSION = MESSAGE_BUILDER_VERSION;
|
|
66
66
|
const messages_js_1 = require("./messages.js");
|
|
67
67
|
const rich_message_utils_js_1 = require("./rich-message-utils.js");
|
|
@@ -318,7 +318,6 @@ class Toolkit {
|
|
|
318
318
|
height,
|
|
319
319
|
})));
|
|
320
320
|
}
|
|
321
|
-
const originalIsBuffer = Buffer.isBuffer(media);
|
|
322
321
|
if (typeof media === 'string' && isUrl(media)) {
|
|
323
322
|
if (isWAUrl(media)) {
|
|
324
323
|
if (resolveWAUrl) {
|
|
@@ -356,9 +355,7 @@ class Toolkit {
|
|
|
356
355
|
if (result === 'base64') {
|
|
357
356
|
return media.toString('base64');
|
|
358
357
|
}
|
|
359
|
-
|
|
360
|
-
return Toolkit.toUrl(_client, media, mediaType);
|
|
361
|
-
}
|
|
358
|
+
// Vanz@Fix 22-08-26 (v4.7): dead-branch cleanup, see ESM file for note.
|
|
362
359
|
return Toolkit.toUrl(_client, media, mediaType);
|
|
363
360
|
}
|
|
364
361
|
static getMp4Duration(buffer, { silent = true } = {}) {
|
|
@@ -577,6 +574,9 @@ class Button extends BaseBuilder {
|
|
|
577
574
|
return this;
|
|
578
575
|
}
|
|
579
576
|
addButton(name, params) {
|
|
577
|
+
if (typeof name !== 'string' || !name.trim()) {
|
|
578
|
+
throw new TypeError('addButton(name, params) requires a non-empty string name');
|
|
579
|
+
}
|
|
580
580
|
this._buttons.push({
|
|
581
581
|
name,
|
|
582
582
|
buttonParamsJson: typeof params === 'string' ? params : JSON.stringify(params),
|
|
@@ -587,6 +587,9 @@ class Button extends BaseBuilder {
|
|
|
587
587
|
if (this._currentSelectionIndex === -1 || this._currentSectionIndex === -1) {
|
|
588
588
|
throw new Error('You need to create a selection and a section first');
|
|
589
589
|
}
|
|
590
|
+
if (!title || !id) {
|
|
591
|
+
throw new TypeError('makeRow() requires both a title and an id');
|
|
592
|
+
}
|
|
590
593
|
const buttonParams = JSON.parse(this._buttons[this._currentSelectionIndex].buttonParamsJson);
|
|
591
594
|
buttonParams.sections[this._currentSectionIndex].rows.push({ header, title, description, id });
|
|
592
595
|
this._buttons[this._currentSelectionIndex].buttonParamsJson = JSON.stringify(buttonParams);
|
|
@@ -603,12 +606,16 @@ class Button extends BaseBuilder {
|
|
|
603
606
|
return this;
|
|
604
607
|
}
|
|
605
608
|
addSelection(title, options = {}) {
|
|
609
|
+
if (!title) throw new TypeError('addSelection(title) requires a non-empty title');
|
|
606
610
|
this._buttons.push({ ...options, name: 'single_select', buttonParamsJson: JSON.stringify({ title, sections: [] }) });
|
|
607
611
|
this._currentSelectionIndex = this._buttons.length - 1;
|
|
608
612
|
this._currentSectionIndex = -1;
|
|
609
613
|
return this;
|
|
610
614
|
}
|
|
611
615
|
addReply(display_text = '', id = '', options = {}) {
|
|
616
|
+
if (!display_text || !id) {
|
|
617
|
+
throw new TypeError('addReply(display_text, id) requires both a label and a unique id');
|
|
618
|
+
}
|
|
612
619
|
this._buttons.push({
|
|
613
620
|
name: 'quick_reply',
|
|
614
621
|
buttonParamsJson: JSON.stringify({
|
|
@@ -619,18 +626,26 @@ class Button extends BaseBuilder {
|
|
|
619
626
|
});
|
|
620
627
|
return this;
|
|
621
628
|
}
|
|
622
|
-
|
|
629
|
+
// Vanz@Fix 22-08-26 (v4.7) --- 2nd arg now writes buttonParamsJson.phone_number instead of
|
|
630
|
+
// .id; see the ESM file's inline note for why (cta_call ignores `id`, WA keys on phone_number).
|
|
631
|
+
addCall(display_text = '', phone_number = '', options = {}) {
|
|
632
|
+
if (!display_text || !phone_number) {
|
|
633
|
+
throw new TypeError('addCall(display_text, phone_number) requires both a label and a phone number');
|
|
634
|
+
}
|
|
623
635
|
this._buttons.push({
|
|
624
636
|
name: 'cta_call',
|
|
625
637
|
buttonParamsJson: JSON.stringify({
|
|
626
638
|
display_text,
|
|
627
|
-
|
|
639
|
+
phone_number,
|
|
628
640
|
...options,
|
|
629
641
|
}),
|
|
630
642
|
});
|
|
631
643
|
return this;
|
|
632
644
|
}
|
|
633
645
|
addReminder(display_text = '', id = '', options = {}) {
|
|
646
|
+
if (!display_text || !id) {
|
|
647
|
+
throw new TypeError('addReminder(display_text, id) requires both a label and a unique id');
|
|
648
|
+
}
|
|
634
649
|
this._buttons.push({
|
|
635
650
|
name: 'cta_reminder',
|
|
636
651
|
buttonParamsJson: JSON.stringify({
|
|
@@ -642,6 +657,9 @@ class Button extends BaseBuilder {
|
|
|
642
657
|
return this;
|
|
643
658
|
}
|
|
644
659
|
addCancelReminder(display_text = '', id = '', options = {}) {
|
|
660
|
+
if (!display_text || !id) {
|
|
661
|
+
throw new TypeError('addCancelReminder(display_text, id) requires both a label and a unique id');
|
|
662
|
+
}
|
|
645
663
|
this._buttons.push({
|
|
646
664
|
name: 'cta_cancel_reminder',
|
|
647
665
|
buttonParamsJson: JSON.stringify({
|
|
@@ -653,6 +671,9 @@ class Button extends BaseBuilder {
|
|
|
653
671
|
return this;
|
|
654
672
|
}
|
|
655
673
|
addAddress(display_text = '', id = '', options = {}) {
|
|
674
|
+
if (!display_text || !id) {
|
|
675
|
+
throw new TypeError('addAddress(display_text, id) requires both a label and a unique id');
|
|
676
|
+
}
|
|
656
677
|
this._buttons.push({
|
|
657
678
|
name: 'address_message',
|
|
658
679
|
buttonParamsJson: JSON.stringify({
|
|
@@ -670,13 +691,18 @@ class Button extends BaseBuilder {
|
|
|
670
691
|
});
|
|
671
692
|
return this;
|
|
672
693
|
}
|
|
694
|
+
// Vanz@Add 22-08-26 (v4.7): merchant_url defaulted to url, see ESM file for note.
|
|
673
695
|
addUrl(display_text = '', url = '', webview_interaction = false, options = {}) {
|
|
696
|
+
if (!display_text || !url) {
|
|
697
|
+
throw new TypeError('addUrl(display_text, url) requires both a label and a url');
|
|
698
|
+
}
|
|
674
699
|
this._buttons.push({
|
|
675
700
|
...options,
|
|
676
701
|
name: 'cta_url',
|
|
677
702
|
buttonParamsJson: JSON.stringify({
|
|
678
703
|
display_text,
|
|
679
704
|
url,
|
|
705
|
+
merchant_url: url,
|
|
680
706
|
webview_interaction,
|
|
681
707
|
...options,
|
|
682
708
|
}),
|
|
@@ -684,6 +710,9 @@ class Button extends BaseBuilder {
|
|
|
684
710
|
return this;
|
|
685
711
|
}
|
|
686
712
|
addCopy(display_text = '', copy_code = '', options = {}) {
|
|
713
|
+
if (!display_text || !copy_code) {
|
|
714
|
+
throw new TypeError('addCopy(display_text, copy_code) requires both a label and the text to copy');
|
|
715
|
+
}
|
|
687
716
|
this._buttons.push({
|
|
688
717
|
name: 'cta_copy',
|
|
689
718
|
buttonParamsJson: JSON.stringify({
|
|
@@ -694,6 +723,66 @@ class Button extends BaseBuilder {
|
|
|
694
723
|
});
|
|
695
724
|
return this;
|
|
696
725
|
}
|
|
726
|
+
// Vanz@Add 22-08-26 (v4.7) --- new native-flow helpers, see ESM file for full JSDoc + caveats.
|
|
727
|
+
addOpenWebview(title = '', url = '', options = {}) {
|
|
728
|
+
if (!title || !url) {
|
|
729
|
+
throw new TypeError('addOpenWebview(title, url) requires both a title and a url');
|
|
730
|
+
}
|
|
731
|
+
this._buttons.push({
|
|
732
|
+
name: 'open_webview',
|
|
733
|
+
buttonParamsJson: JSON.stringify({ title, link: { url }, ...options }),
|
|
734
|
+
});
|
|
735
|
+
return this;
|
|
736
|
+
}
|
|
737
|
+
addCatalog(display_text = '', options = {}) {
|
|
738
|
+
this._buttons.push({
|
|
739
|
+
name: 'cta_catalog',
|
|
740
|
+
buttonParamsJson: JSON.stringify({ ...(display_text ? { display_text } : {}), ...options }),
|
|
741
|
+
});
|
|
742
|
+
return this;
|
|
743
|
+
}
|
|
744
|
+
addViewCatalog(options = {}) {
|
|
745
|
+
this._buttons.push({
|
|
746
|
+
name: 'automated_greeting_message_view_catalog',
|
|
747
|
+
buttonParamsJson: JSON.stringify(options),
|
|
748
|
+
});
|
|
749
|
+
return this;
|
|
750
|
+
}
|
|
751
|
+
addCallPermission(display_text = '', options = {}) {
|
|
752
|
+
this._buttons.push({
|
|
753
|
+
name: 'call_permission_request',
|
|
754
|
+
buttonParamsJson: JSON.stringify({ ...(display_text ? { display_text } : {}), ...options }),
|
|
755
|
+
});
|
|
756
|
+
return this;
|
|
757
|
+
}
|
|
758
|
+
addPaymentInfo(payload = {}) {
|
|
759
|
+
if (typeof payload !== 'object' || payload === null || Array.isArray(payload)) {
|
|
760
|
+
throw new TypeError('addPaymentInfo(payload) requires a plain object');
|
|
761
|
+
}
|
|
762
|
+
this._buttons.push({ name: 'payment_info', buttonParamsJson: JSON.stringify(payload) });
|
|
763
|
+
return this;
|
|
764
|
+
}
|
|
765
|
+
addReviewAndPay(payload = {}) {
|
|
766
|
+
if (typeof payload !== 'object' || payload === null || Array.isArray(payload)) {
|
|
767
|
+
throw new TypeError('addReviewAndPay(payload) requires a plain object');
|
|
768
|
+
}
|
|
769
|
+
this._buttons.push({ name: 'review_and_pay', buttonParamsJson: JSON.stringify(payload) });
|
|
770
|
+
return this;
|
|
771
|
+
}
|
|
772
|
+
addTransactionDetails(payload = {}) {
|
|
773
|
+
if (typeof payload !== 'object' || payload === null || Array.isArray(payload)) {
|
|
774
|
+
throw new TypeError('addTransactionDetails(payload) requires a plain object');
|
|
775
|
+
}
|
|
776
|
+
this._buttons.push({ name: 'wa_payment_transaction_details', buttonParamsJson: JSON.stringify(payload) });
|
|
777
|
+
return this;
|
|
778
|
+
}
|
|
779
|
+
addMultiProduct(payload = {}) {
|
|
780
|
+
if (typeof payload !== 'object' || payload === null || Array.isArray(payload)) {
|
|
781
|
+
throw new TypeError('addMultiProduct(payload) requires a plain object');
|
|
782
|
+
}
|
|
783
|
+
this._buttons.push({ name: 'mpm', buttonParamsJson: JSON.stringify(payload) });
|
|
784
|
+
return this;
|
|
785
|
+
}
|
|
697
786
|
setLimitedTimeOffer({ text = '', url = '', copy_code = '', expiration_time } = {}) {
|
|
698
787
|
const data = { text, url, copy_code, expiration_time };
|
|
699
788
|
__classPrivateFieldGet(_a, _a, "m", _Button_validateAgainstSchema).call(_a, _a.paramsList.limited_time_offer, data, 'limited_time_offer');
|
|
@@ -738,7 +827,39 @@ class Button extends BaseBuilder {
|
|
|
738
827
|
},
|
|
739
828
|
};
|
|
740
829
|
}
|
|
830
|
+
// Vanz@Fix (bug: single_select alone doesn't render) --- lihat catatan yang sama
|
|
831
|
+
// di versi ESM (lib/Utils/MessageBuilder.js) untuk penjelasan lengkap.
|
|
832
|
+
_isLoneSingleSelect() {
|
|
833
|
+
return this._buttons.length === 1 && this._buttons[0].name === 'single_select';
|
|
834
|
+
}
|
|
835
|
+
_toListMessage() {
|
|
836
|
+
const { title: buttonText, sections } = JSON.parse(this._buttons[0].buttonParamsJson);
|
|
837
|
+
return {
|
|
838
|
+
listMessage: {
|
|
839
|
+
title: this._title || undefined,
|
|
840
|
+
description: this._body || undefined,
|
|
841
|
+
footerText: this._footer || undefined,
|
|
842
|
+
buttonText: buttonText || undefined,
|
|
843
|
+
listType: 1,
|
|
844
|
+
sections: (sections || []).map((s) => ({
|
|
845
|
+
title: s.title,
|
|
846
|
+
rows: (s.rows || []).map((r) => ({
|
|
847
|
+
title: r.title || r.header || '',
|
|
848
|
+
description: r.description || '',
|
|
849
|
+
rowId: r.id || '',
|
|
850
|
+
})),
|
|
851
|
+
})),
|
|
852
|
+
contextInfo: this._contextInfo,
|
|
853
|
+
},
|
|
854
|
+
};
|
|
855
|
+
}
|
|
741
856
|
async build(jid, { ...options } = {}) {
|
|
857
|
+
if (this._buttons.length === 0) {
|
|
858
|
+
throw new Error('Button requires at least one button (use addReply/addUrl/addCall/addSelection/addButton/...)');
|
|
859
|
+
}
|
|
860
|
+
if (this._isLoneSingleSelect()) {
|
|
861
|
+
return (0, messages_js_1.generateWAMessageFromContent)(jid, { ...this._extraPayload, ...this._toListMessage() }, { ...options });
|
|
862
|
+
}
|
|
742
863
|
const message = await this.toCard();
|
|
743
864
|
return (0, messages_js_1.generateWAMessageFromContent)(jid, {
|
|
744
865
|
...this._extraPayload,
|
|
@@ -748,21 +869,31 @@ class Button extends BaseBuilder {
|
|
|
748
869
|
},
|
|
749
870
|
}, { ...options });
|
|
750
871
|
}
|
|
872
|
+
// Vanz@Add 22-08-26 (v4.7) --- picks the native_flow node variant for the first button's
|
|
873
|
+
// name, per Button.SPECIAL_FLOW. Falls back to the generic mixed node (previous
|
|
874
|
+
// unconditional behaviour) for anything not in that map. See ESM file for source notes.
|
|
875
|
+
_buildNativeFlowNode() {
|
|
876
|
+
const special = Button.SPECIAL_FLOW[this._buttons[0]?.name];
|
|
877
|
+
return special ? { tag: 'native_flow', attrs: special } : { tag: 'native_flow', attrs: { v: '9', name: 'mixed' } };
|
|
878
|
+
}
|
|
751
879
|
async send(jid, { ...options } = {}) {
|
|
752
880
|
const msg = await this.build(jid, options);
|
|
881
|
+
const bizContent = this._isLoneSingleSelect()
|
|
882
|
+
? [{ tag: 'list', attrs: { v: '2', type: 'product_list' } }]
|
|
883
|
+
: [
|
|
884
|
+
{
|
|
885
|
+
tag: 'interactive',
|
|
886
|
+
attrs: { type: 'native_flow', v: '1' },
|
|
887
|
+
content: [this._buildNativeFlowNode()],
|
|
888
|
+
},
|
|
889
|
+
];
|
|
753
890
|
await __classPrivateFieldGet(this, _Button_client, "f").relayMessage(msg.key.remoteJid, msg.message, {
|
|
754
891
|
messageId: msg.key.id,
|
|
755
892
|
additionalNodes: [
|
|
756
893
|
{
|
|
757
894
|
tag: 'biz',
|
|
758
895
|
attrs: {},
|
|
759
|
-
content:
|
|
760
|
-
{
|
|
761
|
-
tag: 'interactive',
|
|
762
|
-
attrs: { type: 'native_flow', v: '1' },
|
|
763
|
-
content: [{ tag: 'native_flow', attrs: { v: '9', name: 'mixed' } }],
|
|
764
|
-
},
|
|
765
|
-
],
|
|
896
|
+
content: bizContent,
|
|
766
897
|
},
|
|
767
898
|
],
|
|
768
899
|
...options,
|
|
@@ -771,6 +902,16 @@ class Button extends BaseBuilder {
|
|
|
771
902
|
}
|
|
772
903
|
}
|
|
773
904
|
exports.Button = Button;
|
|
905
|
+
Button.SPECIAL_FLOW = {
|
|
906
|
+
review_and_pay: { v: '1', name: 'order_details' },
|
|
907
|
+
payment_info: { v: '1', name: 'payment_info' },
|
|
908
|
+
mpm: { v: '2', name: 'mpm' },
|
|
909
|
+
cta_catalog: { v: '2', name: 'cta_catalog' },
|
|
910
|
+
send_location: { v: '2', name: 'send_location' },
|
|
911
|
+
call_permission_request: { v: '2', name: 'call_permission_request' },
|
|
912
|
+
wa_payment_transaction_details: { v: '2', name: 'wa_payment_transaction_details' },
|
|
913
|
+
automated_greeting_message_view_catalog: { v: '2', name: 'automated_greeting_message_view_catalog' },
|
|
914
|
+
};
|
|
774
915
|
_a = Button, _Button_client = new WeakMap(), _Button_validateAgainstSchema = function _Button_validateAgainstSchema(schema, data, label) {
|
|
775
916
|
for (const [key, type] of Object.entries(schema)) {
|
|
776
917
|
if (data[key] === undefined)
|
|
@@ -820,6 +961,7 @@ class ButtonV2 extends BaseBuilder {
|
|
|
820
961
|
this._buttons = [];
|
|
821
962
|
}
|
|
822
963
|
addButton(displayText = '', buttonId = crypto_1.default.randomUUID()) {
|
|
964
|
+
if (!displayText) throw new TypeError('addButton(displayText) requires a non-empty label');
|
|
823
965
|
this._buttons.push({
|
|
824
966
|
buttonId,
|
|
825
967
|
buttonText: { displayText },
|
|
@@ -847,8 +989,10 @@ class ButtonV2 extends BaseBuilder {
|
|
|
847
989
|
this._data = obj;
|
|
848
990
|
return this;
|
|
849
991
|
}
|
|
850
|
-
|
|
851
|
-
|
|
992
|
+
// Vanz@Fix 22-08-26 (v4.7): _thumbnail only computed when it'll be used; viewOnce now
|
|
993
|
+
// an overridable option (default true). See ESM file for full note.
|
|
994
|
+
async build(jid, { viewOnce = true, ...options } = {}) {
|
|
995
|
+
const _thumbnail = !this._data && this._image ? await Toolkit.resize(Buffer.isBuffer(this._image) ? this._image : await Toolkit.fetchBuffer(this._image, {}, { silent: true }), 300, 300) : null;
|
|
852
996
|
const msg = (0, messages_js_1.generateWAMessageFromContent)(jid, {
|
|
853
997
|
...this._extraPayload,
|
|
854
998
|
buttonsMessage: {
|
|
@@ -866,7 +1010,7 @@ class ButtonV2 extends BaseBuilder {
|
|
|
866
1010
|
jpegThumbnail: _thumbnail,
|
|
867
1011
|
},
|
|
868
1012
|
}),
|
|
869
|
-
viewOnce
|
|
1013
|
+
viewOnce,
|
|
870
1014
|
contextInfo: this._contextInfo,
|
|
871
1015
|
buttons: [...this._buttons],
|
|
872
1016
|
},
|
|
@@ -917,6 +1061,9 @@ class Carousel extends BaseBuilder {
|
|
|
917
1061
|
throw new Error(`Card [${baseIndex + index}] must include an image or video in header`);
|
|
918
1062
|
}
|
|
919
1063
|
}
|
|
1064
|
+
if (this._cards.length + cards.length > Carousel.MAX_CARDS) {
|
|
1065
|
+
throw new Error(`Carousel supports at most ${Carousel.MAX_CARDS} cards (got ${this._cards.length + cards.length})`);
|
|
1066
|
+
}
|
|
920
1067
|
this._cards.push(...cards);
|
|
921
1068
|
return this;
|
|
922
1069
|
}
|
|
@@ -937,6 +1084,7 @@ class Carousel extends BaseBuilder {
|
|
|
937
1084
|
}, { ...options });
|
|
938
1085
|
}
|
|
939
1086
|
async send(jid, { ...options } = {}) {
|
|
1087
|
+
if (this._cards.length === 0) throw new Error('Carousel requires at least one card (use addCard())');
|
|
940
1088
|
const msg = this.build(jid, options);
|
|
941
1089
|
await __classPrivateFieldGet(this, _Carousel_client, "f").relayMessage(msg.key.remoteJid, msg.message, {
|
|
942
1090
|
messageId: msg.key.id,
|
|
@@ -960,6 +1108,101 @@ class Carousel extends BaseBuilder {
|
|
|
960
1108
|
}
|
|
961
1109
|
exports.Carousel = Carousel;
|
|
962
1110
|
_Carousel_client = new WeakMap();
|
|
1111
|
+
// Vanz@Add (v4.8): Poll builder, see ESM file for full docblock/rationale.
|
|
1112
|
+
class Poll extends BaseBuilder {
|
|
1113
|
+
constructor(client) {
|
|
1114
|
+
super();
|
|
1115
|
+
_Poll_client.set(this, void 0);
|
|
1116
|
+
if (!client)
|
|
1117
|
+
throw new Error('Socket is required');
|
|
1118
|
+
__classPrivateFieldSet(this, _Poll_client, client, "f");
|
|
1119
|
+
this._name = '';
|
|
1120
|
+
this._values = [];
|
|
1121
|
+
this._selectableCount = 1;
|
|
1122
|
+
this._hideVoter = false;
|
|
1123
|
+
this._canAddOption = false;
|
|
1124
|
+
this._toAnnouncementGroup = false;
|
|
1125
|
+
this._correctAnswer = undefined;
|
|
1126
|
+
this._endDate = undefined;
|
|
1127
|
+
}
|
|
1128
|
+
setName(name) {
|
|
1129
|
+
if (typeof name !== 'string' || !name)
|
|
1130
|
+
throw new TypeError('setName(name) requires a non-empty string');
|
|
1131
|
+
this._name = name;
|
|
1132
|
+
return this;
|
|
1133
|
+
}
|
|
1134
|
+
addOption(name) {
|
|
1135
|
+
if (typeof name !== 'string' || !name)
|
|
1136
|
+
throw new TypeError('addOption(name) requires a non-empty string');
|
|
1137
|
+
this._values.push(name);
|
|
1138
|
+
return this;
|
|
1139
|
+
}
|
|
1140
|
+
addOptions(names) {
|
|
1141
|
+
if (!Array.isArray(names) || !names.length)
|
|
1142
|
+
throw new TypeError('addOptions(names) requires a non-empty array of strings');
|
|
1143
|
+
names.forEach((name) => this.addOption(name));
|
|
1144
|
+
return this;
|
|
1145
|
+
}
|
|
1146
|
+
setSelectable(count) {
|
|
1147
|
+
if (typeof count !== 'number' || count < 0)
|
|
1148
|
+
throw new TypeError('setSelectable(count) requires a non-negative number');
|
|
1149
|
+
this._selectableCount = count;
|
|
1150
|
+
return this;
|
|
1151
|
+
}
|
|
1152
|
+
setMultiSelect(canSelectMultiple = true) {
|
|
1153
|
+
this._selectableCount = canSelectMultiple ? 0 : 1;
|
|
1154
|
+
return this;
|
|
1155
|
+
}
|
|
1156
|
+
setHideVoter(hide = true) {
|
|
1157
|
+
this._hideVoter = hide;
|
|
1158
|
+
return this;
|
|
1159
|
+
}
|
|
1160
|
+
setCanAddOption(allow = true) {
|
|
1161
|
+
this._canAddOption = allow;
|
|
1162
|
+
return this;
|
|
1163
|
+
}
|
|
1164
|
+
setAnnouncementGroup(isAnnouncement = true) {
|
|
1165
|
+
this._toAnnouncementGroup = isAnnouncement;
|
|
1166
|
+
return this;
|
|
1167
|
+
}
|
|
1168
|
+
setEndDate(date) {
|
|
1169
|
+
this._endDate = date instanceof Date ? date : new Date(date);
|
|
1170
|
+
return this;
|
|
1171
|
+
}
|
|
1172
|
+
setQuiz(correctOptionName) {
|
|
1173
|
+
if (typeof correctOptionName !== 'string' || !correctOptionName) {
|
|
1174
|
+
throw new TypeError('setQuiz(correctOptionName) requires a non-empty string');
|
|
1175
|
+
}
|
|
1176
|
+
this._correctAnswer = correctOptionName;
|
|
1177
|
+
return this;
|
|
1178
|
+
}
|
|
1179
|
+
build() {
|
|
1180
|
+
if (!this._name)
|
|
1181
|
+
throw new Error('Poll requires a name (use setName())');
|
|
1182
|
+
if (this._values.length < 2)
|
|
1183
|
+
throw new Error('Poll requires at least 2 options (use addOption()/addOptions())');
|
|
1184
|
+
if (this._correctAnswer && !this._values.includes(this._correctAnswer)) {
|
|
1185
|
+
throw new Error('setQuiz(correctOptionName) must match one of the added options exactly');
|
|
1186
|
+
}
|
|
1187
|
+
return {
|
|
1188
|
+
poll: {
|
|
1189
|
+
name: this._name,
|
|
1190
|
+
values: this._values,
|
|
1191
|
+
selectableCount: this._selectableCount,
|
|
1192
|
+
toAnnouncementGroup: this._toAnnouncementGroup,
|
|
1193
|
+
hideVoter: this._hideVoter,
|
|
1194
|
+
canAddOption: this._canAddOption,
|
|
1195
|
+
...(this._endDate && { endDate: this._endDate }),
|
|
1196
|
+
...(this._correctAnswer && { pollType: 1, correctAnswer: this._correctAnswer }),
|
|
1197
|
+
},
|
|
1198
|
+
};
|
|
1199
|
+
}
|
|
1200
|
+
async send(jid, options = {}) {
|
|
1201
|
+
return __classPrivateFieldGet(this, _Poll_client, "f").sendMessage(jid, this.build(), options);
|
|
1202
|
+
}
|
|
1203
|
+
}
|
|
1204
|
+
exports.Poll = Poll;
|
|
1205
|
+
_Poll_client = new WeakMap();
|
|
963
1206
|
class AIRich extends BaseBuilder {
|
|
964
1207
|
constructor(client) {
|
|
965
1208
|
if (!client) {
|
|
@@ -1296,6 +1539,11 @@ class AIRich extends BaseBuilder {
|
|
|
1296
1539
|
if (!((data && typeof data === 'object' && !Array.isArray(data)) || (Array.isArray(data) && data.every((item) => item && typeof item === 'object' && !Array.isArray(item))))) {
|
|
1297
1540
|
throw new TypeError('Product items must be an object or an array of objects');
|
|
1298
1541
|
}
|
|
1542
|
+
const itemsToCheck = Array.isArray(data) ? data : [data];
|
|
1543
|
+
const missingTitleAt = itemsToCheck.findIndex((item) => !item.title);
|
|
1544
|
+
if (missingTitleAt !== -1) {
|
|
1545
|
+
throw new TypeError(`addProduct() item[${missingTitleAt}] is missing a required "title"`);
|
|
1546
|
+
}
|
|
1299
1547
|
this._submessages.push({
|
|
1300
1548
|
messageType: 2,
|
|
1301
1549
|
messageText: '[ Produk tidak dapat dimuat ]',
|
|
@@ -1354,6 +1602,9 @@ class AIRich extends BaseBuilder {
|
|
|
1354
1602
|
return this;
|
|
1355
1603
|
}
|
|
1356
1604
|
addTip(text) {
|
|
1605
|
+
if (typeof text !== 'string' || !text) {
|
|
1606
|
+
throw new TypeError('addTip(text) requires a non-empty string');
|
|
1607
|
+
}
|
|
1357
1608
|
this._submessages.push({
|
|
1358
1609
|
messageType: 2,
|
|
1359
1610
|
messageText: text,
|
|
@@ -1364,6 +1615,203 @@ class AIRich extends BaseBuilder {
|
|
|
1364
1615
|
}));
|
|
1365
1616
|
return this;
|
|
1366
1617
|
}
|
|
1618
|
+
// Vanz@Add 22-08-26 (v4.7): addHeading/addImageCard/addWidget/addFooterAction, see ESM file for full notes.
|
|
1619
|
+
addHeading(text) {
|
|
1620
|
+
if (typeof text !== 'string' || !text) {
|
|
1621
|
+
throw new TypeError('addHeading(text) requires a non-empty string');
|
|
1622
|
+
}
|
|
1623
|
+
this._submessages.push({ messageType: 2, messageText: text });
|
|
1624
|
+
this._sections.push(AIRich.newLayout('Single', { text, __typename: 'FOATextPrimitive' }));
|
|
1625
|
+
return this;
|
|
1626
|
+
}
|
|
1627
|
+
addImageCard(previewUrl, fullUrl = previewUrl, { resolveUrl = false } = {}) {
|
|
1628
|
+
if (!(typeof previewUrl === 'string' || Buffer.isBuffer(previewUrl))) {
|
|
1629
|
+
throw new TypeError('addImageCard(previewUrl) requires a string url or buffer');
|
|
1630
|
+
}
|
|
1631
|
+
const preview = Toolkit.resolveMedia(__classPrivateFieldGet(this, _AIRich_client, "f"), previewUrl, 'image', { resolveUrl });
|
|
1632
|
+
const full = fullUrl === previewUrl ? preview : Toolkit.resolveMedia(__classPrivateFieldGet(this, _AIRich_client, "f"), fullUrl, 'image', { resolveUrl });
|
|
1633
|
+
this._submessages.push({
|
|
1634
|
+
messageType: 1,
|
|
1635
|
+
gridImageMetadata: {
|
|
1636
|
+
gridImageUrl: { imagePreviewUrl: preview },
|
|
1637
|
+
imageUrls: [{ imagePreviewUrl: preview, imageHighResUrl: full, sourceUrl: full }],
|
|
1638
|
+
},
|
|
1639
|
+
});
|
|
1640
|
+
this._sections.push(AIRich.newLayout('Single', {
|
|
1641
|
+
preview_image: { url: preview, mime_type: 'image/jpeg', __typename: 'GenAIMediaItem' },
|
|
1642
|
+
full_image: { url: full, mime_type: 'image/jpeg', __typename: 'GenAIMediaItem' },
|
|
1643
|
+
__typename: 'GenAIImagePrimitive',
|
|
1644
|
+
}));
|
|
1645
|
+
return this;
|
|
1646
|
+
}
|
|
1647
|
+
// Vanz@Add (v4.8): { layout } override + ctas/actions alias support, see ESM file for full notes.
|
|
1648
|
+
addWidget(data = {}, { layout } = {}) {
|
|
1649
|
+
const items = Array.isArray(data) ? data : [data];
|
|
1650
|
+
items.forEach((item, i) => {
|
|
1651
|
+
if (!item?.title) {
|
|
1652
|
+
throw new TypeError(`addWidget() item[${i}] is missing a required "title"`);
|
|
1653
|
+
}
|
|
1654
|
+
const ctas = item.ctas ?? item.actions;
|
|
1655
|
+
if (!Array.isArray(ctas) || !ctas.length) {
|
|
1656
|
+
throw new TypeError(`addWidget() item[${i}] requires a non-empty "ctas" (or "actions") array`);
|
|
1657
|
+
}
|
|
1658
|
+
});
|
|
1659
|
+
this._submessages.push({ messageType: 2, messageText: items.map((item) => item.title).join(', ') });
|
|
1660
|
+
const widgets = items.map((item) => {
|
|
1661
|
+
const ctas = item.ctas ?? item.actions;
|
|
1662
|
+
return {
|
|
1663
|
+
header: { title: item.title, __typename: 'GenAI3PExtWidgetStandardHeader' },
|
|
1664
|
+
body: {
|
|
1665
|
+
sections: item.sections ?? [],
|
|
1666
|
+
ctas: ctas.map((cta, idx) => ({
|
|
1667
|
+
label: cta.label ?? '',
|
|
1668
|
+
state: cta.state ?? 'PENDING',
|
|
1669
|
+
kind: cta.kind ?? 'OTHER',
|
|
1670
|
+
tool_call_id: cta.tool_call_id ?? String(idx).padStart(2, '0'),
|
|
1671
|
+
...(cta.toast !== false && {
|
|
1672
|
+
toast: { label: typeof cta.toast === 'string' ? cta.toast : item.title, __typename: 'GenAI3PExtWidgetToast' },
|
|
1673
|
+
}),
|
|
1674
|
+
__typename: 'GenAI3PExtWidgetCTA',
|
|
1675
|
+
})),
|
|
1676
|
+
__typename: item.body_typename ?? 'GenAI3PExtCalendarEventList',
|
|
1677
|
+
},
|
|
1678
|
+
__typename: 'GenAI3PExtWidgetPrimitive',
|
|
1679
|
+
};
|
|
1680
|
+
});
|
|
1681
|
+
const resolvedLayout = layout ?? (Array.isArray(data) ? 'HScroll' : 'Single');
|
|
1682
|
+
const asArray = resolvedLayout !== 'Single';
|
|
1683
|
+
this._sections.push(AIRich.newLayout(resolvedLayout, asArray ? widgets : widgets[0]));
|
|
1684
|
+
return this;
|
|
1685
|
+
}
|
|
1686
|
+
addFooterAction(actions) {
|
|
1687
|
+
const items = Array.isArray(actions) ? actions : [actions];
|
|
1688
|
+
items.forEach((item, i) => {
|
|
1689
|
+
if (!item?.text || !item?.url) {
|
|
1690
|
+
throw new TypeError(`addFooterAction() item[${i}] requires both "text" and "url"`);
|
|
1691
|
+
}
|
|
1692
|
+
});
|
|
1693
|
+
const primitives = items.map((item) => ({
|
|
1694
|
+
cta_text: item.text,
|
|
1695
|
+
cta_type: item.type ?? 'OPEN_URL',
|
|
1696
|
+
cta_url: item.url,
|
|
1697
|
+
__typename: 'GenAIFooterActionPrimitive',
|
|
1698
|
+
}));
|
|
1699
|
+
this._sections.push(AIRich.newLayout('HScroll', primitives));
|
|
1700
|
+
return this;
|
|
1701
|
+
}
|
|
1702
|
+
// Vanz@Add (v4.8): 8 primitives with no dedicated proto submessage type (except Latex), see ESM file.
|
|
1703
|
+
addDivider() {
|
|
1704
|
+
this._submessages.push({ messageType: 2, messageText: '---' });
|
|
1705
|
+
this._sections.push(AIRich.newLayout('Single', { __typename: 'GenAIDividerPrimitive' }));
|
|
1706
|
+
return this;
|
|
1707
|
+
}
|
|
1708
|
+
addSpacer(spacing = 1) {
|
|
1709
|
+
if (typeof spacing !== 'number' || spacing < 0) {
|
|
1710
|
+
throw new TypeError('addSpacer(spacing) requires a non-negative number');
|
|
1711
|
+
}
|
|
1712
|
+
this._submessages.push({ messageType: 2, messageText: `spasi ${spacing}` });
|
|
1713
|
+
this._sections.push(AIRich.newLayout('Single', { spacing, __typename: 'GenAISpacerPrimitive' }));
|
|
1714
|
+
return this;
|
|
1715
|
+
}
|
|
1716
|
+
addLatex(expression) {
|
|
1717
|
+
if (typeof expression !== 'string' || !expression) {
|
|
1718
|
+
throw new TypeError('addLatex(expression) requires a non-empty string');
|
|
1719
|
+
}
|
|
1720
|
+
this._submessages.push({
|
|
1721
|
+
messageType: 8,
|
|
1722
|
+
latexMetadata: { text: expression, expressions: [{ latexExpression: expression }] },
|
|
1723
|
+
});
|
|
1724
|
+
this._sections.push(AIRich.newLayout('Single', { latex_expression: expression, __typename: 'GenAILatexUXPrimitive' }));
|
|
1725
|
+
return this;
|
|
1726
|
+
}
|
|
1727
|
+
addTask(data = {}) {
|
|
1728
|
+
if (!data?.title) {
|
|
1729
|
+
throw new TypeError('addTask() requires a "title"');
|
|
1730
|
+
}
|
|
1731
|
+
this._submessages.push({ messageType: 2, messageText: `Tugas: ${data.title}` });
|
|
1732
|
+
this._sections.push(AIRich.newLayout('Single', {
|
|
1733
|
+
task_id: data.task_id ?? '',
|
|
1734
|
+
title: data.title,
|
|
1735
|
+
subtitle: data.subtitle ?? '',
|
|
1736
|
+
status: data.status ?? 'IN_PROGRESS',
|
|
1737
|
+
__typename: 'GenAITaskPrimitive',
|
|
1738
|
+
}));
|
|
1739
|
+
return this;
|
|
1740
|
+
}
|
|
1741
|
+
addProgressStatus(title, { icon = 'SEARCH', is_in_progress = true, target_secondary_screen_id, target_secondary_screen_tab_id } = {}) {
|
|
1742
|
+
if (typeof title !== 'string' || !title) {
|
|
1743
|
+
throw new TypeError('addProgressStatus(title) requires a non-empty string');
|
|
1744
|
+
}
|
|
1745
|
+
this._submessages.push({ messageType: 2, messageText: title });
|
|
1746
|
+
const primitive = {
|
|
1747
|
+
title, icon, is_in_progress,
|
|
1748
|
+
meta_search_apps: [],
|
|
1749
|
+
__typename: 'GenAIBotProgressStatusPrimitive',
|
|
1750
|
+
};
|
|
1751
|
+
// Must be omitted when unset, not sent as null — explicit null here crashed the WA client renderer.
|
|
1752
|
+
if (target_secondary_screen_id != null) primitive.target_secondary_screen_id = target_secondary_screen_id;
|
|
1753
|
+
if (target_secondary_screen_tab_id != null) primitive.target_secondary_screen_tab_id = target_secondary_screen_tab_id;
|
|
1754
|
+
this._sections.push(AIRich.newLayout('Single', primitive));
|
|
1755
|
+
return this;
|
|
1756
|
+
}
|
|
1757
|
+
addThinkingStatus(title, { icon = 'THINKING', is_in_progress = true, target_secondary_screen_id, target_secondary_screen_tab_id, textFallback = true } = {}) {
|
|
1758
|
+
if (typeof title !== 'string' || !title) {
|
|
1759
|
+
throw new TypeError('addThinkingStatus(title) requires a non-empty string');
|
|
1760
|
+
}
|
|
1761
|
+
this._submessages.push({ messageType: 2, messageText: title });
|
|
1762
|
+
const primitive = {
|
|
1763
|
+
title, icon, is_in_progress,
|
|
1764
|
+
meta_search_apps: [],
|
|
1765
|
+
__typename: 'GenAIBotThinkingStatusPrimitive',
|
|
1766
|
+
};
|
|
1767
|
+
if (target_secondary_screen_id != null) primitive.target_secondary_screen_id = target_secondary_screen_id;
|
|
1768
|
+
if (target_secondary_screen_tab_id != null) primitive.target_secondary_screen_tab_id = target_secondary_screen_tab_id;
|
|
1769
|
+
this._sections.push(AIRich.newLayout('Single', primitive));
|
|
1770
|
+
// Safety net: stock WA client renders this as blank (native UI is a transient spinner).
|
|
1771
|
+
if (textFallback) {
|
|
1772
|
+
this._sections.push(AIRich.newLayout('Single', { text: title, __typename: 'FOATextPrimitive' }));
|
|
1773
|
+
}
|
|
1774
|
+
return this;
|
|
1775
|
+
}
|
|
1776
|
+
addQuotaUpsell(data = {}) {
|
|
1777
|
+
if (!data?.title) {
|
|
1778
|
+
throw new TypeError('addQuotaUpsell() requires a "title"');
|
|
1779
|
+
}
|
|
1780
|
+
this._submessages.push({ messageType: 2, messageText: data.title });
|
|
1781
|
+
this._sections.push(AIRich.newLayout('Single', {
|
|
1782
|
+
title: data.title,
|
|
1783
|
+
body: data.body ?? '',
|
|
1784
|
+
body_line1: data.body_line1 ?? '',
|
|
1785
|
+
body_line2: data.body_line2 ?? '',
|
|
1786
|
+
buttons: (data.buttons ?? []).map((b) => ({
|
|
1787
|
+
label: b.label ?? '',
|
|
1788
|
+
action: b.action ?? 'OPEN_DEEPLINK',
|
|
1789
|
+
deeplink: b.deeplink ?? '',
|
|
1790
|
+
})),
|
|
1791
|
+
__typename: 'GenAIMetaSubsQuotaUpsellPrimitive',
|
|
1792
|
+
}));
|
|
1793
|
+
return this;
|
|
1794
|
+
}
|
|
1795
|
+
addBloks(data = {}) {
|
|
1796
|
+
if (!data?.type) {
|
|
1797
|
+
throw new TypeError('addBloks() requires a "type"');
|
|
1798
|
+
}
|
|
1799
|
+
this._submessages.push({ messageType: 2, messageText: 'Bloks' });
|
|
1800
|
+
const primitive = {
|
|
1801
|
+
type: data.type,
|
|
1802
|
+
data: data.data ?? '{}',
|
|
1803
|
+
uuid: data.uuid ?? '',
|
|
1804
|
+
versioning_id: data.versioning_id ?? '',
|
|
1805
|
+
__typename: 'FOABloksPrimitive',
|
|
1806
|
+
};
|
|
1807
|
+
if (data.initial_response != null) primitive.initial_response = data.initial_response;
|
|
1808
|
+
this._sections.push(AIRich.newLayout('Single', primitive));
|
|
1809
|
+
// Safety net: FOABloksPrimitive needs a real registered Bloks screen to render anything.
|
|
1810
|
+
if (data.textFallback !== false) {
|
|
1811
|
+
this._sections.push(AIRich.newLayout('Single', { text: `Bloks: ${data.type}`, __typename: 'FOATextPrimitive' }));
|
|
1812
|
+
}
|
|
1813
|
+
return this;
|
|
1814
|
+
}
|
|
1367
1815
|
addSuggest(suggestion, { scroll = true, layout } = {}) {
|
|
1368
1816
|
if (!(typeof suggestion === 'string' || (Array.isArray(suggestion) && suggestion.every((v) => typeof v === 'string')))) {
|
|
1369
1817
|
throw new TypeError('Suggestion must be a string or array of strings');
|
|
@@ -1469,10 +1917,6 @@ class AIRich extends BaseBuilder {
|
|
|
1469
1917
|
// for bot-sent messages (confirmed: even a valid WA-CDN url with mediaKey stays blank), so any
|
|
1470
1918
|
// image added via addInlineImage() is sent here as a normal imageMessage instead. Pass
|
|
1471
1919
|
// { skipImageFallback: true } to opt out and send only the (image-less-looking) rich card.
|
|
1472
|
-
// Vanz@Fix (bug 42 / inline image fallback) --- WA won't render AIRichResponseInlineImageMetadata
|
|
1473
|
-
// for bot-sent messages (confirmed: even a valid WA-CDN url with mediaKey stays blank), so any
|
|
1474
|
-
// image added via addInlineImage() is sent here as a normal imageMessage instead. Pass
|
|
1475
|
-
// { skipImageFallback: true } to opt out and send only the (image-less-looking) rich card.
|
|
1476
1920
|
// Vanz@Fix: don't spread relayMessage-shaped `options` into sendMessage()'s options param —
|
|
1477
1921
|
// the two calls expect different option shapes, so the fallback now only forwards `quoted`
|
|
1478
1922
|
// (the one option that clearly applies to both) instead of blindly spreading everything.
|
|
@@ -2161,4 +2605,9 @@ class AIRich extends BaseBuilder {
|
|
|
2161
2605
|
}
|
|
2162
2606
|
}
|
|
2163
2607
|
exports.AIRich = AIRich;
|
|
2608
|
+
// Vanz@Alias --- lihat catatan yang sama di versi ESM (lib/Utils/MessageBuilder.js)
|
|
2609
|
+
exports.AIVanzxy = AIRich;
|
|
2610
|
+
exports.LeafRich = AIRich;
|
|
2611
|
+
exports.VanzxyAI = AIRich;
|
|
2612
|
+
exports.VanzxyRich = AIRich;
|
|
2164
2613
|
_AIRich_client = new WeakMap();
|