@vanzxy/baileys 1.3.9 → 1.4.0

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.
@@ -738,6 +738,45 @@ class Button extends BaseBuilder {
738
738
  return this;
739
739
  }
740
740
 
741
+ // Vanz@Fix (bug 43) --- paramsList documented the schema for these 3 message-level native flow
742
+ // params (limited_time_offer / bottom_sheet / tap_target_configuration) but no helper ever wrote
743
+ // them into this._params — only manual setParams() could, with zero validation against the
744
+ // documented schema. Added dedicated setters + a lightweight type check reusing paramsList.
745
+ static #validateAgainstSchema(schema, data, label) {
746
+ for (const [key, type] of Object.entries(schema)) {
747
+ if (data[key] === undefined) continue;
748
+ const expectsArray = Array.isArray(type);
749
+ if (expectsArray) {
750
+ if (!Array.isArray(data[key]) || !data[key].every((v) => typeof v === type[0])) {
751
+ throw new TypeError(`${label}.${key} must be an array of ${type[0]}`);
752
+ }
753
+ } else if (typeof data[key] !== type) {
754
+ throw new TypeError(`${label}.${key} must be a ${type}`);
755
+ }
756
+ }
757
+ }
758
+
759
+ setLimitedTimeOffer({ text = '', url = '', copy_code = '', expiration_time } = {}) {
760
+ const data = { text, url, copy_code, expiration_time };
761
+ Button.#validateAgainstSchema(Button.paramsList.limited_time_offer, data, 'limited_time_offer');
762
+ this._params = { ...this._params, limited_time_offer: data };
763
+ return this;
764
+ }
765
+
766
+ setBottomSheet({ in_thread_buttons_limit, divider_indices = [], list_title = '', button_title = '' } = {}) {
767
+ const data = { in_thread_buttons_limit, divider_indices, list_title, button_title };
768
+ Button.#validateAgainstSchema(Button.paramsList.bottom_sheet, data, 'bottom_sheet');
769
+ this._params = { ...this._params, bottom_sheet: data };
770
+ return this;
771
+ }
772
+
773
+ setTapTargetConfiguration({ title = '', description = '', canonical_url = '', domain = '', buttonIndex = 0 } = {}) {
774
+ const data = { title, description, canonical_url, domain, buttonIndex };
775
+ Button.#validateAgainstSchema(Button.paramsList.tap_target_configuration, data, 'tap_target_configuration');
776
+ this._params = { ...this._params, tap_target_configuration: data };
777
+ return this;
778
+ }
779
+
741
780
  static paramsList = {
742
781
  limited_time_offer: {
743
782
  text: 'string',
@@ -1016,6 +1055,11 @@ class AIRich extends BaseBuilder {
1016
1055
  this._submessages = [];
1017
1056
  this._sections = [];
1018
1057
  this._richResponseSources = [];
1058
+ // Vanz@Fix (bug 42 / inline image fallback): WA rejects rendering AIRichResponseInlineImageMetadata
1059
+ // for third-party bots regardless of URL (confirmed empirically — Meta/WA CDN url with valid
1060
+ // mediaKey still doesn't render, so it's a trust-chain gate, not a domain/encoding issue).
1061
+ // Track every addInlineImage() call here so send() can fall back to a normal imageMessage.
1062
+ this._inlineImages = [];
1019
1063
  }
1020
1064
 
1021
1065
  addSubmessage(submessage) {
@@ -1279,6 +1323,66 @@ class AIRich extends BaseBuilder {
1279
1323
  return this;
1280
1324
  }
1281
1325
 
1326
+ // Vanz@Fix 15-08-26 (bug 41) --- addImage() only builds GRID_IMAGE (messageType 1).
1327
+ // There was no helper for standalone INLINE_IMAGE (messageType 3): callers were manually
1328
+ // pushing addSubmessage() (correct proto shape) + addSection() (WRONG shape — reused the
1329
+ // GRID_IMAGE/GenAIImaginePrimitive section schema instead of GenAIInlineImageUXPrimitive),
1330
+ // which broke client-side unifiedResponse rendering even though the submessage itself was fine.
1331
+ // Mirrors RichSubMessageType.INLINE_IMAGE handling in rich-message-utils.js's toUnified().
1332
+ addInlineImage(imageUrl, { text = '', alignment = 'center', tapLinkUrl = '', resolveUrl = false } = {}) {
1333
+ if (!(typeof imageUrl === 'string' || Buffer.isBuffer(imageUrl) || (imageUrl && typeof imageUrl === 'object'))) {
1334
+ throw new TypeError('imageUrl must be string | buffer | { imagePreviewUrl, imageHighResUrl, sourceUrl }');
1335
+ }
1336
+
1337
+ const ALIGNMENT_ENUM = { leading: 0, trailing: 1, center: 2 };
1338
+ const ALIGNMENT_NAME = ['AI_RICH_RESPONSE_IMAGE_LAYOUT_LEADING_ALIGNED', 'AI_RICH_RESPONSE_IMAGE_LAYOUT_TRAILING_ALIGNED', 'AI_RICH_RESPONSE_IMAGE_LAYOUT_CENTER_ALIGNED'];
1339
+ const alignmentNum = typeof alignment === 'number' ? alignment : (ALIGNMENT_ENUM[String(alignment).toLowerCase()] ?? ALIGNMENT_ENUM.center);
1340
+
1341
+ const url =
1342
+ imageUrl && typeof imageUrl === 'object'
1343
+ ? {
1344
+ imagePreviewUrl: imageUrl.imagePreviewUrl || imageUrl.url,
1345
+ imageHighResUrl: imageUrl.imageHighResUrl || imageUrl.url,
1346
+ sourceUrl: imageUrl.sourceUrl || imageUrl.url,
1347
+ }
1348
+ : (() => {
1349
+ const resolved = Toolkit.resolveMedia(this.#client, imageUrl, 'image', { resolveUrl });
1350
+ return { imagePreviewUrl: resolved, imageHighResUrl: resolved, sourceUrl: resolved };
1351
+ })();
1352
+
1353
+ this._submessages.push({
1354
+ messageType: 3,
1355
+ imageMetadata: {
1356
+ imageUrl: url,
1357
+ imageText: text,
1358
+ alignment: alignmentNum,
1359
+ tapLinkUrl,
1360
+ },
1361
+ });
1362
+
1363
+ this._sections.push(
1364
+ AIRich.newLayout('Single', {
1365
+ image_url: {
1366
+ image_preview_url: url.imagePreviewUrl || '',
1367
+ image_high_res_url: url.imageHighResUrl || '',
1368
+ source_url: url.sourceUrl || '',
1369
+ },
1370
+ image_text: text,
1371
+ alignment: ALIGNMENT_NAME[alignmentNum],
1372
+ tap_link_url: tapLinkUrl,
1373
+ __typename: 'GenAIInlineImageUXPrimitive',
1374
+ })
1375
+ );
1376
+
1377
+ // Vanz@Fix (bug 42): stash for the imageMessage fallback in send()
1378
+ this._inlineImages.push({
1379
+ url: url.sourceUrl || url.imageHighResUrl || url.imagePreviewUrl,
1380
+ caption: text || undefined,
1381
+ });
1382
+
1383
+ return this;
1384
+ }
1385
+
1282
1386
  // Vanz@Perf 15-08-26 --- autoFill defaults to false (arslan-baileys behavior): skips the
1283
1387
  // fetch-full-video + ffmpeg-frame-extraction + duration-parse round trip per video, which
1284
1388
  // was the main source of blurose's slower response time. Pass { autoFill: true } to opt
@@ -1564,8 +1668,30 @@ class AIRich extends BaseBuilder {
1564
1668
  };
1565
1669
  }
1566
1670
 
1567
- async send(jid, { forwarded, notification, includesUnifiedResponse, includesSubmessages, ...options } = {}) {
1568
- const msg = await this.build({ forwarded, notification, includesUnifiedResponse, includesSubmessages, ...options });
1671
+ // Vanz@Fix (bug 42 / inline image fallback) --- WA won't render AIRichResponseInlineImageMetadata
1672
+ // for bot-sent messages (confirmed: even a valid WA-CDN url with mediaKey stays blank), so any
1673
+ // image added via addInlineImage() is sent here as a normal imageMessage instead. Pass
1674
+ // { skipImageFallback: true } to opt out and send only the (image-less-looking) rich card.
1675
+ // Vanz@Fix (bug 42 / inline image fallback) --- WA won't render AIRichResponseInlineImageMetadata
1676
+ // for bot-sent messages (confirmed: even a valid WA-CDN url with mediaKey stays blank), so any
1677
+ // image added via addInlineImage() is sent here as a normal imageMessage instead. Pass
1678
+ // { skipImageFallback: true } to opt out and send only the (image-less-looking) rich card.
1679
+ // Vanz@Fix: don't spread relayMessage-shaped `options` into sendMessage()'s options param —
1680
+ // the two calls expect different option shapes, so the fallback now only forwards `quoted`
1681
+ // (the one option that clearly applies to both) instead of blindly spreading everything.
1682
+ async send(jid, { forwarded, notification, includesUnifiedResponse, includesSubmessages, skipImageFallback = false, quoted, ...options } = {}) {
1683
+ const msg = await this.build({ forwarded, notification, includesUnifiedResponse, includesSubmessages, quoted, ...options });
1684
+
1685
+ if (!skipImageFallback && this._inlineImages.length) {
1686
+ for (const { url, caption } of this._inlineImages) {
1687
+ try {
1688
+ await this.#client.sendMessage(jid, { image: { url }, caption }, quoted ? { quoted } : {});
1689
+ } catch (err) {
1690
+ // Vanz@Fix: don't let a fallback image failure block the actual rich card from sending
1691
+ this.#client.logger?.warn?.({ err, url }, 'inline image fallback failed, continuing with rich card');
1692
+ }
1693
+ }
1694
+ }
1569
1695
 
1570
1696
  return await this.#client.relayMessage(jid, msg, { ...options });
1571
1697
  }
@@ -863,10 +863,24 @@ export const generateWAMessageContent = async (message, options) => {
863
863
  return message;
864
864
  }
865
865
  // Lia@Changes 09-04-26 --- Add support for code block and table with richResponseMessage
866
+ // Vanz@Fix (bug 41 / inline image standalone): gate only checked code/links/table/richResponse,
867
+ // so sending { inlineImage } alone (or headerText/contentText/latex/items/etc standalone) never
868
+ // reached prepareRichResponseMessage and silently fell through to another branch. Added every
869
+ // key that prepareRichResponseMessage actually destructures.
866
870
  else if (hasNonNullishProperty(message, 'code') ||
867
871
  hasNonNullishProperty(message, 'links') ||
868
872
  hasNonNullishProperty(message, 'table') ||
869
- hasNonNullishProperty(message, 'richResponse')) {
873
+ hasNonNullishProperty(message, 'richResponse') ||
874
+ hasNonNullishProperty(message, 'inlineImage') ||
875
+ hasNonNullishProperty(message, 'inlineVideo') ||
876
+ hasNonNullishProperty(message, 'headerText') ||
877
+ hasNonNullishProperty(message, 'contentText') ||
878
+ hasNonNullishProperty(message, 'footerText') ||
879
+ hasNonNullishProperty(message, 'latex') ||
880
+ hasNonNullishProperty(message, 'items') ||
881
+ hasNonNullishProperty(message, 'posts') ||
882
+ hasNonNullishProperty(message, 'products') ||
883
+ hasNonNullishProperty(message, 'suggested')) {
870
884
  m = prepareRichResponseMessage(message);
871
885
  }
872
886
  else if (hasNonNullishProperty(message, 'text')) {
@@ -126,7 +126,12 @@ export function binaryNodeToString(node, i = 0) {
126
126
  const FLOWS_MAP = {
127
127
  // Original flow types
128
128
  mpm: true,
129
- cta_catalog: true,
129
+ // Vanz@Fix (bug 44): the "catalog" nativeFlow shortcut generates a button
130
+ // named 'catalog_message' (see prepareNativeFlowButtons in messages.js),
131
+ // never 'cta_catalog' — the old key here never matched anything, so
132
+ // catalog_message always fell through to the generic mixed-flow node
133
+ // instead of getting its dedicated native_flow node.
134
+ catalog_message: true,
130
135
  send_location: true,
131
136
  call_permission_request: true,
132
137
  wa_payment_transaction_details: true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vanzxy/baileys",
3
- "version": "1.3.9",
3
+ "version": "1.4.0",
4
4
  "description": "Enhanced Baileys fork by Vanzxy \u2014 based on @itsliaaa/baileys + @whiskeysockets/baileys with fixes for audio group status and clean media without newsletter button.",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",