ishumdz-bail 1.0.26 → 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 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(native.paramsJson)
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
@@ -654,20 +654,101 @@ export const generateWAMessageContent = async (message, options) => {
654
654
  applyContextInfoAndMentions(interactiveMessage, message);
655
655
  m = { interactiveMessage };
656
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
+ }
657
677
  else if ('buttonsMessage' in message && !!message.buttonsMessage) {
658
678
  // PATCH: raw buttonsMessage — classic pass-through. Modern clients render
659
679
  // the horizontal row only when a header exists (image/video/document/
660
680
  // location). A text-only raw message WITHOUT any header is exactly the
661
681
  // "version doesn't support it" case — so when the caller passed none, we
662
682
  // attach the invisible 1x1 PNG image header automatically (same trick the
663
- // `buttons` API uses) and the row always renders. This is unconditional:
664
- // header-less raw messages can never produce the "not supported" bubble.
683
+ // `buttons` API uses) and the row always renders.
665
684
  const raw = proto.Message.ButtonsMessage.fromObject(message.buttonsMessage)
666
685
  // NOTE: fromObject turns missing fields into null (protobuf defaults), so
667
686
  // a nullish headerType (= caller never set it) counts as "no header" too.
668
687
  const hasHeader = !!(raw.imageMessage || raw.videoMessage || raw.documentMessage ||
669
688
  raw.locationMessage ||
670
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 {
671
752
  if (!hasHeader) {
672
753
  try {
673
754
  const media = await prepareWAMessageMedia({ image: BUTTONS_INVISIBLE_PNG() }, options)
@@ -676,6 +757,7 @@ export const generateWAMessageContent = async (message, options) => {
676
757
  } catch { /* upload failed — send as-is */ }
677
758
  }
678
759
  m = { buttonsMessage: raw };
760
+ }
679
761
  }
680
762
  else if ('buttons' in message && !!message.buttons) {
681
763
  // PATCH: `buttons` API — HORIZONTAL button row via classic ButtonsMessage
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ishumdz-bail",
3
- "version": "1.0.26",
3
+ "version": "1.0.27",
4
4
  "description": "WhatsApp API Modification By Lovely",
5
5
  "keywords": [
6
6
  "whatsapp",