@alannxd/baileys 6.0.4 → 6.0.5
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/WAProto/GenerateStatics.sh +3 -0
- package/WAProto/WAProto.proto +5479 -0
- package/WAProto/fix-imports.js +85 -0
- package/WAProto/index.d.ts +14017 -0
- package/WAProto/index.js +201 -160
- package/engine-requirements.js +1 -1
- package/lib/Defaults/index.d.ts +37 -15
- package/lib/Defaults/index.js +119 -136
- package/lib/Signal/Group/ciphertext-message.d.ts +1 -0
- package/lib/Signal/Group/ciphertext-message.js +2 -5
- package/lib/Signal/Group/group-session-builder.d.ts +4 -3
- package/lib/Signal/Group/group-session-builder.js +7 -41
- package/lib/Signal/Group/group_cipher.d.ts +4 -4
- package/lib/Signal/Group/group_cipher.js +37 -51
- package/lib/Signal/Group/index.d.ts +12 -11
- package/lib/Signal/Group/index.js +12 -57
- package/lib/Signal/Group/keyhelper.d.ts +2 -1
- package/lib/Signal/Group/keyhelper.js +7 -44
- package/lib/Signal/Group/sender-chain-key.d.ts +3 -2
- package/lib/Signal/Group/sender-chain-key.js +7 -15
- package/lib/Signal/Group/sender-key-distribution-message.d.ts +2 -1
- package/lib/Signal/Group/sender-key-distribution-message.js +8 -11
- package/lib/Signal/Group/sender-key-message.d.ts +2 -1
- package/lib/Signal/Group/sender-key-message.js +9 -12
- package/lib/Signal/Group/sender-key-name.d.ts +1 -0
- package/lib/Signal/Group/sender-key-name.js +2 -5
- package/lib/Signal/Group/sender-key-record.d.ts +3 -2
- package/lib/Signal/Group/sender-key-record.js +9 -21
- package/lib/Signal/Group/sender-key-state.d.ts +7 -6
- package/lib/Signal/Group/sender-key-state.js +27 -42
- package/lib/Signal/Group/sender-message-key.d.ts +1 -0
- package/lib/Signal/Group/sender-message-key.js +4 -7
- package/lib/Signal/libsignal.d.ts +5 -3
- package/lib/Signal/libsignal.js +347 -90
- package/lib/Signal/lid-mapping.d.ts +23 -0
- package/lib/Signal/lid-mapping.js +277 -0
- package/lib/Socket/Client/index.d.ts +3 -3
- package/lib/Socket/Client/index.js +3 -19
- package/lib/Socket/Client/{abstract-socket-client.d.ts → types.d.ts} +4 -5
- package/lib/Socket/Client/types.js +11 -0
- package/lib/Socket/Client/{web-socket-client.d.ts → websocket.d.ts} +3 -2
- package/lib/Socket/Client/websocket.js +54 -0
- package/lib/Socket/business.d.ts +154 -108
- package/lib/Socket/business.js +162 -43
- package/lib/Socket/chats.d.ts +96 -239
- package/lib/Socket/chats.js +627 -427
- package/lib/Socket/communities.d.ts +239 -146
- package/lib/Socket/communities.js +90 -80
- package/lib/Socket/groups.d.ts +104 -57
- package/lib/Socket/groups.js +154 -161
- package/lib/Socket/index.d.ts +202 -115
- package/lib/Socket/index.js +11 -10
- package/lib/Socket/luxu.d.ts +22 -266
- package/lib/Socket/luxu.js +422 -465
- package/lib/Socket/messages-recv.d.ts +136 -84
- package/lib/Socket/messages-recv.js +1421 -615
- package/lib/Socket/messages-send.d.ts +142 -126
- package/lib/Socket/messages-send.js +878 -671
- package/lib/Socket/mex.d.ts +3 -0
- package/lib/Socket/mex.js +42 -0
- package/lib/Socket/newsletter.d.ts +121 -85
- package/lib/Socket/newsletter.js +147 -272
- package/lib/Socket/socket.d.ts +34 -19
- package/lib/Socket/socket.js +544 -313
- package/lib/Store/index.d.ts +10 -3
- package/lib/Store/index.js +10 -10
- package/lib/Store/keyed-db.d.ts +22 -0
- package/lib/Store/keyed-db.js +108 -0
- package/lib/Store/make-cache-manager-store.d.ts +17 -11
- package/lib/Store/make-cache-manager-store.js +43 -41
- package/lib/Store/make-in-memory-store.d.ts +39 -118
- package/lib/Store/make-in-memory-store.js +112 -341
- package/lib/Store/make-ordered-dictionary.d.ts +11 -10
- package/lib/Store/make-ordered-dictionary.js +14 -20
- package/lib/Store/object-repository.d.ts +10 -9
- package/lib/Store/object-repository.js +11 -6
- package/lib/Types/Auth.d.ts +19 -12
- package/lib/Types/Auth.js +2 -2
- package/lib/Types/Bussines.d.ts +25 -0
- package/lib/Types/Bussines.js +2 -0
- package/lib/Types/Call.d.ts +3 -1
- package/lib/Types/Call.js +2 -2
- package/lib/Types/Chat.d.ts +35 -13
- package/lib/Types/Chat.js +8 -4
- package/lib/Types/Contact.d.ts +8 -1
- package/lib/Types/Contact.js +2 -2
- package/lib/Types/Events.d.ts +116 -17
- package/lib/Types/Events.js +2 -2
- package/lib/Types/GroupMetadata.d.ts +21 -5
- package/lib/Types/GroupMetadata.js +2 -2
- package/lib/Types/Label.d.ts +12 -0
- package/lib/Types/Label.js +3 -5
- package/lib/Types/LabelAssociation.d.ts +1 -0
- package/lib/Types/LabelAssociation.js +3 -5
- package/lib/Types/Message.d.ts +105 -58
- package/lib/Types/Message.js +11 -9
- package/lib/Types/Mex.d.ts +141 -0
- package/lib/Types/Mex.js +37 -0
- package/lib/Types/Product.d.ts +2 -1
- package/lib/Types/Product.js +2 -2
- package/lib/Types/Signal.d.ts +32 -2
- package/lib/Types/Signal.js +2 -2
- package/lib/Types/Socket.d.ts +50 -25
- package/lib/Types/Socket.js +3 -2
- package/lib/Types/State.d.ts +72 -2
- package/lib/Types/State.js +56 -2
- package/lib/Types/USync.d.ts +3 -2
- package/lib/Types/USync.js +2 -2
- package/lib/Types/index.d.ts +22 -14
- package/lib/Types/index.js +15 -31
- package/lib/Utils/auth-utils.d.ts +12 -6
- package/lib/Utils/auth-utils.js +239 -143
- package/lib/Utils/browser-utils.d.ts +4 -0
- package/lib/Utils/browser-utils.js +28 -0
- package/lib/Utils/business.d.ts +3 -2
- package/lib/Utils/business.js +66 -69
- package/lib/Utils/chat-utils.d.ts +52 -23
- package/lib/Utils/chat-utils.js +396 -253
- package/lib/Utils/companion-reg-client-utils.d.ts +17 -0
- package/lib/Utils/companion-reg-client-utils.js +35 -0
- package/lib/Utils/crypto.d.ts +18 -22
- package/lib/Utils/crypto.js +57 -90
- package/lib/Utils/decode-wa-message.d.ts +55 -8
- package/lib/Utils/decode-wa-message.js +203 -84
- package/lib/Utils/event-buffer.d.ts +9 -8
- package/lib/Utils/event-buffer.js +185 -77
- package/lib/Utils/generics.d.ts +28 -29
- package/lib/Utils/generics.js +180 -210
- package/lib/Utils/history.d.ts +18 -9
- package/lib/Utils/history.js +93 -55
- package/lib/Utils/identity-change-handler.d.ts +44 -0
- package/lib/Utils/identity-change-handler.js +50 -0
- package/lib/Utils/index.d.ts +22 -17
- package/lib/Utils/index.js +22 -33
- package/lib/Utils/link-preview.d.ts +5 -5
- package/lib/Utils/link-preview.js +16 -24
- package/lib/Utils/logger.d.ts +11 -3
- package/lib/Utils/logger.js +3 -7
- package/lib/Utils/lt-hash.d.ts +8 -12
- package/lib/Utils/lt-hash.js +3 -46
- package/lib/Utils/make-mutex.d.ts +4 -2
- package/lib/Utils/make-mutex.js +24 -34
- package/lib/Utils/message-retry-manager.d.ts +115 -0
- package/lib/Utils/message-retry-manager.js +265 -0
- package/lib/Utils/messages-media.d.ts +61 -44
- package/lib/Utils/messages-media.js +451 -482
- package/lib/Utils/messages.d.ts +32 -18
- package/lib/Utils/messages.js +458 -369
- package/lib/Utils/noise-handler.d.ts +13 -14
- package/lib/Utils/noise-handler.js +145 -99
- package/lib/Utils/offline-node-processor.d.ts +17 -0
- package/lib/Utils/offline-node-processor.js +40 -0
- package/lib/Utils/pre-key-manager.d.ts +28 -0
- package/lib/Utils/pre-key-manager.js +106 -0
- package/lib/Utils/process-message.d.ts +31 -12
- package/lib/Utils/process-message.js +459 -150
- package/lib/Utils/reporting-utils.d.ts +11 -0
- package/lib/Utils/reporting-utils.js +258 -0
- package/lib/Utils/signal.d.ts +20 -5
- package/lib/Utils/signal.js +120 -72
- package/lib/Utils/stanza-ack.d.ts +11 -0
- package/lib/Utils/stanza-ack.js +38 -0
- package/lib/Utils/sync-action-utils.d.ts +19 -0
- package/lib/Utils/sync-action-utils.js +49 -0
- package/lib/Utils/tc-token-utils.d.ts +37 -0
- package/lib/Utils/tc-token-utils.js +163 -0
- package/lib/Utils/use-multi-file-auth-state.d.ts +2 -2
- package/lib/Utils/use-multi-file-auth-state.js +29 -27
- package/lib/Utils/validate-connection.d.ts +7 -7
- package/lib/Utils/validate-connection.js +73 -99
- package/lib/WABinary/constants.d.ts +25 -27
- package/lib/WABinary/constants.js +1281 -20
- package/lib/WABinary/decode.d.ts +5 -5
- package/lib/WABinary/decode.js +52 -42
- package/lib/WABinary/encode.d.ts +3 -3
- package/lib/WABinary/encode.js +110 -155
- package/lib/WABinary/generic-utils.d.ts +8 -7
- package/lib/WABinary/generic-utils.js +48 -49
- package/lib/WABinary/index.d.ts +6 -5
- package/lib/WABinary/index.js +6 -21
- package/lib/WABinary/jid-utils.d.ts +25 -8
- package/lib/WABinary/jid-utils.js +74 -40
- package/lib/WABinary/types.d.ts +2 -1
- package/lib/WABinary/types.js +2 -2
- package/lib/WAM/BinaryInfo.d.ts +3 -11
- package/lib/WAM/BinaryInfo.js +2 -5
- package/lib/WAM/constants.d.ts +5 -3
- package/lib/WAM/constants.js +19071 -11568
- package/lib/WAM/encode.d.ts +3 -3
- package/lib/WAM/encode.js +17 -22
- package/lib/WAM/index.d.ts +4 -3
- package/lib/WAM/index.js +4 -19
- package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts +4 -3
- package/lib/WAUSync/Protocols/USyncContactProtocol.js +33 -13
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.d.ts +3 -2
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +11 -14
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts +3 -2
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +9 -12
- package/lib/WAUSync/Protocols/USyncStatusProtocol.d.ts +3 -2
- package/lib/WAUSync/Protocols/USyncStatusProtocol.js +9 -13
- package/lib/WAUSync/Protocols/USyncUsernameProtocol.d.ts +10 -0
- package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +25 -0
- package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.d.ts +4 -3
- package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +20 -22
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.d.ts +5 -3
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +13 -8
- package/lib/WAUSync/Protocols/index.d.ts +6 -4
- package/lib/WAUSync/Protocols/index.js +6 -20
- package/lib/WAUSync/USyncQuery.d.ts +6 -4
- package/lib/WAUSync/USyncQuery.js +44 -35
- package/lib/WAUSync/USyncUser.d.ts +10 -5
- package/lib/WAUSync/USyncUser.js +10 -5
- package/lib/WAUSync/index.d.ts +4 -0
- package/lib/WAUSync/index.js +4 -19
- package/lib/index.d.ts +10 -9
- package/lib/index.js +12 -34
- package/package.json +84 -51
- package/WAProto/fix-import.js +0 -29
- package/lib/Defaults/baileys-version.json +0 -3
- package/lib/Defaults/phonenumber-mcc.json +0 -223
- package/lib/Signal/Group/queue-job.d.ts +0 -1
- package/lib/Signal/Group/queue-job.js +0 -57
- package/lib/Socket/Client/abstract-socket-client.js +0 -13
- package/lib/Socket/Client/mobile-socket-client.d.ts +0 -13
- package/lib/Socket/Client/mobile-socket-client.js +0 -65
- package/lib/Socket/Client/web-socket-client.js +0 -62
- package/lib/Socket/registration.d.ts +0 -267
- package/lib/Socket/registration.js +0 -166
- package/lib/Socket/usync.d.ts +0 -36
- package/lib/Socket/usync.js +0 -70
- package/lib/Types/Newsletter.d.ts +0 -103
- package/lib/Types/Newsletter.js +0 -38
- package/lib/Utils/baileys-event-stream.d.ts +0 -16
- package/lib/Utils/baileys-event-stream.js +0 -63
package/lib/Utils/messages.js
CHANGED
|
@@ -1,56 +1,50 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
};
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
const Types_1 = require("../Types");
|
|
14
|
-
const WABinary_1 = require("../WABinary");
|
|
15
|
-
const crypto_2 = require("./crypto");
|
|
16
|
-
const generics_1 = require("./generics");
|
|
17
|
-
const messages_media_1 = require("./messages-media");
|
|
1
|
+
import { Boom } from '@hapi/boom';
|
|
2
|
+
import { randomBytes } from 'crypto';
|
|
3
|
+
import { promises as fs } from 'fs';
|
|
4
|
+
import {} from 'stream';
|
|
5
|
+
import { proto } from '../../WAProto/index.js';
|
|
6
|
+
import { CALL_AUDIO_PREFIX, CALL_VIDEO_PREFIX, MEDIA_KEYS, URL_REGEX, WA_DEFAULT_EPHEMERAL } from '../Defaults/index.js';
|
|
7
|
+
import { WAMessageStatus, WAProto } from '../Types/index.js';
|
|
8
|
+
import { isJidGroup, isJidNewsletter, isJidStatusBroadcast, jidNormalizedUser } from '../WABinary/index.js';
|
|
9
|
+
import { sha256 } from './crypto.js';
|
|
10
|
+
import { generateMessageIDV2, getKeyAuthor, unixTimestampSeconds } from './generics.js';
|
|
11
|
+
import { downloadContentFromMessage, encryptedStream, generateThumbnail, getAudioDuration, getAudioWaveform, getRawMediaUploadData } from './messages-media.js';
|
|
12
|
+
import { shouldIncludeReportingToken } from './reporting-utils.js';
|
|
18
13
|
const MIMETYPE_MAP = {
|
|
19
14
|
image: 'image/jpeg',
|
|
20
15
|
video: 'video/mp4',
|
|
21
16
|
document: 'application/pdf',
|
|
22
17
|
audio: 'audio/ogg; codecs=opus',
|
|
23
18
|
sticker: 'image/webp',
|
|
24
|
-
'product-catalog-image': 'image/jpeg'
|
|
19
|
+
'product-catalog-image': 'image/jpeg'
|
|
25
20
|
};
|
|
26
21
|
const MessageTypeProto = {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
22
|
+
image: WAProto.Message.ImageMessage,
|
|
23
|
+
video: WAProto.Message.VideoMessage,
|
|
24
|
+
audio: WAProto.Message.AudioMessage,
|
|
25
|
+
sticker: WAProto.Message.StickerMessage,
|
|
26
|
+
document: WAProto.Message.DocumentMessage
|
|
32
27
|
};
|
|
33
|
-
const ButtonType =
|
|
28
|
+
const ButtonType = proto.Message.ButtonsMessage.HeaderType;
|
|
34
29
|
/**
|
|
35
30
|
* Uses a regex to test whether the string contains a URL, and returns the URL if it does.
|
|
36
31
|
* @param text eg. hello https://google.com
|
|
37
32
|
* @returns the URL, eg. https://google.com
|
|
38
33
|
*/
|
|
39
|
-
const extractUrlFromText = (text) =>
|
|
40
|
-
|
|
41
|
-
const
|
|
42
|
-
const url = (0, exports.extractUrlFromText)(text);
|
|
34
|
+
export const extractUrlFromText = (text) => text.match(URL_REGEX)?.[0];
|
|
35
|
+
export const generateLinkPreviewIfRequired = async (text, getUrlInfo, logger) => {
|
|
36
|
+
const url = extractUrlFromText(text);
|
|
43
37
|
if (!!getUrlInfo && url) {
|
|
44
38
|
try {
|
|
45
39
|
const urlInfo = await getUrlInfo(url);
|
|
46
40
|
return urlInfo;
|
|
47
41
|
}
|
|
48
|
-
catch (error) {
|
|
49
|
-
|
|
42
|
+
catch (error) {
|
|
43
|
+
// ignore if fails
|
|
44
|
+
logger?.warn({ trace: error.stack }, 'url generation failed');
|
|
50
45
|
}
|
|
51
46
|
}
|
|
52
47
|
};
|
|
53
|
-
exports.generateLinkPreviewIfRequired = generateLinkPreviewIfRequired;
|
|
54
48
|
const assertColor = async (color) => {
|
|
55
49
|
let assertedColor;
|
|
56
50
|
if (typeof color === 'number') {
|
|
@@ -65,159 +59,150 @@ const assertColor = async (color) => {
|
|
|
65
59
|
return assertedColor;
|
|
66
60
|
}
|
|
67
61
|
};
|
|
68
|
-
const prepareWAMessageMedia = async (message, options) => {
|
|
62
|
+
export const prepareWAMessageMedia = async (message, options) => {
|
|
69
63
|
const logger = options.logger;
|
|
70
64
|
let mediaType;
|
|
71
|
-
for (const key of
|
|
65
|
+
for (const key of MEDIA_KEYS) {
|
|
72
66
|
if (key in message) {
|
|
73
67
|
mediaType = key;
|
|
74
68
|
}
|
|
75
69
|
}
|
|
76
70
|
if (!mediaType) {
|
|
77
|
-
throw new
|
|
78
|
-
statusCode: 400
|
|
79
|
-
});
|
|
71
|
+
throw new Boom('Invalid media type', { statusCode: 400 });
|
|
80
72
|
}
|
|
81
|
-
|
|
82
73
|
const uploadData = {
|
|
83
74
|
...message,
|
|
84
|
-
...(message.annotations ? {
|
|
85
|
-
annotations: message.annotations
|
|
86
|
-
} : {
|
|
87
|
-
annotations: [
|
|
88
|
-
{
|
|
89
|
-
polygonVertices: [
|
|
90
|
-
{
|
|
91
|
-
x: 60.71664810180664,
|
|
92
|
-
y: -36.39784622192383
|
|
93
|
-
},
|
|
94
|
-
{
|
|
95
|
-
x: -16.710189819335938,
|
|
96
|
-
y: 49.263675689697266
|
|
97
|
-
},
|
|
98
|
-
{
|
|
99
|
-
x: -56.585853576660156,
|
|
100
|
-
y: 37.85963439941406
|
|
101
|
-
},
|
|
102
|
-
{
|
|
103
|
-
x: 20.840980529785156,
|
|
104
|
-
y: -47.80188751220703
|
|
105
|
-
}
|
|
106
|
-
],
|
|
107
|
-
newsletter: {
|
|
108
|
-
newsletterJid: "120363420757607688@newsletter",
|
|
109
|
-
serverMessageId: 0,
|
|
110
|
-
newsletterName: "7eppeli - Information",
|
|
111
|
-
contentType: "UPDATE",
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
]
|
|
115
|
-
}),
|
|
116
75
|
media: message[mediaType]
|
|
117
76
|
};
|
|
118
77
|
delete uploadData[mediaType];
|
|
78
|
+
// check if cacheable + generate cache key
|
|
119
79
|
const cacheableKey = typeof uploadData.media === 'object' &&
|
|
120
|
-
|
|
80
|
+
'url' in uploadData.media &&
|
|
121
81
|
!!uploadData.media.url &&
|
|
122
|
-
!!options.mediaCache &&
|
|
123
|
-
|
|
124
|
-
|
|
82
|
+
!!options.mediaCache &&
|
|
83
|
+
mediaType + ':' + uploadData.media.url.toString();
|
|
125
84
|
if (mediaType === 'document' && !uploadData.fileName) {
|
|
126
85
|
uploadData.fileName = 'file';
|
|
127
86
|
}
|
|
128
|
-
|
|
129
87
|
if (!uploadData.mimetype) {
|
|
130
88
|
uploadData.mimetype = MIMETYPE_MAP[mediaType];
|
|
131
89
|
}
|
|
132
|
-
|
|
133
90
|
if (cacheableKey) {
|
|
134
|
-
const mediaBuff = options.mediaCache.get(cacheableKey);
|
|
91
|
+
const mediaBuff = await options.mediaCache.get(cacheableKey);
|
|
135
92
|
if (mediaBuff) {
|
|
136
|
-
logger
|
|
137
|
-
const obj =
|
|
93
|
+
logger?.debug({ cacheableKey }, 'got media cache hit');
|
|
94
|
+
const obj = proto.Message.decode(mediaBuff);
|
|
138
95
|
const key = `${mediaType}Message`;
|
|
139
96
|
Object.assign(obj[key], { ...uploadData, media: undefined });
|
|
140
97
|
return obj;
|
|
141
98
|
}
|
|
142
99
|
}
|
|
143
|
-
|
|
100
|
+
const isNewsletter = !!options.jid && isJidNewsletter(options.jid);
|
|
101
|
+
if (isNewsletter) {
|
|
102
|
+
logger?.info({ key: cacheableKey }, 'Preparing raw media for newsletter');
|
|
103
|
+
const { filePath, fileSha256, fileLength } = await getRawMediaUploadData(uploadData.media, options.mediaTypeOverride || mediaType, logger);
|
|
104
|
+
const fileSha256B64 = fileSha256.toString('base64');
|
|
105
|
+
const { mediaUrl, directPath } = await options.upload(filePath, {
|
|
106
|
+
fileEncSha256B64: fileSha256B64,
|
|
107
|
+
mediaType: mediaType,
|
|
108
|
+
timeoutMs: options.mediaUploadTimeoutMs
|
|
109
|
+
});
|
|
110
|
+
await fs.unlink(filePath);
|
|
111
|
+
const obj = WAProto.Message.fromObject({
|
|
112
|
+
// todo: add more support here
|
|
113
|
+
[`${mediaType}Message`]: MessageTypeProto[mediaType].fromObject({
|
|
114
|
+
url: mediaUrl,
|
|
115
|
+
directPath,
|
|
116
|
+
fileSha256,
|
|
117
|
+
fileLength,
|
|
118
|
+
...uploadData,
|
|
119
|
+
media: undefined
|
|
120
|
+
})
|
|
121
|
+
});
|
|
122
|
+
if (uploadData.ptv) {
|
|
123
|
+
obj.ptvMessage = obj.videoMessage;
|
|
124
|
+
delete obj.videoMessage;
|
|
125
|
+
}
|
|
126
|
+
if (obj.stickerMessage) {
|
|
127
|
+
obj.stickerMessage.stickerSentTs = Date.now();
|
|
128
|
+
}
|
|
129
|
+
if (cacheableKey) {
|
|
130
|
+
logger?.debug({ cacheableKey }, 'set cache');
|
|
131
|
+
await options.mediaCache.set(cacheableKey, WAProto.Message.encode(obj).finish());
|
|
132
|
+
}
|
|
133
|
+
return obj;
|
|
134
|
+
}
|
|
144
135
|
const requiresDurationComputation = mediaType === 'audio' && typeof uploadData.seconds === 'undefined';
|
|
145
|
-
const requiresThumbnailComputation = (mediaType === 'image' || mediaType === 'video') &&
|
|
146
|
-
|
|
147
|
-
const requiresWaveformProcessing = mediaType === 'audio' && uploadData.ptt === true;
|
|
136
|
+
const requiresThumbnailComputation = (mediaType === 'image' || mediaType === 'video') && typeof uploadData['jpegThumbnail'] === 'undefined';
|
|
137
|
+
const requiresWaveformProcessing = mediaType === 'audio' && uploadData.ptt === true && typeof uploadData.waveform === 'undefined';
|
|
148
138
|
const requiresAudioBackground = options.backgroundColor && mediaType === 'audio' && uploadData.ptt === true;
|
|
149
139
|
const requiresOriginalForSomeProcessing = requiresDurationComputation || requiresThumbnailComputation;
|
|
150
|
-
|
|
151
|
-
const { mediaKey, encWriteStream, bodyPath, fileEncSha256, fileSha256, fileLength, didSaveToTmpPath, opusConverted } = await (options.newsletter ? messages_media_1.prepareStream : messages_media_1.encryptedStream)(uploadData.media, options.mediaTypeOverride || mediaType, {
|
|
140
|
+
const { mediaKey, encFilePath, originalFilePath, fileEncSha256, fileSha256, fileLength } = await encryptedStream(uploadData.media, options.mediaTypeOverride || mediaType, {
|
|
152
141
|
logger,
|
|
153
142
|
saveOriginalFileIfRequired: requiresOriginalForSomeProcessing,
|
|
154
|
-
opts: options.options
|
|
155
|
-
isPtt: uploadData.ptt,
|
|
156
|
-
forceOpus: (mediaType === "audio" && uploadData.mimetype && uploadData.mimetype.includes('opus'))
|
|
143
|
+
opts: options.options
|
|
157
144
|
});
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
uploadData.mimetype = 'audio/ogg; codecs=opus';
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
const fileEncSha256B64 = (options.newsletter ? fileSha256 : fileEncSha256 !== null && fileEncSha256 !== void 0 ? fileEncSha256 : fileSha256).toString('base64');
|
|
164
|
-
|
|
165
|
-
const [{ mediaUrl, directPath, handle }] = await Promise.all([
|
|
145
|
+
const fileEncSha256B64 = fileEncSha256.toString('base64');
|
|
146
|
+
const [{ mediaUrl, directPath }] = await Promise.all([
|
|
166
147
|
(async () => {
|
|
167
|
-
const result = await options.upload(
|
|
168
|
-
|
|
148
|
+
const result = await options.upload(encFilePath, {
|
|
149
|
+
fileEncSha256B64,
|
|
150
|
+
mediaType,
|
|
151
|
+
timeoutMs: options.mediaUploadTimeoutMs
|
|
152
|
+
});
|
|
153
|
+
logger?.debug({ mediaType, cacheableKey }, 'uploaded media');
|
|
169
154
|
return result;
|
|
170
155
|
})(),
|
|
171
156
|
(async () => {
|
|
172
157
|
try {
|
|
173
158
|
if (requiresThumbnailComputation) {
|
|
174
|
-
const { thumbnail, originalImageDimensions } = await
|
|
159
|
+
const { thumbnail, originalImageDimensions } = await generateThumbnail(originalFilePath, mediaType, options);
|
|
175
160
|
uploadData.jpegThumbnail = thumbnail;
|
|
176
161
|
if (!uploadData.width && originalImageDimensions) {
|
|
177
162
|
uploadData.width = originalImageDimensions.width;
|
|
178
163
|
uploadData.height = originalImageDimensions.height;
|
|
179
|
-
logger
|
|
164
|
+
logger?.debug('set dimensions');
|
|
180
165
|
}
|
|
181
|
-
logger
|
|
166
|
+
logger?.debug('generated thumbnail');
|
|
182
167
|
}
|
|
183
168
|
if (requiresDurationComputation) {
|
|
184
|
-
uploadData.seconds = await
|
|
185
|
-
logger
|
|
169
|
+
uploadData.seconds = await getAudioDuration(originalFilePath);
|
|
170
|
+
logger?.debug('computed audio duration');
|
|
186
171
|
}
|
|
187
172
|
if (requiresWaveformProcessing) {
|
|
188
|
-
uploadData.waveform = await
|
|
189
|
-
logger
|
|
173
|
+
uploadData.waveform = await getAudioWaveform(originalFilePath, logger);
|
|
174
|
+
logger?.debug('processed waveform');
|
|
190
175
|
}
|
|
191
176
|
if (requiresAudioBackground) {
|
|
192
177
|
uploadData.backgroundArgb = await assertColor(options.backgroundColor);
|
|
193
|
-
logger
|
|
178
|
+
logger?.debug('computed backgroundColor audio status');
|
|
194
179
|
}
|
|
195
180
|
}
|
|
196
181
|
catch (error) {
|
|
197
|
-
logger
|
|
182
|
+
logger?.warn({ trace: error.stack }, 'failed to obtain extra info');
|
|
198
183
|
}
|
|
199
|
-
})()
|
|
200
|
-
])
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
184
|
+
})()
|
|
185
|
+
]).finally(async () => {
|
|
186
|
+
try {
|
|
187
|
+
await fs.unlink(encFilePath);
|
|
188
|
+
if (originalFilePath) {
|
|
189
|
+
await fs.unlink(originalFilePath);
|
|
190
|
+
}
|
|
191
|
+
logger?.debug('removed tmp files');
|
|
204
192
|
}
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
await fs_1.promises.unlink(bodyPath);
|
|
208
|
-
logger === null || logger === void 0 ? void 0 : logger.debug('removed tmp files');
|
|
193
|
+
catch (error) {
|
|
194
|
+
logger?.warn('failed to remove tmp file');
|
|
209
195
|
}
|
|
210
196
|
});
|
|
211
|
-
|
|
212
|
-
const obj = Types_1.WAProto.Message.fromObject({
|
|
197
|
+
const obj = WAProto.Message.fromObject({
|
|
213
198
|
[`${mediaType}Message`]: MessageTypeProto[mediaType].fromObject({
|
|
214
|
-
url:
|
|
199
|
+
url: mediaUrl,
|
|
215
200
|
directPath,
|
|
216
|
-
mediaKey
|
|
217
|
-
fileEncSha256
|
|
201
|
+
mediaKey,
|
|
202
|
+
fileEncSha256,
|
|
218
203
|
fileSha256,
|
|
219
204
|
fileLength,
|
|
220
|
-
mediaKeyTimestamp:
|
|
205
|
+
mediaKeyTimestamp: unixTimestampSeconds(),
|
|
221
206
|
...uploadData,
|
|
222
207
|
media: undefined
|
|
223
208
|
})
|
|
@@ -226,73 +211,76 @@ const prepareWAMessageMedia = async (message, options) => {
|
|
|
226
211
|
obj.ptvMessage = obj.videoMessage;
|
|
227
212
|
delete obj.videoMessage;
|
|
228
213
|
}
|
|
229
|
-
|
|
230
214
|
if (cacheableKey) {
|
|
231
|
-
logger
|
|
232
|
-
options.mediaCache.set(cacheableKey,
|
|
215
|
+
logger?.debug({ cacheableKey }, 'set cache');
|
|
216
|
+
await options.mediaCache.set(cacheableKey, WAProto.Message.encode(obj).finish());
|
|
233
217
|
}
|
|
234
|
-
|
|
235
218
|
return obj;
|
|
236
219
|
};
|
|
237
|
-
|
|
238
|
-
const prepareDisappearingMessageSettingContent = (ephemeralExpiration) => {
|
|
220
|
+
export const prepareDisappearingMessageSettingContent = (ephemeralExpiration) => {
|
|
239
221
|
ephemeralExpiration = ephemeralExpiration || 0;
|
|
240
222
|
const content = {
|
|
241
223
|
ephemeralMessage: {
|
|
242
224
|
message: {
|
|
243
225
|
protocolMessage: {
|
|
244
|
-
type:
|
|
226
|
+
type: WAProto.Message.ProtocolMessage.Type.EPHEMERAL_SETTING,
|
|
245
227
|
ephemeralExpiration
|
|
246
228
|
}
|
|
247
229
|
}
|
|
248
230
|
}
|
|
249
231
|
};
|
|
250
|
-
return
|
|
232
|
+
return WAProto.Message.fromObject(content);
|
|
251
233
|
};
|
|
252
|
-
exports.prepareDisappearingMessageSettingContent = prepareDisappearingMessageSettingContent;
|
|
253
234
|
/**
|
|
254
235
|
* Generate forwarded message content like WA does
|
|
255
236
|
* @param message the message to forward
|
|
256
237
|
* @param options.forceForward will show the message as forwarded even if it is from you
|
|
257
238
|
*/
|
|
258
|
-
const generateForwardMessageContent = (message, forceForward) => {
|
|
259
|
-
var _a;
|
|
239
|
+
export const generateForwardMessageContent = (message, forceForward) => {
|
|
260
240
|
let content = message.message;
|
|
261
241
|
if (!content) {
|
|
262
|
-
throw new
|
|
242
|
+
throw new Boom('no content in message', { statusCode: 400 });
|
|
263
243
|
}
|
|
264
244
|
// hacky copy
|
|
265
|
-
content =
|
|
266
|
-
content =
|
|
245
|
+
content = normalizeMessageContent(content);
|
|
246
|
+
content = proto.Message.decode(proto.Message.encode(content).finish());
|
|
267
247
|
let key = Object.keys(content)[0];
|
|
268
|
-
let score =
|
|
248
|
+
let score = content?.[key]?.contextInfo?.forwardingScore || 0;
|
|
269
249
|
score += message.key.fromMe && !forceForward ? 0 : 1;
|
|
270
250
|
if (key === 'conversation') {
|
|
271
251
|
content.extendedTextMessage = { text: content[key] };
|
|
272
252
|
delete content.conversation;
|
|
273
253
|
key = 'extendedTextMessage';
|
|
274
254
|
}
|
|
255
|
+
const key_ = content?.[key];
|
|
275
256
|
if (score > 0) {
|
|
276
|
-
|
|
257
|
+
key_.contextInfo = { forwardingScore: score, isForwarded: true };
|
|
277
258
|
}
|
|
278
259
|
else {
|
|
279
|
-
|
|
260
|
+
key_.contextInfo = {};
|
|
280
261
|
}
|
|
281
262
|
return content;
|
|
282
263
|
};
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
264
|
+
export const hasNonNullishProperty = (message, key) => {
|
|
265
|
+
return (typeof message === 'object' &&
|
|
266
|
+
message !== null &&
|
|
267
|
+
key in message &&
|
|
268
|
+
message[key] !== null &&
|
|
269
|
+
message[key] !== undefined);
|
|
270
|
+
};
|
|
271
|
+
function hasOptionalProperty(obj, key) {
|
|
272
|
+
return typeof obj === 'object' && obj !== null && key in obj && obj[key] !== null;
|
|
273
|
+
}
|
|
274
|
+
export const generateWAMessageContent = async (message, options) => {
|
|
275
|
+
var _a, _b;
|
|
287
276
|
let m = {};
|
|
288
|
-
if ('text'
|
|
277
|
+
if (hasNonNullishProperty(message, 'text')) {
|
|
289
278
|
const extContent = { text: message.text };
|
|
290
279
|
let urlInfo = message.linkPreview;
|
|
291
280
|
if (typeof urlInfo === 'undefined') {
|
|
292
|
-
urlInfo = await
|
|
281
|
+
urlInfo = await generateLinkPreviewIfRequired(message.text, options.getUrlInfo, options.logger);
|
|
293
282
|
}
|
|
294
283
|
if (urlInfo) {
|
|
295
|
-
extContent.canonicalUrl = urlInfo['canonical-url'];
|
|
296
284
|
extContent.matchedText = urlInfo['matched-text'];
|
|
297
285
|
extContent.jpegThumbnail = urlInfo.jpegThumbnail;
|
|
298
286
|
extContent.description = urlInfo.description;
|
|
@@ -317,218 +305,296 @@ const generateWAMessageContent = async (message, options) => {
|
|
|
317
305
|
}
|
|
318
306
|
m.extendedTextMessage = extContent;
|
|
319
307
|
}
|
|
320
|
-
else if ('contacts'
|
|
308
|
+
else if (hasNonNullishProperty(message, 'contacts')) {
|
|
321
309
|
const contactLen = message.contacts.contacts.length;
|
|
322
310
|
if (!contactLen) {
|
|
323
|
-
throw new
|
|
311
|
+
throw new Boom('require atleast 1 contact', { statusCode: 400 });
|
|
324
312
|
}
|
|
325
313
|
if (contactLen === 1) {
|
|
326
|
-
m.contactMessage =
|
|
314
|
+
m.contactMessage = WAProto.Message.ContactMessage.create(message.contacts.contacts[0]);
|
|
327
315
|
}
|
|
328
316
|
else {
|
|
329
|
-
m.contactsArrayMessage =
|
|
317
|
+
m.contactsArrayMessage = WAProto.Message.ContactsArrayMessage.create(message.contacts);
|
|
330
318
|
}
|
|
331
319
|
}
|
|
332
|
-
else if ('
|
|
333
|
-
|
|
320
|
+
else if (hasNonNullishProperty(message, 'buttons')) {
|
|
321
|
+
const buttonsMessage = {
|
|
322
|
+
buttons: message.buttons.map(b => ({ ...b, type: proto.Message.ButtonsMessage.Button.Type.RESPONSE }))
|
|
323
|
+
};
|
|
324
|
+
if ('text' in message) {
|
|
325
|
+
buttonsMessage.contentText = message.text;
|
|
326
|
+
buttonsMessage.headerType = ButtonType.EMPTY;
|
|
327
|
+
}
|
|
328
|
+
else {
|
|
329
|
+
if ('caption' in message) {
|
|
330
|
+
buttonsMessage.contentText = message.caption;
|
|
331
|
+
}
|
|
332
|
+
const contentType = getContentType(m);
|
|
333
|
+
const type = contentType.replace('Message', '').toUpperCase();
|
|
334
|
+
buttonsMessage.headerType = ButtonType[type];
|
|
335
|
+
Object.assign(buttonsMessage, m);
|
|
336
|
+
}
|
|
337
|
+
if ('footer' in message && !!message.footer) {
|
|
338
|
+
buttonsMessage.footerText = message.footer;
|
|
339
|
+
}
|
|
340
|
+
m = { buttonsMessage };
|
|
334
341
|
}
|
|
335
|
-
else if ('location'
|
|
336
|
-
m.locationMessage =
|
|
342
|
+
else if (hasNonNullishProperty(message, 'location')) {
|
|
343
|
+
m.locationMessage = WAProto.Message.LocationMessage.create(message.location);
|
|
337
344
|
}
|
|
338
|
-
else if ('react'
|
|
345
|
+
else if (hasNonNullishProperty(message, 'react')) {
|
|
339
346
|
if (!message.react.senderTimestampMs) {
|
|
340
347
|
message.react.senderTimestampMs = Date.now();
|
|
341
348
|
}
|
|
342
|
-
m.reactionMessage =
|
|
349
|
+
m.reactionMessage = WAProto.Message.ReactionMessage.create(message.react);
|
|
343
350
|
}
|
|
344
|
-
else if ('delete'
|
|
351
|
+
else if (hasNonNullishProperty(message, 'delete')) {
|
|
345
352
|
m.protocolMessage = {
|
|
346
353
|
key: message.delete,
|
|
347
|
-
type:
|
|
354
|
+
type: WAProto.Message.ProtocolMessage.Type.REVOKE
|
|
348
355
|
};
|
|
349
356
|
}
|
|
350
|
-
else if ('forward'
|
|
351
|
-
m =
|
|
357
|
+
else if (hasNonNullishProperty(message, 'forward')) {
|
|
358
|
+
m = generateForwardMessageContent(message.forward, message.force);
|
|
359
|
+
}
|
|
360
|
+
else if (hasNonNullishProperty(message, 'disappearingMessagesInChat')) {
|
|
361
|
+
const exp = typeof message.disappearingMessagesInChat === 'boolean'
|
|
362
|
+
? message.disappearingMessagesInChat
|
|
363
|
+
? WA_DEFAULT_EPHEMERAL
|
|
364
|
+
: 0
|
|
365
|
+
: message.disappearingMessagesInChat;
|
|
366
|
+
m = prepareDisappearingMessageSettingContent(exp);
|
|
367
|
+
}
|
|
368
|
+
else if (hasNonNullishProperty(message, 'groupInvite')) {
|
|
369
|
+
m.groupInviteMessage = {};
|
|
370
|
+
m.groupInviteMessage.inviteCode = message.groupInvite.inviteCode;
|
|
371
|
+
m.groupInviteMessage.inviteExpiration = message.groupInvite.inviteExpiration;
|
|
372
|
+
m.groupInviteMessage.caption = message.groupInvite.text;
|
|
373
|
+
m.groupInviteMessage.groupJid = message.groupInvite.jid;
|
|
374
|
+
m.groupInviteMessage.groupName = message.groupInvite.subject;
|
|
375
|
+
//TODO: use built-in interface and get disappearing mode info etc.
|
|
376
|
+
//TODO: cache / use store!?
|
|
377
|
+
if (options.getProfilePicUrl) {
|
|
378
|
+
const pfpUrl = await options.getProfilePicUrl(message.groupInvite.jid, 'preview');
|
|
379
|
+
if (pfpUrl) {
|
|
380
|
+
const resp = await fetch(pfpUrl, { method: 'GET', dispatcher: options?.options?.dispatcher });
|
|
381
|
+
if (resp.ok) {
|
|
382
|
+
const buf = Buffer.from(await resp.arrayBuffer());
|
|
383
|
+
m.groupInviteMessage.jpegThumbnail = buf;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}
|
|
352
387
|
}
|
|
353
|
-
else if ('
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
m =
|
|
388
|
+
else if (hasNonNullishProperty(message, 'pin')) {
|
|
389
|
+
m.pinInChatMessage = {};
|
|
390
|
+
m.messageContextInfo = {};
|
|
391
|
+
m.pinInChatMessage.key = message.pin;
|
|
392
|
+
m.pinInChatMessage.type = message.type;
|
|
393
|
+
m.pinInChatMessage.senderTimestampMs = Date.now();
|
|
394
|
+
m.messageContextInfo.messageAddOnDurationInSecs = message.type === 1 ? message.time || 86400 : 0;
|
|
358
395
|
}
|
|
359
|
-
else if ('buttonReply'
|
|
396
|
+
else if (hasNonNullishProperty(message, 'buttonReply')) {
|
|
360
397
|
switch (message.type) {
|
|
361
398
|
case 'template':
|
|
362
399
|
m.templateButtonReplyMessage = {
|
|
363
400
|
selectedDisplayText: message.buttonReply.displayText,
|
|
364
401
|
selectedId: message.buttonReply.id,
|
|
365
|
-
selectedIndex: message.buttonReply.index
|
|
402
|
+
selectedIndex: message.buttonReply.index
|
|
366
403
|
};
|
|
367
404
|
break;
|
|
368
405
|
case 'plain':
|
|
369
406
|
m.buttonsResponseMessage = {
|
|
370
407
|
selectedButtonId: message.buttonReply.id,
|
|
371
408
|
selectedDisplayText: message.buttonReply.displayText,
|
|
372
|
-
type:
|
|
409
|
+
type: proto.Message.ButtonsResponseMessage.Type.DISPLAY_TEXT
|
|
373
410
|
};
|
|
374
411
|
break;
|
|
375
412
|
}
|
|
376
413
|
}
|
|
377
|
-
else if ('
|
|
378
|
-
const {
|
|
379
|
-
m.
|
|
414
|
+
else if (hasOptionalProperty(message, 'ptv') && message.ptv) {
|
|
415
|
+
const { videoMessage } = await prepareWAMessageMedia({ video: message.ptv }, options);
|
|
416
|
+
m.ptvMessage = videoMessage;
|
|
417
|
+
}
|
|
418
|
+
else if (hasNonNullishProperty(message, 'product')) {
|
|
419
|
+
const { imageMessage } = await prepareWAMessageMedia({ image: message.product.productImage }, options);
|
|
420
|
+
m.productMessage = WAProto.Message.ProductMessage.create({
|
|
380
421
|
...message,
|
|
381
422
|
product: {
|
|
382
423
|
...message.product,
|
|
383
|
-
productImage: imageMessage
|
|
424
|
+
productImage: imageMessage
|
|
384
425
|
}
|
|
385
426
|
});
|
|
386
427
|
}
|
|
387
|
-
else if ('listReply'
|
|
428
|
+
else if (hasNonNullishProperty(message, 'listReply')) {
|
|
388
429
|
m.listResponseMessage = { ...message.listReply };
|
|
389
430
|
}
|
|
390
|
-
else if ('
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
431
|
+
else if (hasNonNullishProperty(message, 'event')) {
|
|
432
|
+
m.eventMessage = {};
|
|
433
|
+
const startTime = Math.floor(message.event.startDate.getTime() / 1000);
|
|
434
|
+
if (message.event.call && options.getCallLink) {
|
|
435
|
+
const token = await options.getCallLink(message.event.call, { startTime });
|
|
436
|
+
m.eventMessage.joinLink = (message.event.call === 'audio' ? CALL_AUDIO_PREFIX : CALL_VIDEO_PREFIX) + token;
|
|
437
|
+
}
|
|
438
|
+
m.messageContextInfo = {
|
|
439
|
+
// encKey
|
|
440
|
+
messageSecret: message.event.messageSecret || randomBytes(32)
|
|
441
|
+
};
|
|
442
|
+
m.eventMessage.name = message.event.name;
|
|
443
|
+
m.eventMessage.description = message.event.description;
|
|
444
|
+
m.eventMessage.startTime = startTime;
|
|
445
|
+
m.eventMessage.endTime = message.event.endDate ? message.event.endDate.getTime() / 1000 : undefined;
|
|
446
|
+
m.eventMessage.isCanceled = message.event.isCancelled ?? false;
|
|
447
|
+
m.eventMessage.extraGuestsAllowed = message.event.extraGuestsAllowed;
|
|
448
|
+
m.eventMessage.isScheduleCall = message.event.isScheduleCall ?? false;
|
|
449
|
+
m.eventMessage.location = message.event.location;
|
|
450
|
+
}
|
|
451
|
+
else if (hasNonNullishProperty(message, 'poll')) {
|
|
452
|
+
(_a = message.poll).selectableCount || (_a.selectableCount = 0);
|
|
453
|
+
(_b = message.poll).toAnnouncementGroup || (_b.toAnnouncementGroup = false);
|
|
399
454
|
if (!Array.isArray(message.poll.values)) {
|
|
400
|
-
throw new
|
|
455
|
+
throw new Boom('Invalid poll values', { statusCode: 400 });
|
|
401
456
|
}
|
|
402
|
-
if (message.poll.selectableCount < 0
|
|
403
|
-
|
|
404
|
-
|
|
457
|
+
if (message.poll.selectableCount < 0 || message.poll.selectableCount > message.poll.values.length) {
|
|
458
|
+
throw new Boom(`poll.selectableCount in poll should be >= 0 and <= ${message.poll.values.length}`, {
|
|
459
|
+
statusCode: 400
|
|
460
|
+
});
|
|
405
461
|
}
|
|
406
462
|
m.messageContextInfo = {
|
|
407
463
|
// encKey
|
|
408
|
-
messageSecret: message.poll.messageSecret ||
|
|
464
|
+
messageSecret: message.poll.messageSecret || randomBytes(32)
|
|
409
465
|
};
|
|
410
|
-
|
|
466
|
+
const pollCreationMessage = {
|
|
411
467
|
name: message.poll.name,
|
|
412
468
|
selectableOptionsCount: message.poll.selectableCount,
|
|
413
|
-
options: message.poll.values.map(optionName => ({ optionName }))
|
|
414
|
-
pollType: message.poll.type,
|
|
415
|
-
correctAnswer: message.poll.answer
|
|
416
|
-
};
|
|
417
|
-
}
|
|
418
|
-
else if ('sharePhoneNumber' in message) {
|
|
419
|
-
m.protocolMessage = {
|
|
420
|
-
type: WAProto_1.proto.Message.ProtocolMessage.Type.SHARE_PHONE_NUMBER
|
|
421
|
-
};
|
|
422
|
-
}
|
|
423
|
-
else if ('requestPhoneNumber' in message) {
|
|
424
|
-
m.requestPhoneNumberMessage = {};
|
|
425
|
-
}
|
|
426
|
-
else {
|
|
427
|
-
m = await (0, exports.prepareWAMessageMedia)(message, options);
|
|
428
|
-
}
|
|
429
|
-
if ('buttons' in message && !!message.buttons) {
|
|
430
|
-
const buttonsMessage = {
|
|
431
|
-
buttons: message.buttons.map(b => ({ ...b, type: WAProto_1.proto.Message.ButtonsMessage.Button.Type.RESPONSE }))
|
|
469
|
+
options: message.poll.values.map(optionName => ({ optionName }))
|
|
432
470
|
};
|
|
433
|
-
if (
|
|
434
|
-
|
|
435
|
-
|
|
471
|
+
if (message.poll.toAnnouncementGroup) {
|
|
472
|
+
// poll v2 is for community announcement groups (single select and multiple)
|
|
473
|
+
m.pollCreationMessageV2 = pollCreationMessage;
|
|
436
474
|
}
|
|
437
475
|
else {
|
|
438
|
-
if (
|
|
439
|
-
|
|
476
|
+
if (message.poll.selectableCount === 1) {
|
|
477
|
+
//poll v3 is for single select polls
|
|
478
|
+
m.pollCreationMessageV3 = pollCreationMessage;
|
|
479
|
+
}
|
|
480
|
+
else {
|
|
481
|
+
// poll for multiple choice polls
|
|
482
|
+
m.pollCreationMessage = pollCreationMessage;
|
|
440
483
|
}
|
|
441
|
-
const type = Object.keys(m)[0].replace('Message', '').toUpperCase();
|
|
442
|
-
buttonsMessage.headerType = ButtonType[type];
|
|
443
|
-
Object.assign(buttonsMessage, m);
|
|
444
|
-
}
|
|
445
|
-
if ('footer' in message && !!message.footer) {
|
|
446
|
-
buttonsMessage.footerText = message.footer;
|
|
447
484
|
}
|
|
448
|
-
m = { buttonsMessage };
|
|
449
485
|
}
|
|
450
|
-
else if ('
|
|
451
|
-
|
|
452
|
-
|
|
486
|
+
else if (hasNonNullishProperty(message, 'album')) {
|
|
487
|
+
m.albumMessage = {
|
|
488
|
+
expectedImageCount: message.album.expectedImageCount,
|
|
489
|
+
expectedVideoCount: message.album.expectedVideoCount
|
|
453
490
|
};
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
if ('caption' in message) {
|
|
459
|
-
msg.hydratedContentText = message.caption;
|
|
460
|
-
}
|
|
461
|
-
Object.assign(msg, m);
|
|
462
|
-
}
|
|
463
|
-
if ('footer' in message && !!message.footer) {
|
|
464
|
-
msg.hydratedFooterText = message.footer;
|
|
465
|
-
}
|
|
466
|
-
m = {
|
|
467
|
-
templateMessage: {
|
|
468
|
-
fourRowTemplate: msg,
|
|
469
|
-
hydratedTemplate: msg
|
|
470
|
-
}
|
|
491
|
+
}
|
|
492
|
+
else if (hasNonNullishProperty(message, 'sharePhoneNumber')) {
|
|
493
|
+
m.protocolMessage = {
|
|
494
|
+
type: proto.Message.ProtocolMessage.Type.SHARE_PHONE_NUMBER
|
|
471
495
|
};
|
|
472
496
|
}
|
|
473
|
-
if ('
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
497
|
+
else if (hasNonNullishProperty(message, 'requestPhoneNumber')) {
|
|
498
|
+
m.requestPhoneNumberMessage = {};
|
|
499
|
+
}
|
|
500
|
+
else if (hasNonNullishProperty(message, 'limitSharing')) {
|
|
501
|
+
m.protocolMessage = {
|
|
502
|
+
type: proto.Message.ProtocolMessage.Type.LIMIT_SHARING,
|
|
503
|
+
limitSharing: {
|
|
504
|
+
sharingLimited: message.limitSharing === true,
|
|
505
|
+
trigger: 1,
|
|
506
|
+
limitSharingSettingTimestamp: Date.now(),
|
|
507
|
+
initiatedByMe: true
|
|
508
|
+
}
|
|
481
509
|
};
|
|
482
|
-
m = { listMessage };
|
|
483
510
|
}
|
|
484
|
-
|
|
511
|
+
else {
|
|
512
|
+
m = await prepareWAMessageMedia(message, options);
|
|
513
|
+
}
|
|
514
|
+
if (hasOptionalProperty(message, 'viewOnce') && !!message.viewOnce) {
|
|
485
515
|
m = { viewOnceMessage: { message: m } };
|
|
486
516
|
}
|
|
487
|
-
if ('mentions'
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
m[messageType]
|
|
517
|
+
if ((hasOptionalProperty(message, 'mentions') && message.mentions?.length) ||
|
|
518
|
+
(hasOptionalProperty(message, 'mentionAll') && message.mentionAll)) {
|
|
519
|
+
const messageType = Object.keys(m)[0];
|
|
520
|
+
const key = m[messageType];
|
|
521
|
+
if (key && 'contextInfo' in key) {
|
|
522
|
+
key.contextInfo = key.contextInfo || {};
|
|
523
|
+
if (message.mentions?.length) {
|
|
524
|
+
key.contextInfo.mentionedJid = message.mentions;
|
|
525
|
+
}
|
|
526
|
+
if (message.mentionAll) {
|
|
527
|
+
key.contextInfo.nonJidMentions = 1;
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
else if (key) {
|
|
531
|
+
key.contextInfo = {
|
|
532
|
+
mentionedJid: message.mentions,
|
|
533
|
+
nonJidMentions: message.mentionAll ? 1 : 0
|
|
534
|
+
};
|
|
535
|
+
}
|
|
491
536
|
}
|
|
492
|
-
if ('edit'
|
|
537
|
+
if (hasOptionalProperty(message, 'edit')) {
|
|
493
538
|
m = {
|
|
494
539
|
protocolMessage: {
|
|
495
540
|
key: message.edit,
|
|
496
541
|
editedMessage: m,
|
|
497
542
|
timestampMs: Date.now(),
|
|
498
|
-
type:
|
|
543
|
+
type: WAProto.Message.ProtocolMessage.Type.MESSAGE_EDIT
|
|
544
|
+
}
|
|
545
|
+
};
|
|
546
|
+
}
|
|
547
|
+
if (hasOptionalProperty(message, 'contextInfo') && !!message.contextInfo) {
|
|
548
|
+
const messageType = Object.keys(m)[0];
|
|
549
|
+
const key = m[messageType];
|
|
550
|
+
if ('contextInfo' in key && !!key.contextInfo) {
|
|
551
|
+
key.contextInfo = { ...key.contextInfo, ...message.contextInfo };
|
|
552
|
+
}
|
|
553
|
+
else if (key) {
|
|
554
|
+
key.contextInfo = message.contextInfo;
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
if (hasOptionalProperty(message, 'albumParentKey') && !!message.albumParentKey) {
|
|
558
|
+
m.messageContextInfo = {
|
|
559
|
+
...m.messageContextInfo,
|
|
560
|
+
messageAssociation: {
|
|
561
|
+
associationType: WAProto.MessageAssociation.AssociationType.MEDIA_ALBUM,
|
|
562
|
+
parentMessageKey: message.albumParentKey
|
|
499
563
|
}
|
|
500
564
|
};
|
|
501
565
|
}
|
|
502
|
-
if (
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
566
|
+
if (shouldIncludeReportingToken(m)) {
|
|
567
|
+
m.messageContextInfo = m.messageContextInfo || {};
|
|
568
|
+
if (!m.messageContextInfo.messageSecret) {
|
|
569
|
+
m.messageContextInfo.messageSecret = randomBytes(32);
|
|
570
|
+
}
|
|
506
571
|
}
|
|
507
|
-
return
|
|
572
|
+
return WAProto.Message.create(m);
|
|
508
573
|
};
|
|
509
|
-
|
|
510
|
-
const generateWAMessageFromContent = (jid, message, options) => {
|
|
574
|
+
export const generateWAMessageFromContent = (jid, message, options) => {
|
|
511
575
|
// set timestamp to now
|
|
512
576
|
// if not specified
|
|
513
577
|
if (!options.timestamp) {
|
|
514
578
|
options.timestamp = new Date();
|
|
515
579
|
}
|
|
516
|
-
const innerMessage =
|
|
517
|
-
const key =
|
|
518
|
-
const timestamp =
|
|
580
|
+
const innerMessage = normalizeMessageContent(message);
|
|
581
|
+
const key = getContentType(innerMessage);
|
|
582
|
+
const timestamp = unixTimestampSeconds(options.timestamp);
|
|
519
583
|
const { quoted, userJid } = options;
|
|
520
|
-
if (quoted && !(
|
|
521
|
-
const participant = quoted.key.fromMe
|
|
522
|
-
|
|
523
|
-
|
|
584
|
+
if (quoted && !isJidNewsletter(jid)) {
|
|
585
|
+
const participant = quoted.key.fromMe
|
|
586
|
+
? userJid // TODO: Add support for LIDs
|
|
587
|
+
: quoted.participant || quoted.key.participant || quoted.key.remoteJid;
|
|
588
|
+
let quotedMsg = normalizeMessageContent(quoted.message);
|
|
589
|
+
const msgType = getContentType(quotedMsg);
|
|
524
590
|
// strip any redundant properties
|
|
525
|
-
quotedMsg =
|
|
591
|
+
quotedMsg = proto.Message.create({ [msgType]: quotedMsg[msgType] });
|
|
526
592
|
const quotedContent = quotedMsg[msgType];
|
|
527
593
|
if (typeof quotedContent === 'object' && quotedContent && 'contextInfo' in quotedContent) {
|
|
528
594
|
delete quotedContent.contextInfo;
|
|
529
595
|
}
|
|
530
|
-
const contextInfo = innerMessage[key]
|
|
531
|
-
contextInfo.participant =
|
|
596
|
+
const contextInfo = ('contextInfo' in innerMessage[key] && innerMessage[key]?.contextInfo) || {};
|
|
597
|
+
contextInfo.participant = jidNormalizedUser(participant);
|
|
532
598
|
contextInfo.stanzaId = quoted.key.id;
|
|
533
599
|
contextInfo.quotedMessage = quotedMsg;
|
|
534
600
|
// if a participant is quoted, then it must be a group
|
|
@@ -536,62 +602,63 @@ const generateWAMessageFromContent = (jid, message, options) => {
|
|
|
536
602
|
if (jid !== quoted.key.remoteJid) {
|
|
537
603
|
contextInfo.remoteJid = quoted.key.remoteJid;
|
|
538
604
|
}
|
|
539
|
-
innerMessage[key]
|
|
605
|
+
if (contextInfo && innerMessage[key]) {
|
|
606
|
+
/* @ts-ignore */
|
|
607
|
+
innerMessage[key].contextInfo = contextInfo;
|
|
608
|
+
}
|
|
540
609
|
}
|
|
541
610
|
if (
|
|
542
611
|
// if we want to send a disappearing message
|
|
543
|
-
!!
|
|
612
|
+
!!options?.ephemeralExpiration &&
|
|
544
613
|
// and it's not a protocol message -- delete, toggle disappear message
|
|
545
614
|
key !== 'protocolMessage' &&
|
|
546
615
|
// already not converted to disappearing message
|
|
547
616
|
key !== 'ephemeralMessage' &&
|
|
548
|
-
//
|
|
549
|
-
!(
|
|
617
|
+
// newsletters don't support ephemeral messages
|
|
618
|
+
!isJidNewsletter(jid)) {
|
|
619
|
+
/* @ts-ignore */
|
|
550
620
|
innerMessage[key].contextInfo = {
|
|
551
621
|
...(innerMessage[key].contextInfo || {}),
|
|
552
|
-
expiration: options.ephemeralExpiration ||
|
|
622
|
+
expiration: options.ephemeralExpiration || WA_DEFAULT_EPHEMERAL
|
|
553
623
|
//ephemeralSettingTimestamp: options.ephemeralOptions.eph_setting_ts?.toString()
|
|
554
624
|
};
|
|
555
625
|
}
|
|
556
|
-
message =
|
|
626
|
+
message = WAProto.Message.create(message);
|
|
557
627
|
const messageJSON = {
|
|
558
628
|
key: {
|
|
559
629
|
remoteJid: jid,
|
|
560
630
|
fromMe: true,
|
|
561
|
-
id:
|
|
631
|
+
id: options?.messageId || generateMessageIDV2()
|
|
562
632
|
},
|
|
563
633
|
message: message,
|
|
564
634
|
messageTimestamp: timestamp,
|
|
565
635
|
messageStubParameters: [],
|
|
566
|
-
participant:
|
|
567
|
-
status:
|
|
636
|
+
participant: isJidGroup(jid) || isJidStatusBroadcast(jid) ? userJid : undefined, // TODO: Add support for LIDs
|
|
637
|
+
status: WAMessageStatus.PENDING
|
|
568
638
|
};
|
|
569
|
-
return
|
|
639
|
+
return WAProto.WebMessageInfo.fromObject(messageJSON);
|
|
570
640
|
};
|
|
571
|
-
|
|
572
|
-
const generateWAMessage = async (jid, content, options) => {
|
|
573
|
-
var _a;
|
|
641
|
+
export const generateWAMessage = async (jid, content, options) => {
|
|
574
642
|
// ensure msg ID is with every log
|
|
575
|
-
options.logger =
|
|
576
|
-
|
|
643
|
+
options.logger = options?.logger?.child({ msgId: options.messageId });
|
|
644
|
+
// Pass jid in the options to generateWAMessageContent
|
|
645
|
+
return generateWAMessageFromContent(jid, await generateWAMessageContent(content, { ...options, jid }), options);
|
|
577
646
|
};
|
|
578
|
-
exports.generateWAMessage = generateWAMessage;
|
|
579
647
|
/** Get the key to access the true type of content */
|
|
580
|
-
const getContentType = (content) => {
|
|
648
|
+
export const getContentType = (content) => {
|
|
581
649
|
if (content) {
|
|
582
650
|
const keys = Object.keys(content);
|
|
583
651
|
const key = keys.find(k => (k === 'conversation' || k.includes('Message')) && k !== 'senderKeyDistributionMessage');
|
|
584
652
|
return key;
|
|
585
653
|
}
|
|
586
654
|
};
|
|
587
|
-
exports.getContentType = getContentType;
|
|
588
655
|
/**
|
|
589
656
|
* Normalizes ephemeral, view once messages to regular message content
|
|
590
657
|
* Eg. image messages in ephemeral messages, in view once messages etc.
|
|
591
658
|
* @param content
|
|
592
659
|
* @returns
|
|
593
660
|
*/
|
|
594
|
-
const normalizeMessageContent = (content) => {
|
|
661
|
+
export const normalizeMessageContent = (content) => {
|
|
595
662
|
if (!content) {
|
|
596
663
|
return undefined;
|
|
597
664
|
}
|
|
@@ -605,21 +672,22 @@ const normalizeMessageContent = (content) => {
|
|
|
605
672
|
}
|
|
606
673
|
return content;
|
|
607
674
|
function getFutureProofMessage(message) {
|
|
608
|
-
return (
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
675
|
+
return (message?.ephemeralMessage ||
|
|
676
|
+
message?.viewOnceMessage ||
|
|
677
|
+
message?.documentWithCaptionMessage ||
|
|
678
|
+
message?.viewOnceMessageV2 ||
|
|
679
|
+
message?.viewOnceMessageV2Extension ||
|
|
680
|
+
message?.editedMessage ||
|
|
681
|
+
message?.associatedChildMessage ||
|
|
682
|
+
message?.groupStatusMessage ||
|
|
683
|
+
message?.groupStatusMessageV2);
|
|
614
684
|
}
|
|
615
685
|
};
|
|
616
|
-
exports.normalizeMessageContent = normalizeMessageContent;
|
|
617
686
|
/**
|
|
618
687
|
* Extract the true message content from a message
|
|
619
688
|
* Eg. extracts the inner message from a disappearing message/view once message
|
|
620
689
|
*/
|
|
621
|
-
const extractMessageContent = (content) => {
|
|
622
|
-
var _a, _b, _c, _d, _e, _f;
|
|
690
|
+
export const extractMessageContent = (content) => {
|
|
623
691
|
const extractFromTemplateMessage = (msg) => {
|
|
624
692
|
if (msg.imageMessage) {
|
|
625
693
|
return { imageMessage: msg.imageMessage };
|
|
@@ -635,35 +703,39 @@ const extractMessageContent = (content) => {
|
|
|
635
703
|
}
|
|
636
704
|
else {
|
|
637
705
|
return {
|
|
638
|
-
conversation: 'contentText' in msg
|
|
639
|
-
? msg.contentText
|
|
640
|
-
: ('hydratedContentText' in msg ? msg.hydratedContentText : '')
|
|
706
|
+
conversation: 'contentText' in msg ? msg.contentText : 'hydratedContentText' in msg ? msg.hydratedContentText : ''
|
|
641
707
|
};
|
|
642
708
|
}
|
|
643
709
|
};
|
|
644
|
-
content =
|
|
645
|
-
if (content
|
|
710
|
+
content = normalizeMessageContent(content);
|
|
711
|
+
if (content?.buttonsMessage) {
|
|
646
712
|
return extractFromTemplateMessage(content.buttonsMessage);
|
|
647
713
|
}
|
|
648
|
-
if (
|
|
649
|
-
return extractFromTemplateMessage(
|
|
714
|
+
if (content?.templateMessage?.hydratedFourRowTemplate) {
|
|
715
|
+
return extractFromTemplateMessage(content?.templateMessage?.hydratedFourRowTemplate);
|
|
650
716
|
}
|
|
651
|
-
if (
|
|
652
|
-
return extractFromTemplateMessage(
|
|
717
|
+
if (content?.templateMessage?.hydratedTemplate) {
|
|
718
|
+
return extractFromTemplateMessage(content?.templateMessage?.hydratedTemplate);
|
|
653
719
|
}
|
|
654
|
-
if (
|
|
655
|
-
return extractFromTemplateMessage(
|
|
720
|
+
if (content?.templateMessage?.fourRowTemplate) {
|
|
721
|
+
return extractFromTemplateMessage(content?.templateMessage?.fourRowTemplate);
|
|
656
722
|
}
|
|
657
723
|
return content;
|
|
658
724
|
};
|
|
659
|
-
exports.extractMessageContent = extractMessageContent;
|
|
660
725
|
/**
|
|
661
726
|
* Returns the device predicted by message ID
|
|
662
727
|
*/
|
|
663
|
-
const getDevice = (id) => /^3A.{18}$/.test(id)
|
|
664
|
-
|
|
728
|
+
export const getDevice = (id) => /^3A.{18}$/.test(id)
|
|
729
|
+
? 'ios'
|
|
730
|
+
: /^3E.{20}$/.test(id)
|
|
731
|
+
? 'web'
|
|
732
|
+
: /^(.{21}|.{32})$/.test(id)
|
|
733
|
+
? 'android'
|
|
734
|
+
: /^(3F|.{18}$)/.test(id)
|
|
735
|
+
? 'desktop'
|
|
736
|
+
: 'wa bot';
|
|
665
737
|
/** Upserts a receipt in the message */
|
|
666
|
-
const updateMessageWithReceipt = (msg, receipt) => {
|
|
738
|
+
export const updateMessageWithReceipt = (msg, receipt) => {
|
|
667
739
|
msg.userReceipt = msg.userReceipt || [];
|
|
668
740
|
const recp = msg.userReceipt.find(m => m.userJid === receipt.userJid);
|
|
669
741
|
if (recp) {
|
|
@@ -673,41 +745,43 @@ const updateMessageWithReceipt = (msg, receipt) => {
|
|
|
673
745
|
msg.userReceipt.push(receipt);
|
|
674
746
|
}
|
|
675
747
|
};
|
|
676
|
-
exports.updateMessageWithReceipt = updateMessageWithReceipt;
|
|
677
748
|
/** Update the message with a new reaction */
|
|
678
|
-
const updateMessageWithReaction = (msg, reaction) => {
|
|
679
|
-
const authorID =
|
|
680
|
-
const reactions = (msg.reactions || [])
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
reactions.push(reaction);
|
|
684
|
-
}
|
|
749
|
+
export const updateMessageWithReaction = (msg, reaction) => {
|
|
750
|
+
const authorID = getKeyAuthor(reaction.key);
|
|
751
|
+
const reactions = (msg.reactions || []).filter(r => getKeyAuthor(r.key) !== authorID);
|
|
752
|
+
reaction.text = reaction.text || '';
|
|
753
|
+
reactions.push(reaction);
|
|
685
754
|
msg.reactions = reactions;
|
|
686
755
|
};
|
|
687
|
-
exports.updateMessageWithReaction = updateMessageWithReaction;
|
|
688
756
|
/** Update the message with a new poll update */
|
|
689
|
-
const updateMessageWithPollUpdate = (msg, update) => {
|
|
690
|
-
|
|
691
|
-
const
|
|
692
|
-
|
|
693
|
-
.filter(r => (0, generics_1.getKeyAuthor)(r.pollUpdateMessageKey) !== authorID);
|
|
694
|
-
if ((_b = (_a = update.vote) === null || _a === void 0 ? void 0 : _a.selectedOptions) === null || _b === void 0 ? void 0 : _b.length) {
|
|
757
|
+
export const updateMessageWithPollUpdate = (msg, update) => {
|
|
758
|
+
const authorID = getKeyAuthor(update.pollUpdateMessageKey);
|
|
759
|
+
const reactions = (msg.pollUpdates || []).filter(r => getKeyAuthor(r.pollUpdateMessageKey) !== authorID);
|
|
760
|
+
if (update.vote?.selectedOptions?.length) {
|
|
695
761
|
reactions.push(update);
|
|
696
762
|
}
|
|
697
763
|
msg.pollUpdates = reactions;
|
|
698
764
|
};
|
|
699
|
-
|
|
765
|
+
/** Update the message with a new event response */
|
|
766
|
+
export const updateMessageWithEventResponse = (msg, update) => {
|
|
767
|
+
const authorID = getKeyAuthor(update.eventResponseMessageKey);
|
|
768
|
+
const responses = (msg.eventResponses || []).filter(r => getKeyAuthor(r.eventResponseMessageKey) !== authorID);
|
|
769
|
+
responses.push(update);
|
|
770
|
+
msg.eventResponses = responses;
|
|
771
|
+
};
|
|
700
772
|
/**
|
|
701
773
|
* Aggregates all poll updates in a poll.
|
|
702
774
|
* @param msg the poll creation message
|
|
703
775
|
* @param meId your jid
|
|
704
776
|
* @returns A list of options & their voters
|
|
705
777
|
*/
|
|
706
|
-
function getAggregateVotesInPollMessage({ message, pollUpdates }, meId) {
|
|
707
|
-
|
|
708
|
-
|
|
778
|
+
export function getAggregateVotesInPollMessage({ message, pollUpdates }, meId) {
|
|
779
|
+
const opts = message?.pollCreationMessage?.options ||
|
|
780
|
+
message?.pollCreationMessageV2?.options ||
|
|
781
|
+
message?.pollCreationMessageV3?.options ||
|
|
782
|
+
[];
|
|
709
783
|
const voteHashMap = opts.reduce((acc, opt) => {
|
|
710
|
-
const hash =
|
|
784
|
+
const hash = sha256(Buffer.from(opt.optionName || '')).toString();
|
|
711
785
|
acc[hash] = {
|
|
712
786
|
name: opt.optionName || '',
|
|
713
787
|
voters: []
|
|
@@ -729,14 +803,36 @@ function getAggregateVotesInPollMessage({ message, pollUpdates }, meId) {
|
|
|
729
803
|
};
|
|
730
804
|
data = voteHashMap[hash];
|
|
731
805
|
}
|
|
732
|
-
voteHashMap[hash].voters.push(
|
|
806
|
+
voteHashMap[hash].voters.push(getKeyAuthor(update.pollUpdateMessageKey, meId));
|
|
733
807
|
}
|
|
734
808
|
}
|
|
735
809
|
return Object.values(voteHashMap);
|
|
736
810
|
}
|
|
737
|
-
|
|
811
|
+
/**
|
|
812
|
+
* Aggregates all event responses in an event message.
|
|
813
|
+
* @param msg the event creation message
|
|
814
|
+
* @param meId your jid
|
|
815
|
+
* @returns A list of response types & their responders
|
|
816
|
+
*/
|
|
817
|
+
export function getAggregateResponsesInEventMessage({ eventResponses }, meId) {
|
|
818
|
+
const responseTypes = ['GOING', 'NOT_GOING', 'MAYBE'];
|
|
819
|
+
const responseMap = {};
|
|
820
|
+
for (const type of responseTypes) {
|
|
821
|
+
responseMap[type] = {
|
|
822
|
+
response: type,
|
|
823
|
+
responders: []
|
|
824
|
+
};
|
|
825
|
+
}
|
|
826
|
+
for (const update of eventResponses || []) {
|
|
827
|
+
const responseType = update.eventResponse || 'UNKNOWN';
|
|
828
|
+
if (responseType !== 'UNKNOWN' && responseMap[responseType]) {
|
|
829
|
+
responseMap[responseType].responders.push(getKeyAuthor(update.eventResponseMessageKey, meId));
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
return Object.values(responseMap);
|
|
833
|
+
}
|
|
738
834
|
/** Given a list of message keys, aggregates them by chat & sender. Useful for sending read receipts in bulk */
|
|
739
|
-
const aggregateMessageKeysNotFromMe = (keys) => {
|
|
835
|
+
export const aggregateMessageKeysNotFromMe = (keys) => {
|
|
740
836
|
const keyMap = {};
|
|
741
837
|
for (const { remoteJid, id, participant, fromMe } of keys) {
|
|
742
838
|
if (!fromMe) {
|
|
@@ -753,40 +849,34 @@ const aggregateMessageKeysNotFromMe = (keys) => {
|
|
|
753
849
|
}
|
|
754
850
|
return Object.values(keyMap);
|
|
755
851
|
};
|
|
756
|
-
exports.aggregateMessageKeysNotFromMe = aggregateMessageKeysNotFromMe;
|
|
757
852
|
const REUPLOAD_REQUIRED_STATUS = [410, 404];
|
|
758
853
|
/**
|
|
759
854
|
* Downloads the given message. Throws an error if it's not a media message
|
|
760
855
|
*/
|
|
761
|
-
const downloadMediaMessage = async (message, type, options, ctx) => {
|
|
762
|
-
const result = await downloadMsg()
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
message = await ctx.reuploadRequest(message);
|
|
772
|
-
const result = await downloadMsg();
|
|
773
|
-
return result;
|
|
774
|
-
}
|
|
775
|
-
}
|
|
856
|
+
export const downloadMediaMessage = async (message, type, options, ctx) => {
|
|
857
|
+
const result = await downloadMsg().catch(async (error) => {
|
|
858
|
+
if (ctx &&
|
|
859
|
+
typeof error?.status === 'number' && // treat errors with status as HTTP failures requiring reupload
|
|
860
|
+
REUPLOAD_REQUIRED_STATUS.includes(error.status)) {
|
|
861
|
+
ctx.logger.info({ key: message.key }, 'sending reupload media request...');
|
|
862
|
+
// request reupload
|
|
863
|
+
message = await ctx.reuploadRequest(message);
|
|
864
|
+
const result = await downloadMsg();
|
|
865
|
+
return result;
|
|
776
866
|
}
|
|
777
867
|
throw error;
|
|
778
868
|
});
|
|
779
869
|
return result;
|
|
780
870
|
async function downloadMsg() {
|
|
781
|
-
const mContent =
|
|
871
|
+
const mContent = extractMessageContent(message.message);
|
|
782
872
|
if (!mContent) {
|
|
783
|
-
throw new
|
|
873
|
+
throw new Boom('No message present', { statusCode: 400, data: message });
|
|
784
874
|
}
|
|
785
|
-
const contentType =
|
|
786
|
-
let mediaType = contentType
|
|
875
|
+
const contentType = getContentType(mContent);
|
|
876
|
+
let mediaType = contentType?.replace('Message', '');
|
|
787
877
|
const media = mContent[contentType];
|
|
788
878
|
if (!media || typeof media !== 'object' || (!('url' in media) && !('thumbnailDirectPath' in media))) {
|
|
789
|
-
throw new
|
|
879
|
+
throw new Boom(`"${contentType}" message is not a media message`);
|
|
790
880
|
}
|
|
791
881
|
let download;
|
|
792
882
|
if ('thumbnailDirectPath' in media && !('url' in media)) {
|
|
@@ -799,7 +889,7 @@ const downloadMediaMessage = async (message, type, options, ctx) => {
|
|
|
799
889
|
else {
|
|
800
890
|
download = media;
|
|
801
891
|
}
|
|
802
|
-
const stream = await
|
|
892
|
+
const stream = await downloadContentFromMessage(download, mediaType, options);
|
|
803
893
|
if (type === 'buffer') {
|
|
804
894
|
const bufferArray = [];
|
|
805
895
|
for await (const chunk of stream) {
|
|
@@ -810,18 +900,17 @@ const downloadMediaMessage = async (message, type, options, ctx) => {
|
|
|
810
900
|
return stream;
|
|
811
901
|
}
|
|
812
902
|
};
|
|
813
|
-
exports.downloadMediaMessage = downloadMediaMessage;
|
|
814
903
|
/** Checks whether the given message is a media message; if it is returns the inner content */
|
|
815
|
-
const assertMediaContent = (content) => {
|
|
816
|
-
content =
|
|
817
|
-
const mediaContent =
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
904
|
+
export const assertMediaContent = (content) => {
|
|
905
|
+
content = extractMessageContent(content);
|
|
906
|
+
const mediaContent = content?.documentMessage ||
|
|
907
|
+
content?.imageMessage ||
|
|
908
|
+
content?.videoMessage ||
|
|
909
|
+
content?.audioMessage ||
|
|
910
|
+
content?.stickerMessage;
|
|
822
911
|
if (!mediaContent) {
|
|
823
|
-
throw new
|
|
912
|
+
throw new Boom('given message is not a media message', { statusCode: 400, data: content });
|
|
824
913
|
}
|
|
825
914
|
return mediaContent;
|
|
826
915
|
};
|
|
827
|
-
|
|
916
|
+
//# sourceMappingURL=messages.js.map
|