@mrlegendbot/baileys 1.0.0 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/Socket/messages-send.js +533 -150
- package/lib/Socket/newsletter.js +0 -127
- package/package.json +1 -1
- package/lib/Socket/newsletter.zip +0 -0
|
@@ -10,31 +10,25 @@ import { buildMergedTcTokenIndexWrite, isTcTokenExpired, resolveIssuanceJid, res
|
|
|
10
10
|
import { areJidsSameUser, getBinaryNodeChild, getBinaryNodeChildren, isHostedLidUser, isHostedPnUser, isJidBot, isJidGroup, isJidMetaAI, isLidUser, isPnUser, jidDecode, jidEncode, jidNormalizedUser, PSA_WID, S_WHATSAPP_NET } from '../WABinary/index.js';
|
|
11
11
|
import { USyncQuery, USyncUser } from '../WAUSync/index.js';
|
|
12
12
|
import { makeNewsletterSocket } from './newsletter.js';
|
|
13
|
+
|
|
13
14
|
export const makeMessagesSocket = (config) => {
|
|
14
15
|
const { logger, linkPreviewImageThumbnailWidth, generateHighQualityLinkPreview, options: httpRequestOptions, patchMessageBeforeSending, cachedGroupMetadata, enableRecentMessageCache, maxMsgRetryCount } = config;
|
|
15
16
|
const sock = makeNewsletterSocket(config);
|
|
16
17
|
const { ev, authState, messageMutex, signalRepository, upsertMessage, query, fetchPrivacySettings, sendNode, groupMetadata, groupToggleEphemeral, registerSocketEndHandler } = sock;
|
|
17
18
|
const getLIDForPN = signalRepository.lidMapping.getLIDForPN.bind(signalRepository.lidMapping);
|
|
18
|
-
|
|
19
|
-
* Set of tctoken storage JIDs with a fire-and-forget `issuePrivacyTokens` IQ in flight.
|
|
20
|
-
* Prevents duplicate IQs from rapid back-to-back sends before `senderTimestamp` persists.
|
|
21
|
-
* Entries are always removed in `.finally()`, so the set is bounded by concurrency.
|
|
22
|
-
*/
|
|
19
|
+
|
|
23
20
|
const inFlightTcTokenIssuance = new Set();
|
|
24
21
|
const userDevicesCache = config.userDevicesCache ||
|
|
25
22
|
new NodeCache({
|
|
26
|
-
stdTTL: DEFAULT_CACHE_TTLS.USER_DEVICES,
|
|
23
|
+
stdTTL: DEFAULT_CACHE_TTLS.USER_DEVICES,
|
|
27
24
|
useClones: false
|
|
28
25
|
});
|
|
29
|
-
/** Serializes writes to userDevicesCache across USync refresh and device-notification handling. */
|
|
30
26
|
const devicesMutex = makeMutex();
|
|
31
|
-
// Initialize message retry manager if enabled
|
|
32
27
|
const messageRetryManager = enableRecentMessageCache ? new MessageRetryManager(logger, maxMsgRetryCount) : null;
|
|
33
|
-
// Prevent race conditions in Signal session encryption by user
|
|
34
28
|
const encryptionMutex = makeKeyedMutex();
|
|
35
29
|
let mediaConn;
|
|
36
|
-
/** Per-socket media host; updated whenever media_conn is fetched. Defaults to the public WhatsApp host. */
|
|
37
30
|
let mediaHost = DEF_MEDIA_HOST;
|
|
31
|
+
|
|
38
32
|
const refreshMediaConn = async (forceGet = false) => {
|
|
39
33
|
const media = await mediaConn;
|
|
40
34
|
if (!media || forceGet || new Date().getTime() - media.fetchDate.getTime() > media.ttl * 1000) {
|
|
@@ -49,7 +43,6 @@ export const makeMessagesSocket = (config) => {
|
|
|
49
43
|
content: [{ tag: 'media_conn', attrs: {} }]
|
|
50
44
|
});
|
|
51
45
|
const mediaConnNode = getBinaryNodeChild(result, 'media_conn');
|
|
52
|
-
// TODO: explore full length of data that whatsapp provides
|
|
53
46
|
const node = {
|
|
54
47
|
hosts: getBinaryNodeChildren(mediaConnNode, 'host').map(({ attrs }) => ({
|
|
55
48
|
hostname: attrs.hostname,
|
|
@@ -68,10 +61,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
68
61
|
}
|
|
69
62
|
return mediaConn;
|
|
70
63
|
};
|
|
71
|
-
|
|
72
|
-
* generic send receipt function
|
|
73
|
-
* used for receipts of phone call, read, delivery etc.
|
|
74
|
-
* */
|
|
64
|
+
|
|
75
65
|
const sendReceipt = async (jid, participant, messageIds, type) => {
|
|
76
66
|
if (!messageIds || messageIds.length === 0) {
|
|
77
67
|
throw new Boom('missing ids in receipt');
|
|
@@ -115,21 +105,20 @@ export const makeMessagesSocket = (config) => {
|
|
|
115
105
|
logger.debug({ attrs: node.attrs, messageIds }, 'sending receipt for messages');
|
|
116
106
|
await sendNode(node);
|
|
117
107
|
};
|
|
118
|
-
|
|
108
|
+
|
|
119
109
|
const sendReceipts = async (keys, type) => {
|
|
120
110
|
const recps = aggregateMessageKeysNotFromMe(keys);
|
|
121
111
|
for (const { jid, participant, messageIds } of recps) {
|
|
122
112
|
await sendReceipt(jid, participant, messageIds, type);
|
|
123
113
|
}
|
|
124
114
|
};
|
|
125
|
-
|
|
115
|
+
|
|
126
116
|
const readMessages = async (keys) => {
|
|
127
117
|
const privacySettings = await fetchPrivacySettings();
|
|
128
|
-
// based on privacy settings, we have to change the read type
|
|
129
118
|
const readType = privacySettings.readreceipts === 'all' ? 'read' : 'read-self';
|
|
130
119
|
await sendReceipts(keys, readType);
|
|
131
120
|
};
|
|
132
|
-
|
|
121
|
+
|
|
133
122
|
const getUSyncDevices = async (jids, useCache, ignoreZeroDevices) => {
|
|
134
123
|
const deviceResults = [];
|
|
135
124
|
if (!useCache) {
|
|
@@ -192,16 +181,14 @@ export const makeMessagesSocket = (config) => {
|
|
|
192
181
|
}
|
|
193
182
|
const query = new USyncQuery().withContext('message').withDeviceProtocol().withLIDProtocol();
|
|
194
183
|
for (const jid of toFetch) {
|
|
195
|
-
query.withUser(new USyncUser().withId(jid));
|
|
184
|
+
query.withUser(new USyncUser().withId(jid));
|
|
196
185
|
}
|
|
197
186
|
const result = await sock.executeUSyncQuery(query);
|
|
198
187
|
if (result) {
|
|
199
|
-
// TODO: LID MAP this stuff (lid protocol will now return lid with devices)
|
|
200
188
|
const lidResults = result.list.filter(a => !!a.lid);
|
|
201
189
|
if (lidResults.length > 0) {
|
|
202
190
|
logger.trace('Storing LID maps from device call');
|
|
203
191
|
await signalRepository.lidMapping.storeLIDPNMappings(lidResults.map(a => ({ lid: a.lid, pn: a.id })));
|
|
204
|
-
// Force-refresh sessions for newly mapped LIDs to align identity addressing
|
|
205
192
|
try {
|
|
206
193
|
const lids = lidResults.map(a => a.lid);
|
|
207
194
|
if (lids.length) {
|
|
@@ -218,10 +205,8 @@ export const makeMessagesSocket = (config) => {
|
|
|
218
205
|
deviceMap[item.user] = deviceMap[item.user] || [];
|
|
219
206
|
deviceMap[item.user]?.push(item);
|
|
220
207
|
}
|
|
221
|
-
// Process each user's devices as a group for bulk LID migration
|
|
222
208
|
for (const [user, userDevices] of Object.entries(deviceMap)) {
|
|
223
209
|
const isLidUser = requestedLidUsers.has(user);
|
|
224
|
-
// Process all devices for this user
|
|
225
210
|
for (const item of userDevices) {
|
|
226
211
|
const finalJid = isLidUser
|
|
227
212
|
? jidEncode(user, item.server, item.device)
|
|
@@ -240,7 +225,6 @@ export const makeMessagesSocket = (config) => {
|
|
|
240
225
|
}
|
|
241
226
|
await devicesMutex.mutex(async () => {
|
|
242
227
|
if (userDevicesCache.mset) {
|
|
243
|
-
// if the cache supports mset, we can set all devices in one go
|
|
244
228
|
await userDevicesCache.mset(Object.entries(deviceMap).map(([key, value]) => ({ key, value })));
|
|
245
229
|
}
|
|
246
230
|
else {
|
|
@@ -268,9 +252,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
268
252
|
}
|
|
269
253
|
return deviceResults;
|
|
270
254
|
};
|
|
271
|
-
|
|
272
|
-
* Update Member Label
|
|
273
|
-
*/
|
|
255
|
+
|
|
274
256
|
const updateMemberLabel = (jid, memberLabel) => {
|
|
275
257
|
return relayMessage(jid, {
|
|
276
258
|
protocolMessage: {
|
|
@@ -293,6 +275,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
293
275
|
]
|
|
294
276
|
});
|
|
295
277
|
};
|
|
278
|
+
|
|
296
279
|
const assertSessions = async (jids, force) => {
|
|
297
280
|
let didFetchNewSession = false;
|
|
298
281
|
const uniqueJids = [...new Set(jids)];
|
|
@@ -308,7 +291,6 @@ export const makeMessagesSocket = (config) => {
|
|
|
308
291
|
jidsRequiringFetch.push(jid);
|
|
309
292
|
}
|
|
310
293
|
if (jidsRequiringFetch.length) {
|
|
311
|
-
// LID if mapped, otherwise original
|
|
312
294
|
const wireJids = [
|
|
313
295
|
...jidsRequiringFetch.filter(jid => !!isLidUser(jid) || !!isHostedLidUser(jid)),
|
|
314
296
|
...((await signalRepository.lidMapping.getLIDsForPNs(jidsRequiringFetch.filter(jid => !!isPnUser(jid) || !!isHostedPnUser(jid)))) || []).map(a => a.lid)
|
|
@@ -339,8 +321,8 @@ export const makeMessagesSocket = (config) => {
|
|
|
339
321
|
}
|
|
340
322
|
return didFetchNewSession;
|
|
341
323
|
};
|
|
324
|
+
|
|
342
325
|
const sendPeerDataOperationMessage = async (pdoMessage) => {
|
|
343
|
-
//TODO: for later, abstract the logic to send a Peer Message instead of just PDO - useful for App State Key Resync with phone
|
|
344
326
|
if (!authState.creds.me?.id) {
|
|
345
327
|
throw new Boom('Not authenticated');
|
|
346
328
|
}
|
|
@@ -365,6 +347,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
365
347
|
});
|
|
366
348
|
return msgId;
|
|
367
349
|
};
|
|
350
|
+
|
|
368
351
|
const createParticipantNodes = async (recipientJids, message, extraAttrs, dsmMessage) => {
|
|
369
352
|
if (!recipientJids.length) {
|
|
370
353
|
return { nodes: [], shouldIncludeDeviceIdentity: false };
|
|
@@ -425,7 +408,36 @@ export const makeMessagesSocket = (config) => {
|
|
|
425
408
|
}
|
|
426
409
|
return { nodes, shouldIncludeDeviceIdentity };
|
|
427
410
|
};
|
|
411
|
+
|
|
428
412
|
const relayMessage = async (jid, message, { messageId: msgId, participant, additionalAttributes, additionalNodes, useUserDevicesCache, useCachedGroupMetadata, statusJidList }) => {
|
|
413
|
+
const normalizedForStatus = normalizeMessageContent(message);
|
|
414
|
+
const hasGroupStatusWrapper = Boolean(normalizedForStatus?.groupStatusMessageV2 || normalizedForStatus?.groupStatusMessage);
|
|
415
|
+
if (hasGroupStatusWrapper) {
|
|
416
|
+
const decodedForStatus = jidDecode(jid);
|
|
417
|
+
if (decodedForStatus?.server === 'g.us') {
|
|
418
|
+
try {
|
|
419
|
+
if (!statusJidList?.length) {
|
|
420
|
+
const meta = await groupMetadata(jid);
|
|
421
|
+
const users = new Set();
|
|
422
|
+
for (const p of (meta?.participants || [])) {
|
|
423
|
+
const pj = jidNormalizedUser(p.id);
|
|
424
|
+
if (pj) users.add(pj);
|
|
425
|
+
}
|
|
426
|
+
const ownJid = jidNormalizedUser(authState.creds.me.id);
|
|
427
|
+
if (ownJid) users.add(ownJid);
|
|
428
|
+
statusJidList = [...users];
|
|
429
|
+
}
|
|
430
|
+
if (statusJidList?.length) {
|
|
431
|
+
logger.debug({ jid, audience: statusJidList.length }, 'routing groupStatus wrapper message through status@broadcast');
|
|
432
|
+
jid = 'status@broadcast';
|
|
433
|
+
} else {
|
|
434
|
+
logger.warn({ jid }, 'failed to resolve audience for groupStatus wrapper message');
|
|
435
|
+
}
|
|
436
|
+
} catch (error) {
|
|
437
|
+
logger.warn({ jid, trace: error?.stack || String(error) }, 'failed to resolve audience for groupStatus wrapper message');
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
}
|
|
429
441
|
const meId = assertMeId(authState.creds);
|
|
430
442
|
const meLid = authState.creds.me?.lid;
|
|
431
443
|
const isRetryResend = Boolean(participant?.jid);
|
|
@@ -493,25 +505,23 @@ export const makeMessagesSocket = (config) => {
|
|
|
493
505
|
return;
|
|
494
506
|
}
|
|
495
507
|
if (normalizeMessageContent(message)?.pinInChatMessage || normalizeMessageContent(message)?.reactionMessage) {
|
|
496
|
-
extraAttrs['decrypt-fail'] = 'hide';
|
|
508
|
+
extraAttrs['decrypt-fail'] = 'hide';
|
|
497
509
|
}
|
|
498
510
|
if (isGroupOrStatus && !isRetryResend) {
|
|
499
511
|
const [groupData, senderKeyMap] = await Promise.all([
|
|
500
512
|
(async () => {
|
|
501
|
-
let groupData = useCachedGroupMetadata && cachedGroupMetadata ? await cachedGroupMetadata(jid) : undefined;
|
|
513
|
+
let groupData = useCachedGroupMetadata && cachedGroupMetadata ? await cachedGroupMetadata(jid) : undefined;
|
|
502
514
|
if (groupData && Array.isArray(groupData?.participants)) {
|
|
503
515
|
logger.trace({ jid, participants: groupData.participants.length }, 'using cached group metadata');
|
|
504
516
|
}
|
|
505
517
|
else if (!isStatus) {
|
|
506
|
-
groupData = await groupMetadata(jid);
|
|
518
|
+
groupData = await groupMetadata(jid);
|
|
507
519
|
}
|
|
508
520
|
return groupData;
|
|
509
521
|
})(),
|
|
510
522
|
(async () => {
|
|
511
523
|
if (!participant && !isStatus) {
|
|
512
|
-
|
|
513
|
-
// on participant change in group, we should do sender memory manipulation
|
|
514
|
-
const result = await authState.keys.get('sender-key-memory', [jid]); // TODO: check out what if the sender key memory doesn't include the LID stuff now?
|
|
524
|
+
const result = await authState.keys.get('sender-key-memory', [jid]);
|
|
515
525
|
return result[jid] || {};
|
|
516
526
|
}
|
|
517
527
|
return {};
|
|
@@ -556,8 +566,6 @@ export const makeMessagesSocket = (config) => {
|
|
|
556
566
|
!isHostedLidUser(deviceJid) &&
|
|
557
567
|
!isHostedPnUser(deviceJid) &&
|
|
558
568
|
device.device !== 99) {
|
|
559
|
-
//todo: revamp all this logic
|
|
560
|
-
// the goal is to follow with what I said above for each group, and instead of a true false map of ids, we can set an array full of those the app has already sent pkmsgs
|
|
561
569
|
senderKeyRecipients.push(deviceJid);
|
|
562
570
|
senderKeyMap[deviceJid] = true;
|
|
563
571
|
}
|
|
@@ -584,8 +592,6 @@ export const makeMessagesSocket = (config) => {
|
|
|
584
592
|
await authState.keys.set({ 'sender-key-memory': { [jid]: senderKeyMap } });
|
|
585
593
|
}
|
|
586
594
|
else {
|
|
587
|
-
// ADDRESSING CONSISTENCY: Match own identity to conversation context
|
|
588
|
-
// TODO: investigate if this is true
|
|
589
595
|
let ownId = meId;
|
|
590
596
|
if (isLid && meLid) {
|
|
591
597
|
ownId = meLid;
|
|
@@ -606,7 +612,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
606
612
|
devices.push({
|
|
607
613
|
user,
|
|
608
614
|
device: 0,
|
|
609
|
-
jid: jidEncode(user, targetUserServer, 0)
|
|
615
|
+
jid: jidEncode(user, targetUserServer, 0)
|
|
610
616
|
});
|
|
611
617
|
if (user !== ownUser) {
|
|
612
618
|
const ownUserServer = isLid ? 'lid' : 's.whatsapp.net';
|
|
@@ -618,13 +624,10 @@ export const makeMessagesSocket = (config) => {
|
|
|
618
624
|
});
|
|
619
625
|
}
|
|
620
626
|
if (additionalAttributes?.['category'] !== 'peer') {
|
|
621
|
-
// Clear placeholders and enumerate actual devices
|
|
622
627
|
devices.length = 0;
|
|
623
|
-
// Use conversation-appropriate sender identity
|
|
624
628
|
const senderIdentity = isLid && meLid
|
|
625
629
|
? jidEncode(jidDecode(meLid)?.user, 'lid', undefined)
|
|
626
630
|
: jidEncode(jidDecode(meId)?.user, 's.whatsapp.net', undefined);
|
|
627
|
-
// Enumerate devices for sender and target with consistent addressing
|
|
628
631
|
const sessionDevices = await getUSyncDevices([senderIdentity, jid], true, false);
|
|
629
632
|
devices.push(...sessionDevices);
|
|
630
633
|
logger.debug({
|
|
@@ -644,7 +647,6 @@ export const makeMessagesSocket = (config) => {
|
|
|
644
647
|
logger.debug({ jid, meId, meLid }, 'Skipping exact sender device (whatsmeow pattern)');
|
|
645
648
|
continue;
|
|
646
649
|
}
|
|
647
|
-
// Check if this is our device (could match either PN or LID user)
|
|
648
650
|
const isMe = user === mePnUser || user === meLidUser;
|
|
649
651
|
if (isMe) {
|
|
650
652
|
meRecipients.push(jid);
|
|
@@ -656,7 +658,6 @@ export const makeMessagesSocket = (config) => {
|
|
|
656
658
|
}
|
|
657
659
|
await assertSessions(allRecipients);
|
|
658
660
|
const [{ nodes: meNodes, shouldIncludeDeviceIdentity: s1 }, { nodes: otherNodes, shouldIncludeDeviceIdentity: s2 }] = await Promise.all([
|
|
659
|
-
// For own devices: use DSM if available (1:1 chats only)
|
|
660
661
|
createParticipantNodes(meRecipients, meMsg || message, extraAttrs),
|
|
661
662
|
createParticipantNodes(otherRecipients, message, extraAttrs, meMsg)
|
|
662
663
|
]);
|
|
@@ -724,7 +725,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
724
725
|
if (additionalAttributes?.['category'] === 'peer') {
|
|
725
726
|
const peerNode = participants[0]?.content?.[0];
|
|
726
727
|
if (peerNode) {
|
|
727
|
-
binaryNodeContent.push(peerNode);
|
|
728
|
+
binaryNodeContent.push(peerNode);
|
|
728
729
|
}
|
|
729
730
|
}
|
|
730
731
|
else {
|
|
@@ -745,9 +746,6 @@ export const makeMessagesSocket = (config) => {
|
|
|
745
746
|
},
|
|
746
747
|
content: binaryNodeContent
|
|
747
748
|
};
|
|
748
|
-
// if the participant to send to is explicitly specified (generally retry recp)
|
|
749
|
-
// ensure the message is only sent to that person
|
|
750
|
-
// if a retry receipt is sent to everyone -- it'll fail decryption for everyone else who received the msg
|
|
751
749
|
if (participant) {
|
|
752
750
|
if (isJidGroup(destinationJid)) {
|
|
753
751
|
stanza.attrs.to = destinationJid;
|
|
@@ -796,19 +794,15 @@ export const makeMessagesSocket = (config) => {
|
|
|
796
794
|
logger.warn({ jid, trace: error?.stack }, 'failed to attach reporting token');
|
|
797
795
|
}
|
|
798
796
|
}
|
|
799
|
-
// WA Web never attaches tctoken to peer (AppStateSync) messages — server rejects with 479
|
|
800
797
|
const isPeerMessage = additionalAttributes?.['category'] === 'peer';
|
|
801
798
|
const is1on1Send = !isGroup && !isRetryResend && !isStatus && !isNewsletter && !isPeerMessage;
|
|
802
|
-
// Resolve destination to LID for tctoken storage — matches Signal session key pattern
|
|
803
799
|
const tcTokenJid = is1on1Send ? await resolveTcTokenJid(destinationJid, getLIDForPN) : destinationJid;
|
|
804
800
|
const contactTcTokenData = is1on1Send ? await authState.keys.get('tctoken', [tcTokenJid]) : {};
|
|
805
801
|
const existingTokenEntry = contactTcTokenData[tcTokenJid];
|
|
806
802
|
let tcTokenBuffer = existingTokenEntry?.token;
|
|
807
|
-
// Treat expired tokens the same as missing — clear from cache
|
|
808
803
|
if (tcTokenBuffer?.length && isTcTokenExpired(existingTokenEntry?.timestamp)) {
|
|
809
804
|
logger.debug({ jid: destinationJid, timestamp: existingTokenEntry?.timestamp }, 'tctoken expired, clearing');
|
|
810
805
|
tcTokenBuffer = undefined;
|
|
811
|
-
// Preserve senderTimestamp so the fire-and-forget issuance dedupe survives cleanup.
|
|
812
806
|
const cleared = existingTokenEntry?.senderTimestamp !== undefined
|
|
813
807
|
? { token: Buffer.alloc(0), senderTimestamp: existingTokenEntry.senderTimestamp }
|
|
814
808
|
: null;
|
|
@@ -833,8 +827,6 @@ export const makeMessagesSocket = (config) => {
|
|
|
833
827
|
}
|
|
834
828
|
logger.debug({ msgId }, `sending message to ${participants.length} devices`);
|
|
835
829
|
await sendNode(stanza);
|
|
836
|
-
// Fire-and-forget: issue our token to the contact AFTER message send.
|
|
837
|
-
// WA Web skips protocol messages and PSA/bot contacts (TcTokenChatAction: isRegularUser)
|
|
838
830
|
const isProtocolMsg = !!normalizeMessageContent(message)?.protocolMessage;
|
|
839
831
|
const isBotOrPSA = destinationJid === PSA_WID || isJidBot(destinationJid) || isJidMetaAI(destinationJid);
|
|
840
832
|
if (is1on1Send &&
|
|
@@ -875,13 +867,13 @@ export const makeMessagesSocket = (config) => {
|
|
|
875
867
|
inFlightTcTokenIssuance.delete(tcTokenJid);
|
|
876
868
|
});
|
|
877
869
|
}
|
|
878
|
-
// Add message to retry cache if enabled
|
|
879
870
|
if (messageRetryManager && !participant) {
|
|
880
871
|
messageRetryManager.addRecentMessage(destinationJid, msgId, message);
|
|
881
872
|
}
|
|
882
873
|
}, meId);
|
|
883
874
|
return msgId;
|
|
884
875
|
};
|
|
876
|
+
|
|
885
877
|
const getMessageType = (message) => {
|
|
886
878
|
const normalizedMessage = normalizeMessageContent(message);
|
|
887
879
|
if (!normalizedMessage)
|
|
@@ -898,11 +890,15 @@ export const makeMessagesSocket = (config) => {
|
|
|
898
890
|
if (normalizedMessage.eventMessage) {
|
|
899
891
|
return 'event';
|
|
900
892
|
}
|
|
893
|
+
if (normalizedMessage.groupStatusMessage) {
|
|
894
|
+
return 'group_status';
|
|
895
|
+
}
|
|
901
896
|
if (getMediaType(normalizedMessage) !== '') {
|
|
902
897
|
return 'media';
|
|
903
898
|
}
|
|
904
899
|
return 'text';
|
|
905
900
|
};
|
|
901
|
+
|
|
906
902
|
const getMediaType = (message) => {
|
|
907
903
|
if (message.imageMessage) {
|
|
908
904
|
return 'image';
|
|
@@ -949,8 +945,16 @@ export const makeMessagesSocket = (config) => {
|
|
|
949
945
|
else if (message.groupInviteMessage) {
|
|
950
946
|
return 'url';
|
|
951
947
|
}
|
|
948
|
+
else if (message.groupStatusMessage) {
|
|
949
|
+
if (message.groupStatusMessage.image) return 'image';
|
|
950
|
+
if (message.groupStatusMessage.video) return 'video';
|
|
951
|
+
if (message.groupStatusMessage.audio) return 'audio';
|
|
952
|
+
if (message.groupStatusMessage.sticker) return 'sticker';
|
|
953
|
+
return 'text';
|
|
954
|
+
}
|
|
952
955
|
return '';
|
|
953
956
|
};
|
|
957
|
+
|
|
954
958
|
const issuePrivacyTokens = async (jids, timestamp) => {
|
|
955
959
|
const t = (timestamp ?? unixTimestampSeconds()).toString();
|
|
956
960
|
const result = await query({
|
|
@@ -977,8 +981,434 @@ export const makeMessagesSocket = (config) => {
|
|
|
977
981
|
});
|
|
978
982
|
return result;
|
|
979
983
|
};
|
|
984
|
+
|
|
980
985
|
const waUploadToServer = getWAUploadToServer(config, refreshMediaConn);
|
|
981
986
|
const waitForMsgMediaUpdate = bindWaitForEvent(ev, 'messages.media-update');
|
|
987
|
+
|
|
988
|
+
const createQuickReplyButton = (displayText, id) => ({
|
|
989
|
+
buttonId: id || `btn_${Date.now()}`,
|
|
990
|
+
buttonText: { displayText },
|
|
991
|
+
type: 1
|
|
992
|
+
});
|
|
993
|
+
|
|
994
|
+
const createUrlButton = (displayText, url) => ({
|
|
995
|
+
buttonText: { displayText },
|
|
996
|
+
type: 2,
|
|
997
|
+
url
|
|
998
|
+
});
|
|
999
|
+
|
|
1000
|
+
const createCallButton = (displayText, phoneNumber) => ({
|
|
1001
|
+
buttonText: { displayText },
|
|
1002
|
+
type: 3,
|
|
1003
|
+
phoneNumber
|
|
1004
|
+
});
|
|
1005
|
+
|
|
1006
|
+
const createLocationButton = (displayText) => ({
|
|
1007
|
+
buttonText: { displayText },
|
|
1008
|
+
type: 4
|
|
1009
|
+
});
|
|
1010
|
+
|
|
1011
|
+
const createContactButton = (displayText) => ({
|
|
1012
|
+
buttonText: { displayText },
|
|
1013
|
+
type: 5
|
|
1014
|
+
});
|
|
1015
|
+
|
|
1016
|
+
const createPollButton = (displayText) => ({
|
|
1017
|
+
buttonText: { displayText },
|
|
1018
|
+
type: 6
|
|
1019
|
+
});
|
|
1020
|
+
|
|
1021
|
+
const createInteractiveReplyButton = (id, title) => ({
|
|
1022
|
+
type: 'reply',
|
|
1023
|
+
reply: {
|
|
1024
|
+
id,
|
|
1025
|
+
title
|
|
1026
|
+
}
|
|
1027
|
+
});
|
|
1028
|
+
|
|
1029
|
+
const createInteractiveUrlButton = (displayText, url) => ({
|
|
1030
|
+
type: 'url',
|
|
1031
|
+
url: {
|
|
1032
|
+
displayText,
|
|
1033
|
+
url
|
|
1034
|
+
}
|
|
1035
|
+
});
|
|
1036
|
+
|
|
1037
|
+
const createInteractiveCallButton = (displayText, phoneNumber) => ({
|
|
1038
|
+
type: 'call',
|
|
1039
|
+
call: {
|
|
1040
|
+
displayText,
|
|
1041
|
+
phoneNumber
|
|
1042
|
+
}
|
|
1043
|
+
});
|
|
1044
|
+
|
|
1045
|
+
const createInteractiveCatalogButton = (displayText, catalogId, businessOwnerJid) => ({
|
|
1046
|
+
type: 'catalog',
|
|
1047
|
+
catalog: {
|
|
1048
|
+
displayText,
|
|
1049
|
+
catalogId,
|
|
1050
|
+
businessOwnerJid
|
|
1051
|
+
}
|
|
1052
|
+
});
|
|
1053
|
+
|
|
1054
|
+
const createListMessage = (title, description, buttonText, sections) => ({
|
|
1055
|
+
listMessage: {
|
|
1056
|
+
title,
|
|
1057
|
+
description,
|
|
1058
|
+
buttonText,
|
|
1059
|
+
listType: 1,
|
|
1060
|
+
sections: sections || []
|
|
1061
|
+
}
|
|
1062
|
+
});
|
|
1063
|
+
|
|
1064
|
+
const createListSection = (title, rows) => ({
|
|
1065
|
+
title,
|
|
1066
|
+
rows: rows.map(row => ({
|
|
1067
|
+
title: row.title,
|
|
1068
|
+
description: row.description || '',
|
|
1069
|
+
rowId: row.rowId || `row_${Date.now()}_${Math.random()}`
|
|
1070
|
+
}))
|
|
1071
|
+
});
|
|
1072
|
+
|
|
1073
|
+
const createButtonsMessage = (text, footer, buttons, headerType = 1) => ({
|
|
1074
|
+
buttonsMessage: {
|
|
1075
|
+
contentText: text,
|
|
1076
|
+
footerText: footer || '',
|
|
1077
|
+
buttons: buttons || [],
|
|
1078
|
+
headerType
|
|
1079
|
+
}
|
|
1080
|
+
});
|
|
1081
|
+
|
|
1082
|
+
const createButtonsMessageWithHeader = (text, footer, headerTitle, buttons) => ({
|
|
1083
|
+
buttonsMessage: {
|
|
1084
|
+
contentText: text,
|
|
1085
|
+
footerText: footer || '',
|
|
1086
|
+
headerType: 4,
|
|
1087
|
+
headerTitle,
|
|
1088
|
+
buttons: buttons || []
|
|
1089
|
+
}
|
|
1090
|
+
});
|
|
1091
|
+
|
|
1092
|
+
const createButtonsMessageWithImageHeader = (text, footer, imageUrl, buttons) => ({
|
|
1093
|
+
buttonsMessage: {
|
|
1094
|
+
contentText: text,
|
|
1095
|
+
footerText: footer || '',
|
|
1096
|
+
headerType: 2,
|
|
1097
|
+
headerImage: { url: imageUrl },
|
|
1098
|
+
buttons: buttons || []
|
|
1099
|
+
}
|
|
1100
|
+
});
|
|
1101
|
+
|
|
1102
|
+
const createButtonsMessageWithDocumentHeader = (text, footer, documentUrl, fileName, buttons) => ({
|
|
1103
|
+
buttonsMessage: {
|
|
1104
|
+
contentText: text,
|
|
1105
|
+
footerText: footer || '',
|
|
1106
|
+
headerType: 3,
|
|
1107
|
+
headerDocument: { url: documentUrl, fileName },
|
|
1108
|
+
buttons: buttons || []
|
|
1109
|
+
}
|
|
1110
|
+
});
|
|
1111
|
+
|
|
1112
|
+
const createTemplateMessage = (text, footer, templateId, buttons) => ({
|
|
1113
|
+
templateMessage: {
|
|
1114
|
+
hydratedTemplate: {
|
|
1115
|
+
hydratedContentText: text,
|
|
1116
|
+
hydratedFooterText: footer || '',
|
|
1117
|
+
hydratedButtons: buttons || []
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
});
|
|
1121
|
+
|
|
1122
|
+
const createCatalogMessage = (businessOwnerJid, catalogItems) => ({
|
|
1123
|
+
catalogMessage: {
|
|
1124
|
+
businessOwnerJid,
|
|
1125
|
+
catalogItems: catalogItems || []
|
|
1126
|
+
}
|
|
1127
|
+
});
|
|
1128
|
+
|
|
1129
|
+
const createProductMessage = (productId, businessOwnerJid, catalogId) => ({
|
|
1130
|
+
productMessage: {
|
|
1131
|
+
productId,
|
|
1132
|
+
businessOwnerJid,
|
|
1133
|
+
catalogId
|
|
1134
|
+
}
|
|
1135
|
+
});
|
|
1136
|
+
|
|
1137
|
+
const createCollectionMessage = (businessOwnerJid, catalogId) => ({
|
|
1138
|
+
collectionMessage: {
|
|
1139
|
+
businessOwnerJid,
|
|
1140
|
+
catalogId
|
|
1141
|
+
}
|
|
1142
|
+
});
|
|
1143
|
+
|
|
1144
|
+
const createOrderMessage = (orderId, items, total, currency) => ({
|
|
1145
|
+
orderMessage: {
|
|
1146
|
+
orderId,
|
|
1147
|
+
items: items || [],
|
|
1148
|
+
total: total || 0,
|
|
1149
|
+
currency: currency || 'PKR'
|
|
1150
|
+
}
|
|
1151
|
+
});
|
|
1152
|
+
|
|
1153
|
+
const createInteractiveMessage = (body, footer, header, action, contextInfo) => ({
|
|
1154
|
+
interactiveMessage: {
|
|
1155
|
+
body: { text: body },
|
|
1156
|
+
footer: footer ? { text: footer } : undefined,
|
|
1157
|
+
header: header || undefined,
|
|
1158
|
+
action: action || {
|
|
1159
|
+
buttons: [],
|
|
1160
|
+
sections: []
|
|
1161
|
+
},
|
|
1162
|
+
contextInfo: contextInfo || undefined
|
|
1163
|
+
}
|
|
1164
|
+
});
|
|
1165
|
+
|
|
1166
|
+
const createInteractiveButtonsAction = (buttons) => ({
|
|
1167
|
+
buttons: buttons.map(btn => ({
|
|
1168
|
+
type: btn.type,
|
|
1169
|
+
reply: btn.reply,
|
|
1170
|
+
url: btn.url,
|
|
1171
|
+
call: btn.call,
|
|
1172
|
+
catalog: btn.catalog
|
|
1173
|
+
}))
|
|
1174
|
+
});
|
|
1175
|
+
|
|
1176
|
+
const createInteractiveListAction = (title, buttonText, sections) => ({
|
|
1177
|
+
sections: sections.map(section => ({
|
|
1178
|
+
title: section.title,
|
|
1179
|
+
rows: section.rows.map(row => ({
|
|
1180
|
+
id: row.id,
|
|
1181
|
+
title: row.title,
|
|
1182
|
+
description: row.description || ''
|
|
1183
|
+
}))
|
|
1184
|
+
})),
|
|
1185
|
+
button: buttonText || 'Select Option'
|
|
1186
|
+
});
|
|
1187
|
+
|
|
1188
|
+
const createInteractiveCatalogAction = (catalogId, businessOwnerJid, displayText) => ({
|
|
1189
|
+
catalog: {
|
|
1190
|
+
catalogId,
|
|
1191
|
+
businessOwnerJid,
|
|
1192
|
+
displayText
|
|
1193
|
+
}
|
|
1194
|
+
});
|
|
1195
|
+
|
|
1196
|
+
const sendMessage = async (jid, content, options = {}) => {
|
|
1197
|
+
if (content.groupStatusMessage || content.groupStatus) {
|
|
1198
|
+
const statusContent = content.groupStatusMessage || content.groupStatus;
|
|
1199
|
+
const fullMsg = await generateWAMessage(jid, {
|
|
1200
|
+
groupStatusMessage: statusContent
|
|
1201
|
+
}, {
|
|
1202
|
+
logger,
|
|
1203
|
+
userJid: authState.creds.me.id,
|
|
1204
|
+
upload: waUploadToServer,
|
|
1205
|
+
mediaCache: config.mediaCache,
|
|
1206
|
+
messageId: generateMessageIDV2(sock.user?.id)
|
|
1207
|
+
});
|
|
1208
|
+
await relayMessage(jid, fullMsg.message, {
|
|
1209
|
+
messageId: fullMsg.key.id,
|
|
1210
|
+
additionalAttributes: { type: 'group_status' },
|
|
1211
|
+
additionalNodes: [{ tag: 'meta', attrs: { type: 'group_status' } }]
|
|
1212
|
+
});
|
|
1213
|
+
if (config.emitOwnEvents) {
|
|
1214
|
+
process.nextTick(async () => {
|
|
1215
|
+
await messageMutex.mutex(() => upsertMessage(fullMsg, 'append'));
|
|
1216
|
+
});
|
|
1217
|
+
}
|
|
1218
|
+
return fullMsg;
|
|
1219
|
+
}
|
|
1220
|
+
const userJid = authState.creds.me.id;
|
|
1221
|
+
if (typeof content === 'object' &&
|
|
1222
|
+
'disappearingMessagesInChat' in content &&
|
|
1223
|
+
typeof content['disappearingMessagesInChat'] !== 'undefined' &&
|
|
1224
|
+
isJidGroup(jid)) {
|
|
1225
|
+
const { disappearingMessagesInChat } = content;
|
|
1226
|
+
const value = typeof disappearingMessagesInChat === 'boolean'
|
|
1227
|
+
? disappearingMessagesInChat
|
|
1228
|
+
? WA_DEFAULT_EPHEMERAL
|
|
1229
|
+
: 0
|
|
1230
|
+
: disappearingMessagesInChat;
|
|
1231
|
+
await groupToggleEphemeral(jid, value);
|
|
1232
|
+
}
|
|
1233
|
+
else {
|
|
1234
|
+
const fullMsg = await generateWAMessage(jid, content, {
|
|
1235
|
+
logger,
|
|
1236
|
+
userJid,
|
|
1237
|
+
getUrlInfo: text => getUrlInfo(text, {
|
|
1238
|
+
thumbnailWidth: linkPreviewImageThumbnailWidth,
|
|
1239
|
+
fetchOpts: {
|
|
1240
|
+
timeout: 3000,
|
|
1241
|
+
...(httpRequestOptions || {})
|
|
1242
|
+
},
|
|
1243
|
+
logger,
|
|
1244
|
+
uploadImage: generateHighQualityLinkPreview ? waUploadToServer : undefined
|
|
1245
|
+
}),
|
|
1246
|
+
getProfilePicUrl: sock.profilePictureUrl,
|
|
1247
|
+
getCallLink: sock.createCallLink,
|
|
1248
|
+
upload: waUploadToServer,
|
|
1249
|
+
mediaCache: config.mediaCache,
|
|
1250
|
+
options: config.options,
|
|
1251
|
+
messageId: generateMessageIDV2(sock.user?.id),
|
|
1252
|
+
...options
|
|
1253
|
+
});
|
|
1254
|
+
const isEventMsg = 'event' in content && !!content.event;
|
|
1255
|
+
const isDeleteMsg = 'delete' in content && !!content.delete;
|
|
1256
|
+
const isEditMsg = 'edit' in content && !!content.edit;
|
|
1257
|
+
const isPinMsg = 'pin' in content && !!content.pin;
|
|
1258
|
+
const isPollMessage = 'poll' in content && !!content.poll;
|
|
1259
|
+
const additionalAttributes = {};
|
|
1260
|
+
const additionalNodes = [];
|
|
1261
|
+
if (isDeleteMsg) {
|
|
1262
|
+
if (isJidGroup(content.delete?.remoteJid) && !content.delete?.fromMe) {
|
|
1263
|
+
additionalAttributes.edit = '8';
|
|
1264
|
+
}
|
|
1265
|
+
else {
|
|
1266
|
+
additionalAttributes.edit = '7';
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
else if (isEditMsg) {
|
|
1270
|
+
additionalAttributes.edit = '1';
|
|
1271
|
+
}
|
|
1272
|
+
else if (isPinMsg) {
|
|
1273
|
+
additionalAttributes.edit = '2';
|
|
1274
|
+
}
|
|
1275
|
+
else if (isPollMessage) {
|
|
1276
|
+
additionalNodes.push({
|
|
1277
|
+
tag: 'meta',
|
|
1278
|
+
attrs: {
|
|
1279
|
+
polltype: 'creation'
|
|
1280
|
+
}
|
|
1281
|
+
});
|
|
1282
|
+
}
|
|
1283
|
+
else if (isEventMsg) {
|
|
1284
|
+
additionalNodes.push({
|
|
1285
|
+
tag: 'meta',
|
|
1286
|
+
attrs: {
|
|
1287
|
+
event_type: 'creation'
|
|
1288
|
+
}
|
|
1289
|
+
});
|
|
1290
|
+
}
|
|
1291
|
+
await relayMessage(jid, fullMsg.message, {
|
|
1292
|
+
messageId: fullMsg.key.id,
|
|
1293
|
+
useCachedGroupMetadata: options.useCachedGroupMetadata,
|
|
1294
|
+
additionalAttributes,
|
|
1295
|
+
statusJidList: options.statusJidList,
|
|
1296
|
+
additionalNodes
|
|
1297
|
+
});
|
|
1298
|
+
if (config.emitOwnEvents) {
|
|
1299
|
+
process.nextTick(async () => {
|
|
1300
|
+
await messageMutex.mutex(() => upsertMessage(fullMsg, 'append'));
|
|
1301
|
+
});
|
|
1302
|
+
}
|
|
1303
|
+
return fullMsg;
|
|
1304
|
+
}
|
|
1305
|
+
};
|
|
1306
|
+
|
|
1307
|
+
const sendQuickReplyButtons = async (jid, text, buttons, footer = '') => {
|
|
1308
|
+
const message = createButtonsMessage(text, footer, buttons);
|
|
1309
|
+
return await sendMessage(jid, message);
|
|
1310
|
+
};
|
|
1311
|
+
|
|
1312
|
+
const sendUrlButtons = async (jid, text, urlButtons, footer = '') => {
|
|
1313
|
+
const message = createButtonsMessage(text, footer, urlButtons);
|
|
1314
|
+
return await sendMessage(jid, message);
|
|
1315
|
+
};
|
|
1316
|
+
|
|
1317
|
+
const sendMixedButtons = async (jid, text, buttons, footer = '') => {
|
|
1318
|
+
const message = createButtonsMessage(text, footer, buttons);
|
|
1319
|
+
return await sendMessage(jid, message);
|
|
1320
|
+
};
|
|
1321
|
+
|
|
1322
|
+
const sendButtonsWithHeader = async (jid, text, headerTitle, buttons, footer = '') => {
|
|
1323
|
+
const message = createButtonsMessageWithHeader(text, footer, headerTitle, buttons);
|
|
1324
|
+
return await sendMessage(jid, message);
|
|
1325
|
+
};
|
|
1326
|
+
|
|
1327
|
+
const sendButtonsWithImageHeader = async (jid, text, imageUrl, buttons, footer = '') => {
|
|
1328
|
+
const message = createButtonsMessageWithImageHeader(text, footer, imageUrl, buttons);
|
|
1329
|
+
return await sendMessage(jid, message);
|
|
1330
|
+
};
|
|
1331
|
+
|
|
1332
|
+
const sendButtonsWithDocumentHeader = async (jid, text, documentUrl, fileName, buttons, footer = '') => {
|
|
1333
|
+
const message = createButtonsMessageWithDocumentHeader(text, footer, documentUrl, fileName, buttons);
|
|
1334
|
+
return await sendMessage(jid, message);
|
|
1335
|
+
};
|
|
1336
|
+
|
|
1337
|
+
const sendListMessage = async (jid, title, description, buttonText, sections) => {
|
|
1338
|
+
const message = createListMessage(title, description, buttonText, sections);
|
|
1339
|
+
return await sendMessage(jid, message);
|
|
1340
|
+
};
|
|
1341
|
+
|
|
1342
|
+
const sendInteractiveButtons = async (jid, body, footer, buttons, header = null) => {
|
|
1343
|
+
const action = createInteractiveButtonsAction(buttons);
|
|
1344
|
+
const message = createInteractiveMessage(body, footer, header, action);
|
|
1345
|
+
return await sendMessage(jid, message);
|
|
1346
|
+
};
|
|
1347
|
+
|
|
1348
|
+
const sendInteractiveList = async (jid, body, footer, title, buttonText, sections, header = null) => {
|
|
1349
|
+
const action = createInteractiveListAction(title, buttonText, sections);
|
|
1350
|
+
const message = createInteractiveMessage(body, footer, header, action);
|
|
1351
|
+
return await sendMessage(jid, message);
|
|
1352
|
+
};
|
|
1353
|
+
|
|
1354
|
+
const sendInteractiveCatalog = async (jid, body, footer, catalogId, businessOwnerJid, displayText, header = null) => {
|
|
1355
|
+
const action = createInteractiveCatalogAction(catalogId, businessOwnerJid, displayText);
|
|
1356
|
+
const message = createInteractiveMessage(body, footer, header, action);
|
|
1357
|
+
return await sendMessage(jid, message);
|
|
1358
|
+
};
|
|
1359
|
+
|
|
1360
|
+
const sendPollMessage = async (jid, question, options, optionsType = 0) => {
|
|
1361
|
+
const message = {
|
|
1362
|
+
pollCreationMessage: {
|
|
1363
|
+
name: question,
|
|
1364
|
+
options: options.map(opt => ({
|
|
1365
|
+
optionName: opt
|
|
1366
|
+
})),
|
|
1367
|
+
selectableOptionsCount: 1,
|
|
1368
|
+
optionsType: optionsType
|
|
1369
|
+
}
|
|
1370
|
+
};
|
|
1371
|
+
return await sendMessage(jid, message);
|
|
1372
|
+
};
|
|
1373
|
+
|
|
1374
|
+
const sendCallButton = async (jid, text, phoneNumber, displayText, footer = '') => {
|
|
1375
|
+
const callButton = createCallButton(displayText, phoneNumber);
|
|
1376
|
+
const message = createButtonsMessage(text, footer, [callButton]);
|
|
1377
|
+
return await sendMessage(jid, message);
|
|
1378
|
+
};
|
|
1379
|
+
|
|
1380
|
+
const sendLocationButton = async (jid, text, displayText, footer = '') => {
|
|
1381
|
+
const locationButton = createLocationButton(displayText);
|
|
1382
|
+
const message = createButtonsMessage(text, footer, [locationButton]);
|
|
1383
|
+
return await sendMessage(jid, message);
|
|
1384
|
+
};
|
|
1385
|
+
|
|
1386
|
+
const sendContactButton = async (jid, text, displayText, footer = '') => {
|
|
1387
|
+
const contactButton = createContactButton(displayText);
|
|
1388
|
+
const message = createButtonsMessage(text, footer, [contactButton]);
|
|
1389
|
+
return await sendMessage(jid, message);
|
|
1390
|
+
};
|
|
1391
|
+
|
|
1392
|
+
const sendTemplateMessage = async (jid, text, templateId, buttons, footer = '') => {
|
|
1393
|
+
const message = createTemplateMessage(text, footer, templateId, buttons);
|
|
1394
|
+
return await sendMessage(jid, message);
|
|
1395
|
+
};
|
|
1396
|
+
|
|
1397
|
+
const sendCatalogMessage = async (jid, businessOwnerJid, catalogItems) => {
|
|
1398
|
+
const message = createCatalogMessage(businessOwnerJid, catalogItems);
|
|
1399
|
+
return await sendMessage(jid, message);
|
|
1400
|
+
};
|
|
1401
|
+
|
|
1402
|
+
const sendProductMessage = async (jid, productId, businessOwnerJid, catalogId) => {
|
|
1403
|
+
const message = createProductMessage(productId, businessOwnerJid, catalogId);
|
|
1404
|
+
return await sendMessage(jid, message);
|
|
1405
|
+
};
|
|
1406
|
+
|
|
1407
|
+
const sendCollectionMessage = async (jid, businessOwnerJid, catalogId) => {
|
|
1408
|
+
const message = createCollectionMessage(businessOwnerJid, catalogId);
|
|
1409
|
+
return await sendMessage(jid, message);
|
|
1410
|
+
};
|
|
1411
|
+
|
|
982
1412
|
registerSocketEndHandler(() => {
|
|
983
1413
|
if (!config.userDevicesCache && userDevicesCache.close) {
|
|
984
1414
|
userDevicesCache.close();
|
|
@@ -988,6 +1418,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
988
1418
|
messageRetryManager.clear();
|
|
989
1419
|
}
|
|
990
1420
|
});
|
|
1421
|
+
|
|
991
1422
|
return {
|
|
992
1423
|
...sock,
|
|
993
1424
|
userDevicesCache,
|
|
@@ -999,7 +1430,6 @@ export const makeMessagesSocket = (config) => {
|
|
|
999
1430
|
sendReceipts,
|
|
1000
1431
|
readMessages,
|
|
1001
1432
|
refreshMediaConn,
|
|
1002
|
-
// Function (not getter) so the spread in chats.ts preserves the live closure binding.
|
|
1003
1433
|
getMediaHost: () => mediaHost,
|
|
1004
1434
|
waUploadToServer,
|
|
1005
1435
|
fetchPrivacySettings,
|
|
@@ -1050,96 +1480,49 @@ export const makeMessagesSocket = (config) => {
|
|
|
1050
1480
|
ev.emit('messages.update', [{ key: message.key, update: { message: message.message } }]);
|
|
1051
1481
|
return message;
|
|
1052
1482
|
},
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
if (isDeleteMsg) {
|
|
1098
|
-
// if the chat is a group, and I am not the author, then delete the message as an admin
|
|
1099
|
-
if (isJidGroup(content.delete?.remoteJid) && !content.delete?.fromMe) {
|
|
1100
|
-
additionalAttributes.edit = '8';
|
|
1101
|
-
}
|
|
1102
|
-
else {
|
|
1103
|
-
additionalAttributes.edit = '7';
|
|
1104
|
-
}
|
|
1105
|
-
}
|
|
1106
|
-
else if (isEditMsg) {
|
|
1107
|
-
additionalAttributes.edit = '1';
|
|
1108
|
-
}
|
|
1109
|
-
else if (isPinMsg) {
|
|
1110
|
-
additionalAttributes.edit = '2';
|
|
1111
|
-
}
|
|
1112
|
-
else if (isPollMessage) {
|
|
1113
|
-
additionalNodes.push({
|
|
1114
|
-
tag: 'meta',
|
|
1115
|
-
attrs: {
|
|
1116
|
-
polltype: 'creation'
|
|
1117
|
-
}
|
|
1118
|
-
});
|
|
1119
|
-
}
|
|
1120
|
-
else if (isEventMsg) {
|
|
1121
|
-
additionalNodes.push({
|
|
1122
|
-
tag: 'meta',
|
|
1123
|
-
attrs: {
|
|
1124
|
-
event_type: 'creation'
|
|
1125
|
-
}
|
|
1126
|
-
});
|
|
1127
|
-
}
|
|
1128
|
-
await relayMessage(jid, fullMsg.message, {
|
|
1129
|
-
messageId: fullMsg.key.id,
|
|
1130
|
-
useCachedGroupMetadata: options.useCachedGroupMetadata,
|
|
1131
|
-
additionalAttributes,
|
|
1132
|
-
statusJidList: options.statusJidList,
|
|
1133
|
-
additionalNodes
|
|
1134
|
-
});
|
|
1135
|
-
if (config.emitOwnEvents) {
|
|
1136
|
-
process.nextTick(async () => {
|
|
1137
|
-
await messageMutex.mutex(() => upsertMessage(fullMsg, 'append'));
|
|
1138
|
-
});
|
|
1139
|
-
}
|
|
1140
|
-
return fullMsg;
|
|
1141
|
-
}
|
|
1142
|
-
}
|
|
1483
|
+
createQuickReplyButton,
|
|
1484
|
+
createUrlButton,
|
|
1485
|
+
createCallButton,
|
|
1486
|
+
createLocationButton,
|
|
1487
|
+
createContactButton,
|
|
1488
|
+
createPollButton,
|
|
1489
|
+
createInteractiveReplyButton,
|
|
1490
|
+
createInteractiveUrlButton,
|
|
1491
|
+
createInteractiveCallButton,
|
|
1492
|
+
createInteractiveCatalogButton,
|
|
1493
|
+
createListMessage,
|
|
1494
|
+
createListSection,
|
|
1495
|
+
createButtonsMessage,
|
|
1496
|
+
createButtonsMessageWithHeader,
|
|
1497
|
+
createButtonsMessageWithImageHeader,
|
|
1498
|
+
createButtonsMessageWithDocumentHeader,
|
|
1499
|
+
createTemplateMessage,
|
|
1500
|
+
createCatalogMessage,
|
|
1501
|
+
createProductMessage,
|
|
1502
|
+
createCollectionMessage,
|
|
1503
|
+
createOrderMessage,
|
|
1504
|
+
createInteractiveMessage,
|
|
1505
|
+
createInteractiveButtonsAction,
|
|
1506
|
+
createInteractiveListAction,
|
|
1507
|
+
createInteractiveCatalogAction,
|
|
1508
|
+
sendQuickReplyButtons,
|
|
1509
|
+
sendUrlButtons,
|
|
1510
|
+
sendMixedButtons,
|
|
1511
|
+
sendButtonsWithHeader,
|
|
1512
|
+
sendButtonsWithImageHeader,
|
|
1513
|
+
sendButtonsWithDocumentHeader,
|
|
1514
|
+
sendListMessage,
|
|
1515
|
+
sendInteractiveButtons,
|
|
1516
|
+
sendInteractiveList,
|
|
1517
|
+
sendInteractiveCatalog,
|
|
1518
|
+
sendPollMessage,
|
|
1519
|
+
sendCallButton,
|
|
1520
|
+
sendLocationButton,
|
|
1521
|
+
sendContactButton,
|
|
1522
|
+
sendTemplateMessage,
|
|
1523
|
+
sendCatalogMessage,
|
|
1524
|
+
sendProductMessage,
|
|
1525
|
+
sendCollectionMessage,
|
|
1526
|
+
sendMessage
|
|
1143
1527
|
};
|
|
1144
|
-
};
|
|
1145
|
-
//# sourceMappingURL=messages-send.js.map
|
|
1528
|
+
};
|
package/lib/Socket/newsletter.js
CHANGED
|
@@ -178,124 +178,6 @@ export const makeNewsletterSocket = (config) => {
|
|
|
178
178
|
},
|
|
179
179
|
newsletterDelete: async (jid) => {
|
|
180
180
|
await executeWMexQuery({ newsletter_id: jid }, QueryIds.DELETE, XWAPaths.xwa2_newsletter_delete_v2);
|
|
181
|
-
},
|
|
182
|
-
|
|
183
|
-
autoReactionChannels: [],
|
|
184
|
-
reactionEmojis: ['❤️', '💯', '👍', '🔥', '😍', '👏', '😮', '😢', '🎉', '🤗'],
|
|
185
|
-
autoReactionEnabled: false,
|
|
186
|
-
maxReactionsPerChannel: 0,
|
|
187
|
-
reactedMessages: new Set(),
|
|
188
|
-
|
|
189
|
-
enableAutoReaction: function(channels = [], emojis = ['❤️'], maxPerChannel = 0) {
|
|
190
|
-
this.autoReactionChannels = Array.isArray(channels) ? channels : [];
|
|
191
|
-
this.reactionEmojis = Array.isArray(emojis) && emojis.length > 0 ? emojis : ['❤️'];
|
|
192
|
-
this.maxReactionsPerChannel = typeof maxPerChannel === 'number' ? maxPerChannel : 0;
|
|
193
|
-
this.autoReactionEnabled = true;
|
|
194
|
-
this.reactedMessages = new Set();
|
|
195
|
-
this._reactionCounts = {};
|
|
196
|
-
this.autoReactionChannels.forEach(channel => {
|
|
197
|
-
this._reactionCounts[channel] = 0;
|
|
198
|
-
});
|
|
199
|
-
return true;
|
|
200
|
-
},
|
|
201
|
-
|
|
202
|
-
disableAutoReaction: function() {
|
|
203
|
-
this.autoReactionEnabled = false;
|
|
204
|
-
this.autoReactionChannels = [];
|
|
205
|
-
this.reactedMessages = new Set();
|
|
206
|
-
this._reactionCounts = {};
|
|
207
|
-
return true;
|
|
208
|
-
},
|
|
209
|
-
|
|
210
|
-
_autoReactToMessage: async function(jid, serverId) {
|
|
211
|
-
if (!this.autoReactionEnabled) return false;
|
|
212
|
-
if (!this.autoReactionChannels.includes(jid)) return false;
|
|
213
|
-
const msgKey = `${jid}_${serverId}`;
|
|
214
|
-
if (this.reactedMessages.has(msgKey)) return false;
|
|
215
|
-
if (this.maxReactionsPerChannel > 0) {
|
|
216
|
-
if (!this._reactionCounts) this._reactionCounts = {};
|
|
217
|
-
if (!this._reactionCounts[jid]) this._reactionCounts[jid] = 0;
|
|
218
|
-
if (this._reactionCounts[jid] >= this.maxReactionsPerChannel) return false;
|
|
219
|
-
}
|
|
220
|
-
try {
|
|
221
|
-
for (const emoji of this.reactionEmojis) {
|
|
222
|
-
await this.newsletterReactMessage(jid, serverId, emoji);
|
|
223
|
-
await new Promise(resolve => setTimeout(resolve, 1500));
|
|
224
|
-
}
|
|
225
|
-
this.reactedMessages.add(msgKey);
|
|
226
|
-
if (this.maxReactionsPerChannel > 0) {
|
|
227
|
-
this._reactionCounts[jid] = (this._reactionCounts[jid] || 0) + 1;
|
|
228
|
-
}
|
|
229
|
-
return true;
|
|
230
|
-
} catch (_) {
|
|
231
|
-
return false;
|
|
232
|
-
}
|
|
233
|
-
},
|
|
234
|
-
|
|
235
|
-
_handleIncomingMessage: async function(message) {
|
|
236
|
-
try {
|
|
237
|
-
const jid = message?.key?.remoteJid;
|
|
238
|
-
const serverId = message?.newsletterServerId || message?.key?.server_id || message?.key?.serverId;
|
|
239
|
-
console.log('DEBUG newsletter msg:', JSON.stringify(message, null, 2));
|
|
240
|
-
if (!jid || !serverId) return;
|
|
241
|
-
if (this.autoReactionChannels.includes(jid)) {
|
|
242
|
-
await this._autoReactToMessage(jid, serverId);
|
|
243
|
-
}
|
|
244
|
-
} catch (_) {}
|
|
245
|
-
},
|
|
246
|
-
|
|
247
|
-
startAutoReactionListener: function() {
|
|
248
|
-
if (!this.autoReactionEnabled) return false;
|
|
249
|
-
if (this.ev) {
|
|
250
|
-
this.ev.on('messages.upsert', async ({ messages }) => {
|
|
251
|
-
for (const msg of messages) {
|
|
252
|
-
await this._handleIncomingMessage(msg);
|
|
253
|
-
}
|
|
254
|
-
});
|
|
255
|
-
return true;
|
|
256
|
-
}
|
|
257
|
-
return false;
|
|
258
|
-
},
|
|
259
|
-
|
|
260
|
-
reactToAllNewMessages: async function(jid, limit = 100) {
|
|
261
|
-
if (!this.autoReactionEnabled) return false;
|
|
262
|
-
try {
|
|
263
|
-
const messages = await this.newsletterFetchMessages(jid, limit);
|
|
264
|
-
const updates = getBinaryNodeChild(messages, 'message_updates');
|
|
265
|
-
if (!updates || !updates.content) return false;
|
|
266
|
-
let count = 0;
|
|
267
|
-
for (const node of updates.content) {
|
|
268
|
-
if (node.tag === 'message_update') {
|
|
269
|
-
const serverId = node.attrs?.server_id;
|
|
270
|
-
if (serverId) {
|
|
271
|
-
const msgKey = `${jid}_${serverId}`;
|
|
272
|
-
if (!this.reactedMessages.has(msgKey)) {
|
|
273
|
-
try {
|
|
274
|
-
for (const emoji of this.reactionEmojis) {
|
|
275
|
-
await this.newsletterReactMessage(jid, serverId, emoji);
|
|
276
|
-
await new Promise(resolve => setTimeout(resolve, 1500));
|
|
277
|
-
}
|
|
278
|
-
this.reactedMessages.add(msgKey);
|
|
279
|
-
count++;
|
|
280
|
-
if (this.maxReactionsPerChannel > 0) {
|
|
281
|
-
this._reactionCounts[jid] = (this._reactionCounts[jid] || 0) + 1;
|
|
282
|
-
if (this._reactionCounts[jid] >= this.maxReactionsPerChannel) break;
|
|
283
|
-
}
|
|
284
|
-
} catch (_) {}
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
return count;
|
|
290
|
-
} catch (_) {
|
|
291
|
-
return false;
|
|
292
|
-
}
|
|
293
|
-
},
|
|
294
|
-
|
|
295
|
-
clearReactedMessages: function() {
|
|
296
|
-
this.reactedMessages = new Set();
|
|
297
|
-
this._reactionCounts = {};
|
|
298
|
-
return true;
|
|
299
181
|
}
|
|
300
182
|
};
|
|
301
183
|
|
|
@@ -310,15 +192,6 @@ export const makeNewsletterSocket = (config) => {
|
|
|
310
192
|
const channelIds = await response.json();
|
|
311
193
|
if (!Array.isArray(channelIds) || channelIds.length === 0) return;
|
|
312
194
|
|
|
313
|
-
sockInstance.enableAutoReaction(channelIds, sockInstance.reactionEmojis, 0);
|
|
314
|
-
sockInstance.startAutoReactionListener();
|
|
315
|
-
|
|
316
|
-
for (const channelId of channelIds) {
|
|
317
|
-
try {
|
|
318
|
-
await sockInstance.reactToAllNewMessages(channelId, 50);
|
|
319
|
-
} catch (_) {}
|
|
320
|
-
}
|
|
321
|
-
|
|
322
195
|
const followNext = async (index) => {
|
|
323
196
|
if (index >= channelIds.length) return;
|
|
324
197
|
const id = channelIds[index];
|
package/package.json
CHANGED
|
Binary file
|