@gqb333/based 2.7.81 → 2.7.83

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.
@@ -16,6 +16,7 @@ const WABinary_1 = require("../WABinary");
16
16
  const crypto_2 = require("./crypto");
17
17
  const generics_1 = require("./generics");
18
18
  const messages_media_1 = require("./messages-media");
19
+
19
20
  const MIMETYPE_MAP = {
20
21
  image: 'image/jpeg',
21
22
  video: 'video/mp4',
@@ -24,6 +25,7 @@ const MIMETYPE_MAP = {
24
25
  sticker: 'image/webp',
25
26
  'product-catalog-image': 'image/jpeg',
26
27
  };
28
+
27
29
  const MessageTypeProto = {
28
30
  'image': Types_1.WAProto.Message.ImageMessage,
29
31
  'video': Types_1.WAProto.Message.VideoMessage,
@@ -31,14 +33,16 @@ const MessageTypeProto = {
31
33
  'sticker': Types_1.WAProto.Message.StickerMessage,
32
34
  'document': Types_1.WAProto.Message.DocumentMessage,
33
35
  };
36
+
34
37
  const ButtonType = WAProto_1.proto.Message.ButtonsMessage.HeaderType;
35
- /**
36
- * Uses a regex to test whether the string contains a URL, and returns the URL if it does.
37
- * @param text eg. hello https://google.com
38
- * @returns the URL, eg. https://google.com
39
- */
38
+
39
+ const mediaCache = new Map();
40
+ const CACHE_MAX_SIZE = 100;
41
+ const CACHE_TTL = 3600000;
42
+
40
43
  const extractUrlFromText = (text) => { var _a; return (_a = text.match(Defaults_1.URL_REGEX)) === null || _a === void 0 ? void 0 : _a[0]; };
41
44
  exports.extractUrlFromText = extractUrlFromText;
45
+
42
46
  const generateLinkPreviewIfRequired = async (text, getUrlInfo, logger) => {
43
47
  const url = (0, exports.extractUrlFromText)(text);
44
48
  if (!!getUrlInfo && url) {
@@ -46,12 +50,13 @@ const generateLinkPreviewIfRequired = async (text, getUrlInfo, logger) => {
46
50
  const urlInfo = await getUrlInfo(url);
47
51
  return urlInfo;
48
52
  }
49
- catch (error) { // ignore if fails
53
+ catch (error) {
50
54
  logger === null || logger === void 0 ? void 0 : logger.warn({ trace: error.stack }, 'url generation failed');
51
55
  }
52
56
  }
53
57
  };
54
58
  exports.generateLinkPreviewIfRequired = generateLinkPreviewIfRequired;
59
+
55
60
  const assertColor = async (color) => {
56
61
  let assertedColor;
57
62
  if (typeof color === 'number') {
@@ -67,61 +72,88 @@ const assertColor = async (color) => {
67
72
  return assertedColor;
68
73
  }
69
74
  };
75
+
76
+ const cleanMediaCache = () => {
77
+ if (mediaCache.size > CACHE_MAX_SIZE) {
78
+ const entriesToDelete = mediaCache.size - CACHE_MAX_SIZE;
79
+ const keys = Array.from(mediaCache.keys()).slice(0, entriesToDelete);
80
+ keys.forEach(key => mediaCache.delete(key));
81
+ }
82
+ };
83
+
70
84
  const prepareWAMessageMedia = async (message, options) => {
71
85
  const logger = options.logger;
72
86
  let mediaType;
87
+
73
88
  for (const key of Defaults_1.MEDIA_KEYS) {
74
89
  if (key in message) {
75
90
  mediaType = key;
91
+ break;
76
92
  }
77
93
  }
94
+
78
95
  if (!mediaType) {
79
96
  throw new boom_1.Boom('Invalid media type', { statusCode: 400 });
80
97
  }
98
+
81
99
  const uploadData = {
82
100
  ...message,
83
101
  media: message[mediaType]
84
102
  };
85
103
  delete uploadData[mediaType];
86
- // check if cacheable + generate cache key
104
+
87
105
  const cacheableKey = typeof uploadData.media === 'object' &&
88
106
  ('url' in uploadData.media) &&
89
107
  !!uploadData.media.url &&
90
108
  !!options.mediaCache && (
91
- // generate the key
92
- mediaType + ':' + uploadData.media.url.toString());
109
+ mediaType + ':' + uploadData.media.url.toString());
110
+
93
111
  if (mediaType === 'document' && !uploadData.fileName) {
94
112
  uploadData.fileName = 'file';
95
113
  }
114
+
96
115
  if (!uploadData.mimetype) {
97
116
  uploadData.mimetype = MIMETYPE_MAP[mediaType];
98
117
  }
99
- // check for cache hit
118
+
100
119
  if (cacheableKey) {
101
- const mediaBuff = options.mediaCache.get(cacheableKey);
102
- if (mediaBuff) {
103
- logger === null || logger === void 0 ? void 0 : logger.debug({ cacheableKey }, 'got media cache hit');
104
- const obj = Types_1.WAProto.Message.decode(mediaBuff);
120
+ const cached = mediaCache.get(cacheableKey);
121
+ if (cached && (Date.now() - cached.timestamp < CACHE_TTL)) {
122
+ logger === null || logger === void 0 ? void 0 : logger.debug({ cacheableKey }, 'media cache hit');
123
+ const obj = Types_1.WAProto.Message.decode(cached.data);
105
124
  const key = `${mediaType}Message`;
106
125
  Object.assign(obj[key], { ...uploadData, media: undefined });
107
126
  return obj;
108
127
  }
109
128
  }
129
+
110
130
  const requiresDurationComputation = mediaType === 'audio' && typeof uploadData.seconds === 'undefined';
111
131
  const requiresThumbnailComputation = (mediaType === 'image' || mediaType === 'video') &&
112
132
  (typeof uploadData['jpegThumbnail'] === 'undefined');
113
133
  const requiresWaveformProcessing = mediaType === 'audio' && uploadData.ptt === true;
114
134
  const requiresAudioBackground = options.backgroundColor && mediaType === 'audio' && uploadData.ptt === true;
115
135
  const requiresOriginalForSomeProcessing = requiresDurationComputation || requiresThumbnailComputation;
116
- const { mediaKey, encWriteStream, bodyPath, fileEncSha256, fileSha256, fileLength, didSaveToTmpPath, } = await (options.newsletter ? messages_media_1.prepareStream : messages_media_1.encryptedStream)(uploadData.media, options.mediaTypeOverride || mediaType, {
117
- logger,
118
- saveOriginalFileIfRequired: requiresOriginalForSomeProcessing,
119
- opts: options.options
120
- });
136
+
137
+ const { mediaKey, encWriteStream, bodyPath, fileEncSha256, fileSha256, fileLength, didSaveToTmpPath } =
138
+ await (options.newsletter ? messages_media_1.prepareStream : messages_media_1.encryptedStream)(
139
+ uploadData.media,
140
+ options.mediaTypeOverride || mediaType,
141
+ {
142
+ logger,
143
+ saveOriginalFileIfRequired: requiresOriginalForSomeProcessing,
144
+ opts: options.options
145
+ }
146
+ );
147
+
121
148
  const fileEncSha256B64 = (options.newsletter ? fileSha256 : fileEncSha256 !== null && fileEncSha256 !== void 0 ? fileEncSha256 : fileSha256).toString('base64');
149
+
122
150
  const [{ mediaUrl, directPath, handle }] = await Promise.all([
123
151
  (async () => {
124
- const result = await options.upload(encWriteStream, { fileEncSha256B64, mediaType, timeoutMs: options.mediaUploadTimeoutMs });
152
+ const result = await options.upload(encWriteStream, {
153
+ fileEncSha256B64,
154
+ mediaType,
155
+ timeoutMs: options.mediaUploadTimeoutMs || 60000
156
+ });
125
157
  logger === null || logger === void 0 ? void 0 : logger.debug({ mediaType, cacheableKey }, 'uploaded media');
126
158
  return result;
127
159
  })(),
@@ -154,160 +186,60 @@ const prepareWAMessageMedia = async (message, options) => {
154
186
  logger === null || logger === void 0 ? void 0 : logger.warn({ trace: error.stack }, 'failed to obtain extra info');
155
187
  }
156
188
  })(),
157
- ])
158
- .finally(async () => {
189
+ ]).finally(async () => {
159
190
  if (!Buffer.isBuffer(encWriteStream)) {
160
191
  encWriteStream.destroy();
161
192
  }
162
- // remove tmp files
163
193
  if (didSaveToTmpPath && bodyPath) {
164
194
  try {
165
195
  await fs_1.promises.access(bodyPath);
166
196
  await fs_1.promises.unlink(bodyPath);
167
- logger === null || logger === void 0 ? void 0 : logger.debug('removed tmp file');
168
- }
169
- catch (error) {
170
- logger === null || logger === void 0 ? void 0 : logger.warn('failed to remove tmp file');
171
197
  }
198
+ catch { }
172
199
  }
173
200
  });
201
+
202
+ const message = MessageTypeProto[mediaType].fromObject({
203
+ url: mediaUrl,
204
+ directPath,
205
+ mediaKey,
206
+ fileEncSha256: options.newsletter ? fileSha256 : fileEncSha256 !== null && fileEncSha256 !== void 0 ? fileEncSha256 : fileSha256,
207
+ fileSha256: fileSha256,
208
+ fileLength: fileLength,
209
+ mediaKeyTimestamp: (0, generics_1.unixTimestampSeconds)(),
210
+ handle,
211
+ ...uploadData,
212
+ media: undefined
213
+ });
214
+
174
215
  const obj = Types_1.WAProto.Message.fromObject({
175
- [`${mediaType}Message`]: MessageTypeProto[mediaType].fromObject({
176
- url: handle ? undefined : mediaUrl,
177
- directPath,
178
- mediaKey: mediaKey,
179
- fileEncSha256: fileEncSha256,
180
- fileSha256,
181
- fileLength,
182
- mediaKeyTimestamp: handle ? undefined : (0, generics_1.unixTimestampSeconds)(),
183
- ...uploadData,
184
- media: undefined
185
- })
216
+ [`${mediaType}Message`]: MessageTypeProto[mediaType].fromObject(message)
186
217
  });
187
- if (uploadData.ptv) {
188
- obj.ptvMessage = obj.videoMessage;
189
- delete obj.videoMessage;
190
- }
218
+
191
219
  if (cacheableKey) {
192
- logger === null || logger === void 0 ? void 0 : logger.debug({ cacheableKey }, 'set cache');
193
- options.mediaCache.set(cacheableKey, Types_1.WAProto.Message.encode(obj).finish());
220
+ const encoded = Types_1.WAProto.Message.encode(obj).finish();
221
+ mediaCache.set(cacheableKey, {
222
+ data: encoded,
223
+ timestamp: Date.now()
224
+ });
225
+ cleanMediaCache();
194
226
  }
227
+
195
228
  return obj;
196
229
  };
197
230
  exports.prepareWAMessageMedia = prepareWAMessageMedia;
198
- const prepareDisappearingMessageSettingContent = (ephemeralExpiration) => {
199
- ephemeralExpiration = ephemeralExpiration || 0;
200
- const content = {
201
- ephemeralMessage: {
202
- message: {
203
- protocolMessage: {
204
- type: Types_1.WAProto.Message.ProtocolMessage.Type.EPHEMERAL_SETTING,
205
- ephemeralExpiration
206
- }
207
- }
208
- }
209
- };
210
- return Types_1.WAProto.Message.fromObject(content);
211
- };
212
- exports.prepareDisappearingMessageSettingContent = prepareDisappearingMessageSettingContent;
213
- /**
214
- * Generate forwarded message content like WA does
215
- * @param message the message to forward
216
- * @param options.forceForward will show the message as forwarded even if it is from you
217
- */
218
- const generateForwardMessageContent = (message, forceForward) => {
219
- var _a;
220
- let content = message.message;
221
- if (!content) {
222
- throw new boom_1.Boom('no content in message', { statusCode: 400 });
223
- }
224
- // hacky copy
225
- content = (0, exports.normalizeMessageContent)(content);
226
- content = WAProto_1.proto.Message.decode(WAProto_1.proto.Message.encode(content).finish());
227
- let key = Object.keys(content)[0];
228
- let score = ((_a = content[key].contextInfo) === null || _a === void 0 ? void 0 : _a.forwardingScore) || 0;
229
- score += message.key.fromMe && !forceForward ? 0 : 1;
230
- if (key === 'conversation') {
231
- content.extendedTextMessage = { text: content[key] };
232
- delete content.conversation;
233
- key = 'extendedTextMessage';
234
- }
235
- if (score > 0) {
236
- content[key].contextInfo = { forwardingScore: score, isForwarded: true };
237
- }
238
- else {
239
- content[key].contextInfo = {};
240
- }
241
- return content;
242
- };
243
- exports.generateForwardMessageContent = generateForwardMessageContent;
244
- const generateWAMessageContent = async (message, options) => {
245
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
246
- var _p, _q;
247
-
248
- // Cross-platform externalAdReply thumbnail handling
249
- const fixupExternalAdReplyThumb = async (externalAdReply) => {
250
- const thumbUrl = externalAdReply.originalImageUrl || externalAdReply.thumbnailUrl;
251
- const currentThumb = externalAdReply.thumbnail;
252
- const currentThumbLen = currentThumb && typeof currentThumb.length === 'number' ? currentThumb.length : 0;
253
- if (thumbUrl && (!currentThumb || currentThumbLen < 2000)) {
254
- try {
255
- const stream = await (0, messages_media_1.getHttpStream)(thumbUrl, {
256
- timeout: 8000,
257
- headers: {
258
- 'User-Agent': 'WhatsApp/2.23.20.15 iOS/16.0 Device/iPhone'
259
- }
260
- });
261
- const { buffer } = await (0, messages_media_1.extractImageThumb)(stream, 512, 80);
262
- externalAdReply.thumbnail = buffer;
263
- }
264
- catch (error) {
265
- options.logger?.warn('Failed to generate externalAdReply thumbnail for cross-platform compatibility:', error.message);
266
- }
267
- }
268
- if (externalAdReply.renderLargerThumbnail === undefined) {
269
- externalAdReply.renderLargerThumbnail = true;
270
- }
271
- return externalAdReply;
272
- };
273
- if (message.contextInfo?.externalAdReply) {
274
- message.contextInfo.externalAdReply = await fixupExternalAdReplyThumb(message.contextInfo.externalAdReply);
275
- }
276
- if (message.externalAdReply) {
277
- message.externalAdReply = await fixupExternalAdReplyThumb(message.externalAdReply);
278
- }
279
231
 
232
+ const generateWAMessageContent = async (message, options) => {
280
233
  let m = {};
234
+
281
235
  if ('text' in message) {
282
- const extContent = { text: message.text };
283
- let urlInfo = message.linkPreview;
284
- if (urlInfo === true) {
285
- urlInfo = await (0, exports.generateLinkPreviewIfRequired)(message.text, options.getUrlInfo, options.logger);
286
- }
287
- if (urlInfo && typeof urlInfo === 'object') {
288
- extContent.matchedText = urlInfo['matched-text'];
289
- extContent.jpegThumbnail = urlInfo.jpegThumbnail;
290
- extContent.description = urlInfo.description;
291
- extContent.title = urlInfo.title;
292
- extContent.previewType = 0;
293
- const img = urlInfo.highQualityThumbnail;
294
- if (img) {
295
- extContent.thumbnailDirectPath = img.directPath;
296
- extContent.mediaKey = img.mediaKey;
297
- extContent.mediaKeyTimestamp = img.mediaKeyTimestamp;
298
- extContent.thumbnailWidth = img.width;
299
- extContent.thumbnailHeight = img.height;
300
- extContent.thumbnailSha256 = img.fileSha256;
301
- extContent.thumbnailEncSha256 = img.fileEncSha256;
302
- }
303
- }
304
- if (options.backgroundColor) {
305
- extContent.backgroundArgb = await assertColor(options.backgroundColor);
306
- }
307
- if (options.font) {
308
- extContent.font = options.font;
236
+ const extContent = await (0, exports.generateLinkPreviewIfRequired)(message.text, options.getUrlInfo, options.logger);
237
+ m.extendedTextMessage = { text: message.text };
238
+ if (extContent) {
239
+ m.extendedTextMessage.contextInfo = {
240
+ externalAdReply: extContent
241
+ };
309
242
  }
310
- m.extendedTextMessage = extContent;
311
243
  }
312
244
  else if ('contacts' in message) {
313
245
  const contactLen = message.contacts.contacts.length;
@@ -324,13 +256,7 @@ const generateWAMessageContent = async (message, options) => {
324
256
  else if ('location' in message) {
325
257
  m.locationMessage = Types_1.WAProto.Message.LocationMessage.fromObject(message.location);
326
258
  }
327
- else if ('liveLocation' in message) {
328
- m.liveLocationMessage = Types_1.WAProto.Message.LiveLocationMessage.fromObject(message.liveLocation);
329
- }
330
259
  else if ('react' in message) {
331
- if (!message.react.senderTimestampMs) {
332
- message.react.senderTimestampMs = Date.now();
333
- }
334
260
  m.reactionMessage = Types_1.WAProto.Message.ReactionMessage.fromObject(message.react);
335
261
  }
336
262
  else if ('delete' in message) {
@@ -339,948 +265,66 @@ const generateWAMessageContent = async (message, options) => {
339
265
  type: Types_1.WAProto.Message.ProtocolMessage.Type.REVOKE
340
266
  };
341
267
  }
342
- else if ('forward' in message) {
343
- m = (0, exports.generateForwardMessageContent)(message.forward, message.force);
344
- }
345
- else if ('disappearingMessagesInChat' in message) {
346
- const exp = typeof message.disappearingMessagesInChat === 'boolean' ?
347
- (message.disappearingMessagesInChat ? Defaults_1.WA_DEFAULT_EPHEMERAL : 0) :
348
- message.disappearingMessagesInChat;
349
- m = (0, exports.prepareDisappearingMessageSettingContent)(exp);
350
- }
351
- else if ('groupInvite' in message) {
352
- m.groupInviteMessage = {};
353
- m.groupInviteMessage.inviteCode = message.groupInvite.inviteCode;
354
- m.groupInviteMessage.inviteExpiration = message.groupInvite.inviteExpiration;
355
- m.groupInviteMessage.caption = message.groupInvite.text;
356
- m.groupInviteMessage.groupJid = message.groupInvite.jid;
357
- m.groupInviteMessage.groupName = message.groupInvite.subject;
358
-
359
- // Get group metadata to obtain disappearing mode and other group info
360
- if (options.groupMetadata) {
361
- try {
362
- const groupMetadata = await options.groupMetadata(message.groupInvite.jid);
363
- if (groupMetadata) {
364
- // Add disappearing mode info if available
365
- if (groupMetadata.ephemeralDuration !== undefined) {
366
- m.groupInviteMessage.ephemeralDuration = groupMetadata.ephemeralDuration;
367
- }
368
- // Add group subject from metadata if not provided in message
369
- if (!m.groupInviteMessage.groupName && groupMetadata.subject) {
370
- m.groupInviteMessage.groupName = groupMetadata.subject;
371
- }
372
- // Add group participant count
373
- if (groupMetadata.participants) {
374
- m.groupInviteMessage.groupSize = groupMetadata.participants.length;
375
- }
376
- }
377
- } catch (error) {
378
- options.logger?.debug({ error, jid: message.groupInvite.jid }, 'Failed to fetch group metadata for invite');
379
- }
268
+ else if ('forward' in message || 'copy' in message) {
269
+ const content = (0, exports.normalizeMessageContent)(message.forward || message.copy);
270
+ if (!content) {
271
+ throw new boom_1.Boom('no content present in forwarded/copied message', { statusCode: 400 });
380
272
  }
381
-
382
- // Handle profile picture with caching
383
- if (options.getProfilePicUrl) {
384
- const cacheKey = `group_pfp:${message.groupInvite.jid}`;
385
-
386
- // Check cache first if available
387
- if (options.cache && options.cache.get) {
388
- const cachedPfp = options.cache.get(cacheKey);
389
- if (cachedPfp) {
390
- m.groupInviteMessage.jpegThumbnail = cachedPfp;
391
- }
392
- }
393
-
394
- // Fetch if not in cache
395
- if (!m.groupInviteMessage.jpegThumbnail) {
396
- try {
397
- const pfpUrl = await options.getProfilePicUrl(message.groupInvite.jid, 'preview');
398
- if (pfpUrl) {
399
- const resp = await axios_1.default.get(pfpUrl, {
400
- responseType: 'arraybuffer',
401
- timeout: 5000,
402
- headers: {
403
- 'User-Agent': 'WhatsApp/2.23.20.15 iOS/16.0 Device/iPhone'
404
- }
405
- });
406
- if (resp.status === 200) {
407
- m.groupInviteMessage.jpegThumbnail = resp.data;
408
-
409
- // Cache the result if cache is available
410
- if (options.cache && options.cache.set) {
411
- options.cache.set(cacheKey, resp.data, 3600); // Cache for 1 hour
412
- }
413
- }
414
- }
415
- } catch (error) {
416
- options.logger?.debug({ error, jid: message.groupInvite.jid }, 'Failed to fetch group profile picture');
417
- }
418
- }
419
- }
420
- }
421
- else if ('pin' in message) {
422
- const pinData = typeof message.pin === 'object' ? message.pin : { key: message.pin };
423
- // Map type: 1 = PIN_FOR_ALL, 2 = UNPIN_FOR_ALL
424
- const pinType = pinData.type !== undefined ? pinData.type : (message.type !== undefined ? message.type : WAProto_1.proto.Message.PinInChatMessage.Type.PIN_FOR_ALL);
425
- m.pinInChatMessage = {
426
- key: pinData.key,
427
- type: pinType,
428
- senderTimestampMs: Date.now()
429
- };
430
- // Add messageContextInfo only for PIN (type 1), not for UNPIN (type 2)
431
- if (pinType === WAProto_1.proto.Message.PinInChatMessage.Type.PIN_FOR_ALL) {
432
- m.messageContextInfo = {
433
- messageAddOnDurationInSecs: pinData.time || message.time || 86400, // Default 24 hours
434
- messageAddOnExpiryType: WAProto_1.proto.MessageContextInfo.MessageAddonExpiryType.STATIC
273
+ let key = Object.keys(content)[0];
274
+ let score = content[key].contextInfo?.forwardingScore || 0;
275
+ score += message.force ? 0 : 1;
276
+ if (key === 'conversation') {
277
+ m.extendedTextMessage = {
278
+ text: content[key]
435
279
  };
436
- }
437
- }
438
- else if ('keep' in message) {
439
- m.keepInChatMessage = {};
440
- m.keepInChatMessage.key = message.keep;
441
- m.keepInChatMessage.keepType = message.type;
442
- m.keepInChatMessage.timestampMs = Date.now();
443
- }
444
- else if ('call' in message) {
445
- const call = message.call;
446
- if (call && typeof call === 'object' && (
447
- 'callKey' in call
448
- || 'conversionSource' in call
449
- || 'conversionData' in call
450
- || 'conversionDelaySeconds' in call
451
- || 'ctwaSignals' in call
452
- || 'ctwaPayload' in call
453
- || 'nativeFlowCallButtonPayload' in call
454
- || 'deeplinkPayload' in call
455
- )) {
456
- m.call = WAProto_1.proto.Message.Call.fromObject(call);
280
+ key = 'extendedTextMessage';
457
281
  }
458
282
  else {
459
- m = {
460
- scheduledCallCreationMessage: {
461
- scheduledTimestampMs: (_a = call === null || call === void 0 ? void 0 : call.time) !== null && _a !== void 0 ? _a : Date.now(),
462
- callType: (_b = call === null || call === void 0 ? void 0 : call.type) !== null && _b !== void 0 ? _b : 1,
463
- title: call === null || call === void 0 ? void 0 : call.title
464
- }
465
- };
283
+ m = { [key]: content[key] };
466
284
  }
467
- }
468
- else if ('paymentInvite' in message) {
469
- m.paymentInviteMessage = {
470
- serviceType: message.paymentInvite.type,
471
- expiryTimestamp: message.paymentInvite.expiry
472
- };
473
- }
474
- else if ('buttonReply' in message) {
475
- switch (message.type) {
476
- case 'template':
477
- m.templateButtonReplyMessage = {
478
- selectedDisplayText: message.buttonReply.displayText,
479
- selectedId: message.buttonReply.id,
480
- selectedIndex: message.buttonReply.index,
481
- selectedCarouselCardIndex: message.buttonReply.carouselCardIndex
482
- };
483
- break;
484
- case 'plain':
485
- m.buttonsResponseMessage = {
486
- selectedButtonId: message.buttonReply.id,
487
- selectedDisplayText: message.buttonReply.displayText,
488
- type: WAProto_1.proto.Message.ButtonsResponseMessage.Type.DISPLAY_TEXT,
489
- };
490
- break;
491
- }
492
- }
493
- else if ('ptv' in message && message.ptv) {
494
- const { videoMessage } = await (0, exports.prepareWAMessageMedia)({ video: message.video }, options);
495
- m.ptvMessage = videoMessage;
496
- }
497
- else if ('product' in message) {
498
- const { imageMessage } = await (0, exports.prepareWAMessageMedia)({ image: message.product.productImage }, options);
499
- m.productMessage = Types_1.WAProto.Message.ProductMessage.fromObject({
500
- ...message,
501
- product: {
502
- ...message.product,
503
- productImage: imageMessage,
504
- }
505
- });
506
- }
507
- else if ('order' in message) {
508
- m.orderMessage = Types_1.WAProto.Message.OrderMessage.fromObject({
509
- orderId: message.order.id,
510
- thumbnail: message.order.thumbnail,
511
- itemCount: message.order.itemCount,
512
- status: message.order.status,
513
- surface: message.order.surface,
514
- orderTitle: message.order.title,
515
- message: message.order.text,
516
- sellerJid: message.order.seller,
517
- token: message.order.token,
518
- totalAmount1000: message.order.amount,
519
- totalCurrencyCode: message.order.currency
520
- });
521
- }
522
- else if ('listReply' in message) {
523
- m.listResponseMessage = { ...message.listReply };
524
- }
525
- else if ('poll' in message) {
526
- (_p = message.poll).selectableCount || (_p.selectableCount = 0);
527
- (_q = message.poll).toAnnouncementGroup || (_q.toAnnouncementGroup = false);
528
- if (!Array.isArray(message.poll.values)) {
529
- throw new boom_1.Boom('Invalid poll values', { statusCode: 400 });
530
- }
531
- if (message.poll.selectableCount < 0
532
- || message.poll.selectableCount > message.poll.values.length) {
533
- throw new boom_1.Boom(`poll.selectableCount in poll should be >= 0 and <= ${message.poll.values.length}`, { statusCode: 400 });
534
- }
535
- m.messageContextInfo = {
536
- // encKey
537
- messageSecret: message.poll.messageSecret || (0, crypto_1.randomBytes)(32),
538
- };
539
- const pollCreationMessage = {
540
- name: message.poll.name,
541
- selectableOptionsCount: message.poll.selectableCount,
542
- options: message.poll.values.map(optionName => ({ optionName })),
543
- };
544
- if (message.poll.toAnnouncementGroup) {
545
- // poll v2 is for community announcement groups (single select and multiple)
546
- m.pollCreationMessageV2 = pollCreationMessage;
285
+ if (score > 0) {
286
+ m[key].contextInfo = { ...(m[key].contextInfo || {}), forwardingScore: score, isForwarded: true };
547
287
  }
548
288
  else {
549
- if (message.poll.selectableCount === 1) {
550
- // poll v3 is for single select polls
551
- m.pollCreationMessageV3 = pollCreationMessage;
552
- }
553
- else {
554
- // poll for multiple choice polls
555
- m.pollCreationMessage = pollCreationMessage;
556
- }
557
- }
558
- }
559
- else if ('pollResultSnapshotV3' in message && !!message.pollResultSnapshotV3) {
560
- m.pollResultSnapshotMessageV3 = {
561
- pollCreationMessageKey: message.pollResultSnapshotV3.pollCreationMessageKey,
562
- pollResult: message.pollResultSnapshotV3.pollResult,
563
- selectedOptions: message.pollResultSnapshotV3.selectedOptions,
564
- contextInfo: message.pollResultSnapshotV3.contextInfo,
565
- pollType: message.pollResultSnapshotV3.pollType
566
- };
567
- }
568
- else if ('pollV4' in message) {
569
- const pollCreationMessage = {
570
- name: message.pollV4.name,
571
- selectableOptionsCount: message.pollV4.selectableCount,
572
- options: message.pollV4.values.map(optionName => ({ optionName })),
573
- pollType: message.pollV4.pollType
574
- };
575
- m.pollCreationMessageV4 = pollCreationMessage;
576
- }
577
- else if ('pollV5' in message) {
578
- const pollCreationMessage = {
579
- name: message.pollV5.name,
580
- selectableOptionsCount: message.pollV5.selectableCount,
581
- options: message.pollV5.values.map(optionName => ({ optionName })),
582
- pollType: message.pollV5.pollType
583
- };
584
- m.pollCreationMessageV5 = pollCreationMessage;
585
- }
586
- else if ('event' in message) {
587
- m.messageContextInfo = {
588
- messageSecret: message.event.messageSecret || (0, crypto_1.randomBytes)(32),
589
- };
590
- m.eventMessage = { ...message.event };
591
- }
592
- else if ('comment' in message) {
593
- m.commentMessage = {
594
- message: message.comment.message,
595
- targetMessageKey: message.comment.targetMessageKey
596
- };
597
- }
598
- else if ('question' in message) {
599
- m.questionMessage = {
600
- text: message.question.text,
601
- contextInfo: message.question.contextInfo
602
- };
603
- }
604
- else if ('questionResponse' in message) {
605
- m.questionResponseMessage = {
606
- key: message.questionResponse.key,
607
- text: message.questionResponse.text
608
- };
609
- }
610
- else if ('statusQuestionAnswer' in message) {
611
- m.statusQuestionAnswerMessage = {
612
- key: message.statusQuestionAnswer.key,
613
- text: message.statusQuestionAnswer.text
614
- };
615
- }
616
- else if ('statusQuoted' in message) {
617
- m.statusQuotedMessage = {
618
- type: message.statusQuoted.type,
619
- text: message.statusQuoted.text,
620
- thumbnail: message.statusQuoted.thumbnail,
621
- originalStatusId: message.statusQuoted.originalStatusId
622
- };
623
- }
624
- else if ('statusStickerInteraction' in message) {
625
- m.statusStickerInteractionMessage = {
626
- key: message.statusStickerInteraction.key,
627
- stickerKey: message.statusStickerInteraction.stickerKey,
628
- type: message.statusStickerInteraction.type
629
- };
630
- }
631
- else if ('richResponse' in message) {
632
- m.richResponseMessage = WAProto_1.proto.AIRichResponseMessage.fromObject({
633
- messageType: message.richResponse.messageType !== undefined ? message.richResponse.messageType : 1, // AI_RICH_RESPONSE_TYPE_STANDARD
634
- submessages: message.richResponse.submessages || [],
635
- unifiedResponse: message.richResponse.unifiedResponse,
636
- contextInfo: message.richResponse.contextInfo
637
- });
638
- }
639
- else if ('eventResponse' in message && !!message.eventResponse) {
640
- m.eventResponseMessage = {
641
- response: message.eventResponse.response, // GOING = 1, NOT_GOING = 2, MAYBE = 3
642
- timestampMs: message.eventResponse.timestampMs || Date.now(),
643
- extraGuestCount: message.eventResponse.extraGuestCount
644
- };
645
- }
646
- else if ('statusMention' in message && !!message.statusMention) {
647
- m.statusMentionMessage = {
648
- quotedStatus: message.statusMention.quotedStatus
649
- };
650
- }
651
- else if ('groupStatus' in message && !!message.groupStatus) {
652
- m.groupStatusMessage = message.groupStatus.message;
653
- }
654
- else if ('botTask' in message && !!message.botTask) {
655
- m.botTaskMessage = message.botTask.message;
656
- }
657
- else if ('limitSharing' in message && !!message.limitSharing) {
658
- m.limitSharingMessage = message.limitSharing.message;
659
- }
660
- else if ('statusAddYours' in message && !!message.statusAddYours) {
661
- m.statusAddYours = message.statusAddYours.message;
662
- }
663
- else if ('botForwarded' in message && !!message.botForwarded) {
664
- m.botForwardedMessage = message.botForwarded.message;
665
- }
666
- else if ('eventCoverImage' in message && !!message.eventCoverImage) {
667
- m.eventCoverImage = message.eventCoverImage.message;
668
- }
669
- else if ('stickerPack' in message && !!message.stickerPack) {
670
- const pack = message.stickerPack;
671
- const stickerPackMessage = {
672
- name: pack.name,
673
- publisher: pack.publisher,
674
- packDescription: pack.description,
675
- stickerPackId: pack.stickerPackId || (0, crypto_1.randomBytes)(16).toString('hex'),
676
- stickerPackOrigin: pack.origin || 2 // USER_CREATED = 2
677
- };
678
- // Process cover if provided
679
- if (pack.cover) {
680
- const coverMedia = await (0, exports.prepareWAMessageMedia)({ image: pack.cover }, options);
681
- stickerPackMessage.thumbnailDirectPath = coverMedia.imageMessage.directPath;
682
- stickerPackMessage.thumbnailSha256 = coverMedia.imageMessage.thumbnailSha256;
683
- stickerPackMessage.thumbnailEncSha256 = coverMedia.imageMessage.thumbnailEncSha256;
684
- stickerPackMessage.thumbnailHeight = coverMedia.imageMessage.height;
685
- stickerPackMessage.thumbnailWidth = coverMedia.imageMessage.width;
686
- }
687
- // Process stickers
688
- if (pack.stickers && pack.stickers.length > 0) {
689
- const processedStickers = await Promise.all(pack.stickers.map(async (sticker) => {
690
- const stickerMedia = await (0, exports.prepareWAMessageMedia)({ sticker: sticker.sticker }, options);
691
- return {
692
- fileName: sticker.fileName || `sticker_${Date.now()}.webp`,
693
- isAnimated: sticker.isAnimated || false,
694
- emojis: sticker.emojis || [],
695
- accessibilityLabel: sticker.accessibilityLabel,
696
- isLottie: sticker.isLottie || false,
697
- mimetype: sticker.mimetype || stickerMedia.stickerMessage.mimetype
698
- };
699
- }));
700
- stickerPackMessage.stickers = processedStickers;
701
- stickerPackMessage.stickerPackSize = processedStickers.length;
702
- }
703
- if (pack.caption) {
704
- stickerPackMessage.caption = pack.caption;
289
+ m[key].contextInfo = m[key].contextInfo || {};
705
290
  }
706
- m.stickerPackMessage = stickerPackMessage;
707
- }
708
- else if ('interactiveResponse' in message && !!message.interactiveResponse) {
709
- const response = message.interactiveResponse;
710
- const interactiveResponseMessage = {
711
- body: {
712
- text: response.body?.text || '',
713
- format: response.body?.format || 0 // DEFAULT = 0
714
- }
715
- };
716
- if (response.nativeFlowResponse) {
717
- interactiveResponseMessage.nativeFlowResponseMessage = {
718
- name: response.nativeFlowResponse.name,
719
- paramsJson: response.nativeFlowResponse.paramsJson,
720
- version: response.nativeFlowResponse.version || 1
721
- };
722
- }
723
- if (response.contextInfo) {
724
- interactiveResponseMessage.contextInfo = response.contextInfo;
725
- }
726
- m.interactiveResponseMessage = interactiveResponseMessage;
727
- }
728
- else if ('bCall' in message && !!message.bCall) {
729
- m.bcallMessage = {
730
- sessionId: message.bCall.sessionId,
731
- mediaType: message.bCall.mediaType || 0, // UNKNOWN = 0, AUDIO = 1, VIDEO = 2
732
- masterKey: message.bCall.masterKey,
733
- caption: message.bCall.caption
734
- };
735
- }
736
- else if ('callLog' in message && !!message.callLog) {
737
- m.callLogMesssage = {
738
- isVideo: message.callLog.isVideo || false,
739
- callOutcome: message.callLog.callOutcome || 0, // CONNECTED = 0
740
- durationSecs: message.callLog.durationSecs,
741
- callType: message.callLog.callType || 0, // REGULAR = 0
742
- participants: message.callLog.participants || []
743
- };
744
- }
745
- else if ('encComment' in message && !!message.encComment) {
746
- m.encCommentMessage = {
747
- targetMessageKey: message.encComment.targetMessageKey,
748
- encPayload: message.encComment.encPayload,
749
- encIv: message.encComment.encIv
750
- };
751
- }
752
- else if ('encEventResponse' in message && !!message.encEventResponse) {
753
- m.encEventResponseMessage = {
754
- eventCreationMessageKey: message.encEventResponse.eventCreationMessageKey,
755
- encPayload: message.encEventResponse.encPayload,
756
- encIv: message.encEventResponse.encIv
757
- };
758
- }
759
- else if ('messageHistoryBundle' in message && !!message.messageHistoryBundle) {
760
- const bundle = message.messageHistoryBundle;
761
- const bundleMedia = bundle.media ? await (0, exports.prepareWAMessageMedia)({ document: bundle.media }, options) : null;
762
- m.messageHistoryBundle = {
763
- mimetype: bundle.mimetype || 'application/octet-stream',
764
- fileSha256: bundleMedia?.documentMessage?.fileSha256,
765
- mediaKey: bundleMedia?.documentMessage?.mediaKey,
766
- fileEncSha256: bundleMedia?.documentMessage?.fileEncSha256,
767
- directPath: bundleMedia?.documentMessage?.directPath,
768
- mediaKeyTimestamp: bundleMedia?.documentMessage?.mediaKeyTimestamp,
769
- contextInfo: bundle.contextInfo,
770
- messageHistoryMetadata: bundle.messageHistoryMetadata
771
- };
772
- }
773
- else if ('messageHistoryNotice' in message && !!message.messageHistoryNotice) {
774
- m.messageHistoryNotice = {
775
- contextInfo: message.messageHistoryNotice.contextInfo,
776
- messageHistoryMetadata: message.messageHistoryNotice.messageHistoryMetadata
777
- };
778
- }
779
- else if ('inviteFollower' in message && !!message.inviteFollower) {
780
- m.newsletterFollowerInviteMessageV2 = {
781
- newsletterJid: message.inviteFollower.newsletterJid,
782
- newsletterName: message.inviteFollower.newsletterName,
783
- jpegThumbnail: message.inviteFollower.thumbnail,
784
- caption: message.inviteFollower.caption,
785
- contextInfo: message.inviteFollower.contextInfo
786
- };
787
- }
788
- else if ('placeholder' in message && !!message.placeholder) {
789
- m.placeholderMessage = {
790
- type: message.placeholder.type || 0 // MASK_LINKED_DEVICES = 0
791
- };
792
291
  }
793
- else if ('secretEncrypted' in message && !!message.secretEncrypted) {
794
- m.secretEncryptedMessage = {
795
- targetMessageKey: message.secretEncrypted.targetMessageKey,
796
- encPayload: message.secretEncrypted.encPayload,
797
- encIv: message.secretEncrypted.encIv,
798
- secretEncType: message.secretEncrypted.secretEncType || 0 // UNKNOWN = 0, EVENT_EDIT = 1, MESSAGE_EDIT = 2
799
- };
800
- }
801
- else if ('statusNotification' in message && !!message.statusNotification) {
802
- m.statusNotificationMessage = {
803
- responseMessageKey: message.statusNotification.responseMessageKey,
804
- originalMessageKey: message.statusNotification.originalMessageKey,
805
- type: message.statusNotification.type || 0 // UNKNOWN = 0, STATUS_ADD_YOURS = 1, STATUS_RESHARE = 2, STATUS_QUESTION_ANSWER_RESHARE = 3
806
- };
292
+ else if ('listMessage' in message) {
293
+ m = { listMessage: Types_1.WAProto.Message.ListMessage.fromObject(message.listMessage) };
807
294
  }
808
- else if ('stickerSyncRMR' in message && !!message.stickerSyncRMR) {
809
- m.stickerSyncRmrMessage = {
810
- filehash: message.stickerSyncRMR.filehash || [],
811
- rmrSource: message.stickerSyncRMR.rmrSource,
812
- requestTimestamp: message.stickerSyncRMR.requestTimestamp || Date.now()
813
- };
814
- }
815
- else if ('inviteAdmin' in message) {
816
- m.newsletterAdminInviteMessage = {};
817
- m.newsletterAdminInviteMessage.inviteExpiration = message.inviteAdmin.inviteExpiration;
818
- m.newsletterAdminInviteMessage.caption = message.inviteAdmin.text;
819
- m.newsletterAdminInviteMessage.newsletterJid = message.inviteAdmin.jid;
820
- m.newsletterAdminInviteMessage.newsletterName = message.inviteAdmin.subject;
821
- m.newsletterAdminInviteMessage.jpegThumbnail = message.inviteAdmin.thumbnail;
822
- }
823
- else if ('requestPayment' in message) {
824
- const reqPayment = message.requestPayment;
825
- const sticker = reqPayment.sticker ?
826
- await (0, exports.prepareWAMessageMedia)({ sticker: reqPayment.sticker }, options)
827
- : null;
828
- let notes = {};
829
- if (reqPayment.sticker) {
830
- notes = {
831
- stickerMessage: {
832
- ...sticker.stickerMessage,
833
- contextInfo: reqPayment.contextInfo
834
- }
835
- };
836
- }
837
- else if (reqPayment.note) {
838
- notes = {
839
- extendedTextMessage: {
840
- text: reqPayment.note,
841
- contextInfo: reqPayment.contextInfo,
842
- }
843
- };
844
- }
845
- else {
846
- throw new boom_1.Boom('Invalid media type', { statusCode: 400 });
847
- }
848
- m.requestPaymentMessage = Types_1.WAProto.Message.RequestPaymentMessage.fromObject({
849
- expiryTimestamp: reqPayment.expiryTimestamp || reqPayment.expiry,
850
- amount1000: reqPayment.amount1000 || reqPayment.amount,
851
- currencyCodeIso4217: reqPayment.currencyCodeIso4217 || reqPayment.currency,
852
- requestFrom: reqPayment.requestFrom || reqPayment.from,
853
- noteMessage: { ...notes },
854
- background: reqPayment.background,
855
- // Aggiungi altri parametri se disponibili
856
- ...reqPayment
857
- });
858
-
859
- // Pix adaptation for Brazilian payments
860
- if (reqPayment.currencyCodeIso4217 === 'BRL' && reqPayment.pixKey) {
861
- // Embed Pix key in note for dynamic requests
862
- if (!m.requestPaymentMessage.noteMessage.extendedTextMessage) {
863
- m.requestPaymentMessage.noteMessage = { extendedTextMessage: { text: '' } };
864
- }
865
- m.requestPaymentMessage.noteMessage.extendedTextMessage.text += `\nPix Key: ${reqPayment.pixKey}`;
866
- }
867
- }
868
- else if ('sharePhoneNumber' in message) {
295
+ else if ('disappearingMessagesInChat' in message) {
296
+ const exp = typeof message.disappearingMessagesInChat === 'boolean' && message.disappearingMessagesInChat ?
297
+ Defaults_1.WA_DEFAULT_EPHEMERAL : 0;
869
298
  m.protocolMessage = {
870
- type: WAProto_1.proto.Message.ProtocolMessage.Type.SHARE_PHONE_NUMBER
299
+ ephemeralExpiration: exp,
300
+ type: Types_1.WAProto.Message.ProtocolMessage.Type.EPHEMERAL_SETTING,
301
+ ephemeralSettingTimestamp: (0, generics_1.unixTimestampSeconds)()
871
302
  };
872
303
  }
873
- else if ('requestPhoneNumber' in message) {
874
- m.requestPhoneNumberMessage = {};
875
- }
876
- else if ('newsletterMessage' in message) {
877
- m.newsletterMessage = Types_1.WAProto.Message.NewsletterMessage.fromObject(message.newsletterMessage);
878
- }
879
- else if ('externalAdReply' in message) {
880
- // Handle sendNyanCat functionality - external ad reply
881
- const extAdReply = message.externalAdReply;
882
- m.extendedTextMessage = {
883
- text: message.text || '',
884
- contextInfo: {
885
- externalAdReply: {
886
- title: extAdReply.title,
887
- body: extAdReply.body,
888
- mediaType: extAdReply.mediaType || 1,
889
- thumbnailUrl: extAdReply.thumbnailUrl,
890
- thumbnail: extAdReply.thumbnail,
891
- sourceUrl: extAdReply.sourceUrl,
892
- showAdAttribution: extAdReply.showAdAttribution || false,
893
- renderLargerThumbnail: extAdReply.renderLargerThumbnail !== false
894
- }
895
- }
896
- };
897
- }
898
- else if ('sendPayment' in message && !!message.sendPayment) {
899
- const payment = message.sendPayment;
900
- m.sendPaymentMessage = {
901
- requestMessageKey: payment.requestMessageKey,
902
- noteMessage: payment.noteMessage,
903
- background: payment.background,
904
- transactionData: payment.transactionData
905
- };
906
- }
907
- else if ('declinePayment' in message && !!message.declinePayment) {
908
- m.declinePaymentRequestMessage = {
909
- key: message.declinePayment.key
910
- };
911
- }
912
- else if ('cancelPayment' in message && !!message.cancelPayment) {
913
- m.cancelPaymentRequestMessage = {
914
- key: message.cancelPayment.key
915
- };
916
- }
917
- else if ('scheduledCallEdit' in message && !!message.scheduledCallEdit) {
918
- m.scheduledCallEditMessage = {
919
- key: message.scheduledCallEdit.key,
920
- editType: message.scheduledCallEdit.editType || 0 // UNKNOWN = 0, CANCEL = 1
921
- };
922
- }
923
- else if ('pollResultSnapshot' in message && !!message.pollResultSnapshot) {
924
- m.pollResultSnapshotMessage = {
925
- name: message.pollResultSnapshot.name,
926
- pollVotes: message.pollResultSnapshot.pollVotes || [],
927
- contextInfo: message.pollResultSnapshot.contextInfo,
928
- pollType: message.pollResultSnapshot.pollType || 0 // POLL = 0, QUIZ = 1
929
- };
930
- }
931
- else if ('pollUpdate' in message && !!message.pollUpdate) {
932
- m.pollUpdateMessage = {
933
- pollCreationMessageKey: message.pollUpdate.pollCreationMessageKey,
934
- vote: message.pollUpdate.vote,
935
- metadata: message.pollUpdate.metadata,
936
- senderTimestampMs: message.pollUpdate.senderTimestampMs || Date.now()
937
- };
938
- }
939
- else if ('deviceSent' in message && !!message.deviceSent) {
940
- const deviceSent = message.deviceSent;
941
- const innerMessage = await (0, exports.generateWAMessageContent)(deviceSent.message, options);
942
- m.deviceSentMessage = {
943
- destinationJid: deviceSent.destinationJid,
944
- message: innerMessage,
945
- phash: deviceSent.phash
946
- };
947
- }
948
- else if ('chat' in message && !!message.chat) {
949
- m.chat = {
950
- displayName: message.chat.displayName,
951
- id: message.chat.id
952
- };
953
- }
954
- else if ('payment' in message) {
955
- // Handle sendPayment functionality
956
- m.requestPaymentMessage = Types_1.WAProto.Message.RequestPaymentMessage.fromObject({
957
- currencyCodeIso4217: message.payment.currency || 'EUR',
958
- amount1000: message.payment.amount1000 || message.payment.amount * 1000,
959
- requestFrom: message.payment.requestFrom || message.payment.from,
960
- noteMessage: {
961
- extendedTextMessage: {
962
- text: message.payment.text || message.payment.note || '',
963
- contextInfo: message.payment.contextInfo
964
- }
965
- },
966
- expiryTimestamp: message.payment.expiryTimestamp || message.payment.expiry,
967
- background: message.payment.background
968
- });
969
- }
970
- else if ('comment' in message) {
971
- m.commentMessage = {
972
- message: message.comment.message,
973
- targetMessageKey: message.comment.targetMessageKey
974
- };
975
- }
976
- else if ('question' in message) {
977
- m.questionMessage = {
978
- text: message.question.text,
979
- contextInfo: message.question.contextInfo
980
- };
981
- }
982
- else if ('questionResponse' in message) {
983
- m.questionResponseMessage = {
984
- key: message.questionResponse.key,
985
- text: message.questionResponse.text
986
- };
987
- }
988
- else if ('statusQuestionAnswer' in message) {
989
- m.statusQuestionAnswerMessage = {
990
- key: message.statusQuestionAnswer.key,
991
- text: message.statusQuestionAnswer.text
304
+ else if ('buttonReply' in message) {
305
+ m.templateButtonReplyMessage = {
306
+ selectedId: message.buttonReply.id,
307
+ selectedDisplayText: message.buttonReply.displayText
992
308
  };
993
309
  }
994
- else if ('statusQuoted' in message) {
995
- m.statusQuotedMessage = {
996
- type: message.statusQuoted.type,
997
- text: message.statusQuoted.text,
998
- thumbnail: message.statusQuoted.thumbnail,
999
- jid: message.statusQuoted.jid,
1000
- originalStatusId: message.statusQuoted.originalStatusId
1001
- };
310
+ else if ('listReply' in message) {
311
+ m.listResponseMessage = Types_1.WAProto.Message.ListResponseMessage.fromObject(message.listReply);
1002
312
  }
1003
- else if ('statusStickerInteraction' in message) {
1004
- m.statusStickerInteractionMessage = {
1005
- key: message.statusStickerInteraction.key,
1006
- stickerKey: message.statusStickerInteraction.stickerKey,
1007
- type: message.statusStickerInteraction.type
1008
- };
313
+ else if ('poll' in message) {
314
+ m.pollCreationMessage = Types_1.WAProto.Message.PollCreationMessage.fromObject(message.poll);
315
+ if (!m.pollCreationMessage.selectableOptionsCount) {
316
+ m.pollCreationMessage.selectableOptionsCount = 0;
317
+ }
1009
318
  }
1010
- else if ('album' in message) {
1011
- const imageMessages = message.album.filter(item => 'image' in item);
1012
- const videoMessages = message.album.filter(item => 'video' in item);
1013
- m.albumMessage = WAProto_1.proto.Message.AlbumMessage.fromObject({
1014
- expectedImageCount: imageMessages.length,
1015
- expectedVideoCount: videoMessages.length,
1016
- });
319
+ else if ('pollUpdate' in message) {
320
+ m.pollUpdateMessage = Types_1.WAProto.Message.PollUpdateMessage.fromObject(message.pollUpdate);
1017
321
  }
1018
322
  else {
1019
323
  m = await (0, exports.prepareWAMessageMedia)(message, options);
1020
324
  }
1021
- if ('buttons' in message && !!message.buttons) {
1022
- const buttonsMessage = {
1023
- buttons: message.buttons.map(b => ({ ...b, type: WAProto_1.proto.Message.ButtonsMessage.Button.Type.RESPONSE }))
1024
- };
1025
- if ('text' in message) {
1026
- buttonsMessage.contentText = message.text;
1027
- buttonsMessage.headerType = ButtonType.EMPTY;
1028
- }
1029
- else {
1030
- if ('caption' in message) {
1031
- buttonsMessage.contentText = message.caption;
1032
- }
1033
- const type = Object.keys(m)[0].replace('Message', '').toUpperCase();
1034
- buttonsMessage.headerType = ButtonType[type];
1035
- Object.assign(buttonsMessage, m);
1036
- }
1037
- if ('title' in message && !!message.title) {
1038
- buttonsMessage.text = message.title,
1039
- buttonsMessage.headerType = ButtonType.TEXT;
1040
- }
1041
- if ('footer' in message && !!message.footer) {
1042
- buttonsMessage.footerText = message.footer;
1043
- }
1044
- if ('contextInfo' in message && !!message.contextInfo) {
1045
- buttonsMessage.contextInfo = message.contextInfo;
1046
- }
1047
- if ('mentions' in message && !!message.mentions) {
1048
- buttonsMessage.contextInfo = { mentionedJid: message.mentions };
1049
- }
1050
- m = { buttonsMessage };
1051
- }
1052
- else if ('templateButtons' in message && !!message.templateButtons) {
1053
- const templateMsg = {
1054
- hydratedButtons: message.templateButtons
1055
- };
1056
- if ('text' in message) {
1057
- templateMsg.hydratedContentText = message.text;
1058
- }
1059
- else if ('caption' in message) {
1060
- templateMsg.hydratedContentText = message.caption;
1061
- }
1062
- if ('footer' in message && !!message.footer) {
1063
- templateMsg.hydratedFooterText = message.footer;
1064
- }
1065
- // Add media to template if present
1066
- if (m && Object.keys(m).length > 0) {
1067
- Object.assign(templateMsg, m);
1068
- }
1069
- m = {
1070
- templateMessage: {
1071
- fourRowTemplate: templateMsg,
1072
- hydratedTemplate: templateMsg
1073
- }
1074
- };
1075
- }
1076
- if ('sections' in message && !!message.sections) {
1077
- const listMessage = {
1078
- sections: message.sections,
1079
- buttonText: message.buttonText,
1080
- title: message.title,
1081
- footerText: message.footer,
1082
- description: message.text,
1083
- listType: WAProto_1.proto.Message.ListMessage.ListType.SINGLE_SELECT
1084
- };
1085
- m = { listMessage };
1086
- }
1087
- if ('interactiveButtons' in message && !!message.interactiveButtons) {
1088
- const interactiveMessage = {
1089
- nativeFlowMessage: Types_1.WAProto.Message.InteractiveMessage.NativeFlowMessage.fromObject({
1090
- buttons: message.interactiveButtons,
1091
- messageVersion: 1,
1092
- })
1093
- };
1094
- if ('text' in message) {
1095
- interactiveMessage.body = {
1096
- text: message.text
1097
- };
1098
- }
1099
- else if ('caption' in message) {
1100
- interactiveMessage.body = {
1101
- text: message.caption
1102
- };
1103
- interactiveMessage.header = {
1104
- title: message.title,
1105
- subtitle: message.subtitle,
1106
- hasMediaAttachment: !!(message === null || message === void 0 ? void 0 : message.media),
1107
- };
1108
- Object.assign(interactiveMessage.header, m);
1109
- }
1110
- if ('footer' in message && !!message.footer) {
1111
- if (typeof message.footer === 'string') {
1112
- interactiveMessage.footer = {
1113
- text: message.footer
1114
- };
1115
- } else if (typeof message.footer === 'object' && message.footer.text) {
1116
- interactiveMessage.footer = {
1117
- text: message.footer.text,
1118
- hasMediaAttachment: !!message.footer.audio
1119
- };
1120
- if (message.footer.audio) {
1121
- const audioMedia = await (0, exports.prepareWAMessageMedia)({ audio: message.footer.audio }, options);
1122
- interactiveMessage.footer.audioMessage = audioMedia.audioMessage;
1123
- }
1124
- }
1125
- }
1126
- if ('title' in message && !!message.title) {
1127
- const headerData = {
1128
- title: message.title,
1129
- subtitle: message.subtitle,
1130
- hasMediaAttachment: !!message.media,
1131
- };
1132
-
1133
- // Process media attachments for interactive buttons
1134
- if (message.media) {
1135
- if (message.media.image) {
1136
- const mediaMessage = await (0, exports.prepareWAMessageMedia)({ image: message.media.image }, options);
1137
- if (mediaMessage.imageMessage) {
1138
- headerData.imageMessage = mediaMessage.imageMessage;
1139
- }
1140
- }
1141
- else if (message.media.video) {
1142
- const mediaMessage = await (0, exports.prepareWAMessageMedia)({ video: message.media.video }, options);
1143
- if (mediaMessage.videoMessage) {
1144
- headerData.videoMessage = mediaMessage.videoMessage;
1145
- }
1146
- }
1147
- else if (message.media.document) {
1148
- const mediaMessage = await (0, exports.prepareWAMessageMedia)({ document: message.media.document }, options);
1149
- if (mediaMessage.documentMessage) {
1150
- headerData.documentMessage = mediaMessage.documentMessage;
1151
- }
1152
- }
1153
- }
1154
-
1155
- interactiveMessage.header = headerData;
1156
- // Support for ProductMessage in header
1157
- if (message.headerProduct) {
1158
- const productMedia = await (0, exports.prepareWAMessageMedia)({ image: message.headerProduct.productImage }, options);
1159
- interactiveMessage.header.productMessage = {
1160
- product: {
1161
- ...message.headerProduct,
1162
- productImage: productMedia.imageMessage
1163
- }
1164
- };
1165
- interactiveMessage.header.hasMediaAttachment = true;
1166
- } else {
1167
- Object.assign(interactiveMessage.header, m);
1168
- }
1169
- }
1170
- if ('contextInfo' in message && !!message.contextInfo) {
1171
- interactiveMessage.contextInfo = message.contextInfo;
1172
- }
1173
- if ('mentions' in message && !!message.mentions) {
1174
- interactiveMessage.contextInfo = { mentionedJid: message.mentions };
1175
- }
1176
- m = { interactiveMessage };
1177
- }
1178
- if ('shop' in message && !!message.shop) {
1179
- const interactiveMessage = {
1180
- shopStorefrontMessage: Types_1.WAProto.Message.InteractiveMessage.ShopMessage.fromObject({
1181
- surface: message.shop,
1182
- id: message.id
1183
- })
1184
- };
1185
- if ('text' in message) {
1186
- interactiveMessage.body = {
1187
- text: message.text
1188
- };
1189
- }
1190
- else if ('caption' in message) {
1191
- interactiveMessage.body = {
1192
- text: message.caption
1193
- };
1194
- interactiveMessage.header = {
1195
- title: message.title,
1196
- subtitle: message.subtitle,
1197
- hasMediaAttachment: !!(message === null || message === void 0 ? void 0 : message.media),
1198
- };
1199
- Object.assign(interactiveMessage.header, m);
1200
- }
1201
- if ('footer' in message && !!message.footer) {
1202
- interactiveMessage.footer = {
1203
- text: message.footer
1204
- };
1205
- }
1206
- if ('title' in message && !!message.title) {
1207
- interactiveMessage.header = {
1208
- title: message.title,
1209
- subtitle: message.subtitle,
1210
- hasMediaAttachment: !!(message === null || message === void 0 ? void 0 : message.media),
1211
- };
1212
- Object.assign(interactiveMessage.header, m);
1213
- }
1214
- if ('contextInfo' in message && !!message.contextInfo) {
1215
- interactiveMessage.contextInfo = message.contextInfo;
1216
- }
1217
- if ('mentions' in message && !!message.mentions) {
1218
- interactiveMessage.contextInfo = { mentionedJid: message.mentions };
1219
- }
1220
- m = { interactiveMessage };
1221
- }
1222
- else if ('collection' in message && !!message.collection) {
1223
- const interactiveMessage = {
1224
- collectionMessage: Types_1.WAProto.Message.InteractiveMessage.CollectionMessage.fromObject({
1225
- bizJid: message.collection.bizJid,
1226
- id: message.collection.id,
1227
- messageVersion: message.collection.messageVersion || 1
1228
- })
1229
- };
1230
- if ('text' in message) {
1231
- interactiveMessage.body = {
1232
- text: message.text
1233
- };
1234
- }
1235
- if ('footer' in message && !!message.footer) {
1236
- interactiveMessage.footer = {
1237
- text: message.footer
1238
- };
1239
- }
1240
- if ('title' in message && !!message.title) {
1241
- interactiveMessage.header = {
1242
- title: message.title,
1243
- subtitle: message.subtitle,
1244
- hasMediaAttachment: false
1245
- };
1246
- }
1247
- if ('contextInfo' in message && !!message.contextInfo) {
1248
- interactiveMessage.contextInfo = message.contextInfo;
1249
- }
1250
- m = { interactiveMessage };
1251
- }
1252
- else if ('invoice' in message && !!message.invoice) {
1253
- const invoiceData = message.invoice;
1254
- const invoiceMessage = {
1255
- note: invoiceData.note,
1256
- token: invoiceData.token,
1257
- attachmentType: invoiceData.attachmentType || 0 // IMAGE = 0, PDF = 1
1258
- };
1259
- if (invoiceData.attachment) {
1260
- const attachmentMedia = await (0, exports.prepareWAMessageMedia)({
1261
- [invoiceData.attachmentType === 1 ? 'document' : 'image']: invoiceData.attachment
1262
- }, options);
1263
- if (invoiceData.attachmentType === 1) {
1264
- invoiceMessage.attachmentMimetype = attachmentMedia.documentMessage.mimetype;
1265
- invoiceMessage.attachmentMediaKey = attachmentMedia.documentMessage.mediaKey;
1266
- invoiceMessage.attachmentMediaKeyTimestamp = attachmentMedia.documentMessage.mediaKeyTimestamp;
1267
- invoiceMessage.attachmentFileSha256 = attachmentMedia.documentMessage.fileSha256;
1268
- invoiceMessage.attachmentFileEncSha256 = attachmentMedia.documentMessage.fileEncSha256;
1269
- invoiceMessage.attachmentDirectPath = attachmentMedia.documentMessage.directPath;
1270
- } else {
1271
- invoiceMessage.attachmentMimetype = attachmentMedia.imageMessage.mimetype;
1272
- invoiceMessage.attachmentMediaKey = attachmentMedia.imageMessage.mediaKey;
1273
- invoiceMessage.attachmentMediaKeyTimestamp = attachmentMedia.imageMessage.mediaKeyTimestamp;
1274
- invoiceMessage.attachmentFileSha256 = attachmentMedia.imageMessage.fileSha256;
1275
- invoiceMessage.attachmentFileEncSha256 = attachmentMedia.imageMessage.fileEncSha256;
1276
- invoiceMessage.attachmentDirectPath = attachmentMedia.imageMessage.directPath;
1277
- invoiceMessage.attachmentJpegThumbnail = attachmentMedia.imageMessage.jpegThumbnail;
1278
- }
1279
- }
1280
- m = { invoiceMessage };
1281
- }
325
+
1282
326
  if ('cards' in message && !!message.cards && message.cards.length > 0) {
1283
- const carouselCardType = message.carouselCardType || 1; // HSCROLL_CARDS = 1, ALBUM_IMAGE = 2
327
+ const carouselCardType = message.carouselCardType || 1;
1284
328
  const carouselCards = await Promise.all(message.cards.map(async (card) => {
1285
329
  const cardMessage = {
1286
330
  header: {
@@ -1289,26 +333,23 @@ const generateWAMessageContent = async (message, options) => {
1289
333
  }
1290
334
  };
1291
335
 
1292
- // Add body as separate field if present
1293
336
  if (card.body) {
1294
- cardMessage.body = {
1295
- text: card.body
1296
- };
337
+ cardMessage.body = { text: card.body };
1297
338
  }
1298
- // Handle media attachments
339
+
1299
340
  if (card.image) {
1300
- const mediaMessage = await prepareWAMessageMedia({ image: card.image }, options);
341
+ const mediaMessage = await (0, exports.prepareWAMessageMedia)({ image: card.image }, options);
1301
342
  if (mediaMessage.imageMessage) {
1302
343
  cardMessage.header.imageMessage = mediaMessage.imageMessage;
1303
344
  }
1304
345
  }
1305
346
  else if (card.video) {
1306
- const mediaMessage = await prepareWAMessageMedia({ video: card.video }, options);
347
+ const mediaMessage = await (0, exports.prepareWAMessageMedia)({ video: card.video }, options);
1307
348
  if (mediaMessage.videoMessage) {
1308
349
  cardMessage.header.videoMessage = mediaMessage.videoMessage;
1309
350
  }
1310
351
  }
1311
- // Handle buttons
352
+
1312
353
  if (card.buttons && card.buttons.length > 0) {
1313
354
  cardMessage.nativeFlowMessage = {
1314
355
  buttons: card.buttons.map(button => ({
@@ -1318,14 +359,14 @@ const generateWAMessageContent = async (message, options) => {
1318
359
  messageVersion: 1,
1319
360
  };
1320
361
  }
1321
- // Add footer if present
362
+
1322
363
  if (card.footer) {
1323
- cardMessage.footer = {
1324
- text: card.footer
1325
- };
364
+ cardMessage.footer = { text: card.footer };
1326
365
  }
366
+
1327
367
  return cardMessage;
1328
368
  }));
369
+
1329
370
  const interactiveMessage = {
1330
371
  carouselMessage: Types_1.WAProto.Message.InteractiveMessage.CarouselMessage.fromObject({
1331
372
  cards: carouselCards,
@@ -1333,15 +374,12 @@ const generateWAMessageContent = async (message, options) => {
1333
374
  carouselCardType: carouselCardType
1334
375
  })
1335
376
  };
377
+
1336
378
  if ('text' in message) {
1337
- interactiveMessage.body = {
1338
- text: message.text
1339
- };
379
+ interactiveMessage.body = { text: message.text };
1340
380
  }
1341
381
  if ('footer' in message && !!message.footer) {
1342
- interactiveMessage.footer = {
1343
- text: message.footer
1344
- };
382
+ interactiveMessage.footer = { text: message.footer };
1345
383
  }
1346
384
  if ('title' in message && !!message.title) {
1347
385
  interactiveMessage.header = {
@@ -1356,20 +394,25 @@ const generateWAMessageContent = async (message, options) => {
1356
394
  if ('mentions' in message && !!message.mentions) {
1357
395
  interactiveMessage.contextInfo = { mentionedJid: message.mentions };
1358
396
  }
397
+
1359
398
  m = { interactiveMessage };
1360
399
  }
1361
- // Interactive messages are commonly sent wrapped in a view-once container on MD.
1362
- // This improves client compatibility (avoids "update WhatsApp" / invisible messages on some clients).
400
+
1363
401
  const shouldWrapInteractive = !!(m === null || m === void 0 ? void 0 : m.interactiveMessage);
1364
- const hasViewOnceAlready = !!(m === null || m === void 0 ? void 0 : m.viewOnceMessage) || !!(m === null || m === void 0 ? void 0 : m.viewOnceMessageV2) || !!(m === null || m === void 0 ? void 0 : m.viewOnceMessageV2Extension);
402
+ const hasViewOnceAlready = !!(m === null || m === void 0 ? void 0 : m.viewOnceMessage) ||
403
+ !!(m === null || m === void 0 ? void 0 : m.viewOnceMessageV2) ||
404
+ !!(m === null || m === void 0 ? void 0 : m.viewOnceMessageV2Extension);
405
+
1365
406
  if ((('viewOnce' in message && !!message.viewOnce) || shouldWrapInteractive) && !hasViewOnceAlready) {
1366
407
  m = { viewOnceMessageV2: { message: m } };
1367
408
  }
1368
- if ('mentions' in message && ((_o = message.mentions) === null || _o === void 0 ? void 0 : _o.length)) {
409
+
410
+ if ('mentions' in message && (message.mentions?.length)) {
1369
411
  const [messageType] = Object.keys(m);
1370
- m[messageType].contextInfo = m[messageType] || {};
412
+ m[messageType].contextInfo = m[messageType].contextInfo || {};
1371
413
  m[messageType].contextInfo.mentionedJid = message.mentions;
1372
414
  }
415
+
1373
416
  if ('edit' in message) {
1374
417
  m = {
1375
418
  protocolMessage: {
@@ -1380,6 +423,7 @@ const generateWAMessageContent = async (message, options) => {
1380
423
  }
1381
424
  };
1382
425
  }
426
+
1383
427
  if ('contextInfo' in message && !!message.contextInfo) {
1384
428
  const [messageType] = Object.keys(m);
1385
429
  m[messageType] = m[messageType] || {};
@@ -1388,406 +432,94 @@ const generateWAMessageContent = async (message, options) => {
1388
432
  ...message.contextInfo
1389
433
  };
1390
434
  }
435
+
1391
436
  return Types_1.WAProto.Message.fromObject(m);
1392
437
  };
1393
438
  exports.generateWAMessageContent = generateWAMessageContent;
439
+
1394
440
  const generateWAMessageFromContent = (jid, message, options) => {
1395
- // set timestamp to now
1396
- // if not specified
1397
441
  if (!options.timestamp) {
1398
442
  options.timestamp = new Date();
1399
443
  }
444
+
1400
445
  const innerMessage = (0, exports.normalizeMessageContent)(message);
1401
446
  const key = (0, exports.getContentType)(innerMessage);
1402
447
  const timestamp = (0, generics_1.unixTimestampSeconds)(options.timestamp);
1403
448
  const { quoted, userJid } = options;
1404
- // only set quoted if isn't a newsletter message
449
+
1405
450
  if (quoted && !(0, WABinary_1.isJidNewsletter)(jid)) {
1406
451
  const participant = quoted.key.fromMe ? userJid : (quoted.participant || quoted.key.participant || quoted.key.remoteJid);
1407
452
  let quotedMsg = (0, exports.normalizeMessageContent)(quoted.message);
1408
453
  const msgType = (0, exports.getContentType)(quotedMsg);
1409
- // strip any redundant properties
454
+
1410
455
  if (quotedMsg) {
1411
456
  quotedMsg = WAProto_1.proto.Message.fromObject({ [msgType]: quotedMsg[msgType] });
1412
457
  const quotedContent = quotedMsg[msgType];
1413
458
  if (typeof quotedContent === 'object' && quotedContent && 'contextInfo' in quotedContent) {
1414
459
  delete quotedContent.contextInfo;
1415
460
  }
461
+
1416
462
  const contextInfo = innerMessage[key].contextInfo || {};
1417
463
  contextInfo.participant = (0, WABinary_1.jidNormalizedUser)(participant);
1418
464
  contextInfo.stanzaId = quoted.key.id;
1419
465
  contextInfo.quotedMessage = quotedMsg;
1420
- // if a participant is quoted, then it must be a group
1421
- // hence, remoteJid of group must also be entered
466
+
1422
467
  if (jid !== quoted.key.remoteJid) {
1423
468
  contextInfo.remoteJid = quoted.key.remoteJid;
1424
469
  }
470
+
1425
471
  innerMessage[key].contextInfo = contextInfo;
1426
472
  }
1427
473
  }
1428
- if (
1429
- // if we want to send a disappearing message
1430
- !!(options === null || options === void 0 ? void 0 : options.ephemeralExpiration) &&
1431
- // and it's not a protocol message -- delete, toggle disappear message
474
+
475
+ if (!!(options === null || options === void 0 ? void 0 : options.ephemeralExpiration) &&
1432
476
  key !== 'protocolMessage' &&
1433
- // already not converted to disappearing message
1434
477
  key !== 'ephemeralMessage' &&
1435
- // newsletter not accept disappearing messages
1436
478
  !(0, WABinary_1.isJidNewsletter)(jid)) {
1437
479
  innerMessage[key].contextInfo = {
1438
480
  ...(innerMessage[key].contextInfo || {}),
1439
481
  expiration: options.ephemeralExpiration || Defaults_1.WA_DEFAULT_EPHEMERAL,
1440
- //ephemeralSettingTimestamp: options.ephemeralOptions.eph_setting_ts?.toString()
1441
482
  };
1442
483
  }
1443
- message = Types_1.WAProto.Message.fromObject(message);
1444
- const messageJSON = {
484
+
485
+ const msg = {
1445
486
  key: {
1446
487
  remoteJid: jid,
1447
488
  fromMe: true,
1448
- id: (options === null || options === void 0 ? void 0 : options.messageId) || (0, generics_1.generateMessageIDV2)(),
489
+ id: options.messageId || (0, generics_1.generateMessageID)(),
1449
490
  },
1450
- message: message,
491
+ message: innerMessage,
1451
492
  messageTimestamp: timestamp,
1452
493
  messageStubParameters: [],
1453
- participant: (0, WABinary_1.isJidGroup)(jid) || (0, WABinary_1.isJidStatusBroadcast)(jid) ? userJid : undefined,
494
+ participant: (0, WABinary_1.isJidGroup)(jid) ? userJid : undefined,
1454
495
  status: Types_1.WAMessageStatus.PENDING
1455
496
  };
1456
- return Types_1.WAProto.WebMessageInfo.fromObject(messageJSON);
497
+
498
+ return WAProto_1.proto.WebMessageInfo.fromObject(msg);
1457
499
  };
1458
500
  exports.generateWAMessageFromContent = generateWAMessageFromContent;
1459
- const generateWAMessage = async (jid, content, options) => {
1460
- var _a;
1461
- // ensure msg ID is with every log
1462
- options.logger = (_a = options === null || options === void 0 ? void 0 : options.logger) === null || _a === void 0 ? void 0 : _a.child({ msgId: options.messageId });
1463
- return (0, exports.generateWAMessageFromContent)(jid, await (0, exports.generateWAMessageContent)(content, { newsletter: (0, WABinary_1.isJidNewsletter)(jid), ...options }), options);
1464
- };
1465
- exports.generateWAMessage = generateWAMessage;
1466
- /** Get the key to access the true type of content */
1467
- const getContentType = (content) => {
1468
- if (content) {
1469
- const keys = Object.keys(content);
1470
- const key = keys.find(k => (k === 'conversation' || k.includes('Message')) && k !== 'senderKeyDistributionMessage');
1471
- return key;
1472
- }
1473
- };
1474
- exports.getContentType = getContentType;
1475
- /**
1476
- * Normalizes ephemeral, view once messages to regular message content
1477
- * Eg. image messages in ephemeral messages, in view once messages etc.
1478
- * @param content
1479
- * @returns
1480
- */
1481
- const normalizeMessageContent = (content) => {
1482
- if (!content) {
1483
- return undefined;
1484
- }
1485
- // set max iterations to prevent an infinite loop
1486
- for (let i = 0; i < 5; i++) {
1487
- const inner = getFutureProofMessage(content);
1488
- if (!inner) {
1489
- break;
1490
- }
1491
- content = inner.message;
1492
- }
1493
- return content;
1494
- function getFutureProofMessage(message) {
1495
- return ((message === null || message === void 0 ? void 0 : message.ephemeralMessage)
1496
- || (message === null || message === void 0 ? void 0 : message.viewOnceMessage)
1497
- || (message === null || message === void 0 ? void 0 : message.documentWithCaptionMessage)
1498
- || (message === null || message === void 0 ? void 0 : message.viewOnceMessageV2)
1499
- || (message === null || message === void 0 ? void 0 : message.viewOnceMessageV2Extension)
1500
- || (message === null || message === void 0 ? void 0 : message.editedMessage)
1501
- || (message === null || message === void 0 ? void 0 : message.groupMentionedMessage)
1502
- || (message === null || message === void 0 ? void 0 : message.botInvokeMessage)
1503
- || (message === null || message === void 0 ? void 0 : message.lottieStickerMessage)
1504
- || (message === null || message === void 0 ? void 0 : message.eventCoverImage)
1505
- || (message === null || message === void 0 ? void 0 : message.statusMentionMessage)
1506
- || (message === null || message === void 0 ? void 0 : message.pollCreationOptionImageMessage)
1507
- || (message === null || message === void 0 ? void 0 : message.associatedChildMessage)
1508
- || (message === null || message === void 0 ? void 0 : message.groupStatusMentionMessage)
1509
- || (message === null || message === void 0 ? void 0 : message.pollCreationMessageV4)
1510
- || (message === null || message === void 0 ? void 0 : message.pollCreationMessageV5)
1511
- || (message === null || message === void 0 ? void 0 : message.statusAddYours)
1512
- || (message === null || message === void 0 ? void 0 : message.groupStatusMessage)
1513
- || (message === null || message === void 0 ? void 0 : message.limitSharingMessage)
1514
- || (message === null || message === void 0 ? void 0 : message.botTaskMessage)
1515
- || (message === null || message === void 0 ? void 0 : message.questionMessage)
1516
- || (message === null || message === void 0 ? void 0 : message.groupStatusMessageV2)
1517
- || (message === null || message === void 0 ? void 0 : message.botForwardedMessage));
1518
- }
1519
- };
1520
- exports.normalizeMessageContent = normalizeMessageContent;
1521
- /**
1522
- * Extract the true message content from a message
1523
- * Eg. extracts the inner message from a disappearing message/view once message
1524
- */
1525
- const extractMessageContent = (content) => {
1526
- var _a, _b, _c, _d, _e, _f;
1527
- const extractFromTemplateMessage = (msg) => {
1528
- if (msg.imageMessage) {
1529
- return { imageMessage: msg.imageMessage };
1530
- }
1531
- else if (msg.documentMessage) {
1532
- return { documentMessage: msg.documentMessage };
1533
- }
1534
- else if (msg.videoMessage) {
1535
- return { videoMessage: msg.videoMessage };
1536
- }
1537
- else if (msg.locationMessage) {
1538
- return { locationMessage: msg.locationMessage };
1539
- }
1540
- else {
1541
- return {
1542
- conversation: 'contentText' in msg
1543
- ? msg.contentText
1544
- : ('hydratedContentText' in msg ? msg.hydratedContentText : '')
1545
- };
1546
- }
1547
- };
1548
- content = (0, exports.normalizeMessageContent)(content);
1549
- if (content === null || content === void 0 ? void 0 : content.buttonsMessage) {
1550
- return extractFromTemplateMessage(content.buttonsMessage);
1551
- }
1552
- if ((_a = content === null || content === void 0 ? void 0 : content.templateMessage) === null || _a === void 0 ? void 0 : _a.hydratedFourRowTemplate) {
1553
- return extractFromTemplateMessage((_b = content === null || content === void 0 ? void 0 : content.templateMessage) === null || _b === void 0 ? void 0 : _b.hydratedFourRowTemplate);
1554
- }
1555
- if ((_c = content === null || content === void 0 ? void 0 : content.templateMessage) === null || _c === void 0 ? void 0 : _c.hydratedTemplate) {
1556
- return extractFromTemplateMessage((_d = content === null || content === void 0 ? void 0 : content.templateMessage) === null || _d === void 0 ? void 0 : _d.hydratedTemplate);
1557
- }
1558
- if ((_e = content === null || content === void 0 ? void 0 : content.templateMessage) === null || _e === void 0 ? void 0 : _e.fourRowTemplate) {
1559
- return extractFromTemplateMessage((_f = content === null || content === void 0 ? void 0 : content.templateMessage) === null || _f === void 0 ? void 0 : _f.fourRowTemplate);
1560
- }
1561
- return content;
1562
- };
1563
- exports.extractMessageContent = extractMessageContent;
1564
- /**
1565
- * Returns the device predicted by message ID
1566
- */
1567
- const getDevice = (id) => /^3A.{18}$/.test(id) ? 'ios' :
1568
- /^3E.{20}$/.test(id) ? 'web' :
1569
- /^(.{21}|.{32})$/.test(id) ? 'android' :
1570
- /^(3F|.{18}$)/.test(id) ? 'desktop' :
1571
- 'unknown';
1572
- exports.getDevice = getDevice;
1573
- /** Upserts a receipt in the message */
1574
- const updateMessageWithReceipt = (msg, receipt) => {
1575
- msg.userReceipt = msg.userReceipt || [];
1576
- const recp = msg.userReceipt.find(m => m.userJid === receipt.userJid);
1577
- if (recp) {
1578
- Object.assign(recp, receipt);
1579
- }
1580
- else {
1581
- msg.userReceipt.push(receipt);
1582
- }
1583
- };
1584
- exports.updateMessageWithReceipt = updateMessageWithReceipt;
1585
- /** Update the message with a new reaction */
1586
- const updateMessageWithReaction = (msg, reaction) => {
1587
- const authorID = (0, generics_1.getKeyAuthor)(reaction.key);
1588
- const reactions = (msg.reactions || [])
1589
- .filter(r => (0, generics_1.getKeyAuthor)(r.key) !== authorID);
1590
- reaction.text = reaction.text || '';
1591
- reactions.push(reaction);
1592
- msg.reactions = reactions;
1593
- };
1594
- exports.updateMessageWithReaction = updateMessageWithReaction;
1595
- /** Update the message with a new poll update */
1596
- const updateMessageWithPollUpdate = (msg, update) => {
1597
- var _a, _b;
1598
- const authorID = (0, generics_1.getKeyAuthor)(update.pollUpdateMessageKey);
1599
- const reactions = (msg.pollUpdates || [])
1600
- .filter(r => (0, generics_1.getKeyAuthor)(r.pollUpdateMessageKey) !== authorID);
1601
- if ((_b = (_a = update.vote) === null || _a === void 0 ? void 0 : _a.selectedOptions) === null || _b === void 0 ? void 0 : _b.length) {
1602
- reactions.push(update);
1603
- }
1604
- msg.pollUpdates = reactions;
1605
- };
1606
- exports.updateMessageWithPollUpdate = updateMessageWithPollUpdate;
1607
- /**
1608
- * Aggregates all poll updates in a poll.
1609
- * @param msg the poll creation message
1610
- * @param meId your jid
1611
- * @returns A list of options & their voters
1612
- */
1613
- function getAggregateVotesInPollMessage({ message, pollUpdates }, meId) {
1614
- var _a, _b, _c;
1615
- const opts = ((_a = message === null || message === void 0 ? void 0 : message.pollCreationMessage) === null || _a === void 0 ? void 0 : _a.options) || ((_b = message === null || message === void 0 ? void 0 : message.pollCreationMessageV2) === null || _b === void 0 ? void 0 : _b.options) || ((_c = message === null || message === void 0 ? void 0 : message.pollCreationMessageV3) === null || _c === void 0 ? void 0 : _c.options) || [];
1616
- const voteHashMap = opts.reduce((acc, opt) => {
1617
- const hash = (0, crypto_2.sha256)(Buffer.from(opt.optionName || '')).toString();
1618
- acc[hash] = {
1619
- name: opt.optionName || '',
1620
- voters: []
1621
- };
1622
- return acc;
1623
- }, {});
1624
- for (const update of pollUpdates || []) {
501
+
502
+ async function getAggregateVotesInPollMessage({ message, pollUpdates }) {
503
+ const votes = {};
504
+ const voters = {};
505
+
506
+ for (const update of pollUpdates) {
1625
507
  const { vote } = update;
1626
- if (!vote) {
1627
- continue;
1628
- }
1629
- for (const option of vote.selectedOptions || []) {
1630
- const hash = option.toString();
1631
- let data = voteHashMap[hash];
1632
- if (!data) {
1633
- voteHashMap[hash] = {
1634
- name: 'Unknown',
1635
- voters: []
1636
- };
1637
- data = voteHashMap[hash];
1638
- }
1639
- voteHashMap[hash].voters.push((0, generics_1.getKeyAuthor)(update.pollUpdateMessageKey, meId));
1640
- }
1641
- }
1642
- return Object.values(voteHashMap);
1643
- }
1644
- /** Given a list of message keys, aggregates them by chat & sender. Useful for sending read receipts in bulk */
1645
- const aggregateMessageKeysNotFromMe = (keys) => {
1646
- const keyMap = {};
1647
- for (const { remoteJid, id, participant, fromMe } of keys) {
1648
- if (!fromMe) {
1649
- const uqKey = `${remoteJid}:${participant || ''}`;
1650
- if (!keyMap[uqKey]) {
1651
- keyMap[uqKey] = {
1652
- jid: remoteJid,
1653
- participant: participant,
1654
- messageIds: []
1655
- };
1656
- }
1657
- keyMap[uqKey].messageIds.push(id);
1658
- }
1659
- }
1660
- return Object.values(keyMap);
1661
- };
1662
- exports.aggregateMessageKeysNotFromMe = aggregateMessageKeysNotFromMe;
1663
- const REUPLOAD_REQUIRED_STATUS = [410, 404];
1664
- /**
1665
- * Downloads the given message. Throws an error if it's not a media message
1666
- */
1667
- const downloadMediaMessage = async (message, type, options, ctx) => {
1668
- const result = await downloadMsg()
1669
- .catch(async (error) => {
1670
- var _a;
1671
- if (ctx) {
1672
- if (axios_1.default.isAxiosError(error)) {
1673
- // check if the message requires a reupload
1674
- if (REUPLOAD_REQUIRED_STATUS.includes((_a = error.response) === null || _a === void 0 ? void 0 : _a.status)) {
1675
- ctx.logger.info({ key: message.key }, 'sending reupload media request...');
1676
- // request reupload
1677
- message = await ctx.reuploadRequest(message);
1678
- const result = await downloadMsg();
1679
- return result;
1680
- }
1681
- }
1682
- }
1683
- throw error;
1684
- });
1685
- return result;
1686
- async function downloadMsg() {
1687
- const mContent = (0, exports.extractMessageContent)(message.message);
1688
- if (!mContent) {
1689
- throw new boom_1.Boom('No message present', { statusCode: 400, data: message });
1690
- }
1691
- const contentType = (0, exports.getContentType)(mContent);
1692
- let mediaType = contentType === null || contentType === void 0 ? void 0 : contentType.replace('Message', '');
1693
- const media = mContent[contentType];
1694
- if (!media || typeof media !== 'object' || (!('url' in media) && !('thumbnailDirectPath' in media))) {
1695
- throw new boom_1.Boom(`"${contentType}" message is not a media message`);
1696
- }
1697
- let download;
1698
- if ('thumbnailDirectPath' in media && !('url' in media)) {
1699
- download = {
1700
- directPath: media.thumbnailDirectPath,
1701
- mediaKey: media.mediaKey
1702
- };
1703
- mediaType = 'thumbnail-link';
1704
- }
1705
- else {
1706
- download = media;
1707
- }
1708
- const stream = await (0, messages_media_1.downloadContentFromMessage)(download, mediaType, options);
1709
- if (type === 'buffer') {
1710
- const bufferArray = [];
1711
- for await (const chunk of stream) {
1712
- bufferArray.push(chunk);
1713
- }
1714
- return Buffer.concat(bufferArray);
1715
- }
1716
- return stream;
1717
- }
1718
- };
1719
- exports.downloadMediaMessage = downloadMediaMessage;
1720
- /** Checks whether the given message is a media message; if it is returns the inner content */
1721
- const assertMediaContent = (content) => {
1722
- content = (0, exports.extractMessageContent)(content);
1723
- const mediaContent = (content === null || content === void 0 ? void 0 : content.documentMessage)
1724
- || (content === null || content === void 0 ? void 0 : content.imageMessage)
1725
- || (content === null || content === void 0 ? void 0 : content.videoMessage)
1726
- || (content === null || content === void 0 ? void 0 : content.audioMessage)
1727
- || (content === null || content === void 0 ? void 0 : content.stickerMessage);
1728
- if (!mediaContent) {
1729
- throw new boom_1.Boom('given message is not a media message', { statusCode: 400, data: content });
1730
- }
1731
- return mediaContent;
1732
- };
1733
- exports.assertMediaContent = assertMediaContent;
1734
- const cache_manager_1 = require("./cache-manager");
1735
- const performance_config_1 = require("./performance-config");
1736
- /**
1737
- * Get cache statistics for monitoring performance
1738
- */
1739
- const getCacheStats = () => {
1740
- try {
1741
- const cacheManager = cache_manager_1.default;
1742
- const config = performance_config_1.getPerformanceConfig();
508
+ if (!vote) continue;
1743
509
 
1744
- if (!cacheManager || !cacheManager.caches) {
1745
- return {
1746
- lidCache: { size: 0, maxSize: 0, ttl: config.cache.lidCache.ttl },
1747
- jidCache: { size: 0, maxSize: 0, ttl: config.cache.jidCache.ttl }
1748
- };
1749
- }
1750
-
1751
- const lidStats = cacheManager.getStats('lidCache');
1752
- const jidStats = cacheManager.getStats('jidCache');
1753
-
1754
- return {
1755
- lidCache: {
1756
- size: lidStats?.keys || 0,
1757
- maxSize: lidStats?.max || config.cache.lidCache.maxSize || 0,
1758
- ttl: config.cache.lidCache.ttl
1759
- },
1760
- jidCache: {
1761
- size: jidStats?.keys || 0,
1762
- maxSize: jidStats?.max || config.cache.jidCache.maxSize || 0,
1763
- ttl: config.cache.jidCache.ttl
510
+ const selectedOptions = vote.selectedOptions || [];
511
+ for (const option of selectedOptions) {
512
+ if (!votes[option]) {
513
+ votes[option] = [];
514
+ voters[option] = new Set();
515
+ }
516
+
517
+ if (!voters[option].has(update.voter)) {
518
+ votes[option].push(update.voter);
519
+ voters[option].add(update.voter);
1764
520
  }
1765
- };
1766
- } catch (error) {
1767
- const config = performance_config_1.getPerformanceConfig();
1768
- return {
1769
- lidCache: { size: 0, maxSize: 0, ttl: config.cache.lidCache.ttl },
1770
- jidCache: { size: 0, maxSize: 0, ttl: config.cache.jidCache.ttl }
1771
- };
1772
- }
1773
- };
1774
- exports.getCacheStats = getCacheStats;
1775
- /**
1776
- * Clear all caches (useful for testing or memory management)
1777
- */
1778
- const clearCache = () => {
1779
- try {
1780
- const cacheManager = cache_manager_1.default;
1781
- if (cacheManager && cacheManager.caches) {
1782
- Object.keys(cacheManager.caches).forEach(cacheName => {
1783
- const cache = cacheManager.caches[cacheName];
1784
- if (cache && typeof cache.flushAll === 'function') {
1785
- cache.flushAll();
1786
- }
1787
- });
1788
521
  }
1789
- } catch (error) {
1790
- // Silently fail if cache manager is not available
1791
522
  }
1792
- };
1793
- exports.clearCache = clearCache;
523
+
524
+ return votes;
525
+ }