vinnleys 1.0.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.
- package/README.md +108 -0
- package/WAProto/GenerateStatics.sh +3 -0
- package/WAProto/WAProto.proto +6922 -0
- package/WAProto/fix-imports.js +85 -0
- package/WAProto/index.d.ts +79257 -0
- package/WAProto/index.js +242946 -0
- package/engine-requirements.js +10 -0
- package/lib/Defaults/index.js +131 -0
- package/lib/Signal/Group/ciphertext-message.js +12 -0
- package/lib/Signal/Group/group-session-builder.js +30 -0
- package/lib/Signal/Group/group_cipher.js +82 -0
- package/lib/Signal/Group/index.js +12 -0
- package/lib/Signal/Group/keyhelper.js +18 -0
- package/lib/Signal/Group/sender-chain-key.js +26 -0
- package/lib/Signal/Group/sender-key-distribution-message.js +63 -0
- package/lib/Signal/Group/sender-key-message.js +66 -0
- package/lib/Signal/Group/sender-key-name.js +48 -0
- package/lib/Signal/Group/sender-key-record.js +41 -0
- package/lib/Signal/Group/sender-key-state.js +84 -0
- package/lib/Signal/Group/sender-message-key.js +26 -0
- package/lib/Signal/libsignal.js +431 -0
- package/lib/Signal/lid-mapping.js +277 -0
- package/lib/Socket/Client/index.js +3 -0
- package/lib/Socket/Client/types.js +11 -0
- package/lib/Socket/Client/websocket.js +54 -0
- package/lib/Socket/MessageBuilder.js +3728 -0
- package/lib/Socket/business.js +379 -0
- package/lib/Socket/chats.js +1198 -0
- package/lib/Socket/communities.js +431 -0
- package/lib/Socket/graphql.js +716 -0
- package/lib/Socket/groups.js +374 -0
- package/lib/Socket/index.js +24 -0
- package/lib/Socket/interop.js +463 -0
- package/lib/Socket/luxu.js +387 -0
- package/lib/Socket/message-builder.js +521 -0
- package/lib/Socket/messages-recv.js +1916 -0
- package/lib/Socket/messages-send.js +1511 -0
- package/lib/Socket/mex.js +54 -0
- package/lib/Socket/newsletter.js +636 -0
- package/lib/Socket/privacy.js +318 -0
- package/lib/Socket/socket.js +1114 -0
- package/lib/Socket/username.js +236 -0
- package/lib/Store/index.js +10 -0
- package/lib/Store/keyed-db.js +108 -0
- package/lib/Store/make-cache-manager-store.js +85 -0
- package/lib/Store/make-in-memory-store.js +244 -0
- package/lib/Store/make-ordered-dictionary.js +75 -0
- package/lib/Store/object-repository.js +32 -0
- package/lib/Types/Auth.js +2 -0
- package/lib/Types/Bussines.js +2 -0
- package/lib/Types/Call.js +2 -0
- package/lib/Types/Chat.js +8 -0
- package/lib/Types/Contact.js +2 -0
- package/lib/Types/Events.js +2 -0
- package/lib/Types/GroupMetadata.js +2 -0
- package/lib/Types/Label.js +25 -0
- package/lib/Types/LabelAssociation.js +7 -0
- package/lib/Types/Message.js +11 -0
- package/lib/Types/Mex.js +111 -0
- package/lib/Types/Product.js +2 -0
- package/lib/Types/Signal.js +2 -0
- package/lib/Types/Socket.js +3 -0
- package/lib/Types/State.js +56 -0
- package/lib/Types/USync.js +2 -0
- package/lib/Types/index.js +26 -0
- package/lib/Utils/auth-utils.js +302 -0
- package/lib/Utils/browser-utils.js +48 -0
- package/lib/Utils/business.js +231 -0
- package/lib/Utils/chat-utils.js +872 -0
- package/lib/Utils/companion-reg-client-utils.js +35 -0
- package/lib/Utils/crypto.js +118 -0
- package/lib/Utils/decode-wa-message.js +350 -0
- package/lib/Utils/event-buffer.js +622 -0
- package/lib/Utils/generics.js +403 -0
- package/lib/Utils/history.js +134 -0
- package/lib/Utils/identity-change-handler.js +50 -0
- package/lib/Utils/index.js +24 -0
- package/lib/Utils/link-preview.js +85 -0
- package/lib/Utils/logger.js +3 -0
- package/lib/Utils/lt-hash.js +8 -0
- package/lib/Utils/make-mutex.js +33 -0
- package/lib/Utils/message-composer.js +273 -0
- package/lib/Utils/message-retry-manager.js +265 -0
- package/lib/Utils/messages-media.js +870 -0
- package/lib/Utils/messages.js +1394 -0
- package/lib/Utils/noise-handler.js +201 -0
- package/lib/Utils/offline-node-processor.js +40 -0
- package/lib/Utils/pre-key-manager.js +106 -0
- package/lib/Utils/process-message.js +630 -0
- package/lib/Utils/reporting-utils.js +258 -0
- package/lib/Utils/signal.js +201 -0
- package/lib/Utils/stanza-ack.js +38 -0
- package/lib/Utils/sticker.js +133 -0
- package/lib/Utils/sync-action-utils.js +49 -0
- package/lib/Utils/tc-token-utils.js +163 -0
- package/lib/Utils/use-multi-file-auth-state.js +121 -0
- package/lib/Utils/use-sqlite-auth-state.js +162 -0
- package/lib/Utils/validate-connection.js +203 -0
- package/lib/WABinary/constants.js +1301 -0
- package/lib/WABinary/decode.js +262 -0
- package/lib/WABinary/encode.js +220 -0
- package/lib/WABinary/generic-utils.js +204 -0
- package/lib/WABinary/index.js +6 -0
- package/lib/WABinary/jid-utils.js +98 -0
- package/lib/WABinary/types.js +2 -0
- package/lib/WAM/BinaryInfo.js +10 -0
- package/lib/WAM/constants.js +22853 -0
- package/lib/WAM/encode.js +150 -0
- package/lib/WAM/index.js +4 -0
- package/lib/WAUSync/Protocols/USyncBotProfileProtocol.js +53 -0
- package/lib/WAUSync/Protocols/USyncBusinessProtocol.js +43 -0
- package/lib/WAUSync/Protocols/USyncContactProtocol.js +54 -0
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +57 -0
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +30 -0
- package/lib/WAUSync/Protocols/USyncFeatureProtocol.js +58 -0
- package/lib/WAUSync/Protocols/USyncLIDProtocol.js +30 -0
- package/lib/WAUSync/Protocols/USyncPictureProtocol.js +32 -0
- package/lib/WAUSync/Protocols/USyncSidelistProtocol.js +28 -0
- package/lib/WAUSync/Protocols/USyncStatusProtocol.js +39 -0
- package/lib/WAUSync/Protocols/USyncTextStatusProtocol.js +38 -0
- package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +27 -0
- package/lib/WAUSync/Protocols/index.js +12 -0
- package/lib/WAUSync/USyncQuery.js +151 -0
- package/lib/WAUSync/USyncUser.js +56 -0
- package/lib/WAUSync/index.js +3 -0
- package/lib/index.js +33 -0
- package/package.json +135 -0
|
@@ -0,0 +1,3728 @@
|
|
|
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 Baileys with
|
|
7
|
+
* fluent chaining, flexible payload customization,
|
|
8
|
+
* and scalable architecture for modern bot development.
|
|
9
|
+
*
|
|
10
|
+
* Runtime:
|
|
11
|
+
* - Baileys: @whiskeysockets/baileys (latest)
|
|
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.7";
|
|
33
|
+
|
|
34
|
+
const {
|
|
35
|
+
generateWAMessageFromContent,
|
|
36
|
+
prepareWAMessageMedia,
|
|
37
|
+
generateMessageIDV2,
|
|
38
|
+
} = require("../index.js");
|
|
39
|
+
const crypto = require("crypto");
|
|
40
|
+
const sharp = require("sharp");
|
|
41
|
+
const ffmpeg = require("fluent-ffmpeg");
|
|
42
|
+
const { PassThrough, Readable } = require("stream");
|
|
43
|
+
|
|
44
|
+
function extractIE(
|
|
45
|
+
text,
|
|
46
|
+
{ extract = true, hyperlink = true, citation = true, latex = true } = {},
|
|
47
|
+
) {
|
|
48
|
+
if (!extract) {
|
|
49
|
+
return {
|
|
50
|
+
text,
|
|
51
|
+
ie: [],
|
|
52
|
+
inline_entities: [],
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const createIE = (type, ie) => {
|
|
57
|
+
if (type == "hyperlink") {
|
|
58
|
+
return {
|
|
59
|
+
key: ie.key,
|
|
60
|
+
metadata: {
|
|
61
|
+
display_name: ie.text,
|
|
62
|
+
is_trusted: ie.is_trusted,
|
|
63
|
+
url: ie.url,
|
|
64
|
+
__typename: "GenAIInlineLinkItem",
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (type == "citation") {
|
|
70
|
+
return {
|
|
71
|
+
key: ie.key,
|
|
72
|
+
metadata: {
|
|
73
|
+
reference_id: ie.reference_id,
|
|
74
|
+
reference_url: ie.url,
|
|
75
|
+
reference_title: ie.url,
|
|
76
|
+
reference_display_name: ie.url,
|
|
77
|
+
sources: [],
|
|
78
|
+
__typename: "GenAISearchCitationItem",
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (type == "latex") {
|
|
84
|
+
return {
|
|
85
|
+
key: ie.key,
|
|
86
|
+
metadata: {
|
|
87
|
+
latex_expression: ie.text,
|
|
88
|
+
latex_image: {
|
|
89
|
+
url: ie.url,
|
|
90
|
+
width: Number(ie.width) || 100,
|
|
91
|
+
height: Number(ie.height) || 100,
|
|
92
|
+
},
|
|
93
|
+
font_height: Number(ie.font_height) || 83.333333333333,
|
|
94
|
+
padding: Number(ie.padding) || 15,
|
|
95
|
+
__typename: "GenAILatexItem",
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
let ie = [];
|
|
102
|
+
let inline_entities = [];
|
|
103
|
+
let result = "";
|
|
104
|
+
let last = 0;
|
|
105
|
+
let citation_index = 1;
|
|
106
|
+
let hyperlink_index = 0;
|
|
107
|
+
let latex_index = 0;
|
|
108
|
+
let stack = [];
|
|
109
|
+
|
|
110
|
+
for (let i = 0; i < text.length; i++) {
|
|
111
|
+
if (text[i] == "[" && text[i - 1] != "\\") {
|
|
112
|
+
stack.push(i);
|
|
113
|
+
} else if (text[i] == "]" && (text[i + 1] == "(" || text[i + 1] == "<")) {
|
|
114
|
+
let start = stack.pop();
|
|
115
|
+
|
|
116
|
+
if (start == null) continue;
|
|
117
|
+
|
|
118
|
+
let open = text[i + 1];
|
|
119
|
+
let close = open == "(" ? ")" : ">";
|
|
120
|
+
let type = open == "(" ? "link" : "latex";
|
|
121
|
+
let end = i + 2;
|
|
122
|
+
let depth = 1;
|
|
123
|
+
|
|
124
|
+
while (end < text.length && depth) {
|
|
125
|
+
if (text[end] == open && text[end - 1] != "\\") depth++;
|
|
126
|
+
else if (text[end] == close && text[end - 1] != "\\") depth--;
|
|
127
|
+
end++;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (depth) continue;
|
|
131
|
+
|
|
132
|
+
let raw = text.slice(start + 1, i).trim();
|
|
133
|
+
let url = text.slice(i + 2, end - 1).trim();
|
|
134
|
+
|
|
135
|
+
let key;
|
|
136
|
+
let tag;
|
|
137
|
+
let data;
|
|
138
|
+
|
|
139
|
+
if (type == "latex") {
|
|
140
|
+
if (!latex) continue;
|
|
141
|
+
|
|
142
|
+
let [
|
|
143
|
+
txt = "",
|
|
144
|
+
width = null,
|
|
145
|
+
height = null,
|
|
146
|
+
font_height = null,
|
|
147
|
+
padding = null,
|
|
148
|
+
] = raw.split("|");
|
|
149
|
+
|
|
150
|
+
key = `\u004E\u0049\u0058\u0045\u004C_LATEX_${latex_index++}`;
|
|
151
|
+
tag = `{{${key}}}${txt || "image"}{{/${key}}}`;
|
|
152
|
+
|
|
153
|
+
data = {
|
|
154
|
+
type: "latex",
|
|
155
|
+
ie: {
|
|
156
|
+
key,
|
|
157
|
+
text: txt,
|
|
158
|
+
url,
|
|
159
|
+
width,
|
|
160
|
+
height,
|
|
161
|
+
font_height,
|
|
162
|
+
padding,
|
|
163
|
+
},
|
|
164
|
+
};
|
|
165
|
+
} else if (raw) {
|
|
166
|
+
if (!hyperlink) continue;
|
|
167
|
+
|
|
168
|
+
const trusted = !url.startsWith("!");
|
|
169
|
+
|
|
170
|
+
if (!trusted) {
|
|
171
|
+
url = url.slice(1);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
key = `\u004E\u0049\u0058\u0045\u004C_HYPERLINK_${hyperlink_index++}`;
|
|
175
|
+
tag = `{{${key}}}${url}{{/${key}}}`;
|
|
176
|
+
|
|
177
|
+
data = {
|
|
178
|
+
type: "hyperlink",
|
|
179
|
+
ie: {
|
|
180
|
+
key,
|
|
181
|
+
text: raw,
|
|
182
|
+
url,
|
|
183
|
+
is_trusted: trusted,
|
|
184
|
+
},
|
|
185
|
+
};
|
|
186
|
+
} else {
|
|
187
|
+
if (!citation) continue;
|
|
188
|
+
|
|
189
|
+
key = `\u004E\u0049\u0058\u0045\u004C_CITATION_${citation_index - 1}`;
|
|
190
|
+
tag = `{{${key}}}${url}{{/${key}}}`;
|
|
191
|
+
|
|
192
|
+
data = {
|
|
193
|
+
type: "citation",
|
|
194
|
+
ie: {
|
|
195
|
+
reference_id: citation_index++,
|
|
196
|
+
key,
|
|
197
|
+
text: "",
|
|
198
|
+
url,
|
|
199
|
+
},
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
result += text.slice(last, start) + tag;
|
|
204
|
+
last = end;
|
|
205
|
+
|
|
206
|
+
ie.push(data);
|
|
207
|
+
|
|
208
|
+
const entity = createIE(data.type, data.ie);
|
|
209
|
+
|
|
210
|
+
if (entity) {
|
|
211
|
+
inline_entities.push(entity);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
i = end - 1;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
result += text.slice(last);
|
|
219
|
+
|
|
220
|
+
return {
|
|
221
|
+
text: result,
|
|
222
|
+
ie,
|
|
223
|
+
inline_entities,
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
async function waitAllPromises(input) {
|
|
228
|
+
const isPromise = (v) => v && typeof v.then === "function";
|
|
229
|
+
const isObject = (v) => v && typeof v === "object";
|
|
230
|
+
|
|
231
|
+
const deep = async (v) => {
|
|
232
|
+
if (isPromise(v)) return deep(await v);
|
|
233
|
+
if (Array.isArray(v)) return Promise.all(v.map(deep));
|
|
234
|
+
if (isObject(v)) {
|
|
235
|
+
const entries = await Promise.all(
|
|
236
|
+
Object.entries(v).map(async ([k, val]) => [k, await deep(val)]),
|
|
237
|
+
);
|
|
238
|
+
return Object.fromEntries(entries);
|
|
239
|
+
}
|
|
240
|
+
return v;
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
return deep(await input);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
class AIRichError extends Error {
|
|
247
|
+
constructor(message, code, meta = {}) {
|
|
248
|
+
super(message);
|
|
249
|
+
this.name = "AIRichError";
|
|
250
|
+
this.code = code;
|
|
251
|
+
Object.assign(this, meta);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
class ItemNotFoundError extends AIRichError {
|
|
256
|
+
constructor(id, availableIds = []) {
|
|
257
|
+
super(
|
|
258
|
+
`Item id "${id}" not found${availableIds.length ? ` (available: ${availableIds.join(", ")})` : " (no items have an id yet)"}`,
|
|
259
|
+
"ITEM_NOT_FOUND",
|
|
260
|
+
{ id, availableIds },
|
|
261
|
+
);
|
|
262
|
+
this.name = "ItemNotFoundError";
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
class DuplicateIdError extends AIRichError {
|
|
267
|
+
constructor(id) {
|
|
268
|
+
super(`Item id "${id}" already exists`, "DUPLICATE_ID", { id });
|
|
269
|
+
this.name = "DuplicateIdError";
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
class InvalidTargetError extends AIRichError {
|
|
274
|
+
constructor(message, meta = {}) {
|
|
275
|
+
super(message, "INVALID_TARGET", meta);
|
|
276
|
+
this.name = "InvalidTargetError";
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
class ContentValidationError extends AIRichError {
|
|
281
|
+
constructor(message, meta = {}) {
|
|
282
|
+
super(message, "CONTENT_VALIDATION", meta);
|
|
283
|
+
this.name = "ContentValidationError";
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
class Toolkit {
|
|
288
|
+
constructor() {}
|
|
289
|
+
|
|
290
|
+
static extractIE(
|
|
291
|
+
text,
|
|
292
|
+
{ extract = true, hyperlink = true, citation = true, latex = true } = {},
|
|
293
|
+
) {
|
|
294
|
+
return extractIE(text, { extract, hyperlink, citation, latex });
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
static async resize(buffer, x, y, fit = "cover") {
|
|
298
|
+
return await sharp(buffer)
|
|
299
|
+
.resize(x, y, {
|
|
300
|
+
fit,
|
|
301
|
+
position: "center",
|
|
302
|
+
background: { r: 0, g: 0, b: 0, alpha: 0 },
|
|
303
|
+
})
|
|
304
|
+
.png()
|
|
305
|
+
.toBuffer();
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
static async waitAllPromises(input) {
|
|
309
|
+
return await waitAllPromises(input);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
static async fetchBuffer(url, options = {}, { silent = true } = {}) {
|
|
313
|
+
try {
|
|
314
|
+
let response = await fetch(url, options);
|
|
315
|
+
if (!response.ok) throw Error(`HTTP ${response.status}`);
|
|
316
|
+
return Buffer.from(await response.arrayBuffer());
|
|
317
|
+
} catch (error) {
|
|
318
|
+
if (silent) return Buffer.alloc(0);
|
|
319
|
+
throw error;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
static async toUrl(_client, path, mediaType = "document") {
|
|
324
|
+
if (!path) throw new Error("Url or buffer needed");
|
|
325
|
+
|
|
326
|
+
const media = await prepareWAMessageMedia(
|
|
327
|
+
{
|
|
328
|
+
[mediaType]: Buffer.isBuffer(path) ? path : { url: path },
|
|
329
|
+
},
|
|
330
|
+
{
|
|
331
|
+
upload: _client.waUploadToServer,
|
|
332
|
+
jid: "\u0040\u006e\u0065\u0077\u0073\u006c\u0065\u0074\u0074\u0065\u0072",
|
|
333
|
+
},
|
|
334
|
+
);
|
|
335
|
+
|
|
336
|
+
return Object.values(media)[0]?.url;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
static async resolveMedia(
|
|
340
|
+
_client,
|
|
341
|
+
media,
|
|
342
|
+
mediaType = "image",
|
|
343
|
+
{
|
|
344
|
+
resolveUrl = false,
|
|
345
|
+
resolveWAUrl = false,
|
|
346
|
+
result = "url",
|
|
347
|
+
resize = false,
|
|
348
|
+
width = 300,
|
|
349
|
+
height = 300,
|
|
350
|
+
} = {},
|
|
351
|
+
) {
|
|
352
|
+
const isUrl = (str) => /^https?:\/\/.+/i.test(str);
|
|
353
|
+
|
|
354
|
+
const isWAUrl = (str) => /^https?:\/\/[^/]*\.whatsapp\.net\//i.test(str);
|
|
355
|
+
|
|
356
|
+
if (Array.isArray(media)) {
|
|
357
|
+
return Promise.all(
|
|
358
|
+
media.map((item) =>
|
|
359
|
+
Toolkit.resolveMedia(_client, item, mediaType, {
|
|
360
|
+
resolveUrl,
|
|
361
|
+
resolveWAUrl,
|
|
362
|
+
result,
|
|
363
|
+
resize,
|
|
364
|
+
width,
|
|
365
|
+
height,
|
|
366
|
+
}),
|
|
367
|
+
),
|
|
368
|
+
);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
const originalIsBuffer = Buffer.isBuffer(media);
|
|
372
|
+
|
|
373
|
+
if (typeof media === "string" && isUrl(media)) {
|
|
374
|
+
if (isWAUrl(media)) {
|
|
375
|
+
if (resolveWAUrl) {
|
|
376
|
+
media = await Toolkit.fetchBuffer(media, {}, { silent: true });
|
|
377
|
+
} else if (!resolveUrl) {
|
|
378
|
+
if (result === "url") return media;
|
|
379
|
+
|
|
380
|
+
media = await Toolkit.fetchBuffer(media, {}, { silent: true });
|
|
381
|
+
}
|
|
382
|
+
} else {
|
|
383
|
+
if (!resolveUrl) {
|
|
384
|
+
if (result === "url") return media;
|
|
385
|
+
|
|
386
|
+
media = await Toolkit.fetchBuffer(media, {}, { silent: true });
|
|
387
|
+
} else {
|
|
388
|
+
media = await Toolkit.fetchBuffer(media, {}, { silent: true });
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
if (typeof media === "string" && !isUrl(media)) {
|
|
394
|
+
media = Buffer.from(media, "base64");
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
if (!Buffer.isBuffer(media) || !media.length) {
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
if (resize && Buffer.isBuffer(media)) {
|
|
402
|
+
media = await Toolkit.resize(media, width, height);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
if (result === "buffer") {
|
|
406
|
+
return media;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
if (result === "base64") {
|
|
410
|
+
return media.toString("base64");
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
if (originalIsBuffer) {
|
|
414
|
+
return Toolkit.toUrl(_client, media, mediaType);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
return Toolkit.toUrl(_client, media, mediaType);
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
static getMp4Duration(buffer, { silent = true } = {}) {
|
|
421
|
+
try {
|
|
422
|
+
if (!Buffer.isBuffer(buffer) || buffer.length < 8) {
|
|
423
|
+
if (silent) return 0;
|
|
424
|
+
throw new Error("Invalid buffer");
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
let offset = 0;
|
|
428
|
+
|
|
429
|
+
while (offset < buffer.length - 8) {
|
|
430
|
+
const size = buffer.readUInt32BE(offset);
|
|
431
|
+
|
|
432
|
+
if (size < 8 || offset + size > buffer.length) {
|
|
433
|
+
if (silent) return 0;
|
|
434
|
+
throw new Error("Invalid atom size");
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
const type = buffer.toString("ascii", offset + 4, offset + 8);
|
|
438
|
+
|
|
439
|
+
if (type === "moov") {
|
|
440
|
+
let moovOffset = offset + 8;
|
|
441
|
+
const moovEnd = offset + size;
|
|
442
|
+
|
|
443
|
+
while (moovOffset < moovEnd - 8) {
|
|
444
|
+
const childSize = buffer.readUInt32BE(moovOffset);
|
|
445
|
+
|
|
446
|
+
if (childSize < 8 || moovOffset + childSize > moovEnd) {
|
|
447
|
+
if (silent) return 0;
|
|
448
|
+
throw new Error("Invalid child atom size");
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
const childType = buffer.toString(
|
|
452
|
+
"ascii",
|
|
453
|
+
moovOffset + 4,
|
|
454
|
+
moovOffset + 8,
|
|
455
|
+
);
|
|
456
|
+
|
|
457
|
+
if (childType === "mvhd") {
|
|
458
|
+
const version = buffer.readUInt8(moovOffset + 8);
|
|
459
|
+
|
|
460
|
+
if (version === 0) {
|
|
461
|
+
const timescale = buffer.readUInt32BE(moovOffset + 20);
|
|
462
|
+
const duration = buffer.readUInt32BE(moovOffset + 24);
|
|
463
|
+
|
|
464
|
+
if (!timescale) {
|
|
465
|
+
if (silent) return 0;
|
|
466
|
+
throw new Error("Invalid timescale");
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
return duration / timescale;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
if (version === 1) {
|
|
473
|
+
const timescale = buffer.readUInt32BE(moovOffset + 32);
|
|
474
|
+
const duration = Number(
|
|
475
|
+
buffer.readBigUInt64BE(moovOffset + 36),
|
|
476
|
+
);
|
|
477
|
+
|
|
478
|
+
if (!timescale) {
|
|
479
|
+
if (silent) return 0;
|
|
480
|
+
throw new Error("Invalid timescale");
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
return duration / timescale;
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
moovOffset += childSize;
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
offset += size;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
if (silent) return 0;
|
|
495
|
+
|
|
496
|
+
throw new Error("No mvhd found!");
|
|
497
|
+
} catch (err) {
|
|
498
|
+
if (silent) return 0;
|
|
499
|
+
throw err;
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
static getMp4Preview(
|
|
504
|
+
videoBuffer,
|
|
505
|
+
{
|
|
506
|
+
time,
|
|
507
|
+
result = "buffer",
|
|
508
|
+
resize = true,
|
|
509
|
+
width = 300,
|
|
510
|
+
height = 300,
|
|
511
|
+
silent = true,
|
|
512
|
+
} = {},
|
|
513
|
+
) {
|
|
514
|
+
return new Promise((resolve, reject) => {
|
|
515
|
+
const fail = (err) => {
|
|
516
|
+
if (silent) {
|
|
517
|
+
return resolve(result === "base64" ? "" : Buffer.alloc(0));
|
|
518
|
+
}
|
|
519
|
+
return reject(err);
|
|
520
|
+
};
|
|
521
|
+
|
|
522
|
+
try {
|
|
523
|
+
if (!Buffer.isBuffer(videoBuffer) || !videoBuffer.length) {
|
|
524
|
+
return fail(new Error("videoBuffer tidak valid atau kosong"));
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
const inputStream = new Readable({ read() {} });
|
|
528
|
+
inputStream.push(videoBuffer);
|
|
529
|
+
inputStream.push(null);
|
|
530
|
+
|
|
531
|
+
const outputStream = new PassThrough();
|
|
532
|
+
const chunks = [];
|
|
533
|
+
|
|
534
|
+
outputStream.on("data", (chunk) => chunks.push(chunk));
|
|
535
|
+
|
|
536
|
+
outputStream.on("end", async () => {
|
|
537
|
+
try {
|
|
538
|
+
let output = Buffer.concat(chunks);
|
|
539
|
+
|
|
540
|
+
if (!output.length) {
|
|
541
|
+
return fail(
|
|
542
|
+
new Error("Output kosong — cek format atau timestamp video"),
|
|
543
|
+
);
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
if (resize) {
|
|
547
|
+
output = await Toolkit.resize(output, width, height);
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
return resolve(
|
|
551
|
+
result === "base64" ? output.toString("base64") : output,
|
|
552
|
+
);
|
|
553
|
+
} catch (err) {
|
|
554
|
+
return fail(err);
|
|
555
|
+
}
|
|
556
|
+
});
|
|
557
|
+
|
|
558
|
+
outputStream.on("error", fail);
|
|
559
|
+
|
|
560
|
+
time = time ?? Math.min(Toolkit.getMp4Duration(videoBuffer) * 0.2, 10);
|
|
561
|
+
|
|
562
|
+
ffmpeg(inputStream)
|
|
563
|
+
.outputOptions([
|
|
564
|
+
`-ss ${time}`,
|
|
565
|
+
"-vframes 1",
|
|
566
|
+
"-vcodec png",
|
|
567
|
+
"-f image2pipe",
|
|
568
|
+
])
|
|
569
|
+
.on("error", (err) => fail(new Error(`ffmpeg error: ${err.message}`)))
|
|
570
|
+
.pipe(outputStream, { end: true });
|
|
571
|
+
} catch (err) {
|
|
572
|
+
return fail(err);
|
|
573
|
+
}
|
|
574
|
+
});
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
static stringifyEscaped(obj) {
|
|
578
|
+
return JSON.stringify(obj).replace(
|
|
579
|
+
/[\u007f-\uffff]/g,
|
|
580
|
+
(c) => "\\u" + c.charCodeAt(0).toString(16).padStart(4, "0"),
|
|
581
|
+
);
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
class BaseBuilder {
|
|
586
|
+
constructor() {
|
|
587
|
+
this._title = "";
|
|
588
|
+
this._subtitle = "";
|
|
589
|
+
this._body = "";
|
|
590
|
+
this._footer = "";
|
|
591
|
+
this._contextInfo = {};
|
|
592
|
+
this._extraPayload = {};
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
setTitle(title) {
|
|
596
|
+
if (typeof title !== "string") {
|
|
597
|
+
throw new TypeError("Title must be a string");
|
|
598
|
+
}
|
|
599
|
+
this._title = title;
|
|
600
|
+
return this;
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
setSubtitle(subtitle) {
|
|
604
|
+
if (typeof subtitle !== "string") {
|
|
605
|
+
throw new TypeError("Subtitle must be a string");
|
|
606
|
+
}
|
|
607
|
+
this._subtitle = subtitle;
|
|
608
|
+
return this;
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
setBody(body) {
|
|
612
|
+
if (typeof body !== "string") {
|
|
613
|
+
throw new TypeError("Body must be a string");
|
|
614
|
+
}
|
|
615
|
+
this._body = body;
|
|
616
|
+
return this;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
setFooter(footer) {
|
|
620
|
+
if (typeof footer !== "string") {
|
|
621
|
+
throw new TypeError("Footer must be a string");
|
|
622
|
+
}
|
|
623
|
+
this._footer = footer;
|
|
624
|
+
return this;
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
setContextInfo(obj) {
|
|
628
|
+
if (typeof obj !== "object" || obj === null || Array.isArray(obj)) {
|
|
629
|
+
throw new TypeError("ContextInfo must be a plain object");
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
this._contextInfo = obj;
|
|
633
|
+
return this;
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
addPayload(obj) {
|
|
637
|
+
if (typeof obj !== "object" || obj === null || Array.isArray(obj)) {
|
|
638
|
+
throw new TypeError("Payload must be a plain object");
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
Object.assign(this._extraPayload, obj);
|
|
642
|
+
|
|
643
|
+
return this;
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
class Button extends BaseBuilder {
|
|
648
|
+
#client;
|
|
649
|
+
|
|
650
|
+
constructor(client) {
|
|
651
|
+
super();
|
|
652
|
+
if (!client) {
|
|
653
|
+
throw new Error("Socket is required");
|
|
654
|
+
}
|
|
655
|
+
this.#client = client;
|
|
656
|
+
|
|
657
|
+
this._buttons = [];
|
|
658
|
+
this._data;
|
|
659
|
+
this._currentSelectionIndex = -1;
|
|
660
|
+
this._currentSectionIndex = -1;
|
|
661
|
+
this._params = {};
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
loadFrom(msg) {
|
|
665
|
+
if (!msg) throw new Error("interactiveMessage needed");
|
|
666
|
+
if (!msg.interactiveMessage)
|
|
667
|
+
throw new Error("interactiveMessage not found");
|
|
668
|
+
|
|
669
|
+
const { interactiveMessage, ...extraPayload } = msg;
|
|
670
|
+
const iM = interactiveMessage;
|
|
671
|
+
const header = iM.header || {};
|
|
672
|
+
const nativeFlow = iM.nativeFlowMessage || {};
|
|
673
|
+
|
|
674
|
+
this._title = header.title || "";
|
|
675
|
+
this._subtitle = header.subtitle || "";
|
|
676
|
+
this._body = iM.body?.text || "";
|
|
677
|
+
this._footer = iM.footer?.text || "";
|
|
678
|
+
this._contextInfo = iM.contextInfo || {};
|
|
679
|
+
this._extraPayload = extraPayload;
|
|
680
|
+
|
|
681
|
+
this._buttons = Array.isArray(nativeFlow.buttons)
|
|
682
|
+
? nativeFlow.buttons.map((button) => ({
|
|
683
|
+
...button,
|
|
684
|
+
buttonParamsJson:
|
|
685
|
+
typeof button.buttonParamsJson === "string"
|
|
686
|
+
? button.buttonParamsJson
|
|
687
|
+
: JSON.stringify(button.buttonParamsJson || {}),
|
|
688
|
+
}))
|
|
689
|
+
: [];
|
|
690
|
+
|
|
691
|
+
this._data = header.imageMessage
|
|
692
|
+
? { imageMessage: header.imageMessage }
|
|
693
|
+
: header.videoMessage
|
|
694
|
+
? { videoMessage: header.videoMessage }
|
|
695
|
+
: header.documentMessage
|
|
696
|
+
? { documentMessage: header.documentMessage }
|
|
697
|
+
: header.productMessage
|
|
698
|
+
? { productMessage: header.productMessage }
|
|
699
|
+
: undefined;
|
|
700
|
+
|
|
701
|
+
this._params = {};
|
|
702
|
+
|
|
703
|
+
if (typeof nativeFlow.messageParamsJson === "string") {
|
|
704
|
+
try {
|
|
705
|
+
this._params = JSON.parse(nativeFlow.messageParamsJson || "{}");
|
|
706
|
+
} catch {
|
|
707
|
+
this._params = {};
|
|
708
|
+
}
|
|
709
|
+
} else if (
|
|
710
|
+
nativeFlow.messageParamsJson &&
|
|
711
|
+
typeof nativeFlow.messageParamsJson === "object"
|
|
712
|
+
) {
|
|
713
|
+
this._params = { ...nativeFlow.messageParamsJson };
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
this._currentSelectionIndex = this._buttons.findLastIndex(
|
|
717
|
+
(button) => button.name === "single_select",
|
|
718
|
+
);
|
|
719
|
+
|
|
720
|
+
this._currentSectionIndex = -1;
|
|
721
|
+
|
|
722
|
+
if (this._currentSelectionIndex !== -1) {
|
|
723
|
+
try {
|
|
724
|
+
const button = this._buttons[this._currentSelectionIndex];
|
|
725
|
+
const params = JSON.parse(button.buttonParamsJson || "{}");
|
|
726
|
+
|
|
727
|
+
if (Array.isArray(params.sections) && params.sections.length) {
|
|
728
|
+
this._currentSectionIndex = params.sections.length - 1;
|
|
729
|
+
}
|
|
730
|
+
} catch {
|
|
731
|
+
this._currentSelectionIndex = -1;
|
|
732
|
+
this._currentSectionIndex = -1;
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
return this;
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
setImage(path, options = {}) {
|
|
740
|
+
if (!path) throw new Error("Url or buffer needed");
|
|
741
|
+
Buffer.isBuffer(path)
|
|
742
|
+
? (this._data = { image: path, ...options })
|
|
743
|
+
: (this._data = { image: { url: path }, ...options });
|
|
744
|
+
return this;
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
setDocument(path, options = {}) {
|
|
748
|
+
if (!path) throw new Error("Url or buffer needed");
|
|
749
|
+
Buffer.isBuffer(path)
|
|
750
|
+
? (this._data = { document: path, ...options })
|
|
751
|
+
: (this._data = { document: { url: path }, ...options });
|
|
752
|
+
return this;
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
setMedia(obj) {
|
|
756
|
+
if (typeof obj !== "object" || obj === null || Array.isArray(obj)) {
|
|
757
|
+
throw new TypeError("Media must be a plain object");
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
this._data = obj;
|
|
761
|
+
return this;
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
clearButtons() {
|
|
765
|
+
this._buttons = [];
|
|
766
|
+
return this;
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
setParams(obj) {
|
|
770
|
+
this._params = obj;
|
|
771
|
+
return this;
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
addButton(name, params) {
|
|
775
|
+
this._buttons.push({
|
|
776
|
+
name,
|
|
777
|
+
buttonParamsJson:
|
|
778
|
+
typeof params === "string" ? params : JSON.stringify(params),
|
|
779
|
+
});
|
|
780
|
+
|
|
781
|
+
return this;
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
makeRow(header = "", title = "", description = "", id = "") {
|
|
785
|
+
if (
|
|
786
|
+
this._currentSelectionIndex === -1 ||
|
|
787
|
+
this._currentSectionIndex === -1
|
|
788
|
+
) {
|
|
789
|
+
throw new Error("You need to create a selection and a section first");
|
|
790
|
+
}
|
|
791
|
+
const buttonParams = JSON.parse(
|
|
792
|
+
this._buttons[this._currentSelectionIndex].buttonParamsJson,
|
|
793
|
+
);
|
|
794
|
+
buttonParams.sections[this._currentSectionIndex].rows.push({
|
|
795
|
+
header,
|
|
796
|
+
title,
|
|
797
|
+
description,
|
|
798
|
+
id,
|
|
799
|
+
});
|
|
800
|
+
this._buttons[this._currentSelectionIndex].buttonParamsJson =
|
|
801
|
+
JSON.stringify(buttonParams);
|
|
802
|
+
return this;
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
makeSection(title = "", highlight_label = "") {
|
|
806
|
+
if (this._currentSelectionIndex === -1) {
|
|
807
|
+
throw new Error("You need to create a selection first");
|
|
808
|
+
}
|
|
809
|
+
const buttonParams = JSON.parse(
|
|
810
|
+
this._buttons[this._currentSelectionIndex].buttonParamsJson,
|
|
811
|
+
);
|
|
812
|
+
buttonParams.sections.push({ title, highlight_label, rows: [] });
|
|
813
|
+
this._currentSectionIndex = buttonParams.sections.length - 1;
|
|
814
|
+
this._buttons[this._currentSelectionIndex].buttonParamsJson =
|
|
815
|
+
JSON.stringify(buttonParams);
|
|
816
|
+
return this;
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
addSelection(title, options = {}) {
|
|
820
|
+
this._buttons.push({
|
|
821
|
+
name: "single_select",
|
|
822
|
+
buttonParamsJson: JSON.stringify({ title, sections: [], ...options }),
|
|
823
|
+
});
|
|
824
|
+
this._currentSelectionIndex = this._buttons.length - 1;
|
|
825
|
+
this._currentSectionIndex = -1;
|
|
826
|
+
return this;
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
addReply(display_text = "", id = "", options = {}) {
|
|
830
|
+
this._buttons.push({
|
|
831
|
+
name: "quick_reply",
|
|
832
|
+
buttonParamsJson: JSON.stringify({
|
|
833
|
+
display_text,
|
|
834
|
+
id,
|
|
835
|
+
...options,
|
|
836
|
+
}),
|
|
837
|
+
});
|
|
838
|
+
return this;
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
addCall(display_text = "", id = "", options = {}) {
|
|
842
|
+
this._buttons.push({
|
|
843
|
+
name: "cta_call",
|
|
844
|
+
buttonParamsJson: JSON.stringify({
|
|
845
|
+
display_text,
|
|
846
|
+
id,
|
|
847
|
+
...options,
|
|
848
|
+
}),
|
|
849
|
+
});
|
|
850
|
+
return this;
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
addReminder(display_text = "", id = "", options = {}) {
|
|
854
|
+
this._buttons.push({
|
|
855
|
+
name: "cta_reminder",
|
|
856
|
+
buttonParamsJson: JSON.stringify({
|
|
857
|
+
display_text,
|
|
858
|
+
id,
|
|
859
|
+
...options,
|
|
860
|
+
}),
|
|
861
|
+
});
|
|
862
|
+
return this;
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
addCancelReminder(display_text = "", id = "", options = {}) {
|
|
866
|
+
this._buttons.push({
|
|
867
|
+
name: "cta_cancel_reminder",
|
|
868
|
+
buttonParamsJson: JSON.stringify({
|
|
869
|
+
display_text,
|
|
870
|
+
id,
|
|
871
|
+
...options,
|
|
872
|
+
}),
|
|
873
|
+
});
|
|
874
|
+
return this;
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
addAddress(display_text = "", id = "", options = {}) {
|
|
878
|
+
this._buttons.push({
|
|
879
|
+
name: "address_message",
|
|
880
|
+
buttonParamsJson: JSON.stringify({
|
|
881
|
+
display_text,
|
|
882
|
+
id,
|
|
883
|
+
...options,
|
|
884
|
+
}),
|
|
885
|
+
});
|
|
886
|
+
return this;
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
addLocation(options = {}) {
|
|
890
|
+
this._buttons.push({
|
|
891
|
+
name: "send_location",
|
|
892
|
+
buttonParamsJson: JSON.stringify(options),
|
|
893
|
+
});
|
|
894
|
+
return this;
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
addUrl(
|
|
898
|
+
display_text = "",
|
|
899
|
+
url = "",
|
|
900
|
+
webview_interaction = false,
|
|
901
|
+
options = {},
|
|
902
|
+
) {
|
|
903
|
+
this._buttons.push({
|
|
904
|
+
...options,
|
|
905
|
+
name: "cta_url",
|
|
906
|
+
buttonParamsJson: JSON.stringify({
|
|
907
|
+
display_text,
|
|
908
|
+
url,
|
|
909
|
+
webview_interaction,
|
|
910
|
+
...options,
|
|
911
|
+
}),
|
|
912
|
+
});
|
|
913
|
+
return this;
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
addCopy(display_text = "", copy_code = "", options = {}) {
|
|
917
|
+
this._buttons.push({
|
|
918
|
+
name: "cta_copy",
|
|
919
|
+
buttonParamsJson: JSON.stringify({
|
|
920
|
+
display_text,
|
|
921
|
+
copy_code,
|
|
922
|
+
...options,
|
|
923
|
+
}),
|
|
924
|
+
});
|
|
925
|
+
return this;
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
static paramsList = {
|
|
929
|
+
limited_time_offer: {
|
|
930
|
+
text: "string",
|
|
931
|
+
url: "string",
|
|
932
|
+
copy_code: "string",
|
|
933
|
+
expiration_time: "number",
|
|
934
|
+
},
|
|
935
|
+
bottom_sheet: {
|
|
936
|
+
in_thread_buttons_limit: "number",
|
|
937
|
+
divider_indices: ["number"],
|
|
938
|
+
list_title: "string",
|
|
939
|
+
button_title: "string",
|
|
940
|
+
},
|
|
941
|
+
tap_target_configuration: {
|
|
942
|
+
title: "string",
|
|
943
|
+
description: "string",
|
|
944
|
+
canonical_url: "string",
|
|
945
|
+
domain: "string",
|
|
946
|
+
buttonIndex: "number",
|
|
947
|
+
},
|
|
948
|
+
};
|
|
949
|
+
|
|
950
|
+
async toCard() {
|
|
951
|
+
return {
|
|
952
|
+
body: {
|
|
953
|
+
text: this._body,
|
|
954
|
+
},
|
|
955
|
+
footer: {
|
|
956
|
+
text: this._footer,
|
|
957
|
+
},
|
|
958
|
+
header: {
|
|
959
|
+
title: this._title,
|
|
960
|
+
subtitle: this._subtitle,
|
|
961
|
+
hasMediaAttachment: !!this._data,
|
|
962
|
+
...(this._data
|
|
963
|
+
? await prepareWAMessageMedia(this._data, {
|
|
964
|
+
upload: this.#client.waUploadToServer,
|
|
965
|
+
}).catch((e) => {
|
|
966
|
+
if (String(e).includes("Invalid media type")) return this._data;
|
|
967
|
+
throw e;
|
|
968
|
+
})
|
|
969
|
+
: {}),
|
|
970
|
+
},
|
|
971
|
+
nativeFlowMessage: {
|
|
972
|
+
messageParamsJson: JSON.stringify(this._params),
|
|
973
|
+
buttons: this._buttons,
|
|
974
|
+
},
|
|
975
|
+
};
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
async build(jid, { messageId, ...options } = {}) {
|
|
979
|
+
const message = await this.toCard();
|
|
980
|
+
|
|
981
|
+
return generateWAMessageFromContent(
|
|
982
|
+
jid,
|
|
983
|
+
{
|
|
984
|
+
...this._extraPayload,
|
|
985
|
+
interactiveMessage: {
|
|
986
|
+
...message,
|
|
987
|
+
contextInfo: this._contextInfo,
|
|
988
|
+
},
|
|
989
|
+
},
|
|
990
|
+
{ messageId: messageId || generateMessageIDV2(), ...options },
|
|
991
|
+
);
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
async send(jid, { messageId, additionalNodes = [], ...options } = {}) {
|
|
995
|
+
const msg = await this.build(jid, { messageId, ...options });
|
|
996
|
+
|
|
997
|
+
await this.#client.relayMessage(msg.key.remoteJid, msg.message, {
|
|
998
|
+
messageId: msg.key.id,
|
|
999
|
+
additionalNodes: [
|
|
1000
|
+
{
|
|
1001
|
+
tag: "biz",
|
|
1002
|
+
attrs: {},
|
|
1003
|
+
content: [
|
|
1004
|
+
{
|
|
1005
|
+
tag: "interactive",
|
|
1006
|
+
attrs: { type: "native_flow", v: "1" },
|
|
1007
|
+
content: [
|
|
1008
|
+
{ tag: "native_flow", attrs: { v: "9", name: "mixed" } },
|
|
1009
|
+
],
|
|
1010
|
+
},
|
|
1011
|
+
],
|
|
1012
|
+
},
|
|
1013
|
+
...additionalNodes,
|
|
1014
|
+
],
|
|
1015
|
+
...options,
|
|
1016
|
+
});
|
|
1017
|
+
return msg;
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
class ButtonV2 extends BaseBuilder {
|
|
1022
|
+
#client;
|
|
1023
|
+
|
|
1024
|
+
constructor(client) {
|
|
1025
|
+
super();
|
|
1026
|
+
if (!client) {
|
|
1027
|
+
throw new Error("Socket is required");
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
this.#client = client;
|
|
1031
|
+
this._image;
|
|
1032
|
+
this._data;
|
|
1033
|
+
this._buttons = [];
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
loadFrom(msg) {
|
|
1037
|
+
if (!msg) throw new Error("buttonsMessage needed");
|
|
1038
|
+
if (!msg.buttonsMessage) throw new Error("buttonsMessage not found");
|
|
1039
|
+
|
|
1040
|
+
const { buttonsMessage, ...extraPayload } = msg;
|
|
1041
|
+
const bM = buttonsMessage;
|
|
1042
|
+
const location = bM.locationMessage || {};
|
|
1043
|
+
|
|
1044
|
+
this._title = location.name || "";
|
|
1045
|
+
this._subtitle = location.address || "";
|
|
1046
|
+
this._body = bM.contentText || "";
|
|
1047
|
+
this._footer = bM.footerText || "";
|
|
1048
|
+
this._contextInfo = bM.contextInfo || {};
|
|
1049
|
+
this._extraPayload = extraPayload;
|
|
1050
|
+
|
|
1051
|
+
this._buttons = Array.isArray(bM.buttons)
|
|
1052
|
+
? bM.buttons.map((button) => ({
|
|
1053
|
+
...button,
|
|
1054
|
+
...(button.nativeFlowInfo
|
|
1055
|
+
? {
|
|
1056
|
+
nativeFlowInfo: {
|
|
1057
|
+
...button.nativeFlowInfo,
|
|
1058
|
+
paramsJson:
|
|
1059
|
+
typeof button.nativeFlowInfo.paramsJson === "string"
|
|
1060
|
+
? button.nativeFlowInfo.paramsJson
|
|
1061
|
+
: JSON.stringify(button.nativeFlowInfo.paramsJson || {}),
|
|
1062
|
+
},
|
|
1063
|
+
}
|
|
1064
|
+
: {}),
|
|
1065
|
+
}))
|
|
1066
|
+
: [];
|
|
1067
|
+
|
|
1068
|
+
this._image = location.jpegThumbnail || undefined;
|
|
1069
|
+
|
|
1070
|
+
if (!this._image && bM.locationMessage) {
|
|
1071
|
+
this._image = undefined;
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
if (!bM.locationMessage && bM.headerType === 6) {
|
|
1075
|
+
this._image = undefined;
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
this._data = Object.keys(bM).reduce((data, key) => {
|
|
1079
|
+
if (
|
|
1080
|
+
![
|
|
1081
|
+
"contentText",
|
|
1082
|
+
"footerText",
|
|
1083
|
+
"contextInfo",
|
|
1084
|
+
"buttons",
|
|
1085
|
+
"headerType",
|
|
1086
|
+
"locationMessage",
|
|
1087
|
+
"viewOnce",
|
|
1088
|
+
].includes(key)
|
|
1089
|
+
) {
|
|
1090
|
+
data[key] = bM[key];
|
|
1091
|
+
}
|
|
1092
|
+
return data;
|
|
1093
|
+
}, {});
|
|
1094
|
+
|
|
1095
|
+
if (!Object.keys(this._data).length) {
|
|
1096
|
+
this._data = undefined;
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
return this;
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
addButton(displayText = "", buttonId = crypto.randomUUID()) {
|
|
1103
|
+
this._buttons.push({
|
|
1104
|
+
buttonId,
|
|
1105
|
+
buttonText: { displayText },
|
|
1106
|
+
type: 1,
|
|
1107
|
+
});
|
|
1108
|
+
return this;
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
addRawButton(obj) {
|
|
1112
|
+
if (typeof obj !== "object" || obj === null || Array.isArray(obj)) {
|
|
1113
|
+
throw new TypeError("Buttons must be a plain object");
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
this._buttons.push(obj);
|
|
1117
|
+
return this;
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
setRawThumbnail(thumbnail) {
|
|
1121
|
+
if (!thumbnail) throw new Error("Thumbnail needed");
|
|
1122
|
+
this._image = { base64: thumbnail, is_raw: true };
|
|
1123
|
+
return this;
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
setThumbnail(path) {
|
|
1127
|
+
if (!path) throw new Error("Url or buffer needed");
|
|
1128
|
+
this._image = path;
|
|
1129
|
+
return this;
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
setMedia(obj) {
|
|
1133
|
+
if (typeof obj !== "object" || obj === null || Array.isArray(obj)) {
|
|
1134
|
+
throw new TypeError("Media must be a plain object");
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
this._data = obj;
|
|
1138
|
+
return this;
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1141
|
+
async build(jid, { messageId, ...options } = {}) {
|
|
1142
|
+
const _thumbnail = this._image?.is_raw
|
|
1143
|
+
? this._image.base64
|
|
1144
|
+
: this._image
|
|
1145
|
+
? await Toolkit.resize(
|
|
1146
|
+
Buffer.isBuffer(this._image)
|
|
1147
|
+
? this._image
|
|
1148
|
+
: await Toolkit.fetchBuffer(this._image, {}, { silent: true }),
|
|
1149
|
+
300,
|
|
1150
|
+
300,
|
|
1151
|
+
)
|
|
1152
|
+
: null;
|
|
1153
|
+
const msg = generateWAMessageFromContent(
|
|
1154
|
+
jid,
|
|
1155
|
+
{
|
|
1156
|
+
...this._extraPayload,
|
|
1157
|
+
buttonsMessage: {
|
|
1158
|
+
contentText: this._body,
|
|
1159
|
+
footerText: this._footer,
|
|
1160
|
+
...(this._data
|
|
1161
|
+
? this._data
|
|
1162
|
+
: {
|
|
1163
|
+
headerType: 6,
|
|
1164
|
+
locationMessage: {
|
|
1165
|
+
degreesLatitude: 0,
|
|
1166
|
+
degreesLongitude: 0,
|
|
1167
|
+
name: this._title,
|
|
1168
|
+
address: this._subtitle,
|
|
1169
|
+
jpegThumbnail: _thumbnail,
|
|
1170
|
+
},
|
|
1171
|
+
}),
|
|
1172
|
+
viewOnce: true,
|
|
1173
|
+
contextInfo: this._contextInfo,
|
|
1174
|
+
buttons: [...this._buttons],
|
|
1175
|
+
},
|
|
1176
|
+
},
|
|
1177
|
+
{ messageId: messageId || generateMessageIDV2(), ...options },
|
|
1178
|
+
);
|
|
1179
|
+
return msg;
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1182
|
+
async send(jid, { messageId, additionalNodes = [], ...options } = {}) {
|
|
1183
|
+
if (this._buttons.length < 1)
|
|
1184
|
+
throw new Error("ButtonV2 requires at least one button");
|
|
1185
|
+
const msg = await this.build(jid, { messageId, ...options });
|
|
1186
|
+
|
|
1187
|
+
await this.#client.relayMessage(msg.key.remoteJid, msg.message, {
|
|
1188
|
+
messageId: msg.key.id,
|
|
1189
|
+
additionalNodes: [
|
|
1190
|
+
{
|
|
1191
|
+
tag: "biz",
|
|
1192
|
+
attrs: {},
|
|
1193
|
+
content: [
|
|
1194
|
+
{
|
|
1195
|
+
tag: "interactive",
|
|
1196
|
+
attrs: { type: "native_flow", v: "1" },
|
|
1197
|
+
content: [
|
|
1198
|
+
{ tag: "native_flow", attrs: { v: "9", name: "mixed" } },
|
|
1199
|
+
],
|
|
1200
|
+
},
|
|
1201
|
+
],
|
|
1202
|
+
},
|
|
1203
|
+
...additionalNodes,
|
|
1204
|
+
],
|
|
1205
|
+
...options,
|
|
1206
|
+
});
|
|
1207
|
+
return msg;
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
class Carousel extends BaseBuilder {
|
|
1212
|
+
#client;
|
|
1213
|
+
|
|
1214
|
+
constructor(client) {
|
|
1215
|
+
super();
|
|
1216
|
+
if (!client) {
|
|
1217
|
+
throw new Error("Socket is required");
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
this.#client = client;
|
|
1221
|
+
this._cards = [];
|
|
1222
|
+
}
|
|
1223
|
+
|
|
1224
|
+
loadFrom(msg) {
|
|
1225
|
+
if (!msg) throw new Error("interactiveMessage needed");
|
|
1226
|
+
if (!msg.interactiveMessage)
|
|
1227
|
+
throw new Error("interactiveMessage not found");
|
|
1228
|
+
|
|
1229
|
+
const { interactiveMessage, ...extraPayload } = msg;
|
|
1230
|
+
const iM = interactiveMessage;
|
|
1231
|
+
const carousel = iM.carouselMessage || {};
|
|
1232
|
+
|
|
1233
|
+
this._body = iM.body?.text || "";
|
|
1234
|
+
this._footer = iM.footer?.text || "";
|
|
1235
|
+
this._contextInfo = iM.contextInfo || {};
|
|
1236
|
+
this._extraPayload = extraPayload;
|
|
1237
|
+
|
|
1238
|
+
this._cards = Array.isArray(carousel.cards)
|
|
1239
|
+
? carousel.cards.map((card) => ({
|
|
1240
|
+
...card,
|
|
1241
|
+
header: {
|
|
1242
|
+
...(card.header || {}),
|
|
1243
|
+
hasMediaAttachment: !!card.header?.hasMediaAttachment,
|
|
1244
|
+
...(card.header?.imageMessage
|
|
1245
|
+
? { imageMessage: card.header.imageMessage }
|
|
1246
|
+
: {}),
|
|
1247
|
+
...(card.header?.videoMessage
|
|
1248
|
+
? { videoMessage: card.header.videoMessage }
|
|
1249
|
+
: {}),
|
|
1250
|
+
},
|
|
1251
|
+
body: {
|
|
1252
|
+
text: card.body?.text || "",
|
|
1253
|
+
},
|
|
1254
|
+
footer: {
|
|
1255
|
+
text: card.footer?.text || "",
|
|
1256
|
+
},
|
|
1257
|
+
nativeFlowMessage: {
|
|
1258
|
+
...(card.nativeFlowMessage || {}),
|
|
1259
|
+
buttons: Array.isArray(card.nativeFlowMessage?.buttons)
|
|
1260
|
+
? card.nativeFlowMessage.buttons.map((button) => ({
|
|
1261
|
+
...button,
|
|
1262
|
+
buttonParamsJson:
|
|
1263
|
+
typeof button.buttonParamsJson === "string"
|
|
1264
|
+
? button.buttonParamsJson
|
|
1265
|
+
: JSON.stringify(button.buttonParamsJson || {}),
|
|
1266
|
+
}))
|
|
1267
|
+
: [],
|
|
1268
|
+
messageParamsJson:
|
|
1269
|
+
typeof card.nativeFlowMessage?.messageParamsJson === "string"
|
|
1270
|
+
? card.nativeFlowMessage.messageParamsJson
|
|
1271
|
+
: JSON.stringify(
|
|
1272
|
+
card.nativeFlowMessage?.messageParamsJson || {},
|
|
1273
|
+
),
|
|
1274
|
+
},
|
|
1275
|
+
}))
|
|
1276
|
+
: [];
|
|
1277
|
+
|
|
1278
|
+
return this;
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
addCard(card) {
|
|
1282
|
+
const cards = Array.isArray(card) ? card : [card];
|
|
1283
|
+
const baseIndex = this._cards.length;
|
|
1284
|
+
|
|
1285
|
+
for (const [index, c] of cards.entries()) {
|
|
1286
|
+
if (!c?.header?.hasMediaAttachment) {
|
|
1287
|
+
throw new Error(
|
|
1288
|
+
`Card [${baseIndex + index}] must include an image or video in header`,
|
|
1289
|
+
);
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1293
|
+
this._cards.push(...cards);
|
|
1294
|
+
return this;
|
|
1295
|
+
}
|
|
1296
|
+
|
|
1297
|
+
build(jid, { messageId, ...options } = {}) {
|
|
1298
|
+
return generateWAMessageFromContent(
|
|
1299
|
+
jid,
|
|
1300
|
+
{
|
|
1301
|
+
...this._extraPayload,
|
|
1302
|
+
interactiveMessage: {
|
|
1303
|
+
header: {
|
|
1304
|
+
hasMediaAttachment: false,
|
|
1305
|
+
},
|
|
1306
|
+
body: { text: this._body },
|
|
1307
|
+
footer: { text: this._footer },
|
|
1308
|
+
contextInfo: this._contextInfo,
|
|
1309
|
+
carouselMessage: {
|
|
1310
|
+
cards: this._cards,
|
|
1311
|
+
},
|
|
1312
|
+
},
|
|
1313
|
+
},
|
|
1314
|
+
{ messageId: messageId || generateMessageIDV2(), ...options },
|
|
1315
|
+
);
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1318
|
+
async send(jid, { messageId, additionalNodes = [], ...options } = {}) {
|
|
1319
|
+
const msg = this.build(jid, { messageId, ...options });
|
|
1320
|
+
|
|
1321
|
+
await this.#client.relayMessage(msg.key.remoteJid, msg.message, {
|
|
1322
|
+
messageId: msg.key.id,
|
|
1323
|
+
additionalNodes: [
|
|
1324
|
+
{
|
|
1325
|
+
tag: "biz",
|
|
1326
|
+
attrs: {},
|
|
1327
|
+
content: [
|
|
1328
|
+
{
|
|
1329
|
+
tag: "interactive",
|
|
1330
|
+
attrs: { type: "native_flow", v: "1" },
|
|
1331
|
+
content: [
|
|
1332
|
+
{ tag: "native_flow", attrs: { v: "9", name: "mixed" } },
|
|
1333
|
+
],
|
|
1334
|
+
},
|
|
1335
|
+
],
|
|
1336
|
+
},
|
|
1337
|
+
...additionalNodes,
|
|
1338
|
+
],
|
|
1339
|
+
...options,
|
|
1340
|
+
});
|
|
1341
|
+
return msg;
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1344
|
+
|
|
1345
|
+
class AIRich extends BaseBuilder {
|
|
1346
|
+
#client;
|
|
1347
|
+
|
|
1348
|
+
constructor(client, { dynamic = true, unsupportedTypeAlert = true } = {}) {
|
|
1349
|
+
if (!client) {
|
|
1350
|
+
throw new Error("Socket is required");
|
|
1351
|
+
}
|
|
1352
|
+
|
|
1353
|
+
super();
|
|
1354
|
+
this.#client = client;
|
|
1355
|
+
this._contextInfo = {};
|
|
1356
|
+
this._nodes = [];
|
|
1357
|
+
this._idIndex = new Map();
|
|
1358
|
+
this._unsupportedTypeAlert = !!unsupportedTypeAlert;
|
|
1359
|
+
this._dynamic = !!dynamic;
|
|
1360
|
+
this._responseId = crypto.randomUUID();
|
|
1361
|
+
this._botResponseId = crypto.randomUUID();
|
|
1362
|
+
this._lastMessageKey = null;
|
|
1363
|
+
}
|
|
1364
|
+
|
|
1365
|
+
loadFrom(msg) {
|
|
1366
|
+
if (!msg) throw new Error("AI Rich message needed");
|
|
1367
|
+
|
|
1368
|
+
const message = msg.message ?? msg;
|
|
1369
|
+
|
|
1370
|
+
let richResponseMessage =
|
|
1371
|
+
message?.botForwardedMessage?.message?.richResponseMessage;
|
|
1372
|
+
|
|
1373
|
+
if (!richResponseMessage) {
|
|
1374
|
+
richResponseMessage = message?.botForwardedMessage?.richResponseMessage;
|
|
1375
|
+
}
|
|
1376
|
+
|
|
1377
|
+
if (!richResponseMessage) {
|
|
1378
|
+
richResponseMessage = message?.richResponseMessage;
|
|
1379
|
+
}
|
|
1380
|
+
|
|
1381
|
+
if (!richResponseMessage) {
|
|
1382
|
+
throw new Error("richResponseMessage not found");
|
|
1383
|
+
}
|
|
1384
|
+
|
|
1385
|
+
const messageContextInfo = message?.messageContextInfo ?? {};
|
|
1386
|
+
const botMetadata = messageContextInfo?.botMetadata ?? {};
|
|
1387
|
+
|
|
1388
|
+
this._title = botMetadata?.messageDisclaimerText ?? "";
|
|
1389
|
+
|
|
1390
|
+
this._contextInfo = structuredClone(richResponseMessage?.contextInfo ?? {});
|
|
1391
|
+
|
|
1392
|
+
const loadedSubmessages = Array.isArray(richResponseMessage?.submessages)
|
|
1393
|
+
? structuredClone(richResponseMessage.submessages)
|
|
1394
|
+
: [];
|
|
1395
|
+
|
|
1396
|
+
let loadedSections = [];
|
|
1397
|
+
|
|
1398
|
+
const unifiedData = richResponseMessage?.unifiedResponse?.data;
|
|
1399
|
+
|
|
1400
|
+
if (unifiedData) {
|
|
1401
|
+
try {
|
|
1402
|
+
const decoded = Buffer.from(unifiedData, "base64").toString("utf8");
|
|
1403
|
+
const unifiedResponse = JSON.parse(decoded);
|
|
1404
|
+
|
|
1405
|
+
if (Array.isArray(unifiedResponse?.sections)) {
|
|
1406
|
+
loadedSections = structuredClone(unifiedResponse.sections);
|
|
1407
|
+
}
|
|
1408
|
+
} catch {}
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1411
|
+
this._nodes = [];
|
|
1412
|
+
this._idIndex = new Map();
|
|
1413
|
+
|
|
1414
|
+
const maxLength = Math.max(loadedSections.length, loadedSubmessages.length);
|
|
1415
|
+
|
|
1416
|
+
for (let i = 0; i < maxLength; i++) {
|
|
1417
|
+
this._nodes.push({
|
|
1418
|
+
id: null,
|
|
1419
|
+
section: loadedSections[i] ?? null,
|
|
1420
|
+
submessage: loadedSubmessages[i] ?? null,
|
|
1421
|
+
});
|
|
1422
|
+
}
|
|
1423
|
+
|
|
1424
|
+
this._extraPayload = {};
|
|
1425
|
+
|
|
1426
|
+
for (const [key, value] of Object.entries(message)) {
|
|
1427
|
+
if (
|
|
1428
|
+
key !== "messageContextInfo" &&
|
|
1429
|
+
key !== "botForwardedMessage" &&
|
|
1430
|
+
key !== "richResponseMessage"
|
|
1431
|
+
) {
|
|
1432
|
+
this._extraPayload[key] = structuredClone(value);
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1436
|
+
return this;
|
|
1437
|
+
}
|
|
1438
|
+
|
|
1439
|
+
setResponseId(id) {
|
|
1440
|
+
if (typeof id !== "string") {
|
|
1441
|
+
throw new TypeError("ID must be a string");
|
|
1442
|
+
}
|
|
1443
|
+
this._responseId = id;
|
|
1444
|
+
|
|
1445
|
+
return this;
|
|
1446
|
+
}
|
|
1447
|
+
|
|
1448
|
+
refreshResponseId() {
|
|
1449
|
+
this._responseId = crypto.randomUUID();
|
|
1450
|
+
|
|
1451
|
+
return this;
|
|
1452
|
+
}
|
|
1453
|
+
|
|
1454
|
+
setBotResponseId(id) {
|
|
1455
|
+
if (typeof id !== "string") {
|
|
1456
|
+
throw new TypeError("ID must be a string");
|
|
1457
|
+
}
|
|
1458
|
+
this._botResponseId = id;
|
|
1459
|
+
|
|
1460
|
+
return this;
|
|
1461
|
+
}
|
|
1462
|
+
|
|
1463
|
+
refreshBotResponseId() {
|
|
1464
|
+
this._botResponseId = crypto.randomUUID();
|
|
1465
|
+
|
|
1466
|
+
return this;
|
|
1467
|
+
}
|
|
1468
|
+
|
|
1469
|
+
createAlert(type) {
|
|
1470
|
+
if (this._unsupportedTypeAlert) {
|
|
1471
|
+
return {
|
|
1472
|
+
messageType: 2,
|
|
1473
|
+
messageText: `[ UNSUPPORTED_TYPE - ${type}]`,
|
|
1474
|
+
};
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1477
|
+
return undefined;
|
|
1478
|
+
}
|
|
1479
|
+
|
|
1480
|
+
addText(
|
|
1481
|
+
text,
|
|
1482
|
+
{
|
|
1483
|
+
hyperlink = true,
|
|
1484
|
+
citation = true,
|
|
1485
|
+
latex = true,
|
|
1486
|
+
id,
|
|
1487
|
+
replace,
|
|
1488
|
+
insertAt,
|
|
1489
|
+
} = {},
|
|
1490
|
+
) {
|
|
1491
|
+
if (typeof text !== "string") {
|
|
1492
|
+
throw new TypeError("Text must be a string");
|
|
1493
|
+
}
|
|
1494
|
+
|
|
1495
|
+
const { text: extractedText, inline_entities } = extractIE(text, {
|
|
1496
|
+
hyperlink,
|
|
1497
|
+
citation,
|
|
1498
|
+
latex,
|
|
1499
|
+
});
|
|
1500
|
+
|
|
1501
|
+
const section = AIRich.newLayout("Single", {
|
|
1502
|
+
text: extractedText,
|
|
1503
|
+
...(inline_entities.length && { inline_entities }),
|
|
1504
|
+
__typename: "GenAIMarkdownTextUXPrimitive",
|
|
1505
|
+
});
|
|
1506
|
+
|
|
1507
|
+
const submessages = [
|
|
1508
|
+
{
|
|
1509
|
+
messageType: 2,
|
|
1510
|
+
messageText: text,
|
|
1511
|
+
},
|
|
1512
|
+
].filter(Boolean);
|
|
1513
|
+
|
|
1514
|
+
return this._addContent(section, submessages, {
|
|
1515
|
+
id,
|
|
1516
|
+
replace,
|
|
1517
|
+
insertAt,
|
|
1518
|
+
});
|
|
1519
|
+
}
|
|
1520
|
+
|
|
1521
|
+
addFOAText(text, { id, replace, insertAt } = {}) {
|
|
1522
|
+
if (typeof text !== "string") {
|
|
1523
|
+
throw new TypeError("Text must be a string");
|
|
1524
|
+
}
|
|
1525
|
+
|
|
1526
|
+
const section = AIRich.newLayout("Single", {
|
|
1527
|
+
text,
|
|
1528
|
+
__typename: "FOATextPrimitive",
|
|
1529
|
+
});
|
|
1530
|
+
|
|
1531
|
+
const submessages = [
|
|
1532
|
+
{
|
|
1533
|
+
messageType: 2,
|
|
1534
|
+
messageText: text,
|
|
1535
|
+
},
|
|
1536
|
+
];
|
|
1537
|
+
|
|
1538
|
+
return this._addContent(section, submessages, {
|
|
1539
|
+
id,
|
|
1540
|
+
replace,
|
|
1541
|
+
insertAt,
|
|
1542
|
+
});
|
|
1543
|
+
}
|
|
1544
|
+
|
|
1545
|
+
addCode(language, code, { id, replace, insertAt } = {}) {
|
|
1546
|
+
if (typeof language !== "string" || typeof code !== "string") {
|
|
1547
|
+
throw new TypeError("Language and code must be a string");
|
|
1548
|
+
}
|
|
1549
|
+
|
|
1550
|
+
const meta = AIRich.tokenizer(code, language);
|
|
1551
|
+
|
|
1552
|
+
const section = AIRich.newLayout("Single", {
|
|
1553
|
+
language,
|
|
1554
|
+
code_blocks: meta.unified_codeBlock,
|
|
1555
|
+
__typename: "GenAICodeUXPrimitive",
|
|
1556
|
+
});
|
|
1557
|
+
|
|
1558
|
+
const submessages = [
|
|
1559
|
+
{
|
|
1560
|
+
messageType: 5,
|
|
1561
|
+
codeMetadata: {
|
|
1562
|
+
codeLanguage: language,
|
|
1563
|
+
codeBlocks: meta.codeBlock,
|
|
1564
|
+
},
|
|
1565
|
+
},
|
|
1566
|
+
];
|
|
1567
|
+
|
|
1568
|
+
return this._addContent(section, submessages, {
|
|
1569
|
+
id,
|
|
1570
|
+
replace,
|
|
1571
|
+
insertAt,
|
|
1572
|
+
});
|
|
1573
|
+
}
|
|
1574
|
+
|
|
1575
|
+
addTable(
|
|
1576
|
+
table,
|
|
1577
|
+
{
|
|
1578
|
+
hyperlink = true,
|
|
1579
|
+
citation = true,
|
|
1580
|
+
latex = true,
|
|
1581
|
+
id,
|
|
1582
|
+
replace,
|
|
1583
|
+
insertAt,
|
|
1584
|
+
} = {},
|
|
1585
|
+
) {
|
|
1586
|
+
if (!Array.isArray(table)) {
|
|
1587
|
+
throw new TypeError("Table must be an array");
|
|
1588
|
+
}
|
|
1589
|
+
|
|
1590
|
+
const meta = AIRich.toTableMetadata(table, {
|
|
1591
|
+
hyperlink,
|
|
1592
|
+
citation,
|
|
1593
|
+
latex,
|
|
1594
|
+
});
|
|
1595
|
+
|
|
1596
|
+
const section = AIRich.newLayout("Single", {
|
|
1597
|
+
rows: meta.unified_rows,
|
|
1598
|
+
__typename: "GenATableUXPrimitive",
|
|
1599
|
+
});
|
|
1600
|
+
|
|
1601
|
+
const submessages = [
|
|
1602
|
+
{
|
|
1603
|
+
messageType: 4,
|
|
1604
|
+
tableMetadata: {
|
|
1605
|
+
title: meta.title,
|
|
1606
|
+
rows: meta.rows,
|
|
1607
|
+
},
|
|
1608
|
+
},
|
|
1609
|
+
];
|
|
1610
|
+
|
|
1611
|
+
return this._addContent(section, submessages, {
|
|
1612
|
+
id,
|
|
1613
|
+
replace,
|
|
1614
|
+
insertAt,
|
|
1615
|
+
});
|
|
1616
|
+
}
|
|
1617
|
+
|
|
1618
|
+
addSource(sources = [], { id, replace, insertAt } = {}) {
|
|
1619
|
+
if (!Array.isArray(sources)) {
|
|
1620
|
+
throw new TypeError(
|
|
1621
|
+
"Sources must be an array of strings, arrays, or objects",
|
|
1622
|
+
);
|
|
1623
|
+
}
|
|
1624
|
+
|
|
1625
|
+
const isStringArray = sources.every((item) => typeof item === "string");
|
|
1626
|
+
|
|
1627
|
+
const isArrayFormat = sources.every(
|
|
1628
|
+
(item) =>
|
|
1629
|
+
Array.isArray(item) && item.every((value) => typeof value === "string"),
|
|
1630
|
+
);
|
|
1631
|
+
|
|
1632
|
+
const isObjectFormat = sources.every(
|
|
1633
|
+
(item) => item && typeof item === "object" && !Array.isArray(item),
|
|
1634
|
+
);
|
|
1635
|
+
|
|
1636
|
+
if (!isStringArray && !isArrayFormat && !isObjectFormat) {
|
|
1637
|
+
throw new TypeError(
|
|
1638
|
+
"Sources must be a string array, array of string arrays, or array of objects",
|
|
1639
|
+
);
|
|
1640
|
+
}
|
|
1641
|
+
|
|
1642
|
+
if (isStringArray) {
|
|
1643
|
+
sources = [sources];
|
|
1644
|
+
}
|
|
1645
|
+
|
|
1646
|
+
const normalizedSources = sources.map((source) => {
|
|
1647
|
+
if (Array.isArray(source)) {
|
|
1648
|
+
const [icon, url, title, subtitle] = source;
|
|
1649
|
+
|
|
1650
|
+
return {
|
|
1651
|
+
icon,
|
|
1652
|
+
url,
|
|
1653
|
+
title,
|
|
1654
|
+
subtitle,
|
|
1655
|
+
};
|
|
1656
|
+
}
|
|
1657
|
+
|
|
1658
|
+
return {
|
|
1659
|
+
icon: source.favicon ?? source.icon ?? "",
|
|
1660
|
+
url: source.url ?? "",
|
|
1661
|
+
title: source.title ?? "",
|
|
1662
|
+
subtitle: source.subtitle ?? "",
|
|
1663
|
+
};
|
|
1664
|
+
});
|
|
1665
|
+
|
|
1666
|
+
const source = normalizedSources.map(({ icon, url, title, subtitle }) => ({
|
|
1667
|
+
source_type: "THIRD_PARTY",
|
|
1668
|
+
source_display_name: title,
|
|
1669
|
+
source_subtitle: subtitle,
|
|
1670
|
+
source_url: url,
|
|
1671
|
+
favicon: {
|
|
1672
|
+
url: Toolkit.resolveMedia(this.#client, icon, "image"),
|
|
1673
|
+
mime_type: "image/jpeg",
|
|
1674
|
+
width: 16,
|
|
1675
|
+
height: 16,
|
|
1676
|
+
},
|
|
1677
|
+
}));
|
|
1678
|
+
|
|
1679
|
+
const submessage = this.createAlert("GenAISearchResultPrimitive");
|
|
1680
|
+
|
|
1681
|
+
const section = AIRich.newLayout("Single", {
|
|
1682
|
+
sources: source,
|
|
1683
|
+
__typename: "GenAISearchResultPrimitive",
|
|
1684
|
+
});
|
|
1685
|
+
|
|
1686
|
+
return this._addContent(section, submessage, {
|
|
1687
|
+
id,
|
|
1688
|
+
replace,
|
|
1689
|
+
insertAt,
|
|
1690
|
+
});
|
|
1691
|
+
}
|
|
1692
|
+
|
|
1693
|
+
addReels(reelsItems = [], { id, replace, insertAt } = {}) {
|
|
1694
|
+
if (
|
|
1695
|
+
!(
|
|
1696
|
+
(reelsItems &&
|
|
1697
|
+
typeof reelsItems === "object" &&
|
|
1698
|
+
!Array.isArray(reelsItems)) ||
|
|
1699
|
+
(Array.isArray(reelsItems) &&
|
|
1700
|
+
reelsItems.every(
|
|
1701
|
+
(item) => item && typeof item === "object" && !Array.isArray(item),
|
|
1702
|
+
))
|
|
1703
|
+
)
|
|
1704
|
+
) {
|
|
1705
|
+
throw new TypeError(
|
|
1706
|
+
"Reels items must be an object or an array of objects",
|
|
1707
|
+
);
|
|
1708
|
+
}
|
|
1709
|
+
|
|
1710
|
+
const items = Array.isArray(reelsItems) ? reelsItems : [reelsItems];
|
|
1711
|
+
|
|
1712
|
+
const reels = items.map((item) => ({
|
|
1713
|
+
...item,
|
|
1714
|
+
_avatar: Toolkit.resolveMedia(
|
|
1715
|
+
this.#client,
|
|
1716
|
+
item.profileIconUrl ?? item.profile_url ?? item.profile ?? "",
|
|
1717
|
+
"image",
|
|
1718
|
+
),
|
|
1719
|
+
_thumbnail: Toolkit.resolveMedia(
|
|
1720
|
+
this.#client,
|
|
1721
|
+
item.thumbnailUrl ?? item.thumbnail ?? "",
|
|
1722
|
+
"image",
|
|
1723
|
+
),
|
|
1724
|
+
}));
|
|
1725
|
+
|
|
1726
|
+
const section = AIRich.newLayout(
|
|
1727
|
+
"HScroll",
|
|
1728
|
+
reels.map((item) => ({
|
|
1729
|
+
reels_url: item.videoUrl ?? item.url ?? "",
|
|
1730
|
+
thumbnail_url: item._thumbnail,
|
|
1731
|
+
creator: item.username ?? item.title ?? "",
|
|
1732
|
+
avatar_url: item._avatar,
|
|
1733
|
+
reels_title: item.reels_title ?? item.title ?? "",
|
|
1734
|
+
likes_count: item.likes_count ?? item.like ?? 0,
|
|
1735
|
+
shares_count: item.shares_count ?? item.share ?? 0,
|
|
1736
|
+
view_count: item.view_count ?? item.view ?? 0,
|
|
1737
|
+
reel_source: item.reel_source ?? item.source ?? "IG",
|
|
1738
|
+
is_verified: !!(item.is_verified || item.verified),
|
|
1739
|
+
__typename: "GenAIReelPrimitive",
|
|
1740
|
+
})),
|
|
1741
|
+
);
|
|
1742
|
+
|
|
1743
|
+
const submessages = [
|
|
1744
|
+
{
|
|
1745
|
+
messageType: 9,
|
|
1746
|
+
contentItemsMetadata: {
|
|
1747
|
+
contentType: 1,
|
|
1748
|
+
itemsMetadata: reels.map((item) => ({
|
|
1749
|
+
reelItem: {
|
|
1750
|
+
title: item.username ?? "",
|
|
1751
|
+
profileIconUrl: item._avatar,
|
|
1752
|
+
thumbnailUrl: item._thumbnail,
|
|
1753
|
+
videoUrl: item.videoUrl ?? item.url ?? "",
|
|
1754
|
+
},
|
|
1755
|
+
})),
|
|
1756
|
+
},
|
|
1757
|
+
},
|
|
1758
|
+
];
|
|
1759
|
+
|
|
1760
|
+
return this._addContent(section, submessages, {
|
|
1761
|
+
id,
|
|
1762
|
+
replace,
|
|
1763
|
+
insertAt,
|
|
1764
|
+
});
|
|
1765
|
+
}
|
|
1766
|
+
|
|
1767
|
+
addImage(
|
|
1768
|
+
imageUrl,
|
|
1769
|
+
{
|
|
1770
|
+
width,
|
|
1771
|
+
height,
|
|
1772
|
+
status = "READY",
|
|
1773
|
+
update_text,
|
|
1774
|
+
resolveUrl = false,
|
|
1775
|
+
id,
|
|
1776
|
+
replace,
|
|
1777
|
+
insertAt,
|
|
1778
|
+
} = {},
|
|
1779
|
+
) {
|
|
1780
|
+
if (
|
|
1781
|
+
!(
|
|
1782
|
+
typeof imageUrl === "string" ||
|
|
1783
|
+
Buffer.isBuffer(imageUrl) ||
|
|
1784
|
+
(Array.isArray(imageUrl) &&
|
|
1785
|
+
imageUrl.every((v) => typeof v === "string" || Buffer.isBuffer(v)))
|
|
1786
|
+
)
|
|
1787
|
+
) {
|
|
1788
|
+
throw new TypeError(
|
|
1789
|
+
"imageUrl must be string | buffer | array of string/buffer",
|
|
1790
|
+
);
|
|
1791
|
+
}
|
|
1792
|
+
|
|
1793
|
+
const list = Array.isArray(imageUrl)
|
|
1794
|
+
? imageUrl.map((v) => {
|
|
1795
|
+
const url = Toolkit.resolveMedia(this.#client, v, "image", {
|
|
1796
|
+
resolveUrl,
|
|
1797
|
+
});
|
|
1798
|
+
|
|
1799
|
+
return {
|
|
1800
|
+
imagePreviewUrl: url,
|
|
1801
|
+
imageHighResUrl: url,
|
|
1802
|
+
sourceUrl: url,
|
|
1803
|
+
};
|
|
1804
|
+
})
|
|
1805
|
+
: (() => {
|
|
1806
|
+
const url = Toolkit.resolveMedia(this.#client, imageUrl, "image", {
|
|
1807
|
+
resolveUrl,
|
|
1808
|
+
});
|
|
1809
|
+
|
|
1810
|
+
return [
|
|
1811
|
+
{
|
|
1812
|
+
imagePreviewUrl: url,
|
|
1813
|
+
imageHighResUrl: url,
|
|
1814
|
+
sourceUrl: url,
|
|
1815
|
+
},
|
|
1816
|
+
];
|
|
1817
|
+
})();
|
|
1818
|
+
|
|
1819
|
+
const sections = list.map(({ imagePreviewUrl }) =>
|
|
1820
|
+
AIRich.newLayout("Single", {
|
|
1821
|
+
media: {
|
|
1822
|
+
url: imagePreviewUrl,
|
|
1823
|
+
mime_type: "image/png",
|
|
1824
|
+
width,
|
|
1825
|
+
height,
|
|
1826
|
+
},
|
|
1827
|
+
imagine_type: "IMAGE",
|
|
1828
|
+
status: {
|
|
1829
|
+
status,
|
|
1830
|
+
update_text,
|
|
1831
|
+
},
|
|
1832
|
+
__typename: "GenAIImaginePrimitive",
|
|
1833
|
+
}),
|
|
1834
|
+
);
|
|
1835
|
+
|
|
1836
|
+
const submessage = {
|
|
1837
|
+
messageType: 1,
|
|
1838
|
+
gridImageMetadata: {
|
|
1839
|
+
gridImageUrl: {
|
|
1840
|
+
imagePreviewUrl: list[0]?.imagePreviewUrl,
|
|
1841
|
+
},
|
|
1842
|
+
imageUrls: list,
|
|
1843
|
+
},
|
|
1844
|
+
};
|
|
1845
|
+
|
|
1846
|
+
if (id && sections.length !== 1) {
|
|
1847
|
+
throw new Error("Cannot assign one id to multiple image sections");
|
|
1848
|
+
}
|
|
1849
|
+
|
|
1850
|
+
return this._addContent(sections, submessage, {
|
|
1851
|
+
id,
|
|
1852
|
+
replace,
|
|
1853
|
+
insertAt,
|
|
1854
|
+
});
|
|
1855
|
+
}
|
|
1856
|
+
|
|
1857
|
+
addVideo(
|
|
1858
|
+
videoUrl,
|
|
1859
|
+
{
|
|
1860
|
+
autoFill = true,
|
|
1861
|
+
status = "READY",
|
|
1862
|
+
estimatedTime,
|
|
1863
|
+
id,
|
|
1864
|
+
replace,
|
|
1865
|
+
insertAt,
|
|
1866
|
+
} = {},
|
|
1867
|
+
) {
|
|
1868
|
+
const isObjectVideo = (v) =>
|
|
1869
|
+
v && typeof v === "object" && !Array.isArray(v) && v.url;
|
|
1870
|
+
|
|
1871
|
+
const isValidPrimitive =
|
|
1872
|
+
typeof videoUrl === "string" ||
|
|
1873
|
+
Buffer.isBuffer(videoUrl) ||
|
|
1874
|
+
isObjectVideo(videoUrl) ||
|
|
1875
|
+
(Array.isArray(videoUrl) &&
|
|
1876
|
+
videoUrl.every(
|
|
1877
|
+
(v) =>
|
|
1878
|
+
typeof v === "string" || Buffer.isBuffer(v) || isObjectVideo(v),
|
|
1879
|
+
));
|
|
1880
|
+
|
|
1881
|
+
if (!isValidPrimitive) {
|
|
1882
|
+
throw new TypeError("videoUrl must be string | buffer | object | array");
|
|
1883
|
+
}
|
|
1884
|
+
|
|
1885
|
+
const items = Array.isArray(videoUrl) ? videoUrl : [videoUrl];
|
|
1886
|
+
|
|
1887
|
+
const alert = this.createAlert("GenAIImaginePrimitive (ANIMATE)");
|
|
1888
|
+
|
|
1889
|
+
const sections = [];
|
|
1890
|
+
const submessages = [];
|
|
1891
|
+
|
|
1892
|
+
for (const item of items) {
|
|
1893
|
+
const isObject = isObjectVideo(item);
|
|
1894
|
+
|
|
1895
|
+
const url = isObject
|
|
1896
|
+
? Toolkit.resolveMedia(this.#client, item.url ?? "", "video")
|
|
1897
|
+
: Toolkit.resolveMedia(this.#client, item, "video");
|
|
1898
|
+
|
|
1899
|
+
const bufferPromise = autoFill
|
|
1900
|
+
? Promise.resolve(url).then((u) => Toolkit.fetchBuffer(u))
|
|
1901
|
+
: null;
|
|
1902
|
+
|
|
1903
|
+
const file_length =
|
|
1904
|
+
isObject && item.file_length != null
|
|
1905
|
+
? item.file_length
|
|
1906
|
+
: autoFill
|
|
1907
|
+
? bufferPromise.then((b) => b?.length ?? 0)
|
|
1908
|
+
: 0;
|
|
1909
|
+
|
|
1910
|
+
const duration =
|
|
1911
|
+
isObject && item.duration != null
|
|
1912
|
+
? item.duration
|
|
1913
|
+
: autoFill
|
|
1914
|
+
? bufferPromise.then((b) =>
|
|
1915
|
+
Toolkit.getMp4Duration(b, {
|
|
1916
|
+
silent: true,
|
|
1917
|
+
}),
|
|
1918
|
+
)
|
|
1919
|
+
: 0;
|
|
1920
|
+
|
|
1921
|
+
const thumbnail =
|
|
1922
|
+
isObject && item.thumbnail
|
|
1923
|
+
? Toolkit.resolveMedia(this.#client, item.thumbnail, "image", {
|
|
1924
|
+
result: "base64",
|
|
1925
|
+
resize: true,
|
|
1926
|
+
width: 300,
|
|
1927
|
+
height: 300,
|
|
1928
|
+
})
|
|
1929
|
+
: autoFill
|
|
1930
|
+
? bufferPromise?.then((b) =>
|
|
1931
|
+
Toolkit.getMp4Preview(b, {
|
|
1932
|
+
time: 0,
|
|
1933
|
+
result: "base64",
|
|
1934
|
+
}),
|
|
1935
|
+
)
|
|
1936
|
+
: null;
|
|
1937
|
+
|
|
1938
|
+
sections.push(
|
|
1939
|
+
AIRich.newLayout("Single", {
|
|
1940
|
+
media: {
|
|
1941
|
+
url,
|
|
1942
|
+
mime_type: isObject ? (item.mime_type ?? "video/mp4") : "video/mp4",
|
|
1943
|
+
file_length,
|
|
1944
|
+
duration,
|
|
1945
|
+
},
|
|
1946
|
+
imagine_type: "ANIMATE",
|
|
1947
|
+
status: {
|
|
1948
|
+
status,
|
|
1949
|
+
estimated_completion_time:
|
|
1950
|
+
estimatedTime != null
|
|
1951
|
+
? Math.floor((Date.now() + estimatedTime) / 1000)
|
|
1952
|
+
: undefined,
|
|
1953
|
+
},
|
|
1954
|
+
thumbnail: {
|
|
1955
|
+
raw_media: thumbnail,
|
|
1956
|
+
},
|
|
1957
|
+
__typename: "GenAIImaginePrimitive",
|
|
1958
|
+
}),
|
|
1959
|
+
);
|
|
1960
|
+
}
|
|
1961
|
+
|
|
1962
|
+
if (alert !== undefined) {
|
|
1963
|
+
submessages.push(alert);
|
|
1964
|
+
}
|
|
1965
|
+
|
|
1966
|
+
if (submessages.length > 1) {
|
|
1967
|
+
throw new Error("Video content can only have one submessage");
|
|
1968
|
+
}
|
|
1969
|
+
|
|
1970
|
+
return this._addContent(sections, submessages[0], {
|
|
1971
|
+
id,
|
|
1972
|
+
replace,
|
|
1973
|
+
insertAt,
|
|
1974
|
+
});
|
|
1975
|
+
}
|
|
1976
|
+
|
|
1977
|
+
addProduct(data = {}, { id, replace, insertAt } = {}) {
|
|
1978
|
+
if (
|
|
1979
|
+
!(
|
|
1980
|
+
(data && typeof data === "object" && !Array.isArray(data)) ||
|
|
1981
|
+
(Array.isArray(data) &&
|
|
1982
|
+
data.every(
|
|
1983
|
+
(item) => item && typeof item === "object" && !Array.isArray(item),
|
|
1984
|
+
))
|
|
1985
|
+
)
|
|
1986
|
+
) {
|
|
1987
|
+
throw new TypeError(
|
|
1988
|
+
"Product items must be an object or an array of objects",
|
|
1989
|
+
);
|
|
1990
|
+
}
|
|
1991
|
+
|
|
1992
|
+
const items = Array.isArray(data) ? data : [data];
|
|
1993
|
+
|
|
1994
|
+
const product = items.map((item) => ({
|
|
1995
|
+
title: item.title,
|
|
1996
|
+
brand: item.brand,
|
|
1997
|
+
price: item.price,
|
|
1998
|
+
sale_price: item.sale_price,
|
|
1999
|
+
product_url: item.product_url ?? item.url,
|
|
2000
|
+
image: {
|
|
2001
|
+
url: Toolkit.resolveMedia(
|
|
2002
|
+
this.#client,
|
|
2003
|
+
item.image_url ?? item.image,
|
|
2004
|
+
"image",
|
|
2005
|
+
),
|
|
2006
|
+
},
|
|
2007
|
+
additional_images: [
|
|
2008
|
+
{
|
|
2009
|
+
url: Toolkit.resolveMedia(
|
|
2010
|
+
this.#client,
|
|
2011
|
+
item.icon_url ?? item.icon,
|
|
2012
|
+
"image",
|
|
2013
|
+
),
|
|
2014
|
+
},
|
|
2015
|
+
],
|
|
2016
|
+
__typename: "GenAIProductItemCardPrimitive",
|
|
2017
|
+
}));
|
|
2018
|
+
|
|
2019
|
+
const section = AIRich.newLayout(
|
|
2020
|
+
Array.isArray(data) ? "HScroll" : "Single",
|
|
2021
|
+
Array.isArray(data) ? product : product[0],
|
|
2022
|
+
);
|
|
2023
|
+
|
|
2024
|
+
const submessage = this.createAlert("GenAIProductItemCardPrimitive");
|
|
2025
|
+
|
|
2026
|
+
return this._addContent(section, submessage, {
|
|
2027
|
+
id,
|
|
2028
|
+
replace,
|
|
2029
|
+
insertAt,
|
|
2030
|
+
});
|
|
2031
|
+
}
|
|
2032
|
+
|
|
2033
|
+
addPost(data = {}, { id, replace, insertAt } = {}) {
|
|
2034
|
+
if (
|
|
2035
|
+
!(
|
|
2036
|
+
(data && typeof data === "object" && !Array.isArray(data)) ||
|
|
2037
|
+
(Array.isArray(data) &&
|
|
2038
|
+
data.every(
|
|
2039
|
+
(item) => item && typeof item === "object" && !Array.isArray(item),
|
|
2040
|
+
))
|
|
2041
|
+
)
|
|
2042
|
+
) {
|
|
2043
|
+
throw new TypeError(
|
|
2044
|
+
"Post items must be an object or an array of objects",
|
|
2045
|
+
);
|
|
2046
|
+
}
|
|
2047
|
+
|
|
2048
|
+
const posts = Array.isArray(data) ? data : [data];
|
|
2049
|
+
|
|
2050
|
+
const primitives = posts.map((p) => ({
|
|
2051
|
+
title: p.title ?? "",
|
|
2052
|
+
subtitle: p.subtitle ?? "",
|
|
2053
|
+
username: p.username ?? "",
|
|
2054
|
+
profile_picture_url: Toolkit.resolveMedia(
|
|
2055
|
+
this.#client,
|
|
2056
|
+
p.profile_picture_url ?? p.profile_url ?? p.profile ?? "",
|
|
2057
|
+
"image",
|
|
2058
|
+
),
|
|
2059
|
+
is_verified: !!(p.is_verified || p.verified),
|
|
2060
|
+
thumbnail_url: Toolkit.resolveMedia(
|
|
2061
|
+
this.#client,
|
|
2062
|
+
p.thumbnail_url ?? p.thumbnail ?? "",
|
|
2063
|
+
"image",
|
|
2064
|
+
),
|
|
2065
|
+
post_caption: p.post_caption ?? p.caption ?? "",
|
|
2066
|
+
likes_count: p.likes_count ?? p.like ?? 0,
|
|
2067
|
+
comments_count: p.comments_count ?? p.comment ?? 0,
|
|
2068
|
+
shares_count: p.shares_count ?? p.share ?? 0,
|
|
2069
|
+
post_url: p.post_url ?? p.url ?? "",
|
|
2070
|
+
post_deeplink: p.post_deeplink ?? p.deeplink ?? "",
|
|
2071
|
+
source_app: p.source_app || p.source || "INSTAGRAM",
|
|
2072
|
+
footer_label: p.footer_label ?? p.footer ?? "",
|
|
2073
|
+
footer_icon: Toolkit.resolveMedia(
|
|
2074
|
+
this.#client,
|
|
2075
|
+
p.footer_icon ?? p.icon ?? "",
|
|
2076
|
+
"image",
|
|
2077
|
+
),
|
|
2078
|
+
is_carousel: posts.length > 1,
|
|
2079
|
+
orientation: p.orientation ?? "LANDSCAPE",
|
|
2080
|
+
post_type: p.post_type ?? "VIDEO",
|
|
2081
|
+
__typename: "GenAIPostPrimitive",
|
|
2082
|
+
}));
|
|
2083
|
+
|
|
2084
|
+
const section = AIRich.newLayout("HScroll", primitives);
|
|
2085
|
+
|
|
2086
|
+
const submessage = this.createAlert("GenAIPostPrimitive");
|
|
2087
|
+
|
|
2088
|
+
return this._addContent(section, submessage, {
|
|
2089
|
+
id,
|
|
2090
|
+
replace,
|
|
2091
|
+
insertAt,
|
|
2092
|
+
});
|
|
2093
|
+
}
|
|
2094
|
+
|
|
2095
|
+
addMetadata(text, { id, replace, insertAt } = {}) {
|
|
2096
|
+
if (typeof text !== "string") {
|
|
2097
|
+
throw new TypeError("Text must be a string");
|
|
2098
|
+
}
|
|
2099
|
+
|
|
2100
|
+
const section = AIRich.newLayout("Single", {
|
|
2101
|
+
text,
|
|
2102
|
+
__typename: "GenAIMetadataTextPrimitive",
|
|
2103
|
+
});
|
|
2104
|
+
|
|
2105
|
+
const submessage = {
|
|
2106
|
+
messageType: 2,
|
|
2107
|
+
messageText: text,
|
|
2108
|
+
};
|
|
2109
|
+
|
|
2110
|
+
return this._addContent(section, submessage, {
|
|
2111
|
+
id,
|
|
2112
|
+
replace,
|
|
2113
|
+
insertAt,
|
|
2114
|
+
});
|
|
2115
|
+
}
|
|
2116
|
+
|
|
2117
|
+
addTip(text, { id, replace, insertAt } = {}) {
|
|
2118
|
+
if (typeof text !== "string") {
|
|
2119
|
+
throw new TypeError("Text must be a string");
|
|
2120
|
+
}
|
|
2121
|
+
|
|
2122
|
+
const section = AIRich.newLayout("Single", {
|
|
2123
|
+
text: "ⓘ " + text,
|
|
2124
|
+
__typename: "GenAIMetadataTextPrimitive",
|
|
2125
|
+
});
|
|
2126
|
+
|
|
2127
|
+
const submessage = {
|
|
2128
|
+
messageType: 2,
|
|
2129
|
+
messageText: text,
|
|
2130
|
+
};
|
|
2131
|
+
|
|
2132
|
+
return this._addContent(section, submessage, {
|
|
2133
|
+
id,
|
|
2134
|
+
replace,
|
|
2135
|
+
insertAt,
|
|
2136
|
+
});
|
|
2137
|
+
}
|
|
2138
|
+
|
|
2139
|
+
addWidget(data, { layout, id, replace, insertAt, ...options } = {}) {
|
|
2140
|
+
if (
|
|
2141
|
+
!(
|
|
2142
|
+
(data && typeof data === "object" && !Array.isArray(data)) ||
|
|
2143
|
+
(Array.isArray(data) &&
|
|
2144
|
+
data.every(
|
|
2145
|
+
(item) => item && typeof item === "object" && !Array.isArray(item),
|
|
2146
|
+
))
|
|
2147
|
+
)
|
|
2148
|
+
) {
|
|
2149
|
+
throw new TypeError("Widget must be an object or an array of objects");
|
|
2150
|
+
}
|
|
2151
|
+
|
|
2152
|
+
const isArray = Array.isArray(data);
|
|
2153
|
+
|
|
2154
|
+
const items = isArray ? data : [data];
|
|
2155
|
+
|
|
2156
|
+
const widgets = items.map((item) => ({
|
|
2157
|
+
__typename: "GenAI3PExtWidgetPrimitive",
|
|
2158
|
+
|
|
2159
|
+
header: {
|
|
2160
|
+
__typename: "GenAI3PExtWidgetStandardHeader",
|
|
2161
|
+
title: item.title ?? "",
|
|
2162
|
+
...(item.header ?? {}),
|
|
2163
|
+
},
|
|
2164
|
+
|
|
2165
|
+
body: {
|
|
2166
|
+
__typename: "GenAI3PExtCalendarEventList",
|
|
2167
|
+
sections: item.sections ?? [],
|
|
2168
|
+
|
|
2169
|
+
ctas: (item.actions ?? []).map((action) => ({
|
|
2170
|
+
__typename: "GenAI3PExtWidgetCTA",
|
|
2171
|
+
label: action.label ?? "",
|
|
2172
|
+
state: action.state ?? "PENDING",
|
|
2173
|
+
kind: action.kind ?? "OTHER",
|
|
2174
|
+
tool_call_id: action.tool_call_id ?? action.id ?? "",
|
|
2175
|
+
|
|
2176
|
+
...(action.toast && {
|
|
2177
|
+
toast: {
|
|
2178
|
+
__typename: "GenAI3PExtWidgetToast",
|
|
2179
|
+
label: action.toast.label ?? action.label ?? "",
|
|
2180
|
+
},
|
|
2181
|
+
}),
|
|
2182
|
+
})),
|
|
2183
|
+
|
|
2184
|
+
...(item.body ?? {}),
|
|
2185
|
+
},
|
|
2186
|
+
}));
|
|
2187
|
+
|
|
2188
|
+
const section = AIRich.newLayout(
|
|
2189
|
+
layout ?? (isArray ? "HScroll" : "Single"),
|
|
2190
|
+
isArray ? widgets : widgets[0],
|
|
2191
|
+
options,
|
|
2192
|
+
);
|
|
2193
|
+
|
|
2194
|
+
const submessage = this.createAlert("GenAI3PExtWidgetStandardHeader");
|
|
2195
|
+
|
|
2196
|
+
return this._addContent(section, submessage, {
|
|
2197
|
+
id,
|
|
2198
|
+
replace,
|
|
2199
|
+
insertAt,
|
|
2200
|
+
});
|
|
2201
|
+
}
|
|
2202
|
+
|
|
2203
|
+
addFooterAction(data, { layout, id, replace, insertAt, ...options } = {}) {
|
|
2204
|
+
if (
|
|
2205
|
+
!(
|
|
2206
|
+
(data && typeof data === "object" && !Array.isArray(data)) ||
|
|
2207
|
+
(Array.isArray(data) &&
|
|
2208
|
+
data.every(
|
|
2209
|
+
(item) => item && typeof item === "object" && !Array.isArray(item),
|
|
2210
|
+
))
|
|
2211
|
+
)
|
|
2212
|
+
) {
|
|
2213
|
+
throw new TypeError(
|
|
2214
|
+
"Footer action must be an object or an array of objects",
|
|
2215
|
+
);
|
|
2216
|
+
}
|
|
2217
|
+
|
|
2218
|
+
const isArray = Array.isArray(data);
|
|
2219
|
+
|
|
2220
|
+
const items = isArray ? data : [data];
|
|
2221
|
+
|
|
2222
|
+
const actions = items.map((item) => ({
|
|
2223
|
+
__typename: "GenAIFooterActionPrimitive",
|
|
2224
|
+
|
|
2225
|
+
cta_text: item.text ?? item.cta_text ?? "",
|
|
2226
|
+
|
|
2227
|
+
cta_type: item.type ?? item.cta_type ?? "OPEN_URL",
|
|
2228
|
+
|
|
2229
|
+
cta_url: item.url ?? item.cta_url ?? "",
|
|
2230
|
+
}));
|
|
2231
|
+
|
|
2232
|
+
const section = AIRich.newLayout(
|
|
2233
|
+
layout ?? (isArray ? "HScroll" : "Single"),
|
|
2234
|
+
isArray ? actions : actions[0],
|
|
2235
|
+
options,
|
|
2236
|
+
);
|
|
2237
|
+
|
|
2238
|
+
const submessage = this.createAlert("GenAIFooterActionPrimitive");
|
|
2239
|
+
|
|
2240
|
+
return this._addContent(section, submessage, {
|
|
2241
|
+
id,
|
|
2242
|
+
replace,
|
|
2243
|
+
insertAt,
|
|
2244
|
+
});
|
|
2245
|
+
}
|
|
2246
|
+
|
|
2247
|
+
addSuggest(
|
|
2248
|
+
suggestion,
|
|
2249
|
+
{ scroll = true, layout, id, replace, insertAt } = {},
|
|
2250
|
+
) {
|
|
2251
|
+
if (
|
|
2252
|
+
!(
|
|
2253
|
+
typeof suggestion === "string" ||
|
|
2254
|
+
(Array.isArray(suggestion) &&
|
|
2255
|
+
suggestion.every((v) => typeof v === "string"))
|
|
2256
|
+
)
|
|
2257
|
+
) {
|
|
2258
|
+
throw new TypeError("Suggestion must be a string or array of strings");
|
|
2259
|
+
}
|
|
2260
|
+
|
|
2261
|
+
const suggest = Array.isArray(suggestion)
|
|
2262
|
+
? suggestion.map((text) => ({
|
|
2263
|
+
prompt_text: text,
|
|
2264
|
+
prompt_type: "SUGGESTED_PROMPT",
|
|
2265
|
+
__typename: "GenAIFollowUpSuggestionPillPrimitive",
|
|
2266
|
+
}))
|
|
2267
|
+
: [
|
|
2268
|
+
{
|
|
2269
|
+
prompt_text: suggestion,
|
|
2270
|
+
prompt_type: "SUGGESTED_PROMPT",
|
|
2271
|
+
__typename: "GenAIFollowUpSuggestionPillPrimitive",
|
|
2272
|
+
},
|
|
2273
|
+
];
|
|
2274
|
+
|
|
2275
|
+
const type =
|
|
2276
|
+
layout ??
|
|
2277
|
+
(suggest.length === 1 ? "Single" : scroll ? "HScroll" : "ActionRow");
|
|
2278
|
+
|
|
2279
|
+
const section = AIRich.newLayout(
|
|
2280
|
+
type,
|
|
2281
|
+
type === "Single" ? suggest[0] : suggest,
|
|
2282
|
+
{
|
|
2283
|
+
__typename: "GenAIUnifiedResponseSection",
|
|
2284
|
+
},
|
|
2285
|
+
);
|
|
2286
|
+
|
|
2287
|
+
const submessage = this.createAlert("GenAIFollowUpSuggestionPillPrimitive");
|
|
2288
|
+
|
|
2289
|
+
return this._addContent(section, submessage, {
|
|
2290
|
+
id,
|
|
2291
|
+
replace,
|
|
2292
|
+
insertAt,
|
|
2293
|
+
});
|
|
2294
|
+
}
|
|
2295
|
+
|
|
2296
|
+
async build(
|
|
2297
|
+
jid,
|
|
2298
|
+
{
|
|
2299
|
+
bypassDownload = true,
|
|
2300
|
+
forwarded = true,
|
|
2301
|
+
notification = false,
|
|
2302
|
+
includesUnifiedResponse = true,
|
|
2303
|
+
includesSubmessages = true,
|
|
2304
|
+
quoted,
|
|
2305
|
+
quotedParticipant,
|
|
2306
|
+
messageId,
|
|
2307
|
+
...options
|
|
2308
|
+
} = {},
|
|
2309
|
+
) {
|
|
2310
|
+
const forward = forwarded
|
|
2311
|
+
? {
|
|
2312
|
+
forwardingScore: 1,
|
|
2313
|
+
isForwarded: true,
|
|
2314
|
+
forwardedAiBotMessageInfo: { botJid: "867051314767696@bot" },
|
|
2315
|
+
forwardOrigin: 4,
|
|
2316
|
+
}
|
|
2317
|
+
: {};
|
|
2318
|
+
|
|
2319
|
+
const notif = notification
|
|
2320
|
+
? {
|
|
2321
|
+
sessionTransparencyMetadata: {
|
|
2322
|
+
disclaimerText: "~ Ahmad tumbuh kembang",
|
|
2323
|
+
hcaId: `hca_${Date.now()}`,
|
|
2324
|
+
sessionTransparencyType: 1,
|
|
2325
|
+
},
|
|
2326
|
+
}
|
|
2327
|
+
: {};
|
|
2328
|
+
|
|
2329
|
+
const qObj = quoted
|
|
2330
|
+
? {
|
|
2331
|
+
stanzaId: quoted?.key?.id || quoted?.id,
|
|
2332
|
+
participant:
|
|
2333
|
+
quotedParticipant ||
|
|
2334
|
+
quoted?.key?.participant ||
|
|
2335
|
+
quoted?.participant ||
|
|
2336
|
+
quoted?.key?.remoteJid,
|
|
2337
|
+
quotedType: 0,
|
|
2338
|
+
quotedMessage:
|
|
2339
|
+
typeof quoted === "object" && quoted !== null
|
|
2340
|
+
? (quoted.message ?? quoted)
|
|
2341
|
+
: undefined,
|
|
2342
|
+
}
|
|
2343
|
+
: {};
|
|
2344
|
+
|
|
2345
|
+
const sections = this._footer
|
|
2346
|
+
? [
|
|
2347
|
+
...(await waitAllPromises(this._sections)),
|
|
2348
|
+
AIRich.newLayout("Single", {
|
|
2349
|
+
text: this._footer,
|
|
2350
|
+
__typename: "GenAIMetadataTextPrimitive",
|
|
2351
|
+
}),
|
|
2352
|
+
]
|
|
2353
|
+
: [...(await waitAllPromises(this._sections))];
|
|
2354
|
+
|
|
2355
|
+
if (this._dynamic) {
|
|
2356
|
+
this.refreshResponseId();
|
|
2357
|
+
this.refreshBotResponseId();
|
|
2358
|
+
}
|
|
2359
|
+
|
|
2360
|
+
return generateWAMessageFromContent(
|
|
2361
|
+
jid,
|
|
2362
|
+
{
|
|
2363
|
+
messageContextInfo: {
|
|
2364
|
+
deviceListMetadata: {},
|
|
2365
|
+
deviceListMetadataVersion: 2,
|
|
2366
|
+
botMetadata: {
|
|
2367
|
+
messageDisclaimerText: this._title,
|
|
2368
|
+
...notif,
|
|
2369
|
+
verificationMetadata: AIRich.generateVerificationMetadata(),
|
|
2370
|
+
botResponseId: this._botResponseId,
|
|
2371
|
+
},
|
|
2372
|
+
},
|
|
2373
|
+
...this._extraPayload,
|
|
2374
|
+
botForwardedMessage: {
|
|
2375
|
+
message: {
|
|
2376
|
+
richResponseMessage: {
|
|
2377
|
+
messageType: 1,
|
|
2378
|
+
submessages: includesSubmessages
|
|
2379
|
+
? await waitAllPromises(this._submessages)
|
|
2380
|
+
: [],
|
|
2381
|
+
unifiedResponse: {
|
|
2382
|
+
data: includesUnifiedResponse
|
|
2383
|
+
? Buffer.from(
|
|
2384
|
+
Toolkit.stringifyEscaped({
|
|
2385
|
+
response_id: this._responseId,
|
|
2386
|
+
sections,
|
|
2387
|
+
}),
|
|
2388
|
+
).toString("base64")
|
|
2389
|
+
: "",
|
|
2390
|
+
},
|
|
2391
|
+
contextInfo: {
|
|
2392
|
+
...forward,
|
|
2393
|
+
...qObj,
|
|
2394
|
+
...this._contextInfo,
|
|
2395
|
+
},
|
|
2396
|
+
},
|
|
2397
|
+
},
|
|
2398
|
+
},
|
|
2399
|
+
},
|
|
2400
|
+
{ messageId: messageId || generateMessageIDV2(), ...options },
|
|
2401
|
+
);
|
|
2402
|
+
}
|
|
2403
|
+
|
|
2404
|
+
async buildEdit(targetJid, targetId, { msg, messageId, ...options } = {}) {
|
|
2405
|
+
if (!msg) {
|
|
2406
|
+
msg = (await this.build(targetJid, options)).message;
|
|
2407
|
+
}
|
|
2408
|
+
|
|
2409
|
+
const editedMessage = msg;
|
|
2410
|
+
|
|
2411
|
+
if (!editedMessage) {
|
|
2412
|
+
throw new Error("buildEdit: msg does not contain botForwardedMessage");
|
|
2413
|
+
}
|
|
2414
|
+
|
|
2415
|
+
return generateWAMessageFromContent(
|
|
2416
|
+
targetJid,
|
|
2417
|
+
{
|
|
2418
|
+
botForwardedMessage: {
|
|
2419
|
+
message: {
|
|
2420
|
+
protocolMessage: {
|
|
2421
|
+
key: {
|
|
2422
|
+
remoteJid: targetJid,
|
|
2423
|
+
fromMe: true,
|
|
2424
|
+
id: targetId,
|
|
2425
|
+
},
|
|
2426
|
+
type: 14,
|
|
2427
|
+
editedMessage,
|
|
2428
|
+
},
|
|
2429
|
+
},
|
|
2430
|
+
},
|
|
2431
|
+
},
|
|
2432
|
+
{ messageId: messageId || generateMessageIDV2(), ...options },
|
|
2433
|
+
);
|
|
2434
|
+
}
|
|
2435
|
+
|
|
2436
|
+
async sendEdit(
|
|
2437
|
+
jid,
|
|
2438
|
+
id,
|
|
2439
|
+
{ msg, messageId, additionalNodes = [], ...options } = {},
|
|
2440
|
+
) {
|
|
2441
|
+
jid = jid ?? this._lastMessageKey?.remoteJid;
|
|
2442
|
+
id = id ?? this._lastMessageKey?.id;
|
|
2443
|
+
|
|
2444
|
+
if (!jid) {
|
|
2445
|
+
throw new Error("JID is required");
|
|
2446
|
+
}
|
|
2447
|
+
|
|
2448
|
+
if (!id) {
|
|
2449
|
+
throw new Error("Message id is required");
|
|
2450
|
+
}
|
|
2451
|
+
|
|
2452
|
+
const msgEdit = await this.buildEdit(jid, id, {
|
|
2453
|
+
msg,
|
|
2454
|
+
messageId: messageId || generateMessageIDV2(),
|
|
2455
|
+
...options,
|
|
2456
|
+
});
|
|
2457
|
+
|
|
2458
|
+
await this.#client.relayMessage(jid, msgEdit.message, {
|
|
2459
|
+
messageId: msgEdit.key.id,
|
|
2460
|
+
additionalNodes,
|
|
2461
|
+
});
|
|
2462
|
+
|
|
2463
|
+
return msgEdit;
|
|
2464
|
+
}
|
|
2465
|
+
|
|
2466
|
+
async send(
|
|
2467
|
+
jid,
|
|
2468
|
+
{
|
|
2469
|
+
bypassDownload = true,
|
|
2470
|
+
forwarded = true,
|
|
2471
|
+
notification = false,
|
|
2472
|
+
includesUnifiedResponse = true,
|
|
2473
|
+
includesSubmessages = true,
|
|
2474
|
+
messageId,
|
|
2475
|
+
additionalNodes = [],
|
|
2476
|
+
...options
|
|
2477
|
+
} = {},
|
|
2478
|
+
) {
|
|
2479
|
+
const msg = await this.build(jid, {
|
|
2480
|
+
forwarded,
|
|
2481
|
+
notification,
|
|
2482
|
+
includesUnifiedResponse,
|
|
2483
|
+
includesSubmessages,
|
|
2484
|
+
messageId,
|
|
2485
|
+
...options,
|
|
2486
|
+
});
|
|
2487
|
+
|
|
2488
|
+
await this.#client.relayMessage(msg.key.remoteJid, msg.message, {
|
|
2489
|
+
messageId: msg.key.id,
|
|
2490
|
+
additionalNodes,
|
|
2491
|
+
...options,
|
|
2492
|
+
});
|
|
2493
|
+
|
|
2494
|
+
if (includesUnifiedResponse && bypassDownload) {
|
|
2495
|
+
await this.sendEdit(jid, msg.key.id, {
|
|
2496
|
+
msg: msg.message,
|
|
2497
|
+
});
|
|
2498
|
+
}
|
|
2499
|
+
|
|
2500
|
+
this._lastMessageKey = msg.key;
|
|
2501
|
+
|
|
2502
|
+
return msg;
|
|
2503
|
+
}
|
|
2504
|
+
|
|
2505
|
+
static tokenizer(code, lang = "javascript") {
|
|
2506
|
+
const keywordsMap = {
|
|
2507
|
+
javascript: new Set([
|
|
2508
|
+
"break",
|
|
2509
|
+
"case",
|
|
2510
|
+
"catch",
|
|
2511
|
+
"continue",
|
|
2512
|
+
"debugger",
|
|
2513
|
+
"delete",
|
|
2514
|
+
"do",
|
|
2515
|
+
"else",
|
|
2516
|
+
"finally",
|
|
2517
|
+
"for",
|
|
2518
|
+
"function",
|
|
2519
|
+
"if",
|
|
2520
|
+
"in",
|
|
2521
|
+
"instanceof",
|
|
2522
|
+
"new",
|
|
2523
|
+
"return",
|
|
2524
|
+
"switch",
|
|
2525
|
+
"this",
|
|
2526
|
+
"throw",
|
|
2527
|
+
"try",
|
|
2528
|
+
"typeof",
|
|
2529
|
+
"var",
|
|
2530
|
+
"void",
|
|
2531
|
+
"while",
|
|
2532
|
+
"with",
|
|
2533
|
+
"true",
|
|
2534
|
+
"false",
|
|
2535
|
+
"null",
|
|
2536
|
+
"undefined",
|
|
2537
|
+
"class",
|
|
2538
|
+
"const",
|
|
2539
|
+
"let",
|
|
2540
|
+
"super",
|
|
2541
|
+
"extends",
|
|
2542
|
+
"export",
|
|
2543
|
+
"import",
|
|
2544
|
+
"yield",
|
|
2545
|
+
"static",
|
|
2546
|
+
"constructor",
|
|
2547
|
+
"async",
|
|
2548
|
+
"await",
|
|
2549
|
+
"get",
|
|
2550
|
+
"set",
|
|
2551
|
+
]),
|
|
2552
|
+
|
|
2553
|
+
typescript: new Set([
|
|
2554
|
+
"abstract",
|
|
2555
|
+
"any",
|
|
2556
|
+
"as",
|
|
2557
|
+
"asserts",
|
|
2558
|
+
"bigint",
|
|
2559
|
+
"boolean",
|
|
2560
|
+
"declare",
|
|
2561
|
+
"enum",
|
|
2562
|
+
"implements",
|
|
2563
|
+
"infer",
|
|
2564
|
+
"interface",
|
|
2565
|
+
"is",
|
|
2566
|
+
"keyof",
|
|
2567
|
+
"module",
|
|
2568
|
+
"namespace",
|
|
2569
|
+
"never",
|
|
2570
|
+
"readonly",
|
|
2571
|
+
"require",
|
|
2572
|
+
"number",
|
|
2573
|
+
"object",
|
|
2574
|
+
"override",
|
|
2575
|
+
"private",
|
|
2576
|
+
"protected",
|
|
2577
|
+
"public",
|
|
2578
|
+
"satisfies",
|
|
2579
|
+
"string",
|
|
2580
|
+
"symbol",
|
|
2581
|
+
"type",
|
|
2582
|
+
"unknown",
|
|
2583
|
+
"using",
|
|
2584
|
+
"from",
|
|
2585
|
+
"break",
|
|
2586
|
+
"case",
|
|
2587
|
+
"catch",
|
|
2588
|
+
"continue",
|
|
2589
|
+
"do",
|
|
2590
|
+
"else",
|
|
2591
|
+
"finally",
|
|
2592
|
+
"for",
|
|
2593
|
+
"function",
|
|
2594
|
+
"if",
|
|
2595
|
+
"new",
|
|
2596
|
+
"return",
|
|
2597
|
+
"switch",
|
|
2598
|
+
"this",
|
|
2599
|
+
"throw",
|
|
2600
|
+
"try",
|
|
2601
|
+
"var",
|
|
2602
|
+
"void",
|
|
2603
|
+
"while",
|
|
2604
|
+
"class",
|
|
2605
|
+
"const",
|
|
2606
|
+
"let",
|
|
2607
|
+
"extends",
|
|
2608
|
+
"import",
|
|
2609
|
+
"export",
|
|
2610
|
+
"async",
|
|
2611
|
+
"await",
|
|
2612
|
+
]),
|
|
2613
|
+
|
|
2614
|
+
python: new Set([
|
|
2615
|
+
"False",
|
|
2616
|
+
"None",
|
|
2617
|
+
"True",
|
|
2618
|
+
"and",
|
|
2619
|
+
"as",
|
|
2620
|
+
"assert",
|
|
2621
|
+
"async",
|
|
2622
|
+
"await",
|
|
2623
|
+
"break",
|
|
2624
|
+
"class",
|
|
2625
|
+
"continue",
|
|
2626
|
+
"def",
|
|
2627
|
+
"del",
|
|
2628
|
+
"elif",
|
|
2629
|
+
"else",
|
|
2630
|
+
"except",
|
|
2631
|
+
"finally",
|
|
2632
|
+
"for",
|
|
2633
|
+
"from",
|
|
2634
|
+
"global",
|
|
2635
|
+
"if",
|
|
2636
|
+
"import",
|
|
2637
|
+
"in",
|
|
2638
|
+
"is",
|
|
2639
|
+
"lambda",
|
|
2640
|
+
"nonlocal",
|
|
2641
|
+
"not",
|
|
2642
|
+
"or",
|
|
2643
|
+
"pass",
|
|
2644
|
+
"raise",
|
|
2645
|
+
"return",
|
|
2646
|
+
"try",
|
|
2647
|
+
"while",
|
|
2648
|
+
"with",
|
|
2649
|
+
"yield",
|
|
2650
|
+
]),
|
|
2651
|
+
|
|
2652
|
+
java: new Set([
|
|
2653
|
+
"abstract",
|
|
2654
|
+
"assert",
|
|
2655
|
+
"boolean",
|
|
2656
|
+
"break",
|
|
2657
|
+
"byte",
|
|
2658
|
+
"case",
|
|
2659
|
+
"catch",
|
|
2660
|
+
"char",
|
|
2661
|
+
"class",
|
|
2662
|
+
"const",
|
|
2663
|
+
"continue",
|
|
2664
|
+
"default",
|
|
2665
|
+
"do",
|
|
2666
|
+
"double",
|
|
2667
|
+
"else",
|
|
2668
|
+
"enum",
|
|
2669
|
+
"extends",
|
|
2670
|
+
"final",
|
|
2671
|
+
"finally",
|
|
2672
|
+
"float",
|
|
2673
|
+
"for",
|
|
2674
|
+
"goto",
|
|
2675
|
+
"if",
|
|
2676
|
+
"implements",
|
|
2677
|
+
"import",
|
|
2678
|
+
"instanceof",
|
|
2679
|
+
"int",
|
|
2680
|
+
"interface",
|
|
2681
|
+
"long",
|
|
2682
|
+
"native",
|
|
2683
|
+
"new",
|
|
2684
|
+
"package",
|
|
2685
|
+
"private",
|
|
2686
|
+
"protected",
|
|
2687
|
+
"public",
|
|
2688
|
+
"return",
|
|
2689
|
+
"short",
|
|
2690
|
+
"static",
|
|
2691
|
+
"strictfp",
|
|
2692
|
+
"super",
|
|
2693
|
+
"switch",
|
|
2694
|
+
"synchronized",
|
|
2695
|
+
"this",
|
|
2696
|
+
"throw",
|
|
2697
|
+
"throws",
|
|
2698
|
+
"transient",
|
|
2699
|
+
"try",
|
|
2700
|
+
"void",
|
|
2701
|
+
"volatile",
|
|
2702
|
+
"while",
|
|
2703
|
+
]),
|
|
2704
|
+
|
|
2705
|
+
golang: new Set([
|
|
2706
|
+
"break",
|
|
2707
|
+
"case",
|
|
2708
|
+
"chan",
|
|
2709
|
+
"const",
|
|
2710
|
+
"continue",
|
|
2711
|
+
"default",
|
|
2712
|
+
"defer",
|
|
2713
|
+
"else",
|
|
2714
|
+
"fallthrough",
|
|
2715
|
+
"for",
|
|
2716
|
+
"func",
|
|
2717
|
+
"go",
|
|
2718
|
+
"goto",
|
|
2719
|
+
"if",
|
|
2720
|
+
"import",
|
|
2721
|
+
"interface",
|
|
2722
|
+
"map",
|
|
2723
|
+
"package",
|
|
2724
|
+
"range",
|
|
2725
|
+
"return",
|
|
2726
|
+
"select",
|
|
2727
|
+
"struct",
|
|
2728
|
+
"switch",
|
|
2729
|
+
"type",
|
|
2730
|
+
"var",
|
|
2731
|
+
]),
|
|
2732
|
+
|
|
2733
|
+
c: new Set([
|
|
2734
|
+
"auto",
|
|
2735
|
+
"break",
|
|
2736
|
+
"case",
|
|
2737
|
+
"char",
|
|
2738
|
+
"const",
|
|
2739
|
+
"continue",
|
|
2740
|
+
"default",
|
|
2741
|
+
"do",
|
|
2742
|
+
"double",
|
|
2743
|
+
"else",
|
|
2744
|
+
"enum",
|
|
2745
|
+
"extern",
|
|
2746
|
+
"float",
|
|
2747
|
+
"for",
|
|
2748
|
+
"goto",
|
|
2749
|
+
"if",
|
|
2750
|
+
"int",
|
|
2751
|
+
"long",
|
|
2752
|
+
"register",
|
|
2753
|
+
"return",
|
|
2754
|
+
"short",
|
|
2755
|
+
"signed",
|
|
2756
|
+
"sizeof",
|
|
2757
|
+
"static",
|
|
2758
|
+
"struct",
|
|
2759
|
+
"switch",
|
|
2760
|
+
"typedef",
|
|
2761
|
+
"union",
|
|
2762
|
+
"unsigned",
|
|
2763
|
+
"void",
|
|
2764
|
+
"volatile",
|
|
2765
|
+
"while",
|
|
2766
|
+
]),
|
|
2767
|
+
|
|
2768
|
+
cpp: new Set([
|
|
2769
|
+
"alignas",
|
|
2770
|
+
"alignof",
|
|
2771
|
+
"and",
|
|
2772
|
+
"auto",
|
|
2773
|
+
"bool",
|
|
2774
|
+
"break",
|
|
2775
|
+
"case",
|
|
2776
|
+
"catch",
|
|
2777
|
+
"class",
|
|
2778
|
+
"const",
|
|
2779
|
+
"constexpr",
|
|
2780
|
+
"continue",
|
|
2781
|
+
"delete",
|
|
2782
|
+
"do",
|
|
2783
|
+
"double",
|
|
2784
|
+
"else",
|
|
2785
|
+
"enum",
|
|
2786
|
+
"explicit",
|
|
2787
|
+
"export",
|
|
2788
|
+
"extern",
|
|
2789
|
+
"false",
|
|
2790
|
+
"float",
|
|
2791
|
+
"for",
|
|
2792
|
+
"friend",
|
|
2793
|
+
"if",
|
|
2794
|
+
"inline",
|
|
2795
|
+
"int",
|
|
2796
|
+
"long",
|
|
2797
|
+
"mutable",
|
|
2798
|
+
"namespace",
|
|
2799
|
+
"new",
|
|
2800
|
+
"noexcept",
|
|
2801
|
+
"nullptr",
|
|
2802
|
+
"operator",
|
|
2803
|
+
"private",
|
|
2804
|
+
"protected",
|
|
2805
|
+
"public",
|
|
2806
|
+
"return",
|
|
2807
|
+
"short",
|
|
2808
|
+
"signed",
|
|
2809
|
+
"sizeof",
|
|
2810
|
+
"static",
|
|
2811
|
+
"struct",
|
|
2812
|
+
"switch",
|
|
2813
|
+
"template",
|
|
2814
|
+
"this",
|
|
2815
|
+
"throw",
|
|
2816
|
+
"true",
|
|
2817
|
+
"try",
|
|
2818
|
+
"typedef",
|
|
2819
|
+
"typename",
|
|
2820
|
+
"union",
|
|
2821
|
+
"unsigned",
|
|
2822
|
+
"using",
|
|
2823
|
+
"virtual",
|
|
2824
|
+
"void",
|
|
2825
|
+
"while",
|
|
2826
|
+
]),
|
|
2827
|
+
|
|
2828
|
+
php: new Set([
|
|
2829
|
+
"abstract",
|
|
2830
|
+
"and",
|
|
2831
|
+
"array",
|
|
2832
|
+
"as",
|
|
2833
|
+
"break",
|
|
2834
|
+
"callable",
|
|
2835
|
+
"case",
|
|
2836
|
+
"catch",
|
|
2837
|
+
"class",
|
|
2838
|
+
"clone",
|
|
2839
|
+
"const",
|
|
2840
|
+
"continue",
|
|
2841
|
+
"declare",
|
|
2842
|
+
"default",
|
|
2843
|
+
"do",
|
|
2844
|
+
"echo",
|
|
2845
|
+
"else",
|
|
2846
|
+
"elseif",
|
|
2847
|
+
"empty",
|
|
2848
|
+
"enddeclare",
|
|
2849
|
+
"endfor",
|
|
2850
|
+
"endforeach",
|
|
2851
|
+
"endif",
|
|
2852
|
+
"endswitch",
|
|
2853
|
+
"endwhile",
|
|
2854
|
+
"extends",
|
|
2855
|
+
"final",
|
|
2856
|
+
"finally",
|
|
2857
|
+
"fn",
|
|
2858
|
+
"for",
|
|
2859
|
+
"foreach",
|
|
2860
|
+
"function",
|
|
2861
|
+
"global",
|
|
2862
|
+
"goto",
|
|
2863
|
+
"if",
|
|
2864
|
+
"implements",
|
|
2865
|
+
"include",
|
|
2866
|
+
"include_once",
|
|
2867
|
+
"instanceof",
|
|
2868
|
+
"interface",
|
|
2869
|
+
"match",
|
|
2870
|
+
"namespace",
|
|
2871
|
+
"new",
|
|
2872
|
+
"null",
|
|
2873
|
+
"or",
|
|
2874
|
+
"private",
|
|
2875
|
+
"protected",
|
|
2876
|
+
"public",
|
|
2877
|
+
"require",
|
|
2878
|
+
"require_once",
|
|
2879
|
+
"return",
|
|
2880
|
+
"static",
|
|
2881
|
+
"switch",
|
|
2882
|
+
"throw",
|
|
2883
|
+
"trait",
|
|
2884
|
+
"try",
|
|
2885
|
+
"use",
|
|
2886
|
+
"var",
|
|
2887
|
+
"while",
|
|
2888
|
+
"yield",
|
|
2889
|
+
]),
|
|
2890
|
+
|
|
2891
|
+
rust: new Set([
|
|
2892
|
+
"as",
|
|
2893
|
+
"break",
|
|
2894
|
+
"const",
|
|
2895
|
+
"continue",
|
|
2896
|
+
"crate",
|
|
2897
|
+
"else",
|
|
2898
|
+
"enum",
|
|
2899
|
+
"extern",
|
|
2900
|
+
"false",
|
|
2901
|
+
"fn",
|
|
2902
|
+
"for",
|
|
2903
|
+
"if",
|
|
2904
|
+
"impl",
|
|
2905
|
+
"in",
|
|
2906
|
+
"let",
|
|
2907
|
+
"loop",
|
|
2908
|
+
"match",
|
|
2909
|
+
"mod",
|
|
2910
|
+
"move",
|
|
2911
|
+
"mut",
|
|
2912
|
+
"pub",
|
|
2913
|
+
"ref",
|
|
2914
|
+
"return",
|
|
2915
|
+
"self",
|
|
2916
|
+
"Self",
|
|
2917
|
+
"static",
|
|
2918
|
+
"struct",
|
|
2919
|
+
"super",
|
|
2920
|
+
"trait",
|
|
2921
|
+
"true",
|
|
2922
|
+
"type",
|
|
2923
|
+
"unsafe",
|
|
2924
|
+
"use",
|
|
2925
|
+
"where",
|
|
2926
|
+
"while",
|
|
2927
|
+
]),
|
|
2928
|
+
|
|
2929
|
+
html: new Set([
|
|
2930
|
+
"html",
|
|
2931
|
+
"head",
|
|
2932
|
+
"body",
|
|
2933
|
+
"div",
|
|
2934
|
+
"span",
|
|
2935
|
+
"p",
|
|
2936
|
+
"a",
|
|
2937
|
+
"img",
|
|
2938
|
+
"video",
|
|
2939
|
+
"audio",
|
|
2940
|
+
"script",
|
|
2941
|
+
"style",
|
|
2942
|
+
"link",
|
|
2943
|
+
"meta",
|
|
2944
|
+
"form",
|
|
2945
|
+
"input",
|
|
2946
|
+
"button",
|
|
2947
|
+
"table",
|
|
2948
|
+
"tr",
|
|
2949
|
+
"td",
|
|
2950
|
+
"th",
|
|
2951
|
+
"ul",
|
|
2952
|
+
"ol",
|
|
2953
|
+
"li",
|
|
2954
|
+
"section",
|
|
2955
|
+
"article",
|
|
2956
|
+
"header",
|
|
2957
|
+
"footer",
|
|
2958
|
+
"nav",
|
|
2959
|
+
"main",
|
|
2960
|
+
]),
|
|
2961
|
+
|
|
2962
|
+
bash: new Set([
|
|
2963
|
+
"if",
|
|
2964
|
+
"then",
|
|
2965
|
+
"else",
|
|
2966
|
+
"elif",
|
|
2967
|
+
"fi",
|
|
2968
|
+
"for",
|
|
2969
|
+
"while",
|
|
2970
|
+
"do",
|
|
2971
|
+
"done",
|
|
2972
|
+
"case",
|
|
2973
|
+
"esac",
|
|
2974
|
+
"function",
|
|
2975
|
+
"in",
|
|
2976
|
+
"select",
|
|
2977
|
+
"until",
|
|
2978
|
+
"break",
|
|
2979
|
+
"continue",
|
|
2980
|
+
"return",
|
|
2981
|
+
"export",
|
|
2982
|
+
"readonly",
|
|
2983
|
+
"local",
|
|
2984
|
+
"declare",
|
|
2985
|
+
]),
|
|
2986
|
+
|
|
2987
|
+
markdown: new Set(["#", "##", "###", "####", "#####", "######"]),
|
|
2988
|
+
};
|
|
2989
|
+
|
|
2990
|
+
if (!lang || lang === "txt" || lang === "text" || lang === "plaintext") {
|
|
2991
|
+
return {
|
|
2992
|
+
codeBlock: [
|
|
2993
|
+
{
|
|
2994
|
+
codeContent: code,
|
|
2995
|
+
highlightType: 0,
|
|
2996
|
+
},
|
|
2997
|
+
],
|
|
2998
|
+
unified_codeBlock: [
|
|
2999
|
+
{
|
|
3000
|
+
content: code,
|
|
3001
|
+
type: "DEFAULT",
|
|
3002
|
+
},
|
|
3003
|
+
],
|
|
3004
|
+
};
|
|
3005
|
+
}
|
|
3006
|
+
|
|
3007
|
+
const TYPE_MAP = {
|
|
3008
|
+
0: "DEFAULT",
|
|
3009
|
+
1: "KEYWORD",
|
|
3010
|
+
2: "METHOD",
|
|
3011
|
+
3: "STR",
|
|
3012
|
+
4: "NUMBER",
|
|
3013
|
+
5: "COMMENT",
|
|
3014
|
+
};
|
|
3015
|
+
|
|
3016
|
+
const keywords = keywordsMap[lang.toLowerCase()] || new Set();
|
|
3017
|
+
const tokens = [];
|
|
3018
|
+
|
|
3019
|
+
let i = 0;
|
|
3020
|
+
|
|
3021
|
+
const push = (content, type) => {
|
|
3022
|
+
if (!content) return;
|
|
3023
|
+
|
|
3024
|
+
const last = tokens[tokens.length - 1];
|
|
3025
|
+
|
|
3026
|
+
if (last && last.highlightType === type) {
|
|
3027
|
+
last.codeContent += content;
|
|
3028
|
+
} else {
|
|
3029
|
+
tokens.push({
|
|
3030
|
+
codeContent: content,
|
|
3031
|
+
highlightType: type,
|
|
3032
|
+
});
|
|
3033
|
+
}
|
|
3034
|
+
};
|
|
3035
|
+
|
|
3036
|
+
const isIdentifier = (char) => {
|
|
3037
|
+
switch (lang.toLowerCase()) {
|
|
3038
|
+
case "css":
|
|
3039
|
+
return /[a-zA-Z0-9_$-]/.test(char);
|
|
3040
|
+
|
|
3041
|
+
case "html":
|
|
3042
|
+
return /[a-zA-Z0-9_$:-]/.test(char);
|
|
3043
|
+
|
|
3044
|
+
default:
|
|
3045
|
+
return /[a-zA-Z0-9_$]/.test(char);
|
|
3046
|
+
}
|
|
3047
|
+
};
|
|
3048
|
+
|
|
3049
|
+
while (i < code.length) {
|
|
3050
|
+
const c = code[i];
|
|
3051
|
+
|
|
3052
|
+
if (/\s/.test(c)) {
|
|
3053
|
+
let s = i;
|
|
3054
|
+
|
|
3055
|
+
while (i < code.length && /\s/.test(code[i])) {
|
|
3056
|
+
i++;
|
|
3057
|
+
}
|
|
3058
|
+
|
|
3059
|
+
push(code.slice(s, i), 0);
|
|
3060
|
+
continue;
|
|
3061
|
+
}
|
|
3062
|
+
|
|
3063
|
+
if (
|
|
3064
|
+
(c === "/" && code[i + 1] === "/") ||
|
|
3065
|
+
(c === "#" && ["python", "bash"].includes(lang))
|
|
3066
|
+
) {
|
|
3067
|
+
let s = i;
|
|
3068
|
+
|
|
3069
|
+
while (i < code.length && code[i] !== "\n") {
|
|
3070
|
+
i++;
|
|
3071
|
+
}
|
|
3072
|
+
|
|
3073
|
+
push(code.slice(s, i), 5);
|
|
3074
|
+
continue;
|
|
3075
|
+
}
|
|
3076
|
+
|
|
3077
|
+
if (c === '"' || c === "'" || c === "`") {
|
|
3078
|
+
let s = i;
|
|
3079
|
+
const q = c;
|
|
3080
|
+
|
|
3081
|
+
i++;
|
|
3082
|
+
|
|
3083
|
+
while (i < code.length) {
|
|
3084
|
+
if (code[i] === "\\" && i + 1 < code.length) {
|
|
3085
|
+
i += 2;
|
|
3086
|
+
} else if (code[i] === q) {
|
|
3087
|
+
i++;
|
|
3088
|
+
break;
|
|
3089
|
+
} else {
|
|
3090
|
+
i++;
|
|
3091
|
+
}
|
|
3092
|
+
}
|
|
3093
|
+
|
|
3094
|
+
push(code.slice(s, i), 3);
|
|
3095
|
+
continue;
|
|
3096
|
+
}
|
|
3097
|
+
|
|
3098
|
+
if (/[0-9]/.test(c)) {
|
|
3099
|
+
let s = i;
|
|
3100
|
+
|
|
3101
|
+
while (i < code.length && /[0-9._]/.test(code[i])) {
|
|
3102
|
+
i++;
|
|
3103
|
+
}
|
|
3104
|
+
|
|
3105
|
+
push(code.slice(s, i), 4);
|
|
3106
|
+
continue;
|
|
3107
|
+
}
|
|
3108
|
+
|
|
3109
|
+
if (/[a-zA-Z_$]/.test(c)) {
|
|
3110
|
+
let s = i;
|
|
3111
|
+
|
|
3112
|
+
while (i < code.length && isIdentifier(code[i])) {
|
|
3113
|
+
i++;
|
|
3114
|
+
}
|
|
3115
|
+
|
|
3116
|
+
const word = code.slice(s, i);
|
|
3117
|
+
|
|
3118
|
+
let type = 0;
|
|
3119
|
+
|
|
3120
|
+
if (keywords.has(word)) {
|
|
3121
|
+
type = 1;
|
|
3122
|
+
} else if (lang === "css") {
|
|
3123
|
+
let j = i;
|
|
3124
|
+
|
|
3125
|
+
while (j < code.length && /\s/.test(code[j])) {
|
|
3126
|
+
j++;
|
|
3127
|
+
}
|
|
3128
|
+
|
|
3129
|
+
if (code[j] === ":") {
|
|
3130
|
+
type = 1;
|
|
3131
|
+
}
|
|
3132
|
+
} else if (lang === "html") {
|
|
3133
|
+
let p = s - 1;
|
|
3134
|
+
|
|
3135
|
+
while (p >= 0 && /\s/.test(code[p])) {
|
|
3136
|
+
p--;
|
|
3137
|
+
}
|
|
3138
|
+
|
|
3139
|
+
if (code[p] === "<" || (code[p] === "/" && code[p - 1] === "<")) {
|
|
3140
|
+
type = 1;
|
|
3141
|
+
}
|
|
3142
|
+
}
|
|
3143
|
+
|
|
3144
|
+
if (type === 0) {
|
|
3145
|
+
let j = i;
|
|
3146
|
+
|
|
3147
|
+
while (j < code.length && /\s/.test(code[j])) {
|
|
3148
|
+
j++;
|
|
3149
|
+
}
|
|
3150
|
+
|
|
3151
|
+
if (code[j] === "(") {
|
|
3152
|
+
type = 2;
|
|
3153
|
+
}
|
|
3154
|
+
}
|
|
3155
|
+
|
|
3156
|
+
push(word, type);
|
|
3157
|
+
continue;
|
|
3158
|
+
}
|
|
3159
|
+
|
|
3160
|
+
push(c, 0);
|
|
3161
|
+
i++;
|
|
3162
|
+
}
|
|
3163
|
+
|
|
3164
|
+
return {
|
|
3165
|
+
codeBlock: tokens,
|
|
3166
|
+
unified_codeBlock: tokens.map((t) => ({
|
|
3167
|
+
content: t.codeContent,
|
|
3168
|
+
type: TYPE_MAP[t.highlightType],
|
|
3169
|
+
})),
|
|
3170
|
+
};
|
|
3171
|
+
}
|
|
3172
|
+
|
|
3173
|
+
static toTableMetadata(
|
|
3174
|
+
arr,
|
|
3175
|
+
{ hyperlink = true, citation = true, latex = true } = {},
|
|
3176
|
+
) {
|
|
3177
|
+
if (
|
|
3178
|
+
!Array.isArray(arr) ||
|
|
3179
|
+
!arr.every(
|
|
3180
|
+
(row) =>
|
|
3181
|
+
Array.isArray(row) && row.every((cell) => typeof cell === "string"),
|
|
3182
|
+
)
|
|
3183
|
+
) {
|
|
3184
|
+
throw new TypeError("Table must be a nested array of strings");
|
|
3185
|
+
}
|
|
3186
|
+
|
|
3187
|
+
const [header, ...rows] = arr;
|
|
3188
|
+
|
|
3189
|
+
const maxLen = Math.max(header.length, ...rows.map((r) => r.length));
|
|
3190
|
+
|
|
3191
|
+
const normalize = (r) => [...r, ...Array(maxLen - r.length).fill("")];
|
|
3192
|
+
|
|
3193
|
+
const unified_rows = [
|
|
3194
|
+
{
|
|
3195
|
+
is_header: true,
|
|
3196
|
+
cells: normalize(header),
|
|
3197
|
+
},
|
|
3198
|
+
...rows.map((r) => ({
|
|
3199
|
+
is_header: false,
|
|
3200
|
+
cells: normalize(r),
|
|
3201
|
+
})),
|
|
3202
|
+
].map((row) => {
|
|
3203
|
+
const markdown_cells = row.cells.map((cell) => {
|
|
3204
|
+
const extracted = extractIE(cell, { hyperlink, citation, latex });
|
|
3205
|
+
|
|
3206
|
+
return {
|
|
3207
|
+
text: extracted.text,
|
|
3208
|
+
...(extracted.inline_entities.length
|
|
3209
|
+
? { inline_entities: extracted.inline_entities }
|
|
3210
|
+
: {}),
|
|
3211
|
+
};
|
|
3212
|
+
});
|
|
3213
|
+
|
|
3214
|
+
return {
|
|
3215
|
+
...row,
|
|
3216
|
+
...(markdown_cells.some((c) => c.inline_entities?.length)
|
|
3217
|
+
? { markdown_cells }
|
|
3218
|
+
: {}),
|
|
3219
|
+
};
|
|
3220
|
+
});
|
|
3221
|
+
|
|
3222
|
+
const rowsMeta = unified_rows.map((r) => ({
|
|
3223
|
+
items: r.cells,
|
|
3224
|
+
...(r.is_header ? { isHeading: true } : {}),
|
|
3225
|
+
}));
|
|
3226
|
+
|
|
3227
|
+
return {
|
|
3228
|
+
title: "",
|
|
3229
|
+
rows: rowsMeta,
|
|
3230
|
+
unified_rows,
|
|
3231
|
+
};
|
|
3232
|
+
}
|
|
3233
|
+
|
|
3234
|
+
static generateVerificationMetadata() {
|
|
3235
|
+
const signatureMaterial = Buffer.from(
|
|
3236
|
+
`\u004E\u0049\u0058\u0045\u004C\u002E\u004D\u0065\u0073\u0073\u0061\u0067\u0065\u0042\u0075\u0069\u006C\u0064\u0065\u0072\u0056${VERSION}\u002D\u0056\u0065\u0072\u0069\u0066\u0069\u0063\u0061\u0074\u0069\u006F\u006E\u0053\u0069\u0067\u006E\u0061\u0074\u0075\u0072\u0065\u002E\u004D\u0065\u0074\u0061\u0064\u0061\u0074\u0061`,
|
|
3237
|
+
);
|
|
3238
|
+
|
|
3239
|
+
const certificateMaterial = Buffer.from(
|
|
3240
|
+
`\u004E\u0049\u0058\u0045\u004C\u002E\u004D\u0065\u0073\u0073\u0061\u0067\u0065\u0042\u0075\u0069\u006C\u0064\u0065\u0072\u0056${VERSION}\u002D\u0043\u0065\u0072\u0074\u0069\u0066\u0069\u0063\u0061\u0074\u0065\u0043\u0068\u0061\u0069\u006E\u002E\u004D\u0065\u0074\u0061\u0064\u0061\u0074\u0061`,
|
|
3241
|
+
);
|
|
3242
|
+
|
|
3243
|
+
const signature = Buffer.concat([
|
|
3244
|
+
signatureMaterial,
|
|
3245
|
+
crypto.randomBytes(64 - signatureMaterial.length),
|
|
3246
|
+
]).toString("base64");
|
|
3247
|
+
|
|
3248
|
+
const certificateChain = [
|
|
3249
|
+
Buffer.concat([
|
|
3250
|
+
certificateMaterial,
|
|
3251
|
+
crypto.randomBytes(684 - certificateMaterial.length),
|
|
3252
|
+
]).toString("base64"),
|
|
3253
|
+
|
|
3254
|
+
Buffer.concat([
|
|
3255
|
+
certificateMaterial,
|
|
3256
|
+
crypto.randomBytes(892 - certificateMaterial.length),
|
|
3257
|
+
]).toString("base64"),
|
|
3258
|
+
];
|
|
3259
|
+
|
|
3260
|
+
return {
|
|
3261
|
+
proofs: [
|
|
3262
|
+
{
|
|
3263
|
+
version: 1,
|
|
3264
|
+
useCase: 1,
|
|
3265
|
+
signature,
|
|
3266
|
+
certificateChain,
|
|
3267
|
+
},
|
|
3268
|
+
],
|
|
3269
|
+
};
|
|
3270
|
+
}
|
|
3271
|
+
|
|
3272
|
+
static newLayout(name, data, extra = {}) {
|
|
3273
|
+
return {
|
|
3274
|
+
...extra,
|
|
3275
|
+
view_model: {
|
|
3276
|
+
[Array.isArray(data) ? "primitives" : "primitive"]: data,
|
|
3277
|
+
__typename: `GenAI${name}LayoutViewModel`,
|
|
3278
|
+
},
|
|
3279
|
+
};
|
|
3280
|
+
}
|
|
3281
|
+
|
|
3282
|
+
_makeNode(id, section, submessage) {
|
|
3283
|
+
return {
|
|
3284
|
+
id: id ?? null,
|
|
3285
|
+
section: section ?? null,
|
|
3286
|
+
submessage: submessage ?? null,
|
|
3287
|
+
};
|
|
3288
|
+
}
|
|
3289
|
+
|
|
3290
|
+
_registerId(node, id) {
|
|
3291
|
+
if (id === undefined || id === null || id === "") return;
|
|
3292
|
+
|
|
3293
|
+
if (typeof id !== "string") {
|
|
3294
|
+
throw new ContentValidationError("Item id must be a string", { id });
|
|
3295
|
+
}
|
|
3296
|
+
|
|
3297
|
+
if (this._idIndex.has(id)) {
|
|
3298
|
+
throw new DuplicateIdError(id);
|
|
3299
|
+
}
|
|
3300
|
+
|
|
3301
|
+
node.id = id;
|
|
3302
|
+
this._idIndex.set(id, node);
|
|
3303
|
+
}
|
|
3304
|
+
|
|
3305
|
+
_unregisterId(node) {
|
|
3306
|
+
if (node.id && this._idIndex.get(node.id) === node) {
|
|
3307
|
+
this._idIndex.delete(node.id);
|
|
3308
|
+
}
|
|
3309
|
+
}
|
|
3310
|
+
|
|
3311
|
+
hasId(id) {
|
|
3312
|
+
return typeof id === "string" && this._idIndex.has(id);
|
|
3313
|
+
}
|
|
3314
|
+
|
|
3315
|
+
getIds() {
|
|
3316
|
+
return [...this._idIndex.keys()];
|
|
3317
|
+
}
|
|
3318
|
+
|
|
3319
|
+
peek(id) {
|
|
3320
|
+
const node = this._idIndex.get(id);
|
|
3321
|
+
|
|
3322
|
+
if (!node) return null;
|
|
3323
|
+
|
|
3324
|
+
return {
|
|
3325
|
+
id: node.id,
|
|
3326
|
+
section: node.section,
|
|
3327
|
+
submessage: node.submessage,
|
|
3328
|
+
};
|
|
3329
|
+
}
|
|
3330
|
+
|
|
3331
|
+
assignId(index, id) {
|
|
3332
|
+
if (!Number.isInteger(index) || index < 0 || index >= this._nodes.length) {
|
|
3333
|
+
throw new InvalidTargetError(
|
|
3334
|
+
`Node index ${index} is out of range (0-${this._nodes.length - 1})`,
|
|
3335
|
+
{ index },
|
|
3336
|
+
);
|
|
3337
|
+
}
|
|
3338
|
+
|
|
3339
|
+
const node = this._nodes[index];
|
|
3340
|
+
|
|
3341
|
+
if (node.id) {
|
|
3342
|
+
throw new AIRichError(
|
|
3343
|
+
`Node at index ${index} already has id "${node.id}"`,
|
|
3344
|
+
"ALREADY_HAS_ID",
|
|
3345
|
+
{ index, id: node.id },
|
|
3346
|
+
);
|
|
3347
|
+
}
|
|
3348
|
+
|
|
3349
|
+
this._registerId(node, id);
|
|
3350
|
+
|
|
3351
|
+
return this;
|
|
3352
|
+
}
|
|
3353
|
+
|
|
3354
|
+
_getNode(id) {
|
|
3355
|
+
if (typeof id !== "string" || !id) {
|
|
3356
|
+
throw new ContentValidationError("Item id must be a non-empty string", {
|
|
3357
|
+
id,
|
|
3358
|
+
});
|
|
3359
|
+
}
|
|
3360
|
+
|
|
3361
|
+
const node = this._idIndex.get(id);
|
|
3362
|
+
|
|
3363
|
+
if (!node) {
|
|
3364
|
+
throw new ItemNotFoundError(id, this.getIds());
|
|
3365
|
+
}
|
|
3366
|
+
|
|
3367
|
+
return node;
|
|
3368
|
+
}
|
|
3369
|
+
|
|
3370
|
+
_resolveTarget(target) {
|
|
3371
|
+
if (Array.isArray(target)) {
|
|
3372
|
+
if (target.length < 1 || target.length > 2) {
|
|
3373
|
+
throw new ContentValidationError("Target must be id or [id, offset]", {
|
|
3374
|
+
target,
|
|
3375
|
+
});
|
|
3376
|
+
}
|
|
3377
|
+
|
|
3378
|
+
const [id, offset = 0] = target;
|
|
3379
|
+
|
|
3380
|
+
if (typeof id !== "string" || !id) {
|
|
3381
|
+
throw new ContentValidationError(
|
|
3382
|
+
"Target id must be a non-empty string",
|
|
3383
|
+
{ target },
|
|
3384
|
+
);
|
|
3385
|
+
}
|
|
3386
|
+
|
|
3387
|
+
if (!Number.isInteger(offset)) {
|
|
3388
|
+
throw new ContentValidationError("Offset must be an integer", {
|
|
3389
|
+
target,
|
|
3390
|
+
});
|
|
3391
|
+
}
|
|
3392
|
+
|
|
3393
|
+
return { id, offset };
|
|
3394
|
+
}
|
|
3395
|
+
|
|
3396
|
+
if (typeof target !== "string" || !target) {
|
|
3397
|
+
throw new ContentValidationError(
|
|
3398
|
+
"Target must be a non-empty id or [id, offset]",
|
|
3399
|
+
{ target },
|
|
3400
|
+
);
|
|
3401
|
+
}
|
|
3402
|
+
|
|
3403
|
+
return { id: target, offset: 0 };
|
|
3404
|
+
}
|
|
3405
|
+
|
|
3406
|
+
_resolveNodeIndex(target) {
|
|
3407
|
+
const { id, offset } = this._resolveTarget(target);
|
|
3408
|
+
const node = this._getNode(id);
|
|
3409
|
+
const baseIndex = this._nodes.indexOf(node);
|
|
3410
|
+
|
|
3411
|
+
if (baseIndex === -1) {
|
|
3412
|
+
throw new InvalidTargetError(
|
|
3413
|
+
`Item id "${id}" is registered but not present in the node list (internal desync)`,
|
|
3414
|
+
{ id },
|
|
3415
|
+
);
|
|
3416
|
+
}
|
|
3417
|
+
|
|
3418
|
+
const index = baseIndex + offset;
|
|
3419
|
+
|
|
3420
|
+
if (index < 0 || index >= this._nodes.length) {
|
|
3421
|
+
throw new InvalidTargetError(
|
|
3422
|
+
`Target "${id}" with offset ${offset} resolves to index ${index}, which is out of range (0-${this._nodes.length - 1})`,
|
|
3423
|
+
{ id, offset, index },
|
|
3424
|
+
);
|
|
3425
|
+
}
|
|
3426
|
+
|
|
3427
|
+
return { id, offset, baseIndex, index };
|
|
3428
|
+
}
|
|
3429
|
+
|
|
3430
|
+
_validateSections(section) {
|
|
3431
|
+
const items = Array.isArray(section) ? section : [section];
|
|
3432
|
+
|
|
3433
|
+
if (!items.length) {
|
|
3434
|
+
throw new ContentValidationError("At least one section is required");
|
|
3435
|
+
}
|
|
3436
|
+
|
|
3437
|
+
for (const item of items) {
|
|
3438
|
+
if (!item || typeof item !== "object" || Array.isArray(item)) {
|
|
3439
|
+
throw new ContentValidationError("Sections must be plain objects");
|
|
3440
|
+
}
|
|
3441
|
+
}
|
|
3442
|
+
|
|
3443
|
+
return items;
|
|
3444
|
+
}
|
|
3445
|
+
|
|
3446
|
+
_validateSubmessages(submessage) {
|
|
3447
|
+
if (submessage === undefined || submessage === null) {
|
|
3448
|
+
return [];
|
|
3449
|
+
}
|
|
3450
|
+
|
|
3451
|
+
const items = Array.isArray(submessage) ? submessage : [submessage];
|
|
3452
|
+
|
|
3453
|
+
for (const item of items) {
|
|
3454
|
+
if (!item || typeof item !== "object" || Array.isArray(item)) {
|
|
3455
|
+
throw new ContentValidationError("Submessages must be plain objects");
|
|
3456
|
+
}
|
|
3457
|
+
}
|
|
3458
|
+
|
|
3459
|
+
return items;
|
|
3460
|
+
}
|
|
3461
|
+
|
|
3462
|
+
_pairSubmessages(sections, submessages) {
|
|
3463
|
+
const n = sections.length;
|
|
3464
|
+
const m = submessages.length;
|
|
3465
|
+
|
|
3466
|
+
if (m === 0) return sections.map(() => null);
|
|
3467
|
+
if (m === 1)
|
|
3468
|
+
return sections.map((_, i) => (i === 0 ? submessages[0] : null));
|
|
3469
|
+
if (m === n) return submessages;
|
|
3470
|
+
|
|
3471
|
+
throw new ContentValidationError(
|
|
3472
|
+
`Cannot pair ${m} submessage(s) with ${n} section(s): expected 0, 1, or ${n}`,
|
|
3473
|
+
{ sectionCount: n, submessageCount: m },
|
|
3474
|
+
);
|
|
3475
|
+
}
|
|
3476
|
+
|
|
3477
|
+
_addContent(section, submessage, { id, replace, insertAt } = {}) {
|
|
3478
|
+
const hasReplace =
|
|
3479
|
+
replace !== undefined && replace !== null && replace !== "";
|
|
3480
|
+
|
|
3481
|
+
const hasInsertAt =
|
|
3482
|
+
insertAt !== undefined && insertAt !== null && insertAt !== "";
|
|
3483
|
+
|
|
3484
|
+
if (hasReplace && hasInsertAt) {
|
|
3485
|
+
throw new ContentValidationError(
|
|
3486
|
+
"replace and insertAt cannot be used together",
|
|
3487
|
+
);
|
|
3488
|
+
}
|
|
3489
|
+
|
|
3490
|
+
const sections = this._validateSections(section);
|
|
3491
|
+
const submessages = this._validateSubmessages(submessage);
|
|
3492
|
+
|
|
3493
|
+
if (!sections.length) {
|
|
3494
|
+
throw new ContentValidationError("At least one section is required");
|
|
3495
|
+
}
|
|
3496
|
+
|
|
3497
|
+
if (id !== undefined && id !== null && id !== "" && sections.length !== 1) {
|
|
3498
|
+
throw new ContentValidationError(
|
|
3499
|
+
"One id can only be assigned to one node",
|
|
3500
|
+
{
|
|
3501
|
+
id,
|
|
3502
|
+
sectionCount: sections.length,
|
|
3503
|
+
},
|
|
3504
|
+
);
|
|
3505
|
+
}
|
|
3506
|
+
|
|
3507
|
+
if (
|
|
3508
|
+
submessages.length &&
|
|
3509
|
+
submessages.length !== sections.length &&
|
|
3510
|
+
submessages.length !== 1
|
|
3511
|
+
) {
|
|
3512
|
+
throw new ContentValidationError(
|
|
3513
|
+
"Section and submessage count must match",
|
|
3514
|
+
);
|
|
3515
|
+
}
|
|
3516
|
+
|
|
3517
|
+
const pairedSubmessages = sections.map((_, index) => {
|
|
3518
|
+
if (!submessages.length) return undefined;
|
|
3519
|
+
|
|
3520
|
+
return submessages.length === 1 ? submessages[0] : submessages[index];
|
|
3521
|
+
});
|
|
3522
|
+
|
|
3523
|
+
if (
|
|
3524
|
+
id &&
|
|
3525
|
+
this._idIndex.has(id) &&
|
|
3526
|
+
!(hasReplace && this._resolveTarget(replace)?.id === id)
|
|
3527
|
+
) {
|
|
3528
|
+
throw new DuplicateIdError(id);
|
|
3529
|
+
}
|
|
3530
|
+
|
|
3531
|
+
const newNodes = sections.map((currentSection, index) => {
|
|
3532
|
+
return this._makeNode(
|
|
3533
|
+
index === 0 ? id : null,
|
|
3534
|
+
currentSection,
|
|
3535
|
+
pairedSubmessages[index],
|
|
3536
|
+
);
|
|
3537
|
+
});
|
|
3538
|
+
|
|
3539
|
+
if (hasReplace) {
|
|
3540
|
+
if (newNodes.length !== 1) {
|
|
3541
|
+
throw new ContentValidationError(
|
|
3542
|
+
"replace only supports adding exactly one node",
|
|
3543
|
+
);
|
|
3544
|
+
}
|
|
3545
|
+
|
|
3546
|
+
const target = this._resolveNodeIndex(replace);
|
|
3547
|
+
|
|
3548
|
+
if (!target) {
|
|
3549
|
+
throw new ContentValidationError("Target node could not be resolved");
|
|
3550
|
+
}
|
|
3551
|
+
|
|
3552
|
+
const oldNode = this._nodes[target.index];
|
|
3553
|
+
const newNode = newNodes[0];
|
|
3554
|
+
|
|
3555
|
+
if (!newNode.id && oldNode?.id) {
|
|
3556
|
+
newNode.id = oldNode.id;
|
|
3557
|
+
}
|
|
3558
|
+
|
|
3559
|
+
this._unregisterId(oldNode);
|
|
3560
|
+
|
|
3561
|
+
this._nodes.splice(target.index, 1, newNode);
|
|
3562
|
+
|
|
3563
|
+
if (newNode.id) {
|
|
3564
|
+
this._idIndex.set(newNode.id, newNode);
|
|
3565
|
+
}
|
|
3566
|
+
|
|
3567
|
+
return this;
|
|
3568
|
+
}
|
|
3569
|
+
|
|
3570
|
+
if (hasInsertAt) {
|
|
3571
|
+
const target = this._resolveNodeIndex(insertAt);
|
|
3572
|
+
|
|
3573
|
+
if (!target) {
|
|
3574
|
+
throw new ContentValidationError("Target node could not be resolved");
|
|
3575
|
+
}
|
|
3576
|
+
|
|
3577
|
+
const insertIndex = target.offset < 0 ? target.index : target.index + 1;
|
|
3578
|
+
|
|
3579
|
+
this._nodes.splice(insertIndex, 0, ...newNodes);
|
|
3580
|
+
|
|
3581
|
+
for (const node of newNodes) {
|
|
3582
|
+
if (node.id) {
|
|
3583
|
+
this._idIndex.set(node.id, node);
|
|
3584
|
+
}
|
|
3585
|
+
}
|
|
3586
|
+
|
|
3587
|
+
return this;
|
|
3588
|
+
}
|
|
3589
|
+
|
|
3590
|
+
this._nodes.push(...newNodes);
|
|
3591
|
+
|
|
3592
|
+
for (const node of newNodes) {
|
|
3593
|
+
if (node.id) {
|
|
3594
|
+
this._idIndex.set(node.id, node);
|
|
3595
|
+
}
|
|
3596
|
+
}
|
|
3597
|
+
|
|
3598
|
+
return this;
|
|
3599
|
+
}
|
|
3600
|
+
|
|
3601
|
+
addSection(section, options = {}) {
|
|
3602
|
+
return this._addContent(section, undefined, options);
|
|
3603
|
+
}
|
|
3604
|
+
|
|
3605
|
+
addSubmessage(submessage, options = {}) {
|
|
3606
|
+
const items = this._validateSubmessages(submessage);
|
|
3607
|
+
|
|
3608
|
+
if (!items.length) {
|
|
3609
|
+
throw new ContentValidationError("At least one submessage is required");
|
|
3610
|
+
}
|
|
3611
|
+
|
|
3612
|
+
return this._addContent(undefined, items, options);
|
|
3613
|
+
}
|
|
3614
|
+
|
|
3615
|
+
delete(target) {
|
|
3616
|
+
const { index } = this._resolveNodeIndex(target);
|
|
3617
|
+
const [oldNode] = this._nodes.splice(index, 1);
|
|
3618
|
+
|
|
3619
|
+
this._unregisterId(oldNode);
|
|
3620
|
+
|
|
3621
|
+
return this;
|
|
3622
|
+
}
|
|
3623
|
+
|
|
3624
|
+
get _sections() {
|
|
3625
|
+
return this._nodes.filter((n) => n.section !== null).map((n) => n.section);
|
|
3626
|
+
}
|
|
3627
|
+
|
|
3628
|
+
get _submessages() {
|
|
3629
|
+
return this._nodes
|
|
3630
|
+
.filter((n) => n.submessage !== null)
|
|
3631
|
+
.map((n) => n.submessage);
|
|
3632
|
+
}
|
|
3633
|
+
|
|
3634
|
+
get sections() {
|
|
3635
|
+
return this._sections;
|
|
3636
|
+
}
|
|
3637
|
+
|
|
3638
|
+
get items() {
|
|
3639
|
+
return this._sections.flatMap((section) => {
|
|
3640
|
+
const vm = section?.view_model;
|
|
3641
|
+
|
|
3642
|
+
if (Array.isArray(vm?.primitives)) {
|
|
3643
|
+
return vm.primitives;
|
|
3644
|
+
}
|
|
3645
|
+
|
|
3646
|
+
if (vm?.primitive) {
|
|
3647
|
+
return [vm.primitive];
|
|
3648
|
+
}
|
|
3649
|
+
|
|
3650
|
+
return [];
|
|
3651
|
+
});
|
|
3652
|
+
}
|
|
3653
|
+
}
|
|
3654
|
+
|
|
3655
|
+
function bind(client) {
|
|
3656
|
+
if (!client) {
|
|
3657
|
+
throw new Error("Socket is required");
|
|
3658
|
+
}
|
|
3659
|
+
let sock = Object.defineProperties(client, {
|
|
3660
|
+
sendLinkPreview: {
|
|
3661
|
+
configurable: true,
|
|
3662
|
+
writable: true,
|
|
3663
|
+
async value(
|
|
3664
|
+
jid,
|
|
3665
|
+
text,
|
|
3666
|
+
link,
|
|
3667
|
+
title,
|
|
3668
|
+
description,
|
|
3669
|
+
thumbnail,
|
|
3670
|
+
options = {},
|
|
3671
|
+
) {
|
|
3672
|
+
if (typeof jid !== "string") {
|
|
3673
|
+
throw new TypeError("jid is not string");
|
|
3674
|
+
}
|
|
3675
|
+
if (typeof text !== "string") {
|
|
3676
|
+
throw new TypeError("text is not string");
|
|
3677
|
+
}
|
|
3678
|
+
if (typeof link !== "string") {
|
|
3679
|
+
throw new TypeError("link is not string");
|
|
3680
|
+
}
|
|
3681
|
+
if (typeof title !== "string") {
|
|
3682
|
+
throw new TypeError("title is not string");
|
|
3683
|
+
}
|
|
3684
|
+
if (description && typeof description !== "string") {
|
|
3685
|
+
throw new TypeError("description is not string");
|
|
3686
|
+
}
|
|
3687
|
+
if (
|
|
3688
|
+
thumbnail &&
|
|
3689
|
+
!Buffer.isBuffer(thumbnail) &&
|
|
3690
|
+
typeof thumbnail.url !== "string"
|
|
3691
|
+
) {
|
|
3692
|
+
throw new TypeError(
|
|
3693
|
+
"thumbnail must be Buffer or object with url key",
|
|
3694
|
+
);
|
|
3695
|
+
}
|
|
3696
|
+
const image = thumbnail
|
|
3697
|
+
? await prepareWAMessageMedia(
|
|
3698
|
+
{
|
|
3699
|
+
image: thumbnail,
|
|
3700
|
+
},
|
|
3701
|
+
{
|
|
3702
|
+
upload: client.waUploadToServer,
|
|
3703
|
+
mediaTypeOverride: "thumbnail-link",
|
|
3704
|
+
},
|
|
3705
|
+
).then((v) => v.imageMessage)
|
|
3706
|
+
: undefined;
|
|
3707
|
+
text = text.includes(link) ? text : `${link}\n${text}`;
|
|
3708
|
+
return await client.sendMessage(
|
|
3709
|
+
jid,
|
|
3710
|
+
{
|
|
3711
|
+
text,
|
|
3712
|
+
linkPreview: {
|
|
3713
|
+
"matched-text": link,
|
|
3714
|
+
title,
|
|
3715
|
+
description,
|
|
3716
|
+
jpegThumbnail: image?.jpegThumbnail,
|
|
3717
|
+
highQualityThumbnail: image,
|
|
3718
|
+
},
|
|
3719
|
+
},
|
|
3720
|
+
options,
|
|
3721
|
+
);
|
|
3722
|
+
},
|
|
3723
|
+
},
|
|
3724
|
+
});
|
|
3725
|
+
return (client = sock);
|
|
3726
|
+
}
|
|
3727
|
+
|
|
3728
|
+
module.exports = { VERSION, Button, ButtonV2, Carousel, AIRich, Toolkit, bind };
|