@pontalabs/baileys 1.0.4 → 1.0.6

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 (447) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +267 -839
  3. package/WAProto/GenerateStatics.sh +3 -4
  4. package/WAProto/WAProto.proto +1215 -511
  5. package/WAProto/fix-imports.js +85 -0
  6. package/WAProto/index.d.ts +14017 -55
  7. package/WAProto/index.js +97689 -29
  8. package/engine-requirements.js +10 -0
  9. package/lib/Defaults/index.d.ts +72 -74
  10. package/lib/Defaults/index.d.ts.map +1 -0
  11. package/lib/Defaults/index.js +94 -108
  12. package/lib/Defaults/index.js.map +1 -0
  13. package/lib/Signal/Group/ciphertext-message.d.ts +8 -7
  14. package/lib/Signal/Group/ciphertext-message.d.ts.map +1 -0
  15. package/lib/Signal/Group/ciphertext-message.js +9 -16
  16. package/lib/Signal/Group/ciphertext-message.js.map +1 -0
  17. package/lib/Signal/Group/group-session-builder.d.ts +11 -13
  18. package/lib/Signal/Group/group-session-builder.d.ts.map +1 -0
  19. package/lib/Signal/Group/group-session-builder.js +19 -61
  20. package/lib/Signal/Group/group-session-builder.js.map +1 -0
  21. package/lib/Signal/Group/group_cipher.d.ts +14 -16
  22. package/lib/Signal/Group/group_cipher.d.ts.map +1 -0
  23. package/lib/Signal/Group/group_cipher.js +41 -70
  24. package/lib/Signal/Group/group_cipher.js.map +1 -0
  25. package/lib/Signal/Group/index.d.ts +12 -11
  26. package/lib/Signal/Group/index.d.ts.map +1 -0
  27. package/lib/Signal/Group/index.js +12 -61
  28. package/lib/Signal/Group/index.js.map +1 -0
  29. package/lib/Signal/Group/keyhelper.d.ts +9 -14
  30. package/lib/Signal/Group/keyhelper.d.ts.map +1 -0
  31. package/lib/Signal/Group/keyhelper.js +10 -58
  32. package/lib/Signal/Group/keyhelper.js.map +1 -0
  33. package/lib/Signal/Group/sender-chain-key.d.ts +13 -13
  34. package/lib/Signal/Group/sender-chain-key.d.ts.map +1 -0
  35. package/lib/Signal/Group/sender-chain-key.js +13 -34
  36. package/lib/Signal/Group/sender-chain-key.js.map +1 -0
  37. package/lib/Signal/Group/sender-key-distribution-message.d.ts +16 -16
  38. package/lib/Signal/Group/sender-key-distribution-message.d.ts.map +1 -0
  39. package/lib/Signal/Group/sender-key-distribution-message.js +28 -36
  40. package/lib/Signal/Group/sender-key-distribution-message.js.map +1 -0
  41. package/lib/Signal/Group/sender-key-message.d.ts +18 -18
  42. package/lib/Signal/Group/sender-key-message.d.ts.map +1 -0
  43. package/lib/Signal/Group/sender-key-message.js +38 -45
  44. package/lib/Signal/Group/sender-key-message.js.map +1 -0
  45. package/lib/Signal/Group/sender-key-name.d.ts +14 -15
  46. package/lib/Signal/Group/sender-key-name.d.ts.map +1 -0
  47. package/lib/Signal/Group/sender-key-name.js +20 -31
  48. package/lib/Signal/Group/sender-key-name.js.map +1 -0
  49. package/lib/Signal/Group/sender-key-record.d.ts +24 -25
  50. package/lib/Signal/Group/sender-key-record.d.ts.map +1 -0
  51. package/lib/Signal/Group/sender-key-record.js +18 -35
  52. package/lib/Signal/Group/sender-key-record.js.map +1 -0
  53. package/lib/Signal/Group/sender-key-state.d.ts +29 -34
  54. package/lib/Signal/Group/sender-key-state.d.ts.map +1 -0
  55. package/lib/Signal/Group/sender-key-state.js +37 -100
  56. package/lib/Signal/Group/sender-key-state.js.map +1 -0
  57. package/lib/Signal/Group/sender-message-key.d.ts +11 -10
  58. package/lib/Signal/Group/sender-message-key.d.ts.map +1 -0
  59. package/lib/Signal/Group/sender-message-key.js +15 -22
  60. package/lib/Signal/Group/sender-message-key.js.map +1 -0
  61. package/lib/Signal/libsignal.d.ts +5 -8
  62. package/lib/Signal/libsignal.d.ts.map +1 -0
  63. package/lib/Signal/libsignal.js +279 -121
  64. package/lib/Signal/libsignal.js.map +1 -0
  65. package/lib/Signal/lid-mapping.d.ts +23 -28
  66. package/lib/Signal/lid-mapping.d.ts.map +1 -0
  67. package/lib/Signal/lid-mapping.js +277 -184
  68. package/lib/Signal/lid-mapping.js.map +1 -0
  69. package/lib/Socket/Client/index.d.ts +3 -2
  70. package/lib/Socket/Client/index.d.ts.map +1 -0
  71. package/lib/Socket/Client/index.js +3 -22
  72. package/lib/Socket/Client/index.js.map +1 -0
  73. package/lib/Socket/Client/types.d.ts +15 -15
  74. package/lib/Socket/Client/types.d.ts.map +1 -0
  75. package/lib/Socket/Client/types.js +8 -15
  76. package/lib/Socket/Client/types.js.map +1 -0
  77. package/lib/Socket/Client/websocket.d.ts +12 -12
  78. package/lib/Socket/Client/websocket.d.ts.map +1 -0
  79. package/lib/Socket/Client/websocket.js +29 -37
  80. package/lib/Socket/Client/websocket.js.map +1 -0
  81. package/lib/Socket/business.d.ts +208 -178
  82. package/lib/Socket/business.d.ts.map +1 -0
  83. package/lib/Socket/business.js +91 -127
  84. package/lib/Socket/business.js.map +1 -0
  85. package/lib/Socket/chats.d.ts +120 -93
  86. package/lib/Socket/chats.d.ts.map +1 -0
  87. package/lib/Socket/chats.js +727 -652
  88. package/lib/Socket/chats.js.map +1 -0
  89. package/lib/Socket/communities.d.ts +273 -0
  90. package/lib/Socket/communities.d.ts.map +1 -0
  91. package/lib/Socket/communities.js +431 -0
  92. package/lib/Socket/communities.js.map +1 -0
  93. package/lib/Socket/dugong.js +261 -0
  94. package/lib/Socket/dugong.js.bak +204 -0
  95. package/lib/Socket/groups.d.ts +143 -111
  96. package/lib/Socket/groups.d.ts.map +1 -0
  97. package/lib/Socket/groups.js +165 -177
  98. package/lib/Socket/groups.js.map +1 -0
  99. package/lib/Socket/index.d.ts +252 -183
  100. package/lib/Socket/index.d.ts.map +1 -0
  101. package/lib/Socket/index.js +38 -18
  102. package/lib/Socket/index.js.bak +44 -0
  103. package/lib/Socket/index.js.map +1 -0
  104. package/lib/Socket/messages-recv.d.ts +196 -167
  105. package/lib/Socket/messages-recv.d.ts.map +1 -0
  106. package/lib/Socket/messages-recv.js +1443 -1563
  107. package/lib/Socket/messages-recv.js.map +1 -0
  108. package/lib/Socket/messages-send.d.ts +192 -158
  109. package/lib/Socket/messages-send.d.ts.map +1 -0
  110. package/lib/Socket/messages-send.js +1102 -1208
  111. package/lib/Socket/messages-send.js.bak +1400 -0
  112. package/lib/Socket/messages-send.js.map +1 -0
  113. package/lib/Socket/mex.d.ts +3 -0
  114. package/lib/Socket/mex.d.ts.map +1 -0
  115. package/lib/Socket/mex.js +42 -0
  116. package/lib/Socket/mex.js.map +1 -0
  117. package/lib/Socket/newsletter.d.ts +163 -138
  118. package/lib/Socket/newsletter.d.ts.map +1 -0
  119. package/lib/Socket/newsletter.js +153 -249
  120. package/lib/Socket/newsletter.js.map +1 -0
  121. package/lib/Socket/socket.d.ts +50 -36
  122. package/lib/Socket/socket.d.ts.map +1 -0
  123. package/lib/Socket/socket.js +749 -820
  124. package/lib/Socket/socket.js.map +1 -0
  125. package/lib/Store/index.d.ts +4 -4
  126. package/lib/Store/index.d.ts.map +1 -0
  127. package/lib/Store/index.js +4 -24
  128. package/lib/Store/index.js.map +1 -0
  129. package/lib/Store/make-in-memory-store.d.ts +44 -104
  130. package/lib/Store/make-in-memory-store.d.ts.map +1 -0
  131. package/lib/Store/make-in-memory-store.js +199 -213
  132. package/lib/Store/make-in-memory-store.js.map +1 -0
  133. package/lib/Store/make-ordered-dictionary.d.ts +13 -12
  134. package/lib/Store/make-ordered-dictionary.d.ts.map +1 -0
  135. package/lib/Store/make-ordered-dictionary.js +38 -45
  136. package/lib/Store/make-ordered-dictionary.js.map +1 -0
  137. package/lib/Store/object-repository.d.ts +11 -10
  138. package/lib/Store/object-repository.d.ts.map +1 -0
  139. package/lib/Store/object-repository.js +9 -16
  140. package/lib/Store/object-repository.js.map +1 -0
  141. package/lib/Types/Auth.d.ts +93 -97
  142. package/lib/Types/Auth.d.ts.map +1 -0
  143. package/lib/Types/Auth.js +2 -3
  144. package/lib/Types/Auth.js.map +1 -0
  145. package/lib/Types/Bussines.d.ts +25 -0
  146. package/lib/Types/Bussines.d.ts.map +1 -0
  147. package/lib/Types/Bussines.js +2 -3
  148. package/lib/Types/Bussines.js.map +1 -0
  149. package/lib/Types/Call.d.ts +14 -13
  150. package/lib/Types/Call.d.ts.map +1 -0
  151. package/lib/Types/Call.js +2 -3
  152. package/lib/Types/Call.js.map +1 -0
  153. package/lib/Types/Chat.d.ts +78 -97
  154. package/lib/Types/Chat.d.ts.map +1 -0
  155. package/lib/Types/Chat.js +8 -9
  156. package/lib/Types/Chat.js.map +1 -0
  157. package/lib/Types/Contact.d.ts +12 -9
  158. package/lib/Types/Contact.d.ts.map +1 -0
  159. package/lib/Types/Contact.js +2 -3
  160. package/lib/Types/Contact.js.map +1 -0
  161. package/lib/Types/Events.d.ts +206 -176
  162. package/lib/Types/Events.d.ts.map +1 -0
  163. package/lib/Types/Events.js +2 -3
  164. package/lib/Types/Events.js.map +1 -0
  165. package/lib/Types/GroupMetadata.d.ts +53 -48
  166. package/lib/Types/GroupMetadata.d.ts.map +1 -0
  167. package/lib/Types/GroupMetadata.js +2 -3
  168. package/lib/Types/GroupMetadata.js.map +1 -0
  169. package/lib/Types/Label.d.ts +13 -14
  170. package/lib/Types/Label.d.ts.map +1 -0
  171. package/lib/Types/Label.js +24 -30
  172. package/lib/Types/Label.js.map +1 -0
  173. package/lib/Types/LabelAssociation.d.ts +15 -20
  174. package/lib/Types/LabelAssociation.d.ts.map +1 -0
  175. package/lib/Types/LabelAssociation.js +6 -12
  176. package/lib/Types/LabelAssociation.js.map +1 -0
  177. package/lib/Types/Message.d.ts +248 -412
  178. package/lib/Types/Message.d.ts.map +1 -0
  179. package/lib/Types/Message.js +17 -19
  180. package/lib/Types/Message.js.map +1 -0
  181. package/lib/Types/Mex.d.ts +141 -0
  182. package/lib/Types/Mex.d.ts.map +1 -0
  183. package/lib/Types/Mex.js +37 -0
  184. package/lib/Types/Mex.js.map +1 -0
  185. package/lib/Types/Product.d.ts +58 -71
  186. package/lib/Types/Product.d.ts.map +1 -0
  187. package/lib/Types/Product.js +2 -3
  188. package/lib/Types/Product.js.map +1 -0
  189. package/lib/Types/RichType.d.ts +3 -0
  190. package/lib/Types/RichType.d.ts.map +1 -0
  191. package/lib/Types/RichType.js +23 -0
  192. package/lib/Types/RichType.js.bak +23 -0
  193. package/lib/Types/RichType.js.map +1 -0
  194. package/lib/Types/Signal.d.ts +71 -82
  195. package/lib/Types/Signal.d.ts.map +1 -0
  196. package/lib/Types/Signal.js +2 -3
  197. package/lib/Types/Signal.js.map +1 -0
  198. package/lib/Types/Socket.d.ts +76 -81
  199. package/lib/Types/Socket.d.ts.map +1 -0
  200. package/lib/Types/Socket.js +3 -3
  201. package/lib/Types/Socket.js.map +1 -0
  202. package/lib/Types/State.d.ts +75 -19
  203. package/lib/Types/State.d.ts.map +1 -0
  204. package/lib/Types/State.js +56 -14
  205. package/lib/Types/State.js.map +1 -0
  206. package/lib/Types/USync.d.ts +8 -8
  207. package/lib/Types/USync.d.ts.map +1 -0
  208. package/lib/Types/USync.js +2 -3
  209. package/lib/Types/USync.js.map +1 -0
  210. package/lib/Types/index.d.ts +47 -62
  211. package/lib/Types/index.d.ts.map +1 -0
  212. package/lib/Types/index.js +26 -50
  213. package/lib/Types/index.js.map +1 -0
  214. package/lib/Utils/auth-utils.d.ts +13 -10
  215. package/lib/Utils/auth-utils.d.ts.map +1 -0
  216. package/lib/Utils/auth-utils.js +213 -454
  217. package/lib/Utils/auth-utils.js.map +1 -0
  218. package/lib/Utils/browser-utils.d.ts +4 -0
  219. package/lib/Utils/browser-utils.d.ts.map +1 -0
  220. package/lib/Utils/browser-utils.js +28 -0
  221. package/lib/Utils/browser-utils.js.map +1 -0
  222. package/lib/Utils/business.d.ts +14 -20
  223. package/lib/Utils/business.d.ts.map +1 -0
  224. package/lib/Utils/business.js +110 -134
  225. package/lib/Utils/business.js.map +1 -0
  226. package/lib/Utils/chat-utils.d.ts +88 -70
  227. package/lib/Utils/chat-utils.d.ts.map +1 -0
  228. package/lib/Utils/chat-utils.js +466 -403
  229. package/lib/Utils/chat-utils.js.map +1 -0
  230. package/lib/Utils/companion-reg-client-utils.d.ts +17 -0
  231. package/lib/Utils/companion-reg-client-utils.d.ts.map +1 -0
  232. package/lib/Utils/companion-reg-client-utils.js +35 -0
  233. package/lib/Utils/companion-reg-client-utils.js.map +1 -0
  234. package/lib/Utils/crypto.d.ts +27 -46
  235. package/lib/Utils/crypto.d.ts.map +1 -0
  236. package/lib/Utils/crypto.js +117 -188
  237. package/lib/Utils/crypto.js.map +1 -0
  238. package/lib/Utils/decode-wa-message.d.ts +58 -45
  239. package/lib/Utils/decode-wa-message.d.ts.map +1 -0
  240. package/lib/Utils/decode-wa-message.js +213 -303
  241. package/lib/Utils/decode-wa-message.js.map +1 -0
  242. package/lib/Utils/event-buffer.d.ts +14 -17
  243. package/lib/Utils/event-buffer.d.ts.map +1 -0
  244. package/lib/Utils/event-buffer.js +321 -296
  245. package/lib/Utils/event-buffer.js.map +1 -0
  246. package/lib/Utils/generics.d.ts +66 -92
  247. package/lib/Utils/generics.d.ts.map +1 -0
  248. package/lib/Utils/generics.js +270 -436
  249. package/lib/Utils/generics.js.map +1 -0
  250. package/lib/Utils/history.d.ts +24 -23
  251. package/lib/Utils/history.d.ts.map +1 -0
  252. package/lib/Utils/history.js +106 -76
  253. package/lib/Utils/history.js.map +1 -0
  254. package/lib/Utils/identity-change-handler.d.ts +44 -0
  255. package/lib/Utils/identity-change-handler.d.ts.map +1 -0
  256. package/lib/Utils/identity-change-handler.js +50 -0
  257. package/lib/Utils/identity-change-handler.js.map +1 -0
  258. package/lib/Utils/index.d.ts +24 -21
  259. package/lib/Utils/index.d.ts.map +1 -0
  260. package/lib/Utils/index.js +24 -41
  261. package/lib/Utils/index.js.map +1 -0
  262. package/lib/Utils/link-preview.d.ts +12 -14
  263. package/lib/Utils/link-preview.d.ts.map +1 -0
  264. package/lib/Utils/link-preview.js +40 -75
  265. package/lib/Utils/link-preview.js.map +1 -0
  266. package/lib/Utils/logger.d.ts +10 -11
  267. package/lib/Utils/logger.d.ts.map +1 -0
  268. package/lib/Utils/logger.js +3 -7
  269. package/lib/Utils/logger.js.map +1 -0
  270. package/lib/Utils/lt-hash.d.ts +8 -14
  271. package/lib/Utils/lt-hash.d.ts.map +1 -0
  272. package/lib/Utils/lt-hash.js +3 -53
  273. package/lib/Utils/lt-hash.js.map +1 -0
  274. package/lib/Utils/make-mutex.d.ts +7 -7
  275. package/lib/Utils/make-mutex.d.ts.map +1 -0
  276. package/lib/Utils/make-mutex.js +28 -44
  277. package/lib/Utils/make-mutex.js.map +1 -0
  278. package/lib/Utils/message-retry-manager.d.ts +115 -88
  279. package/lib/Utils/message-retry-manager.d.ts.map +1 -0
  280. package/lib/Utils/message-retry-manager.js +265 -160
  281. package/lib/Utils/message-retry-manager.js.map +1 -0
  282. package/lib/Utils/messages-media.d.ts +105 -107
  283. package/lib/Utils/messages-media.d.ts.map +1 -0
  284. package/lib/Utils/messages-media.js +548 -619
  285. package/lib/Utils/messages-media.js.bak +786 -0
  286. package/lib/Utils/messages-media.js.map +1 -0
  287. package/lib/Utils/messages.d.ts +52 -66
  288. package/lib/Utils/messages.d.ts.map +1 -0
  289. package/lib/Utils/messages.js +1730 -1558
  290. package/lib/Utils/messages.js.backup +1768 -0
  291. package/lib/Utils/messages.js.bak +1809 -0
  292. package/lib/Utils/messages.js.bak2 +893 -0
  293. package/lib/Utils/messages.js.bak3 +1183 -0
  294. package/lib/Utils/messages.js.map +1 -0
  295. package/lib/Utils/noise-handler.d.ts +18 -18
  296. package/lib/Utils/noise-handler.d.ts.map +1 -0
  297. package/lib/Utils/noise-handler.js +176 -130
  298. package/lib/Utils/noise-handler.js.map +1 -0
  299. package/lib/Utils/offline-node-processor.d.ts +17 -0
  300. package/lib/Utils/offline-node-processor.d.ts.map +1 -0
  301. package/lib/Utils/offline-node-processor.js +40 -0
  302. package/lib/Utils/offline-node-processor.js.map +1 -0
  303. package/lib/Utils/pre-key-manager.d.ts +28 -0
  304. package/lib/Utils/pre-key-manager.d.ts.map +1 -0
  305. package/lib/Utils/pre-key-manager.js +106 -0
  306. package/lib/Utils/pre-key-manager.js.map +1 -0
  307. package/lib/Utils/process-message.d.ts +43 -32
  308. package/lib/Utils/process-message.d.ts.map +1 -0
  309. package/lib/Utils/process-message.js +484 -282
  310. package/lib/Utils/process-message.js.map +1 -0
  311. package/lib/Utils/reporting-utils.d.ts +11 -0
  312. package/lib/Utils/reporting-utils.d.ts.map +1 -0
  313. package/lib/Utils/reporting-utils.js +258 -0
  314. package/lib/Utils/reporting-utils.js.map +1 -0
  315. package/lib/Utils/rich-message-utils.d.ts +49 -0
  316. package/lib/Utils/rich-message-utils.d.ts.map +1 -0
  317. package/lib/Utils/rich-message-utils.js +1220 -724
  318. package/lib/Utils/rich-message-utils.js.backup +706 -0
  319. package/lib/Utils/rich-message-utils.js.bak +246 -0
  320. package/lib/Utils/rich-message-utils.js.map +1 -0
  321. package/lib/Utils/rich-message-utils.js.original +1332 -0
  322. package/lib/Utils/signal.d.ts +37 -32
  323. package/lib/Utils/signal.d.ts.map +1 -0
  324. package/lib/Utils/signal.js +140 -105
  325. package/lib/Utils/signal.js.map +1 -0
  326. package/lib/Utils/stanza-ack.d.ts +11 -0
  327. package/lib/Utils/stanza-ack.d.ts.map +1 -0
  328. package/lib/Utils/stanza-ack.js +38 -0
  329. package/lib/Utils/stanza-ack.js.map +1 -0
  330. package/lib/Utils/sync-action-utils.d.ts +19 -0
  331. package/lib/Utils/sync-action-utils.d.ts.map +1 -0
  332. package/lib/Utils/sync-action-utils.js +49 -0
  333. package/lib/Utils/sync-action-utils.js.map +1 -0
  334. package/lib/Utils/tc-token-utils.d.ts +37 -0
  335. package/lib/Utils/tc-token-utils.d.ts.map +1 -0
  336. package/lib/Utils/tc-token-utils.js +163 -0
  337. package/lib/Utils/tc-token-utils.js.map +1 -0
  338. package/lib/Utils/use-multi-file-auth-state.d.ts +5 -5
  339. package/lib/Utils/use-multi-file-auth-state.d.ts.map +1 -0
  340. package/lib/Utils/use-multi-file-auth-state.js +70 -120
  341. package/lib/Utils/use-multi-file-auth-state.js.map +1 -0
  342. package/lib/Utils/use-single-file-auth-state.d.ts +11 -13
  343. package/lib/Utils/use-single-file-auth-state.d.ts.map +1 -0
  344. package/lib/Utils/use-single-file-auth-state.js +92 -66
  345. package/lib/Utils/use-single-file-auth-state.js.map +1 -0
  346. package/lib/Utils/use-sqlite-auth-state.d.ts +11 -0
  347. package/lib/Utils/use-sqlite-auth-state.d.ts.map +1 -0
  348. package/lib/Utils/use-sqlite-auth-state.js +109 -0
  349. package/lib/Utils/use-sqlite-auth-state.js.map +1 -0
  350. package/lib/Utils/validate-connection.d.ts +11 -13
  351. package/lib/Utils/validate-connection.d.ts.map +1 -0
  352. package/lib/Utils/validate-connection.js +128 -113
  353. package/lib/Utils/validate-connection.js.map +1 -0
  354. package/lib/WABinary/constants.d.ts +25 -27
  355. package/lib/WABinary/constants.d.ts.map +1 -0
  356. package/lib/WABinary/constants.js +1451 -1292
  357. package/lib/WABinary/constants.js.bak +1373 -0
  358. package/lib/WABinary/constants.js.map +1 -0
  359. package/lib/WABinary/decode.d.ts +7 -9
  360. package/lib/WABinary/decode.d.ts.map +1 -0
  361. package/lib/WABinary/decode.js +163 -189
  362. package/lib/WABinary/decode.js.map +1 -0
  363. package/lib/WABinary/encode.d.ts +3 -3
  364. package/lib/WABinary/encode.d.ts.map +1 -0
  365. package/lib/WABinary/encode.js +110 -155
  366. package/lib/WABinary/encode.js.map +1 -0
  367. package/lib/WABinary/generic-utils.d.ts +14 -27
  368. package/lib/WABinary/generic-utils.d.ts.map +1 -0
  369. package/lib/WABinary/generic-utils.js +177 -105
  370. package/lib/WABinary/generic-utils.js.map +1 -0
  371. package/lib/WABinary/index.d.ts +6 -5
  372. package/lib/WABinary/index.d.ts.map +1 -0
  373. package/lib/WABinary/index.js +6 -25
  374. package/lib/WABinary/index.js.map +1 -0
  375. package/lib/WABinary/jid-utils.d.ts +41 -51
  376. package/lib/WABinary/jid-utils.d.ts.map +1 -0
  377. package/lib/WABinary/jid-utils.js +83 -120
  378. package/lib/WABinary/jid-utils.js.map +1 -0
  379. package/lib/WABinary/types.d.ts +10 -13
  380. package/lib/WABinary/types.d.ts.map +1 -0
  381. package/lib/WABinary/types.js +2 -3
  382. package/lib/WABinary/types.js.map +1 -0
  383. package/lib/WAM/BinaryInfo.d.ts +8 -15
  384. package/lib/WAM/BinaryInfo.d.ts.map +1 -0
  385. package/lib/WAM/BinaryInfo.js +7 -14
  386. package/lib/WAM/BinaryInfo.js.map +1 -0
  387. package/lib/WAM/constants.d.ts +30 -37
  388. package/lib/WAM/constants.d.ts.map +1 -0
  389. package/lib/WAM/constants.js +19193 -11711
  390. package/lib/WAM/constants.js.map +1 -0
  391. package/lib/WAM/encode.d.ts +3 -3
  392. package/lib/WAM/encode.d.ts.map +1 -0
  393. package/lib/WAM/encode.js +95 -109
  394. package/lib/WAM/encode.js.map +1 -0
  395. package/lib/WAM/index.d.ts +4 -3
  396. package/lib/WAM/index.d.ts.map +1 -0
  397. package/lib/WAM/index.js +4 -23
  398. package/lib/WAM/index.js.map +1 -0
  399. package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts +9 -9
  400. package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts.map +1 -0
  401. package/lib/WAUSync/Protocols/USyncContactProtocol.js +37 -21
  402. package/lib/WAUSync/Protocols/USyncContactProtocol.js.map +1 -0
  403. package/lib/WAUSync/Protocols/USyncDeviceProtocol.d.ts +19 -22
  404. package/lib/WAUSync/Protocols/USyncDeviceProtocol.d.ts.map +1 -0
  405. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +18 -26
  406. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js.map +1 -0
  407. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts +11 -12
  408. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts.map +1 -0
  409. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +12 -20
  410. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js.map +1 -0
  411. package/lib/WAUSync/Protocols/USyncStatusProtocol.d.ts +11 -12
  412. package/lib/WAUSync/Protocols/USyncStatusProtocol.d.ts.map +1 -0
  413. package/lib/WAUSync/Protocols/USyncStatusProtocol.js +16 -24
  414. package/lib/WAUSync/Protocols/USyncStatusProtocol.js.map +1 -0
  415. package/lib/WAUSync/Protocols/USyncUsernameProtocol.d.ts +10 -0
  416. package/lib/WAUSync/Protocols/USyncUsernameProtocol.d.ts.map +1 -0
  417. package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +25 -0
  418. package/lib/WAUSync/Protocols/USyncUsernameProtocol.js.map +1 -0
  419. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.d.ts +26 -0
  420. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.d.ts.map +1 -0
  421. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +51 -0
  422. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js.map +1 -0
  423. package/lib/WAUSync/Protocols/UsyncLIDProtocol.d.ts +10 -0
  424. package/lib/WAUSync/Protocols/UsyncLIDProtocol.d.ts.map +1 -0
  425. package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +29 -0
  426. package/lib/WAUSync/Protocols/UsyncLIDProtocol.js.map +1 -0
  427. package/lib/WAUSync/Protocols/index.d.ts +6 -6
  428. package/lib/WAUSync/Protocols/index.d.ts.map +1 -0
  429. package/lib/WAUSync/Protocols/index.js +6 -26
  430. package/lib/WAUSync/Protocols/index.js.map +1 -0
  431. package/lib/WAUSync/USyncQuery.d.ts +27 -28
  432. package/lib/WAUSync/USyncQuery.d.ts.map +1 -0
  433. package/lib/WAUSync/USyncQuery.js +68 -62
  434. package/lib/WAUSync/USyncQuery.js.map +1 -0
  435. package/lib/WAUSync/USyncUser.d.ts +15 -10
  436. package/lib/WAUSync/USyncUser.d.ts.map +1 -0
  437. package/lib/WAUSync/USyncUser.js +20 -19
  438. package/lib/WAUSync/USyncUser.js.map +1 -0
  439. package/lib/WAUSync/index.d.ts +4 -3
  440. package/lib/WAUSync/index.d.ts.map +1 -0
  441. package/lib/WAUSync/index.js +4 -23
  442. package/lib/WAUSync/index.js.map +1 -0
  443. package/lib/index.d.ts +11 -12
  444. package/lib/index.d.ts.map +1 -0
  445. package/lib/index.js +12 -39
  446. package/lib/index.js.map +1 -0
  447. package/package.json +86 -42
@@ -1,845 +1,1341 @@
1
- "use strict"
1
+ import { getRandomValues, randomUUID, randomBytes } from 'crypto';
2
+ import { DONATE_URL, LEXER_REGEX } from '../Defaults/index.js';
3
+ import { LANGUAGE_KEYWORDS } from '../WABinary/constants.js';
4
+ import { CodeHighlightType, RichSubMessageType } from '../Types/RichType.js';
5
+ import { proto } from '../../WAProto/index.js';
6
+ import { unixTimestampSeconds, generateMessageIDV2 } from './generics.js';
2
7
 
3
- /**
4
- * rich-message-utils.js
5
- * @pontalabs-baileys
6
- * Tambahkan file ini ke: node_modules/@whiskeysockets/baileys/lib/Utils/rich-message-utils.js
7
- */
8
+ const NOOP = new Set([]);
9
+
10
+ /* ─────────────────────────────────────────────────────────────
11
+ LATEX URL GENERATOR
12
+ WhatsApp client membutuhkan URL gambar render untuk setiap
13
+ LaTeX expression. Tanpa URL, pesan tampil kosong.
14
+ Gunakan latex.codecogs.com sebagai fallback gratis~
15
+ ───────────────────────────────────────────────────────────── */
16
+ const buildLatexUrl = (expression) => {
17
+ if (!expression) return null;
18
+ const encoded = encodeURIComponent(expression);
19
+ return `https://latex.codecogs.com/png.image?\dpi{150}\bg{white}${encoded}`;
20
+ };
21
+
22
+ /* ─────────────────────────────────────────────────────────────
23
+ IMAGE URL HELPER
24
+ Konversi objek AIRichResponseImageURL ke snake_case JSON
25
+ agar WA client bisa baca dengan benar~
26
+ ───────────────────────────────────────────────────────────── */
27
+ const toImageUrlJson = (imgUrl) => {
28
+ if (!imgUrl) return null;
29
+ // support both plain string and object
30
+ if (typeof imgUrl === 'string') return { image_preview_url: imgUrl, image_high_res_url: imgUrl, source_url: null };
31
+ return {
32
+ image_preview_url: imgUrl.imagePreviewUrl || imgUrl.image_preview_url || null,
33
+ image_high_res_url: imgUrl.imageHighResUrl || imgUrl.image_high_res_url || null,
34
+ source_url: imgUrl.sourceUrl || imgUrl.source_url || null
35
+ };
36
+ };
8
37
 
9
- Object.defineProperty(exports, "__esModule", { value: true })
10
- exports.prepareRichResponseMessage = exports.tokenizeCode = void 0
11
-
12
- const crypto_1 = require("crypto")
13
- const WAProto_1 = require("../../WAProto")
14
-
15
- // ─── Enums (sesuai AIRichResponseCodeHighlightType di WAProto) ────────────────
16
-
17
- const CodeHighlightType = {
18
- DEFAULT: 0,
19
- KEYWORD: 1,
20
- METHOD: 2,
21
- STRING: 3,
22
- NUMBER: 4,
23
- COMMENT: 5,
24
- }
25
-
26
- const RichSubMessageType = {
27
- UNKNOWN: 0, IMAGES: 1, TEXT: 2, TABLE: 4, CODE: 5, VIDEO: 7, SUGGESTIONS: 8,
28
- REELS: 9, PRODUCT: 10, POST: 11, SOURCES: 12, TIP: 13, FOOTER: 14,
29
- LATEX: 99
30
- }
31
-
32
- // ─── Keyword Sets ─────────────────────────────────────────────────────────────
33
-
34
- const JS_KEYWORDS = new Set([
35
- 'import','export','from','default','as','const','let','var','function','class','extends','new',
36
- 'return','if','else','for','while','do','switch','case','break','continue',
37
- 'try','catch','finally','throw','async','await','yield',
38
- 'typeof','instanceof','in','of','delete','void',
39
- 'true','false','null','undefined','NaN','Infinity',
40
- 'this','super','static','get','set','debugger','with'
41
- ])
42
- const PYTHON_KEYWORDS = new Set([
43
- 'import','from','as','def','class','return','if','elif','else',
44
- 'for','while','break','continue','try','except','finally','raise',
45
- 'with','yield','lambda','pass','del','global','nonlocal','assert',
46
- 'True','False','None','and','or','not','in','is','async','await','self','print'
47
- ])
48
- const BASH_KEYWORDS = new Set([
49
- 'if','then','else','elif','fi','case','esac','for','while',
50
- 'until','do','done','in','function','select','time','coproc',
51
- 'echo','printf','read','cd','pwd','exit','export','unset',
52
- 'alias','unalias','source','exec','eval','test','shift',
53
- 'trap','wait','jobs','kill','bg','fg','history','type',
54
- 'ulimit','umask','set','true','false'
55
- ])
56
- const GO_KEYWORDS = new Set([
57
- 'break','default','func','interface','select','case','defer','go','map','struct',
58
- 'chan','else','goto','package','switch','const','fallthrough','if','range','type',
59
- 'continue','for','import','return','var','true','false','nil'
60
- ])
61
- const CPP_KEYWORDS = new Set([
62
- 'alignas','alignof','and','asm','auto','bool','break','case','catch','char','class',
63
- 'const','constexpr','continue','decltype','default','delete','do','double','else',
64
- 'enum','explicit','export','extern','false','float','for','friend','goto','if',
65
- 'inline','int','long','mutable','namespace','new','noexcept','nullptr','operator',
66
- 'private','protected','public','return','short','signed','sizeof','static','struct',
67
- 'switch','template','this','throw','true','try','typedef','typename','union',
68
- 'unsigned','using','virtual','void','volatile','while'
69
- ])
70
- const RUST_KEYWORDS = new Set([
71
- 'as','break','const','continue','crate','else','enum','extern','false','fn',
72
- 'for','if','impl','in','let','loop','match','mod','move','mut','pub','ref',
73
- 'return','self','Self','static','struct','super','trait','true','type','unsafe',
74
- 'use','where','while','async','await','dyn','try'
75
- ])
76
- const C_KEYWORDS = new Set([
77
- 'auto','break','case','char','const','continue','default','do','double','else',
78
- 'enum','extern','float','for','goto','if','inline','int','long','register',
79
- 'restrict','return','short','signed','sizeof','static','struct','switch',
80
- 'typedef','union','unsigned','void','volatile','while'
81
- ])
82
- const CSHARP_KEYWORDS = new Set([
83
- 'abstract','as','base','bool','break','byte','case','catch','char','checked',
84
- 'class','const','continue','decimal','default','delegate','do','double','else',
85
- 'enum','event','explicit','extern','false','finally','fixed','float','for',
86
- 'foreach','goto','if','implicit','in','int','interface','internal','is','lock',
87
- 'long','namespace','new','null','object','operator','out','override','params',
88
- 'private','protected','public','readonly','ref','return','sbyte','sealed','short',
89
- 'sizeof','static','string','struct','switch','this','throw','true','try','typeof',
90
- 'uint','ulong','unchecked','unsafe','ushort','using','virtual','void','volatile',
91
- 'while','async','await','var','yield'
92
- ])
93
- const CSS_KEYWORDS = new Set([
94
- 'import','media','font-face','keyframes','supports','charset',
95
- 'important','root','hover','active','focus','visited','before','after',
96
- 'not','nth-child','first-child','last-child','none','inherit','initial','auto'
97
- ])
98
- const HTML_KEYWORDS = new Set([
99
- 'html','head','body','title','meta','link','script','style',
100
- 'header','footer','main','section','article','div','span',
101
- 'h1','h2','h3','h4','h5','h6','p','a','img','ul','ol','li',
102
- 'table','tr','td','th','thead','tbody','form','input','button','select',
103
- 'textarea','label','option','canvas','svg','iframe','video','audio'
104
- ])
105
- const CMD_KEYWORDS = new Set([
106
- 'echo','set','if','else','for','in','do','goto','call','exit','shift',
107
- 'pause','start','cls','rem','dir','copy','move','del','mkdir','rmdir',
108
- 'type','ren','ping','ipconfig','netstat','shutdown'
109
- ])
110
- const POWERSHELL_KEYWORDS = new Set([
111
- 'function','filter','param','begin','process','end','if','else','elseif',
112
- 'switch','foreach','for','while','do','break','continue','return',
113
- 'throw','try','catch','finally','$true','$false','$null',
114
- 'Write-Host','Write-Output','Get-ChildItem','Test-Path','Invoke-Command'
115
- ])
116
-
117
- const LANGUAGE_KEYWORDS = {
118
- css: CSS_KEYWORDS, html: HTML_KEYWORDS,
119
- javascript: JS_KEYWORDS, typescript: JS_KEYWORDS, js: JS_KEYWORDS, ts: JS_KEYWORDS,
120
- python: PYTHON_KEYWORDS, py: PYTHON_KEYWORDS,
121
- go: GO_KEYWORDS, golang: GO_KEYWORDS,
122
- cpp: CPP_KEYWORDS, 'c++': CPP_KEYWORDS,
123
- rust: RUST_KEYWORDS, rs: RUST_KEYWORDS,
124
- c: C_KEYWORDS, h: C_KEYWORDS,
125
- csharp: CSHARP_KEYWORDS, cs: CSHARP_KEYWORDS,
126
- bash: BASH_KEYWORDS, sh: BASH_KEYWORDS, zsh: BASH_KEYWORDS,
127
- cmd: CMD_KEYWORDS, bat: CMD_KEYWORDS,
128
- powershell: POWERSHELL_KEYWORDS, ps1: POWERSHELL_KEYWORDS
129
- }
130
-
131
- const LEXER_REGEX = /(\/\/.*|\/\*[\s\S]*?\*\/|#.*)|("(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|`[\s\S]*?`)|(\b[a-zA-Z_]\w*\b)(?=\s*\()|(\b[a-zA-Z_]\w*\b)|(\b\d+(?:\.\d+)?\b)|(\s+|[^\w\s]+)/g
132
-
133
- const NOOP = new Set([])
134
-
135
- // ─── tokenizeCode ─────────────────────────────────────────────────────────────
136
-
137
- const tokenizeCode = (code, language = 'javascript') => {
138
- const keywords = LANGUAGE_KEYWORDS[language] || NOOP
139
- const blocks = []
140
- LEXER_REGEX.lastIndex = 0
141
- let match
38
+ /* ─────────────────────────────────────────────────────────────
39
+ TOKENIZER
40
+ ───────────────────────────────────────────────────────────── */
41
+
42
+ export const tokenizeCode = (code, language = 'javascript') => {
43
+ const keywords = LANGUAGE_KEYWORDS[language] || NOOP;
44
+ const blocks = [];
45
+ LEXER_REGEX.lastIndex = 0;
46
+ let match;
142
47
  while ((match = LEXER_REGEX.exec(code)) !== null) {
143
48
  if (match[1]) {
144
- blocks.push({ highlightType: CodeHighlightType.COMMENT, codeContent: match[1] })
49
+ blocks.push({ highlightType: CodeHighlightType.COMMENT, codeContent: match[1] });
145
50
  } else if (match[2]) {
146
- blocks.push({ highlightType: CodeHighlightType.STRING, codeContent: match[2] })
51
+ blocks.push({ highlightType: CodeHighlightType.STRING, codeContent: match[2] });
147
52
  } else if (match[3]) {
148
53
  blocks.push({
149
54
  highlightType: keywords.has(match[3]) ? CodeHighlightType.KEYWORD : CodeHighlightType.METHOD,
150
55
  codeContent: match[3],
151
- })
56
+ });
152
57
  } else if (match[4]) {
153
58
  blocks.push({
154
59
  highlightType: keywords.has(match[4]) ? CodeHighlightType.KEYWORD : CodeHighlightType.DEFAULT,
155
60
  codeContent: match[4],
156
- })
61
+ });
157
62
  } else if (match[5]) {
158
- blocks.push({ highlightType: CodeHighlightType.NUMBER, codeContent: match[5] })
63
+ blocks.push({ highlightType: CodeHighlightType.NUMBER, codeContent: match[5] });
159
64
  } else {
160
- blocks.push({ highlightType: CodeHighlightType.DEFAULT, codeContent: match[6] })
65
+ blocks.push({ highlightType: CodeHighlightType.DEFAULT, codeContent: match[6] });
161
66
  }
162
67
  }
163
- return blocks
164
- }
165
- exports.tokenizeCode = tokenizeCode
68
+ return blocks;
69
+ };
166
70
 
167
- // ─── toUnified ────────────────────────────────────────────────────────────────
71
+ /* ─────────────────────────────────────────────────────────────
72
+ INCOMING DECODER — parse rich message yang diterima
73
+ ───────────────────────────────────────────────────────────── */
168
74
 
169
- const toUnified = (submessages, uuid) => ({
170
- response_id: uuid,
171
- sections: submessages.flatMap((submessage) => {
172
- if (submessage.messageType === RichSubMessageType.IMAGES) {
173
- return (submessage._imageUrls || []).map(url => ({
174
- view_model: {
175
- primitive: {
176
- media: { url, mime_type: submessage._mimeType || 'image/jpeg' },
177
- imagine_type: 3,
178
- status: { status: 'READY' },
179
- __typename: 'GenAIImaginePrimitive'
180
- },
181
- __typename: 'GenAISingleLayoutViewModel'
182
- }
183
- }))
184
- }
185
- if (submessage.messageType === RichSubMessageType.TABLE) {
186
- const tm = submessage.tableMetadata
75
+ /**
76
+ * Parse sebuah AIRichResponseSubMessage proto menjadi object JS yang mudah dipakai.
77
+ * Return null kalau tipe tidak dikenal.
78
+ */
79
+ export const parseRichSubMessage = (submessage) => {
80
+ if (!submessage) return null;
81
+ const type = submessage.messageType;
82
+
83
+ switch (type) {
84
+ case RichSubMessageType.TEXT:
85
+ return {
86
+ type: 'text',
87
+ text: submessage.messageText || '',
88
+ };
89
+
90
+ case RichSubMessageType.CODE:
91
+ return {
92
+ type: 'code',
93
+ language: submessage.codeMetadata?.codeLanguage || 'plain',
94
+ blocks: (submessage.codeMetadata?.codeBlocks || []).map(b => ({
95
+ highlight: CodeHighlightType[b.highlightType] ?? 'DEFAULT',
96
+ content: b.codeContent || '',
97
+ })),
98
+ /** Helper: ambil source code mentah tanpa highlight info */
99
+ get raw() {
100
+ return this.blocks.map(b => b.content).join('');
101
+ },
102
+ };
103
+
104
+ case RichSubMessageType.TABLE:
105
+ return {
106
+ type: 'table',
107
+ title: submessage.tableMetadata?.title || '',
108
+ rows: (submessage.tableMetadata?.rows || []).map(row => ({
109
+ isHeading: row.isHeading ?? false,
110
+ items: row.items || [],
111
+ })),
112
+ };
113
+
114
+ case RichSubMessageType.GRID_IMAGE:
115
+ return {
116
+ type: 'gridImage',
117
+ gridImageUrl: submessage.gridImageMetadata?.gridImageUrl || null,
118
+ imageUrls: submessage.gridImageMetadata?.imageUrls || [],
119
+ };
120
+
121
+ case RichSubMessageType.INLINE_IMAGE:
122
+ return {
123
+ type: 'inlineImage',
124
+ imageUrl: submessage.imageMetadata?.imageUrl || null,
125
+ imageText: submessage.imageMetadata?.imageText || '',
126
+ alignment: submessage.imageMetadata?.alignment ?? 0,
127
+ tapLinkUrl: submessage.imageMetadata?.tapLinkUrl || null,
128
+ };
129
+
130
+ case RichSubMessageType.DYNAMIC:
131
+ return {
132
+ type: 'dynamic',
133
+ dynamicType: submessage.dynamicMetadata?.type ?? 0,
134
+ version: submessage.dynamicMetadata?.version ?? 0,
135
+ url: submessage.dynamicMetadata?.url || null,
136
+ loopCount: submessage.dynamicMetadata?.loopCount ?? 0,
137
+ };
138
+
139
+ case RichSubMessageType.MAP:
140
+ return {
141
+ type: 'map',
142
+ centerLatitude: submessage.mapMetadata?.centerLatitude ?? 0,
143
+ centerLongitude: submessage.mapMetadata?.centerLongitude ?? 0,
144
+ latitudeDelta: submessage.mapMetadata?.latitudeDelta ?? 0,
145
+ longitudeDelta: submessage.mapMetadata?.longitudeDelta ?? 0,
146
+ showInfoList: submessage.mapMetadata?.showInfoList ?? false,
147
+ annotations: (submessage.mapMetadata?.annotations || []).map(a => ({
148
+ number: a.annotationNumber ?? 0,
149
+ latitude: a.latitude ?? 0,
150
+ longitude: a.longitude ?? 0,
151
+ title: a.title || '',
152
+ body: a.body || '',
153
+ })),
154
+ };
155
+
156
+ case RichSubMessageType.LATEX:
157
+ return {
158
+ type: 'latex',
159
+ text: submessage.latexMetadata?.text || '',
160
+ expressions: (submessage.latexMetadata?.expressions || []).map(e => ({
161
+ expression: e.latexExpression || '',
162
+ url: e.url || null,
163
+ width: e.width ?? 0,
164
+ height: e.height ?? 0,
165
+ })),
166
+ };
167
+
168
+ case RichSubMessageType.CONTENT_ITEMS:
169
+ return {
170
+ type: 'contentItems',
171
+ contentType: submessage.contentItemsMetadata?.contentType ?? 0,
172
+ items: (submessage.contentItemsMetadata?.itemsMetadata || []).map(item => {
173
+ if (item.reelItem) {
174
+ return {
175
+ kind: 'reel',
176
+ title: item.reelItem.title || '',
177
+ profileIconUrl: item.reelItem.profileIconUrl || null,
178
+ thumbnailUrl: item.reelItem.thumbnailUrl || null,
179
+ videoUrl: item.reelItem.videoUrl || null,
180
+ };
181
+ }
182
+ return { kind: 'unknown' };
183
+ }),
184
+ };
185
+
186
+ default:
187
+ return { type: 'unknown', raw: submessage };
188
+ }
189
+ };
190
+
191
+ /**
192
+ * Parse seluruh AIRichResponseMessage menjadi array parsed submessages.
193
+ * Bisa dipanggil langsung dari handler messages.upsert:
194
+ *
195
+ * const inner = normalizeMessageContent(msg.message)
196
+ * const parsed = parseRichMessage(inner?.richResponseMessage)
197
+ */
198
+ export const parseRichMessage = (richResponseMessage) => {
199
+ if (!richResponseMessage) return null;
200
+
201
+ const submessages = (richResponseMessage.submessages || [])
202
+ .map(parseRichSubMessage)
203
+ .filter(Boolean);
204
+
205
+ let unifiedData = null;
206
+ if (richResponseMessage.unifiedResponse?.data) {
207
+ try {
208
+ const buf = richResponseMessage.unifiedResponse.data;
209
+ unifiedData = JSON.parse(Buffer.isBuffer(buf) ? buf.toString('utf-8') : Buffer.from(buf).toString('utf-8'));
210
+ } catch (_) { /* ignore parse error */ }
211
+ }
212
+
213
+ return {
214
+ messageType: richResponseMessage.messageType ?? 0,
215
+ submessages,
216
+ unifiedData,
217
+ };
218
+ };
219
+
220
+ /* ─────────────────────────────────────────────────────────────
221
+ OUTGOING BUILDER — unified response JSON per subtype
222
+ ───────────────────────────────────────────────────────────── */
223
+
224
+ const buildUnifiedSection = (submessage) => {
225
+ switch (submessage.messageType) {
226
+ case RichSubMessageType.TEXT:
187
227
  return {
188
228
  view_model: {
189
229
  primitive: {
190
- title: tm.title || null,
191
- rows: tm.rows.map(row => ({
192
- is_header: row.isHeading || false,
193
- cells: row.items,
194
- markdown_cells: row.items.map(item => ({ text: item }))
195
- })),
196
- __typename: 'GenATableUXPrimitive'
230
+ text: submessage.messageText,
231
+ inline_entities: submessage.inlineEntities || [],
232
+ __typename: 'GenAIMarkdownTextUXPrimitive'
197
233
  },
198
234
  __typename: 'GenAISingleLayoutViewModel'
199
235
  }
200
- }
201
- }
202
- if (submessage.messageType === RichSubMessageType.CODE) {
203
- const cm = submessage.codeMetadata
236
+ };
237
+
238
+ case RichSubMessageType.CODE: {
239
+ const cm = submessage.codeMetadata;
204
240
  return {
205
241
  view_model: {
206
242
  primitive: {
207
243
  language: cm.codeLanguage,
208
- code_blocks: cm.codeBlocks.map((block) => ({
209
- content: block.codeContent,
210
- type: Object.keys(CodeHighlightType).find(k => CodeHighlightType[k] === block.highlightType) || 'DEFAULT'
244
+ code_blocks: cm.codeBlocks.map(b => ({
245
+ content: b.codeContent,
246
+ type: CodeHighlightType[b.highlightType]
211
247
  })),
212
248
  __typename: 'GenAICodeUXPrimitive'
213
249
  },
214
250
  __typename: 'GenAISingleLayoutViewModel'
215
251
  }
216
- }
252
+ };
217
253
  }
218
- if (submessage.messageType === RichSubMessageType.TEXT) {
254
+
255
+ case RichSubMessageType.TABLE: {
256
+ const tm = submessage.tableMetadata;
219
257
  return {
220
258
  view_model: {
221
259
  primitive: {
222
- text: submessage.messageText,
223
- inline_entities: submessage.inlineEntities || [],
224
- __typename: 'GenAIMarkdownTextUXPrimitive'
260
+ title: tm.title,
261
+ rows: tm.rows.map(row => ({
262
+ is_header: row.isHeading,
263
+ cells: row.items,
264
+ markdown_cells: row.items.map(item => ({ text: item }))
265
+ })),
266
+ __typename: 'GenATableUXPrimitive'
225
267
  },
226
268
  __typename: 'GenAISingleLayoutViewModel'
227
269
  }
228
- }
270
+ };
229
271
  }
230
- if (submessage.messageType === RichSubMessageType.VIDEO) {
231
- const vm = submessage.videoMetadata
272
+
273
+ case RichSubMessageType.GRID_IMAGE: {
274
+ const gm = submessage.gridImageMetadata;
232
275
  return {
233
276
  view_model: {
234
277
  primitive: {
235
- media: { url: vm.url, mime_type: vm.mimeType || 'video/mp4', duration: vm.duration || 10 },
236
- imagine_type: 'ANIMATE',
237
- status: { status: 'READY' },
238
- __typename: 'GenAIImaginePrimitive'
278
+ grid_image_url: toImageUrlJson(gm.gridImageUrl),
279
+ image_urls: (gm.imageUrls || []).map(toImageUrlJson),
280
+ __typename: 'GenAIGridImageUXPrimitive'
239
281
  },
240
282
  __typename: 'GenAISingleLayoutViewModel'
241
283
  }
242
- }
243
- }
244
- if (submessage.messageType === RichSubMessageType.SUGGESTIONS) {
245
- return {
246
- view_model: {
247
- primitives: submessage.suggestions.map(s => ({
248
- prompt_text: s,
249
- prompt_type: 'SUGGESTED_PROMPT',
250
- __typename: 'GenAIFollowUpSuggestionPillPrimitive'
251
- })),
252
- __typename: 'GenAIActionRowLayoutViewModel'
253
- }
254
- }
255
- }
256
- if (submessage.messageType === RichSubMessageType.REELS) {
257
- return {
258
- view_model: {
259
- primitives: (submessage._reelItems || []).map(i => ({
260
- reels_url: i.videoUrl,
261
- thumbnail_url: i.thumbnailUrl,
262
- creator: i.title,
263
- avatar_url: i.profileIconUrl,
264
- reels_title: i.reels_title || '',
265
- likes_count: i.likes_count || 0,
266
- shares_count: i.shares_count || 0,
267
- view_count: i.view_count || 0,
268
- reel_source: i.reel_source || 'IG',
269
- is_verified: i.is_verified || false,
270
- __typename: 'GenAIReelPrimitive'
271
- })),
272
- __typename: 'GenAIHScrollLayoutViewModel'
273
- }
274
- }
275
- }
276
- if (submessage.messageType === RichSubMessageType.PRODUCT) {
277
- const { isMultiple, products } = submessage.productMetadata
278
- if (isMultiple) {
279
- return {
280
- view_model: {
281
- primitives: products.map(p => ({ ...p, __typename: 'GenAIProductItemCardPrimitive' })),
282
- __typename: 'GenAIHScrollLayoutViewModel'
283
- }
284
- }
285
- }
286
- return {
287
- view_model: {
288
- primitive: { ...products[0], __typename: 'GenAIProductItemCardPrimitive' },
289
- __typename: 'GenAISingleLayoutViewModel'
290
- }
291
- }
284
+ };
292
285
  }
293
- if (submessage.messageType === RichSubMessageType.POST) {
294
- const { isMultiple, posts } = submessage.postMetadata
295
- if (isMultiple) {
296
- return {
297
- view_model: {
298
- primitives: posts.map(p => ({ ...p, __typename: 'GenAIPostPrimitive' })),
299
- __typename: 'GenAIHScrollLayoutViewModel'
300
- }
301
- }
302
- }
286
+
287
+ case RichSubMessageType.INLINE_IMAGE: {
288
+ const im = submessage.imageMetadata;
303
289
  return {
304
290
  view_model: {
305
- primitive: { ...posts[0], __typename: 'GenAIPostPrimitive' },
291
+ primitive: {
292
+ image_url: toImageUrlJson(im.imageUrl),
293
+ image_text: im.imageText,
294
+ alignment: im.alignment ?? 0,
295
+ tap_link_url: im.tapLinkUrl || null,
296
+ __typename: 'GenAIInlineImageUXPrimitive'
297
+ },
306
298
  __typename: 'GenAISingleLayoutViewModel'
307
299
  }
308
- }
300
+ };
309
301
  }
310
- if (submessage.messageType === RichSubMessageType.SOURCES) {
302
+
303
+ case RichSubMessageType.DYNAMIC: {
304
+ const dm = submessage.dynamicMetadata;
311
305
  return {
312
306
  view_model: {
313
307
  primitive: {
314
- sources: submessage.sourcesMetadata.sources.map(s => Array.isArray(s) ? {
315
- source_type: 'THIRD_PARTY',
316
- source_display_name: s[2] || '',
317
- source_subtitle: 'AI',
318
- source_url: s[1] || '',
319
- favicon: { url: s[0] || '', mime_type: 'image/jpeg', width: 16, height: 16 }
320
- } : s),
321
- __typename: 'GenAISearchResultPrimitive'
308
+ type: dm.type ?? 0,
309
+ version: dm.version ?? 0,
310
+ url: dm.url,
311
+ loop_count: dm.loopCount ?? 0,
312
+ __typename: 'GenAIDynamicUXPrimitive'
322
313
  },
323
314
  __typename: 'GenAISingleLayoutViewModel'
324
315
  }
325
- }
316
+ };
326
317
  }
327
- if (submessage.messageType === RichSubMessageType.TIP) {
318
+
319
+ case RichSubMessageType.MAP: {
320
+ const mm = submessage.mapMetadata;
328
321
  return {
329
322
  view_model: {
330
- primitive: { text: submessage.tipText, __typename: 'GenAIMetadataTextPrimitive' },
323
+ primitive: {
324
+ center_latitude: mm.centerLatitude,
325
+ center_longitude: mm.centerLongitude,
326
+ latitude_delta: mm.latitudeDelta,
327
+ longitude_delta: mm.longitudeDelta,
328
+ show_info_list: mm.showInfoList ?? false,
329
+ annotations: (mm.annotations || []).map(a => ({
330
+ annotation_number: a.annotationNumber,
331
+ latitude: a.latitude,
332
+ longitude: a.longitude,
333
+ title: a.title,
334
+ body: a.body
335
+ })),
336
+ __typename: 'GenAIMapUXPrimitive'
337
+ },
331
338
  __typename: 'GenAISingleLayoutViewModel'
332
339
  }
333
- }
340
+ };
334
341
  }
335
- if (submessage.messageType === RichSubMessageType.FOOTER) {
342
+
343
+ case RichSubMessageType.LATEX: {
344
+ const lm = submessage.latexMetadata;
336
345
  return {
337
346
  view_model: {
338
- primitive: { text: submessage.footerText, __typename: 'GenAIMetadataTextPrimitive' },
347
+ primitive: {
348
+ text: lm.text,
349
+ expressions: (lm.expressions || []).map(e => ({
350
+ latex_expression: e.latexExpression,
351
+ url: e.url,
352
+ width: e.width,
353
+ height: e.height,
354
+ font_height: e.fontHeight,
355
+ image_top_padding: e.imageTopPadding,
356
+ image_leading_padding: e.imageLeadingPadding,
357
+ image_bottom_padding: e.imageBottomPadding,
358
+ image_trailing_padding: e.imageTrailingPadding
359
+ })),
360
+ __typename: 'GenAILatexUXPrimitive'
361
+ },
339
362
  __typename: 'GenAISingleLayoutViewModel'
340
363
  }
341
- }
364
+ };
342
365
  }
343
- if (submessage.messageType === RichSubMessageType.LATEX) {
344
- const lm = submessage.latexMetadata
345
- const key = 'PONTA_LATEX_0'
366
+
367
+ case RichSubMessageType.CONTENT_ITEMS: {
368
+ const ci = submessage.contentItemsMetadata;
346
369
  return {
347
370
  view_model: {
348
371
  primitive: {
349
- text: `{{${key}}}${lm.text || 'image'}{{/${key}}}`,
350
- inline_entities: [{
351
- key,
352
- metadata: {
353
- latex_expression: lm.text || '',
354
- latex_image: { url: lm.url, width: lm.width || 100, height: lm.height || 100 },
355
- font_height: lm.font_height || 83.33,
356
- padding: lm.padding || 15,
357
- __typename: 'GenAILatexItem'
372
+ content_type: ci.contentType ?? 0,
373
+ items_metadata: (ci.itemsMetadata || []).map(item => {
374
+ if (item.reelItem) {
375
+ return {
376
+ reel_item: {
377
+ title: item.reelItem.title,
378
+ profile_icon_url: item.reelItem.profileIconUrl,
379
+ thumbnail_url: item.reelItem.thumbnailUrl,
380
+ video_url: item.reelItem.videoUrl
381
+ }
382
+ };
358
383
  }
359
- }],
360
- __typename: 'GenAIMarkdownTextUXPrimitive'
384
+ return {};
385
+ }),
386
+ __typename: 'GenAIContentItemsUXPrimitive'
361
387
  },
362
388
  __typename: 'GenAISingleLayoutViewModel'
363
389
  }
364
- }
390
+ };
365
391
  }
366
- return {}
367
- })
368
- })
369
-
370
- // ─── botMetadataSignature / botMetadataCertificate ───────────────────────────
371
-
372
- const botMetadataSignature = () => {
373
- const sig = new Uint8Array(64)
374
- crypto_1.getRandomValues(sig)
375
- return sig
376
- }
377
-
378
- const botMetadataCertificate = (length = 685) => {
379
- const cert = new Uint8Array(length)
380
- cert[0] = 48
381
- cert[1] = 130
382
- crypto_1.getRandomValues(cert.subarray(2))
383
- return cert
384
- }
385
-
386
- // ─── prepareRichResponseMessage ───────────────────────────────────────────────
387
-
388
- const prepareRichResponseMessage = (content) => {
389
-
390
- // Normalize ke array of items
391
- // Support:
392
- // { code, language } — single code block
393
- // { codes: [{ code, language }, ...] } — multi code block
394
- // { table: { title?, headers?, rows } } — single table
395
- // { richText: 'string' } — single text
396
- // { richImages: 'url' | ['url1', 'url2'] } — image grid shorthand
397
- // { richSuggestions: ['a', 'b'] } — suggestion pills shorthand
398
- // { richLatex: 'url' | { url, text?, ... } } — latex shorthand
399
- // { richProduct: {} | [{}] } — product card(s) shorthand
400
- // { richPost: {} | [{}] } — post card(s) shorthand
401
- // { richReels: {} | [{}] } — reels carousel shorthand
402
- // { richSources: [{...}|[fav,url,name]] } — search sources shorthand
403
- // { richTip: 'text' } — tip/metadata text shorthand
404
- // { richFooter: 'text' } — footer text shorthand
405
- // { items: [{ text }|{ code }|{ table }|{ videoUrl }|{ images }|{ suggestions }
406
- // |{ latexUrl }|{ product }|{ post }|{ reels }
407
- // |{ sources }|{ tip }|{ footer }] }
408
- // { richResponse: [{ text }|{ code }|{ table }|{ video }|{ images }|{ suggestions }
409
- // |{ latex }|{ product }|{ post }|{ reels }
410
- // |{ sources }|{ tip }|{ footer }] }
411
-
412
- let submessages = []
413
-
414
- if (Array.isArray(content.richResponse)) {
415
- // ── richResponse array mode ───────────────────────────────────────────
416
- submessages = content.richResponse.flatMap(sub => {
417
- if (sub.text !== undefined) {
418
- return {
419
- messageType: RichSubMessageType.TEXT,
420
- messageText: sub.text,
421
- ...(sub.inlineEntities ? { inlineEntities: sub.inlineEntities } : {})
422
- }
423
- }
424
- if (sub.code !== undefined) {
425
- const lang = sub.language || 'javascript'
392
+
393
+ default:
394
+ return submessage;
395
+ }
396
+ };
397
+
398
+ export const toUnified = (submessages) => ({
399
+ response_id: randomUUID(),
400
+ sections: submessages.map(buildUnifiedSection)
401
+ });
402
+
403
+ /* ─────────────────────────────────────────────────────────────
404
+ PREPARE HELPERS builder per tipe submessage
405
+ ───────────────────────────────────────────────────────────── */
406
+
407
+ /** Buat submessage TEXT */
408
+ const makeTextSub = (text, inlineEntities) => ({
409
+ messageType: RichSubMessageType.TEXT,
410
+ messageText: text,
411
+ ...(inlineEntities ? { inlineEntities } : {})
412
+ });
413
+
414
+ /** Buat submessage CODE dengan auto-tokenize */
415
+ const makeCodeSub = (code, language = 'javascript') => ({
416
+ messageType: RichSubMessageType.CODE,
417
+ codeMetadata: {
418
+ codeLanguage: language,
419
+ codeBlocks: tokenizeCode(code, language)
420
+ }
421
+ });
422
+
423
+ /** Buat submessage TABLE */
424
+ const makeTableSub = (rows, title, noHeading) => ({
425
+ messageType: RichSubMessageType.TABLE,
426
+ tableMetadata: {
427
+ title: title || '',
428
+ rows: rows.map((items, i) => ({
429
+ isHeading: !noHeading && i === 0,
430
+ items
431
+ }))
432
+ }
433
+ });
434
+
435
+ /** Normalize input ke format AIRichResponseImageURL */
436
+ const normalizeImageUrl = (u) => {
437
+ if (!u) return null;
438
+ if (typeof u === 'string') return { imagePreviewUrl: u, imageHighResUrl: u, sourceUrl: null };
439
+ return {
440
+ imagePreviewUrl: u.imagePreviewUrl || u.image_preview_url || null,
441
+ imageHighResUrl: u.imageHighResUrl || u.image_high_res_url || null,
442
+ sourceUrl: u.sourceUrl || u.source_url || null
443
+ };
444
+ };
445
+
446
+ /** Buat submessage GRID_IMAGE */
447
+ const makeGridImageSub = (gridImageUrl, imageUrls = []) => ({
448
+ messageType: RichSubMessageType.GRID_IMAGE,
449
+ gridImageMetadata: {
450
+ gridImageUrl: normalizeImageUrl(gridImageUrl),
451
+ imageUrls: (imageUrls || []).map(normalizeImageUrl)
452
+ }
453
+ });
454
+
455
+ /** Buat submessage INLINE_IMAGE */
456
+ const makeInlineImageSub = (imageUrl, imageText = '', alignment = 0, tapLinkUrl = null) => ({
457
+ messageType: RichSubMessageType.INLINE_IMAGE,
458
+ imageMetadata: {
459
+ imageUrl: normalizeImageUrl(imageUrl),
460
+ imageText,
461
+ alignment,
462
+ tapLinkUrl
463
+ }
464
+ });
465
+
466
+ /** Buat submessage DYNAMIC (animated image/GIF) */
467
+ const makeDynamicSub = (url, dynamicType = 1, version = 1, loopCount = 0) => ({
468
+ messageType: RichSubMessageType.DYNAMIC,
469
+ dynamicMetadata: { type: dynamicType, version, url, loopCount }
470
+ });
471
+
472
+ /** Buat submessage MAP */
473
+ const makeMapSub = (centerLatitude, centerLongitude, options = {}) => ({
474
+ messageType: RichSubMessageType.MAP,
475
+ mapMetadata: {
476
+ centerLatitude,
477
+ centerLongitude,
478
+ latitudeDelta: options.latitudeDelta ?? 0.05,
479
+ longitudeDelta: options.longitudeDelta ?? 0.05,
480
+ showInfoList: options.showInfoList ?? false,
481
+ annotations: (options.annotations || []).map((a, i) => ({
482
+ annotationNumber: a.number ?? i + 1,
483
+ latitude: a.latitude,
484
+ longitude: a.longitude,
485
+ title: a.title || '',
486
+ body: a.body || ''
487
+ }))
488
+ }
489
+ });
490
+
491
+ /** Buat submessage LATEX */
492
+ const makeLatexSub = (text, expressions = []) => ({
493
+ messageType: RichSubMessageType.LATEX,
494
+ latexMetadata: {
495
+ text,
496
+ expressions: expressions.map(e => {
497
+ const expr = e.expression || e.latexExpression || '';
498
+ // url WAJIB ada agar WA client bisa render — auto-generate jika tidak disupply
499
+ const url = e.url || buildLatexUrl(expr);
500
+ return {
501
+ latexExpression: expr,
502
+ url,
503
+ width: e.width ?? 120,
504
+ height: e.height ?? 40,
505
+ fontHeight: e.fontHeight ?? 0,
506
+ imageTopPadding: e.imageTopPadding ?? 0,
507
+ imageLeadingPadding: e.imageLeadingPadding ?? 0,
508
+ imageBottomPadding: e.imageBottomPadding ?? 0,
509
+ imageTrailingPadding: e.imageTrailingPadding ?? 0
510
+ };
511
+ })
512
+ }
513
+ });
514
+
515
+ /** Buat submessage CONTENT_ITEMS (carousel reel) */
516
+ const makeContentItemsSub = (items, contentType = 0) => ({
517
+ messageType: RichSubMessageType.CONTENT_ITEMS,
518
+ contentItemsMetadata: {
519
+ contentType,
520
+ itemsMetadata: items.map(item => {
521
+ if (item.reelItem || item.kind === 'reel') {
522
+ const r = item.reelItem || item;
426
523
  return {
427
- messageType: RichSubMessageType.CODE,
428
- codeMetadata: {
429
- codeLanguage: lang,
430
- codeBlocks: tokenizeCode(sub.code, lang)
524
+ reelItem: {
525
+ title: r.title || '',
526
+ profileIconUrl: r.profileIconUrl || null,
527
+ thumbnailUrl: r.thumbnailUrl || null,
528
+ videoUrl: r.videoUrl || null
431
529
  }
432
- }
530
+ };
433
531
  }
434
- if (sub.table !== undefined) {
435
- return {
436
- messageType: RichSubMessageType.TABLE,
437
- tableMetadata: {
438
- ...(sub.title ? { title: sub.title } : {}),
439
- rows: sub.table
532
+ return {};
533
+ })
534
+ }
535
+ });
536
+
537
+ /** Buat section SOURCE (search result links) — hanya unified, tidak ada submessage proto */
538
+ const makeSourceSection = (sources = []) => {
539
+ const list = Array.isArray(sources) ? sources : [sources];
540
+ return {
541
+ view_model: {
542
+ primitive: {
543
+ sources: list.map(s => ({
544
+ source_url: s.url ?? s.source_url ?? '',
545
+ source_title: s.title ?? s.source_title ?? '',
546
+ source_display_name: s.display_name ?? s.displayName ?? s.title ?? '',
547
+ source_subtitle: s.subtitle ?? s.source_subtitle ?? '',
548
+ source_type: s.source_type ?? 'THIRD_PARTY',
549
+ favicon: {
550
+ url: s.favicon ?? s.faviconCDNURL ?? '',
551
+ width: 16,
552
+ height: 16
440
553
  }
441
- }
554
+ })),
555
+ __typename: 'GenAISearchResultPrimitive'
556
+ },
557
+ __typename: 'GenAISingleLayoutViewModel'
558
+ }
559
+ };
560
+ };
561
+
562
+ /** Buat submessage + unified section untuk IMAGE (grid image style) */
563
+ const makeImageSub = (imageUrl) => {
564
+ const urls = Array.isArray(imageUrl) ? imageUrl : [imageUrl];
565
+ const imageUrls = urls.map(u => ({
566
+ imagePreviewUrl: u,
567
+ imageHighResUrl: u,
568
+ sourceUrl: null
569
+ }));
570
+ return {
571
+ sub: {
572
+ messageType: RichSubMessageType.GRID_IMAGE,
573
+ gridImageMetadata: {
574
+ gridImageUrl: normalizeImageUrl(urls[0]),
575
+ imageUrls: imageUrls.map(normalizeImageUrl)
442
576
  }
443
- if (sub.images !== undefined) {
444
- const raw = sub.images
445
- const urls = typeof raw === 'string' ? [raw] : (Array.isArray(raw) ? raw : [raw])
446
- const mimeType = 'image/jpeg'
447
- return {
448
- messageType: RichSubMessageType.IMAGES,
449
- gridImageMetadata: {
450
- gridImageUrl: { imagePreviewUrl: urls[0] },
451
- imageUrls: urls.map(url => ({ imagePreviewUrl: url, imageHighResUrl: url, sourceUrl: url }))
452
- },
453
- _imageUrls: urls,
454
- _mimeType: mimeType
455
- }
577
+ },
578
+ sections: imageUrls.map(({ imagePreviewUrl }) => ({
579
+ view_model: {
580
+ primitive: {
581
+ media: { url: imagePreviewUrl, mime_type: 'image/png' },
582
+ imagine_type: 'IMAGE',
583
+ status: { status: 'READY' },
584
+ __typename: 'GenAIImaginePrimitive'
585
+ },
586
+ __typename: 'GenAISingleLayoutViewModel'
456
587
  }
457
- if (sub.video !== undefined) {
458
- const url = typeof sub.video === 'string' ? sub.video : sub.video.url
459
- const mimeType = (typeof sub.video === 'object' && sub.video.mimeType) || 'video/mp4'
460
- const duration = (typeof sub.video === 'object' && sub.video.duration) || 10
461
- const fallbackText = (typeof sub.video === 'object' && sub.video.fallbackText) || '[ VIDEO - PontaCT ]'
462
- return [
463
- { messageType: RichSubMessageType.TEXT, messageText: fallbackText },
464
- { messageType: RichSubMessageType.VIDEO, videoMetadata: { url, mimeType, duration } }
465
- ]
588
+ }))
589
+ };
590
+ };
591
+
592
+ /** Buat submessage + unified section untuk VIDEO */
593
+ const makeVideoSub = (videoUrl) => {
594
+ const urls = Array.isArray(videoUrl) ? videoUrl : [videoUrl];
595
+ const parsed = urls.map(item => {
596
+ const [url, duration = '0'] = item.split('|');
597
+ return { url, duration: Number(duration) || 0 };
598
+ });
599
+ return {
600
+ sub: {
601
+ messageType: RichSubMessageType.DYNAMIC,
602
+ dynamicMetadata: {
603
+ type: 1,
604
+ version: 1,
605
+ url: parsed[0]?.url || '',
606
+ loopCount: 0
466
607
  }
467
- if (sub.suggestions !== undefined) {
468
- const arr = Array.isArray(sub.suggestions) ? sub.suggestions : [sub.suggestions]
469
- return { messageType: RichSubMessageType.SUGGESTIONS, suggestions: arr }
608
+ },
609
+ sections: parsed.map(({ url, duration }) => ({
610
+ view_model: {
611
+ primitive: {
612
+ media: { url, mime_type: 'video/mp4', duration },
613
+ imagine_type: 'ANIMATE',
614
+ status: { status: 'READY' },
615
+ __typename: 'GenAIImaginePrimitive'
616
+ },
617
+ __typename: 'GenAISingleLayoutViewModel'
470
618
  }
471
- if (sub.latex !== undefined) {
472
- const raw = sub.latex
473
- const url = typeof raw === 'string' ? raw : raw.url
474
- const text = (typeof raw === 'object' && raw.text) || ''
475
- return [
476
- { messageType: RichSubMessageType.TEXT, messageText: text || '[latex]' },
477
- {
478
- messageType: RichSubMessageType.LATEX,
479
- latexMetadata: {
480
- url,
481
- text,
482
- width: Number((typeof raw === 'object' && raw.width) || 100),
483
- height: Number((typeof raw === 'object' && raw.height) || 100),
484
- font_height: Number((typeof raw === 'object' && raw.font_height) || 83.33),
485
- padding: Number((typeof raw === 'object' && raw.padding) || 15)
486
- }
619
+ }))
620
+ };
621
+ };
622
+
623
+ /** Buat submessage + unified section untuk REELS (HScroll) */
624
+ const makeReelsSub = (reelsItems = []) => {
625
+ const list = Array.isArray(reelsItems) ? reelsItems : [reelsItems];
626
+ return {
627
+ sub: {
628
+ messageType: RichSubMessageType.CONTENT_ITEMS,
629
+ contentItemsMetadata: {
630
+ contentType: 1,
631
+ itemsMetadata: list.map(item => ({
632
+ reelItem: {
633
+ title: item.username ?? item.title ?? '',
634
+ profileIconUrl: item.profileIconUrl ?? item.profile_url ?? null,
635
+ thumbnailUrl: item.thumbnailUrl ?? item.thumbnail ?? null,
636
+ videoUrl: item.videoUrl ?? item.url ?? null
487
637
  }
488
- ]
638
+ }))
489
639
  }
490
- if (sub.product !== undefined) {
491
- const isMultiple = Array.isArray(sub.product)
492
- const products = isMultiple ? sub.product : [sub.product]
493
- return [
494
- { messageType: RichSubMessageType.TEXT, messageText: '[ PRODUCT - PontaCT ]' },
495
- { messageType: RichSubMessageType.PRODUCT, productMetadata: { isMultiple, products } }
496
- ]
640
+ },
641
+ section: {
642
+ view_model: {
643
+ primitives: list.map(item => ({
644
+ reels_url: item.videoUrl ?? item.url ?? '',
645
+ thumbnail_url: item.thumbnailUrl ?? item.thumbnail ?? '',
646
+ creator: item.username ?? item.title ?? '',
647
+ avatar_url: item.profileIconUrl ?? item.profile_url ?? '',
648
+ reels_title: item.reels_title ?? item.title ?? '',
649
+ likes_count: item.likes_count ?? item.like ?? 0,
650
+ shares_count: item.shares_count ?? item.share ?? 0,
651
+ view_count: item.view_count ?? item.view ?? 0,
652
+ reel_source: item.reel_source ?? item.source ?? 'IG',
653
+ is_verified: !!(item.is_verified || item.verified),
654
+ __typename: 'GenAIReelPrimitive'
655
+ })),
656
+ __typename: 'GenAIHScrollLayoutViewModel'
497
657
  }
498
- if (sub.post !== undefined) {
499
- const isMultiple = Array.isArray(sub.post)
500
- const posts = isMultiple ? sub.post : [sub.post]
501
- return [
502
- { messageType: RichSubMessageType.TEXT, messageText: '[ POST - PontaCT ]' },
503
- { messageType: RichSubMessageType.POST, postMetadata: { isMultiple, posts } }
504
- ]
658
+ }
659
+ };
660
+ };
661
+
662
+ /** Buat unified section untuk PRODUCT (single: Single layout, array: HScroll) */
663
+ const makeProductSection = (data) => {
664
+ const items = Array.isArray(data) ? data : [data];
665
+ const primitives = items.map(item => ({
666
+ title: item.title ?? '',
667
+ brand: item.brand ?? '',
668
+ price: item.price ?? '',
669
+ sale_price: item.sale_price ?? item.salePrice ?? '',
670
+ product_url: (() => {
671
+ const u = item.product_url ?? item.url ?? '';
672
+ if (!u || !/^https?:\/\//i.test(u)) {
673
+ console.warn('[baileys] richProduct: product_url/url kosong atau tidak diawali http(s):// — tautan produk ini kemungkinan besar tidak akan bisa dibuka di WhatsApp. Nilai yang diterima:', u || '(kosong)');
505
674
  }
506
- if (sub.reels !== undefined) {
507
- const reelItems = Array.isArray(sub.reels) ? sub.reels : [sub.reels]
508
- return {
509
- messageType: RichSubMessageType.REELS,
510
- contentItemsMetadata: {
511
- contentType: 1,
512
- itemsMetadata: reelItems.map(i => ({
513
- reelItem: { title: i.title, profileIconUrl: i.profileIconUrl, thumbnailUrl: i.thumbnailUrl, videoUrl: i.videoUrl }
514
- }))
515
- },
516
- _reelItems: reelItems
675
+ return u;
676
+ })(),
677
+ image: { url: item.image_url ?? item.image ?? '' },
678
+ additional_images: [{ url: item.icon_url ?? item.icon ?? '' }],
679
+ __typename: 'GenAIProductItemCardPrimitive'
680
+ }));
681
+ const isMultiple = Array.isArray(data);
682
+ return {
683
+ sub: {
684
+ messageType: RichSubMessageType.TEXT,
685
+ messageText: ''
686
+ },
687
+ section: isMultiple
688
+ ? {
689
+ view_model: {
690
+ primitives,
691
+ __typename: 'GenAIHScrollLayoutViewModel'
517
692
  }
518
693
  }
519
- if (sub.sources !== undefined) {
520
- const arr = Array.isArray(sub.sources) ? sub.sources : [sub.sources]
521
- return { messageType: RichSubMessageType.SOURCES, sourcesMetadata: { sources: arr } }
522
- }
523
- if (sub.tip !== undefined) {
524
- return { messageType: RichSubMessageType.TIP, tipText: sub.tip }
525
- }
526
- if (sub.footer !== undefined) {
527
- return { messageType: RichSubMessageType.FOOTER, footerText: sub.footer }
528
- }
529
- // passthrough — kalau ada tipe lain langsung lewat
530
- return sub
531
- })
532
- } else if ('richImages' in content) {
533
- // ── richImages shorthand ──────────────────────────────────────────────
534
- const raw = content.richImages
535
- const urls = typeof raw === 'string' ? [raw] : (Array.isArray(raw) ? raw : [raw])
536
- submessages = [{
537
- messageType: RichSubMessageType.IMAGES,
538
- gridImageMetadata: {
539
- gridImageUrl: { imagePreviewUrl: urls[0] },
540
- imageUrls: urls.map(url => ({ imagePreviewUrl: url, imageHighResUrl: url, sourceUrl: url }))
541
- },
542
- _imageUrls: urls,
543
- _mimeType: 'image/jpeg'
544
- }]
545
- } else if ('richVideo' in content) {
546
- // ── richVideo shorthand ───────────────────────────────────────────────
547
- const rawVideo = content.richVideo
548
- const url = typeof rawVideo === 'string' ? rawVideo : rawVideo.url
549
- const mimeType = (typeof rawVideo === 'object' && rawVideo.mimeType) || 'video/mp4'
550
- const duration = (typeof rawVideo === 'object' && rawVideo.duration) || 10
551
- const fallbackText = (typeof rawVideo === 'object' && rawVideo.fallbackText) || '[ VIDEO - PontaCT ]'
552
- submessages = [
553
- { messageType: RichSubMessageType.TEXT, messageText: fallbackText },
554
- { messageType: RichSubMessageType.VIDEO, videoMetadata: { url, mimeType, duration } }
555
- ]
556
- } else if ('richSuggestions' in content) {
557
- // ── richSuggestions shorthand ─────────────────────────────────────────
558
- const arr = Array.isArray(content.richSuggestions) ? content.richSuggestions : [content.richSuggestions]
559
- submessages = [{ messageType: RichSubMessageType.SUGGESTIONS, suggestions: arr }]
560
- } else if ('richLatex' in content) {
561
- // ── richLatex shorthand ───────────────────────────────────────────────
562
- const raw = content.richLatex
563
- const url = typeof raw === 'string' ? raw : raw.url
564
- const text = (typeof raw === 'object' && raw.text) || ''
565
- submessages = [
566
- { messageType: RichSubMessageType.TEXT, messageText: text || '[latex]' },
567
- {
568
- messageType: RichSubMessageType.LATEX,
569
- latexMetadata: {
570
- url,
571
- text,
572
- width: Number((typeof raw === 'object' && raw.width) || 100),
573
- height: Number((typeof raw === 'object' && raw.height) || 100),
574
- font_height: Number((typeof raw === 'object' && raw.font_height) || 83.33),
575
- padding: Number((typeof raw === 'object' && raw.padding) || 15)
694
+ : {
695
+ view_model: {
696
+ primitive: primitives[0],
697
+ __typename: 'GenAISingleLayoutViewModel'
576
698
  }
577
699
  }
578
- ]
579
- } else if ('richProduct' in content) {
580
- // ── richProduct shorthand ─────────────────────────────────────────────
581
- const isMultiple = Array.isArray(content.richProduct)
582
- const products = isMultiple ? content.richProduct : [content.richProduct]
583
- submessages = [
584
- { messageType: RichSubMessageType.TEXT, messageText: '[ PRODUCT - PontaCT ]' },
585
- { messageType: RichSubMessageType.PRODUCT, productMetadata: { isMultiple, products } }
586
- ]
587
- } else if ('richPost' in content) {
588
- // ── richPost shorthand ────────────────────────────────────────────────
589
- const isMultiple = Array.isArray(content.richPost)
590
- const posts = isMultiple ? content.richPost : [content.richPost]
591
- submessages = [
592
- { messageType: RichSubMessageType.TEXT, messageText: '[ POST - PontaCT ]' },
593
- { messageType: RichSubMessageType.POST, postMetadata: { isMultiple, posts } }
594
- ]
595
- } else if ('richReels' in content) {
596
- // ── richReels shorthand ───────────────────────────────────────────────
597
- const reelItems = Array.isArray(content.richReels) ? content.richReels : [content.richReels]
598
- submessages = [{
599
- messageType: RichSubMessageType.REELS,
600
- contentItemsMetadata: {
601
- contentType: 1,
602
- itemsMetadata: reelItems.map(i => ({
603
- reelItem: { title: i.title, profileIconUrl: i.profileIconUrl, thumbnailUrl: i.thumbnailUrl, videoUrl: i.videoUrl }
604
- }))
700
+ };
701
+ };
702
+
703
+ /** Buat unified section untuk POST (HScroll) */
704
+ const makePostSection = (data) => {
705
+ const posts = Array.isArray(data) ? data : [data];
706
+ const primitives = posts.map(p => ({
707
+ title: p.title ?? '',
708
+ subtitle: p.subtitle ?? '',
709
+ username: p.username ?? '',
710
+ profile_picture_url: p.profile_picture_url ?? p.profile_url ?? '',
711
+ is_verified: !!(p.is_verified || p.verified),
712
+ thumbnail_url: p.thumbnail_url ?? p.thumbnail ?? '',
713
+ post_caption: p.post_caption ?? p.caption ?? '',
714
+ likes_count: p.likes_count ?? p.like ?? 0,
715
+ comments_count: p.comments_count ?? p.comment ?? 0,
716
+ shares_count: p.shares_count ?? p.share ?? 0,
717
+ post_url: p.post_url ?? p.url ?? '',
718
+ post_deeplink: p.post_deeplink ?? p.deeplink ?? '',
719
+ source_app: p.source_app ?? p.source ?? 'INSTAGRAM',
720
+ footer_label: p.footer_label ?? p.footer ?? '',
721
+ footer_icon: p.footer_icon ?? p.icon ?? '',
722
+ is_carousel: posts.length > 1,
723
+ orientation: p.orientation ?? 'LANDSCAPE',
724
+ post_type: p.post_type ?? 'VIDEO',
725
+ __typename: 'GenAIPostPrimitive'
726
+ }));
727
+ return {
728
+ sub: {
729
+ messageType: RichSubMessageType.TEXT,
730
+ messageText: ''
731
+ },
732
+ section: {
733
+ view_model: {
734
+ primitives,
735
+ __typename: 'GenAIHScrollLayoutViewModel'
736
+ }
737
+ }
738
+ };
739
+ };
740
+
741
+ /** Buat submessage + unified section untuk TIP (metadata text) */
742
+ const makeTipSub = (text) => ({
743
+ sub: {
744
+ messageType: RichSubMessageType.TEXT,
745
+ messageText: text
746
+ },
747
+ section: {
748
+ view_model: {
749
+ primitive: {
750
+ text,
751
+ __typename: 'GenAIMetadataTextPrimitive'
605
752
  },
606
- _reelItems: reelItems
607
- }]
608
- } else if ('richSources' in content) {
609
- // ── richSources shorthand ─────────────────────────────────────────────
610
- const arr = Array.isArray(content.richSources) ? content.richSources : [content.richSources]
611
- submessages = [{ messageType: RichSubMessageType.SOURCES, sourcesMetadata: { sources: arr } }]
612
- } else if ('richTip' in content) {
613
- // ── richTip shorthand ─────────────────────────────────────────────────
614
- submessages = [{ messageType: RichSubMessageType.TIP, tipText: content.richTip }]
615
- } else if ('richFooter' in content) {
616
- // ── richFooter shorthand ──────────────────────────────────────────────
617
- submessages = [{ messageType: RichSubMessageType.FOOTER, footerText: content.richFooter }]
618
- } else {
619
- // ── shorthand / items mode ────────────────────────────────────────────
620
- let items = []
621
-
622
- if (content.items) {
623
- items = content.items
624
- } else if (content.codes) {
625
- items = content.codes.map(c => ({ code: c.code, language: c.language }))
626
- } else if (content.table) {
627
- items = [{ table: content.table }]
628
- } else if ('richText' in content) {
629
- items = Array.isArray(content.richText)
630
- ? content.richText.map(t => ({ text: t }))
631
- : [{ text: content.richText }]
632
- } else {
633
- items = [{ code: content.code, language: content.language }]
753
+ __typename: 'GenAISingleLayoutViewModel'
634
754
  }
755
+ }
756
+ });
635
757
 
636
- submessages = items.flatMap(item => {
637
- // ── TEXT ──────────────────────────────────────────────────────────
638
- if ('text' in item) {
639
- return {
640
- messageType: RichSubMessageType.TEXT,
641
- messageText: item.text,
642
- ...(item.inlineEntities ? { inlineEntities: item.inlineEntities } : {})
643
- }
644
- }
758
+ /** Buat unified section untuk SUGGEST (ActionRow pill buttons) — tidak ada submessage proto */
759
+ const makeSuggestSection = (suggestion) => {
760
+ const suggestions = Array.isArray(suggestion) ? suggestion : [suggestion];
761
+ return {
762
+ view_model: {
763
+ primitives: suggestions.map(text => ({
764
+ prompt_text: text,
765
+ prompt_type: 'SUGGESTED_PROMPT',
766
+ __typename: 'GenAIFollowUpSuggestionPillPrimitive'
767
+ })),
768
+ __typename: 'GenAIActionRowLayoutViewModel'
769
+ }
770
+ };
771
+ };
645
772
 
646
- // ── IMAGES ────────────────────────────────────────────────────────
647
- if ('images' in item) {
648
- const raw = item.images
649
- const urls = typeof raw === 'string' ? [raw] : (Array.isArray(raw) ? raw : [raw])
650
- return {
651
- messageType: RichSubMessageType.IMAGES,
652
- gridImageMetadata: {
653
- gridImageUrl: { imagePreviewUrl: urls[0] },
654
- imageUrls: urls.map(url => ({ imagePreviewUrl: url, imageHighResUrl: url, sourceUrl: url }))
655
- },
656
- _imageUrls: urls,
657
- _mimeType: 'image/jpeg'
658
- }
659
- }
773
+ /* ─────────────────────────────────────────────────────────────
774
+ MAIN BUILDER prepareRichResponseMessage
775
+ ───────────────────────────────────────────────────────────── */
660
776
 
661
- // ── VIDEO ─────────────────────────────────────────────────────────
662
- if ('videoUrl' in item) {
663
- const fallbackText = item.fallbackText || '[ VIDEO - PontaCT ]'
664
- return [
665
- { messageType: RichSubMessageType.TEXT, messageText: fallbackText },
666
- {
667
- messageType: RichSubMessageType.VIDEO,
668
- videoMetadata: {
669
- url: item.videoUrl,
670
- mimeType: item.mimeType || 'video/mp4',
671
- duration: item.duration || 10
672
- }
673
- }
674
- ]
675
- }
777
+ export const prepareRichResponseMessage = (content) => {
778
+ const {
779
+ code, contentText, aiNotice: disclaimerText, bottomText: footerText, topText: headerText,
780
+ language, links, noHeading, aiBlocks: richResponse, table, title,
781
+ // sub-types lama
782
+ gridImage, inlineImage, dynamic: dynamicContent,
783
+ map: mapContent, latex, contentItems,
784
+ // sub-types baru (prefixed 'rich' agar tidak konflik dengan media biasa)
785
+ richImage, richVideo, reels, source, richProduct, richPost, tip, suggest
786
+ } = content;
676
787
 
677
- // ── SUGGESTIONS ───────────────────────────────────────────────────
678
- if ('suggestions' in item) {
679
- const arr = Array.isArray(item.suggestions) ? item.suggestions : [item.suggestions]
680
- return { messageType: RichSubMessageType.SUGGESTIONS, suggestions: arr }
681
- }
788
+ let submessages = [];
789
+ // extraSections: section-section unified yang tidak punya proto submessage 1:1
790
+ // (source, product, post, suggest) atau punya struktur multi-section (image, video, reels)
791
+ let extraSections = null;
682
792
 
683
- // ── LATEX ─────────────────────────────────────────────────────────
684
- if ('latexUrl' in item) {
685
- const text = item.latexText || ''
686
- return [
687
- { messageType: RichSubMessageType.TEXT, messageText: text || '[latex]' },
688
- {
689
- messageType: RichSubMessageType.LATEX,
690
- latexMetadata: {
691
- url: item.latexUrl,
692
- text,
693
- width: Number(item.latexWidth || 100),
694
- height: Number(item.latexHeight || 100),
695
- font_height: Number(item.latexFontHeight || 83.33),
696
- padding: Number(item.latexPadding || 15)
697
- }
698
- }
699
- ]
700
- }
793
+ /**
794
+ * Helper: push ke submessages dan optionally ke extraSections.
795
+ * Untuk tipe yang punya make*Sub yang mengembalikan { sub, sections[] } atau { sub, section }
796
+ */
797
+ const pushRich = (built) => {
798
+ if (!built) return;
799
+ if (built.sub) submessages.push(built.sub);
800
+ if (!extraSections) extraSections = [];
801
+ if (built.sections) extraSections.push(...built.sections);
802
+ else if (built.section) extraSections.push(built.section);
803
+ };
701
804
 
702
- // ── PRODUCT ───────────────────────────────────────────────────────
703
- if ('product' in item) {
704
- const isMultiple = Array.isArray(item.product)
705
- const products = isMultiple ? item.product : [item.product]
706
- return [
707
- { messageType: RichSubMessageType.TEXT, messageText: '[ PRODUCT - PontaCT ]' },
708
- { messageType: RichSubMessageType.PRODUCT, productMetadata: { isMultiple, products } }
709
- ]
710
- }
805
+ /* ── mode array (aiBlocks) — multi-section campuran ── */
806
+ if (Array.isArray(richResponse)) {
807
+ if (headerText) submessages.push(makeTextSub(headerText));
808
+ richResponse.forEach(sub => {
809
+ if (sub.text != null) { submessages.push(makeTextSub(sub.text, sub.inlineEntities)); return; }
810
+ if (sub.code != null) { submessages.push(makeCodeSub(sub.code, sub.language || 'javascript')); return; }
811
+ if (sub.table != null) { submessages.push(makeTableSub(sub.table, sub.title, sub.noHeading)); return; }
812
+ if (sub.gridImage != null) { submessages.push(makeGridImageSub(sub.gridImage.gridImageUrl, sub.gridImage.imageUrls)); return; }
813
+ if (sub.inlineImage != null) { submessages.push(makeInlineImageSub(sub.inlineImage.imageUrl, sub.inlineImage.imageText, sub.inlineImage.alignment, sub.inlineImage.tapLinkUrl)); return; }
814
+ if (sub.dynamic != null) { submessages.push(makeDynamicSub(sub.dynamic.url, sub.dynamic.type, sub.dynamic.version, sub.dynamic.loopCount)); return; }
815
+ if (sub.map != null) { submessages.push(makeMapSub(sub.map.centerLatitude, sub.map.centerLongitude, sub.map)); return; }
816
+ if (sub.latex != null) { submessages.push(makeLatexSub(sub.latex.text, sub.latex.expressions)); return; }
817
+ if (sub.contentItems != null) { submessages.push(makeContentItemsSub(sub.contentItems.items, sub.contentItems.contentType)); return; }
818
+ // tipe baru
819
+ if (sub.richImage != null) { pushRich(makeImageSub(sub.richImage)); return; }
820
+ if (sub.richVideo != null) { pushRich(makeVideoSub(sub.richVideo)); return; }
821
+ if (sub.reels != null) { pushRich(makeReelsSub(sub.reels)); return; }
822
+ if (sub.source != null) { if (!extraSections) extraSections = []; extraSections.push(makeSourceSection(sub.source)); return; }
823
+ if (sub.richProduct != null) { pushRich(makeProductSection(sub.richProduct)); return; }
824
+ if (sub.richPost != null) { pushRich(makePostSection(sub.richPost)); return; }
825
+ if (sub.tip != null) { pushRich(makeTipSub(sub.tip)); return; }
826
+ if (sub.suggest != null) { if (!extraSections) extraSections = []; extraSections.push(makeSuggestSection(sub.suggest)); return; }
827
+ submessages.push(sub); // passthrough kalau sudah bentuk proto
828
+ });
829
+ if (footerText) submessages.push(makeTextSub(footerText));
711
830
 
712
- // ── POST ──────────────────────────────────────────────────────────
713
- if ('post' in item) {
714
- const isMultiple = Array.isArray(item.post)
715
- const posts = isMultiple ? item.post : [item.post]
716
- return [
717
- { messageType: RichSubMessageType.TEXT, messageText: '[ POST - PontaCT ]' },
718
- { messageType: RichSubMessageType.POST, postMetadata: { isMultiple, posts } }
719
- ]
720
- }
831
+ /* ── mode flat (convenience fields) ── */
832
+ } else {
833
+ if (headerText) submessages.push(makeTextSub(headerText));
721
834
 
722
- // ── REELS ─────────────────────────────────────────────────────────
723
- if ('reels' in item) {
724
- const reelItems = Array.isArray(item.reels) ? item.reels : [item.reels]
725
- return {
726
- messageType: RichSubMessageType.REELS,
727
- contentItemsMetadata: {
728
- contentType: 1,
729
- itemsMetadata: reelItems.map(i => ({
730
- reelItem: { title: i.title, profileIconUrl: i.profileIconUrl, thumbnailUrl: i.thumbnailUrl, videoUrl: i.videoUrl }
731
- }))
732
- },
733
- _reelItems: reelItems
835
+ if (code) submessages.push(makeCodeSub(code, language || 'javascript'));
836
+ if (table) submessages.push(makeTableSub(table, title, noHeading));
837
+ if (gridImage) submessages.push(makeGridImageSub(gridImage.gridImageUrl, gridImage.imageUrls));
838
+ if (inlineImage) submessages.push(makeInlineImageSub(inlineImage.imageUrl, inlineImage.imageText, inlineImage.alignment, inlineImage.tapLinkUrl));
839
+ if (dynamicContent) submessages.push(makeDynamicSub(dynamicContent.url, dynamicContent.type, dynamicContent.version, dynamicContent.loopCount));
840
+ if (mapContent) submessages.push(makeMapSub(mapContent.centerLatitude, mapContent.centerLongitude, mapContent));
841
+ if (latex) submessages.push(makeLatexSub(latex.text, latex.expressions));
842
+ if (contentItems) submessages.push(makeContentItemsSub(contentItems.items, contentItems.contentType));
843
+
844
+ // ── tipe baru ──
845
+ if (richImage) pushRich(makeImageSub(richImage));
846
+ if (richVideo) pushRich(makeVideoSub(richVideo));
847
+ if (reels) pushRich(makeReelsSub(reels));
848
+ if (source) { if (!extraSections) extraSections = []; extraSections.push(makeSourceSection(source)); }
849
+ if (richProduct) pushRich(makeProductSection(richProduct));
850
+ if (richPost) pushRich(makePostSection(richPost));
851
+ if (contentText) submessages.push(makeTextSub(contentText)); // ← setelah produk/post, tampil di bawah card
852
+ if (tip) pushRich(makeTipSub(tip));
853
+ if (suggest) { if (!extraSections) extraSections = []; extraSections.push(makeSuggestSection(suggest)); }
854
+
855
+ /* links — bisa dikombinasi dengan tipe lain di atas */
856
+ if (links && Array.isArray(links)) {
857
+ links.forEach((linkField, index) => {
858
+ const prefix = 'SS_' + index;
859
+ const url = (linkField.url && /^https?:\/\//i.test(linkField.url)) ? linkField.url : DONATE_URL;
860
+ if (url === DONATE_URL) {
861
+ console.warn('[baileys] links[].url kosong/tidak valid (harus http:// atau https://) — dipakai DONATE_URL sebagai gantinya. Cek nilai url yang dikirim ke field "links".');
734
862
  }
735
- }
863
+ const sources = (linkField.sources || []).map(s => ({
864
+ source_type: 'THIRD_PARTY',
865
+ source_display_name: s.displayName || 'Source',
866
+ source_subtitle: s.subtitle || '',
867
+ source_url: s.url || url
868
+ }));
869
+ submessages.push(makeTextSub(
870
+ linkField.text + ` {{${prefix}}}¹{{/${prefix}}} `,
871
+ [{
872
+ key: prefix,
873
+ metadata: {
874
+ reference_id: index + 1,
875
+ reference_url: url,
876
+ reference_title: linkField.title || url,
877
+ reference_display_name: linkField.displayName || url,
878
+ sources,
879
+ __typename: 'GenAISearchCitationItem'
880
+ }
881
+ }]
882
+ ));
883
+ });
884
+ }
736
885
 
737
- // ── SOURCES ───────────────────────────────────────────────────────
738
- if ('sources' in item) {
739
- const arr = Array.isArray(item.sources) ? item.sources : [item.sources]
740
- return { messageType: RichSubMessageType.SOURCES, sourcesMetadata: { sources: arr } }
741
- }
886
+ if (footerText) submessages.push(makeTextSub(footerText));
887
+ }
742
888
 
743
- // ── TIP ───────────────────────────────────────────────────────────
744
- if ('tip' in item) {
745
- return { messageType: RichSubMessageType.TIP, tipText: item.tip }
746
- }
889
+ /* build unifiedResponse JSON — gabungkan sections dari submessages + extraSections */
890
+ // Pisahkan footerSubs (teks setelah media) agar selalu muncul SETELAH extraSections (video/image)
891
+ const footerSubMessages = footerText ? [makeTextSub(footerText)] : [];
892
+ // Hapus footerText dari submessages jika sudah ada (sudah di-push sebelumnya)
893
+ const mainSubmessages = footerText
894
+ ? submessages.filter(s => !(s.messageType === RichSubMessageType.TEXT && s.messageText === footerText))
895
+ : submessages;
896
+ const baseUnified = toUnified(mainSubmessages);
897
+ const footerSections = footerSubMessages.map(buildUnifiedSection);
898
+ const unified = extraSections && extraSections.length > 0
899
+ ? { ...baseUnified, sections: [...baseUnified.sections, ...extraSections, ...footerSections] }
900
+ : { ...baseUnified, sections: [...baseUnified.sections, ...footerSections] };
747
901
 
748
- // ── FOOTER ────────────────────────────────────────────────────────
749
- if ('footer' in item) {
750
- return { messageType: RichSubMessageType.FOOTER, footerText: item.footer }
751
- }
902
+ const richResponseMessage = proto.AIRichResponseMessage.create({
903
+ submessages,
904
+ messageType: proto.AIRichResponseMessageType.AI_RICH_RESPONSE_TYPE_STANDARD,
905
+ unifiedResponse: {
906
+ data: Buffer.from(JSON.stringify(unified), 'utf-8')
907
+ },
908
+ contextInfo: {
909
+ isForwarded: true,
910
+ forwardingScore: 1,
911
+ forwardOrigin: 4
912
+ }
913
+ });
752
914
 
753
- // ── TABLE ─────────────────────────────────────────────────────────
754
- if (item.table) {
755
- const { title, headers, rows } = item.table
756
- const allRows = []
757
- if (headers && headers.length) {
758
- allRows.push({ items: headers, isHeading: true })
759
- }
760
- for (const row of (rows || [])) {
761
- allRows.push({ items: row, isHeading: false })
762
- }
763
- const tableSubmessage = {
764
- messageType: RichSubMessageType.TABLE,
765
- tableMetadata: { rows: allRows }
766
- }
767
- if (title) {
768
- return [
769
- {
770
- messageType: RichSubMessageType.TEXT,
771
- messageText: title
772
- },
773
- tableSubmessage
774
- ]
775
- }
776
- return tableSubmessage
777
- }
915
+ const message = wrapToBotForwardedMessage(richResponseMessage);
916
+ const botMetadata = message.messageContextInfo.botMetadata;
778
917
 
779
- // ── CODE (default) ────────────────────────────────────────────────
780
- const lang = item.language || 'javascript'
781
- const codeBlocks = tokenizeCode(item.code, lang)
782
- return {
783
- messageType: RichSubMessageType.CODE,
784
- codeMetadata: {
785
- codeLanguage: lang,
786
- codeBlocks: codeBlocks.map(b => ({
787
- highlightType: b.highlightType,
788
- codeContent: b.codeContent
789
- }))
790
- }
791
- }
792
- })
918
+ if (disclaimerText) {
919
+ botMetadata.messageDisclaimerText = disclaimerText;
793
920
  }
921
+ botMetadata.botResponseId = unified.response_id;
794
922
 
795
- const uuid = crypto_1.randomUUID()
796
- const unified = toUnified(submessages, uuid)
797
- const aiForwarded = content.aiForwarded !== false
798
-
799
- const pontaSources = submessages
800
- .filter(s => s.messageType === RichSubMessageType.REELS && s._reelItems)
801
- .flatMap(s => (s._reelItems || []).map((i, idx) => ({
802
- provider: 'PontaCT',
803
- thumbnailCDNURL: i.thumbnailUrl,
804
- sourceProviderURL: i.videoUrl,
805
- sourceQuery: '',
806
- faviconCDNURL: i.profileIconUrl,
807
- citationNumber: idx + 1,
808
- sourceTitle: i.title
809
- })))
923
+ return message;
924
+ };
810
925
 
811
- return {
812
- messageContextInfo: {
813
- botMetadata: {
814
- ...(pontaSources.length ? { richResponseSourcesMetadata: { sources: pontaSources } } : {}),
815
- verificationMetadata: {
816
- proofs: [{
817
- certificateChain: [botMetadataCertificate(), botMetadataCertificate(892)],
926
+ /* ─────────────────────────────────────────────────────────────
927
+ BOT WRAPPER HELPERS
928
+ ───────────────────────────────────────────────────────────── */
929
+
930
+ export const botMetadataSignature = () => {
931
+ const signature = new Uint8Array(64);
932
+ getRandomValues(signature);
933
+ return signature;
934
+ };
935
+
936
+ export const botMetadataCertificate = (length = 685) => {
937
+ const certificate = new Uint8Array(length);
938
+ certificate[0] = 48;
939
+ certificate[1] = 130;
940
+ getRandomValues(certificate.subarray(2));
941
+ return certificate;
942
+ };
943
+
944
+ export const wrapToBotForwardedMessage = (richResponseMessage) => ({
945
+ messageContextInfo: {
946
+ botMetadata: {
947
+ verificationMetadata: {
948
+ proofs: [
949
+ {
950
+ certificateChain: [
951
+ botMetadataCertificate(),
952
+ botMetadataCertificate(892)
953
+ ],
818
954
  version: 1,
819
955
  useCase: 1,
820
956
  signature: botMetadataSignature()
821
- }]
822
- },
823
- botResponseId: uuid
824
- }
825
- },
826
- botForwardedMessage: {
827
- message: {
828
- richResponseMessage: {
829
- messageType: 1,
830
- submessages,
831
- unifiedResponse: {
832
- data: Buffer.from(JSON.stringify(unified))
833
- },
834
- contextInfo: {
835
- isForwarded: true,
836
- forwardingScore: 1,
837
- ...(aiForwarded ? { forwardedAiBotMessageInfo: { botJid: '867051314767696@bot' } } : {}),
838
- forwardOrigin: 4
839
957
  }
840
- }
958
+ ]
841
959
  }
842
960
  }
961
+ },
962
+ botForwardedMessage: {
963
+ message: { richResponseMessage }
964
+ }
965
+ });
966
+
967
+ /* ─────────────────────────────────────────────────────────────
968
+ STANDALONE GENERATORS (kompatibel dengan baileys upstream)
969
+ Semua fungsi di bawah ini di-port dari baileys-main/src/Utils/rich-messages.js
970
+ agar API nya 100% kompatibel dengan baileys — termasuk sendTable, sendLatex, dll.
971
+ ───────────────────────────────────────────────────────────── */
972
+
973
+ /* helper: bangun contextInfo dari quoted */
974
+ const buildRichContextInfo = (quoted) => {
975
+ const ctxInfo = {
976
+ isForwarded: true,
977
+ forwardingScore: 1,
978
+ forwardOrigin: 4,
979
+ };
980
+ if (quoted?.key) {
981
+ ctxInfo.stanzaId = quoted.key.id;
982
+ ctxInfo.participant = quoted.key.participant || quoted.sender || quoted.key.remoteJid;
983
+ ctxInfo.quotedMessage = quoted.message;
984
+ }
985
+ return ctxInfo;
986
+ };
987
+
988
+ /* helper: wrap submessages + contextInfo ke botForwardedMessage (format lama/V1) */
989
+ const buildBotForwardedMessage = (submessages, contextInfo, unifiedResponse) => {
990
+ const richResponse = { messageType: 1, submessages, contextInfo };
991
+ if (unifiedResponse) richResponse.unifiedResponse = unifiedResponse;
992
+ return { botForwardedMessage: { message: { richResponseMessage: richResponse } } };
993
+ };
994
+
995
+ /* helper: wrap proto AIRichResponseMessage ke botForwardedMessage dengan messageContextInfo */
996
+ const _wrapProtoToResult = (submessages, quoted) => {
997
+ const unified = toUnified(submessages);
998
+ const richResponseMessage = proto.AIRichResponseMessage.create({
999
+ submessages,
1000
+ messageType: proto.AIRichResponseMessageType.AI_RICH_RESPONSE_TYPE_STANDARD,
1001
+ unifiedResponse: { data: Buffer.from(JSON.stringify(unified), 'utf-8') },
1002
+ contextInfo: buildRichContextInfo(quoted),
1003
+ });
1004
+ return { message: wrapToBotForwardedMessage(richResponseMessage), messageId: generateMessageIDV2() };
1005
+ };
1006
+
1007
+ // ── Table ──────────────────────────────────────────────────
1008
+
1009
+ export const generateTableContent = (title, headers, rows, quoted, options = {}) => {
1010
+ const { footer, headerText } = options;
1011
+ const tableRows = [{ items: headers, isHeading: true }, ...rows.map(row => ({ items: row.map(String) }))];
1012
+ const subs = [];
1013
+ if (headerText) subs.push({ messageType: RichSubMessageType.TEXT, messageText: headerText });
1014
+ subs.push({ messageType: RichSubMessageType.TABLE, tableMetadata: { title, rows: tableRows } });
1015
+ if (footer) subs.push({ messageType: RichSubMessageType.TEXT, messageText: footer });
1016
+ return _wrapProtoToResult(subs, quoted);
1017
+ };
1018
+
1019
+ export const generateListContent = (title, items, quoted, options = {}) => {
1020
+ const { footer, headerText } = options;
1021
+ const tableRows = items.map(item => ({ items: Array.isArray(item) ? item.map(String) : [String(item)] }));
1022
+ const subs = [];
1023
+ if (headerText) subs.push({ messageType: RichSubMessageType.TEXT, messageText: headerText });
1024
+ subs.push({ messageType: RichSubMessageType.TABLE, tableMetadata: { title, rows: tableRows } });
1025
+ if (footer) subs.push({ messageType: RichSubMessageType.TEXT, messageText: footer });
1026
+ return _wrapProtoToResult(subs, quoted);
1027
+ };
1028
+
1029
+ export const toTableMetadataV2 = (arr) => {
1030
+ if (!Array.isArray(arr) || arr.length === 0) throw new Error('Input must be a non-empty array');
1031
+ const [title, headerStr, ...rest] = arr;
1032
+ const splitCols = (str) => typeof str !== 'string' ? [] : str.includes('|') ? str.split('|').map(s => s.trim()) : str.split(',').map(s => s.trim());
1033
+ const splitRows = (str) => typeof str !== 'string' ? [] : str.split(';;').map(row => splitCols(row));
1034
+ const header = splitCols(headerStr);
1035
+ const parsedRows = rest.flatMap(splitRows);
1036
+ const maxLen = Math.max(header.length, ...parsedRows.map(r => r.length));
1037
+ const unified_rows = [
1038
+ { is_header: true, cells: [...header, ...Array(maxLen - header.length).fill('')] },
1039
+ ...parsedRows.map(cells => ({ is_header: false, cells: [...cells, ...Array(maxLen - cells.length).fill('')] }))
1040
+ ];
1041
+ const rows = unified_rows.map(r => ({ items: r.cells, ...(r.is_header ? { isHeading: true } : {}) }));
1042
+ return { title, rows, unified_rows };
1043
+ };
1044
+
1045
+ export const generateTableContentV2 = (table, quoted, options = {}) => {
1046
+ const { title, footer, headerText, text } = options;
1047
+ const { unified_rows } = toTableMetadataV2(table);
1048
+ const subs = [];
1049
+ const sections = [];
1050
+ if (headerText || title) sections.push({ view_model: { primitive: { text: headerText || title, __typename: 'GenAIMarkdownTextUXPrimitive' }, __typename: 'GenAISingleLayoutViewModel' } });
1051
+ if (text) sections.push({ view_model: { primitive: { text, __typename: 'GenAIMarkdownTextUXPrimitive' }, __typename: 'GenAISingleLayoutViewModel' } });
1052
+ sections.push({ view_model: { primitive: { rows: unified_rows, __typename: 'GenATableUXPrimitive' }, __typename: 'GenAISingleLayoutViewModel' } });
1053
+ if (footer) sections.push({ view_model: { primitive: { text: footer, __typename: 'GenAIMarkdownTextUXPrimitive' }, __typename: 'GenAISingleLayoutViewModel' } });
1054
+ // using randomUUID and randomBytes from top-level import
1055
+ const base64Data = Buffer.from(JSON.stringify({ response_id: randomUUID(), sections })).toString('base64');
1056
+ const ctxInfo = buildRichContextInfo(quoted);
1057
+ ctxInfo.forwardingScore = 2;
1058
+ ctxInfo.botMessageSharingInfo = { botEntryPointOrigin: 1, forwardScore: 2 };
1059
+ const content = {
1060
+ messageContextInfo: { threadId: [], deviceListMetadata: { senderKeyIndexes: [], recipientKeyIndexes: [], recipientKeyHash: '', recipientTimestamp: Math.floor(Date.now() / 1000) }, deviceListMetadataVersion: 2, messageSecret: randomBytes(32) },
1061
+ botForwardedMessage: { message: { richResponseMessage: { submessages: subs, messageType: 1, unifiedResponse: { data: base64Data }, contextInfo: ctxInfo } } }
1062
+ };
1063
+ return { message: content, messageId: generateMessageIDV2() };
1064
+ };
1065
+
1066
+ // ── Code Block ────────────────────────────────────────────
1067
+
1068
+ export const generateCodeBlockContent = (code, quoted, options = {}) => {
1069
+ const { title, footer, language = 'javascript' } = options;
1070
+ const subs = [];
1071
+ if (title) subs.push({ messageType: RichSubMessageType.TEXT, messageText: title });
1072
+ subs.push({ messageType: RichSubMessageType.CODE, codeMetadata: { codeLanguage: language, codeBlocks: tokenizeCode(code, language) } });
1073
+ if (footer) subs.push({ messageType: RichSubMessageType.TEXT, messageText: footer });
1074
+ return _wrapProtoToResult(subs, quoted);
1075
+ };
1076
+
1077
+ export const generateCodeBlockContentV2 = (code, quoted, options = {}) => {
1078
+ const { title, footer, language = 'javascript', text } = options;
1079
+ const { unified_codeBlock } = tokenizeCodeV2(code, language);
1080
+ const sections = [];
1081
+ if (text) sections.push({ view_model: { primitive: { text, __typename: 'GenAIMarkdownTextUXPrimitive' }, __typename: 'GenAISingleLayoutViewModel' } });
1082
+ sections.push({ view_model: { primitive: { language, code_blocks: unified_codeBlock, __typename: 'GenAICodeUXPrimitive' }, __typename: 'GenAISingleLayoutViewModel' } });
1083
+ if (footer) sections.push({ view_model: { primitive: { text: footer, __typename: 'GenAIMarkdownTextUXPrimitive' }, __typename: 'GenAISingleLayoutViewModel' } });
1084
+ // using randomUUID and randomBytes from top-level import
1085
+ const base64Data = Buffer.from(JSON.stringify({ response_id: randomUUID(), sections })).toString('base64');
1086
+ const ctxInfo = buildRichContextInfo(quoted);
1087
+ ctxInfo.forwardingScore = 2;
1088
+ ctxInfo.mentionedJid = [];
1089
+ ctxInfo.groupMentions = [];
1090
+ ctxInfo.statusAttributions = [];
1091
+ ctxInfo.botMessageSharingInfo = { botEntryPointOrigin: 1, forwardScore: 2 };
1092
+ const content = {
1093
+ messageContextInfo: { threadId: [], deviceListMetadata: { senderKeyIndexes: [], recipientKeyIndexes: [], recipientKeyHash: '', recipientTimestamp: Math.floor(Date.now() / 1000) }, deviceListMetadataVersion: 2, messageSecret: randomBytes(32) },
1094
+ botForwardedMessage: { message: { richResponseMessage: { submessages: [], messageType: 1, unifiedResponse: { data: base64Data }, contextInfo: ctxInfo } } }
1095
+ };
1096
+ return { message: content, messageId: generateMessageIDV2() };
1097
+ };
1098
+
1099
+ // ── Rich Message (generic) ────────────────────────────────
1100
+
1101
+ export const generateRichMessageContent = (submessages, quoted) => {
1102
+ return _wrapProtoToResult(submessages, quoted);
1103
+ };
1104
+
1105
+ export const generateUnifiedResponseContent = (quoted, captured) => {
1106
+ const richResponseMessage = proto.AIRichResponseMessage.create({
1107
+ submessages: captured.submessages,
1108
+ messageType: proto.AIRichResponseMessageType.AI_RICH_RESPONSE_TYPE_STANDARD,
1109
+ unifiedResponse: captured.unifiedResponse,
1110
+ contextInfo: buildRichContextInfo(quoted),
1111
+ });
1112
+ return { message: wrapToBotForwardedMessage(richResponseMessage), messageId: generateMessageIDV2() };
1113
+ };
1114
+
1115
+ export const captureUnifiedResponse = (msg) => {
1116
+ const botFwd = msg?.botForwardedMessage?.message;
1117
+ if (!botFwd) return null;
1118
+ const rich = botFwd.richResponseMessage;
1119
+ if (!rich?.unifiedResponse?.data) return null;
1120
+ return { unifiedResponse: { data: rich.unifiedResponse.data }, submessages: rich.submessages || [], contextInfo: rich.contextInfo || {} };
1121
+ };
1122
+
1123
+ // ── Link ──────────────────────────────────────────────────
1124
+
1125
+ export const generateLinkContent = (text, links, quoted, options = {}) => {
1126
+ const { footer, forwardingScore = 3, citations = [], proofs = [] } = options;
1127
+ const subs = [];
1128
+ const fullText = footer ? `${text}${footer}` : text;
1129
+ subs.push({ messageType: RichSubMessageType.TEXT, messageText: fullText });
1130
+ const sections = [];
1131
+ const inlineEntities = links.map((link, i) => {
1132
+ const url = typeof link === 'string' ? link : link.url;
1133
+ const displayName = typeof link === 'object' && link.displayName ? link.displayName : citations[i]?.sourceTitle || `Link ${i + 1}`;
1134
+ return { key: `IE_${i}`, metadata: { display_name: displayName, is_trusted: false, url, __typename: 'GenAIInlineLinkItem' } };
1135
+ });
1136
+ sections.push({ view_model: { primitive: { text, inline_entities: inlineEntities, __typename: 'GenAIMarkdownTextUXPrimitive' }, __typename: 'GenAISingleLayoutViewModel' } });
1137
+ if (footer) sections.push({ view_model: { primitive: { text: footer, __typename: 'GenAIMarkdownTextUXPrimitive' }, __typename: 'GenAISingleLayoutViewModel' } });
1138
+ // using randomUUID and randomBytes from top-level import
1139
+ const base64Data = Buffer.from(JSON.stringify({ response_id: randomUUID(), sections })).toString('base64');
1140
+ const ctxInfo = buildRichContextInfo(quoted);
1141
+ ctxInfo.forwardingScore = forwardingScore;
1142
+ ctxInfo.botMessageSharingInfo = { forwardScore: forwardingScore };
1143
+ const messageContextInfo = { messageSecret: randomBytes(32) };
1144
+ if (citations.length > 0 || proofs.length > 0) {
1145
+ const botMetadata = {};
1146
+ if (citations.length > 0) botMetadata.richResponseSourcesMetadata = { sources: citations.map((c, i) => ({ provider: 1, thumbnailCdnUrl: '', sourceProviderUrl: typeof links[i] === 'string' ? links[i] : links[i]?.url || '', sourceQuery: c.sourceQuery || '', faviconCdnUrl: c.faviconCdnUrl || '', citationNumber: c.citationNumber ?? i + 1, sourceTitle: c.sourceTitle || '' })) };
1147
+ if (proofs.length > 0) botMetadata.verificationMetadata = { proofs: proofs.map(p => ({ version: p.version || 1, useCase: p.useCase || 1, signature: p.signature || '', certificateChain: p.certificateChain || [] })) };
1148
+ messageContextInfo.botMetadata = botMetadata;
1149
+ }
1150
+ const content = { messageContextInfo, botForwardedMessage: { message: { richResponseMessage: { messageType: 1, submessages: subs, unifiedResponse: { data: base64Data }, contextInfo: ctxInfo } } } };
1151
+ return { message: content, messageId: generateMessageIDV2() };
1152
+ };
1153
+
1154
+ export const generateLinkContentV2 = (text, links, quoted, options = {}) => {
1155
+ const { footer, searchEngine = 'MAME' } = options;
1156
+ const subs = [];
1157
+ const fullText = footer ? `${text}${footer}` : text;
1158
+ subs.push({ messageType: RichSubMessageType.TEXT, messageText: fullText });
1159
+ const sections = [];
1160
+ const inlineEntities = links.map((link, i) => {
1161
+ const url = typeof link === 'string' ? link : link.url;
1162
+ const displayName = typeof link === 'object' && link.displayName ? link.displayName : `Link ${i + 1}`;
1163
+ const sourceDisplayName = typeof link === 'object' && link.sourceDisplayName ? link.sourceDisplayName : `Source ${i + 1}`;
1164
+ const sourceSubtitle = typeof link === 'object' && link.sourceSubtitle ? link.sourceSubtitle : '';
1165
+ return { key: `IE_${i}`, metadata: { reference_id: i + 1, reference_url: url, reference_title: displayName, reference_display_name: displayName, sources: [{ source_type: 'THIRD_PARTY', source_display_name: sourceDisplayName, source_subtitle: sourceSubtitle, source_url: url }], __typename: 'GenAISearchCitationItem' } };
1166
+ });
1167
+ sections.push({ view_model: { primitive: { text, inline_entities: inlineEntities, __typename: 'GenAIMarkdownTextUXPrimitive' }, __typename: 'GenAISingleLayoutViewModel' } });
1168
+ const searchSources = links.map((link, i) => {
1169
+ const url = typeof link === 'string' ? link : link.url;
1170
+ const sourceDisplayName = typeof link === 'object' && link.sourceDisplayName ? link.sourceDisplayName : `Source ${i + 1}`;
1171
+ const sourceSubtitle = typeof link === 'object' && link.sourceSubtitle ? link.sourceSubtitle : '';
1172
+ return { source_type: 'THIRD_PARTY', source_display_name: sourceDisplayName, source_subtitle: sourceSubtitle, source_url: url };
1173
+ });
1174
+ sections.push({ view_model: { primitive: { sources: searchSources, search_engine: searchEngine, __typename: 'GenAISearchResultPrimitive' }, __typename: 'GenAISingleLayoutViewModel' } });
1175
+ if (footer) sections.push({ view_model: { primitive: { text: footer, __typename: 'GenAIMarkdownTextUXPrimitive' }, __typename: 'GenAISingleLayoutViewModel' } });
1176
+ // using randomUUID and randomBytes from top-level import
1177
+ const base64Data = Buffer.from(JSON.stringify({ response_id: randomUUID(), sections })).toString('base64');
1178
+ const ctxInfo = { isForwarded: true, forwardOrigin: 4 };
1179
+ if (quoted?.key) { ctxInfo.participant = quoted.key.participant || quoted.sender || quoted.key.remoteJid; ctxInfo.quotedMessage = quoted.message; }
1180
+ const content = { messageContextInfo: { threadId: [], messageSecret: randomBytes(32) }, botForwardedMessage: { message: { richResponseMessage: { messageType: 1, submessages: subs, unifiedResponse: { data: base64Data }, contextInfo: ctxInfo } } } };
1181
+ return { message: content, messageId: generateMessageIDV2() };
1182
+ };
1183
+
1184
+ // ── LaTeX (3 varian, port dari baileys) ──────────────────
1185
+
1186
+ /**
1187
+ * generateLatexContent — kirim LaTeX dengan URL gambar yang sudah ada (pre-rendered).
1188
+ * Jika `expr.url` tidak diisi, otomatis di-generate via buildLatexUrl (codecogs).
1189
+ *
1190
+ * @param {object} quoted - pesan yang di-quote (boleh null)
1191
+ * @param {object} options - { text, expressions, headerText, footer }
1192
+ * expressions: Array<{ latexExpression, url?, width?, height?,
1193
+ * fontHeight?, imageTopPadding?, imageLeadingPadding?,
1194
+ * imageBottomPadding?, imageTrailingPadding? }>
1195
+ */
1196
+ export const generateLatexContent = (quoted, options) => {
1197
+ const { text, expressions, headerText, footer } = options;
1198
+ const subs = [];
1199
+ if (headerText) subs.push({ messageType: RichSubMessageType.TEXT, messageText: headerText });
1200
+ const latexExpressions = expressions.map((expr) => {
1201
+ const entry = {
1202
+ latexExpression: expr.latexExpression,
1203
+ url: expr.url || buildLatexUrl(expr.latexExpression),
1204
+ width: expr.width ?? 120,
1205
+ height: expr.height ?? 40,
1206
+ };
1207
+ if (expr.fontHeight !== undefined) entry.fontHeight = expr.fontHeight;
1208
+ if (expr.imageTopPadding !== undefined) entry.imageTopPadding = expr.imageTopPadding;
1209
+ if (expr.imageLeadingPadding !== undefined) entry.imageLeadingPadding = expr.imageLeadingPadding;
1210
+ if (expr.imageBottomPadding !== undefined) entry.imageBottomPadding = expr.imageBottomPadding;
1211
+ if (expr.imageTrailingPadding !== undefined) entry.imageTrailingPadding = expr.imageTrailingPadding;
1212
+ return entry;
1213
+ });
1214
+ subs.push({ messageType: RichSubMessageType.LATEX, latexMetadata: { text: text || '', expressions: latexExpressions } });
1215
+ if (footer) subs.push({ messageType: RichSubMessageType.TEXT, messageText: footer });
1216
+ return _wrapProtoToResult(subs, quoted);
1217
+ };
1218
+
1219
+ /**
1220
+ * generateLatexImageContent — render LaTeX ke PNG via renderLatexToPng,
1221
+ * upload via uploadFn, kirim sebagai LaTeX message dengan URL hasil upload.
1222
+ *
1223
+ * @param {object} quoted - pesan yang di-quote (boleh null)
1224
+ * @param {object} options - { text, expressions, headerText, footer }
1225
+ * @param {Function} uploadFn - async (buffer, type) => { url, directPath }
1226
+ * @param {Function} renderLatexToPng - async (latexExpression) => { buffer, width, height }
1227
+ */
1228
+ export const generateLatexImageContent = async (quoted, options, uploadFn, renderLatexToPng) => {
1229
+ const { text, expressions, headerText, footer } = options;
1230
+ const subs = [];
1231
+ if (headerText) subs.push({ messageType: RichSubMessageType.TEXT, messageText: headerText });
1232
+ const latexExpressions = await Promise.all(
1233
+ expressions.map(async (expr) => {
1234
+ const { buffer, width, height } = await renderLatexToPng(expr.latexExpression);
1235
+ const uploadResult = await uploadFn(buffer, 'image');
1236
+ const imageUrl = uploadResult.url || uploadResult.directPath;
1237
+ return { latexExpression: expr.latexExpression, url: imageUrl, width, height };
1238
+ }),
1239
+ );
1240
+ subs.push({ messageType: RichSubMessageType.LATEX, latexMetadata: { text: text || '', expressions: latexExpressions } });
1241
+ if (footer) subs.push({ messageType: RichSubMessageType.TEXT, messageText: footer });
1242
+ return _wrapProtoToResult(subs, quoted);
1243
+ };
1244
+
1245
+ /**
1246
+ * generateLatexInlineImageContent — render LaTeX ke PNG, upload, kirim sebagai
1247
+ * deretan INLINE_IMAGE (satu per expression). Fallback untuk klien tanpa LaTeX native.
1248
+ *
1249
+ * @param {object} quoted - pesan yang di-quote (boleh null)
1250
+ * @param {object} options - { text, expressions, headerText, footer }
1251
+ * @param {Function} uploadFn - async (buffer, type) => { url, directPath }
1252
+ * @param {Function} renderLatexToPng - async (latexExpression) => { buffer, width, height }
1253
+ */
1254
+ export const generateLatexInlineImageContent = async (quoted, options, uploadFn, renderLatexToPng) => {
1255
+ const { text, expressions, headerText, footer } = options;
1256
+ const subs = [];
1257
+ if (headerText) subs.push({ messageType: RichSubMessageType.TEXT, messageText: headerText });
1258
+ if (text) subs.push({ messageType: RichSubMessageType.TEXT, messageText: text });
1259
+ for (const expr of expressions) {
1260
+ const { buffer, width, height } = await renderLatexToPng(expr.latexExpression);
1261
+ const uploadResult = await uploadFn(buffer, 'image');
1262
+ const imageUrl = uploadResult.url || uploadResult.directPath;
1263
+ subs.push({
1264
+ messageType: RichSubMessageType.INLINE_IMAGE,
1265
+ imageMetadata: {
1266
+ imageUrl: { imagePreviewUrl: imageUrl, imageHighResUrl: imageUrl },
1267
+ imageText: expr.latexExpression,
1268
+ alignment: 2,
1269
+ },
1270
+ });
1271
+ }
1272
+ if (footer) subs.push({ messageType: RichSubMessageType.TEXT, messageText: footer });
1273
+ return _wrapProtoToResult(subs, quoted);
1274
+ };
1275
+
1276
+ // ── tokenizeCodeV2 (dipakai oleh generateCodeBlockContentV2) ─
1277
+
1278
+ export const tokenizeCodeV2 = (code, language = 'javascript') => {
1279
+ const keywords = LANGUAGE_KEYWORDS[language] || LANGUAGE_KEYWORDS['javascript'] || new Set();
1280
+ const tokens = [];
1281
+ let i = 0;
1282
+ const n = code.length;
1283
+ const push = (codeContent, highlightType) => {
1284
+ if (!codeContent) return;
1285
+ const last = tokens[tokens.length - 1];
1286
+ if (last && last.highlightType === highlightType) last.codeContent += codeContent;
1287
+ else tokens.push({ codeContent, highlightType });
1288
+ };
1289
+ const isWordStart = (c) => /[a-zA-Z_$]/.test(c);
1290
+ const isWord = (c) => /[a-zA-Z0-9_$]/.test(c);
1291
+ const isNum = (c) => /[0-9]/.test(c);
1292
+ const HIGHLIGHT_TYPE_MAP = { 0: 'DEFAULT', 1: 'KEYWORD', 2: 'METHOD', 3: 'STR', 4: 'NUMBER', 5: 'COMMENT' };
1293
+ const isPyBash = ['python','py','bash','sh','shell'].includes(language);
1294
+ while (i < n) {
1295
+ const c = code[i];
1296
+ if (/\s/.test(c)) {
1297
+ let s = i; while (i < n && /\s/.test(code[i])) i++;
1298
+ push(code.slice(s, i), 0); continue;
1299
+ }
1300
+ if (c === '/' && code[i + 1] === '/') {
1301
+ let s = i; i += 2; while (i < n && code[i] !== '\n') i++;
1302
+ push(code.slice(s, i), 5); continue;
1303
+ }
1304
+ if (c === '/' && code[i + 1] === '*') {
1305
+ let s = i; i += 2;
1306
+ while (i < n - 1 && !(code[i] === '*' && code[i + 1] === '/')) i++;
1307
+ i += 2; push(code.slice(s, i), 5); continue;
1308
+ }
1309
+ if (c === '#' && isPyBash) {
1310
+ let s = i; i++; while (i < n && code[i] !== '\n') i++;
1311
+ push(code.slice(s, i), 5); continue;
1312
+ }
1313
+ if (c === '"' || c === "'" || c === '`') {
1314
+ let s = i; const q = c; i++;
1315
+ while (i < n) { if (code[i] === '\\' && i + 1 < n) i += 2; else if (code[i] === q) { i++; break; } else i++; }
1316
+ push(code.slice(s, i), 3); continue;
1317
+ }
1318
+ if (isNum(c)) {
1319
+ let s = i; while (i < n && /[0-9.xXa-fA-FeEbBoO_]/.test(code[i])) i++;
1320
+ push(code.slice(s, i), 4); continue;
1321
+ }
1322
+ if (isWordStart(c)) {
1323
+ let s = i; while (i < n && isWord(code[i])) i++;
1324
+ const word = code.slice(s, i);
1325
+ let type = 0;
1326
+ if (keywords.has(word)) type = 1;
1327
+ else { let j = i; while (j < n && /\s/.test(code[j])) j++; if (code[j] === '(') type = 2; }
1328
+ push(word, type); continue;
1329
+ }
1330
+ push(c, 0); i++;
843
1331
  }
844
- }
845
- exports.prepareRichResponseMessage = prepareRichResponseMessage
1332
+ return {
1333
+ codeBlock: tokens,
1334
+ unified_codeBlock: tokens.map(t => ({ content: t.codeContent, type: HIGHLIGHT_TYPE_MAP[t.highlightType] || 'DEFAULT' }))
1335
+ };
1336
+ };
1337
+
1338
+ /* Re-export LANGUAGE_KEYWORDS dari WABinary/constants.js agar kompatibel dengan baileys export */
1339
+ export { LANGUAGE_KEYWORDS } from '../WABinary/constants.js';
1340
+
1341
+ //# sourceMappingURL=rich-message-utils.js.map