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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/README.md +12 -9
  2. package/docs/CHANGELOG.md +35 -4
  3. package/docs/SPR.md +61 -24
  4. package/lib/Defaults/index.js +5 -1
  5. package/lib/Socket/dinonic-handler.d.ts +27 -0
  6. package/lib/Socket/dinonic-handler.js +882 -0
  7. package/lib/Socket/index.js +8 -1
  8. package/lib/Socket/messages-recv.js +26 -0
  9. package/lib/Socket/messages-send.js +25 -0
  10. package/lib/Utils/MessageBuilder.d.ts +215 -0
  11. package/lib/Utils/MessageBuilder.js +3991 -0
  12. package/lib/Utils/a2ui.d.ts +202 -0
  13. package/lib/Utils/a2ui.js +732 -0
  14. package/lib/Utils/airich-registry.js +3 -0
  15. package/lib/Utils/baileys-event-stream.js +58 -0
  16. package/lib/Utils/bot-signature.d.ts +22 -0
  17. package/lib/Utils/bot-signature.js +124 -0
  18. package/lib/Utils/dinonic-spr.d.ts +73 -0
  19. package/lib/Utils/dinonic-spr.js +739 -0
  20. package/lib/Utils/extras.d.ts +449 -0
  21. package/lib/Utils/extras.js +1377 -0
  22. package/lib/Utils/html-app.d.ts +39 -0
  23. package/lib/Utils/html-app.js +291 -0
  24. package/lib/Utils/index.js +14 -2
  25. package/lib/Utils/metaai.d.ts +438 -0
  26. package/lib/Utils/metaai.js +911 -0
  27. package/lib/Utils/modern-messages.d.ts +150 -0
  28. package/lib/Utils/modern-messages.js +496 -0
  29. package/lib/Utils/native-flow.d.ts +14 -0
  30. package/lib/Utils/native-flow.js +118 -0
  31. package/lib/Utils/newsletter-status.js +9 -53
  32. package/lib/Utils/payment-messages.d.ts +59 -0
  33. package/lib/Utils/payment-messages.js +156 -0
  34. package/lib/Utils/scheduled-message.d.ts +82 -0
  35. package/lib/Utils/scheduled-message.js +113 -0
  36. package/lib/Utils/status-stickers.d.ts +78 -0
  37. package/lib/Utils/status-stickers.js +261 -0
  38. package/lib/index.js +2 -2
  39. package/package.json +4 -4
  40. package/lib/Utils/dinolith-spr.d.ts +0 -26
  41. package/lib/Utils/dinolith-spr.js +0 -521
@@ -0,0 +1,882 @@
1
+ import { proto } from '../../WAProto/index.js';
2
+ import * as link_preview_1 from '../Utils/link-preview.js';
3
+ import * as crypto from 'crypto';
4
+ import * as fs from 'fs';
5
+ import * as path from 'path';
6
+ import * as Utils_1 from '../Utils/index.js';
7
+ import * as WABinary_1 from '../WABinary/index.js';
8
+ const WAProto = proto;
9
+
10
+ class DinonicHandler {
11
+ constructor(utils, waUploadToServer, relayMessageFn, config, sock) {
12
+ this.utils = utils;
13
+ this.relayMessage = relayMessageFn;
14
+ this.waUploadToServer = waUploadToServer;
15
+ this.config = config;
16
+ this.sock = sock;
17
+
18
+ this.bail = {
19
+ generateWAMessageContent: this.utils.generateWAMessageContent || Utils_1.generateWAMessageContent,
20
+ generateMessageID: Utils_1.generateMessageID,
21
+ getContentType: (msg) => Object.keys(msg.message || {})[0]
22
+ };
23
+
24
+ this.contactCache = new Map();
25
+ const cachePath = path.join(process.cwd(), 'contacts-cache.json');
26
+ try {
27
+ if (fs.existsSync(cachePath)) {
28
+ const data = JSON.parse(fs.readFileSync(cachePath, 'utf8'));
29
+ for (const [key, val] of Object.entries(data)) {
30
+ this.contactCache.set(key, val);
31
+ }
32
+ }
33
+ } catch (err) {
34
+ console.error('[DinonicHandler] Failed to load contact cache:', err);
35
+ }
36
+
37
+ this.saveTimeout = null;
38
+ this.saveCache = () => {
39
+ if (this.saveTimeout) clearTimeout(this.saveTimeout);
40
+ this.saveTimeout = setTimeout(() => {
41
+ try {
42
+ const obj = {};
43
+ for (const [key, val] of this.contactCache.entries()) {
44
+ obj[key] = val;
45
+ }
46
+ // fs.writeFileSync(cachePath, JSON.stringify(obj, null, 2));
47
+ } catch (err) {
48
+ console.error('[DinonicHandler] Failed to save contact cache:', err);
49
+ }
50
+ }, 3000);
51
+ };
52
+
53
+ if (this.sock && this.sock.ev) {
54
+ this.sock.ev.on('contacts.upsert', (contacts) => {
55
+ let changed = false;
56
+ for (const contact of contacts) {
57
+ if (contact.id) {
58
+ this.contactCache.set(contact.id, contact);
59
+ changed = true;
60
+ }
61
+ }
62
+ if (changed) this.saveCache();
63
+ });
64
+ this.sock.ev.on('contacts.update', (updates) => {
65
+ let changed = false;
66
+ for (const update of updates) {
67
+ if (update.id) {
68
+ const current = this.contactCache.get(update.id) || {};
69
+ this.contactCache.set(update.id, { ...current, ...update });
70
+ changed = true;
71
+ }
72
+ }
73
+ if (changed) this.saveCache();
74
+ });
75
+ this.sock.ev.on('messaging-history.set', ({ contacts }) => {
76
+ if (contacts) {
77
+ let changed = false;
78
+ for (const contact of contacts) {
79
+ if (contact.id) {
80
+ this.contactCache.set(contact.id, contact);
81
+ changed = true;
82
+ }
83
+ }
84
+ if (changed) this.saveCache();
85
+ }
86
+ });
87
+ this.sock.ev.on('messages.upsert', ({ messages }) => {
88
+ let changed = false;
89
+ for (const msg of messages) {
90
+ if (msg.pushName) {
91
+ const jid = WABinary_1.jidNormalizedUser(msg.key.fromMe ? (this.sock.authState?.creds?.me?.id || '') : (msg.key.participant || msg.key.remoteJid));
92
+ if (jid) {
93
+ const current = this.contactCache.get(jid) || {};
94
+ this.contactCache.set(jid, {
95
+ ...current,
96
+ id: jid,
97
+ notify: msg.pushName,
98
+ name: current.name || msg.pushName
99
+ });
100
+ changed = true;
101
+ }
102
+ }
103
+ }
104
+ if (changed) this.saveCache();
105
+ });
106
+ }
107
+ }
108
+
109
+ detectType(content) {
110
+ if (!content || typeof content !== 'object') return null;
111
+ if (content.requestPaymentMessage) return 'PAYMENT';
112
+ if (content.productMessage) return 'PRODUCT';
113
+ if (content.interactiveMessage || content.carouselMessage || content.cards) return 'INTERACTIVE';
114
+ if (content.buttonsMessage) return 'BUTTONS';
115
+ if (content.albumMessage) return 'ALBUM';
116
+ if (content.eventMessage) return 'EVENT';
117
+ if (content.pollResultMessage) return 'POLL_RESULT';
118
+ if (content.groupStatusMessage) return 'GROUP_STORY';
119
+ if (content.flowMessage) return 'FLOW';
120
+ return null;
121
+ }
122
+
123
+ async getName(jid) {
124
+ if (!jid) return 'Unknown';
125
+ const normalizedJid = WABinary_1.jidNormalizedUser(jid);
126
+
127
+ // 1. Cek jika JID kita sendiri
128
+ const myJid = this.sock.authState?.creds?.me?.id ? WABinary_1.jidNormalizedUser(this.sock.authState.creds.me.id) : null;
129
+ if (myJid && normalizedJid === myJid) {
130
+ return this.sock.authState.creds.me.name || "Saya";
131
+ }
132
+
133
+ // 2. Cek cache lokal DinonicHandler
134
+ const cached = this.contactCache.get(normalizedJid);
135
+ if (cached) {
136
+ const name = cached.name || cached.verifiedName || cached.notify;
137
+ if (name) return name;
138
+ }
139
+
140
+ // 3. Cek jika itu JID grup
141
+ if (WABinary_1.isJidGroup(normalizedJid)) {
142
+ try {
143
+ const groupMetadata = await this.sock.groupMetadata(normalizedJid);
144
+ if (groupMetadata && groupMetadata.subject) {
145
+ const current = this.contactCache.get(normalizedJid) || {};
146
+ if (current.name !== groupMetadata.subject) {
147
+ this.contactCache.set(normalizedJid, {
148
+ ...current,
149
+ id: normalizedJid,
150
+ name: groupMetadata.subject,
151
+ notify: groupMetadata.subject
152
+ });
153
+ this.saveCache();
154
+ }
155
+ return groupMetadata.subject;
156
+ }
157
+ } catch (err) {
158
+ // Silently ignore
159
+ }
160
+ }
161
+
162
+ // 4. Fallback ke nomor telepon saja
163
+ return normalizedJid.split('@')[0];
164
+ }
165
+
166
+ async handlePayment(content, quoted) {
167
+ const data = content.requestPaymentMessage;
168
+ let notes = {};
169
+
170
+ try {
171
+ if (data.sticker?.stickerMessage) {
172
+ notes = {
173
+ stickerMessage: {
174
+ ...data.sticker.stickerMessage,
175
+ contextInfo: {
176
+ stanzaId: quoted?.key?.id,
177
+ participant: quoted?.key?.participant || content.sender,
178
+ quotedMessage: quoted?.message
179
+ }
180
+ }
181
+ };
182
+ } else if (data.note) {
183
+ notes = {
184
+ extendedTextMessage: {
185
+ text: data.note,
186
+ contextInfo: {
187
+ stanzaId: quoted?.key?.id,
188
+ participant: quoted?.key?.participant || content.sender,
189
+ quotedMessage: quoted?.message
190
+ }
191
+ }
192
+ };
193
+ }
194
+ } catch (err) {
195
+ if (this.config.logger) {
196
+ this.config.logger.error(`Error handling notes in payment: ${err}`);
197
+ }
198
+ }
199
+
200
+ return {
201
+ requestPaymentMessage: WAProto.Message.RequestPaymentMessage.fromObject({
202
+ expiryTimestamp: data.expiry || 0,
203
+ amount1000: data.amount || 0,
204
+ currencyCodeIso4217: data.currency || "IDR",
205
+ requestFrom: data.from || "0@s.whatsapp.net",
206
+ noteMessage: notes,
207
+ background: data.background ?? {
208
+ id: "DEFAULT",
209
+ placeholderArgb: 0xFFF0F0F0
210
+ }
211
+ })
212
+ };
213
+ }
214
+
215
+ async handleProduct(content, jid, quoted) {
216
+ const {
217
+ title,
218
+ description,
219
+ thumbnail,
220
+ productId,
221
+ retailerId,
222
+ url,
223
+ body = "",
224
+ footer = "",
225
+ buttons = [],
226
+ priceAmount1000 = null,
227
+ currencyCode = "IDR",
228
+ businessOwnerJid = "0@s.whatsapp.net"
229
+ } = content.productMessage;
230
+
231
+ let productImage;
232
+
233
+ try {
234
+ if (Buffer.isBuffer(thumbnail)) {
235
+ const { imageMessage } = await this.utils.generateWAMessageContent(
236
+ { image: thumbnail },
237
+ { upload: this.waUploadToServer }
238
+ );
239
+ productImage = imageMessage;
240
+ } else if (typeof thumbnail === 'object' && thumbnail.url) {
241
+ const { imageMessage } = await this.utils.generateWAMessageContent(
242
+ { image: { url: thumbnail.url }},
243
+ { upload: this.waUploadToServer }
244
+ );
245
+ productImage = imageMessage;
246
+ }
247
+ } catch (err) {
248
+ if (this.config.logger) {
249
+ this.config.logger.error(`Error preparing product image: ${err}`);
250
+ }
251
+ }
252
+
253
+ return {
254
+ viewOnceMessage: {
255
+ message: {
256
+ interactiveMessage: {
257
+ body: { text: body },
258
+ footer: { text: footer },
259
+ header: {
260
+ title,
261
+ hasMediaAttachment: true,
262
+ productMessage: {
263
+ product: {
264
+ productImage,
265
+ productId,
266
+ title,
267
+ description,
268
+ currencyCode,
269
+ priceAmount1000,
270
+ retailerId,
271
+ url,
272
+ productImageCount: 1
273
+ },
274
+ businessOwnerJid
275
+ }
276
+ },
277
+ nativeFlowMessage: { buttons }
278
+ }
279
+ }
280
+ }
281
+ };
282
+ }
283
+
284
+ async handleInteractive(content, jid, quoted) {
285
+ if (content.interactiveMessage?.carouselMessage) {
286
+ return content;
287
+ }
288
+ if (content.carouselMessage) {
289
+ return {
290
+ interactiveMessage: {
291
+ header: content.header || { hasMediaAttachment: false },
292
+ body: content.body || { text: content.text || content.caption || "" },
293
+ footer: content.footer || { text: "" },
294
+ contextInfo: content.contextInfo || {},
295
+ carouselMessage: content.carouselMessage
296
+ }
297
+ };
298
+ }
299
+ if (Array.isArray(content.cards)) {
300
+ return {
301
+ interactiveMessage: {
302
+ header: { hasMediaAttachment: false },
303
+ body: { text: content.text || content.caption || "" },
304
+ footer: { text: content.footer || "" },
305
+ contextInfo: content.contextInfo || {},
306
+ carouselMessage: {
307
+ cards: content.cards
308
+ }
309
+ }
310
+ };
311
+ }
312
+
313
+ const iMsg = content.interactiveMessage || content;
314
+ const {
315
+ title,
316
+ footer,
317
+ thumbnail,
318
+ image,
319
+ video,
320
+ document,
321
+ mimetype,
322
+ fileName,
323
+ jpegThumbnail,
324
+ contextInfo,
325
+ externalAdReply,
326
+ buttons = [],
327
+ nativeFlowMessage,
328
+ carouselMessage,
329
+ header
330
+ } = iMsg;
331
+
332
+ let media = null;
333
+ let mediaType = null;
334
+
335
+ try {
336
+ if (thumbnail) {
337
+ media = await this.utils.prepareWAMessageMedia(
338
+ { image: { url: thumbnail } },
339
+ { upload: this.waUploadToServer }
340
+ );
341
+ mediaType = 'image';
342
+ } else if (image) {
343
+ if (typeof image === 'object' && image.url) {
344
+ media = await this.utils.prepareWAMessageMedia(
345
+ { image: { url: image.url } },
346
+ { upload: this.waUploadToServer }
347
+ );
348
+ } else {
349
+ media = await this.utils.prepareWAMessageMedia(
350
+ { image: image },
351
+ { upload: this.waUploadToServer }
352
+ );
353
+ }
354
+ mediaType = 'image';
355
+ } else if (video) {
356
+ if (typeof video === 'object' && video.url) {
357
+ media = await this.utils.prepareWAMessageMedia(
358
+ { video: { url: video.url } },
359
+ { upload: this.waUploadToServer }
360
+ );
361
+ } else {
362
+ media = await this.utils.prepareWAMessageMedia(
363
+ { video: video },
364
+ { upload: this.waUploadToServer }
365
+ );
366
+ }
367
+ mediaType = 'video';
368
+ } else if (document) {
369
+ let documentPayload = {
370
+ document: document
371
+ };
372
+ if (jpegThumbnail) {
373
+ if (typeof jpegThumbnail === 'object' && jpegThumbnail.url) {
374
+ documentPayload.jpegThumbnail = { url: jpegThumbnail.url };
375
+ } else {
376
+ documentPayload.jpegThumbnail = jpegThumbnail;
377
+ }
378
+ }
379
+
380
+ media = await this.utils.prepareWAMessageMedia(
381
+ documentPayload,
382
+ { upload: this.waUploadToServer }
383
+ );
384
+ if (fileName) {
385
+ media.documentMessage.fileName = fileName;
386
+ }
387
+ if (mimetype) {
388
+ media.documentMessage.mimetype = mimetype;
389
+ }
390
+ mediaType = 'document';
391
+ }
392
+ } catch (err) {
393
+ if (this.config.logger) {
394
+ this.config.logger.error(`Error preparing interactive media: ${err}`);
395
+ }
396
+ }
397
+
398
+ let interactiveMessage = {
399
+ body: { text: title || iMsg.text || "" },
400
+ footer: { text: footer || "" }
401
+ };
402
+ if (carouselMessage) {
403
+ interactiveMessage.carouselMessage = carouselMessage;
404
+ } else if (buttons && buttons.length > 0) {
405
+ interactiveMessage.nativeFlowMessage = {
406
+ buttons: buttons
407
+ };
408
+ if (nativeFlowMessage) {
409
+ interactiveMessage.nativeFlowMessage = {
410
+ ...interactiveMessage.nativeFlowMessage,
411
+ ...nativeFlowMessage
412
+ };
413
+ }
414
+ } else if (nativeFlowMessage) {
415
+ interactiveMessage.nativeFlowMessage = nativeFlowMessage;
416
+ }
417
+
418
+ if (media) {
419
+ interactiveMessage.header = {
420
+ title: header || "",
421
+ hasMediaAttachment: true,
422
+ ...media
423
+ };
424
+ } else {
425
+ interactiveMessage.header = {
426
+ title: header || "",
427
+ hasMediaAttachment: false
428
+ };
429
+ }
430
+
431
+ let finalContextInfo = {};
432
+ if (contextInfo) {
433
+ finalContextInfo = {
434
+ mentionedJid: contextInfo.mentionedJid || [],
435
+ forwardingScore: contextInfo.forwardingScore || 0,
436
+ isForwarded: contextInfo.isForwarded || false,
437
+ ...contextInfo
438
+ };
439
+ }
440
+
441
+ if (externalAdReply) {
442
+ finalContextInfo.externalAdReply = {
443
+ title: externalAdReply.title || "",
444
+ body: externalAdReply.body || "",
445
+ mediaType: externalAdReply.mediaType || 1,
446
+ thumbnailUrl: externalAdReply.thumbnailUrl || "",
447
+ mediaUrl: externalAdReply.mediaUrl || "",
448
+ sourceUrl: externalAdReply.sourceUrl || "",
449
+ showAdAttribution: externalAdReply.showAdAttribution || false,
450
+ renderLargerThumbnail: externalAdReply.renderLargerThumbnail || false,
451
+ ...externalAdReply
452
+ };
453
+ }
454
+
455
+ if (Object.keys(finalContextInfo).length > 0) {
456
+ interactiveMessage.contextInfo = finalContextInfo;
457
+ }
458
+ return {
459
+ interactiveMessage: interactiveMessage
460
+ };
461
+ }
462
+
463
+ async handleAlbum(content, jid, quoted) {
464
+ const array = content.albumMessage;
465
+ const albumOptions = content.albumOptions || {};
466
+ const album = await this.utils.generateWAMessageFromContent(jid, {
467
+ messageContextInfo: {
468
+ messageSecret: crypto.randomBytes(32),
469
+ },
470
+ albumMessage: {
471
+ expectedImageCount: array.filter((a) => a.hasOwnProperty("image")).length,
472
+ expectedVideoCount: array.filter((a) => a.hasOwnProperty("video")).length,
473
+ },
474
+ }, {
475
+ userJid: this.utils.generateMessageID().split('@')[0] + '@s.whatsapp.net',
476
+ quoted,
477
+ upload: this.waUploadToServer
478
+ });
479
+
480
+ await this.relayMessage(jid, album.message, {
481
+ messageId: album.key.id,
482
+ });
483
+
484
+ for (let content of array) {
485
+ const img = await this.utils.generateWAMessage(jid, content, {
486
+ upload: this.waUploadToServer,
487
+ });
488
+
489
+ img.message.messageContextInfo = {
490
+ messageSecret: crypto.randomBytes(32),
491
+ messageAssociation: {
492
+ associationType: 1,
493
+ parentMessageKey: album.key,
494
+ },
495
+ participant: "0@s.whatsapp.net",
496
+ remoteJid: "status@broadcast",
497
+ forwardingScore: 99999,
498
+ isForwarded: true,
499
+ mentionedJid: [jid],
500
+ starred: true,
501
+ labels: ["Y", "Important"],
502
+ isHighlighted: true,
503
+ businessMessageForwardInfo: {
504
+ businessOwnerJid: jid,
505
+ },
506
+ dataSharingContext: {
507
+ showMmDisclosure: true,
508
+ },
509
+ };
510
+
511
+ if (albumOptions.newsletterJid) {
512
+ img.message.forwardedNewsletterMessageInfo = {
513
+ newsletterJid: albumOptions.newsletterJid,
514
+ serverMessageId: albumOptions.serverMessageId || 1,
515
+ newsletterName: albumOptions.newsletterName || `WhatsApp`,
516
+ contentType: albumOptions.contentType || 1,
517
+ timestamp: new Date().toISOString(),
518
+ senderName: albumOptions.senderName || "Who know",
519
+ content: albumOptions.content || "Text Message",
520
+ priority: "high",
521
+ status: "sent",
522
+ };
523
+ }
524
+
525
+ img.message.disappearingMode = {
526
+ initiator: 3,
527
+ trigger: 4,
528
+ initiatorDeviceJid: jid,
529
+ initiatedByExternalService: true,
530
+ initiatedByUserDevice: true,
531
+ initiatedBySystem: true,
532
+ initiatedByServer: true,
533
+ initiatedByAdmin: true,
534
+ initiatedByUser: true,
535
+ initiatedByApp: true,
536
+ initiatedByBot: true,
537
+ initiatedByMe: true,
538
+ };
539
+
540
+ await this.relayMessage(jid, img.message, {
541
+ messageId: img.key.id,
542
+ quoted: {
543
+ key: {
544
+ remoteJid: album.key.remoteJid,
545
+ id: album.key.id,
546
+ fromMe: true,
547
+ participant: this.utils.generateMessageID().split('@')[0] + '@s.whatsapp.net',
548
+ },
549
+ message: album.message,
550
+ },
551
+ });
552
+ }
553
+ return album;
554
+ }
555
+
556
+ async handleEvent(content, jid, quoted) {
557
+ const eventData = content.eventMessage;
558
+
559
+ const msg = await this.utils.generateWAMessageFromContent(jid, {
560
+ viewOnceMessage: {
561
+ message: {
562
+ messageContextInfo: {
563
+ deviceListMetadata: {},
564
+ deviceListMetadataVersion: 2,
565
+ messageSecret: crypto.randomBytes(32),
566
+ supportPayload: JSON.stringify({
567
+ version: 2,
568
+ is_ai_message: true,
569
+ should_show_system_message: true,
570
+ ticket_id: crypto.randomBytes(16).toString('hex')
571
+ })
572
+ },
573
+ eventMessage: {
574
+ contextInfo: {
575
+ mentionedJid: [jid],
576
+ participant: jid,
577
+ remoteJid: "status@broadcast",
578
+ forwardedNewsletterMessageInfo: eventData.newsletterJid ? {
579
+ newsletterName: eventData.newsletterName || "WhatsApp",
580
+ newsletterJid: eventData.newsletterJid,
581
+ serverMessageId: eventData.serverMessageId || 1
582
+ } : undefined
583
+ },
584
+ isCanceled: eventData.isCanceled || false,
585
+ name: eventData.name,
586
+ description: eventData.description,
587
+ location: eventData.location || {
588
+ degreesLatitude: 0,
589
+ degreesLongitude: 0,
590
+ name: "Location"
591
+ },
592
+ joinLink: eventData.joinLink || '',
593
+ startTime: typeof eventData.startTime === 'string' ? parseInt(eventData.startTime) : eventData.startTime || Date.now(),
594
+ endTime: typeof eventData.endTime === 'string' ? parseInt(eventData.endTime) : eventData.endTime || Date.now() + 3600000,
595
+ extraGuestsAllowed: eventData.extraGuestsAllowed !== false
596
+ }
597
+ }
598
+ }
599
+ }, { quoted });
600
+
601
+ await this.relayMessage(jid, msg.message, {
602
+ messageId: msg.key.id
603
+ });
604
+ return msg;
605
+ }
606
+
607
+ async handlePollResult(content, jid, quoted) {
608
+ const pollData = content.pollResultMessage;
609
+
610
+ const msg = await this.utils.generateWAMessageFromContent(jid, {
611
+ pollResultSnapshotMessage: {
612
+ name: pollData.name,
613
+ pollVotes: pollData.pollVotes.map(vote => ({
614
+ optionName: vote.optionName,
615
+ optionVoteCount: typeof vote.optionVoteCount === 'number'
616
+ ? vote.optionVoteCount.toString()
617
+ : vote.optionVoteCount
618
+ }))
619
+ }
620
+ }, {
621
+ userJid: this.utils.generateMessageID().split('@')[0] + '@s.whatsapp.net',
622
+ quoted
623
+ });
624
+
625
+ await this.relayMessage(jid, msg.message, {
626
+ messageId: msg.key.id
627
+ });
628
+
629
+ return msg;
630
+ }
631
+
632
+ async handleGroupStory(content, jid, quoted) {
633
+ const storyData = content.groupStatusMessage;
634
+ let waMsgContent;
635
+
636
+ if (storyData.message) {
637
+ waMsgContent = storyData;
638
+ } else {
639
+ if (typeof this.bail?.generateWAMessageContent === "function") {
640
+ waMsgContent = await this.bail.generateWAMessageContent(storyData, {
641
+ upload: this.waUploadToServer
642
+ });
643
+ } else if (typeof this.utils?.generateWAMessageContent === "function") {
644
+ waMsgContent = await this.utils.generateWAMessageContent(storyData, {
645
+ upload: this.waUploadToServer
646
+ });
647
+ } else if (typeof this.utils?.prepareMessageContent === "function") {
648
+ waMsgContent = await this.utils.prepareMessageContent(storyData, {
649
+ upload: this.waUploadToServer
650
+ });
651
+ } else {
652
+ waMsgContent = await Utils_1.generateWAMessageContent(storyData, {
653
+ upload: this.waUploadToServer
654
+ });
655
+ }
656
+ }
657
+
658
+ let msg = {
659
+ message: {
660
+ groupStatusMessageV2: {
661
+ message: waMsgContent.message || waMsgContent
662
+ }
663
+ }
664
+ };
665
+
666
+ return await this.relayMessage(jid, msg.message, {
667
+ messageId: this.bail.generateMessageID()
668
+ });
669
+ }
670
+
671
+ async handleFlow(content, jid, quoted) {
672
+ const {
673
+ title,
674
+ body,
675
+ footer,
676
+ flowId,
677
+ flowToken = crypto.randomBytes(16).toString('hex'),
678
+ buttonText = "Open Flow",
679
+ screen = "UNION",
680
+ params = {},
681
+ contextInfo
682
+ } = content.flowMessage;
683
+
684
+ const buttonParamsJson = JSON.stringify({
685
+ flow_token: flowToken,
686
+ flow_id: flowId,
687
+ flow_cta: buttonText,
688
+ flow_action: "navigate",
689
+ flow_action_payload: {
690
+ screen: screen,
691
+ data: params
692
+ }
693
+ });
694
+
695
+ let interactiveMessage = {
696
+ body: { text: body || "" },
697
+ footer: { text: footer || "" },
698
+ header: {
699
+ title: title || "",
700
+ hasMediaAttachment: false
701
+ },
702
+ nativeFlowMessage: {
703
+ buttons: [
704
+ {
705
+ name: "flow",
706
+ buttonParamsJson: buttonParamsJson
707
+ }
708
+ ]
709
+ }
710
+ };
711
+
712
+ if (contextInfo) {
713
+ interactiveMessage.contextInfo = contextInfo;
714
+ }
715
+
716
+ return {
717
+ interactiveMessage: interactiveMessage
718
+ };
719
+ }
720
+
721
+ async sendStatusWhatsApp(content, jids = []) {
722
+ const userJid = WABinary_1.jidNormalizedUser(this.sock.authState.creds.me.id);
723
+ let allUsers = new Set();
724
+ allUsers.add(userJid);
725
+
726
+ for (const id of jids) {
727
+ const isGroup = WABinary_1.isJidGroup(id);
728
+ const isPrivate = WABinary_1.isJidUser(id);
729
+
730
+ if (isGroup) {
731
+ try {
732
+ const metadata = await this.sock.groupMetadata(id);
733
+ const participants = metadata.participants.map(p => WABinary_1.jidNormalizedUser(p.id));
734
+ participants.forEach(jid => allUsers.add(jid));
735
+ } catch (error) {
736
+ if (this.config.logger) {
737
+ this.config.logger.error(`Error getting metadata for group ${id}: ${error}`);
738
+ }
739
+ }
740
+ } else if (isPrivate) {
741
+ allUsers.add(WABinary_1.jidNormalizedUser(id));
742
+ }
743
+ }
744
+
745
+ const uniqueUsers = Array.from(allUsers);
746
+ const getRandomHexColor = () => "#" + Math.floor(Math.random() * 16777215).toString(16).padStart(6, "0");
747
+
748
+ const isMedia = content.image || content.video || content.audio;
749
+ const isAudio = !!content.audio;
750
+
751
+ const messageContent = { ...content };
752
+
753
+ if (isMedia && !isAudio) {
754
+ if (messageContent.text) {
755
+ messageContent.caption = messageContent.text;
756
+ delete messageContent.text;
757
+ }
758
+ delete messageContent.ptt;
759
+ delete messageContent.font;
760
+ delete messageContent.backgroundColor;
761
+ delete messageContent.textColor;
762
+ }
763
+
764
+ if (isAudio) {
765
+ delete messageContent.text;
766
+ delete messageContent.caption;
767
+ delete messageContent.font;
768
+ delete messageContent.textColor;
769
+ }
770
+
771
+ const font = !isMedia ? (content.font || Math.floor(Math.random() * 9)) : undefined;
772
+ const textColor = !isMedia ? (content.textColor || getRandomHexColor()) : undefined;
773
+ const backgroundColor = (!isMedia || isAudio) ? (content.backgroundColor || getRandomHexColor()) : undefined;
774
+ const ptt = isAudio ? (typeof content.ptt === 'boolean' ? content.ptt : true) : undefined;
775
+
776
+ let msg;
777
+ let mediaHandle;
778
+
779
+ try {
780
+
781
+
782
+ msg = await Utils_1.generateWAMessage(WABinary_1.STORIES_JID, messageContent, {
783
+ logger: this.config.logger,
784
+ userJid,
785
+ getUrlInfo: text => link_preview_1.getUrlInfo(text, {
786
+ thumbnailWidth: this.config.linkPreviewImageThumbnailWidth,
787
+ fetchOpts: { timeout: 3000, ...this.config.options || {} },
788
+ logger: this.config.logger,
789
+ uploadImage: this.config.generateHighQualityLinkPreview ? this.waUploadToServer : undefined
790
+ }),
791
+ upload: async (encFilePath, opts) => {
792
+ const up = await this.waUploadToServer(encFilePath, { ...opts });
793
+ mediaHandle = up.handle;
794
+ return up;
795
+ },
796
+ mediaCache: this.config.mediaCache,
797
+ options: this.config.options,
798
+ font,
799
+ textColor,
800
+ backgroundColor,
801
+ ptt
802
+ });
803
+ } catch (error) {
804
+ if (this.config.logger) {
805
+ this.config.logger.error(`Error generating message: ${error}`);
806
+ }
807
+ throw error;
808
+ }
809
+
810
+ await this.relayMessage(WABinary_1.STORIES_JID, msg.message, {
811
+ messageId: msg.key.id,
812
+ statusJidList: uniqueUsers,
813
+ additionalNodes: [
814
+ {
815
+ tag: 'meta',
816
+ attrs: {},
817
+ content: [
818
+ {
819
+ tag: 'mentioned_users',
820
+ attrs: {},
821
+ content: jids.map(jid => ({
822
+ tag: 'to',
823
+ attrs: { jid: WABinary_1.jidNormalizedUser(jid) }
824
+ }))
825
+ }
826
+ ]
827
+ }
828
+ ]
829
+ });
830
+
831
+ for (const id of jids) {
832
+ try {
833
+ const normalizedId = WABinary_1.jidNormalizedUser(id);
834
+ const isPrivate = WABinary_1.isJidUser(normalizedId);
835
+ const type = isPrivate ? 'statusMentionMessage' : 'groupStatusMentionMessage';
836
+
837
+ const protocolMessage = {
838
+ [type]: {
839
+ message: {
840
+ protocolMessage: {
841
+ key: msg.key,
842
+ type: 25
843
+ }
844
+ }
845
+ },
846
+ messageContextInfo: {
847
+ messageSecret: crypto.randomBytes(32)
848
+ }
849
+ };
850
+
851
+ const statusMsg = await Utils_1.generateWAMessageFromContent(
852
+ normalizedId,
853
+ protocolMessage,
854
+ {}
855
+ );
856
+
857
+ await this.relayMessage(
858
+ normalizedId,
859
+ statusMsg.message,
860
+ {
861
+ additionalNodes: [{
862
+ tag: 'meta',
863
+ attrs: isPrivate ?
864
+ { is_status_mention: 'true' } :
865
+ { is_group_status_mention: 'true' }
866
+ }]
867
+ }
868
+ );
869
+
870
+ await Utils_1.delay(2000);
871
+ } catch (error) {
872
+ if (this.config.logger) {
873
+ this.config.logger.error(`Error sending status mention to ${id}: ${error}`);
874
+ }
875
+ }
876
+ }
877
+
878
+ return msg;
879
+ }
880
+ }
881
+
882
+ export default DinonicHandler;