@codexverified/baileys 2.17.17 → 2.17.18
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 +78 -2
- package/lib/Socket/messages-send.js +106 -1
- package/lib/Utils/rich-message-utils.js +321 -4
- package/lib/index.d.ts +94 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -58,13 +58,14 @@ The package is maintained by **Codex** under the **CodexVerified** organization.
|
|
|
58
58
|
- [Comparison references](#comparison-references)
|
|
59
59
|
- [Additional functional compatibility helpers](#additional-functional-compatibility-helpers)
|
|
60
60
|
- [AI generation primitive](#ai-generation-primitive)
|
|
61
|
+
- [New AIRich metadata helpers](#new-airich-metadata-helpers)
|
|
61
62
|
|
|
62
63
|
## At a glance
|
|
63
64
|
|
|
64
65
|
| Property | Value |
|
|
65
66
|
| --- | --- |
|
|
66
67
|
| Package | `@codexverified/baileys` |
|
|
67
|
-
| Version | `2.17.
|
|
68
|
+
| Version | `2.17.18` |
|
|
68
69
|
| Runtime | Node.js 20 or newer |
|
|
69
70
|
| Module format | ESM, with CommonJS compatibility where supported |
|
|
70
71
|
| Type declarations | Included at `lib/index.d.ts` |
|
|
@@ -78,7 +79,7 @@ The package is maintained by **Codex** under the **CodexVerified** organization.
|
|
|
78
79
|
| Method | Command | Notes |
|
|
79
80
|
| --- | --- | --- |
|
|
80
81
|
| From npm | `npm install @codexverified/baileys` | Standard install when published under your organization |
|
|
81
|
-
| From local archive | `npm install ./codex-baileys-2.17.
|
|
82
|
+
| From local archive | `npm install ./codex-baileys-2.17.18.tgz` | Place the `.tgz` beside your application |
|
|
82
83
|
| Source audit (no scripts) | `npm install --ignore-scripts` | Skips install hooks for local review |
|
|
83
84
|
|
|
84
85
|
Both npm and archive installs use the same import name:
|
|
@@ -859,6 +860,81 @@ await sock.sendMiniApp(jid, {
|
|
|
859
860
|
|
|
860
861
|
The package also exports `BotCapabilityType`, `normalizeBotCapabilities`, `buildBotCapabilityMetadata`, and `buildBotRichResponse` for applications that need to construct compatible bot metadata.
|
|
861
862
|
|
|
863
|
+
|
|
864
|
+
## New AIRich metadata helpers
|
|
865
|
+
|
|
866
|
+
The package includes experimental helpers for protocol-backed rich clients. Rendering depends on the recipient's WhatsApp client version; these helpers do not call Meta AI or any private backend.
|
|
867
|
+
|
|
868
|
+
```js
|
|
869
|
+
await sock.sendA2UIMessage(jid, {
|
|
870
|
+
type: 'im_a2ui',
|
|
871
|
+
data: {
|
|
872
|
+
version: 'v0.9',
|
|
873
|
+
createSurface: {
|
|
874
|
+
surfaceId: 'custom-card',
|
|
875
|
+
catalogId: 'https://a2ui.org/specification/v0_9/catalogs/basic/catalog.json',
|
|
876
|
+
components: [{ id: 'root', component: 'Column', children: ['title'] }]
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
})
|
|
880
|
+
|
|
881
|
+
await sock.sendRichMap(jid, {
|
|
882
|
+
centerLatitude: 6.5244,
|
|
883
|
+
centerLongitude: 3.3792,
|
|
884
|
+
annotations: [{ latitude: 6.53, longitude: 3.38, title: 'Lagos', body: 'Nigeria' }],
|
|
885
|
+
showInfoList: true
|
|
886
|
+
})
|
|
887
|
+
|
|
888
|
+
await sock.sendBotPromptSuggestions(jid, {
|
|
889
|
+
text: 'Choose a follow-up',
|
|
890
|
+
suggestions: ['Summarize this', 'Translate this', 'Explain further'],
|
|
891
|
+
selectedPromptId: 'translate'
|
|
892
|
+
})
|
|
893
|
+
|
|
894
|
+
await sock.sendBotSources(jid, {
|
|
895
|
+
text: 'Relevant sources:',
|
|
896
|
+
sources: [{
|
|
897
|
+
provider: 2,
|
|
898
|
+
url: 'https://example.com/docs',
|
|
899
|
+
query: 'baileys proto',
|
|
900
|
+
title: 'Documentation',
|
|
901
|
+
citationNumber: 1
|
|
902
|
+
}]
|
|
903
|
+
})
|
|
904
|
+
|
|
905
|
+
await sock.sendRichDynamicMedia(jid, {
|
|
906
|
+
type: 'IMAGE',
|
|
907
|
+
url: 'https://example.com/image.jpg',
|
|
908
|
+
version: 1
|
|
909
|
+
})
|
|
910
|
+
|
|
911
|
+
await sock.sendBotPttTranscript(jid, {
|
|
912
|
+
text: 'Voice transcript',
|
|
913
|
+
transcript: 'Hello, this text came from a voice message.'
|
|
914
|
+
})
|
|
915
|
+
|
|
916
|
+
await sock.sendSocialEntity(jid, {
|
|
917
|
+
platform: 'YOUTUBE',
|
|
918
|
+
username: 'example',
|
|
919
|
+
title: 'Example creator',
|
|
920
|
+
imageUrl: 'https://example.com/avatar.png',
|
|
921
|
+
entityUrl: 'https://www.youtube.com/@example',
|
|
922
|
+
isVerified: true,
|
|
923
|
+
resultText: 'See results'
|
|
924
|
+
})
|
|
925
|
+
|
|
926
|
+
await sock.sendInstagramProfile(jid, {
|
|
927
|
+
username: 'example',
|
|
928
|
+
title: 'Example profile',
|
|
929
|
+
imageUrl: 'https://example.com/avatar.png',
|
|
930
|
+
entityUrl: 'https://www.instagram.com/example',
|
|
931
|
+
isVerified: true,
|
|
932
|
+
resultText: 'See results'
|
|
933
|
+
})
|
|
934
|
+
```
|
|
935
|
+
|
|
936
|
+
The map, prompt, source, dynamic-media, transcript, A2UI, and social/entity payloads are serialized from the generated `WAProto` structures. Validate URLs, button identifiers, and any user-supplied metadata in your own application before sending.
|
|
937
|
+
|
|
862
938
|
<div align="center">
|
|
863
939
|
|
|
864
940
|
<sub>Thanks for reading my README.</sub>
|
|
@@ -12,7 +12,7 @@ import { areJidsSameUser, getBinaryNodeChild, getBinaryNodeChildren, getBizBinar
|
|
|
12
12
|
import { USyncQuery, USyncUser } from '../WAUSync/index.js';
|
|
13
13
|
import { captureUnifiedResponse, generateButtonGridContent, generateCodeBlockContent, generateLatexContent, generateListContent, generateRichMenuContent, generateTableContent, generateUnifiedResponseContent } from '../Utils/message-composer.js';
|
|
14
14
|
import { Baron } from './interactive-handler.js';
|
|
15
|
-
import { prepareRichResponseMessage, prepareRichGenerationMessage, prepareRichTextMessage, prepareRichImageMessage, prepareRichLinkMessage, prepareA2UICommandMenu, prepareAIRichCommandMenu, prepareVideoGridMessage, prepareVerticalAlbumMessage, prepareHtmlMessage, prepareRichHtmlMessage } from '../Utils/rich-message-utils.js';
|
|
15
|
+
import { prepareRichResponseMessage, prepareRichGenerationMessage, prepareRichTextMessage, prepareRichImageMessage, prepareRichLinkMessage, prepareA2UICommandMenu, prepareAIRichCommandMenu, prepareVideoGridMessage, prepareVerticalAlbumMessage, prepareHtmlMessage, prepareRichHtmlMessage, prepareA2UIMessage, prepareBotPromptSuggestionsMessage, prepareBotPttTranscriptMessage, prepareBotSourcesMessage, prepareInstagramProfileMessage, prepareRichDynamicMediaMessage, prepareRichMapMessage, prepareSocialEntityMessage } from '../Utils/rich-message-utils.js';
|
|
16
16
|
import { generateSlotMachineHtml } from '../Utils/games/slot-machine.js';
|
|
17
17
|
import { generateMiniAppHtml } from '../Utils/games/miniapp.js';
|
|
18
18
|
import { generateWebsitePreviewHtml, generateLinkPreviewHtml } from '../Utils/website-preview.js';
|
|
@@ -1322,6 +1322,111 @@ export const makeMessagesSocket = (config) => {
|
|
|
1322
1322
|
await relayMessage(jid, fullMsg.message, { messageId: fullMsg.key.id, useCachedGroupMetadata: options.useCachedGroupMetadata, statusJidList: options.statusJidList });
|
|
1323
1323
|
return fullMsg;
|
|
1324
1324
|
},
|
|
1325
|
+
sendA2UIMessage: async (jid, content = {}, options = {}) => {
|
|
1326
|
+
if (!jid) throw new Boom('sendA2UIMessage requires a target JID', { statusCode: 400 });
|
|
1327
|
+
const { image, ...payload } = content || {};
|
|
1328
|
+
let imageMessage;
|
|
1329
|
+
if (image) {
|
|
1330
|
+
const prepared = await prepareWAMessageMedia({ image }, { upload: waUploadToServer });
|
|
1331
|
+
imageMessage = prepared.imageMessage;
|
|
1332
|
+
}
|
|
1333
|
+
const wrapped = prepareA2UIMessage({ ...payload, imageMessage });
|
|
1334
|
+
const fullMsg = await generateWAMessageFromContent(jid, wrapped, {
|
|
1335
|
+
logger,
|
|
1336
|
+
userJid: authState.creds.me?.id,
|
|
1337
|
+
messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id || jid),
|
|
1338
|
+
...options,
|
|
1339
|
+
});
|
|
1340
|
+
await relayRichMessage(jid, fullMsg, { ...options, forceRichEdit: true });
|
|
1341
|
+
if (config.emitOwnEvents) process.nextTick(async () => { await messageMutex.mutex(() => upsertMessage(fullMsg, 'append')); });
|
|
1342
|
+
return fullMsg;
|
|
1343
|
+
},
|
|
1344
|
+
sendBotPromptSuggestions: async (jid, content = {}, options = {}) => {
|
|
1345
|
+
if (!jid) throw new Boom('sendBotPromptSuggestions requires a target JID', { statusCode: 400 });
|
|
1346
|
+
const wrapped = prepareBotPromptSuggestionsMessage(content);
|
|
1347
|
+
const fullMsg = await generateWAMessageFromContent(jid, wrapped, {
|
|
1348
|
+
logger,
|
|
1349
|
+
userJid: authState.creds.me?.id,
|
|
1350
|
+
messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id),
|
|
1351
|
+
...options
|
|
1352
|
+
});
|
|
1353
|
+
await relayRichMessage(jid, fullMsg, options);
|
|
1354
|
+
return fullMsg;
|
|
1355
|
+
},
|
|
1356
|
+
sendBotPttTranscript: async (jid, content = {}, options = {}) => {
|
|
1357
|
+
if (!jid) throw new Boom('sendBotPttTranscript requires a target JID', { statusCode: 400 });
|
|
1358
|
+
const wrapped = prepareBotPttTranscriptMessage(content);
|
|
1359
|
+
const fullMsg = await generateWAMessageFromContent(jid, wrapped, {
|
|
1360
|
+
logger,
|
|
1361
|
+
userJid: authState.creds.me?.id,
|
|
1362
|
+
messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id),
|
|
1363
|
+
...options
|
|
1364
|
+
});
|
|
1365
|
+
await relayRichMessage(jid, fullMsg, options);
|
|
1366
|
+
return fullMsg;
|
|
1367
|
+
},
|
|
1368
|
+
sendBotSources: async (jid, content = {}, options = {}) => {
|
|
1369
|
+
if (!jid) throw new Boom('sendBotSources requires a target JID', { statusCode: 400 });
|
|
1370
|
+
const wrapped = prepareBotSourcesMessage(content);
|
|
1371
|
+
const fullMsg = await generateWAMessageFromContent(jid, wrapped, {
|
|
1372
|
+
logger,
|
|
1373
|
+
userJid: authState.creds.me?.id,
|
|
1374
|
+
messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id),
|
|
1375
|
+
...options
|
|
1376
|
+
});
|
|
1377
|
+
await relayRichMessage(jid, fullMsg, options);
|
|
1378
|
+
return fullMsg;
|
|
1379
|
+
},
|
|
1380
|
+
sendInstagramProfile: async (jid, content = {}, options = {}) => {
|
|
1381
|
+
if (!jid) throw new Boom('sendInstagramProfile requires a target JID', { statusCode: 400 });
|
|
1382
|
+
const wrapped = prepareInstagramProfileMessage(content);
|
|
1383
|
+
const fullMsg = await generateWAMessageFromContent(jid, wrapped, {
|
|
1384
|
+
logger,
|
|
1385
|
+
userJid: authState.creds.me?.id,
|
|
1386
|
+
messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id || jid),
|
|
1387
|
+
...options
|
|
1388
|
+
});
|
|
1389
|
+
await relayRichMessage(jid, fullMsg, options);
|
|
1390
|
+
if (config.emitOwnEvents) process.nextTick(async () => { await messageMutex.mutex(() => upsertMessage(fullMsg, 'append')); });
|
|
1391
|
+
return fullMsg;
|
|
1392
|
+
},
|
|
1393
|
+
sendRichDynamicMedia: async (jid, content = {}, options = {}) => {
|
|
1394
|
+
if (!jid) throw new Boom('sendRichDynamicMedia requires a target JID', { statusCode: 400 });
|
|
1395
|
+
const wrapped = prepareRichDynamicMediaMessage(content);
|
|
1396
|
+
const fullMsg = await generateWAMessageFromContent(jid, wrapped, {
|
|
1397
|
+
logger,
|
|
1398
|
+
userJid: authState.creds.me?.id,
|
|
1399
|
+
messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id),
|
|
1400
|
+
...options
|
|
1401
|
+
});
|
|
1402
|
+
await relayRichMessage(jid, fullMsg, options);
|
|
1403
|
+
return fullMsg;
|
|
1404
|
+
},
|
|
1405
|
+
sendRichMap: async (jid, content = {}, options = {}) => {
|
|
1406
|
+
if (!jid) throw new Boom('sendRichMap requires a target JID', { statusCode: 400 });
|
|
1407
|
+
const wrapped = prepareRichMapMessage(content);
|
|
1408
|
+
const fullMsg = await generateWAMessageFromContent(jid, wrapped, {
|
|
1409
|
+
logger,
|
|
1410
|
+
userJid: authState.creds.me?.id,
|
|
1411
|
+
messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id),
|
|
1412
|
+
...options
|
|
1413
|
+
});
|
|
1414
|
+
await relayRichMessage(jid, fullMsg, options);
|
|
1415
|
+
return fullMsg;
|
|
1416
|
+
},
|
|
1417
|
+
sendSocialEntity: async (jid, content = {}, options = {}) => {
|
|
1418
|
+
if (!jid) throw new Boom('sendSocialEntity requires a target JID', { statusCode: 400 });
|
|
1419
|
+
const wrapped = prepareSocialEntityMessage(content);
|
|
1420
|
+
const fullMsg = await generateWAMessageFromContent(jid, wrapped, {
|
|
1421
|
+
logger,
|
|
1422
|
+
userJid: authState.creds.me?.id,
|
|
1423
|
+
messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id || jid),
|
|
1424
|
+
...options,
|
|
1425
|
+
});
|
|
1426
|
+
await relayRichMessage(jid, fullMsg, options);
|
|
1427
|
+
if (config.emitOwnEvents) process.nextTick(async () => { await messageMutex.mutex(() => upsertMessage(fullMsg, 'append')); });
|
|
1428
|
+
return fullMsg;
|
|
1429
|
+
},
|
|
1325
1430
|
/** Send the large A2UI command menu with an uploaded image header, rows, and URL buttons. */
|
|
1326
1431
|
/** Sends the manually serialized AIRich command card shown in the screenshot. */
|
|
1327
1432
|
sendAIRichCommandMenu: async (jid, content = {}, options = {}) => {
|
|
@@ -504,7 +504,7 @@ export const wrapToBotForwardedMessage = (richResponseMessage) => ({
|
|
|
504
504
|
*/
|
|
505
505
|
/** Build the A2UI interactive command menu used by the full-size card layout. */
|
|
506
506
|
/** Build the manually serialized AIRich command menu shown in the screenshot. */
|
|
507
|
-
export const prepareAIRichCommandMenu = ({ image, title = '
|
|
507
|
+
export const prepareAIRichCommandMenu = ({ image, title = 'CODEX AI', subtitle = '', code = '', rows = [], buttons = [], footer = 'Developed by - CODEX AI', latexImage, latexExpression = '' } = {}) => {
|
|
508
508
|
if (!image) throw new Error('AIRich command menu requires an image URL');
|
|
509
509
|
if (!Array.isArray(rows)) throw new Error('AIRich command-menu rows must be an array');
|
|
510
510
|
if (!Array.isArray(buttons)) throw new Error('AIRich command-menu buttons must be an array');
|
|
@@ -531,7 +531,7 @@ export const prepareAIRichCommandMenu = ({ image, title = 'CODY AI', subtitle =
|
|
|
531
531
|
return wrapToBotForwardedMessage(richResponseMessage);
|
|
532
532
|
};
|
|
533
533
|
|
|
534
|
-
export const prepareA2UICommandMenu = ({ imageMessage, title = '
|
|
534
|
+
export const prepareA2UICommandMenu = ({ imageMessage, title = 'CODEX AI', rows = [], buttons = [], fallback = '' } = {}) => {
|
|
535
535
|
if (!Array.isArray(rows)) throw new Error('A2UI command-menu rows must be an array');
|
|
536
536
|
if (!Array.isArray(buttons)) throw new Error('A2UI command-menu buttons must be an array');
|
|
537
537
|
const safeRows = rows.map((row, index) => ({
|
|
@@ -556,7 +556,7 @@ export const prepareA2UICommandMenu = ({ imageMessage, title = 'CODY AI', rows =
|
|
|
556
556
|
{ id: `command_${index}`, component: 'Text', text: row.title },
|
|
557
557
|
{ id: `description_${index}`, component: 'Text', text: row.description }
|
|
558
558
|
]),
|
|
559
|
-
{ id: 'footer', component: 'Text', text: 'Developed by -
|
|
559
|
+
{ id: 'footer', component: 'Text', text: 'Developed by - CODEX AI', variant: 'caption' }
|
|
560
560
|
];
|
|
561
561
|
if (safeButtons.length) {
|
|
562
562
|
components.push({ id: 'buttonRow', component: 'Row', justify: 'spaceEvenly', children: safeButtons.flatMap((button, index) => [`buttonLabel_${index}`, `button_${index}`]) });
|
|
@@ -748,4 +748,321 @@ export const buildImaginePrimitive = ({
|
|
|
748
748
|
};
|
|
749
749
|
};
|
|
750
750
|
|
|
751
|
-
|
|
751
|
+
export const prepareSocialEntityMessage = ({
|
|
752
|
+
username = '',
|
|
753
|
+
platform = 'GENERIC',
|
|
754
|
+
title = 'CODEX AI',
|
|
755
|
+
subtitle = '⚉',
|
|
756
|
+
imageUrl = '',
|
|
757
|
+
entityId,
|
|
758
|
+
entityUrl = '',
|
|
759
|
+
entityType,
|
|
760
|
+
fullName = 'NOT found',
|
|
761
|
+
isVerified = false,
|
|
762
|
+
resultText = 'See results',
|
|
763
|
+
botJid = '867051314767696@bot',
|
|
764
|
+
responseId
|
|
765
|
+
} = {}) => {
|
|
766
|
+
const normalizedPlatform = String(platform || 'GENERIC').toUpperCase();
|
|
767
|
+
const profileUrl = entityUrl || (username ? `https://www.${normalizedPlatform.toLowerCase()}.com/${encodeURIComponent(username)}` : '');
|
|
768
|
+
const resolvedType = entityType || (normalizedPlatform === 'INSTAGRAM' ? 'IG_PROFILE' : 'SOCIAL_PROFILE');
|
|
769
|
+
const displayName = username || fullName || 'Profile';
|
|
770
|
+
const sections = [
|
|
771
|
+
{
|
|
772
|
+
view_model: {
|
|
773
|
+
primitives: [{
|
|
774
|
+
title,
|
|
775
|
+
subtitle,
|
|
776
|
+
...(imageUrl ? { image: { url: imageUrl, mime_type: 'image/png' } } : {}),
|
|
777
|
+
entity_id: String(entityId ?? username ?? ''),
|
|
778
|
+
entity_url: profileUrl,
|
|
779
|
+
entity_type: 'WEBSITE',
|
|
780
|
+
action_type: 'OPEN_URL',
|
|
781
|
+
is_verified: !!isVerified,
|
|
782
|
+
__typename: 'GenAICompactEntityPrimitive'
|
|
783
|
+
}],
|
|
784
|
+
__typename: 'GenAIActionRowLayoutViewModel'
|
|
785
|
+
}
|
|
786
|
+
},
|
|
787
|
+
{
|
|
788
|
+
view_model: {
|
|
789
|
+
primitives: [{ type: 'HORIZONTAL_LINE', __typename: 'GenAIDividerPrimitive' }],
|
|
790
|
+
__typename: 'GenAIVStackLayoutViewModel'
|
|
791
|
+
}
|
|
792
|
+
},
|
|
793
|
+
{
|
|
794
|
+
view_model: {
|
|
795
|
+
primitives: [
|
|
796
|
+
{ __typename: 'GenAISpacerPrimitive' },
|
|
797
|
+
{
|
|
798
|
+
text: `# {{social_entity_1}}${resultText}\0{{/social_entity_1}} `,
|
|
799
|
+
inline_entities: [{
|
|
800
|
+
key: 'social_entity_1',
|
|
801
|
+
metadata: {
|
|
802
|
+
__typename: 'GenAISocialEntityItem',
|
|
803
|
+
entity_id: String(entityId ?? username ?? ''),
|
|
804
|
+
entity_name: displayName,
|
|
805
|
+
entity_full_name: fullName,
|
|
806
|
+
platform: String(platform || 'GENERIC').toUpperCase(),
|
|
807
|
+
entity_picture_url: imageUrl,
|
|
808
|
+
entity_url: profileUrl,
|
|
809
|
+
entity_type: resolvedType,
|
|
810
|
+
platform: normalizedPlatform,
|
|
811
|
+
is_verified: !!isVerified
|
|
812
|
+
}
|
|
813
|
+
}],
|
|
814
|
+
__typename: 'GenAIMarkdownTextUXPrimitive'
|
|
815
|
+
},
|
|
816
|
+
{ __typename: 'GenAISpacerPrimitive' }
|
|
817
|
+
],
|
|
818
|
+
__typename: 'GenAIActionRowLayoutViewModel'
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
];
|
|
822
|
+
return {
|
|
823
|
+
botForwardedMessage: {
|
|
824
|
+
message: {
|
|
825
|
+
richResponseMessage: {
|
|
826
|
+
messageType: 1,
|
|
827
|
+
submessages: [],
|
|
828
|
+
unifiedResponse: {
|
|
829
|
+
response_id: responseId || randomUUID(),
|
|
830
|
+
data: Buffer.from(JSON.stringify({ sections })).toString('base64')
|
|
831
|
+
},
|
|
832
|
+
contextInfo: {
|
|
833
|
+
isForwarded: true,
|
|
834
|
+
forwardOrigin: 4,
|
|
835
|
+
forwardedAiBotMessageInfo: { botJid }
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
};
|
|
841
|
+
};
|
|
842
|
+
|
|
843
|
+
/** Dedicated Instagram profile card using the universal social-entity wire format. */
|
|
844
|
+
|
|
845
|
+
export const prepareInstagramProfileMessage = (content = {}) => prepareSocialProfileMessage({
|
|
846
|
+
...content,
|
|
847
|
+
platform: 'INSTAGRAM',
|
|
848
|
+
entityType: 'IG_PROFILE',
|
|
849
|
+
entityUrl: content.entityUrl || (content.username ? `https://www.instagram.com/${encodeURIComponent(content.username)}` : undefined)
|
|
850
|
+
});
|
|
851
|
+
|
|
852
|
+
export const prepareSocialProfileMessage = (options = {}) => {
|
|
853
|
+
const {
|
|
854
|
+
username,
|
|
855
|
+
platform = 'instagram',
|
|
856
|
+
title = 'CODEX AI',
|
|
857
|
+
subtitle = '⚉',
|
|
858
|
+
imageUrl = '',
|
|
859
|
+
entityId = username,
|
|
860
|
+
entityUrl = `https://www.${platform}.com/${username || ''}`,
|
|
861
|
+
entityType = platform === 'instagram' ? 'IG_PROFILE' : `${String(platform).toUpperCase()}_PROFILE`,
|
|
862
|
+
fullName = 'NOT found',
|
|
863
|
+
isVerified = false,
|
|
864
|
+
resultText = 'See results'
|
|
865
|
+
} = options;
|
|
866
|
+
if (!username || typeof username !== 'string') {
|
|
867
|
+
throw new Boom('sendSocialProfile requires a username', { statusCode: 400 });
|
|
868
|
+
}
|
|
869
|
+
const image = imageUrl ? { url: imageUrl, mime_type: 'image/png' } : undefined;
|
|
870
|
+
const sections = [
|
|
871
|
+
{
|
|
872
|
+
view_model: {
|
|
873
|
+
primitives: [{
|
|
874
|
+
title,
|
|
875
|
+
subtitle,
|
|
876
|
+
...(image ? { image } : {}),
|
|
877
|
+
entity_id: String(entityId || username),
|
|
878
|
+
entity_url: entityUrl,
|
|
879
|
+
entity_type: 'WEBSITE',
|
|
880
|
+
action_type: 'OPEN_URL',
|
|
881
|
+
is_verified: Boolean(isVerified),
|
|
882
|
+
__typename: 'GenAICompactEntityPrimitive'
|
|
883
|
+
}],
|
|
884
|
+
__typename: 'GenAIActionRowLayoutViewModel'
|
|
885
|
+
}
|
|
886
|
+
},
|
|
887
|
+
{
|
|
888
|
+
view_model: {
|
|
889
|
+
primitives: [{ type: 'HORIZONTAL_LINE', __typename: 'GenAIDividerPrimitive' }],
|
|
890
|
+
__typename: 'GenAIVStackLayoutViewModel'
|
|
891
|
+
}
|
|
892
|
+
},
|
|
893
|
+
{
|
|
894
|
+
view_model: {
|
|
895
|
+
primitives: [
|
|
896
|
+
{ __typename: 'GenAISpacerPrimitive' },
|
|
897
|
+
{
|
|
898
|
+
text: `# {{social_entity_1}}${resultText}\0{{/social_entity_1}} `,
|
|
899
|
+
inline_entities: [{
|
|
900
|
+
key: 'social_entity_1',
|
|
901
|
+
metadata: {
|
|
902
|
+
__typename: 'GenAISocialEntityItem',
|
|
903
|
+
entity_id: username,
|
|
904
|
+
entity_name: username,
|
|
905
|
+
entity_full_name: fullName,
|
|
906
|
+
platform: String(platform || 'GENERIC').toUpperCase(),
|
|
907
|
+
entity_picture_url: imageUrl,
|
|
908
|
+
entity_url: entityUrl,
|
|
909
|
+
entity_type: entityType,
|
|
910
|
+
is_verified: Boolean(isVerified)
|
|
911
|
+
}
|
|
912
|
+
}],
|
|
913
|
+
__typename: 'GenAIMarkdownTextUXPrimitive'
|
|
914
|
+
},
|
|
915
|
+
{ __typename: 'GenAISpacerPrimitive' }
|
|
916
|
+
],
|
|
917
|
+
__typename: 'GenAIActionRowLayoutViewModel'
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
];
|
|
921
|
+
const richResponseMessage = proto.AIRichResponseMessage.create({
|
|
922
|
+
submessages: [],
|
|
923
|
+
messageType: proto.AIRichResponseMessageType.AI_RICH_RESPONSE_TYPE_STANDARD,
|
|
924
|
+
unifiedResponse: { data: Buffer.from(JSON.stringify({ sections })) },
|
|
925
|
+
contextInfo: { isForwarded: true, forwardOrigin: 4 }
|
|
926
|
+
});
|
|
927
|
+
return wrapToBotForwardedMessage(richResponseMessage);
|
|
928
|
+
};
|
|
929
|
+
|
|
930
|
+
|
|
931
|
+
/**
|
|
932
|
+
* Builds a generic unified-response envelope without reducing its sections to
|
|
933
|
+
* plain text. This is the extension point for newer WhatsApp primitives that
|
|
934
|
+
* are present in WAProto but do not yet have a dedicated convenience helper.
|
|
935
|
+
*/
|
|
936
|
+
|
|
937
|
+
export const prepareRichMapMessage = ({ centerLatitude, centerLongitude, latitudeDelta, longitudeDelta, annotations = [], showInfoList = false, verificationMetadata } = {}) => {
|
|
938
|
+
if (!Number.isFinite(Number(centerLatitude)) || !Number.isFinite(Number(centerLongitude))) {
|
|
939
|
+
throw new Boom('prepareRichMapMessage requires centerLatitude and centerLongitude', { statusCode: 400 });
|
|
940
|
+
}
|
|
941
|
+
const submessages = [{
|
|
942
|
+
messageType: RichSubMessageType.MAP,
|
|
943
|
+
mapMetadata: {
|
|
944
|
+
centerLatitude: Number(centerLatitude),
|
|
945
|
+
centerLongitude: Number(centerLongitude),
|
|
946
|
+
...(latitudeDelta == null ? {} : { latitudeDelta: Number(latitudeDelta) }),
|
|
947
|
+
...(longitudeDelta == null ? {} : { longitudeDelta: Number(longitudeDelta) }),
|
|
948
|
+
showInfoList: Boolean(showInfoList),
|
|
949
|
+
annotations: (Array.isArray(annotations) ? annotations : []).map((annotation, index) => ({
|
|
950
|
+
annotationNumber: annotation.annotationNumber ?? index + 1,
|
|
951
|
+
latitude: Number(annotation.latitude),
|
|
952
|
+
longitude: Number(annotation.longitude),
|
|
953
|
+
title: String(annotation.title || ''),
|
|
954
|
+
body: String(annotation.body || '')
|
|
955
|
+
}))
|
|
956
|
+
}
|
|
957
|
+
}];
|
|
958
|
+
const richResponseMessage = proto.AIRichResponseMessage.create({
|
|
959
|
+
messageType: proto.AIRichResponseMessageType.AI_RICH_RESPONSE_TYPE_STANDARD,
|
|
960
|
+
submessages,
|
|
961
|
+
unifiedResponse: { data: Buffer.from(JSON.stringify(toUnified(submessages, randomUUID()))) },
|
|
962
|
+
contextInfo: { isForwarded: true, forwardingScore: 1, forwardOrigin: 4 }
|
|
963
|
+
});
|
|
964
|
+
return wrapToBotForwardedMessage(richResponseMessage, verificationMetadata);
|
|
965
|
+
};
|
|
966
|
+
|
|
967
|
+
/** Build a rich response carrying BotSuggestedPromptMetadata from WAProto. */
|
|
968
|
+
|
|
969
|
+
export const prepareBotPromptSuggestionsMessage = ({ text = '', suggestions = [], selectedPromptIndex, selectedPromptId, verificationMetadata } = {}) => {
|
|
970
|
+
if (!Array.isArray(suggestions) || suggestions.length === 0) {
|
|
971
|
+
throw new Boom('prepareBotPromptSuggestionsMessage requires at least one suggestion', { statusCode: 400 });
|
|
972
|
+
}
|
|
973
|
+
const envelope = wrapToBotForwardedMessage(proto.AIRichResponseMessage.create({
|
|
974
|
+
messageType: proto.AIRichResponseMessageType.AI_RICH_RESPONSE_TYPE_STANDARD,
|
|
975
|
+
submessages: [{ messageType: RichSubMessageType.TEXT, messageText: String(text) }],
|
|
976
|
+
contextInfo: { isForwarded: true, forwardingScore: 1, forwardOrigin: 4 }
|
|
977
|
+
}), verificationMetadata);
|
|
978
|
+
envelope.messageContextInfo.botMetadata.suggestedPromptMetadata = {
|
|
979
|
+
suggestedPrompts: suggestions.map(String),
|
|
980
|
+
...(selectedPromptIndex == null ? {} : { selectedPromptIndex: Number(selectedPromptIndex) }),
|
|
981
|
+
...(selectedPromptId == null ? {} : { selectedPromptId: String(selectedPromptId) })
|
|
982
|
+
};
|
|
983
|
+
return envelope;
|
|
984
|
+
};
|
|
985
|
+
|
|
986
|
+
/** Build a rich response carrying BotSourcesMetadata for citations/search results. */
|
|
987
|
+
|
|
988
|
+
export const prepareBotSourcesMessage = ({ text = '', sources = [], verificationMetadata } = {}) => {
|
|
989
|
+
if (!Array.isArray(sources) || sources.length === 0) {
|
|
990
|
+
throw new Boom('prepareBotSourcesMessage requires at least one source', { statusCode: 400 });
|
|
991
|
+
}
|
|
992
|
+
const envelope = wrapToBotForwardedMessage(proto.AIRichResponseMessage.create({
|
|
993
|
+
messageType: proto.AIRichResponseMessageType.AI_RICH_RESPONSE_TYPE_STANDARD,
|
|
994
|
+
submessages: [{ messageType: RichSubMessageType.TEXT, messageText: String(text) }],
|
|
995
|
+
contextInfo: { isForwarded: true, forwardingScore: 1, forwardOrigin: 4 }
|
|
996
|
+
}), verificationMetadata);
|
|
997
|
+
envelope.messageContextInfo.botMetadata.richResponseSourcesMetadata = {
|
|
998
|
+
sources: sources.map((source, index) => ({
|
|
999
|
+
provider: source.provider ?? proto.BotSourcesMetadata.BotSourceItem.SourceProvider.OTHER,
|
|
1000
|
+
thumbnailCdnUrl: source.thumbnailCdnUrl || source.thumbnailUrl || '',
|
|
1001
|
+
sourceProviderUrl: source.sourceProviderUrl || source.url || '',
|
|
1002
|
+
sourceQuery: source.sourceQuery || source.query || '',
|
|
1003
|
+
faviconCdnUrl: source.faviconCdnUrl || source.faviconUrl || '',
|
|
1004
|
+
citationNumber: source.citationNumber ?? index + 1,
|
|
1005
|
+
sourceTitle: source.sourceTitle || source.title || ''
|
|
1006
|
+
}))
|
|
1007
|
+
};
|
|
1008
|
+
return envelope;
|
|
1009
|
+
};
|
|
1010
|
+
|
|
1011
|
+
/** Build an AIRich dynamic image/GIF submessage from WAProto metadata. */
|
|
1012
|
+
|
|
1013
|
+
export const prepareRichDynamicMediaMessage = ({ url = '', type = 'IMAGE', version = 1, loopCount, verificationMetadata } = {}) => {
|
|
1014
|
+
if (!url || typeof url !== 'string') throw new Boom('prepareRichDynamicMediaMessage requires a URL', { statusCode: 400 });
|
|
1015
|
+
const dynamicTypes = proto.AIRichResponseDynamicMetadata.AIRichResponseDynamicMetadataType;
|
|
1016
|
+
const normalizedType = String(type).toUpperCase();
|
|
1017
|
+
const dynamicMetadata = {
|
|
1018
|
+
type: normalizedType === 'GIF'
|
|
1019
|
+
? dynamicTypes.AI_RICH_RESPONSE_DYNAMIC_METADATA_TYPE_GIF
|
|
1020
|
+
: dynamicTypes.AI_RICH_RESPONSE_DYNAMIC_METADATA_TYPE_IMAGE,
|
|
1021
|
+
version: Number(version),
|
|
1022
|
+
url,
|
|
1023
|
+
...(loopCount == null ? {} : { loopCount: Number(loopCount) })
|
|
1024
|
+
};
|
|
1025
|
+
const submessages = [{ messageType: RichSubMessageType.DYNAMIC, dynamicMetadata }];
|
|
1026
|
+
const richResponseMessage = proto.AIRichResponseMessage.create({
|
|
1027
|
+
messageType: proto.AIRichResponseMessageType.AI_RICH_RESPONSE_TYPE_STANDARD,
|
|
1028
|
+
submessages,
|
|
1029
|
+
unifiedResponse: { data: Buffer.from(JSON.stringify(toUnified(submessages, randomUUID()))) },
|
|
1030
|
+
contextInfo: { isForwarded: true, forwardingScore: 1, forwardOrigin: 4 }
|
|
1031
|
+
});
|
|
1032
|
+
return wrapToBotForwardedMessage(richResponseMessage, verificationMetadata);
|
|
1033
|
+
};
|
|
1034
|
+
|
|
1035
|
+
/** Build a rich response carrying the exact BotPttPromptMetadata transcript field. */
|
|
1036
|
+
|
|
1037
|
+
export const prepareBotPttTranscriptMessage = ({ text = '', transcript = '', verificationMetadata } = {}) => {
|
|
1038
|
+
if (!transcript || typeof transcript !== 'string') {
|
|
1039
|
+
throw new Boom('prepareBotPttTranscriptMessage requires a transcript', { statusCode: 400 });
|
|
1040
|
+
}
|
|
1041
|
+
const envelope = wrapToBotForwardedMessage(proto.AIRichResponseMessage.create({
|
|
1042
|
+
messageType: proto.AIRichResponseMessageType.AI_RICH_RESPONSE_TYPE_STANDARD,
|
|
1043
|
+
submessages: [{ messageType: RichSubMessageType.TEXT, messageText: String(text || transcript) }],
|
|
1044
|
+
contextInfo: { isForwarded: true, forwardingScore: 1, forwardOrigin: 4 }
|
|
1045
|
+
}), verificationMetadata);
|
|
1046
|
+
envelope.messageContextInfo.botMetadata.pttPromptMetadata = { transcript };
|
|
1047
|
+
return envelope;
|
|
1048
|
+
};
|
|
1049
|
+
|
|
1050
|
+
export const prepareA2UIMessage = ({ imageMessage, bloksWidget = {}, nativeFlowMessage, fallback = '', ...interactiveFields } = {}) => ({
|
|
1051
|
+
interactiveMessage: {
|
|
1052
|
+
...interactiveFields,
|
|
1053
|
+
...(imageMessage ? { header: { imageMessage, hasMediaAttachment: true } } : {}),
|
|
1054
|
+
bloksWidget: {
|
|
1055
|
+
type: bloksWidget.type || 'im_a2ui',
|
|
1056
|
+
data: typeof bloksWidget.data === 'string' ? bloksWidget.data : JSON.stringify(bloksWidget.data || {}),
|
|
1057
|
+
...(bloksWidget.fallback || fallback ? { fallback: String(bloksWidget.fallback || fallback) } : {})
|
|
1058
|
+
},
|
|
1059
|
+
...(nativeFlowMessage ? {
|
|
1060
|
+
nativeFlowMessage: {
|
|
1061
|
+
...nativeFlowMessage,
|
|
1062
|
+
...(nativeFlowMessage.buttons ? { buttons: nativeFlowMessage.buttons } : {})
|
|
1063
|
+
}
|
|
1064
|
+
} : {})
|
|
1065
|
+
}
|
|
1066
|
+
});
|
|
1067
|
+
|
|
1068
|
+
/** Build the A2UI interactive command menu used by the full-size card layout. */
|
package/lib/index.d.ts
CHANGED
|
@@ -121,6 +121,83 @@ export interface AIPromptOptions {
|
|
|
121
121
|
[key: string]: unknown;
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
+
export interface SocialEntityContent {
|
|
125
|
+
username?: string;
|
|
126
|
+
platform?: string;
|
|
127
|
+
title?: string;
|
|
128
|
+
subtitle?: string;
|
|
129
|
+
imageUrl?: string;
|
|
130
|
+
entityId?: string | number;
|
|
131
|
+
entityUrl?: string;
|
|
132
|
+
entityType?: string;
|
|
133
|
+
fullName?: string;
|
|
134
|
+
isVerified?: boolean;
|
|
135
|
+
resultText?: string;
|
|
136
|
+
botJid?: string;
|
|
137
|
+
responseId?: string;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export interface RichMapAnnotation {
|
|
141
|
+
annotationNumber?: number;
|
|
142
|
+
latitude: number;
|
|
143
|
+
longitude: number;
|
|
144
|
+
title?: string;
|
|
145
|
+
body?: string;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export interface RichMapContent {
|
|
149
|
+
centerLatitude: number;
|
|
150
|
+
centerLongitude: number;
|
|
151
|
+
latitudeDelta?: number;
|
|
152
|
+
longitudeDelta?: number;
|
|
153
|
+
annotations?: RichMapAnnotation[];
|
|
154
|
+
showInfoList?: boolean;
|
|
155
|
+
verificationMetadata?: Record<string, unknown>;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export interface BotPromptSuggestionsContent {
|
|
159
|
+
text?: string;
|
|
160
|
+
suggestions: string[];
|
|
161
|
+
selectedPromptIndex?: number;
|
|
162
|
+
selectedPromptId?: string;
|
|
163
|
+
verificationMetadata?: Record<string, unknown>;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export interface BotSourceContent {
|
|
167
|
+
provider?: number;
|
|
168
|
+
thumbnailCdnUrl?: string;
|
|
169
|
+
thumbnailUrl?: string;
|
|
170
|
+
sourceProviderUrl?: string;
|
|
171
|
+
url?: string;
|
|
172
|
+
sourceQuery?: string;
|
|
173
|
+
query?: string;
|
|
174
|
+
faviconCdnUrl?: string;
|
|
175
|
+
faviconUrl?: string;
|
|
176
|
+
citationNumber?: number;
|
|
177
|
+
sourceTitle?: string;
|
|
178
|
+
title?: string;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export interface BotSourcesContent {
|
|
182
|
+
text?: string;
|
|
183
|
+
sources: BotSourceContent[];
|
|
184
|
+
verificationMetadata?: Record<string, unknown>;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export interface RichDynamicMediaContent {
|
|
188
|
+
url: string;
|
|
189
|
+
type?: 'IMAGE' | 'GIF' | string;
|
|
190
|
+
version?: number;
|
|
191
|
+
loopCount?: number;
|
|
192
|
+
verificationMetadata?: Record<string, unknown>;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export interface BotPttTranscriptContent {
|
|
196
|
+
transcript: string;
|
|
197
|
+
text?: string;
|
|
198
|
+
verificationMetadata?: Record<string, unknown>;
|
|
199
|
+
}
|
|
200
|
+
|
|
124
201
|
export interface RelayMessageOptions {
|
|
125
202
|
messageId?: string;
|
|
126
203
|
/** Recipient-only delivery: skip the sender’s own devices in a one-to-one chat. */
|
|
@@ -305,6 +382,22 @@ export interface WASocket {
|
|
|
305
382
|
sendQuoteCopy(jid: string, content: { text?: string; copyText: string; copyLabel?: string; alignment?: 'END' | 'START' | 'CENTER' }, options?: Record<string, unknown>): Promise<unknown>;
|
|
306
383
|
/** Send a full-width stacked AIRich album with at least two image/video URL items. */
|
|
307
384
|
sendAlbumMessage(jid: string, medias: Array<Record<string, unknown>>, options?: Record<string, unknown>): Promise<unknown>;
|
|
385
|
+
/** Send a provider-neutral AIRich social/entity result card. */
|
|
386
|
+
sendSocialEntity(jid: string, content?: SocialEntityContent, options?: Record<string, unknown>): Promise<unknown>;
|
|
387
|
+
/** Send a protocol-backed AIRich map with optional numbered annotations. */
|
|
388
|
+
sendRichMap(jid: string, content: RichMapContent, options?: Record<string, unknown>): Promise<unknown>;
|
|
389
|
+
/** Send BotSuggestedPromptMetadata with a rich-response text fallback. */
|
|
390
|
+
sendBotPromptSuggestions(jid: string, content: BotPromptSuggestionsContent, options?: Record<string, unknown>): Promise<unknown>;
|
|
391
|
+
/** Send BotSourcesMetadata for citation-aware bot responses. */
|
|
392
|
+
sendBotSources(jid: string, content: BotSourcesContent, options?: Record<string, unknown>): Promise<unknown>;
|
|
393
|
+
/** Send an experimental AIRich dynamic image/GIF submessage. */
|
|
394
|
+
sendRichDynamicMedia(jid: string, content: RichDynamicMediaContent, options?: Record<string, unknown>): Promise<unknown>;
|
|
395
|
+
/** Send BotPttPromptMetadata containing a caller-provided transcript. */
|
|
396
|
+
sendBotPttTranscript(jid: string, content: BotPttTranscriptContent, options?: Record<string, unknown>): Promise<unknown>;
|
|
397
|
+
/** Send the primary Instagram profile result using the universal social/entity format. */
|
|
398
|
+
sendInstagramProfile(jid: string, content: SocialEntityContent, options?: Record<string, unknown>): Promise<unknown>;
|
|
399
|
+
/** Send arbitrary A2UI/interactive payloads with immediate relay/edit rendering. */
|
|
400
|
+
sendA2UIMessage(jid: string, content?: A2UIMessageContent, options?: Record<string, unknown>): Promise<unknown>;
|
|
308
401
|
/** Send the large A2UI command/function menu with an image header and URL buttons. */
|
|
309
402
|
sendA2UICommandMenu(jid: string, content?: { image?: unknown; title?: string; rows?: Array<[string, string, string?] | { title?: string; description?: string; id?: string }>; buttons?: Array<{ text?: string; label?: string; url?: string }>; fallback?: string }, options?: Record<string, unknown>): Promise<unknown>;
|
|
310
403
|
/** Send the manually serialized AIRich command card with image, Markdown, widget CTAs, and footer actions. */
|
|
@@ -451,4 +544,5 @@ export declare function buildBotRichResponse(options?: Record<string, unknown>):
|
|
|
451
544
|
export declare function prepareVerticalAlbumMessage(options?: { items?: Array<Record<string, unknown>>; verificationMetadata?: Record<string, unknown> }): Record<string, unknown>;
|
|
452
545
|
export declare function prepareAIRichCommandMenu(options?: { image?: string; title?: string; subtitle?: string; code?: string; rows?: Array<[string, string] | Record<string, unknown>>; buttons?: Array<Record<string, unknown>>; footer?: string; latexImage?: string; latexExpression?: string }): Record<string, unknown>;
|
|
453
546
|
export declare function prepareVideoGridMessage(options?: { videos?: Array<string | Record<string, unknown>>; verificationMetadata?: Record<string, unknown> }): Record<string, unknown>;
|
|
547
|
+
|
|
454
548
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codexverified/baileys",
|
|
3
|
-
"version": "2.17.
|
|
3
|
+
"version": "2.17.18",
|
|
4
4
|
"description": "CODEX TECHNOLOGY a premium Baileys developed and built by Dev Codex, with Meta compositing, bot planning replay, welcome flow, rich messages, interactive messages, albums, and more.",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"type": "module",
|