@gqb333/based 2.7.83 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/Utils/crypto.js +3 -0
- package/lib/Utils/messages.js +1451 -183
- package/package.json +1 -1
package/lib/Utils/messages.js
CHANGED
|
@@ -16,7 +16,6 @@ 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
|
-
|
|
20
19
|
const MIMETYPE_MAP = {
|
|
21
20
|
image: 'image/jpeg',
|
|
22
21
|
video: 'video/mp4',
|
|
@@ -25,7 +24,6 @@ const MIMETYPE_MAP = {
|
|
|
25
24
|
sticker: 'image/webp',
|
|
26
25
|
'product-catalog-image': 'image/jpeg',
|
|
27
26
|
};
|
|
28
|
-
|
|
29
27
|
const MessageTypeProto = {
|
|
30
28
|
'image': Types_1.WAProto.Message.ImageMessage,
|
|
31
29
|
'video': Types_1.WAProto.Message.VideoMessage,
|
|
@@ -33,16 +31,14 @@ const MessageTypeProto = {
|
|
|
33
31
|
'sticker': Types_1.WAProto.Message.StickerMessage,
|
|
34
32
|
'document': Types_1.WAProto.Message.DocumentMessage,
|
|
35
33
|
};
|
|
36
|
-
|
|
37
34
|
const ButtonType = WAProto_1.proto.Message.ButtonsMessage.HeaderType;
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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
|
+
*/
|
|
43
40
|
const extractUrlFromText = (text) => { var _a; return (_a = text.match(Defaults_1.URL_REGEX)) === null || _a === void 0 ? void 0 : _a[0]; };
|
|
44
41
|
exports.extractUrlFromText = extractUrlFromText;
|
|
45
|
-
|
|
46
42
|
const generateLinkPreviewIfRequired = async (text, getUrlInfo, logger) => {
|
|
47
43
|
const url = (0, exports.extractUrlFromText)(text);
|
|
48
44
|
if (!!getUrlInfo && url) {
|
|
@@ -50,13 +46,12 @@ const generateLinkPreviewIfRequired = async (text, getUrlInfo, logger) => {
|
|
|
50
46
|
const urlInfo = await getUrlInfo(url);
|
|
51
47
|
return urlInfo;
|
|
52
48
|
}
|
|
53
|
-
catch (error) {
|
|
49
|
+
catch (error) { // ignore if fails
|
|
54
50
|
logger === null || logger === void 0 ? void 0 : logger.warn({ trace: error.stack }, 'url generation failed');
|
|
55
51
|
}
|
|
56
52
|
}
|
|
57
53
|
};
|
|
58
54
|
exports.generateLinkPreviewIfRequired = generateLinkPreviewIfRequired;
|
|
59
|
-
|
|
60
55
|
const assertColor = async (color) => {
|
|
61
56
|
let assertedColor;
|
|
62
57
|
if (typeof color === 'number') {
|
|
@@ -72,88 +67,61 @@ const assertColor = async (color) => {
|
|
|
72
67
|
return assertedColor;
|
|
73
68
|
}
|
|
74
69
|
};
|
|
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
|
-
|
|
84
70
|
const prepareWAMessageMedia = async (message, options) => {
|
|
85
71
|
const logger = options.logger;
|
|
86
72
|
let mediaType;
|
|
87
|
-
|
|
88
73
|
for (const key of Defaults_1.MEDIA_KEYS) {
|
|
89
74
|
if (key in message) {
|
|
90
75
|
mediaType = key;
|
|
91
|
-
break;
|
|
92
76
|
}
|
|
93
77
|
}
|
|
94
|
-
|
|
95
78
|
if (!mediaType) {
|
|
96
79
|
throw new boom_1.Boom('Invalid media type', { statusCode: 400 });
|
|
97
80
|
}
|
|
98
|
-
|
|
99
81
|
const uploadData = {
|
|
100
82
|
...message,
|
|
101
83
|
media: message[mediaType]
|
|
102
84
|
};
|
|
103
85
|
delete uploadData[mediaType];
|
|
104
|
-
|
|
86
|
+
// check if cacheable + generate cache key
|
|
105
87
|
const cacheableKey = typeof uploadData.media === 'object' &&
|
|
106
88
|
('url' in uploadData.media) &&
|
|
107
89
|
!!uploadData.media.url &&
|
|
108
90
|
!!options.mediaCache && (
|
|
109
|
-
|
|
110
|
-
|
|
91
|
+
// generate the key
|
|
92
|
+
mediaType + ':' + uploadData.media.url.toString());
|
|
111
93
|
if (mediaType === 'document' && !uploadData.fileName) {
|
|
112
94
|
uploadData.fileName = 'file';
|
|
113
95
|
}
|
|
114
|
-
|
|
115
96
|
if (!uploadData.mimetype) {
|
|
116
97
|
uploadData.mimetype = MIMETYPE_MAP[mediaType];
|
|
117
98
|
}
|
|
118
|
-
|
|
99
|
+
// check for cache hit
|
|
119
100
|
if (cacheableKey) {
|
|
120
|
-
const
|
|
121
|
-
if (
|
|
122
|
-
logger === null || logger === void 0 ? void 0 : logger.debug({ cacheableKey }, 'media cache hit');
|
|
123
|
-
const obj = Types_1.WAProto.Message.decode(
|
|
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);
|
|
124
105
|
const key = `${mediaType}Message`;
|
|
125
106
|
Object.assign(obj[key], { ...uploadData, media: undefined });
|
|
126
107
|
return obj;
|
|
127
108
|
}
|
|
128
109
|
}
|
|
129
|
-
|
|
130
110
|
const requiresDurationComputation = mediaType === 'audio' && typeof uploadData.seconds === 'undefined';
|
|
131
111
|
const requiresThumbnailComputation = (mediaType === 'image' || mediaType === 'video') &&
|
|
132
112
|
(typeof uploadData['jpegThumbnail'] === 'undefined');
|
|
133
113
|
const requiresWaveformProcessing = mediaType === 'audio' && uploadData.ptt === true;
|
|
134
114
|
const requiresAudioBackground = options.backgroundColor && mediaType === 'audio' && uploadData.ptt === true;
|
|
135
115
|
const requiresOriginalForSomeProcessing = requiresDurationComputation || requiresThumbnailComputation;
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
{
|
|
142
|
-
logger,
|
|
143
|
-
saveOriginalFileIfRequired: requiresOriginalForSomeProcessing,
|
|
144
|
-
opts: options.options
|
|
145
|
-
}
|
|
146
|
-
);
|
|
147
|
-
|
|
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
|
+
});
|
|
148
121
|
const fileEncSha256B64 = (options.newsletter ? fileSha256 : fileEncSha256 !== null && fileEncSha256 !== void 0 ? fileEncSha256 : fileSha256).toString('base64');
|
|
149
|
-
|
|
150
122
|
const [{ mediaUrl, directPath, handle }] = await Promise.all([
|
|
151
123
|
(async () => {
|
|
152
|
-
const result = await options.upload(encWriteStream, {
|
|
153
|
-
fileEncSha256B64,
|
|
154
|
-
mediaType,
|
|
155
|
-
timeoutMs: options.mediaUploadTimeoutMs || 60000
|
|
156
|
-
});
|
|
124
|
+
const result = await options.upload(encWriteStream, { fileEncSha256B64, mediaType, timeoutMs: options.mediaUploadTimeoutMs });
|
|
157
125
|
logger === null || logger === void 0 ? void 0 : logger.debug({ mediaType, cacheableKey }, 'uploaded media');
|
|
158
126
|
return result;
|
|
159
127
|
})(),
|
|
@@ -186,60 +154,160 @@ const prepareWAMessageMedia = async (message, options) => {
|
|
|
186
154
|
logger === null || logger === void 0 ? void 0 : logger.warn({ trace: error.stack }, 'failed to obtain extra info');
|
|
187
155
|
}
|
|
188
156
|
})(),
|
|
189
|
-
])
|
|
157
|
+
])
|
|
158
|
+
.finally(async () => {
|
|
190
159
|
if (!Buffer.isBuffer(encWriteStream)) {
|
|
191
160
|
encWriteStream.destroy();
|
|
192
161
|
}
|
|
162
|
+
// remove tmp files
|
|
193
163
|
if (didSaveToTmpPath && bodyPath) {
|
|
194
164
|
try {
|
|
195
165
|
await fs_1.promises.access(bodyPath);
|
|
196
166
|
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');
|
|
197
171
|
}
|
|
198
|
-
catch { }
|
|
199
172
|
}
|
|
200
173
|
});
|
|
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
|
-
|
|
215
174
|
const obj = Types_1.WAProto.Message.fromObject({
|
|
216
|
-
[`${mediaType}Message`]: MessageTypeProto[mediaType].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
|
+
})
|
|
217
186
|
});
|
|
218
|
-
|
|
187
|
+
if (uploadData.ptv) {
|
|
188
|
+
obj.ptvMessage = obj.videoMessage;
|
|
189
|
+
delete obj.videoMessage;
|
|
190
|
+
}
|
|
219
191
|
if (cacheableKey) {
|
|
220
|
-
|
|
221
|
-
mediaCache.set(cacheableKey,
|
|
222
|
-
data: encoded,
|
|
223
|
-
timestamp: Date.now()
|
|
224
|
-
});
|
|
225
|
-
cleanMediaCache();
|
|
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());
|
|
226
194
|
}
|
|
227
|
-
|
|
228
195
|
return obj;
|
|
229
196
|
};
|
|
230
197
|
exports.prepareWAMessageMedia = prepareWAMessageMedia;
|
|
231
|
-
|
|
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;
|
|
232
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
|
+
|
|
233
280
|
let m = {};
|
|
234
|
-
|
|
235
281
|
if ('text' in message) {
|
|
236
|
-
const extContent =
|
|
237
|
-
|
|
238
|
-
if (
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
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);
|
|
242
306
|
}
|
|
307
|
+
if (options.font) {
|
|
308
|
+
extContent.font = options.font;
|
|
309
|
+
}
|
|
310
|
+
m.extendedTextMessage = extContent;
|
|
243
311
|
}
|
|
244
312
|
else if ('contacts' in message) {
|
|
245
313
|
const contactLen = message.contacts.contacts.length;
|
|
@@ -256,7 +324,13 @@ const generateWAMessageContent = async (message, options) => {
|
|
|
256
324
|
else if ('location' in message) {
|
|
257
325
|
m.locationMessage = Types_1.WAProto.Message.LocationMessage.fromObject(message.location);
|
|
258
326
|
}
|
|
327
|
+
else if ('liveLocation' in message) {
|
|
328
|
+
m.liveLocationMessage = Types_1.WAProto.Message.LiveLocationMessage.fromObject(message.liveLocation);
|
|
329
|
+
}
|
|
259
330
|
else if ('react' in message) {
|
|
331
|
+
if (!message.react.senderTimestampMs) {
|
|
332
|
+
message.react.senderTimestampMs = Date.now();
|
|
333
|
+
}
|
|
260
334
|
m.reactionMessage = Types_1.WAProto.Message.ReactionMessage.fromObject(message.react);
|
|
261
335
|
}
|
|
262
336
|
else if ('delete' in message) {
|
|
@@ -265,66 +339,948 @@ const generateWAMessageContent = async (message, options) => {
|
|
|
265
339
|
type: Types_1.WAProto.Message.ProtocolMessage.Type.REVOKE
|
|
266
340
|
};
|
|
267
341
|
}
|
|
268
|
-
else if ('forward' in message
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
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
|
+
}
|
|
272
380
|
}
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
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
|
|
279
435
|
};
|
|
280
|
-
|
|
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);
|
|
281
457
|
}
|
|
282
458
|
else {
|
|
283
|
-
m = {
|
|
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
|
+
};
|
|
284
466
|
}
|
|
285
|
-
|
|
286
|
-
|
|
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;
|
|
287
547
|
}
|
|
288
548
|
else {
|
|
289
|
-
|
|
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
|
+
}
|
|
290
557
|
}
|
|
291
558
|
}
|
|
292
|
-
else if ('
|
|
293
|
-
m = {
|
|
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
|
+
};
|
|
294
567
|
}
|
|
295
|
-
else if ('
|
|
296
|
-
const
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
ephemeralSettingTimestamp: (0, generics_1.unixTimestampSeconds)()
|
|
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
|
|
302
574
|
};
|
|
575
|
+
m.pollCreationMessageV4 = pollCreationMessage;
|
|
303
576
|
}
|
|
304
|
-
else if ('
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
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
|
|
308
583
|
};
|
|
584
|
+
m.pollCreationMessageV5 = pollCreationMessage;
|
|
309
585
|
}
|
|
310
|
-
else if ('
|
|
311
|
-
m.
|
|
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 };
|
|
312
591
|
}
|
|
313
|
-
else if ('
|
|
314
|
-
m.
|
|
315
|
-
|
|
316
|
-
|
|
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;
|
|
705
|
+
}
|
|
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
|
+
}
|
|
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
|
+
};
|
|
807
|
+
}
|
|
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
|
+
};
|
|
317
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) {
|
|
869
|
+
m.protocolMessage = {
|
|
870
|
+
type: WAProto_1.proto.Message.ProtocolMessage.Type.SHARE_PHONE_NUMBER
|
|
871
|
+
};
|
|
872
|
+
}
|
|
873
|
+
else if ('requestPhoneNumber' in message) {
|
|
874
|
+
m.requestPhoneNumberMessage = {};
|
|
318
875
|
}
|
|
319
|
-
else if ('
|
|
320
|
-
m.
|
|
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
|
|
992
|
+
};
|
|
993
|
+
}
|
|
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
|
+
};
|
|
1002
|
+
}
|
|
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
|
+
};
|
|
1009
|
+
}
|
|
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
|
+
});
|
|
321
1017
|
}
|
|
322
1018
|
else {
|
|
323
1019
|
m = await (0, exports.prepareWAMessageMedia)(message, options);
|
|
324
1020
|
}
|
|
325
|
-
|
|
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
|
+
}
|
|
326
1282
|
if ('cards' in message && !!message.cards && message.cards.length > 0) {
|
|
327
|
-
const carouselCardType = message.carouselCardType || 1;
|
|
1283
|
+
const carouselCardType = message.carouselCardType || 1; // HSCROLL_CARDS = 1, ALBUM_IMAGE = 2
|
|
328
1284
|
const carouselCards = await Promise.all(message.cards.map(async (card) => {
|
|
329
1285
|
const cardMessage = {
|
|
330
1286
|
header: {
|
|
@@ -333,23 +1289,26 @@ const generateWAMessageContent = async (message, options) => {
|
|
|
333
1289
|
}
|
|
334
1290
|
};
|
|
335
1291
|
|
|
1292
|
+
// Add body as separate field if present
|
|
336
1293
|
if (card.body) {
|
|
337
|
-
cardMessage.body = {
|
|
1294
|
+
cardMessage.body = {
|
|
1295
|
+
text: card.body
|
|
1296
|
+
};
|
|
338
1297
|
}
|
|
339
|
-
|
|
1298
|
+
// Handle media attachments
|
|
340
1299
|
if (card.image) {
|
|
341
|
-
const mediaMessage = await
|
|
1300
|
+
const mediaMessage = await prepareWAMessageMedia({ image: card.image }, options);
|
|
342
1301
|
if (mediaMessage.imageMessage) {
|
|
343
1302
|
cardMessage.header.imageMessage = mediaMessage.imageMessage;
|
|
344
1303
|
}
|
|
345
1304
|
}
|
|
346
1305
|
else if (card.video) {
|
|
347
|
-
const mediaMessage = await
|
|
1306
|
+
const mediaMessage = await prepareWAMessageMedia({ video: card.video }, options);
|
|
348
1307
|
if (mediaMessage.videoMessage) {
|
|
349
1308
|
cardMessage.header.videoMessage = mediaMessage.videoMessage;
|
|
350
1309
|
}
|
|
351
1310
|
}
|
|
352
|
-
|
|
1311
|
+
// Handle buttons
|
|
353
1312
|
if (card.buttons && card.buttons.length > 0) {
|
|
354
1313
|
cardMessage.nativeFlowMessage = {
|
|
355
1314
|
buttons: card.buttons.map(button => ({
|
|
@@ -359,14 +1318,14 @@ const generateWAMessageContent = async (message, options) => {
|
|
|
359
1318
|
messageVersion: 1,
|
|
360
1319
|
};
|
|
361
1320
|
}
|
|
362
|
-
|
|
1321
|
+
// Add footer if present
|
|
363
1322
|
if (card.footer) {
|
|
364
|
-
cardMessage.footer = {
|
|
1323
|
+
cardMessage.footer = {
|
|
1324
|
+
text: card.footer
|
|
1325
|
+
};
|
|
365
1326
|
}
|
|
366
|
-
|
|
367
1327
|
return cardMessage;
|
|
368
1328
|
}));
|
|
369
|
-
|
|
370
1329
|
const interactiveMessage = {
|
|
371
1330
|
carouselMessage: Types_1.WAProto.Message.InteractiveMessage.CarouselMessage.fromObject({
|
|
372
1331
|
cards: carouselCards,
|
|
@@ -374,12 +1333,15 @@ const generateWAMessageContent = async (message, options) => {
|
|
|
374
1333
|
carouselCardType: carouselCardType
|
|
375
1334
|
})
|
|
376
1335
|
};
|
|
377
|
-
|
|
378
1336
|
if ('text' in message) {
|
|
379
|
-
interactiveMessage.body = {
|
|
1337
|
+
interactiveMessage.body = {
|
|
1338
|
+
text: message.text
|
|
1339
|
+
};
|
|
380
1340
|
}
|
|
381
1341
|
if ('footer' in message && !!message.footer) {
|
|
382
|
-
interactiveMessage.footer = {
|
|
1342
|
+
interactiveMessage.footer = {
|
|
1343
|
+
text: message.footer
|
|
1344
|
+
};
|
|
383
1345
|
}
|
|
384
1346
|
if ('title' in message && !!message.title) {
|
|
385
1347
|
interactiveMessage.header = {
|
|
@@ -394,25 +1356,20 @@ const generateWAMessageContent = async (message, options) => {
|
|
|
394
1356
|
if ('mentions' in message && !!message.mentions) {
|
|
395
1357
|
interactiveMessage.contextInfo = { mentionedJid: message.mentions };
|
|
396
1358
|
}
|
|
397
|
-
|
|
398
1359
|
m = { interactiveMessage };
|
|
399
1360
|
}
|
|
400
|
-
|
|
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).
|
|
401
1363
|
const shouldWrapInteractive = !!(m === null || m === void 0 ? void 0 : m.interactiveMessage);
|
|
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
|
-
|
|
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);
|
|
406
1365
|
if ((('viewOnce' in message && !!message.viewOnce) || shouldWrapInteractive) && !hasViewOnceAlready) {
|
|
407
1366
|
m = { viewOnceMessageV2: { message: m } };
|
|
408
1367
|
}
|
|
409
|
-
|
|
410
|
-
if ('mentions' in message && (message.mentions?.length)) {
|
|
1368
|
+
if ('mentions' in message && ((_o = message.mentions) === null || _o === void 0 ? void 0 : _o.length)) {
|
|
411
1369
|
const [messageType] = Object.keys(m);
|
|
412
|
-
m[messageType].contextInfo = m[messageType]
|
|
1370
|
+
m[messageType].contextInfo = m[messageType] || {};
|
|
413
1371
|
m[messageType].contextInfo.mentionedJid = message.mentions;
|
|
414
1372
|
}
|
|
415
|
-
|
|
416
1373
|
if ('edit' in message) {
|
|
417
1374
|
m = {
|
|
418
1375
|
protocolMessage: {
|
|
@@ -423,7 +1380,6 @@ const generateWAMessageContent = async (message, options) => {
|
|
|
423
1380
|
}
|
|
424
1381
|
};
|
|
425
1382
|
}
|
|
426
|
-
|
|
427
1383
|
if ('contextInfo' in message && !!message.contextInfo) {
|
|
428
1384
|
const [messageType] = Object.keys(m);
|
|
429
1385
|
m[messageType] = m[messageType] || {};
|
|
@@ -432,94 +1388,406 @@ const generateWAMessageContent = async (message, options) => {
|
|
|
432
1388
|
...message.contextInfo
|
|
433
1389
|
};
|
|
434
1390
|
}
|
|
435
|
-
|
|
436
1391
|
return Types_1.WAProto.Message.fromObject(m);
|
|
437
1392
|
};
|
|
438
1393
|
exports.generateWAMessageContent = generateWAMessageContent;
|
|
439
|
-
|
|
440
1394
|
const generateWAMessageFromContent = (jid, message, options) => {
|
|
1395
|
+
// set timestamp to now
|
|
1396
|
+
// if not specified
|
|
441
1397
|
if (!options.timestamp) {
|
|
442
1398
|
options.timestamp = new Date();
|
|
443
1399
|
}
|
|
444
|
-
|
|
445
1400
|
const innerMessage = (0, exports.normalizeMessageContent)(message);
|
|
446
1401
|
const key = (0, exports.getContentType)(innerMessage);
|
|
447
1402
|
const timestamp = (0, generics_1.unixTimestampSeconds)(options.timestamp);
|
|
448
1403
|
const { quoted, userJid } = options;
|
|
449
|
-
|
|
1404
|
+
// only set quoted if isn't a newsletter message
|
|
450
1405
|
if (quoted && !(0, WABinary_1.isJidNewsletter)(jid)) {
|
|
451
1406
|
const participant = quoted.key.fromMe ? userJid : (quoted.participant || quoted.key.participant || quoted.key.remoteJid);
|
|
452
1407
|
let quotedMsg = (0, exports.normalizeMessageContent)(quoted.message);
|
|
453
1408
|
const msgType = (0, exports.getContentType)(quotedMsg);
|
|
454
|
-
|
|
1409
|
+
// strip any redundant properties
|
|
455
1410
|
if (quotedMsg) {
|
|
456
1411
|
quotedMsg = WAProto_1.proto.Message.fromObject({ [msgType]: quotedMsg[msgType] });
|
|
457
1412
|
const quotedContent = quotedMsg[msgType];
|
|
458
1413
|
if (typeof quotedContent === 'object' && quotedContent && 'contextInfo' in quotedContent) {
|
|
459
1414
|
delete quotedContent.contextInfo;
|
|
460
1415
|
}
|
|
461
|
-
|
|
462
1416
|
const contextInfo = innerMessage[key].contextInfo || {};
|
|
463
1417
|
contextInfo.participant = (0, WABinary_1.jidNormalizedUser)(participant);
|
|
464
1418
|
contextInfo.stanzaId = quoted.key.id;
|
|
465
1419
|
contextInfo.quotedMessage = quotedMsg;
|
|
466
|
-
|
|
1420
|
+
// if a participant is quoted, then it must be a group
|
|
1421
|
+
// hence, remoteJid of group must also be entered
|
|
467
1422
|
if (jid !== quoted.key.remoteJid) {
|
|
468
1423
|
contextInfo.remoteJid = quoted.key.remoteJid;
|
|
469
1424
|
}
|
|
470
|
-
|
|
471
1425
|
innerMessage[key].contextInfo = contextInfo;
|
|
472
1426
|
}
|
|
473
1427
|
}
|
|
474
|
-
|
|
475
|
-
if
|
|
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
|
|
476
1432
|
key !== 'protocolMessage' &&
|
|
1433
|
+
// already not converted to disappearing message
|
|
477
1434
|
key !== 'ephemeralMessage' &&
|
|
1435
|
+
// newsletter not accept disappearing messages
|
|
478
1436
|
!(0, WABinary_1.isJidNewsletter)(jid)) {
|
|
479
1437
|
innerMessage[key].contextInfo = {
|
|
480
1438
|
...(innerMessage[key].contextInfo || {}),
|
|
481
1439
|
expiration: options.ephemeralExpiration || Defaults_1.WA_DEFAULT_EPHEMERAL,
|
|
1440
|
+
//ephemeralSettingTimestamp: options.ephemeralOptions.eph_setting_ts?.toString()
|
|
482
1441
|
};
|
|
483
1442
|
}
|
|
484
|
-
|
|
485
|
-
const
|
|
1443
|
+
message = Types_1.WAProto.Message.fromObject(message);
|
|
1444
|
+
const messageJSON = {
|
|
486
1445
|
key: {
|
|
487
1446
|
remoteJid: jid,
|
|
488
1447
|
fromMe: true,
|
|
489
|
-
id: options.messageId || (0, generics_1.
|
|
1448
|
+
id: (options === null || options === void 0 ? void 0 : options.messageId) || (0, generics_1.generateMessageIDV2)(),
|
|
490
1449
|
},
|
|
491
|
-
message:
|
|
1450
|
+
message: message,
|
|
492
1451
|
messageTimestamp: timestamp,
|
|
493
1452
|
messageStubParameters: [],
|
|
494
|
-
participant: (0, WABinary_1.isJidGroup)(jid) ? userJid : undefined,
|
|
1453
|
+
participant: (0, WABinary_1.isJidGroup)(jid) || (0, WABinary_1.isJidStatusBroadcast)(jid) ? userJid : undefined,
|
|
495
1454
|
status: Types_1.WAMessageStatus.PENDING
|
|
496
1455
|
};
|
|
497
|
-
|
|
498
|
-
return WAProto_1.proto.WebMessageInfo.fromObject(msg);
|
|
1456
|
+
return Types_1.WAProto.WebMessageInfo.fromObject(messageJSON);
|
|
499
1457
|
};
|
|
500
1458
|
exports.generateWAMessageFromContent = generateWAMessageFromContent;
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
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 || []) {
|
|
507
1625
|
const { vote } = update;
|
|
508
|
-
if (!vote)
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
for (const option of selectedOptions) {
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
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];
|
|
515
1638
|
}
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
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();
|
|
1743
|
+
|
|
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
|
|
520
1764
|
}
|
|
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
|
+
});
|
|
521
1788
|
}
|
|
1789
|
+
} catch (error) {
|
|
1790
|
+
// Silently fail if cache manager is not available
|
|
522
1791
|
}
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
}
|
|
1792
|
+
};
|
|
1793
|
+
exports.clearCache = clearCache;
|