@vanzxy/baileys 1.4.4 → 1.4.6

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.
@@ -61,7 +61,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
61
61
  var _a, _Button_client, _Button_validateAgainstSchema, _ButtonV2_client, _Carousel_client, _Poll_client, _AIRich_client;
62
62
  Object.defineProperty(exports, "__esModule", { value: true });
63
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';
64
+ const MESSAGE_BUILDER_VERSION = '4.8';
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");
@@ -1736,6 +1736,11 @@ class AIRich extends BaseBuilder {
1736
1736
  status: data.status ?? 'IN_PROGRESS',
1737
1737
  __typename: 'GenAITaskPrimitive',
1738
1738
  }));
1739
+ // Safety net: stock WA client doesn't render this primitive visibly.
1740
+ if (data.textFallback !== false) {
1741
+ const fallbackText = data.subtitle ? `${data.title} — ${data.subtitle}` : data.title;
1742
+ this._sections.push(AIRich.newLayout('Single', { text: `Tugas: ${fallbackText}`, __typename: 'FOATextPrimitive' }));
1743
+ }
1739
1744
  return this;
1740
1745
  }
1741
1746
  addProgressStatus(title, { icon = 'SEARCH', is_in_progress = true, target_secondary_screen_id, target_secondary_screen_tab_id } = {}) {
@@ -2594,6 +2599,69 @@ class AIRich extends BaseBuilder {
2594
2599
  unified_rows,
2595
2600
  };
2596
2601
  }
2602
+ addGenerating({ imagine_type = 'IMAGE', estimated_completion_time, textFallback = true } = {}) {
2603
+ this._submessages.push({ messageType: 2, messageText: '[ Sedang diproses... ]' });
2604
+ this._sections.push(AIRich.newLayout('Single', {
2605
+ media: { url: '', mime_type: imagine_type === 'ANIMATE' ? 'video/mp4' : 'image/png' },
2606
+ imagine_type,
2607
+ status: {
2608
+ status: 'GENERATING',
2609
+ estimated_completion_time: estimated_completion_time ?? Math.floor(Date.now() / 1000) + 30,
2610
+ },
2611
+ __typename: 'GenAIImaginePrimitive',
2612
+ }));
2613
+ // Vanz@Fix 23-08-26 (v4.8) --- instant FOATextPrimitive fallback instead of
2614
+ // relying on WA's own generation-timeout text. Set { textFallback: false } to skip.
2615
+ if (textFallback) {
2616
+ this._sections.push(AIRich.newLayout('Single', { text: '[ Sedang diproses... ]', __typename: 'FOATextPrimitive' }));
2617
+ }
2618
+ return this;
2619
+ }
2620
+ static async sendSupportPayload(client, jid, text, { ticketId = crypto_1.default.randomUUID(), isAiMessage = true, shouldShowSystemMessage = true, version = 1 } = {}) {
2621
+ if (!client) throw new Error('Socket is required');
2622
+ if (typeof text !== 'string' || !text) throw new TypeError('sendSupportPayload(client, jid, text) requires a non-empty string text');
2623
+ const msg = {
2624
+ conversation: text,
2625
+ messageContextInfo: {
2626
+ messageSecret: crypto_1.default.randomBytes(32),
2627
+ supportPayload: JSON.stringify({
2628
+ version,
2629
+ is_ai_message: isAiMessage,
2630
+ should_show_system_message: shouldShowSystemMessage,
2631
+ ticket_id: ticketId,
2632
+ }),
2633
+ },
2634
+ };
2635
+ return client.relayMessage(jid, msg, {
2636
+ additionalNodes: [
2637
+ { tag: 'bot', attrs: { biz_bot: '1' } },
2638
+ { tag: 'biz', attrs: {} },
2639
+ ],
2640
+ });
2641
+ }
2642
+ static async sendPairedMedia(client, jid, { image, video } = {}) {
2643
+ if (!client) throw new Error('Socket is required');
2644
+ if (!image || !video) throw new TypeError('sendPairedMedia() requires both "image" and "video"');
2645
+ const imagePrepared = await (0, messages_js_1.prepareWAMessageMedia)({ image: typeof image === 'string' ? { url: image } : image }, { upload: client.waUploadToServer });
2646
+ const videoPrepared = await (0, messages_js_1.prepareWAMessageMedia)({ video: typeof video === 'string' ? { url: video } : video }, { upload: client.waUploadToServer });
2647
+ const imageMsg = (0, messages_js_1.generateWAMessageFromContent)(jid, {
2648
+ imageMessage: {
2649
+ ...imagePrepared.imageMessage,
2650
+ contextInfo: { pairedMediaType: 5, statusSourceType: 0 },
2651
+ },
2652
+ }, {});
2653
+ await client.relayMessage(jid, imageMsg.message, { messageId: imageMsg.key.id });
2654
+ await client.relayMessage(jid, {
2655
+ videoMessage: {
2656
+ ...videoPrepared.videoMessage,
2657
+ contextInfo: { pairedMediaType: 6, statusSourceType: 0 },
2658
+ },
2659
+ messageContextInfo: {
2660
+ messageAssociation: { associationType: 12, parentMessageKey: imageMsg.key },
2661
+ },
2662
+ }, {});
2663
+ return imageMsg.key;
2664
+ }
2597
2665
  static newLayout(name, data, extra = {}) {
2598
2666
  return {
2599
2667
  ...extra,
@@ -166,7 +166,8 @@ const FLOWS_MAP = {
166
166
  authentication_button: true,
167
167
  cta_reminder: true,
168
168
  cta_cancel_reminder: true,
169
- single_select: true,
169
+ // Vanz@Fix (single_select never renders alone) --- see ESM copy for full note.
170
+ // Removed on purpose so single_select always falls through to the mixed-flow branch.
170
171
  };
171
172
  const DECISION_SOURCE_CONTENT = [
172
173
  {
@@ -170,7 +170,7 @@ export class AIRich extends BaseBuilder {
170
170
  /** GenAILatexUXPrimitive — has a real AI_RICH_RESPONSE_LATEX submessage (unlike most primitives here). */
171
171
  addLatex(expression: string): this;
172
172
  /** GenAITaskPrimitive — task/checklist card. */
173
- addTask(data: { task_id?: string; title: string; subtitle?: string; status?: string }): this;
173
+ addTask(data: { task_id?: string; title: string; subtitle?: string; status?: string; textFallback?: boolean }): this;
174
174
  /** GenAIBotProgressStatusPrimitive — one-shot "searching/working" status chip. */
175
175
  addProgressStatus(title: string, options?: { icon?: string; is_in_progress?: boolean; target_secondary_screen_id?: string; target_secondary_screen_tab_id?: string }): this;
176
176
  /** GenAIBotThinkingStatusPrimitive — one-shot "thinking" status chip. */
@@ -180,12 +180,18 @@ export class AIRich extends BaseBuilder {
180
180
  /** FOABloksPrimitive — raw Bloks payload; most experimental primitive, fields passed through as-is. */
181
181
  addBloks(data: { type: string; data?: string; uuid?: string; initial_response?: any; versioning_id?: string; textFallback?: boolean }): this;
182
182
  addSuggest(suggestion: Record<string, any>, options?: { scroll?: boolean; layout?: string }): this;
183
+ /** GenAIImaginePrimitive with status GENERATING — pending-generation placeholder, distinct from addImage()/addVideo()'s READY status. */
184
+ addGenerating(options?: { imagine_type?: 'IMAGE' | 'ANIMATE'; estimated_completion_time?: number; textFallback?: boolean }): this;
183
185
  build(): Record<string, any>;
184
186
  send(jid: string, options?: Record<string, any>): Promise<any>;
185
187
 
186
188
  static tokenizer(code: string, lang?: string): Record<string, any>;
187
189
  static toTableMetadata(arr: string[][], options?: AddTextOptions): Record<string, any>;
188
190
  static newLayout(name: string, data: Record<string, any> | Record<string, any>[], extra?: Record<string, any>): Record<string, any>;
191
+ /** Send a support-ticket marker message (messageContextInfo.supportPayload). */
192
+ static sendSupportPayload(client: any, jid: string, text: string, options?: { ticketId?: string; isAiMessage?: boolean; shouldShowSystemMessage?: boolean; version?: number }): Promise<any>;
193
+ /** Send an image + video as one paired-media unit (messageAssociation). */
194
+ static sendPairedMedia(client: any, jid: string, media: { image: string | Buffer; video: string | Buffer }): Promise<any>;
189
195
  }
190
196
 
191
197
  // Same class as AIRich — exported under alternate names (see Vanz@Alias in
@@ -10,6 +10,12 @@
10
10
  * and message-authenticity fields backported from arslan-baileys 1.1.0 and
11
11
  * this project's own rich-message-utils.js. See changes tagged "Vanz@" below.
12
12
  *
13
+ * Vanz@Fix 23-08-26 --- v4.7 -> v4.8. addGenerating() now defaults to appending a
14
+ * FOATextPrimitive text fallback ('[ Sedang diproses... ]'), same pattern as
15
+ * addTask/addThinkingStatus/addBloks. Previously the card had no client-visible
16
+ * content until WA's own timeout swapped it for its built-in failed-generation
17
+ * text; this makes the fallback instant. Opt out with { textFallback: false }.
18
+ *
13
19
  * Vanz@Merge 22-08-26 --- v4.6 -> v4.7. Button class hardened + extended:
14
20
  * - Bug fix: addCall() wrote its second arg into buttonParamsJson.id, but
15
21
  * the cta_call native-flow schema keys on `phone_number` (id is ignored
@@ -38,7 +44,7 @@
38
44
 
39
45
  'use strict';
40
46
 
41
- const MESSAGE_BUILDER_VERSION = '4.7';
47
+ const MESSAGE_BUILDER_VERSION = '4.8';
42
48
 
43
49
  import { generateWAMessageFromContent, prepareWAMessageMedia } from './messages.js';
44
50
  import { botMetadataSignature, botMetadataCertificate } from './rich-message-utils.js';
@@ -2308,6 +2314,13 @@ class AIRich extends BaseBuilder {
2308
2314
  __typename: 'GenAITaskPrimitive',
2309
2315
  })
2310
2316
  );
2317
+ // Safety net: GenAITaskPrimitive is a custom AI-only component the stock WA client
2318
+ // doesn't render visibly. Append a plain text section so the task is still visible.
2319
+ // Set data.textFallback = false to skip.
2320
+ if (data.textFallback !== false) {
2321
+ const fallbackText = data.subtitle ? `${data.title} — ${data.subtitle}` : data.title;
2322
+ this._sections.push(AIRich.newLayout('Single', { text: `Tugas: ${fallbackText}`, __typename: 'FOATextPrimitive' }));
2323
+ }
2311
2324
  return this;
2312
2325
  }
2313
2326
 
@@ -3275,6 +3288,119 @@ class AIRich extends BaseBuilder {
3275
3288
  };
3276
3289
  }
3277
3290
 
3291
+ /**
3292
+ * Add an "AI is generating..." placeholder card (`GenAIImaginePrimitive` with status
3293
+ * GENERATING) — distinct from addImage()/addVideo() which always send status READY.
3294
+ * Use this to show a pending-generation state before the real media is ready.
3295
+ * @param {{ imagine_type?: 'IMAGE'|'ANIMATE', estimated_completion_time?: number }} [options]
3296
+ */
3297
+ addGenerating({ imagine_type = 'IMAGE', estimated_completion_time, textFallback = true } = {}) {
3298
+ this._submessages.push({ messageType: 2, messageText: '[ Sedang diproses... ]' });
3299
+ this._sections.push(
3300
+ AIRich.newLayout('Single', {
3301
+ media: { url: '', mime_type: imagine_type === 'ANIMATE' ? 'video/mp4' : 'image/png' },
3302
+ imagine_type,
3303
+ status: {
3304
+ status: 'GENERATING',
3305
+ estimated_completion_time: estimated_completion_time ?? Math.floor(Date.now() / 1000) + 30,
3306
+ },
3307
+ __typename: 'GenAIImaginePrimitive',
3308
+ })
3309
+ );
3310
+ // Vanz@Fix 23-08-26 (v4.8) --- media.url kosong + status GENERATING gak punya renderer
3311
+ // visual instan di stock WA client; sebelumnya cuma diem sampe WA nge-timeout sendiri
3312
+ // dan nampilin fallback bawaannya ("Saat ini, saya tidak bisa membuat gambar itu...").
3313
+ // Same fix class kayak addTask/addBloks: append FOATextPrimitive biar ada fallback
3314
+ // instan, gak perlu nunggu timeout WA. Set { textFallback: false } buat skip.
3315
+ if (textFallback) {
3316
+ this._sections.push(AIRich.newLayout('Single', { text: '[ Sedang diproses... ]', __typename: 'FOATextPrimitive' }));
3317
+ }
3318
+ return this;
3319
+ }
3320
+
3321
+ /**
3322
+ * Send a support-ticket marker message (`messageContextInfo.supportPayload`) — a plain
3323
+ * conversation message tagged as an AI/support-bot ticket, distinct from richResponseMessage.
3324
+ * @param {import('../../WAProto/index.js').WASocket} client
3325
+ * @param {string} jid
3326
+ * @param {string} text
3327
+ * @param {{ ticketId?: string, isAiMessage?: boolean, shouldShowSystemMessage?: boolean, version?: number }} [options]
3328
+ */
3329
+ static async sendSupportPayload(client, jid, text, { ticketId = crypto.randomUUID(), isAiMessage = true, shouldShowSystemMessage = true, version = 1 } = {}) {
3330
+ if (!client) throw new Error('Socket is required');
3331
+ if (typeof text !== 'string' || !text) throw new TypeError('sendSupportPayload(client, jid, text) requires a non-empty string text');
3332
+
3333
+ const msg = {
3334
+ conversation: text,
3335
+ messageContextInfo: {
3336
+ messageSecret: crypto.randomBytes(32),
3337
+ supportPayload: JSON.stringify({
3338
+ version,
3339
+ is_ai_message: isAiMessage,
3340
+ should_show_system_message: shouldShowSystemMessage,
3341
+ ticket_id: ticketId,
3342
+ }),
3343
+ },
3344
+ };
3345
+
3346
+ return client.relayMessage(jid, msg, {
3347
+ additionalNodes: [
3348
+ { tag: 'bot', attrs: { biz_bot: '1' } },
3349
+ { tag: 'biz', attrs: {} },
3350
+ ],
3351
+ });
3352
+ }
3353
+
3354
+ /**
3355
+ * Send an image and video as one paired-media unit (image sent first, video linked to it via
3356
+ * `messageAssociation`). Distinct from a plain album — the client treats them as a single group.
3357
+ * @param {import('../../WAProto/index.js').WASocket} client
3358
+ * @param {string} jid
3359
+ * @param {{ image: string|Buffer, video: string|Buffer }} media
3360
+ */
3361
+ static async sendPairedMedia(client, jid, { image, video } = {}) {
3362
+ if (!client) throw new Error('Socket is required');
3363
+ if (!image || !video) throw new TypeError('sendPairedMedia() requires both "image" and "video"');
3364
+
3365
+ const imagePrepared = await prepareWAMessageMedia(
3366
+ { image: typeof image === 'string' ? { url: image } : image },
3367
+ { upload: client.waUploadToServer }
3368
+ );
3369
+ const videoPrepared = await prepareWAMessageMedia(
3370
+ { video: typeof video === 'string' ? { url: video } : video },
3371
+ { upload: client.waUploadToServer }
3372
+ );
3373
+
3374
+ const imageMsg = generateWAMessageFromContent(
3375
+ jid,
3376
+ {
3377
+ imageMessage: {
3378
+ ...imagePrepared.imageMessage,
3379
+ contextInfo: { pairedMediaType: 5, statusSourceType: 0 },
3380
+ },
3381
+ },
3382
+ {}
3383
+ );
3384
+
3385
+ await client.relayMessage(jid, imageMsg.message, { messageId: imageMsg.key.id });
3386
+
3387
+ await client.relayMessage(
3388
+ jid,
3389
+ {
3390
+ videoMessage: {
3391
+ ...videoPrepared.videoMessage,
3392
+ contextInfo: { pairedMediaType: 6, statusSourceType: 0 },
3393
+ },
3394
+ messageContextInfo: {
3395
+ messageAssociation: { associationType: 12, parentMessageKey: imageMsg.key },
3396
+ },
3397
+ },
3398
+ {}
3399
+ );
3400
+
3401
+ return imageMsg.key;
3402
+ }
3403
+
3278
3404
  /** Build a raw submessage layout block by name — escape hatch for layouts not covered by the add*() helpers. */
3279
3405
  static newLayout(name, data, extra = {}) {
3280
3406
  return {
@@ -153,7 +153,14 @@ const FLOWS_MAP = {
153
153
  authentication_button: true,
154
154
  cta_reminder: true,
155
155
  cta_cancel_reminder: true,
156
- single_select: true,
156
+ // Vanz@Fix (single_select never renders alone) --- single_select must NEVER get
157
+ // its own dedicated native_flow node here. WhatsApp only renders a single_select
158
+ // button through the generic <native_flow v='9' name='mixed'> node — the same one
159
+ // used when it's combined with other buttons. Giving it a dedicated
160
+ // <native_flow v='2' name='single_select'> node (like the other FLOWS_MAP entries)
161
+ // silently fails to render client-side, whether single_select is alone or is simply
162
+ // the first button in the array. Removed from this map on purpose so it always
163
+ // falls through to the `flowMsg` mixed-flow branch below.
157
164
  };
158
165
  const DECISION_SOURCE_CONTENT = [
159
166
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vanzxy/baileys",
3
- "version": "1.4.4",
3
+ "version": "1.4.6",
4
4
  "description": "Enhanced Baileys fork by Vanzxy — based on @itsliaaa/baileys + @whiskeysockets/baileys with fixes for audio group status and clean media without newsletter button.",
5
5
  "type": "module",
6
6
  "main": "./cjs/lib/index.js",