@pontalabs/baileys 1.2.3 → 1.2.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/README.md CHANGED
@@ -621,7 +621,7 @@ await sock.sendMessage(jid, {
621
621
 
622
622
  Urutannya menjadi `Build 1 → tunggu 1 detik → Build 2 → tunggu 1 detik → Build 3`.
623
623
 
624
- Tanpa `buildDelay`, perilaku `items` lama tetap dipakai: semua item digabung menjadi **satu Rich AI message**.
624
+ Tanpa `buildDelay`, item Rich AI tetap digabung menjadi **satu Rich AI message**. Jika `items` berisi `build.button()`, `build.buttonV2()`, atau `build.carousel()`, item interactive dikirim sebagai message native-flow tersendiri karena bukan Rich AI primitive.
625
625
 
626
626
  > `buildDelay` hanya berlaku untuk `items`. Nilai dalam milidetik harus lebih besar dari `0`.
627
627
 
@@ -629,6 +629,9 @@ Tanpa `buildDelay`, perilaku `items` lama tetap dipakai: semua item digabung men
629
629
 
630
630
  | Factory | Contoh | Hasil |
631
631
  | --- | --- | --- |
632
+ | `build.button()` | `build.button().addReply('OK', 'ok')` | Native Flow buttons |
633
+ | `build.buttonV2()` | `build.buttonV2().addButton('OK')` | Buttons V2 |
634
+ | `build.carousel()` | `build.carousel().addCard(card)` | Interactive carousel |
632
635
  | `build.richText(text)` | `build.richText('Halo')` | Text |
633
636
  | `build.richFOAText(text)` | `build.richFOAText('Halo')` | FOA text |
634
637
  | `build.richHtml(html)` | `build.richHtml('<html>...</html>')` | HTML WebView |
@@ -646,6 +649,105 @@ Tanpa `buildDelay`, perilaku `items` lama tetap dipakai: semua item digabung men
646
649
  | `build.richFooterAction(data)` | `build.richFooterAction({...})` | Footer action |
647
650
  | `build.richSuggest(value)` | `build.richSuggest('Lanjutkan')` | Suggestion |
648
651
 
652
+ #### 🧩 Interactive Builder — Button, ButtonV2 & Carousel
653
+
654
+ Builder interactive dari `mbuilder.js` juga tersedia langsung di namespace `build` dan **tidak membutuhkan `sock` saat dibuat**. Pesannya tetap dikirim melalui `sock.sendMessage()`.
655
+
656
+ ##### Native Flow — `build.button()`
657
+
658
+ ```js
659
+ const button = build.button()
660
+ .setTitle('Menu')
661
+ .setBody('Pilih salah satu')
662
+ .setFooter('PontaLabs')
663
+ .addReply('Halo', 'hello')
664
+ .addUrl('Website', 'https://example.com')
665
+ .addCopy('Copy ID', 'ABC123')
666
+
667
+ await sock.sendMessage(jid, {
668
+ items: [button]
669
+ })
670
+ ```
671
+
672
+ Semua method `Button` dari builder asli tetap tersedia, termasuk:
673
+
674
+ - `setTitle()` / `setSubtitle()` / `setBody()` / `setFooter()`
675
+ - `setContextInfo()` / `addPayload()`
676
+ - `setImage()` / `setDocument()` / `setMedia()`
677
+ - `clearButtons()` / `setParams()` / `addButton()`
678
+ - `addSelection()` / `makeSection()` / `makeRow()`
679
+ - `addReply()` / `addCall()` / `addReminder()` / `addCancelReminder()`
680
+ - `addAddress()` / `addLocation()` / `addUrl()` / `addCopy()`
681
+
682
+ ##### ButtonV2 — `build.buttonV2()`
683
+
684
+ ```js
685
+ const buttons = build.buttonV2()
686
+ .setBody('Pilih aksi')
687
+ .setFooter('PontaLabs')
688
+ .addButton('Yes')
689
+ .addButton('No')
690
+
691
+ await sock.sendMessage(jid, {
692
+ items: [buttons]
693
+ })
694
+ ```
695
+
696
+ Method yang tersedia dari `ButtonV2` antara lain `addButton()`, `addRawButton()`, `setRawThumbnail()`, `setThumbnail()`, `setMedia()`, serta semua setter dari `BaseBuilder`.
697
+
698
+ ##### Carousel — `build.carousel()`
699
+
700
+ ```js
701
+ const carousel = build.carousel()
702
+ .setBody('Pilih produk')
703
+ .setFooter('PontaLabs')
704
+ .addCard({
705
+ header: {
706
+ hasMediaAttachment: true,
707
+ imageMessage: imageMessage
708
+ },
709
+ body: { text: 'Produk A' },
710
+ footer: { text: 'Rp 10.000' },
711
+ nativeFlowMessage: {
712
+ messageParamsJson: '{}',
713
+ buttons: [{
714
+ name: 'quick_reply',
715
+ buttonParamsJson: JSON.stringify({
716
+ display_text: 'Pilih',
717
+ id: 'product_a'
718
+ })
719
+ }]
720
+ }
721
+ })
722
+
723
+ await sock.sendMessage(jid, {
724
+ items: [carousel]
725
+ })
726
+ ```
727
+
728
+ `addCard()` menerima satu card atau array card. Card harus memiliki `header.hasMediaAttachment = true`, sama seperti builder aslinya.
729
+
730
+ ##### ⏱️ Interactive + `buildDelay`
731
+
732
+ Semua builder dapat dicampur. Jika `buildDelay` dipasang, setiap item dikirim sebagai pesan terpisah dengan jeda yang sama, termasuk Button, ButtonV2, Carousel, dan Rich AI:
733
+
734
+ ```js
735
+ await sock.sendMessage(jid, {
736
+ items: [
737
+ build.richText('Halo 👋'),
738
+ build.button().addReply('Lanjut', 'next'),
739
+ build.richHtml('<h1>WebView</h1>'),
740
+ build.buttonV2().addButton('OK'),
741
+ build.carousel().addCard(card)
742
+ ],
743
+ buildDelay: 5000
744
+ })
745
+ ```
746
+
747
+ Hasilnya: `Text → 5 detik → Button → 5 detik → WebView → 5 detik → ButtonV2 → 5 detik → Carousel`.
748
+
749
+ > `build.button()`, `build.buttonV2()`, dan `build.carousel()` adalah payload builders. Tidak perlu `send()` dan tidak perlu memasukkan `sock` ke factory. `sock.sendMessage()` tetap menjadi jalur pengiriman utama.
750
+
649
751
  #### 🧩 Campur dengan shortcut lama
650
752
 
651
753
  API lama **tetap dipertahankan**. Builder bisa dicampur dengan object Rich AI biasa di `items`.
@@ -14,6 +14,7 @@ import { USyncQuery, USyncUser } from '../WAUSync/index.js';
14
14
  import { makeNewsletterSocket } from './newsletter.js';
15
15
  import kikyy from './dugong.js';
16
16
  import { generateTableContent, generateTableContentV2, generateListContent, generateCodeBlockContent, generateCodeBlockContentV2, generateLinkContent, generateLinkContentV2, generateRichMessageContent, generateUnifiedResponseContent, captureUnifiedResponse, generateLatexContent, generateLatexImageContent, generateLatexInlineImageContent } from '../Utils/rich-message-utils.js';
17
+ import { Button, ButtonV2, Carousel } from '../Utils/mbuilder.js';
17
18
  export const makeMessagesSocket = (config) => {
18
19
  const { logger, linkPreviewImageThumbnailWidth, generateHighQualityLinkPreview, options: httpRequestOptions, patchMessageBeforeSending, cachedGroupMetadata, enableRecentMessageCache, maxMsgRetryCount } = config;
19
20
  const sock = makeNewsletterSocket(config);
@@ -1132,18 +1133,66 @@ export const makeMessagesSocket = (config) => {
1132
1133
  sendMessage: sendMessageImpl = async (jid, content, options = {}) => {
1133
1134
  const userJid = authState.creds.me.id;
1134
1135
 
1135
- // `buildDelay` sends each item in `content.items` as its own Rich AI
1136
- // message, waiting between items. Without buildDelay, the existing
1137
- // mixed-items behavior is unchanged (all items are one Rich AI message).
1138
- if (content && !Array.isArray(jid) && Array.isArray(content.items) && content.items.length > 1) {
1136
+ // `items` may contain Rich AI build descriptors as well as the
1137
+ // interactive builders exported by mbuilder.js. Rich AI items can
1138
+ // stay grouped when no delay is requested; interactive builders
1139
+ // are always sent as their own native-flow message because they
1140
+ // are not valid Rich AI primitives.
1141
+ if (content && !Array.isArray(jid) && Array.isArray(content.items) && content.items.length > 0) {
1142
+ const items = content.items;
1139
1143
  const buildDelay = Number(options.buildDelay ?? content.buildDelay ?? 0);
1140
- if (Number.isFinite(buildDelay) && buildDelay > 0) {
1144
+ const hasDelay = Number.isFinite(buildDelay) && buildDelay > 0;
1145
+ const isInteractiveBuilder = (item) => item instanceof Button || item instanceof ButtonV2 || item instanceof Carousel;
1146
+ const hasInteractiveBuilder = items.some(isInteractiveBuilder);
1147
+
1148
+ if (hasDelay || hasInteractiveBuilder) {
1141
1149
  const sendOptions = { ...options };
1142
1150
  delete sendOptions.buildDelay;
1151
+ delete sendOptions.additionalNodes;
1143
1152
  const results = [];
1144
- for (let index = 0; index < content.items.length; index++) {
1145
- if (index > 0) await delay(buildDelay);
1146
- results.push(await sendMessageImpl(jid, content.items[index], sendOptions));
1153
+
1154
+ const sendInteractiveBuilder = async (builder) => {
1155
+ // Builder instances are intentionally socket-less when
1156
+ // created through build.button()/buttonV2()/carousel().
1157
+ // Bind only the upload capability needed while building
1158
+ // media; the actual send still uses this socket's
1159
+ // relayMessage path, exactly like the native sendMessage
1160
+ // implementation.
1161
+ builder.setClient({ waUploadToServer });
1162
+ const msg = await builder.build(jid, sendOptions);
1163
+ await relayMessage(msg.key.remoteJid, msg.message, {
1164
+ messageId: msg.key.id,
1165
+ additionalNodes: [
1166
+ {
1167
+ tag: 'biz',
1168
+ attrs: {},
1169
+ content: [
1170
+ {
1171
+ tag: 'interactive',
1172
+ attrs: { type: 'native_flow', v: '1' },
1173
+ content: [{ tag: 'native_flow', attrs: { v: '9', name: 'mixed' } }],
1174
+ },
1175
+ ],
1176
+ },
1177
+ ...(options.additionalNodes || []),
1178
+ ],
1179
+ ...sendOptions,
1180
+ });
1181
+ return msg;
1182
+ };
1183
+
1184
+ for (let index = 0; index < items.length; index++) {
1185
+ if (index > 0 && hasDelay) await delay(buildDelay);
1186
+
1187
+ const item = items[index];
1188
+ if (isInteractiveBuilder(item)) {
1189
+ results.push(await sendInteractiveBuilder(item));
1190
+ } else {
1191
+ // Keep the same Rich AI normalization path used by
1192
+ // the regular shortcut, preventing build descriptors
1193
+ // from reaching prepareWAMessageMedia().
1194
+ results.push(await sendMessageImpl(jid, { items: [item] }, sendOptions));
1195
+ }
1147
1196
  }
1148
1197
  return results;
1149
1198
  }
@@ -1,7 +1,7 @@
1
1
  export declare const VERSION: string;
2
- export declare class Button { constructor(client: any, options?: any); loadFrom(data: any): this; build(jid: string, options?: any): any; send(jid: string, options?: any): Promise<any>; [key: string]: any; }
3
- export declare class ButtonV2 { constructor(client: any, options?: any); loadFrom(data: any): this; build(jid: string, options?: any): any; send(jid: string, options?: any): Promise<any>; [key: string]: any; }
4
- export declare class Carousel { constructor(client: any, options?: any); loadFrom(data: any): this; build(jid: string, options?: any): any; send(jid: string, options?: any): Promise<any>; [key: string]: any; }
2
+ export declare class Button { constructor(client?: any, options?: any); loadFrom(data: any): this; build(jid: string, options?: any): any; send(jid: string, options?: any): Promise<any>; [key: string]: any; }
3
+ export declare class ButtonV2 { constructor(client?: any, options?: any); loadFrom(data: any): this; build(jid: string, options?: any): any; send(jid: string, options?: any): Promise<any>; [key: string]: any; }
4
+ export declare class Carousel { constructor(client?: any, options?: any); loadFrom(data: any): this; build(jid: string, options?: any): any; send(jid: string, options?: any): Promise<any>; [key: string]: any; }
5
5
  export declare class AIRich {
6
6
  constructor(client: any, options?: { dynamic?: boolean; unsupportedTypeAlert?: boolean });
7
7
  loadFrom(msg: any): this;
@@ -38,6 +38,12 @@ export declare class AIRich {
38
38
  export declare class Toolkit { [key: string]: any; }
39
39
  export declare const build: {
40
40
  AIRich: (client: any, options?: any) => AIRich;
41
+ button: (client?: any) => Button;
42
+ buttonV2: (client?: any) => ButtonV2;
43
+ carousel: (client?: any) => Carousel;
44
+ Button: (client?: any) => Button;
45
+ ButtonV2: (client?: any) => ButtonV2;
46
+ Carousel: (client?: any) => Carousel;
41
47
  richText: (text: string) => any;
42
48
  richFOAText: (text: string) => any;
43
49
  richHtml: (html: string) => any;
@@ -557,11 +557,8 @@ class BaseBuilder {
557
557
  class Button extends BaseBuilder {
558
558
  #client;
559
559
 
560
- constructor(client) {
560
+ constructor(client = null) {
561
561
  super();
562
- if (!client) {
563
- throw new Error('Socket is required');
564
- }
565
562
  this.#client = client;
566
563
 
567
564
  this._buttons = [];
@@ -571,6 +568,11 @@ class Button extends BaseBuilder {
571
568
  this._params = {};
572
569
  }
573
570
 
571
+ setClient(client) {
572
+ this.#client = client;
573
+ return this;
574
+ }
575
+
574
576
  loadFrom(msg) {
575
577
  if (!msg) throw new Error('interactiveMessage needed');
576
578
  if (!msg.interactiveMessage) throw new Error('interactiveMessage not found');
@@ -891,18 +893,19 @@ class Button extends BaseBuilder {
891
893
  class ButtonV2 extends BaseBuilder {
892
894
  #client;
893
895
 
894
- constructor(client) {
896
+ constructor(client = null) {
895
897
  super();
896
- if (!client) {
897
- throw new Error('Socket is required');
898
- }
899
-
900
898
  this.#client = client;
901
899
  this._image;
902
900
  this._data;
903
901
  this._buttons = [];
904
902
  }
905
903
 
904
+ setClient(client) {
905
+ this.#client = client;
906
+ return this;
907
+ }
908
+
906
909
  loadFrom(msg) {
907
910
  if (!msg) throw new Error('buttonsMessage needed');
908
911
  if (!msg.buttonsMessage) throw new Error('buttonsMessage not found');
@@ -1059,16 +1062,17 @@ class ButtonV2 extends BaseBuilder {
1059
1062
  class Carousel extends BaseBuilder {
1060
1063
  #client;
1061
1064
 
1062
- constructor(client) {
1065
+ constructor(client = null) {
1063
1066
  super();
1064
- if (!client) {
1065
- throw new Error('Socket is required');
1066
- }
1067
-
1068
1067
  this.#client = client;
1069
1068
  this._cards = [];
1070
1069
  }
1071
1070
 
1071
+ setClient(client) {
1072
+ this.#client = client;
1073
+ return this;
1074
+ }
1075
+
1072
1076
  loadFrom(msg) {
1073
1077
  if (!msg) throw new Error('interactiveMessage needed');
1074
1078
  if (!msg.interactiveMessage) throw new Error('interactiveMessage not found');
@@ -3201,6 +3205,13 @@ class AIRich extends BaseBuilder {
3201
3205
  */
3202
3206
  const build = {
3203
3207
  AIRich: (client, options) => new AIRich(client, options),
3208
+ button: (client = null) => new Button(client),
3209
+ buttonV2: (client = null) => new ButtonV2(client),
3210
+ carousel: (client = null) => new Carousel(client),
3211
+ // Class aliases for developers who prefer constructor-style naming.
3212
+ Button: (client = null) => new Button(client),
3213
+ ButtonV2: (client = null) => new ButtonV2(client),
3214
+ Carousel: (client = null) => new Carousel(client),
3204
3215
  richText: (text) => ({ richText: text }),
3205
3216
  richFOAText: (text) => ({ richFOAText: text }),
3206
3217
  richCode: (code, language = 'javascript') => ({ richCode: code, language }),
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pontalabs/baileys",
3
3
  "type": "module",
4
- "version": "1.2.3",
4
+ "version": "1.2.4",
5
5
  "description": "PontaLabs Baileys is a lightweight, modern, and customizable WhatsApp Web API library built on Baileys.",
6
6
  "keywords": [
7
7
  "whatsapp",