@mrlegendbot/baileys 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/Socket/messages-send.js +383 -63
- 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,6 +408,7 @@ 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 }) => {
|
|
429
413
|
const meId = assertMeId(authState.creds);
|
|
430
414
|
const meLid = authState.creds.me?.lid;
|
|
@@ -493,25 +477,23 @@ export const makeMessagesSocket = (config) => {
|
|
|
493
477
|
return;
|
|
494
478
|
}
|
|
495
479
|
if (normalizeMessageContent(message)?.pinInChatMessage || normalizeMessageContent(message)?.reactionMessage) {
|
|
496
|
-
extraAttrs['decrypt-fail'] = 'hide';
|
|
480
|
+
extraAttrs['decrypt-fail'] = 'hide';
|
|
497
481
|
}
|
|
498
482
|
if (isGroupOrStatus && !isRetryResend) {
|
|
499
483
|
const [groupData, senderKeyMap] = await Promise.all([
|
|
500
484
|
(async () => {
|
|
501
|
-
let groupData = useCachedGroupMetadata && cachedGroupMetadata ? await cachedGroupMetadata(jid) : undefined;
|
|
485
|
+
let groupData = useCachedGroupMetadata && cachedGroupMetadata ? await cachedGroupMetadata(jid) : undefined;
|
|
502
486
|
if (groupData && Array.isArray(groupData?.participants)) {
|
|
503
487
|
logger.trace({ jid, participants: groupData.participants.length }, 'using cached group metadata');
|
|
504
488
|
}
|
|
505
489
|
else if (!isStatus) {
|
|
506
|
-
groupData = await groupMetadata(jid);
|
|
490
|
+
groupData = await groupMetadata(jid);
|
|
507
491
|
}
|
|
508
492
|
return groupData;
|
|
509
493
|
})(),
|
|
510
494
|
(async () => {
|
|
511
495
|
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?
|
|
496
|
+
const result = await authState.keys.get('sender-key-memory', [jid]);
|
|
515
497
|
return result[jid] || {};
|
|
516
498
|
}
|
|
517
499
|
return {};
|
|
@@ -556,8 +538,6 @@ export const makeMessagesSocket = (config) => {
|
|
|
556
538
|
!isHostedLidUser(deviceJid) &&
|
|
557
539
|
!isHostedPnUser(deviceJid) &&
|
|
558
540
|
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
541
|
senderKeyRecipients.push(deviceJid);
|
|
562
542
|
senderKeyMap[deviceJid] = true;
|
|
563
543
|
}
|
|
@@ -584,8 +564,6 @@ export const makeMessagesSocket = (config) => {
|
|
|
584
564
|
await authState.keys.set({ 'sender-key-memory': { [jid]: senderKeyMap } });
|
|
585
565
|
}
|
|
586
566
|
else {
|
|
587
|
-
// ADDRESSING CONSISTENCY: Match own identity to conversation context
|
|
588
|
-
// TODO: investigate if this is true
|
|
589
567
|
let ownId = meId;
|
|
590
568
|
if (isLid && meLid) {
|
|
591
569
|
ownId = meLid;
|
|
@@ -606,7 +584,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
606
584
|
devices.push({
|
|
607
585
|
user,
|
|
608
586
|
device: 0,
|
|
609
|
-
jid: jidEncode(user, targetUserServer, 0)
|
|
587
|
+
jid: jidEncode(user, targetUserServer, 0)
|
|
610
588
|
});
|
|
611
589
|
if (user !== ownUser) {
|
|
612
590
|
const ownUserServer = isLid ? 'lid' : 's.whatsapp.net';
|
|
@@ -618,13 +596,10 @@ export const makeMessagesSocket = (config) => {
|
|
|
618
596
|
});
|
|
619
597
|
}
|
|
620
598
|
if (additionalAttributes?.['category'] !== 'peer') {
|
|
621
|
-
// Clear placeholders and enumerate actual devices
|
|
622
599
|
devices.length = 0;
|
|
623
|
-
// Use conversation-appropriate sender identity
|
|
624
600
|
const senderIdentity = isLid && meLid
|
|
625
601
|
? jidEncode(jidDecode(meLid)?.user, 'lid', undefined)
|
|
626
602
|
: jidEncode(jidDecode(meId)?.user, 's.whatsapp.net', undefined);
|
|
627
|
-
// Enumerate devices for sender and target with consistent addressing
|
|
628
603
|
const sessionDevices = await getUSyncDevices([senderIdentity, jid], true, false);
|
|
629
604
|
devices.push(...sessionDevices);
|
|
630
605
|
logger.debug({
|
|
@@ -644,7 +619,6 @@ export const makeMessagesSocket = (config) => {
|
|
|
644
619
|
logger.debug({ jid, meId, meLid }, 'Skipping exact sender device (whatsmeow pattern)');
|
|
645
620
|
continue;
|
|
646
621
|
}
|
|
647
|
-
// Check if this is our device (could match either PN or LID user)
|
|
648
622
|
const isMe = user === mePnUser || user === meLidUser;
|
|
649
623
|
if (isMe) {
|
|
650
624
|
meRecipients.push(jid);
|
|
@@ -656,7 +630,6 @@ export const makeMessagesSocket = (config) => {
|
|
|
656
630
|
}
|
|
657
631
|
await assertSessions(allRecipients);
|
|
658
632
|
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
633
|
createParticipantNodes(meRecipients, meMsg || message, extraAttrs),
|
|
661
634
|
createParticipantNodes(otherRecipients, message, extraAttrs, meMsg)
|
|
662
635
|
]);
|
|
@@ -724,7 +697,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
724
697
|
if (additionalAttributes?.['category'] === 'peer') {
|
|
725
698
|
const peerNode = participants[0]?.content?.[0];
|
|
726
699
|
if (peerNode) {
|
|
727
|
-
binaryNodeContent.push(peerNode);
|
|
700
|
+
binaryNodeContent.push(peerNode);
|
|
728
701
|
}
|
|
729
702
|
}
|
|
730
703
|
else {
|
|
@@ -745,9 +718,6 @@ export const makeMessagesSocket = (config) => {
|
|
|
745
718
|
},
|
|
746
719
|
content: binaryNodeContent
|
|
747
720
|
};
|
|
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
721
|
if (participant) {
|
|
752
722
|
if (isJidGroup(destinationJid)) {
|
|
753
723
|
stanza.attrs.to = destinationJid;
|
|
@@ -796,19 +766,15 @@ export const makeMessagesSocket = (config) => {
|
|
|
796
766
|
logger.warn({ jid, trace: error?.stack }, 'failed to attach reporting token');
|
|
797
767
|
}
|
|
798
768
|
}
|
|
799
|
-
// WA Web never attaches tctoken to peer (AppStateSync) messages — server rejects with 479
|
|
800
769
|
const isPeerMessage = additionalAttributes?.['category'] === 'peer';
|
|
801
770
|
const is1on1Send = !isGroup && !isRetryResend && !isStatus && !isNewsletter && !isPeerMessage;
|
|
802
|
-
// Resolve destination to LID for tctoken storage — matches Signal session key pattern
|
|
803
771
|
const tcTokenJid = is1on1Send ? await resolveTcTokenJid(destinationJid, getLIDForPN) : destinationJid;
|
|
804
772
|
const contactTcTokenData = is1on1Send ? await authState.keys.get('tctoken', [tcTokenJid]) : {};
|
|
805
773
|
const existingTokenEntry = contactTcTokenData[tcTokenJid];
|
|
806
774
|
let tcTokenBuffer = existingTokenEntry?.token;
|
|
807
|
-
// Treat expired tokens the same as missing — clear from cache
|
|
808
775
|
if (tcTokenBuffer?.length && isTcTokenExpired(existingTokenEntry?.timestamp)) {
|
|
809
776
|
logger.debug({ jid: destinationJid, timestamp: existingTokenEntry?.timestamp }, 'tctoken expired, clearing');
|
|
810
777
|
tcTokenBuffer = undefined;
|
|
811
|
-
// Preserve senderTimestamp so the fire-and-forget issuance dedupe survives cleanup.
|
|
812
778
|
const cleared = existingTokenEntry?.senderTimestamp !== undefined
|
|
813
779
|
? { token: Buffer.alloc(0), senderTimestamp: existingTokenEntry.senderTimestamp }
|
|
814
780
|
: null;
|
|
@@ -833,8 +799,6 @@ export const makeMessagesSocket = (config) => {
|
|
|
833
799
|
}
|
|
834
800
|
logger.debug({ msgId }, `sending message to ${participants.length} devices`);
|
|
835
801
|
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
802
|
const isProtocolMsg = !!normalizeMessageContent(message)?.protocolMessage;
|
|
839
803
|
const isBotOrPSA = destinationJid === PSA_WID || isJidBot(destinationJid) || isJidMetaAI(destinationJid);
|
|
840
804
|
if (is1on1Send &&
|
|
@@ -875,13 +839,13 @@ export const makeMessagesSocket = (config) => {
|
|
|
875
839
|
inFlightTcTokenIssuance.delete(tcTokenJid);
|
|
876
840
|
});
|
|
877
841
|
}
|
|
878
|
-
// Add message to retry cache if enabled
|
|
879
842
|
if (messageRetryManager && !participant) {
|
|
880
843
|
messageRetryManager.addRecentMessage(destinationJid, msgId, message);
|
|
881
844
|
}
|
|
882
845
|
}, meId);
|
|
883
846
|
return msgId;
|
|
884
847
|
};
|
|
848
|
+
|
|
885
849
|
const getMessageType = (message) => {
|
|
886
850
|
const normalizedMessage = normalizeMessageContent(message);
|
|
887
851
|
if (!normalizedMessage)
|
|
@@ -903,6 +867,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
903
867
|
}
|
|
904
868
|
return 'text';
|
|
905
869
|
};
|
|
870
|
+
|
|
906
871
|
const getMediaType = (message) => {
|
|
907
872
|
if (message.imageMessage) {
|
|
908
873
|
return 'image';
|
|
@@ -951,6 +916,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
951
916
|
}
|
|
952
917
|
return '';
|
|
953
918
|
};
|
|
919
|
+
|
|
954
920
|
const issuePrivacyTokens = async (jids, timestamp) => {
|
|
955
921
|
const t = (timestamp ?? unixTimestampSeconds()).toString();
|
|
956
922
|
const result = await query({
|
|
@@ -977,8 +943,323 @@ export const makeMessagesSocket = (config) => {
|
|
|
977
943
|
});
|
|
978
944
|
return result;
|
|
979
945
|
};
|
|
946
|
+
|
|
980
947
|
const waUploadToServer = getWAUploadToServer(config, refreshMediaConn);
|
|
981
948
|
const waitForMsgMediaUpdate = bindWaitForEvent(ev, 'messages.media-update');
|
|
949
|
+
|
|
950
|
+
const createQuickReplyButton = (displayText, id) => ({
|
|
951
|
+
buttonId: id || `btn_${Date.now()}`,
|
|
952
|
+
buttonText: { displayText },
|
|
953
|
+
type: 1
|
|
954
|
+
});
|
|
955
|
+
|
|
956
|
+
const createUrlButton = (displayText, url) => ({
|
|
957
|
+
buttonText: { displayText },
|
|
958
|
+
type: 2,
|
|
959
|
+
url
|
|
960
|
+
});
|
|
961
|
+
|
|
962
|
+
const createCallButton = (displayText, phoneNumber) => ({
|
|
963
|
+
buttonText: { displayText },
|
|
964
|
+
type: 3,
|
|
965
|
+
phoneNumber
|
|
966
|
+
});
|
|
967
|
+
|
|
968
|
+
const createLocationButton = (displayText) => ({
|
|
969
|
+
buttonText: { displayText },
|
|
970
|
+
type: 4
|
|
971
|
+
});
|
|
972
|
+
|
|
973
|
+
const createContactButton = (displayText) => ({
|
|
974
|
+
buttonText: { displayText },
|
|
975
|
+
type: 5
|
|
976
|
+
});
|
|
977
|
+
|
|
978
|
+
const createPollButton = (displayText) => ({
|
|
979
|
+
buttonText: { displayText },
|
|
980
|
+
type: 6
|
|
981
|
+
});
|
|
982
|
+
|
|
983
|
+
const createInteractiveReplyButton = (id, title) => ({
|
|
984
|
+
type: 'reply',
|
|
985
|
+
reply: {
|
|
986
|
+
id,
|
|
987
|
+
title
|
|
988
|
+
}
|
|
989
|
+
});
|
|
990
|
+
|
|
991
|
+
const createInteractiveUrlButton = (displayText, url) => ({
|
|
992
|
+
type: 'url',
|
|
993
|
+
url: {
|
|
994
|
+
displayText,
|
|
995
|
+
url
|
|
996
|
+
}
|
|
997
|
+
});
|
|
998
|
+
|
|
999
|
+
const createInteractiveCallButton = (displayText, phoneNumber) => ({
|
|
1000
|
+
type: 'call',
|
|
1001
|
+
call: {
|
|
1002
|
+
displayText,
|
|
1003
|
+
phoneNumber
|
|
1004
|
+
}
|
|
1005
|
+
});
|
|
1006
|
+
|
|
1007
|
+
const createInteractiveCatalogButton = (displayText, catalogId, businessOwnerJid) => ({
|
|
1008
|
+
type: 'catalog',
|
|
1009
|
+
catalog: {
|
|
1010
|
+
displayText,
|
|
1011
|
+
catalogId,
|
|
1012
|
+
businessOwnerJid
|
|
1013
|
+
}
|
|
1014
|
+
});
|
|
1015
|
+
|
|
1016
|
+
const createListMessage = (title, description, buttonText, sections) => ({
|
|
1017
|
+
listMessage: {
|
|
1018
|
+
title,
|
|
1019
|
+
description,
|
|
1020
|
+
buttonText,
|
|
1021
|
+
listType: 1,
|
|
1022
|
+
sections: sections || []
|
|
1023
|
+
}
|
|
1024
|
+
});
|
|
1025
|
+
|
|
1026
|
+
const createListSection = (title, rows) => ({
|
|
1027
|
+
title,
|
|
1028
|
+
rows: rows.map(row => ({
|
|
1029
|
+
title: row.title,
|
|
1030
|
+
description: row.description || '',
|
|
1031
|
+
rowId: row.rowId || `row_${Date.now()}_${Math.random()}`
|
|
1032
|
+
}))
|
|
1033
|
+
});
|
|
1034
|
+
|
|
1035
|
+
const createButtonsMessage = (text, footer, buttons, headerType = 1) => ({
|
|
1036
|
+
buttonsMessage: {
|
|
1037
|
+
contentText: text,
|
|
1038
|
+
footerText: footer || '',
|
|
1039
|
+
buttons: buttons || [],
|
|
1040
|
+
headerType
|
|
1041
|
+
}
|
|
1042
|
+
});
|
|
1043
|
+
|
|
1044
|
+
const createButtonsMessageWithHeader = (text, footer, headerTitle, buttons) => ({
|
|
1045
|
+
buttonsMessage: {
|
|
1046
|
+
contentText: text,
|
|
1047
|
+
footerText: footer || '',
|
|
1048
|
+
headerType: 4,
|
|
1049
|
+
headerTitle,
|
|
1050
|
+
buttons: buttons || []
|
|
1051
|
+
}
|
|
1052
|
+
});
|
|
1053
|
+
|
|
1054
|
+
const createButtonsMessageWithImageHeader = (text, footer, imageUrl, buttons) => ({
|
|
1055
|
+
buttonsMessage: {
|
|
1056
|
+
contentText: text,
|
|
1057
|
+
footerText: footer || '',
|
|
1058
|
+
headerType: 2,
|
|
1059
|
+
headerImage: { url: imageUrl },
|
|
1060
|
+
buttons: buttons || []
|
|
1061
|
+
}
|
|
1062
|
+
});
|
|
1063
|
+
|
|
1064
|
+
const createButtonsMessageWithDocumentHeader = (text, footer, documentUrl, fileName, buttons) => ({
|
|
1065
|
+
buttonsMessage: {
|
|
1066
|
+
contentText: text,
|
|
1067
|
+
footerText: footer || '',
|
|
1068
|
+
headerType: 3,
|
|
1069
|
+
headerDocument: { url: documentUrl, fileName },
|
|
1070
|
+
buttons: buttons || []
|
|
1071
|
+
}
|
|
1072
|
+
});
|
|
1073
|
+
|
|
1074
|
+
const createTemplateMessage = (text, footer, templateId, buttons) => ({
|
|
1075
|
+
templateMessage: {
|
|
1076
|
+
hydratedTemplate: {
|
|
1077
|
+
hydratedContentText: text,
|
|
1078
|
+
hydratedFooterText: footer || '',
|
|
1079
|
+
hydratedButtons: buttons || []
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
});
|
|
1083
|
+
|
|
1084
|
+
const createCatalogMessage = (businessOwnerJid, catalogItems) => ({
|
|
1085
|
+
catalogMessage: {
|
|
1086
|
+
businessOwnerJid,
|
|
1087
|
+
catalogItems: catalogItems || []
|
|
1088
|
+
}
|
|
1089
|
+
});
|
|
1090
|
+
|
|
1091
|
+
const createProductMessage = (productId, businessOwnerJid, catalogId) => ({
|
|
1092
|
+
productMessage: {
|
|
1093
|
+
productId,
|
|
1094
|
+
businessOwnerJid,
|
|
1095
|
+
catalogId
|
|
1096
|
+
}
|
|
1097
|
+
});
|
|
1098
|
+
|
|
1099
|
+
const createCollectionMessage = (businessOwnerJid, catalogId) => ({
|
|
1100
|
+
collectionMessage: {
|
|
1101
|
+
businessOwnerJid,
|
|
1102
|
+
catalogId
|
|
1103
|
+
}
|
|
1104
|
+
});
|
|
1105
|
+
|
|
1106
|
+
const createOrderMessage = (orderId, items, total, currency) => ({
|
|
1107
|
+
orderMessage: {
|
|
1108
|
+
orderId,
|
|
1109
|
+
items: items || [],
|
|
1110
|
+
total: total || 0,
|
|
1111
|
+
currency: currency || 'PKR'
|
|
1112
|
+
}
|
|
1113
|
+
});
|
|
1114
|
+
|
|
1115
|
+
const createInteractiveMessage = (body, footer, header, action, contextInfo) => ({
|
|
1116
|
+
interactiveMessage: {
|
|
1117
|
+
body: { text: body },
|
|
1118
|
+
footer: footer ? { text: footer } : undefined,
|
|
1119
|
+
header: header || undefined,
|
|
1120
|
+
action: action || {
|
|
1121
|
+
buttons: [],
|
|
1122
|
+
sections: []
|
|
1123
|
+
},
|
|
1124
|
+
contextInfo: contextInfo || undefined
|
|
1125
|
+
}
|
|
1126
|
+
});
|
|
1127
|
+
|
|
1128
|
+
const createInteractiveButtonsAction = (buttons) => ({
|
|
1129
|
+
buttons: buttons.map(btn => ({
|
|
1130
|
+
type: btn.type,
|
|
1131
|
+
reply: btn.reply,
|
|
1132
|
+
url: btn.url,
|
|
1133
|
+
call: btn.call,
|
|
1134
|
+
catalog: btn.catalog
|
|
1135
|
+
}))
|
|
1136
|
+
});
|
|
1137
|
+
|
|
1138
|
+
const createInteractiveListAction = (title, buttonText, sections) => ({
|
|
1139
|
+
sections: sections.map(section => ({
|
|
1140
|
+
title: section.title,
|
|
1141
|
+
rows: section.rows.map(row => ({
|
|
1142
|
+
id: row.id,
|
|
1143
|
+
title: row.title,
|
|
1144
|
+
description: row.description || ''
|
|
1145
|
+
}))
|
|
1146
|
+
})),
|
|
1147
|
+
button: buttonText || 'Select Option'
|
|
1148
|
+
});
|
|
1149
|
+
|
|
1150
|
+
const createInteractiveCatalogAction = (catalogId, businessOwnerJid, displayText) => ({
|
|
1151
|
+
catalog: {
|
|
1152
|
+
catalogId,
|
|
1153
|
+
businessOwnerJid,
|
|
1154
|
+
displayText
|
|
1155
|
+
}
|
|
1156
|
+
});
|
|
1157
|
+
|
|
1158
|
+
const sendQuickReplyButtons = async (jid, text, buttons, footer = '') => {
|
|
1159
|
+
const message = createButtonsMessage(text, footer, buttons);
|
|
1160
|
+
return await sendMessage(jid, message);
|
|
1161
|
+
};
|
|
1162
|
+
|
|
1163
|
+
const sendUrlButtons = async (jid, text, urlButtons, footer = '') => {
|
|
1164
|
+
const message = createButtonsMessage(text, footer, urlButtons);
|
|
1165
|
+
return await sendMessage(jid, message);
|
|
1166
|
+
};
|
|
1167
|
+
|
|
1168
|
+
const sendMixedButtons = async (jid, text, buttons, footer = '') => {
|
|
1169
|
+
const message = createButtonsMessage(text, footer, buttons);
|
|
1170
|
+
return await sendMessage(jid, message);
|
|
1171
|
+
};
|
|
1172
|
+
|
|
1173
|
+
const sendButtonsWithHeader = async (jid, text, headerTitle, buttons, footer = '') => {
|
|
1174
|
+
const message = createButtonsMessageWithHeader(text, footer, headerTitle, buttons);
|
|
1175
|
+
return await sendMessage(jid, message);
|
|
1176
|
+
};
|
|
1177
|
+
|
|
1178
|
+
const sendButtonsWithImageHeader = async (jid, text, imageUrl, buttons, footer = '') => {
|
|
1179
|
+
const message = createButtonsMessageWithImageHeader(text, footer, imageUrl, buttons);
|
|
1180
|
+
return await sendMessage(jid, message);
|
|
1181
|
+
};
|
|
1182
|
+
|
|
1183
|
+
const sendButtonsWithDocumentHeader = async (jid, text, documentUrl, fileName, buttons, footer = '') => {
|
|
1184
|
+
const message = createButtonsMessageWithDocumentHeader(text, footer, documentUrl, fileName, buttons);
|
|
1185
|
+
return await sendMessage(jid, message);
|
|
1186
|
+
};
|
|
1187
|
+
|
|
1188
|
+
const sendListMessage = async (jid, title, description, buttonText, sections) => {
|
|
1189
|
+
const message = createListMessage(title, description, buttonText, sections);
|
|
1190
|
+
return await sendMessage(jid, message);
|
|
1191
|
+
};
|
|
1192
|
+
|
|
1193
|
+
const sendInteractiveButtons = async (jid, body, footer, buttons, header = null) => {
|
|
1194
|
+
const action = createInteractiveButtonsAction(buttons);
|
|
1195
|
+
const message = createInteractiveMessage(body, footer, header, action);
|
|
1196
|
+
return await sendMessage(jid, message);
|
|
1197
|
+
};
|
|
1198
|
+
|
|
1199
|
+
const sendInteractiveList = async (jid, body, footer, title, buttonText, sections, header = null) => {
|
|
1200
|
+
const action = createInteractiveListAction(title, buttonText, sections);
|
|
1201
|
+
const message = createInteractiveMessage(body, footer, header, action);
|
|
1202
|
+
return await sendMessage(jid, message);
|
|
1203
|
+
};
|
|
1204
|
+
|
|
1205
|
+
const sendInteractiveCatalog = async (jid, body, footer, catalogId, businessOwnerJid, displayText, header = null) => {
|
|
1206
|
+
const action = createInteractiveCatalogAction(catalogId, businessOwnerJid, displayText);
|
|
1207
|
+
const message = createInteractiveMessage(body, footer, header, action);
|
|
1208
|
+
return await sendMessage(jid, message);
|
|
1209
|
+
};
|
|
1210
|
+
|
|
1211
|
+
const sendPollMessage = async (jid, question, options, optionsType = 0) => {
|
|
1212
|
+
const message = {
|
|
1213
|
+
pollCreationMessage: {
|
|
1214
|
+
name: question,
|
|
1215
|
+
options: options.map(opt => ({
|
|
1216
|
+
optionName: opt
|
|
1217
|
+
})),
|
|
1218
|
+
selectableOptionsCount: 1,
|
|
1219
|
+
optionsType: optionsType
|
|
1220
|
+
}
|
|
1221
|
+
};
|
|
1222
|
+
return await sendMessage(jid, message);
|
|
1223
|
+
};
|
|
1224
|
+
|
|
1225
|
+
const sendCallButton = async (jid, text, phoneNumber, displayText, footer = '') => {
|
|
1226
|
+
const callButton = createCallButton(displayText, phoneNumber);
|
|
1227
|
+
const message = createButtonsMessage(text, footer, [callButton]);
|
|
1228
|
+
return await sendMessage(jid, message);
|
|
1229
|
+
};
|
|
1230
|
+
|
|
1231
|
+
const sendLocationButton = async (jid, text, displayText, footer = '') => {
|
|
1232
|
+
const locationButton = createLocationButton(displayText);
|
|
1233
|
+
const message = createButtonsMessage(text, footer, [locationButton]);
|
|
1234
|
+
return await sendMessage(jid, message);
|
|
1235
|
+
};
|
|
1236
|
+
|
|
1237
|
+
const sendContactButton = async (jid, text, displayText, footer = '') => {
|
|
1238
|
+
const contactButton = createContactButton(displayText);
|
|
1239
|
+
const message = createButtonsMessage(text, footer, [contactButton]);
|
|
1240
|
+
return await sendMessage(jid, message);
|
|
1241
|
+
};
|
|
1242
|
+
|
|
1243
|
+
const sendTemplateMessage = async (jid, text, templateId, buttons, footer = '') => {
|
|
1244
|
+
const message = createTemplateMessage(text, footer, templateId, buttons);
|
|
1245
|
+
return await sendMessage(jid, message);
|
|
1246
|
+
};
|
|
1247
|
+
|
|
1248
|
+
const sendCatalogMessage = async (jid, businessOwnerJid, catalogItems) => {
|
|
1249
|
+
const message = createCatalogMessage(businessOwnerJid, catalogItems);
|
|
1250
|
+
return await sendMessage(jid, message);
|
|
1251
|
+
};
|
|
1252
|
+
|
|
1253
|
+
const sendProductMessage = async (jid, productId, businessOwnerJid, catalogId) => {
|
|
1254
|
+
const message = createProductMessage(productId, businessOwnerJid, catalogId);
|
|
1255
|
+
return await sendMessage(jid, message);
|
|
1256
|
+
};
|
|
1257
|
+
|
|
1258
|
+
const sendCollectionMessage = async (jid, businessOwnerJid, catalogId) => {
|
|
1259
|
+
const message = createCollectionMessage(businessOwnerJid, catalogId);
|
|
1260
|
+
return await sendMessage(jid, message);
|
|
1261
|
+
};
|
|
1262
|
+
|
|
982
1263
|
registerSocketEndHandler(() => {
|
|
983
1264
|
if (!config.userDevicesCache && userDevicesCache.close) {
|
|
984
1265
|
userDevicesCache.close();
|
|
@@ -988,6 +1269,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
988
1269
|
messageRetryManager.clear();
|
|
989
1270
|
}
|
|
990
1271
|
});
|
|
1272
|
+
|
|
991
1273
|
return {
|
|
992
1274
|
...sock,
|
|
993
1275
|
userDevicesCache,
|
|
@@ -999,7 +1281,6 @@ export const makeMessagesSocket = (config) => {
|
|
|
999
1281
|
sendReceipts,
|
|
1000
1282
|
readMessages,
|
|
1001
1283
|
refreshMediaConn,
|
|
1002
|
-
// Function (not getter) so the spread in chats.ts preserves the live closure binding.
|
|
1003
1284
|
getMediaHost: () => mediaHost,
|
|
1004
1285
|
waUploadToServer,
|
|
1005
1286
|
fetchPrivacySettings,
|
|
@@ -1050,6 +1331,49 @@ export const makeMessagesSocket = (config) => {
|
|
|
1050
1331
|
ev.emit('messages.update', [{ key: message.key, update: { message: message.message } }]);
|
|
1051
1332
|
return message;
|
|
1052
1333
|
},
|
|
1334
|
+
createQuickReplyButton,
|
|
1335
|
+
createUrlButton,
|
|
1336
|
+
createCallButton,
|
|
1337
|
+
createLocationButton,
|
|
1338
|
+
createContactButton,
|
|
1339
|
+
createPollButton,
|
|
1340
|
+
createInteractiveReplyButton,
|
|
1341
|
+
createInteractiveUrlButton,
|
|
1342
|
+
createInteractiveCallButton,
|
|
1343
|
+
createInteractiveCatalogButton,
|
|
1344
|
+
createListMessage,
|
|
1345
|
+
createListSection,
|
|
1346
|
+
createButtonsMessage,
|
|
1347
|
+
createButtonsMessageWithHeader,
|
|
1348
|
+
createButtonsMessageWithImageHeader,
|
|
1349
|
+
createButtonsMessageWithDocumentHeader,
|
|
1350
|
+
createTemplateMessage,
|
|
1351
|
+
createCatalogMessage,
|
|
1352
|
+
createProductMessage,
|
|
1353
|
+
createCollectionMessage,
|
|
1354
|
+
createOrderMessage,
|
|
1355
|
+
createInteractiveMessage,
|
|
1356
|
+
createInteractiveButtonsAction,
|
|
1357
|
+
createInteractiveListAction,
|
|
1358
|
+
createInteractiveCatalogAction,
|
|
1359
|
+
sendQuickReplyButtons,
|
|
1360
|
+
sendUrlButtons,
|
|
1361
|
+
sendMixedButtons,
|
|
1362
|
+
sendButtonsWithHeader,
|
|
1363
|
+
sendButtonsWithImageHeader,
|
|
1364
|
+
sendButtonsWithDocumentHeader,
|
|
1365
|
+
sendListMessage,
|
|
1366
|
+
sendInteractiveButtons,
|
|
1367
|
+
sendInteractiveList,
|
|
1368
|
+
sendInteractiveCatalog,
|
|
1369
|
+
sendPollMessage,
|
|
1370
|
+
sendCallButton,
|
|
1371
|
+
sendLocationButton,
|
|
1372
|
+
sendContactButton,
|
|
1373
|
+
sendTemplateMessage,
|
|
1374
|
+
sendCatalogMessage,
|
|
1375
|
+
sendProductMessage,
|
|
1376
|
+
sendCollectionMessage,
|
|
1053
1377
|
sendMessage: async (jid, content, options = {}) => {
|
|
1054
1378
|
const userJid = authState.creds.me.id;
|
|
1055
1379
|
if (typeof content === 'object' &&
|
|
@@ -1077,7 +1401,6 @@ export const makeMessagesSocket = (config) => {
|
|
|
1077
1401
|
logger,
|
|
1078
1402
|
uploadImage: generateHighQualityLinkPreview ? waUploadToServer : undefined
|
|
1079
1403
|
}),
|
|
1080
|
-
//TODO: CACHE
|
|
1081
1404
|
getProfilePicUrl: sock.profilePictureUrl,
|
|
1082
1405
|
getCallLink: sock.createCallLink,
|
|
1083
1406
|
upload: waUploadToServer,
|
|
@@ -1093,9 +1416,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
1093
1416
|
const isPollMessage = 'poll' in content && !!content.poll;
|
|
1094
1417
|
const additionalAttributes = {};
|
|
1095
1418
|
const additionalNodes = [];
|
|
1096
|
-
// required for delete
|
|
1097
1419
|
if (isDeleteMsg) {
|
|
1098
|
-
// if the chat is a group, and I am not the author, then delete the message as an admin
|
|
1099
1420
|
if (isJidGroup(content.delete?.remoteJid) && !content.delete?.fromMe) {
|
|
1100
1421
|
additionalAttributes.edit = '8';
|
|
1101
1422
|
}
|
|
@@ -1141,5 +1462,4 @@ export const makeMessagesSocket = (config) => {
|
|
|
1141
1462
|
}
|
|
1142
1463
|
}
|
|
1143
1464
|
};
|
|
1144
|
-
};
|
|
1145
|
-
//# sourceMappingURL=messages-send.js.map
|
|
1465
|
+
};
|
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
|