@pontalabs/baileys 1.2.4 → 1.2.5

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.
@@ -14,7 +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
+ import { AIRich, Button, ButtonV2, Carousel } from '../Utils/mbuilder.js';
18
18
  export const makeMessagesSocket = (config) => {
19
19
  const { logger, linkPreviewImageThumbnailWidth, generateHighQualityLinkPreview, options: httpRequestOptions, patchMessageBeforeSending, cachedGroupMetadata, enableRecentMessageCache, maxMsgRetryCount } = config;
20
20
  const sock = makeNewsletterSocket(config);
@@ -1134,67 +1134,155 @@ export const makeMessagesSocket = (config) => {
1134
1134
  const userJid = authState.creds.me.id;
1135
1135
 
1136
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.
1137
+ // interactive builders exported by mbuilder.js. When buildDelay is
1138
+ // enabled, keep ONE WhatsApp message id and progressively edit that
1139
+ // message instead of sending a new bubble for every item.
1141
1140
  if (content && !Array.isArray(jid) && Array.isArray(content.items) && content.items.length > 0) {
1142
1141
  const items = content.items;
1143
1142
  const buildDelay = Number(options.buildDelay ?? content.buildDelay ?? 0);
1144
1143
  const hasDelay = Number.isFinite(buildDelay) && buildDelay > 0;
1145
1144
  const isInteractiveBuilder = (item) => item instanceof Button || item instanceof ButtonV2 || item instanceof Carousel;
1145
+ const isAIRichBuilder = (item) => item instanceof AIRich;
1146
1146
  const hasInteractiveBuilder = items.some(isInteractiveBuilder);
1147
1147
 
1148
1148
  if (hasDelay || hasInteractiveBuilder) {
1149
1149
  const sendOptions = { ...options };
1150
1150
  delete sendOptions.buildDelay;
1151
1151
  delete sendOptions.additionalNodes;
1152
- const results = [];
1153
1152
 
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
- ],
1153
+ // One target id for the entire progressive sequence. If the
1154
+ // caller supplied messageId, it is used; otherwise the first
1155
+ // generated message id becomes the target for all edits.
1156
+ let targetMessageId = options.messageId;
1157
+ let lastMessage;
1158
+
1159
+ const buildItemMessage = async (item) => {
1160
+ if (isInteractiveBuilder(item)) {
1161
+ item.setClient({ waUploadToServer });
1162
+ return await item.build(jid, { ...sendOptions, messageId: targetMessageId });
1163
+ }
1164
+
1165
+ if (isAIRichBuilder(item)) {
1166
+ return await item.build(jid, { ...sendOptions, messageId: targetMessageId });
1167
+ }
1168
+
1169
+ // Send Rich AI descriptors through the normal Rich AI
1170
+ // generator, but force the same message id.
1171
+ return await generateWAMessage(jid, { items: [item] }, {
1172
+ logger,
1173
+ userJid,
1174
+ upload: waUploadToServer,
1175
+ mediaCache: config.mediaCache,
1176
+ options: config.options,
1179
1177
  ...sendOptions,
1178
+ messageId: targetMessageId || generateMessageIDV2(userJid)
1179
+ });
1180
+ };
1181
+
1182
+ const isRichAiMessage = (msg) => !!(
1183
+ msg?.message?.botForwardedMessage?.message?.richResponseMessage ||
1184
+ msg?.message?.richResponseMessage
1185
+ );
1186
+
1187
+ const relayEdit = async (msg, targetId) => {
1188
+ const editedMessage = msg.message;
1189
+ const editMessage = await generateWAMessageFromContent(jid, {
1190
+ botForwardedMessage: { message: { protocolMessage: {
1191
+ key: { remoteJid: jid, fromMe: true, id: targetId },
1192
+ type: 14,
1193
+ editedMessage
1194
+ } } }
1195
+ }, { messageId: generateMessageIDV2(userJid) });
1196
+
1197
+ await relayMessage(jid, editMessage.message, {
1198
+ messageId: editMessage.key.id,
1199
+ additionalNodes: options.additionalNodes || []
1180
1200
  });
1181
- return msg;
1201
+ return editMessage;
1182
1202
  };
1183
1203
 
1204
+ // Build a cumulative snapshot on every step. This is the
1205
+ // important part of buildDelay: each edit contains everything
1206
+ // built so far, rather than replacing the previous message
1207
+ // with only the newest item.
1208
+ const cumulativeItems = [];
1209
+
1184
1210
  for (let index = 0; index < items.length; index++) {
1185
- if (index > 0 && hasDelay) await delay(buildDelay);
1211
+ if (index > 0 && hasDelay) {
1212
+ await delay(buildDelay);
1213
+ }
1186
1214
 
1187
- const item = items[index];
1188
- if (isInteractiveBuilder(item)) {
1189
- results.push(await sendInteractiveBuilder(item));
1215
+ cumulativeItems.push(items[index]);
1216
+
1217
+ // AIRich instances represent an already assembled rich
1218
+ // response. For these, use their own build() directly.
1219
+ // For ordinary descriptors we rebuild the cumulative set.
1220
+ let msg;
1221
+ if (cumulativeItems.length === 1 && isAIRichBuilder(cumulativeItems[0])) {
1222
+ msg = await buildItemMessage(cumulativeItems[0]);
1223
+ } else if (cumulativeItems.every(isInteractiveBuilder) && cumulativeItems.length === 1) {
1224
+ msg = await buildItemMessage(cumulativeItems[0]);
1225
+ } else {
1226
+ const hasAirich = cumulativeItems.some(isAIRichBuilder);
1227
+ if (hasAirich) {
1228
+ // Mixed AIRich + descriptor items are flattened by
1229
+ // taking the AIRich message as the current snapshot
1230
+ // and are intentionally not sent as media.
1231
+ const ai = cumulativeItems.find(isAIRichBuilder);
1232
+ msg = await ai.build(jid, { ...sendOptions, messageId: targetMessageId });
1233
+ } else {
1234
+ msg = await generateWAMessage(jid, { items: cumulativeItems }, {
1235
+ logger,
1236
+ userJid,
1237
+ upload: waUploadToServer,
1238
+ mediaCache: config.mediaCache,
1239
+ options: config.options,
1240
+ ...sendOptions,
1241
+ messageId: targetMessageId || generateMessageIDV2(userJid)
1242
+ });
1243
+ }
1244
+ }
1245
+
1246
+ if (!targetMessageId) {
1247
+ targetMessageId = msg.key.id;
1248
+ }
1249
+
1250
+ if (index === 0) {
1251
+ const additionalNodes = isInteractiveBuilder(items[index])
1252
+ ? [
1253
+ {
1254
+ tag: 'biz',
1255
+ attrs: {},
1256
+ content: [{
1257
+ tag: 'interactive',
1258
+ attrs: { type: 'native_flow', v: '1' },
1259
+ content: [{ tag: 'native_flow', attrs: { v: '9', name: 'mixed' } }],
1260
+ }],
1261
+ },
1262
+ ...(options.additionalNodes || []),
1263
+ ]
1264
+ : (options.additionalNodes || []);
1265
+
1266
+ await relayMessage(jid, msg.message, {
1267
+ messageId: targetMessageId,
1268
+ additionalNodes,
1269
+ ...sendOptions,
1270
+ });
1271
+
1272
+ if (isRichAiMessage(msg) && options.bypassDownload !== false) {
1273
+ await relayEdit(msg, targetMessageId);
1274
+ }
1190
1275
  } 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));
1276
+ await relayEdit(msg, targetMessageId);
1195
1277
  }
1278
+
1279
+ lastMessage = msg;
1280
+ }
1281
+
1282
+ if (lastMessage) {
1283
+ lastMessage.key.id = targetMessageId;
1196
1284
  }
1197
- return results;
1285
+ return lastMessage;
1198
1286
  }
1199
1287
  }
1200
1288
  // Update rahmi's userJid in case it changed after login
@@ -826,6 +826,34 @@ const normalizeTableInput = (t, fallbackTitle, fallbackNoHeading) => {
826
826
  return { rows: [], title: fallbackTitle, noHeading: fallbackNoHeading };
827
827
  };
828
828
 
829
+ /** Buat unified section untuk RICH CARD / ENTITY */
830
+ const makeRichCardSection = (data) => {
831
+ const item = data || {};
832
+ const thumbnailUrl = item.thumbnail_url ?? item.thumbnailUrl ?? item.thumbnail ?? '';
833
+ const profileUrl = item.profile_url ?? item.profileUrl ?? thumbnailUrl;
834
+
835
+ return {
836
+ view_model: {
837
+ primitive: {
838
+ __typename: 'GenAICompactEntityPrimitive',
839
+ title: item.title ?? '',
840
+ subtitle: item.subtitle ?? '',
841
+ secondary_subtitle: item.description ?? '',
842
+ entity_id: item.entity_id ?? item.entityId ?? '',
843
+ entity_url: item.entity_url ?? item.entityUrl ?? '',
844
+ entity_type: item.entity_type ?? 'PAGE',
845
+ action_type: item.action_type ?? 'FOLLOW',
846
+ is_verified: !!item.verification,
847
+ image: {
848
+ url: thumbnailUrl,
849
+ url_fallback: profileUrl
850
+ }
851
+ },
852
+ __typename: 'GenAISingleLayoutViewModel'
853
+ }
854
+ };
855
+ };
856
+
829
857
  /* ─────────────────────────────────────────────────────────────
830
858
  MAIN BUILDER — prepareRichResponseMessage
831
859
  ───────────────────────────────────────────────────────────── */
@@ -839,7 +867,7 @@ export const prepareRichResponseMessage = (content) => {
839
867
  map: mapContent, latex, contentItems,
840
868
  // sub-types baru (prefixed 'rich' agar tidak konflik dengan media biasa)
841
869
  richImage, richVideo, reels, source, richProduct, richPost, tip, suggest,
842
- richWidget, widget, richFooterAction, footerAction, richMetadata, metadata, richFOAText, foaText, richHtml,
870
+ richWidget, widget, richFooterAction, footerAction, richMetadata, metadata, richFOAText, foaText, richHtml, richCard,
843
871
  // opsi tambahan (belum ada di versi ponta.zip semula)
844
872
  aiForwarded
845
873
  } = content;
@@ -928,6 +956,7 @@ export const prepareRichResponseMessage = (content) => {
928
956
  if (sub.footerAction != null) return push(null, makeFooterActionSection(sub.footerAction));
929
957
  if (sub.metadata != null) { const built = makeMetadataSub(sub.metadata); return push(built.sub, built.section); }
930
958
  if (sub.foaText != null) { const built = makeMetadataSub(sub.foaText, 'FOATextPrimitive'); return push(built.sub, built.section); }
959
+ if (sub.richCard != null) return push(null, makeRichCardSection(sub.richCard));
931
960
  if (sub.richHtml != null) return push(null, makeHtmlSection(sub.richHtml));
932
961
  // passthrough — kalau sudah bentuk proto submessage manual
933
962
  return push(sub, buildUnifiedSection(sub));
@@ -1538,6 +1567,7 @@ const translateReadmeItem = (item) => {
1538
1567
  if (item.richText != null) { out.text = item.richText; }
1539
1568
  if (item.richFOAText != null) { out.foaText = item.richFOAText; }
1540
1569
  if (item.richHtml != null) { out.richHtml = item.richHtml; }
1570
+ if (item.richCard != null) { out.richCard = item.richCard; }
1541
1571
  if (item.richCode != null) { out.code = item.richCode; out.language = item.language; }
1542
1572
  if (item.richTable != null) { out.table = item.richTable; }
1543
1573
  if (item.richSource != null) { out.source = item.richSource; }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pontalabs/baileys",
3
3
  "type": "module",
4
- "version": "1.2.4",
4
+ "version": "1.2.5",
5
5
  "description": "PontaLabs Baileys is a lightweight, modern, and customizable WhatsApp Web API library built on Baileys.",
6
6
  "keywords": [
7
7
  "whatsapp",