ishumdz-bail 1.0.18 → 1.0.19

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
@@ -416,15 +416,18 @@ await sock.sendMessage(jid, {
416
416
 
417
417
  ## 🔘 Horizontal Buttons (Interactive Messages)
418
418
 
419
- > ⚡ **Fixed in this fork:** classic text-only `buttonsMessage` is rejected by new WhatsApp
420
- > clients ("Your version of WhatsApp doesn't support it"). The `buttons` API now sends
421
- > **native flow (interactiveMessage)** buttons that render on **all modern clients** —
422
- > normal messages, images, videos and GIFs. Location keeps the classic map-card style.
419
+ > ⚡ **How it renders:** the `buttons` API sends the **classic ButtonsMessage** — the
420
+ > only format WhatsApp renders as a true **horizontal button row**. Modern clients
421
+ > render it when the message has a **header** (image / video / GIF / location map-card).
422
+ > A **location header needs no media upload** — coordinates alone give the big map
423
+ > card + horizontal row, and a **custom image or GIF** works with one media upload.
424
+ > Set `{ nativeFlow: true }` for vertical native-flow quick_reply buttons instead.
423
425
 
424
- ### Text + Horizontal Buttons
426
+ ### Text + Horizontal Buttons (location header = zero uploads)
425
427
 
426
428
  ```javascript
427
429
  await sock.sendMessage(jid, {
430
+ location: { degreesLatitude: 9.9312, degreesLongitude: 76.2673 }, // simple map card
428
431
  text: 'Pong 9 Ms ⚡\nDeveloper: ISHAN-X × LOVELY',
429
432
  footer: 'ISHAN-X MD PRO',
430
433
  buttons: [
@@ -434,10 +437,10 @@ await sock.sendMessage(jid, {
434
437
  })
435
438
  ```
436
439
 
437
- ### Image / Video / GIF + Buttons
440
+ ### Custom Pic / GIF + Horizontal Buttons
438
441
 
439
442
  ```javascript
440
- // Image header
443
+ // Image header (one media upload, then horizontal row)
441
444
  await sock.sendMessage(jid, {
442
445
  image: { url: './banner.jpg' },
443
446
  caption: 'Welcome!',
@@ -448,7 +451,7 @@ await sock.sendMessage(jid, {
448
451
  ]
449
452
  })
450
453
 
451
- // GIF header (animated, loops like a GIF)
454
+ // Animated GIF header
452
455
  await sock.sendMessage(jid, {
453
456
  gif: { url: './animation.gif' },
454
457
  caption: 'Live preview!',
@@ -464,7 +467,7 @@ await sock.sendMessage(jid, {
464
467
  })
465
468
  ```
466
469
 
467
- ### Location Map-Card + Buttons (classic style, still renders on new clients)
470
+ ### Location Map-Card + Buttons (custom name/address)
468
471
 
469
472
  ```javascript
470
473
  await sock.sendMessage(jid, {
@@ -476,10 +479,24 @@ await sock.sendMessage(jid, {
476
479
  // jpegThumbnail: buffer — custom map image (optional)
477
480
  },
478
481
  text: 'Pong 9 Ms ⚡',
479
- buttons: [
480
- { buttonText: { displayText: 'menu' }, buttonId: 'menu', type: 1 },
481
- { buttonText: { displayText: 'owner' }, buttonId: 'owner', type: 1 }
482
- ]
482
+ buttons: [ /* ... */ ]
483
+ })
484
+ ```
485
+
486
+ ### Text-only (TEXT header, best-effort) & native flow escape hatch
487
+
488
+ ```javascript
489
+ // text-only: TEXT headerType — some clients still show the row vertically;
490
+ // for a guaranteed horizontal row attach image/gif/location as above.
491
+ await sock.sendMessage(jid, {
492
+ text: 'Pong 9 Ms ⚡', footer: 'ISHAN-X',
493
+ buttons: [ { buttonText: { displayText: 'menu' }, buttonId: 'menu', type: 1 } ]
494
+ })
495
+
496
+ // vertical native-flow quick_reply buttons (renders on all modern clients)
497
+ await sock.sendMessage(jid, {
498
+ text: 'Menu?', nativeFlow: true,
499
+ buttons: [ { buttonText: { displayText: 'menu' }, buttonId: 'menu', type: 1 } ]
483
500
  })
484
501
  ```
485
502
 
@@ -517,6 +517,13 @@ const applyContextInfoAndMentions = (interactiveMessage, message) => {
517
517
  }
518
518
  }
519
519
  }
520
+ // PATCH: 1x1 transparent PNG — text-only buttons attach this as an invisible
521
+ // IMAGE header so modern clients render the horizontal row (classic requires
522
+ // a header), with no map card and no "version doesn't support it" error.
523
+ const BUTTONS_INVISIBLE_PNG = () => Buffer.from(
524
+ 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=',
525
+ 'base64'
526
+ )
520
527
  export const generateWAMessageContent = async (message, options) => {
521
528
  var _a, _b;
522
529
  let m = {};
@@ -589,45 +596,46 @@ export const generateWAMessageContent = async (message, options) => {
589
596
  m = { interactiveMessage };
590
597
  }
591
598
  else if ('buttonsMessage' in message && !!message.buttonsMessage) {
592
- // PATCH: raw buttonsMessage — media/location headers keep classic pass-through
593
- // (new WhatsApp clients still render those fine, e.g. location+menu cards).
594
- // Text-only ButtonsMessage is rejected by new clients ("version doesn't
595
- // support it"), so convert it to interactiveMessage (native flow
596
- // quick_reply buttons) which renders on all modern clients.
597
- const bMsg = message.buttonsMessage;
598
- const hasMediaHeader = !!(bMsg.imageMessage || bMsg.videoMessage || bMsg.documentMessage || bMsg.locationMessage);
599
- if (hasMediaHeader) {
600
- m = { buttonsMessage: proto.Message.ButtonsMessage.create(bMsg) };
601
- } else {
602
- const flowButtons = (bMsg.buttons || []).map(btn => ({
603
- name: 'quick_reply',
604
- buttonParamsJson: JSON.stringify({
605
- display_text: btn.buttonText?.displayText || btn.buttonText || '',
606
- id: btn.buttonId || btn.buttonText?.displayText || ''
607
- })
608
- }));
609
- const interactive = {
610
- nativeFlowMessage: {
611
- buttons: flowButtons,
612
- messageParamsJson: '',
613
- messageVersion: 1
614
- },
615
- body: { text: bMsg.contentText || bMsg.text || '' },
616
- footer: bMsg.footerText ? { text: bMsg.footerText } : undefined
617
- };
618
- applyContextInfoAndMentions(interactive, { contextInfo: bMsg.contextInfo });
619
- m = { interactiveMessage: interactive };
620
- }
599
+ // PATCH: raw buttonsMessage — always classic pass-through. Modern clients
600
+ // render the horizontal row when a header exists (image/video/document/
601
+ // location) or when a thumbnail header is attached; text-only without any
602
+ // header is the "version doesn't support it" case. Add a header in that
603
+ // situation, or use the `buttons` API which auto-adds one.
604
+ m = { buttonsMessage: proto.Message.ButtonsMessage.create(message.buttonsMessage) };
621
605
  }
622
606
  else if ('buttons' in message && !!message.buttons) {
623
- // PATCH: `buttons` API — text/caption/img/video builds interactiveMessage
624
- // (native flow) so the horizontal button row renders on ALL modern
625
- // WhatsApp clients (classic text-only buttonsMessage is rejected by new
626
- // clients: "version doesn't support it").
627
- // `location` keeps the classic map-card style (LOCATION header 6) —
628
- // big map header + title + body + horizontal buttons below, still
629
- // rendered by modern clients.
630
- if ('location' in message && !!message.location) {
607
+ // PATCH: `buttons` API — HORIZONTAL button row via classic ButtonsMessage
608
+ // with a header (modern clients only render classic horizontal buttons
609
+ // when a header exists: image/video/gif/location, or an embedded
610
+ // thumbnail for text-only). Set { nativeFlow: true } to opt out and get
611
+ // vertical native-flow quick_reply buttons instead.
612
+ if (message.nativeFlow === true) {
613
+ const flowButtons = message.buttons.map(b => ({
614
+ name: 'quick_reply',
615
+ buttonParamsJson: JSON.stringify({
616
+ display_text: b.buttonText?.displayText || b.displayText || b.text || '',
617
+ id: b.buttonId || b.id || b.buttonText?.displayText || ''
618
+ })
619
+ }));
620
+ const interactiveMessage = {
621
+ nativeFlowMessage: {
622
+ buttons: flowButtons,
623
+ messageParamsJson: '',
624
+ messageVersion: 1
625
+ }
626
+ };
627
+ if ('text' in message) {
628
+ interactiveMessage.body = { text: message.text };
629
+ } else if ('caption' in message) {
630
+ interactiveMessage.body = { text: message.caption };
631
+ }
632
+ if ('footer' in message && !!message.footer) {
633
+ interactiveMessage.footer = { text: message.footer };
634
+ }
635
+ applyContextInfoAndMentions(interactiveMessage, message);
636
+ m = { interactiveMessage };
637
+ }
638
+ else if ('location' in message && !!message.location) {
631
639
  const loc = message.location;
632
640
  const buttonsMessage = {
633
641
  buttons: message.buttons.map(b => ({ ...b, type: proto.Message.ButtonsMessage.Button.Type.RESPONSE })),
@@ -653,62 +661,58 @@ export const generateWAMessageContent = async (message, options) => {
653
661
  m = { buttonsMessage: proto.Message.ButtonsMessage.create(buttonsMessage) };
654
662
  }
655
663
  else {
656
- const flowButtons = message.buttons.map(b => ({
657
- name: 'quick_reply',
658
- buttonParamsJson: JSON.stringify({
659
- display_text: b.buttonText?.displayText || b.displayText || b.text || '',
660
- id: b.buttonId || b.id || b.buttonText?.displayText || ''
661
- })
662
- }));
663
- const interactiveMessage = {
664
- nativeFlowMessage: {
665
- buttons: flowButtons,
666
- messageParamsJson: '',
667
- messageVersion: 1
668
- }
664
+ const buttonsMessage = {
665
+ buttons: message.buttons.map(b => ({ ...b, type: proto.Message.ButtonsMessage.Button.Type.RESPONSE }))
669
666
  };
670
- if ('text' in message) {
671
- interactiveMessage.body = { text: message.text };
672
- } else if ('caption' in message) {
673
- interactiveMessage.body = { text: message.caption };
667
+ if ('footer' in message && !!message.footer) {
668
+ buttonsMessage.footerText = message.footer;
674
669
  }
675
- if ('title' in message && !!message.title) {
676
- interactiveMessage.header = {
677
- title: message.title,
678
- subtitle: message.subtitle || '',
679
- hasMediaAttachment: false
670
+ if (message.contextInfo || message.mentions) {
671
+ buttonsMessage.contextInfo = {
672
+ ...(message.contextInfo || {}),
673
+ ...(message.mentions ? { mentionedJid: message.mentions } : {})
680
674
  };
681
675
  }
682
676
  if ('video' in message && !!message.video) {
683
677
  const media = await prepareWAMessageMedia({ video: message.video }, options);
684
- interactiveMessage.header = {
685
- ...(interactiveMessage.header || {}),
686
- videoMessage: media.videoMessage,
687
- hasMediaAttachment: true
688
- };
689
- if (message.gifPlayback) interactiveMessage.header.videoMessage.gifPlayback = true;
678
+ buttonsMessage.videoMessage = media.videoMessage;
679
+ if (message.gifPlayback) buttonsMessage.videoMessage.gifPlayback = true;
680
+ buttonsMessage.headerType = ButtonType.VIDEO;
690
681
  } else if ('gif' in message && !!message.gif) {
691
- // PATCH: direct `gif` key — animated GIF header (video with gifPlayback)
692
682
  const media = await prepareWAMessageMedia({ video: message.gif }, options);
693
- interactiveMessage.header = {
694
- ...(interactiveMessage.header || {}),
695
- videoMessage: media.videoMessage,
696
- hasMediaAttachment: true
697
- };
698
- interactiveMessage.header.videoMessage.gifPlayback = true;
683
+ buttonsMessage.videoMessage = media.videoMessage;
684
+ buttonsMessage.videoMessage.gifPlayback = true;
685
+ buttonsMessage.headerType = ButtonType.VIDEO;
699
686
  } else if ('image' in message && !!message.image) {
700
687
  const media = await prepareWAMessageMedia({ image: message.image }, options);
701
- interactiveMessage.header = {
702
- ...(interactiveMessage.header || {}),
703
- imageMessage: media.imageMessage,
704
- hasMediaAttachment: true
705
- };
688
+ buttonsMessage.imageMessage = media.imageMessage;
689
+ buttonsMessage.headerType = ButtonType.IMAGE;
690
+ } else {
691
+ if ('text' in message || 'caption' in message) {
692
+ const body = message.text ?? message.caption;
693
+ buttonsMessage.contentText = body;
694
+ // PATCH: text-only — invisible 1x1 PNG header so the horizontal
695
+ // row renders on modern clients without a map card and without
696
+ // the "doesn't support it" error. Upload failure falls back to
697
+ // the TEXT header (may render vertical, still no error).
698
+ try {
699
+ const media = await prepareWAMessageMedia({ image: BUTTONS_INVISIBLE_PNG() }, options);
700
+ buttonsMessage.imageMessage = media.imageMessage;
701
+ buttonsMessage.headerType = ButtonType.IMAGE;
702
+ } catch {
703
+ buttonsMessage.text = (message.title || String(body).split('\n')[0] || '').slice(0, 60);
704
+ buttonsMessage.headerType = ButtonType.TEXT;
705
+ }
706
+ } else {
707
+ buttonsMessage.headerType = ButtonType.EMPTY;
708
+ }
706
709
  }
707
- if ('footer' in message && !!message.footer) {
708
- interactiveMessage.footer = { text: message.footer };
710
+ if ('text' in message && (buttonsMessage.videoMessage || buttonsMessage.imageMessage)) {
711
+ // media header already carries the caption
712
+ if (buttonsMessage.videoMessage && 'caption' in message) buttonsMessage.videoMessage.caption = message.caption;
713
+ if (buttonsMessage.imageMessage && 'caption' in message) buttonsMessage.imageMessage.caption = message.caption;
709
714
  }
710
- applyContextInfoAndMentions(interactiveMessage, message);
711
- m = { interactiveMessage };
715
+ m = { buttonsMessage: proto.Message.ButtonsMessage.create(buttonsMessage) };
712
716
  }
713
717
  }
714
718
  else if (hasNonNullishProperty(message, 'sections') || hasNonNullishProperty(message, 'productList')) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ishumdz-bail",
3
- "version": "1.0.18",
3
+ "version": "1.0.19",
4
4
  "description": "WhatsApp API Modification By Lovely",
5
5
  "keywords": [
6
6
  "whatsapp",