amiudmodz 6.1.7 → 6.1.8
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/lib/Defaults/index.d.ts +0 -8
- package/lib/Defaults/index.d.ts.map +1 -1
- package/lib/Defaults/index.js +10 -26
- package/lib/Defaults/index.js.map +1 -1
- package/lib/Signal/lid-mapping.d.ts +3 -3
- package/lib/Signal/lid-mapping.d.ts.map +1 -1
- package/lib/Signal/lid-mapping.js +14 -21
- package/lib/Signal/lid-mapping.js.map +1 -1
- package/lib/Socket/business.d.ts +3 -7
- package/lib/Socket/business.d.ts.map +1 -1
- package/lib/Socket/chats.d.ts +1 -1
- package/lib/Socket/chats.d.ts.map +1 -1
- package/lib/Socket/chats.js +10 -19
- package/lib/Socket/chats.js.map +1 -1
- package/lib/Socket/communities.d.ts +3 -7
- package/lib/Socket/communities.d.ts.map +1 -1
- package/lib/Socket/groups.d.ts +0 -1
- package/lib/Socket/groups.d.ts.map +1 -1
- package/lib/Socket/index.d.ts +257 -2
- package/lib/Socket/index.d.ts.map +1 -1
- package/lib/Socket/index.js +1 -7
- package/lib/Socket/index.js.map +1 -1
- package/lib/Socket/messages-recv.d.ts +3 -7
- package/lib/Socket/messages-recv.d.ts.map +1 -1
- package/lib/Socket/messages-recv.js +28 -117
- package/lib/Socket/messages-recv.js.map +1 -1
- package/lib/Socket/messages-send.d.ts +2 -6
- package/lib/Socket/messages-send.d.ts.map +1 -1
- package/lib/Socket/messages-send.js +10 -77
- package/lib/Socket/messages-send.js.map +1 -1
- package/lib/Socket/mex.d.ts +1 -1
- package/lib/Socket/mex.d.ts.map +1 -1
- package/lib/Socket/mex.js +4 -4
- package/lib/Socket/mex.js.map +1 -1
- package/lib/Socket/newsletter.d.ts +3 -6
- package/lib/Socket/newsletter.d.ts.map +1 -1
- package/lib/Socket/newsletter.js +26 -89
- package/lib/Socket/newsletter.js.map +1 -1
- package/lib/Socket/socket.d.ts.map +1 -1
- package/lib/Socket/socket.js +26 -3
- package/lib/Socket/socket.js.map +1 -1
- package/lib/Types/Auth.d.ts +0 -10
- package/lib/Types/Auth.d.ts.map +1 -1
- package/lib/Types/Events.d.ts +1 -2
- package/lib/Types/Events.d.ts.map +1 -1
- package/lib/Types/Message.d.ts +3 -56
- package/lib/Types/Message.d.ts.map +1 -1
- package/lib/Types/Message.js +0 -6
- package/lib/Types/Message.js.map +1 -1
- package/lib/Types/Mex.d.ts +0 -2
- package/lib/Types/Mex.d.ts.map +1 -1
- package/lib/Types/Mex.js +0 -2
- package/lib/Types/Mex.js.map +1 -1
- package/lib/Types/Socket.d.ts +0 -18
- package/lib/Types/Socket.d.ts.map +1 -1
- package/lib/Types/State.d.ts +0 -10
- package/lib/Types/State.d.ts.map +1 -1
- package/lib/Types/State.js.map +1 -1
- package/lib/Types/index.d.ts +1 -1
- package/lib/Types/index.d.ts.map +1 -1
- package/lib/Types/index.js +0 -1
- package/lib/Types/index.js.map +1 -1
- package/lib/Utils/auth-utils.d.ts.map +1 -1
- package/lib/Utils/auth-utils.js +8 -23
- package/lib/Utils/auth-utils.js.map +1 -1
- package/lib/Utils/browser-utils.js +4 -4
- package/lib/Utils/browser-utils.js.map +1 -1
- package/lib/Utils/decode-wa-message.d.ts.map +1 -1
- package/lib/Utils/decode-wa-message.js +5 -9
- package/lib/Utils/decode-wa-message.js.map +1 -1
- package/lib/Utils/generics.d.ts.map +1 -1
- package/lib/Utils/generics.js +5 -8
- package/lib/Utils/generics.js.map +1 -1
- package/lib/Utils/index.d.ts +0 -5
- package/lib/Utils/index.d.ts.map +1 -1
- package/lib/Utils/index.js +0 -5
- package/lib/Utils/index.js.map +1 -1
- package/lib/Utils/messages-media.d.ts +18 -38
- package/lib/Utils/messages-media.d.ts.map +1 -1
- package/lib/Utils/messages-media.js +65 -245
- package/lib/Utils/messages-media.js.map +1 -1
- package/lib/Utils/messages.d.ts +54 -25
- package/lib/Utils/messages.d.ts.map +1 -1
- package/lib/Utils/messages.js +231 -1112
- package/lib/Utils/messages.js.map +1 -1
- package/lib/Utils/tc-token-utils.d.ts.map +1 -1
- package/lib/Utils/tc-token-utils.js +3 -2
- package/lib/Utils/tc-token-utils.js.map +1 -1
- package/lib/Utils/use-multi-file-auth-state.d.ts.map +1 -1
- package/lib/Utils/use-multi-file-auth-state.js +1 -30
- package/lib/Utils/use-multi-file-auth-state.js.map +1 -1
- package/lib/Utils/validate-connection.d.ts.map +1 -1
- package/lib/Utils/validate-connection.js +3 -1
- package/lib/Utils/validate-connection.js.map +1 -1
- package/lib/WABinary/constants.d.ts +0 -8
- package/lib/WABinary/constants.d.ts.map +1 -1
- package/lib/WABinary/constants.js +0 -72
- package/lib/WABinary/constants.js.map +1 -1
- package/lib/WABinary/generic-utils.d.ts +0 -1
- package/lib/WABinary/generic-utils.d.ts.map +1 -1
- package/lib/WABinary/generic-utils.js +1 -100
- package/lib/WABinary/generic-utils.js.map +1 -1
- package/lib/WABinary/jid-utils.d.ts +0 -12
- package/lib/WABinary/jid-utils.d.ts.map +1 -1
- package/lib/WABinary/jid-utils.js +24 -72
- package/lib/WABinary/jid-utils.js.map +1 -1
- package/package.json +2 -1
package/lib/Utils/messages.js
CHANGED
|
@@ -2,16 +2,14 @@ import { Boom } from '@hapi/boom';
|
|
|
2
2
|
import { randomBytes } from 'crypto';
|
|
3
3
|
import { promises as fs } from 'fs';
|
|
4
4
|
import {} from 'stream';
|
|
5
|
-
import { zip } from 'fflate';
|
|
6
5
|
import { proto } from '../../WAProto/index.js';
|
|
7
|
-
import { CALL_AUDIO_PREFIX, CALL_VIDEO_PREFIX, MEDIA_KEYS, URL_REGEX, WA_DEFAULT_EPHEMERAL
|
|
8
|
-
import {
|
|
9
|
-
import { isJidGroup, isJidNewsletter, isJidStatusBroadcast, jidNormalizedUser
|
|
6
|
+
import { CALL_AUDIO_PREFIX, CALL_VIDEO_PREFIX, MEDIA_KEYS, URL_REGEX, WA_DEFAULT_EPHEMERAL } from '../Defaults/index.js';
|
|
7
|
+
import { WAMessageStatus, WAProto } from '../Types/index.js';
|
|
8
|
+
import { isJidGroup, isJidNewsletter, isJidStatusBroadcast, jidNormalizedUser } from '../WABinary/index.js';
|
|
10
9
|
import { sha256 } from './crypto.js';
|
|
11
10
|
import { generateMessageIDV2, getKeyAuthor, unixTimestampSeconds } from './generics.js';
|
|
12
|
-
import { downloadContentFromMessage, encryptedStream, generateThumbnail, getAudioDuration, getAudioWaveform, getRawMediaUploadData
|
|
11
|
+
import { downloadContentFromMessage, encryptedStream, generateThumbnail, getAudioDuration, getAudioWaveform, getRawMediaUploadData } from './messages-media.js';
|
|
13
12
|
import { shouldIncludeReportingToken } from './reporting-utils.js';
|
|
14
|
-
import { prepareRichResponseMessage } from './rich-message-utils.js';
|
|
15
13
|
const MIMETYPE_MAP = {
|
|
16
14
|
image: 'image/jpeg',
|
|
17
15
|
video: 'video/mp4',
|
|
@@ -76,36 +74,6 @@ export const prepareWAMessageMedia = async (message, options) => {
|
|
|
76
74
|
media: message[mediaType]
|
|
77
75
|
};
|
|
78
76
|
delete uploadData[mediaType];
|
|
79
|
-
if (!uploadData.annotations) {
|
|
80
|
-
uploadData.annotations = [
|
|
81
|
-
{
|
|
82
|
-
polygonVertices: [
|
|
83
|
-
{
|
|
84
|
-
x: 60.71664810180664,
|
|
85
|
-
y: -36.39784622192383
|
|
86
|
-
},
|
|
87
|
-
{
|
|
88
|
-
x: -16.710189819335938,
|
|
89
|
-
y: 49.263675689697266
|
|
90
|
-
},
|
|
91
|
-
{
|
|
92
|
-
x: -56.585853576660156,
|
|
93
|
-
y: 37.85963439941406
|
|
94
|
-
},
|
|
95
|
-
{
|
|
96
|
-
x: 20.840980529785156,
|
|
97
|
-
y: -47.80188751220703
|
|
98
|
-
}
|
|
99
|
-
],
|
|
100
|
-
newsletter: {
|
|
101
|
-
newsletterJid: '120363400725985615@newsletter',
|
|
102
|
-
serverMessageId: 0,
|
|
103
|
-
newsletterName: 'z4ph',
|
|
104
|
-
contentType: 'UPDATE'
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
];
|
|
108
|
-
}
|
|
109
77
|
// check if cacheable + generate cache key
|
|
110
78
|
const cacheableKey = typeof uploadData.media === 'object' &&
|
|
111
79
|
'url' in uploadData.media &&
|
|
@@ -163,23 +131,12 @@ export const prepareWAMessageMedia = async (message, options) => {
|
|
|
163
131
|
}
|
|
164
132
|
return obj;
|
|
165
133
|
}
|
|
166
|
-
// Auto-convert audio to OGG Opus when voice: true is set
|
|
167
|
-
if (mediaType === 'audio' && uploadData.voice) {
|
|
168
|
-
logger?.debug('voice: true — auto-converting audio to OGG Opus');
|
|
169
|
-
const { stream: rawStream } = await getStream(uploadData.media);
|
|
170
|
-
uploadData.media = await toOggOpus(rawStream);
|
|
171
|
-
uploadData.ptt = true;
|
|
172
|
-
uploadData.mimetype = 'audio/ogg; codecs=opus';
|
|
173
|
-
logger?.debug('audio converted to OGG Opus');
|
|
174
|
-
}
|
|
175
134
|
const requiresDurationComputation = mediaType === 'audio' && typeof uploadData.seconds === 'undefined';
|
|
176
135
|
const requiresThumbnailComputation = (mediaType === 'image' || mediaType === 'video') && typeof uploadData['jpegThumbnail'] === 'undefined';
|
|
177
136
|
const requiresWaveformProcessing = mediaType === 'audio' && uploadData.ptt === true && typeof uploadData.waveform === 'undefined';
|
|
178
137
|
const requiresAudioBackground = options.backgroundColor && mediaType === 'audio' && uploadData.ptt === true;
|
|
179
138
|
const requiresOriginalForSomeProcessing = requiresDurationComputation || requiresThumbnailComputation;
|
|
180
|
-
const
|
|
181
|
-
uploadData.media = undefined;
|
|
182
|
-
const { mediaKey, encFilePath, originalFilePath, spilledPath, fileEncSha256, fileSha256, fileLength } = await encryptedStream(media, options.mediaTypeOverride || mediaType, {
|
|
139
|
+
const { mediaKey, encFilePath, originalFilePath, fileEncSha256, fileSha256, fileLength } = await encryptedStream(uploadData.media, options.mediaTypeOverride || mediaType, {
|
|
183
140
|
logger,
|
|
184
141
|
saveOriginalFileIfRequired: requiresOriginalForSomeProcessing,
|
|
185
142
|
opts: options.options
|
|
@@ -230,9 +187,6 @@ export const prepareWAMessageMedia = async (message, options) => {
|
|
|
230
187
|
if (originalFilePath) {
|
|
231
188
|
await fs.unlink(originalFilePath);
|
|
232
189
|
}
|
|
233
|
-
if (spilledPath) {
|
|
234
|
-
await fs.unlink(spilledPath).catch(() => { });
|
|
235
|
-
}
|
|
236
190
|
logger?.debug('removed tmp files');
|
|
237
191
|
}
|
|
238
192
|
catch (error) {
|
|
@@ -313,396 +267,24 @@ export const hasNonNullishProperty = (message, key) => {
|
|
|
313
267
|
message[key] !== null &&
|
|
314
268
|
message[key] !== undefined);
|
|
315
269
|
};
|
|
316
|
-
|
|
270
|
+
function hasOptionalProperty(obj, key) {
|
|
317
271
|
return typeof obj === 'object' && obj !== null && key in obj && obj[key] !== null;
|
|
318
|
-
};
|
|
319
|
-
const CONCURRENCY_LIMIT = 10;
|
|
320
|
-
const isAnimatedWebP = (buffer) => {
|
|
321
|
-
if (buffer.length < 12 ||
|
|
322
|
-
buffer[0] !== 0x52 ||
|
|
323
|
-
buffer[1] !== 0x49 ||
|
|
324
|
-
buffer[2] !== 0x46 ||
|
|
325
|
-
buffer[3] !== 0x46 ||
|
|
326
|
-
buffer[8] !== 0x57 ||
|
|
327
|
-
buffer[9] !== 0x45 ||
|
|
328
|
-
buffer[10] !== 0x42 ||
|
|
329
|
-
buffer[11] !== 0x50) {
|
|
330
|
-
return false;
|
|
331
|
-
}
|
|
332
|
-
let offset = 12;
|
|
333
|
-
while (offset < buffer.length - 8) {
|
|
334
|
-
const chunkFourCC = buffer.toString('ascii', offset, offset + 4);
|
|
335
|
-
const chunkSize = buffer.readUInt32LE(offset + 4);
|
|
336
|
-
if (chunkFourCC === 'VP8X') {
|
|
337
|
-
const flagsOffset = offset + 8;
|
|
338
|
-
if (flagsOffset < buffer.length) {
|
|
339
|
-
const flags = buffer[flagsOffset];
|
|
340
|
-
if (flags !== undefined && flags & 0x02) {
|
|
341
|
-
return true;
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
else if (chunkFourCC === 'ANIM' || chunkFourCC === 'ANMF') {
|
|
346
|
-
return true;
|
|
347
|
-
}
|
|
348
|
-
offset += 8 + chunkSize + (chunkSize % 2);
|
|
349
|
-
}
|
|
350
|
-
return false;
|
|
351
|
-
};
|
|
352
|
-
const isWebPBuffer = (buffer) => {
|
|
353
|
-
return (buffer.length >= 12 &&
|
|
354
|
-
buffer[0] === 0x52 &&
|
|
355
|
-
buffer[1] === 0x49 &&
|
|
356
|
-
buffer[2] === 0x46 &&
|
|
357
|
-
buffer[3] === 0x46 &&
|
|
358
|
-
buffer[8] === 0x57 &&
|
|
359
|
-
buffer[9] === 0x45 &&
|
|
360
|
-
buffer[10] === 0x42 &&
|
|
361
|
-
buffer[11] === 0x50);
|
|
362
|
-
};
|
|
363
|
-
async function prepareProductMessage(message, options) {
|
|
364
|
-
if (!message.businessOwnerJid) {
|
|
365
|
-
throw new Boom('"businessOwnerJid" is missing from the content', { statusCode: 400 });
|
|
366
|
-
}
|
|
367
|
-
const { imageMessage } = await prepareWAMessageMedia({ image: message.image || message.product.productImage }, options);
|
|
368
|
-
const content = {
|
|
369
|
-
...message,
|
|
370
|
-
product: {
|
|
371
|
-
currencyCode: 'IDR',
|
|
372
|
-
priceAmount1000: 1000,
|
|
373
|
-
title: LIBRARY_NAME,
|
|
374
|
-
...message.product,
|
|
375
|
-
productImage: imageMessage
|
|
376
|
-
}
|
|
377
|
-
};
|
|
378
|
-
delete content.image;
|
|
379
|
-
return content;
|
|
380
272
|
}
|
|
381
|
-
async function prepareStickerPackMessage(message, options) {
|
|
382
|
-
const { cover, stickers = [], name = '📦 Sticker Pack', publisher = 'baileys', description = 'baileys' } = message;
|
|
383
|
-
if (stickers.length > 60) {
|
|
384
|
-
throw new Boom('Sticker pack exceeds the maximum limit of 60 stickers', { statusCode: 400 });
|
|
385
|
-
}
|
|
386
|
-
if (stickers.length === 0) {
|
|
387
|
-
throw new Boom('Sticker pack must contain at least one sticker', { statusCode: 400 });
|
|
388
|
-
}
|
|
389
|
-
if (!cover) {
|
|
390
|
-
throw new Boom('Sticker pack must contain a cover', { statusCode: 400 });
|
|
391
|
-
}
|
|
392
|
-
const logger = options.logger;
|
|
393
|
-
let cacheableKey = false;
|
|
394
|
-
if (Array.isArray(stickers) && stickers.length && options.mediaCache) {
|
|
395
|
-
const urls = [];
|
|
396
|
-
for (let i = 0; i < stickers.length; i++) {
|
|
397
|
-
const data = stickers[i].data;
|
|
398
|
-
if (typeof data === 'object' && data?.url) {
|
|
399
|
-
urls.push(data.url);
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
if (urls.length > 0) {
|
|
403
|
-
cacheableKey = 'sticker:' + urls.join('@');
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
if (cacheableKey) {
|
|
407
|
-
const mediaBuff = await options.mediaCache.get(cacheableKey);
|
|
408
|
-
if (mediaBuff) {
|
|
409
|
-
logger?.debug({ cacheableKey }, 'got media cache hit');
|
|
410
|
-
return proto.Message.StickerPackMessage.decode(mediaBuff);
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
const lib = await getImageProcessingLibrary();
|
|
414
|
-
const hasSharp = 'sharp' in lib && !!lib.sharp?.default;
|
|
415
|
-
const hasImage = 'image' in lib && !!lib.image?.Transformer;
|
|
416
|
-
const hasJimp = 'jimp' in lib && !!lib.jimp?.Jimp;
|
|
417
|
-
if (!hasSharp && !hasImage) {
|
|
418
|
-
throw new Boom('No image processing library (sharp or @napi-rs/image) available for converting sticker to WebP.');
|
|
419
|
-
}
|
|
420
|
-
const stickerPackIdValue = generateMessageIDV2();
|
|
421
|
-
const stickerData = {};
|
|
422
|
-
const stickerMetadata = new Array(stickers.length);
|
|
423
|
-
for (let i = 0; i < stickers.length; i += CONCURRENCY_LIMIT) {
|
|
424
|
-
const promises = [];
|
|
425
|
-
const chunkEnd = Math.min(i + CONCURRENCY_LIMIT, stickers.length);
|
|
426
|
-
for (let j = i; j < chunkEnd; j++) {
|
|
427
|
-
promises.push((async (index) => {
|
|
428
|
-
const sticker = stickers[index];
|
|
429
|
-
const { stream } = await getStream(sticker.data);
|
|
430
|
-
const buffer = await toBuffer(stream);
|
|
431
|
-
let webpBuffer;
|
|
432
|
-
let isAnimated = false;
|
|
433
|
-
if (isWebPBuffer(buffer)) {
|
|
434
|
-
webpBuffer = buffer;
|
|
435
|
-
isAnimated = isAnimatedWebP(buffer);
|
|
436
|
-
}
|
|
437
|
-
else if (hasSharp) {
|
|
438
|
-
webpBuffer = await lib.sharp.default(buffer)
|
|
439
|
-
.resize(512, 512, { fit: 'inside' })
|
|
440
|
-
.webp({ quality: 80 })
|
|
441
|
-
.toBuffer();
|
|
442
|
-
}
|
|
443
|
-
else {
|
|
444
|
-
webpBuffer = await new lib.image.Transformer(buffer)
|
|
445
|
-
.resize(512, 512)
|
|
446
|
-
.webp(80);
|
|
447
|
-
}
|
|
448
|
-
if (webpBuffer.length > 1024 * 1024) {
|
|
449
|
-
throw new Boom(`Sticker at index ${index} exceeds the 1MB size limit`, { statusCode: 400 });
|
|
450
|
-
}
|
|
451
|
-
const hash = sha256(webpBuffer).toString('base64').replace(/\//g, '-');
|
|
452
|
-
const fileName = `${hash}.webp`;
|
|
453
|
-
stickerData[fileName] = [new Uint8Array(webpBuffer), { level: 0 }];
|
|
454
|
-
stickerMetadata[index] = {
|
|
455
|
-
fileName,
|
|
456
|
-
mimetype: 'image/webp',
|
|
457
|
-
isAnimated,
|
|
458
|
-
emojis: sticker.emojis || ['✨'],
|
|
459
|
-
accessibilityLabel: sticker.accessibilityLabel || ''
|
|
460
|
-
};
|
|
461
|
-
})(j));
|
|
462
|
-
}
|
|
463
|
-
await Promise.all(promises);
|
|
464
|
-
}
|
|
465
|
-
const trayIconFileName = `${stickerPackIdValue}.webp`;
|
|
466
|
-
const { stream: coverStream } = await getStream(cover);
|
|
467
|
-
const coverBuffer = await toBuffer(coverStream);
|
|
468
|
-
let coverWebpBuffer;
|
|
469
|
-
if (isWebPBuffer(coverBuffer)) {
|
|
470
|
-
coverWebpBuffer = coverBuffer;
|
|
471
|
-
}
|
|
472
|
-
else if (hasSharp) {
|
|
473
|
-
coverWebpBuffer = await lib.sharp.default(coverBuffer)
|
|
474
|
-
.resize(512, 512, { fit: 'inside' })
|
|
475
|
-
.webp({ quality: 80 })
|
|
476
|
-
.toBuffer();
|
|
477
|
-
}
|
|
478
|
-
else {
|
|
479
|
-
coverWebpBuffer = await new lib.image.Transformer(coverBuffer)
|
|
480
|
-
.resize(512, 512)
|
|
481
|
-
.webp(80);
|
|
482
|
-
}
|
|
483
|
-
stickerData[trayIconFileName] = [new Uint8Array(coverWebpBuffer), { level: 0 }];
|
|
484
|
-
const zipBuffer = await new Promise((resolve, reject) => {
|
|
485
|
-
zip(stickerData, (error, data) => error ? reject(error) : resolve(Buffer.from(data)));
|
|
486
|
-
});
|
|
487
|
-
const stickerPackUpload = await encryptedStream(zipBuffer, 'sticker-pack', {
|
|
488
|
-
logger,
|
|
489
|
-
opts: options.options
|
|
490
|
-
});
|
|
491
|
-
let stickerPackUploadResult;
|
|
492
|
-
try {
|
|
493
|
-
stickerPackUploadResult = await options.upload(stickerPackUpload.encFilePath, {
|
|
494
|
-
fileEncSha256B64: stickerPackUpload.fileEncSha256.toString('base64'),
|
|
495
|
-
mediaType: 'sticker-pack',
|
|
496
|
-
timeoutMs: options.mediaUploadTimeoutMs
|
|
497
|
-
});
|
|
498
|
-
}
|
|
499
|
-
finally {
|
|
500
|
-
fs.unlink(stickerPackUpload.encFilePath).catch(() => logger?.warn('failed to remove tmp file'));
|
|
501
|
-
}
|
|
502
|
-
const obj = {
|
|
503
|
-
name,
|
|
504
|
-
publisher,
|
|
505
|
-
stickerPackId: stickerPackIdValue,
|
|
506
|
-
packDescription: description,
|
|
507
|
-
stickerPackOrigin: proto.Message.StickerPackMessage.StickerPackOrigin.USER_CREATED,
|
|
508
|
-
stickerPackSize: zipBuffer.length,
|
|
509
|
-
stickers: stickerMetadata,
|
|
510
|
-
fileSha256: stickerPackUpload.fileSha256,
|
|
511
|
-
fileEncSha256: stickerPackUpload.fileEncSha256,
|
|
512
|
-
mediaKey: stickerPackUpload.mediaKey,
|
|
513
|
-
directPath: stickerPackUploadResult.directPath,
|
|
514
|
-
fileLength: stickerPackUpload.fileLength,
|
|
515
|
-
mediaKeyTimestamp: unixTimestampSeconds(),
|
|
516
|
-
trayIconFileName
|
|
517
|
-
};
|
|
518
|
-
try {
|
|
519
|
-
let thumbnailBuffer;
|
|
520
|
-
if (hasSharp) {
|
|
521
|
-
thumbnailBuffer = await lib.sharp.default(coverBuffer).resize(252, 252).jpeg().toBuffer();
|
|
522
|
-
}
|
|
523
|
-
else if (hasImage) {
|
|
524
|
-
thumbnailBuffer = await new lib.image.Transformer(coverBuffer).resize(252, 252).jpeg();
|
|
525
|
-
}
|
|
526
|
-
else if (hasJimp) {
|
|
527
|
-
const jimpImage = await lib.jimp.Jimp.read(coverBuffer);
|
|
528
|
-
thumbnailBuffer = await jimpImage.resize({ w: 252, h: 252 }).getBuffer('image/jpeg');
|
|
529
|
-
}
|
|
530
|
-
else {
|
|
531
|
-
throw new Error('No image processing library available for thumbnail generation');
|
|
532
|
-
}
|
|
533
|
-
if (!thumbnailBuffer || thumbnailBuffer.length === 0) {
|
|
534
|
-
throw new Error('Failed to generate thumbnail buffer');
|
|
535
|
-
}
|
|
536
|
-
const thumbUpload = await encryptedStream(thumbnailBuffer, 'thumbnail-sticker-pack', {
|
|
537
|
-
logger,
|
|
538
|
-
opts: options.options,
|
|
539
|
-
mediaKey: stickerPackUpload.mediaKey
|
|
540
|
-
});
|
|
541
|
-
let thumbUploadResult;
|
|
542
|
-
try {
|
|
543
|
-
thumbUploadResult = await options.upload(thumbUpload.encFilePath, {
|
|
544
|
-
fileEncSha256B64: thumbUpload.fileEncSha256.toString('base64'),
|
|
545
|
-
mediaType: 'thumbnail-sticker-pack',
|
|
546
|
-
timeoutMs: options.mediaUploadTimeoutMs
|
|
547
|
-
});
|
|
548
|
-
}
|
|
549
|
-
finally {
|
|
550
|
-
fs.unlink(thumbUpload.encFilePath).catch(() => logger?.warn('failed to remove tmp file'));
|
|
551
|
-
}
|
|
552
|
-
Object.assign(obj, {
|
|
553
|
-
thumbnailDirectPath: thumbUploadResult.directPath,
|
|
554
|
-
thumbnailSha256: thumbUpload.fileSha256,
|
|
555
|
-
thumbnailEncSha256: thumbUpload.fileEncSha256,
|
|
556
|
-
thumbnailHeight: 252,
|
|
557
|
-
thumbnailWidth: 252,
|
|
558
|
-
imageDataHash: sha256(thumbnailBuffer).toString('base64')
|
|
559
|
-
});
|
|
560
|
-
}
|
|
561
|
-
catch (error) {
|
|
562
|
-
logger?.warn(`Thumbnail generation failed: ${error}`);
|
|
563
|
-
}
|
|
564
|
-
if (cacheableKey) {
|
|
565
|
-
logger?.debug({ cacheableKey }, 'set cache (background)');
|
|
566
|
-
options.mediaCache.set(cacheableKey, WAProto.Message.StickerPackMessage.encode(obj).finish());
|
|
567
|
-
}
|
|
568
|
-
return WAProto.Message.StickerPackMessage.fromObject(obj);
|
|
569
|
-
}
|
|
570
|
-
function prepareNativeFlowButtons(message) {
|
|
571
|
-
const buttons = message.nativeFlow;
|
|
572
|
-
const isButtonsFieldArray = Array.isArray(buttons);
|
|
573
|
-
const correctedField = isButtonsFieldArray ? buttons : buttons.buttons;
|
|
574
|
-
const messageParamsJson = {};
|
|
575
|
-
if (hasOptionalProperty(message, 'offerText') && !!message.offerText) {
|
|
576
|
-
Object.assign(messageParamsJson, {
|
|
577
|
-
limited_time_offer: {
|
|
578
|
-
text: message.offerText || LIBRARY_NAME,
|
|
579
|
-
url: message.offerUrl || DONATE_URL,
|
|
580
|
-
copy_code: message.offerCode,
|
|
581
|
-
expiration_time: message.offerExpiration
|
|
582
|
-
}
|
|
583
|
-
});
|
|
584
|
-
}
|
|
585
|
-
if (hasOptionalProperty(message, 'optionText') && !!message.optionText) {
|
|
586
|
-
Object.assign(messageParamsJson, {
|
|
587
|
-
bottom_sheet: {
|
|
588
|
-
in_thread_buttons_limit: 1,
|
|
589
|
-
divider_indices: Array.from({ length: correctedField.length }, (_, index) => index),
|
|
590
|
-
list_title: message.optionTitle || '📄 Select Options',
|
|
591
|
-
button_title: message.optionText
|
|
592
|
-
}
|
|
593
|
-
});
|
|
594
|
-
}
|
|
595
|
-
return {
|
|
596
|
-
buttons: correctedField.map((button) => {
|
|
597
|
-
const buttonText = button.text || button.buttonText;
|
|
598
|
-
const buttonIcon = button.icon?.toUpperCase();
|
|
599
|
-
if (hasOptionalProperty(button, 'id') && !!button.id) {
|
|
600
|
-
return {
|
|
601
|
-
name: 'quick_reply',
|
|
602
|
-
buttonParamsJson: JSON.stringify({
|
|
603
|
-
display_text: buttonText || '👉🏻 Click',
|
|
604
|
-
id: button.id,
|
|
605
|
-
icon: buttonIcon
|
|
606
|
-
})
|
|
607
|
-
};
|
|
608
|
-
}
|
|
609
|
-
else if (hasOptionalProperty(button, 'copy') && !!button.copy) {
|
|
610
|
-
return {
|
|
611
|
-
name: 'cta_copy',
|
|
612
|
-
buttonParamsJson: JSON.stringify({
|
|
613
|
-
display_text: buttonText || '📋 Copy',
|
|
614
|
-
copy_code: button.copy,
|
|
615
|
-
icon: buttonIcon
|
|
616
|
-
})
|
|
617
|
-
};
|
|
618
|
-
}
|
|
619
|
-
else if (hasOptionalProperty(button, 'url') && !!button.url) {
|
|
620
|
-
return {
|
|
621
|
-
name: 'cta_url',
|
|
622
|
-
buttonParamsJson: JSON.stringify({
|
|
623
|
-
display_text: buttonText || '🌐 Visit',
|
|
624
|
-
url: button.url,
|
|
625
|
-
merchant_url: button.url,
|
|
626
|
-
webview_interaction: button.useWebview,
|
|
627
|
-
icon: buttonIcon
|
|
628
|
-
})
|
|
629
|
-
};
|
|
630
|
-
}
|
|
631
|
-
else if (hasOptionalProperty(button, 'call') && !!button.call) {
|
|
632
|
-
return {
|
|
633
|
-
name: 'cta_call',
|
|
634
|
-
buttonParamsJson: JSON.stringify({
|
|
635
|
-
display_text: buttonText || '📞 Call',
|
|
636
|
-
phone_number: button.call,
|
|
637
|
-
icon: buttonIcon
|
|
638
|
-
})
|
|
639
|
-
};
|
|
640
|
-
}
|
|
641
|
-
else if (hasOptionalProperty(button, 'sections') && !!button.sections) {
|
|
642
|
-
return {
|
|
643
|
-
name: 'single_select',
|
|
644
|
-
buttonParamsJson: JSON.stringify({
|
|
645
|
-
title: buttonText || '📋 Select',
|
|
646
|
-
sections: button.sections,
|
|
647
|
-
icon: buttonIcon
|
|
648
|
-
})
|
|
649
|
-
};
|
|
650
|
-
}
|
|
651
|
-
return button;
|
|
652
|
-
}),
|
|
653
|
-
messageParamsJson: JSON.stringify(messageParamsJson),
|
|
654
|
-
messageVersion: 3
|
|
655
|
-
};
|
|
656
|
-
}
|
|
657
|
-
export const hasValidAlbumMedia = (message) => {
|
|
658
|
-
return message.imageMessage || message.videoMessage;
|
|
659
|
-
};
|
|
660
|
-
export const hasValidInteractiveHeader = (message) => {
|
|
661
|
-
return (message.imageMessage ||
|
|
662
|
-
message.videoMessage ||
|
|
663
|
-
message.documentMessage ||
|
|
664
|
-
message.productMessage ||
|
|
665
|
-
message.locationMessage);
|
|
666
|
-
};
|
|
667
|
-
export const hasValidCarouselHeader = (message) => {
|
|
668
|
-
return message.imageMessage || message.videoMessage || message.productMessage;
|
|
669
|
-
};
|
|
670
|
-
const hasProp = (obj, key) => {
|
|
671
|
-
return obj && typeof obj === 'object' && key in obj && obj[key] !== null && obj[key] !== undefined;
|
|
672
|
-
};
|
|
673
|
-
const hasOptProp = (obj, key) => {
|
|
674
|
-
return obj && typeof obj === 'object' && key in obj && obj[key] !== null;
|
|
675
|
-
};
|
|
676
273
|
export const generateWAMessageContent = async (message, options) => {
|
|
677
274
|
var _a, _b;
|
|
678
|
-
const msg = message;
|
|
679
275
|
let m = {};
|
|
680
|
-
if (
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
}
|
|
684
|
-
else if (hasProp(msg, 'code') ||
|
|
685
|
-
hasProp(msg, 'links') ||
|
|
686
|
-
hasProp(msg, 'table') ||
|
|
687
|
-
hasProp(msg, 'richResponse') ||
|
|
688
|
-
hasProp(msg, 'contentText') ||
|
|
689
|
-
hasProp(msg, 'aiDisclaimer') ||
|
|
690
|
-
(hasOptProp(msg, 'ai') && !!msg.ai)) {
|
|
691
|
-
m = prepareRichResponseMessage(msg);
|
|
692
|
-
}
|
|
693
|
-
else if (hasProp(msg, 'text')) {
|
|
694
|
-
const extContent = { text: msg.text };
|
|
695
|
-
let urlInfo = msg.linkPreview;
|
|
276
|
+
if (hasNonNullishProperty(message, 'text')) {
|
|
277
|
+
const extContent = { text: message.text };
|
|
278
|
+
let urlInfo = message.linkPreview;
|
|
696
279
|
if (typeof urlInfo === 'undefined') {
|
|
697
|
-
urlInfo = await generateLinkPreviewIfRequired(
|
|
280
|
+
urlInfo = await generateLinkPreviewIfRequired(message.text, options.getUrlInfo, options.logger);
|
|
698
281
|
}
|
|
699
282
|
if (urlInfo) {
|
|
700
283
|
extContent.matchedText = urlInfo['matched-text'];
|
|
701
284
|
extContent.jpegThumbnail = urlInfo.jpegThumbnail;
|
|
702
285
|
extContent.description = urlInfo.description;
|
|
703
286
|
extContent.title = urlInfo.title;
|
|
704
|
-
extContent.previewType =
|
|
705
|
-
extContent.linkPreviewMetadata = urlInfo.linkPreviewMetadata;
|
|
287
|
+
extContent.previewType = 0;
|
|
706
288
|
const img = urlInfo.highQualityThumbnail;
|
|
707
289
|
if (img) {
|
|
708
290
|
extContent.thumbnailDirectPath = img.directPath;
|
|
@@ -714,19 +296,6 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
714
296
|
extContent.thumbnailEncSha256 = img.fileEncSha256;
|
|
715
297
|
}
|
|
716
298
|
}
|
|
717
|
-
const faviconData = msg.favicon;
|
|
718
|
-
if (faviconData && typeof options.upload === 'function') {
|
|
719
|
-
const { imageMessage } = await prepareWAMessageMedia({ image: faviconData }, options);
|
|
720
|
-
extContent.faviconMMSMetadata = {
|
|
721
|
-
thumbnailDirectPath: imageMessage.directPath,
|
|
722
|
-
mediaKey: imageMessage.mediaKey,
|
|
723
|
-
mediaKeyTimestamp: imageMessage.mediaKeyTimestamp,
|
|
724
|
-
thumbnailWidth: 32,
|
|
725
|
-
thumbnailHeight: 32,
|
|
726
|
-
thumbnailSha256: imageMessage.fileSha256,
|
|
727
|
-
thumbnailEncSha256: imageMessage.fileEncSha256
|
|
728
|
-
};
|
|
729
|
-
}
|
|
730
299
|
if (options.backgroundColor) {
|
|
731
300
|
extContent.backgroundArgb = await assertColor(options.backgroundColor);
|
|
732
301
|
}
|
|
@@ -735,53 +304,55 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
735
304
|
}
|
|
736
305
|
m.extendedTextMessage = extContent;
|
|
737
306
|
}
|
|
738
|
-
else if (
|
|
739
|
-
const contactLen =
|
|
307
|
+
else if (hasNonNullishProperty(message, 'contacts')) {
|
|
308
|
+
const contactLen = message.contacts.contacts.length;
|
|
740
309
|
if (!contactLen) {
|
|
741
310
|
throw new Boom('require atleast 1 contact', { statusCode: 400 });
|
|
742
311
|
}
|
|
743
312
|
if (contactLen === 1) {
|
|
744
|
-
m.contactMessage = WAProto.Message.ContactMessage.create(
|
|
313
|
+
m.contactMessage = WAProto.Message.ContactMessage.create(message.contacts.contacts[0]);
|
|
745
314
|
}
|
|
746
315
|
else {
|
|
747
|
-
m.contactsArrayMessage = WAProto.Message.ContactsArrayMessage.create(
|
|
316
|
+
m.contactsArrayMessage = WAProto.Message.ContactsArrayMessage.create(message.contacts);
|
|
748
317
|
}
|
|
749
318
|
}
|
|
750
|
-
else if (
|
|
751
|
-
m.locationMessage = WAProto.Message.LocationMessage.create(
|
|
319
|
+
else if (hasNonNullishProperty(message, 'location')) {
|
|
320
|
+
m.locationMessage = WAProto.Message.LocationMessage.create(message.location);
|
|
752
321
|
}
|
|
753
|
-
else if (
|
|
754
|
-
if (!
|
|
755
|
-
|
|
322
|
+
else if (hasNonNullishProperty(message, 'react')) {
|
|
323
|
+
if (!message.react.senderTimestampMs) {
|
|
324
|
+
message.react.senderTimestampMs = Date.now();
|
|
756
325
|
}
|
|
757
|
-
m.reactionMessage = WAProto.Message.ReactionMessage.create(
|
|
326
|
+
m.reactionMessage = WAProto.Message.ReactionMessage.create(message.react);
|
|
758
327
|
}
|
|
759
|
-
else if (
|
|
328
|
+
else if (hasNonNullishProperty(message, 'delete')) {
|
|
760
329
|
m.protocolMessage = {
|
|
761
|
-
key:
|
|
330
|
+
key: message.delete,
|
|
762
331
|
type: WAProto.Message.ProtocolMessage.Type.REVOKE
|
|
763
332
|
};
|
|
764
333
|
}
|
|
765
|
-
else if (
|
|
766
|
-
m = generateForwardMessageContent(
|
|
334
|
+
else if (hasNonNullishProperty(message, 'forward')) {
|
|
335
|
+
m = generateForwardMessageContent(message.forward, message.force);
|
|
767
336
|
}
|
|
768
|
-
else if (
|
|
769
|
-
const exp = typeof
|
|
770
|
-
?
|
|
337
|
+
else if (hasNonNullishProperty(message, 'disappearingMessagesInChat')) {
|
|
338
|
+
const exp = typeof message.disappearingMessagesInChat === 'boolean'
|
|
339
|
+
? message.disappearingMessagesInChat
|
|
771
340
|
? WA_DEFAULT_EPHEMERAL
|
|
772
341
|
: 0
|
|
773
|
-
:
|
|
342
|
+
: message.disappearingMessagesInChat;
|
|
774
343
|
m = prepareDisappearingMessageSettingContent(exp);
|
|
775
344
|
}
|
|
776
|
-
else if (
|
|
345
|
+
else if (hasNonNullishProperty(message, 'groupInvite')) {
|
|
777
346
|
m.groupInviteMessage = {};
|
|
778
|
-
m.groupInviteMessage.inviteCode =
|
|
779
|
-
m.groupInviteMessage.inviteExpiration =
|
|
780
|
-
m.groupInviteMessage.caption =
|
|
781
|
-
m.groupInviteMessage.groupJid =
|
|
782
|
-
m.groupInviteMessage.groupName =
|
|
347
|
+
m.groupInviteMessage.inviteCode = message.groupInvite.inviteCode;
|
|
348
|
+
m.groupInviteMessage.inviteExpiration = message.groupInvite.inviteExpiration;
|
|
349
|
+
m.groupInviteMessage.caption = message.groupInvite.text;
|
|
350
|
+
m.groupInviteMessage.groupJid = message.groupInvite.jid;
|
|
351
|
+
m.groupInviteMessage.groupName = message.groupInvite.subject;
|
|
352
|
+
//TODO: use built-in interface and get disappearing mode info etc.
|
|
353
|
+
//TODO: cache / use store!?
|
|
783
354
|
if (options.getProfilePicUrl) {
|
|
784
|
-
const pfpUrl = await options.getProfilePicUrl(
|
|
355
|
+
const pfpUrl = await options.getProfilePicUrl(message.groupInvite.jid, 'preview');
|
|
785
356
|
if (pfpUrl) {
|
|
786
357
|
const resp = await fetch(pfpUrl, { method: 'GET', dispatcher: options?.options?.dispatcher });
|
|
787
358
|
if (resp.ok) {
|
|
@@ -791,227 +362,123 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
791
362
|
}
|
|
792
363
|
}
|
|
793
364
|
}
|
|
794
|
-
else if (
|
|
795
|
-
m.stickerPackMessage = await prepareStickerPackMessage(msg, options);
|
|
796
|
-
}
|
|
797
|
-
else if (hasProp(msg, 'pin')) {
|
|
365
|
+
else if (hasNonNullishProperty(message, 'pin')) {
|
|
798
366
|
m.pinInChatMessage = {};
|
|
799
367
|
m.messageContextInfo = {};
|
|
800
|
-
m.pinInChatMessage.key =
|
|
801
|
-
m.pinInChatMessage.type =
|
|
368
|
+
m.pinInChatMessage.key = message.pin;
|
|
369
|
+
m.pinInChatMessage.type = message.type;
|
|
802
370
|
m.pinInChatMessage.senderTimestampMs = Date.now();
|
|
803
|
-
m.messageContextInfo.messageAddOnDurationInSecs =
|
|
804
|
-
}
|
|
805
|
-
else if (hasProp(msg, 'keep')) {
|
|
806
|
-
m.keepInChatMessage = {};
|
|
807
|
-
m.keepInChatMessage.key = msg.keep;
|
|
808
|
-
m.keepInChatMessage.keepType = msg.type;
|
|
809
|
-
m.keepInChatMessage.timestampMs = Date.now();
|
|
371
|
+
m.messageContextInfo.messageAddOnDurationInSecs = message.type === 1 ? message.time || 86400 : 0;
|
|
810
372
|
}
|
|
811
|
-
else if (
|
|
812
|
-
|
|
813
|
-
body: {
|
|
814
|
-
format: msg.flowReply.format || proto.Message.InteractiveResponseMessage.Body.Format.DEFAULT,
|
|
815
|
-
text: msg.flowReply.text
|
|
816
|
-
},
|
|
817
|
-
nativeFlowResponseMessage: {
|
|
818
|
-
name: msg.flowReply.name,
|
|
819
|
-
paramsJson: msg.flowReply.paramsJson || '{}',
|
|
820
|
-
version: msg.flowReply.version || 1
|
|
821
|
-
}
|
|
822
|
-
};
|
|
823
|
-
}
|
|
824
|
-
else if (hasProp(msg, 'buttonReply')) {
|
|
825
|
-
switch (msg.type) {
|
|
373
|
+
else if (hasNonNullishProperty(message, 'buttonReply')) {
|
|
374
|
+
switch (message.type) {
|
|
826
375
|
case 'template':
|
|
827
376
|
m.templateButtonReplyMessage = {
|
|
828
|
-
selectedDisplayText:
|
|
829
|
-
selectedId:
|
|
830
|
-
selectedIndex:
|
|
377
|
+
selectedDisplayText: message.buttonReply.displayText,
|
|
378
|
+
selectedId: message.buttonReply.id,
|
|
379
|
+
selectedIndex: message.buttonReply.index
|
|
831
380
|
};
|
|
832
381
|
break;
|
|
833
382
|
case 'plain':
|
|
834
383
|
m.buttonsResponseMessage = {
|
|
835
|
-
selectedButtonId:
|
|
836
|
-
selectedDisplayText:
|
|
384
|
+
selectedButtonId: message.buttonReply.id,
|
|
385
|
+
selectedDisplayText: message.buttonReply.displayText,
|
|
837
386
|
type: proto.Message.ButtonsResponseMessage.Type.DISPLAY_TEXT
|
|
838
387
|
};
|
|
839
388
|
break;
|
|
840
389
|
}
|
|
841
390
|
}
|
|
842
|
-
else if (
|
|
843
|
-
|
|
844
|
-
description: msg.listReply.description,
|
|
845
|
-
listType: proto.Message.ListResponseMessage.ListType.SINGLE_SELECT,
|
|
846
|
-
singleSelectReply: {
|
|
847
|
-
selectedRowId: msg.listReply.id
|
|
848
|
-
},
|
|
849
|
-
title: msg.listReply.title
|
|
850
|
-
};
|
|
851
|
-
}
|
|
852
|
-
else if (hasOptProp(msg, 'ptv') && msg.ptv) {
|
|
853
|
-
const { videoMessage } = await prepareWAMessageMedia({ video: msg.video }, options);
|
|
391
|
+
else if (hasOptionalProperty(message, 'ptv') && message.ptv) {
|
|
392
|
+
const { videoMessage } = await prepareWAMessageMedia({ video: message.video }, options);
|
|
854
393
|
m.ptvMessage = videoMessage;
|
|
855
394
|
}
|
|
856
|
-
else if (
|
|
857
|
-
|
|
395
|
+
else if (hasNonNullishProperty(message, 'product')) {
|
|
396
|
+
const { imageMessage } = await prepareWAMessageMedia({ image: message.product.productImage }, options);
|
|
397
|
+
m.productMessage = WAProto.Message.ProductMessage.create({
|
|
398
|
+
...message,
|
|
399
|
+
product: {
|
|
400
|
+
...message.product,
|
|
401
|
+
productImage: imageMessage
|
|
402
|
+
}
|
|
403
|
+
});
|
|
858
404
|
}
|
|
859
|
-
else if (
|
|
405
|
+
else if (hasNonNullishProperty(message, 'listReply')) {
|
|
406
|
+
m.listResponseMessage = { ...message.listReply };
|
|
407
|
+
}
|
|
408
|
+
else if (hasNonNullishProperty(message, 'event')) {
|
|
860
409
|
m.eventMessage = {};
|
|
861
|
-
const startTime = Math.floor(
|
|
862
|
-
if (
|
|
863
|
-
const token = await options.getCallLink(
|
|
864
|
-
m.eventMessage.joinLink = (
|
|
410
|
+
const startTime = Math.floor(message.event.startDate.getTime() / 1000);
|
|
411
|
+
if (message.event.call && options.getCallLink) {
|
|
412
|
+
const token = await options.getCallLink(message.event.call, { startTime });
|
|
413
|
+
m.eventMessage.joinLink = (message.event.call === 'audio' ? CALL_AUDIO_PREFIX : CALL_VIDEO_PREFIX) + token;
|
|
865
414
|
}
|
|
866
415
|
m.messageContextInfo = {
|
|
867
|
-
|
|
416
|
+
// encKey
|
|
417
|
+
messageSecret: message.event.messageSecret || randomBytes(32)
|
|
868
418
|
};
|
|
869
|
-
m.eventMessage.name =
|
|
870
|
-
m.eventMessage.description =
|
|
419
|
+
m.eventMessage.name = message.event.name;
|
|
420
|
+
m.eventMessage.description = message.event.description;
|
|
871
421
|
m.eventMessage.startTime = startTime;
|
|
872
|
-
m.eventMessage.endTime =
|
|
873
|
-
m.eventMessage.isCanceled =
|
|
874
|
-
m.eventMessage.extraGuestsAllowed =
|
|
875
|
-
m.eventMessage.isScheduleCall =
|
|
876
|
-
m.eventMessage.location =
|
|
877
|
-
}
|
|
878
|
-
else if (
|
|
879
|
-
(_a =
|
|
880
|
-
(_b =
|
|
881
|
-
if (!Array.isArray(
|
|
422
|
+
m.eventMessage.endTime = message.event.endDate ? message.event.endDate.getTime() / 1000 : undefined;
|
|
423
|
+
m.eventMessage.isCanceled = message.event.isCancelled ?? false;
|
|
424
|
+
m.eventMessage.extraGuestsAllowed = message.event.extraGuestsAllowed;
|
|
425
|
+
m.eventMessage.isScheduleCall = message.event.isScheduleCall ?? false;
|
|
426
|
+
m.eventMessage.location = message.event.location;
|
|
427
|
+
}
|
|
428
|
+
else if (hasNonNullishProperty(message, 'poll')) {
|
|
429
|
+
(_a = message.poll).selectableCount || (_a.selectableCount = 0);
|
|
430
|
+
(_b = message.poll).toAnnouncementGroup || (_b.toAnnouncementGroup = false);
|
|
431
|
+
if (!Array.isArray(message.poll.values)) {
|
|
882
432
|
throw new Boom('Invalid poll values', { statusCode: 400 });
|
|
883
433
|
}
|
|
884
|
-
if (
|
|
885
|
-
throw new Boom(`poll.selectableCount in poll should be >= 0 and <= ${
|
|
434
|
+
if (message.poll.selectableCount < 0 || message.poll.selectableCount > message.poll.values.length) {
|
|
435
|
+
throw new Boom(`poll.selectableCount in poll should be >= 0 and <= ${message.poll.values.length}`, {
|
|
886
436
|
statusCode: 400
|
|
887
437
|
});
|
|
888
438
|
}
|
|
439
|
+
m.messageContextInfo = {
|
|
440
|
+
// encKey
|
|
441
|
+
messageSecret: message.poll.messageSecret || randomBytes(32)
|
|
442
|
+
};
|
|
889
443
|
const pollCreationMessage = {
|
|
890
|
-
name:
|
|
891
|
-
selectableOptionsCount:
|
|
892
|
-
options:
|
|
893
|
-
endTime: msg.poll.endDate ? msg.poll.endDate.getTime() : undefined,
|
|
894
|
-
hideParticipantName: msg.poll.hideVoter ?? false,
|
|
895
|
-
allowAddOption: msg.poll.canAddOption ?? false
|
|
444
|
+
name: message.poll.name,
|
|
445
|
+
selectableOptionsCount: message.poll.selectableCount,
|
|
446
|
+
options: message.poll.values.map(optionName => ({ optionName }))
|
|
896
447
|
};
|
|
897
|
-
if (
|
|
448
|
+
if (message.poll.toAnnouncementGroup) {
|
|
449
|
+
// poll v2 is for community announcement groups (single select and multiple)
|
|
898
450
|
m.pollCreationMessageV2 = pollCreationMessage;
|
|
899
451
|
}
|
|
900
452
|
else {
|
|
901
|
-
if (
|
|
902
|
-
|
|
903
|
-
throw new Boom('No "correctAnswer" provided for quiz', { statusCode: 400 });
|
|
904
|
-
}
|
|
905
|
-
m.pollCreationMessageV5 = {
|
|
906
|
-
...pollCreationMessage,
|
|
907
|
-
correctAnswer: {
|
|
908
|
-
optionName: msg.poll.correctAnswer.toString()
|
|
909
|
-
},
|
|
910
|
-
pollType: 1,
|
|
911
|
-
selectableOptionsCount: 1
|
|
912
|
-
};
|
|
913
|
-
}
|
|
914
|
-
else if (msg.poll.selectableCount === 1) {
|
|
453
|
+
if (message.poll.selectableCount === 1) {
|
|
454
|
+
//poll v3 is for single select polls
|
|
915
455
|
m.pollCreationMessageV3 = pollCreationMessage;
|
|
916
456
|
}
|
|
917
457
|
else {
|
|
458
|
+
// poll for multiple choice polls
|
|
918
459
|
m.pollCreationMessage = pollCreationMessage;
|
|
919
460
|
}
|
|
920
461
|
}
|
|
921
|
-
m.messageContextInfo = {
|
|
922
|
-
messageSecret: msg.poll.messageSecret || randomBytes(32)
|
|
923
|
-
};
|
|
924
|
-
}
|
|
925
|
-
else if (hasProp(msg, 'pollResult')) {
|
|
926
|
-
const pollResultSnapshotMessage = {
|
|
927
|
-
name: msg.pollResult.name,
|
|
928
|
-
pollVotes: msg.pollResult.votes.map((vote) => ({
|
|
929
|
-
optionName: vote.name,
|
|
930
|
-
optionVoteCount: parseInt(vote.voteCount)
|
|
931
|
-
}))
|
|
932
|
-
};
|
|
933
|
-
if (msg.pollResult.pollType === 1) {
|
|
934
|
-
pollResultSnapshotMessage.pollType = proto.Message.PollType.QUIZ;
|
|
935
|
-
m.pollResultSnapshotMessageV3 = pollResultSnapshotMessage;
|
|
936
|
-
}
|
|
937
|
-
else {
|
|
938
|
-
pollResultSnapshotMessage.pollType = proto.Message.PollType.POLL;
|
|
939
|
-
m.pollResultSnapshotMessage = pollResultSnapshotMessage;
|
|
940
|
-
}
|
|
941
462
|
}
|
|
942
|
-
else if (
|
|
943
|
-
if (!msg.pollUpdate.key) {
|
|
944
|
-
throw new Boom('Message key is required', { statusCode: 400 });
|
|
945
|
-
}
|
|
946
|
-
if (!msg.pollUpdate.vote) {
|
|
947
|
-
throw new Boom('Encrypted vote payload is required', { statusCode: 400 });
|
|
948
|
-
}
|
|
949
|
-
m.pollUpdateMessage = {
|
|
950
|
-
metadata: msg.pollUpdate.metadata,
|
|
951
|
-
pollCreationMessageKey: msg.pollUpdate.key,
|
|
952
|
-
senderTimestampMs: Date.now(),
|
|
953
|
-
vote: msg.pollUpdate.vote
|
|
954
|
-
};
|
|
955
|
-
}
|
|
956
|
-
else if (hasProp(msg, 'paymentInviteServiceType')) {
|
|
957
|
-
m.paymentInviteMessage = {
|
|
958
|
-
expiryTimestamp: Date.now(),
|
|
959
|
-
serviceType: msg.paymentInviteServiceType
|
|
960
|
-
};
|
|
961
|
-
}
|
|
962
|
-
else if (hasProp(msg, 'orderText')) {
|
|
963
|
-
if (!Buffer.isBuffer(msg.thumbnail)) {
|
|
964
|
-
throw new Boom('Must provide thumbnail buffer in order message', { statusCode: 400 });
|
|
965
|
-
}
|
|
966
|
-
m.orderMessage = {
|
|
967
|
-
itemCount: 1,
|
|
968
|
-
messageVersion: 1,
|
|
969
|
-
orderTitle: LIBRARY_NAME,
|
|
970
|
-
status: proto.Message.OrderMessage.OrderStatus.INQUIRY,
|
|
971
|
-
surface: proto.Message.OrderMessage.OrderSurface.CATALOG,
|
|
972
|
-
token: generateMessageIDV2(),
|
|
973
|
-
totalAmount1000: 1000,
|
|
974
|
-
totalCurrencyCode: 'IDR',
|
|
975
|
-
...msg,
|
|
976
|
-
message: msg.orderText
|
|
977
|
-
};
|
|
978
|
-
delete m.orderMessage.orderText;
|
|
979
|
-
}
|
|
980
|
-
else if (hasProp(msg, 'album')) {
|
|
981
|
-
if (!Array.isArray(msg.album)) {
|
|
982
|
-
throw new Boom('Invalid album type. Expected an array.', { statusCode: 400 });
|
|
983
|
-
}
|
|
984
|
-
let videoCount = 0;
|
|
985
|
-
for (let i = 0; i < msg.album.length; i++) {
|
|
986
|
-
if (msg.album[i].video)
|
|
987
|
-
videoCount++;
|
|
988
|
-
}
|
|
989
|
-
let imageCount = 0;
|
|
990
|
-
for (let i = 0; i < msg.album.length; i++) {
|
|
991
|
-
if (msg.album[i].image)
|
|
992
|
-
imageCount++;
|
|
993
|
-
}
|
|
994
|
-
if (videoCount + imageCount < 2) {
|
|
995
|
-
throw new Boom('Minimum provide 2 media to upload album message', { statusCode: 400 });
|
|
996
|
-
}
|
|
463
|
+
else if (hasNonNullishProperty(message, 'album')) {
|
|
997
464
|
m.albumMessage = {
|
|
998
|
-
expectedImageCount:
|
|
999
|
-
expectedVideoCount:
|
|
465
|
+
expectedImageCount: message.album.expectedImageCount,
|
|
466
|
+
expectedVideoCount: message.album.expectedVideoCount
|
|
1000
467
|
};
|
|
1001
468
|
}
|
|
1002
|
-
else if (
|
|
469
|
+
else if (hasNonNullishProperty(message, 'sharePhoneNumber')) {
|
|
1003
470
|
m.protocolMessage = {
|
|
1004
471
|
type: proto.Message.ProtocolMessage.Type.SHARE_PHONE_NUMBER
|
|
1005
472
|
};
|
|
1006
473
|
}
|
|
1007
|
-
else if (
|
|
474
|
+
else if (hasNonNullishProperty(message, 'requestPhoneNumber')) {
|
|
1008
475
|
m.requestPhoneNumberMessage = {};
|
|
1009
476
|
}
|
|
1010
|
-
else if (
|
|
477
|
+
else if (hasNonNullishProperty(message, 'limitSharing')) {
|
|
1011
478
|
m.protocolMessage = {
|
|
1012
479
|
type: proto.Message.ProtocolMessage.Type.LIMIT_SHARING,
|
|
1013
480
|
limitSharing: {
|
|
1014
|
-
sharingLimited:
|
|
481
|
+
sharingLimited: message.limitSharing === true,
|
|
1015
482
|
trigger: 1,
|
|
1016
483
|
limitSharingSettingTimestamp: Date.now(),
|
|
1017
484
|
initiatedByMe: true
|
|
@@ -1019,408 +486,57 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
1019
486
|
};
|
|
1020
487
|
}
|
|
1021
488
|
else {
|
|
1022
|
-
m = await prepareWAMessageMedia(
|
|
1023
|
-
}
|
|
1024
|
-
if (hasProp(msg, 'buttons')) {
|
|
1025
|
-
const buttonsMessage = {
|
|
1026
|
-
buttons: msg.buttons.map((button) => {
|
|
1027
|
-
const buttonText = button.text || button.buttonText;
|
|
1028
|
-
if (hasOptProp(button, 'sections')) {
|
|
1029
|
-
return {
|
|
1030
|
-
nativeFlowInfo: {
|
|
1031
|
-
name: 'single_select',
|
|
1032
|
-
paramsJson: JSON.stringify({
|
|
1033
|
-
title: buttonText,
|
|
1034
|
-
sections: button.sections
|
|
1035
|
-
})
|
|
1036
|
-
},
|
|
1037
|
-
type: ButtonType.NATIVE_FLOW
|
|
1038
|
-
};
|
|
1039
|
-
}
|
|
1040
|
-
else if (hasOptProp(button, 'name')) {
|
|
1041
|
-
return {
|
|
1042
|
-
nativeFlowInfo: {
|
|
1043
|
-
name: button.name,
|
|
1044
|
-
paramsJson: button.paramsJson
|
|
1045
|
-
},
|
|
1046
|
-
type: ButtonType.NATIVE_FLOW
|
|
1047
|
-
};
|
|
1048
|
-
}
|
|
1049
|
-
return {
|
|
1050
|
-
buttonId: button.id || button.buttonId,
|
|
1051
|
-
buttonText: typeof buttonText === 'string' ? { displayText: buttonText } : buttonText,
|
|
1052
|
-
type: button.type || ButtonType.RESPONSE
|
|
1053
|
-
};
|
|
1054
|
-
})
|
|
1055
|
-
};
|
|
1056
|
-
if (hasOptProp(msg, 'text')) {
|
|
1057
|
-
buttonsMessage.contentText = msg.text;
|
|
1058
|
-
buttonsMessage.headerType = ButtonHeaderType.EMPTY;
|
|
1059
|
-
}
|
|
1060
|
-
else {
|
|
1061
|
-
if (hasOptProp(msg, 'caption')) {
|
|
1062
|
-
buttonsMessage.contentText = msg.caption;
|
|
1063
|
-
}
|
|
1064
|
-
const type = Object.keys(m)[0].replace('Message', '').toUpperCase();
|
|
1065
|
-
buttonsMessage.headerType = ButtonHeaderType[type];
|
|
1066
|
-
Object.assign(buttonsMessage, m);
|
|
1067
|
-
}
|
|
1068
|
-
if (hasOptProp(msg, 'footer')) {
|
|
1069
|
-
buttonsMessage.footerText = msg.footer;
|
|
1070
|
-
}
|
|
1071
|
-
m = { buttonsMessage };
|
|
1072
|
-
}
|
|
1073
|
-
else if (hasProp(msg, 'sections')) {
|
|
1074
|
-
const listMessage = {
|
|
1075
|
-
sections: msg.sections,
|
|
1076
|
-
buttonText: msg.buttonText,
|
|
1077
|
-
title: msg.title,
|
|
1078
|
-
footerText: msg.footer,
|
|
1079
|
-
description: msg.text,
|
|
1080
|
-
listType: ListType.SINGLE_SELECT
|
|
1081
|
-
};
|
|
1082
|
-
m = { listMessage };
|
|
1083
|
-
}
|
|
1084
|
-
else if (hasProp(msg, 'templateButtons')) {
|
|
1085
|
-
const hydratedTemplate = {
|
|
1086
|
-
hydratedButtons: msg.templateButtons.map((button, i) => {
|
|
1087
|
-
const buttonText = button.text || button.buttonText;
|
|
1088
|
-
if (hasOptProp(button, 'id')) {
|
|
1089
|
-
return {
|
|
1090
|
-
index: i,
|
|
1091
|
-
quickReplyButton: {
|
|
1092
|
-
displayText: buttonText || '👉🏻 Click',
|
|
1093
|
-
id: button.id
|
|
1094
|
-
}
|
|
1095
|
-
};
|
|
1096
|
-
}
|
|
1097
|
-
else if (hasOptProp(button, 'url')) {
|
|
1098
|
-
return {
|
|
1099
|
-
index: i,
|
|
1100
|
-
urlButton: {
|
|
1101
|
-
displayText: buttonText || '🌐 Visit',
|
|
1102
|
-
url: button.url
|
|
1103
|
-
}
|
|
1104
|
-
};
|
|
1105
|
-
}
|
|
1106
|
-
else if (hasOptProp(button, 'call')) {
|
|
1107
|
-
return {
|
|
1108
|
-
index: i,
|
|
1109
|
-
callButton: {
|
|
1110
|
-
displayText: buttonText || '📞 Call',
|
|
1111
|
-
phoneNumber: button.call
|
|
1112
|
-
}
|
|
1113
|
-
};
|
|
1114
|
-
}
|
|
1115
|
-
button.index = button.index || i;
|
|
1116
|
-
return button;
|
|
1117
|
-
})
|
|
1118
|
-
};
|
|
1119
|
-
if (hasOptProp(msg, 'text')) {
|
|
1120
|
-
hydratedTemplate.hydratedContentText = msg.text;
|
|
1121
|
-
}
|
|
1122
|
-
else {
|
|
1123
|
-
if (hasOptProp(msg, 'caption')) {
|
|
1124
|
-
hydratedTemplate.hydratedTitleText = msg.title;
|
|
1125
|
-
hydratedTemplate.hydratedContentText = msg.caption;
|
|
1126
|
-
}
|
|
1127
|
-
Object.assign(hydratedTemplate, m);
|
|
1128
|
-
}
|
|
1129
|
-
if (hasOptProp(msg, 'footer')) {
|
|
1130
|
-
hydratedTemplate.hydratedFooterText = msg.footer;
|
|
1131
|
-
}
|
|
1132
|
-
hydratedTemplate.templateId = msg.id || 'template-' + Date.now();
|
|
1133
|
-
m = {
|
|
1134
|
-
templateMessage: {
|
|
1135
|
-
hydratedFourRowTemplate: hydratedTemplate,
|
|
1136
|
-
hydratedTemplate: hydratedTemplate
|
|
1137
|
-
}
|
|
1138
|
-
};
|
|
1139
|
-
}
|
|
1140
|
-
else if (hasProp(msg, 'nativeFlow')) {
|
|
1141
|
-
const interactiveMessage = {
|
|
1142
|
-
nativeFlowMessage: prepareNativeFlowButtons(msg)
|
|
1143
|
-
};
|
|
1144
|
-
if (hasOptProp(msg, 'bizJid')) {
|
|
1145
|
-
interactiveMessage.collectionMessage = {
|
|
1146
|
-
bizJid: msg.bizJid,
|
|
1147
|
-
id: msg.id,
|
|
1148
|
-
messageVersion: 1
|
|
1149
|
-
};
|
|
1150
|
-
}
|
|
1151
|
-
else if (hasOptProp(msg, 'shopSurface')) {
|
|
1152
|
-
interactiveMessage.shopStorefrontMessage = {
|
|
1153
|
-
surface: msg.shopSurface,
|
|
1154
|
-
id: msg.id,
|
|
1155
|
-
messageVersion: 1
|
|
1156
|
-
};
|
|
1157
|
-
}
|
|
1158
|
-
if (hasOptProp(msg, 'text')) {
|
|
1159
|
-
interactiveMessage.body = { text: msg.text };
|
|
1160
|
-
}
|
|
1161
|
-
else {
|
|
1162
|
-
if (hasOptProp(msg, 'caption')) {
|
|
1163
|
-
const isValidHeader = hasValidInteractiveHeader(m);
|
|
1164
|
-
if (!isValidHeader) {
|
|
1165
|
-
throw new Boom('Invalid media type for interactive message header', { statusCode: 400 });
|
|
1166
|
-
}
|
|
1167
|
-
interactiveMessage.header = {
|
|
1168
|
-
title: msg.title || '',
|
|
1169
|
-
subtitle: msg.subtitle || '',
|
|
1170
|
-
hasMediaAttachment: isValidHeader
|
|
1171
|
-
};
|
|
1172
|
-
interactiveMessage.body = { text: msg.caption };
|
|
1173
|
-
}
|
|
1174
|
-
if (hasOptProp(msg, 'thumbnail') && !!msg.thumbnail) {
|
|
1175
|
-
interactiveMessage.jpegThumbnail = msg.thumbnail;
|
|
1176
|
-
}
|
|
1177
|
-
Object.assign(interactiveMessage.header, m);
|
|
1178
|
-
}
|
|
1179
|
-
if (hasOptProp(msg, 'audioFooter')) {
|
|
1180
|
-
const { audioMessage } = await prepareWAMessageMedia({ audio: msg.audioFooter }, options);
|
|
1181
|
-
interactiveMessage.footer = {
|
|
1182
|
-
audioMessage,
|
|
1183
|
-
hasMediaAttachment: true
|
|
1184
|
-
};
|
|
1185
|
-
}
|
|
1186
|
-
else if (hasOptProp(msg, 'footer')) {
|
|
1187
|
-
interactiveMessage.footer = { text: msg.footer };
|
|
1188
|
-
}
|
|
1189
|
-
m = { interactiveMessage };
|
|
1190
|
-
}
|
|
1191
|
-
else if (hasProp(msg, 'cards')) {
|
|
1192
|
-
const interactiveMessage = {
|
|
1193
|
-
carouselMessage: {
|
|
1194
|
-
cards: await Promise.all(msg.cards.map(async (card) => {
|
|
1195
|
-
let carouselHeader = {};
|
|
1196
|
-
if (hasProp(card, 'product')) {
|
|
1197
|
-
carouselHeader.productMessage = await prepareProductMessage(card, options);
|
|
1198
|
-
}
|
|
1199
|
-
else {
|
|
1200
|
-
carouselHeader = await prepareWAMessageMedia(card, options).catch(() => ({}));
|
|
1201
|
-
}
|
|
1202
|
-
const isValidHeader = hasValidCarouselHeader(carouselHeader);
|
|
1203
|
-
if (!isValidHeader) {
|
|
1204
|
-
throw new Boom('Invalid media type for carousel card', { statusCode: 400 });
|
|
1205
|
-
}
|
|
1206
|
-
const carouselCard = {
|
|
1207
|
-
nativeFlowMessage: prepareNativeFlowButtons(card.nativeFlow ? card : [])
|
|
1208
|
-
};
|
|
1209
|
-
if (hasOptProp(card, 'text')) {
|
|
1210
|
-
carouselCard.body = { text: card.text };
|
|
1211
|
-
}
|
|
1212
|
-
else {
|
|
1213
|
-
if (hasOptProp(card, 'caption')) {
|
|
1214
|
-
carouselCard.header = {
|
|
1215
|
-
title: card.title || '',
|
|
1216
|
-
subtitle: card.subtitle || '',
|
|
1217
|
-
hasMediaAttachment: isValidHeader
|
|
1218
|
-
};
|
|
1219
|
-
carouselCard.body = { text: card.caption };
|
|
1220
|
-
}
|
|
1221
|
-
if (hasOptProp(card, 'thumbnail') && !!card.thumbnail) {
|
|
1222
|
-
carouselCard.jpegThumbnail = card.thumbnail;
|
|
1223
|
-
}
|
|
1224
|
-
Object.assign(carouselCard.header, carouselHeader);
|
|
1225
|
-
}
|
|
1226
|
-
if (hasOptProp(card, 'audioFooter')) {
|
|
1227
|
-
const { audioMessage } = await prepareWAMessageMedia({ audio: card.audioFooter }, options);
|
|
1228
|
-
carouselCard.footer = {
|
|
1229
|
-
audioMessage,
|
|
1230
|
-
hasMediaAttachment: true
|
|
1231
|
-
};
|
|
1232
|
-
}
|
|
1233
|
-
else if (hasOptProp(card, 'footer')) {
|
|
1234
|
-
carouselCard.footer = { text: card.footer };
|
|
1235
|
-
}
|
|
1236
|
-
return carouselCard;
|
|
1237
|
-
})),
|
|
1238
|
-
carouselCardType: CarouselCardType.UNKNOWN,
|
|
1239
|
-
messageVersion: 1
|
|
1240
|
-
}
|
|
1241
|
-
};
|
|
1242
|
-
if (hasOptProp(msg, 'text')) {
|
|
1243
|
-
interactiveMessage.body = { text: msg.text };
|
|
1244
|
-
}
|
|
1245
|
-
if (hasOptProp(msg, 'footer')) {
|
|
1246
|
-
interactiveMessage.footer = { text: msg.footer };
|
|
1247
|
-
}
|
|
1248
|
-
m = { interactiveMessage };
|
|
489
|
+
m = await prepareWAMessageMedia(message, options);
|
|
1249
490
|
}
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
amount: {
|
|
1253
|
-
currencyCode: 'IDR',
|
|
1254
|
-
offset: 1000,
|
|
1255
|
-
value: 1000
|
|
1256
|
-
},
|
|
1257
|
-
amount1000: 1000,
|
|
1258
|
-
currencyCodeIso4217: 'IDR',
|
|
1259
|
-
expiryTimestamp: Date.now(),
|
|
1260
|
-
noteMessage: m,
|
|
1261
|
-
requestFrom: msg.requestPaymentFrom,
|
|
1262
|
-
...msg
|
|
1263
|
-
};
|
|
1264
|
-
delete requestPaymentMessage.requestPaymentFrom;
|
|
1265
|
-
if (hasProp(m, 'extendedTextMessage') || hasProp(m, 'stickerMessage')) {
|
|
1266
|
-
Object.assign(requestPaymentMessage.noteMessage, m);
|
|
1267
|
-
}
|
|
1268
|
-
else {
|
|
1269
|
-
throw new Boom('Invalid message type for request payment note message', { statusCode: 400 });
|
|
1270
|
-
}
|
|
1271
|
-
m = { requestPaymentMessage };
|
|
1272
|
-
}
|
|
1273
|
-
else if (hasProp(msg, 'invoiceNote')) {
|
|
1274
|
-
const attachment = m.imageMessage || m.documentMessage;
|
|
1275
|
-
const type = Object.keys(m)[0].replace('Message', '').toUpperCase();
|
|
1276
|
-
const invoiceMessage = {
|
|
1277
|
-
attachmentType: proto.Message.InvoiceMessage.AttachmentType[type === 'DOCUMENT' ? 'PDF' : 'IMAGE'],
|
|
1278
|
-
note: msg.invoiceNote
|
|
1279
|
-
};
|
|
1280
|
-
if (attachment) {
|
|
1281
|
-
const { directPath, fileEncSha256, fileSha256, jpegThumbnail = undefined, mediaKey, mediaKeyTimestamp, mimetype } = attachment;
|
|
1282
|
-
Object.assign(invoiceMessage, {
|
|
1283
|
-
attachmentDirectPath: directPath,
|
|
1284
|
-
attachmentFileEncSha256: fileEncSha256,
|
|
1285
|
-
attachmentFileSha256: fileSha256,
|
|
1286
|
-
attachmentJpegThumbnail: jpegThumbnail,
|
|
1287
|
-
attachmentMediaKey: mediaKey,
|
|
1288
|
-
attachmentMediaKeyTimestamp: mediaKeyTimestamp,
|
|
1289
|
-
attachmentMimetype: mimetype,
|
|
1290
|
-
token: generateMessageIDV2()
|
|
1291
|
-
});
|
|
1292
|
-
}
|
|
1293
|
-
else {
|
|
1294
|
-
throw new Boom('Invalid media type for invoice message', { statusCode: 400 });
|
|
1295
|
-
}
|
|
1296
|
-
m = { invoiceMessage };
|
|
1297
|
-
}
|
|
1298
|
-
if (hasOptProp(msg, 'externalAdReply') && !!msg.externalAdReply) {
|
|
1299
|
-
const messageType = Object.keys(m)[0];
|
|
1300
|
-
const key = m[messageType];
|
|
1301
|
-
const content = msg.externalAdReply;
|
|
1302
|
-
if ('thumbnail' in content && !Buffer.isBuffer(content.thumbnail)) {
|
|
1303
|
-
throw new Boom('Thumbnail must in buffer type', { statusCode: 400 });
|
|
1304
|
-
}
|
|
1305
|
-
if (!content.url || typeof content.url !== 'string') {
|
|
1306
|
-
content.url = DONATE_URL;
|
|
1307
|
-
}
|
|
1308
|
-
const externalAdReply = {
|
|
1309
|
-
...content,
|
|
1310
|
-
body: content.body,
|
|
1311
|
-
mediaType: content.mediaType || 1,
|
|
1312
|
-
mediaUrl: content.url,
|
|
1313
|
-
renderLargerThumbnail: content.largeThumbnail,
|
|
1314
|
-
sourceUrl: content.url,
|
|
1315
|
-
thumbnail: content.thumbnail,
|
|
1316
|
-
thumbnailUrl: content.url + '?update=' + Date.now(),
|
|
1317
|
-
title: content.title || LIBRARY_NAME
|
|
1318
|
-
};
|
|
1319
|
-
delete externalAdReply.subTitle;
|
|
1320
|
-
delete externalAdReply.largeThumbnail;
|
|
1321
|
-
delete externalAdReply.url;
|
|
1322
|
-
if (key && 'contextInfo' in key && !!key.contextInfo) {
|
|
1323
|
-
key.contextInfo.externalAdReply = { ...key.contextInfo.externalAdReply, ...externalAdReply };
|
|
1324
|
-
}
|
|
1325
|
-
else if (key) {
|
|
1326
|
-
key.contextInfo = { externalAdReply };
|
|
1327
|
-
}
|
|
491
|
+
if (hasOptionalProperty(message, 'viewOnce') && !!message.viewOnce) {
|
|
492
|
+
m = { viewOnceMessage: { message: m } };
|
|
1328
493
|
}
|
|
1329
|
-
if ((
|
|
1330
|
-
(
|
|
494
|
+
if ((hasOptionalProperty(message, 'mentions') && message.mentions?.length) ||
|
|
495
|
+
(hasOptionalProperty(message, 'mentionAll') && message.mentionAll)) {
|
|
1331
496
|
const messageType = Object.keys(m)[0];
|
|
1332
497
|
const key = m[messageType];
|
|
1333
498
|
if (key && 'contextInfo' in key) {
|
|
1334
499
|
key.contextInfo = key.contextInfo || {};
|
|
1335
|
-
if (
|
|
1336
|
-
key.contextInfo.mentionedJid =
|
|
500
|
+
if (message.mentions?.length) {
|
|
501
|
+
key.contextInfo.mentionedJid = message.mentions;
|
|
1337
502
|
}
|
|
1338
|
-
if (
|
|
503
|
+
if (message.mentionAll) {
|
|
1339
504
|
key.contextInfo.nonJidMentions = 1;
|
|
1340
505
|
}
|
|
1341
506
|
}
|
|
1342
507
|
else if (key) {
|
|
1343
508
|
key.contextInfo = {
|
|
1344
|
-
mentionedJid:
|
|
1345
|
-
nonJidMentions:
|
|
509
|
+
mentionedJid: message.mentions,
|
|
510
|
+
nonJidMentions: message.mentionAll ? 1 : 0
|
|
1346
511
|
};
|
|
1347
512
|
}
|
|
1348
513
|
}
|
|
1349
|
-
if (
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
}
|
|
1358
|
-
}
|
|
1359
|
-
if (hasOptProp(msg, 'groupStatus') && !!msg.groupStatus) {
|
|
1360
|
-
const messageType = Object.keys(m)[0];
|
|
1361
|
-
const key = m[messageType];
|
|
1362
|
-
if (key && 'contextInfo' in key && !!key.contextInfo) {
|
|
1363
|
-
key.contextInfo.isGroupStatus = msg.groupStatus;
|
|
1364
|
-
}
|
|
1365
|
-
else if (key) {
|
|
1366
|
-
key.contextInfo = {
|
|
1367
|
-
isGroupStatus: msg.groupStatus
|
|
1368
|
-
};
|
|
1369
|
-
}
|
|
1370
|
-
m = { groupStatusMessageV2: { message: m } };
|
|
1371
|
-
delete msg.groupStatus;
|
|
514
|
+
if (hasOptionalProperty(message, 'edit')) {
|
|
515
|
+
m = {
|
|
516
|
+
protocolMessage: {
|
|
517
|
+
key: message.edit,
|
|
518
|
+
editedMessage: m,
|
|
519
|
+
timestampMs: Date.now(),
|
|
520
|
+
type: WAProto.Message.ProtocolMessage.Type.MESSAGE_EDIT
|
|
521
|
+
}
|
|
522
|
+
};
|
|
1372
523
|
}
|
|
1373
|
-
if (
|
|
524
|
+
if (hasOptionalProperty(message, 'contextInfo') && !!message.contextInfo) {
|
|
1374
525
|
const messageType = Object.keys(m)[0];
|
|
1375
526
|
const key = m[messageType];
|
|
1376
|
-
if (
|
|
1377
|
-
key.contextInfo
|
|
527
|
+
if ('contextInfo' in key && !!key.contextInfo) {
|
|
528
|
+
key.contextInfo = { ...key.contextInfo, ...message.contextInfo };
|
|
1378
529
|
}
|
|
1379
530
|
else if (key) {
|
|
1380
|
-
key.contextInfo =
|
|
1381
|
-
isSpoiler: msg.spoiler
|
|
1382
|
-
};
|
|
1383
|
-
}
|
|
1384
|
-
m = { spoilerMessage: { message: m } };
|
|
1385
|
-
delete msg.spoiler;
|
|
1386
|
-
}
|
|
1387
|
-
else if (hasOptProp(msg, 'interactiveAsTemplate') && !!msg.interactiveAsTemplate) {
|
|
1388
|
-
if (!m.interactiveMessage) {
|
|
1389
|
-
throw new Boom('Invalid message type for template', { statusCode: 400 });
|
|
531
|
+
key.contextInfo = message.contextInfo;
|
|
1390
532
|
}
|
|
1391
|
-
m = {
|
|
1392
|
-
templateMessage: {
|
|
1393
|
-
interactiveMessageTemplate: m.interactiveMessage,
|
|
1394
|
-
templateId: msg.id || 'template-' + Date.now()
|
|
1395
|
-
}
|
|
1396
|
-
};
|
|
1397
|
-
delete msg.interactiveAsTemplate;
|
|
1398
|
-
}
|
|
1399
|
-
if (hasOptProp(msg, 'ephemeral') && !!msg.ephemeral) {
|
|
1400
|
-
m = { ephemeralMessage: { message: m } };
|
|
1401
|
-
delete msg.ephemeral;
|
|
1402
|
-
}
|
|
1403
|
-
if (hasOptProp(msg, 'isLottie') && !!msg.isLottie) {
|
|
1404
|
-
m = { lottieStickerMessage: { message: m } };
|
|
1405
|
-
}
|
|
1406
|
-
else if (hasOptProp(msg, 'viewOnce') && !!msg.viewOnce) {
|
|
1407
|
-
m = { viewOnceMessage: { message: m } };
|
|
1408
|
-
}
|
|
1409
|
-
else if (hasOptProp(msg, 'viewOnceV2') && !!msg.viewOnceV2) {
|
|
1410
|
-
m = { viewOnceMessageV2: { message: m } };
|
|
1411
|
-
delete msg.viewOnceV2;
|
|
1412
533
|
}
|
|
1413
|
-
|
|
1414
|
-
m = {
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
protocolMessage: {
|
|
1420
|
-
key: msg.edit,
|
|
1421
|
-
editedMessage: m,
|
|
1422
|
-
timestampMs: Date.now(),
|
|
1423
|
-
type: WAProto.Message.ProtocolMessage.Type.MESSAGE_EDIT
|
|
534
|
+
if (hasOptionalProperty(message, 'albumParentKey') && !!message.albumParentKey) {
|
|
535
|
+
m.messageContextInfo = {
|
|
536
|
+
...m.messageContextInfo,
|
|
537
|
+
messageAssociation: {
|
|
538
|
+
associationType: WAProto.MessageAssociation.AssociationType.MEDIA_ALBUM,
|
|
539
|
+
parentMessageKey: message.albumParentKey
|
|
1424
540
|
}
|
|
1425
541
|
};
|
|
1426
542
|
}
|
|
@@ -1433,82 +549,79 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
1433
549
|
return WAProto.Message.create(m);
|
|
1434
550
|
};
|
|
1435
551
|
export const generateWAMessageFromContent = (jid, message, options) => {
|
|
552
|
+
// set timestamp to now
|
|
553
|
+
// if not specified
|
|
1436
554
|
if (!options.timestamp) {
|
|
1437
555
|
options.timestamp = new Date();
|
|
1438
556
|
}
|
|
1439
557
|
const innerMessage = normalizeMessageContent(message);
|
|
1440
|
-
const messageContextInfo = message.messageContextInfo;
|
|
1441
558
|
const key = getContentType(innerMessage);
|
|
1442
559
|
const timestamp = unixTimestampSeconds(options.timestamp);
|
|
1443
|
-
const isNewsletter = isJidNewsletter(jid);
|
|
1444
560
|
const { quoted, userJid } = options;
|
|
1445
|
-
if (quoted &&
|
|
561
|
+
if (quoted && !isJidNewsletter(jid)) {
|
|
1446
562
|
const participant = quoted.key.fromMe
|
|
1447
|
-
? userJid
|
|
563
|
+
? userJid // TODO: Add support for LIDs
|
|
1448
564
|
: quoted.participant || quoted.key.participant || quoted.key.remoteJid;
|
|
1449
565
|
let quotedMsg = normalizeMessageContent(quoted.message);
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
566
|
+
const msgType = getContentType(quotedMsg);
|
|
567
|
+
// strip any redundant properties
|
|
568
|
+
quotedMsg = proto.Message.create({ [msgType]: quotedMsg[msgType] });
|
|
569
|
+
const quotedContent = quotedMsg[msgType];
|
|
570
|
+
if (typeof quotedContent === 'object' && quotedContent && 'contextInfo' in quotedContent) {
|
|
571
|
+
delete quotedContent.contextInfo;
|
|
572
|
+
}
|
|
573
|
+
const contextInfo = ('contextInfo' in innerMessage[key] && innerMessage[key]?.contextInfo) || {};
|
|
574
|
+
contextInfo.participant = jidNormalizedUser(participant);
|
|
575
|
+
contextInfo.stanzaId = quoted.key.id;
|
|
576
|
+
contextInfo.quotedMessage = quotedMsg;
|
|
577
|
+
// if a participant is quoted, then it must be a group
|
|
578
|
+
// hence, remoteJid of group must also be entered
|
|
579
|
+
if (jid !== quoted.key.remoteJid) {
|
|
580
|
+
contextInfo.remoteJid = quoted.key.remoteJid;
|
|
581
|
+
}
|
|
582
|
+
if (contextInfo && innerMessage[key]) {
|
|
583
|
+
/* @ts-ignore */
|
|
584
|
+
innerMessage[key].contextInfo = contextInfo;
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
if (
|
|
588
|
+
// if we want to send a disappearing message
|
|
589
|
+
!!options?.ephemeralExpiration &&
|
|
590
|
+
// and it's not a protocol message -- delete, toggle disappear message
|
|
1472
591
|
key !== 'protocolMessage' &&
|
|
592
|
+
// already not converted to disappearing message
|
|
1473
593
|
key !== 'ephemeralMessage' &&
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
}
|
|
1482
|
-
}
|
|
1483
|
-
if (messageContextInfo?.messageSecret && (isPnUser(jid) || isLidUser(jid))) {
|
|
1484
|
-
messageContextInfo.deviceListMetadata = {
|
|
1485
|
-
recipientKeyHash: randomBytes(10),
|
|
1486
|
-
recipientTimestamp: unixTimestampSeconds()
|
|
594
|
+
// newsletters don't support ephemeral messages
|
|
595
|
+
!isJidNewsletter(jid)) {
|
|
596
|
+
/* @ts-ignore */
|
|
597
|
+
innerMessage[key].contextInfo = {
|
|
598
|
+
...(innerMessage[key].contextInfo || {}),
|
|
599
|
+
expiration: options.ephemeralExpiration || WA_DEFAULT_EPHEMERAL
|
|
600
|
+
//ephemeralSettingTimestamp: options.ephemeralOptions.eph_setting_ts?.toString()
|
|
1487
601
|
};
|
|
1488
|
-
messageContextInfo.deviceListMetadataVersion = 2;
|
|
1489
602
|
}
|
|
1490
|
-
|
|
603
|
+
message = WAProto.Message.create(message);
|
|
1491
604
|
const messageJSON = {
|
|
1492
605
|
key: {
|
|
1493
606
|
remoteJid: jid,
|
|
1494
607
|
fromMe: true,
|
|
1495
608
|
id: options?.messageId || generateMessageIDV2()
|
|
1496
609
|
},
|
|
1497
|
-
message:
|
|
610
|
+
message: message,
|
|
1498
611
|
messageTimestamp: timestamp,
|
|
1499
612
|
messageStubParameters: [],
|
|
1500
|
-
participant: isJidGroup(jid) || isJidStatusBroadcast(jid) ? userJid : undefined,
|
|
613
|
+
participant: isJidGroup(jid) || isJidStatusBroadcast(jid) ? userJid : undefined, // TODO: Add support for LIDs
|
|
1501
614
|
status: WAMessageStatus.PENDING
|
|
1502
615
|
};
|
|
1503
616
|
return WAProto.WebMessageInfo.fromObject(messageJSON);
|
|
1504
617
|
};
|
|
1505
618
|
export const generateWAMessage = async (jid, content, options) => {
|
|
619
|
+
// ensure msg ID is with every log
|
|
1506
620
|
options.logger = options?.logger?.child({ msgId: options.messageId });
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
}
|
|
1510
|
-
return generateWAMessageFromContent(jid, await generateWAMessageContent(content, options), options);
|
|
621
|
+
// Pass jid in the options to generateWAMessageContent
|
|
622
|
+
return generateWAMessageFromContent(jid, await generateWAMessageContent(content, { ...options, jid }), options);
|
|
1511
623
|
};
|
|
624
|
+
/** Get the key to access the true type of content */
|
|
1512
625
|
export const getContentType = (content) => {
|
|
1513
626
|
if (content) {
|
|
1514
627
|
const keys = Object.keys(content);
|
|
@@ -1516,10 +629,17 @@ export const getContentType = (content) => {
|
|
|
1516
629
|
return key;
|
|
1517
630
|
}
|
|
1518
631
|
};
|
|
632
|
+
/**
|
|
633
|
+
* Normalizes ephemeral, view once messages to regular message content
|
|
634
|
+
* Eg. image messages in ephemeral messages, in view once messages etc.
|
|
635
|
+
* @param content
|
|
636
|
+
* @returns
|
|
637
|
+
*/
|
|
1519
638
|
export const normalizeMessageContent = (content) => {
|
|
1520
639
|
if (!content) {
|
|
1521
640
|
return undefined;
|
|
1522
641
|
}
|
|
642
|
+
// set max iterations to prevent an infinite loop
|
|
1523
643
|
for (let i = 0; i < 5; i++) {
|
|
1524
644
|
const inner = getFutureProofMessage(content);
|
|
1525
645
|
if (!inner) {
|
|
@@ -1527,37 +647,23 @@ export const normalizeMessageContent = (content) => {
|
|
|
1527
647
|
}
|
|
1528
648
|
content = inner.message;
|
|
1529
649
|
}
|
|
1530
|
-
return content
|
|
650
|
+
return content;
|
|
1531
651
|
function getFutureProofMessage(message) {
|
|
1532
|
-
return (message?.
|
|
1533
|
-
message?.
|
|
1534
|
-
message?.botInvokeMessage ||
|
|
1535
|
-
message?.botTaskMessage ||
|
|
652
|
+
return (message?.ephemeralMessage ||
|
|
653
|
+
message?.viewOnceMessage ||
|
|
1536
654
|
message?.documentWithCaptionMessage ||
|
|
655
|
+
message?.viewOnceMessageV2 ||
|
|
656
|
+
message?.viewOnceMessageV2Extension ||
|
|
1537
657
|
message?.editedMessage ||
|
|
1538
|
-
message?.
|
|
1539
|
-
message?.eventCoverImage ||
|
|
1540
|
-
message?.groupMentionedMessage ||
|
|
1541
|
-
message?.groupStatusMentionMessage ||
|
|
658
|
+
message?.associatedChildMessage ||
|
|
1542
659
|
message?.groupStatusMessage ||
|
|
1543
|
-
message?.groupStatusMessageV2
|
|
1544
|
-
message?.limitSharingMessage ||
|
|
1545
|
-
message?.lottieStickerMessage ||
|
|
1546
|
-
message?.newsletterAdminProfileMessage ||
|
|
1547
|
-
message?.newsletterAdminProfileMessageV2 ||
|
|
1548
|
-
message?.newsletterAdminProfileStatusMessage ||
|
|
1549
|
-
message?.pollCreationMessageV4 ||
|
|
1550
|
-
message?.pollCreationOptionImageMessage ||
|
|
1551
|
-
message?.questionMessage ||
|
|
1552
|
-
message?.questionReplyMessage ||
|
|
1553
|
-
message?.spoilerMessage ||
|
|
1554
|
-
message?.statusAddYours ||
|
|
1555
|
-
message?.statusMentionMessage ||
|
|
1556
|
-
message?.viewOnceMessage ||
|
|
1557
|
-
message?.viewOnceMessageV2 ||
|
|
1558
|
-
message?.viewOnceMessageV2Extension);
|
|
660
|
+
message?.groupStatusMessageV2);
|
|
1559
661
|
}
|
|
1560
662
|
};
|
|
663
|
+
/**
|
|
664
|
+
* Extract the true message content from a message
|
|
665
|
+
* Eg. extracts the inner message from a disappearing message/view once message
|
|
666
|
+
*/
|
|
1561
667
|
export const extractMessageContent = (content) => {
|
|
1562
668
|
const extractFromTemplateMessage = (msg) => {
|
|
1563
669
|
if (msg.imageMessage) {
|
|
@@ -1593,6 +699,9 @@ export const extractMessageContent = (content) => {
|
|
|
1593
699
|
}
|
|
1594
700
|
return content;
|
|
1595
701
|
};
|
|
702
|
+
/**
|
|
703
|
+
* Returns the device predicted by message ID
|
|
704
|
+
*/
|
|
1596
705
|
export const getDevice = (id) => /^3A.{18}$/.test(id)
|
|
1597
706
|
? 'ios'
|
|
1598
707
|
: /^3E.{20}$/.test(id)
|
|
@@ -1602,6 +711,7 @@ export const getDevice = (id) => /^3A.{18}$/.test(id)
|
|
|
1602
711
|
: /^(3F|.{18}$)/.test(id)
|
|
1603
712
|
? 'desktop'
|
|
1604
713
|
: 'unknown';
|
|
714
|
+
/** Upserts a receipt in the message */
|
|
1605
715
|
export const updateMessageWithReceipt = (msg, receipt) => {
|
|
1606
716
|
msg.userReceipt = msg.userReceipt || [];
|
|
1607
717
|
const recp = msg.userReceipt.find(m => m.userJid === receipt.userJid);
|
|
@@ -1612,6 +722,7 @@ export const updateMessageWithReceipt = (msg, receipt) => {
|
|
|
1612
722
|
msg.userReceipt.push(receipt);
|
|
1613
723
|
}
|
|
1614
724
|
};
|
|
725
|
+
/** Update the message with a new reaction */
|
|
1615
726
|
export const updateMessageWithReaction = (msg, reaction) => {
|
|
1616
727
|
const authorID = getKeyAuthor(reaction.key);
|
|
1617
728
|
const reactions = (msg.reactions || []).filter(r => getKeyAuthor(r.key) !== authorID);
|
|
@@ -1619,20 +730,28 @@ export const updateMessageWithReaction = (msg, reaction) => {
|
|
|
1619
730
|
reactions.push(reaction);
|
|
1620
731
|
msg.reactions = reactions;
|
|
1621
732
|
};
|
|
733
|
+
/** Update the message with a new poll update */
|
|
1622
734
|
export const updateMessageWithPollUpdate = (msg, update) => {
|
|
1623
|
-
const authorID = getKeyAuthor(update.pollUpdateMessageKey
|
|
1624
|
-
const
|
|
735
|
+
const authorID = getKeyAuthor(update.pollUpdateMessageKey);
|
|
736
|
+
const reactions = (msg.pollUpdates || []).filter(r => getKeyAuthor(r.pollUpdateMessageKey) !== authorID);
|
|
1625
737
|
if (update.vote?.selectedOptions?.length) {
|
|
1626
|
-
|
|
738
|
+
reactions.push(update);
|
|
1627
739
|
}
|
|
1628
|
-
msg.pollUpdates =
|
|
740
|
+
msg.pollUpdates = reactions;
|
|
1629
741
|
};
|
|
742
|
+
/** Update the message with a new event response */
|
|
1630
743
|
export const updateMessageWithEventResponse = (msg, update) => {
|
|
1631
|
-
const authorID = getKeyAuthor(update.eventResponseMessageKey
|
|
1632
|
-
const responses = (msg.eventResponses || []).filter(r => getKeyAuthor(r.eventResponseMessageKey
|
|
744
|
+
const authorID = getKeyAuthor(update.eventResponseMessageKey);
|
|
745
|
+
const responses = (msg.eventResponses || []).filter(r => getKeyAuthor(r.eventResponseMessageKey) !== authorID);
|
|
1633
746
|
responses.push(update);
|
|
1634
747
|
msg.eventResponses = responses;
|
|
1635
748
|
};
|
|
749
|
+
/**
|
|
750
|
+
* Aggregates all poll updates in a poll.
|
|
751
|
+
* @param msg the poll creation message
|
|
752
|
+
* @param meId your jid
|
|
753
|
+
* @returns A list of options & their voters
|
|
754
|
+
*/
|
|
1636
755
|
export function getAggregateVotesInPollMessage({ message, pollUpdates }, meId) {
|
|
1637
756
|
const opts = message?.pollCreationMessage?.options ||
|
|
1638
757
|
message?.pollCreationMessageV2?.options ||
|
|
@@ -1661,11 +780,17 @@ export function getAggregateVotesInPollMessage({ message, pollUpdates }, meId) {
|
|
|
1661
780
|
};
|
|
1662
781
|
data = voteHashMap[hash];
|
|
1663
782
|
}
|
|
1664
|
-
|
|
783
|
+
voteHashMap[hash].voters.push(getKeyAuthor(update.pollUpdateMessageKey, meId));
|
|
1665
784
|
}
|
|
1666
785
|
}
|
|
1667
786
|
return Object.values(voteHashMap);
|
|
1668
787
|
}
|
|
788
|
+
/**
|
|
789
|
+
* Aggregates all event responses in an event message.
|
|
790
|
+
* @param msg the event creation message
|
|
791
|
+
* @param meId your jid
|
|
792
|
+
* @returns A list of response types & their responders
|
|
793
|
+
*/
|
|
1669
794
|
export function getAggregateResponsesInEventMessage({ eventResponses }, meId) {
|
|
1670
795
|
const responseTypes = ['GOING', 'NOT_GOING', 'MAYBE'];
|
|
1671
796
|
const responseMap = {};
|
|
@@ -1676,13 +801,14 @@ export function getAggregateResponsesInEventMessage({ eventResponses }, meId) {
|
|
|
1676
801
|
};
|
|
1677
802
|
}
|
|
1678
803
|
for (const update of eventResponses || []) {
|
|
1679
|
-
const responseType = update.
|
|
804
|
+
const responseType = update.eventResponse || 'UNKNOWN';
|
|
1680
805
|
if (responseType !== 'UNKNOWN' && responseMap[responseType]) {
|
|
1681
|
-
responseMap[responseType].responders.push(getKeyAuthor(
|
|
806
|
+
responseMap[responseType].responders.push(getKeyAuthor(update.eventResponseMessageKey, meId));
|
|
1682
807
|
}
|
|
1683
808
|
}
|
|
1684
809
|
return Object.values(responseMap);
|
|
1685
810
|
}
|
|
811
|
+
/** Given a list of message keys, aggregates them by chat & sender. Useful for sending read receipts in bulk */
|
|
1686
812
|
export const aggregateMessageKeysNotFromMe = (keys) => {
|
|
1687
813
|
const keyMap = {};
|
|
1688
814
|
for (const { remoteJid, id, participant, fromMe } of keys) {
|
|
@@ -1691,7 +817,7 @@ export const aggregateMessageKeysNotFromMe = (keys) => {
|
|
|
1691
817
|
if (!keyMap[uqKey]) {
|
|
1692
818
|
keyMap[uqKey] = {
|
|
1693
819
|
jid: remoteJid,
|
|
1694
|
-
participant: participant
|
|
820
|
+
participant: participant,
|
|
1695
821
|
messageIds: []
|
|
1696
822
|
};
|
|
1697
823
|
}
|
|
@@ -1701,12 +827,16 @@ export const aggregateMessageKeysNotFromMe = (keys) => {
|
|
|
1701
827
|
return Object.values(keyMap);
|
|
1702
828
|
};
|
|
1703
829
|
const REUPLOAD_REQUIRED_STATUS = [410, 404];
|
|
830
|
+
/**
|
|
831
|
+
* Downloads the given message. Throws an error if it's not a media message
|
|
832
|
+
*/
|
|
1704
833
|
export const downloadMediaMessage = async (message, type, options, ctx) => {
|
|
1705
834
|
const result = await downloadMsg().catch(async (error) => {
|
|
1706
835
|
if (ctx &&
|
|
1707
|
-
typeof error?.status === 'number' &&
|
|
836
|
+
typeof error?.status === 'number' && // treat errors with status as HTTP failures requiring reupload
|
|
1708
837
|
REUPLOAD_REQUIRED_STATUS.includes(error.status)) {
|
|
1709
838
|
ctx.logger.info({ key: message.key }, 'sending reupload media request...');
|
|
839
|
+
// request reupload
|
|
1710
840
|
message = await ctx.reuploadRequest(message);
|
|
1711
841
|
const result = await downloadMsg();
|
|
1712
842
|
return result;
|
|
@@ -1747,28 +877,17 @@ export const downloadMediaMessage = async (message, type, options, ctx) => {
|
|
|
1747
877
|
return stream;
|
|
1748
878
|
}
|
|
1749
879
|
};
|
|
880
|
+
/** Checks whether the given message is a media message; if it is returns the inner content */
|
|
1750
881
|
export const assertMediaContent = (content) => {
|
|
1751
882
|
content = extractMessageContent(content);
|
|
1752
883
|
const mediaContent = content?.documentMessage ||
|
|
1753
884
|
content?.imageMessage ||
|
|
1754
885
|
content?.videoMessage ||
|
|
1755
886
|
content?.audioMessage ||
|
|
1756
|
-
content?.stickerMessage
|
|
1757
|
-
content?.ptvMessage;
|
|
887
|
+
content?.stickerMessage;
|
|
1758
888
|
if (!mediaContent) {
|
|
1759
889
|
throw new Boom('given message is not a media message', { statusCode: 400, data: content });
|
|
1760
890
|
}
|
|
1761
891
|
return mediaContent;
|
|
1762
892
|
};
|
|
1763
|
-
export const shouldIncludeBizBinaryNode = (message) => {
|
|
1764
|
-
const normalized = normalizeMessageContent(message);
|
|
1765
|
-
const hasValidInteractive = normalized?.interactiveMessage &&
|
|
1766
|
-
!normalized.interactiveMessage.carouselMessage &&
|
|
1767
|
-
!normalized.interactiveMessage.collectionMessage &&
|
|
1768
|
-
!normalized.interactiveMessage.shopStorefrontMessage;
|
|
1769
|
-
return !!(normalized?.buttonsMessage ||
|
|
1770
|
-
normalized?.interactiveMessage ||
|
|
1771
|
-
normalized?.listMessage ||
|
|
1772
|
-
hasValidInteractive);
|
|
1773
|
-
};
|
|
1774
893
|
//# sourceMappingURL=messages.js.map
|