@ryuu-reinzz/haruka-lib 3.7.1 → 4.0.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +496 -133
- package/main/index.js +20 -4
- package/main/socket.js +1707 -2
- package/package.json +2 -2
package/main/socket.js
CHANGED
|
@@ -1,7 +1,46 @@
|
|
|
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:
|
|
15
|
+
* - ~ Ahmad tumbuh kembang
|
|
16
|
+
* - RyuuReinzz (Added "messageBuilder" wrapper, "extendSocketsBotz", Owner of @ryuu-reinzz/baileys)
|
|
17
|
+
*
|
|
18
|
+
* WhatsApp: wa.me/6282139672290
|
|
19
|
+
* Channel: https://whatsapp.com/channel/0029VbCV1ck8fewpdNb2TY2k
|
|
20
|
+
*
|
|
21
|
+
* Owner WhatsApp: wa.me/6288246552068 RyuuReinzz
|
|
22
|
+
*
|
|
23
|
+
* Note:
|
|
24
|
+
* This project is being sold because it has been
|
|
25
|
+
* modified and has been added to
|
|
26
|
+
* many other things that make it more valuable.
|
|
27
|
+
*
|
|
28
|
+
* Copyright (c) 2026 Nixel
|
|
29
|
+
* Copyright (c) 2026 RyuuReinzz
|
|
30
|
+
*
|
|
31
|
+
* Permission is granted to use and modify this library
|
|
32
|
+
* for personal or commercial projects.
|
|
33
|
+
*
|
|
34
|
+
* Reuploading, reselling, relicensing, or redistributing
|
|
35
|
+
* this library as a standalone product is prohibited.
|
|
36
|
+
*
|
|
37
|
+
* Do not claim this project as your own original work.
|
|
38
|
+
*/
|
|
1
39
|
import crypto from "crypto";
|
|
2
40
|
import fetch from "node-fetch";
|
|
3
41
|
import fs from "fs";
|
|
4
42
|
import path from "path";
|
|
43
|
+
import sharp from "sharp";
|
|
5
44
|
import {
|
|
6
45
|
fileURLToPath
|
|
7
46
|
} from 'url';
|
|
@@ -16,7 +55,7 @@ const __dirname = dirname(__filename);
|
|
|
16
55
|
* @param {import('baileys').WASocket} socket
|
|
17
56
|
*/
|
|
18
57
|
|
|
19
|
-
|
|
58
|
+
function addProperty(socket, baileys) {
|
|
20
59
|
const {
|
|
21
60
|
proto,
|
|
22
61
|
generateWAMessageFromContent,
|
|
@@ -26,9 +65,1667 @@ export default function addProperty(socket, baileys) {
|
|
|
26
65
|
generateMessageID,
|
|
27
66
|
generateWAMessage
|
|
28
67
|
} = baileys;
|
|
68
|
+
let sendMessage = socket.sendMessage;
|
|
69
|
+
|
|
70
|
+
function extractIE(text, {
|
|
71
|
+
extract = true,
|
|
72
|
+
hyperlink = true,
|
|
73
|
+
citation = true,
|
|
74
|
+
latex = true
|
|
75
|
+
} = {}) {
|
|
76
|
+
if (!extract) {
|
|
77
|
+
return {
|
|
78
|
+
text,
|
|
79
|
+
ie: [],
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
let ie = [],
|
|
83
|
+
result = '',
|
|
84
|
+
last = 0,
|
|
85
|
+
citation_index = 1,
|
|
86
|
+
hyperlink_index = 0,
|
|
87
|
+
latex_index = 0,
|
|
88
|
+
stack = [];
|
|
89
|
+
for (let i = 0; i < text.length; i++) {
|
|
90
|
+
if (text[i] == '[' && text[i - 1] != '\\') {
|
|
91
|
+
stack.push(i);
|
|
92
|
+
} else if (text[i] == ']' && (text[i + 1] == '(' || text[i + 1] == '<')) {
|
|
93
|
+
let start = stack.pop();
|
|
94
|
+
if (start == null) continue;
|
|
95
|
+
let open = text[i + 1],
|
|
96
|
+
close = open == '(' ? ')' : '>',
|
|
97
|
+
type = open == '(' ? 'link' : 'latex',
|
|
98
|
+
end = i + 2,
|
|
99
|
+
depth = 1;
|
|
100
|
+
while (end < text.length && depth) {
|
|
101
|
+
if (text[end] == open && text[end - 1] != '\\') depth++;
|
|
102
|
+
else if (text[end] == close && text[end - 1] != '\\') depth--;
|
|
103
|
+
end++;
|
|
104
|
+
}
|
|
105
|
+
if (depth) continue;
|
|
106
|
+
let raw = text.slice(start + 1, i).trim(),
|
|
107
|
+
url = text.slice(i + 2, end - 1).trim(),
|
|
108
|
+
key,
|
|
109
|
+
tag,
|
|
110
|
+
data;
|
|
111
|
+
if (type == 'latex') {
|
|
112
|
+
if (!latex) continue;
|
|
113
|
+
let [txt = '', width = null, height = null, font_height = null, padding = null] = raw.split('|');
|
|
114
|
+
key = `\u004E\u0049\u0058\u0045\u004C_LATEX_${latex_index++}`;
|
|
115
|
+
tag = `{{${key}}}${txt || 'image'}{{/${key}}}`;
|
|
116
|
+
data = {
|
|
117
|
+
type: 'latex',
|
|
118
|
+
ie: {
|
|
119
|
+
key,
|
|
120
|
+
text: txt,
|
|
121
|
+
url,
|
|
122
|
+
width,
|
|
123
|
+
height,
|
|
124
|
+
font_height,
|
|
125
|
+
padding,
|
|
126
|
+
},
|
|
127
|
+
};
|
|
128
|
+
} else if (raw) {
|
|
129
|
+
if (!hyperlink) continue;
|
|
130
|
+
key = `\u004E\u0049\u0058\u0045\u004C_HYPERLINK_${hyperlink_index++}`;
|
|
131
|
+
tag = `{{${key}}}${url}{{/${key}}}`;
|
|
132
|
+
data = {
|
|
133
|
+
type: 'hyperlink',
|
|
134
|
+
ie: {
|
|
135
|
+
key,
|
|
136
|
+
text: raw,
|
|
137
|
+
url,
|
|
138
|
+
},
|
|
139
|
+
};
|
|
140
|
+
} else {
|
|
141
|
+
if (!citation) continue;
|
|
142
|
+
key = `\u004E\u0049\u0058\u0045\u004C_CITATION_${citation_index - 1}`;
|
|
143
|
+
tag = `{{${key}}}${url}{{/${key}}}`;
|
|
144
|
+
data = {
|
|
145
|
+
type: 'citation',
|
|
146
|
+
ie: {
|
|
147
|
+
reference_id: citation_index++,
|
|
148
|
+
key,
|
|
149
|
+
text: '',
|
|
150
|
+
url,
|
|
151
|
+
},
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
result += text.slice(last, start) + tag;
|
|
155
|
+
last = end;
|
|
156
|
+
ie.push(data);
|
|
157
|
+
i = end - 1;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
result += text.slice(last);
|
|
161
|
+
return {
|
|
162
|
+
text: result,
|
|
163
|
+
ie,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
class BaseBuilder {
|
|
168
|
+
constructor() {
|
|
169
|
+
this._title = '';
|
|
170
|
+
this._subtitle = '';
|
|
171
|
+
this._body = '';
|
|
172
|
+
this._footer = '';
|
|
173
|
+
this._contextInfo = {};
|
|
174
|
+
this._extraPayload = {};
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
setTitle(title) {
|
|
178
|
+
if (typeof title !== 'string') {
|
|
179
|
+
throw new TypeError('Title must be a string');
|
|
180
|
+
}
|
|
181
|
+
this._title = title;
|
|
182
|
+
return this;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
setSubtitle(subtitle) {
|
|
186
|
+
if (typeof subtitle !== 'string') {
|
|
187
|
+
throw new TypeError('Subtitle must be a string');
|
|
188
|
+
}
|
|
189
|
+
this._subtitle = subtitle;
|
|
190
|
+
return this;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
setBody(body) {
|
|
194
|
+
if (typeof body !== 'string') {
|
|
195
|
+
throw new TypeError('Body must be a string');
|
|
196
|
+
}
|
|
197
|
+
this._body = body;
|
|
198
|
+
return this;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
setFooter(footer) {
|
|
202
|
+
if (typeof footer !== 'string') {
|
|
203
|
+
throw new TypeError('Footer must be a string');
|
|
204
|
+
}
|
|
205
|
+
this._footer = footer;
|
|
206
|
+
return this;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
setContextInfo(obj) {
|
|
210
|
+
if (typeof obj !== 'object' || obj === null || Array.isArray(obj)) {
|
|
211
|
+
throw new TypeError('ContextInfo must be a plain object');
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
this._contextInfo = obj;
|
|
215
|
+
return this;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
addPayload(obj) {
|
|
219
|
+
if (typeof obj !== 'object' || obj === null || Array.isArray(obj)) {
|
|
220
|
+
throw new TypeError('Payload must be a plain object');
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
Object.assign(this._extraPayload, obj);
|
|
224
|
+
|
|
225
|
+
return this;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
static async resize(buffer, x, y, fit = 'cover') {
|
|
229
|
+
return await sharp(buffer)
|
|
230
|
+
.resize(x, y, {
|
|
231
|
+
fit,
|
|
232
|
+
position: 'center',
|
|
233
|
+
background: {
|
|
234
|
+
r: 0,
|
|
235
|
+
g: 0,
|
|
236
|
+
b: 0,
|
|
237
|
+
alpha: 0
|
|
238
|
+
},
|
|
239
|
+
})
|
|
240
|
+
.png()
|
|
241
|
+
.toBuffer();
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
static async fetchBuffer(url, options = {}, config = {}) {
|
|
245
|
+
try {
|
|
246
|
+
let response = await fetch(url, options);
|
|
247
|
+
if (!response.ok) throw Error(`HTTP ${response.status}`);
|
|
248
|
+
return Buffer.from(await response.arrayBuffer());
|
|
249
|
+
} catch (error) {
|
|
250
|
+
if (config.silent) return Buffer.alloc(0);
|
|
251
|
+
throw error;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
class Button extends BaseBuilder {
|
|
257
|
+
#client;
|
|
258
|
+
|
|
259
|
+
constructor(client) {
|
|
260
|
+
super();
|
|
261
|
+
if (!client) {
|
|
262
|
+
throw new Error('Socket is required');
|
|
263
|
+
}
|
|
264
|
+
this.#client = client;
|
|
265
|
+
|
|
266
|
+
this._buttons = [];
|
|
267
|
+
this._data;
|
|
268
|
+
this._currentSelectionIndex = -1;
|
|
269
|
+
this._currentSectionIndex = -1;
|
|
270
|
+
this._params = {};
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
setVideo(path, options = {}) {
|
|
274
|
+
if (!path) throw new Error('Url or buffer needed');
|
|
275
|
+
Buffer.isBuffer(path) ? (this._data = {
|
|
276
|
+
video: path,
|
|
277
|
+
...options
|
|
278
|
+
}) : (this._data = {
|
|
279
|
+
video: {
|
|
280
|
+
url: path
|
|
281
|
+
},
|
|
282
|
+
...options
|
|
283
|
+
});
|
|
284
|
+
return this;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
setImage(path, options = {}) {
|
|
288
|
+
if (!path) throw new Error('Url or buffer needed');
|
|
289
|
+
Buffer.isBuffer(path) ? (this._data = {
|
|
290
|
+
image: path,
|
|
291
|
+
...options
|
|
292
|
+
}) : (this._data = {
|
|
293
|
+
image: {
|
|
294
|
+
url: path
|
|
295
|
+
},
|
|
296
|
+
...options
|
|
297
|
+
});
|
|
298
|
+
return this;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
setDocument(path, options = {}) {
|
|
302
|
+
if (!path) throw new Error('Url or buffer needed');
|
|
303
|
+
Buffer.isBuffer(path) ? (this._data = {
|
|
304
|
+
document: path,
|
|
305
|
+
...options
|
|
306
|
+
}) : (this._data = {
|
|
307
|
+
document: {
|
|
308
|
+
url: path
|
|
309
|
+
},
|
|
310
|
+
...options
|
|
311
|
+
});
|
|
312
|
+
return this;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
setMedia(obj) {
|
|
316
|
+
if (typeof obj !== 'object' || obj === null || Array.isArray(obj)) {
|
|
317
|
+
throw new TypeError('Media must be a plain object');
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
this._data = obj;
|
|
321
|
+
return this;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
clearButtons() {
|
|
325
|
+
this._buttons = [];
|
|
326
|
+
return this;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
setParams(obj) {
|
|
330
|
+
this._params = obj;
|
|
331
|
+
return this;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
addButton(name, params) {
|
|
335
|
+
this._buttons.push({
|
|
336
|
+
name,
|
|
337
|
+
buttonParamsJson: typeof params === 'string' ? params : JSON.stringify(params),
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
return this;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
makeRow(header = '', title = '', description = '', id = '') {
|
|
344
|
+
if (this._currentSelectionIndex === -1 || this._currentSectionIndex === -1) {
|
|
345
|
+
throw new Error('You need to create a selection and a section first');
|
|
346
|
+
}
|
|
347
|
+
const buttonParams = JSON.parse(this._buttons[this._currentSelectionIndex].buttonParamsJson);
|
|
348
|
+
buttonParams.sections[this._currentSectionIndex].rows.push({
|
|
349
|
+
header,
|
|
350
|
+
title,
|
|
351
|
+
description,
|
|
352
|
+
id
|
|
353
|
+
});
|
|
354
|
+
this._buttons[this._currentSelectionIndex].buttonParamsJson = JSON.stringify(buttonParams);
|
|
355
|
+
return this;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
makeSection(title = '', highlight_label = '') {
|
|
359
|
+
if (this._currentSelectionIndex === -1) {
|
|
360
|
+
throw new Error('You need to create a selection first');
|
|
361
|
+
}
|
|
362
|
+
const buttonParams = JSON.parse(this._buttons[this._currentSelectionIndex].buttonParamsJson);
|
|
363
|
+
buttonParams.sections.push({
|
|
364
|
+
title,
|
|
365
|
+
highlight_label,
|
|
366
|
+
rows: []
|
|
367
|
+
});
|
|
368
|
+
this._currentSectionIndex = buttonParams.sections.length - 1;
|
|
369
|
+
this._buttons[this._currentSelectionIndex].buttonParamsJson = JSON.stringify(buttonParams);
|
|
370
|
+
return this;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
addSelection(title, options = {}) {
|
|
374
|
+
this._buttons.push({
|
|
375
|
+
...options,
|
|
376
|
+
name: 'single_select',
|
|
377
|
+
buttonParamsJson: JSON.stringify({
|
|
378
|
+
title,
|
|
379
|
+
sections: []
|
|
380
|
+
})
|
|
381
|
+
});
|
|
382
|
+
this._currentSelectionIndex = this._buttons.length - 1;
|
|
383
|
+
this._currentSectionIndex = -1;
|
|
384
|
+
return this;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
addReply(display_text = '', id = '', options = {}) {
|
|
388
|
+
this._buttons.push({
|
|
389
|
+
name: 'quick_reply',
|
|
390
|
+
buttonParamsJson: JSON.stringify({
|
|
391
|
+
display_text,
|
|
392
|
+
id,
|
|
393
|
+
...options,
|
|
394
|
+
}),
|
|
395
|
+
});
|
|
396
|
+
return this;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
addCall(display_text = '', id = '', options = {}) {
|
|
400
|
+
this._buttons.push({
|
|
401
|
+
name: 'cta_call',
|
|
402
|
+
buttonParamsJson: JSON.stringify({
|
|
403
|
+
display_text,
|
|
404
|
+
id,
|
|
405
|
+
...options,
|
|
406
|
+
}),
|
|
407
|
+
});
|
|
408
|
+
return this;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
addReminder(display_text = '', id = '', options = {}) {
|
|
412
|
+
this._buttons.push({
|
|
413
|
+
name: 'cta_reminder',
|
|
414
|
+
buttonParamsJson: JSON.stringify({
|
|
415
|
+
display_text,
|
|
416
|
+
id,
|
|
417
|
+
...options,
|
|
418
|
+
}),
|
|
419
|
+
});
|
|
420
|
+
return this;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
addCancelReminder(display_text = '', id = '', options = {}) {
|
|
424
|
+
this._buttons.push({
|
|
425
|
+
name: 'cta_cancel_reminder',
|
|
426
|
+
buttonParamsJson: JSON.stringify({
|
|
427
|
+
display_text,
|
|
428
|
+
id,
|
|
429
|
+
...options,
|
|
430
|
+
}),
|
|
431
|
+
});
|
|
432
|
+
return this;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
addAddress(display_text = '', id = '', options = {}) {
|
|
436
|
+
this._buttons.push({
|
|
437
|
+
name: 'address_message',
|
|
438
|
+
buttonParamsJson: JSON.stringify({
|
|
439
|
+
display_text,
|
|
440
|
+
id,
|
|
441
|
+
...options,
|
|
442
|
+
}),
|
|
443
|
+
});
|
|
444
|
+
return this;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
addLocation(options = {}) {
|
|
448
|
+
this._buttons.push({
|
|
449
|
+
name: 'send_location',
|
|
450
|
+
buttonParamsJson: JSON.stringify(options),
|
|
451
|
+
});
|
|
452
|
+
return this;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
addUrl(display_text = '', url = '', webview_interaction = false, options = {}) {
|
|
456
|
+
this._buttons.push({
|
|
457
|
+
...options,
|
|
458
|
+
name: 'cta_url',
|
|
459
|
+
buttonParamsJson: JSON.stringify({
|
|
460
|
+
display_text,
|
|
461
|
+
url,
|
|
462
|
+
webview_interaction,
|
|
463
|
+
...options,
|
|
464
|
+
}),
|
|
465
|
+
});
|
|
466
|
+
return this;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
addCopy(display_text = '', copy_code = '', options = {}) {
|
|
470
|
+
this._buttons.push({
|
|
471
|
+
name: 'cta_copy',
|
|
472
|
+
buttonParamsJson: JSON.stringify({
|
|
473
|
+
display_text,
|
|
474
|
+
copy_code,
|
|
475
|
+
...options,
|
|
476
|
+
}),
|
|
477
|
+
});
|
|
478
|
+
return this;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
static paramsList = {
|
|
482
|
+
limited_time_offer: {
|
|
483
|
+
text: 'string',
|
|
484
|
+
url: 'string',
|
|
485
|
+
copy_code: 'string',
|
|
486
|
+
expiration_time: 'number',
|
|
487
|
+
},
|
|
488
|
+
bottom_sheet: {
|
|
489
|
+
in_thread_buttons_limit: 'number',
|
|
490
|
+
divider_indices: ['number'],
|
|
491
|
+
list_title: 'string',
|
|
492
|
+
button_title: 'string',
|
|
493
|
+
},
|
|
494
|
+
tap_target_configuration: {
|
|
495
|
+
title: 'string',
|
|
496
|
+
description: 'string',
|
|
497
|
+
canonical_url: 'string',
|
|
498
|
+
domain: 'string',
|
|
499
|
+
buttonIndex: 'number',
|
|
500
|
+
},
|
|
501
|
+
};
|
|
502
|
+
|
|
503
|
+
async toCard() {
|
|
504
|
+
return {
|
|
505
|
+
body: {
|
|
506
|
+
text: this._body,
|
|
507
|
+
},
|
|
508
|
+
footer: {
|
|
509
|
+
text: this._footer,
|
|
510
|
+
},
|
|
511
|
+
header: {
|
|
512
|
+
title: this._title,
|
|
513
|
+
subtitle: this._subtitle,
|
|
514
|
+
hasMediaAttachment: !!this._data,
|
|
515
|
+
...(this._data ?
|
|
516
|
+
await prepareWAMessageMedia(this._data, {
|
|
517
|
+
upload: this.#client.waUploadToServer
|
|
518
|
+
}).catch((e) => {
|
|
519
|
+
if (String(e).includes('Invalid media type')) return this._data;
|
|
520
|
+
throw e;
|
|
521
|
+
}) : {}),
|
|
522
|
+
},
|
|
523
|
+
nativeFlowMessage: {
|
|
524
|
+
messageParamsJson: JSON.stringify(this._params),
|
|
525
|
+
buttons: this._buttons,
|
|
526
|
+
},
|
|
527
|
+
};
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
async build(jid, {
|
|
531
|
+
...options
|
|
532
|
+
} = {}) {
|
|
533
|
+
const message = await this.toCard();
|
|
534
|
+
|
|
535
|
+
return generateWAMessageFromContent(
|
|
536
|
+
jid, {
|
|
537
|
+
...this._extraPayload,
|
|
538
|
+
interactiveMessage: {
|
|
539
|
+
...message,
|
|
540
|
+
contextInfo: this._contextInfo,
|
|
541
|
+
},
|
|
542
|
+
}, {
|
|
543
|
+
...options
|
|
544
|
+
}
|
|
545
|
+
);
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
async send(jid, {
|
|
549
|
+
...options
|
|
550
|
+
} = {}) {
|
|
551
|
+
const msg = await this.build(jid, options);
|
|
552
|
+
|
|
553
|
+
await this.#client.relayMessage(msg.key.remoteJid, msg.message, {
|
|
554
|
+
messageId: msg.key.id,
|
|
555
|
+
additionalNodes: [{
|
|
556
|
+
tag: 'biz',
|
|
557
|
+
attrs: {},
|
|
558
|
+
content: [{
|
|
559
|
+
tag: 'interactive',
|
|
560
|
+
attrs: {
|
|
561
|
+
type: 'native_flow',
|
|
562
|
+
v: '1'
|
|
563
|
+
},
|
|
564
|
+
content: [{
|
|
565
|
+
tag: 'native_flow',
|
|
566
|
+
attrs: {
|
|
567
|
+
v: '9',
|
|
568
|
+
name: 'mixed'
|
|
569
|
+
}
|
|
570
|
+
}],
|
|
571
|
+
}, ],
|
|
572
|
+
}, ],
|
|
573
|
+
...options,
|
|
574
|
+
});
|
|
575
|
+
return msg;
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
class ButtonV2 extends BaseBuilder {
|
|
580
|
+
#client;
|
|
581
|
+
|
|
582
|
+
constructor(client) {
|
|
583
|
+
super();
|
|
584
|
+
if (!client) {
|
|
585
|
+
throw new Error('Socket is required');
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
this.#client = client;
|
|
589
|
+
this._image;
|
|
590
|
+
this._data;
|
|
591
|
+
this._buttons = [];
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
addButton(displayText = '', buttonId = crypto.randomUUID()) {
|
|
595
|
+
this._buttons.push({
|
|
596
|
+
buttonId,
|
|
597
|
+
buttonText: {
|
|
598
|
+
displayText
|
|
599
|
+
},
|
|
600
|
+
type: 1,
|
|
601
|
+
});
|
|
602
|
+
return this;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
addRawButton(obj) {
|
|
606
|
+
if (typeof obj !== 'object' || obj === null || Array.isArray(obj)) {
|
|
607
|
+
throw new TypeError('Buttons must be a plain object');
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
this._buttons.push(obj);
|
|
611
|
+
return this;
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
setThumbnail(path) {
|
|
615
|
+
if (!path) throw new Error('Url or buffer needed');
|
|
616
|
+
this._image = path;
|
|
617
|
+
return this;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
setMedia(obj) {
|
|
621
|
+
if (typeof obj !== 'object' || obj === null || Array.isArray(obj)) {
|
|
622
|
+
throw new TypeError('Media must be a plain object');
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
this._data = obj;
|
|
626
|
+
return this;
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
async build(jid, {
|
|
630
|
+
...options
|
|
631
|
+
} = {}) {
|
|
632
|
+
let _thumbnail = this._image ? await BaseBuilder.resize(Buffer.isBuffer(this._image) ? this._image : await BaseBuilder.fetchBuffer(this._image, {}, {
|
|
633
|
+
silent: true
|
|
634
|
+
}), 300, 300) : null;
|
|
635
|
+
const msg = generateWAMessageFromContent(
|
|
636
|
+
jid, {
|
|
637
|
+
...this._extraPayload,
|
|
638
|
+
buttonsMessage: {
|
|
639
|
+
contentText: this._body,
|
|
640
|
+
footerText: this._footer,
|
|
641
|
+
...(this._data ?
|
|
642
|
+
this._data : {
|
|
643
|
+
headerType: 6,
|
|
644
|
+
locationMessage: {
|
|
645
|
+
degreesLatitude: 0,
|
|
646
|
+
degreesLongitude: 0,
|
|
647
|
+
name: this._title,
|
|
648
|
+
address: this._subtitle,
|
|
649
|
+
jpegThumbnail: _thumbnail,
|
|
650
|
+
},
|
|
651
|
+
}),
|
|
652
|
+
viewOnce: true,
|
|
653
|
+
contextInfo: this._contextInfo,
|
|
654
|
+
buttons: [...this._buttons],
|
|
655
|
+
},
|
|
656
|
+
}, {
|
|
657
|
+
...options
|
|
658
|
+
}
|
|
659
|
+
);
|
|
660
|
+
return msg;
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
async send(jid, {
|
|
664
|
+
...options
|
|
665
|
+
} = {}) {
|
|
666
|
+
if (this._buttons.length < 1) throw new Error('ButtonV2 requires at least one button');
|
|
667
|
+
const msg = await this.build(jid, options);
|
|
668
|
+
|
|
669
|
+
await this.#client.relayMessage(msg.key.remoteJid, msg.message, {
|
|
670
|
+
messageId: msg.key.id,
|
|
671
|
+
additionalNodes: [{
|
|
672
|
+
tag: 'biz',
|
|
673
|
+
attrs: {},
|
|
674
|
+
content: [{
|
|
675
|
+
tag: 'interactive',
|
|
676
|
+
attrs: {
|
|
677
|
+
type: 'native_flow',
|
|
678
|
+
v: '1'
|
|
679
|
+
},
|
|
680
|
+
content: [{
|
|
681
|
+
tag: 'native_flow',
|
|
682
|
+
attrs: {
|
|
683
|
+
v: '9',
|
|
684
|
+
name: 'mixed'
|
|
685
|
+
}
|
|
686
|
+
}],
|
|
687
|
+
}, ],
|
|
688
|
+
}, ],
|
|
689
|
+
...options,
|
|
690
|
+
});
|
|
691
|
+
return msg;
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
class Carousel extends BaseBuilder {
|
|
696
|
+
#client;
|
|
697
|
+
|
|
698
|
+
constructor(client) {
|
|
699
|
+
super();
|
|
700
|
+
if (!client) {
|
|
701
|
+
throw new Error('Socket is required');
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
this.#client = client;
|
|
705
|
+
this._cards = [];
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
addCard(card) {
|
|
709
|
+
const cards = Array.isArray(card) ? card : [card];
|
|
710
|
+
const baseIndex = this._cards.length;
|
|
711
|
+
|
|
712
|
+
for (const [index, c] of cards.entries()) {
|
|
713
|
+
if (!c?.header?.hasMediaAttachment) {
|
|
714
|
+
throw new Error(`Card [${baseIndex + index}] must include an image or video in header`);
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
this._cards.push(...cards);
|
|
719
|
+
return this;
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
build(jid, {
|
|
723
|
+
...options
|
|
724
|
+
} = {}) {
|
|
725
|
+
return generateWAMessageFromContent(
|
|
726
|
+
jid, {
|
|
727
|
+
...this._extraPayload,
|
|
728
|
+
interactiveMessage: {
|
|
729
|
+
header: {
|
|
730
|
+
hasMediaAttachment: false,
|
|
731
|
+
},
|
|
732
|
+
body: {
|
|
733
|
+
text: this._body
|
|
734
|
+
},
|
|
735
|
+
footer: {
|
|
736
|
+
text: this._footer
|
|
737
|
+
},
|
|
738
|
+
contextInfo: this._contextInfo,
|
|
739
|
+
carouselMessage: {
|
|
740
|
+
cards: this._cards,
|
|
741
|
+
},
|
|
742
|
+
},
|
|
743
|
+
}, {
|
|
744
|
+
...options
|
|
745
|
+
}
|
|
746
|
+
);
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
async send(jid, {
|
|
750
|
+
...options
|
|
751
|
+
} = {}) {
|
|
752
|
+
const msg = this.build(jid, options);
|
|
753
|
+
|
|
754
|
+
await this.#client.relayMessage(msg.key.remoteJid, msg.message, {
|
|
755
|
+
messageId: msg.key.id,
|
|
756
|
+
additionalNodes: [{
|
|
757
|
+
tag: 'biz',
|
|
758
|
+
attrs: {},
|
|
759
|
+
content: [{
|
|
760
|
+
tag: 'interactive',
|
|
761
|
+
attrs: {
|
|
762
|
+
type: 'native_flow',
|
|
763
|
+
v: '1'
|
|
764
|
+
},
|
|
765
|
+
content: [{
|
|
766
|
+
tag: 'native_flow',
|
|
767
|
+
attrs: {
|
|
768
|
+
v: '9',
|
|
769
|
+
name: 'mixed'
|
|
770
|
+
}
|
|
771
|
+
}],
|
|
772
|
+
}, ],
|
|
773
|
+
}, ],
|
|
774
|
+
...options,
|
|
775
|
+
});
|
|
776
|
+
return msg;
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
class AIRich extends BaseBuilder {
|
|
781
|
+
#client;
|
|
782
|
+
|
|
783
|
+
constructor(client) {
|
|
784
|
+
if (!client) {
|
|
785
|
+
throw new Error('Socket is required');
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
super();
|
|
789
|
+
this.#client = client;
|
|
790
|
+
this._contextInfo = {};
|
|
791
|
+
this._submessages = [];
|
|
792
|
+
this._sections = [];
|
|
793
|
+
this._richResponseSources = [];
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
static newLayout(name, data) {
|
|
797
|
+
return {
|
|
798
|
+
view_model: {
|
|
799
|
+
[Array.isArray(data) ? 'primitives' : 'primitive']: data,
|
|
800
|
+
__typename: `GenAI${name}LayoutViewModel`,
|
|
801
|
+
},
|
|
802
|
+
};
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
addSubmessage(submessage) {
|
|
806
|
+
const items = Array.isArray(submessage) ? submessage : [submessage];
|
|
807
|
+
|
|
808
|
+
for (const item of items) {
|
|
809
|
+
if (typeof item !== 'object' || item === null || Array.isArray(item)) {
|
|
810
|
+
throw new TypeError('Submessage must be a plain object or array of plain objects');
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
this._submessages.push(item);
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
return this;
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
addSection(section) {
|
|
820
|
+
const items = Array.isArray(section) ? section : [section];
|
|
821
|
+
|
|
822
|
+
for (const item of items) {
|
|
823
|
+
if (typeof item !== 'object' || item === null || Array.isArray(item)) {
|
|
824
|
+
throw new TypeError('Section must be a plain object or array of plain objects');
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
this._sections.push(item);
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
return this;
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
addText(text, {
|
|
834
|
+
hyperlink = true,
|
|
835
|
+
citation = true,
|
|
836
|
+
latex = true
|
|
837
|
+
} = {}) {
|
|
838
|
+
if (typeof text != 'string') {
|
|
839
|
+
throw new TypeError('Text must be a string');
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
const extractedIE = extractIE(text, {
|
|
843
|
+
hyperlink,
|
|
844
|
+
citation,
|
|
845
|
+
latex,
|
|
846
|
+
});
|
|
847
|
+
|
|
848
|
+
const inline_entities = extractedIE.ie.map(({
|
|
849
|
+
type,
|
|
850
|
+
ie
|
|
851
|
+
}) => {
|
|
852
|
+
if (type == 'hyperlink') {
|
|
853
|
+
return {
|
|
854
|
+
key: ie.key,
|
|
855
|
+
metadata: {
|
|
856
|
+
display_name: ie.text,
|
|
857
|
+
is_trusted: true,
|
|
858
|
+
url: ie.url,
|
|
859
|
+
__typename: 'GenAIInlineLinkItem',
|
|
860
|
+
},
|
|
861
|
+
};
|
|
862
|
+
}
|
|
863
|
+
if (type == 'citation') {
|
|
864
|
+
return {
|
|
865
|
+
key: ie.key,
|
|
866
|
+
metadata: {
|
|
867
|
+
reference_id: ie.reference_id,
|
|
868
|
+
reference_url: ie.url,
|
|
869
|
+
reference_title: ie.url,
|
|
870
|
+
reference_display_name: ie.url,
|
|
871
|
+
sources: [],
|
|
872
|
+
__typename: 'GenAISearchCitationItem',
|
|
873
|
+
},
|
|
874
|
+
};
|
|
875
|
+
}
|
|
876
|
+
if (type == 'latex') {
|
|
877
|
+
return {
|
|
878
|
+
key: ie.key,
|
|
879
|
+
metadata: {
|
|
880
|
+
latex_expression: ie.text,
|
|
881
|
+
latex_image: {
|
|
882
|
+
url: ie.url,
|
|
883
|
+
width: Number(ie.width) || 100,
|
|
884
|
+
height: Number(ie.height) || 100,
|
|
885
|
+
},
|
|
886
|
+
font_height: Number(ie.font_height) || 83.333333333333,
|
|
887
|
+
padding: Number(ie.padding) || 15,
|
|
888
|
+
__typename: 'GenAILatexItem',
|
|
889
|
+
},
|
|
890
|
+
};
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
return {
|
|
894
|
+
key: ie.key,
|
|
895
|
+
metadata: {
|
|
896
|
+
latex_expression: ie.text,
|
|
897
|
+
latex_image: {
|
|
898
|
+
url: ie.url,
|
|
899
|
+
width,
|
|
900
|
+
height,
|
|
901
|
+
},
|
|
902
|
+
font_height: Number(ie.font_height) || 83.333333333333,
|
|
903
|
+
padding: Number(ie.padding) || 15,
|
|
904
|
+
__typename: 'GenAILatexItem',
|
|
905
|
+
},
|
|
906
|
+
};
|
|
907
|
+
});
|
|
29
908
|
|
|
909
|
+
this._submessages.push({
|
|
910
|
+
messageType: 2,
|
|
911
|
+
messageText: extractedIE.text,
|
|
912
|
+
});
|
|
913
|
+
|
|
914
|
+
this._sections.push(
|
|
915
|
+
AIRich.newLayout('Single', {
|
|
916
|
+
text: extractedIE.text,
|
|
917
|
+
...(inline_entities.length && {
|
|
918
|
+
inline_entities,
|
|
919
|
+
}),
|
|
920
|
+
__typename: 'GenAIMarkdownTextUXPrimitive',
|
|
921
|
+
})
|
|
922
|
+
);
|
|
923
|
+
|
|
924
|
+
return this;
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
addCode(language, code) {
|
|
928
|
+
if (typeof language !== 'string' || typeof code !== 'string') {
|
|
929
|
+
throw new TypeError('Language and code must be a string');
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
const meta = AIRich.tokenizer(code, language);
|
|
933
|
+
|
|
934
|
+
this._submessages.push({
|
|
935
|
+
messageType: 5,
|
|
936
|
+
codeMetadata: {
|
|
937
|
+
codeLanguage: language,
|
|
938
|
+
codeBlocks: meta.codeBlock,
|
|
939
|
+
},
|
|
940
|
+
});
|
|
941
|
+
|
|
942
|
+
this._sections.push(
|
|
943
|
+
AIRich.newLayout('Single', {
|
|
944
|
+
language,
|
|
945
|
+
code_blocks: meta.unified_codeBlock,
|
|
946
|
+
__typename: 'GenAICodeUXPrimitive',
|
|
947
|
+
})
|
|
948
|
+
);
|
|
949
|
+
|
|
950
|
+
return this;
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
addTable(table) {
|
|
954
|
+
if (!Array.isArray(table)) {
|
|
955
|
+
throw new TypeError('Table must be an array');
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
const meta = AIRich.toTableMetadata(table);
|
|
959
|
+
|
|
960
|
+
this._submessages.push({
|
|
961
|
+
messageType: 4,
|
|
962
|
+
tableMetadata: {
|
|
963
|
+
title: meta.title,
|
|
964
|
+
rows: meta.rows,
|
|
965
|
+
},
|
|
966
|
+
});
|
|
967
|
+
|
|
968
|
+
this._sections.push(
|
|
969
|
+
AIRich.newLayout('Single', {
|
|
970
|
+
rows: meta.unified_rows,
|
|
971
|
+
__typename: 'GenATableUXPrimitive',
|
|
972
|
+
})
|
|
973
|
+
);
|
|
974
|
+
|
|
975
|
+
return this;
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
|
|
979
|
+
addSource(sources = []) {
|
|
980
|
+
if (!(Array.isArray(sources) && (sources.every((item) => typeof item === 'string') || sources.every((item) => Array.isArray(item) && item.every((v) => typeof v === 'string'))))) {
|
|
981
|
+
throw new TypeError('Sources must be a string array or an array of string arrays');
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
if (sources.every((item) => typeof item === 'string')) {
|
|
985
|
+
sources = [sources];
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
const source = sources.map(([profile_url, url, text]) => ({
|
|
989
|
+
source_type: 'THIRD_PARTY',
|
|
990
|
+
source_display_name: text ?? '',
|
|
991
|
+
source_subtitle: 'AI',
|
|
992
|
+
source_url: url ?? '',
|
|
993
|
+
favicon: {
|
|
994
|
+
url: profile_url ?? '',
|
|
995
|
+
mime_type: 'image/jpeg',
|
|
996
|
+
width: 16,
|
|
997
|
+
height: 16,
|
|
998
|
+
},
|
|
999
|
+
}));
|
|
1000
|
+
|
|
1001
|
+
this._sections.push(
|
|
1002
|
+
AIRich.newLayout('Single', {
|
|
1003
|
+
sources: source,
|
|
1004
|
+
__typename: 'GenAISearchResultPrimitive',
|
|
1005
|
+
})
|
|
1006
|
+
);
|
|
1007
|
+
|
|
1008
|
+
return this;
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
addReels(reelsItems = []) {
|
|
1012
|
+
if (
|
|
1013
|
+
!(
|
|
1014
|
+
(reelsItems && typeof reelsItems === 'object' && !Array.isArray(reelsItems)) ||
|
|
1015
|
+
(Array.isArray(reelsItems) && reelsItems.every((item) => item && typeof item === 'object' && !Array.isArray(item)))
|
|
1016
|
+
)
|
|
1017
|
+
) {
|
|
1018
|
+
throw new TypeError('Reels items must be an object or an array of objects');
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
if (!Array.isArray(reelsItems)) {
|
|
1022
|
+
reelsItems = [reelsItems];
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
this._submessages.push({
|
|
1026
|
+
messageType: 9,
|
|
1027
|
+
contentItemsMetadata: {
|
|
1028
|
+
contentType: 1,
|
|
1029
|
+
itemsMetadata: reelsItems.map((item) => ({
|
|
1030
|
+
reelItem: {
|
|
1031
|
+
title: item.username ?? '',
|
|
1032
|
+
profileIconUrl: item.profileIconUrl ?? item.profile_url ?? '',
|
|
1033
|
+
thumbnailUrl: item.thumbnailUrl ?? item.thumbnail ?? '',
|
|
1034
|
+
videoUrl: item.videoUrl ?? item.url ?? '',
|
|
1035
|
+
},
|
|
1036
|
+
})),
|
|
1037
|
+
},
|
|
1038
|
+
});
|
|
1039
|
+
|
|
1040
|
+
reelsItems.forEach((item, idx) => {
|
|
1041
|
+
this._richResponseSources.push({
|
|
1042
|
+
provider: '\u004E\u0049\u0058\u0045\u004C',
|
|
1043
|
+
thumbnailCDNURL: item.thumbnailUrl ?? item.thumbnail ?? '',
|
|
1044
|
+
sourceProviderURL: item.videoUrl ?? item.url ?? '',
|
|
1045
|
+
sourceQuery: '',
|
|
1046
|
+
faviconCDNURL: item.profileIconUrl ?? item.profile_url ?? '',
|
|
1047
|
+
citationNumber: idx + 1,
|
|
1048
|
+
sourceTitle: item.username ?? '',
|
|
1049
|
+
});
|
|
1050
|
+
});
|
|
1051
|
+
|
|
1052
|
+
this._sections.push(
|
|
1053
|
+
AIRich.newLayout(
|
|
1054
|
+
'HScroll',
|
|
1055
|
+
reelsItems.map((item) => ({
|
|
1056
|
+
reels_url: item.videoUrl ?? item.url ?? '',
|
|
1057
|
+
thumbnail_url: item.thumbnailUrl ?? item.thumbnail ?? '',
|
|
1058
|
+
creator: item.username ?? item.title ?? '',
|
|
1059
|
+
avatar_url: item.profileIconUrl ?? item.profile_url ?? '',
|
|
1060
|
+
reels_title: item.reels_title ?? item.title ?? '',
|
|
1061
|
+
likes_count: item.likes_count ?? item.like ?? 0,
|
|
1062
|
+
shares_count: item.shares_count ?? item.share ?? 0,
|
|
1063
|
+
view_count: item.view_count ?? item.view ?? 0,
|
|
1064
|
+
reel_source: item.reel_source ?? item.source ?? 'IG',
|
|
1065
|
+
is_verified: !!(item.is_verified || item.verified),
|
|
1066
|
+
__typename: 'GenAIReelPrimitive',
|
|
1067
|
+
}))
|
|
1068
|
+
)
|
|
1069
|
+
);
|
|
1070
|
+
|
|
1071
|
+
return this;
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
addImage(imageUrl) {
|
|
1075
|
+
if (!(typeof imageUrl === 'string' || (Array.isArray(imageUrl) && imageUrl.every((v) => typeof v === 'string')))) {
|
|
1076
|
+
throw new TypeError('imageUrl must be a string or array of strings');
|
|
1077
|
+
}
|
|
1078
|
+
const imageUrls = Array.isArray(imageUrl) ?
|
|
1079
|
+
imageUrl.map((url) => ({
|
|
1080
|
+
imagePreviewUrl: url,
|
|
1081
|
+
imageHighResUrl: url,
|
|
1082
|
+
sourceUrl: String.fromCharCode(104, 116, 116, 112, 115, 58, 47, 47, 102, 105, 111, 114, 97, 46, 110, 105, 120, 101, 108, 46, 109, 121, 46, 105, 100, 47),
|
|
1083
|
+
})) : [{
|
|
1084
|
+
imagePreviewUrl: imageUrl,
|
|
1085
|
+
imageHighResUrl: imageUrl,
|
|
1086
|
+
sourceUrl: String.fromCharCode(104, 116, 116, 112, 115, 58, 47, 47, 102, 105, 111, 114, 97, 46, 110, 105, 120, 101, 108, 46, 109, 121, 46, 105, 100, 47),
|
|
1087
|
+
}, ];
|
|
1088
|
+
|
|
1089
|
+
this._submessages.push({
|
|
1090
|
+
messageType: 1,
|
|
1091
|
+
gridImageMetadata: {
|
|
1092
|
+
gridImageUrl: {
|
|
1093
|
+
imagePreviewUrl: Array.isArray(imageUrl) ? imageUrl[0] : imageUrl,
|
|
1094
|
+
},
|
|
1095
|
+
imageUrls,
|
|
1096
|
+
},
|
|
1097
|
+
});
|
|
1098
|
+
|
|
1099
|
+
imageUrls.forEach(({
|
|
1100
|
+
imagePreviewUrl
|
|
1101
|
+
}) => {
|
|
1102
|
+
this._sections.push(
|
|
1103
|
+
AIRich.newLayout('Single', {
|
|
1104
|
+
media: {
|
|
1105
|
+
url: imagePreviewUrl,
|
|
1106
|
+
mime_type: 'image/png',
|
|
1107
|
+
},
|
|
1108
|
+
imagine_type: 'IMAGE',
|
|
1109
|
+
status: {
|
|
1110
|
+
status: 'READY',
|
|
1111
|
+
},
|
|
1112
|
+
__typename: 'GenAIImaginePrimitive',
|
|
1113
|
+
})
|
|
1114
|
+
);
|
|
1115
|
+
});
|
|
1116
|
+
|
|
1117
|
+
return this;
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
addVideo(videoUrl) {
|
|
1121
|
+
if (!(typeof videoUrl === 'string' || (Array.isArray(videoUrl) && videoUrl.every((v) => typeof v === 'string')))) {
|
|
1122
|
+
throw new TypeError('videoUrl must be a string or array of strings');
|
|
1123
|
+
}
|
|
1124
|
+
|
|
1125
|
+
const videoUrls = (Array.isArray(videoUrl) ? videoUrl : [videoUrl]).map((item) => {
|
|
1126
|
+
const [url, duration = 0] = item.split('|');
|
|
1127
|
+
|
|
1128
|
+
return {
|
|
1129
|
+
videoPreviewUrl: url,
|
|
1130
|
+
videoHighResUrl: url,
|
|
1131
|
+
duration: Number(duration) || 0,
|
|
1132
|
+
sourceUrl: String.fromCharCode(104, 116, 116, 112, 115, 58, 47, 47, 102, 105, 111, 114, 97, 46, 110, 105, 120, 101, 108, 46, 109, 121, 46, 105, 100, 47),
|
|
1133
|
+
};
|
|
1134
|
+
});
|
|
1135
|
+
|
|
1136
|
+
this._submessages.push({
|
|
1137
|
+
messageType: 2,
|
|
1138
|
+
messageText: '[ CANNOT_LOAD_VIDEO - \u0052\u0059\u0055\u0055 ]',
|
|
1139
|
+
});
|
|
1140
|
+
|
|
1141
|
+
videoUrls.forEach(({
|
|
1142
|
+
videoPreviewUrl,
|
|
1143
|
+
duration = 0
|
|
1144
|
+
}) => {
|
|
1145
|
+
this._sections.push(
|
|
1146
|
+
AIRich.newLayout('Single', {
|
|
1147
|
+
media: {
|
|
1148
|
+
url: videoPreviewUrl,
|
|
1149
|
+
mime_type: 'video/mp4',
|
|
1150
|
+
duration,
|
|
1151
|
+
},
|
|
1152
|
+
imagine_type: 'ANIMATE',
|
|
1153
|
+
status: {
|
|
1154
|
+
status: 'READY',
|
|
1155
|
+
},
|
|
1156
|
+
__typename: 'GenAIImaginePrimitive',
|
|
1157
|
+
})
|
|
1158
|
+
);
|
|
1159
|
+
});
|
|
1160
|
+
|
|
1161
|
+
return this;
|
|
1162
|
+
}
|
|
1163
|
+
|
|
1164
|
+
addProduct(data = {}) {
|
|
1165
|
+
if (!((data && typeof data === 'object' && !Array.isArray(data)) || (Array.isArray(data) && data.every((item) => item && typeof item === 'object' && !Array.isArray(item))))) {
|
|
1166
|
+
throw new TypeError('Product items must be an object or an array of objects');
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
this._submessages.push({
|
|
1170
|
+
messageType: 2,
|
|
1171
|
+
messageText: '[ CANNOT_LOAD_PRODUCT - \u0052\u0059\u0055\u0055 ]',
|
|
1172
|
+
});
|
|
1173
|
+
|
|
1174
|
+
const items = Array.isArray(data) ? data : [data];
|
|
1175
|
+
|
|
1176
|
+
const product = items.map((item) => ({
|
|
1177
|
+
title: item.title,
|
|
1178
|
+
brand: item.brand,
|
|
1179
|
+
price: item.price,
|
|
1180
|
+
sale_price: item.sale_price,
|
|
1181
|
+
product_url: item.product_url ?? item.url,
|
|
1182
|
+
image: {
|
|
1183
|
+
url: item.image_url ?? item.image,
|
|
1184
|
+
},
|
|
1185
|
+
additional_images: [{
|
|
1186
|
+
url: item.icon_url ?? item.icon,
|
|
1187
|
+
}, ],
|
|
1188
|
+
__typename: 'GenAIProductItemCardPrimitive',
|
|
1189
|
+
}));
|
|
1190
|
+
|
|
1191
|
+
this._sections.push(AIRich.newLayout(Array.isArray(data) ? 'HScroll' : 'Single', Array.isArray(data) ? product : product[0]));
|
|
1192
|
+
|
|
1193
|
+
return this;
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
addPost(data = {}) {
|
|
1197
|
+
if (!((data && typeof data === 'object' && !Array.isArray(data)) || (Array.isArray(data) && data.every((item) => item && typeof item === 'object' && !Array.isArray(item))))) {
|
|
1198
|
+
throw new TypeError('Post items must be an object or an array of objects');
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1201
|
+
const posts = Array.isArray(data) ? data : [data];
|
|
1202
|
+
|
|
1203
|
+
this._submessages.push({
|
|
1204
|
+
messageType: 2,
|
|
1205
|
+
messageText: '[ CANNOT_LOAD_POST - \u0052\u0059\u0055\u0055 ]',
|
|
1206
|
+
});
|
|
1207
|
+
|
|
1208
|
+
const primitives = posts.map((p) => ({
|
|
1209
|
+
title: p.title ?? '',
|
|
1210
|
+
subtitle: p.subtitle ?? '',
|
|
1211
|
+
username: p.username ?? '',
|
|
1212
|
+
profile_picture_url: p.profile_picture_url ?? p.profile_url ?? '',
|
|
1213
|
+
is_verified: !!(p.is_verified || p.verified),
|
|
1214
|
+
thumbnail_url: p.thumbnail_url ?? p.thumbnail ?? '',
|
|
1215
|
+
post_caption: p.post_caption ?? p.caption ?? '',
|
|
1216
|
+
likes_count: p.likes_count ?? p.like ?? 0,
|
|
1217
|
+
comments_count: p.comments_count ?? p.comment ?? 0,
|
|
1218
|
+
shares_count: p.shares_count ?? p.share ?? 0,
|
|
1219
|
+
post_url: p.post_url ?? p.url ?? '',
|
|
1220
|
+
post_deeplink: p.post_deeplink ?? p.deeplink ?? '',
|
|
1221
|
+
source_app: p.source_app || p.source || 'INSTAGRAM',
|
|
1222
|
+
footer_label: p.footer_label ?? p.footer ?? '',
|
|
1223
|
+
footer_icon: p.footer_icon ?? p.icon ?? '',
|
|
1224
|
+
is_carousel: posts.length > 1,
|
|
1225
|
+
orientation: p.orientation ?? 'LANDSCAPE',
|
|
1226
|
+
post_type: p.post_type ?? 'VIDEO',
|
|
1227
|
+
__typename: 'GenAIPostPrimitive',
|
|
1228
|
+
}));
|
|
1229
|
+
|
|
1230
|
+
this._sections.push(AIRich.newLayout('HScroll', primitives));
|
|
1231
|
+
|
|
1232
|
+
return this;
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1235
|
+
addTip(text) {
|
|
1236
|
+
this._submessages.push({
|
|
1237
|
+
messageType: 2,
|
|
1238
|
+
messageText: text,
|
|
1239
|
+
});
|
|
1240
|
+
|
|
1241
|
+
this._sections.push(
|
|
1242
|
+
AIRich.newLayout('Single', {
|
|
1243
|
+
text,
|
|
1244
|
+
__typename: 'GenAIMetadataTextPrimitive',
|
|
1245
|
+
})
|
|
1246
|
+
);
|
|
1247
|
+
|
|
1248
|
+
return this;
|
|
1249
|
+
}
|
|
1250
|
+
|
|
1251
|
+
addSuggest(suggestion) {
|
|
1252
|
+
if (!(typeof suggestion === 'string' || (Array.isArray(suggestion) && suggestion.every((v) => typeof v === 'string')))) {
|
|
1253
|
+
throw new TypeError('Suggestion must be a string or array of strings');
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1256
|
+
const suggest = Array.isArray(suggestion) ?
|
|
1257
|
+
suggestion.map((text) => ({
|
|
1258
|
+
prompt_text: text,
|
|
1259
|
+
prompt_type: 'SUGGESTED_PROMPT',
|
|
1260
|
+
__typename: 'GenAIFollowUpSuggestionPillPrimitive',
|
|
1261
|
+
})) : [{
|
|
1262
|
+
prompt_text: suggestion,
|
|
1263
|
+
prompt_type: 'SUGGESTED_PROMPT',
|
|
1264
|
+
__typename: 'GenAIFollowUpSuggestionPillPrimitive',
|
|
1265
|
+
}, ];
|
|
1266
|
+
|
|
1267
|
+
this._sections.push(AIRich.newLayout('ActionRow', suggest));
|
|
1268
|
+
|
|
1269
|
+
return this;
|
|
1270
|
+
}
|
|
1271
|
+
|
|
1272
|
+
build({
|
|
1273
|
+
forwarded = true,
|
|
1274
|
+
includesUnifiedResponse = true,
|
|
1275
|
+
includesSubmessages = true,
|
|
1276
|
+
quoted,
|
|
1277
|
+
quotedParticipant,
|
|
1278
|
+
...options
|
|
1279
|
+
} = {}) {
|
|
1280
|
+
const forward = forwarded ? {
|
|
1281
|
+
forwardingScore: 1,
|
|
1282
|
+
isForwarded: true,
|
|
1283
|
+
forwardedAiBotMessageInfo: {
|
|
1284
|
+
botJid: '0@bot'
|
|
1285
|
+
},
|
|
1286
|
+
forwardOrigin: 4,
|
|
1287
|
+
} : {};
|
|
1288
|
+
|
|
1289
|
+
const qObj = quoted ? {
|
|
1290
|
+
stanzaId: quoted?.key?.id || quoted?.id,
|
|
1291
|
+
participant: quotedParticipant || quoted?.key?.participant || quoted?.key?.remoteJid,
|
|
1292
|
+
quotedType: 0,
|
|
1293
|
+
quotedMessage: typeof quoted === 'object' && quoted !== null ? (quoted.message ?? quoted) : undefined,
|
|
1294
|
+
} : {};
|
|
1295
|
+
|
|
1296
|
+
const sections = this._footer ? [
|
|
1297
|
+
...this._sections,
|
|
1298
|
+
AIRich.newLayout('Single', {
|
|
1299
|
+
text: this._footer,
|
|
1300
|
+
__typename: 'GenAIMetadataTextPrimitive',
|
|
1301
|
+
}),
|
|
1302
|
+
] : [...this._sections];
|
|
1303
|
+
|
|
1304
|
+
return {
|
|
1305
|
+
messageContextInfo: {
|
|
1306
|
+
deviceListMetadata: {},
|
|
1307
|
+
deviceListMetadataVersion: 2,
|
|
1308
|
+
botMetadata: {
|
|
1309
|
+
messageDisclaimerText: this._title,
|
|
1310
|
+
richResponseSourcesMetadata: {
|
|
1311
|
+
sources: this._richResponseSources
|
|
1312
|
+
},
|
|
1313
|
+
},
|
|
1314
|
+
},
|
|
1315
|
+
...this._extraPayload,
|
|
1316
|
+
botForwardedMessage: {
|
|
1317
|
+
message: {
|
|
1318
|
+
richResponseMessage: {
|
|
1319
|
+
messageType: 1,
|
|
1320
|
+
submessages: includesSubmessages ? this._submessages : [],
|
|
1321
|
+
unifiedResponse: {
|
|
1322
|
+
data: includesUnifiedResponse ? Buffer.from(JSON.stringify({
|
|
1323
|
+
response_id: crypto.randomUUID(),
|
|
1324
|
+
sections
|
|
1325
|
+
})).toString("base64") : ''
|
|
1326
|
+
},
|
|
1327
|
+
contextInfo: {
|
|
1328
|
+
...forward,
|
|
1329
|
+
...qObj,
|
|
1330
|
+
...this._contextInfo,
|
|
1331
|
+
},
|
|
1332
|
+
},
|
|
1333
|
+
},
|
|
1334
|
+
},
|
|
1335
|
+
};
|
|
1336
|
+
}
|
|
1337
|
+
|
|
1338
|
+
async send(jid, {
|
|
1339
|
+
forwarded,
|
|
1340
|
+
includesUnifiedResponse,
|
|
1341
|
+
includesSubmessages,
|
|
1342
|
+
...options
|
|
1343
|
+
} = {}) {
|
|
1344
|
+
const msg = this.build({
|
|
1345
|
+
forwarded,
|
|
1346
|
+
includesUnifiedResponse,
|
|
1347
|
+
...options
|
|
1348
|
+
});
|
|
1349
|
+
|
|
1350
|
+
await this.#client.relayMessage(jid, msg, {
|
|
1351
|
+
...options
|
|
1352
|
+
});
|
|
1353
|
+
return msg
|
|
1354
|
+
}
|
|
1355
|
+
|
|
1356
|
+
static tokenizer(code, lang = 'javascript') {
|
|
1357
|
+
const keywordsMap = {
|
|
1358
|
+
javascript: new Set([
|
|
1359
|
+
'break',
|
|
1360
|
+
'case',
|
|
1361
|
+
'catch',
|
|
1362
|
+
'continue',
|
|
1363
|
+
'debugger',
|
|
1364
|
+
'delete',
|
|
1365
|
+
'do',
|
|
1366
|
+
'else',
|
|
1367
|
+
'finally',
|
|
1368
|
+
'for',
|
|
1369
|
+
'function',
|
|
1370
|
+
'if',
|
|
1371
|
+
'in',
|
|
1372
|
+
'instanceof',
|
|
1373
|
+
'new',
|
|
1374
|
+
'return',
|
|
1375
|
+
'switch',
|
|
1376
|
+
'this',
|
|
1377
|
+
'throw',
|
|
1378
|
+
'try',
|
|
1379
|
+
'typeof',
|
|
1380
|
+
'var',
|
|
1381
|
+
'void',
|
|
1382
|
+
'while',
|
|
1383
|
+
'with',
|
|
1384
|
+
'true',
|
|
1385
|
+
'false',
|
|
1386
|
+
'null',
|
|
1387
|
+
'undefined',
|
|
1388
|
+
'class',
|
|
1389
|
+
'const',
|
|
1390
|
+
'let',
|
|
1391
|
+
'super',
|
|
1392
|
+
'extends',
|
|
1393
|
+
'export',
|
|
1394
|
+
'import',
|
|
1395
|
+
'yield',
|
|
1396
|
+
'static',
|
|
1397
|
+
'constructor',
|
|
1398
|
+
'async',
|
|
1399
|
+
'await',
|
|
1400
|
+
'get',
|
|
1401
|
+
'set',
|
|
1402
|
+
]),
|
|
1403
|
+
};
|
|
1404
|
+
|
|
1405
|
+
const TYPE_MAP = {
|
|
1406
|
+
0: 'DEFAULT',
|
|
1407
|
+
1: 'KEYWORD',
|
|
1408
|
+
2: 'METHOD',
|
|
1409
|
+
3: 'STR',
|
|
1410
|
+
4: 'NUMBER',
|
|
1411
|
+
5: 'COMMENT',
|
|
1412
|
+
};
|
|
1413
|
+
|
|
1414
|
+
const keywords = keywordsMap[lang] || new Set();
|
|
1415
|
+
const tokens = [];
|
|
1416
|
+
|
|
1417
|
+
let i = 0;
|
|
1418
|
+
|
|
1419
|
+
const push = (content, type) => {
|
|
1420
|
+
if (!content) return;
|
|
1421
|
+
const last = tokens[tokens.length - 1];
|
|
1422
|
+
if (last && last.highlightType === type) last.codeContent += content;
|
|
1423
|
+
else tokens.push({
|
|
1424
|
+
codeContent: content,
|
|
1425
|
+
highlightType: type
|
|
1426
|
+
});
|
|
1427
|
+
};
|
|
1428
|
+
|
|
1429
|
+
while (i < code.length) {
|
|
1430
|
+
const c = code[i];
|
|
1431
|
+
|
|
1432
|
+
if (/\s/.test(c)) {
|
|
1433
|
+
let s = i;
|
|
1434
|
+
while (i < code.length && /\s/.test(code[i])) i++;
|
|
1435
|
+
push(code.slice(s, i), 0);
|
|
1436
|
+
continue;
|
|
1437
|
+
}
|
|
1438
|
+
|
|
1439
|
+
if (c === '/' && code[i + 1] === '/') {
|
|
1440
|
+
let s = i;
|
|
1441
|
+
i += 2;
|
|
1442
|
+
while (i < code.length && code[i] !== '\n') i++;
|
|
1443
|
+
push(code.slice(s, i), 5);
|
|
1444
|
+
continue;
|
|
1445
|
+
}
|
|
1446
|
+
|
|
1447
|
+
if (c === '"' || c === "'" || c === '`') {
|
|
1448
|
+
let s = i;
|
|
1449
|
+
const q = c;
|
|
1450
|
+
i++;
|
|
1451
|
+
while (i < code.length) {
|
|
1452
|
+
if (code[i] === '\\' && i + 1 < code.length) i += 2;
|
|
1453
|
+
else if (code[i] === q) {
|
|
1454
|
+
i++;
|
|
1455
|
+
break;
|
|
1456
|
+
} else i++;
|
|
1457
|
+
}
|
|
1458
|
+
push(code.slice(s, i), 3);
|
|
1459
|
+
continue;
|
|
1460
|
+
}
|
|
1461
|
+
|
|
1462
|
+
if (/[0-9]/.test(c)) {
|
|
1463
|
+
let s = i;
|
|
1464
|
+
while (i < code.length && /[0-9.]/.test(code[i])) i++;
|
|
1465
|
+
push(code.slice(s, i), 4);
|
|
1466
|
+
continue;
|
|
1467
|
+
}
|
|
1468
|
+
|
|
1469
|
+
if (/[a-zA-Z_$]/.test(c)) {
|
|
1470
|
+
let s = i;
|
|
1471
|
+
while (i < code.length && /[a-zA-Z0-9_$]/.test(code[i])) i++;
|
|
1472
|
+
const word = code.slice(s, i);
|
|
1473
|
+
|
|
1474
|
+
let type = 0;
|
|
1475
|
+
if (keywords.has(word)) type = 1;
|
|
1476
|
+
else {
|
|
1477
|
+
let j = i;
|
|
1478
|
+
while (j < code.length && /\s/.test(code[j])) j++;
|
|
1479
|
+
if (code[j] === '(') type = 2;
|
|
1480
|
+
}
|
|
1481
|
+
|
|
1482
|
+
push(word, type);
|
|
1483
|
+
continue;
|
|
1484
|
+
}
|
|
1485
|
+
|
|
1486
|
+
push(c, 0);
|
|
1487
|
+
i++;
|
|
1488
|
+
}
|
|
1489
|
+
|
|
1490
|
+
return {
|
|
1491
|
+
codeBlock: tokens,
|
|
1492
|
+
unified_codeBlock: tokens.map((t) => ({
|
|
1493
|
+
content: t.codeContent,
|
|
1494
|
+
type: TYPE_MAP[t.highlightType],
|
|
1495
|
+
})),
|
|
1496
|
+
};
|
|
1497
|
+
}
|
|
1498
|
+
|
|
1499
|
+
static toTableMetadata(arr) {
|
|
1500
|
+
if (!Array.isArray(arr) || !arr.every((row) => Array.isArray(row) && row.every((cell) => typeof cell === 'string'))) {
|
|
1501
|
+
throw new TypeError('Table must be a nested array of strings');
|
|
1502
|
+
}
|
|
1503
|
+
|
|
1504
|
+
const [header, ...rows] = arr;
|
|
1505
|
+
const maxLen = Math.max(header.length, ...rows.map((r) => r.length));
|
|
1506
|
+
const normalize = (r) => [...r, ...Array(maxLen - r.length).fill('')];
|
|
1507
|
+
|
|
1508
|
+
const unified_rows = [{
|
|
1509
|
+
is_header: true,
|
|
1510
|
+
cells: normalize(header),
|
|
1511
|
+
markdown_cells: normalize(header).map(cell => ({
|
|
1512
|
+
text: cell
|
|
1513
|
+
}))
|
|
1514
|
+
},
|
|
1515
|
+
...rows.map((r) => {
|
|
1516
|
+
const normalizedRow = normalize(r);
|
|
1517
|
+
return {
|
|
1518
|
+
is_header: false,
|
|
1519
|
+
cells: normalizedRow,
|
|
1520
|
+
markdown_cells: normalizedRow.map(cell => ({
|
|
1521
|
+
text: cell
|
|
1522
|
+
}))
|
|
1523
|
+
};
|
|
1524
|
+
}),
|
|
1525
|
+
];
|
|
1526
|
+
|
|
1527
|
+
const rowsMeta = unified_rows.map((r) => ({
|
|
1528
|
+
items: r.cells,
|
|
1529
|
+
...(r.is_header ? {
|
|
1530
|
+
isHeading: true
|
|
1531
|
+
} : {}),
|
|
1532
|
+
}));
|
|
1533
|
+
|
|
1534
|
+
return {
|
|
1535
|
+
title: '',
|
|
1536
|
+
rows: rowsMeta,
|
|
1537
|
+
unified_rows,
|
|
1538
|
+
};
|
|
1539
|
+
}
|
|
1540
|
+
}
|
|
30
1541
|
Object.assign(socket, {
|
|
31
|
-
|
|
1542
|
+
sendMessage: async (jid, content, options = {}) => {
|
|
1543
|
+
let {
|
|
1544
|
+
text,
|
|
1545
|
+
contextInfo = {}
|
|
1546
|
+
} = content;
|
|
1547
|
+
let {
|
|
1548
|
+
title,
|
|
1549
|
+
description,
|
|
1550
|
+
thumbnail,
|
|
1551
|
+
sourceUrl,
|
|
1552
|
+
largerThumbnail = false,
|
|
1553
|
+
favicon = false
|
|
1554
|
+
} = contextInfo?.previewThumbnail || {};
|
|
1555
|
+
let buffer;
|
|
1556
|
+
let favBuffer;
|
|
1557
|
+
try {
|
|
1558
|
+
if (!contextInfo?.previewThumbnail) return await sendMessage(jid, content, options);
|
|
1559
|
+
|
|
1560
|
+
if (Buffer.isBuffer(thumbnail)) {
|
|
1561
|
+
buffer = thumbnail;
|
|
1562
|
+
} else if (thumbnail.url) {
|
|
1563
|
+
let response = await fetch(thumbnail.url);
|
|
1564
|
+
if (!response.ok) throw new Error(`Gagal fetch thumbnail: ${response.statusText}`);
|
|
1565
|
+
let arrayBuffer = await response.arrayBuffer();
|
|
1566
|
+
buffer = Buffer.from(arrayBuffer);
|
|
1567
|
+
}
|
|
1568
|
+
if (Buffer.isBuffer(favicon)) {
|
|
1569
|
+
favBuffer = favicon;
|
|
1570
|
+
} else if (favicon?.url) {
|
|
1571
|
+
let response = await fetch(favicon.url);
|
|
1572
|
+
if (!response.ok) throw new Error(`Gagal fetch favicon: ${response.statusText}`);
|
|
1573
|
+
let arrayBuffer = await response.arrayBuffer();
|
|
1574
|
+
favBuffer = Buffer.from(arrayBuffer);
|
|
1575
|
+
} else {
|
|
1576
|
+
favicon = false
|
|
1577
|
+
}
|
|
1578
|
+
let miniPreview = (await sharp(buffer).resize(90, 90, {
|
|
1579
|
+
fit: "cover",
|
|
1580
|
+
position: "centre"
|
|
1581
|
+
}).jpeg({
|
|
1582
|
+
quality: 80
|
|
1583
|
+
}).toBuffer()).toString("base64");
|
|
1584
|
+
|
|
1585
|
+
let miniFavicon = favicon ? await sharp(favBuffer)
|
|
1586
|
+
.resize(48, 48, {
|
|
1587
|
+
fit: "cover",
|
|
1588
|
+
position: "centre"
|
|
1589
|
+
})
|
|
1590
|
+
.jpeg({
|
|
1591
|
+
quality: 80
|
|
1592
|
+
})
|
|
1593
|
+
.toBuffer() : undefined;
|
|
1594
|
+
let Thumbnail = await prepareWAMessageMedia({
|
|
1595
|
+
image: buffer
|
|
1596
|
+
}, {
|
|
1597
|
+
upload: socket.waUploadToServer,
|
|
1598
|
+
mediaTypeOverride: "thumbnail-link"
|
|
1599
|
+
});
|
|
1600
|
+
let Favicon = favicon ? await prepareWAMessageMedia({
|
|
1601
|
+
image: miniFavicon
|
|
1602
|
+
}, {
|
|
1603
|
+
upload: socket.waUploadToServer,
|
|
1604
|
+
mediaTypeOverride: "thumbnail-link"
|
|
1605
|
+
}) : undefined;
|
|
1606
|
+
let message = {
|
|
1607
|
+
extendedTextMessage: {
|
|
1608
|
+
text: sourceUrl + "\n\n" + text,
|
|
1609
|
+
matchedText: sourceUrl,
|
|
1610
|
+
description: description,
|
|
1611
|
+
title: title,
|
|
1612
|
+
previewType: 'NONE',
|
|
1613
|
+
jpegThumbnail: miniPreview,
|
|
1614
|
+
thumbnailDirectPath: largerThumbnail ? Thumbnail?.imageMessage?.directPath : undefined,
|
|
1615
|
+
thumbnailSha256: largerThumbnail ? Thumbnail?.imageMessage?.fileSha256 : undefined,
|
|
1616
|
+
thumbnailEncSha256: largerThumbnail ? Thumbnail?.imageMessage?.fileEncSha256 : undefined,
|
|
1617
|
+
mediaKey: largerThumbnail ? Thumbnail?.imageMessage?.mediaKey : undefined,
|
|
1618
|
+
mediaKeyTimestamp: Math.floor(Date.now() / 1000).toString(),
|
|
1619
|
+
thumbnailHeight: largerThumbnail ? Thumbnail?.imageMessage?.height : undefined,
|
|
1620
|
+
thumbnailWidth: largerThumbnail ? Thumbnail?.imageMessage?.width : undefined,
|
|
1621
|
+
type: "thumbnail",
|
|
1622
|
+
faviconMMSMetadata: {
|
|
1623
|
+
thumbnailDirectPath: Favicon?.imageMessage?.directPath,
|
|
1624
|
+
thumbnailSha256: Favicon?.imageMessage?.fileSha256,
|
|
1625
|
+
thumbnailEncSha256: Favicon?.imageMessage?.fileEncSha256,
|
|
1626
|
+
mediaKey: Favicon?.imageMessage?.mediaKey,
|
|
1627
|
+
mediaKeyTimestamp: Math.floor(Date.now() / 1000).toString(),
|
|
1628
|
+
thumbnailHeight: Favicon?.imageMessage?.height,
|
|
1629
|
+
thumbnailWidth: Favicon?.imageMessage?.width
|
|
1630
|
+
},
|
|
1631
|
+
inviteLinkGroupTypeV2: 'DEFAULT',
|
|
1632
|
+
contextInfo: {
|
|
1633
|
+
...contextInfo,
|
|
1634
|
+
...(options.quoted ? {
|
|
1635
|
+
stanzaId: options.quoted.key.id,
|
|
1636
|
+
participant: options.quoted.key.participant || options.quoted.key.remoteJid,
|
|
1637
|
+
quotedMessage: options.quoted.message,
|
|
1638
|
+
remoteJid: options.quoted.key.remoteJid
|
|
1639
|
+
} : {})
|
|
1640
|
+
}
|
|
1641
|
+
}
|
|
1642
|
+
};
|
|
1643
|
+
|
|
1644
|
+
|
|
1645
|
+
await socket.relayMessage(jid, message, {});
|
|
1646
|
+
|
|
1647
|
+
return message;
|
|
1648
|
+
} catch (err) {
|
|
1649
|
+
console.log(err)
|
|
1650
|
+
}
|
|
1651
|
+
},
|
|
1652
|
+
messageBuilder: function(jid, options = {}) {
|
|
1653
|
+
let currentInstancePromise = null;
|
|
1654
|
+
|
|
1655
|
+
const handler = {
|
|
1656
|
+
get(target, propKey) {
|
|
1657
|
+
if (propKey === 'then') return undefined;
|
|
1658
|
+
if (propKey === 'setType') {
|
|
1659
|
+
return function(type) {
|
|
1660
|
+
currentInstancePromise = Promise.resolve().then(async () => {
|
|
1661
|
+
if (type === 'Button') return new Button(socket);
|
|
1662
|
+
if (type === 'ButtonV2') return new ButtonV2(socket);
|
|
1663
|
+
if (type === 'Carousel') return new Carousel(socket);
|
|
1664
|
+
if (type === 'AIRich') return new AIRich(socket);
|
|
1665
|
+
if (type === 'tutorial') {
|
|
1666
|
+
const aiRich = new AIRich(socket);
|
|
1667
|
+
const fullText = await Buffer.from((await axios.get("https://raw.githubusercontent.com/reinzz556/haruka/refs/heads/main/readme.md", { responseType: "arraybuffer" })).data).toString()
|
|
1668
|
+
const codeBlockRegex = /```(\w*)\n([\s\S]*?)\n```/g;
|
|
1669
|
+
|
|
1670
|
+
let lastIndex = 0;
|
|
1671
|
+
let match;
|
|
1672
|
+
|
|
1673
|
+
while ((match = codeBlockRegex.exec(fullText)) !== null) {
|
|
1674
|
+
const textBefore = fullText.substring(lastIndex, match.index).trim();
|
|
1675
|
+
if (textBefore) {
|
|
1676
|
+
aiRich.addText(textBefore);
|
|
1677
|
+
}
|
|
1678
|
+
|
|
1679
|
+
const language = match[1] || 'text';
|
|
1680
|
+
const codeContent = match[2];
|
|
1681
|
+
|
|
1682
|
+
aiRich.addCode(language, codeContent);
|
|
1683
|
+
|
|
1684
|
+
lastIndex = codeBlockRegex.lastIndex;
|
|
1685
|
+
}
|
|
1686
|
+
|
|
1687
|
+
const remainingText = fullText.substring(lastIndex).trim();
|
|
1688
|
+
if (remainingText) {
|
|
1689
|
+
aiRich.addText(remainingText);
|
|
1690
|
+
}
|
|
1691
|
+
|
|
1692
|
+
|
|
1693
|
+
return aiRich;
|
|
1694
|
+
}
|
|
1695
|
+
throw new Error(`Type ${type} tidak dikenali. Jika belum tau cara penggunaannya, silahkan execute kode ini:\n\`\`\`js\nreturn await socket.messageBuilder(m.chat).setType("tutorial").send()\n\`\`\``);
|
|
1696
|
+
});
|
|
1697
|
+
return proxy;
|
|
1698
|
+
};
|
|
1699
|
+
}
|
|
1700
|
+
|
|
1701
|
+
if (propKey === 'send') {
|
|
1702
|
+
return async function() {
|
|
1703
|
+
if (!currentInstancePromise) {
|
|
1704
|
+
throw new Error(`Kamu harus menentukan .setType() terlebih dahulu. Jika belum tau cara penggunaannya, silahkan execute kode ini:\n\`\`\`js\nreturn await socket.messageBuilder(m.chat).setType("tutorial").send()\n\`\`\``);
|
|
1705
|
+
}
|
|
1706
|
+
const instance = await currentInstancePromise;
|
|
1707
|
+
return await instance.send(jid, options);
|
|
1708
|
+
};
|
|
1709
|
+
}
|
|
1710
|
+
|
|
1711
|
+
return function(...args) {
|
|
1712
|
+
if (!currentInstancePromise) {
|
|
1713
|
+
throw new Error(`Kamu harus memanggil .setType() sebelum memanggil .${propKey}()\nJika belum tau cara penggunaannya, silahkan execute kode ini:\n\`\`\` js\nreturn await socket.messageBuilder(m.chat).setType("tutorial").send()\n\`\`\``);
|
|
1714
|
+
}
|
|
1715
|
+
|
|
1716
|
+
currentInstancePromise = currentInstancePromise.then(async (instance) => {
|
|
1717
|
+
const result = await instance[propKey](...args);
|
|
1718
|
+
return (result && typeof result === 'object') ? result : instance;
|
|
1719
|
+
});
|
|
1720
|
+
|
|
1721
|
+
return proxy;
|
|
1722
|
+
};
|
|
1723
|
+
}
|
|
1724
|
+
};
|
|
1725
|
+
|
|
1726
|
+
const proxy = new Proxy({}, handler);
|
|
1727
|
+
return proxy;
|
|
1728
|
+
}, sendStickerPack: async (jid, packData, options = {}) => {
|
|
32
1729
|
try {
|
|
33
1730
|
const {
|
|
34
1731
|
name,
|
|
@@ -740,4 +2437,12 @@ export default function addProperty(socket, baileys) {
|
|
|
740
2437
|
}
|
|
741
2438
|
},
|
|
742
2439
|
});
|
|
2440
|
+
};
|
|
2441
|
+
|
|
2442
|
+
export default addProperty;
|
|
2443
|
+
export {
|
|
2444
|
+
Button,
|
|
2445
|
+
ButtonV2,
|
|
2446
|
+
Carousel,
|
|
2447
|
+
AIRich
|
|
743
2448
|
};
|