@badzz88/baileys 8.5.3 → 8.5.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/WAProto/WAProto.proto +1256 -75
- package/WAProto/index.d.ts +36042 -19649
- package/WAProto/index.js +181990 -135645
- package/engine-requirements.js +7 -15
- package/lib/Defaults/index.js +22 -17
- package/lib/Signal/Group/group_cipher.js +5 -5
- package/lib/Signal/Group/keyhelper.js +4 -4
- package/lib/Signal/Group/sender-chain-key.js +2 -2
- package/lib/Signal/Group/sender-key-distribution-message.js +1 -1
- package/lib/Signal/Group/sender-key-message.js +3 -3
- package/lib/Signal/Group/sender-key-record.js +1 -1
- package/lib/Signal/Group/sender-message-key.js +5 -5
- package/lib/Signal/libsignal.js +39 -59
- package/lib/Signal/lid-mapping.js +28 -10
- package/lib/Socket/aigroups.js +5 -5
- package/lib/Socket/business.js +3 -11
- package/lib/Socket/chats.js +668 -319
- package/lib/Socket/communities.js +85 -89
- package/lib/Socket/graphql.js +435 -228
- package/lib/Socket/groups.js +132 -211
- package/lib/Socket/index.js +9 -7
- package/lib/Socket/interactive-handler.js +117 -60
- package/lib/Socket/interop.js +56 -175
- package/lib/Socket/managed-account.js +79 -48
- package/lib/Socket/messages-recv.js +898 -340
- package/lib/Socket/messages-send.js +462 -160
- package/lib/Socket/mex.js +40 -53
- package/lib/Socket/newsletter.js +291 -295
- package/lib/Socket/privacy.js +77 -265
- package/lib/Socket/registration.js +164 -157
- package/lib/Socket/socket.js +181 -199
- package/lib/Socket/username.js +144 -227
- package/lib/Store/make-cache-manager-store.js +2 -2
- package/lib/Store/make-in-memory-store.js +25 -141
- package/lib/Types/Auth.js +3 -3
- package/lib/Types/Label.js +1 -1
- package/lib/Types/LabelAssociation.js +1 -1
- package/lib/Types/Newsletter.js +96 -65
- package/lib/Types/State.js +4 -4
- package/lib/Types/index.js +1 -1
- package/lib/Utils/auth-utils.js +52 -57
- package/lib/Utils/browser-utils.js +1 -1
- package/lib/Utils/business.js +2 -6
- package/lib/Utils/chat-utils.js +102 -38
- package/lib/Utils/crypto.js +54 -84
- package/lib/Utils/decode-wa-message.js +316 -83
- package/lib/Utils/event-buffer.js +37 -61
- package/lib/Utils/generics.js +157 -103
- package/lib/Utils/group-history.js +3 -12
- package/lib/Utils/history.js +15 -15
- package/lib/Utils/index.js +1 -5
- package/lib/Utils/link-preview.js +3 -8
- package/lib/Utils/lt-hash.js +2 -35
- package/lib/Utils/make-mutex.js +1 -1
- package/lib/Utils/message-inspect.js +393 -0
- package/lib/Utils/message-retry-manager.js +27 -92
- package/lib/Utils/messages-media.js +159 -130
- package/lib/Utils/messages.js +144 -566
- package/lib/Utils/meta-ai-msmsg.js +62 -202
- package/lib/Utils/noise-handler.js +19 -21
- package/lib/Utils/offline-node-processor.js +3 -8
- package/lib/Utils/pre-key-manager.js +13 -23
- package/lib/Utils/process-message.js +197 -106
- package/lib/Utils/reporting-utils.js +2 -2
- package/lib/Utils/signal.js +28 -63
- package/lib/Utils/stanza-ack.js +39 -12
- package/lib/Utils/sync-action-utils.js +4 -7
- package/lib/Utils/tc-token-utils.js +20 -25
- package/lib/Utils/use-multi-file-auth-state.js +30 -14
- package/lib/Utils/validate-connection.js +59 -19
- package/lib/WABinary/decode.js +50 -16
- package/lib/WABinary/encode.js +54 -224
- package/lib/WABinary/generic-utils.js +7 -97
- package/lib/WABinary/jid-utils.js +27 -14
- package/lib/WAM/encode.js +7 -7
- package/lib/WAUSync/Protocols/USyncBusinessProtocol.js +58 -1
- package/lib/WAUSync/Protocols/USyncContactProtocol.js +7 -1
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +13 -5
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +1 -4
- package/lib/WAUSync/Protocols/USyncFeatureProtocol.js +20 -7
- package/lib/WAUSync/Protocols/USyncNewsletterProtocol.js +865 -0
- package/lib/WAUSync/Protocols/USyncPictureProtocol.js +1 -1
- package/lib/WAUSync/Protocols/USyncSidelistProtocol.js +2 -2
- package/lib/WAUSync/Protocols/USyncStatusProtocol.js +7 -2
- package/lib/WAUSync/Protocols/USyncTextStatusProtocol.js +1 -1
- package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +2 -1
- package/lib/WAUSync/Protocols/index.js +1 -0
- package/lib/WAUSync/USyncBackoff.js +26 -0
- package/lib/WAUSync/USyncQuery.js +77 -6
- package/lib/WAUSync/USyncUser.js +16 -8
- package/lib/WAUSync/index.js +1 -0
- package/lib/antiban.js +608 -854
- package/lib/index.js +1 -1
- package/package.json +16 -20
- package/lib/Socket/luxu.js +0 -387
- package/lib/Socket/text-router.js +0 -83
- package/lib/Store/keyed-db.js +0 -108
- package/lib/Types/Mex.js +0 -112
- package/lib/Utils/command-loader.d.ts +0 -31
- package/lib/Utils/command-loader.js +0 -100
- package/lib/Utils/companion-reg-client-utils.js +0 -42
- package/lib/Utils/curve25519-js.js +0 -275
- package/lib/Utils/native-bridge.js +0 -82
- package/lib/Utils/session-pool.d.ts +0 -16
- package/lib/Utils/session-pool.js +0 -94
- package/lib/Utils/sticker.d.ts +0 -17
- package/lib/Utils/sticker.js +0 -145
- package/lib/Utils/view-once-cache.d.ts +0 -9
- package/lib/Utils/view-once-cache.js +0 -79
package/lib/Utils/messages.js
CHANGED
|
@@ -1,17 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
Object.defineProperty(exports, '__esModule', { value: true })
|
|
3
|
-
exports.
|
|
4
|
-
exports.downloadMediaMessage =
|
|
5
|
-
exports.aggregateMessageKeysNotFromMe =
|
|
6
|
-
exports.updateMessageWithEventResponse =
|
|
7
|
-
exports.updateMessageWithPollUpdate =
|
|
8
|
-
exports.updateMessageWithReaction =
|
|
9
|
-
exports.updateMessageWithReceipt =
|
|
10
|
-
exports.getDevice =
|
|
11
|
-
exports.extractMessageContent =
|
|
12
|
-
exports.normalizeMessageContent =
|
|
13
|
-
exports.getContentType =
|
|
14
|
-
exports.generateWAMessage =
|
|
3
|
+
exports.generateWAMessage =
|
|
15
4
|
exports.generateWAMessageFromContent =
|
|
16
5
|
exports.generateWAMessageContent =
|
|
17
6
|
exports.hasNonNullishProperty =
|
|
@@ -21,12 +10,10 @@ exports.assertMediaContent =
|
|
|
21
10
|
exports.generateLinkPreviewIfRequired =
|
|
22
11
|
exports.extractUrlFromText =
|
|
23
12
|
void 0
|
|
24
|
-
exports.getAggregateVotesInPollMessage = getAggregateVotesInPollMessage
|
|
25
|
-
exports.getAggregateResponsesInEventMessage = getAggregateResponsesInEventMessage
|
|
26
13
|
const boom_1 = require('@hapi/boom')
|
|
27
14
|
const crypto_1 = require('crypto')
|
|
28
15
|
const fs_1 = require('fs')
|
|
29
|
-
const
|
|
16
|
+
const lru_cache_1 = require('lru-cache')
|
|
30
17
|
const WAProto_1 = require('../../WAProto/index.js')
|
|
31
18
|
const Defaults_1 = require('../Defaults')
|
|
32
19
|
const Types_1 = require('../Types')
|
|
@@ -36,6 +23,12 @@ const generics_1 = require('./generics')
|
|
|
36
23
|
const messages_media_1 = require('./messages-media')
|
|
37
24
|
const reporting_utils_1 = require('./reporting-utils')
|
|
38
25
|
const jid_display_normalization_1 = require('./jid-display-normalization')
|
|
26
|
+
const message_inspect_1 = require('./message-inspect')
|
|
27
|
+
Object.assign(exports, message_inspect_1)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
const groupInviteThumbnailCache = new lru_cache_1.LRUCache({ max: 100, ttl: 5 * 60 * 1000 })
|
|
39
32
|
const MIMETYPE_MAP = {
|
|
40
33
|
image: 'image/jpeg',
|
|
41
34
|
video: 'video/mp4',
|
|
@@ -52,14 +45,14 @@ const MessageTypeProto = {
|
|
|
52
45
|
document: WAProto_1.proto.Message.DocumentMessage
|
|
53
46
|
}
|
|
54
47
|
|
|
55
|
-
|
|
48
|
+
|
|
56
49
|
const MEDIA_MESSAGE_TYPE_ALIASES = {
|
|
57
50
|
imageMessage: 'image',
|
|
58
51
|
videoMessage: 'video',
|
|
59
52
|
audioMessage: 'audio',
|
|
60
53
|
documentMessage: 'document',
|
|
61
54
|
stickerMessage: 'sticker',
|
|
62
|
-
|
|
55
|
+
|
|
63
56
|
ptvMessage: 'video'
|
|
64
57
|
}
|
|
65
58
|
const MEDIA_MESSAGE_TYPE_ALIAS_KEYS = Object.keys(MEDIA_MESSAGE_TYPE_ALIASES)
|
|
@@ -196,11 +189,7 @@ const tokenizeCode = code => {
|
|
|
196
189
|
return merged
|
|
197
190
|
}
|
|
198
191
|
|
|
199
|
-
|
|
200
|
-
* Uses a regex to test whether the string contains a URL, and returns the URL if it does.
|
|
201
|
-
* @param text eg. hello https://google.com
|
|
202
|
-
* @returns the URL, eg. https://google.com
|
|
203
|
-
*/
|
|
192
|
+
|
|
204
193
|
const extractUrlFromText = text => text.match(Defaults_1.URL_REGEX)?.[0]
|
|
205
194
|
exports.extractUrlFromText = extractUrlFromText
|
|
206
195
|
const generateLinkPreviewIfRequired = async (text, getUrlInfo, logger) => {
|
|
@@ -210,7 +199,7 @@ const generateLinkPreviewIfRequired = async (text, getUrlInfo, logger) => {
|
|
|
210
199
|
const urlInfo = await getUrlInfo(url)
|
|
211
200
|
return urlInfo
|
|
212
201
|
} catch (error) {
|
|
213
|
-
|
|
202
|
+
|
|
214
203
|
logger?.warn({ trace: error.stack }, 'url generation failed')
|
|
215
204
|
}
|
|
216
205
|
}
|
|
@@ -231,6 +220,9 @@ const assertColor = async color => {
|
|
|
231
220
|
}
|
|
232
221
|
const prepareWAMessageMedia = async (message, options) => {
|
|
233
222
|
const logger = options.logger
|
|
223
|
+
|
|
224
|
+
const mediaAbProps = options.mediaAbProps || null
|
|
225
|
+
const getMediaProp = propName => (0, messages_media_1.getMediaProp)(mediaAbProps, propName)
|
|
234
226
|
let mediaType
|
|
235
227
|
for (const key of Defaults_1.MEDIA_KEYS) {
|
|
236
228
|
if (key in message) {
|
|
@@ -245,7 +237,20 @@ const prepareWAMessageMedia = async (message, options) => {
|
|
|
245
237
|
media: message[mediaType]
|
|
246
238
|
}
|
|
247
239
|
delete uploadData[mediaType]
|
|
248
|
-
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
if (mediaType === 'video' && uploadData.mimetype) {
|
|
245
|
+
const isHevc = uploadData.mimetype.includes('hevc') || uploadData.mimetype.includes('x-matroska')
|
|
246
|
+
if (isHevc && !getMediaProp('hevc_video_dual_upload')) {
|
|
247
|
+
|
|
248
|
+
uploadData.mimetype = MIMETYPE_MAP['video']
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
|
|
249
254
|
const cacheableKey =
|
|
250
255
|
typeof uploadData.media === 'object' &&
|
|
251
256
|
'url' in uploadData.media &&
|
|
@@ -262,7 +267,7 @@ const prepareWAMessageMedia = async (message, options) => {
|
|
|
262
267
|
const mediaBuff = await options.mediaCache.get(cacheableKey)
|
|
263
268
|
if (mediaBuff) {
|
|
264
269
|
logger?.debug({ cacheableKey }, 'got media cache hit')
|
|
265
|
-
const obj =
|
|
270
|
+
const obj = WAProto_1.proto.Message.decode(mediaBuff)
|
|
266
271
|
const key = `${mediaType}Message`
|
|
267
272
|
Object.assign(obj[key], { ...uploadData, media: undefined })
|
|
268
273
|
return obj
|
|
@@ -284,7 +289,7 @@ const prepareWAMessageMedia = async (message, options) => {
|
|
|
284
289
|
})
|
|
285
290
|
await fs_1.promises.unlink(filePath)
|
|
286
291
|
const obj = WAProto_1.proto.Message.fromObject({
|
|
287
|
-
|
|
292
|
+
|
|
288
293
|
[`${mediaType}Message`]: MessageTypeProto[mediaType].fromObject({
|
|
289
294
|
url: mediaUrl,
|
|
290
295
|
directPath,
|
|
@@ -375,6 +380,27 @@ const prepareWAMessageMedia = async (message, options) => {
|
|
|
375
380
|
logger?.warn('failed to remove tmp file')
|
|
376
381
|
}
|
|
377
382
|
})
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
const hdImageEnabled = mediaType === 'image' && getMediaProp('hd_image_dual_upload') && !!uploadData.hd
|
|
387
|
+
const hdVideoEnabled = mediaType === 'video' && getMediaProp('hd_video_dual_upload') && !!uploadData.hd
|
|
388
|
+
if (hdImageEnabled || hdVideoEnabled) {
|
|
389
|
+
uploadData.mediaHd = true
|
|
390
|
+
logger?.debug({ mediaType }, 'HD dual upload enabled, setting mediaHd flag')
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
if (mediaType === 'image' && uploadData.motionPhoto != null) {
|
|
396
|
+
|
|
397
|
+
|
|
398
|
+
if (typeof uploadData.motionPhoto === 'boolean') {
|
|
399
|
+
uploadData.motionPhoto = uploadData.motionPhoto ? 1 : 0
|
|
400
|
+
}
|
|
401
|
+
logger?.debug('motion photo field set on image message')
|
|
402
|
+
}
|
|
403
|
+
|
|
378
404
|
const obj = WAProto_1.proto.Message.fromObject({
|
|
379
405
|
[`${mediaType}Message`]: MessageTypeProto[mediaType].fromObject({
|
|
380
406
|
url: mediaUrl,
|
|
@@ -414,19 +440,15 @@ const prepareDisappearingMessageSettingContent = ephemeralExpiration => {
|
|
|
414
440
|
return WAProto_1.proto.Message.fromObject(content)
|
|
415
441
|
}
|
|
416
442
|
exports.prepareDisappearingMessageSettingContent = prepareDisappearingMessageSettingContent
|
|
417
|
-
|
|
418
|
-
* Generate forwarded message content like WA does
|
|
419
|
-
* @param message the message to forward
|
|
420
|
-
* @param options.forceForward will show the message as forwarded even if it is from you
|
|
421
|
-
*/
|
|
443
|
+
|
|
422
444
|
const generateForwardMessageContent = (message, forceForward) => {
|
|
423
445
|
let content = message.message
|
|
424
446
|
if (!content) {
|
|
425
447
|
throw new boom_1.Boom('no content in message', { statusCode: 400 })
|
|
426
448
|
}
|
|
427
|
-
|
|
449
|
+
|
|
428
450
|
content = (0, exports.normalizeMessageContent)(content)
|
|
429
|
-
content =
|
|
451
|
+
content = WAProto_1.proto.Message.decode(WAProto_1.proto.Message.encode(content).finish())
|
|
430
452
|
let key = Object.keys(content)[0]
|
|
431
453
|
let score = content?.[key]?.contextInfo?.forwardingScore || 0
|
|
432
454
|
score += message.key.fromMe && !forceForward ? 0 : 1
|
|
@@ -654,15 +676,19 @@ const generateWAMessageContent = async (message, options) => {
|
|
|
654
676
|
m.groupInviteMessage.caption = message.groupInvite.text
|
|
655
677
|
m.groupInviteMessage.groupJid = message.groupInvite.jid
|
|
656
678
|
m.groupInviteMessage.groupName = message.groupInvite.subject
|
|
657
|
-
//TODO: use built-in interface and get disappearing mode info etc.
|
|
658
|
-
//TODO: cache / use store!?
|
|
659
679
|
if (options.getProfilePicUrl) {
|
|
660
|
-
const
|
|
661
|
-
if (
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
680
|
+
const cached = groupInviteThumbnailCache.get(message.groupInvite.jid)
|
|
681
|
+
if (cached) {
|
|
682
|
+
m.groupInviteMessage.jpegThumbnail = cached
|
|
683
|
+
} else {
|
|
684
|
+
const pfpUrl = await options.getProfilePicUrl(message.groupInvite.jid, 'preview')
|
|
685
|
+
if (pfpUrl) {
|
|
686
|
+
const resp = await fetch(pfpUrl, { method: 'GET', dispatcher: options?.options?.dispatcher })
|
|
687
|
+
if (resp.ok) {
|
|
688
|
+
const buf = Buffer.from(await resp.arrayBuffer())
|
|
689
|
+
m.groupInviteMessage.jpegThumbnail = buf
|
|
690
|
+
groupInviteThumbnailCache.set(message.groupInvite.jid, buf)
|
|
691
|
+
}
|
|
666
692
|
}
|
|
667
693
|
}
|
|
668
694
|
}
|
|
@@ -686,7 +712,7 @@ const generateWAMessageContent = async (message, options) => {
|
|
|
686
712
|
m.buttonsResponseMessage = {
|
|
687
713
|
selectedButtonId: message.buttonReply.id,
|
|
688
714
|
selectedDisplayText: message.buttonReply.displayText,
|
|
689
|
-
type:
|
|
715
|
+
type: WAProto_1.proto.Message.ButtonsResponseMessage.Type.DISPLAY_TEXT
|
|
690
716
|
}
|
|
691
717
|
break
|
|
692
718
|
case 'interactive':
|
|
@@ -736,7 +762,7 @@ const generateWAMessageContent = async (message, options) => {
|
|
|
736
762
|
(message.event.call === 'audio' ? Defaults_1.CALL_AUDIO_PREFIX : Defaults_1.CALL_VIDEO_PREFIX) + token
|
|
737
763
|
}
|
|
738
764
|
m.messageContextInfo = {
|
|
739
|
-
|
|
765
|
+
|
|
740
766
|
messageSecret: message.event.messageSecret || (0, crypto_1.randomBytes)(32)
|
|
741
767
|
}
|
|
742
768
|
m.eventMessage.name = message.event.name
|
|
@@ -780,21 +806,26 @@ const generateWAMessageContent = async (message, options) => {
|
|
|
780
806
|
...(message.poll.hideParticipantName !== undefined
|
|
781
807
|
? { hideParticipantName: !!message.poll.hideParticipantName }
|
|
782
808
|
: {}),
|
|
783
|
-
...(message.poll.allowAddOption !== undefined ? { allowAddOption: !!message.poll.allowAddOption } : {})
|
|
809
|
+
...(message.poll.allowAddOption !== undefined ? { allowAddOption: !!message.poll.allowAddOption } : {}),
|
|
810
|
+
|
|
811
|
+
|
|
812
|
+
...((0, messages_media_1.getMediaProp)(options.mediaAbProps, 'media_poll') && message.poll.mediaPoll != null
|
|
813
|
+
? { mediaPoll: !!message.poll.mediaPoll }
|
|
814
|
+
: {})
|
|
784
815
|
}
|
|
785
816
|
if (message.poll.version === 6 || message.poll.v6) {
|
|
786
817
|
m.pollCreationMessageV6 = pollCreationMessage
|
|
787
818
|
} else if (message.poll.version === 5 || message.poll.v5) {
|
|
788
819
|
m.pollCreationMessageV5 = pollCreationMessage
|
|
789
820
|
} else if (message.poll.toAnnouncementGroup) {
|
|
790
|
-
|
|
821
|
+
|
|
791
822
|
m.pollCreationMessageV2 = pollCreationMessage
|
|
792
823
|
} else {
|
|
793
824
|
if (message.poll.selectableCount === 1) {
|
|
794
|
-
|
|
825
|
+
|
|
795
826
|
m.pollCreationMessageV3 = pollCreationMessage
|
|
796
827
|
} else {
|
|
797
|
-
|
|
828
|
+
|
|
798
829
|
m.pollCreationMessage = pollCreationMessage
|
|
799
830
|
}
|
|
800
831
|
}
|
|
@@ -923,13 +954,13 @@ const generateWAMessageContent = async (message, options) => {
|
|
|
923
954
|
}
|
|
924
955
|
} else if ((0, exports.hasNonNullishProperty)(message, 'sharePhoneNumber')) {
|
|
925
956
|
m.protocolMessage = {
|
|
926
|
-
type:
|
|
957
|
+
type: WAProto_1.proto.Message.ProtocolMessage.Type.SHARE_PHONE_NUMBER
|
|
927
958
|
}
|
|
928
959
|
} else if ((0, exports.hasNonNullishProperty)(message, 'requestPhoneNumber')) {
|
|
929
960
|
m.requestPhoneNumberMessage = {}
|
|
930
961
|
} else if ((0, exports.hasNonNullishProperty)(message, 'limitSharing')) {
|
|
931
962
|
m.protocolMessage = {
|
|
932
|
-
type:
|
|
963
|
+
type: WAProto_1.proto.Message.ProtocolMessage.Type.LIMIT_SHARING,
|
|
933
964
|
limitSharing: {
|
|
934
965
|
sharingLimited: message.limitSharing === true,
|
|
935
966
|
trigger: 1,
|
|
@@ -986,7 +1017,7 @@ const generateWAMessageContent = async (message, options) => {
|
|
|
986
1017
|
} else if ('interactiveMessage' in message) {
|
|
987
1018
|
m = { interactiveMessage: message.interactiveMessage }
|
|
988
1019
|
} else if ('richResponse' in message) {
|
|
989
|
-
|
|
1020
|
+
|
|
990
1021
|
} else if ('groupStatusMessage' in message) {
|
|
991
1022
|
m = { groupStatusMessage: WAProto_1.proto.Message.GroupStatusMessage.fromObject(message.groupStatusMessage) }
|
|
992
1023
|
} else if (hasCaptionWithoutMedia && !hasCaptionContainer) {
|
|
@@ -1032,7 +1063,7 @@ const generateWAMessageContent = async (message, options) => {
|
|
|
1032
1063
|
m = { interactiveMessage }
|
|
1033
1064
|
} else if ('templateButtons' in message && !!message.templateButtons) {
|
|
1034
1065
|
const msg = {
|
|
1035
|
-
hydratedButtons: message.
|
|
1066
|
+
hydratedButtons: message.templateButtons
|
|
1036
1067
|
}
|
|
1037
1068
|
if ('text' in message) {
|
|
1038
1069
|
msg.hydratedContentText = message.text
|
|
@@ -1089,73 +1120,42 @@ const generateWAMessageContent = async (message, options) => {
|
|
|
1089
1120
|
}
|
|
1090
1121
|
}
|
|
1091
1122
|
if ('interactiveButtons' in message && !!message.interactiveButtons) {
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
} else if ('document' in message && !!message.document) {
|
|
1129
|
-
media = await prepareWAMessageMedia({ document: message.document }, options);
|
|
1130
|
-
interactiveMessage.header.documentMessage = media.documentMessage;
|
|
1131
|
-
let docuR = interactiveMessage.header.documentMessage;
|
|
1132
|
-
docuR.fileName = message.document.fileName || "Document";
|
|
1133
|
-
docuR.mimetype = message.document.mimetype || docuR.mimetype;
|
|
1134
|
-
if (message.document.caption) docuR.caption = message.document.caption;
|
|
1135
|
-
if (message.document.jpegThumbnail) docuR.jpegThumbnail = message.document.jpegThumbnail;
|
|
1136
|
-
} else if ('location' in message && !!message.location) {
|
|
1137
|
-
let mLoc = message.location;
|
|
1138
|
-
interactiveMessage.header.locationMessage = {
|
|
1139
|
-
degreesLongitude: mLoc.longitude || 0,
|
|
1140
|
-
degreesLatitude: mLoc.latitude || 0,
|
|
1141
|
-
name: mLoc.name || null,
|
|
1142
|
-
address: mLoc.address || null,
|
|
1143
|
-
url: mLoc.url || null
|
|
1144
|
-
};
|
|
1145
|
-
media = true;
|
|
1146
|
-
} else if ('thumbnail' in message && !!message.thumbnail) {
|
|
1147
|
-
interactiveMessage.header.jpegThumbnail = message.thumbnail;
|
|
1148
|
-
}
|
|
1149
|
-
if (media || ('thumbnail' in message && !!message.thumbnail)) {
|
|
1150
|
-
interactiveMessage.header.hasMediaAttachment = true;
|
|
1151
|
-
}
|
|
1152
|
-
}
|
|
1153
|
-
if ('footer' in message && !!message.footer) {
|
|
1154
|
-
interactiveMessage.footer = { text: message.footer };
|
|
1155
|
-
}
|
|
1156
|
-
applyContextInfoAndMentions(interactiveMessage, message);
|
|
1157
|
-
m = { interactiveMessage };
|
|
1158
|
-
}
|
|
1123
|
+
const interactiveMessage = {
|
|
1124
|
+
nativeFlowMessage: WAProto_1.proto.Message.InteractiveMessage.NativeFlowMessage.fromObject({
|
|
1125
|
+
buttons: message.interactiveButtons
|
|
1126
|
+
})
|
|
1127
|
+
}
|
|
1128
|
+
if ('text' in message) {
|
|
1129
|
+
interactiveMessage.body = {
|
|
1130
|
+
text: message.text
|
|
1131
|
+
}
|
|
1132
|
+
} else if ('caption' in message) {
|
|
1133
|
+
interactiveMessage.body = {
|
|
1134
|
+
text: message.caption
|
|
1135
|
+
}
|
|
1136
|
+
interactiveMessage.header = {
|
|
1137
|
+
title: message.title,
|
|
1138
|
+
subtitle: message.subtitle,
|
|
1139
|
+
hasMediaAttachment: Boolean(message.hasMediaAttachment)
|
|
1140
|
+
}
|
|
1141
|
+
Object.assign(interactiveMessage.header, m)
|
|
1142
|
+
}
|
|
1143
|
+
if ('footer' in message && !!message.footer) {
|
|
1144
|
+
interactiveMessage.footer = {
|
|
1145
|
+
text: message.footer
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1148
|
+
if ('title' in message && !!message.title) {
|
|
1149
|
+
interactiveMessage.header = {
|
|
1150
|
+
title: message.title,
|
|
1151
|
+
subtitle: message.subtitle,
|
|
1152
|
+
hasMediaAttachment: Boolean(message.hasMediaAttachment)
|
|
1153
|
+
}
|
|
1154
|
+
Object.assign(interactiveMessage.header, m)
|
|
1155
|
+
}
|
|
1156
|
+
applyContextInfoAndMentions(interactiveMessage, message)
|
|
1157
|
+
m = { interactiveMessage }
|
|
1158
|
+
}
|
|
1159
1159
|
if ('shop' in message && !!message.shop) {
|
|
1160
1160
|
const interactiveMessage = {
|
|
1161
1161
|
shopStorefrontMessage: WAProto_1.proto.Message.InteractiveMessage.ShopMessage.fromObject({
|
|
@@ -1232,22 +1232,12 @@ const generateWAMessageContent = async (message, options) => {
|
|
|
1232
1232
|
}
|
|
1233
1233
|
})
|
|
1234
1234
|
}
|
|
1235
|
-
if (table) {
|
|
1236
|
-
const isPlainArrayTable = Array.isArray(table)
|
|
1237
|
-
const rows = isPlainArrayTable ? table : table.rows
|
|
1238
|
-
if (!Array.isArray(rows)) {
|
|
1239
|
-
throw new boom_1.Boom(
|
|
1240
|
-
'richResponse.table must be an array of rows (e.g. [["h1","h2"],["a","b"]]) or { rows: [...] }',
|
|
1241
|
-
{ statusCode: 400 }
|
|
1242
|
-
)
|
|
1243
|
-
}
|
|
1235
|
+
if (table && Array.isArray(table.rows)) {
|
|
1244
1236
|
sections.push({
|
|
1245
1237
|
view_model: {
|
|
1246
1238
|
primitive: {
|
|
1247
|
-
rows: rows.map(
|
|
1248
|
-
cells: Array.isArray(row) ? row.map(c => ({ text: String(c) })) : row.cells
|
|
1249
|
-
// when a plain 2D array is passed, the first row is treated as the table header
|
|
1250
|
-
isHeading: Array.isArray(row) ? isPlainArrayTable && idx === 0 : row.isHeading
|
|
1239
|
+
rows: table.rows.map(row => ({
|
|
1240
|
+
cells: Array.isArray(row) ? row.map(c => ({ text: String(c) })) : row.cells
|
|
1251
1241
|
})),
|
|
1252
1242
|
__typename: 'GenAITableUXPrimitive'
|
|
1253
1243
|
},
|
|
@@ -1878,9 +1868,10 @@ const generateWAMessageContent = async (message, options) => {
|
|
|
1878
1868
|
...existing,
|
|
1879
1869
|
botThreadInfo: {
|
|
1880
1870
|
clientInfo: {
|
|
1881
|
-
type:
|
|
1882
|
-
|
|
1883
|
-
|
|
1871
|
+
type:
|
|
1872
|
+
typeof bt.type === 'string'
|
|
1873
|
+
? (threadTypeMap[bt.type.toLowerCase()] ?? threadTypeEnum.UNKNOWN)
|
|
1874
|
+
: (bt.type ?? threadTypeEnum.UNKNOWN),
|
|
1884
1875
|
sourceChatJid: bt.sourceChatJid || ''
|
|
1885
1876
|
}
|
|
1886
1877
|
}
|
|
@@ -2281,7 +2272,7 @@ const generateWAMessageContent = async (message, options) => {
|
|
|
2281
2272
|
m.messageContextInfo = {
|
|
2282
2273
|
...(m.messageContextInfo || {}),
|
|
2283
2274
|
messageAddOnDurationInSecs: message.afterReadDuration,
|
|
2284
|
-
messageAddOnExpiryType:
|
|
2275
|
+
messageAddOnExpiryType: WAProto_1.proto.MessageContextInfo.MessageAddonExpiryType.DEPENDENT_ON_PARENT
|
|
2285
2276
|
}
|
|
2286
2277
|
}
|
|
2287
2278
|
if ('raw' in message && !!message.raw) {
|
|
@@ -2410,8 +2401,8 @@ const generateWAMessageContent = async (message, options) => {
|
|
|
2410
2401
|
}
|
|
2411
2402
|
exports.generateWAMessageContent = generateWAMessageContent
|
|
2412
2403
|
const generateWAMessageFromContent = (jid, message, options) => {
|
|
2413
|
-
|
|
2414
|
-
|
|
2404
|
+
|
|
2405
|
+
|
|
2415
2406
|
if (!options.timestamp) {
|
|
2416
2407
|
options.timestamp = new Date()
|
|
2417
2408
|
}
|
|
@@ -2421,12 +2412,12 @@ const generateWAMessageFromContent = (jid, message, options) => {
|
|
|
2421
2412
|
const { quoted, userJid } = options
|
|
2422
2413
|
if (quoted && !(0, WABinary_1.isJidNewsletter)(jid)) {
|
|
2423
2414
|
const participant = quoted.key.fromMe
|
|
2424
|
-
? userJid
|
|
2415
|
+
? userJid
|
|
2425
2416
|
: quoted.participant || quoted.key.participant || quoted.key.remoteJid
|
|
2426
2417
|
let quotedMsg = (0, exports.normalizeMessageContent)(quoted.message)
|
|
2427
2418
|
const msgType = (0, exports.getContentType)(quotedMsg)
|
|
2428
|
-
|
|
2429
|
-
quotedMsg =
|
|
2419
|
+
|
|
2420
|
+
quotedMsg = WAProto_1.proto.Message.create({ [msgType]: quotedMsg[msgType] })
|
|
2430
2421
|
const quotedContent = quotedMsg[msgType]
|
|
2431
2422
|
if (typeof quotedContent === 'object' && quotedContent && 'contextInfo' in quotedContent) {
|
|
2432
2423
|
delete quotedContent.contextInfo
|
|
@@ -2435,62 +2426,53 @@ const generateWAMessageFromContent = (jid, message, options) => {
|
|
|
2435
2426
|
contextInfo.participant = (0, WABinary_1.jidNormalizedUser)(participant)
|
|
2436
2427
|
contextInfo.stanzaId = quoted.key.id
|
|
2437
2428
|
contextInfo.quotedMessage = quotedMsg
|
|
2438
|
-
|
|
2439
|
-
|
|
2429
|
+
|
|
2430
|
+
|
|
2440
2431
|
if (jid !== quoted.key.remoteJid) {
|
|
2441
2432
|
contextInfo.remoteJid = quoted.key.remoteJid
|
|
2442
2433
|
}
|
|
2443
2434
|
if (contextInfo && innerMessage[key]) {
|
|
2444
|
-
|
|
2435
|
+
|
|
2445
2436
|
innerMessage[key].contextInfo = contextInfo
|
|
2446
2437
|
}
|
|
2447
2438
|
}
|
|
2448
2439
|
if (
|
|
2449
|
-
|
|
2440
|
+
|
|
2450
2441
|
!!options.ephemeralExpiration &&
|
|
2451
|
-
|
|
2442
|
+
|
|
2452
2443
|
key !== 'protocolMessage' &&
|
|
2453
|
-
|
|
2444
|
+
|
|
2454
2445
|
key !== 'ephemeralMessage' &&
|
|
2455
|
-
|
|
2446
|
+
|
|
2456
2447
|
!(0, WABinary_1.isJidNewsletter)(jid)
|
|
2457
2448
|
) {
|
|
2458
|
-
|
|
2449
|
+
|
|
2459
2450
|
innerMessage[key].contextInfo = {
|
|
2460
2451
|
...(innerMessage[key].contextInfo || {}),
|
|
2461
2452
|
expiration: options.ephemeralExpiration || Defaults_1.WA_DEFAULT_EPHEMERAL
|
|
2462
|
-
|
|
2453
|
+
|
|
2463
2454
|
}
|
|
2464
2455
|
}
|
|
2465
2456
|
message = WAProto_1.proto.Message.create(message)
|
|
2466
|
-
const iosBros = options?.browser?.[0] === 'iOS' || options?.browser?.[1] === 'Safari'
|
|
2467
|
-
const androidBros = options?.browser?.[0] === 'Android'
|
|
2468
|
-
const pickedMessageId =
|
|
2469
|
-
options?.messageId ||
|
|
2470
|
-
(iosBros
|
|
2471
|
-
? (0, generics_1.generateIOSMessageID)()
|
|
2472
|
-
: androidBros
|
|
2473
|
-
? (0, generics_1.generateAndroMessageID)()
|
|
2474
|
-
: (0, generics_1.generateMessageIDV2)(userJid))
|
|
2475
2457
|
const messageJSON = {
|
|
2476
2458
|
key: {
|
|
2477
2459
|
remoteJid: jid,
|
|
2478
2460
|
fromMe: true,
|
|
2479
|
-
id:
|
|
2461
|
+
id: options?.messageId || (0, generics_1.generateMessageIDV2)()
|
|
2480
2462
|
},
|
|
2481
2463
|
message: message,
|
|
2482
2464
|
messageTimestamp: timestamp,
|
|
2483
2465
|
messageStubParameters: [],
|
|
2484
|
-
participant: (0, WABinary_1.isJidGroup)(jid) || (0, WABinary_1.isJidStatusBroadcast)(jid) ? userJid : undefined,
|
|
2466
|
+
participant: (0, WABinary_1.isJidGroup)(jid) || (0, WABinary_1.isJidStatusBroadcast)(jid) ? userJid : undefined,
|
|
2485
2467
|
status: Types_1.WAMessageStatus.PENDING
|
|
2486
2468
|
}
|
|
2487
2469
|
return WAProto_1.proto.WebMessageInfo.fromObject(messageJSON)
|
|
2488
2470
|
}
|
|
2489
2471
|
exports.generateWAMessageFromContent = generateWAMessageFromContent
|
|
2490
2472
|
const generateWAMessage = async (jid, content, options) => {
|
|
2491
|
-
|
|
2473
|
+
|
|
2492
2474
|
options.logger = options?.logger?.child({ msgId: options.messageId })
|
|
2493
|
-
|
|
2475
|
+
|
|
2494
2476
|
return (0, exports.generateWAMessageFromContent)(
|
|
2495
2477
|
jid,
|
|
2496
2478
|
await (0, exports.generateWAMessageContent)(content, { ...options, jid }),
|
|
@@ -2498,407 +2480,3 @@ const generateWAMessage = async (jid, content, options) => {
|
|
|
2498
2480
|
)
|
|
2499
2481
|
}
|
|
2500
2482
|
exports.generateWAMessage = generateWAMessage
|
|
2501
|
-
/** Get the key to access the true type of content */
|
|
2502
|
-
const getContentType = content => {
|
|
2503
|
-
if (content) {
|
|
2504
|
-
const keys = Object.keys(content)
|
|
2505
|
-
const key = keys.find(k => (k === 'conversation' || k.includes('Message')) && k !== 'senderKeyDistributionMessage')
|
|
2506
|
-
return key
|
|
2507
|
-
}
|
|
2508
|
-
}
|
|
2509
|
-
exports.getContentType = getContentType
|
|
2510
|
-
/**
|
|
2511
|
-
* Normalizes ephemeral, view once messages to regular message content
|
|
2512
|
-
* Eg. image messages in ephemeral messages, in view once messages etc.
|
|
2513
|
-
* @param content
|
|
2514
|
-
* @returns
|
|
2515
|
-
*/
|
|
2516
|
-
const normalizeMessageContent = content => {
|
|
2517
|
-
if (!content) {
|
|
2518
|
-
return undefined
|
|
2519
|
-
}
|
|
2520
|
-
// set max iterations to prevent an infinite loop
|
|
2521
|
-
for (let i = 0; i < 5; i++) {
|
|
2522
|
-
const inner = getFutureProofMessage(content)
|
|
2523
|
-
if (!inner) {
|
|
2524
|
-
break
|
|
2525
|
-
}
|
|
2526
|
-
content = inner.message
|
|
2527
|
-
}
|
|
2528
|
-
return content
|
|
2529
|
-
function getFutureProofMessage(message) {
|
|
2530
|
-
return (
|
|
2531
|
-
message.ephemeralMessage ||
|
|
2532
|
-
message.viewOnceMessage ||
|
|
2533
|
-
message.documentWithCaptionMessage ||
|
|
2534
|
-
message.viewOnceMessageV2 ||
|
|
2535
|
-
message.viewOnceMessageV2Extension ||
|
|
2536
|
-
message.editedMessage ||
|
|
2537
|
-
message.groupMentionedMessage ||
|
|
2538
|
-
message.botInvokeMessage ||
|
|
2539
|
-
message.lottieStickerMessage ||
|
|
2540
|
-
message.eventCoverImage ||
|
|
2541
|
-
message.statusMentionMessage ||
|
|
2542
|
-
message.pollCreationOptionImageMessage ||
|
|
2543
|
-
message.associatedChildMessage ||
|
|
2544
|
-
message.groupStatusMentionMessage ||
|
|
2545
|
-
message.pollCreationMessageV4 ||
|
|
2546
|
-
message.pollCreationMessageV5 ||
|
|
2547
|
-
message.statusAddYours ||
|
|
2548
|
-
message.groupStatusMessage ||
|
|
2549
|
-
message.limitSharingMessage ||
|
|
2550
|
-
message.botTaskMessage ||
|
|
2551
|
-
message.questionMessage ||
|
|
2552
|
-
message.groupStatusMessageV2 ||
|
|
2553
|
-
message.botForwardedMessage ||
|
|
2554
|
-
message.questionReplyMessage ||
|
|
2555
|
-
message.newsletterAdminProfileMessage ||
|
|
2556
|
-
message.newsletterAdminProfileMessageV2 ||
|
|
2557
|
-
message.newsletterAdminProfileStatusMessage ||
|
|
2558
|
-
message.spoilerMessage ||
|
|
2559
|
-
message.groupStatusV3Message ||
|
|
2560
|
-
message.pollCreationMessageV6
|
|
2561
|
-
)
|
|
2562
|
-
}
|
|
2563
|
-
}
|
|
2564
|
-
exports.normalizeMessageContent = normalizeMessageContent
|
|
2565
|
-
/**
|
|
2566
|
-
* Extract the true message content from a message
|
|
2567
|
-
* Eg. extracts the inner message from a disappearing message/view once message
|
|
2568
|
-
*/
|
|
2569
|
-
const extractMessageContent = content => {
|
|
2570
|
-
const extractFromTemplateMessage = msg => {
|
|
2571
|
-
if (msg.imageMessage) {
|
|
2572
|
-
return { imageMessage: msg.imageMessage }
|
|
2573
|
-
} else if (msg.documentMessage) {
|
|
2574
|
-
return { documentMessage: msg.documentMessage }
|
|
2575
|
-
} else if (msg.videoMessage) {
|
|
2576
|
-
return { videoMessage: msg.videoMessage }
|
|
2577
|
-
} else if (msg.locationMessage) {
|
|
2578
|
-
return { locationMessage: msg.locationMessage }
|
|
2579
|
-
} else {
|
|
2580
|
-
return {
|
|
2581
|
-
conversation:
|
|
2582
|
-
'contentText' in msg ? msg.contentText : 'hydratedContentText' in msg ? msg.hydratedContentText : ''
|
|
2583
|
-
}
|
|
2584
|
-
}
|
|
2585
|
-
}
|
|
2586
|
-
content = (0, exports.normalizeMessageContent)(content)
|
|
2587
|
-
if (content?.buttonsMessage) {
|
|
2588
|
-
return extractFromTemplateMessage(content.buttonsMessage)
|
|
2589
|
-
}
|
|
2590
|
-
if (content?.templateMessage?.hydratedFourRowTemplate) {
|
|
2591
|
-
return extractFromTemplateMessage(content?.templateMessage?.hydratedFourRowTemplate)
|
|
2592
|
-
}
|
|
2593
|
-
if (content?.templateMessage?.hydratedTemplate) {
|
|
2594
|
-
return extractFromTemplateMessage(content?.templateMessage?.hydratedTemplate)
|
|
2595
|
-
}
|
|
2596
|
-
if (content?.templateMessage?.fourRowTemplate) {
|
|
2597
|
-
return extractFromTemplateMessage(content?.templateMessage?.fourRowTemplate)
|
|
2598
|
-
}
|
|
2599
|
-
return content
|
|
2600
|
-
}
|
|
2601
|
-
exports.extractMessageContent = extractMessageContent
|
|
2602
|
-
/**
|
|
2603
|
-
* Returns the device predicted by message ID
|
|
2604
|
-
*/
|
|
2605
|
-
const getDevice = id =>
|
|
2606
|
-
/^3A.{18}$/.test(id)
|
|
2607
|
-
? 'ios'
|
|
2608
|
-
: /^3E.{20}$/.test(id)
|
|
2609
|
-
? 'web'
|
|
2610
|
-
: /^(.{21}|.{32})$/.test(id)
|
|
2611
|
-
? 'android'
|
|
2612
|
-
: /^(3F|.{18}$)/.test(id)
|
|
2613
|
-
? 'desktop'
|
|
2614
|
-
: 'api/baileys'
|
|
2615
|
-
exports.getDevice = getDevice
|
|
2616
|
-
/** Upserts a receipt in the message */
|
|
2617
|
-
const updateMessageWithReceipt = (msg, receipt) => {
|
|
2618
|
-
msg.userReceipt = msg.userReceipt || []
|
|
2619
|
-
const recp = msg.userReceipt.find(m => m.userJid === receipt.userJid)
|
|
2620
|
-
if (recp) {
|
|
2621
|
-
Object.assign(recp, receipt)
|
|
2622
|
-
} else {
|
|
2623
|
-
msg.userReceipt.push(receipt)
|
|
2624
|
-
}
|
|
2625
|
-
}
|
|
2626
|
-
exports.updateMessageWithReceipt = updateMessageWithReceipt
|
|
2627
|
-
/** Update the message with a new reaction */
|
|
2628
|
-
const updateMessageWithReaction = (msg, reaction) => {
|
|
2629
|
-
const authorID = (0, generics_1.getKeyAuthor)(reaction.key)
|
|
2630
|
-
const reactions = (msg.reactions || []).filter(r => (0, generics_1.getKeyAuthor)(r.key) !== authorID)
|
|
2631
|
-
reaction.text = reaction.text || ''
|
|
2632
|
-
reactions.push(reaction)
|
|
2633
|
-
msg.reactions = reactions
|
|
2634
|
-
}
|
|
2635
|
-
exports.updateMessageWithReaction = updateMessageWithReaction
|
|
2636
|
-
/** Update the message with a new poll update */
|
|
2637
|
-
const updateMessageWithPollUpdate = (msg, update) => {
|
|
2638
|
-
const authorID = (0, generics_1.getKeyAuthor)(update.pollUpdateMessageKey)
|
|
2639
|
-
const reactions = (msg.pollUpdates || []).filter(
|
|
2640
|
-
r => (0, generics_1.getKeyAuthor)(r.pollUpdateMessageKey) !== authorID
|
|
2641
|
-
)
|
|
2642
|
-
if (update.vote?.selectedOptions?.length) {
|
|
2643
|
-
reactions.push(update)
|
|
2644
|
-
}
|
|
2645
|
-
msg.pollUpdates = reactions
|
|
2646
|
-
}
|
|
2647
|
-
exports.updateMessageWithPollUpdate = updateMessageWithPollUpdate
|
|
2648
|
-
/** Update the message with a new event response */
|
|
2649
|
-
const updateMessageWithEventResponse = (msg, update) => {
|
|
2650
|
-
const authorID = (0, generics_1.getKeyAuthor)(update.eventResponseMessageKey)
|
|
2651
|
-
const responses = (msg.eventResponses || []).filter(
|
|
2652
|
-
r => (0, generics_1.getKeyAuthor)(r.eventResponseMessageKey) !== authorID
|
|
2653
|
-
)
|
|
2654
|
-
responses.push(update)
|
|
2655
|
-
msg.eventResponses = responses
|
|
2656
|
-
}
|
|
2657
|
-
exports.updateMessageWithEventResponse = updateMessageWithEventResponse
|
|
2658
|
-
/**
|
|
2659
|
-
* Aggregates all poll updates in a poll.
|
|
2660
|
-
* @param msg the poll creation message
|
|
2661
|
-
* @param meId your jid
|
|
2662
|
-
* @returns A list of options & their voters
|
|
2663
|
-
*/
|
|
2664
|
-
function getAggregateVotesInPollMessage({ message, pollUpdates }, meId) {
|
|
2665
|
-
const opts =
|
|
2666
|
-
message?.pollCreationMessage?.options ||
|
|
2667
|
-
message?.pollCreationMessageV2?.options ||
|
|
2668
|
-
message?.pollCreationMessageV3?.options ||
|
|
2669
|
-
message?.pollCreationMessageV5?.options ||
|
|
2670
|
-
message?.pollCreationMessageV6?.options ||
|
|
2671
|
-
message?.pollCreationMessageV4?.message?.pollCreationMessage?.options ||
|
|
2672
|
-
message?.pollCreationMessageV4?.message?.pollCreationMessageV3?.options ||
|
|
2673
|
-
[]
|
|
2674
|
-
const voteHashMap = opts.reduce((acc, opt) => {
|
|
2675
|
-
const hash = (0, crypto_2.sha256)(Buffer.from(opt.optionName || '')).toString()
|
|
2676
|
-
acc[hash] = {
|
|
2677
|
-
name: opt.optionName || '',
|
|
2678
|
-
voters: []
|
|
2679
|
-
}
|
|
2680
|
-
return acc
|
|
2681
|
-
}, {})
|
|
2682
|
-
for (const update of pollUpdates || []) {
|
|
2683
|
-
const { vote } = update
|
|
2684
|
-
if (!vote) {
|
|
2685
|
-
continue
|
|
2686
|
-
}
|
|
2687
|
-
for (const option of vote.selectedOptions || []) {
|
|
2688
|
-
const hash = option.toString()
|
|
2689
|
-
let data = voteHashMap[hash]
|
|
2690
|
-
if (!data) {
|
|
2691
|
-
voteHashMap[hash] = {
|
|
2692
|
-
name: 'Unknown',
|
|
2693
|
-
voters: []
|
|
2694
|
-
}
|
|
2695
|
-
data = voteHashMap[hash]
|
|
2696
|
-
}
|
|
2697
|
-
voteHashMap[hash].voters.push((0, generics_1.getKeyAuthor)(update.pollUpdateMessageKey, meId))
|
|
2698
|
-
}
|
|
2699
|
-
}
|
|
2700
|
-
return Object.values(voteHashMap)
|
|
2701
|
-
}
|
|
2702
|
-
/** Given a list of message keys, aggregates them by chat & sender. Useful for sending read receipts in bulk */
|
|
2703
|
-
const aggregateMessageKeysNotFromMe = keys => {
|
|
2704
|
-
const keyMap = {}
|
|
2705
|
-
for (const { remoteJid, id, participant, fromMe, sts } of keys) {
|
|
2706
|
-
if (!fromMe) {
|
|
2707
|
-
const uqKey = `${remoteJid}:${participant || ''}`
|
|
2708
|
-
if (!keyMap[uqKey]) {
|
|
2709
|
-
keyMap[uqKey] = {
|
|
2710
|
-
jid: remoteJid,
|
|
2711
|
-
participant: participant,
|
|
2712
|
-
messageIds: [],
|
|
2713
|
-
// sts is per-message; kept only for single-message interop receipts
|
|
2714
|
-
sts: sts
|
|
2715
|
-
}
|
|
2716
|
-
} else if (keyMap[uqKey].sts !== sts) {
|
|
2717
|
-
// Multiple messages with different sts — can't aggregate a single sts
|
|
2718
|
-
keyMap[uqKey].sts = undefined
|
|
2719
|
-
}
|
|
2720
|
-
keyMap[uqKey].messageIds.push(id)
|
|
2721
|
-
}
|
|
2722
|
-
}
|
|
2723
|
-
return Object.values(keyMap)
|
|
2724
|
-
}
|
|
2725
|
-
exports.aggregateMessageKeysNotFromMe = aggregateMessageKeysNotFromMe
|
|
2726
|
-
|
|
2727
|
-
/**
|
|
2728
|
-
* Check if a WebMessageInfo has a scheduled reveal time (ConditionalRevealMessage)
|
|
2729
|
-
*/
|
|
2730
|
-
const isScheduledMessage = msg => !!msg?.scheduledMessageMetadata?.scheduledTime
|
|
2731
|
-
exports.isScheduledMessage = isScheduledMessage
|
|
2732
|
-
|
|
2733
|
-
/**
|
|
2734
|
-
* Get scheduled reveal time of a message as a Date, or null
|
|
2735
|
-
*/
|
|
2736
|
-
const getScheduledMessageTime = msg => {
|
|
2737
|
-
const t = msg?.scheduledMessageMetadata?.scheduledTime
|
|
2738
|
-
if (!t) return null
|
|
2739
|
-
return new Date(Number(t) * 1000)
|
|
2740
|
-
}
|
|
2741
|
-
exports.getScheduledMessageTime = getScheduledMessageTime
|
|
2742
|
-
|
|
2743
|
-
/**
|
|
2744
|
-
* Extract PaymentInfo from a WebMessageInfo (the payment status field, not the message content)
|
|
2745
|
-
*/
|
|
2746
|
-
const getMessagePaymentInfo = msg => msg?.paymentInfo || msg?.quotedPaymentInfo || null
|
|
2747
|
-
exports.getMessagePaymentInfo = getMessagePaymentInfo
|
|
2748
|
-
|
|
2749
|
-
/**
|
|
2750
|
-
* Get all comment metadata from a WebMessageInfo
|
|
2751
|
-
*/
|
|
2752
|
-
const getMessageCommentMetadata = msg => msg?.commentMetadata || null
|
|
2753
|
-
exports.getMessageCommentMetadata = getMessageCommentMetadata
|
|
2754
|
-
|
|
2755
|
-
/**
|
|
2756
|
-
* Get all message add-ons (reactions, poll updates, pins) from a WebMessageInfo
|
|
2757
|
-
*/
|
|
2758
|
-
const getMessageAddOns = msg => msg?.messageAddOns || []
|
|
2759
|
-
exports.getMessageAddOns = getMessageAddOns
|
|
2760
|
-
|
|
2761
|
-
/**
|
|
2762
|
-
* Get the quiz correct answer from a poll creation message, if it's a quiz
|
|
2763
|
-
*/
|
|
2764
|
-
const getPollCorrectAnswer = pollMsg => {
|
|
2765
|
-
const poll =
|
|
2766
|
-
pollMsg?.pollCreationMessage ||
|
|
2767
|
-
pollMsg?.pollCreationMessageV2 ||
|
|
2768
|
-
pollMsg?.pollCreationMessageV3 ||
|
|
2769
|
-
pollMsg?.pollCreationMessageV5 ||
|
|
2770
|
-
pollMsg?.pollCreationMessageV6
|
|
2771
|
-
if (!poll) return null
|
|
2772
|
-
const isQuiz = poll.pollType === WAProto_1.proto.Message.PollType?.QUIZ || poll.pollType === 1
|
|
2773
|
-
return isQuiz ? poll.correctAnswer?.optionName || null : null
|
|
2774
|
-
}
|
|
2775
|
-
exports.getPollCorrectAnswer = getPollCorrectAnswer
|
|
2776
|
-
|
|
2777
|
-
/**
|
|
2778
|
-
* Aggregates all event responses in an event message.
|
|
2779
|
-
* @param msg the event creation message
|
|
2780
|
-
* @param meLid your lid
|
|
2781
|
-
* @returns A list of response types & their responders
|
|
2782
|
-
*/
|
|
2783
|
-
function getAggregateResponsesInEventMessage({ eventResponses }, meLid) {
|
|
2784
|
-
const responseTypes = ['GOING', 'NOT_GOING', 'MAYBE']
|
|
2785
|
-
const responseMap = {}
|
|
2786
|
-
|
|
2787
|
-
for (const type of responseTypes) {
|
|
2788
|
-
responseMap[type] = {
|
|
2789
|
-
response: type,
|
|
2790
|
-
responders: []
|
|
2791
|
-
}
|
|
2792
|
-
}
|
|
2793
|
-
for (const update of eventResponses) {
|
|
2794
|
-
const { response } = update.response || {}
|
|
2795
|
-
const responseType = index_js_1.proto.Message.EventResponseMessage.EventResponseType[response]
|
|
2796
|
-
if (responseType !== 'UNKNOWN' && responseMap[responseType]) {
|
|
2797
|
-
responseMap[responseType].responders.push(generics_1.getKeyAuthor(update.eventResponseMessageKey, meLid))
|
|
2798
|
-
}
|
|
2799
|
-
}
|
|
2800
|
-
|
|
2801
|
-
return Object.values(responseMap)
|
|
2802
|
-
}
|
|
2803
|
-
|
|
2804
|
-
exports.getAggregateResponsesInEventMessage = getAggregateResponsesInEventMessage
|
|
2805
|
-
|
|
2806
|
-
const REUPLOAD_REQUIRED_STATUS = [410, 404]
|
|
2807
|
-
/**
|
|
2808
|
-
* Downloads the given message. Throws an error if it's not a media message
|
|
2809
|
-
*/
|
|
2810
|
-
const downloadMediaMessage = async (message, type, options, ctx) => {
|
|
2811
|
-
const result = await downloadMsg().catch(async error => {
|
|
2812
|
-
if (
|
|
2813
|
-
ctx &&
|
|
2814
|
-
typeof error?.status === 'number' && // treat errors with status as HTTP failures requiring reupload
|
|
2815
|
-
REUPLOAD_REQUIRED_STATUS.includes(error.status)
|
|
2816
|
-
) {
|
|
2817
|
-
ctx.logger.info({ key: message.key }, 'sending reupload media request...')
|
|
2818
|
-
// request reupload
|
|
2819
|
-
message = await ctx.reuploadRequest(message)
|
|
2820
|
-
const result = await downloadMsg()
|
|
2821
|
-
return result
|
|
2822
|
-
}
|
|
2823
|
-
throw error
|
|
2824
|
-
})
|
|
2825
|
-
return result
|
|
2826
|
-
async function downloadMsg() {
|
|
2827
|
-
const mContent = (0, exports.extractMessageContent)(message.message)
|
|
2828
|
-
if (!mContent) {
|
|
2829
|
-
throw new boom_1.Boom('No message present', { statusCode: 400, data: message })
|
|
2830
|
-
}
|
|
2831
|
-
const contentType = (0, exports.getContentType)(mContent)
|
|
2832
|
-
let mediaType = contentType?.replace('Message', '')
|
|
2833
|
-
const media = mContent[contentType]
|
|
2834
|
-
if (!media || typeof media !== 'object' || (!('url' in media) && !('thumbnailDirectPath' in media))) {
|
|
2835
|
-
throw new boom_1.Boom(`"${contentType}" message is not a media message`)
|
|
2836
|
-
}
|
|
2837
|
-
let download
|
|
2838
|
-
if ('thumbnailDirectPath' in media && !('url' in media)) {
|
|
2839
|
-
download = {
|
|
2840
|
-
directPath: media.thumbnailDirectPath,
|
|
2841
|
-
mediaKey: media.mediaKey
|
|
2842
|
-
}
|
|
2843
|
-
mediaType = 'thumbnail-link'
|
|
2844
|
-
} else {
|
|
2845
|
-
download = media
|
|
2846
|
-
}
|
|
2847
|
-
const stream = await (0, messages_media_1.downloadContentFromMessage)(download, mediaType, options)
|
|
2848
|
-
if (type === 'buffer') {
|
|
2849
|
-
const bufferArray = []
|
|
2850
|
-
for await (const chunk of stream) {
|
|
2851
|
-
bufferArray.push(chunk)
|
|
2852
|
-
}
|
|
2853
|
-
return Buffer.concat(bufferArray)
|
|
2854
|
-
}
|
|
2855
|
-
return stream
|
|
2856
|
-
}
|
|
2857
|
-
}
|
|
2858
|
-
exports.downloadMediaMessage = downloadMediaMessage
|
|
2859
|
-
/** Checks whether the given message is a media message; if it is returns the inner content */
|
|
2860
|
-
const assertMediaContent = content => {
|
|
2861
|
-
content = (0, exports.extractMessageContent)(content)
|
|
2862
|
-
const mediaContent =
|
|
2863
|
-
content?.documentMessage ||
|
|
2864
|
-
content?.imageMessage ||
|
|
2865
|
-
content?.videoMessage ||
|
|
2866
|
-
content?.audioMessage ||
|
|
2867
|
-
content?.stickerMessage
|
|
2868
|
-
if (!mediaContent) {
|
|
2869
|
-
throw new boom_1.Boom('given message is not a media message', { statusCode: 400, data: content })
|
|
2870
|
-
}
|
|
2871
|
-
return mediaContent
|
|
2872
|
-
}
|
|
2873
|
-
exports.assertMediaContent = assertMediaContent
|
|
2874
|
-
/**
|
|
2875
|
-
* Normalizes a bare user id to @s.whatsapp.net. Does not convert LID↔PN; use lidMapping / PN in key.remoteJidAlt when needed.
|
|
2876
|
-
*/
|
|
2877
|
-
const toJid = id => {
|
|
2878
|
-
if (!id) return ''
|
|
2879
|
-
if (id.includes('@')) return id
|
|
2880
|
-
return `${id}@s.whatsapp.net`
|
|
2881
|
-
}
|
|
2882
|
-
exports.toJid = toJid
|
|
2883
|
-
/**
|
|
2884
|
-
* Returns the peer LID JID when the key is LID-primary (decode sets remoteJid/participant to @lid when WA sends LID).
|
|
2885
|
-
*/
|
|
2886
|
-
const getSenderLid = message => {
|
|
2887
|
-
const k = message.key
|
|
2888
|
-
if (!k) {
|
|
2889
|
-
return { jid: '', lid: '' }
|
|
2890
|
-
}
|
|
2891
|
-
const jid = k.participant || k.remoteJid || ''
|
|
2892
|
-
if (jid.endsWith('@lid') || jid.endsWith('@hosted.lid')) {
|
|
2893
|
-
return { jid, lid: jid }
|
|
2894
|
-
}
|
|
2895
|
-
if (k.lid && typeof k.lid === 'string') {
|
|
2896
|
-
const lid = k.lid.includes('@') ? k.lid : (0, WABinary_1.jidEncode)(k.lid, 'lid')
|
|
2897
|
-
return { jid, lid }
|
|
2898
|
-
}
|
|
2899
|
-
if (k.participantLid && (0, WABinary_1.isLidUser)(k.participantLid)) {
|
|
2900
|
-
return { jid, lid: k.participantLid }
|
|
2901
|
-
}
|
|
2902
|
-
return { jid, lid: '' }
|
|
2903
|
-
}
|
|
2904
|
-
exports.getSenderLid = getSenderLid
|