@xbibzlibrary/whatsbibz 1.3.0

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 (260) hide show
  1. package/CHANGELOG.md +93 -0
  2. package/LICENSE +22 -0
  3. package/LICENSE.upstream +21 -0
  4. package/README.md +280 -0
  5. package/VERIFIKASI-IDENTITAS-2026-09-03.md +138 -0
  6. package/WAProto/GenerateStatics.sh +3 -0
  7. package/WAProto/WAProto.proto +6035 -0
  8. package/WAProto/fix-imports.js +81 -0
  9. package/WAProto/index.d.ts +15314 -0
  10. package/WAProto/index.js +132326 -0
  11. package/assets/logo/README.md +21 -0
  12. package/assets/logo/png/banner-1200x360.png +0 -0
  13. package/assets/logo/png/icon-1024.png +0 -0
  14. package/assets/logo/png/icon-128.png +0 -0
  15. package/assets/logo/png/icon-16.png +0 -0
  16. package/assets/logo/png/icon-24.png +0 -0
  17. package/assets/logo/png/icon-256.png +0 -0
  18. package/assets/logo/png/icon-32.png +0 -0
  19. package/assets/logo/png/icon-48.png +0 -0
  20. package/assets/logo/png/icon-512.png +0 -0
  21. package/assets/logo/png/icon-64.png +0 -0
  22. package/assets/logo/png/mark-512.png +0 -0
  23. package/assets/logo/preview.png +0 -0
  24. package/assets/logo/whatsbibz.ico +0 -0
  25. package/lib/BibzWhats/client.d.ts +95 -0
  26. package/lib/BibzWhats/client.js +501 -0
  27. package/lib/BibzWhats/device-identity.d.ts +60 -0
  28. package/lib/BibzWhats/device-identity.js +234 -0
  29. package/lib/BibzWhats/extract.d.ts +29 -0
  30. package/lib/BibzWhats/extract.js +115 -0
  31. package/lib/BibzWhats/index.d.ts +7 -0
  32. package/lib/BibzWhats/index.js +8 -0
  33. package/lib/BibzWhats/jid.d.ts +22 -0
  34. package/lib/BibzWhats/jid.js +98 -0
  35. package/lib/BibzWhats/pairing.d.ts +35 -0
  36. package/lib/BibzWhats/pairing.js +186 -0
  37. package/lib/BibzWhats/send.d.ts +9 -0
  38. package/lib/BibzWhats/send.js +107 -0
  39. package/lib/BibzWhats/version.d.ts +6 -0
  40. package/lib/BibzWhats/version.js +7 -0
  41. package/lib/Defaults/index.d.ts +73 -0
  42. package/lib/Defaults/index.js +141 -0
  43. package/lib/Modded/message_builder.d.ts +15 -0
  44. package/lib/Modded/message_builder.js +2330 -0
  45. package/lib/Signal/Group/ciphertext-message.d.ts +9 -0
  46. package/lib/Signal/Group/ciphertext-message.js +11 -0
  47. package/lib/Signal/Group/group-session-builder.d.ts +14 -0
  48. package/lib/Signal/Group/group-session-builder.js +29 -0
  49. package/lib/Signal/Group/group_cipher.d.ts +16 -0
  50. package/lib/Signal/Group/group_cipher.js +81 -0
  51. package/lib/Signal/Group/index.d.ts +11 -0
  52. package/lib/Signal/Group/index.js +11 -0
  53. package/lib/Signal/Group/keyhelper.d.ts +10 -0
  54. package/lib/Signal/Group/keyhelper.js +17 -0
  55. package/lib/Signal/Group/sender-chain-key.d.ts +13 -0
  56. package/lib/Signal/Group/sender-chain-key.js +25 -0
  57. package/lib/Signal/Group/sender-key-distribution-message.d.ts +16 -0
  58. package/lib/Signal/Group/sender-key-distribution-message.js +62 -0
  59. package/lib/Signal/Group/sender-key-message.d.ts +18 -0
  60. package/lib/Signal/Group/sender-key-message.js +65 -0
  61. package/lib/Signal/Group/sender-key-name.d.ts +17 -0
  62. package/lib/Signal/Group/sender-key-name.js +47 -0
  63. package/lib/Signal/Group/sender-key-record.d.ts +30 -0
  64. package/lib/Signal/Group/sender-key-record.js +40 -0
  65. package/lib/Signal/Group/sender-key-state.d.ts +38 -0
  66. package/lib/Signal/Group/sender-key-state.js +83 -0
  67. package/lib/Signal/Group/sender-message-key.d.ts +11 -0
  68. package/lib/Signal/Group/sender-message-key.js +25 -0
  69. package/lib/Signal/libsignal.d.ts +4 -0
  70. package/lib/Signal/libsignal.js +406 -0
  71. package/lib/Signal/lid-mapping.d.ts +18 -0
  72. package/lib/Signal/lid-mapping.js +276 -0
  73. package/lib/Socket/Client/index.d.ts +2 -0
  74. package/lib/Socket/Client/index.js +2 -0
  75. package/lib/Socket/Client/types.d.ts +15 -0
  76. package/lib/Socket/Client/types.js +10 -0
  77. package/lib/Socket/Client/websocket.d.ts +12 -0
  78. package/lib/Socket/Client/websocket.js +53 -0
  79. package/lib/Socket/business.d.ts +537 -0
  80. package/lib/Socket/business.js +421 -0
  81. package/lib/Socket/chats.d.ts +110 -0
  82. package/lib/Socket/chats.js +1006 -0
  83. package/lib/Socket/communities.d.ts +646 -0
  84. package/lib/Socket/communities.js +430 -0
  85. package/lib/Socket/engine.d.ts +129 -0
  86. package/lib/Socket/engine.js +767 -0
  87. package/lib/Socket/groups.d.ts +149 -0
  88. package/lib/Socket/groups.js +326 -0
  89. package/lib/Socket/index.d.ts +637 -0
  90. package/lib/Socket/index.js +14 -0
  91. package/lib/Socket/messages-recv.d.ts +239 -0
  92. package/lib/Socket/messages-recv.js +1307 -0
  93. package/lib/Socket/messages-send.d.ts +580 -0
  94. package/lib/Socket/messages-send.js +1639 -0
  95. package/lib/Socket/mex.d.ts +2 -0
  96. package/lib/Socket/mex.js +47 -0
  97. package/lib/Socket/newsletter.d.ts +176 -0
  98. package/lib/Socket/newsletter.js +456 -0
  99. package/lib/Socket/socket.d.ts +56 -0
  100. package/lib/Socket/socket.js +998 -0
  101. package/lib/Types/Auth.d.ts +115 -0
  102. package/lib/Types/Auth.js +1 -0
  103. package/lib/Types/Bussines.d.ts +36 -0
  104. package/lib/Types/Bussines.js +1 -0
  105. package/lib/Types/Call.d.ts +14 -0
  106. package/lib/Types/Call.js +1 -0
  107. package/lib/Types/Chat.d.ts +124 -0
  108. package/lib/Types/Chat.js +7 -0
  109. package/lib/Types/Contact.d.ts +23 -0
  110. package/lib/Types/Contact.js +1 -0
  111. package/lib/Types/Events.d.ts +241 -0
  112. package/lib/Types/Events.js +1 -0
  113. package/lib/Types/GroupMetadata.d.ts +67 -0
  114. package/lib/Types/GroupMetadata.js +1 -0
  115. package/lib/Types/Label.d.ts +46 -0
  116. package/lib/Types/Label.js +24 -0
  117. package/lib/Types/LabelAssociation.d.ts +29 -0
  118. package/lib/Types/LabelAssociation.js +6 -0
  119. package/lib/Types/Message.d.ts +427 -0
  120. package/lib/Types/Message.js +10 -0
  121. package/lib/Types/Newsletter.d.ts +134 -0
  122. package/lib/Types/Newsletter.js +30 -0
  123. package/lib/Types/Product.d.ts +78 -0
  124. package/lib/Types/Product.js +1 -0
  125. package/lib/Types/Signal.d.ts +77 -0
  126. package/lib/Types/Signal.js +1 -0
  127. package/lib/Types/Socket.d.ts +173 -0
  128. package/lib/Types/Socket.js +2 -0
  129. package/lib/Types/State.d.ts +38 -0
  130. package/lib/Types/State.js +12 -0
  131. package/lib/Types/USync.d.ts +25 -0
  132. package/lib/Types/USync.js +1 -0
  133. package/lib/Types/index.d.ts +75 -0
  134. package/lib/Types/index.js +32 -0
  135. package/lib/Utils/auth-utils.d.ts +18 -0
  136. package/lib/Utils/auth-utils.js +289 -0
  137. package/lib/Utils/browser-utils.d.ts +3 -0
  138. package/lib/Utils/browser-utils.js +47 -0
  139. package/lib/Utils/business.d.ts +22 -0
  140. package/lib/Utils/business.js +230 -0
  141. package/lib/Utils/chat-utils.d.ts +69 -0
  142. package/lib/Utils/chat-utils.js +811 -0
  143. package/lib/Utils/companion-reg-client-utils.d.ts +20 -0
  144. package/lib/Utils/companion-reg-client-utils.js +66 -0
  145. package/lib/Utils/crypto.d.ts +41 -0
  146. package/lib/Utils/crypto.js +117 -0
  147. package/lib/Utils/decode-wa-message.d.ts +47 -0
  148. package/lib/Utils/decode-wa-message.js +282 -0
  149. package/lib/Utils/event-buffer.d.ts +35 -0
  150. package/lib/Utils/event-buffer.js +590 -0
  151. package/lib/Utils/generics.d.ts +90 -0
  152. package/lib/Utils/generics.js +384 -0
  153. package/lib/Utils/history.d.ts +21 -0
  154. package/lib/Utils/history.js +130 -0
  155. package/lib/Utils/identity-change-handler.d.ts +36 -0
  156. package/lib/Utils/identity-change-handler.js +48 -0
  157. package/lib/Utils/index.d.ts +25 -0
  158. package/lib/Utils/index.js +24 -0
  159. package/lib/Utils/link-preview.d.ts +20 -0
  160. package/lib/Utils/link-preview.js +84 -0
  161. package/lib/Utils/logger.d.ts +12 -0
  162. package/lib/Utils/logger.js +2 -0
  163. package/lib/Utils/lt-hash.d.ts +10 -0
  164. package/lib/Utils/lt-hash.js +7 -0
  165. package/lib/Utils/make-mutex.d.ts +8 -0
  166. package/lib/Utils/make-mutex.js +32 -0
  167. package/lib/Utils/message-retry-manager.d.ts +109 -0
  168. package/lib/Utils/message-retry-manager.js +224 -0
  169. package/lib/Utils/messages-media.d.ts +129 -0
  170. package/lib/Utils/messages-media.js +784 -0
  171. package/lib/Utils/messages.d.ts +90 -0
  172. package/lib/Utils/messages.js +1240 -0
  173. package/lib/Utils/noise-handler.d.ts +19 -0
  174. package/lib/Utils/noise-handler.js +200 -0
  175. package/lib/Utils/offline-node-processor.d.ts +16 -0
  176. package/lib/Utils/offline-node-processor.js +39 -0
  177. package/lib/Utils/platform-identity.d.ts +14 -0
  178. package/lib/Utils/platform-identity.js +148 -0
  179. package/lib/Utils/pre-key-manager.d.ts +27 -0
  180. package/lib/Utils/pre-key-manager.js +105 -0
  181. package/lib/Utils/process-message.d.ts +59 -0
  182. package/lib/Utils/process-message.js +544 -0
  183. package/lib/Utils/reporting-utils.d.ts +10 -0
  184. package/lib/Utils/reporting-utils.js +257 -0
  185. package/lib/Utils/rich-messages.d.ts +276 -0
  186. package/lib/Utils/rich-messages.js +1143 -0
  187. package/lib/Utils/signal.d.ts +33 -0
  188. package/lib/Utils/signal.js +158 -0
  189. package/lib/Utils/stanza-ack.d.ts +10 -0
  190. package/lib/Utils/stanza-ack.js +37 -0
  191. package/lib/Utils/sticker-pack.d.ts +10 -0
  192. package/lib/Utils/sticker-pack.js +111 -0
  193. package/lib/Utils/sync-action-utils.d.ts +18 -0
  194. package/lib/Utils/sync-action-utils.js +47 -0
  195. package/lib/Utils/tc-token-utils.d.ts +8 -0
  196. package/lib/Utils/tc-token-utils.js +45 -0
  197. package/lib/Utils/use-multi-file-auth-state.d.ts +12 -0
  198. package/lib/Utils/use-multi-file-auth-state.js +120 -0
  199. package/lib/Utils/validate-connection.d.ts +10 -0
  200. package/lib/Utils/validate-connection.js +222 -0
  201. package/lib/VoIP/audio-feeder.d.ts +15 -0
  202. package/lib/VoIP/audio-feeder.js +136 -0
  203. package/lib/VoIP/index.d.ts +12 -0
  204. package/lib/VoIP/index.js +282 -0
  205. package/lib/VoIP/relay-transport.d.ts +43 -0
  206. package/lib/VoIP/relay-transport.js +559 -0
  207. package/lib/VoIP/signaling.js +603 -0
  208. package/lib/VoIP/types.d.ts +69 -0
  209. package/lib/VoIP/types.js +17 -0
  210. package/lib/VoIP/wasm-engine.d.ts +103 -0
  211. package/lib/VoIP/wasm-engine.js +1214 -0
  212. package/lib/VoIP/worker-bootstrap.js +1042 -0
  213. package/lib/WABinary/constants.d.ts +27 -0
  214. package/lib/WABinary/constants.js +1300 -0
  215. package/lib/WABinary/decode.d.ts +6 -0
  216. package/lib/WABinary/decode.js +261 -0
  217. package/lib/WABinary/encode.d.ts +2 -0
  218. package/lib/WABinary/encode.js +219 -0
  219. package/lib/WABinary/generic-utils.d.ts +16 -0
  220. package/lib/WABinary/generic-utils.js +190 -0
  221. package/lib/WABinary/index.d.ts +5 -0
  222. package/lib/WABinary/index.js +5 -0
  223. package/lib/WABinary/jid-utils.d.ts +47 -0
  224. package/lib/WABinary/jid-utils.js +95 -0
  225. package/lib/WABinary/types.d.ts +18 -0
  226. package/lib/WABinary/types.js +1 -0
  227. package/lib/WAM/BinaryInfo.d.ts +8 -0
  228. package/lib/WAM/BinaryInfo.js +9 -0
  229. package/lib/WAM/constants.d.ts +39 -0
  230. package/lib/WAM/constants.js +22852 -0
  231. package/lib/WAM/encode.d.ts +2 -0
  232. package/lib/WAM/encode.js +149 -0
  233. package/lib/WAM/index.d.ts +3 -0
  234. package/lib/WAM/index.js +3 -0
  235. package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts +9 -0
  236. package/lib/WAUSync/Protocols/USyncContactProtocol.js +28 -0
  237. package/lib/WAUSync/Protocols/USyncDeviceProtocol.d.ts +22 -0
  238. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +53 -0
  239. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts +12 -0
  240. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +26 -0
  241. package/lib/WAUSync/Protocols/USyncStatusProtocol.d.ts +12 -0
  242. package/lib/WAUSync/Protocols/USyncStatusProtocol.js +37 -0
  243. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.d.ts +25 -0
  244. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +50 -0
  245. package/lib/WAUSync/Protocols/UsyncLIDProtocol.d.ts +9 -0
  246. package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +28 -0
  247. package/lib/WAUSync/Protocols/index.d.ts +4 -0
  248. package/lib/WAUSync/Protocols/index.js +4 -0
  249. package/lib/WAUSync/USyncQuery.d.ts +28 -0
  250. package/lib/WAUSync/USyncQuery.js +93 -0
  251. package/lib/WAUSync/USyncUser.d.ts +12 -0
  252. package/lib/WAUSync/USyncUser.js +22 -0
  253. package/lib/WAUSync/index.d.ts +3 -0
  254. package/lib/WAUSync/index.js +3 -0
  255. package/lib/assets/wasm/loader.js +5 -0
  256. package/lib/assets/wasm/whatsapp.wasm +0 -0
  257. package/lib/assets/wasm/worker-modules.js +273 -0
  258. package/lib/index.d.ts +21 -0
  259. package/lib/index.js +22 -0
  260. package/package.json +111 -0
@@ -0,0 +1,2330 @@
1
+ /**
2
+ * Do not remove this watermark.
3
+ *
4
+ * NIXCODE - Advanced WhatsApp Interactive Message Builder
5
+ * Built for creating buttons, carousels, native flows,
6
+ * and AI rich response payloads using BibzWhats with
7
+ * fluent chaining, flexible payload customization,
8
+ * and scalable architecture for modern bot development.
9
+ *
10
+ * Runtime:
11
+ * - BibzWhats (fork Baileys)
12
+ *
13
+ * Created by Nixel
14
+ * Contributors: ~ Ahmad tumbuh kembang
15
+ *
16
+ * WhatsApp: wa.me/6285188349341
17
+ * Channel: https://whatsapp.com/channel/0029VbCV1ck8fewpdNb2TY2k
18
+ *
19
+ * Copyright (c) 2026 Nixel
20
+ *
21
+ * Permission is granted to use and modify this library
22
+ * for personal or commercial projects.
23
+ *
24
+ * Reuploading, reselling, relicensing, or redistributing
25
+ * this library as a standalone product is prohibited.
26
+ *
27
+ * Do not claim this project as your own original work.
28
+ */
29
+
30
+ 'use strict';
31
+
32
+ const VERSION = '4.6';
33
+
34
+ import { generateWAMessageFromContent, prepareWAMessageMedia } from '../index.js';
35
+ import crypto from 'crypto';
36
+ import { PassThrough, Readable } from 'stream';
37
+
38
+ let sharp, ffmpeg;
39
+ try {
40
+ sharp = (await import('sharp')).default;
41
+ } catch {
42
+ console.warn('⚠️ [BibzWhats] WARNING: Module "sharp" is not installed. Image resizing & processing may not work.\n👉 Please run: npm install sharp');
43
+ }
44
+
45
+ try {
46
+ ffmpeg = (await import('fluent-ffmpeg')).default;
47
+ } catch {
48
+ console.warn('⚠️ [BibzWhats] WARNING: Module "fluent-ffmpeg" is not installed. Video previews may not work.\n👉 Please run: npm install fluent-ffmpeg');
49
+ }
50
+
51
+ function extractIE(text, { extract = true, hyperlink = true, citation = true, latex = true } = {}) {
52
+ if (!extract) {
53
+ return {
54
+ text,
55
+ ie: [],
56
+ inline_entities: [],
57
+ };
58
+ }
59
+
60
+ const createIE = (type, ie) => {
61
+ if (type == 'hyperlink') {
62
+ return {
63
+ key: ie.key,
64
+ metadata: {
65
+ display_name: ie.text,
66
+ is_trusted: ie.is_trusted,
67
+ url: ie.url,
68
+ __typename: 'GenAIInlineLinkItem',
69
+ },
70
+ };
71
+ }
72
+
73
+ if (type == 'citation') {
74
+ return {
75
+ key: ie.key,
76
+ metadata: {
77
+ reference_id: ie.reference_id,
78
+ reference_url: ie.url,
79
+ reference_title: ie.url,
80
+ reference_display_name: ie.url,
81
+ sources: [],
82
+ __typename: 'GenAISearchCitationItem',
83
+ },
84
+ };
85
+ }
86
+
87
+ if (type == 'latex') {
88
+ return {
89
+ key: ie.key,
90
+ metadata: {
91
+ latex_expression: ie.text,
92
+ latex_image: {
93
+ url: ie.url,
94
+ width: Number(ie.width) || 100,
95
+ height: Number(ie.height) || 100,
96
+ },
97
+ font_height: Number(ie.font_height) || 83.333333333333,
98
+ padding: Number(ie.padding) || 15,
99
+ __typename: 'GenAILatexItem',
100
+ },
101
+ };
102
+ }
103
+ };
104
+
105
+ let ie = [];
106
+ let inline_entities = [];
107
+ let result = '';
108
+ let last = 0;
109
+ let citation_index = 1;
110
+ let hyperlink_index = 0;
111
+ let latex_index = 0;
112
+ let stack = [];
113
+
114
+ for (let i = 0; i < text.length; i++) {
115
+ if (text[i] == '[' && text[i - 1] != '\\') {
116
+ stack.push(i);
117
+ } else if (text[i] == ']' && (text[i + 1] == '(' || text[i + 1] == '<')) {
118
+ let start = stack.pop();
119
+
120
+ if (start == null) continue;
121
+
122
+ let open = text[i + 1];
123
+ let close = open == '(' ? ')' : '>';
124
+ let type = open == '(' ? 'link' : 'latex';
125
+ let end = i + 2;
126
+ let depth = 1;
127
+
128
+ while (end < text.length && depth) {
129
+ if (text[end] == open && text[end - 1] != '\\') depth++;
130
+ else if (text[end] == close && text[end - 1] != '\\') depth--;
131
+ end++;
132
+ }
133
+
134
+ if (depth) continue;
135
+
136
+ let raw = text.slice(start + 1, i).trim();
137
+ let url = text.slice(i + 2, end - 1).trim();
138
+
139
+ let key;
140
+ let tag;
141
+ let data;
142
+
143
+ if (type == 'latex') {
144
+ if (!latex) continue;
145
+
146
+ let [txt = '', width = null, height = null, font_height = null, padding = null] = raw.split('|');
147
+
148
+ key = `\u004E\u0049\u0058\u0045\u004C_LATEX_${latex_index++}`;
149
+ tag = `{{${key}}}${txt || 'image'}{{/${key}}}`;
150
+
151
+ data = {
152
+ type: 'latex',
153
+ ie: {
154
+ key,
155
+ text: txt,
156
+ url,
157
+ width,
158
+ height,
159
+ font_height,
160
+ padding,
161
+ },
162
+ };
163
+ } else if (raw) {
164
+ if (!hyperlink) continue;
165
+
166
+ const trusted = !url.startsWith('!');
167
+
168
+ if (!trusted) {
169
+ url = url.slice(1);
170
+ }
171
+
172
+ key = `\u004E\u0049\u0058\u0045\u004C_HYPERLINK_${hyperlink_index++}`;
173
+ tag = `{{${key}}}${url}{{/${key}}}`;
174
+
175
+ data = {
176
+ type: 'hyperlink',
177
+ ie: {
178
+ key,
179
+ text: raw,
180
+ url,
181
+ is_trusted: trusted,
182
+ },
183
+ };
184
+ } else {
185
+ if (!citation) continue;
186
+
187
+ key = `\u004E\u0049\u0058\u0045\u004C_CITATION_${citation_index - 1}`;
188
+ tag = `{{${key}}}${url}{{/${key}}}`;
189
+
190
+ data = {
191
+ type: 'citation',
192
+ ie: {
193
+ reference_id: citation_index++,
194
+ key,
195
+ text: '',
196
+ url,
197
+ },
198
+ };
199
+ }
200
+
201
+ result += text.slice(last, start) + tag;
202
+ last = end;
203
+
204
+ ie.push(data);
205
+
206
+ const entity = createIE(data.type, data.ie);
207
+
208
+ if (entity) {
209
+ inline_entities.push(entity);
210
+ }
211
+
212
+ i = end - 1;
213
+ }
214
+ }
215
+
216
+ result += text.slice(last);
217
+
218
+ return {
219
+ text: result,
220
+ ie,
221
+ inline_entities,
222
+ };
223
+ }
224
+
225
+ async function waitAllPromises(input) {
226
+ const isPromise = (v) => v && typeof v.then === 'function';
227
+ const isObject = (v) => v && typeof v === 'object';
228
+
229
+ const deep = async (v) => {
230
+ if (isPromise(v)) return deep(await v);
231
+ if (Array.isArray(v)) return Promise.all(v.map(deep));
232
+ if (isObject(v)) {
233
+ const entries = await Promise.all(Object.entries(v).map(async ([k, val]) => [k, await deep(val)]));
234
+ return Object.fromEntries(entries);
235
+ }
236
+ return v;
237
+ };
238
+
239
+ return deep(await input);
240
+ }
241
+
242
+ class Toolkit {
243
+ constructor() { }
244
+
245
+ static extractIE(text, { extract = true, hyperlink = true, citation = true, latex = true } = {}) {
246
+ return extractIE(text, { extract, hyperlink, citation, latex });
247
+ }
248
+
249
+ static async resize(buffer, x, y, fit = 'cover') {
250
+ return await sharp(buffer)
251
+ .resize(x, y, {
252
+ fit,
253
+ position: 'center',
254
+ background: { r: 0, g: 0, b: 0, alpha: 0 },
255
+ })
256
+ .png()
257
+ .toBuffer();
258
+ }
259
+
260
+ static async waitAllPromises(input) {
261
+ return await waitAllPromises(input);
262
+ }
263
+
264
+ static async fetchBuffer(url, options = {}, { silent = true } = {}) {
265
+ try {
266
+ let response = await fetch(url, options);
267
+ if (!response.ok) throw Error(`HTTP ${response.status}`);
268
+ return Buffer.from(await response.arrayBuffer());
269
+ } catch (error) {
270
+ if (silent) return Buffer.alloc(0);
271
+ throw error;
272
+ }
273
+ }
274
+
275
+ static async toUrl(_client, path, mediaType = 'document') {
276
+ if (!path) throw new Error('Url or buffer needed');
277
+
278
+ const media = await prepareWAMessageMedia(
279
+ {
280
+ [mediaType]: Buffer.isBuffer(path) ? path : { url: path },
281
+ },
282
+ {
283
+ upload: _client.waUploadToServer,
284
+ jid: '\u0040\u006e\u0065\u0077\u0073\u006c\u0065\u0074\u0074\u0065\u0072',
285
+ }
286
+ );
287
+
288
+ return Object.values(media)[0]?.url;
289
+ }
290
+
291
+ static async resolveMedia(_client, media, mediaType = 'image', { resolveUrl = false, resolveWAUrl = false, result = 'url', resize = false, width = 300, height = 300 } = {}) {
292
+ const isUrl = (str) => /^https?:\/\/.+/i.test(str);
293
+
294
+ const isWAUrl = (str) => /^https?:\/\/[^/]*\.whatsapp\.net\//i.test(str);
295
+
296
+ if (Array.isArray(media)) {
297
+ return Promise.all(
298
+ media.map((item) =>
299
+ Toolkit.resolveMedia(_client, item, mediaType, {
300
+ resolveUrl,
301
+ resolveWAUrl,
302
+ result,
303
+ resize,
304
+ width,
305
+ height,
306
+ })
307
+ )
308
+ );
309
+ }
310
+
311
+ const originalIsBuffer = Buffer.isBuffer(media);
312
+
313
+ if (typeof media === 'string' && isUrl(media)) {
314
+ if (isWAUrl(media)) {
315
+ if (resolveWAUrl) {
316
+ media = await Toolkit.fetchBuffer(media, {}, { silent: true });
317
+ } else if (!resolveUrl) {
318
+ if (result === 'url') return media;
319
+
320
+ media = await Toolkit.fetchBuffer(media, {}, { silent: true });
321
+ }
322
+ } else {
323
+ if (!resolveUrl) {
324
+ if (result === 'url') return media;
325
+
326
+ media = await Toolkit.fetchBuffer(media, {}, { silent: true });
327
+ } else {
328
+ media = await Toolkit.fetchBuffer(media, {}, { silent: true });
329
+ }
330
+ }
331
+ }
332
+
333
+ if (typeof media === 'string' && !isUrl(media)) {
334
+ media = Buffer.from(media, 'base64');
335
+ }
336
+
337
+ if (!Buffer.isBuffer(media) || !media.length) {
338
+ return;
339
+ }
340
+
341
+ if (resize && Buffer.isBuffer(media)) {
342
+ media = await Toolkit.resize(media, width, height);
343
+ }
344
+
345
+ if (result === 'buffer') {
346
+ return media;
347
+ }
348
+
349
+ if (result === 'base64') {
350
+ return media.toString('base64');
351
+ }
352
+
353
+ if (originalIsBuffer) {
354
+ return Toolkit.toUrl(_client, media, mediaType);
355
+ }
356
+
357
+ return Toolkit.toUrl(_client, media, mediaType);
358
+ }
359
+
360
+ static getMp4Duration(buffer, { silent = true } = {}) {
361
+ try {
362
+ if (!Buffer.isBuffer(buffer) || buffer.length < 8) {
363
+ if (silent) return 0;
364
+ throw new Error('Invalid buffer');
365
+ }
366
+
367
+ let offset = 0;
368
+
369
+ while (offset < buffer.length - 8) {
370
+ const size = buffer.readUInt32BE(offset);
371
+
372
+ if (size < 8 || offset + size > buffer.length) {
373
+ if (silent) return 0;
374
+ throw new Error('Invalid atom size');
375
+ }
376
+
377
+ const type = buffer.toString('ascii', offset + 4, offset + 8);
378
+
379
+ if (type === 'moov') {
380
+ let moovOffset = offset + 8;
381
+ const moovEnd = offset + size;
382
+
383
+ while (moovOffset < moovEnd - 8) {
384
+ const childSize = buffer.readUInt32BE(moovOffset);
385
+
386
+ if (childSize < 8 || moovOffset + childSize > moovEnd) {
387
+ if (silent) return 0;
388
+ throw new Error('Invalid child atom size');
389
+ }
390
+
391
+ const childType = buffer.toString('ascii', moovOffset + 4, moovOffset + 8);
392
+
393
+ if (childType === 'mvhd') {
394
+ const version = buffer.readUInt8(moovOffset + 8);
395
+
396
+ if (version === 0) {
397
+ const timescale = buffer.readUInt32BE(moovOffset + 20);
398
+ const duration = buffer.readUInt32BE(moovOffset + 24);
399
+
400
+ if (!timescale) {
401
+ if (silent) return 0;
402
+ throw new Error('Invalid timescale');
403
+ }
404
+
405
+ return duration / timescale;
406
+ }
407
+
408
+ if (version === 1) {
409
+ const timescale = buffer.readUInt32BE(moovOffset + 32);
410
+ const duration = Number(buffer.readBigUInt64BE(moovOffset + 36));
411
+
412
+ if (!timescale) {
413
+ if (silent) return 0;
414
+ throw new Error('Invalid timescale');
415
+ }
416
+
417
+ return duration / timescale;
418
+ }
419
+ }
420
+
421
+ moovOffset += childSize;
422
+ }
423
+ }
424
+
425
+ offset += size;
426
+ }
427
+
428
+ if (silent) return 0;
429
+
430
+ throw new Error('No mvhd found!');
431
+ } catch (err) {
432
+ if (silent) return 0;
433
+ throw err;
434
+ }
435
+ }
436
+
437
+ static getMp4Preview(videoBuffer, { time, result = 'buffer', resize = true, width = 300, height = 300, silent = true } = {}) {
438
+ return new Promise((resolve, reject) => {
439
+ const fail = (err) => {
440
+ if (silent) {
441
+ return resolve(result === 'base64' ? '' : Buffer.alloc(0));
442
+ }
443
+ return reject(err);
444
+ };
445
+
446
+ try {
447
+ if (!Buffer.isBuffer(videoBuffer) || !videoBuffer.length) {
448
+ return fail(new Error('videoBuffer tidak valid atau kosong'));
449
+ }
450
+
451
+ const inputStream = new Readable({ read() { } });
452
+ inputStream.push(videoBuffer);
453
+ inputStream.push(null);
454
+
455
+ const outputStream = new PassThrough();
456
+ const chunks = [];
457
+
458
+ outputStream.on('data', (chunk) => chunks.push(chunk));
459
+
460
+ outputStream.on('end', async () => {
461
+ try {
462
+ let output = Buffer.concat(chunks);
463
+
464
+ if (!output.length) {
465
+ return fail(new Error('Output kosong — cek format atau timestamp video'));
466
+ }
467
+
468
+ if (resize) {
469
+ output = await Toolkit.resize(output, width, height);
470
+ }
471
+
472
+ return resolve(result === 'base64' ? output.toString('base64') : output);
473
+ } catch (err) {
474
+ return fail(err);
475
+ }
476
+ });
477
+
478
+ outputStream.on('error', fail);
479
+
480
+ time ??= Math.min(Toolkit.getMp4Duration(videoBuffer) * 0.2, 10);
481
+
482
+ ffmpeg(inputStream)
483
+ .outputOptions([`-ss ${time}`, '-vframes 1', '-vcodec png', '-f image2pipe'])
484
+ .on('error', (err) => fail(new Error(`ffmpeg error: ${err.message}`)))
485
+ .pipe(outputStream, { end: true });
486
+ } catch (err) {
487
+ return fail(err);
488
+ }
489
+ });
490
+ }
491
+ }
492
+
493
+
494
+ class RowBuilder {
495
+ constructor() { this.buttons = []; }
496
+ button(displayText, buttonId) {
497
+ this.buttons.push({ buttonId, buttonText: { displayText }, type: 1 });
498
+ return this;
499
+ }
500
+ }
501
+ class CardBuilder {
502
+ constructor(client) { this._card = new Button(client); }
503
+ image(url) { this._card.setImage(url); return this; }
504
+ title(t) { this._card.setTitle(t); return this; }
505
+ text(t) { this._card.setBody(t); return this; }
506
+ button(displayText, id) { this._card.addReply(displayText, id); return this; }
507
+ }
508
+
509
+ class BaseBuilder {
510
+ constructor() {
511
+ this._title = '';
512
+ this._subtitle = '';
513
+ this._body = '';
514
+ this._footer = '';
515
+ this._contextInfo = {};
516
+ this._extraPayload = {};
517
+ }
518
+
519
+ setTitle(title) {
520
+ if (typeof title !== 'string') {
521
+ throw new TypeError('Title must be a string');
522
+ }
523
+ this._title = title;
524
+ return this;
525
+ }
526
+
527
+ setSubtitle(subtitle) {
528
+ if (typeof subtitle !== 'string') {
529
+ throw new TypeError('Subtitle must be a string');
530
+ }
531
+ this._subtitle = subtitle;
532
+ return this;
533
+ }
534
+
535
+ setBody(body) {
536
+ if (typeof body !== 'string') {
537
+ throw new TypeError('Body must be a string');
538
+ }
539
+ this._body = body;
540
+ return this;
541
+ }
542
+
543
+ setFooter(footer) {
544
+ if (typeof footer !== 'string') {
545
+ throw new TypeError('Footer must be a string');
546
+ }
547
+ this._footer = footer;
548
+ return this;
549
+ }
550
+
551
+ setContextInfo(obj) {
552
+ if (typeof obj !== 'object' || obj === null || Array.isArray(obj)) {
553
+ throw new TypeError('ContextInfo must be a plain object');
554
+ }
555
+
556
+ this._contextInfo = obj;
557
+ return this;
558
+ }
559
+
560
+ addPayload(obj) {
561
+ if (typeof obj !== 'object' || obj === null || Array.isArray(obj)) {
562
+ throw new TypeError('Payload must be a plain object');
563
+ }
564
+
565
+ Object.assign(this._extraPayload, obj);
566
+
567
+ return this;
568
+ }
569
+ text(t) { return this.setBody(t); }
570
+ footer(f) { return this.setFooter(f); }
571
+ title(t) { return this.setTitle(t); }
572
+ subtitle(s) { return this.setSubtitle(s); }
573
+ image(url, opts = {}) {
574
+ if (this.setImage) return this.setImage(url, opts);
575
+ if (this.setThumbnail) return this.setThumbnail(url);
576
+ if (this.addImage) return this.addImage(url, opts);
577
+ return this;
578
+ }
579
+
580
+ }
581
+
582
+ class Button extends BaseBuilder {
583
+ #client;
584
+
585
+ constructor(client) {
586
+ super();
587
+ if (!client) {
588
+ throw new Error('Socket is required');
589
+ }
590
+ this.#client = client;
591
+
592
+ this._buttons = [];
593
+ this._data;
594
+ this._currentSelectionIndex = -1;
595
+ this._currentSectionIndex = -1;
596
+ this._params = {};
597
+ }
598
+
599
+ setVideo(path, options = {}) {
600
+ if (!path) throw new Error('Url or buffer needed');
601
+ Buffer.isBuffer(path) ? (this._data = { video: path, ...options }) : (this._data = { video: { url: path }, ...options });
602
+ return this;
603
+ }
604
+
605
+ setImage(path, options = {}) {
606
+ if (!path) throw new Error('Url or buffer needed');
607
+ Buffer.isBuffer(path) ? (this._data = { image: path, ...options }) : (this._data = { image: { url: path }, ...options });
608
+ return this;
609
+ }
610
+
611
+ setDocument(path, options = {}) {
612
+ if (!path) throw new Error('Url or buffer needed');
613
+ Buffer.isBuffer(path) ? (this._data = { document: path, ...options }) : (this._data = { document: { url: path }, ...options });
614
+ return this;
615
+ }
616
+
617
+ setMedia(obj) {
618
+ if (typeof obj !== 'object' || obj === null || Array.isArray(obj)) {
619
+ throw new TypeError('Media must be a plain object');
620
+ }
621
+
622
+ this._data = obj;
623
+ return this;
624
+ }
625
+
626
+ clearButtons() {
627
+ this._buttons = [];
628
+ return this;
629
+ }
630
+
631
+ setParams(obj) {
632
+ this._params = obj;
633
+ return this;
634
+ }
635
+
636
+ addButton(name, params) {
637
+ this._buttons.push({
638
+ name,
639
+ buttonParamsJson: typeof params === 'string' ? params : JSON.stringify(params),
640
+ });
641
+
642
+ return this;
643
+ }
644
+
645
+ makeRow(header = '', title = '', description = '', id = '') {
646
+ if (this._currentSelectionIndex === -1 || this._currentSectionIndex === -1) {
647
+ throw new Error('You need to create a selection and a section first');
648
+ }
649
+ const buttonParams = JSON.parse(this._buttons[this._currentSelectionIndex].buttonParamsJson);
650
+ buttonParams.sections[this._currentSectionIndex].rows.push({ header, title, description, id });
651
+ this._buttons[this._currentSelectionIndex].buttonParamsJson = JSON.stringify(buttonParams);
652
+ return this;
653
+ }
654
+
655
+ makeSection(title = '', highlight_label = '') {
656
+ if (this._currentSelectionIndex === -1) {
657
+ throw new Error('You need to create a selection first');
658
+ }
659
+ const buttonParams = JSON.parse(this._buttons[this._currentSelectionIndex].buttonParamsJson);
660
+ buttonParams.sections.push({ title, highlight_label, rows: [] });
661
+ this._currentSectionIndex = buttonParams.sections.length - 1;
662
+ this._buttons[this._currentSelectionIndex].buttonParamsJson = JSON.stringify(buttonParams);
663
+ return this;
664
+ }
665
+
666
+ addSelection(title, options = {}) {
667
+ this._buttons.push({ ...options, name: 'single_select', buttonParamsJson: JSON.stringify({ title, sections: [] }) });
668
+ this._currentSelectionIndex = this._buttons.length - 1;
669
+ this._currentSectionIndex = -1;
670
+ return this;
671
+ }
672
+
673
+ addReply(display_text = '', id = '', options = {}) {
674
+ this._buttons.push({
675
+ name: 'quick_reply',
676
+ buttonParamsJson: JSON.stringify({
677
+ display_text,
678
+ id,
679
+ ...options,
680
+ }),
681
+ });
682
+ return this;
683
+ }
684
+
685
+ addCall(display_text = '', id = '', options = {}) {
686
+ this._buttons.push({
687
+ name: 'cta_call',
688
+ buttonParamsJson: JSON.stringify({
689
+ display_text,
690
+ id,
691
+ ...options,
692
+ }),
693
+ });
694
+ return this;
695
+ }
696
+
697
+ addReminder(display_text = '', id = '', options = {}) {
698
+ this._buttons.push({
699
+ name: 'cta_reminder',
700
+ buttonParamsJson: JSON.stringify({
701
+ display_text,
702
+ id,
703
+ ...options,
704
+ }),
705
+ });
706
+ return this;
707
+ }
708
+
709
+ addCancelReminder(display_text = '', id = '', options = {}) {
710
+ this._buttons.push({
711
+ name: 'cta_cancel_reminder',
712
+ buttonParamsJson: JSON.stringify({
713
+ display_text,
714
+ id,
715
+ ...options,
716
+ }),
717
+ });
718
+ return this;
719
+ }
720
+
721
+ addAddress(display_text = '', id = '', options = {}) {
722
+ this._buttons.push({
723
+ name: 'address_message',
724
+ buttonParamsJson: JSON.stringify({
725
+ display_text,
726
+ id,
727
+ ...options,
728
+ }),
729
+ });
730
+ return this;
731
+ }
732
+
733
+ addLocation(options = {}) {
734
+ this._buttons.push({
735
+ name: 'send_location',
736
+ buttonParamsJson: JSON.stringify(options),
737
+ });
738
+ return this;
739
+ }
740
+
741
+ addUrl(display_text = '', url = '', webview_interaction = false, options = {}) {
742
+ this._buttons.push({
743
+ ...options,
744
+ name: 'cta_url',
745
+ buttonParamsJson: JSON.stringify({
746
+ display_text,
747
+ url,
748
+ webview_interaction,
749
+ ...options,
750
+ }),
751
+ });
752
+ return this;
753
+ }
754
+
755
+ addCopy(display_text = '', copy_code = '', options = {}) {
756
+ this._buttons.push({
757
+ name: 'cta_copy',
758
+ buttonParamsJson: JSON.stringify({
759
+ display_text,
760
+ copy_code,
761
+ ...options,
762
+ }),
763
+ });
764
+ return this;
765
+ }
766
+
767
+ static paramsList = {
768
+ limited_time_offer: {
769
+ text: 'string',
770
+ url: 'string',
771
+ copy_code: 'string',
772
+ expiration_time: 'number',
773
+ },
774
+ bottom_sheet: {
775
+ in_thread_buttons_limit: 'number',
776
+ divider_indices: ['number'],
777
+ list_title: 'string',
778
+ button_title: 'string',
779
+ },
780
+ tap_target_configuration: {
781
+ title: 'string',
782
+ description: 'string',
783
+ canonical_url: 'string',
784
+ domain: 'string',
785
+ buttonIndex: 'number',
786
+ },
787
+ };
788
+
789
+ async toCard() {
790
+ return {
791
+ body: {
792
+ text: this._body,
793
+ },
794
+ footer: {
795
+ text: this._footer,
796
+ },
797
+ header: {
798
+ title: this._title,
799
+ subtitle: this._subtitle,
800
+ hasMediaAttachment: !!this._data,
801
+ ...(this._data
802
+ ? await prepareWAMessageMedia(this._data, { upload: this.#client.waUploadToServer }).catch((e) => {
803
+ if (String(e).includes('Invalid media type')) return this._data;
804
+ throw e;
805
+ })
806
+ : {}),
807
+ },
808
+ nativeFlowMessage: {
809
+ messageParamsJson: JSON.stringify(this._params),
810
+ buttons: this._buttons,
811
+ },
812
+ };
813
+ }
814
+
815
+ async build(jid, { ...options } = {}) {
816
+ if (this._cardBuilders && this._cardBuilders.length > 0) {
817
+ for (const builder of this._cardBuilders) {
818
+ this.addCard(await builder._card.toCard());
819
+ }
820
+ this._cardBuilders = [];
821
+ }
822
+ return generateWAMessageFromContent(
823
+ jid,
824
+ {
825
+ ...this._extraPayload,
826
+ interactiveMessage: {
827
+ ...message,
828
+ contextInfo: this._contextInfo,
829
+ },
830
+ },
831
+ { ...options }
832
+ );
833
+ }
834
+
835
+ async send(jid, { ...options } = {}) {
836
+ const msg = await this.build(jid, options);
837
+
838
+ await this.#client.relayMessage(msg.key.remoteJid, msg.message, {
839
+ messageId: msg.key.id,
840
+ additionalNodes: [
841
+ {
842
+ tag: 'biz',
843
+ attrs: {},
844
+ content: [
845
+ {
846
+ tag: 'interactive',
847
+ attrs: { type: 'native_flow', v: '1' },
848
+ content: [{ tag: 'native_flow', attrs: { v: '9', name: 'mixed' } }],
849
+ },
850
+ ],
851
+ },
852
+ ],
853
+ ...options,
854
+ });
855
+ return msg;
856
+ }
857
+ button(displayText, id) { return this.addReply(displayText, id); }
858
+
859
+ }
860
+
861
+ class ButtonV2 extends BaseBuilder {
862
+ #client;
863
+
864
+ constructor(client) {
865
+ super();
866
+ if (!client) {
867
+ throw new Error('Socket is required');
868
+ }
869
+
870
+ this.#client = client;
871
+ this._image;
872
+ this._data;
873
+ this._buttons = [];
874
+ }
875
+
876
+ addButton(displayText = '', buttonId = crypto.randomUUID()) {
877
+ this._buttons.push({
878
+ buttonId,
879
+ buttonText: { displayText },
880
+ type: 1,
881
+ });
882
+ return this;
883
+ }
884
+
885
+ addRawButton(obj) {
886
+ if (typeof obj !== 'object' || obj === null || Array.isArray(obj)) {
887
+ throw new TypeError('Buttons must be a plain object');
888
+ }
889
+
890
+ this._buttons.push(obj);
891
+ return this;
892
+ }
893
+
894
+ setThumbnail(path) {
895
+ if (!path) throw new Error('Url or buffer needed');
896
+ this._image = path;
897
+ return this;
898
+ }
899
+
900
+ setMedia(obj) {
901
+ if (typeof obj !== 'object' || obj === null || Array.isArray(obj)) {
902
+ throw new TypeError('Media must be a plain object');
903
+ }
904
+
905
+ this._data = obj;
906
+ return this;
907
+ }
908
+
909
+ async build(jid, { ...options } = {}) {
910
+ let _thumbnail = this._image ? await Toolkit.resize(Buffer.isBuffer(this._image) ? this._image : await Toolkit.fetchBuffer(this._image, {}, { silent: true }), 300, 300) : null;
911
+ const msg = generateWAMessageFromContent(
912
+ jid,
913
+ {
914
+ ...this._extraPayload,
915
+ buttonsMessage: {
916
+ contentText: this._body,
917
+ footerText: this._footer,
918
+ ...(this._data
919
+ ? this._data
920
+ : {
921
+ headerType: 6,
922
+ locationMessage: {
923
+ degreesLatitude: 0,
924
+ degreesLongitude: 0,
925
+ name: this._title,
926
+ address: this._subtitle,
927
+ jpegThumbnail: _thumbnail,
928
+ },
929
+ }),
930
+ viewOnce: true,
931
+ contextInfo: this._contextInfo,
932
+ buttons: [...this._buttons],
933
+ },
934
+ },
935
+ { ...options }
936
+ );
937
+ return msg;
938
+ }
939
+
940
+ async send(jid, { ...options } = {}) {
941
+ if (this._buttons.length < 1) throw new Error('ButtonV2 requires at least one button');
942
+ const msg = await this.build(jid, options);
943
+
944
+ await this.#client.relayMessage(msg.key.remoteJid, msg.message, {
945
+ messageId: msg.key.id,
946
+ additionalNodes: [
947
+ {
948
+ tag: 'biz',
949
+ attrs: {},
950
+ content: [
951
+ {
952
+ tag: 'interactive',
953
+ attrs: { type: 'native_flow', v: '1' },
954
+ content: [{ tag: 'native_flow', attrs: { v: '9', name: 'mixed' } }],
955
+ },
956
+ ],
957
+ },
958
+ ],
959
+ ...options,
960
+ });
961
+ return msg;
962
+ }
963
+ button(displayText, id) { return this.addButton(displayText, id); }
964
+ row(cb) {
965
+ const r = new RowBuilder();
966
+ cb(r);
967
+ r.buttons.forEach(b => this._buttons.push(b));
968
+ return this;
969
+ }
970
+
971
+ }
972
+
973
+ class Carousel extends BaseBuilder {
974
+ #client;
975
+
976
+ constructor(client) {
977
+ super();
978
+ if (!client) {
979
+ throw new Error('Socket is required');
980
+ }
981
+
982
+ this.#client = client;
983
+ this._cards = [];
984
+ }
985
+
986
+ addCard(card) {
987
+ const cards = Array.isArray(card) ? card : [card];
988
+ const baseIndex = this._cards.length;
989
+
990
+ for (const [index, c] of cards.entries()) {
991
+ if (!c?.header?.hasMediaAttachment) {
992
+ throw new Error(`Card [${baseIndex + index}] must include an image or video in header`);
993
+ }
994
+ }
995
+
996
+ this._cards.push(...cards);
997
+ return this;
998
+ }
999
+
1000
+ build(jid, { ...options } = {}) {
1001
+ return generateWAMessageFromContent(
1002
+ jid,
1003
+ {
1004
+ ...this._extraPayload,
1005
+ interactiveMessage: {
1006
+ header: {
1007
+ hasMediaAttachment: false,
1008
+ },
1009
+ body: { text: this._body },
1010
+ footer: { text: this._footer },
1011
+ contextInfo: this._contextInfo,
1012
+ carouselMessage: {
1013
+ cards: this._cards,
1014
+ },
1015
+ },
1016
+ },
1017
+ { ...options }
1018
+ );
1019
+ }
1020
+
1021
+ async send(jid, { ...options } = {}) {
1022
+ const msg = await this.build(jid, options);
1023
+
1024
+ await this.#client.relayMessage(msg.key.remoteJid, msg.message, {
1025
+ messageId: msg.key.id,
1026
+ additionalNodes: [
1027
+ {
1028
+ tag: 'biz',
1029
+ attrs: {},
1030
+ content: [
1031
+ {
1032
+ tag: 'interactive',
1033
+ attrs: { type: 'native_flow', v: '1' },
1034
+ content: [{ tag: 'native_flow', attrs: { v: '9', name: 'mixed' } }],
1035
+ },
1036
+ ],
1037
+ },
1038
+ ],
1039
+ ...options,
1040
+ });
1041
+ return msg;
1042
+ }
1043
+ card(cb) {
1044
+ if (!this._cardBuilders) this._cardBuilders = [];
1045
+ const cbObj = new CardBuilder(this.#client);
1046
+ cb(cbObj);
1047
+ this._cardBuilders.push(cbObj);
1048
+ return this;
1049
+ }
1050
+
1051
+ }
1052
+
1053
+ class AIRich extends BaseBuilder {
1054
+ #client;
1055
+
1056
+ constructor(client) {
1057
+ if (!client) {
1058
+ throw new Error('Socket is required');
1059
+ }
1060
+
1061
+ super();
1062
+ this.#client = client;
1063
+ this._contextInfo = {};
1064
+ this._submessages = [];
1065
+ this._sections = [];
1066
+ this._richResponseSources = [];
1067
+ }
1068
+
1069
+ addSubmessage(submessage) {
1070
+ const items = Array.isArray(submessage) ? submessage : [submessage];
1071
+
1072
+ for (const item of items) {
1073
+ if (typeof item !== 'object' || item === null || Array.isArray(item)) {
1074
+ throw new TypeError('Submessage must be a plain object or array of plain objects');
1075
+ }
1076
+
1077
+ this._submessages.push(item);
1078
+ }
1079
+
1080
+ return this;
1081
+ }
1082
+
1083
+ addSection(section) {
1084
+ const items = Array.isArray(section) ? section : [section];
1085
+
1086
+ for (const item of items) {
1087
+ if (typeof item !== 'object' || item === null || Array.isArray(item)) {
1088
+ throw new TypeError('Section must be a plain object or array of plain objects');
1089
+ }
1090
+
1091
+ this._sections.push(item);
1092
+ }
1093
+
1094
+ return this;
1095
+ }
1096
+
1097
+ addText(text, { hyperlink = true, citation = true, latex = true } = {}) {
1098
+ if (typeof text != 'string') {
1099
+ throw new TypeError('Text must be a string');
1100
+ }
1101
+
1102
+ const { text: extractedText, inline_entities } = extractIE(text, {
1103
+ hyperlink,
1104
+ citation,
1105
+ latex,
1106
+ });
1107
+
1108
+ this._submessages.push({
1109
+ messageType: 2,
1110
+ messageText: extractedText,
1111
+ });
1112
+
1113
+ this._sections.push(
1114
+ AIRich.newLayout('Single', {
1115
+ text: extractedText,
1116
+ ...(inline_entities.length && {
1117
+ inline_entities,
1118
+ }),
1119
+ __typename: 'GenAIMarkdownTextUXPrimitive',
1120
+ })
1121
+ );
1122
+
1123
+ return this;
1124
+ }
1125
+
1126
+ addCode(language, code) {
1127
+ if (typeof language !== 'string' || typeof code !== 'string') {
1128
+ throw new TypeError('Language and code must be a string');
1129
+ }
1130
+
1131
+ const meta = AIRich.tokenizer(code, language);
1132
+
1133
+ this._submessages.push({
1134
+ messageType: 5,
1135
+ codeMetadata: {
1136
+ codeLanguage: language,
1137
+ codeBlocks: meta.codeBlock,
1138
+ },
1139
+ });
1140
+
1141
+ this._sections.push(
1142
+ AIRich.newLayout('Single', {
1143
+ language,
1144
+ code_blocks: meta.unified_codeBlock,
1145
+ __typename: 'GenAICodeUXPrimitive',
1146
+ })
1147
+ );
1148
+
1149
+ return this;
1150
+ }
1151
+
1152
+ addTable(table, { hyperlink = true, citation = true, latex = true } = {}) {
1153
+ if (!Array.isArray(table)) {
1154
+ throw new TypeError('Table must be an array');
1155
+ }
1156
+
1157
+ const meta = AIRich.toTableMetadata(table, { hyperlink, citation, latex });
1158
+
1159
+ this._submessages.push({
1160
+ messageType: 4,
1161
+ tableMetadata: {
1162
+ title: meta.title,
1163
+ rows: meta.rows,
1164
+ },
1165
+ });
1166
+
1167
+ this._sections.push(
1168
+ AIRich.newLayout('Single', {
1169
+ rows: meta.unified_rows,
1170
+ __typename: 'GenATableUXPrimitive',
1171
+ })
1172
+ );
1173
+
1174
+ return this;
1175
+ }
1176
+
1177
+ addSource(sources = []) {
1178
+ if (!(Array.isArray(sources) && (sources.every((item) => typeof item === 'string') || sources.every((item) => Array.isArray(item) && item.every((v) => typeof v === 'string'))))) {
1179
+ throw new TypeError('Sources must be a string array or an array of string arrays');
1180
+ }
1181
+
1182
+ if (sources.every((item) => typeof item === 'string')) {
1183
+ sources = [sources];
1184
+ }
1185
+
1186
+ const source = sources.map(([icon, url, text]) => ({
1187
+ source_type: 'THIRD_PARTY',
1188
+ source_display_name: text ?? '',
1189
+ source_subtitle: 'AI',
1190
+ source_url: url ?? '',
1191
+ favicon: {
1192
+ url: Toolkit.resolveMedia(this.#client, icon ?? '', 'image'),
1193
+ mime_type: 'image/jpeg',
1194
+ width: 16,
1195
+ height: 16,
1196
+ },
1197
+ }));
1198
+
1199
+ this._sections.push(
1200
+ AIRich.newLayout('Single', {
1201
+ sources: source,
1202
+ __typename: 'GenAISearchResultPrimitive',
1203
+ })
1204
+ );
1205
+
1206
+ return this;
1207
+ }
1208
+
1209
+ addReels(reelsItems = []) {
1210
+ if (
1211
+ !(
1212
+ (reelsItems && typeof reelsItems === 'object' && !Array.isArray(reelsItems)) ||
1213
+ (Array.isArray(reelsItems) && reelsItems.every((item) => item && typeof item === 'object' && !Array.isArray(item)))
1214
+ )
1215
+ ) {
1216
+ throw new TypeError('Reels items must be an object or an array of objects');
1217
+ }
1218
+
1219
+ if (!Array.isArray(reelsItems)) {
1220
+ reelsItems = [reelsItems];
1221
+ }
1222
+
1223
+ const reels = reelsItems.map((item) => ({
1224
+ ...item,
1225
+ _avatar: Toolkit.resolveMedia(this.#client, item.profileIconUrl ?? item.profile_url ?? item.profile ?? '', 'image'),
1226
+ _thumbnail: Toolkit.resolveMedia(this.#client, item.thumbnailUrl ?? item.thumbnail ?? '', 'image'),
1227
+ }));
1228
+
1229
+ this._submessages.push({
1230
+ messageType: 9,
1231
+ contentItemsMetadata: {
1232
+ contentType: 1,
1233
+ itemsMetadata: reels.map((item) => ({
1234
+ reelItem: {
1235
+ title: item.username ?? '',
1236
+ profileIconUrl: item._avatar,
1237
+ thumbnailUrl: item._thumbnail,
1238
+ videoUrl: item.videoUrl ?? item.url ?? '',
1239
+ },
1240
+ })),
1241
+ },
1242
+ });
1243
+
1244
+ reels.forEach((item, idx) => {
1245
+ this._richResponseSources.push({
1246
+ provider: '\u004E\u0049\u0058\u0045\u004C',
1247
+ thumbnailCDNURL: item._thumbnail,
1248
+ sourceProviderURL: item.videoUrl ?? item.url ?? '',
1249
+ sourceQuery: '',
1250
+ faviconCDNURL: item._avatar,
1251
+ citationNumber: idx + 1,
1252
+ sourceTitle: item.username ?? '',
1253
+ });
1254
+ });
1255
+
1256
+ this._sections.push(
1257
+ AIRich.newLayout(
1258
+ 'HScroll',
1259
+ reels.map((item) => ({
1260
+ reels_url: item.videoUrl ?? item.url ?? '',
1261
+ thumbnail_url: item._thumbnail,
1262
+ creator: item.username ?? item.title ?? '',
1263
+ avatar_url: item._avatar,
1264
+ reels_title: item.reels_title ?? item.title ?? '',
1265
+ likes_count: item.likes_count ?? item.like ?? 0,
1266
+ shares_count: item.shares_count ?? item.share ?? 0,
1267
+ view_count: item.view_count ?? item.view ?? 0,
1268
+ reel_source: item.reel_source ?? item.source ?? 'IG',
1269
+ is_verified: !!(item.is_verified || item.verified),
1270
+ __typename: 'GenAIReelPrimitive',
1271
+ }))
1272
+ )
1273
+ );
1274
+
1275
+ return this;
1276
+ }
1277
+
1278
+ addImage(imageUrl, { resolveUrl = false } = {}) {
1279
+ if (!(typeof imageUrl === 'string' || Buffer.isBuffer(imageUrl) || (Array.isArray(imageUrl) && imageUrl.every((v) => typeof v === 'string' || Buffer.isBuffer(v))))) {
1280
+ throw new TypeError('imageUrl must be string | buffer | array of string/buffer');
1281
+ }
1282
+
1283
+ const list = Array.isArray(imageUrl)
1284
+ ? imageUrl.map((v) => {
1285
+ const url = Toolkit.resolveMedia(this.#client, v, 'image', { resolveUrl });
1286
+ return {
1287
+ imagePreviewUrl: url,
1288
+ imageHighResUrl: url,
1289
+ sourceUrl: url,
1290
+ };
1291
+ })
1292
+ : (() => {
1293
+ const url = Toolkit.resolveMedia(this.#client, imageUrl, 'image', { resolveUrl });
1294
+ return [
1295
+ {
1296
+ imagePreviewUrl: url,
1297
+ imageHighResUrl: url,
1298
+ sourceUrl: url,
1299
+ },
1300
+ ];
1301
+ })();
1302
+
1303
+ this._submessages.push({
1304
+ messageType: 1,
1305
+ gridImageMetadata: {
1306
+ gridImageUrl: {
1307
+ imagePreviewUrl: list[0]?.imagePreviewUrl,
1308
+ },
1309
+ imageUrls: list,
1310
+ },
1311
+ });
1312
+
1313
+ list.forEach(({ imagePreviewUrl }) => {
1314
+ this._sections.push(
1315
+ AIRich.newLayout('Single', {
1316
+ media: {
1317
+ url: imagePreviewUrl,
1318
+ mime_type: 'image/png',
1319
+ },
1320
+ imagine_type: 'IMAGE',
1321
+ status: { status: 'READY' },
1322
+ __typename: 'GenAIImaginePrimitive',
1323
+ })
1324
+ );
1325
+ });
1326
+
1327
+ return this;
1328
+ }
1329
+
1330
+ addVideo(videoUrl, { autoFill = true } = {}) {
1331
+ const isObjectVideo = (v) => v && typeof v === 'object' && v.url;
1332
+
1333
+ const isValidPrimitive =
1334
+ typeof videoUrl === 'string' ||
1335
+ Buffer.isBuffer(videoUrl) ||
1336
+ isObjectVideo(videoUrl) ||
1337
+ (Array.isArray(videoUrl) && videoUrl.every((v) => typeof v === 'string' || Buffer.isBuffer(v) || isObjectVideo(v)));
1338
+
1339
+ if (!isValidPrimitive) {
1340
+ throw new TypeError('videoUrl must be string | buffer | object | array');
1341
+ }
1342
+
1343
+ const items = Array.isArray(videoUrl) ? videoUrl : [videoUrl];
1344
+
1345
+ this._submessages.push({
1346
+ messageType: 2,
1347
+ messageText: '[ CANNOT_LOAD_VIDEO - \u004E\u0049\u0058\u0045\u004C ]',
1348
+ });
1349
+
1350
+ items.forEach((item) => {
1351
+ const isObject = isObjectVideo(item);
1352
+
1353
+ const url = isObject ? Toolkit.resolveMedia(this.#client, item.url ?? '', 'video') : Toolkit.resolveMedia(this.#client, item, 'video');
1354
+
1355
+ const bufferPromise = autoFill ? Promise.resolve(url).then((u) => Toolkit.fetchBuffer(u)) : null;
1356
+
1357
+ const file_length = isObject && item.file_length != null ? item.file_length : autoFill ? bufferPromise.then((b) => b?.length ?? 0) : 0;
1358
+
1359
+ const duration =
1360
+ isObject && item.duration != null
1361
+ ? item.duration
1362
+ : autoFill
1363
+ ? bufferPromise.then((b) =>
1364
+ Toolkit.getMp4Duration(b, {
1365
+ silent: true,
1366
+ })
1367
+ )
1368
+ : 0;
1369
+
1370
+ const thumbnail =
1371
+ isObject && item.thumbnail
1372
+ ? Toolkit.resolveMedia(this.#client, item.thumbnail, 'image', {
1373
+ result: 'base64',
1374
+ resize: true,
1375
+ width: 300,
1376
+ height: 300,
1377
+ })
1378
+ : autoFill
1379
+ ? bufferPromise
1380
+ ? bufferPromise.then((b) =>
1381
+ Toolkit.getMp4Preview(b, {
1382
+ time: 0,
1383
+ result: 'base64',
1384
+ })
1385
+ )
1386
+ : null
1387
+ : null;
1388
+
1389
+ this._sections.push(
1390
+ AIRich.newLayout('Single', {
1391
+ media: {
1392
+ url,
1393
+ mime_type: isObject ? (item.mime_type ?? 'video/mp4') : 'video/mp4',
1394
+ file_length,
1395
+ duration,
1396
+ },
1397
+ imagine_type: 'ANIMATE',
1398
+ status: { status: 'READY' },
1399
+ thumbnail: {
1400
+ raw_media: thumbnail,
1401
+ },
1402
+ __typename: 'GenAIImaginePrimitive',
1403
+ })
1404
+ );
1405
+ });
1406
+
1407
+ return this;
1408
+ }
1409
+
1410
+ addProduct(data = {}) {
1411
+ if (!((data && typeof data === 'object' && !Array.isArray(data)) || (Array.isArray(data) && data.every((item) => item && typeof item === 'object' && !Array.isArray(item))))) {
1412
+ throw new TypeError('Product items must be an object or an array of objects');
1413
+ }
1414
+
1415
+ this._submessages.push({
1416
+ messageType: 2,
1417
+ messageText: '[ CANNOT_LOAD_PRODUCT - NIXEL ]',
1418
+ });
1419
+
1420
+ const items = Array.isArray(data) ? data : [data];
1421
+
1422
+ const product = items.map((item) => ({
1423
+ title: item.title,
1424
+ brand: item.brand,
1425
+ price: item.price,
1426
+ sale_price: item.sale_price,
1427
+ product_url: item.product_url ?? item.url,
1428
+ image: {
1429
+ url: Toolkit.resolveMedia(this.#client, item.image_url ?? item.image, 'image'),
1430
+ },
1431
+ additional_images: [
1432
+ {
1433
+ url: Toolkit.resolveMedia(this.#client, item.icon_url ?? item.icon, 'image'),
1434
+ },
1435
+ ],
1436
+ __typename: 'GenAIProductItemCardPrimitive',
1437
+ }));
1438
+
1439
+ this._sections.push(AIRich.newLayout(Array.isArray(data) ? 'HScroll' : 'Single', Array.isArray(data) ? product : product[0]));
1440
+
1441
+ return this;
1442
+ }
1443
+
1444
+ addPost(data = {}) {
1445
+ if (!((data && typeof data === 'object' && !Array.isArray(data)) || (Array.isArray(data) && data.every((item) => item && typeof item === 'object' && !Array.isArray(item))))) {
1446
+ throw new TypeError('Post items must be an object or an array of objects');
1447
+ }
1448
+
1449
+ const posts = Array.isArray(data) ? data : [data];
1450
+
1451
+ this._submessages.push({
1452
+ messageType: 2,
1453
+ messageText: '[ CANNOT_LOAD_POST - NIXEL ]',
1454
+ });
1455
+
1456
+ const primitives = posts.map((p) => ({
1457
+ title: p.title ?? '',
1458
+ subtitle: p.subtitle ?? '',
1459
+ username: p.username ?? '',
1460
+ profile_picture_url: Toolkit.resolveMedia(this.#client, p.profile_picture_url ?? p.profile_url ?? p.profile ?? '', 'image'),
1461
+ is_verified: !!(p.is_verified || p.verified),
1462
+ thumbnail_url: Toolkit.resolveMedia(this.#client, p.thumbnail_url ?? p.thumbnail ?? '', 'image'),
1463
+ post_caption: p.post_caption ?? p.caption ?? '',
1464
+ likes_count: p.likes_count ?? p.like ?? 0,
1465
+ comments_count: p.comments_count ?? p.comment ?? 0,
1466
+ shares_count: p.shares_count ?? p.share ?? 0,
1467
+ post_url: p.post_url ?? p.url ?? '',
1468
+ post_deeplink: p.post_deeplink ?? p.deeplink ?? '',
1469
+ source_app: p.source_app || p.source || 'INSTAGRAM',
1470
+ footer_label: p.footer_label ?? p.footer ?? '',
1471
+ footer_icon: Toolkit.resolveMedia(this.#client, p.footer_icon ?? p.icon ?? '', 'image'),
1472
+ is_carousel: posts.length > 1,
1473
+ orientation: p.orientation ?? 'LANDSCAPE',
1474
+ post_type: p.post_type ?? 'VIDEO',
1475
+ __typename: 'GenAIPostPrimitive',
1476
+ }));
1477
+
1478
+ this._sections.push(AIRich.newLayout('HScroll', primitives));
1479
+
1480
+ return this;
1481
+ }
1482
+
1483
+ addTip(text) {
1484
+ this._submessages.push({
1485
+ messageType: 2,
1486
+ messageText: text,
1487
+ });
1488
+
1489
+ this._sections.push(
1490
+ AIRich.newLayout('Single', {
1491
+ text,
1492
+ __typename: 'GenAIMetadataTextPrimitive',
1493
+ })
1494
+ );
1495
+
1496
+ return this;
1497
+ }
1498
+
1499
+ addSuggest(suggestion, { scroll = true, layout } = {}) {
1500
+ if (!(typeof suggestion === 'string' || (Array.isArray(suggestion) && suggestion.every((v) => typeof v === 'string')))) {
1501
+ throw new TypeError('Suggestion must be a string or array of strings');
1502
+ }
1503
+
1504
+ const suggest = Array.isArray(suggestion)
1505
+ ? suggestion.map((text) => ({
1506
+ prompt_text: text,
1507
+ prompt_type: 'SUGGESTED_PROMPT',
1508
+ __typename: 'GenAIFollowUpSuggestionPillPrimitive',
1509
+ }))
1510
+ : [
1511
+ {
1512
+ prompt_text: suggestion,
1513
+ prompt_type: 'SUGGESTED_PROMPT',
1514
+ __typename: 'GenAIFollowUpSuggestionPillPrimitive',
1515
+ },
1516
+ ];
1517
+
1518
+ const type = layout ?? (suggest.length === 1 ? 'Single' : scroll ? 'HScroll' : 'ActionRow');
1519
+
1520
+ this._sections.push(AIRich.newLayout(type, type === 'Single' ? suggest[0] : suggest, { __typename: 'GenAIUnifiedResponseSection' }));
1521
+
1522
+ return this;
1523
+ }
1524
+
1525
+ async build({ forwarded = true, notification = false, includesUnifiedResponse = true, includesSubmessages = true, quoted, quotedParticipant, ...options } = {}) {
1526
+ const forward = forwarded
1527
+ ? {
1528
+ forwardingScore: 1,
1529
+ isForwarded: true,
1530
+ forwardedAiBotMessageInfo: { botJid: '0@bot' },
1531
+ forwardOrigin: 4,
1532
+ }
1533
+ : {};
1534
+
1535
+ const notif = notification
1536
+ ? {
1537
+ sessionTransparencyMetadata: {
1538
+ disclaimerText: '~ Ahmad tumbuh kembang',
1539
+ hcaId: `hca_${Date.now()}`,
1540
+ sessionTransparencyType: 1,
1541
+ },
1542
+ }
1543
+ : {};
1544
+
1545
+ const qObj = quoted
1546
+ ? {
1547
+ stanzaId: quoted?.key?.id || quoted?.id,
1548
+ participant: quotedParticipant || quoted?.key?.participant || quoted?.key?.remoteJid,
1549
+ quotedType: 0,
1550
+ quotedMessage: typeof quoted === 'object' && quoted !== null ? (quoted.message ?? quoted) : undefined,
1551
+ }
1552
+ : {};
1553
+
1554
+ const sections = this._footer
1555
+ ? [
1556
+ ...(await waitAllPromises(this._sections)),
1557
+ AIRich.newLayout('Single', {
1558
+ text: this._footer,
1559
+ __typename: 'GenAIMetadataTextPrimitive',
1560
+ }),
1561
+ ]
1562
+ : [...(await waitAllPromises(this._sections))];
1563
+
1564
+ return {
1565
+ messageContextInfo: {
1566
+ deviceListMetadata: {},
1567
+ deviceListMetadataVersion: 2,
1568
+ botMetadata: {
1569
+ messageDisclaimerText: this._title,
1570
+ richResponseSourcesMetadata: { sources: this._richResponseSources },
1571
+ ...notif,
1572
+ },
1573
+ },
1574
+ ...this._extraPayload,
1575
+ botForwardedMessage: {
1576
+ message: {
1577
+ richResponseMessage: {
1578
+ messageType: 1,
1579
+ submessages: includesSubmessages ? await waitAllPromises(this._submessages) : [],
1580
+ unifiedResponse: {
1581
+ data: includesUnifiedResponse ? Buffer.from(JSON.stringify({ response_id: crypto.randomUUID(), sections })).toString('base64') : '',
1582
+ },
1583
+ contextInfo: {
1584
+ ...forward,
1585
+ ...qObj,
1586
+ ...this._contextInfo,
1587
+ },
1588
+ },
1589
+ },
1590
+ },
1591
+ };
1592
+ }
1593
+
1594
+ async send(jid, { forwarded, notification, includesUnifiedResponse, includesSubmessages, ...options } = {}) {
1595
+ const msg = await this.build({ forwarded, notification, includesUnifiedResponse, includesSubmessages, ...options });
1596
+
1597
+ return await this.#client.relayMessage(jid, msg, { ...options });
1598
+ }
1599
+
1600
+ static tokenizer(code, lang = 'javascript') {
1601
+ const keywordsMap = {
1602
+ javascript: new Set([
1603
+ 'break',
1604
+ 'case',
1605
+ 'catch',
1606
+ 'continue',
1607
+ 'debugger',
1608
+ 'delete',
1609
+ 'do',
1610
+ 'else',
1611
+ 'finally',
1612
+ 'for',
1613
+ 'function',
1614
+ 'if',
1615
+ 'in',
1616
+ 'instanceof',
1617
+ 'new',
1618
+ 'return',
1619
+ 'switch',
1620
+ 'this',
1621
+ 'throw',
1622
+ 'try',
1623
+ 'typeof',
1624
+ 'var',
1625
+ 'void',
1626
+ 'while',
1627
+ 'with',
1628
+ 'true',
1629
+ 'false',
1630
+ 'null',
1631
+ 'undefined',
1632
+ 'class',
1633
+ 'const',
1634
+ 'let',
1635
+ 'super',
1636
+ 'extends',
1637
+ 'export',
1638
+ 'import',
1639
+ 'yield',
1640
+ 'static',
1641
+ 'constructor',
1642
+ 'async',
1643
+ 'await',
1644
+ 'get',
1645
+ 'set',
1646
+ ]),
1647
+
1648
+ typescript: new Set([
1649
+ 'abstract',
1650
+ 'any',
1651
+ 'as',
1652
+ 'asserts',
1653
+ 'bigint',
1654
+ 'boolean',
1655
+ 'declare',
1656
+ 'enum',
1657
+ 'implements',
1658
+ 'infer',
1659
+ 'interface',
1660
+ 'is',
1661
+ 'keyof',
1662
+ 'module',
1663
+ 'namespace',
1664
+ 'never',
1665
+ 'readonly',
1666
+ 'require',
1667
+ 'number',
1668
+ 'object',
1669
+ 'override',
1670
+ 'private',
1671
+ 'protected',
1672
+ 'public',
1673
+ 'satisfies',
1674
+ 'string',
1675
+ 'symbol',
1676
+ 'type',
1677
+ 'unknown',
1678
+ 'using',
1679
+ 'from',
1680
+ 'break',
1681
+ 'case',
1682
+ 'catch',
1683
+ 'continue',
1684
+ 'do',
1685
+ 'else',
1686
+ 'finally',
1687
+ 'for',
1688
+ 'function',
1689
+ 'if',
1690
+ 'new',
1691
+ 'return',
1692
+ 'switch',
1693
+ 'this',
1694
+ 'throw',
1695
+ 'try',
1696
+ 'var',
1697
+ 'void',
1698
+ 'while',
1699
+ 'class',
1700
+ 'const',
1701
+ 'let',
1702
+ 'extends',
1703
+ 'import',
1704
+ 'export',
1705
+ 'async',
1706
+ 'await',
1707
+ ]),
1708
+
1709
+ python: new Set([
1710
+ 'False',
1711
+ 'None',
1712
+ 'True',
1713
+ 'and',
1714
+ 'as',
1715
+ 'assert',
1716
+ 'async',
1717
+ 'await',
1718
+ 'break',
1719
+ 'class',
1720
+ 'continue',
1721
+ 'def',
1722
+ 'del',
1723
+ 'elif',
1724
+ 'else',
1725
+ 'except',
1726
+ 'finally',
1727
+ 'for',
1728
+ 'from',
1729
+ 'global',
1730
+ 'if',
1731
+ 'import',
1732
+ 'in',
1733
+ 'is',
1734
+ 'lambda',
1735
+ 'nonlocal',
1736
+ 'not',
1737
+ 'or',
1738
+ 'pass',
1739
+ 'raise',
1740
+ 'return',
1741
+ 'try',
1742
+ 'while',
1743
+ 'with',
1744
+ 'yield',
1745
+ ]),
1746
+
1747
+ java: new Set([
1748
+ 'abstract',
1749
+ 'assert',
1750
+ 'boolean',
1751
+ 'break',
1752
+ 'byte',
1753
+ 'case',
1754
+ 'catch',
1755
+ 'char',
1756
+ 'class',
1757
+ 'const',
1758
+ 'continue',
1759
+ 'default',
1760
+ 'do',
1761
+ 'double',
1762
+ 'else',
1763
+ 'enum',
1764
+ 'extends',
1765
+ 'final',
1766
+ 'finally',
1767
+ 'float',
1768
+ 'for',
1769
+ 'goto',
1770
+ 'if',
1771
+ 'implements',
1772
+ 'import',
1773
+ 'instanceof',
1774
+ 'int',
1775
+ 'interface',
1776
+ 'long',
1777
+ 'native',
1778
+ 'new',
1779
+ 'package',
1780
+ 'private',
1781
+ 'protected',
1782
+ 'public',
1783
+ 'return',
1784
+ 'short',
1785
+ 'static',
1786
+ 'strictfp',
1787
+ 'super',
1788
+ 'switch',
1789
+ 'synchronized',
1790
+ 'this',
1791
+ 'throw',
1792
+ 'throws',
1793
+ 'transient',
1794
+ 'try',
1795
+ 'void',
1796
+ 'volatile',
1797
+ 'while',
1798
+ ]),
1799
+
1800
+ golang: new Set([
1801
+ 'break',
1802
+ 'case',
1803
+ 'chan',
1804
+ 'const',
1805
+ 'continue',
1806
+ 'default',
1807
+ 'defer',
1808
+ 'else',
1809
+ 'fallthrough',
1810
+ 'for',
1811
+ 'func',
1812
+ 'go',
1813
+ 'goto',
1814
+ 'if',
1815
+ 'import',
1816
+ 'interface',
1817
+ 'map',
1818
+ 'package',
1819
+ 'range',
1820
+ 'return',
1821
+ 'select',
1822
+ 'struct',
1823
+ 'switch',
1824
+ 'type',
1825
+ 'var',
1826
+ ]),
1827
+
1828
+ c: new Set([
1829
+ 'auto',
1830
+ 'break',
1831
+ 'case',
1832
+ 'char',
1833
+ 'const',
1834
+ 'continue',
1835
+ 'default',
1836
+ 'do',
1837
+ 'double',
1838
+ 'else',
1839
+ 'enum',
1840
+ 'extern',
1841
+ 'float',
1842
+ 'for',
1843
+ 'goto',
1844
+ 'if',
1845
+ 'int',
1846
+ 'long',
1847
+ 'register',
1848
+ 'return',
1849
+ 'short',
1850
+ 'signed',
1851
+ 'sizeof',
1852
+ 'static',
1853
+ 'struct',
1854
+ 'switch',
1855
+ 'typedef',
1856
+ 'union',
1857
+ 'unsigned',
1858
+ 'void',
1859
+ 'volatile',
1860
+ 'while',
1861
+ ]),
1862
+
1863
+ cpp: new Set([
1864
+ 'alignas',
1865
+ 'alignof',
1866
+ 'and',
1867
+ 'auto',
1868
+ 'bool',
1869
+ 'break',
1870
+ 'case',
1871
+ 'catch',
1872
+ 'class',
1873
+ 'const',
1874
+ 'constexpr',
1875
+ 'continue',
1876
+ 'delete',
1877
+ 'do',
1878
+ 'double',
1879
+ 'else',
1880
+ 'enum',
1881
+ 'explicit',
1882
+ 'export',
1883
+ 'extern',
1884
+ 'false',
1885
+ 'float',
1886
+ 'for',
1887
+ 'friend',
1888
+ 'if',
1889
+ 'inline',
1890
+ 'int',
1891
+ 'long',
1892
+ 'mutable',
1893
+ 'namespace',
1894
+ 'new',
1895
+ 'noexcept',
1896
+ 'nullptr',
1897
+ 'operator',
1898
+ 'private',
1899
+ 'protected',
1900
+ 'public',
1901
+ 'return',
1902
+ 'short',
1903
+ 'signed',
1904
+ 'sizeof',
1905
+ 'static',
1906
+ 'struct',
1907
+ 'switch',
1908
+ 'template',
1909
+ 'this',
1910
+ 'throw',
1911
+ 'true',
1912
+ 'try',
1913
+ 'typedef',
1914
+ 'typename',
1915
+ 'union',
1916
+ 'unsigned',
1917
+ 'using',
1918
+ 'virtual',
1919
+ 'void',
1920
+ 'while',
1921
+ ]),
1922
+
1923
+ php: new Set([
1924
+ 'abstract',
1925
+ 'and',
1926
+ 'array',
1927
+ 'as',
1928
+ 'break',
1929
+ 'callable',
1930
+ 'case',
1931
+ 'catch',
1932
+ 'class',
1933
+ 'clone',
1934
+ 'const',
1935
+ 'continue',
1936
+ 'declare',
1937
+ 'default',
1938
+ 'do',
1939
+ 'echo',
1940
+ 'else',
1941
+ 'elseif',
1942
+ 'empty',
1943
+ 'enddeclare',
1944
+ 'endfor',
1945
+ 'endforeach',
1946
+ 'endif',
1947
+ 'endswitch',
1948
+ 'endwhile',
1949
+ 'extends',
1950
+ 'final',
1951
+ 'finally',
1952
+ 'fn',
1953
+ 'for',
1954
+ 'foreach',
1955
+ 'function',
1956
+ 'global',
1957
+ 'goto',
1958
+ 'if',
1959
+ 'implements',
1960
+ 'include',
1961
+ 'include_once',
1962
+ 'instanceof',
1963
+ 'interface',
1964
+ 'match',
1965
+ 'namespace',
1966
+ 'new',
1967
+ 'null',
1968
+ 'or',
1969
+ 'private',
1970
+ 'protected',
1971
+ 'public',
1972
+ 'require',
1973
+ 'require_once',
1974
+ 'return',
1975
+ 'static',
1976
+ 'switch',
1977
+ 'throw',
1978
+ 'trait',
1979
+ 'try',
1980
+ 'use',
1981
+ 'var',
1982
+ 'while',
1983
+ 'yield',
1984
+ ]),
1985
+
1986
+ rust: new Set([
1987
+ 'as',
1988
+ 'break',
1989
+ 'const',
1990
+ 'continue',
1991
+ 'crate',
1992
+ 'else',
1993
+ 'enum',
1994
+ 'extern',
1995
+ 'false',
1996
+ 'fn',
1997
+ 'for',
1998
+ 'if',
1999
+ 'impl',
2000
+ 'in',
2001
+ 'let',
2002
+ 'loop',
2003
+ 'match',
2004
+ 'mod',
2005
+ 'move',
2006
+ 'mut',
2007
+ 'pub',
2008
+ 'ref',
2009
+ 'return',
2010
+ 'self',
2011
+ 'Self',
2012
+ 'static',
2013
+ 'struct',
2014
+ 'super',
2015
+ 'trait',
2016
+ 'true',
2017
+ 'type',
2018
+ 'unsafe',
2019
+ 'use',
2020
+ 'where',
2021
+ 'while',
2022
+ ]),
2023
+
2024
+ html: new Set([
2025
+ 'html',
2026
+ 'head',
2027
+ 'body',
2028
+ 'div',
2029
+ 'span',
2030
+ 'p',
2031
+ 'a',
2032
+ 'img',
2033
+ 'video',
2034
+ 'audio',
2035
+ 'script',
2036
+ 'style',
2037
+ 'link',
2038
+ 'meta',
2039
+ 'form',
2040
+ 'input',
2041
+ 'button',
2042
+ 'table',
2043
+ 'tr',
2044
+ 'td',
2045
+ 'th',
2046
+ 'ul',
2047
+ 'ol',
2048
+ 'li',
2049
+ 'section',
2050
+ 'article',
2051
+ 'header',
2052
+ 'footer',
2053
+ 'nav',
2054
+ 'main',
2055
+ ]),
2056
+
2057
+ bash: new Set([
2058
+ 'if',
2059
+ 'then',
2060
+ 'else',
2061
+ 'elif',
2062
+ 'fi',
2063
+ 'for',
2064
+ 'while',
2065
+ 'do',
2066
+ 'done',
2067
+ 'case',
2068
+ 'esac',
2069
+ 'function',
2070
+ 'in',
2071
+ 'select',
2072
+ 'until',
2073
+ 'break',
2074
+ 'continue',
2075
+ 'return',
2076
+ 'export',
2077
+ 'readonly',
2078
+ 'local',
2079
+ 'declare',
2080
+ ]),
2081
+
2082
+ markdown: new Set(['#', '##', '###', '####', '#####', '######']),
2083
+ };
2084
+
2085
+ if (!lang || lang === 'txt' || lang === 'text' || lang === 'plaintext') {
2086
+ return {
2087
+ codeBlock: [
2088
+ {
2089
+ codeContent: code,
2090
+ highlightType: 0,
2091
+ },
2092
+ ],
2093
+ unified_codeBlock: [
2094
+ {
2095
+ content: code,
2096
+ type: 'DEFAULT',
2097
+ },
2098
+ ],
2099
+ };
2100
+ }
2101
+
2102
+ const TYPE_MAP = {
2103
+ 0: 'DEFAULT',
2104
+ 1: 'KEYWORD',
2105
+ 2: 'METHOD',
2106
+ 3: 'STR',
2107
+ 4: 'NUMBER',
2108
+ 5: 'COMMENT',
2109
+ };
2110
+
2111
+ const keywords = keywordsMap[lang.toLowerCase()] || new Set();
2112
+ const tokens = [];
2113
+
2114
+ let i = 0;
2115
+
2116
+ const push = (content, type) => {
2117
+ if (!content) return;
2118
+
2119
+ const last = tokens[tokens.length - 1];
2120
+
2121
+ if (last && last.highlightType === type) {
2122
+ last.codeContent += content;
2123
+ } else {
2124
+ tokens.push({
2125
+ codeContent: content,
2126
+ highlightType: type,
2127
+ });
2128
+ }
2129
+ };
2130
+
2131
+ const isIdentifier = (char) => {
2132
+ switch (lang.toLowerCase()) {
2133
+ case 'css':
2134
+ return /[a-zA-Z0-9_$-]/.test(char);
2135
+
2136
+ case 'html':
2137
+ return /[a-zA-Z0-9_$:-]/.test(char);
2138
+
2139
+ default:
2140
+ return /[a-zA-Z0-9_$]/.test(char);
2141
+ }
2142
+ };
2143
+
2144
+ while (i < code.length) {
2145
+ const c = code[i];
2146
+
2147
+ if (/\s/.test(c)) {
2148
+ let s = i;
2149
+
2150
+ while (i < code.length && /\s/.test(code[i])) {
2151
+ i++;
2152
+ }
2153
+
2154
+ push(code.slice(s, i), 0);
2155
+ continue;
2156
+ }
2157
+
2158
+ if ((c === '/' && code[i + 1] === '/') || (c === '#' && ['python', 'bash'].includes(lang))) {
2159
+ let s = i;
2160
+
2161
+ while (i < code.length && code[i] !== '\n') {
2162
+ i++;
2163
+ }
2164
+
2165
+ push(code.slice(s, i), 5);
2166
+ continue;
2167
+ }
2168
+
2169
+ if (c === '"' || c === "'" || c === '`') {
2170
+ let s = i;
2171
+ const q = c;
2172
+
2173
+ i++;
2174
+
2175
+ while (i < code.length) {
2176
+ if (code[i] === '\\' && i + 1 < code.length) {
2177
+ i += 2;
2178
+ } else if (code[i] === q) {
2179
+ i++;
2180
+ break;
2181
+ } else {
2182
+ i++;
2183
+ }
2184
+ }
2185
+
2186
+ push(code.slice(s, i), 3);
2187
+ continue;
2188
+ }
2189
+
2190
+ if (/[0-9]/.test(c)) {
2191
+ let s = i;
2192
+
2193
+ while (i < code.length && /[0-9._]/.test(code[i])) {
2194
+ i++;
2195
+ }
2196
+
2197
+ push(code.slice(s, i), 4);
2198
+ continue;
2199
+ }
2200
+
2201
+ if (/[a-zA-Z_$]/.test(c)) {
2202
+ let s = i;
2203
+
2204
+ while (i < code.length && isIdentifier(code[i])) {
2205
+ i++;
2206
+ }
2207
+
2208
+ const word = code.slice(s, i);
2209
+
2210
+ let type = 0;
2211
+
2212
+ if (keywords.has(word)) {
2213
+ type = 1;
2214
+ } else if (lang === 'css') {
2215
+ let j = i;
2216
+
2217
+ while (j < code.length && /\s/.test(code[j])) {
2218
+ j++;
2219
+ }
2220
+
2221
+ if (code[j] === ':') {
2222
+ type = 1;
2223
+ }
2224
+ } else if (lang === 'html') {
2225
+ let p = s - 1;
2226
+
2227
+ while (p >= 0 && /\s/.test(code[p])) {
2228
+ p--;
2229
+ }
2230
+
2231
+ if (code[p] === '<' || (code[p] === '/' && code[p - 1] === '<')) {
2232
+ type = 1;
2233
+ }
2234
+ }
2235
+
2236
+ if (type === 0) {
2237
+ let j = i;
2238
+
2239
+ while (j < code.length && /\s/.test(code[j])) {
2240
+ j++;
2241
+ }
2242
+
2243
+ if (code[j] === '(') {
2244
+ type = 2;
2245
+ }
2246
+ }
2247
+
2248
+ push(word, type);
2249
+ continue;
2250
+ }
2251
+
2252
+ push(c, 0);
2253
+ i++;
2254
+ }
2255
+
2256
+ return {
2257
+ codeBlock: tokens,
2258
+ unified_codeBlock: tokens.map((t) => ({
2259
+ content: t.codeContent,
2260
+ type: TYPE_MAP[t.highlightType],
2261
+ })),
2262
+ };
2263
+ }
2264
+
2265
+ static toTableMetadata(arr, { hyperlink = true, citation = true, latex = true } = {}) {
2266
+ if (!Array.isArray(arr) || !arr.every((row) => Array.isArray(row) && row.every((cell) => typeof cell === 'string'))) {
2267
+ throw new TypeError('Table must be a nested array of strings');
2268
+ }
2269
+
2270
+ const [header, ...rows] = arr;
2271
+
2272
+ const maxLen = Math.max(header.length, ...rows.map((r) => r.length));
2273
+
2274
+ const normalize = (r) => [...r, ...Array(maxLen - r.length).fill('')];
2275
+
2276
+ const unified_rows = [
2277
+ {
2278
+ is_header: true,
2279
+ cells: normalize(header),
2280
+ },
2281
+ ...rows.map((r) => ({
2282
+ is_header: false,
2283
+ cells: normalize(r),
2284
+ })),
2285
+ ].map((row) => {
2286
+ const markdown_cells = row.cells.map((cell) => {
2287
+ const extracted = extractIE(cell, { hyperlink, citation, latex });
2288
+
2289
+ return {
2290
+ text: extracted.text,
2291
+ ...(extracted.inline_entities.length ? { inline_entities: extracted.inline_entities } : {}),
2292
+ };
2293
+ });
2294
+
2295
+ return {
2296
+ ...row,
2297
+ ...(markdown_cells.some((c) => c.inline_entities?.length) ? { markdown_cells } : {}),
2298
+ };
2299
+ });
2300
+
2301
+ const rowsMeta = unified_rows.map((r) => ({
2302
+ items: r.cells,
2303
+ ...(r.is_header ? { isHeading: true } : {}),
2304
+ }));
2305
+
2306
+ return {
2307
+ title: '',
2308
+ rows: rowsMeta,
2309
+ unified_rows,
2310
+ };
2311
+ }
2312
+
2313
+ static newLayout(name, data, extra = {}) {
2314
+ return {
2315
+ ...extra,
2316
+ view_model: {
2317
+ [Array.isArray(data) ? 'primitives' : 'primitive']: data,
2318
+ __typename: `GenAI${name}LayoutViewModel`,
2319
+ },
2320
+ };
2321
+ }
2322
+ text(t) { return this.addText(t); }
2323
+
2324
+ }
2325
+
2326
+ class ORich extends AIRich { }
2327
+
2328
+
2329
+
2330
+ export { VERSION, Button, ButtonV2, Carousel, AIRich, ORich, Toolkit };