plogme 2.0.4 → 2.0.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.
@@ -5,7 +5,7 @@ import { proto } from '../../WAProto/index.js';
5
5
  import { BIZ_BOT_SUPPORT_PAYLOAD, DEFAULT_CACHE_TTLS, WA_DEFAULT_EPHEMERAL } from '../Defaults/index.js';
6
6
  import { aggregateMessageKeysNotFromMe, assertMediaContent, assertMeId, bindWaitForEvent, buildLinkPreview, decryptMediaRetryData, DEF_MEDIA_HOST, delay, encodeNewsletterMessage, encodeSignedDeviceIdentity, encodeWAMessage, encryptMediaRetryRequest, extractDeviceJids, extractImageThumb, generateMessageIDV2, generateParticipantHashV2, generateWAMessage, generateWAMessageFromContent, getStatusCodeForMediaRetry, makeWhatsAppFlowButton, getUrlFromDirectPath, getWAUploadToServer, MessageRetryManager, normalizeMessageContent, parseAndInjectE2ESessions, prepareWAMessageMedia, shouldIncludeBizBinaryNode, unixTimestampSeconds } from '../Utils/index.js';
7
7
  import { getUrlInfo } from '../Utils/link-preview.js';
8
- import { prepareRichMenuMessage, prepareA2UICommandMenu, prepareAIRichCommandMenu, prepareRichResponseMessage, prepareRichGenerationMessage, prepareCopyToClipboardMessage, prepareRichTextMessage, prepareRichQuoteMessage, prepareRichImageMessage, prepareRichLinkMessage, prepareGridImageMessage, prepareVerticalAlbumMessage, prepareVideoGridMessage, prepareHtmlMessage, prepareRichHtmlMessage, attachBotVerificationProofs, hasVerifiableProofs } from '../Utils/rich-message-utils.js';
8
+ import { prepareRichMenuMessage, prepareA2UIMessage, prepareA2UICommandMenu, prepareAIRichCommandMenu, prepareSocialEntityMessage, prepareInstagramProfileMessage, prepareRichResponseMessage, prepareRichGenerationMessage, prepareCopyToClipboardMessage, prepareRichTextMessage, prepareRichQuoteMessage, prepareRichImageMessage, prepareRichLinkMessage, prepareGridImageMessage, prepareVerticalAlbumMessage, prepareVideoGridMessage, prepareHtmlMessage, prepareRichHtmlMessage, attachBotVerificationProofs, hasVerifiableProofs } from '../Utils/rich-message-utils.js';
9
9
  import { generateSlotMachineHtml } from '../Utils/games/slot-machine.js';
10
10
  import { generateMiniAppHtml } from '../Utils/games/miniapp.js';
11
11
  import { generateWebsitePreviewHtml, generateLinkPreviewHtml } from '../Utils/games/website-preview.js';
@@ -1051,7 +1051,7 @@ export const makeMessagesSocket = (config) => {
1051
1051
  await relayMessage(jid, fullMsg.message, relayOptions);
1052
1052
 
1053
1053
  const richEnvelope = fullMsg.message?.botForwardedMessage?.message?.richResponseMessage;
1054
- if (options.renderRichResponse !== false && richEnvelope) {
1054
+ if (options.renderRichResponse !== false && (richEnvelope || options.forceRichEdit || fullMsg.message?.interactiveMessage?.bloksWidget)) {
1055
1055
  const editContent = proto.Message.fromObject({
1056
1056
  botForwardedMessage: {
1057
1057
  message: {
@@ -2407,7 +2407,7 @@ export const makeMessagesSocket = (config) => {
2407
2407
  messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id || jid),
2408
2408
  ...options,
2409
2409
  });
2410
- await relayMessage(jid, fullMsg.message, { messageId: fullMsg.key.id, ...options.relayOptions });
2410
+ await relayRichMessage(jid, fullMsg, { ...options, forceRichEdit: true });
2411
2411
  if (config.emitOwnEvents) {
2412
2412
  process.nextTick(async () => {
2413
2413
  await messageMutex.mutex(() => upsertMessage(fullMsg, 'append'));
@@ -2415,6 +2415,27 @@ export const makeMessagesSocket = (config) => {
2415
2415
  }
2416
2416
  return fullMsg;
2417
2417
  };
2418
+ /** Send arbitrary A2UI/interactive payloads; sendA2UICommandMenu is a preset wrapper. */
2419
+ socket.sendA2UIMessage = async (jid, content = {}, options = {}) => {
2420
+ if (!jid) throw new Boom('sendA2UIMessage requires a target JID', { statusCode: 400 });
2421
+ const { image, ...payload } = content || {};
2422
+ let imageMessage;
2423
+ if (image) {
2424
+ const prepared = await prepareWAMessageMedia({ image }, { upload: waUploadToServer });
2425
+ imageMessage = prepared.imageMessage;
2426
+ }
2427
+ const wrapped = prepareA2UIMessage({ ...payload, imageMessage });
2428
+ const fullMsg = await generateWAMessageFromContent(jid, wrapped, {
2429
+ logger,
2430
+ userJid: authState.creds.me?.id,
2431
+ messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id || jid),
2432
+ ...options,
2433
+ });
2434
+ await relayRichMessage(jid, fullMsg, { ...options, forceRichEdit: true });
2435
+ if (config.emitOwnEvents) process.nextTick(async () => { await messageMutex.mutex(() => upsertMessage(fullMsg, 'append')); });
2436
+ return fullMsg;
2437
+ };
2438
+
2418
2439
  /** Sends the manually serialized AIRich command card shown in the screenshot. */
2419
2440
  socket.sendAIRichCommandMenu = async (jid, content = {}, options = {}) => {
2420
2441
  if (!jid) throw new Boom('sendAIRichCommandMenu requires a target JID', { statusCode: 400 });
@@ -2433,6 +2454,36 @@ export const makeMessagesSocket = (config) => {
2433
2454
  }
2434
2455
  return fullMsg;
2435
2456
  };
2457
+ /** Send a provider-neutral AIRich social/entity result card. */
2458
+ socket.sendSocialEntity = async (jid, content = {}, options = {}) => {
2459
+ if (!jid) throw new Boom('sendSocialEntity requires a target JID', { statusCode: 400 });
2460
+ const wrapped = prepareSocialEntityMessage(content);
2461
+ const fullMsg = await generateWAMessageFromContent(jid, wrapped, {
2462
+ logger,
2463
+ userJid: authState.creds.me?.id,
2464
+ messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id || jid),
2465
+ ...options,
2466
+ });
2467
+ await relayRichMessage(jid, fullMsg, options);
2468
+ if (config.emitOwnEvents) process.nextTick(async () => { await messageMutex.mutex(() => upsertMessage(fullMsg, 'append')); });
2469
+ return fullMsg;
2470
+ };
2471
+
2472
+ /** Send the primary Instagram profile result using the universal social/entity API. */
2473
+ socket.sendInstagramProfile = async (jid, content = {}, options = {}) => {
2474
+ if (!jid) throw new Boom('sendInstagramProfile requires a target JID', { statusCode: 400 });
2475
+ const wrapped = prepareInstagramProfileMessage(content);
2476
+ const fullMsg = await generateWAMessageFromContent(jid, wrapped, {
2477
+ logger,
2478
+ userJid: authState.creds.me?.id,
2479
+ messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id || jid),
2480
+ ...options,
2481
+ });
2482
+ await relayRichMessage(jid, fullMsg, options);
2483
+ if (config.emitOwnEvents) process.nextTick(async () => { await messageMutex.mutex(() => upsertMessage(fullMsg, 'append')); });
2484
+ return fullMsg;
2485
+ };
2486
+
2436
2487
  /** Sends a rich response with experimental BotInfrastructureDiagnostics metadata. */
2437
2488
  socket.sendBotDiagnostics = async (jid, content = {}, options = {}) => {
2438
2489
  if (!jid) throw new Boom('sendBotDiagnostics requires a target JID', { statusCode: 400 });
@@ -2792,11 +2843,7 @@ export const makeMessagesSocket = (config) => {
2792
2843
  messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id),
2793
2844
  ...options
2794
2845
  });
2795
- await relayMessage(jid, fullMsg.message, {
2796
- messageId: fullMsg.key.id,
2797
- useCachedGroupMetadata: options.useCachedGroupMetadata,
2798
- statusJidList: options.statusJidList
2799
- });
2846
+ await relayRichMessage(jid, fullMsg, { ...options, forceRichEdit: true });
2800
2847
  return fullMsg;
2801
2848
  };
2802
2849
 
@@ -1592,7 +1592,16 @@ export const generateWAMessageContent = async (message, options) => {
1592
1592
  m = { lottieStickerMessage: { message: m } };
1593
1593
  }
1594
1594
  else if (hasOptionalProperty(message, 'viewOnce') && !!message.viewOnce) {
1595
- m = { viewOnceMessage: { message: m } };
1595
+ // Text view-once clients expect the flag on the inner
1596
+ // ExtendedTextMessage. Media continues to use the standard outer
1597
+ // viewOnceMessage envelope.
1598
+ if (m.extendedTextMessage) {
1599
+ m.extendedTextMessage.viewOnce = true;
1600
+ }
1601
+ else {
1602
+ m = { viewOnceMessage: { message: m } };
1603
+ }
1604
+ delete message.viewOnce;
1596
1605
  }
1597
1606
  // Lia@Changes 03-02-26 --- Add "viewOnceV2" boolean to wrap message into viewOnceMessageV2 like "viewOnce"
1598
1607
  else if (hasOptionalProperty(message, 'viewOnceV2') && !!message.viewOnceV2) {
@@ -376,6 +376,110 @@ const richMenuButton = (button, toast = '') => {
376
376
  * This is an experimental WhatsApp rich-response format, not a standard
377
377
  * buttonsMessage/nativeFlowMessage payload.
378
378
  */
379
+ /**
380
+ * Build a universal AIRich social/entity result card.
381
+ * The wire format is provider-neutral; Instagram is exposed as a dedicated
382
+ * convenience wrapper below because it is the primary supported profile view.
383
+ */
384
+ export const prepareSocialEntityMessage = ({
385
+ username = '',
386
+ platform = 'GENERIC',
387
+ title = 'CODY AI',
388
+ subtitle = '⚉',
389
+ imageUrl = '',
390
+ entityId,
391
+ entityUrl = '',
392
+ entityType,
393
+ fullName = 'NOT found',
394
+ isVerified = false,
395
+ resultText = 'See results',
396
+ botJid = '867051314767696@bot',
397
+ responseId
398
+ } = {}) => {
399
+ const normalizedPlatform = String(platform || 'GENERIC').toUpperCase();
400
+ const profileUrl = entityUrl || (username ? `https://www.${normalizedPlatform.toLowerCase()}.com/${encodeURIComponent(username)}` : '');
401
+ const resolvedType = entityType || (normalizedPlatform === 'INSTAGRAM' ? 'IG_PROFILE' : 'SOCIAL_PROFILE');
402
+ const displayName = username || fullName || 'Profile';
403
+ const sections = [
404
+ {
405
+ view_model: {
406
+ primitives: [{
407
+ title,
408
+ subtitle,
409
+ ...(imageUrl ? { image: { url: imageUrl, mime_type: 'image/png' } } : {}),
410
+ entity_id: String(entityId ?? username ?? ''),
411
+ entity_url: profileUrl,
412
+ entity_type: 'WEBSITE',
413
+ action_type: 'OPEN_URL',
414
+ is_verified: !!isVerified,
415
+ __typename: 'GenAICompactEntityPrimitive'
416
+ }],
417
+ __typename: 'GenAIActionRowLayoutViewModel'
418
+ }
419
+ },
420
+ {
421
+ view_model: {
422
+ primitives: [{ type: 'HORIZONTAL_LINE', __typename: 'GenAIDividerPrimitive' }],
423
+ __typename: 'GenAIVStackLayoutViewModel'
424
+ }
425
+ },
426
+ {
427
+ view_model: {
428
+ primitives: [
429
+ { __typename: 'GenAISpacerPrimitive' },
430
+ {
431
+ text: `# {{social_entity_1}}${resultText}\0{{/social_entity_1}} `,
432
+ inline_entities: [{
433
+ key: 'social_entity_1',
434
+ metadata: {
435
+ __typename: 'GenAISocialEntityItem',
436
+ entity_id: String(entityId ?? username ?? ''),
437
+ entity_name: displayName,
438
+ entity_full_name: fullName,
439
+ entity_picture_url: imageUrl,
440
+ entity_url: profileUrl,
441
+ entity_type: resolvedType,
442
+ platform: normalizedPlatform,
443
+ is_verified: !!isVerified
444
+ }
445
+ }],
446
+ __typename: 'GenAIMarkdownTextUXPrimitive'
447
+ },
448
+ { __typename: 'GenAISpacerPrimitive' }
449
+ ],
450
+ __typename: 'GenAIActionRowLayoutViewModel'
451
+ }
452
+ }
453
+ ];
454
+ return {
455
+ botForwardedMessage: {
456
+ message: {
457
+ richResponseMessage: {
458
+ messageType: 1,
459
+ submessages: [],
460
+ unifiedResponse: {
461
+ response_id: responseId || randomUUID(),
462
+ data: Buffer.from(JSON.stringify({ sections })).toString('base64')
463
+ },
464
+ contextInfo: {
465
+ isForwarded: true,
466
+ forwardOrigin: 4,
467
+ forwardedAiBotMessageInfo: { botJid }
468
+ }
469
+ }
470
+ }
471
+ }
472
+ };
473
+ };
474
+
475
+ /** Dedicated Instagram profile card using the universal social-entity wire format. */
476
+ export const prepareInstagramProfileMessage = (content = {}) => prepareSocialEntityMessage({
477
+ ...content,
478
+ platform: 'INSTAGRAM',
479
+ entityType: 'IG_PROFILE',
480
+ entityUrl: content.entityUrl || (content.username ? `https://www.instagram.com/${encodeURIComponent(content.username)}` : undefined)
481
+ });
482
+
379
483
  export const prepareRichMenuMessage = (content = {}) => {
380
484
  const { header = {}, body = {}, footer = {}, verificationMetadata } = content || {};
381
485
  const sections = [];
@@ -500,6 +604,29 @@ export const prepareAIRichCommandMenu = ({ image, title = 'CODY AI', subtitle =
500
604
  return wrapToBotForwardedMessage(richResponseMessage);
501
605
  };
502
606
 
607
+ /**
608
+ * Build an arbitrary A2UI interactive message. The command-menu helper below
609
+ * is only a convenience preset; callers may provide any supported component,
610
+ * widget, or native-flow payload through this universal builder.
611
+ */
612
+ export const prepareA2UIMessage = ({ imageMessage, bloksWidget = {}, nativeFlowMessage, fallback = '', ...interactiveFields } = {}) => ({
613
+ interactiveMessage: {
614
+ ...interactiveFields,
615
+ ...(imageMessage ? { header: { imageMessage, hasMediaAttachment: true } } : {}),
616
+ bloksWidget: {
617
+ type: bloksWidget.type || 'im_a2ui',
618
+ data: typeof bloksWidget.data === 'string' ? bloksWidget.data : JSON.stringify(bloksWidget.data || {}),
619
+ ...(bloksWidget.fallback || fallback ? { fallback: String(bloksWidget.fallback || fallback) } : {})
620
+ },
621
+ ...(nativeFlowMessage ? {
622
+ nativeFlowMessage: {
623
+ ...nativeFlowMessage,
624
+ ...(nativeFlowMessage.buttons ? { buttons: nativeFlowMessage.buttons } : {})
625
+ }
626
+ } : {})
627
+ }
628
+ });
629
+
503
630
  /** Build the A2UI interactive command menu used by the full-size card layout. */
504
631
  export const prepareA2UICommandMenu = ({ imageMessage, title = 'CODY AI', rows = [], buttons = [], fallback = '' } = {}) => {
505
632
  if (!Array.isArray(rows)) throw new Error('A2UI command-menu rows must be an array');
@@ -798,10 +925,12 @@ export const prepareVerticalAlbumMessage = ({ items = [], verificationMetadata }
798
925
  const height = image?.height || item?.height || 400;
799
926
  const mimeType = image?.mimeType || image?.mime_type || 'image/png';
800
927
  return {
801
- preview_image: { url: previewUrl, mime_type: mimeType, expiration_timestamp_ms: expiration, width, height },
802
- full_image: { url: fullUrl, mime_type: mimeType, expiration_timestamp_ms: expiration, width, height },
803
- dark_mode_preview_image: { url: image?.darkModePreviewUrl || previewUrl, mime_type: mimeType, expiration_timestamp_ms: expiration, width, height },
804
- dark_mode_full_image: { url: image?.darkModeHighResUrl || image?.darkModePreviewUrl || fullUrl, mime_type: mimeType, expiration_timestamp_ms: expiration, width, height },
928
+ preview_image: { url: previewUrl, url_fallback: previewUrl, mime_type: mimeType, expiration_timestamp_ms: expiration, width, height },
929
+ full_image: { url: fullUrl, url_fallback: fullUrl, mime_type: mimeType, expiration_timestamp_ms: expiration, width, height },
930
+ dark_mode_preview_image: { url: image?.darkModePreviewUrl || previewUrl, url_fallback: image?.darkModePreviewUrl || previewUrl, mime_type: mimeType, expiration_timestamp_ms: expiration, width, height },
931
+ dark_mode_full_image: { url: image?.darkModeHighResUrl || image?.darkModePreviewUrl || fullUrl, url_fallback: image?.darkModeHighResUrl || image?.darkModePreviewUrl || fullUrl, mime_type: mimeType, expiration_timestamp_ms: expiration, width, height },
932
+ display_mode: 'FULL_WIDTH',
933
+ full_width: true,
805
934
  asset_query_status: 'FETCHED',
806
935
  __typename: 'GenAIImagePrimitive'
807
936
  };
@@ -809,7 +938,7 @@ export const prepareVerticalAlbumMessage = ({ items = [], verificationMetadata }
809
938
  const richResponseMessage = proto.AIRichResponseMessage.create({
810
939
  submessages: [],
811
940
  messageType: proto.AIRichResponseMessageType.AI_RICH_RESPONSE_TYPE_STANDARD,
812
- unifiedResponse: { data: Buffer.from(JSON.stringify({ response_id: randomUUID(), sections: [{ view_model: { primitives, __typename: 'GenAIVStackLayoutViewModel' } }] })) },
941
+ unifiedResponse: { data: Buffer.from(JSON.stringify({ response_id: randomUUID(), sections: [{ view_model: { primitives, display_mode: 'FULL_WIDTH', full_width: true, __typename: 'GenAIVStackLayoutViewModel' } }] })) },
813
942
  contextInfo: { isForwarded: true, forwardingScore: 1, forwardedAiBotMessageInfo: { botJid: '867051314767696@bot' }, forwardOrigin: 4 }
814
943
  });
815
944
  return wrapToBotForwardedMessage(richResponseMessage, verificationMetadata);
package/lib/index.d.ts CHANGED
@@ -247,6 +247,13 @@ export interface AnimatedWallpaperInput {
247
247
  opacity?: number;
248
248
  }
249
249
 
250
+ export interface A2UIMessageContent {
251
+ image?: unknown;
252
+ bloksWidget?: { type?: string; data?: unknown; fallback?: string };
253
+ nativeFlowMessage?: { messageParamsJson?: string; buttons?: unknown[]; [key: string]: unknown };
254
+ [key: string]: unknown;
255
+ }
256
+
250
257
  export interface A2UICommandMenuContent {
251
258
  image?: unknown;
252
259
  title?: string;
@@ -255,6 +262,22 @@ export interface A2UICommandMenuContent {
255
262
  fallback?: string;
256
263
  }
257
264
 
265
+ export interface SocialEntityContent {
266
+ username?: string;
267
+ platform?: string;
268
+ title?: string;
269
+ subtitle?: string;
270
+ imageUrl?: string;
271
+ entityId?: string | number;
272
+ entityUrl?: string;
273
+ entityType?: string;
274
+ fullName?: string;
275
+ isVerified?: boolean;
276
+ resultText?: string;
277
+ botJid?: string;
278
+ responseId?: string;
279
+ }
280
+
258
281
  export interface AIRichCommandMenuContent {
259
282
  image: string;
260
283
  title?: string;
@@ -301,6 +324,12 @@ export interface WASocket {
301
324
  relayMessage(jid: string, message: Record<string, unknown>, options?: RelayMessageOptions): Promise<unknown>;
302
325
  /** Send an experimental Meta AI-style rich menu with image, card buttons, and an optional URL footer. */
303
326
  richMenu(jid: string, content?: RichMenuContent, options?: Record<string, unknown>): Promise<unknown>;
327
+ /** Send a provider-neutral AIRich social/entity result card. */
328
+ sendSocialEntity(jid: string, content?: SocialEntityContent, options?: Record<string, unknown>): Promise<unknown>;
329
+ /** Send the primary Instagram profile result using the universal social/entity format. */
330
+ sendInstagramProfile(jid: string, content: SocialEntityContent, options?: Record<string, unknown>): Promise<unknown>;
331
+ /** Send arbitrary A2UI/interactive payloads with immediate relay/edit rendering. */
332
+ sendA2UIMessage(jid: string, content?: A2UIMessageContent, options?: Record<string, unknown>): Promise<unknown>;
304
333
  /** Send the large A2UI card/menu with an image header, command table, URL buttons, and native-flow selector. */
305
334
  sendA2UICommandMenu(jid: string, content?: A2UICommandMenuContent, options?: Record<string, unknown>): Promise<unknown>;
306
335
  /** Send the manually serialized AIRich command card with image, Markdown, widget CTAs, and footer actions. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "plogme",
3
- "version": "2.0.4",
3
+ "version": "2.0.5",
4
4
  "description": "Production-ready Baileys fork ⚉ with AI groups, Meta AI prompting, safe compositing fallbacks, rich responses, interactive messages, albums, newsletters, and communities — without antiban wrappers.",
5
5
  "main": "lib/index.js",
6
6
  "type": "module",