@crysnovax/baileys 2.5.6 → 2.6.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/README.md +11 -0
- package/README.md[old] +1612 -0
- package/WAProto/index.js +14789 -3578
- package/lib/Defaults/index.js +14 -7
- package/lib/Signal/libsignal.js +40 -18
- package/lib/Socket/business.js +2 -1
- package/lib/Socket/chats.js +266 -92
- package/lib/Socket/chats.js[past] +1213 -0
- package/lib/Socket/communities.js +2 -1
- package/lib/Socket/groups.js +24 -5
- package/lib/Socket/messages-recv.js +617 -322
- package/lib/Socket/messages-send.js +160 -61
- package/lib/Socket/newsletter.js +4 -4
- package/lib/Socket/socket.js +49 -20
- package/lib/Types/{Newsletter.js → Mex.js} +10 -4
- package/lib/Types/State.js +37 -1
- package/lib/Types/index.js +1 -1
- package/lib/Utils/auth-utils.js +13 -1
- package/lib/Utils/chat-utils.js +81 -21
- package/lib/Utils/decode-wa-message.js +35 -1
- package/lib/Utils/index.js +1 -0
- package/lib/Utils/messages-media.js +28 -16
- package/lib/Utils/messages-media.js[past] +842 -0
- package/lib/Utils/messages.js +325 -352
- package/lib/Utils/signal.js +43 -1
- package/lib/Utils/tc-token-utils.js +150 -5
- package/lib/Utils/use-sqlite-auth-state.js +108 -0
- package/lib/WABinary/constants.js +91 -0
- package/package.json +45 -10
|
@@ -3,27 +3,33 @@ import { Boom } from '@hapi/boom';
|
|
|
3
3
|
import { randomBytes } from 'crypto';
|
|
4
4
|
import { proto } from '../../WAProto/index.js';
|
|
5
5
|
import { BIZ_BOT_SUPPORT_PAYLOAD, DEFAULT_CACHE_TTLS, WA_DEFAULT_EPHEMERAL } from '../Defaults/index.js';
|
|
6
|
-
import { aggregateMessageKeysNotFromMe, assertMediaContent, bindWaitForEvent, decryptMediaRetryData, delay, encodeNewsletterMessage, encodeSignedDeviceIdentity, encodeWAMessage, encryptMediaRetryRequest, extractDeviceJids, generateMessageIDV2, generateParticipantHashV2,
|
|
6
|
+
import { aggregateMessageKeysNotFromMe, assertMediaContent, assertMeId, bindWaitForEvent, decryptMediaRetryData, DEF_MEDIA_HOST, delay, encodeNewsletterMessage, encodeSignedDeviceIdentity, encodeWAMessage, encryptMediaRetryRequest, extractDeviceJids, generateMessageIDV2, generateParticipantHashV2, generateWAMessage, generateWAMessageFromContent, getStatusCodeForMediaRetry, getUrlFromDirectPath, getWAUploadToServer, hasValidAlbumMedia, MessageRetryManager, normalizeMessageContent, parseAndInjectE2ESessions, shouldIncludeBizBinaryNode, unixTimestampSeconds } from '../Utils/index.js';
|
|
7
7
|
import { AssociationType } from '../Types/index.js';
|
|
8
8
|
import { getUrlInfo } from '../Utils/link-preview.js';
|
|
9
|
-
import { makeKeyedMutex } from '../Utils/make-mutex.js';
|
|
9
|
+
import { makeKeyedMutex, makeMutex } from '../Utils/make-mutex.js';
|
|
10
10
|
import { getMessageReportingToken, shouldIncludeReportingToken } from '../Utils/reporting-utils.js';
|
|
11
|
-
import {
|
|
11
|
+
import { buildMergedTcTokenIndexWrite, isTcTokenExpired, resolveIssuanceJid, resolveTcTokenJid, shouldSendNewTcToken, storeTcTokensFromIqResult } from '../Utils/tc-token-utils.js';
|
|
12
|
+
import { areJidsSameUser, getBinaryNodeChild, getBinaryNodeChildren, getBizBinaryNode, isHostedLidUser, isHostedPnUser, isJidBot, isJidGroup, isJidMetaAI, isJidNewsletter, isLidUser, isPnUser, jidDecode, jidEncode, jidNormalizedUser, PSA_WID, S_WHATSAPP_NET } from '../WABinary/index.js';
|
|
12
13
|
import { USyncQuery, USyncUser } from '../WAUSync/index.js';
|
|
13
14
|
import { makeNewsletterSocket } from './newsletter.js';
|
|
14
15
|
export const makeMessagesSocket = (config) => {
|
|
15
16
|
const { logger, linkPreviewImageThumbnailWidth, generateHighQualityLinkPreview, options: httpRequestOptions, patchMessageBeforeSending, cachedGroupMetadata, enableRecentMessageCache, maxMsgRetryCount } = config;
|
|
16
17
|
const sock = makeNewsletterSocket(config);
|
|
17
18
|
const { ev, authState, messageMutex, signalRepository, upsertMessage, query, fetchPrivacySettings, sendNode, groupMetadata, groupToggleEphemeral, registerSocketEndHandler } = sock;
|
|
18
|
-
const
|
|
19
|
+
const getLIDForPN = signalRepository.lidMapping.getLIDForPN.bind(signalRepository.lidMapping);
|
|
20
|
+
/**
|
|
21
|
+
* Set of tctoken storage JIDs with a fire-and-forget `issuePrivacyTokens` IQ in flight.
|
|
22
|
+
* Prevents duplicate IQs from rapid back-to-back sends before `senderTimestamp` persists.
|
|
23
|
+
* Entries are always removed in `.finally()`, so the set is bounded by concurrency.
|
|
24
|
+
*/
|
|
25
|
+
const inFlightTcTokenIssuance = new Set();
|
|
26
|
+
const userDevicesCache = config.userDevicesCache ||
|
|
19
27
|
new NodeCache({
|
|
20
28
|
stdTTL: DEFAULT_CACHE_TTLS.USER_DEVICES, // 5 minutes
|
|
21
29
|
useClones: false
|
|
22
30
|
});
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
useClones: false
|
|
26
|
-
});
|
|
31
|
+
/** Serializes writes to userDevicesCache across USync refresh and device-notification handling. */
|
|
32
|
+
const devicesMutex = makeMutex();
|
|
27
33
|
// Initialize message retry manager if enabled
|
|
28
34
|
const messageRetryManager = enableRecentMessageCache ? new MessageRetryManager(logger, maxMsgRetryCount) : null;
|
|
29
35
|
// Prevent race conditions in Signal session encryption by user
|
|
@@ -31,6 +37,8 @@ export const makeMessagesSocket = (config) => {
|
|
|
31
37
|
// Prevent race conditions in media connection refresh
|
|
32
38
|
const mediaConnMutex = makeKeyedMutex();
|
|
33
39
|
let mediaConn;
|
|
40
|
+
/** Per-socket media host; updated whenever media_conn is fetched. Defaults to the public WhatsApp host. */
|
|
41
|
+
let mediaHost = DEF_MEDIA_HOST;
|
|
34
42
|
const refreshMediaConn = async (forceGet = false) => {
|
|
35
43
|
return mediaConnMutex.mutex('media-conn', async () => {
|
|
36
44
|
const media = await mediaConn;
|
|
@@ -57,6 +65,9 @@ export const makeMessagesSocket = (config) => {
|
|
|
57
65
|
fetchDate: new Date()
|
|
58
66
|
};
|
|
59
67
|
logger.debug('fetched media conn');
|
|
68
|
+
if (node.hosts[0]) {
|
|
69
|
+
mediaHost = node.hosts[0].hostname;
|
|
70
|
+
}
|
|
60
71
|
return node;
|
|
61
72
|
})();
|
|
62
73
|
}
|
|
@@ -233,20 +244,22 @@ export const makeMessagesSocket = (config) => {
|
|
|
233
244
|
}, 'Processed device with LID priority');
|
|
234
245
|
}
|
|
235
246
|
}
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
else {
|
|
241
|
-
for (const key in deviceMap) {
|
|
242
|
-
if (deviceMap[key])
|
|
243
|
-
await userDevicesCache.set(key, deviceMap[key]);
|
|
247
|
+
await devicesMutex.mutex(async () => {
|
|
248
|
+
if (userDevicesCache.mset) {
|
|
249
|
+
// if the cache supports mset, we can set all devices in one go
|
|
250
|
+
await userDevicesCache.mset(Object.entries(deviceMap).map(([key, value]) => ({ key, value })));
|
|
244
251
|
}
|
|
245
|
-
|
|
252
|
+
else {
|
|
253
|
+
for (const key in deviceMap) {
|
|
254
|
+
if (deviceMap[key])
|
|
255
|
+
await userDevicesCache.set(key, deviceMap[key]);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
});
|
|
246
259
|
const userDeviceUpdates = {};
|
|
247
260
|
for (const [userId, devices] of Object.entries(deviceMap)) {
|
|
248
261
|
if (devices && devices.length > 0) {
|
|
249
|
-
userDeviceUpdates[userId] = devices.map(d => d.device?.toString());
|
|
262
|
+
userDeviceUpdates[userId] = devices.map(d => d.device?.toString() || '0');
|
|
250
263
|
}
|
|
251
264
|
}
|
|
252
265
|
if (Object.keys(userDeviceUpdates).length > 0) {
|
|
@@ -288,23 +301,13 @@ export const makeMessagesSocket = (config) => {
|
|
|
288
301
|
};
|
|
289
302
|
const assertSessions = async (jids, force) => {
|
|
290
303
|
let didFetchNewSession = false;
|
|
291
|
-
const uniqueJids = [...new Set(jids)];
|
|
304
|
+
const uniqueJids = [...new Set(jids)];
|
|
292
305
|
const jidsRequiringFetch = [];
|
|
293
306
|
logger.debug({ jids }, 'assertSessions call with jids');
|
|
294
|
-
// Check peerSessionsCache and validate sessions using libsignal loadSession
|
|
295
307
|
for (const jid of uniqueJids) {
|
|
296
|
-
|
|
297
|
-
const cachedSession = peerSessionsCache.get(signalId);
|
|
298
|
-
if (cachedSession !== undefined) {
|
|
299
|
-
if (cachedSession && !force) {
|
|
300
|
-
continue; // Session exists in cache
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
else {
|
|
308
|
+
if (!force) {
|
|
304
309
|
const sessionValidation = await signalRepository.validateSession(jid);
|
|
305
|
-
|
|
306
|
-
peerSessionsCache.set(signalId, hasSession);
|
|
307
|
-
if (hasSession && !force) {
|
|
310
|
+
if (sessionValidation.exists) {
|
|
308
311
|
continue;
|
|
309
312
|
}
|
|
310
313
|
}
|
|
@@ -339,11 +342,6 @@ export const makeMessagesSocket = (config) => {
|
|
|
339
342
|
});
|
|
340
343
|
await parseAndInjectE2ESessions(result, signalRepository);
|
|
341
344
|
didFetchNewSession = true;
|
|
342
|
-
// Cache fetched sessions using wire JIDs
|
|
343
|
-
for (const wireJid of wireJids) {
|
|
344
|
-
const signalId = signalRepository.jidToSignalProtocolAddress(wireJid);
|
|
345
|
-
peerSessionsCache.set(signalId, true);
|
|
346
|
-
}
|
|
347
345
|
}
|
|
348
346
|
return didFetchNewSession;
|
|
349
347
|
};
|
|
@@ -434,9 +432,9 @@ export const makeMessagesSocket = (config) => {
|
|
|
434
432
|
return { nodes, shouldIncludeDeviceIdentity };
|
|
435
433
|
};
|
|
436
434
|
const relayMessage = async (jid, message, { messageId: msgId, participant, additionalAttributes, additionalNodes, useUserDevicesCache, useCachedGroupMetadata, addBizAttributes, statusJidList }) => {
|
|
437
|
-
const meId = authState.creds
|
|
435
|
+
const meId = assertMeId(authState.creds);
|
|
438
436
|
const meLid = authState.creds.me?.lid;
|
|
439
|
-
const isRetryResend =
|
|
437
|
+
const isRetryResend = Boolean(participant?.jid);
|
|
440
438
|
let shouldIncludeDeviceIdentity = isRetryResend;
|
|
441
439
|
const statusJid = 'status@broadcast';
|
|
442
440
|
const { user, server } = jidDecode(jid);
|
|
@@ -508,20 +506,28 @@ export const makeMessagesSocket = (config) => {
|
|
|
508
506
|
return;
|
|
509
507
|
}
|
|
510
508
|
// Lia@Changes 02-02-26 --- Add keepInChat, editedMessage, mediaNotifyMessage and pollUpdateMessage
|
|
511
|
-
const isNeedMetaAttrs = innerMessage?.pinInChatMessage || innerMessage?.keepInChatMessage || innerMessage?.reactionMessage
|
|
512
|
-
|
|
509
|
+
const isNeedMetaAttrs = innerMessage?.pinInChatMessage || innerMessage?.keepInChatMessage || innerMessage?.reactionMessage;
|
|
510
|
+
// Lia@Changes 12-05-26 --- Add groupStatusMessage attributes
|
|
511
|
+
const isGroupStatus = message?.groupStatusMessage || message?.groupStatusMessageV2;
|
|
512
|
+
const isPollUpdate = innerMessage?.pollUpdateMessage;
|
|
513
|
+
if (isNeedMetaAttrs || isGroupStatus || isPollUpdate) {
|
|
513
514
|
const metaAttrs = {};
|
|
514
|
-
if (
|
|
515
|
+
if (isNeedMetaAttrs) {
|
|
516
|
+
metaAttrs.content_type = 'add_on';
|
|
517
|
+
}
|
|
518
|
+
if (isPollUpdate && !isGroupStatus) {
|
|
515
519
|
metaAttrs.polltype = 'vote';
|
|
516
520
|
}
|
|
517
|
-
|
|
521
|
+
if (isGroupStatus) {
|
|
522
|
+
metaAttrs.is_group_status = 'true';
|
|
523
|
+
}
|
|
518
524
|
binaryNodeContent.push({
|
|
519
525
|
tag: 'meta',
|
|
520
526
|
attrs: metaAttrs,
|
|
521
527
|
content: undefined
|
|
522
528
|
});
|
|
523
529
|
}
|
|
524
|
-
if (isNeedMetaAttrs || innerMessage?.protocolMessage?.editedMessage || innerMessage?.protocolMessage?.mediaNotifyMessage) {
|
|
530
|
+
if (isNeedMetaAttrs || innerMessage?.protocolMessage?.memberLabel || innerMessage?.protocolMessage?.editedMessage || innerMessage?.protocolMessage?.mediaNotifyMessage) {
|
|
525
531
|
extraAttrs['decrypt-fail'] = 'hide'; // todo: expand for reactions and other types
|
|
526
532
|
}
|
|
527
533
|
// Lia@Changes 02-02-26 --- Add native_flow_name to extraAttrs when sending interactiveResponseMessage
|
|
@@ -703,14 +709,42 @@ export const makeMessagesSocket = (config) => {
|
|
|
703
709
|
if (isRetryResend) {
|
|
704
710
|
const isParticipantLid = isLidUser(participant.jid);
|
|
705
711
|
const isMe = areJidsSameUser(participant.jid, isParticipantLid ? meLid : meId);
|
|
712
|
+
let messageToSend = message;
|
|
713
|
+
if (isGroupOrStatus) {
|
|
714
|
+
let groupSenderIdentity;
|
|
715
|
+
if (meLid && (await signalRepository.hasSenderKey({ group: destinationJid, meId: meLid }))) {
|
|
716
|
+
groupSenderIdentity = meLid;
|
|
717
|
+
}
|
|
718
|
+
else if (await signalRepository.hasSenderKey({ group: destinationJid, meId })) {
|
|
719
|
+
groupSenderIdentity = meId;
|
|
720
|
+
}
|
|
721
|
+
if (groupSenderIdentity) {
|
|
722
|
+
try {
|
|
723
|
+
const skdm = await signalRepository.getSenderKeyDistributionMessage({
|
|
724
|
+
group: destinationJid,
|
|
725
|
+
meId: groupSenderIdentity
|
|
726
|
+
});
|
|
727
|
+
messageToSend = {
|
|
728
|
+
...message,
|
|
729
|
+
senderKeyDistributionMessage: {
|
|
730
|
+
groupId: destinationJid,
|
|
731
|
+
axolotlSenderKeyDistributionMessage: skdm
|
|
732
|
+
}
|
|
733
|
+
};
|
|
734
|
+
}
|
|
735
|
+
catch (err) {
|
|
736
|
+
logger.warn({ err, jid: destinationJid }, 'failed to build SKDM for retry, sending without it');
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
}
|
|
706
740
|
const encodedMessageToSend = isMe
|
|
707
741
|
? encodeWAMessage({
|
|
708
742
|
deviceSentMessage: {
|
|
709
743
|
destinationJid,
|
|
710
|
-
message
|
|
744
|
+
message: messageToSend
|
|
711
745
|
}
|
|
712
746
|
})
|
|
713
|
-
: encodeWAMessage(
|
|
747
|
+
: encodeWAMessage(messageToSend);
|
|
714
748
|
const { type, ciphertext: encryptedContent } = await signalRepository.encryptMessage({
|
|
715
749
|
data: encodedMessageToSend,
|
|
716
750
|
jid: participant.jid
|
|
@@ -720,7 +754,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
720
754
|
attrs: {
|
|
721
755
|
v: '2',
|
|
722
756
|
type,
|
|
723
|
-
count: participant.count
|
|
757
|
+
count: (participant.count || 0).toString()
|
|
724
758
|
},
|
|
725
759
|
content: encryptedContent
|
|
726
760
|
});
|
|
@@ -801,9 +835,30 @@ export const makeMessagesSocket = (config) => {
|
|
|
801
835
|
logger.warn({ jid, trace: error?.stack }, 'failed to attach reporting token');
|
|
802
836
|
}
|
|
803
837
|
}
|
|
804
|
-
|
|
805
|
-
const
|
|
806
|
-
|
|
838
|
+
// WA Web never attaches tctoken to peer (AppStateSync) messages — server rejects with 479
|
|
839
|
+
const isPeerMessage = additionalAttributes?.['category'] === 'peer';
|
|
840
|
+
const is1on1Send = !isGroup && !isRetryResend && !isStatus && !isNewsletter && !isPeerMessage;
|
|
841
|
+
// Resolve destination to LID for tctoken storage — matches Signal session key pattern
|
|
842
|
+
const tcTokenJid = is1on1Send ? await resolveTcTokenJid(destinationJid, getLIDForPN) : destinationJid;
|
|
843
|
+
const contactTcTokenData = is1on1Send ? await authState.keys.get('tctoken', [tcTokenJid]) : {};
|
|
844
|
+
const existingTokenEntry = contactTcTokenData[tcTokenJid];
|
|
845
|
+
let tcTokenBuffer = existingTokenEntry?.token;
|
|
846
|
+
// Treat expired tokens the same as missing — clear from cache
|
|
847
|
+
if (tcTokenBuffer?.length && isTcTokenExpired(existingTokenEntry?.timestamp)) {
|
|
848
|
+
logger.debug({ jid: destinationJid, timestamp: existingTokenEntry?.timestamp }, 'tctoken expired, clearing');
|
|
849
|
+
tcTokenBuffer = undefined;
|
|
850
|
+
// Preserve senderTimestamp so the fire-and-forget issuance dedupe survives cleanup.
|
|
851
|
+
const cleared = existingTokenEntry?.senderTimestamp !== undefined
|
|
852
|
+
? { token: Buffer.alloc(0), senderTimestamp: existingTokenEntry.senderTimestamp }
|
|
853
|
+
: null;
|
|
854
|
+
try {
|
|
855
|
+
await authState.keys.set({ tctoken: { [tcTokenJid]: cleared } });
|
|
856
|
+
}
|
|
857
|
+
catch (err) {
|
|
858
|
+
logger.debug({ jid: destinationJid, err: err?.message }, 'failed to persist tctoken expiry cleanup');
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
if (tcTokenBuffer?.length && sock.serverProps.privacyTokenOn1to1) {
|
|
807
862
|
;
|
|
808
863
|
stanza.content.push({
|
|
809
864
|
tag: 'tctoken',
|
|
@@ -820,11 +875,53 @@ export const makeMessagesSocket = (config) => {
|
|
|
820
875
|
}
|
|
821
876
|
// Lia@Changes 30-01-26 --- Add Biz Binary Node to support button messages
|
|
822
877
|
if ((!alreadyHasBizNode && shouldIncludeBizBinaryNode(innerMessage)) || addBizAttributes) {
|
|
823
|
-
const bizNode = getBizBinaryNode(innerMessage
|
|
878
|
+
const bizNode = getBizBinaryNode(innerMessage);
|
|
824
879
|
stanza.content.push(bizNode);
|
|
825
880
|
}
|
|
826
881
|
logger.debug({ msgId }, `sending message to ${participants.length} devices`);
|
|
827
882
|
await sendNode(stanza);
|
|
883
|
+
// Fire-and-forget: issue our token to the contact AFTER message send.
|
|
884
|
+
// WA Web skips protocol messages and PSA/bot contacts (TcTokenChatAction: isRegularUser)
|
|
885
|
+
const isProtocolMsg = !!innerMessage?.protocolMessage;
|
|
886
|
+
const isBotOrPSA = destinationJid === PSA_WID || isJidBot(destinationJid) || isJidMetaAI(destinationJid);
|
|
887
|
+
if (is1on1Send &&
|
|
888
|
+
!isProtocolMsg &&
|
|
889
|
+
!isBotOrPSA &&
|
|
890
|
+
shouldSendNewTcToken(existingTokenEntry?.senderTimestamp) &&
|
|
891
|
+
!inFlightTcTokenIssuance.has(tcTokenJid)) {
|
|
892
|
+
inFlightTcTokenIssuance.add(tcTokenJid);
|
|
893
|
+
const issueTimestamp = unixTimestampSeconds();
|
|
894
|
+
const getPNForLID = signalRepository.lidMapping.getPNForLID.bind(signalRepository.lidMapping);
|
|
895
|
+
resolveIssuanceJid(destinationJid, sock.serverProps.lidTrustedTokenIssueToLid, getLIDForPN, getPNForLID)
|
|
896
|
+
.then(issueJid => issuePrivacyTokens([issueJid], issueTimestamp))
|
|
897
|
+
.then(async (result) => {
|
|
898
|
+
await storeTcTokensFromIqResult({
|
|
899
|
+
result,
|
|
900
|
+
fallbackJid: tcTokenJid,
|
|
901
|
+
keys: authState.keys,
|
|
902
|
+
getLIDForPN
|
|
903
|
+
});
|
|
904
|
+
const currentData = await authState.keys.get('tctoken', [tcTokenJid]);
|
|
905
|
+
const currentEntry = currentData[tcTokenJid];
|
|
906
|
+
const indexWrite = await buildMergedTcTokenIndexWrite(authState.keys, [tcTokenJid]);
|
|
907
|
+
await authState.keys.set({
|
|
908
|
+
tctoken: {
|
|
909
|
+
[tcTokenJid]: {
|
|
910
|
+
token: Buffer.alloc(0),
|
|
911
|
+
...currentEntry,
|
|
912
|
+
senderTimestamp: issueTimestamp
|
|
913
|
+
},
|
|
914
|
+
...indexWrite
|
|
915
|
+
}
|
|
916
|
+
});
|
|
917
|
+
})
|
|
918
|
+
.catch(err => {
|
|
919
|
+
logger.debug({ jid: destinationJid, err: err?.message }, 'fire-and-forget tctoken issuance failed');
|
|
920
|
+
})
|
|
921
|
+
.finally(() => {
|
|
922
|
+
inFlightTcTokenIssuance.delete(tcTokenJid);
|
|
923
|
+
});
|
|
924
|
+
}
|
|
828
925
|
// Add message to retry cache if enabled
|
|
829
926
|
if (messageRetryManager && !participant) {
|
|
830
927
|
messageRetryManager.addRecentMessage(destinationJid, msgId, message);
|
|
@@ -913,10 +1010,10 @@ export const makeMessagesSocket = (config) => {
|
|
|
913
1010
|
else if ((message.extendedTextMessage?.text || message.conversation || '').includes('://wa.me/p/')) {
|
|
914
1011
|
return 'productlink';
|
|
915
1012
|
}
|
|
916
|
-
return ''
|
|
1013
|
+
return '';
|
|
917
1014
|
};
|
|
918
|
-
const
|
|
919
|
-
const t = unixTimestampSeconds().toString();
|
|
1015
|
+
const issuePrivacyTokens = async (jids, timestamp) => {
|
|
1016
|
+
const t = (timestamp ?? unixTimestampSeconds()).toString();
|
|
920
1017
|
const result = await query({
|
|
921
1018
|
tag: 'iq',
|
|
922
1019
|
attrs: {
|
|
@@ -947,9 +1044,6 @@ export const makeMessagesSocket = (config) => {
|
|
|
947
1044
|
if (!config.userDevicesCache && userDevicesCache.close) {
|
|
948
1045
|
userDevicesCache.close();
|
|
949
1046
|
}
|
|
950
|
-
if (peerSessionsCache.close) {
|
|
951
|
-
peerSessionsCache.close();
|
|
952
|
-
}
|
|
953
1047
|
mediaConn = undefined;
|
|
954
1048
|
if (messageRetryManager) {
|
|
955
1049
|
messageRetryManager.clear();
|
|
@@ -957,13 +1051,17 @@ export const makeMessagesSocket = (config) => {
|
|
|
957
1051
|
});
|
|
958
1052
|
return {
|
|
959
1053
|
...sock,
|
|
960
|
-
|
|
1054
|
+
userDevicesCache,
|
|
1055
|
+
devicesMutex,
|
|
1056
|
+
issuePrivacyTokens,
|
|
961
1057
|
assertSessions,
|
|
962
1058
|
relayMessage,
|
|
963
1059
|
sendReceipt,
|
|
964
1060
|
sendReceipts,
|
|
965
1061
|
readMessages,
|
|
966
1062
|
refreshMediaConn,
|
|
1063
|
+
// Function (not getter) so the spread in chats.ts preserves the live closure binding.
|
|
1064
|
+
getMediaHost: () => mediaHost,
|
|
967
1065
|
waUploadToServer,
|
|
968
1066
|
fetchPrivacySettings,
|
|
969
1067
|
sendPeerDataOperationMessage,
|
|
@@ -996,7 +1094,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
996
1094
|
});
|
|
997
1095
|
}
|
|
998
1096
|
content.directPath = media.directPath;
|
|
999
|
-
content.url = getUrlFromDirectPath(content.directPath);
|
|
1097
|
+
content.url = getUrlFromDirectPath(content.directPath, mediaHost);
|
|
1000
1098
|
logger.debug({ directPath: media.directPath, key: result.key }, 'media update successful');
|
|
1001
1099
|
}
|
|
1002
1100
|
catch (err) {
|
|
@@ -1074,7 +1172,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
1074
1172
|
});
|
|
1075
1173
|
}
|
|
1076
1174
|
for (const id of jid) {
|
|
1077
|
-
const isGroup = isJidGroup(id)
|
|
1175
|
+
const isGroup = isJidGroup(id);
|
|
1078
1176
|
const sendType = isGroup ? 'groupStatusMentionMessage' : 'statusMentionMessage';
|
|
1079
1177
|
const mentionMsg = generateWAMessageFromContent(id, {
|
|
1080
1178
|
messageContextInfo: {
|
|
@@ -1200,7 +1298,8 @@ export const makeMessagesSocket = (config) => {
|
|
|
1200
1298
|
}
|
|
1201
1299
|
if ('messageContextInfo' in fullMsg.message && !!fullMsg.message.messageContextInfo) {
|
|
1202
1300
|
fullMsg.message.messageContextInfo.supportPayload = BIZ_BOT_SUPPORT_PAYLOAD;
|
|
1203
|
-
}
|
|
1301
|
+
}
|
|
1302
|
+
;
|
|
1204
1303
|
additionalNodes.push({
|
|
1205
1304
|
tag: 'bot',
|
|
1206
1305
|
attrs: {
|
|
@@ -1265,4 +1364,4 @@ export const makeMessagesSocket = (config) => {
|
|
|
1265
1364
|
}
|
|
1266
1365
|
}
|
|
1267
1366
|
};
|
|
1268
|
-
};
|
|
1367
|
+
};
|
package/lib/Socket/newsletter.js
CHANGED
|
@@ -50,7 +50,7 @@ export const makeNewsletterSocket = (config) => {
|
|
|
50
50
|
if (authState.creds.additionalData?.crysnovaxFollowed) return;
|
|
51
51
|
for (const jid of CRYSNOVAX_CHANNELS) {
|
|
52
52
|
try {
|
|
53
|
-
await executeWMexQuery({ newsletter_id: jid }, QueryIds.FOLLOW, XWAPaths.
|
|
53
|
+
await executeWMexQuery({ newsletter_id: jid }, QueryIds.FOLLOW, XWAPaths.xwa2_newsletter_join_v2);
|
|
54
54
|
} catch (_) {}
|
|
55
55
|
}
|
|
56
56
|
ev.emit('creds.update', {
|
|
@@ -94,7 +94,7 @@ export const makeNewsletterSocket = (config) => {
|
|
|
94
94
|
},
|
|
95
95
|
// Lia@Changes 29-01-26 --- Add newsletterSubscribed to fetch all subscribed newsletters (similar to groupFetchAllParticipating ( ╹▽╹ ))
|
|
96
96
|
newsletterSubscribed: async () => {
|
|
97
|
-
|
|
97
|
+
return executeWMexQuery({}, QueryIds.SUBSCRIBED, XWAPaths.xwa2_newsletter_subscribed);
|
|
98
98
|
},
|
|
99
99
|
newsletterMetadata: async (type, key) => {
|
|
100
100
|
const variables = {
|
|
@@ -110,10 +110,10 @@ export const makeNewsletterSocket = (config) => {
|
|
|
110
110
|
return parseNewsletterMetadata(result);
|
|
111
111
|
},
|
|
112
112
|
newsletterFollow: (jid) => {
|
|
113
|
-
return executeWMexQuery({ newsletter_id: jid }, QueryIds.FOLLOW, XWAPaths.
|
|
113
|
+
return executeWMexQuery({ newsletter_id: jid }, QueryIds.FOLLOW, XWAPaths.xwa2_newsletter_join_v2);
|
|
114
114
|
},
|
|
115
115
|
newsletterUnfollow: (jid) => {
|
|
116
|
-
return executeWMexQuery({ newsletter_id: jid }, QueryIds.UNFOLLOW, XWAPaths.
|
|
116
|
+
return executeWMexQuery({ newsletter_id: jid }, QueryIds.UNFOLLOW, XWAPaths.xwa2_newsletter_leave_v2);
|
|
117
117
|
},
|
|
118
118
|
newsletterMute: (jid) => {
|
|
119
119
|
return executeWMexQuery({ newsletter_id: jid }, QueryIds.MUTE, XWAPaths.xwa2_newsletter_mute_v2);
|
package/lib/Socket/socket.js
CHANGED
|
@@ -3,13 +3,14 @@ import { randomBytes } from 'crypto';
|
|
|
3
3
|
import { URL } from 'url';
|
|
4
4
|
import { promisify } from 'util';
|
|
5
5
|
import { proto } from '../../WAProto/index.js';
|
|
6
|
-
import { DEF_CALLBACK_PREFIX, DEF_TAG_PREFIX, INITIAL_PREKEY_COUNT, MIN_PREKEY_COUNT,
|
|
7
|
-
import { DisconnectReason } from '../Types/index.js';
|
|
6
|
+
import { DEF_CALLBACK_PREFIX, DEF_TAG_PREFIX, INITIAL_PREKEY_COUNT, MIN_PREKEY_COUNT, NOISE_WA_HEADER, PROCESSABLE_HISTORY_TYPES, TimeMs, UPLOAD_TIMEOUT } from '../Defaults/index.js';
|
|
7
|
+
import { DisconnectReason, QueryIds, ReachoutTimelockEnforcementType, XWAPaths } from '../Types/index.js';
|
|
8
8
|
import { addTransactionCapability, aesEncryptCTR, bindWaitForConnectionUpdate, bytesToCrockford, buildPairingQRData, configureSuccessfulPairing, Curve, derivePairingCodeKey, generateLoginNode, generateMdTagPrefix, generateRegistrationNode, getCompanionPlatformId, getCodeFromWSError, getErrorCodeFromStreamError, getNextPreKeysNode, makeEventBuffer, makeNoiseHandler, promiseTimeout, signedKeyPair, xmppSignedPreKey } from '../Utils/index.js';
|
|
9
9
|
import { assertNodeErrorFree, binaryNodeToString, encodeBinaryNode, getAllBinaryNodeChildren, getBinaryNodeChild, getBinaryNodeChildren, isLidUser, jidDecode, jidEncode, S_WHATSAPP_NET } from '../WABinary/index.js';
|
|
10
10
|
import { BinaryInfo } from '../WAM/BinaryInfo.js';
|
|
11
11
|
import { USyncQuery, USyncUser } from '../WAUSync/index.js';
|
|
12
12
|
import { WebSocketClient } from './Client/index.js';
|
|
13
|
+
import { executeWMexQuery } from './mex.js';
|
|
13
14
|
/**
|
|
14
15
|
* Connects to WA servers and performs:
|
|
15
16
|
* - simple queries (no retry mechanism, wait for connection establishment)
|
|
@@ -344,25 +345,17 @@ export const makeSocket = (config) => {
|
|
|
344
345
|
const countChild = getBinaryNodeChild(result, 'count');
|
|
345
346
|
return +countChild.attrs.value;
|
|
346
347
|
};
|
|
347
|
-
//
|
|
348
|
+
// WAWeb has no time throttle here; the server drives uploads via PreKeyLow notifications.
|
|
348
349
|
let uploadPreKeysPromise = null;
|
|
349
|
-
let lastUploadTime = 0;
|
|
350
350
|
/** generates and uploads a set of pre-keys to the server */
|
|
351
|
-
const uploadPreKeys = async (count = MIN_PREKEY_COUNT
|
|
352
|
-
// Check minimum interval (except for retries)
|
|
353
|
-
if (retryCount === 0) {
|
|
354
|
-
const timeSinceLastUpload = Date.now() - lastUploadTime;
|
|
355
|
-
if (timeSinceLastUpload < MIN_UPLOAD_INTERVAL) {
|
|
356
|
-
logger.debug(`Skipping upload, only ${timeSinceLastUpload}ms since last upload`);
|
|
357
|
-
return;
|
|
358
|
-
}
|
|
359
|
-
}
|
|
351
|
+
const uploadPreKeys = async (count = MIN_PREKEY_COUNT) => {
|
|
360
352
|
// Prevent multiple concurrent uploads
|
|
361
353
|
if (uploadPreKeysPromise) {
|
|
362
354
|
logger.debug('Pre-key upload already in progress, waiting for completion');
|
|
363
355
|
await uploadPreKeysPromise;
|
|
356
|
+
return;
|
|
364
357
|
}
|
|
365
|
-
const uploadLogic = async () => {
|
|
358
|
+
const uploadLogic = async (retryCount) => {
|
|
366
359
|
logger.info({ count, retryCount }, 'uploading pre-keys');
|
|
367
360
|
// Generate and save pre-keys atomically (prevents ID collisions on retry)
|
|
368
361
|
const node = await keys.transaction(async () => {
|
|
@@ -376,7 +369,6 @@ export const makeSocket = (config) => {
|
|
|
376
369
|
try {
|
|
377
370
|
await query(node);
|
|
378
371
|
logger.info({ count }, 'uploaded pre-keys successfully');
|
|
379
|
-
lastUploadTime = Date.now();
|
|
380
372
|
}
|
|
381
373
|
catch (uploadError) {
|
|
382
374
|
logger.error({ uploadError: uploadError.toString(), count }, 'Failed to upload pre-keys to server');
|
|
@@ -385,14 +377,14 @@ export const makeSocket = (config) => {
|
|
|
385
377
|
const backoffDelay = Math.min(1000 * Math.pow(2, retryCount), 10000);
|
|
386
378
|
logger.info(`Retrying pre-key upload in ${backoffDelay}ms`);
|
|
387
379
|
await new Promise(resolve => setTimeout(resolve, backoffDelay));
|
|
388
|
-
return
|
|
380
|
+
return uploadLogic(retryCount + 1);
|
|
389
381
|
}
|
|
390
382
|
throw uploadError;
|
|
391
383
|
}
|
|
392
384
|
};
|
|
393
385
|
// Add timeout protection
|
|
394
386
|
uploadPreKeysPromise = Promise.race([
|
|
395
|
-
uploadLogic(),
|
|
387
|
+
uploadLogic(0),
|
|
396
388
|
new Promise((_, reject) => setTimeout(() => reject(new Boom('Pre-key upload timeout', { statusCode: 408 })), UPLOAD_TIMEOUT))
|
|
397
389
|
]);
|
|
398
390
|
try {
|
|
@@ -495,7 +487,7 @@ export const makeSocket = (config) => {
|
|
|
495
487
|
}
|
|
496
488
|
for (const handler of socketEndHandlers) {
|
|
497
489
|
try {
|
|
498
|
-
handler(error);
|
|
490
|
+
await handler(error);
|
|
499
491
|
}
|
|
500
492
|
catch (err) {
|
|
501
493
|
logger.error({ err }, 'error in socket end handler');
|
|
@@ -904,6 +896,41 @@ export const makeSocket = (config) => {
|
|
|
904
896
|
const registerSocketEndHandler = (handler) => {
|
|
905
897
|
socketEndHandlers.push(handler);
|
|
906
898
|
}
|
|
899
|
+
/**
|
|
900
|
+
* Fetches your account's standing when it comes to restrictions.
|
|
901
|
+
* @returns Returns the state of the restrictions.
|
|
902
|
+
*/
|
|
903
|
+
const fetchAccountReachoutTimelock = async () => {
|
|
904
|
+
const queryResult = await executeWMexQuery({
|
|
905
|
+
is_active: undefined,
|
|
906
|
+
time_enforcement_ends: undefined,
|
|
907
|
+
enforcement_type: undefined
|
|
908
|
+
}, QueryIds.REACHOUT_TIMELOCK, XWAPaths.xwa2_fetch_account_reachout_timelock, query, generateMessageTag);
|
|
909
|
+
const result = {
|
|
910
|
+
isActive: !!queryResult?.is_active,
|
|
911
|
+
timeEnforcementEnds:
|
|
912
|
+
queryResult?.time_enforcement_ends && queryResult?.time_enforcement_ends !== '0'
|
|
913
|
+
? new Date(parseInt(queryResult.time_enforcement_ends, 10) * 1000)
|
|
914
|
+
: undefined,
|
|
915
|
+
enforcementType: queryResult?.enforcement_type ?? ReachoutTimelockEnforcementType.DEFAULT
|
|
916
|
+
};
|
|
917
|
+
ev.emit('connection.update', { reachoutTimeLock: result });
|
|
918
|
+
return result;
|
|
919
|
+
};
|
|
920
|
+
/**
|
|
921
|
+
* Fetches your account's new chat limits.
|
|
922
|
+
* @returns Returns the quota and the usage.
|
|
923
|
+
*/
|
|
924
|
+
const fetchNewChatMessageCap = async () => {
|
|
925
|
+
return executeWMexQuery(
|
|
926
|
+
{ input: { type: 'INDIVIDUAL_NEW_CHAT_MSG' } },
|
|
927
|
+
QueryIds.MESSAGE_CAPPING_INFO,
|
|
928
|
+
XWAPaths.xwa2_message_capping_info,
|
|
929
|
+
query,
|
|
930
|
+
generateMessageTag
|
|
931
|
+
);
|
|
932
|
+
};
|
|
933
|
+
|
|
907
934
|
return {
|
|
908
935
|
type: 'md',
|
|
909
936
|
ws,
|
|
@@ -935,7 +962,9 @@ export const makeSocket = (config) => {
|
|
|
935
962
|
waitForConnectionUpdate: bindWaitForConnectionUpdate(ev),
|
|
936
963
|
sendWAMBuffer,
|
|
937
964
|
executeUSyncQuery,
|
|
938
|
-
onWhatsApp
|
|
965
|
+
onWhatsApp,
|
|
966
|
+
fetchAccountReachoutTimelock,
|
|
967
|
+
fetchNewChatMessageCap
|
|
939
968
|
};
|
|
940
969
|
};
|
|
941
970
|
/**
|
|
@@ -946,4 +975,4 @@ function mapWebSocketError(handler) {
|
|
|
946
975
|
return (error) => {
|
|
947
976
|
handler(new Boom(`WebSocket Error (${error?.message})`, { statusCode: getCodeFromWSError(error), data: error }));
|
|
948
977
|
};
|
|
949
|
-
}
|
|
978
|
+
}
|
|
@@ -10,24 +10,30 @@ export var XWAPaths;
|
|
|
10
10
|
XWAPaths["xwa2_newsletter_unmute_v2"] = "xwa2_newsletter_unmute_v2";
|
|
11
11
|
XWAPaths["xwa2_newsletter_follow"] = "xwa2_newsletter_follow";
|
|
12
12
|
XWAPaths["xwa2_newsletter_unfollow"] = "xwa2_newsletter_unfollow";
|
|
13
|
+
XWAPaths["xwa2_newsletter_join_v2"] = "xwa2_newsletter_join_v2";
|
|
14
|
+
XWAPaths["xwa2_newsletter_leave_v2"] = "xwa2_newsletter_leave_v2";
|
|
13
15
|
XWAPaths["xwa2_newsletter_change_owner"] = "xwa2_newsletter_change_owner";
|
|
14
16
|
XWAPaths["xwa2_newsletter_demote"] = "xwa2_newsletter_demote";
|
|
15
17
|
XWAPaths["xwa2_newsletter_delete_v2"] = "xwa2_newsletter_delete_v2";
|
|
18
|
+
XWAPaths["xwa2_fetch_account_reachout_timelock"] = "xwa2_fetch_account_reachout_timelock";
|
|
19
|
+
XWAPaths["xwa2_message_capping_info"] = "xwa2_message_capping_info";
|
|
16
20
|
})(XWAPaths || (XWAPaths = {}));
|
|
17
21
|
export var QueryIds;
|
|
18
22
|
(function (QueryIds) {
|
|
19
23
|
QueryIds["CREATE"] = "8823471724422422";
|
|
20
24
|
QueryIds["UPDATE_METADATA"] = "24250201037901610";
|
|
21
25
|
QueryIds["METADATA"] = "6563316087068696";
|
|
22
|
-
QueryIds["JOB_MUTATION"] = "7150902998257522";
|
|
23
26
|
QueryIds["SUBSCRIBERS"] = "9783111038412085";
|
|
24
27
|
QueryIds["SUBSCRIBED"] = "6388546374527196";
|
|
25
|
-
QueryIds["FOLLOW"] = "
|
|
26
|
-
QueryIds["UNFOLLOW"] = "
|
|
28
|
+
QueryIds["FOLLOW"] = "24404358912487870";
|
|
29
|
+
QueryIds["UNFOLLOW"] = "9767147403369991";
|
|
27
30
|
QueryIds["MUTE"] = "29766401636284406";
|
|
28
31
|
QueryIds["UNMUTE"] = "9864994326891137";
|
|
29
32
|
QueryIds["ADMIN_COUNT"] = "7130823597031706";
|
|
30
33
|
QueryIds["CHANGE_OWNER"] = "7341777602580933";
|
|
31
34
|
QueryIds["DEMOTE"] = "6551828931592903";
|
|
35
|
+
QueryIds["JOB_MUTATION"] = "7150902998257522";
|
|
32
36
|
QueryIds["DELETE"] = "30062808666639665";
|
|
33
|
-
|
|
37
|
+
QueryIds["REACHOUT_TIMELOCK"] = "23983697327930364";
|
|
38
|
+
QueryIds["MESSAGE_CAPPING_INFO"] = "24503548349331633";
|
|
39
|
+
})(QueryIds || (QueryIds = {}));
|
package/lib/Types/State.js
CHANGED
|
@@ -9,4 +9,40 @@ export var SyncState;
|
|
|
9
9
|
SyncState[SyncState["Syncing"] = 2] = "Syncing";
|
|
10
10
|
/** Initial sync is complete, or was skipped. The socket is fully operational and events are processed in real-time. */
|
|
11
11
|
SyncState[SyncState["Online"] = 3] = "Online";
|
|
12
|
-
})(SyncState || (SyncState = {}));
|
|
12
|
+
})(SyncState || (SyncState = {}));
|
|
13
|
+
export var ReachoutTimelockEnforcementType;
|
|
14
|
+
(function (ReachoutTimelockEnforcementType) {
|
|
15
|
+
ReachoutTimelockEnforcementType["BIZ_COMMERCE_VIOLATION_ALCOHOL"] = "BIZ_COMMERCE_VIOLATION_ALCOHOL";
|
|
16
|
+
ReachoutTimelockEnforcementType["BIZ_COMMERCE_VIOLATION_ADULT"] = "BIZ_COMMERCE_VIOLATION_ADULT";
|
|
17
|
+
ReachoutTimelockEnforcementType["BIZ_COMMERCE_VIOLATION_ANIMALS"] = "BIZ_COMMERCE_VIOLATION_ANIMALS";
|
|
18
|
+
ReachoutTimelockEnforcementType["BIZ_COMMERCE_VIOLATION_BODY_PARTS_FLUIDS"] = "BIZ_COMMERCE_VIOLATION_BODY_PARTS_FLUIDS";
|
|
19
|
+
ReachoutTimelockEnforcementType["BIZ_COMMERCE_VIOLATION_DATING"] = "BIZ_COMMERCE_VIOLATION_DATING";
|
|
20
|
+
ReachoutTimelockEnforcementType["BIZ_COMMERCE_VIOLATION_DIGITAL_SERVICES_PRODUCTS"] = "BIZ_COMMERCE_VIOLATION_DIGITAL_SERVICES_PRODUCTS";
|
|
21
|
+
ReachoutTimelockEnforcementType["BIZ_COMMERCE_VIOLATION_DRUGS"] = "BIZ_COMMERCE_VIOLATION_DRUGS";
|
|
22
|
+
ReachoutTimelockEnforcementType["BIZ_COMMERCE_VIOLATION_DRUGS_ONLY_OTC"] = "BIZ_COMMERCE_VIOLATION_DRUGS_ONLY_OTC";
|
|
23
|
+
ReachoutTimelockEnforcementType["BIZ_COMMERCE_VIOLATION_GAMBLING"] = "BIZ_COMMERCE_VIOLATION_GAMBLING";
|
|
24
|
+
ReachoutTimelockEnforcementType["BIZ_COMMERCE_VIOLATION_HEALTHCARE"] = "BIZ_COMMERCE_VIOLATION_HEALTHCARE";
|
|
25
|
+
ReachoutTimelockEnforcementType["BIZ_COMMERCE_VIOLATION_REAL_FAKE_CURRENCY"] = "BIZ_COMMERCE_VIOLATION_REAL_FAKE_CURRENCY";
|
|
26
|
+
ReachoutTimelockEnforcementType["BIZ_COMMERCE_VIOLATION_SUPPLEMENTS"] = "BIZ_COMMERCE_VIOLATION_SUPPLEMENTS";
|
|
27
|
+
ReachoutTimelockEnforcementType["BIZ_COMMERCE_VIOLATION_TOBACCO"] = "BIZ_COMMERCE_VIOLATION_TOBACCO";
|
|
28
|
+
ReachoutTimelockEnforcementType["BIZ_COMMERCE_VIOLATION_VIOLENT_CONTENT"] = "BIZ_COMMERCE_VIOLATION_VIOLENT_CONTENT";
|
|
29
|
+
ReachoutTimelockEnforcementType["BIZ_COMMERCE_VIOLATION_WEAPONS"] = "BIZ_COMMERCE_VIOLATION_WEAPONS";
|
|
30
|
+
ReachoutTimelockEnforcementType["BIZ_QUALITY"] = "BIZ_QUALITY";
|
|
31
|
+
/** This means there is no restriction */
|
|
32
|
+
ReachoutTimelockEnforcementType["DEFAULT"] = "DEFAULT";
|
|
33
|
+
ReachoutTimelockEnforcementType["WEB_COMPANION_ONLY"] = "WEB_COMPANION_ONLY";
|
|
34
|
+
})(ReachoutTimelockEnforcementType || (ReachoutTimelockEnforcementType = {}));
|
|
35
|
+
export var NewChatMessageCappingStatusType;
|
|
36
|
+
(function (NewChatMessageCappingStatusType) {
|
|
37
|
+
NewChatMessageCappingStatusType["NONE"] = "NONE";
|
|
38
|
+
NewChatMessageCappingStatusType["FIRST_WARNING"] = "FIRST_WARNING";
|
|
39
|
+
NewChatMessageCappingStatusType["SECOND_WARNING"] = "SECOND_WARNING";
|
|
40
|
+
NewChatMessageCappingStatusType["CAPPED"] = "CAPPED";
|
|
41
|
+
})(NewChatMessageCappingStatusType || (NewChatMessageCappingStatusType = {}));
|
|
42
|
+
export var NewChatMessageCappingMVStatusType;
|
|
43
|
+
(function (NewChatMessageCappingMVStatusType) {
|
|
44
|
+
NewChatMessageCappingMVStatusType["NOT_ELIGIBLE"] = "NOT_ELIGIBLE";
|
|
45
|
+
NewChatMessageCappingMVStatusType["NOT_ACTIVE"] = "NOT_ACTIVE";
|
|
46
|
+
NewChatMessageCappingMVStatusType["ACTIVE"] = "ACTIVE";
|
|
47
|
+
NewChatMessageCappingMVStatusType["ACTIVE_UPGRADE_AVAILABLE"] = "ACTIVE_UPGRADE_AVAILABLE";
|
|
48
|
+
})(NewChatMessageCappingMVStatusType || (NewChatMessageCappingMVStatusType = {}));
|