plogme 2.0.2 → 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 +153 -124
- package/lib/Utils/messages.js +1 -23
- package/lib/Utils/rich-message-utils.js +52 -1
- 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, attachBotVerificationProofs, hasVerifiableProofs } 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';
|
|
@@ -1033,6 +1033,53 @@ export const makeMessagesSocket = (config) => {
|
|
|
1033
1033
|
return msgId;
|
|
1034
1034
|
};
|
|
1035
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
|
+
|
|
1036
1083
|
const getMessageType = (message) => {
|
|
1037
1084
|
if (!message)
|
|
1038
1085
|
return 'text';
|
|
@@ -1391,11 +1438,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
1391
1438
|
quoted,
|
|
1392
1439
|
...options
|
|
1393
1440
|
});
|
|
1394
|
-
await
|
|
1395
|
-
messageId: generated.key.id,
|
|
1396
|
-
useCachedGroupMetadata: options.useCachedGroupMetadata,
|
|
1397
|
-
statusJidList: options.statusJidList
|
|
1398
|
-
});
|
|
1441
|
+
await relayRichMessage(jid, generated, options);
|
|
1399
1442
|
return { ...generated, messageId: generated.key.id };
|
|
1400
1443
|
},
|
|
1401
1444
|
/**
|
|
@@ -1408,9 +1451,15 @@ export const makeMessagesSocket = (config) => {
|
|
|
1408
1451
|
responseId: options.responseId,
|
|
1409
1452
|
forwarded: options.forwarded !== false
|
|
1410
1453
|
});
|
|
1411
|
-
const
|
|
1412
|
-
|
|
1413
|
-
|
|
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 };
|
|
1414
1463
|
},
|
|
1415
1464
|
/**
|
|
1416
1465
|
* Replace the generation primitive in an existing rich response.
|
|
@@ -1476,14 +1525,47 @@ export const makeMessagesSocket = (config) => {
|
|
|
1476
1525
|
quoted,
|
|
1477
1526
|
...options
|
|
1478
1527
|
});
|
|
1479
|
-
await
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
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,
|
|
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,
|
|
1483
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
|
+
}
|
|
1484
1566
|
return fullMsg;
|
|
1485
1567
|
},
|
|
1486
|
-
captureAndResendUnifiedResponse: async (jid, metaAiMsg, quoted) => {
|
|
1568
|
+
captureAndResendUnifiedResponse: async (jid, metaAiMsg, quoted, options = {}) => {
|
|
1487
1569
|
const captured = captureUnifiedResponse(metaAiMsg);
|
|
1488
1570
|
if (!captured) {
|
|
1489
1571
|
throw new Boom('captureAndResendUnifiedResponse: message contains no unifiedResponse data');
|
|
@@ -1495,11 +1577,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
1495
1577
|
messageId: generated.messageId || generateMessageIDV2(jid),
|
|
1496
1578
|
quoted
|
|
1497
1579
|
});
|
|
1498
|
-
await
|
|
1499
|
-
messageId: fullMsg.key.id,
|
|
1500
|
-
useCachedGroupMetadata: options?.useCachedGroupMetadata,
|
|
1501
|
-
statusJidList: options?.statusJidList
|
|
1502
|
-
});
|
|
1580
|
+
await relayRichMessage(jid, fullMsg, options);
|
|
1503
1581
|
return fullMsg;
|
|
1504
1582
|
},
|
|
1505
1583
|
updateMediaMessage: async (message) => {
|
|
@@ -2039,6 +2117,9 @@ export const makeMessagesSocket = (config) => {
|
|
|
2039
2117
|
}
|
|
2040
2118
|
// ── NORMAL MESSAGE HANDLING ──
|
|
2041
2119
|
else {
|
|
2120
|
+
if ('album' in content) {
|
|
2121
|
+
return socket.sendAlbumMessage(jid, content.album, options);
|
|
2122
|
+
}
|
|
2042
2123
|
const fullMsg = await generateWAMessage(jid, content, {
|
|
2043
2124
|
logger,
|
|
2044
2125
|
userJid,
|
|
@@ -2127,13 +2208,6 @@ export const makeMessagesSocket = (config) => {
|
|
|
2127
2208
|
delete content.ai;
|
|
2128
2209
|
}
|
|
2129
2210
|
|
|
2130
|
-
if ('album' in content) {
|
|
2131
|
-
if (!Array.isArray(content.album) || content.album.length < 2) {
|
|
2132
|
-
throw new Boom('Album requires at least two image or video items', { statusCode: 400 });
|
|
2133
|
-
}
|
|
2134
|
-
fullMsg.message.messageContextInfo ||= {};
|
|
2135
|
-
fullMsg.message.messageContextInfo.messageSecret ||= randomBytes(32);
|
|
2136
|
-
}
|
|
2137
2211
|
await relayMessage(jid, fullMsg.message, {
|
|
2138
2212
|
messageId: fullMsg.key.id,
|
|
2139
2213
|
useCachedGroupMetadata: options.useCachedGroupMetadata,
|
|
@@ -2150,55 +2224,6 @@ export const makeMessagesSocket = (config) => {
|
|
|
2150
2224
|
});
|
|
2151
2225
|
}
|
|
2152
2226
|
|
|
2153
|
-
if ('album' in content) {
|
|
2154
|
-
const { delayMs = 1500 } = options;
|
|
2155
|
-
for (const [messageIndex, albumMedia] of content.album.entries()) {
|
|
2156
|
-
// Give the album collection stanza time to register before
|
|
2157
|
-
// its associated media children are relayed. This mirrors
|
|
2158
|
-
// the ordering used by WhatsApp clients and avoids the
|
|
2159
|
-
// children being treated as unrelated media messages.
|
|
2160
|
-
await delay(delayMs);
|
|
2161
|
-
const albumMsg = await generateWAMessage(jid, albumMedia, {
|
|
2162
|
-
logger,
|
|
2163
|
-
userJid,
|
|
2164
|
-
upload: waUploadToServer,
|
|
2165
|
-
mediaCache: config.mediaCache,
|
|
2166
|
-
options: config.options,
|
|
2167
|
-
...options,
|
|
2168
|
-
messageId: generateMessageIDV2(userJid)
|
|
2169
|
-
});
|
|
2170
|
-
if (!hasValidAlbumMedia(normalizeMessageContent(albumMsg.message))) {
|
|
2171
|
-
throw new Boom('Invalid message type for album', { statusCode: 400 });
|
|
2172
|
-
}
|
|
2173
|
-
albumMsg.message.messageContextInfo ||= {};
|
|
2174
|
-
// WhatsApp expects an encrypted context secret on each album
|
|
2175
|
-
// child. Without it, clients may show the album as an
|
|
2176
|
-
// unsupported message or fail to group the media together.
|
|
2177
|
-
albumMsg.message.messageContextInfo.messageSecret ||= randomBytes(32);
|
|
2178
|
-
albumMsg.message.messageContextInfo.messageAssociation = {
|
|
2179
|
-
parentMessageKey: fullMsg.key,
|
|
2180
|
-
// WhatsApp album child messages use association type 1.
|
|
2181
|
-
// The generated MEDIA_ALBUM enum value (63) is a message
|
|
2182
|
-
// category, not the child-association wire value.
|
|
2183
|
-
associationType: 1,
|
|
2184
|
-
messageIndex
|
|
2185
|
-
};
|
|
2186
|
-
await relayMessage(jid, albumMsg.message, {
|
|
2187
|
-
messageId: albumMsg.key.id,
|
|
2188
|
-
useCachedGroupMetadata: options.useCachedGroupMetadata,
|
|
2189
|
-
addBizAttributes: isNeedBizAttrs,
|
|
2190
|
-
statusJidList: options.statusJidList,
|
|
2191
|
-
additionalAttributes,
|
|
2192
|
-
additionalNodes
|
|
2193
|
-
});
|
|
2194
|
-
if (config.emitOwnEvents) {
|
|
2195
|
-
process.nextTick(async () => {
|
|
2196
|
-
await messageMutex.mutex(() => upsertMessage(albumMsg, 'append'));
|
|
2197
|
-
});
|
|
2198
|
-
}
|
|
2199
|
-
}
|
|
2200
|
-
}
|
|
2201
|
-
|
|
2202
2227
|
return fullMsg;
|
|
2203
2228
|
}
|
|
2204
2229
|
}
|
|
@@ -2216,11 +2241,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
2216
2241
|
messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id),
|
|
2217
2242
|
...options,
|
|
2218
2243
|
});
|
|
2219
|
-
await
|
|
2220
|
-
messageId: fullMsg.key.id,
|
|
2221
|
-
useCachedGroupMetadata: options.useCachedGroupMetadata,
|
|
2222
|
-
statusJidList: options.statusJidList,
|
|
2223
|
-
});
|
|
2244
|
+
await relayRichMessage(jid, fullMsg, options);
|
|
2224
2245
|
if (config.emitOwnEvents) {
|
|
2225
2246
|
process.nextTick(async () => {
|
|
2226
2247
|
await messageMutex.mutex(() => upsertMessage(fullMsg, 'append'));
|
|
@@ -2241,11 +2262,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
2241
2262
|
messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id),
|
|
2242
2263
|
...options,
|
|
2243
2264
|
});
|
|
2244
|
-
await
|
|
2245
|
-
messageId: fullMsg.key.id,
|
|
2246
|
-
useCachedGroupMetadata: options.useCachedGroupMetadata,
|
|
2247
|
-
statusJidList: options.statusJidList,
|
|
2248
|
-
});
|
|
2265
|
+
await relayRichMessage(jid, fullMsg, options);
|
|
2249
2266
|
if (config.emitOwnEvents) {
|
|
2250
2267
|
process.nextTick(async () => {
|
|
2251
2268
|
await messageMutex.mutex(() => upsertMessage(fullMsg, 'append'));
|
|
@@ -2259,7 +2276,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
2259
2276
|
if (!content.copyText) throw new Boom('sendRichTextCopy requires copyText content', { statusCode: 400 });
|
|
2260
2277
|
const wrapped = prepareRichQuoteMessage(content);
|
|
2261
2278
|
const fullMsg = await generateWAMessageFromContent(jid, wrapped, { logger, userJid: authState.creds.me?.id, messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id), ...options });
|
|
2262
|
-
await
|
|
2279
|
+
await relayRichMessage(jid, fullMsg, options);
|
|
2263
2280
|
return fullMsg;
|
|
2264
2281
|
};
|
|
2265
2282
|
/** Sends Markdown text containing blockquotes in a forwarded GenAI rich response. */
|
|
@@ -2267,7 +2284,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
2267
2284
|
if (!jid) throw new Boom('sendMarkdownQuote requires a target JID', { statusCode: 400 });
|
|
2268
2285
|
const wrapped = prepareRichQuoteMessage(content);
|
|
2269
2286
|
const fullMsg = await generateWAMessageFromContent(jid, wrapped, { logger, userJid: authState.creds.me?.id, messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id), ...options });
|
|
2270
|
-
await
|
|
2287
|
+
await relayRichMessage(jid, fullMsg, options);
|
|
2271
2288
|
return fullMsg;
|
|
2272
2289
|
};
|
|
2273
2290
|
/** Sends Markdown blockquotes followed by a GenAI COPY_TO_CLIPBOARD action. */
|
|
@@ -2276,7 +2293,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
2276
2293
|
if (!content.copyText) throw new Boom('sendQuoteCopy requires copyText content', { statusCode: 400 });
|
|
2277
2294
|
const wrapped = prepareRichQuoteMessage(content);
|
|
2278
2295
|
const fullMsg = await generateWAMessageFromContent(jid, wrapped, { logger, userJid: authState.creds.me?.id, messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id), ...options });
|
|
2279
|
-
await
|
|
2296
|
+
await relayRichMessage(jid, fullMsg, options);
|
|
2280
2297
|
return fullMsg;
|
|
2281
2298
|
};
|
|
2282
2299
|
/**
|
|
@@ -2291,11 +2308,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
2291
2308
|
messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id),
|
|
2292
2309
|
...options,
|
|
2293
2310
|
});
|
|
2294
|
-
await
|
|
2295
|
-
messageId: fullMsg.key.id,
|
|
2296
|
-
useCachedGroupMetadata: options.useCachedGroupMetadata,
|
|
2297
|
-
statusJidList: options.statusJidList,
|
|
2298
|
-
});
|
|
2311
|
+
await relayRichMessage(jid, fullMsg, options);
|
|
2299
2312
|
if (config.emitOwnEvents) {
|
|
2300
2313
|
process.nextTick(async () => {
|
|
2301
2314
|
await messageMutex.mutex(() => upsertMessage(fullMsg, 'append'));
|
|
@@ -2315,11 +2328,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
2315
2328
|
messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id),
|
|
2316
2329
|
...options,
|
|
2317
2330
|
});
|
|
2318
|
-
await
|
|
2319
|
-
messageId: fullMsg.key.id,
|
|
2320
|
-
useCachedGroupMetadata: options.useCachedGroupMetadata,
|
|
2321
|
-
statusJidList: options.statusJidList,
|
|
2322
|
-
});
|
|
2331
|
+
await relayRichMessage(jid, fullMsg, options);
|
|
2323
2332
|
if (config.emitOwnEvents) {
|
|
2324
2333
|
process.nextTick(async () => {
|
|
2325
2334
|
await messageMutex.mutex(() => upsertMessage(fullMsg, 'append'));
|
|
@@ -2336,11 +2345,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
2336
2345
|
messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id),
|
|
2337
2346
|
...options,
|
|
2338
2347
|
});
|
|
2339
|
-
await
|
|
2340
|
-
messageId: fullMsg.key.id,
|
|
2341
|
-
useCachedGroupMetadata: options.useCachedGroupMetadata,
|
|
2342
|
-
statusJidList: options.statusJidList,
|
|
2343
|
-
});
|
|
2348
|
+
await relayRichMessage(jid, fullMsg, options);
|
|
2344
2349
|
if (config.emitOwnEvents) {
|
|
2345
2350
|
process.nextTick(async () => {
|
|
2346
2351
|
await messageMutex.mutex(() => upsertMessage(fullMsg, 'append'));
|
|
@@ -2357,7 +2362,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
2357
2362
|
botForwardedMessage: { message: { richResponseMessage: { messageType: 1, submessages: [{ messageType: 2, messageText: text }], contextInfo: { isForwarded: true, forwardingScore: 1, forwardedAiBotMessageInfo: { botJid }, forwardOrigin: 4 } } } }
|
|
2358
2363
|
};
|
|
2359
2364
|
const fullMsg = await generateWAMessageFromContent(jid, wrapped, { logger, userJid: authState.creds.me?.id, messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id), ...options });
|
|
2360
|
-
await
|
|
2365
|
+
await relayRichMessage(jid, fullMsg, options);
|
|
2361
2366
|
return fullMsg;
|
|
2362
2367
|
};
|
|
2363
2368
|
/** Sends a rich response with experimental BotCommandMetadata. */
|
|
@@ -2366,7 +2371,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
2366
2371
|
const { text = 'Bot command test', commandName = '', commandDescription = '', commandPrompt = '', botJid = '867051314767696@bot' } = content;
|
|
2367
2372
|
const wrapped = buildBotRichResponse({ text, botJid, botMetadata: { commandMetadata: { commandName, commandDescription, commandPrompt } } });
|
|
2368
2373
|
const fullMsg = await generateWAMessageFromContent(jid, wrapped, { logger, userJid: authState.creds.me?.id, messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id), ...options });
|
|
2369
|
-
await
|
|
2374
|
+
await relayRichMessage(jid, fullMsg, options);
|
|
2370
2375
|
return fullMsg;
|
|
2371
2376
|
};
|
|
2372
2377
|
/** Sends a planning/execution-plan rich response with WAProto capabilities. */
|
|
@@ -2389,7 +2394,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
2389
2394
|
]
|
|
2390
2395
|
});
|
|
2391
2396
|
const fullMsg = await generateWAMessageFromContent(jid, wrapped, { logger, userJid: authState.creds.me?.id, messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id), ...options });
|
|
2392
|
-
await
|
|
2397
|
+
await relayRichMessage(jid, fullMsg, options);
|
|
2393
2398
|
return fullMsg;
|
|
2394
2399
|
};
|
|
2395
2400
|
/** Sends a rich response with experimental BotResolvedToolCallMetadata. */
|
|
@@ -2408,7 +2413,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
2408
2413
|
}
|
|
2409
2414
|
});
|
|
2410
2415
|
const fullMsg = await generateWAMessageFromContent(jid, wrapped, { logger, userJid: authState.creds.me?.id, messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id), ...options });
|
|
2411
|
-
await
|
|
2416
|
+
await relayRichMessage(jid, fullMsg, options);
|
|
2412
2417
|
return fullMsg;
|
|
2413
2418
|
};
|
|
2414
2419
|
socket.sendStatus = async (content, options = {}) => {
|
|
@@ -2611,25 +2616,53 @@ export const makeMessagesSocket = (config) => {
|
|
|
2611
2616
|
|
|
2612
2617
|
|
|
2613
2618
|
/**
|
|
2614
|
-
* Sends an
|
|
2615
|
-
*
|
|
2616
|
-
*
|
|
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.
|
|
2617
2622
|
*/
|
|
2618
2623
|
socket.sendAlbumMessage = async (jid, medias = [], options = {}) => {
|
|
2619
2624
|
if (!jid) throw new Boom('sendAlbumMessage requires a target JID', { statusCode: 400 });
|
|
2620
2625
|
if (!Array.isArray(medias) || medias.length < 2) {
|
|
2621
2626
|
throw new Boom('sendAlbumMessage requires at least two media items', { statusCode: 400 });
|
|
2622
2627
|
}
|
|
2623
|
-
const
|
|
2624
|
-
const
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
if (index === 0 && options.caption && !normalized.caption) {
|
|
2628
|
-
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 });
|
|
2629
2632
|
}
|
|
2630
|
-
|
|
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
|
|
2631
2658
|
});
|
|
2632
|
-
|
|
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;
|
|
2633
2666
|
};
|
|
2634
2667
|
|
|
2635
2668
|
|
|
@@ -2688,11 +2721,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
2688
2721
|
messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id),
|
|
2689
2722
|
...options
|
|
2690
2723
|
});
|
|
2691
|
-
await
|
|
2692
|
-
messageId: fullMsg.key.id,
|
|
2693
|
-
useCachedGroupMetadata: options.useCachedGroupMetadata,
|
|
2694
|
-
statusJidList: options.statusJidList
|
|
2695
|
-
});
|
|
2724
|
+
await relayRichMessage(jid, fullMsg, options);
|
|
2696
2725
|
return fullMsg;
|
|
2697
2726
|
};
|
|
2698
2727
|
|
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 = {
|
|
@@ -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) => {
|
|
@@ -649,6 +673,30 @@ export const prepareRichLinkMessage = (options = {}) => {
|
|
|
649
673
|
return wrapToBotForwardedMessage(richResponseMessage, verificationMetadata);
|
|
650
674
|
};
|
|
651
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);
|
|
698
|
+
};
|
|
699
|
+
|
|
652
700
|
export const prepareRichResponseMessage = (content) => {
|
|
653
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;
|
|
654
702
|
let submessages = [];
|
|
@@ -770,7 +818,10 @@ export const prepareRichResponseMessage = (content) => {
|
|
|
770
818
|
reelSource: reel?.reelSource || reel?.reel_source || 'IG',
|
|
771
819
|
isVerified: !!(reel?.isVerified ?? reel?.is_verified)
|
|
772
820
|
} })) : [];
|
|
773
|
-
const resolvedItems =
|
|
821
|
+
const resolvedItems = [
|
|
822
|
+
...(Array.isArray(items) ? items : []),
|
|
823
|
+
...reelItems
|
|
824
|
+
];
|
|
774
825
|
if (resolvedItems?.length) {
|
|
775
826
|
submessages.push({
|
|
776
827
|
messageType: RichSubMessageType.CONTENT_ITEMS,
|
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",
|