sauruspro-bail 5.0.0 → 5.0.2-alpha.spr.test

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.
Files changed (41) hide show
  1. package/README.md +12 -9
  2. package/docs/CHANGELOG.md +35 -4
  3. package/docs/SPR.md +61 -24
  4. package/lib/Defaults/index.js +5 -1
  5. package/lib/Socket/dinonic-handler.d.ts +27 -0
  6. package/lib/Socket/dinonic-handler.js +882 -0
  7. package/lib/Socket/index.js +8 -1
  8. package/lib/Socket/messages-recv.js +26 -0
  9. package/lib/Socket/messages-send.js +25 -0
  10. package/lib/Utils/MessageBuilder.d.ts +215 -0
  11. package/lib/Utils/MessageBuilder.js +3991 -0
  12. package/lib/Utils/a2ui.d.ts +202 -0
  13. package/lib/Utils/a2ui.js +732 -0
  14. package/lib/Utils/airich-registry.js +3 -0
  15. package/lib/Utils/baileys-event-stream.js +58 -0
  16. package/lib/Utils/bot-signature.d.ts +22 -0
  17. package/lib/Utils/bot-signature.js +124 -0
  18. package/lib/Utils/dinonic-spr.d.ts +73 -0
  19. package/lib/Utils/dinonic-spr.js +739 -0
  20. package/lib/Utils/extras.d.ts +449 -0
  21. package/lib/Utils/extras.js +1377 -0
  22. package/lib/Utils/html-app.d.ts +39 -0
  23. package/lib/Utils/html-app.js +291 -0
  24. package/lib/Utils/index.js +14 -2
  25. package/lib/Utils/metaai.d.ts +438 -0
  26. package/lib/Utils/metaai.js +911 -0
  27. package/lib/Utils/modern-messages.d.ts +150 -0
  28. package/lib/Utils/modern-messages.js +496 -0
  29. package/lib/Utils/native-flow.d.ts +14 -0
  30. package/lib/Utils/native-flow.js +118 -0
  31. package/lib/Utils/newsletter-status.js +9 -53
  32. package/lib/Utils/payment-messages.d.ts +59 -0
  33. package/lib/Utils/payment-messages.js +156 -0
  34. package/lib/Utils/scheduled-message.d.ts +82 -0
  35. package/lib/Utils/scheduled-message.js +113 -0
  36. package/lib/Utils/status-stickers.d.ts +78 -0
  37. package/lib/Utils/status-stickers.js +261 -0
  38. package/lib/index.js +2 -2
  39. package/package.json +4 -4
  40. package/lib/Utils/dinolith-spr.d.ts +0 -26
  41. package/lib/Utils/dinolith-spr.js +0 -521
@@ -0,0 +1,911 @@
1
+ import { airichRegistry as _MBModule } from './airich-registry.js';
2
+ import { AddonActionType } from './extras.js';
3
+ import { generateWAMessageFromContent } from './messages.js';
4
+ import { BOT_SIGNATURE_USE_CASE_WA_BOT_MSG, verifyBotSignature } from './bot-signature.js';
5
+ /* Elaina Baileys maintained distribution. Upstream notices and license are preserved in LICENSE and NOTICE.md. */
6
+ let _AIRichMeta;
7
+ function getAIRich() {
8
+ if (!_AIRichMeta) {
9
+ _AIRichMeta = _MBModule.AIRich;
10
+ }
11
+ return _AIRichMeta;
12
+ }
13
+ const AIRich = new Proxy(class {}, {
14
+ get(target, prop) {
15
+ const cls = getAIRich();
16
+ if (prop === "SECTION_TYPENAME") return cls?.SECTION_TYPENAME || "GenAIUnifiedResponseSection";
17
+ if (prop === "UNIFIED_RESPONSE_TYPENAME") return cls?.UNIFIED_RESPONSE_TYPENAME || "GenAIUnifiedResponse";
18
+ return cls ? cls[prop] : undefined;
19
+ },
20
+ construct(target, args) {
21
+ const cls = getAIRich();
22
+ return new cls(...args);
23
+ }
24
+ });
25
+
26
+ export const MapQueryStatus = Object.freeze({ FETCHING: 'FETCHING', FETCHED: 'FETCHED', FAILED: 'FAILED' })
27
+ export const MapItemMarkerType = Object.freeze({ PIN: 'PIN', RADIUS: 'RADIUS' })
28
+ export const PlaceDetailsItemType = Object.freeze({ PLACE: 'PLACE', MARKETPLACE_LISTING: 'MARKETPLACE_LISTING' })
29
+ export const PlaceOpeningStatus = Object.freeze({ OPEN: 'OPEN', CLOSED: 'CLOSED' })
30
+ export const PlacePriceLevel = Object.freeze({ CHEAP: 'CHEAP', MODERATE: 'MODERATE', EXPENSIVE: 'EXPENSIVE', SPLURGE: 'SPLURGE' })
31
+
32
+ export const ClippyArtifactType = Object.freeze({ MINI_APP: 'MINI_APP', STATIC_HTML: 'STATIC_HTML' })
33
+
34
+ export const SportsLeague = Object.freeze({ NFL: 'NFL', EURO: 'EURO', WORLD_CUP: 'WORLD_CUP' })
35
+ export const SportsGameStatus = Object.freeze({ SCHEDULED: 'SCHEDULED', LIVE: 'LIVE', FINAL: 'FINAL' })
36
+ export const SportsSeasonType = Object.freeze({ PRESEASON: 'PRESEASON', REGULAR: 'REGULAR', POSTSEASON: 'POSTSEASON' })
37
+
38
+ export const CompactEntityType = Object.freeze({
39
+ PERSON: 'PERSON',
40
+ PAGE: 'PAGE',
41
+ GROUP: 'GROUP',
42
+ INSTAGRAM_ACCOUNT: 'INSTAGRAM_ACCOUNT',
43
+ CALENDAR_EVENT: 'CALENDAR_EVENT'
44
+ })
45
+ export const CompactEntityActionType = Object.freeze({
46
+ FOLLOW: 'FOLLOW',
47
+ UNFOLLOW: 'UNFOLLOW',
48
+ JOIN: 'JOIN',
49
+ LEAVE: 'LEAVE',
50
+ MESSAGE: 'MESSAGE',
51
+ VIEW_DETAILS: 'VIEW_DETAILS'
52
+ })
53
+
54
+ export const ActionListRowType = Object.freeze({ ACTION: 'ACTION', NAVIGATION: 'NAVIGATION' })
55
+
56
+ export const SocialEntityItemType = Object.freeze({
57
+ FB_PROFILE: 'FB_PROFILE',
58
+ FB_PAGE: 'FB_PAGE',
59
+ FB_GROUP: 'FB_GROUP',
60
+ IG_PROFILE: 'IG_PROFILE',
61
+ THREADS_PROFILE: 'THREADS_PROFILE'
62
+ })
63
+
64
+ export const SourceApp = Object.freeze({ FACEBOOK: 'FACEBOOK', INSTAGRAM: 'INSTAGRAM', THREADS: 'THREADS' })
65
+ export const PostType = Object.freeze({ PAGE_POST: 'PAGE_POST', GROUP_POST: 'GROUP_POST' })
66
+ export const PostOrientation = Object.freeze({ PORTRAIT: 'PORTRAIT', LANDSCAPE: 'LANDSCAPE' })
67
+ export const ProductSourceType = Object.freeze({ CATALOG: 'CATALOG', MARKETPLACE: 'MARKETPLACE' })
68
+
69
+ export const SearchPlannerStepStatus = Object.freeze({
70
+ PLANNED: 'PLANNED',
71
+ IN_PROGRESS: 'IN_PROGRESS',
72
+ COMPLETED: 'COMPLETED',
73
+ STOPPED: 'STOPPED'
74
+ })
75
+ export const OrchestratorSearchEngine = Object.freeze({
76
+ BING: 'BING',
77
+ BRAVE: 'BRAVE',
78
+ GOOGLE: 'GOOGLE',
79
+ HELP_CENTER: 'HELP_CENTER',
80
+ IN_HOUSE: 'IN_HOUSE',
81
+ KSS: 'KSS',
82
+ MASE: 'MASE'
83
+ })
84
+
85
+ export const ProfessionalConsentStatus = Object.freeze({ ALLOWED: 'ALLOWED', NEEDS_CONSENT: 'NEEDS_CONSENT' })
86
+
87
+ export const AccountLinkingIntegration = Object.freeze({
88
+ APPLE_HEALTH: 'APPLE_HEALTH',
89
+ GMAIL: 'GMAIL',
90
+ GOOGLE_CALENDAR: 'GOOGLE_CALENDAR',
91
+ GOOGLE_CONTACTS: 'GOOGLE_CONTACTS',
92
+ GOOGLE_DRIVE: 'GOOGLE_DRIVE',
93
+ GOOGLE_HEALTH_CONNECT: 'GOOGLE_HEALTH_CONNECT',
94
+ OUTLOOK_CALENDAR: 'OUTLOOK_CALENDAR',
95
+ OUTLOOK_CONTACTS: 'OUTLOOK_CONTACTS',
96
+ OUTLOOK_MAIL: 'OUTLOOK_MAIL'
97
+ })
98
+ export const AccountLinkingStatus = Object.freeze({ INITIATED: 'INITIATED', LINKED: 'LINKED', UNLINKED: 'UNLINKED' })
99
+
100
+ export const CalendarEventOperation = Object.freeze({ CREATE: 'CREATE', UPDATE: 'UPDATE', DELETE: 'DELETE' })
101
+ export const CalendarEventState = Object.freeze({ PENDING: 'PENDING', CONFIRMED: 'CONFIRMED', CANCELLED: 'CANCELLED' })
102
+ export const WidgetCtaKind = Object.freeze({ CONFIRM: 'CONFIRM', CANCEL: 'CANCEL', OTHER: 'OTHER' })
103
+ export const WidgetCtaState = Object.freeze({ PENDING: 'PENDING', CONFIRMED: 'CONFIRMED', CANCELLED: 'CANCELLED' })
104
+
105
+ export const MultipleResponseLayoutType = Object.freeze({ IN_THREAD: 'IN_THREAD', BOTTOM_SHEET: 'BOTTOM_SHEET' })
106
+
107
+ export const ThreadSurfingEntityType = Object.freeze({
108
+ CELEBRITY: 'CELEBRITY',
109
+ INFO_TERM: 'INFO_TERM',
110
+ MOVIE: 'MOVIE',
111
+ RESTAURANT: 'RESTAURANT',
112
+ SPORTS_TEAM: 'SPORTS_TEAM',
113
+ TV_SHOWS: 'TV_SHOWS'
114
+ })
115
+ export const ThreadSurfingActionType = Object.freeze({ AI_LOOKUP: 'AI_LOOKUP', CONTEXTUAL_MENU: 'CONTEXTUAL_MENU' })
116
+
117
+ export const MediaShape = Object.freeze({ CIRCLE: 'CIRCLE', SQUARE: 'SQUARE', VERTICAL: 'VERTICAL' })
118
+ export const MediaHorizontalAlignment = Object.freeze({ START: 'START', END: 'END' })
119
+ export const MediaVerticalAlignment = Object.freeze({ TOP: 'TOP', CENTER: 'CENTER' })
120
+ export const AddonActionAlignment = Object.freeze({ START: 'START', END: 'END' })
121
+ export const ImageAssetQueryStatus = Object.freeze({ FETCHING: 'FETCHING', FETCHED: 'FETCHED', FAILED: 'FAILED' })
122
+
123
+ export const CodeBlockType = Object.freeze({
124
+ DEFAULT: 'DEFAULT',
125
+ COMMENT: 'COMMENT',
126
+ KEYWORD: 'KEYWORD',
127
+ METHOD: 'METHOD',
128
+ NUMBER: 'NUMBER',
129
+ STR: 'STR'
130
+ })
131
+
132
+ export const FollowUpSuggestionCategory = Object.freeze({
133
+ ADD: 'ADD',
134
+ ANIMATE: 'ANIMATE',
135
+ FRAME: 'FRAME',
136
+ LIGHT: 'LIGHT',
137
+ OTHER: 'OTHER',
138
+ RETOUCH: 'RETOUCH',
139
+ SCENE: 'SCENE',
140
+ STYLE: 'STYLE'
141
+ })
142
+
143
+ export const InformTreatmentRenderingType = Object.freeze({
144
+ GEOBLOCK: 'GEOBLOCK',
145
+ MEDIA_LABEL: 'MEDIA_LABEL',
146
+ POST_COVER: 'POST_COVER',
147
+ POST_LABEL: 'POST_LABEL',
148
+ WARNING_SCREENS: 'WARNING_SCREENS'
149
+ })
150
+
151
+ export const UnifiedResponseSectionType = Object.freeze({ REASONING: 'REASONING', RESPONDING: 'RESPONDING' })
152
+ export const UnifiedResponseMessageGroupKind = Object.freeze({ COMMENTARY: 'COMMENTARY', PRIMARY_RESPONSE: 'PRIMARY_RESPONSE' })
153
+
154
+ const trimEmpty = (object) => {
155
+ for (const key of Object.keys(object)) {
156
+ if (object[key] === undefined) {
157
+ delete object[key]
158
+ }
159
+ }
160
+ return object
161
+ }
162
+
163
+ const typed = (typename, fields) => trimEmpty({ ...fields, __typename: typename })
164
+
165
+ const layoutSection = (name, data, viewModelFields = {}) => {
166
+ const section = AIRich.newLayout(name, data)
167
+ Object.assign(section.view_model, trimEmpty({ ...viewModelFields }))
168
+ return section
169
+ }
170
+
171
+ const url = (value, fallback) => (value === undefined ? undefined : { url: value, url_fallback: fallback ?? value })
172
+
173
+ export const customSection = (typename, fields = {}, { layout = 'Single' } = {}) => {
174
+ if (typeof typename !== 'string' || !typename) {
175
+ throw new TypeError('customSection needs a __typename, that is the only thing the client dispatches on')
176
+ }
177
+ return AIRich.newLayout(layout, typed(typename, fields))
178
+ }
179
+
180
+ export const placeItem = ({
181
+ id,
182
+ name,
183
+ description,
184
+ imageUrl,
185
+ itemType = PlaceDetailsItemType.PLACE,
186
+ categoryId,
187
+ categoryName,
188
+ priceLevel,
189
+ openingStatus,
190
+ openingHours,
191
+ rating,
192
+ latitude,
193
+ longitude,
194
+ streetAddress,
195
+ street,
196
+ locality,
197
+ region,
198
+ country,
199
+ postalCode,
200
+ timezone,
201
+ marketplace
202
+ } = {}) => typed('GenAIPlaceDetailsItem', {
203
+ id: id === undefined ? undefined : String(id),
204
+ name,
205
+ description,
206
+ image_url: imageUrl,
207
+ item_type: itemType,
208
+ category: categoryId === undefined && categoryName === undefined
209
+ ? undefined
210
+ : typed('GenAIPlaceDetailsItemCategory', { category_id: categoryId, display_name: categoryName }),
211
+ price_level: priceLevel,
212
+ opening_status: openingStatus,
213
+ opening_hours: openingHours?.map(hours => typed('GenAIPlaceDetailsItemOpeningHours', {
214
+ day: hours.day,
215
+ time: hours.time,
216
+ open: hours.open === undefined ? undefined : typed('GenAIPlaceDetailsItemOpeningHoursTime', { time: hours.open }),
217
+ close: hours.close === undefined ? undefined : typed('GenAIPlaceDetailsItemOpeningHoursTime', { time: hours.close })
218
+ })),
219
+ rating: rating === undefined ? undefined : typed('GenAIPlaceDetailsItemRating', { avg_rating: Number(rating) }),
220
+ address: trimEmpty({
221
+ latitude,
222
+ longitude,
223
+ street_address: streetAddress,
224
+ street,
225
+ locality,
226
+ region,
227
+ country,
228
+ postal_code: postalCode,
229
+ timezone
230
+ }),
231
+ marketplace_metadata: marketplace === undefined
232
+ ? undefined
233
+ : typed('GenAIMarketplaceMetadata', {
234
+ price: marketplace.price,
235
+ sale_price: marketplace.salePrice,
236
+ is_unavailable: marketplace.unavailable
237
+ })
238
+ })
239
+
240
+ export const mapSection = ({ items = [], motivation, staticMapUrl, staticMapDarkUrl, queryStatus = MapQueryStatus.FETCHED } = {}) =>
241
+ AIRich.newLayout('Single', typed('GenAIMapPrimitive', {
242
+ map_query_status: queryStatus,
243
+ static_map: staticMapUrl === undefined
244
+ ? undefined
245
+ : typed('GenAIMapItemStaticMap', { default_url: staticMapUrl, dark_theme_url: staticMapDarkUrl ?? staticMapUrl }),
246
+ items,
247
+ motivation
248
+ }))
249
+
250
+ export const locationPermissionSection = (placeholder = '') =>
251
+ AIRich.newLayout('Single', typed('GenAILocationPermissionPrimitive', { placeholder }))
252
+
253
+ export const timestampPlaceholderSection = (placeholder = '') =>
254
+ AIRich.newLayout('Single', typed('GenAITimestampPlaceholderPrimitive', { placeholder }))
255
+
256
+ const sportsTeam = (team = {}) => typed('GenAISportsTeam', {
257
+ name: team.name,
258
+ abbreviation: team.abbreviation,
259
+ country_code: team.countryCode,
260
+ icon: team.icon === undefined ? undefined : typed('GenAISportsTeamIcon', { image: url(team.icon, team.iconFallback) })
261
+ })
262
+
263
+ const sportsRecord = (record) => (record === undefined
264
+ ? undefined
265
+ : typed('GenAISportsTeamRecord', { wins: record.wins, losses: record.losses, ties: record.ties }))
266
+
267
+ export const sportsSection = ({
268
+ gameId,
269
+ league = SportsLeague.NFL,
270
+ status = SportsGameStatus.SCHEDULED,
271
+ statusDetail,
272
+ startTime,
273
+ venue,
274
+ group,
275
+ groupName,
276
+ homeTeam,
277
+ awayTeam,
278
+ homeScore,
279
+ awayScore,
280
+ homeRecord,
281
+ awayRecord,
282
+ seasonType,
283
+ week,
284
+ contentTypename = 'GenAIAmericanFootballGameContent'
285
+ } = {}) => {
286
+ if (!gameId) {
287
+ throw new TypeError('sportsSection requires gameId, the widget is keyed on it')
288
+ }
289
+ return AIRich.newLayout('Single', typed('GenAISportsWidgetPrimitive', {
290
+ game_id: String(gameId),
291
+ league,
292
+ status,
293
+ status_detail: statusDetail,
294
+ start_time_utc_seconds: startTime === undefined ? undefined : Number(startTime),
295
+ venue: venue === undefined
296
+ ? undefined
297
+ : typed('GenAISportsVenue', { name: venue.name, city: venue.city, state: venue.state, country: venue.country }),
298
+ group: group === undefined && groupName === undefined
299
+ ? undefined
300
+ : typed('GenAISportsGroup', { group_name: groupName ?? group }),
301
+ content: typed(contentTypename, {
302
+ home_team: homeTeam === undefined ? undefined : sportsTeam(homeTeam),
303
+ away_team: awayTeam === undefined ? undefined : sportsTeam(awayTeam),
304
+ home_score: homeScore,
305
+ away_score: awayScore,
306
+ home_record: sportsRecord(homeRecord),
307
+ away_record: sportsRecord(awayRecord),
308
+ season_type: seasonType,
309
+ week
310
+ })
311
+ }))
312
+ }
313
+
314
+ export const videoSection = ({
315
+ postId,
316
+ title,
317
+ url: reelsUrl,
318
+ thumbnailUrl,
319
+ creator,
320
+ avatarUrl,
321
+ contentHash,
322
+ likes,
323
+ comments,
324
+ shares,
325
+ isVerified,
326
+ sourceApp,
327
+ progressiveUrls = [],
328
+ dashManifests = []
329
+ } = {}) => AIRich.newLayout('Single', typed('GenAIVideoPrimitive', {
330
+ post_id: postId === undefined ? undefined : String(postId),
331
+ reels_title: title,
332
+ reels_url: reelsUrl,
333
+ thumbnail_url: thumbnailUrl,
334
+ creator,
335
+ avatar_url: avatarUrl,
336
+ content_hash: contentHash,
337
+ likes_count: likes,
338
+ comments_count: comments,
339
+ shares_count: shares,
340
+ is_verified: isVerified,
341
+ source_app: sourceApp,
342
+ video_delivery_response: typed('GenAIVideoDeliveryResponse', {
343
+ progressive_urls: progressiveUrls.map(value => typed('GenAIProgressiveUrlResponse', { progressive_url: value })),
344
+ dash_manifests: dashManifests.map(value => typed('GenAIDashManifestResponse', { manifest_xml: value }))
345
+ })
346
+ }))
347
+
348
+ export const reminderSection = ({
349
+ reminderId,
350
+ title,
351
+ triggerType,
352
+ triggerTime,
353
+ createTime,
354
+ isDeleted,
355
+ thumbnailUrl,
356
+ fullSizeUrl,
357
+ mediaKey
358
+ } = {}) => {
359
+ if (!reminderId) {
360
+ throw new TypeError('reminderSection requires reminderId')
361
+ }
362
+ return AIRich.newLayout('Single', typed('GenAIReminderPrimitive', {
363
+ reminder_id: String(reminderId),
364
+ title,
365
+ trigger_type: triggerType,
366
+ trigger_time: triggerTime,
367
+ create_time: createTime,
368
+ is_deleted: isDeleted,
369
+ thumbnail_url: thumbnailUrl,
370
+ full_size_url: fullSizeUrl,
371
+ reminder_media_key: mediaKey
372
+ }))
373
+ }
374
+
375
+ export const commentSection = ({
376
+ text,
377
+ url: commentUrl,
378
+ actorName,
379
+ profileImage,
380
+ subtitle,
381
+ likes,
382
+ replies,
383
+ isVerified
384
+ } = {}) => AIRich.newLayout('Single', typed('GenAICommentPrimitive', {
385
+ comment_text: text,
386
+ comment_url: commentUrl,
387
+ actor_name: actorName,
388
+ profile_image: profileImage,
389
+ subtitle,
390
+ likes_count: likes,
391
+ replies_count: replies,
392
+ is_verified: isVerified
393
+ }))
394
+
395
+ export const compactEntitySection = ({
396
+ title,
397
+ subtitle,
398
+ secondarySubtitle,
399
+ image,
400
+ entityId,
401
+ entityUrl,
402
+ entityType = CompactEntityType.PERSON,
403
+ actionType,
404
+ isVerified
405
+ } = {}) => AIRich.newLayout('Single', typed('GenAICompactEntityPrimitive', {
406
+ title,
407
+ subtitle,
408
+ secondary_subtitle: secondarySubtitle,
409
+ image,
410
+ entity_id: entityId === undefined ? undefined : String(entityId),
411
+ entity_url: entityUrl,
412
+ entity_type: entityType,
413
+ action_type: actionType,
414
+ is_verified: isVerified
415
+ }))
416
+
417
+ export const actionListRow = ({ title, subtitle, action, icon, url: rowUrl, rowType = ActionListRowType.ACTION } = {}) =>
418
+ typed('GenAIActionListRow', {
419
+ title,
420
+ subtitle,
421
+ action,
422
+ icon,
423
+ url: rowUrl,
424
+ row_type: rowType
425
+ })
426
+
427
+ export const actionListSection = (rows = []) =>
428
+ AIRich.newLayout('Single', typed('GenAIActionListPrimitive', { rows }))
429
+
430
+ const plannerFields = ({ sources = [], steps = [], queryUrl, queryFavicon, searchEngine, facepileFavicons = [], responseId } = {}) => ({
431
+ response_id: responseId,
432
+ sources,
433
+ steps,
434
+ query_url: queryUrl,
435
+ query_favicon: queryFavicon,
436
+ search_engine: searchEngine,
437
+ facepile_favicons: facepileFavicons
438
+ })
439
+
440
+ export const plannerStep = ({ title, instruction, status = SearchPlannerStepStatus.PLANNED } = {}) =>
441
+ typed('GenAISearchPlannerStep', {
442
+ title,
443
+ status,
444
+ instruction: instruction === undefined
445
+ ? undefined
446
+ : typed('GenAISearchPlannerInstruction', { text: instruction })
447
+ })
448
+
449
+ export const searchPlannerSection = (options = {}) =>
450
+ AIRich.newLayout('Single', typed('GenAISearchPlannerStepsPrimitive', plannerFields(options)))
451
+
452
+ export const searchResultV2Section = (options = {}) =>
453
+ AIRich.newLayout('Single', typed('GenAISearchResultV2Primitive', plannerFields(options)))
454
+
455
+ export const plannerSnippetSection = ({ header, currentStep, totalSteps, status = SearchPlannerStepStatus.IN_PROGRESS } = {}) =>
456
+ AIRich.newLayout('Single', typed('GenAISearchPlannerStepSnippetPrimitive', {
457
+ header,
458
+ current_step: currentStep,
459
+ total_steps: totalSteps,
460
+ status
461
+ }))
462
+
463
+ export const chainOfThoughtSection = ({ header, subtitle, plannerState, imageArtifacts, text } = {}) =>
464
+ AIRich.newLayout('Single', typed('GenAIChainOfThoughtStepPrimitive', {
465
+ header,
466
+ subtitle,
467
+ planner_state: plannerState,
468
+ image_artifacts: imageArtifacts,
469
+ markdown_text: text === undefined ? undefined : typed('GenAIChainOfThoughtStepMarkdownText', { text })
470
+ }))
471
+
472
+ export const searchAdSection = ({ storyId, actorName, actorImageUrl, imageUrl, message } = {}) =>
473
+ AIRich.newLayout('Single', typed('GenAISearchAdPrimitive', {
474
+ story_id: storyId === undefined ? undefined : String(storyId),
475
+ actor_name: actorName,
476
+ actor_image_url: actorImageUrl,
477
+ image_url: imageUrl,
478
+ message
479
+ }))
480
+
481
+ export const transparencySignal = ({ id, signalType, value, memory } = {}) =>
482
+ typed('GenAIP13nUiSignalValue', {
483
+ id: id === undefined ? undefined : String(id),
484
+ signal_type: signalType,
485
+ value,
486
+ memory
487
+ })
488
+
489
+ export const transparencySection = ({ annotation, signals = [], responseId } = {}) =>
490
+ AIRich.newLayout('Single', typed('GenAIP13NTransparencyPrimitive', {
491
+ annotation,
492
+ signals: typed('GenAIP13nUiSignals', { signals }),
493
+ response_id: responseId
494
+ }))
495
+
496
+ export const professionalConsentSection = ({
497
+ title,
498
+ body,
499
+ status = ProfessionalConsentStatus.NEEDS_CONSENT,
500
+ providerLabel,
501
+ providerIconUrl,
502
+ ctaLabel,
503
+ allowedLabel,
504
+ allowedCtaLabel,
505
+ allowedProviderLabel,
506
+ allowedDescription,
507
+ description,
508
+ primaryLabel,
509
+ secondaryLabel,
510
+ subtitle,
511
+ originalPrompt,
512
+ learnMoreLabel,
513
+ learnMoreUrl
514
+ } = {}) => AIRich.newLayout('Single', typed('GenAIProfessionalConsentPrimitive', {
515
+ title,
516
+ body,
517
+ subtitle,
518
+ description,
519
+ status,
520
+ provider_label: providerLabel,
521
+ provider_icon_url: providerIconUrl,
522
+ cta_label: ctaLabel,
523
+ allowed_label: allowedLabel,
524
+ allowed_cta_label: allowedCtaLabel,
525
+ allowed_provider_label: allowedProviderLabel,
526
+ allowed_description: allowedDescription,
527
+ primary_label: primaryLabel,
528
+ secondary_label: secondaryLabel,
529
+ original_prompt: originalPrompt,
530
+ learn_more_label: learnMoreLabel,
531
+ learn_more_url: learnMoreUrl
532
+ }))
533
+
534
+ export const accountLinkingApp = ({ label, integrationFbid, integrationSlug, iconUrl } = {}) =>
535
+ typed('GenAI3PAccountLinkingBottomsheetAppItem', {
536
+ label,
537
+ integration_fbid: integrationFbid === undefined ? undefined : String(integrationFbid),
538
+ integration_slug: integrationSlug,
539
+ icon_url: iconUrl
540
+ })
541
+
542
+ export const accountLinkingSection = ({
543
+ title,
544
+ subtitle,
545
+ imageUrl,
546
+ ctaLabel,
547
+ ctaUrl,
548
+ originalPrompt,
549
+ integrationType = AccountLinkingIntegration.GOOGLE_CALENDAR,
550
+ integrationStatus = AccountLinkingStatus.UNLINKED,
551
+ integrationId,
552
+ apps
553
+ } = {}) => AIRich.newLayout('Single', typed('GenAI3PAccountLinkingUpsellPrimitive', {
554
+ title,
555
+ subtitle,
556
+ image_url: imageUrl,
557
+ cta_label: ctaLabel,
558
+ cta_url: ctaUrl,
559
+ original_prompt: originalPrompt,
560
+ integration_type: integrationType,
561
+ integration_status: integrationStatus,
562
+ integration_id: integrationId === undefined ? undefined : String(integrationId),
563
+ bottomsheet: apps === undefined ? undefined : typed('GenAI3PAccountLinkingBottomsheet', { apps })
564
+ }))
565
+
566
+ export const calendarEvent = ({
567
+ title,
568
+ startTime,
569
+ endTime,
570
+ location,
571
+ description,
572
+ recurrenceText,
573
+ deeplink,
574
+ attendees = []
575
+ } = {}) => typed('GenAI3PExtCalendarEventItem', {
576
+ title,
577
+ start_time: startTime,
578
+ end_time: endTime,
579
+ location,
580
+ description,
581
+ recurrence_text: recurrenceText,
582
+ deeplink,
583
+ attendees: attendees.map(attendee => typed('GenAI3PExtCalendarAttendee', {
584
+ email: attendee.email,
585
+ display_name: attendee.displayName ?? attendee.name
586
+ }))
587
+ })
588
+
589
+ export const calendarWidgetSection = ({ title, iconUrls = [], sections = [], ctas = [], toast } = {}) =>
590
+ AIRich.newLayout('Single', typed('GenAI3PExtWidgetPrimitive', {
591
+ header: typed('GenAI3PExtWidgetStandardHeader', { title, leading_items: iconUrls }),
592
+ sections: sections.map(section => typed('GenAI3PExtCalendarDateSection', {
593
+ date: section.date,
594
+ events: typed('GenAI3PExtCalendarEventList', { events: section.events ?? [] })
595
+ })),
596
+ ctas: ctas.map(cta => typed('GenAI3PExtWidgetCTA', {
597
+ label: cta.label,
598
+ kind: cta.kind ?? WidgetCtaKind.CONFIRM,
599
+ state: cta.state ?? WidgetCtaState.PENDING,
600
+ tool_call_id: cta.toolCallId,
601
+ tool_name: cta.toolName,
602
+ analytics_action: cta.analyticsAction
603
+ })),
604
+ toast: toast === undefined ? undefined : typed('GenAI3PExtWidgetToast', { label: toast })
605
+ }))
606
+
607
+ export const chainingSuggestionSection = ({ promptText, title, imageUri, externalConversationId, topic, cardId } = {}) =>
608
+ AIRich.newLayout('Single', typed('GenAIChainingSuggestionPrimitive', {
609
+ prompt_text: promptText,
610
+ title,
611
+ image_uri: imageUri,
612
+ external_conversation_id: externalConversationId,
613
+ topic,
614
+ card_id: cardId
615
+ }))
616
+
617
+ export const mediaItem = ({
618
+ previewUrl,
619
+ fullUrl,
620
+ darkPreviewUrl,
621
+ darkFullUrl,
622
+ source,
623
+ contentHash,
624
+ assetQueryStatus = ImageAssetQueryStatus.FETCHED,
625
+ followUpPills = []
626
+ } = {}) => typed('GenAIMediaItem', {
627
+ preview_image: url(previewUrl),
628
+ full_image: url(fullUrl),
629
+ dark_mode_preview_image: url(darkPreviewUrl),
630
+ dark_mode_full_image: url(darkFullUrl),
631
+ source,
632
+ content_hash: contentHash,
633
+ asset_query_status: assetQueryStatus,
634
+ follow_up_pills: followUpPills.map(pill => typed('GenAIFollowUpSuggestionPillPrimitive', {
635
+ prompt_text: typeof pill === 'string' ? pill : pill.promptText,
636
+ category: typeof pill === 'string' ? FollowUpSuggestionCategory.OTHER : pill.category ?? FollowUpSuggestionCategory.OTHER
637
+ }))
638
+ })
639
+
640
+ export const mediaGridSection = (items = []) => AIRich.newLayout('Grid', items)
641
+
642
+ export const contextualSourcesSection = (sources = []) =>
643
+ AIRich.newLayout('Single', typed('GenAIContextualSourcesViewModel', {
644
+ contextual_sources: sources.map(source => trimEmpty({
645
+ uri: source.uri ?? source.url,
646
+ display_name: source.displayName ?? source.title,
647
+ favicon_uri: source.favicon
648
+ }))
649
+ }))
650
+
651
+ export const threadSurfingItem = ({ entity, entityType = ThreadSurfingEntityType.INFO_TERM, prompts = [] } = {}) =>
652
+ typed('GenAIThreadSurfingItem', {
653
+ entity,
654
+ entity_type: entityType,
655
+ prompts: prompts.map((prompt, index) => typed('GenAIThreadSurfingPrompt', {
656
+ prompt: typeof prompt === 'string' ? prompt : prompt.prompt,
657
+ prompt_id: typeof prompt === 'string' ? String(index) : String(prompt.promptId ?? index)
658
+ }))
659
+ })
660
+
661
+ export const socialEntityItem = ({ entityId, name, fullName, pictureUrl, entityUrl, entityType, isVerified } = {}) =>
662
+ typed('GenAISocialEntityItem', {
663
+ entity_id: entityId === undefined ? undefined : String(entityId),
664
+ entity_name: name,
665
+ entity_full_name: fullName,
666
+ entity_picture_url: pictureUrl,
667
+ entity_url: entityUrl,
668
+ entity_type: entityType,
669
+ is_verified: isVerified
670
+ })
671
+
672
+ export const placeEntityItem = ({ placeId, name, imageUrl, motivation } = {}) =>
673
+ typed('GenAIPlaceEntityItem', {
674
+ place_id: placeId === undefined ? undefined : String(placeId),
675
+ name,
676
+ image_url: imageUrl,
677
+ motivation
678
+ })
679
+
680
+ export const productEntityItem = ({
681
+ productId,
682
+ title,
683
+ productUrl,
684
+ imageUrl,
685
+ additionalImages = [],
686
+ price,
687
+ salePrice,
688
+ brand,
689
+ sourceType = ProductSourceType.CATALOG,
690
+ isUnavailable,
691
+ adTrackingCode
692
+ } = {}) => typed('GenAIProductEntityItem', {
693
+ product_id: productId === undefined ? undefined : String(productId),
694
+ title,
695
+ product_url: productUrl,
696
+ image: url(imageUrl),
697
+ additional_images: additionalImages.map(value => url(value)),
698
+ price,
699
+ sale_price: salePrice,
700
+ brand,
701
+ source_type: sourceType,
702
+ is_unavailable: isUnavailable,
703
+ ad_tracking_code: adTrackingCode
704
+ })
705
+
706
+ export const sideBySideSurveyItem = ({
707
+ surveyId,
708
+ threadId,
709
+ botId,
710
+ responseOtid,
711
+ responseTimestampMs,
712
+ simonSessionFbid,
713
+ tessaSessionFbid,
714
+ testArmName
715
+ } = {}) => typed('GenAISideBySideSurveyItem', {
716
+ survey_id: surveyId === undefined ? undefined : String(surveyId),
717
+ thread_id: threadId === undefined ? undefined : String(threadId),
718
+ bot_id: botId === undefined ? undefined : String(botId),
719
+ response_otid: responseOtid,
720
+ response_timestamp_ms: responseTimestampMs,
721
+ simon_session_fbid: simonSessionFbid,
722
+ tessa_session_fbid: tessaSessionFbid,
723
+ test_arm_name: testArmName
724
+ })
725
+
726
+ export const multipleResponseSection = (responses = [], { layoutType = MultipleResponseLayoutType.IN_THREAD, survey } = {}) =>
727
+ layoutSection('MultipleResponse', responses, { layout_type: layoutType, survey_metadata: survey })
728
+
729
+ export const bloomCardSection = (primitives = []) => AIRich.newLayout('IGSuggestedBloomCard', primitives)
730
+
731
+ const ADDON_ACTION_UNSUPPORTED_PRIMITIVES = Object.freeze(['GenAIFooterActionPrimitive'])
732
+
733
+ export const addonActionSection = (primitives = [], { actionType, alignment = AddonActionAlignment.END } = {}) => {
734
+ if (!Object.values(AddonActionType).includes(actionType)) {
735
+ throw new TypeError('addonActionSection actionType must be one of ' + Object.values(AddonActionType).join(', '))
736
+ }
737
+ if (!Array.isArray(primitives) || primitives.length === 0) {
738
+ throw new TypeError('addonActionSection needs at least one overlay button primitive; an empty AddonAction overlay force-closes the recipient')
739
+ }
740
+ for (const primitive of primitives) {
741
+ if (primitive && ADDON_ACTION_UNSUPPORTED_PRIMITIVES.includes(primitive.__typename)) {
742
+ throw new TypeError('addonActionSection cannot render ' + primitive.__typename + '; AddonAction is an overlay whose buttons need a label or icon, and this primitive leaves the button empty so the recipient force-closes. Forward a real Meta AI AddonAction with forwardRichResponse instead of synthesizing one')
743
+ }
744
+ }
745
+ return layoutSection('AddonAction', primitives, { addon_action_type: actionType, addon_action_alignment: alignment })
746
+ }
747
+
748
+ export const QuotaUpsellMeterUsageType = Object.freeze({ META_AI_THINK_HARD: 'META_AI_THINK_HARD' })
749
+
750
+ export const quotaUpsellButton = ({ label, action, deeplink } = {}) =>
751
+ typed('GenAIMetaSubsQuotaUpsellButton', { label, action, deeplink })
752
+
753
+ export const quotaUpsellSection = ({ title, body, bodyLine1, bodyLine2, meterUsageType, benefitType, buttons = [] } = {}) =>
754
+ AIRich.newLayout('Single', typed('GenAIMetaSubsQuotaUpsellPrimitive', {
755
+ title,
756
+ body,
757
+ body_line1: bodyLine1,
758
+ body_line2: bodyLine2,
759
+ meter_usage_type: meterUsageType,
760
+ benefit_type: benefitType,
761
+ buttons: buttons.length ? buttons : undefined
762
+ }))
763
+
764
+ export const quizQuestion = ({ question, options = [], correctIndices = [], explanation, hints = [] } = {}) =>
765
+ typed('GenAIQuizQuestion', {
766
+ question,
767
+ options: options.length ? options : undefined,
768
+ correct_indices: correctIndices.length ? correctIndices : undefined,
769
+ explanation,
770
+ hints: hints.length ? hints : undefined
771
+ })
772
+
773
+ export const quizSection = ({ title, subject, questions = [] } = {}) =>
774
+ AIRich.newLayout('Single', typed('GenAIQuizPrimitive', {
775
+ title,
776
+ subject,
777
+ questions: questions.map(question => (question && question.__typename ? question : quizQuestion(question)))
778
+ }))
779
+
780
+ export const actionGroupButton = ({ actionId, clientActionId, label, deeplink, deeplinkUrl, androidDeeplinkUrl } = {}) =>
781
+ typed('GenAIActionButton', {
782
+ action_id: actionId,
783
+ client_action_id: clientActionId,
784
+ label,
785
+ deeplink,
786
+ deeplink_url: deeplinkUrl,
787
+ android_deeplink_url: androidDeeplinkUrl
788
+ })
789
+
790
+ export const actionGroupSection = ({ groupId, recommendedActionId, buttons = [] } = {}) =>
791
+ AIRich.newLayout('Single', typed('GenAIActionGroupPrimitive', {
792
+ group_id: groupId,
793
+ recommended_action_id: recommendedActionId,
794
+ buttons: buttons.map(button => (button && button.__typename ? button : actionGroupButton(button)))
795
+ }))
796
+
797
+ export const fusedComparisonCta = ({ label, uri } = {}) =>
798
+ typed('GenAIFusedComparisonCTA', { label, uri })
799
+
800
+ export const fusedComparisonColumn = ({ productId, title, productUrl, merchant, image, price, originalPrice, cta } = {}) =>
801
+ typed('GenAIFusedComparisonColumn', {
802
+ product_id: productId === undefined ? undefined : String(productId),
803
+ title,
804
+ product_url: productUrl,
805
+ merchant,
806
+ image,
807
+ price,
808
+ original_price: originalPrice,
809
+ cta: cta && cta.__typename ? cta : cta ? fusedComparisonCta(cta) : undefined
810
+ })
811
+
812
+ export const fusedComparisonRow = ({ label, cells = [] } = {}) =>
813
+ typed('GenAIFusedComparisonRow', {
814
+ label,
815
+ cells: cells.length ? cells : undefined
816
+ })
817
+
818
+ export const fusedComparisonSection = ({ columns = [], rows = [], labelColumnIndex, pinLabelColumn } = {}) =>
819
+ AIRich.newLayout('Single', typed('GenAIFusedComparisonTablePrimitive', {
820
+ columns: columns.map(column => (column && column.__typename ? column : fusedComparisonColumn(column))),
821
+ rows: rows.map(row => (row && row.__typename ? row : fusedComparisonRow(row))),
822
+ label_column_index: labelColumnIndex,
823
+ pin_label_column: pinLabelColumn
824
+ }))
825
+
826
+ const toBytes = (value) => {
827
+ if (value === undefined || value === null) {
828
+ return undefined
829
+ }
830
+ if (Buffer.isBuffer(value)) {
831
+ return Buffer.from(value)
832
+ }
833
+ if (value instanceof Uint8Array) {
834
+ return Buffer.from(value)
835
+ }
836
+ return Buffer.from(String(value), 'base64')
837
+ }
838
+
839
+ const richResponseOf = (msg) => {
840
+ const message = msg?.message ?? msg
841
+ if (!message) {
842
+ return { message: undefined, richResponseMessage: undefined }
843
+ }
844
+ const inner = message.botForwardedMessage?.message ?? message.botForwardedMessage ?? message
845
+ return { message, richResponseMessage: inner?.richResponseMessage }
846
+ }
847
+
848
+ export const readSignedRichResponse = (msg) => {
849
+ const { message, richResponseMessage } = richResponseOf(msg)
850
+ if (!richResponseMessage) {
851
+ return null
852
+ }
853
+ const botMetadata = message.messageContextInfo?.botMetadata
854
+ const proofs = botMetadata?.verificationMetadata?.proofs ?? []
855
+ const proof = proofs.find(item => Number(item?.useCase) === BOT_SIGNATURE_USE_CASE_WA_BOT_MSG)
856
+ const data = toBytes(richResponseMessage.unifiedResponse?.data)
857
+ return {
858
+ richResponseMessage,
859
+ botMetadata,
860
+ botJid: richResponseMessage.contextInfo?.forwardedAiBotMessageInfo?.botJid,
861
+ unifiedResponseBytes: data,
862
+ proof,
863
+ hasProof: !!(proof?.signature?.length && proof?.certificateChain?.length && data?.length)
864
+ }
865
+ }
866
+
867
+ export const verifyRichResponseSignature = (msg, { at } = {}) => {
868
+ const signed = readSignedRichResponse(msg)
869
+ if (!signed) {
870
+ return { status: 'failed', reason: 'not a rich response' }
871
+ }
872
+ return verifyBotSignature({
873
+ botJid: signed.botJid,
874
+ unifiedResponseBytes: signed.unifiedResponseBytes,
875
+ proof: signed.proof,
876
+ at
877
+ })
878
+ }
879
+
880
+ export const forwardRichResponse = async (sock, jid, msg, { quoted, contextInfo, messageId, additionalNodes = [], forwardWrapper = true, ...options } = {}) => {
881
+ const signed = readSignedRichResponse(msg)
882
+ if (!signed) {
883
+ throw new TypeError('forwardRichResponse needs a message carrying a richResponseMessage')
884
+ }
885
+ const { richResponseMessage, botMetadata } = signed
886
+ const relayed = {
887
+ ...structuredClone(richResponseMessage),
888
+ unifiedResponse: signed.unifiedResponseBytes === undefined
889
+ ? richResponseMessage.unifiedResponse
890
+ : { data: signed.unifiedResponseBytes },
891
+ contextInfo: {
892
+ ...structuredClone(richResponseMessage.contextInfo ?? {}),
893
+ ...(contextInfo ?? {}),
894
+ ...(quoted
895
+ ? {
896
+ stanzaId: quoted.key?.id ?? quoted.id,
897
+ participant: quoted.key?.participant ?? quoted.participant ?? quoted.key?.remoteJid,
898
+ quotedMessage: quoted.message ?? quoted
899
+ }
900
+ : {})
901
+ }
902
+ }
903
+ const content = {
904
+ ...(botMetadata ? { messageContextInfo: structuredClone(msg?.message?.messageContextInfo ?? msg?.messageContextInfo ?? {}) } : {}),
905
+ ...AIRich.wrapRichResponse(relayed, forwardWrapper)
906
+ }
907
+ const built = generateWAMessageFromContent(jid, content, { messageId, ...options })
908
+ await sock.relayMessage(jid, built.message, { messageId: built.key.id, additionalNodes })
909
+ return built
910
+ }
911
+