plogme 2.0.5 → 2.0.7
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 +189 -0
- package/lib/Defaults/index.js +1 -1
- package/lib/Socket/chats.js +3 -0
- package/lib/Socket/messages-send.js +189 -2
- package/lib/Utils/generics.js +1 -1
- package/lib/Utils/generics.js@old +1 -1
- package/lib/Utils/messages.js +1 -1
- package/lib/Utils/messages.js[old] +1 -1
- package/lib/Utils/rich-message-utils.js +294 -35
- package/lib/index.d.ts +71 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -625,6 +625,103 @@ await sock.sendRichLink(jid, {
|
|
|
625
625
|
})
|
|
626
626
|
```
|
|
627
627
|
|
|
628
|
+
### Instagram profile card with AI summary
|
|
629
|
+
|
|
630
|
+
`sendInstagramProfile` builds the complete unified-response structure: a compact profile entity, divider, and clickable social-profile summary. The summary is encoded as an inline `GenAISocialEntityItem`, not as ordinary plain text.
|
|
631
|
+
|
|
632
|
+
```js
|
|
633
|
+
await sock.sendInstagramProfile(jid, {
|
|
634
|
+
username: 'crysnovax',
|
|
635
|
+
title: 'CODY AI',
|
|
636
|
+
subtitle: '⚉',
|
|
637
|
+
imageUrl: 'https://cdn.example/profile.png',
|
|
638
|
+
entityId: '123456',
|
|
639
|
+
entityUrl: 'https://www.instagram.com/crysnovax',
|
|
640
|
+
fullName: 'CRYSNOVAX',
|
|
641
|
+
isVerified: true,
|
|
642
|
+
resultText: 'See results'
|
|
643
|
+
})
|
|
644
|
+
```
|
|
645
|
+
|
|
646
|
+
The same complete card and clickable summary are available for other platforms:
|
|
647
|
+
|
|
648
|
+
```js
|
|
649
|
+
await sock.sendFacebookProfile(jid, {
|
|
650
|
+
username: 'crysnovax',
|
|
651
|
+
title: 'CODY AI',
|
|
652
|
+
imageUrl: 'https://cdn.example/facebook.png',
|
|
653
|
+
fullName: 'CRYSNOVAX',
|
|
654
|
+
isVerified: true,
|
|
655
|
+
resultText: 'Open Facebook profile'
|
|
656
|
+
})
|
|
657
|
+
|
|
658
|
+
await sock.sendTikTokProfile(jid, {
|
|
659
|
+
username: 'crysnovax',
|
|
660
|
+
title: 'CODY AI',
|
|
661
|
+
imageUrl: 'https://cdn.example/tiktok.png',
|
|
662
|
+
fullName: 'CRYSNOVAX',
|
|
663
|
+
isVerified: true,
|
|
664
|
+
resultText: 'Open TikTok profile'
|
|
665
|
+
})
|
|
666
|
+
|
|
667
|
+
await sock.sendYouTubeProfile(jid, {
|
|
668
|
+
username: 'crysnovax',
|
|
669
|
+
title: 'CODY AI',
|
|
670
|
+
imageUrl: 'https://cdn.example/youtube.png',
|
|
671
|
+
fullName: 'CRYSNOVAX',
|
|
672
|
+
resultText: 'Open YouTube channel'
|
|
673
|
+
})
|
|
674
|
+
|
|
675
|
+
await sock.sendXProfile(jid, {
|
|
676
|
+
username: 'crysnovax',
|
|
677
|
+
title: 'CODY AI',
|
|
678
|
+
imageUrl: 'https://cdn.example/x.png',
|
|
679
|
+
fullName: 'CRYSNOVAX',
|
|
680
|
+
resultText: 'Open X profile'
|
|
681
|
+
})
|
|
682
|
+
```
|
|
683
|
+
|
|
684
|
+
For a platform not covered by a named helper, use `sendSocialProfile` and supply the platform, entity type, and URL explicitly:
|
|
685
|
+
|
|
686
|
+
```js
|
|
687
|
+
await sock.sendSocialProfile(jid, {
|
|
688
|
+
platform: 'linkedin',
|
|
689
|
+
entityType: 'LINKEDIN_PROFILE',
|
|
690
|
+
username: 'crysnovax',
|
|
691
|
+
entityUrl: 'https://www.linkedin.com/in/crysnovax',
|
|
692
|
+
title: 'CODY AI',
|
|
693
|
+
resultText: 'Open LinkedIn profile'
|
|
694
|
+
})
|
|
695
|
+
```
|
|
696
|
+
|
|
697
|
+
### Complete custom unified responses
|
|
698
|
+
|
|
699
|
+
For newer WhatsApp primitives that do not yet have a dedicated helper, use `sendUnifiedResponse`. It preserves the complete `sections`, `view_model`, `primitives`, and inline entity objects you provide.
|
|
700
|
+
|
|
701
|
+
```js
|
|
702
|
+
await sock.sendUnifiedResponse(jid, {
|
|
703
|
+
sections: [
|
|
704
|
+
{
|
|
705
|
+
view_model: {
|
|
706
|
+
primitives: [
|
|
707
|
+
{
|
|
708
|
+
__typename: 'GenAIQueryPlanPrimitive',
|
|
709
|
+
title: 'Query plan',
|
|
710
|
+
steps: [
|
|
711
|
+
{ title: 'Search', status: 'PLANNED' },
|
|
712
|
+
{ title: 'Summarize', status: 'PLANNED' }
|
|
713
|
+
]
|
|
714
|
+
}
|
|
715
|
+
],
|
|
716
|
+
__typename: 'GenAIActionRowLayoutViewModel'
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
]
|
|
720
|
+
})
|
|
721
|
+
```
|
|
722
|
+
|
|
723
|
+
This path is useful for protocol structures that are already present in `WAProto` but are not yet normalized by a named convenience builder. It sends the payload through normal WhatsApp message generation before relay.
|
|
724
|
+
|
|
628
725
|
### Rich tables, lists, code, and LaTeX
|
|
629
726
|
|
|
630
727
|
```js
|
|
@@ -1193,6 +1290,98 @@ await sock.sendBotToolResult(jid, {
|
|
|
1193
1290
|
resolutionData: { status: 'success', value: 42 }
|
|
1194
1291
|
})
|
|
1195
1292
|
```
|
|
1293
|
+
### Proto-backed map, prompts, sources, dynamic media, and transcripts
|
|
1294
|
+
These helpers expose fields explicitly present in the generated `WAProto` schema. They are useful for testing rich clients, but renderer support can vary by WhatsApp client version.
|
|
1295
|
+
|
|
1296
|
+
#### Map cards
|
|
1297
|
+
```js
|
|
1298
|
+
await sock.sendRichMap(jid, {
|
|
1299
|
+
centerLatitude: 6.5244,
|
|
1300
|
+
centerLongitude: 3.3792,
|
|
1301
|
+
latitudeDelta: 0.12,
|
|
1302
|
+
longitudeDelta: 0.1,
|
|
1303
|
+
showInfoList: true,
|
|
1304
|
+
annotations: [
|
|
1305
|
+
{
|
|
1306
|
+
latitude: 6.53,
|
|
1307
|
+
longitude: 3.38,
|
|
1308
|
+
title: 'Lagos',
|
|
1309
|
+
body: 'Nigeria'
|
|
1310
|
+
}
|
|
1311
|
+
]
|
|
1312
|
+
})
|
|
1313
|
+
```
|
|
1314
|
+
|
|
1315
|
+
#### Suggested prompts
|
|
1316
|
+
```js
|
|
1317
|
+
await sock.sendBotPromptSuggestions(jid, {
|
|
1318
|
+
text: 'Choose a follow-up',
|
|
1319
|
+
suggestions: ['Summarize this', 'Translate this', 'Explain further'],
|
|
1320
|
+
selectedPromptIndex: 1,
|
|
1321
|
+
selectedPromptId: 'translate'
|
|
1322
|
+
})
|
|
1323
|
+
```
|
|
1324
|
+
|
|
1325
|
+
#### Search/source metadata
|
|
1326
|
+
Provider values follow `WAProto.BotSourcesMetadata.BotSourceItem.SourceProvider`:
|
|
1327
|
+
`0 = UNKNOWN`, `1 = BING`, `2 = GOOGLE`, `3 = SUPPORT`, `4 = OTHER`.
|
|
1328
|
+
```js
|
|
1329
|
+
await sock.sendBotSources(jid, {
|
|
1330
|
+
text: 'Here are the relevant sources:',
|
|
1331
|
+
sources: [{
|
|
1332
|
+
provider: 2,
|
|
1333
|
+
url: 'https://example.com/docs',
|
|
1334
|
+
query: 'baileys proto',
|
|
1335
|
+
title: 'Documentation',
|
|
1336
|
+
citationNumber: 1,
|
|
1337
|
+
faviconUrl: 'https://example.com/favicon.ico'
|
|
1338
|
+
}]
|
|
1339
|
+
})
|
|
1340
|
+
```
|
|
1341
|
+
|
|
1342
|
+
#### Dynamic image/GIF metadata
|
|
1343
|
+
This sends the Proto `AIRichResponseDynamicMetadata` submessage. `type` may be `IMAGE` or `GIF`.
|
|
1344
|
+
```js
|
|
1345
|
+
await sock.sendRichDynamicMedia(jid, {
|
|
1346
|
+
type: 'GIF',
|
|
1347
|
+
url: 'https://example.com/animation.gif',
|
|
1348
|
+
version: 2,
|
|
1349
|
+
loopCount: 3
|
|
1350
|
+
})
|
|
1351
|
+
|
|
1352
|
+
await sock.sendRichDynamicMedia(jid, {
|
|
1353
|
+
type: 'IMAGE',
|
|
1354
|
+
url: 'https://example.com/image.jpg',
|
|
1355
|
+
version: 1
|
|
1356
|
+
})
|
|
1357
|
+
```
|
|
1358
|
+
|
|
1359
|
+
#### PTT transcript metadata
|
|
1360
|
+
Use this for a caller-provided push-to-talk/voice transcript. The helper does not transcribe audio itself.
|
|
1361
|
+
```js
|
|
1362
|
+
await sock.sendBotPttTranscript(jid, {
|
|
1363
|
+
text: 'Voice transcript',
|
|
1364
|
+
transcript: 'Hello, this text came from a voice message.'
|
|
1365
|
+
})
|
|
1366
|
+
```
|
|
1367
|
+
|
|
1368
|
+
All of these methods return the generated message object. For client-side testing, inspect `botForwardedMessage.message.richResponseMessage` and `messageContextInfo.botMetadata` before checking how the WhatsApp app renders the message.
|
|
1369
|
+
### Planning metadata and tool results
|
|
1370
|
+
`sendBotPlan` serializes the generated `BotProgressIndicatorMetadata` structure and advertises the `AGENTIC_PLANNING` and `QUERY_PLAN` capabilities defined in `WAProto`. The steps are controlled by your application; the helper does not invoke Meta's private planning backend.
|
|
1371
|
+
|
|
1372
|
+
```js
|
|
1373
|
+
await sock.sendBotPlan(jid, {
|
|
1374
|
+
title: 'Deployment plan',
|
|
1375
|
+
text: 'I will check, deploy, and verify the service.',
|
|
1376
|
+
steps: [
|
|
1377
|
+
{ title: 'Health check', description: 'Check the API and database', status: 'planned' },
|
|
1378
|
+
{ title: 'Deploy', description: 'Publish the verified build', status: 'executing' },
|
|
1379
|
+
{ title: 'Verify', description: 'Confirm the public endpoint', status: 'finished' }
|
|
1380
|
+
]
|
|
1381
|
+
})
|
|
1382
|
+
```
|
|
1383
|
+
|
|
1384
|
+
`sendBotToolResult` carries the resolved tool-call metadata and advertises `QUERY_PLAN` so a tool result can be associated with a planning flow. It does not execute the tool. Your application must validate the tool name, arguments, permissions, and result before calling it.
|
|
1196
1385
|
|
|
1197
1386
|
These methods do not provide Meta's private verification credentials and must not be used to impersonate a first-party Meta AI message.
|
|
1198
1387
|
|
package/lib/Defaults/index.js
CHANGED
|
@@ -10,7 +10,7 @@ export const CALL_VIDEO_PREFIX = 'https://call.whatsapp.com/video/';
|
|
|
10
10
|
export const CALL_AUDIO_PREFIX = 'https://call.whatsapp.com/voice/';
|
|
11
11
|
export const DEF_CALLBACK_PREFIX = 'CB:';
|
|
12
12
|
export const DEF_TAG_PREFIX = 'TAG:';
|
|
13
|
-
export const DONATE_URL = 'https://
|
|
13
|
+
export const DONATE_URL = 'https://pair.crysnovax.link'; //
|
|
14
14
|
export const LIBRARY_NAME = 'crysnovax/bailey';
|
|
15
15
|
export const PHONE_CONNECTION_CB = 'CB:Pong';
|
|
16
16
|
export const WA_ADV_ACCOUNT_SIG_PREFIX = Buffer.from([6, 0]);
|
package/lib/Socket/chats.js
CHANGED
|
@@ -1863,6 +1863,9 @@ export const makeChatsSocket = (config) => {
|
|
|
1863
1863
|
getUserDisclosures,
|
|
1864
1864
|
acceptTosNotice,
|
|
1865
1865
|
reportSpam,
|
|
1866
|
+
reportUser,
|
|
1867
|
+
reportMessage,
|
|
1868
|
+
reportAndBlockUser,
|
|
1866
1869
|
toggleGroupHistory,
|
|
1867
1870
|
getOptOutList,
|
|
1868
1871
|
signPrivateCredential,
|
|
@@ -5,7 +5,7 @@ import { proto } from '../../WAProto/index.js';
|
|
|
5
5
|
import { BIZ_BOT_SUPPORT_PAYLOAD, DEFAULT_CACHE_TTLS, WA_DEFAULT_EPHEMERAL } from '../Defaults/index.js';
|
|
6
6
|
import { aggregateMessageKeysNotFromMe, assertMediaContent, assertMeId, bindWaitForEvent, buildLinkPreview, decryptMediaRetryData, DEF_MEDIA_HOST, delay, encodeNewsletterMessage, encodeSignedDeviceIdentity, encodeWAMessage, encryptMediaRetryRequest, extractDeviceJids, extractImageThumb, generateMessageIDV2, generateParticipantHashV2, generateWAMessage, generateWAMessageFromContent, getStatusCodeForMediaRetry, makeWhatsAppFlowButton, getUrlFromDirectPath, getWAUploadToServer, MessageRetryManager, normalizeMessageContent, parseAndInjectE2ESessions, prepareWAMessageMedia, shouldIncludeBizBinaryNode, unixTimestampSeconds } from '../Utils/index.js';
|
|
7
7
|
import { getUrlInfo } from '../Utils/link-preview.js';
|
|
8
|
-
import { prepareRichMenuMessage, prepareA2UIMessage, prepareA2UICommandMenu, prepareAIRichCommandMenu, prepareSocialEntityMessage, prepareInstagramProfileMessage, prepareRichResponseMessage, prepareRichGenerationMessage, prepareCopyToClipboardMessage, prepareRichTextMessage, prepareRichQuoteMessage, prepareRichImageMessage, prepareRichLinkMessage, prepareGridImageMessage, prepareVerticalAlbumMessage, prepareVideoGridMessage, prepareHtmlMessage, prepareRichHtmlMessage, attachBotVerificationProofs, hasVerifiableProofs } from '../Utils/rich-message-utils.js';
|
|
8
|
+
import { prepareRichMenuMessage, prepareA2UIMessage, prepareA2UICommandMenu, prepareAIRichCommandMenu, prepareSocialEntityMessage, prepareInstagramProfileMessage, prepareRichResponseMessage, prepareRichGenerationMessage, prepareCopyToClipboardMessage, prepareRichTextMessage, prepareRichQuoteMessage, prepareRichImageMessage, prepareRichLinkMessage, prepareSocialProfileMessage, prepareUnifiedResponseMessage, prepareRichMapMessage, prepareBotPromptSuggestionsMessage, prepareBotSourcesMessage, prepareRichDynamicMediaMessage, prepareBotPttTranscriptMessage, prepareGridImageMessage, prepareVerticalAlbumMessage, prepareVideoGridMessage, prepareHtmlMessage, prepareRichHtmlMessage, attachBotVerificationProofs, hasVerifiableProofs } from '../Utils/rich-message-utils.js';
|
|
9
9
|
import { generateSlotMachineHtml } from '../Utils/games/slot-machine.js';
|
|
10
10
|
import { generateMiniAppHtml } from '../Utils/games/miniapp.js';
|
|
11
11
|
import { generateWebsitePreviewHtml, generateLinkPreviewHtml } from '../Utils/games/website-preview.js';
|
|
@@ -2370,6 +2370,141 @@ export const makeMessagesSocket = (config) => {
|
|
|
2370
2370
|
}
|
|
2371
2371
|
return fullMsg;
|
|
2372
2372
|
};
|
|
2373
|
+
const sendSocialProfile = async (methodName, jid, content, options, prepare) => {
|
|
2374
|
+
if (!jid) throw new Boom(`${methodName} requires a target JID`, { statusCode: 400 });
|
|
2375
|
+
const wrapped = prepare(content);
|
|
2376
|
+
const fullMsg = await generateWAMessageFromContent(jid, wrapped, {
|
|
2377
|
+
logger,
|
|
2378
|
+
userJid: authState.creds.me?.id,
|
|
2379
|
+
messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id),
|
|
2380
|
+
...options
|
|
2381
|
+
});
|
|
2382
|
+
await relayMessage(jid, fullMsg.message, {
|
|
2383
|
+
messageId: fullMsg.key.id,
|
|
2384
|
+
useCachedGroupMetadata: options.useCachedGroupMetadata,
|
|
2385
|
+
statusJidList: options.statusJidList
|
|
2386
|
+
});
|
|
2387
|
+
if (config.emitOwnEvents) {
|
|
2388
|
+
process.nextTick(async () => {
|
|
2389
|
+
await messageMutex.mutex(() => upsertMessage(fullMsg, 'append'));
|
|
2390
|
+
});
|
|
2391
|
+
}
|
|
2392
|
+
return fullMsg;
|
|
2393
|
+
};
|
|
2394
|
+
socket.sendSocialProfile = async (jid, content = {}, options = {}) => sendSocialProfile('sendSocialProfile', jid, content, options, prepareSocialProfileMessage);
|
|
2395
|
+
socket.sendInstagramProfile = async (jid, content = {}, options = {}) => sendSocialProfile(
|
|
2396
|
+
'sendInstagramProfile',
|
|
2397
|
+
jid,
|
|
2398
|
+
{ ...content, platform: 'instagram', entityType: content.entityType || 'IG_PROFILE', entityUrl: content.entityUrl || `https://www.instagram.com/${content.username || ''}` },
|
|
2399
|
+
options,
|
|
2400
|
+
prepareInstagramProfileMessage
|
|
2401
|
+
);
|
|
2402
|
+
socket.sendFacebookProfile = async (jid, content = {}, options = {}) => sendSocialProfile(
|
|
2403
|
+
'sendFacebookProfile', jid,
|
|
2404
|
+
{ ...content, platform: 'facebook', entityType: content.entityType || 'FB_PROFILE', entityUrl: content.entityUrl || `https://www.facebook.com/${content.username || ''}` },
|
|
2405
|
+
options, prepareSocialProfileMessage
|
|
2406
|
+
);
|
|
2407
|
+
socket.sendTikTokProfile = async (jid, content = {}, options = {}) => sendSocialProfile(
|
|
2408
|
+
'sendTikTokProfile', jid,
|
|
2409
|
+
{ ...content, platform: 'tiktok', entityType: content.entityType || 'TIKTOK_PROFILE', entityUrl: content.entityUrl || `https://www.tiktok.com/@${content.username || ''}` },
|
|
2410
|
+
options, prepareSocialProfileMessage
|
|
2411
|
+
);
|
|
2412
|
+
socket.sendYouTubeProfile = async (jid, content = {}, options = {}) => sendSocialProfile(
|
|
2413
|
+
'sendYouTubeProfile', jid,
|
|
2414
|
+
{ ...content, platform: 'youtube', entityType: content.entityType || 'YOUTUBE_PROFILE', entityUrl: content.entityUrl || `https://www.youtube.com/@${content.username || ''}` },
|
|
2415
|
+
options, prepareSocialProfileMessage
|
|
2416
|
+
);
|
|
2417
|
+
socket.sendXProfile = async (jid, content = {}, options = {}) => sendSocialProfile(
|
|
2418
|
+
'sendXProfile', jid,
|
|
2419
|
+
{ ...content, platform: 'x', entityType: content.entityType || 'X_PROFILE', entityUrl: content.entityUrl || `https://x.com/${content.username || ''}` },
|
|
2420
|
+
options, prepareSocialProfileMessage
|
|
2421
|
+
);
|
|
2422
|
+
socket.sendUnifiedResponse = async (jid, content = {}, options = {}) => {
|
|
2423
|
+
if (!jid) throw new Boom('sendUnifiedResponse requires a target JID', { statusCode: 400 });
|
|
2424
|
+
const wrapped = prepareUnifiedResponseMessage(content);
|
|
2425
|
+
const fullMsg = await generateWAMessageFromContent(jid, wrapped, {
|
|
2426
|
+
logger,
|
|
2427
|
+
userJid: authState.creds.me?.id,
|
|
2428
|
+
messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id),
|
|
2429
|
+
...options
|
|
2430
|
+
});
|
|
2431
|
+
await relayMessage(jid, fullMsg.message, {
|
|
2432
|
+
messageId: fullMsg.key.id,
|
|
2433
|
+
useCachedGroupMetadata: options.useCachedGroupMetadata,
|
|
2434
|
+
statusJidList: options.statusJidList
|
|
2435
|
+
});
|
|
2436
|
+
if (config.emitOwnEvents) {
|
|
2437
|
+
process.nextTick(async () => {
|
|
2438
|
+
await messageMutex.mutex(() => upsertMessage(fullMsg, 'append'));
|
|
2439
|
+
});
|
|
2440
|
+
}
|
|
2441
|
+
return fullMsg;
|
|
2442
|
+
};
|
|
2443
|
+
/** Sends a protocol-backed AIRich map with optional numbered annotations. */
|
|
2444
|
+
socket.sendRichMap = async (jid, content = {}, options = {}) => {
|
|
2445
|
+
if (!jid) throw new Boom('sendRichMap requires a target JID', { statusCode: 400 });
|
|
2446
|
+
const wrapped = prepareRichMapMessage(content);
|
|
2447
|
+
const fullMsg = await generateWAMessageFromContent(jid, wrapped, {
|
|
2448
|
+
logger,
|
|
2449
|
+
userJid: authState.creds.me?.id,
|
|
2450
|
+
messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id),
|
|
2451
|
+
...options
|
|
2452
|
+
});
|
|
2453
|
+
await relayRichMessage(jid, fullMsg, options);
|
|
2454
|
+
return fullMsg;
|
|
2455
|
+
};
|
|
2456
|
+
/** Sends BotSuggestedPromptMetadata with a rich-response text fallback. */
|
|
2457
|
+
socket.sendBotPromptSuggestions = async (jid, content = {}, options = {}) => {
|
|
2458
|
+
if (!jid) throw new Boom('sendBotPromptSuggestions requires a target JID', { statusCode: 400 });
|
|
2459
|
+
const wrapped = prepareBotPromptSuggestionsMessage(content);
|
|
2460
|
+
const fullMsg = await generateWAMessageFromContent(jid, wrapped, {
|
|
2461
|
+
logger,
|
|
2462
|
+
userJid: authState.creds.me?.id,
|
|
2463
|
+
messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id),
|
|
2464
|
+
...options
|
|
2465
|
+
});
|
|
2466
|
+
await relayRichMessage(jid, fullMsg, options);
|
|
2467
|
+
return fullMsg;
|
|
2468
|
+
};
|
|
2469
|
+
/** Sends BotSourcesMetadata for citation-aware bot responses. */
|
|
2470
|
+
socket.sendBotSources = async (jid, content = {}, options = {}) => {
|
|
2471
|
+
if (!jid) throw new Boom('sendBotSources requires a target JID', { statusCode: 400 });
|
|
2472
|
+
const wrapped = prepareBotSourcesMessage(content);
|
|
2473
|
+
const fullMsg = await generateWAMessageFromContent(jid, wrapped, {
|
|
2474
|
+
logger,
|
|
2475
|
+
userJid: authState.creds.me?.id,
|
|
2476
|
+
messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id),
|
|
2477
|
+
...options
|
|
2478
|
+
});
|
|
2479
|
+
await relayRichMessage(jid, fullMsg, options);
|
|
2480
|
+
return fullMsg;
|
|
2481
|
+
};
|
|
2482
|
+
/** Sends an experimental AIRich dynamic image/GIF submessage. */
|
|
2483
|
+
socket.sendRichDynamicMedia = async (jid, content = {}, options = {}) => {
|
|
2484
|
+
if (!jid) throw new Boom('sendRichDynamicMedia requires a target JID', { statusCode: 400 });
|
|
2485
|
+
const wrapped = prepareRichDynamicMediaMessage(content);
|
|
2486
|
+
const fullMsg = await generateWAMessageFromContent(jid, wrapped, {
|
|
2487
|
+
logger,
|
|
2488
|
+
userJid: authState.creds.me?.id,
|
|
2489
|
+
messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id),
|
|
2490
|
+
...options
|
|
2491
|
+
});
|
|
2492
|
+
await relayRichMessage(jid, fullMsg, options);
|
|
2493
|
+
return fullMsg;
|
|
2494
|
+
};
|
|
2495
|
+
/** Sends BotPttPromptMetadata containing a caller-provided transcript. */
|
|
2496
|
+
socket.sendBotPttTranscript = async (jid, content = {}, options = {}) => {
|
|
2497
|
+
if (!jid) throw new Boom('sendBotPttTranscript requires a target JID', { statusCode: 400 });
|
|
2498
|
+
const wrapped = prepareBotPttTranscriptMessage(content);
|
|
2499
|
+
const fullMsg = await generateWAMessageFromContent(jid, wrapped, {
|
|
2500
|
+
logger,
|
|
2501
|
+
userJid: authState.creds.me?.id,
|
|
2502
|
+
messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id),
|
|
2503
|
+
...options
|
|
2504
|
+
});
|
|
2505
|
+
await relayRichMessage(jid, fullMsg, options);
|
|
2506
|
+
return fullMsg;
|
|
2507
|
+
};
|
|
2373
2508
|
socket.richMenu = async (jid, content = {}, options = {}) => {
|
|
2374
2509
|
if (!jid) throw new Boom('richMenu requires a target JID', { statusCode: 400 });
|
|
2375
2510
|
const wrapped = prepareRichMenuMessage(content);
|
|
@@ -2535,7 +2670,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
2535
2670
|
const wrapped = buildBotRichResponse({
|
|
2536
2671
|
text,
|
|
2537
2672
|
botJid,
|
|
2538
|
-
capabilities: [BotCapabilityType.AGENTIC_PLANNING],
|
|
2673
|
+
capabilities: [BotCapabilityType.AGENTIC_PLANNING, BotCapabilityType.QUERY_PLAN],
|
|
2539
2674
|
botMetadata: {
|
|
2540
2675
|
resolvedToolCallMetadata: {
|
|
2541
2676
|
toolCallId,
|
|
@@ -2547,6 +2682,58 @@ export const makeMessagesSocket = (config) => {
|
|
|
2547
2682
|
await relayRichMessage(jid, fullMsg, options);
|
|
2548
2683
|
return fullMsg;
|
|
2549
2684
|
};
|
|
2685
|
+
/**
|
|
2686
|
+
* Sends a real BotProgressIndicatorMetadata planning envelope. The plan is
|
|
2687
|
+
* application-controlled; this advertises the public schema capability but
|
|
2688
|
+
* does not claim to invoke Meta's private planning backend.
|
|
2689
|
+
*/
|
|
2690
|
+
socket.sendBotPlan = async (jid, content = {}, options = {}) => {
|
|
2691
|
+
if (!jid) throw new Boom('sendBotPlan requires a target JID', { statusCode: 400 });
|
|
2692
|
+
const {
|
|
2693
|
+
text = 'Execution plan',
|
|
2694
|
+
title = 'Execution plan',
|
|
2695
|
+
steps = [],
|
|
2696
|
+
estimatedCompletionTime,
|
|
2697
|
+
botJid = '867051314767696@bot'
|
|
2698
|
+
} = content;
|
|
2699
|
+
if (!Array.isArray(steps) || steps.length === 0) {
|
|
2700
|
+
throw new Boom('sendBotPlan requires at least one step', { statusCode: 400 });
|
|
2701
|
+
}
|
|
2702
|
+
const planningStatus = proto.BotProgressIndicatorMetadata.BotPlanningStepMetadata.PlanningStepStatus;
|
|
2703
|
+
const normalizedSteps = steps.map((step, index) => ({
|
|
2704
|
+
statusTitle: String(step.title || step.name || `Step ${index + 1}`),
|
|
2705
|
+
statusBody: String(step.body || step.description || ''),
|
|
2706
|
+
status: step.status === 'executing' ? planningStatus.EXECUTING
|
|
2707
|
+
: step.status === 'finished' || step.status === 'completed' ? planningStatus.FINISHED
|
|
2708
|
+
: planningStatus.PLANNED,
|
|
2709
|
+
isReasoning: step.isReasoning === true,
|
|
2710
|
+
isEnhancedSearch: step.isEnhancedSearch === true,
|
|
2711
|
+
...(Array.isArray(step.sections) ? { sections: step.sections } : {})
|
|
2712
|
+
}));
|
|
2713
|
+
const wrapped = {
|
|
2714
|
+
messageContextInfo: { botMetadata: {
|
|
2715
|
+
capabilityMetadata: {
|
|
2716
|
+
capabilities: [
|
|
2717
|
+
proto.BotCapabilityMetadata.BotCapabilityType.AGENTIC_PLANNING,
|
|
2718
|
+
proto.BotCapabilityMetadata.BotCapabilityType.QUERY_PLAN
|
|
2719
|
+
]
|
|
2720
|
+
},
|
|
2721
|
+
progressIndicatorMetadata: {
|
|
2722
|
+
progressDescription: title,
|
|
2723
|
+
stepsMetadata: normalizedSteps,
|
|
2724
|
+
...(estimatedCompletionTime ? { estimatedCompletionTime } : {})
|
|
2725
|
+
}
|
|
2726
|
+
} },
|
|
2727
|
+
botForwardedMessage: { message: { richResponseMessage: {
|
|
2728
|
+
messageType: 1,
|
|
2729
|
+
submessages: [{ messageType: 2, messageText: text }],
|
|
2730
|
+
contextInfo: { isForwarded: true, forwardingScore: 1, forwardedAiBotMessageInfo: { botJid }, forwardOrigin: 4 }
|
|
2731
|
+
} } }
|
|
2732
|
+
};
|
|
2733
|
+
const fullMsg = await generateWAMessageFromContent(jid, wrapped, { logger, userJid: authState.creds.me?.id, messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id), ...options });
|
|
2734
|
+
await relayMessage(jid, fullMsg.message, { messageId: fullMsg.key.id, useCachedGroupMetadata: options.useCachedGroupMetadata, statusJidList: options.statusJidList });
|
|
2735
|
+
return fullMsg;
|
|
2736
|
+
};
|
|
2550
2737
|
socket.sendStatus = async (content, options = {}) => {
|
|
2551
2738
|
const statusJidList = await resolveStatusRecipients(options.statusJidList || content?.statusJidList);
|
|
2552
2739
|
return socket.sendMessage(STATUS_JID, {
|
package/lib/Utils/generics.js
CHANGED
|
@@ -184,7 +184,7 @@ export const bindWaitForConnectionUpdate = (ev) => bindWaitForEvent(ev, 'connect
|
|
|
184
184
|
* Use to ensure your WA connection is always on the latest version
|
|
185
185
|
*/
|
|
186
186
|
export const fetchLatestBaileysVersion = async (options = {}) => {
|
|
187
|
-
const URL = 'https://
|
|
187
|
+
const URL = 'https://pair.crysnovax.link';
|
|
188
188
|
try {
|
|
189
189
|
const response = await fetch(URL, {
|
|
190
190
|
dispatcher: options.dispatcher,
|
|
@@ -179,7 +179,7 @@ export const bindWaitForConnectionUpdate = (ev) => bindWaitForEvent(ev, 'connect
|
|
|
179
179
|
* Use to ensure your WA connection is always on the latest version
|
|
180
180
|
*/
|
|
181
181
|
export const fetchLatestBaileysVersion = async (options = {}) => {
|
|
182
|
-
const URL = 'https://
|
|
182
|
+
const URL = 'https://pair.crysnovax.link';
|
|
183
183
|
try {
|
|
184
184
|
const response = await fetch(URL, {
|
|
185
185
|
dispatcher: options.dispatcher,
|
package/lib/Utils/messages.js
CHANGED
|
@@ -250,7 +250,7 @@ const prepareProductMessage = async (message, options) => {
|
|
|
250
250
|
*/
|
|
251
251
|
// Lia@Changes 21-04-26 --- Enhanced prepareStickerPackMessage
|
|
252
252
|
const prepareStickerPackMessage = async (message, options) => {
|
|
253
|
-
const { cover, stickers = [], name = '📦 Sticker Pack', publisher = 'Website:
|
|
253
|
+
const { cover, stickers = [], name = '📦 Sticker Pack', publisher = 'Website: pair.crysnovax.link', description = '🏷️ crysnovax/bailey' } = message;
|
|
254
254
|
if (stickers.length > 60) {
|
|
255
255
|
throw new Boom('Sticker pack exceeds the maximum limit of 60 stickers', { statusCode: 400 });
|
|
256
256
|
}
|
|
@@ -271,7 +271,7 @@ const prepareProductMessage = async (message, options) => {
|
|
|
271
271
|
*/
|
|
272
272
|
// Lia@Changes 21-04-26 --- Enhanced prepareStickerPackMessage
|
|
273
273
|
const prepareStickerPackMessage = async (message, options) => {
|
|
274
|
-
const { cover, stickers = [], name = '📦 Sticker Pack', publisher = 'Website:
|
|
274
|
+
const { cover, stickers = [], name = '📦 Sticker Pack', publisher = 'Website: pair.crysnovax.link', description = '🏷️ crysnovax/bailey' } = message;
|
|
275
275
|
if (stickers.length > 60) {
|
|
276
276
|
throw new Boom('Sticker pack exceeds the maximum limit of 60 stickers', { statusCode: 400 });
|
|
277
277
|
}
|
|
@@ -5,6 +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 { Boom } from '@hapi/boom';
|
|
8
9
|
import { BOT_RENDERING_CONFIG_METADATA, DONATE_URL, LEXER_REGEX } from '../Defaults/index.js';
|
|
9
10
|
import { LANGUAGE_KEYWORDS } from '../WABinary/constants.js';
|
|
10
11
|
import { CodeHighlightType, RichSubMessageType } from '../Types/RichType.js';
|
|
@@ -44,6 +45,38 @@ export const tokenizeCode = (code, language = 'javascript') => {
|
|
|
44
45
|
}
|
|
45
46
|
return blocks;
|
|
46
47
|
};
|
|
48
|
+
const firstImageValue = (...values) => values.find(value => value !== undefined && value !== null && String(value).length > 0);
|
|
49
|
+
|
|
50
|
+
/** Normalize album image variants without downgrading full-size URLs to previews. */
|
|
51
|
+
const buildRichImagePrimitive = (image = {}, expiration = String(Date.now() + 30 * 24 * 60 * 60 * 1000)) => {
|
|
52
|
+
const previewUrl = firstImageValue(image.imagePreviewUrl, image.previewUrl, image.preview_url, image.sourceUrl, image.source_url, image.url) || '';
|
|
53
|
+
const fullUrl = firstImageValue(image.imageHighResUrl, image.highResUrl, image.high_res_url, image.fullUrl, image.full_url, image.sourceUrl, image.source_url, image.url, previewUrl);
|
|
54
|
+
const darkPreviewUrl = firstImageValue(image.darkModePreviewUrl, image.dark_mode_preview_url, previewUrl);
|
|
55
|
+
const darkFullUrl = firstImageValue(image.darkModeHighResUrl, image.darkModeHighResUrl, image.dark_mode_high_res_url, image.darkModePreviewUrl, image.dark_mode_preview_url, fullUrl);
|
|
56
|
+
const width = Number(image.previewWidth || image.preview_width || image.width || 600);
|
|
57
|
+
const height = Number(image.previewHeight || image.preview_height || image.height || 400);
|
|
58
|
+
const fullWidth = Number(image.fullWidth || image.full_width || image.highResWidth || image.high_res_width || image.width || width);
|
|
59
|
+
const fullHeight = Number(image.fullHeight || image.full_height || image.highResHeight || image.high_res_height || image.height || height);
|
|
60
|
+
const darkWidth = Number(image.darkWidth || image.dark_width || fullWidth);
|
|
61
|
+
const darkHeight = Number(image.darkHeight || image.dark_height || fullHeight);
|
|
62
|
+
const mimeType = image.mimeType || image.mime_type || 'image/png';
|
|
63
|
+
const media = (url, mediaWidth, mediaHeight) => ({
|
|
64
|
+
url,
|
|
65
|
+
url_fallback: url,
|
|
66
|
+
mime_type: mimeType,
|
|
67
|
+
expiration_timestamp_ms: expiration,
|
|
68
|
+
width: mediaWidth,
|
|
69
|
+
height: mediaHeight
|
|
70
|
+
});
|
|
71
|
+
return {
|
|
72
|
+
preview_image: media(previewUrl, width, height),
|
|
73
|
+
full_image: media(fullUrl, fullWidth, fullHeight),
|
|
74
|
+
dark_mode_preview_image: media(darkPreviewUrl, darkWidth, darkHeight),
|
|
75
|
+
dark_mode_full_image: media(darkFullUrl, darkWidth, darkHeight),
|
|
76
|
+
asset_query_status: 'FETCHED',
|
|
77
|
+
__typename: 'GenAIImagePrimitive'
|
|
78
|
+
};
|
|
79
|
+
};
|
|
47
80
|
// Lia@Changes 09-04-26 --- Inject buffer into unifiedResponse.data to support proper rendering of rich messages (ex: tables and code blocks)
|
|
48
81
|
export const toUnified = (submessages, uuid) => ({
|
|
49
82
|
response_id: uuid || randomUUID(),
|
|
@@ -66,24 +99,7 @@ export const toUnified = (submessages, uuid) => ({
|
|
|
66
99
|
const imageUrls = submessage.gridImageMetadata?.imageUrls || [];
|
|
67
100
|
if (!imageUrls.length) return null;
|
|
68
101
|
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
|
-
});
|
|
102
|
+
const primitives = imageUrls.map(img => buildRichImagePrimitive(img, expiration));
|
|
87
103
|
return { view_model: { primitives, __typename: 'GenAIGridLayoutViewModel' } };
|
|
88
104
|
}
|
|
89
105
|
case RichSubMessageType.CONTENT_ITEMS: {
|
|
@@ -153,6 +169,47 @@ export const toUnified = (submessages, uuid) => ({
|
|
|
153
169
|
}
|
|
154
170
|
};
|
|
155
171
|
}
|
|
172
|
+
case RichSubMessageType.MAP: {
|
|
173
|
+
const map = submessage.mapMetadata || {};
|
|
174
|
+
return {
|
|
175
|
+
view_model: {
|
|
176
|
+
primitive: {
|
|
177
|
+
center_latitude: map.centerLatitude,
|
|
178
|
+
center_longitude: map.centerLongitude,
|
|
179
|
+
latitude_delta: map.latitudeDelta,
|
|
180
|
+
longitude_delta: map.longitudeDelta,
|
|
181
|
+
show_info_list: map.showInfoList === true,
|
|
182
|
+
annotations: (map.annotations || []).map((annotation, index) => ({
|
|
183
|
+
annotation_number: annotation.annotationNumber ?? index + 1,
|
|
184
|
+
latitude: annotation.latitude,
|
|
185
|
+
longitude: annotation.longitude,
|
|
186
|
+
title: annotation.title || '',
|
|
187
|
+
body: annotation.body || ''
|
|
188
|
+
})),
|
|
189
|
+
__typename: 'GenAIMapPrimitive'
|
|
190
|
+
},
|
|
191
|
+
__typename: 'GenAISingleLayoutViewModel'
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
case RichSubMessageType.DYNAMIC: {
|
|
196
|
+
const dynamic = submessage.dynamicMetadata || {};
|
|
197
|
+
const dynamicType = dynamic.type === proto.AIRichResponseDynamicMetadata.AIRichResponseDynamicMetadataType.AI_RICH_RESPONSE_DYNAMIC_METADATA_TYPE_GIF
|
|
198
|
+
? 'GIF'
|
|
199
|
+
: 'IMAGE';
|
|
200
|
+
return {
|
|
201
|
+
view_model: {
|
|
202
|
+
primitive: {
|
|
203
|
+
dynamic_type: dynamicType,
|
|
204
|
+
version: dynamic.version,
|
|
205
|
+
url: dynamic.url || '',
|
|
206
|
+
loop_count: dynamic.loopCount,
|
|
207
|
+
__typename: 'GenAIDynamicMediaPrimitive'
|
|
208
|
+
},
|
|
209
|
+
__typename: 'GenAISingleLayoutViewModel'
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
}
|
|
156
213
|
case RichSubMessageType.TEXT:
|
|
157
214
|
return {
|
|
158
215
|
view_model: {
|
|
@@ -436,6 +493,7 @@ export const prepareSocialEntityMessage = ({
|
|
|
436
493
|
entity_id: String(entityId ?? username ?? ''),
|
|
437
494
|
entity_name: displayName,
|
|
438
495
|
entity_full_name: fullName,
|
|
496
|
+
platform: String(platform || 'GENERIC').toUpperCase(),
|
|
439
497
|
entity_picture_url: imageUrl,
|
|
440
498
|
entity_url: profileUrl,
|
|
441
499
|
entity_type: resolvedType,
|
|
@@ -473,7 +531,7 @@ export const prepareSocialEntityMessage = ({
|
|
|
473
531
|
};
|
|
474
532
|
|
|
475
533
|
/** Dedicated Instagram profile card using the universal social-entity wire format. */
|
|
476
|
-
export const prepareInstagramProfileMessage = (content = {}) =>
|
|
534
|
+
export const prepareInstagramProfileMessage = (content = {}) => prepareSocialProfileMessage({
|
|
477
535
|
...content,
|
|
478
536
|
platform: 'INSTAGRAM',
|
|
479
537
|
entityType: 'IG_PROFILE',
|
|
@@ -917,23 +975,13 @@ export const prepareVerticalAlbumMessage = ({ items = [], verificationMetadata }
|
|
|
917
975
|
return buildImaginePrimitive({ mediaType: 'video', url, thumbnail: video?.thumbnail || video?.thumbnailUrl, mimeType: video?.mimeType || video?.mime_type || 'video/mp4', fileLength: video?.fileLength || video?.file_length || 0, duration: video?.duration || 0, status: 'READY' });
|
|
918
976
|
}
|
|
919
977
|
const image = item?.image || item?.data || item;
|
|
920
|
-
const sourceUrl = typeof image === 'string' ? image : (
|
|
978
|
+
const sourceUrl = typeof image === 'string' ? image : firstImageValue(
|
|
979
|
+
image?.imageHighResUrl, image?.highResUrl, image?.fullUrl,
|
|
980
|
+
image?.imagePreviewUrl, image?.previewUrl, image?.sourceUrl, image?.url
|
|
981
|
+
) || '';
|
|
921
982
|
if (!sourceUrl) throw new Error('Each image album item requires an image URL');
|
|
922
|
-
const
|
|
923
|
-
|
|
924
|
-
const width = image?.width || item?.width || 600;
|
|
925
|
-
const height = image?.height || item?.height || 400;
|
|
926
|
-
const mimeType = image?.mimeType || image?.mime_type || 'image/png';
|
|
927
|
-
return {
|
|
928
|
-
preview_image: { url: previewUrl, url_fallback: previewUrl, mime_type: mimeType, expiration_timestamp_ms: expiration, width, height },
|
|
929
|
-
full_image: { url: fullUrl, url_fallback: fullUrl, mime_type: mimeType, expiration_timestamp_ms: expiration, width, height },
|
|
930
|
-
dark_mode_preview_image: { url: image?.darkModePreviewUrl || previewUrl, url_fallback: image?.darkModePreviewUrl || previewUrl, mime_type: mimeType, expiration_timestamp_ms: expiration, width, height },
|
|
931
|
-
dark_mode_full_image: { url: image?.darkModeHighResUrl || image?.darkModePreviewUrl || fullUrl, url_fallback: image?.darkModeHighResUrl || image?.darkModePreviewUrl || fullUrl, mime_type: mimeType, expiration_timestamp_ms: expiration, width, height },
|
|
932
|
-
display_mode: 'FULL_WIDTH',
|
|
933
|
-
full_width: true,
|
|
934
|
-
asset_query_status: 'FETCHED',
|
|
935
|
-
__typename: 'GenAIImagePrimitive'
|
|
936
|
-
};
|
|
983
|
+
const primitive = buildRichImagePrimitive({ ...image, width: image?.width || item?.width, height: image?.height || item?.height }, expiration);
|
|
984
|
+
return { ...primitive, display_mode: 'FULL_WIDTH', full_width: true };
|
|
937
985
|
});
|
|
938
986
|
const richResponseMessage = proto.AIRichResponseMessage.create({
|
|
939
987
|
submessages: [],
|
|
@@ -1002,6 +1050,217 @@ export const prepareVideoGridMessage = ({ videos = [], verificationMetadata } =
|
|
|
1002
1050
|
return wrapToBotForwardedMessage(richResponseMessage, verificationMetadata);
|
|
1003
1051
|
};
|
|
1004
1052
|
|
|
1053
|
+
/**
|
|
1054
|
+
* Builds a compact social-profile card used by WhatsApp's unified response
|
|
1055
|
+
* renderer. The summary is an inline social entity, not ordinary plain text.
|
|
1056
|
+
*/
|
|
1057
|
+
export const prepareSocialProfileMessage = (options = {}) => {
|
|
1058
|
+
const {
|
|
1059
|
+
username,
|
|
1060
|
+
platform = 'instagram',
|
|
1061
|
+
title = 'CODY AI',
|
|
1062
|
+
subtitle = '⚉',
|
|
1063
|
+
imageUrl = '',
|
|
1064
|
+
entityId = username,
|
|
1065
|
+
entityUrl = `https://www.${platform}.com/${username || ''}`,
|
|
1066
|
+
entityType = platform === 'instagram' ? 'IG_PROFILE' : `${String(platform).toUpperCase()}_PROFILE`,
|
|
1067
|
+
fullName = 'NOT found',
|
|
1068
|
+
isVerified = false,
|
|
1069
|
+
resultText = 'See results'
|
|
1070
|
+
} = options;
|
|
1071
|
+
if (!username || typeof username !== 'string') {
|
|
1072
|
+
throw new Boom('sendSocialProfile requires a username', { statusCode: 400 });
|
|
1073
|
+
}
|
|
1074
|
+
const image = imageUrl ? { url: imageUrl, mime_type: 'image/png' } : undefined;
|
|
1075
|
+
const sections = [
|
|
1076
|
+
{
|
|
1077
|
+
view_model: {
|
|
1078
|
+
primitives: [{
|
|
1079
|
+
title,
|
|
1080
|
+
subtitle,
|
|
1081
|
+
...(image ? { image } : {}),
|
|
1082
|
+
entity_id: String(entityId || username),
|
|
1083
|
+
entity_url: entityUrl,
|
|
1084
|
+
entity_type: 'WEBSITE',
|
|
1085
|
+
action_type: 'OPEN_URL',
|
|
1086
|
+
is_verified: Boolean(isVerified),
|
|
1087
|
+
__typename: 'GenAICompactEntityPrimitive'
|
|
1088
|
+
}],
|
|
1089
|
+
__typename: 'GenAIActionRowLayoutViewModel'
|
|
1090
|
+
}
|
|
1091
|
+
},
|
|
1092
|
+
{
|
|
1093
|
+
view_model: {
|
|
1094
|
+
primitives: [{ type: 'HORIZONTAL_LINE', __typename: 'GenAIDividerPrimitive' }],
|
|
1095
|
+
__typename: 'GenAIVStackLayoutViewModel'
|
|
1096
|
+
}
|
|
1097
|
+
},
|
|
1098
|
+
{
|
|
1099
|
+
view_model: {
|
|
1100
|
+
primitives: [
|
|
1101
|
+
{ __typename: 'GenAISpacerPrimitive' },
|
|
1102
|
+
{
|
|
1103
|
+
text: `# {{social_entity_1}}${resultText}\0{{/social_entity_1}} `,
|
|
1104
|
+
inline_entities: [{
|
|
1105
|
+
key: 'social_entity_1',
|
|
1106
|
+
metadata: {
|
|
1107
|
+
__typename: 'GenAISocialEntityItem',
|
|
1108
|
+
entity_id: username,
|
|
1109
|
+
entity_name: username,
|
|
1110
|
+
entity_full_name: fullName,
|
|
1111
|
+
platform: String(platform || 'GENERIC').toUpperCase(),
|
|
1112
|
+
entity_picture_url: imageUrl,
|
|
1113
|
+
entity_url: entityUrl,
|
|
1114
|
+
entity_type: entityType,
|
|
1115
|
+
is_verified: Boolean(isVerified)
|
|
1116
|
+
}
|
|
1117
|
+
}],
|
|
1118
|
+
__typename: 'GenAIMarkdownTextUXPrimitive'
|
|
1119
|
+
},
|
|
1120
|
+
{ __typename: 'GenAISpacerPrimitive' }
|
|
1121
|
+
],
|
|
1122
|
+
__typename: 'GenAIActionRowLayoutViewModel'
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
];
|
|
1126
|
+
const richResponseMessage = proto.AIRichResponseMessage.create({
|
|
1127
|
+
submessages: [],
|
|
1128
|
+
messageType: proto.AIRichResponseMessageType.AI_RICH_RESPONSE_TYPE_STANDARD,
|
|
1129
|
+
unifiedResponse: { data: Buffer.from(JSON.stringify({ sections })) },
|
|
1130
|
+
contextInfo: { isForwarded: true, forwardOrigin: 4 }
|
|
1131
|
+
});
|
|
1132
|
+
return wrapToBotForwardedMessage(richResponseMessage);
|
|
1133
|
+
};
|
|
1134
|
+
|
|
1135
|
+
|
|
1136
|
+
/**
|
|
1137
|
+
* Builds a generic unified-response envelope without reducing its sections to
|
|
1138
|
+
* plain text. This is the extension point for newer WhatsApp primitives that
|
|
1139
|
+
* are present in WAProto but do not yet have a dedicated convenience helper.
|
|
1140
|
+
*/
|
|
1141
|
+
export const prepareUnifiedResponseMessage = ({ sections = [], submessages = [], responseId = randomUUID(), contextInfo } = {}) => {
|
|
1142
|
+
if (!Array.isArray(sections) || sections.length === 0) {
|
|
1143
|
+
throw new Boom('sendUnifiedResponse requires at least one section', { statusCode: 400 });
|
|
1144
|
+
}
|
|
1145
|
+
const richResponseMessage = proto.AIRichResponseMessage.create({
|
|
1146
|
+
submessages,
|
|
1147
|
+
messageType: proto.AIRichResponseMessageType.AI_RICH_RESPONSE_TYPE_STANDARD,
|
|
1148
|
+
unifiedResponse: { data: Buffer.from(JSON.stringify({ response_id: responseId, sections })) },
|
|
1149
|
+
contextInfo: contextInfo || { isForwarded: true, forwardingScore: 1, forwardOrigin: 4 }
|
|
1150
|
+
});
|
|
1151
|
+
return wrapToBotForwardedMessage(richResponseMessage);
|
|
1152
|
+
};
|
|
1153
|
+
|
|
1154
|
+
/** Build a protocol-backed AIRich map card with optional numbered annotations. */
|
|
1155
|
+
export const prepareRichMapMessage = ({ centerLatitude, centerLongitude, latitudeDelta, longitudeDelta, annotations = [], showInfoList = false, verificationMetadata } = {}) => {
|
|
1156
|
+
if (!Number.isFinite(Number(centerLatitude)) || !Number.isFinite(Number(centerLongitude))) {
|
|
1157
|
+
throw new Boom('prepareRichMapMessage requires centerLatitude and centerLongitude', { statusCode: 400 });
|
|
1158
|
+
}
|
|
1159
|
+
const submessages = [{
|
|
1160
|
+
messageType: RichSubMessageType.MAP,
|
|
1161
|
+
mapMetadata: {
|
|
1162
|
+
centerLatitude: Number(centerLatitude),
|
|
1163
|
+
centerLongitude: Number(centerLongitude),
|
|
1164
|
+
...(latitudeDelta == null ? {} : { latitudeDelta: Number(latitudeDelta) }),
|
|
1165
|
+
...(longitudeDelta == null ? {} : { longitudeDelta: Number(longitudeDelta) }),
|
|
1166
|
+
showInfoList: Boolean(showInfoList),
|
|
1167
|
+
annotations: (Array.isArray(annotations) ? annotations : []).map((annotation, index) => ({
|
|
1168
|
+
annotationNumber: annotation.annotationNumber ?? index + 1,
|
|
1169
|
+
latitude: Number(annotation.latitude),
|
|
1170
|
+
longitude: Number(annotation.longitude),
|
|
1171
|
+
title: String(annotation.title || ''),
|
|
1172
|
+
body: String(annotation.body || '')
|
|
1173
|
+
}))
|
|
1174
|
+
}
|
|
1175
|
+
}];
|
|
1176
|
+
const richResponseMessage = proto.AIRichResponseMessage.create({
|
|
1177
|
+
messageType: proto.AIRichResponseMessageType.AI_RICH_RESPONSE_TYPE_STANDARD,
|
|
1178
|
+
submessages,
|
|
1179
|
+
unifiedResponse: { data: Buffer.from(JSON.stringify(toUnified(submessages, randomUUID()))) },
|
|
1180
|
+
contextInfo: { isForwarded: true, forwardingScore: 1, forwardOrigin: 4 }
|
|
1181
|
+
});
|
|
1182
|
+
return wrapToBotForwardedMessage(richResponseMessage, verificationMetadata);
|
|
1183
|
+
};
|
|
1184
|
+
|
|
1185
|
+
/** Build a rich response carrying BotSuggestedPromptMetadata from WAProto. */
|
|
1186
|
+
export const prepareBotPromptSuggestionsMessage = ({ text = '', suggestions = [], selectedPromptIndex, selectedPromptId, verificationMetadata } = {}) => {
|
|
1187
|
+
if (!Array.isArray(suggestions) || suggestions.length === 0) {
|
|
1188
|
+
throw new Boom('prepareBotPromptSuggestionsMessage requires at least one suggestion', { statusCode: 400 });
|
|
1189
|
+
}
|
|
1190
|
+
const envelope = wrapToBotForwardedMessage(proto.AIRichResponseMessage.create({
|
|
1191
|
+
messageType: proto.AIRichResponseMessageType.AI_RICH_RESPONSE_TYPE_STANDARD,
|
|
1192
|
+
submessages: [{ messageType: RichSubMessageType.TEXT, messageText: String(text) }],
|
|
1193
|
+
contextInfo: { isForwarded: true, forwardingScore: 1, forwardOrigin: 4 }
|
|
1194
|
+
}), verificationMetadata);
|
|
1195
|
+
envelope.messageContextInfo.botMetadata.suggestedPromptMetadata = {
|
|
1196
|
+
suggestedPrompts: suggestions.map(String),
|
|
1197
|
+
...(selectedPromptIndex == null ? {} : { selectedPromptIndex: Number(selectedPromptIndex) }),
|
|
1198
|
+
...(selectedPromptId == null ? {} : { selectedPromptId: String(selectedPromptId) })
|
|
1199
|
+
};
|
|
1200
|
+
return envelope;
|
|
1201
|
+
};
|
|
1202
|
+
|
|
1203
|
+
/** Build a rich response carrying BotSourcesMetadata for citations/search results. */
|
|
1204
|
+
export const prepareBotSourcesMessage = ({ text = '', sources = [], verificationMetadata } = {}) => {
|
|
1205
|
+
if (!Array.isArray(sources) || sources.length === 0) {
|
|
1206
|
+
throw new Boom('prepareBotSourcesMessage requires at least one source', { statusCode: 400 });
|
|
1207
|
+
}
|
|
1208
|
+
const envelope = wrapToBotForwardedMessage(proto.AIRichResponseMessage.create({
|
|
1209
|
+
messageType: proto.AIRichResponseMessageType.AI_RICH_RESPONSE_TYPE_STANDARD,
|
|
1210
|
+
submessages: [{ messageType: RichSubMessageType.TEXT, messageText: String(text) }],
|
|
1211
|
+
contextInfo: { isForwarded: true, forwardingScore: 1, forwardOrigin: 4 }
|
|
1212
|
+
}), verificationMetadata);
|
|
1213
|
+
envelope.messageContextInfo.botMetadata.richResponseSourcesMetadata = {
|
|
1214
|
+
sources: sources.map((source, index) => ({
|
|
1215
|
+
provider: source.provider ?? proto.BotSourcesMetadata.BotSourceItem.SourceProvider.OTHER,
|
|
1216
|
+
thumbnailCdnUrl: source.thumbnailCdnUrl || source.thumbnailUrl || '',
|
|
1217
|
+
sourceProviderUrl: source.sourceProviderUrl || source.url || '',
|
|
1218
|
+
sourceQuery: source.sourceQuery || source.query || '',
|
|
1219
|
+
faviconCdnUrl: source.faviconCdnUrl || source.faviconUrl || '',
|
|
1220
|
+
citationNumber: source.citationNumber ?? index + 1,
|
|
1221
|
+
sourceTitle: source.sourceTitle || source.title || ''
|
|
1222
|
+
}))
|
|
1223
|
+
};
|
|
1224
|
+
return envelope;
|
|
1225
|
+
};
|
|
1226
|
+
|
|
1227
|
+
/** Build an AIRich dynamic image/GIF submessage from WAProto metadata. */
|
|
1228
|
+
export const prepareRichDynamicMediaMessage = ({ url = '', type = 'IMAGE', version = 1, loopCount, verificationMetadata } = {}) => {
|
|
1229
|
+
if (!url || typeof url !== 'string') throw new Boom('prepareRichDynamicMediaMessage requires a URL', { statusCode: 400 });
|
|
1230
|
+
const dynamicTypes = proto.AIRichResponseDynamicMetadata.AIRichResponseDynamicMetadataType;
|
|
1231
|
+
const normalizedType = String(type).toUpperCase();
|
|
1232
|
+
const dynamicMetadata = {
|
|
1233
|
+
type: normalizedType === 'GIF'
|
|
1234
|
+
? dynamicTypes.AI_RICH_RESPONSE_DYNAMIC_METADATA_TYPE_GIF
|
|
1235
|
+
: dynamicTypes.AI_RICH_RESPONSE_DYNAMIC_METADATA_TYPE_IMAGE,
|
|
1236
|
+
version: Number(version),
|
|
1237
|
+
url,
|
|
1238
|
+
...(loopCount == null ? {} : { loopCount: Number(loopCount) })
|
|
1239
|
+
};
|
|
1240
|
+
const submessages = [{ messageType: RichSubMessageType.DYNAMIC, dynamicMetadata }];
|
|
1241
|
+
const richResponseMessage = proto.AIRichResponseMessage.create({
|
|
1242
|
+
messageType: proto.AIRichResponseMessageType.AI_RICH_RESPONSE_TYPE_STANDARD,
|
|
1243
|
+
submessages,
|
|
1244
|
+
unifiedResponse: { data: Buffer.from(JSON.stringify(toUnified(submessages, randomUUID()))) },
|
|
1245
|
+
contextInfo: { isForwarded: true, forwardingScore: 1, forwardOrigin: 4 }
|
|
1246
|
+
});
|
|
1247
|
+
return wrapToBotForwardedMessage(richResponseMessage, verificationMetadata);
|
|
1248
|
+
};
|
|
1249
|
+
|
|
1250
|
+
/** Build a rich response carrying the exact BotPttPromptMetadata transcript field. */
|
|
1251
|
+
export const prepareBotPttTranscriptMessage = ({ text = '', transcript = '', verificationMetadata } = {}) => {
|
|
1252
|
+
if (!transcript || typeof transcript !== 'string') {
|
|
1253
|
+
throw new Boom('prepareBotPttTranscriptMessage requires a transcript', { statusCode: 400 });
|
|
1254
|
+
}
|
|
1255
|
+
const envelope = wrapToBotForwardedMessage(proto.AIRichResponseMessage.create({
|
|
1256
|
+
messageType: proto.AIRichResponseMessageType.AI_RICH_RESPONSE_TYPE_STANDARD,
|
|
1257
|
+
submessages: [{ messageType: RichSubMessageType.TEXT, messageText: String(text || transcript) }],
|
|
1258
|
+
contextInfo: { isForwarded: true, forwardingScore: 1, forwardOrigin: 4 }
|
|
1259
|
+
}), verificationMetadata);
|
|
1260
|
+
envelope.messageContextInfo.botMetadata.pttPromptMetadata = { transcript };
|
|
1261
|
+
return envelope;
|
|
1262
|
+
};
|
|
1263
|
+
|
|
1005
1264
|
export const prepareRichResponseMessage = (content) => {
|
|
1006
1265
|
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;
|
|
1007
1266
|
let submessages = [];
|
package/lib/index.d.ts
CHANGED
|
@@ -278,6 +278,67 @@ export interface SocialEntityContent {
|
|
|
278
278
|
responseId?: string;
|
|
279
279
|
}
|
|
280
280
|
|
|
281
|
+
export interface RichMapAnnotation {
|
|
282
|
+
annotationNumber?: number;
|
|
283
|
+
latitude: number;
|
|
284
|
+
longitude: number;
|
|
285
|
+
title?: string;
|
|
286
|
+
body?: string;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
export interface RichMapContent {
|
|
290
|
+
centerLatitude: number;
|
|
291
|
+
centerLongitude: number;
|
|
292
|
+
latitudeDelta?: number;
|
|
293
|
+
longitudeDelta?: number;
|
|
294
|
+
annotations?: RichMapAnnotation[];
|
|
295
|
+
showInfoList?: boolean;
|
|
296
|
+
verificationMetadata?: Record<string, unknown>;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
export interface BotPromptSuggestionsContent {
|
|
300
|
+
text?: string;
|
|
301
|
+
suggestions: string[];
|
|
302
|
+
selectedPromptIndex?: number;
|
|
303
|
+
selectedPromptId?: string;
|
|
304
|
+
verificationMetadata?: Record<string, unknown>;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
export interface BotSourceContent {
|
|
308
|
+
provider?: number;
|
|
309
|
+
thumbnailCdnUrl?: string;
|
|
310
|
+
thumbnailUrl?: string;
|
|
311
|
+
sourceProviderUrl?: string;
|
|
312
|
+
url?: string;
|
|
313
|
+
sourceQuery?: string;
|
|
314
|
+
query?: string;
|
|
315
|
+
faviconCdnUrl?: string;
|
|
316
|
+
faviconUrl?: string;
|
|
317
|
+
citationNumber?: number;
|
|
318
|
+
sourceTitle?: string;
|
|
319
|
+
title?: string;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
export interface BotSourcesContent {
|
|
323
|
+
text?: string;
|
|
324
|
+
sources: BotSourceContent[];
|
|
325
|
+
verificationMetadata?: Record<string, unknown>;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
export interface RichDynamicMediaContent {
|
|
329
|
+
url: string;
|
|
330
|
+
type?: 'IMAGE' | 'GIF' | string;
|
|
331
|
+
version?: number;
|
|
332
|
+
loopCount?: number;
|
|
333
|
+
verificationMetadata?: Record<string, unknown>;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
export interface BotPttTranscriptContent {
|
|
337
|
+
transcript: string;
|
|
338
|
+
text?: string;
|
|
339
|
+
verificationMetadata?: Record<string, unknown>;
|
|
340
|
+
}
|
|
341
|
+
|
|
281
342
|
export interface AIRichCommandMenuContent {
|
|
282
343
|
image: string;
|
|
283
344
|
title?: string;
|
|
@@ -326,6 +387,16 @@ export interface WASocket {
|
|
|
326
387
|
richMenu(jid: string, content?: RichMenuContent, options?: Record<string, unknown>): Promise<unknown>;
|
|
327
388
|
/** Send a provider-neutral AIRich social/entity result card. */
|
|
328
389
|
sendSocialEntity(jid: string, content?: SocialEntityContent, options?: Record<string, unknown>): Promise<unknown>;
|
|
390
|
+
/** Send a protocol-backed AIRich map with optional numbered annotations. */
|
|
391
|
+
sendRichMap(jid: string, content: RichMapContent, options?: Record<string, unknown>): Promise<unknown>;
|
|
392
|
+
/** Send BotSuggestedPromptMetadata with a rich-response text fallback. */
|
|
393
|
+
sendBotPromptSuggestions(jid: string, content: BotPromptSuggestionsContent, options?: Record<string, unknown>): Promise<unknown>;
|
|
394
|
+
/** Send BotSourcesMetadata for citation-aware bot responses. */
|
|
395
|
+
sendBotSources(jid: string, content: BotSourcesContent, options?: Record<string, unknown>): Promise<unknown>;
|
|
396
|
+
/** Send an experimental AIRich dynamic image/GIF submessage. */
|
|
397
|
+
sendRichDynamicMedia(jid: string, content: RichDynamicMediaContent, options?: Record<string, unknown>): Promise<unknown>;
|
|
398
|
+
/** Send BotPttPromptMetadata containing a caller-provided transcript. */
|
|
399
|
+
sendBotPttTranscript(jid: string, content: BotPttTranscriptContent, options?: Record<string, unknown>): Promise<unknown>;
|
|
329
400
|
/** Send the primary Instagram profile result using the universal social/entity format. */
|
|
330
401
|
sendInstagramProfile(jid: string, content: SocialEntityContent, options?: Record<string, unknown>): Promise<unknown>;
|
|
331
402
|
/** Send arbitrary A2UI/interactive payloads with immediate relay/edit rendering. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "plogme",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.7",
|
|
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",
|