plogme 2.0.1 → 2.0.3
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 +90 -10
- package/lib/Socket/messages-send.js +164 -124
- package/lib/Utils/bot-planning-replay.js +0 -1
- package/lib/Utils/messages.js +1 -23
- package/lib/Utils/rich-message-utils.js +171 -68
- package/lib/index.d.ts +14 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -291,29 +291,36 @@ await sock.sendMessage(jid, {
|
|
|
291
291
|
|
|
292
292
|
### Albums
|
|
293
293
|
|
|
294
|
-
|
|
294
|
+
Albums now use the AIRich `GRID_IMAGE` unified-response layout. Provide at least two image URLs; the client receives one forwarded rich message containing preview, full-resolution, and dark-mode image primitives. The old `albumMessage` parent/child collection is no longer generated.
|
|
295
295
|
|
|
296
296
|
```js
|
|
297
297
|
await sock.sendAlbumMessage(jid, [
|
|
298
|
-
{ type: 'image', data: { url: '
|
|
299
|
-
{
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
298
|
+
{ type: 'image', data: { url: 'https://example.com/one.jpg', width: 1200, height: 800 } },
|
|
299
|
+
{
|
|
300
|
+
image: {
|
|
301
|
+
sourceUrl: 'https://example.com/two-preview.jpg',
|
|
302
|
+
imageHighResUrl: 'https://example.com/two.jpg',
|
|
303
|
+
darkModePreviewUrl: 'https://example.com/two-dark-preview.jpg',
|
|
304
|
+
darkModeHighResUrl: 'https://example.com/two-dark.jpg',
|
|
305
|
+
width: 1200,
|
|
306
|
+
height: 800
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
])
|
|
303
310
|
```
|
|
304
311
|
|
|
305
|
-
The general `sendMessage` album form
|
|
312
|
+
The general `sendMessage` album form delegates to the same GRID_IMAGE implementation:
|
|
306
313
|
|
|
307
314
|
```js
|
|
308
315
|
await sock.sendMessage(jid, {
|
|
309
316
|
album: [
|
|
310
|
-
{ image: { url: '
|
|
311
|
-
{
|
|
317
|
+
{ image: { url: 'https://example.com/one.jpg' } },
|
|
318
|
+
{ image: { url: 'https://example.com/two.jpg' } }
|
|
312
319
|
]
|
|
313
320
|
})
|
|
314
321
|
```
|
|
315
322
|
|
|
316
|
-
|
|
323
|
+
GRID_IMAGE albums support images only. Video items and local `Buffer`/file inputs are rejected because this layout carries fetchable image URLs rather than uploaded album children.
|
|
317
324
|
|
|
318
325
|
## Interactive messages
|
|
319
326
|
|
|
@@ -475,6 +482,79 @@ await sock.sendRichAIResponse(jid, {
|
|
|
475
482
|
|
|
476
483
|
`sendRichAIResponse` also accepts `list`, `codeBlock`, and `latex` content objects. For a pre-existing Meta AI response, `captureAndResendUnifiedResponse(jid, message, quoted)` captures and resends its unified response.
|
|
477
484
|
|
|
485
|
+
### One unified Plogme response
|
|
486
|
+
|
|
487
|
+
Use `sendPlogmeMessage` when a response may contain several optional sections. It combines every section that is present into one AIRich `unifiedResponse`; omitted sections are ignored, so callers do not need to construct a different payload for every result shape.
|
|
488
|
+
|
|
489
|
+
```js
|
|
490
|
+
const result = await sock.sendPlogmeMessage(jid, {
|
|
491
|
+
headerText: 'CODY AI result',
|
|
492
|
+
contentText: 'The deployment completed successfully.',
|
|
493
|
+
|
|
494
|
+
// Optional highlighted code section.
|
|
495
|
+
code: 'const status = "online"',
|
|
496
|
+
language: 'javascript',
|
|
497
|
+
|
|
498
|
+
// Optional table section. The first row is treated as the heading by default.
|
|
499
|
+
title: 'Service status',
|
|
500
|
+
table: [
|
|
501
|
+
['Service', 'State'],
|
|
502
|
+
['API', 'Online'],
|
|
503
|
+
['Worker', 'Online']
|
|
504
|
+
],
|
|
505
|
+
noHeading: false,
|
|
506
|
+
|
|
507
|
+
// Optional carousel/content items or reels.
|
|
508
|
+
items: [
|
|
509
|
+
{ title: 'API documentation', url: 'https://example.com/docs' }
|
|
510
|
+
],
|
|
511
|
+
reels: [
|
|
512
|
+
{
|
|
513
|
+
title: 'Release notes',
|
|
514
|
+
url: 'https://example.com/release.mp4',
|
|
515
|
+
thumbnail_url: 'https://example.com/release.jpg'
|
|
516
|
+
}
|
|
517
|
+
],
|
|
518
|
+
|
|
519
|
+
// Optional inline media and LaTeX sections.
|
|
520
|
+
inlineImage: 'https://example.com/status.jpg',
|
|
521
|
+
imageText: 'Deployment status',
|
|
522
|
+
alignment: 2,
|
|
523
|
+
latex: [
|
|
524
|
+
{ latexExpression: 'E = mc^2', url: 'https://example.com/equation.png' }
|
|
525
|
+
],
|
|
526
|
+
|
|
527
|
+
// Optional sources/links, posts, products, or suggested prompts.
|
|
528
|
+
links: [
|
|
529
|
+
{
|
|
530
|
+
text: 'Open the deployment logs',
|
|
531
|
+
url: 'https://example.com/logs',
|
|
532
|
+
title: 'Deployment logs',
|
|
533
|
+
displayName: 'Logs'
|
|
534
|
+
}
|
|
535
|
+
],
|
|
536
|
+
suggested: true,
|
|
537
|
+
footerText: 'Generated by CODY AI'
|
|
538
|
+
}, undefined, {
|
|
539
|
+
// The compatibility relay is enabled by default. It sends the rich
|
|
540
|
+
// envelope normally, then uses WhatsApp's type-14 edit protocol so
|
|
541
|
+
// compatible clients render it immediately instead of showing Download.
|
|
542
|
+
renderRichResponse: true
|
|
543
|
+
})
|
|
544
|
+
|
|
545
|
+
console.log('Sent message:', result.key.id)
|
|
546
|
+
```
|
|
547
|
+
|
|
548
|
+
Every field in the example is optional. A minimal response is valid as well:
|
|
549
|
+
|
|
550
|
+
```js
|
|
551
|
+
await sock.sendPlogmeMessage(jid, {
|
|
552
|
+
contentText: 'Only the text section is available right now.'
|
|
553
|
+
})
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
The compatibility edit can be disabled for a specific send with `{ renderRichResponse: false }`. This sends the generated rich envelope once without the follow-up edit.
|
|
557
|
+
|
|
478
558
|
## Rich menus, reels, and grids
|
|
479
559
|
|
|
480
560
|
### Original Gen4 rich menu
|
|
@@ -3,9 +3,9 @@ import { Boom } from '@hapi/boom';
|
|
|
3
3
|
import { randomBytes } from 'crypto';
|
|
4
4
|
import { proto } from '../../WAProto/index.js';
|
|
5
5
|
import { BIZ_BOT_SUPPORT_PAYLOAD, DEFAULT_CACHE_TTLS, WA_DEFAULT_EPHEMERAL } from '../Defaults/index.js';
|
|
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,
|
|
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, prepareHtmlMessage, prepareRichHtmlMessage } from '../Utils/rich-message-utils.js';
|
|
8
|
+
import { prepareRichMenuMessage, prepareRichResponseMessage, prepareRichGenerationMessage, prepareCopyToClipboardMessage, prepareRichTextMessage, prepareRichQuoteMessage, prepareRichImageMessage, prepareRichLinkMessage, prepareGridImageMessage, 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';
|
|
@@ -555,7 +555,18 @@ export const makeMessagesSocket = (config) => {
|
|
|
555
555
|
};
|
|
556
556
|
}
|
|
557
557
|
const applyForwarded = m => {
|
|
558
|
+
// Auto-inject trusted verification proofs configured once on the socket
|
|
559
|
+
// (config.metaAiRendering.verificationMetadata). Per-message proofs win:
|
|
560
|
+
// an envelope that already carries verificationMetadata is left untouched.
|
|
561
|
+
// The second target covers edited rich envelopes (protocolMessage.editedMessage,
|
|
562
|
+
// used by updateRichGeneration) so an in-place rich update keeps its proofs too.
|
|
563
|
+
const edited = m?.botForwardedMessage?.message?.protocolMessage?.editedMessage;
|
|
558
564
|
const rich = m?.botForwardedMessage?.message?.richResponseMessage || m?.richResponseMessage;
|
|
565
|
+
if (!rich && !edited) return m;
|
|
566
|
+
if (hasVerifiableProofs(config?.metaAiRendering?.verificationMetadata)) {
|
|
567
|
+
attachBotVerificationProofs(m, config.metaAiRendering.verificationMetadata);
|
|
568
|
+
attachBotVerificationProofs(edited, config.metaAiRendering.verificationMetadata);
|
|
569
|
+
}
|
|
559
570
|
if (!rich) return m;
|
|
560
571
|
rich.contextInfo = { ...rich.contextInfo, isForwarded: true, forwardOrigin: 4 };
|
|
561
572
|
return m.botForwardedMessage ? m : { botForwardedMessage: { message: m } };
|
|
@@ -1022,6 +1033,53 @@ export const makeMessagesSocket = (config) => {
|
|
|
1022
1033
|
return msgId;
|
|
1023
1034
|
};
|
|
1024
1035
|
|
|
1036
|
+
/**
|
|
1037
|
+
* Relay a rich envelope and then replay it as a type-14 edit. Some
|
|
1038
|
+
* WhatsApp clients otherwise show a Download prompt before rendering the
|
|
1039
|
+
* AIRich unifiedResponse. The edit is only applied to bot-forwarded rich
|
|
1040
|
+
* envelopes, so ordinary messages are never duplicated accidentally.
|
|
1041
|
+
* Set renderRichResponse: false for callers that explicitly do not want
|
|
1042
|
+
* the compatibility replay.
|
|
1043
|
+
*/
|
|
1044
|
+
const relayRichMessage = async (jid, fullMsg, options = {}) => {
|
|
1045
|
+
const relayOptions = {
|
|
1046
|
+
messageId: fullMsg.key.id,
|
|
1047
|
+
useCachedGroupMetadata: options.useCachedGroupMetadata,
|
|
1048
|
+
statusJidList: options.statusJidList,
|
|
1049
|
+
...options.relayOptions,
|
|
1050
|
+
};
|
|
1051
|
+
await relayMessage(jid, fullMsg.message, relayOptions);
|
|
1052
|
+
|
|
1053
|
+
const richEnvelope = fullMsg.message?.botForwardedMessage?.message?.richResponseMessage;
|
|
1054
|
+
if (options.renderRichResponse !== false && richEnvelope) {
|
|
1055
|
+
const editContent = proto.Message.fromObject({
|
|
1056
|
+
botForwardedMessage: {
|
|
1057
|
+
message: {
|
|
1058
|
+
protocolMessage: {
|
|
1059
|
+
key: {
|
|
1060
|
+
remoteJid: jid,
|
|
1061
|
+
fromMe: true,
|
|
1062
|
+
id: fullMsg.key.id,
|
|
1063
|
+
},
|
|
1064
|
+
type: proto.Message.ProtocolMessage.Type.MESSAGE_EDIT,
|
|
1065
|
+
editedMessage: fullMsg.message,
|
|
1066
|
+
},
|
|
1067
|
+
},
|
|
1068
|
+
},
|
|
1069
|
+
});
|
|
1070
|
+
const editMessage = generateWAMessageFromContent(jid, editContent, {
|
|
1071
|
+
logger,
|
|
1072
|
+
userJid: authState.creds.me?.id,
|
|
1073
|
+
messageId: generateMessageIDV2(authState.creds.me?.id || jid),
|
|
1074
|
+
});
|
|
1075
|
+
await relayMessage(jid, editMessage.message, {
|
|
1076
|
+
...relayOptions,
|
|
1077
|
+
messageId: editMessage.key.id,
|
|
1078
|
+
});
|
|
1079
|
+
}
|
|
1080
|
+
return fullMsg;
|
|
1081
|
+
};
|
|
1082
|
+
|
|
1025
1083
|
const getMessageType = (message) => {
|
|
1026
1084
|
if (!message)
|
|
1027
1085
|
return 'text';
|
|
@@ -1380,11 +1438,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
1380
1438
|
quoted,
|
|
1381
1439
|
...options
|
|
1382
1440
|
});
|
|
1383
|
-
await
|
|
1384
|
-
messageId: generated.key.id,
|
|
1385
|
-
useCachedGroupMetadata: options.useCachedGroupMetadata,
|
|
1386
|
-
statusJidList: options.statusJidList
|
|
1387
|
-
});
|
|
1441
|
+
await relayRichMessage(jid, generated, options);
|
|
1388
1442
|
return { ...generated, messageId: generated.key.id };
|
|
1389
1443
|
},
|
|
1390
1444
|
/**
|
|
@@ -1397,9 +1451,15 @@ export const makeMessagesSocket = (config) => {
|
|
|
1397
1451
|
responseId: options.responseId,
|
|
1398
1452
|
forwarded: options.forwarded !== false
|
|
1399
1453
|
});
|
|
1400
|
-
const
|
|
1401
|
-
|
|
1402
|
-
|
|
1454
|
+
const fullMsg = generateWAMessageFromContent(jid, generated.message, {
|
|
1455
|
+
logger,
|
|
1456
|
+
userJid: authState.creds.me?.id,
|
|
1457
|
+
messageId: options.messageId || generated.messageId || generateMessageIDV2(jid),
|
|
1458
|
+
quoted,
|
|
1459
|
+
...options,
|
|
1460
|
+
});
|
|
1461
|
+
await relayRichMessage(jid, fullMsg, options);
|
|
1462
|
+
return { ...generated, messageId: fullMsg.key.id };
|
|
1403
1463
|
},
|
|
1404
1464
|
/**
|
|
1405
1465
|
* Replace the generation primitive in an existing rich response.
|
|
@@ -1465,14 +1525,47 @@ export const makeMessagesSocket = (config) => {
|
|
|
1465
1525
|
quoted,
|
|
1466
1526
|
...options
|
|
1467
1527
|
});
|
|
1468
|
-
await
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1528
|
+
await relayRichMessage(jid, fullMsg, options);
|
|
1529
|
+
return fullMsg;
|
|
1530
|
+
},
|
|
1531
|
+
/**
|
|
1532
|
+
* Send one tolerant AIRich/unified response containing every supported
|
|
1533
|
+
* section present in `content`. Missing sections are intentionally
|
|
1534
|
+
* ignored by prepareRichResponseMessage instead of causing a partial
|
|
1535
|
+
* response to fail. This is the stable entry point for Plogme/CODY
|
|
1536
|
+
* callers that may receive optional text, links, media, products,
|
|
1537
|
+
* reels, tables, code, latex, or suggestion data.
|
|
1538
|
+
*/
|
|
1539
|
+
sendPlogmeMessage: async (jid, content = {}, quoted, options = {}) => {
|
|
1540
|
+
if (!jid) throw new Boom('sendPlogmeMessage requires a target JID', { statusCode: 400 });
|
|
1541
|
+
if (!content || typeof content !== 'object' || Array.isArray(content)) {
|
|
1542
|
+
throw new Boom('sendPlogmeMessage content must be an object', { statusCode: 400 });
|
|
1543
|
+
}
|
|
1544
|
+
|
|
1545
|
+
const wrapped = prepareRichResponseMessage({
|
|
1546
|
+
...content,
|
|
1547
|
+
// Avoid silently appending the library donation link to a
|
|
1548
|
+
// unified response unless the caller explicitly opts in.
|
|
1549
|
+
noDonation: options.noDonation ?? true,
|
|
1472
1550
|
});
|
|
1551
|
+
const fullMsg = generateWAMessageFromContent(jid, wrapped, {
|
|
1552
|
+
logger,
|
|
1553
|
+
userJid: authState.creds.me?.id,
|
|
1554
|
+
messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id || jid),
|
|
1555
|
+
quoted,
|
|
1556
|
+
...options,
|
|
1557
|
+
});
|
|
1558
|
+
|
|
1559
|
+
await relayRichMessage(jid, fullMsg, options);
|
|
1560
|
+
|
|
1561
|
+
if (config.emitOwnEvents) {
|
|
1562
|
+
process.nextTick(async () => {
|
|
1563
|
+
await messageMutex.mutex(() => upsertMessage(fullMsg, 'append'));
|
|
1564
|
+
});
|
|
1565
|
+
}
|
|
1473
1566
|
return fullMsg;
|
|
1474
1567
|
},
|
|
1475
|
-
captureAndResendUnifiedResponse: async (jid, metaAiMsg, quoted) => {
|
|
1568
|
+
captureAndResendUnifiedResponse: async (jid, metaAiMsg, quoted, options = {}) => {
|
|
1476
1569
|
const captured = captureUnifiedResponse(metaAiMsg);
|
|
1477
1570
|
if (!captured) {
|
|
1478
1571
|
throw new Boom('captureAndResendUnifiedResponse: message contains no unifiedResponse data');
|
|
@@ -1484,11 +1577,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
1484
1577
|
messageId: generated.messageId || generateMessageIDV2(jid),
|
|
1485
1578
|
quoted
|
|
1486
1579
|
});
|
|
1487
|
-
await
|
|
1488
|
-
messageId: fullMsg.key.id,
|
|
1489
|
-
useCachedGroupMetadata: options?.useCachedGroupMetadata,
|
|
1490
|
-
statusJidList: options?.statusJidList
|
|
1491
|
-
});
|
|
1580
|
+
await relayRichMessage(jid, fullMsg, options);
|
|
1492
1581
|
return fullMsg;
|
|
1493
1582
|
},
|
|
1494
1583
|
updateMediaMessage: async (message) => {
|
|
@@ -2028,6 +2117,9 @@ export const makeMessagesSocket = (config) => {
|
|
|
2028
2117
|
}
|
|
2029
2118
|
// ── NORMAL MESSAGE HANDLING ──
|
|
2030
2119
|
else {
|
|
2120
|
+
if ('album' in content) {
|
|
2121
|
+
return socket.sendAlbumMessage(jid, content.album, options);
|
|
2122
|
+
}
|
|
2031
2123
|
const fullMsg = await generateWAMessage(jid, content, {
|
|
2032
2124
|
logger,
|
|
2033
2125
|
userJid,
|
|
@@ -2116,13 +2208,6 @@ export const makeMessagesSocket = (config) => {
|
|
|
2116
2208
|
delete content.ai;
|
|
2117
2209
|
}
|
|
2118
2210
|
|
|
2119
|
-
if ('album' in content) {
|
|
2120
|
-
if (!Array.isArray(content.album) || content.album.length < 2) {
|
|
2121
|
-
throw new Boom('Album requires at least two image or video items', { statusCode: 400 });
|
|
2122
|
-
}
|
|
2123
|
-
fullMsg.message.messageContextInfo ||= {};
|
|
2124
|
-
fullMsg.message.messageContextInfo.messageSecret ||= randomBytes(32);
|
|
2125
|
-
}
|
|
2126
2211
|
await relayMessage(jid, fullMsg.message, {
|
|
2127
2212
|
messageId: fullMsg.key.id,
|
|
2128
2213
|
useCachedGroupMetadata: options.useCachedGroupMetadata,
|
|
@@ -2139,55 +2224,6 @@ export const makeMessagesSocket = (config) => {
|
|
|
2139
2224
|
});
|
|
2140
2225
|
}
|
|
2141
2226
|
|
|
2142
|
-
if ('album' in content) {
|
|
2143
|
-
const { delayMs = 1500 } = options;
|
|
2144
|
-
for (const [messageIndex, albumMedia] of content.album.entries()) {
|
|
2145
|
-
// Give the album collection stanza time to register before
|
|
2146
|
-
// its associated media children are relayed. This mirrors
|
|
2147
|
-
// the ordering used by WhatsApp clients and avoids the
|
|
2148
|
-
// children being treated as unrelated media messages.
|
|
2149
|
-
await delay(delayMs);
|
|
2150
|
-
const albumMsg = await generateWAMessage(jid, albumMedia, {
|
|
2151
|
-
logger,
|
|
2152
|
-
userJid,
|
|
2153
|
-
upload: waUploadToServer,
|
|
2154
|
-
mediaCache: config.mediaCache,
|
|
2155
|
-
options: config.options,
|
|
2156
|
-
...options,
|
|
2157
|
-
messageId: generateMessageIDV2(userJid)
|
|
2158
|
-
});
|
|
2159
|
-
if (!hasValidAlbumMedia(normalizeMessageContent(albumMsg.message))) {
|
|
2160
|
-
throw new Boom('Invalid message type for album', { statusCode: 400 });
|
|
2161
|
-
}
|
|
2162
|
-
albumMsg.message.messageContextInfo ||= {};
|
|
2163
|
-
// WhatsApp expects an encrypted context secret on each album
|
|
2164
|
-
// child. Without it, clients may show the album as an
|
|
2165
|
-
// unsupported message or fail to group the media together.
|
|
2166
|
-
albumMsg.message.messageContextInfo.messageSecret ||= randomBytes(32);
|
|
2167
|
-
albumMsg.message.messageContextInfo.messageAssociation = {
|
|
2168
|
-
parentMessageKey: fullMsg.key,
|
|
2169
|
-
// WhatsApp album child messages use association type 1.
|
|
2170
|
-
// The generated MEDIA_ALBUM enum value (63) is a message
|
|
2171
|
-
// category, not the child-association wire value.
|
|
2172
|
-
associationType: 1,
|
|
2173
|
-
messageIndex
|
|
2174
|
-
};
|
|
2175
|
-
await relayMessage(jid, albumMsg.message, {
|
|
2176
|
-
messageId: albumMsg.key.id,
|
|
2177
|
-
useCachedGroupMetadata: options.useCachedGroupMetadata,
|
|
2178
|
-
addBizAttributes: isNeedBizAttrs,
|
|
2179
|
-
statusJidList: options.statusJidList,
|
|
2180
|
-
additionalAttributes,
|
|
2181
|
-
additionalNodes
|
|
2182
|
-
});
|
|
2183
|
-
if (config.emitOwnEvents) {
|
|
2184
|
-
process.nextTick(async () => {
|
|
2185
|
-
await messageMutex.mutex(() => upsertMessage(albumMsg, 'append'));
|
|
2186
|
-
});
|
|
2187
|
-
}
|
|
2188
|
-
}
|
|
2189
|
-
}
|
|
2190
|
-
|
|
2191
2227
|
return fullMsg;
|
|
2192
2228
|
}
|
|
2193
2229
|
}
|
|
@@ -2205,11 +2241,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
2205
2241
|
messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id),
|
|
2206
2242
|
...options,
|
|
2207
2243
|
});
|
|
2208
|
-
await
|
|
2209
|
-
messageId: fullMsg.key.id,
|
|
2210
|
-
useCachedGroupMetadata: options.useCachedGroupMetadata,
|
|
2211
|
-
statusJidList: options.statusJidList,
|
|
2212
|
-
});
|
|
2244
|
+
await relayRichMessage(jid, fullMsg, options);
|
|
2213
2245
|
if (config.emitOwnEvents) {
|
|
2214
2246
|
process.nextTick(async () => {
|
|
2215
2247
|
await messageMutex.mutex(() => upsertMessage(fullMsg, 'append'));
|
|
@@ -2230,11 +2262,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
2230
2262
|
messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id),
|
|
2231
2263
|
...options,
|
|
2232
2264
|
});
|
|
2233
|
-
await
|
|
2234
|
-
messageId: fullMsg.key.id,
|
|
2235
|
-
useCachedGroupMetadata: options.useCachedGroupMetadata,
|
|
2236
|
-
statusJidList: options.statusJidList,
|
|
2237
|
-
});
|
|
2265
|
+
await relayRichMessage(jid, fullMsg, options);
|
|
2238
2266
|
if (config.emitOwnEvents) {
|
|
2239
2267
|
process.nextTick(async () => {
|
|
2240
2268
|
await messageMutex.mutex(() => upsertMessage(fullMsg, 'append'));
|
|
@@ -2248,7 +2276,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
2248
2276
|
if (!content.copyText) throw new Boom('sendRichTextCopy requires copyText content', { statusCode: 400 });
|
|
2249
2277
|
const wrapped = prepareRichQuoteMessage(content);
|
|
2250
2278
|
const fullMsg = await generateWAMessageFromContent(jid, wrapped, { logger, userJid: authState.creds.me?.id, messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id), ...options });
|
|
2251
|
-
await
|
|
2279
|
+
await relayRichMessage(jid, fullMsg, options);
|
|
2252
2280
|
return fullMsg;
|
|
2253
2281
|
};
|
|
2254
2282
|
/** Sends Markdown text containing blockquotes in a forwarded GenAI rich response. */
|
|
@@ -2256,7 +2284,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
2256
2284
|
if (!jid) throw new Boom('sendMarkdownQuote requires a target JID', { statusCode: 400 });
|
|
2257
2285
|
const wrapped = prepareRichQuoteMessage(content);
|
|
2258
2286
|
const fullMsg = await generateWAMessageFromContent(jid, wrapped, { logger, userJid: authState.creds.me?.id, messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id), ...options });
|
|
2259
|
-
await
|
|
2287
|
+
await relayRichMessage(jid, fullMsg, options);
|
|
2260
2288
|
return fullMsg;
|
|
2261
2289
|
};
|
|
2262
2290
|
/** Sends Markdown blockquotes followed by a GenAI COPY_TO_CLIPBOARD action. */
|
|
@@ -2265,7 +2293,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
2265
2293
|
if (!content.copyText) throw new Boom('sendQuoteCopy requires copyText content', { statusCode: 400 });
|
|
2266
2294
|
const wrapped = prepareRichQuoteMessage(content);
|
|
2267
2295
|
const fullMsg = await generateWAMessageFromContent(jid, wrapped, { logger, userJid: authState.creds.me?.id, messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id), ...options });
|
|
2268
|
-
await
|
|
2296
|
+
await relayRichMessage(jid, fullMsg, options);
|
|
2269
2297
|
return fullMsg;
|
|
2270
2298
|
};
|
|
2271
2299
|
/**
|
|
@@ -2280,11 +2308,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
2280
2308
|
messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id),
|
|
2281
2309
|
...options,
|
|
2282
2310
|
});
|
|
2283
|
-
await
|
|
2284
|
-
messageId: fullMsg.key.id,
|
|
2285
|
-
useCachedGroupMetadata: options.useCachedGroupMetadata,
|
|
2286
|
-
statusJidList: options.statusJidList,
|
|
2287
|
-
});
|
|
2311
|
+
await relayRichMessage(jid, fullMsg, options);
|
|
2288
2312
|
if (config.emitOwnEvents) {
|
|
2289
2313
|
process.nextTick(async () => {
|
|
2290
2314
|
await messageMutex.mutex(() => upsertMessage(fullMsg, 'append'));
|
|
@@ -2304,11 +2328,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
2304
2328
|
messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id),
|
|
2305
2329
|
...options,
|
|
2306
2330
|
});
|
|
2307
|
-
await
|
|
2308
|
-
messageId: fullMsg.key.id,
|
|
2309
|
-
useCachedGroupMetadata: options.useCachedGroupMetadata,
|
|
2310
|
-
statusJidList: options.statusJidList,
|
|
2311
|
-
});
|
|
2331
|
+
await relayRichMessage(jid, fullMsg, options);
|
|
2312
2332
|
if (config.emitOwnEvents) {
|
|
2313
2333
|
process.nextTick(async () => {
|
|
2314
2334
|
await messageMutex.mutex(() => upsertMessage(fullMsg, 'append'));
|
|
@@ -2325,11 +2345,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
2325
2345
|
messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id),
|
|
2326
2346
|
...options,
|
|
2327
2347
|
});
|
|
2328
|
-
await
|
|
2329
|
-
messageId: fullMsg.key.id,
|
|
2330
|
-
useCachedGroupMetadata: options.useCachedGroupMetadata,
|
|
2331
|
-
statusJidList: options.statusJidList,
|
|
2332
|
-
});
|
|
2348
|
+
await relayRichMessage(jid, fullMsg, options);
|
|
2333
2349
|
if (config.emitOwnEvents) {
|
|
2334
2350
|
process.nextTick(async () => {
|
|
2335
2351
|
await messageMutex.mutex(() => upsertMessage(fullMsg, 'append'));
|
|
@@ -2346,7 +2362,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
2346
2362
|
botForwardedMessage: { message: { richResponseMessage: { messageType: 1, submessages: [{ messageType: 2, messageText: text }], contextInfo: { isForwarded: true, forwardingScore: 1, forwardedAiBotMessageInfo: { botJid }, forwardOrigin: 4 } } } }
|
|
2347
2363
|
};
|
|
2348
2364
|
const fullMsg = await generateWAMessageFromContent(jid, wrapped, { logger, userJid: authState.creds.me?.id, messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id), ...options });
|
|
2349
|
-
await
|
|
2365
|
+
await relayRichMessage(jid, fullMsg, options);
|
|
2350
2366
|
return fullMsg;
|
|
2351
2367
|
};
|
|
2352
2368
|
/** Sends a rich response with experimental BotCommandMetadata. */
|
|
@@ -2355,7 +2371,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
2355
2371
|
const { text = 'Bot command test', commandName = '', commandDescription = '', commandPrompt = '', botJid = '867051314767696@bot' } = content;
|
|
2356
2372
|
const wrapped = buildBotRichResponse({ text, botJid, botMetadata: { commandMetadata: { commandName, commandDescription, commandPrompt } } });
|
|
2357
2373
|
const fullMsg = await generateWAMessageFromContent(jid, wrapped, { logger, userJid: authState.creds.me?.id, messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id), ...options });
|
|
2358
|
-
await
|
|
2374
|
+
await relayRichMessage(jid, fullMsg, options);
|
|
2359
2375
|
return fullMsg;
|
|
2360
2376
|
};
|
|
2361
2377
|
/** Sends a planning/execution-plan rich response with WAProto capabilities. */
|
|
@@ -2378,7 +2394,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
2378
2394
|
]
|
|
2379
2395
|
});
|
|
2380
2396
|
const fullMsg = await generateWAMessageFromContent(jid, wrapped, { logger, userJid: authState.creds.me?.id, messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id), ...options });
|
|
2381
|
-
await
|
|
2397
|
+
await relayRichMessage(jid, fullMsg, options);
|
|
2382
2398
|
return fullMsg;
|
|
2383
2399
|
};
|
|
2384
2400
|
/** Sends a rich response with experimental BotResolvedToolCallMetadata. */
|
|
@@ -2397,7 +2413,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
2397
2413
|
}
|
|
2398
2414
|
});
|
|
2399
2415
|
const fullMsg = await generateWAMessageFromContent(jid, wrapped, { logger, userJid: authState.creds.me?.id, messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id), ...options });
|
|
2400
|
-
await
|
|
2416
|
+
await relayRichMessage(jid, fullMsg, options);
|
|
2401
2417
|
return fullMsg;
|
|
2402
2418
|
};
|
|
2403
2419
|
socket.sendStatus = async (content, options = {}) => {
|
|
@@ -2600,25 +2616,53 @@ export const makeMessagesSocket = (config) => {
|
|
|
2600
2616
|
|
|
2601
2617
|
|
|
2602
2618
|
/**
|
|
2603
|
-
* Sends an
|
|
2604
|
-
*
|
|
2605
|
-
*
|
|
2619
|
+
* Sends an AIRich GRID_IMAGE album. Unlike the legacy albumMessage
|
|
2620
|
+
* collection, this is one forwarded unified-response message containing
|
|
2621
|
+
* the requested image primitives.
|
|
2606
2622
|
*/
|
|
2607
2623
|
socket.sendAlbumMessage = async (jid, medias = [], options = {}) => {
|
|
2608
2624
|
if (!jid) throw new Boom('sendAlbumMessage requires a target JID', { statusCode: 400 });
|
|
2609
2625
|
if (!Array.isArray(medias) || medias.length < 2) {
|
|
2610
2626
|
throw new Boom('sendAlbumMessage requires at least two media items', { statusCode: 400 });
|
|
2611
2627
|
}
|
|
2612
|
-
const
|
|
2613
|
-
const
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
if (index === 0 && options.caption && !normalized.caption) {
|
|
2617
|
-
normalized.caption = options.caption;
|
|
2628
|
+
const imageUrls = medias.map((media) => {
|
|
2629
|
+
const raw = media?.type && media?.data ? media.data : (media?.image ?? media);
|
|
2630
|
+
if (media?.video || media?.type === 'video') {
|
|
2631
|
+
throw new Boom('GRID_IMAGE albums support images only', { statusCode: 400 });
|
|
2618
2632
|
}
|
|
2619
|
-
|
|
2633
|
+
const sourceUrl = typeof raw === 'string' ? raw : (raw?.sourceUrl || raw?.url || '');
|
|
2634
|
+
if (!sourceUrl) {
|
|
2635
|
+
throw new Boom('Each GRID_IMAGE album item requires an image URL', { statusCode: 400 });
|
|
2636
|
+
}
|
|
2637
|
+
return {
|
|
2638
|
+
sourceUrl,
|
|
2639
|
+
imagePreviewUrl: raw?.imagePreviewUrl || raw?.previewUrl || sourceUrl,
|
|
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
|
|
2647
|
+
};
|
|
2648
|
+
});
|
|
2649
|
+
const wrapped = prepareGridImageMessage({
|
|
2650
|
+
imageUrls,
|
|
2651
|
+
verificationMetadata: options.verificationMetadata
|
|
2652
|
+
});
|
|
2653
|
+
const fullMsg = generateWAMessageFromContent(jid, wrapped, {
|
|
2654
|
+
logger,
|
|
2655
|
+
userJid: authState.creds.me?.id,
|
|
2656
|
+
messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id || jid),
|
|
2657
|
+
...options
|
|
2620
2658
|
});
|
|
2621
|
-
|
|
2659
|
+
await relayRichMessage(jid, fullMsg, options);
|
|
2660
|
+
if (config.emitOwnEvents) {
|
|
2661
|
+
process.nextTick(async () => {
|
|
2662
|
+
await messageMutex.mutex(() => upsertMessage(fullMsg, 'append'));
|
|
2663
|
+
});
|
|
2664
|
+
}
|
|
2665
|
+
return fullMsg;
|
|
2622
2666
|
};
|
|
2623
2667
|
|
|
2624
2668
|
|
|
@@ -2677,11 +2721,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
2677
2721
|
messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id),
|
|
2678
2722
|
...options
|
|
2679
2723
|
});
|
|
2680
|
-
await
|
|
2681
|
-
messageId: fullMsg.key.id,
|
|
2682
|
-
useCachedGroupMetadata: options.useCachedGroupMetadata,
|
|
2683
|
-
statusJidList: options.statusJidList
|
|
2684
|
-
});
|
|
2724
|
+
await relayRichMessage(jid, fullMsg, options);
|
|
2685
2725
|
return fullMsg;
|
|
2686
2726
|
};
|
|
2687
2727
|
|
|
@@ -24,7 +24,6 @@ import {
|
|
|
24
24
|
buildPlainPlaceholder,
|
|
25
25
|
PlanningStepStatus
|
|
26
26
|
} from './meta-compositing.js';
|
|
27
|
-
import { botMetadataSignature, botMetadataCertificate } from './rich-message-utils.js';
|
|
28
27
|
import { BOT_RENDERING_CONFIG_METADATA } from '../Defaults/index.js';
|
|
29
28
|
import { delay } from './generics.js';
|
|
30
29
|
|
package/lib/Utils/messages.js
CHANGED
|
@@ -1061,30 +1061,8 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
1061
1061
|
};
|
|
1062
1062
|
delete m.orderMessage.orderText;
|
|
1063
1063
|
}
|
|
1064
|
-
// Lia@Changes 31-01-26 --- Add support for album messages
|
|
1065
1064
|
else if (hasNonNullishProperty(message, 'album')) {
|
|
1066
|
-
|
|
1067
|
-
throw new Boom('Invalid album type. Expected an array.', { statusCode: 400 });
|
|
1068
|
-
}
|
|
1069
|
-
let videoCount = 0;
|
|
1070
|
-
for (let i = 0; i < message.album.length; i++) {
|
|
1071
|
-
if (message.album[i].video)
|
|
1072
|
-
videoCount++;
|
|
1073
|
-
}
|
|
1074
|
-
;
|
|
1075
|
-
let imageCount = 0;
|
|
1076
|
-
for (let i = 0; i < message.album.length; i++) {
|
|
1077
|
-
if (message.album[i].image)
|
|
1078
|
-
imageCount++;
|
|
1079
|
-
}
|
|
1080
|
-
;
|
|
1081
|
-
if ((videoCount + imageCount) < 2) {
|
|
1082
|
-
throw new Boom('Minimum provide 2 media to upload album message', { statusCode: 400 });
|
|
1083
|
-
}
|
|
1084
|
-
m.albumMessage = {
|
|
1085
|
-
expectedImageCount: imageCount,
|
|
1086
|
-
expectedVideoCount: videoCount
|
|
1087
|
-
};
|
|
1065
|
+
throw new Boom('Legacy albumMessage is removed; use socket.sendAlbumMessage() for an AIRich GRID_IMAGE album', { statusCode: 400 });
|
|
1088
1066
|
}
|
|
1089
1067
|
else if (hasNonNullishProperty(message, 'sharePhoneNumber')) {
|
|
1090
1068
|
m.protocolMessage = {
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* If you use or copy this code, please credit my name or project. AND DO NOT CHANGE THIS NOTE
|
|
6
6
|
*/
|
|
7
7
|
import { getRandomValues, randomUUID, randomBytes } from 'crypto';
|
|
8
|
-
import { DONATE_URL, LEXER_REGEX } from '../Defaults/index.js';
|
|
8
|
+
import { BOT_RENDERING_CONFIG_METADATA, DONATE_URL, LEXER_REGEX } from '../Defaults/index.js';
|
|
9
9
|
import { LANGUAGE_KEYWORDS } from '../WABinary/constants.js';
|
|
10
10
|
import { CodeHighlightType, RichSubMessageType } from '../Types/RichType.js';
|
|
11
11
|
import { proto } from '../../WAProto/index.js';
|
|
@@ -62,6 +62,30 @@ export const toUnified = (submessages, uuid) => ({
|
|
|
62
62
|
}
|
|
63
63
|
};
|
|
64
64
|
}
|
|
65
|
+
case RichSubMessageType.GRID_IMAGE: {
|
|
66
|
+
const imageUrls = submessage.gridImageMetadata?.imageUrls || [];
|
|
67
|
+
if (!imageUrls.length) return null;
|
|
68
|
+
const expiration = String(Date.now() + 30 * 24 * 60 * 60 * 1000);
|
|
69
|
+
const primitives = imageUrls.map(img => {
|
|
70
|
+
const previewUrl = img.imagePreviewUrl || img.sourceUrl || '';
|
|
71
|
+
const fullUrl = img.imageHighResUrl || img.imagePreviewUrl || img.sourceUrl || '';
|
|
72
|
+
const width = img.width || 600;
|
|
73
|
+
const height = img.height || 400;
|
|
74
|
+
const darkPreviewUrl = img.darkModePreviewUrl || previewUrl;
|
|
75
|
+
const darkFullUrl = img.darkModeHighResUrl || img.darkModePreviewUrl || fullUrl;
|
|
76
|
+
const darkWidth = img.darkWidth || width;
|
|
77
|
+
const darkHeight = img.darkHeight || height;
|
|
78
|
+
return {
|
|
79
|
+
preview_image: { url: previewUrl, mime_type: 'image/png', expiration_timestamp_ms: expiration, width, height },
|
|
80
|
+
full_image: { url: fullUrl, mime_type: 'image/png', expiration_timestamp_ms: expiration, width, height },
|
|
81
|
+
dark_mode_preview_image: { url: darkPreviewUrl, mime_type: 'image/png', expiration_timestamp_ms: expiration, width: darkWidth, height: darkHeight },
|
|
82
|
+
dark_mode_full_image: { url: darkFullUrl, mime_type: 'image/png', expiration_timestamp_ms: expiration, width: darkWidth, height: darkHeight },
|
|
83
|
+
asset_query_status: 'FETCHED',
|
|
84
|
+
__typename: 'GenAIImagePrimitive'
|
|
85
|
+
};
|
|
86
|
+
});
|
|
87
|
+
return { view_model: { primitives, __typename: 'GenAIGridLayoutViewModel' } };
|
|
88
|
+
}
|
|
65
89
|
case RichSubMessageType.CONTENT_ITEMS: {
|
|
66
90
|
const items = submessage.contentItemsMetadata?.itemsMetadata || [];
|
|
67
91
|
const primitives = items.map((item) => {
|
|
@@ -196,7 +220,8 @@ export const prepareRichGenerationMessage = ({
|
|
|
196
220
|
estimatedMs,
|
|
197
221
|
itemId = `imagine_${randomUUID()}`,
|
|
198
222
|
responseId = randomUUID(),
|
|
199
|
-
forwarded = true
|
|
223
|
+
forwarded = true,
|
|
224
|
+
verificationMetadata
|
|
200
225
|
} = {}) => {
|
|
201
226
|
const sections = [];
|
|
202
227
|
if (text) {
|
|
@@ -210,7 +235,7 @@ export const prepareRichGenerationMessage = ({
|
|
|
210
235
|
unifiedResponse: { data: Buffer.from(JSON.stringify({ response_id: responseId, sections })) },
|
|
211
236
|
contextInfo: forwarded ? { isForwarded: true, forwardingScore: 1, forwardedAiBotMessageInfo: { botJid: '867051314767696@bot' }, forwardOrigin: 4 } : {}
|
|
212
237
|
});
|
|
213
|
-
const message = wrapToBotForwardedMessage(richResponseMessage);
|
|
238
|
+
const message = wrapToBotForwardedMessage(richResponseMessage, verificationMetadata);
|
|
214
239
|
message.messageContextInfo = message.messageContextInfo || {};
|
|
215
240
|
message.messageContextInfo.botMetadata = {
|
|
216
241
|
...(message.messageContextInfo.botMetadata || {}),
|
|
@@ -220,56 +245,72 @@ export const prepareRichGenerationMessage = ({
|
|
|
220
245
|
};
|
|
221
246
|
|
|
222
247
|
// Lia@Note 17-04-26 --- WIP
|
|
248
|
+
/**
|
|
249
|
+
* A preview-media descriptor is only meaningful when the client can locate and
|
|
250
|
+
* decrypt the media. A descriptor without a key, hash and direct path describes
|
|
251
|
+
* media that cannot be fetched, so it is dropped rather than shipped
|
|
252
|
+
* present-but-empty (which is what previously produced `''` crypto fields and a
|
|
253
|
+
* hard-coded `image/jpeg` mimetype on every reel).
|
|
254
|
+
*
|
|
255
|
+
* Callers that upload real media supply it as `previewMedia` on the reel item or
|
|
256
|
+
* LaTeX expression: `{ fileSha256, mediaKey, fileEncSha256, directPath, mimetype?, mediaKeyTimestamp?, mediaId? }`.
|
|
257
|
+
*/
|
|
258
|
+
const normalizePreviewMedia = (media) => {
|
|
259
|
+
if (!media || typeof media !== 'object') return null;
|
|
260
|
+
const { fileSha256, mediaKey, fileEncSha256, directPath, mimetype, mediaKeyTimestamp } = media;
|
|
261
|
+
if (!fileSha256 || !mediaKey || !fileEncSha256 || !directPath) return null;
|
|
262
|
+
return {
|
|
263
|
+
fileSha256,
|
|
264
|
+
mediaKey,
|
|
265
|
+
fileEncSha256,
|
|
266
|
+
directPath,
|
|
267
|
+
mediaKeyTimestamp: mediaKeyTimestamp ?? unixTimestampSeconds(),
|
|
268
|
+
mimetype: mimetype || 'image/jpeg'
|
|
269
|
+
};
|
|
270
|
+
};
|
|
271
|
+
|
|
223
272
|
export const buildAdditionalBotMetadataContext = (submessages) => {
|
|
224
273
|
const sources = [];
|
|
225
274
|
const mediaDetailsMetadataList = [];
|
|
226
|
-
for (
|
|
227
|
-
const submessage = submessages[i];
|
|
275
|
+
for (const submessage of submessages) {
|
|
228
276
|
switch (submessage.messageType) {
|
|
229
277
|
case RichSubMessageType.CONTENT_ITEMS: {
|
|
230
278
|
const itemsMetadata = submessage.contentItemsMetadata?.itemsMetadata || [];
|
|
231
|
-
for (
|
|
232
|
-
const reelItem =
|
|
279
|
+
for (const item of itemsMetadata) {
|
|
280
|
+
const reelItem = item?.reelItem || item || {};
|
|
233
281
|
sources.push({
|
|
234
282
|
provider: 0,
|
|
235
283
|
thumbnailCdnUrl: reelItem.thumbnailUrl || reelItem.thumbnail_url || '',
|
|
236
284
|
sourceProviderUrl: reelItem.videoUrl || reelItem.reels_url || reelItem.url || '',
|
|
237
285
|
sourceQuery: '',
|
|
238
286
|
faviconCdnUrl: reelItem.profileIconUrl || reelItem.avatar_url || '',
|
|
239
|
-
|
|
287
|
+
// 1-based source ordinal, not the submessage index.
|
|
288
|
+
citationNumber: sources.length + 1,
|
|
240
289
|
sourceTitle: reelItem.title || reelItem.reels_title || reelItem.creator || ''
|
|
241
290
|
});
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
mediaKeyTimestamp: unixTimestampSeconds(),
|
|
250
|
-
mimetype: 'image/jpeg'
|
|
251
|
-
}
|
|
252
|
-
});
|
|
291
|
+
const previewMedia = normalizePreviewMedia(reelItem.previewMedia);
|
|
292
|
+
if (previewMedia) {
|
|
293
|
+
mediaDetailsMetadataList.push({
|
|
294
|
+
id: reelItem.mediaId || reelItem.previewMedia?.mediaId || randomBytes(32).toString('hex'),
|
|
295
|
+
previewMedia
|
|
296
|
+
});
|
|
297
|
+
}
|
|
253
298
|
}
|
|
254
299
|
break;
|
|
255
300
|
}
|
|
256
|
-
case RichSubMessageType.LATEX:
|
|
257
|
-
const expressions = submessage.latexMetadata
|
|
258
|
-
for (
|
|
259
|
-
const
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
directPath: '',
|
|
267
|
-
mediaKeyTimestamp: unixTimestampSeconds(),
|
|
268
|
-
mimetype: 'image/jpeg'
|
|
269
|
-
}
|
|
270
|
-
});
|
|
301
|
+
case RichSubMessageType.LATEX: {
|
|
302
|
+
const expressions = submessage.latexMetadata?.expressions || [];
|
|
303
|
+
for (const expression of expressions) {
|
|
304
|
+
const previewMedia = normalizePreviewMedia(expression?.previewMedia);
|
|
305
|
+
if (previewMedia) {
|
|
306
|
+
mediaDetailsMetadataList.push({
|
|
307
|
+
id: expression.mediaId || expression.previewMedia?.mediaId || randomBytes(32).toString('hex'),
|
|
308
|
+
previewMedia
|
|
309
|
+
});
|
|
310
|
+
}
|
|
271
311
|
}
|
|
272
312
|
break;
|
|
313
|
+
}
|
|
273
314
|
}
|
|
274
315
|
}
|
|
275
316
|
return { sources, mediaDetailsMetadataList };
|
|
@@ -336,7 +377,7 @@ const richMenuButton = (button, toast = '') => {
|
|
|
336
377
|
* buttonsMessage/nativeFlowMessage payload.
|
|
337
378
|
*/
|
|
338
379
|
export const prepareRichMenuMessage = (content = {}) => {
|
|
339
|
-
const { header = {}, body = {}, footer = {} } = content || {};
|
|
380
|
+
const { header = {}, body = {}, footer = {}, verificationMetadata } = content || {};
|
|
340
381
|
const sections = [];
|
|
341
382
|
const title = header?.title || '';
|
|
342
383
|
if (title) {
|
|
@@ -418,7 +459,7 @@ export const prepareRichMenuMessage = (content = {}) => {
|
|
|
418
459
|
unifiedResponse: { data: Buffer.from(JSON.stringify(unified)) },
|
|
419
460
|
contextInfo: { isForwarded: true, forwardingScore: 1, forwardOrigin: 4 },
|
|
420
461
|
});
|
|
421
|
-
return wrapToBotForwardedMessage(richResponseMessage);
|
|
462
|
+
return wrapToBotForwardedMessage(richResponseMessage, verificationMetadata);
|
|
422
463
|
};
|
|
423
464
|
|
|
424
465
|
/**
|
|
@@ -432,7 +473,7 @@ export const prepareRichMenuMessage = (content = {}) => {
|
|
|
432
473
|
* @returns {Object} Wrapped botForwardedMessage ready for relayMessage
|
|
433
474
|
*/
|
|
434
475
|
export const prepareCopyToClipboardMessage = (options = {}) => {
|
|
435
|
-
const { text = '', label, alignment = 'END' } = options;
|
|
476
|
+
const { text = '', label, alignment = 'END', verificationMetadata } = options;
|
|
436
477
|
const displayText = label || text;
|
|
437
478
|
const sections = [
|
|
438
479
|
{
|
|
@@ -458,7 +499,7 @@ export const prepareCopyToClipboardMessage = (options = {}) => {
|
|
|
458
499
|
unifiedResponse: { data: Buffer.from(JSON.stringify(unified)) },
|
|
459
500
|
contextInfo: { isForwarded: true, forwardingScore: 1, forwardOrigin: 4 },
|
|
460
501
|
});
|
|
461
|
-
return wrapToBotForwardedMessage(richResponseMessage);
|
|
502
|
+
return wrapToBotForwardedMessage(richResponseMessage, verificationMetadata);
|
|
462
503
|
};
|
|
463
504
|
|
|
464
505
|
/**
|
|
@@ -470,7 +511,7 @@ export const prepareCopyToClipboardMessage = (options = {}) => {
|
|
|
470
511
|
* @returns {Object} Wrapped botForwardedMessage ready for relayMessage
|
|
471
512
|
*/
|
|
472
513
|
export const prepareRichTextMessage = (options = {}) => {
|
|
473
|
-
const { text = '' } = options;
|
|
514
|
+
const { text = '', verificationMetadata } = options;
|
|
474
515
|
const sections = [
|
|
475
516
|
{
|
|
476
517
|
__typename: 'GenAIUnifiedResponseSection',
|
|
@@ -491,12 +532,12 @@ export const prepareRichTextMessage = (options = {}) => {
|
|
|
491
532
|
unifiedResponse: { data: Buffer.from(JSON.stringify(unified)) },
|
|
492
533
|
contextInfo: { isForwarded: true, forwardingScore: 1, forwardOrigin: 4 },
|
|
493
534
|
});
|
|
494
|
-
return wrapToBotForwardedMessage(richResponseMessage);
|
|
535
|
+
return wrapToBotForwardedMessage(richResponseMessage, verificationMetadata);
|
|
495
536
|
};
|
|
496
537
|
|
|
497
538
|
/** Builds Markdown text with an optional GenAI COPY_TO_CLIPBOARD action section. */
|
|
498
539
|
export const prepareRichQuoteMessage = (options = {}) => {
|
|
499
|
-
const { text = '', copyText, copyLabel = copyText, alignment = 'END' } = options;
|
|
540
|
+
const { text = '', copyText, copyLabel = copyText, alignment = 'END', verificationMetadata } = options;
|
|
500
541
|
const sections = [{
|
|
501
542
|
__typename: 'GenAIUnifiedResponseSection',
|
|
502
543
|
view_model: {
|
|
@@ -522,7 +563,7 @@ export const prepareRichQuoteMessage = (options = {}) => {
|
|
|
522
563
|
unifiedResponse: { data: Buffer.from(JSON.stringify(unified)) },
|
|
523
564
|
contextInfo: { isForwarded: true, forwardingScore: 1, forwardOrigin: 4 },
|
|
524
565
|
});
|
|
525
|
-
return wrapToBotForwardedMessage(richResponseMessage);
|
|
566
|
+
return wrapToBotForwardedMessage(richResponseMessage, verificationMetadata);
|
|
526
567
|
};
|
|
527
568
|
|
|
528
569
|
/**
|
|
@@ -535,7 +576,7 @@ export const prepareRichQuoteMessage = (options = {}) => {
|
|
|
535
576
|
* @returns {Object} Wrapped botForwardedMessage ready for relayMessage
|
|
536
577
|
*/
|
|
537
578
|
export const prepareRichImageMessage = (options = {}) => {
|
|
538
|
-
const { url = '', mimeType = 'image/png' } = options;
|
|
579
|
+
const { url = '', mimeType = 'image/png', verificationMetadata } = options;
|
|
539
580
|
const media = {
|
|
540
581
|
__typename: 'GenAIMediaItem',
|
|
541
582
|
mime_type: mimeType,
|
|
@@ -562,7 +603,7 @@ export const prepareRichImageMessage = (options = {}) => {
|
|
|
562
603
|
unifiedResponse: { data: Buffer.from(JSON.stringify(unified)) },
|
|
563
604
|
contextInfo: { isForwarded: true, forwardingScore: 1, forwardOrigin: 4 },
|
|
564
605
|
});
|
|
565
|
-
return wrapToBotForwardedMessage(richResponseMessage);
|
|
606
|
+
return wrapToBotForwardedMessage(richResponseMessage, verificationMetadata);
|
|
566
607
|
};
|
|
567
608
|
|
|
568
609
|
|
|
@@ -575,7 +616,7 @@ export const prepareRichImageMessage = (options = {}) => {
|
|
|
575
616
|
* @returns {Object} Wrapped botForwardedMessage ready for relayMessage
|
|
576
617
|
*/
|
|
577
618
|
export const prepareRichLinkMessage = (options = {}) => {
|
|
578
|
-
const { links = [], text: fallbackText } = options;
|
|
619
|
+
const { links = [], text: fallbackText, verificationMetadata } = options;
|
|
579
620
|
const sections = [];
|
|
580
621
|
const allInlineEntities = [];
|
|
581
622
|
let combinedText = '';
|
|
@@ -629,11 +670,35 @@ export const prepareRichLinkMessage = (options = {}) => {
|
|
|
629
670
|
unifiedResponse: { data: Buffer.from(JSON.stringify(unified)) },
|
|
630
671
|
contextInfo: { isForwarded: true, forwardingScore: 1, forwardOrigin: 4 },
|
|
631
672
|
});
|
|
632
|
-
return wrapToBotForwardedMessage(richResponseMessage);
|
|
673
|
+
return wrapToBotForwardedMessage(richResponseMessage, verificationMetadata);
|
|
674
|
+
};
|
|
675
|
+
|
|
676
|
+
/** Build an AIRich GRID_IMAGE album instead of the legacy albumMessage collection. */
|
|
677
|
+
export const prepareGridImageMessage = ({ imageUrls = [], verificationMetadata } = {}) => {
|
|
678
|
+
if (!Array.isArray(imageUrls) || imageUrls.length < 2) {
|
|
679
|
+
throw new Error('GRID_IMAGE album requires at least two images');
|
|
680
|
+
}
|
|
681
|
+
const submessages = [{
|
|
682
|
+
messageType: RichSubMessageType.GRID_IMAGE,
|
|
683
|
+
gridImageMetadata: { imageUrls }
|
|
684
|
+
}];
|
|
685
|
+
const unified = toUnified(submessages, randomUUID());
|
|
686
|
+
const richResponseMessage = proto.AIRichResponseMessage.create({
|
|
687
|
+
submessages,
|
|
688
|
+
messageType: proto.AIRichResponseMessageType.AI_RICH_RESPONSE_TYPE_STANDARD,
|
|
689
|
+
unifiedResponse: { data: Buffer.from(JSON.stringify(unified)) },
|
|
690
|
+
contextInfo: {
|
|
691
|
+
isForwarded: true,
|
|
692
|
+
forwardingScore: 1,
|
|
693
|
+
forwardedAiBotMessageInfo: { botJid: '867051314767696@bot' },
|
|
694
|
+
forwardOrigin: 4
|
|
695
|
+
}
|
|
696
|
+
});
|
|
697
|
+
return wrapToBotForwardedMessage(richResponseMessage, verificationMetadata);
|
|
633
698
|
};
|
|
634
699
|
|
|
635
700
|
export const prepareRichResponseMessage = (content) => {
|
|
636
|
-
const { alignment, code, contentText, disclaimerText, footerText, headerText, imageText, inlineImage, inlineVideo, items, language, latex, links, noDonation, noHeading, posts, products, reels, sources: sourceInputs, suggested, richResponse, table, tapLinkUrl, title } = content;
|
|
701
|
+
const { alignment, code, contentText, disclaimerText, footerText, headerText, imageText, inlineImage, inlineVideo, items, language, latex, links, noDonation, noHeading, posts, products, reels, sources: sourceInputs, suggested, richResponse, table, tapLinkUrl, title, verificationMetadata } = content;
|
|
637
702
|
let submessages = [];
|
|
638
703
|
if (Array.isArray(richResponse)) {
|
|
639
704
|
submessages = richResponse.map((submessage) => {
|
|
@@ -753,7 +818,10 @@ export const prepareRichResponseMessage = (content) => {
|
|
|
753
818
|
reelSource: reel?.reelSource || reel?.reel_source || 'IG',
|
|
754
819
|
isVerified: !!(reel?.isVerified ?? reel?.is_verified)
|
|
755
820
|
} })) : [];
|
|
756
|
-
const resolvedItems =
|
|
821
|
+
const resolvedItems = [
|
|
822
|
+
...(Array.isArray(items) ? items : []),
|
|
823
|
+
...reelItems
|
|
824
|
+
];
|
|
757
825
|
if (resolvedItems?.length) {
|
|
758
826
|
submessages.push({
|
|
759
827
|
messageType: RichSubMessageType.CONTENT_ITEMS,
|
|
@@ -879,7 +947,7 @@ export const prepareRichResponseMessage = (content) => {
|
|
|
879
947
|
forwardOrigin: 4
|
|
880
948
|
}
|
|
881
949
|
});
|
|
882
|
-
const message = wrapToBotForwardedMessage(richResponseMessage);
|
|
950
|
+
const message = wrapToBotForwardedMessage(richResponseMessage, verificationMetadata);
|
|
883
951
|
const botMetadata = message.messageContextInfo.botMetadata;
|
|
884
952
|
// Lia@Note 13-05-26 --- Add disclaimer text on richResponseMessage
|
|
885
953
|
if (disclaimerText) {
|
|
@@ -898,6 +966,11 @@ export const prepareRichResponseMessage = (content) => {
|
|
|
898
966
|
return message;
|
|
899
967
|
};
|
|
900
968
|
// Lia@Note 17-04-26 --- signature and certificateChain for proofs[] field
|
|
969
|
+
/**
|
|
970
|
+
* @deprecated Generates random bytes that verify against nothing. Kept only for
|
|
971
|
+
* experimental tooling; the library no longer attaches generated proofs to
|
|
972
|
+
* messages. Pass real proofs through the `verificationMetadata` option instead.
|
|
973
|
+
*/
|
|
901
974
|
export const botMetadataSignature = () => {
|
|
902
975
|
const signature = new Uint8Array(64);
|
|
903
976
|
getRandomValues(signature);
|
|
@@ -923,7 +996,7 @@ export const botMetadataCertificate = (length = 685) => {
|
|
|
923
996
|
* @returns {Object} Wrapped botForwardedMessage ready for relayMessage
|
|
924
997
|
*/
|
|
925
998
|
export const prepareHtmlMessage = (options = {}) => {
|
|
926
|
-
const { html = '', trustedSources = [] } = options;
|
|
999
|
+
const { html = '', trustedSources = [], verificationMetadata } = options;
|
|
927
1000
|
const sections = [
|
|
928
1001
|
{
|
|
929
1002
|
__typename: 'GenAIUnifiedResponseSection',
|
|
@@ -944,7 +1017,7 @@ export const prepareHtmlMessage = (options = {}) => {
|
|
|
944
1017
|
unifiedResponse: { data: Buffer.from(JSON.stringify(unified)) },
|
|
945
1018
|
contextInfo: { isForwarded: true, forwardingScore: 1, forwardOrigin: 4 },
|
|
946
1019
|
});
|
|
947
|
-
return wrapToBotForwardedMessage(richResponseMessage);
|
|
1020
|
+
return wrapToBotForwardedMessage(richResponseMessage, verificationMetadata);
|
|
948
1021
|
};
|
|
949
1022
|
|
|
950
1023
|
/**
|
|
@@ -959,7 +1032,8 @@ export const prepareRichHtmlMessage = (options = {}) => {
|
|
|
959
1032
|
url = '',
|
|
960
1033
|
title = 'Preview',
|
|
961
1034
|
tabHeader = 'HTML',
|
|
962
|
-
tabs
|
|
1035
|
+
tabs,
|
|
1036
|
+
verificationMetadata
|
|
963
1037
|
} = options;
|
|
964
1038
|
const tabItems = Array.isArray(tabs) && tabs.length
|
|
965
1039
|
? tabs
|
|
@@ -1003,26 +1077,55 @@ export const prepareRichHtmlMessage = (options = {}) => {
|
|
|
1003
1077
|
unifiedResponse: { data: Buffer.from(JSON.stringify(unified)) },
|
|
1004
1078
|
contextInfo: { isForwarded: true, forwardingScore: 1, forwardOrigin: 4 }
|
|
1005
1079
|
});
|
|
1006
|
-
return wrapToBotForwardedMessage(richResponseMessage);
|
|
1080
|
+
return wrapToBotForwardedMessage(richResponseMessage, verificationMetadata);
|
|
1081
|
+
};
|
|
1082
|
+
|
|
1083
|
+
/**
|
|
1084
|
+
* Proofs are forwarded only when the caller supplies real, verifiable proofs.
|
|
1085
|
+
* The library never fabricates a certificate chain or signature: an unverifiable
|
|
1086
|
+
* proof is worse than none, because it asserts provenance the caller cannot back.
|
|
1087
|
+
*/
|
|
1088
|
+
export const hasVerifiableProofs = (verificationMetadata) =>
|
|
1089
|
+
Array.isArray(verificationMetadata?.proofs) && verificationMetadata.proofs.length > 0;
|
|
1090
|
+
|
|
1091
|
+
/**
|
|
1092
|
+
* Attach trusted verification proofs to an already-built rich envelope.
|
|
1093
|
+
*
|
|
1094
|
+
* Pure, null-safe, and idempotent: returns the envelope untouched when no
|
|
1095
|
+
* verifiable proofs are supplied or when the envelope carries no botMetadata.
|
|
1096
|
+
* Used by the send pipeline (`relayMessage`) to auto-inject proofs configured
|
|
1097
|
+
* once on the socket as `config.metaAiRendering.verificationMetadata`, so every
|
|
1098
|
+
* rich message (menu, reels, rich text/image/link, HTML) is covered without each
|
|
1099
|
+
* send method needing to thread the config through.
|
|
1100
|
+
*/
|
|
1101
|
+
export const attachBotVerificationProofs = (envelope, verificationMetadata) => {
|
|
1102
|
+
if (!envelope || !hasVerifiableProofs(verificationMetadata))
|
|
1103
|
+
return envelope;
|
|
1104
|
+
const botMetadata = envelope?.messageContextInfo?.botMetadata;
|
|
1105
|
+
if (!botMetadata || botMetadata.verificationMetadata)
|
|
1106
|
+
return envelope;
|
|
1107
|
+
botMetadata.verificationMetadata = verificationMetadata;
|
|
1108
|
+
return envelope;
|
|
1007
1109
|
};
|
|
1008
1110
|
|
|
1009
|
-
|
|
1111
|
+
/**
|
|
1112
|
+
* Wrap a rich response in the bot-forwarded envelope.
|
|
1113
|
+
*
|
|
1114
|
+
* @param {Object} richResponseMessage - proto.AIRichResponseMessage
|
|
1115
|
+
* @param {Object} [verificationMetadata] - Trusted proofs supplied by the caller
|
|
1116
|
+
* (typically `config.metaAiRendering.verificationMetadata`). Omitted when absent
|
|
1117
|
+
* or empty, so no fabricated provenance is ever sent.
|
|
1118
|
+
*/
|
|
1119
|
+
export const wrapToBotForwardedMessage = (richResponseMessage, verificationMetadata) => ({
|
|
1010
1120
|
messageContextInfo: {
|
|
1011
1121
|
botMetadata: {
|
|
1012
|
-
|
|
1013
|
-
verificationMetadata: {
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
],
|
|
1020
|
-
version: 1,
|
|
1021
|
-
useCase: 1,
|
|
1022
|
-
signature: botMetadataSignature()
|
|
1023
|
-
}
|
|
1024
|
-
]
|
|
1025
|
-
}
|
|
1122
|
+
pluginMetadata: {},
|
|
1123
|
+
...(hasVerifiableProofs(verificationMetadata) ? { verificationMetadata } : {}),
|
|
1124
|
+
// Lia@Fix --- The Bloks rendering config is required for the client to resolve
|
|
1125
|
+
// and verify rich media. Without it, rich messages attach media the client
|
|
1126
|
+
// treats as unverified: "WhatsApp can't verify the security of this media",
|
|
1127
|
+
// tapping Download crashes the app, and reel previews stop rendering.
|
|
1128
|
+
botRenderingConfigMetadata: BOT_RENDERING_CONFIG_METADATA
|
|
1026
1129
|
}
|
|
1027
1130
|
},
|
|
1028
1131
|
botForwardedMessage: {
|
package/lib/index.d.ts
CHANGED
|
@@ -224,7 +224,17 @@ export interface RelayMessageOptions {
|
|
|
224
224
|
|
|
225
225
|
export interface AlbumMediaInput {
|
|
226
226
|
image?: unknown;
|
|
227
|
-
|
|
227
|
+
type?: 'image';
|
|
228
|
+
data?: unknown;
|
|
229
|
+
sourceUrl?: string;
|
|
230
|
+
imagePreviewUrl?: string;
|
|
231
|
+
imageHighResUrl?: string;
|
|
232
|
+
darkModePreviewUrl?: string;
|
|
233
|
+
darkModeHighResUrl?: string;
|
|
234
|
+
width?: number;
|
|
235
|
+
height?: number;
|
|
236
|
+
darkWidth?: number;
|
|
237
|
+
darkHeight?: number;
|
|
228
238
|
caption?: string;
|
|
229
239
|
[key: string]: unknown;
|
|
230
240
|
}
|
|
@@ -238,7 +248,7 @@ export interface AnimatedWallpaperInput {
|
|
|
238
248
|
|
|
239
249
|
export interface WASocket {
|
|
240
250
|
sendMessage(jid: string | string[], content: StatusContent | GroupStatusContent | Record<string, unknown>, options?: Partial<StatusOptions> & Record<string, unknown>): Promise<unknown>;
|
|
241
|
-
/** Send at least two image
|
|
251
|
+
/** Send at least two image URL items as an AIRich GRID_IMAGE album. */
|
|
242
252
|
sendAlbumMessage(jid: string, medias: AlbumMediaInput[], options?: Record<string, unknown>): Promise<unknown>;
|
|
243
253
|
/** Update the connected account's WhatsApp About/profile status. */
|
|
244
254
|
updateProfileStatus(status: string): Promise<void>;
|
|
@@ -270,6 +280,8 @@ export interface WASocket {
|
|
|
270
280
|
sendBotPlanning(jid: string, content?: { text?: string; steps?: Array<string | { title?: string; name?: string; body?: string }>; queryPlan?: boolean; botJid?: string }, options?: Record<string, unknown>): Promise<unknown>;
|
|
271
281
|
/** Send a rich response with experimental resolved tool-call metadata. */
|
|
272
282
|
sendBotToolResult(jid: string, content?: { text?: string; toolCallId?: string; resolutionData?: unknown; resolutionDataSerialized?: string; botJid?: string }, options?: Record<string, unknown>): Promise<unknown>;
|
|
283
|
+
/** Send one tolerant AIRich response containing every supported section supplied in content. */
|
|
284
|
+
sendPlogmeMessage(jid: string, content?: Record<string, unknown>, quoted?: unknown, options?: Record<string, unknown>): Promise<unknown>;
|
|
273
285
|
/** Resolve a WhatsApp Channel invite code or invite URL to channel metadata. */
|
|
274
286
|
newsletterGetInviteInfo(inviteCodeOrUrl: string): Promise<Record<string, unknown> | null>;
|
|
275
287
|
/** React to a Channel post; pass an empty string, null, or undefined to remove the reaction. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "plogme",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.3",
|
|
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",
|