ishumdz-bail 1.0.25 → 1.0.27
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/README.md +54 -1
- package/lib/Utils/messages.js +145 -3
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -651,7 +651,7 @@ function resolveButtonResponse(msg) {
|
|
|
651
651
|
const nf = msg.message?.interactiveResponseMessage?.nativeFlowResponseMessage
|
|
652
652
|
if (nf?.paramsJson) {
|
|
653
653
|
try {
|
|
654
|
-
const p = JSON.parse(
|
|
654
|
+
const p = JSON.parse(nf.paramsJson)
|
|
655
655
|
return p.id || p.selectedId || p.selected_row_id || null
|
|
656
656
|
} catch { /* ignore */ }
|
|
657
657
|
}
|
|
@@ -695,6 +695,59 @@ Action buttons (`url` / `copy` / `call`) never send a reply — nothing to handl
|
|
|
695
695
|
> (`.menu` → custom image/GIF + buttons + highlighted menu sheet), plus a visual
|
|
696
696
|
> preview in [`banner-preview.html`](banner-preview.html).
|
|
697
697
|
|
|
698
|
+
### Base Compatibility — cantarella / Case X Style Code (v1.0.27+)
|
|
699
|
+
|
|
700
|
+
Code copied from other Baileys bases (cantarella-baileys, Case X Plugin YOUHU MD, etc.)
|
|
701
|
+
runs without changes. Three shapes are accepted:
|
|
702
|
+
|
|
703
|
+
**1) Raw `buttonsMessage` classic menu card — even the risky mix.** A raw classic
|
|
704
|
+
message that mixes `nativeFlowInfo` (single_select sheet) or `cta_*` buttons with
|
|
705
|
+
plain buttons is **auto-upgraded to a native-flow interactive card**, so it can never
|
|
706
|
+
render the "version doesn't support it" bubble:
|
|
707
|
+
|
|
708
|
+
```javascript
|
|
709
|
+
// Case X / cantarella style — works as-is:
|
|
710
|
+
await sock.sendMessage(jid, {
|
|
711
|
+
buttonsMessage: {
|
|
712
|
+
locationMessage: { degreesLatitude: 0, degreesLongitude: 0, name: 'Youhu base', address: '📍Today' },
|
|
713
|
+
contentText: menuText, footerText: footer, headerType: 6,
|
|
714
|
+
buttons: [
|
|
715
|
+
{ buttonId: 'menu', buttonText: { displayText: '☰ menu' }, type: 1,
|
|
716
|
+
nativeFlowInfo: { name: 'single_select', paramsJson: JSON.stringify({
|
|
717
|
+
title: 'Pilih Menu',
|
|
718
|
+
sections: [{ title: 'base', highlight_label: '🔥', rows: [{ title: 'ping', description: 'live', id: '/ping' }] }]
|
|
719
|
+
}) } },
|
|
720
|
+
{ buttonId: 'sc', buttonText: { displayText: '⌕ script' }, type: 1 }
|
|
721
|
+
]
|
|
722
|
+
}
|
|
723
|
+
})
|
|
724
|
+
```
|
|
725
|
+
|
|
726
|
+
**2) Raw `interactiveMessage` native-flow card — straight through `sendMessage`.**
|
|
727
|
+
No `generateWAMessageFromContent` + `relayMessage` dance needed (though that still
|
|
728
|
+
works too). `messageVersion` defaults to 1:
|
|
729
|
+
|
|
730
|
+
```javascript
|
|
731
|
+
await sock.sendMessage(jid, {
|
|
732
|
+
interactiveMessage: {
|
|
733
|
+
body: { text: 'Pairing code: 1234-5678' },
|
|
734
|
+
footer: { text: 'Tap to copy' },
|
|
735
|
+
header: { hasMediaAttachment: false },
|
|
736
|
+
nativeFlowMessage: {
|
|
737
|
+
buttons: [{ name: 'cta_copy', buttonParamsJson: JSON.stringify({ display_text: 'Copy', copy_code: '12345678' }) }]
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
})
|
|
741
|
+
|
|
742
|
+
// short form also accepted:
|
|
743
|
+
await sock.sendMessage(jid, { interactiveMessage: { buttons: [{ name: 'quick_reply', buttonParamsJson: '{"display_text":"hi","id":"hi"}' }] } })
|
|
744
|
+
```
|
|
745
|
+
|
|
746
|
+
**3) Plain raw `buttonsMessage`** (no native-flow extras) stays classic and gets the
|
|
747
|
+
automatic invisible-PNG header when you omit one. Flow params are accepted as
|
|
748
|
+
`paramsJson` or `buttonParamsJson`, and `single_select` / `cta_url` / `cta_copy` /
|
|
749
|
+
`cta_call` / `quick_reply` names are preserved as-is.
|
|
750
|
+
|
|
698
751
|
---
|
|
699
752
|
|
|
700
753
|
## 🚫 Ban Checker
|
package/lib/Utils/messages.js
CHANGED
|
@@ -586,7 +586,10 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
586
586
|
if ('interactiveButtons' in message && !!message.interactiveButtons) {
|
|
587
587
|
const nativeFlow = proto.Message.InteractiveMessage.NativeFlowMessage.fromObject({
|
|
588
588
|
buttons: message.interactiveButtons,
|
|
589
|
-
messageParamsJson: message.messageParams ?? "{}"
|
|
589
|
+
messageParamsJson: message.messageParams ?? "{}",
|
|
590
|
+
// PATCH (1.0.26): default messageVersion to 1 — version 0 renders as
|
|
591
|
+
// greyed-out, untappable placeholder buttons on current clients.
|
|
592
|
+
messageVersion: message.messageVersion ?? 1
|
|
590
593
|
});
|
|
591
594
|
let interactiveMessage = { nativeFlowMessage: nativeFlow };
|
|
592
595
|
if ('text' in message) {
|
|
@@ -651,20 +654,101 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
651
654
|
applyContextInfoAndMentions(interactiveMessage, message);
|
|
652
655
|
m = { interactiveMessage };
|
|
653
656
|
}
|
|
657
|
+
else if ('interactiveMessage' in message && !!message.interactiveMessage) {
|
|
658
|
+
// PATCH (1.0.27): cantarella / Case X-style RAW interactiveMessage
|
|
659
|
+
// pass-through — send the card exactly like those bases do, but via a
|
|
660
|
+
// normal sendMessage call. Two accepted shapes:
|
|
661
|
+
// { interactiveMessage: { body, footer, header, nativeFlowMessage: { buttons } } }
|
|
662
|
+
// { interactiveMessage: { buttons } } (short form)
|
|
663
|
+
// messageVersion defaults to 1 (0 renders greyed-out placeholders).
|
|
664
|
+
let card = message.interactiveMessage;
|
|
665
|
+
if (card && !card.nativeFlowMessage && Array.isArray(card.buttons)) {
|
|
666
|
+
const { buttons, messageParamsJson, ...rest } = card;
|
|
667
|
+
card = { ...rest, nativeFlowMessage: { buttons, messageParamsJson: messageParamsJson || "" } };
|
|
668
|
+
}
|
|
669
|
+
if (card?.nativeFlowMessage && (card.nativeFlowMessage.messageVersion == null || card.nativeFlowMessage.messageVersion === 0)) {
|
|
670
|
+
card.nativeFlowMessage.messageVersion = 1;
|
|
671
|
+
}
|
|
672
|
+
if (card && !card.body && 'text' in message && !!message.text) {
|
|
673
|
+
card.body = { text: message.text };
|
|
674
|
+
}
|
|
675
|
+
m = { interactiveMessage: card };
|
|
676
|
+
}
|
|
654
677
|
else if ('buttonsMessage' in message && !!message.buttonsMessage) {
|
|
655
678
|
// PATCH: raw buttonsMessage — classic pass-through. Modern clients render
|
|
656
679
|
// the horizontal row only when a header exists (image/video/document/
|
|
657
680
|
// location). A text-only raw message WITHOUT any header is exactly the
|
|
658
681
|
// "version doesn't support it" case — so when the caller passed none, we
|
|
659
682
|
// attach the invisible 1x1 PNG image header automatically (same trick the
|
|
660
|
-
// `buttons` API uses) and the row always renders.
|
|
661
|
-
// header-less raw messages can never produce the "not supported" bubble.
|
|
683
|
+
// `buttons` API uses) and the row always renders.
|
|
662
684
|
const raw = proto.Message.ButtonsMessage.fromObject(message.buttonsMessage)
|
|
663
685
|
// NOTE: fromObject turns missing fields into null (protobuf defaults), so
|
|
664
686
|
// a nullish headerType (= caller never set it) counts as "no header" too.
|
|
665
687
|
const hasHeader = !!(raw.imageMessage || raw.videoMessage || raw.documentMessage ||
|
|
666
688
|
raw.locationMessage ||
|
|
667
689
|
(raw.headerType != null && raw.headerType !== ButtonType.EMPTY && raw.headerType !== ButtonType.UNKNOWN))
|
|
690
|
+
// PATCH (1.0.27): a raw classic message that MIXES native-flow extras
|
|
691
|
+
// (single_select nativeFlowInfo, cta_* buttons) into a ButtonsMessage is
|
|
692
|
+
// the Case X / cantarella menu-card pattern — on current clients it
|
|
693
|
+
// renders as "version doesn't support it" (real-device evidence). Convert
|
|
694
|
+
// the whole message to a native-flow interactive card that renders fully.
|
|
695
|
+
// Read the caller's ORIGINAL button objects — proto fromObject drops
|
|
696
|
+
// unknown fields (e.g. nativeFlowInfo.buttonParamsJson), and some bases
|
|
697
|
+
// (cantarella) put params there.
|
|
698
|
+
const inputButtons = Array.isArray(message.buttonsMessage.buttons) ? message.buttonsMessage.buttons : raw.buttons
|
|
699
|
+
const rawExtras = (inputButtons || []).filter(b =>
|
|
700
|
+
b?.nativeFlowInfo?.name || Number(b?.type) === proto.Message.ButtonsMessage.Button.Type.NATIVE_FLOW)
|
|
701
|
+
if (rawExtras.length) {
|
|
702
|
+
const rawLoc = raw.locationMessage
|
|
703
|
+
const flowButtons = inputButtons.map(b => {
|
|
704
|
+
const name = b?.nativeFlowInfo?.name
|
|
705
|
+
if (name === 'single_select') {
|
|
706
|
+
let params = b.nativeFlowInfo.paramsJson
|
|
707
|
+
try { params = JSON.stringify(JSON.parse(params)) } catch { params = typeof params === 'string' ? params : '{}' }
|
|
708
|
+
return { name: 'single_select', buttonParamsJson: params }
|
|
709
|
+
}
|
|
710
|
+
if (name) {
|
|
711
|
+
return { name, buttonParamsJson: b.nativeFlowInfo.buttonParamsJson || b.nativeFlowInfo.paramsJson || '{}' }
|
|
712
|
+
}
|
|
713
|
+
return {
|
|
714
|
+
name: 'quick_reply',
|
|
715
|
+
buttonParamsJson: JSON.stringify({
|
|
716
|
+
display_text: b.buttonText?.displayText || '',
|
|
717
|
+
id: b.buttonId || b.buttonText?.displayText || ''
|
|
718
|
+
})
|
|
719
|
+
}
|
|
720
|
+
})
|
|
721
|
+
const interactiveMessage = {
|
|
722
|
+
nativeFlowMessage: { buttons: flowButtons, messageParamsJson: '', messageVersion: 1 }
|
|
723
|
+
}; const bodyText = raw.contentText || (raw.imageMessage?.caption ?? raw.videoMessage?.caption ?? '') || ''
|
|
724
|
+
if (bodyText) interactiveMessage.body = { text: bodyText };
|
|
725
|
+
if (raw.footerText) interactiveMessage.footer = { text: raw.footerText };
|
|
726
|
+
const header = { title: raw.text || (interactiveMessage.body.text ? String(interactiveMessage.body.text).split('\n')[0].slice(0, 42) : '') || 'Menu', subtitle: '', hasMediaAttachment: false };
|
|
727
|
+
if (rawLoc) {
|
|
728
|
+
header.locationMessage = {
|
|
729
|
+
degreesLatitude: rawLoc.degreesLatitude ?? 0,
|
|
730
|
+
degreesLongitude: rawLoc.degreesLongitude ?? 0,
|
|
731
|
+
name: rawLoc.name ?? null,
|
|
732
|
+
address: rawLoc.address ?? null,
|
|
733
|
+
...(rawLoc.jpegThumbnail ? { jpegThumbnail: rawLoc.jpegThumbnail } : {})
|
|
734
|
+
};
|
|
735
|
+
header.hasMediaAttachment = true;
|
|
736
|
+
} else if (raw.imageMessage) {
|
|
737
|
+
header.imageMessage = raw.imageMessage;
|
|
738
|
+
header.hasMediaAttachment = true;
|
|
739
|
+
} else if (raw.videoMessage) {
|
|
740
|
+
header.videoMessage = raw.videoMessage;
|
|
741
|
+
header.hasMediaAttachment = true;
|
|
742
|
+
} else if (raw.documentMessage) {
|
|
743
|
+
header.documentMessage = raw.documentMessage;
|
|
744
|
+
header.hasMediaAttachment = true;
|
|
745
|
+
}
|
|
746
|
+
if (header.title || header.hasMediaAttachment) interactiveMessage.header = header;
|
|
747
|
+
if (raw.contextInfo?.mentionedJid?.length) {
|
|
748
|
+
interactiveMessage.contextInfo = { mentionedJid: raw.contextInfo.mentionedJid };
|
|
749
|
+
}
|
|
750
|
+
m = { interactiveMessage };
|
|
751
|
+
} else {
|
|
668
752
|
if (!hasHeader) {
|
|
669
753
|
try {
|
|
670
754
|
const media = await prepareWAMessageMedia({ image: BUTTONS_INVISIBLE_PNG() }, options)
|
|
@@ -673,6 +757,7 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
673
757
|
} catch { /* upload failed — send as-is */ }
|
|
674
758
|
}
|
|
675
759
|
m = { buttonsMessage: raw };
|
|
760
|
+
}
|
|
676
761
|
}
|
|
677
762
|
else if ('buttons' in message && !!message.buttons) {
|
|
678
763
|
// PATCH: `buttons` API — HORIZONTAL button row via classic ButtonsMessage
|
|
@@ -722,6 +807,63 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
722
807
|
applyContextInfoAndMentions(interactiveMessage, message);
|
|
723
808
|
m = { interactiveMessage };
|
|
724
809
|
}
|
|
810
|
+
else if (message.buttons.some(b => buildActionFlow(b) || buildButtonSections(b))) {
|
|
811
|
+
// PATCH (1.0.26): a classic ButtonsMessage that MIXES native-flow
|
|
812
|
+
// extras (rows/sections sheet, url/copy/call actions) with a media
|
|
813
|
+
// or location header renders as "version doesn't support it" on
|
|
814
|
+
// current clients (real-device evidence). So when any button
|
|
815
|
+
// carries an extra, the WHOLE message is upgraded to a native-flow
|
|
816
|
+
// interactive card — map/media header + body + footer + every
|
|
817
|
+
// button type (single_select, cta_url, quick_reply) — which modern
|
|
818
|
+
// clients render fully. Plain-only rows keep the classic
|
|
819
|
+
// horizontal ButtonsMessage (that path is proven to render).
|
|
820
|
+
const flowButtons = message.buttons.map(b => {
|
|
821
|
+
const action = buildActionFlow(b);
|
|
822
|
+
if (action) return { name: action.name, buttonParamsJson: JSON.stringify(action.params) };
|
|
823
|
+
const sections = buildButtonSections(b);
|
|
824
|
+
if (sections) return { name: 'single_select', buttonParamsJson: JSON.stringify({ title: b.buttonText?.displayText || b.displayText || 'Menu', sections }) };
|
|
825
|
+
return { name: 'quick_reply', buttonParamsJson: JSON.stringify({ display_text: b.buttonText?.displayText || b.displayText || b.text || '', id: b.buttonId || b.id || b.buttonText?.displayText || '' }) };
|
|
826
|
+
});
|
|
827
|
+
const interactiveMessage = {
|
|
828
|
+
nativeFlowMessage: { buttons: flowButtons, messageParamsJson: '', messageVersion: 1 }
|
|
829
|
+
};
|
|
830
|
+
if ('text' in message) interactiveMessage.body = { text: message.text };
|
|
831
|
+
else if ('caption' in message) interactiveMessage.body = { text: message.caption };
|
|
832
|
+
if ('footer' in message && !!message.footer) interactiveMessage.footer = { text: message.footer };
|
|
833
|
+
const header = {
|
|
834
|
+
title: message.title || (message.caption ? String(message.caption).split('\n')[0].slice(0, 42) : '') || 'Menu',
|
|
835
|
+
subtitle: message.subtitle || '',
|
|
836
|
+
hasMediaAttachment: false
|
|
837
|
+
};
|
|
838
|
+
if ('location' in message && !!message.location) {
|
|
839
|
+
const loc = message.location;
|
|
840
|
+
header.locationMessage = {
|
|
841
|
+
degreesLatitude: loc.degreesLatitude ?? loc.latitude ?? 0,
|
|
842
|
+
degreesLongitude: loc.degreesLongitude ?? loc.longitude ?? 0,
|
|
843
|
+
name: loc.name ?? null,
|
|
844
|
+
address: loc.address ?? null,
|
|
845
|
+
...(loc.jpegThumbnail ? { jpegThumbnail: loc.jpegThumbnail } : {})
|
|
846
|
+
};
|
|
847
|
+
header.hasMediaAttachment = true;
|
|
848
|
+
} else if ('video' in message && !!message.video) {
|
|
849
|
+
const media = await prepareWAMessageMedia({ video: message.video }, options);
|
|
850
|
+
header.videoMessage = media.videoMessage;
|
|
851
|
+
if (message.gifPlayback) header.videoMessage.gifPlayback = true;
|
|
852
|
+
header.hasMediaAttachment = true;
|
|
853
|
+
} else if ('gif' in message && !!message.gif) {
|
|
854
|
+
const media = await prepareWAMessageMedia({ video: message.gif }, options);
|
|
855
|
+
header.videoMessage = media.videoMessage;
|
|
856
|
+
header.videoMessage.gifPlayback = true;
|
|
857
|
+
header.hasMediaAttachment = true;
|
|
858
|
+
} else if ('image' in message && !!message.image) {
|
|
859
|
+
const media = await prepareWAMessageMedia({ image: message.image }, options);
|
|
860
|
+
header.imageMessage = media.imageMessage;
|
|
861
|
+
header.hasMediaAttachment = true;
|
|
862
|
+
}
|
|
863
|
+
if (header.title || header.hasMediaAttachment) interactiveMessage.header = header;
|
|
864
|
+
applyContextInfoAndMentions(interactiveMessage, message);
|
|
865
|
+
m = { interactiveMessage };
|
|
866
|
+
}
|
|
725
867
|
else if ('location' in message && !!message.location) {
|
|
726
868
|
const loc = message.location;
|
|
727
869
|
const buttonsMessage = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ishumdz-bail",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.27",
|
|
4
4
|
"description": "WhatsApp API Modification By Lovely",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"whatsapp",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"prepare": "",
|
|
44
44
|
"preinstall": "node ./engine-requirements.js",
|
|
45
45
|
"release": "release-it",
|
|
46
|
-
"test": "
|
|
46
|
+
"test": "node --test \"test/**/*.test.mjs\""
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
49
|
"@cacheable/node-cache": "^1.4.0",
|