plogme 2.0.3 → 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.
- package/README.md +1530 -8
- package/lib/Socket/messages-send.js +184 -37
- package/lib/Utils/messages.js +10 -1
- package/lib/Utils/rich-message-utils.js +397 -6
- package/lib/index.d.ts +76 -2
- package/package.json +1 -1
|
@@ -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, prepareRichResponseMessage, prepareRichGenerationMessage, prepareCopyToClipboardMessage, prepareRichTextMessage, prepareRichQuoteMessage, prepareRichImageMessage, prepareRichLinkMessage, prepareGridImageMessage, 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: {
|
|
@@ -1276,18 +1276,39 @@ export const makeMessagesSocket = (config) => {
|
|
|
1276
1276
|
},
|
|
1277
1277
|
sendTable: async (jid, title, headers, rows, quoted, options = {}) => {
|
|
1278
1278
|
const { message, messageId } = generateTableContent(title, headers, rows, quoted, options);
|
|
1279
|
-
|
|
1280
|
-
|
|
1279
|
+
const fullMsg = generateWAMessageFromContent(jid, message, {
|
|
1280
|
+
logger,
|
|
1281
|
+
userJid: authState.creds.me?.id,
|
|
1282
|
+
messageId: options.messageId || messageId || generateMessageIDV2(jid),
|
|
1283
|
+
quoted,
|
|
1284
|
+
...options
|
|
1285
|
+
});
|
|
1286
|
+
await relayRichMessage(jid, fullMsg, options);
|
|
1287
|
+
return fullMsg;
|
|
1281
1288
|
},
|
|
1282
1289
|
sendList: async (jid, title, items, quoted, options = {}) => {
|
|
1283
1290
|
const { message, messageId } = generateListContent(title, items, quoted, options);
|
|
1284
|
-
|
|
1285
|
-
|
|
1291
|
+
const fullMsg = generateWAMessageFromContent(jid, message, {
|
|
1292
|
+
logger,
|
|
1293
|
+
userJid: authState.creds.me?.id,
|
|
1294
|
+
messageId: options.messageId || messageId || generateMessageIDV2(jid),
|
|
1295
|
+
quoted,
|
|
1296
|
+
...options
|
|
1297
|
+
});
|
|
1298
|
+
await relayRichMessage(jid, fullMsg, options);
|
|
1299
|
+
return fullMsg;
|
|
1286
1300
|
},
|
|
1287
1301
|
sendCodeBlock: async (jid, code, quoted, options = {}) => {
|
|
1288
1302
|
const { message, messageId } = generateCodeBlockContent(code, quoted, options);
|
|
1289
|
-
|
|
1290
|
-
|
|
1303
|
+
const fullMsg = generateWAMessageFromContent(jid, message, {
|
|
1304
|
+
logger,
|
|
1305
|
+
userJid: authState.creds.me?.id,
|
|
1306
|
+
messageId: options.messageId || messageId || generateMessageIDV2(jid),
|
|
1307
|
+
quoted,
|
|
1308
|
+
...options
|
|
1309
|
+
});
|
|
1310
|
+
await relayRichMessage(jid, fullMsg, options);
|
|
1311
|
+
return fullMsg;
|
|
1291
1312
|
},
|
|
1292
1313
|
sendCarousel: async (jid, cards, options = {}) => {
|
|
1293
1314
|
if (!Array.isArray(cards) || cards.length === 0) {
|
|
@@ -1323,8 +1344,15 @@ export const makeMessagesSocket = (config) => {
|
|
|
1323
1344
|
},
|
|
1324
1345
|
sendLatex: async (jid, quoted, options = {}) => {
|
|
1325
1346
|
const { message, messageId } = generateLatexContent(quoted, { expressions: [], ...options });
|
|
1326
|
-
|
|
1327
|
-
|
|
1347
|
+
const fullMsg = generateWAMessageFromContent(jid, message, {
|
|
1348
|
+
logger,
|
|
1349
|
+
userJid: authState.creds.me?.id,
|
|
1350
|
+
messageId: options.messageId || messageId || generateMessageIDV2(jid),
|
|
1351
|
+
quoted,
|
|
1352
|
+
...options
|
|
1353
|
+
});
|
|
1354
|
+
await relayRichMessage(jid, fullMsg, options);
|
|
1355
|
+
return fullMsg;
|
|
1328
1356
|
},
|
|
1329
1357
|
/**
|
|
1330
1358
|
* Send LaTeX as rendered PNG image (like Meta AI does).
|
|
@@ -1352,8 +1380,14 @@ export const makeMessagesSocket = (config) => {
|
|
|
1352
1380
|
headerText,
|
|
1353
1381
|
footer
|
|
1354
1382
|
});
|
|
1355
|
-
|
|
1356
|
-
|
|
1383
|
+
const fullMsg = generateWAMessageFromContent(jid, message, {
|
|
1384
|
+
logger,
|
|
1385
|
+
userJid: authState.creds.me?.id,
|
|
1386
|
+
messageId: options.messageId || messageId || generateMessageIDV2(jid),
|
|
1387
|
+
...options
|
|
1388
|
+
});
|
|
1389
|
+
await relayRichMessage(jid, fullMsg, options);
|
|
1390
|
+
return fullMsg;
|
|
1357
1391
|
},
|
|
1358
1392
|
sendMetaAI: async (a, b, c = {}) => {
|
|
1359
1393
|
// baron signature: (jid, text, opts) — README signature: (text, opts)
|
|
@@ -2353,6 +2387,103 @@ export const makeMessagesSocket = (config) => {
|
|
|
2353
2387
|
}
|
|
2354
2388
|
return fullMsg;
|
|
2355
2389
|
};
|
|
2390
|
+
/**
|
|
2391
|
+
* Sends the A2UI interactive card/menu format used by WhatsApp's large
|
|
2392
|
+
* command-card presentation. This is intentionally separate from richMenu
|
|
2393
|
+
* because it is an interactiveMessage, not an AIRich unifiedResponse.
|
|
2394
|
+
*/
|
|
2395
|
+
socket.sendA2UICommandMenu = async (jid, content = {}, options = {}) => {
|
|
2396
|
+
if (!jid) throw new Boom('sendA2UICommandMenu requires a target JID', { statusCode: 400 });
|
|
2397
|
+
const { image, ...menuContent } = content || {};
|
|
2398
|
+
let imageMessage;
|
|
2399
|
+
if (image) {
|
|
2400
|
+
const prepared = await prepareWAMessageMedia({ image }, { upload: waUploadToServer });
|
|
2401
|
+
imageMessage = prepared.imageMessage;
|
|
2402
|
+
}
|
|
2403
|
+
const wrapped = prepareA2UICommandMenu({ ...menuContent, imageMessage });
|
|
2404
|
+
const fullMsg = await generateWAMessageFromContent(jid, wrapped, {
|
|
2405
|
+
logger,
|
|
2406
|
+
userJid: authState.creds.me?.id,
|
|
2407
|
+
messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id || jid),
|
|
2408
|
+
...options,
|
|
2409
|
+
});
|
|
2410
|
+
await relayRichMessage(jid, fullMsg, { ...options, forceRichEdit: true });
|
|
2411
|
+
if (config.emitOwnEvents) {
|
|
2412
|
+
process.nextTick(async () => {
|
|
2413
|
+
await messageMutex.mutex(() => upsertMessage(fullMsg, 'append'));
|
|
2414
|
+
});
|
|
2415
|
+
}
|
|
2416
|
+
return fullMsg;
|
|
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
|
+
|
|
2439
|
+
/** Sends the manually serialized AIRich command card shown in the screenshot. */
|
|
2440
|
+
socket.sendAIRichCommandMenu = async (jid, content = {}, options = {}) => {
|
|
2441
|
+
if (!jid) throw new Boom('sendAIRichCommandMenu requires a target JID', { statusCode: 400 });
|
|
2442
|
+
const wrapped = prepareAIRichCommandMenu(content);
|
|
2443
|
+
const fullMsg = await generateWAMessageFromContent(jid, wrapped, {
|
|
2444
|
+
logger,
|
|
2445
|
+
userJid: authState.creds.me?.id,
|
|
2446
|
+
messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id || jid),
|
|
2447
|
+
...options,
|
|
2448
|
+
});
|
|
2449
|
+
await relayRichMessage(jid, fullMsg, options);
|
|
2450
|
+
if (config.emitOwnEvents) {
|
|
2451
|
+
process.nextTick(async () => {
|
|
2452
|
+
await messageMutex.mutex(() => upsertMessage(fullMsg, 'append'));
|
|
2453
|
+
});
|
|
2454
|
+
}
|
|
2455
|
+
return fullMsg;
|
|
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
|
+
|
|
2356
2487
|
/** Sends a rich response with experimental BotInfrastructureDiagnostics metadata. */
|
|
2357
2488
|
socket.sendBotDiagnostics = async (jid, content = {}, options = {}) => {
|
|
2358
2489
|
if (!jid) throw new Boom('sendBotDiagnostics requires a target JID', { statusCode: 400 });
|
|
@@ -2616,38 +2747,58 @@ export const makeMessagesSocket = (config) => {
|
|
|
2616
2747
|
|
|
2617
2748
|
|
|
2618
2749
|
/**
|
|
2619
|
-
* Sends
|
|
2620
|
-
* collection, this is one
|
|
2621
|
-
*
|
|
2750
|
+
* Sends a full-width vertical AIRich album. Unlike the legacy
|
|
2751
|
+
* albumMessage collection or compact GRID_IMAGE layout, this is one
|
|
2752
|
+
* forwarded unified-response message with one large media item per row.
|
|
2622
2753
|
*/
|
|
2623
2754
|
socket.sendAlbumMessage = async (jid, medias = [], options = {}) => {
|
|
2624
2755
|
if (!jid) throw new Boom('sendAlbumMessage requires a target JID', { statusCode: 400 });
|
|
2625
2756
|
if (!Array.isArray(medias) || medias.length < 2) {
|
|
2626
2757
|
throw new Boom('sendAlbumMessage requires at least two media items', { statusCode: 400 });
|
|
2627
2758
|
}
|
|
2628
|
-
const
|
|
2759
|
+
const albumItems = medias.map((media) => {
|
|
2629
2760
|
const raw = media?.type && media?.data ? media.data : (media?.image ?? media);
|
|
2630
2761
|
if (media?.video || media?.type === 'video') {
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
throw new Boom('Each GRID_IMAGE album item requires an image URL', { statusCode: 400 });
|
|
2762
|
+
const video = media?.video || raw;
|
|
2763
|
+
const sourceUrl = typeof video === 'string' ? video : (video?.url || video?.videoUrl || '');
|
|
2764
|
+
if (!sourceUrl) throw new Boom('Each video album item requires a video URL', { statusCode: 400 });
|
|
2765
|
+
return { type: 'video', video: { ...video, url: sourceUrl } };
|
|
2636
2766
|
}
|
|
2637
2767
|
return {
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
imageHighResUrl: raw?.imageHighResUrl || raw?.highResUrl || raw?.url || sourceUrl,
|
|
2641
|
-
darkModePreviewUrl: raw?.darkModePreviewUrl,
|
|
2642
|
-
darkModeHighResUrl: raw?.darkModeHighResUrl,
|
|
2643
|
-
width: raw?.width || media?.width || 600,
|
|
2644
|
-
height: raw?.height || media?.height || 400,
|
|
2645
|
-
darkWidth: raw?.darkWidth || media?.darkWidth,
|
|
2646
|
-
darkHeight: raw?.darkHeight || media?.darkHeight
|
|
2768
|
+
type: 'image',
|
|
2769
|
+
image: raw
|
|
2647
2770
|
};
|
|
2648
2771
|
});
|
|
2649
|
-
const wrapped =
|
|
2650
|
-
|
|
2772
|
+
const wrapped = prepareVerticalAlbumMessage({
|
|
2773
|
+
items: albumItems,
|
|
2774
|
+
verificationMetadata: options.verificationMetadata
|
|
2775
|
+
});
|
|
2776
|
+
const fullMsg = generateWAMessageFromContent(jid, wrapped, {
|
|
2777
|
+
logger,
|
|
2778
|
+
userJid: authState.creds.me?.id,
|
|
2779
|
+
messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id || jid),
|
|
2780
|
+
...options
|
|
2781
|
+
});
|
|
2782
|
+
await relayRichMessage(jid, fullMsg, options);
|
|
2783
|
+
if (config.emitOwnEvents) {
|
|
2784
|
+
process.nextTick(async () => {
|
|
2785
|
+
await messageMutex.mutex(() => upsertMessage(fullMsg, 'append'));
|
|
2786
|
+
});
|
|
2787
|
+
}
|
|
2788
|
+
return fullMsg;
|
|
2789
|
+
};
|
|
2790
|
+
|
|
2791
|
+
/**
|
|
2792
|
+
* Sends a unified-response video grid. This uses GenAIVideoPrimitive items
|
|
2793
|
+
* inside GenAIGridLayoutViewModel; it is not the image-only GRID_IMAGE type.
|
|
2794
|
+
*/
|
|
2795
|
+
socket.sendVideoGridMessage = async (jid, videos = [], options = {}) => {
|
|
2796
|
+
if (!jid) throw new Boom('sendVideoGridMessage requires a target JID', { statusCode: 400 });
|
|
2797
|
+
if (!Array.isArray(videos) || videos.length < 2) {
|
|
2798
|
+
throw new Boom('sendVideoGridMessage requires at least two videos', { statusCode: 400 });
|
|
2799
|
+
}
|
|
2800
|
+
const wrapped = prepareVideoGridMessage({
|
|
2801
|
+
videos,
|
|
2651
2802
|
verificationMetadata: options.verificationMetadata
|
|
2652
2803
|
});
|
|
2653
2804
|
const fullMsg = generateWAMessageFromContent(jid, wrapped, {
|
|
@@ -2692,11 +2843,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
2692
2843
|
messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id),
|
|
2693
2844
|
...options
|
|
2694
2845
|
});
|
|
2695
|
-
await
|
|
2696
|
-
messageId: fullMsg.key.id,
|
|
2697
|
-
useCachedGroupMetadata: options.useCachedGroupMetadata,
|
|
2698
|
-
statusJidList: options.statusJidList
|
|
2699
|
-
});
|
|
2846
|
+
await relayRichMessage(jid, fullMsg, { ...options, forceRichEdit: true });
|
|
2700
2847
|
return fullMsg;
|
|
2701
2848
|
};
|
|
2702
2849
|
|
package/lib/Utils/messages.js
CHANGED
|
@@ -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
|
-
|
|
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) {
|