plogme 2.1.0 → 2.1.2
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 +226 -2
- package/WAProto/WAProto.proto +12 -0
- package/WAProto/index.d.ts +12 -0
- package/WAProto/index.js +12 -0
- package/engine-requirements.js +12 -0
- package/lib/Defaults/ban-checker.js +12 -0
- package/lib/Defaults/index.js +12 -0
- package/lib/Signal/Group/ciphertext-message.js +12 -0
- package/lib/Signal/Group/group-session-builder.js +12 -0
- package/lib/Signal/Group/group_cipher.js +12 -0
- package/lib/Signal/Group/index.js +12 -0
- package/lib/Signal/Group/keyhelper.js +12 -0
- package/lib/Signal/Group/sender-chain-key.js +12 -0
- package/lib/Signal/Group/sender-key-distribution-message.js +12 -0
- package/lib/Signal/Group/sender-key-message.js +12 -0
- package/lib/Signal/Group/sender-key-name.js +12 -0
- package/lib/Signal/Group/sender-key-record.js +12 -0
- package/lib/Signal/Group/sender-key-state.js +12 -0
- package/lib/Signal/Group/sender-message-key.js +12 -0
- package/lib/Signal/libsignal.js +12 -0
- package/lib/Signal/lid-mapping.js +12 -0
- package/lib/Socket/Client/index.js +12 -0
- package/lib/Socket/Client/types.js +12 -0
- package/lib/Socket/Client/websocket.js +12 -0
- package/lib/Socket/aigroups.js +12 -0
- package/lib/Socket/ban-checker.js +12 -0
- package/lib/Socket/business.js +12 -0
- package/lib/Socket/chats.js +12 -0
- package/lib/Socket/communities.js +12 -0
- package/lib/Socket/graphql.js +12 -0
- package/lib/Socket/groups.js +12 -0
- package/lib/Socket/index.js +12 -0
- package/lib/Socket/interactive-handler.js +12 -0
- package/lib/Socket/interop.js +12 -0
- package/lib/Socket/managed-account.js +12 -0
- package/lib/Socket/messages-recv.js +12 -0
- package/lib/Socket/messages-send.js +358 -7
- package/lib/Socket/mex.js +12 -0
- package/lib/Socket/newsletter.js +12 -0
- package/lib/Socket/privacy.js +12 -0
- package/lib/Socket/registration.js +12 -0
- package/lib/Socket/socket.js +12 -0
- package/lib/Socket/username.js +12 -0
- package/lib/Store/index.js +12 -0
- package/lib/Store/make-cache-manager-store.js +12 -0
- package/lib/Store/make-in-memory-store.js +12 -0
- package/lib/Store/make-ordered-dictionary.js +12 -0
- package/lib/Store/object-repository.js +12 -0
- package/lib/Types/Auth.js +12 -0
- package/lib/Types/Bussines.js +12 -0
- package/lib/Types/Call.js +12 -0
- package/lib/Types/Chat.js +12 -0
- package/lib/Types/Contact.js +12 -0
- package/lib/Types/Events.js +12 -0
- package/lib/Types/GroupMetadata.js +12 -0
- package/lib/Types/Label.js +12 -0
- package/lib/Types/LabelAssociation.js +12 -0
- package/lib/Types/Message.js +12 -0
- package/lib/Types/Mex.js +12 -0
- package/lib/Types/Product.js +12 -0
- package/lib/Types/RichType.js +12 -0
- package/lib/Types/Signal.js +12 -0
- package/lib/Types/Socket.js +12 -0
- package/lib/Types/State.js +12 -0
- package/lib/Types/USync.js +12 -0
- package/lib/Types/index.js +12 -0
- package/lib/Utils/auth-utils.js +12 -0
- package/lib/Utils/bot-capabilities.js +12 -0
- package/lib/Utils/bot-planning-replay.js +12 -0
- package/lib/Utils/browser-utils.js +12 -0
- package/lib/Utils/business.js +12 -0
- package/lib/Utils/channel-policy.js +12 -0
- package/lib/Utils/chat-utils.js +12 -0
- package/lib/Utils/companion-reg-client-utils.js +12 -0
- package/lib/Utils/consumer-application.js +12 -0
- package/lib/Utils/crypto.js +12 -0
- package/lib/Utils/decode-wa-message.js +12 -0
- package/lib/Utils/event-buffer.js +12 -0
- package/lib/Utils/games/miniapp.js +12 -0
- package/lib/Utils/games/slot-machine.js +12 -0
- package/lib/Utils/games/website-preview.js +12 -0
- package/lib/Utils/generics.js +12 -0
- package/lib/Utils/group-history.js +12 -0
- package/lib/Utils/history.js +12 -0
- package/lib/Utils/identity-change-handler.js +12 -0
- package/lib/Utils/index.js +12 -0
- package/lib/Utils/jid-display-normalization.js +12 -0
- package/lib/Utils/link-preview.js +12 -0
- package/lib/Utils/logger.js +12 -0
- package/lib/Utils/lt-hash.js +12 -0
- package/lib/Utils/make-mutex.js +12 -0
- package/lib/Utils/message-composer.js +18 -1
- package/lib/Utils/message-inspect.js +12 -0
- package/lib/Utils/message-retry-manager.js +12 -0
- package/lib/Utils/messages-media.js +12 -0
- package/lib/Utils/messages.js +232 -4
- package/lib/Utils/meta-ai-msmsg.js +12 -0
- package/lib/Utils/meta-compositing.js +12 -0
- package/lib/Utils/native-flow.js +12 -0
- package/lib/Utils/noise-handler.js +12 -0
- package/lib/Utils/offline-node-processor.js +12 -0
- package/lib/Utils/pre-key-manager.js +12 -0
- package/lib/Utils/process-message.js +12 -0
- package/lib/Utils/reporting-utils.js +12 -0
- package/lib/Utils/rich-message-utils.js +484 -91
- package/lib/Utils/signal.js +12 -0
- package/lib/Utils/source-grep.js +12 -0
- package/lib/Utils/stanza-ack.js +12 -0
- package/lib/Utils/sync-action-utils.js +12 -0
- package/lib/Utils/tc-token-utils.js +12 -0
- package/lib/Utils/use-multi-file-auth-state.js +12 -0
- package/lib/Utils/use-single-file-auth-state.js +12 -0
- package/lib/Utils/use-sqlite-auth-state.js +12 -0
- package/lib/Utils/validate-connection.js +12 -0
- package/lib/Utils/view-once-utils.js +12 -0
- package/lib/Utils/voip-rekey.js +12 -0
- package/lib/Utils/welcome-flow.js +12 -0
- package/lib/WABinary/constants.js +12 -0
- package/lib/WABinary/decode.js +12 -0
- package/lib/WABinary/encode.js +12 -0
- package/lib/WABinary/generic-utils.js +12 -0
- package/lib/WABinary/index.js +12 -0
- package/lib/WABinary/jid-utils.js +12 -0
- package/lib/WABinary/types.js +12 -0
- package/lib/WAM/BinaryInfo.js +12 -0
- package/lib/WAM/constants.js +12 -0
- package/lib/WAM/encode.js +12 -0
- package/lib/WAM/index.js +12 -0
- package/lib/WAUSync/Protocols/USyncBusinessProtocol.js +12 -0
- package/lib/WAUSync/Protocols/USyncContactProtocol.js +12 -0
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +12 -0
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +12 -0
- package/lib/WAUSync/Protocols/USyncFeatureProtocol.js +12 -0
- package/lib/WAUSync/Protocols/USyncPictureProtocol.js +12 -0
- package/lib/WAUSync/Protocols/USyncSidelistProtocol.js +12 -0
- package/lib/WAUSync/Protocols/USyncStatusProtocol.js +12 -0
- package/lib/WAUSync/Protocols/USyncTextStatusProtocol.js +12 -0
- package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +12 -0
- package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +12 -0
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +12 -0
- package/lib/WAUSync/Protocols/index.js +12 -0
- package/lib/WAUSync/USyncQuery.js +12 -0
- package/lib/WAUSync/USyncUser.js +12 -0
- package/lib/WAUSync/index.js +12 -0
- package/lib/index.d.ts +50 -2
- package/lib/index.js +12 -0
- package/package.json +9 -2
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @crysnpvax
|
|
3
|
+
*
|
|
4
|
+
* File: lib/Utils/rich-message-utils.js
|
|
5
|
+
* About: Rich message utils module for the Plogme WhatsApp protocol client.
|
|
6
|
+
* Important exports: tokenizeCode, normalizeNewReel, normalizeNewRichImage, prepareNewRichMediaCompatibility, toUnified, buildImaginePrimitive, prepareRichGenerationMessage, buildAdditionalBotMetadataContext; …
|
|
7
|
+
* Directions: Import the listed exports and preserve protocol, validation, and compatibility invariants when modifying.
|
|
8
|
+
*
|
|
9
|
+
* Copyright and attribution notice.
|
|
10
|
+
* Do not copy, reproduce, redistribute, modify, or create derivative works
|
|
11
|
+
* from this source without explicit written permission.
|
|
12
|
+
*/
|
|
1
13
|
/**
|
|
2
14
|
* Lia@Changes 09-04-26 [WIP]
|
|
3
15
|
* Adds support for tables and code blocks with richResponseMessage (wrapped inside botForwardedMessage).
|
|
@@ -11,6 +23,7 @@ import { LANGUAGE_KEYWORDS } from '../WABinary/constants.js';
|
|
|
11
23
|
import { CodeHighlightType, RichSubMessageType } from '../Types/RichType.js';
|
|
12
24
|
import { proto } from '../../WAProto/index.js';
|
|
13
25
|
import { unixTimestampSeconds } from './generics.js';
|
|
26
|
+
import { generateTableContent } from './message-composer.js';
|
|
14
27
|
const NOOP = new Set([]);
|
|
15
28
|
export const tokenizeCode = (code, language = 'javascript') => {
|
|
16
29
|
const keywords = LANGUAGE_KEYWORDS[language] || NOOP;
|
|
@@ -47,6 +60,14 @@ export const tokenizeCode = (code, language = 'javascript') => {
|
|
|
47
60
|
};
|
|
48
61
|
const firstImageValue = (...values) => values.find(value => value !== undefined && value !== null && String(value).length > 0);
|
|
49
62
|
|
|
63
|
+
const inferImageMimeType = (url = '') => {
|
|
64
|
+
const path = String(url).split('?')[0].toLowerCase();
|
|
65
|
+
if (path.endsWith('.jpg') || path.endsWith('.jpeg')) return 'image/jpeg';
|
|
66
|
+
if (path.endsWith('.webp')) return 'image/webp';
|
|
67
|
+
if (path.endsWith('.gif')) return 'image/gif';
|
|
68
|
+
return 'image/png';
|
|
69
|
+
};
|
|
70
|
+
|
|
50
71
|
/** Normalize album image variants without downgrading full-size URLs to previews. */
|
|
51
72
|
const buildRichImagePrimitive = (image = {}, expiration = String(Date.now() + 30 * 24 * 60 * 60 * 1000)) => {
|
|
52
73
|
const previewUrl = firstImageValue(image.imagePreviewUrl, image.previewUrl, image.preview_url, image.sourceUrl, image.source_url, image.url) || '';
|
|
@@ -59,13 +80,7 @@ const buildRichImagePrimitive = (image = {}, expiration = String(Date.now() + 30
|
|
|
59
80
|
const fullHeight = Number(image.fullHeight || image.full_height || image.highResHeight || image.high_res_height || image.height || height);
|
|
60
81
|
const darkWidth = Number(image.darkWidth || image.dark_width || fullWidth);
|
|
61
82
|
const darkHeight = Number(image.darkHeight || image.dark_height || fullHeight);
|
|
62
|
-
const mimeType = image.mimeType || image.mime_type || (
|
|
63
|
-
const value = String(fullUrl || previewUrl).split('?')[0].toLowerCase();
|
|
64
|
-
if (value.endsWith('.jpg') || value.endsWith('.jpeg')) return 'image/jpeg';
|
|
65
|
-
if (value.endsWith('.webp')) return 'image/webp';
|
|
66
|
-
if (value.endsWith('.gif')) return 'image/gif';
|
|
67
|
-
return 'image/png';
|
|
68
|
-
})();
|
|
83
|
+
const mimeType = image.mimeType || image.mime_type || inferImageMimeType(fullUrl || previewUrl);
|
|
69
84
|
const media = (url, mediaWidth, mediaHeight) => ({
|
|
70
85
|
url,
|
|
71
86
|
url_fallback: url,
|
|
@@ -86,6 +101,54 @@ const buildRichImagePrimitive = (image = {}, expiration = String(Date.now() + 30
|
|
|
86
101
|
primitive.dark_mode_full_image = media(darkFullUrl, darkWidth, darkHeight);
|
|
87
102
|
return primitive;
|
|
88
103
|
};
|
|
104
|
+
|
|
105
|
+
/** Normalize the field names used by New compatibility's Meta/reels helpers. */
|
|
106
|
+
export const normalizeNewReel = (reel = {}) => ({
|
|
107
|
+
reels_url: reel.videoUrl || reel.video_url || reel.reels_url || reel.reelsUrl || reel.url || '',
|
|
108
|
+
thumbnail_url: reel.thumbnailUrl || reel.thumbnail_url || reel.thumbnail || '',
|
|
109
|
+
creator: reel.creator || reel.username || reel.title || '',
|
|
110
|
+
avatar_url: reel.profileIconUrl || reel.avatar_url || reel.avatar || reel.icon || '',
|
|
111
|
+
reels_title: reel.title || reel.reels_title || reel.reelsTitle || '',
|
|
112
|
+
likes_count: reel.likesCount ?? reel.likes_count ?? reel.likes ?? 0,
|
|
113
|
+
comments_count: reel.commentsCount ?? reel.comments_count ?? reel.comments ?? 0,
|
|
114
|
+
shares_count: reel.sharesCount ?? reel.shares_count ?? reel.shares ?? 0,
|
|
115
|
+
view_count: reel.viewCount ?? reel.view_count ?? reel.views ?? 0,
|
|
116
|
+
reel_source: reel.reelSource || reel.reel_source || reel.source || 'IG',
|
|
117
|
+
is_verified: !!(reel.isVerified ?? reel.is_verified ?? reel.verified),
|
|
118
|
+
orientation: reel.orientation || reel.ratio || 'LANDSCAPE',
|
|
119
|
+
post_type: reel.postType || reel.post_type || 'VIDEO',
|
|
120
|
+
is_carousel: reel.isCarousel ?? reel.is_carousel ?? false
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
/** Build the New-compatible image/post shape without replacing native image data. */
|
|
124
|
+
export const normalizeNewRichImage = (image = {}) => ({
|
|
125
|
+
thumbnail_url: image.thumbnailUrl || image.thumbnail_url || image.thumbnail || image.previewUrl || image.preview_url || '',
|
|
126
|
+
image_url: image.imageUrl || image.image_url || image.fullUrl || image.full_url || image.url || '',
|
|
127
|
+
source_url: image.sourceUrl || image.source_url || image.url || '',
|
|
128
|
+
title: image.title || image.caption || '',
|
|
129
|
+
creator: image.creator || image.username || '',
|
|
130
|
+
avatar_url: image.profileIconUrl || image.avatar_url || image.avatar || '',
|
|
131
|
+
is_verified: !!(image.isVerified ?? image.is_verified ?? image.verified),
|
|
132
|
+
post_caption: image.postCaption || image.post_caption || image.caption || '',
|
|
133
|
+
likes_count: image.likesCount ?? image.likes_count ?? image.likes ?? 0,
|
|
134
|
+
comments_count: image.commentsCount ?? image.comments_count ?? image.comments ?? 0,
|
|
135
|
+
shares_count: image.sharesCount ?? image.shares_count ?? image.shares ?? 0,
|
|
136
|
+
orientation: image.orientation || image.ratio || 'LANDSCAPE',
|
|
137
|
+
post_type: image.postType || image.post_type || 'IMAGE',
|
|
138
|
+
is_carousel: image.isCarousel ?? image.is_carousel ?? false
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
/** Create the second New-shaped representation beside native AIRich sections. */
|
|
142
|
+
export const prepareNewRichMediaCompatibility = (content = {}) => {
|
|
143
|
+
const reels = (Array.isArray(content.reels) ? content.reels : []).map(normalizeNewReel);
|
|
144
|
+
const images = (Array.isArray(content.images) ? content.images : content.image ? [content.image] : []).map(normalizeNewRichImage);
|
|
145
|
+
const posts = (Array.isArray(content.posts) ? content.posts : content.post ? [content.post] : []).map(normalizeNewRichImage);
|
|
146
|
+
const sections = [];
|
|
147
|
+
if (reels.length) sections.push({ view_model: { primitives: reels.map(item => ({ ...item, __typename: 'GenAIReelPrimitive' })), __typename: 'GenAIHScrollLayoutViewModel' } });
|
|
148
|
+
if (images.length) sections.push({ view_model: { primitives: images.map(item => ({ ...item, __typename: 'GenAIImagePrimitive' })), __typename: 'GenAIHScrollLayoutViewModel' } });
|
|
149
|
+
if (posts.length) sections.push({ view_model: { primitives: posts.map(item => ({ ...item, __typename: 'GenAIPostPrimitive' })), __typename: 'GenAIHScrollLayoutViewModel' } });
|
|
150
|
+
return { compatibility: 'new-rich-media', reels, images, posts, sections };
|
|
151
|
+
};
|
|
89
152
|
// Lia@Changes 09-04-26 --- Inject buffer into unifiedResponse.data to support proper rendering of rich messages (ex: tables and code blocks)
|
|
90
153
|
export const toUnified = (submessages, uuid) => ({
|
|
91
154
|
response_id: uuid || randomUUID(),
|
|
@@ -138,8 +201,24 @@ export const toUnified = (submessages, uuid) => ({
|
|
|
138
201
|
}
|
|
139
202
|
case RichSubMessageType.INLINE_IMAGE: {
|
|
140
203
|
const image = submessage.imageMetadata || {};
|
|
141
|
-
const
|
|
142
|
-
|
|
204
|
+
const rawImage = image.imageUrl || image.url || image.image;
|
|
205
|
+
const imageData = typeof rawImage === 'string'
|
|
206
|
+
? { ...image, url: rawImage }
|
|
207
|
+
: { ...image, ...(rawImage || {}) };
|
|
208
|
+
const primitive = buildRichImagePrimitive({
|
|
209
|
+
...imageData,
|
|
210
|
+
mimeType: imageData.mimeType || imageData.mime_type,
|
|
211
|
+
});
|
|
212
|
+
return primitive.full_image.url
|
|
213
|
+
? {
|
|
214
|
+
view_model: {
|
|
215
|
+
primitives: [{ ...primitive, display_mode: 'FULL_WIDTH', full_width: true }],
|
|
216
|
+
display_mode: 'FULL_WIDTH',
|
|
217
|
+
full_width: true,
|
|
218
|
+
__typename: 'GenAIVStackLayoutViewModel'
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
: {};
|
|
143
222
|
}
|
|
144
223
|
case RichSubMessageType.LATEX: {
|
|
145
224
|
const metadata = submessage.latexMetadata || {};
|
|
@@ -842,23 +921,20 @@ export const prepareRichQuoteMessage = (options = {}) => {
|
|
|
842
921
|
* @returns {Object} Wrapped botForwardedMessage ready for relayMessage
|
|
843
922
|
*/
|
|
844
923
|
export const prepareRichImageMessage = (options = {}) => {
|
|
845
|
-
const { url = '', mimeType
|
|
846
|
-
const
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
url_fallback: url,
|
|
924
|
+
const { url = '', mimeType, verificationMetadata } = options;
|
|
925
|
+
const primitive = {
|
|
926
|
+
...buildRichImagePrimitive({ url, mimeType }),
|
|
927
|
+
display_mode: 'FULL_WIDTH',
|
|
928
|
+
full_width: true,
|
|
851
929
|
};
|
|
852
930
|
const sections = [
|
|
853
931
|
{
|
|
854
932
|
__typename: 'GenAIUnifiedResponseSection',
|
|
855
933
|
view_model: {
|
|
856
|
-
__typename: '
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
full_image: media,
|
|
861
|
-
},
|
|
934
|
+
__typename: 'GenAIVStackLayoutViewModel',
|
|
935
|
+
primitives: [primitive],
|
|
936
|
+
display_mode: 'FULL_WIDTH',
|
|
937
|
+
full_width: true,
|
|
862
938
|
},
|
|
863
939
|
},
|
|
864
940
|
];
|
|
@@ -1320,8 +1396,61 @@ export const prepareBotPttTranscriptMessage = ({ text = '', transcript = '', ver
|
|
|
1320
1396
|
return envelope;
|
|
1321
1397
|
};
|
|
1322
1398
|
|
|
1323
|
-
|
|
1324
|
-
|
|
1399
|
+
const buildFoaHtmlSection = (html, trustedSources = []) => ({
|
|
1400
|
+
__typename: 'GenAIUnifiedResponseSection',
|
|
1401
|
+
view_model: {
|
|
1402
|
+
__typename: 'GenAISingleLayoutViewModel',
|
|
1403
|
+
primitive: {
|
|
1404
|
+
__typename: 'FOAHtmlPrimitiveDemoDONOTUSE',
|
|
1405
|
+
trusted_sources: Array.isArray(trustedSources) ? trustedSources : [],
|
|
1406
|
+
payload: String(html ?? '').trim()
|
|
1407
|
+
}
|
|
1408
|
+
}
|
|
1409
|
+
});
|
|
1410
|
+
|
|
1411
|
+
const buildRichHtmlScreen = (options = {}) => {
|
|
1412
|
+
const {
|
|
1413
|
+
html = '',
|
|
1414
|
+
trustedSources = [],
|
|
1415
|
+
url = '',
|
|
1416
|
+
title = 'Preview',
|
|
1417
|
+
tabHeader = 'HTML',
|
|
1418
|
+
tabs
|
|
1419
|
+
} = options;
|
|
1420
|
+
const tabItems = Array.isArray(tabs) && tabs.length
|
|
1421
|
+
? tabs
|
|
1422
|
+
: [{ id: 'tab_0', tab_header: tabHeader, html }];
|
|
1423
|
+
const embeddedTabs = tabItems.map((tab, index) => ({
|
|
1424
|
+
id: tab.id || `tab_${index}`,
|
|
1425
|
+
tab_header: tab.tab_header || tab.title || `HTML ${index + 1}`,
|
|
1426
|
+
sections: [{
|
|
1427
|
+
__typename: 'GenAIUnifiedResponseSection',
|
|
1428
|
+
view_model: {
|
|
1429
|
+
__typename: 'GenAISingleLayoutViewModel',
|
|
1430
|
+
primitive: {
|
|
1431
|
+
__typename: 'GenAIaeacdsnwHtmlPrimitive',
|
|
1432
|
+
payload: String(tab.html ?? tab.payload ?? html).trim(),
|
|
1433
|
+
url: tab.url || url,
|
|
1434
|
+
trusted_sources: tab.trustedSources || trustedSources
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1437
|
+
}],
|
|
1438
|
+
step_entries: []
|
|
1439
|
+
}));
|
|
1440
|
+
return {
|
|
1441
|
+
title,
|
|
1442
|
+
embeddedScreen: {
|
|
1443
|
+
title,
|
|
1444
|
+
content: [{
|
|
1445
|
+
__typename: 'FOAIDNixelButtonSheets',
|
|
1446
|
+
tabs: embeddedTabs
|
|
1447
|
+
}]
|
|
1448
|
+
}
|
|
1449
|
+
};
|
|
1450
|
+
};
|
|
1451
|
+
|
|
1452
|
+
const prepareRichResponseMessageFixedOrder = (content) => {
|
|
1453
|
+
const { alignment, code, compatibility, contentText, disclaimerText, footerText, headerText, html, richHtml, trustedSources, imageText, image, images, inlineImage, inlineVideo, items, language, latex, links, noDonation, noHeading, posts, products, reels, sources: sourceInputs, suggested, richResponse, table, tapLinkUrl, title, verificationMetadata, sections: rawSections, richSections, copyButton, copyToClipboard, copyText, copyLabel, richText, quote, richImage, richLinks, richMap, map, dynamicMedia, richDynamicMedia, socialEntity, socialProfile, richMenu, airichCommandMenu, unifiedResponse, gridImages, verticalAlbum, videoGrid, richGeneration, richLabel, suggestedPrompt, botSources, botPttTranscript } = content;
|
|
1325
1454
|
let submessages = [];
|
|
1326
1455
|
const extraSections = [];
|
|
1327
1456
|
if (Array.isArray(richResponse)) {
|
|
@@ -1456,28 +1585,34 @@ export const prepareRichResponseMessage = (content) => {
|
|
|
1456
1585
|
});
|
|
1457
1586
|
}
|
|
1458
1587
|
if (inlineImage) {
|
|
1588
|
+
const image = typeof inlineImage === 'string' ? { url: inlineImage } : (inlineImage || {});
|
|
1459
1589
|
submessages.push({
|
|
1460
1590
|
messageType: RichSubMessageType.INLINE_IMAGE,
|
|
1461
1591
|
imageMetadata: {
|
|
1462
|
-
|
|
1592
|
+
...image,
|
|
1593
|
+
imageUrl: image.url || image.imageUrl || image.image || '',
|
|
1463
1594
|
imageText,
|
|
1464
1595
|
alignment,
|
|
1465
|
-
tapLinkUrl
|
|
1596
|
+
tapLinkUrl,
|
|
1597
|
+
mimeType: image.mimeType || image.mime_type,
|
|
1598
|
+
width: image.width,
|
|
1599
|
+
height: image.height,
|
|
1600
|
+
fullWidth: image.fullWidth || image.full_width,
|
|
1601
|
+
fullHeight: image.fullHeight || image.full_height
|
|
1466
1602
|
}
|
|
1467
1603
|
});
|
|
1468
1604
|
}
|
|
1469
1605
|
if (inlineVideo) {
|
|
1470
1606
|
const video = typeof inlineVideo === 'string' ? { url: inlineVideo } : inlineVideo;
|
|
1471
|
-
submessages.push({ messageType: RichSubMessageType.TEXT, messageText: '[ CANNOT_LOAD_VIDEO - NIXEL ]' });
|
|
1472
1607
|
extraSections.push({
|
|
1473
1608
|
view_model: {
|
|
1474
1609
|
primitive: buildImaginePrimitive({
|
|
1475
1610
|
mediaType: 'video',
|
|
1476
|
-
url: video?.url || video?.videoUrl || '',
|
|
1477
|
-
mimeType: video?.mimeType || video?.mime_type || 'video/mp4',
|
|
1478
|
-
fileLength: video?.fileLength
|
|
1479
|
-
duration: video?.duration
|
|
1480
|
-
thumbnail: video?.thumbnail,
|
|
1611
|
+
url: video?.url || video?.videoUrl || video?.video_url || '',
|
|
1612
|
+
mimeType: video?.mimeType || video?.mime_type || video?.mimetype || 'video/mp4',
|
|
1613
|
+
fileLength: video?.fileLength ?? video?.file_length ?? video?.filesize ?? 0,
|
|
1614
|
+
duration: video?.duration ?? 0,
|
|
1615
|
+
thumbnail: video?.thumbnail || video?.thumbnailUrl || video?.thumbnail_url,
|
|
1481
1616
|
status: video?.status || 'READY'
|
|
1482
1617
|
}),
|
|
1483
1618
|
__typename: 'GenAISingleLayoutViewModel'
|
|
@@ -1565,10 +1700,6 @@ export const prepareRichResponseMessage = (content) => {
|
|
|
1565
1700
|
});
|
|
1566
1701
|
}
|
|
1567
1702
|
if (posts) {
|
|
1568
|
-
submessages.push({
|
|
1569
|
-
messageType: RichSubMessageType.TEXT,
|
|
1570
|
-
messageText: '[ CANNOT_LOAD_POST - NIXEL ]'
|
|
1571
|
-
});
|
|
1572
1703
|
const postItems = (Array.isArray(posts) ? posts : [posts]).map((post) => ({
|
|
1573
1704
|
title: post?.title || '',
|
|
1574
1705
|
subtitle: post?.subtitle || '',
|
|
@@ -1593,10 +1724,6 @@ export const prepareRichResponseMessage = (content) => {
|
|
|
1593
1724
|
if (postItems.length) extraSections.push({ view_model: { primitives: postItems, __typename: 'GenAIHScrollLayoutViewModel' } });
|
|
1594
1725
|
}
|
|
1595
1726
|
if (products) {
|
|
1596
|
-
submessages.push({
|
|
1597
|
-
messageType: RichSubMessageType.TEXT,
|
|
1598
|
-
messageText: '[ CANNOT_LOAD_PRODUCT - NIXEL ]'
|
|
1599
|
-
});
|
|
1600
1727
|
const productItems = (Array.isArray(products) ? products : [products]).map((product) => ({
|
|
1601
1728
|
title: product?.title || '',
|
|
1602
1729
|
brand: product?.brand || '',
|
|
@@ -1621,14 +1748,14 @@ export const prepareRichResponseMessage = (content) => {
|
|
|
1621
1748
|
messageText: 'SUGGESTED_PROMPT'
|
|
1622
1749
|
});
|
|
1623
1750
|
}
|
|
1624
|
-
if (table) {
|
|
1751
|
+
if (Array.isArray(table)) {
|
|
1625
1752
|
submessages.push({
|
|
1626
1753
|
messageType: RichSubMessageType.TABLE,
|
|
1627
1754
|
tableMetadata: {
|
|
1628
1755
|
title,
|
|
1629
1756
|
rows: table.map((items, index) => ({
|
|
1630
1757
|
isHeading: !noHeading && index == 0,
|
|
1631
|
-
items
|
|
1758
|
+
items: Array.isArray(items) ? items.map(String) : [String(items)]
|
|
1632
1759
|
}))
|
|
1633
1760
|
}
|
|
1634
1761
|
});
|
|
@@ -1640,11 +1767,82 @@ export const prepareRichResponseMessage = (content) => {
|
|
|
1640
1767
|
});
|
|
1641
1768
|
}
|
|
1642
1769
|
}
|
|
1770
|
+
const htmlIsTabbedConfig = html && typeof html === 'object' && Array.isArray(html.tabs);
|
|
1771
|
+
const simpleHtmlPayload = htmlIsTabbedConfig ? '' : (typeof html === 'string' ? html : (html?.html ?? html?.payload ?? ''));
|
|
1772
|
+
const htmlPayload = simpleHtmlPayload;
|
|
1773
|
+
const htmlTrustedSources = Array.isArray(html?.trustedSources) ? html.trustedSources : trustedSources;
|
|
1774
|
+
if (String(htmlPayload).trim()) {
|
|
1775
|
+
extraSections.push(buildFoaHtmlSection(htmlPayload, htmlTrustedSources));
|
|
1776
|
+
}
|
|
1777
|
+
const richHtmlOptions = richHtml ?? (htmlIsTabbedConfig ? html : null);
|
|
1778
|
+
const richHtmlConfig = typeof richHtmlOptions === 'string'
|
|
1779
|
+
? { html: richHtmlOptions, trustedSources }
|
|
1780
|
+
: (richHtmlOptions && typeof richHtmlOptions === 'object'
|
|
1781
|
+
? { ...richHtmlOptions, trustedSources: richHtmlOptions.trustedSources ?? trustedSources }
|
|
1782
|
+
: null);
|
|
1783
|
+
const hasRichHtmlContent = !!(richHtmlConfig && (
|
|
1784
|
+
String(richHtmlConfig.html || '').trim() ||
|
|
1785
|
+
(Array.isArray(richHtmlConfig.tabs) && richHtmlConfig.tabs.some(tab => String(tab?.html ?? tab?.payload ?? '').trim()))
|
|
1786
|
+
));
|
|
1787
|
+
let richHtmlScreen;
|
|
1788
|
+
if (hasRichHtmlContent) {
|
|
1789
|
+
richHtmlScreen = buildRichHtmlScreen(richHtmlConfig);
|
|
1790
|
+
submessages.unshift({
|
|
1791
|
+
messageType: RichSubMessageType.TEXT,
|
|
1792
|
+
messageText: `> ${richHtmlScreen.title}`
|
|
1793
|
+
});
|
|
1794
|
+
}
|
|
1643
1795
|
const uuid = randomUUID();
|
|
1644
1796
|
const unified = toUnified(submessages, uuid);
|
|
1645
1797
|
unified.sections = [...unified.sections.filter(Boolean), ...extraSections];
|
|
1798
|
+
if (compatibility === 'new-rich-media' || compatibility === 'both') {
|
|
1799
|
+
const compatible = prepareNewRichMediaCompatibility({ reels, images: images || (inlineImage ? [inlineImage] : image ? [image] : []), posts });
|
|
1800
|
+
unified.sections.push(...compatible.sections);
|
|
1801
|
+
unified.new_rich_media = {
|
|
1802
|
+
compatibility: compatible.compatibility,
|
|
1803
|
+
reels: compatible.reels,
|
|
1804
|
+
images: compatible.images,
|
|
1805
|
+
posts: compatible.posts
|
|
1806
|
+
};
|
|
1807
|
+
}
|
|
1808
|
+
if (richHtmlScreen) unified.embedded_screens = [richHtmlScreen.embeddedScreen];
|
|
1809
|
+
|
|
1810
|
+
// Compose the remaining AIRich convenience formats as sections. These
|
|
1811
|
+
// aliases intentionally mirror the standalone send* helpers, allowing a
|
|
1812
|
+
// caller to mix them with text, HTML, tables, media, and citations in one
|
|
1813
|
+
// PLOGME message. Raw sections remain available as the forward-compatible
|
|
1814
|
+
// escape hatch for new WhatsApp primitives.
|
|
1815
|
+
const composed = { sections: unified.sections, embedded_screens: unified.embedded_screens, submessages, botMetadata: {} };
|
|
1816
|
+
const append = (prepared) => appendPreparedRichContent(composed, prepared);
|
|
1817
|
+
if (copyButton || copyToClipboard || copyText) append(prepareCopyToClipboardMessage(copyButton || copyToClipboard || { text: copyText, label: copyLabel }));
|
|
1818
|
+
if (richText) append(prepareRichTextMessage(typeof richText === 'string' ? { text: richText } : richText));
|
|
1819
|
+
if (quote) append(prepareRichQuoteMessage(typeof quote === 'string' ? { text: quote } : quote));
|
|
1820
|
+
if (richImage) append(prepareRichImageMessage(typeof richImage === 'string' ? { url: richImage } : richImage));
|
|
1821
|
+
if (richLinks) append(prepareRichLinkMessage(Array.isArray(richLinks) ? { links: richLinks } : richLinks));
|
|
1822
|
+
if (richMap || map) append(prepareRichMapMessage(richMap || map));
|
|
1823
|
+
if (dynamicMedia || richDynamicMedia) append(prepareRichDynamicMediaMessage(dynamicMedia || richDynamicMedia));
|
|
1824
|
+
if (socialEntity) append(prepareSocialEntityMessage(socialEntity));
|
|
1825
|
+
if (socialProfile) append(prepareSocialProfileMessage(socialProfile));
|
|
1826
|
+
if (richMenu) append(prepareRichMenuMessage(richMenu));
|
|
1827
|
+
if (airichCommandMenu) append(prepareAIRichCommandMenu(airichCommandMenu));
|
|
1828
|
+
if (gridImages) append(prepareGridImageMessage({ imageUrls: gridImages, verificationMetadata }));
|
|
1829
|
+
if (verticalAlbum) append(prepareVerticalAlbumMessage({ items: verticalAlbum, verificationMetadata }));
|
|
1830
|
+
if (videoGrid) append(prepareVideoGridMessage({ videos: videoGrid, verificationMetadata }));
|
|
1831
|
+
if (richGeneration) append(prepareRichGenerationMessage({ ...richGeneration, verificationMetadata }));
|
|
1832
|
+
if (richLabel) append(buildRichLabelMessage(richLabel));
|
|
1833
|
+
if (suggestedPrompt) append(prepareBotPromptSuggestionsMessage({ ...suggestedPrompt, verificationMetadata }));
|
|
1834
|
+
if (botSources) append(prepareBotSourcesMessage({ ...botSources, verificationMetadata }));
|
|
1835
|
+
if (botPttTranscript) append(prepareBotPttTranscriptMessage({ ...botPttTranscript, verificationMetadata }));
|
|
1836
|
+
if (unifiedResponse?.sections) {
|
|
1837
|
+
unified.sections.push(...unifiedResponse.sections);
|
|
1838
|
+
if (Array.isArray(unifiedResponse.embedded_screens)) unified.embedded_screens = [...(unified.embedded_screens || []), ...unifiedResponse.embedded_screens];
|
|
1839
|
+
}
|
|
1840
|
+
for (const section of [...(Array.isArray(rawSections) ? rawSections : []), ...(Array.isArray(richSections) ? richSections : [])]) {
|
|
1841
|
+
if (section && typeof section === 'object') unified.sections.push(section);
|
|
1842
|
+
}
|
|
1843
|
+
if (composed.embedded_screens?.length) unified.embedded_screens = composed.embedded_screens;
|
|
1646
1844
|
const richResponseMessage = proto.AIRichResponseMessage.create({
|
|
1647
|
-
submessages,
|
|
1845
|
+
submessages: composed.submessages,
|
|
1648
1846
|
messageType: proto.AIRichResponseMessageType.AI_RICH_RESPONSE_TYPE_STANDARD,
|
|
1649
1847
|
unifiedResponse: {
|
|
1650
1848
|
data: Buffer.from(JSON.stringify(unified)) // Lia@Note 25-04-26 --- Expects "ArrayBufferLike"
|
|
@@ -1658,6 +1856,7 @@ export const prepareRichResponseMessage = (content) => {
|
|
|
1658
1856
|
});
|
|
1659
1857
|
const message = wrapToBotForwardedMessage(richResponseMessage, verificationMetadata);
|
|
1660
1858
|
const botMetadata = message.messageContextInfo.botMetadata;
|
|
1859
|
+
Object.assign(botMetadata, composed.botMetadata);
|
|
1661
1860
|
// Lia@Note 13-05-26 --- Add disclaimer text on richResponseMessage
|
|
1662
1861
|
if (disclaimerText) {
|
|
1663
1862
|
botMetadata.messageDisclaimerText = disclaimerText;
|
|
@@ -1706,19 +1905,7 @@ export const botMetadataCertificate = (length = 685) => {
|
|
|
1706
1905
|
*/
|
|
1707
1906
|
export const prepareHtmlMessage = (options = {}) => {
|
|
1708
1907
|
const { html = '', trustedSources = [], verificationMetadata } = options;
|
|
1709
|
-
const sections = [
|
|
1710
|
-
{
|
|
1711
|
-
__typename: 'GenAIUnifiedResponseSection',
|
|
1712
|
-
view_model: {
|
|
1713
|
-
__typename: 'GenAISingleLayoutViewModel',
|
|
1714
|
-
primitive: {
|
|
1715
|
-
__typename: 'FOAHtmlPrimitiveDemoDONOTUSE',
|
|
1716
|
-
trusted_sources: trustedSources,
|
|
1717
|
-
payload: String(html).trim()
|
|
1718
|
-
}
|
|
1719
|
-
}
|
|
1720
|
-
}
|
|
1721
|
-
];
|
|
1908
|
+
const sections = [buildFoaHtmlSection(html, trustedSources)];
|
|
1722
1909
|
const unified = { response_id: randomUUID(), sections };
|
|
1723
1910
|
const richResponseMessage = proto.AIRichResponseMessage.create({
|
|
1724
1911
|
submessages: [],
|
|
@@ -1735,35 +1922,8 @@ export const prepareHtmlMessage = (options = {}) => {
|
|
|
1735
1922
|
* aeacdsnw HTML primitive used by the attached game message.
|
|
1736
1923
|
*/
|
|
1737
1924
|
export const prepareRichHtmlMessage = (options = {}) => {
|
|
1738
|
-
const {
|
|
1739
|
-
|
|
1740
|
-
trustedSources = [],
|
|
1741
|
-
url = '',
|
|
1742
|
-
title = 'Preview',
|
|
1743
|
-
tabHeader = 'HTML',
|
|
1744
|
-
tabs,
|
|
1745
|
-
verificationMetadata
|
|
1746
|
-
} = options;
|
|
1747
|
-
const tabItems = Array.isArray(tabs) && tabs.length
|
|
1748
|
-
? tabs
|
|
1749
|
-
: [{ id: 'tab_0', tab_header: tabHeader, html }];
|
|
1750
|
-
const embeddedTabs = tabItems.map((tab, index) => ({
|
|
1751
|
-
id: tab.id || `tab_${index}`,
|
|
1752
|
-
tab_header: tab.tab_header || tab.title || `HTML ${index + 1}`,
|
|
1753
|
-
sections: [{
|
|
1754
|
-
__typename: 'GenAIUnifiedResponseSection',
|
|
1755
|
-
view_model: {
|
|
1756
|
-
__typename: 'GenAISingleLayoutViewModel',
|
|
1757
|
-
primitive: {
|
|
1758
|
-
__typename: 'GenAIaeacdsnwHtmlPrimitive',
|
|
1759
|
-
payload: String(tab.html ?? tab.payload ?? html).trim(),
|
|
1760
|
-
url: tab.url || url,
|
|
1761
|
-
trusted_sources: tab.trustedSources || trustedSources
|
|
1762
|
-
}
|
|
1763
|
-
}
|
|
1764
|
-
}],
|
|
1765
|
-
step_entries: []
|
|
1766
|
-
}));
|
|
1925
|
+
const { verificationMetadata } = options;
|
|
1926
|
+
const { title, embeddedScreen } = buildRichHtmlScreen(options);
|
|
1767
1927
|
const unified = {
|
|
1768
1928
|
response_id: randomUUID(),
|
|
1769
1929
|
sections: [{
|
|
@@ -1772,13 +1932,7 @@ export const prepareRichHtmlMessage = (options = {}) => {
|
|
|
1772
1932
|
__typename: 'GenAISingleLayoutViewModel'
|
|
1773
1933
|
}
|
|
1774
1934
|
}],
|
|
1775
|
-
embedded_screens: [
|
|
1776
|
-
title,
|
|
1777
|
-
content: [{
|
|
1778
|
-
__typename: 'FOAIDNixelButtonSheets',
|
|
1779
|
-
tabs: embeddedTabs
|
|
1780
|
-
}]
|
|
1781
|
-
}]
|
|
1935
|
+
embedded_screens: [embeddedScreen]
|
|
1782
1936
|
};
|
|
1783
1937
|
const richResponseMessage = proto.AIRichResponseMessage.create({
|
|
1784
1938
|
messageType: proto.AIRichResponseMessageType.AI_RICH_RESPONSE_TYPE_STANDARD,
|
|
@@ -1789,6 +1943,245 @@ export const prepareRichHtmlMessage = (options = {}) => {
|
|
|
1789
1943
|
return wrapToBotForwardedMessage(richResponseMessage, verificationMetadata);
|
|
1790
1944
|
};
|
|
1791
1945
|
|
|
1946
|
+
const decodePreparedUnified = (prepared) => {
|
|
1947
|
+
const richResponse = prepared?.botForwardedMessage?.message?.richResponseMessage;
|
|
1948
|
+
const rawData = richResponse?.unifiedResponse?.data;
|
|
1949
|
+
if (!rawData) return null;
|
|
1950
|
+
try {
|
|
1951
|
+
const text = Buffer.isBuffer(rawData)
|
|
1952
|
+
? rawData.toString()
|
|
1953
|
+
: (rawData instanceof Uint8Array ? Buffer.from(rawData).toString() : String(rawData));
|
|
1954
|
+
const decoded = Buffer.from(text, /^[A-Za-z0-9+/]+=*$/.test(text) ? 'base64' : 'utf8').toString();
|
|
1955
|
+
return JSON.parse(decoded);
|
|
1956
|
+
}
|
|
1957
|
+
catch {
|
|
1958
|
+
return null;
|
|
1959
|
+
}
|
|
1960
|
+
};
|
|
1961
|
+
|
|
1962
|
+
/**
|
|
1963
|
+
* Compose each rich fragment in the order its key appears in the caller's
|
|
1964
|
+
* object. The fixed-order renderer remains the single source of wire formats;
|
|
1965
|
+
* this wrapper only orders independently rendered sections before combining
|
|
1966
|
+
* them into one AIRich response.
|
|
1967
|
+
*/
|
|
1968
|
+
export const prepareRichResponseMessage = (content = {}) => {
|
|
1969
|
+
if (!content || typeof content !== 'object' || Array.isArray(content)) {
|
|
1970
|
+
throw new Boom('rich response content must be an object', { statusCode: 400 });
|
|
1971
|
+
}
|
|
1972
|
+
const submessages = [];
|
|
1973
|
+
const sections = [];
|
|
1974
|
+
const embeddedScreens = [];
|
|
1975
|
+
const mergedBotMetadata = {};
|
|
1976
|
+
const compatibility = content.compatibility === 'new-rich-media' || content.compatibility === 'both';
|
|
1977
|
+
let compatibilityAdded = false;
|
|
1978
|
+
let newRichMedia;
|
|
1979
|
+
|
|
1980
|
+
const appendPrepared = (prepared) => {
|
|
1981
|
+
const unified = decodePreparedUnified(prepared);
|
|
1982
|
+
if (Array.isArray(unified?.sections)) sections.push(...unified.sections.filter(Boolean));
|
|
1983
|
+
if (Array.isArray(unified?.embedded_screens)) embeddedScreens.push(...unified.embedded_screens);
|
|
1984
|
+
const richResponse = prepared?.botForwardedMessage?.message?.richResponseMessage;
|
|
1985
|
+
if (Array.isArray(richResponse?.submessages)) submessages.push(...richResponse.submessages);
|
|
1986
|
+
const botMetadata = prepared?.messageContextInfo?.botMetadata;
|
|
1987
|
+
if (botMetadata) Object.assign(mergedBotMetadata, botMetadata);
|
|
1988
|
+
};
|
|
1989
|
+
|
|
1990
|
+
const appendField = (key, value) => {
|
|
1991
|
+
const fragment = { noDonation: true, verificationMetadata: content.verificationMetadata };
|
|
1992
|
+
switch (key) {
|
|
1993
|
+
case 'text':
|
|
1994
|
+
fragment.contentText = value;
|
|
1995
|
+
break;
|
|
1996
|
+
case 'table':
|
|
1997
|
+
appendTableValue(value);
|
|
1998
|
+
return;
|
|
1999
|
+
case 'code':
|
|
2000
|
+
fragment.code = value;
|
|
2001
|
+
fragment.language = content.language;
|
|
2002
|
+
break;
|
|
2003
|
+
case 'inlineImage':
|
|
2004
|
+
fragment.inlineImage = value;
|
|
2005
|
+
fragment.imageText = content.imageText;
|
|
2006
|
+
fragment.alignment = content.alignment;
|
|
2007
|
+
fragment.tapLinkUrl = content.tapLinkUrl;
|
|
2008
|
+
break;
|
|
2009
|
+
case 'html':
|
|
2010
|
+
fragment.html = value;
|
|
2011
|
+
fragment.trustedSources = content.trustedSources;
|
|
2012
|
+
break;
|
|
2013
|
+
case 'richHtml':
|
|
2014
|
+
fragment.richHtml = value;
|
|
2015
|
+
fragment.trustedSources = content.trustedSources;
|
|
2016
|
+
break;
|
|
2017
|
+
case 'richTable':
|
|
2018
|
+
appendTableValue(value);
|
|
2019
|
+
return;
|
|
2020
|
+
case 'tables':
|
|
2021
|
+
if (Array.isArray(value)) value.forEach(appendTableValue);
|
|
2022
|
+
return;
|
|
2023
|
+
case 'richResponse': {
|
|
2024
|
+
if (!Array.isArray(value)) break;
|
|
2025
|
+
for (const item of value) {
|
|
2026
|
+
if (item?.inlineVideo) appendField('inlineVideo', item.inlineVideo);
|
|
2027
|
+
else if (Object.hasOwn(item || {}, 'table')) appendField('table', item.table);
|
|
2028
|
+
else if (item?.posts) appendField('posts', item.posts);
|
|
2029
|
+
else if (item?.products) appendField('products', item.products);
|
|
2030
|
+
else if (item?.suggested) appendField('suggested', item.suggested);
|
|
2031
|
+
else appendPrepared(prepareRichResponseMessageFixedOrder({
|
|
2032
|
+
richResponse: [item],
|
|
2033
|
+
noDonation: true,
|
|
2034
|
+
verificationMetadata: content.verificationMetadata
|
|
2035
|
+
}));
|
|
2036
|
+
}
|
|
2037
|
+
return;
|
|
2038
|
+
}
|
|
2039
|
+
case 'contentItemsGroup':
|
|
2040
|
+
Object.assign(fragment, value);
|
|
2041
|
+
break;
|
|
2042
|
+
default:
|
|
2043
|
+
fragment[key] = value;
|
|
2044
|
+
}
|
|
2045
|
+
appendPrepared(prepareRichResponseMessageFixedOrder(fragment));
|
|
2046
|
+
};
|
|
2047
|
+
|
|
2048
|
+
const appendSimpleTable = (tableRows) => {
|
|
2049
|
+
const normalizedRows = tableRows.map(row => Array.isArray(row) ? row : [row]);
|
|
2050
|
+
appendPrepared(prepareRichResponseMessageFixedOrder({
|
|
2051
|
+
table: normalizedRows,
|
|
2052
|
+
title: content.title,
|
|
2053
|
+
noHeading: content.noHeading,
|
|
2054
|
+
noDonation: true,
|
|
2055
|
+
verificationMetadata: content.verificationMetadata
|
|
2056
|
+
}));
|
|
2057
|
+
};
|
|
2058
|
+
|
|
2059
|
+
const appendRichTable = (table) => {
|
|
2060
|
+
if (!table || typeof table !== 'object' || Array.isArray(table)) return;
|
|
2061
|
+
const richTable = generateTableContent(
|
|
2062
|
+
String(table.title ?? ''),
|
|
2063
|
+
Array.isArray(table.headers) ? table.headers : [],
|
|
2064
|
+
Array.isArray(table.rows) ? table.rows : [],
|
|
2065
|
+
undefined,
|
|
2066
|
+
{ headerText: table.headerText, footer: table.footer }
|
|
2067
|
+
);
|
|
2068
|
+
const richResponse = richTable?.message?.botForwardedMessage?.message?.richResponseMessage;
|
|
2069
|
+
if (Array.isArray(richResponse?.submessages)) submessages.push(...richResponse.submessages);
|
|
2070
|
+
};
|
|
2071
|
+
|
|
2072
|
+
const appendTableValue = (table) => {
|
|
2073
|
+
if (Array.isArray(table)) {
|
|
2074
|
+
appendSimpleTable(table);
|
|
2075
|
+
return;
|
|
2076
|
+
}
|
|
2077
|
+
if (!table || typeof table !== 'object') return;
|
|
2078
|
+
if (Array.isArray(table.headers) && Array.isArray(table.rows)) {
|
|
2079
|
+
appendRichTable(table);
|
|
2080
|
+
}
|
|
2081
|
+
else if (Array.isArray(table.rows)) {
|
|
2082
|
+
appendSimpleTable([...(Array.isArray(table.headers) ? [table.headers] : []), ...table.rows]);
|
|
2083
|
+
}
|
|
2084
|
+
};
|
|
2085
|
+
|
|
2086
|
+
const appendCompatibility = () => {
|
|
2087
|
+
if (compatibilityAdded || !compatibility) return;
|
|
2088
|
+
compatibilityAdded = true;
|
|
2089
|
+
const compatible = prepareNewRichMediaCompatibility({
|
|
2090
|
+
reels: content.reels,
|
|
2091
|
+
images: content.images || (content.image ? [content.image] : []),
|
|
2092
|
+
posts: content.posts
|
|
2093
|
+
});
|
|
2094
|
+
if (!compatible.sections.length) return;
|
|
2095
|
+
sections.push(...compatible.sections);
|
|
2096
|
+
newRichMedia = {
|
|
2097
|
+
compatibility: compatible.compatibility,
|
|
2098
|
+
reels: compatible.reels,
|
|
2099
|
+
images: compatible.images,
|
|
2100
|
+
posts: compatible.posts
|
|
2101
|
+
};
|
|
2102
|
+
};
|
|
2103
|
+
|
|
2104
|
+
const nonRenderableKeys = new Set([
|
|
2105
|
+
'alignment', 'compatibility', 'copyLabel', 'disclaimerText',
|
|
2106
|
+
'image', 'images', 'language', 'noDonation', 'noHeading', 'title',
|
|
2107
|
+
'tapLinkUrl', 'trustedSources', 'verificationMetadata'
|
|
2108
|
+
]);
|
|
2109
|
+
const renderableKeys = new Set([
|
|
2110
|
+
'headerText', 'contentText', 'text', 'footerText', 'code', 'table', 'richTable', 'tables', 'items', 'reels',
|
|
2111
|
+
'inlineImage', 'inlineVideo', 'latex', 'links', 'sources', 'posts', 'products', 'suggested',
|
|
2112
|
+
'html', 'richHtml', 'richResponse', 'copyButton', 'copyToClipboard', 'copyText',
|
|
2113
|
+
'richText', 'quote', 'richImage', 'richLinks', 'richMap', 'map', 'dynamicMedia',
|
|
2114
|
+
'richDynamicMedia', 'socialEntity', 'socialProfile', 'richMenu', 'airichCommandMenu',
|
|
2115
|
+
'unifiedResponse', 'gridImages', 'verticalAlbum', 'videoGrid', 'richGeneration',
|
|
2116
|
+
'richLabel', 'suggestedPrompt', 'botSources', 'botPttTranscript', 'sections', 'richSections'
|
|
2117
|
+
]);
|
|
2118
|
+
const inputEntries = Object.entries(content);
|
|
2119
|
+
const entries = [
|
|
2120
|
+
...inputEntries.filter(([key]) => key === 'headerText'),
|
|
2121
|
+
...inputEntries.filter(([key]) => key !== 'headerText' && key !== 'footerText'),
|
|
2122
|
+
...inputEntries.filter(([key]) => key === 'footerText')
|
|
2123
|
+
];
|
|
2124
|
+
for (let index = 0; index < entries.length; index++) {
|
|
2125
|
+
const [key, value] = entries[index];
|
|
2126
|
+
if (['reels', 'images', 'image', 'posts'].includes(key)) appendCompatibility();
|
|
2127
|
+
if (key === 'items' || key === 'reels') {
|
|
2128
|
+
const grouped = {};
|
|
2129
|
+
let nextIndex = index;
|
|
2130
|
+
while (nextIndex < entries.length && ['items', 'reels'].includes(entries[nextIndex][0])) {
|
|
2131
|
+
const [groupKey, groupValue] = entries[nextIndex];
|
|
2132
|
+
grouped[groupKey] = groupValue;
|
|
2133
|
+
nextIndex++;
|
|
2134
|
+
}
|
|
2135
|
+
if (Object.hasOwn(grouped, 'reels')) appendCompatibility();
|
|
2136
|
+
appendField('contentItemsGroup', grouped);
|
|
2137
|
+
index = nextIndex - 1;
|
|
2138
|
+
continue;
|
|
2139
|
+
}
|
|
2140
|
+
if (!renderableKeys.has(key) || nonRenderableKeys.has(key)) continue;
|
|
2141
|
+
appendField(key, value);
|
|
2142
|
+
}
|
|
2143
|
+
|
|
2144
|
+
if (content.noDonation !== true) {
|
|
2145
|
+
appendPrepared(prepareRichResponseMessageFixedOrder({ links: [], noDonation: false }));
|
|
2146
|
+
}
|
|
2147
|
+
|
|
2148
|
+
const responseId = randomUUID();
|
|
2149
|
+
const unified = {
|
|
2150
|
+
response_id: responseId,
|
|
2151
|
+
sections,
|
|
2152
|
+
...(embeddedScreens.length ? { embedded_screens: embeddedScreens } : {}),
|
|
2153
|
+
...(newRichMedia ? { new_rich_media: newRichMedia } : {})
|
|
2154
|
+
};
|
|
2155
|
+
const richResponseMessage = proto.AIRichResponseMessage.create({
|
|
2156
|
+
submessages,
|
|
2157
|
+
messageType: proto.AIRichResponseMessageType.AI_RICH_RESPONSE_TYPE_STANDARD,
|
|
2158
|
+
unifiedResponse: { data: Buffer.from(JSON.stringify(unified)) },
|
|
2159
|
+
contextInfo: { isForwarded: true, forwardingScore: 1, forwardedAiBotMessageInfo: { botJid: '867051314767696@bot' }, forwardOrigin: 4 }
|
|
2160
|
+
});
|
|
2161
|
+
const message = wrapToBotForwardedMessage(richResponseMessage, content.verificationMetadata);
|
|
2162
|
+
const botMetadata = message.messageContextInfo.botMetadata;
|
|
2163
|
+
Object.assign(botMetadata, mergedBotMetadata);
|
|
2164
|
+
if (content.disclaimerText) botMetadata.messageDisclaimerText = content.disclaimerText;
|
|
2165
|
+
botMetadata.botResponseId = responseId;
|
|
2166
|
+
const { sources, mediaDetailsMetadataList } = buildAdditionalBotMetadataContext(submessages);
|
|
2167
|
+
if (sources.length > 0) botMetadata.richResponseSourcesMetadata = { sources };
|
|
2168
|
+
if (mediaDetailsMetadataList.length > 0) botMetadata.unifiedResponseMutation = { mediaDetailsMetadataList };
|
|
2169
|
+
return message;
|
|
2170
|
+
};
|
|
2171
|
+
|
|
2172
|
+
/** Merge any prepared AIRich helper into a single PLOGME response. */
|
|
2173
|
+
const appendPreparedRichContent = (target, prepared) => {
|
|
2174
|
+
const unified = decodePreparedUnified(prepared);
|
|
2175
|
+
if (unified?.sections?.length) target.sections.push(...unified.sections);
|
|
2176
|
+
if (Array.isArray(unified?.embedded_screens)) {
|
|
2177
|
+
target.embedded_screens = [...(target.embedded_screens || []), ...unified.embedded_screens];
|
|
2178
|
+
}
|
|
2179
|
+
const richResponse = prepared?.botForwardedMessage?.message?.richResponseMessage;
|
|
2180
|
+
if (Array.isArray(richResponse?.submessages)) target.submessages.push(...richResponse.submessages);
|
|
2181
|
+
const botMetadata = prepared?.messageContextInfo?.botMetadata;
|
|
2182
|
+
if (botMetadata) Object.assign(target.botMetadata, botMetadata);
|
|
2183
|
+
};
|
|
2184
|
+
|
|
1792
2185
|
/**
|
|
1793
2186
|
* Proofs are forwarded only when the caller supplies real, verifiable proofs.
|
|
1794
2187
|
* The library never fabricates a certificate chain or signature: an unverifiable
|