@codexverified/baileys 2.14.14 → 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 +277 -8
- package/lib/Socket/messages-send.js +303 -3
- package/lib/Socket/newsletter.js +19 -0
- package/lib/Utils/bot-capabilities.js +84 -0
- package/lib/Utils/games/miniapp.js +5 -0
- package/lib/Utils/index.js +4 -0
- package/lib/Utils/rich-message-utils.js +506 -1
- package/lib/Utils/source-grep.js +46 -0
- package/lib/index.d.ts +124 -1
- package/package.json +1 -1
|
@@ -152,6 +152,64 @@ export const buildAdditionalBotMetadataContext = (submessages) => {
|
|
|
152
152
|
}
|
|
153
153
|
return { sources, mediaDetailsMetadataList };
|
|
154
154
|
}
|
|
155
|
+
export const prepareVideoGridMessage = ({ videos = [], verificationMetadata } = {}) => {
|
|
156
|
+
if (!Array.isArray(videos) || videos.length < 2) {
|
|
157
|
+
throw new Error('Video grid requires at least two videos');
|
|
158
|
+
}
|
|
159
|
+
const primitives = videos.map((video) => {
|
|
160
|
+
const url = typeof video === 'string' ? video : (video?.url || video?.videoUrl || video?.reelsUrl || '');
|
|
161
|
+
if (!url) throw new Error('Each video-grid item requires a video URL');
|
|
162
|
+
const item = typeof video === 'string' ? {} : video;
|
|
163
|
+
return {
|
|
164
|
+
post_id: item.postId == null ? undefined : String(item.postId),
|
|
165
|
+
reels_url: url,
|
|
166
|
+
reels_title: item.title,
|
|
167
|
+
thumbnail_url: item.thumbnailUrl || item.thumbnail,
|
|
168
|
+
creator: item.creator,
|
|
169
|
+
avatar_url: item.avatarUrl,
|
|
170
|
+
content_hash: item.contentHash,
|
|
171
|
+
likes_count: item.likes,
|
|
172
|
+
comments_count: item.comments,
|
|
173
|
+
shares_count: item.shares,
|
|
174
|
+
is_verified: item.isVerified,
|
|
175
|
+
source_app: item.sourceApp,
|
|
176
|
+
video_delivery_response: {
|
|
177
|
+
progressive_urls: (item.progressiveUrls || []).map((value) => ({
|
|
178
|
+
progressive_url: value,
|
|
179
|
+
__typename: 'GenAIProgressiveUrlResponse'
|
|
180
|
+
})),
|
|
181
|
+
dash_manifests: (item.dashManifests || []).map((value) => ({
|
|
182
|
+
manifest_xml: value,
|
|
183
|
+
__typename: 'GenAIDashManifestResponse'
|
|
184
|
+
})),
|
|
185
|
+
__typename: 'GenAIVideoDeliveryResponse'
|
|
186
|
+
},
|
|
187
|
+
__typename: 'GenAIVideoPrimitive'
|
|
188
|
+
};
|
|
189
|
+
});
|
|
190
|
+
const unified = {
|
|
191
|
+
response_id: randomUUID(),
|
|
192
|
+
sections: [{
|
|
193
|
+
view_model: {
|
|
194
|
+
primitives,
|
|
195
|
+
__typename: 'GenAIGridLayoutViewModel'
|
|
196
|
+
}
|
|
197
|
+
}]
|
|
198
|
+
};
|
|
199
|
+
const richResponseMessage = proto.AIRichResponseMessage.create({
|
|
200
|
+
submessages: [],
|
|
201
|
+
messageType: proto.AIRichResponseMessageType.AI_RICH_RESPONSE_TYPE_STANDARD,
|
|
202
|
+
unifiedResponse: { data: Buffer.from(JSON.stringify(unified)) },
|
|
203
|
+
contextInfo: {
|
|
204
|
+
isForwarded: true,
|
|
205
|
+
forwardingScore: 1,
|
|
206
|
+
forwardedAiBotMessageInfo: { botJid: '867051314767696@bot' },
|
|
207
|
+
forwardOrigin: 4
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
return wrapToBotForwardedMessage(richResponseMessage, verificationMetadata);
|
|
211
|
+
};
|
|
212
|
+
|
|
155
213
|
export const prepareRichResponseMessage = (content) => {
|
|
156
214
|
const { alignment, code, contentText, disclaimerText, footerText, headerText, imageText, inlineImage, inlineVideo, items, language, latex, links, noDonation, noHeading, posts, products, suggested, richResponse, table, tapLinkUrl, title } = content;
|
|
157
215
|
let submessages = [];
|
|
@@ -444,6 +502,78 @@ export const wrapToBotForwardedMessage = (richResponseMessage) => ({
|
|
|
444
502
|
* @param {{text?: string, label?: string, alignment?: 'END'|'START'|'CENTER'}} options
|
|
445
503
|
* @returns {{messageContextInfo: object, botForwardedMessage: object}}
|
|
446
504
|
*/
|
|
505
|
+
/** Build the A2UI interactive command menu used by the full-size card layout. */
|
|
506
|
+
/** Build the manually serialized AIRich command menu shown in the screenshot. */
|
|
507
|
+
export const prepareAIRichCommandMenu = ({ image, title = 'CODEX AI', subtitle = '', code = '', rows = [], buttons = [], footer = 'Developed by - CODEX AI', latexImage, latexExpression = '' } = {}) => {
|
|
508
|
+
if (!image) throw new Error('AIRich command menu requires an image URL');
|
|
509
|
+
if (!Array.isArray(rows)) throw new Error('AIRich command-menu rows must be an array');
|
|
510
|
+
if (!Array.isArray(buttons)) throw new Error('AIRich command-menu buttons must be an array');
|
|
511
|
+
const safeRows = rows.map((row, index) => ({ command: String(row?.[0] ?? row?.command ?? `command_${index + 1}`), description: String(row?.[1] ?? row?.description ?? '') }));
|
|
512
|
+
const table = ['Command | Function', '--- | ---', ...safeRows.map((row) => `${row.command} | ${row.description}`)].join('\n');
|
|
513
|
+
const inlineEntities = latexImage ? [{ key: 'NGA', metadata: { latex_expression: String(latexExpression), latex_image: { url: String(latexImage), width: 400, height: 400 }, font_height: 83.333, padding: 15, __typename: 'GenAILatexItem' } }] : [];
|
|
514
|
+
const text = [String(title), subtitle && String(subtitle), code && `Code: ${String(code)}`, '## Command List', table, footer && String(footer)].filter(Boolean).join('\n');
|
|
515
|
+
const imagePrimitive = { __typename: 'GenAIImagePrimitive', preview_image: { __typename: 'GenAIMediaItem', mime_type: 'image/png', url: String(image) }, full_image: { __typename: 'GenAIMediaItem', mime_type: 'image/png', url: String(image) } };
|
|
516
|
+
const ctas = buttons.map((button, index) => ({ label: String(button?.text || button?.label || `Button ${index + 1}`), state: 'PENDING', kind: 'OTHER', tool_call_id: String(button?.id || `airich_menu_${index + 1}`), toast: { label: String(button?.toast || ''), __typename: 'GenAIExtWidgetToast' }, __typename: 'GenAI3PExtWidgetCTA' }));
|
|
517
|
+
const footerPrimitives = buttons.map((button, index) => ({ cta_text: String(button?.text || button?.label || `Button ${index + 1}`), cta_type: 'OPEN_URL', cta_url: String(button?.url || ''), __typename: 'GenAIFooterActionPrimitive' }));
|
|
518
|
+
footerPrimitives.push({ cta_text: '☷ OPEN MENU', cta_type: 'OPEN_URL', cta_url: String(buttons[0]?.url || ''), __typename: 'GenAIFooterActionPrimitive' });
|
|
519
|
+
const sections = [
|
|
520
|
+
{ __typename: 'GenAIUnifiedResponseSection', view_model: { __typename: 'GenAISingleLayoutViewModel', primitive: imagePrimitive } },
|
|
521
|
+
...(ctas.length ? [{ __typename: 'GenAIUnifiedResponseSection', view_model: { primitives: [{ __typename: 'GenAI3PExtWidgetPrimitive', header: { __typename: 'GenAI3PExtWidgetStandardHeader', title: 'Command List' }, body: { __typename: 'GenAIExtCalendarEventList', ctas, sections: [] } }], __typename: 'GenAIActionRowLayoutViewModel' } }] : []),
|
|
522
|
+
{ __typename: 'GenAIUnifiedResponseSection', view_model: { primitive: { text: `{{NGA}}${text}{{/NGA}}`, inline_entities: inlineEntities, __typename: 'GenAIMarkdownTextUXPrimitive' }, __typename: 'GenAISingleLayoutViewModel' } },
|
|
523
|
+
{ __typename: 'GenAIUnifiedResponseSection', view_model: { primitives: footerPrimitives, __typename: 'GenAIActionRowLayoutViewModel' } }
|
|
524
|
+
];
|
|
525
|
+
const richResponseMessage = proto.AIRichResponseMessage.create({
|
|
526
|
+
submessages: [{ messageType: RichSubMessageType.TEXT, messageText: text }],
|
|
527
|
+
messageType: proto.AIRichResponseMessageType.AI_RICH_RESPONSE_TYPE_STANDARD,
|
|
528
|
+
unifiedResponse: { data: Buffer.from(JSON.stringify({ response_id: randomUUID(), sections })) },
|
|
529
|
+
contextInfo: { isForwarded: true, forwardingScore: 1, forwardedAiBotMessageInfo: { botJid: '867051314767696@bot' }, forwardOrigin: 4 }
|
|
530
|
+
});
|
|
531
|
+
return wrapToBotForwardedMessage(richResponseMessage);
|
|
532
|
+
};
|
|
533
|
+
|
|
534
|
+
export const prepareA2UICommandMenu = ({ imageMessage, title = 'CODEX AI', rows = [], buttons = [], fallback = '' } = {}) => {
|
|
535
|
+
if (!Array.isArray(rows)) throw new Error('A2UI command-menu rows must be an array');
|
|
536
|
+
if (!Array.isArray(buttons)) throw new Error('A2UI command-menu buttons must be an array');
|
|
537
|
+
const safeRows = rows.map((row, index) => ({
|
|
538
|
+
title: String(row?.[0] ?? row?.title ?? `Command ${index + 1}`),
|
|
539
|
+
description: String(row?.[1] ?? row?.description ?? ''),
|
|
540
|
+
id: String(row?.[2] ?? row?.id ?? row?.[0] ?? `command_${index + 1}`)
|
|
541
|
+
}));
|
|
542
|
+
const safeButtons = buttons.map((button, index) => ({ id: `a2ui_button_${index + 1}`, label: String(button?.text || button?.label || `Button ${index + 1}`), url: String(button?.url || '') }));
|
|
543
|
+
const componentIds = ['title', 'divider', 'tableCard', 'footer', ...(safeButtons.length ? ['buttonRow'] : [])];
|
|
544
|
+
const components = [
|
|
545
|
+
{ id: 'root', component: 'Column', align: 'center', children: componentIds },
|
|
546
|
+
{ id: 'title', component: 'Text', text: String(title), variant: 'h2' },
|
|
547
|
+
{ id: 'divider', component: 'Divider' },
|
|
548
|
+
{ id: 'tableCard', component: 'Card', child: 'tableColumn' },
|
|
549
|
+
{ id: 'tableColumn', component: 'Column', children: ['headerRow', ...safeRows.flatMap((_, index) => [`divider_${index}`, `row_${index}`])] },
|
|
550
|
+
{ id: 'headerRow', component: 'Row', children: ['headerCommand', 'headerFunction'] },
|
|
551
|
+
{ id: 'headerCommand', component: 'Text', text: 'Command', variant: 'h5' },
|
|
552
|
+
{ id: 'headerFunction', component: 'Text', text: 'Function', variant: 'h5' },
|
|
553
|
+
...safeRows.flatMap((row, index) => [
|
|
554
|
+
{ id: `divider_${index}`, component: 'Divider' },
|
|
555
|
+
{ id: `row_${index}`, component: 'Row', children: [`command_${index}`, `description_${index}`] },
|
|
556
|
+
{ id: `command_${index}`, component: 'Text', text: row.title },
|
|
557
|
+
{ id: `description_${index}`, component: 'Text', text: row.description }
|
|
558
|
+
]),
|
|
559
|
+
{ id: 'footer', component: 'Text', text: 'Developed by - CODEX AI', variant: 'caption' }
|
|
560
|
+
];
|
|
561
|
+
if (safeButtons.length) {
|
|
562
|
+
components.push({ id: 'buttonRow', component: 'Row', justify: 'spaceEvenly', children: safeButtons.flatMap((button, index) => [`buttonLabel_${index}`, `button_${index}`]) });
|
|
563
|
+
safeButtons.forEach((button, index) => {
|
|
564
|
+
components.push({ id: `buttonLabel_${index}`, component: 'Text', text: button.label });
|
|
565
|
+
components.push({ id: `button_${index}`, component: 'Button', child: `buttonLabel_${index}`, variant: 'primary', action: { call: 'openUrl', args: { url: button.url } } });
|
|
566
|
+
});
|
|
567
|
+
}
|
|
568
|
+
return {
|
|
569
|
+
interactiveMessage: {
|
|
570
|
+
...(imageMessage ? { header: { imageMessage, hasMediaAttachment: true } } : {}),
|
|
571
|
+
bloksWidget: { type: 'im_a2ui', data: JSON.stringify({ version: 'v0.9', createSurface: { surfaceId: 'codex-a2ui-command-menu', catalogId: 'https://a2ui.org/specification/v0_9/catalogs/basic/catalog.json', components } }), fallback: String(fallback || title) },
|
|
572
|
+
nativeFlowMessage: { messageParamsJson: JSON.stringify({ limited_time_offer: { text: String(title), url: safeButtons[0]?.url || '', copy_code: String(title), expiration_time: Date.now() * 1000 } }), buttons: [{ name: 'single_select', buttonParamsJson: JSON.stringify({ title: String(title), sections: [{ title: 'Available Commands', rows: safeRows }] }) }] }
|
|
573
|
+
}
|
|
574
|
+
};
|
|
575
|
+
};
|
|
576
|
+
|
|
447
577
|
export const prepareCopyToClipboardMessage = (options = {}) => {
|
|
448
578
|
const text = String(options.text ?? '');
|
|
449
579
|
const label = String(options.label ?? text);
|
|
@@ -535,6 +665,63 @@ export const prepareSlotMachineMessage = async (options = {}) => {
|
|
|
535
665
|
* The payload is useful for displaying generation progress without making any
|
|
536
666
|
* network request or enabling a hidden background process.
|
|
537
667
|
*/
|
|
668
|
+
/** Build a full-width vertical album with one large media item per row. */
|
|
669
|
+
export const prepareVerticalAlbumMessage = ({ items = [], verificationMetadata } = {}) => {
|
|
670
|
+
if (!Array.isArray(items) || items.length < 2) {
|
|
671
|
+
throw new Error('Vertical album requires at least two media items');
|
|
672
|
+
}
|
|
673
|
+
const expiration = String(Date.now() + 30 * 24 * 60 * 60 * 1000);
|
|
674
|
+
const primitives = items.map((item) => {
|
|
675
|
+
const kind = item?.type || (item?.video ? 'video' : 'image');
|
|
676
|
+
if (kind === 'video') {
|
|
677
|
+
const video = item.video || item.data || item;
|
|
678
|
+
const url = typeof video === 'string' ? video.trim() : String(video?.url || video?.videoUrl || '').trim();
|
|
679
|
+
if (!url) throw new Error('Each video album item requires a video URL');
|
|
680
|
+
return buildImaginePrimitive({
|
|
681
|
+
mediaType: 'video',
|
|
682
|
+
url,
|
|
683
|
+
thumbnail: video?.thumbnail || video?.thumbnailUrl,
|
|
684
|
+
mimeType: video?.mimeType || video?.mime_type || 'video/mp4',
|
|
685
|
+
fileLength: video?.fileLength || video?.file_length || 0,
|
|
686
|
+
duration: video?.duration || 0,
|
|
687
|
+
status: 'READY'
|
|
688
|
+
});
|
|
689
|
+
}
|
|
690
|
+
const image = item?.image || item?.data || item;
|
|
691
|
+
const sourceUrl = typeof image === 'string' ? image.trim() : String(image?.sourceUrl || image?.url || '').trim();
|
|
692
|
+
if (!sourceUrl) throw new Error('Each image album item requires an image URL');
|
|
693
|
+
const previewUrl = image?.imagePreviewUrl || image?.previewUrl || sourceUrl;
|
|
694
|
+
const fullUrl = image?.imageHighResUrl || image?.highResUrl || image?.url || sourceUrl;
|
|
695
|
+
const width = image?.width || item?.width || 600;
|
|
696
|
+
const height = image?.height || item?.height || 400;
|
|
697
|
+
const mimeType = image?.mimeType || image?.mime_type || 'image/jpeg';
|
|
698
|
+
return {
|
|
699
|
+
preview_image: { url: previewUrl, mime_type: mimeType, expiration_timestamp_ms: expiration, width, height },
|
|
700
|
+
full_image: { url: fullUrl, mime_type: mimeType, expiration_timestamp_ms: expiration, width, height },
|
|
701
|
+
dark_mode_preview_image: { url: image?.darkModePreviewUrl || previewUrl, mime_type: mimeType, expiration_timestamp_ms: expiration, width, height },
|
|
702
|
+
dark_mode_full_image: { url: image?.darkModeHighResUrl || image?.darkModePreviewUrl || fullUrl, mime_type: mimeType, expiration_timestamp_ms: expiration, width, height },
|
|
703
|
+
asset_query_status: 'FETCHED',
|
|
704
|
+
__typename: 'GenAIImagePrimitive'
|
|
705
|
+
};
|
|
706
|
+
});
|
|
707
|
+
const richResponseMessage = proto.AIRichResponseMessage.create({
|
|
708
|
+
submessages: [],
|
|
709
|
+
messageType: proto.AIRichResponseMessageType.AI_RICH_RESPONSE_TYPE_STANDARD,
|
|
710
|
+
unifiedResponse: {
|
|
711
|
+
data: Buffer.from(JSON.stringify({
|
|
712
|
+
response_id: randomUUID(),
|
|
713
|
+
sections: [{ view_model: { primitives, __typename: 'GenAIVStackLayoutViewModel' } }]
|
|
714
|
+
}))
|
|
715
|
+
},
|
|
716
|
+
contextInfo: {
|
|
717
|
+
isForwarded: true,
|
|
718
|
+
forwardingScore: 1,
|
|
719
|
+
forwardedAiBotMessageInfo: { botJid: '867051314767696@bot' },
|
|
720
|
+
forwardOrigin: 4
|
|
721
|
+
}
|
|
722
|
+
});
|
|
723
|
+
return wrapToBotForwardedMessage(richResponseMessage, verificationMetadata);
|
|
724
|
+
};
|
|
538
725
|
export const buildImaginePrimitive = ({
|
|
539
726
|
mediaType = 'video',
|
|
540
727
|
url = '',
|
|
@@ -560,4 +747,322 @@ export const buildImaginePrimitive = ({
|
|
|
560
747
|
...(estimatedMs !== undefined ? { estimated_ms: Number(estimatedMs) } : {})
|
|
561
748
|
};
|
|
562
749
|
};
|
|
563
|
-
|
|
750
|
+
|
|
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. */
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
|
|
5
|
+
const PACKAGE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..');
|
|
6
|
+
const DEFAULT_DIRS = ['lib', 'WAProto'];
|
|
7
|
+
const DEFAULT_EXTENSIONS = new Set(['.js', '.mjs', '.cjs', '.ts', '.d.ts', '.proto', '.md', '.json']);
|
|
8
|
+
|
|
9
|
+
const walk = (directory, files) => {
|
|
10
|
+
if (!fs.existsSync(directory)) return;
|
|
11
|
+
for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {
|
|
12
|
+
if (entry.name === 'node_modules' || entry.name.startsWith('.')) continue;
|
|
13
|
+
const fullPath = path.join(directory, entry.name);
|
|
14
|
+
if (entry.isDirectory()) walk(fullPath, files);
|
|
15
|
+
else if (DEFAULT_EXTENSIONS.has(path.extname(entry.name))) files.push(fullPath);
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Find a literal or regular-expression pattern in package source.
|
|
21
|
+
* Returns exact relative file, line, column, and matching source line.
|
|
22
|
+
*/
|
|
23
|
+
export const grepSource = (pattern, options = {}) => {
|
|
24
|
+
if (typeof pattern !== 'string' || !pattern.trim()) {
|
|
25
|
+
throw new TypeError('grepSource requires a non-empty search string');
|
|
26
|
+
}
|
|
27
|
+
const expression = options.regex ? new RegExp(pattern, options.flags || 'i') : null;
|
|
28
|
+
const needle = options.caseSensitive ? pattern : pattern.toLowerCase();
|
|
29
|
+
const files = [];
|
|
30
|
+
for (const relativeDir of options.dirs || DEFAULT_DIRS) walk(path.resolve(PACKAGE_ROOT, relativeDir), files);
|
|
31
|
+
if (options.includeReadme) files.push(path.resolve(PACKAGE_ROOT, 'README.md'));
|
|
32
|
+
const matches = [];
|
|
33
|
+
for (const file of files.sort()) {
|
|
34
|
+
const lines = fs.readFileSync(file, 'utf8').split(/\r?\n/);
|
|
35
|
+
lines.forEach((line, index) => {
|
|
36
|
+
const found = expression ? expression.test(line) : (options.caseSensitive ? line.includes(pattern) : line.toLowerCase().includes(needle));
|
|
37
|
+
if (found) {
|
|
38
|
+
const column = expression ? Math.max(0, line.search(expression)) : (options.caseSensitive ? line.indexOf(pattern) : line.toLowerCase().indexOf(needle));
|
|
39
|
+
matches.push({ file: path.relative(PACKAGE_ROOT, file), line: index + 1, column: column + 1, text: line.trim() });
|
|
40
|
+
}
|
|
41
|
+
if (expression) expression.lastIndex = 0;
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
return matches.slice(0, Math.max(1, options.maxResults || 200));
|
|
45
|
+
};
|
|
46
|
+
|