@charape/baileys 1.0.9 → 1.0.10
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/Defaults/index.js +3 -1
- package/lib/Socket/chats.js +39 -6
- package/lib/Socket/index.js +2 -1
- package/lib/Socket/message-builder.js +20 -8
- package/lib/Socket/messages-recv.js +37 -4
- package/lib/Socket/messages-send.js +86 -157
- package/lib/Socket/socket.js +41 -20
- package/lib/Store/make-cache-manager-store.js +22 -3
- package/lib/Utils/charape-runtime.js +230 -0
- package/lib/Utils/decode-wa-message.js +5 -2
- package/lib/Utils/index.js +1 -0
- package/lib/index.cjs +433 -178
- package/lib/index.js +4 -3
- package/package.json +1 -1
package/lib/Socket/socket.js
CHANGED
|
@@ -406,6 +406,7 @@ export const makeSocket = (config) => {
|
|
|
406
406
|
let lastDateRecv;
|
|
407
407
|
let epoch = 1;
|
|
408
408
|
let keepAliveReq;
|
|
409
|
+
let missedKeepAlives = 0;
|
|
409
410
|
let qrTimer;
|
|
410
411
|
let closed = false;
|
|
411
412
|
const socketEndHandlers = [];
|
|
@@ -610,8 +611,11 @@ export const makeSocket = (config) => {
|
|
|
610
611
|
}
|
|
611
612
|
closed = true;
|
|
612
613
|
logger.info({ trace: error?.stack }, error ? 'connection errored' : 'connection closed');
|
|
614
|
+
missedKeepAlives = 0;
|
|
613
615
|
clearInterval(keepAliveReq);
|
|
616
|
+
keepAliveReq = undefined;
|
|
614
617
|
clearTimeout(qrTimer);
|
|
618
|
+
qrTimer = undefined;
|
|
615
619
|
ws.removeAllListeners('close');
|
|
616
620
|
ws.removeAllListeners('open');
|
|
617
621
|
ws.removeAllListeners('message');
|
|
@@ -661,20 +665,13 @@ export const makeSocket = (config) => {
|
|
|
661
665
|
ws.off('error', onClose);
|
|
662
666
|
});
|
|
663
667
|
};
|
|
664
|
-
const startKeepAliveRequest = () =>
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
it could be that the network is down
|
|
672
|
-
*/
|
|
673
|
-
if (diff > keepAliveIntervalMs + 5000) {
|
|
674
|
-
void end(new Boom('Connection was lost', { statusCode: DisconnectReason.connectionLost }));
|
|
675
|
-
}
|
|
676
|
-
else if (ws.isOpen) {
|
|
677
|
-
// if its all good, send a keep alive request
|
|
668
|
+
const startKeepAliveRequest = () => {
|
|
669
|
+
missedKeepAlives = 0;
|
|
670
|
+
const sendKeepAlivePing = () => {
|
|
671
|
+
if (!ws.isOpen) {
|
|
672
|
+
logger.warn('keep alive called when WS not open');
|
|
673
|
+
return;
|
|
674
|
+
}
|
|
678
675
|
query({
|
|
679
676
|
tag: 'iq',
|
|
680
677
|
attrs: {
|
|
@@ -684,14 +681,38 @@ export const makeSocket = (config) => {
|
|
|
684
681
|
xmlns: 'w:p'
|
|
685
682
|
},
|
|
686
683
|
content: [{ tag: 'ping', attrs: {} }]
|
|
684
|
+
}).then(() => {
|
|
685
|
+
lastDateRecv = new Date();
|
|
686
|
+
missedKeepAlives = 0;
|
|
687
687
|
}).catch(err => {
|
|
688
|
-
logger.error({ trace: err
|
|
688
|
+
logger.error({ trace: err?.stack }, 'error in sending keep alive');
|
|
689
689
|
});
|
|
690
|
-
}
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
690
|
+
};
|
|
691
|
+
keepAliveReq = setInterval(() => {
|
|
692
|
+
if (!lastDateRecv) {
|
|
693
|
+
lastDateRecv = new Date();
|
|
694
|
+
}
|
|
695
|
+
const diff = Date.now() - lastDateRecv.getTime();
|
|
696
|
+
const maxGraceDiff = Math.max(keepAliveIntervalMs * 2.5, keepAliveIntervalMs + 20000);
|
|
697
|
+
if (diff > keepAliveIntervalMs + 5000) {
|
|
698
|
+
missedKeepAlives++;
|
|
699
|
+
if (missedKeepAlives >= 2 || diff > maxGraceDiff) {
|
|
700
|
+
void end(new Boom('Connection was lost', { statusCode: DisconnectReason.connectionLost }));
|
|
701
|
+
} else {
|
|
702
|
+
logger.debug({ diff, missedKeepAlives }, 'keep-alive latency tolerance, sending retry ping');
|
|
703
|
+
sendKeepAlivePing();
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
else if (ws.isOpen) {
|
|
707
|
+
missedKeepAlives = 0;
|
|
708
|
+
sendKeepAlivePing();
|
|
709
|
+
}
|
|
710
|
+
else {
|
|
711
|
+
logger.warn('keep alive called when WS not open');
|
|
712
|
+
}
|
|
713
|
+
}, keepAliveIntervalMs);
|
|
714
|
+
return keepAliveReq;
|
|
715
|
+
};
|
|
695
716
|
/** i have no idea why this exists. pls enlighten me */
|
|
696
717
|
const sendPassiveIq = (tag) => query({
|
|
697
718
|
tag: 'iq',
|
|
@@ -1,6 +1,24 @@
|
|
|
1
1
|
import { createRequire } from "module";
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
import { join } from "path";
|
|
3
|
+
import { pathToFileURL } from "url";
|
|
4
|
+
|
|
5
|
+
let cacheManager;
|
|
6
|
+
const loadCacheManager = async () => {
|
|
7
|
+
if (cacheManager) return cacheManager;
|
|
8
|
+
if (typeof require === "function") {
|
|
9
|
+
cacheManager = require("cache-manager");
|
|
10
|
+
return cacheManager;
|
|
11
|
+
}
|
|
12
|
+
try {
|
|
13
|
+
const mod = await import("cache-manager");
|
|
14
|
+
cacheManager = mod?.default || mod;
|
|
15
|
+
return cacheManager;
|
|
16
|
+
} catch {
|
|
17
|
+
const _require = createRequire(pathToFileURL(join(process.cwd(), "package.json")).href);
|
|
18
|
+
cacheManager = _require("cache-manager");
|
|
19
|
+
return cacheManager;
|
|
20
|
+
}
|
|
21
|
+
};
|
|
4
22
|
|
|
5
23
|
import * as WAProto_1 from "../../WAProto/index.js";
|
|
6
24
|
import * as Utils_1 from "../Utils/index.js";
|
|
@@ -8,7 +26,8 @@ import logger from "../Utils/logger.js";
|
|
|
8
26
|
|
|
9
27
|
export default async function makeCacheManagerAuthState(store, sessionKey) {
|
|
10
28
|
const defaultKey = (file) => `${sessionKey}:${file}`;
|
|
11
|
-
const
|
|
29
|
+
const cm = await loadCacheManager();
|
|
30
|
+
const databaseConn = await cm.caching(store);
|
|
12
31
|
|
|
13
32
|
const writeData = async (file, data) => {
|
|
14
33
|
let ttl = undefined;
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import { jidNormalizedUser, isLidUser, isHostedLidUser, isPnUser, isHostedPnUser } from '../WABinary/index.js';
|
|
2
|
+
|
|
3
|
+
const ANSI = {
|
|
4
|
+
reset: '\x1b[0m',
|
|
5
|
+
bold: '\x1b[1m',
|
|
6
|
+
dim: '\x1b[2m',
|
|
7
|
+
cyan: '\x1b[36m',
|
|
8
|
+
blue: '\x1b[34m',
|
|
9
|
+
green: '\x1b[32m',
|
|
10
|
+
magenta: '\x1b[35m',
|
|
11
|
+
yellow: '\x1b[33m',
|
|
12
|
+
white: '\x1b[37m'
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Insert or refresh an entry in a Map while enforcing an upper bound (FIFO/LRU eviction).
|
|
17
|
+
*/
|
|
18
|
+
export const setBoundedMapEntry = (map, key, value, maxEntries = 2000) => {
|
|
19
|
+
if (!map || key === undefined || key === null) return map;
|
|
20
|
+
if (map.has(key)) {
|
|
21
|
+
map.delete(key);
|
|
22
|
+
}
|
|
23
|
+
map.set(key, value);
|
|
24
|
+
while (map.size > maxEntries) {
|
|
25
|
+
const oldestKey = map.keys().next().value;
|
|
26
|
+
if (oldestKey === undefined) break;
|
|
27
|
+
map.delete(oldestKey);
|
|
28
|
+
}
|
|
29
|
+
return map;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Insert or refresh an entry in a Set while enforcing an upper bound.
|
|
34
|
+
*/
|
|
35
|
+
export const addBoundedSetEntry = (set, value, maxEntries = 2000) => {
|
|
36
|
+
if (!set || value === undefined || value === null) return set;
|
|
37
|
+
if (set.has(value)) {
|
|
38
|
+
set.delete(value);
|
|
39
|
+
}
|
|
40
|
+
set.add(value);
|
|
41
|
+
while (set.size > maxEntries) {
|
|
42
|
+
const oldestValue = set.values().next().value;
|
|
43
|
+
if (oldestValue === undefined) break;
|
|
44
|
+
set.delete(oldestValue);
|
|
45
|
+
}
|
|
46
|
+
return set;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Resolve PN (@s.whatsapp.net) or LID (@lid) JID safely through lidMapping without throwing.
|
|
51
|
+
*/
|
|
52
|
+
export const resolveJidWithMapping = async (jid, lidMapping, target = 'pn') => {
|
|
53
|
+
if (!jid || typeof jid !== 'string') return jid;
|
|
54
|
+
const normalized = jidNormalizedUser(jid);
|
|
55
|
+
if (!lidMapping) return normalized;
|
|
56
|
+
|
|
57
|
+
try {
|
|
58
|
+
if (target === 'pn') {
|
|
59
|
+
if (isPnUser(normalized) || isHostedPnUser(normalized)) return normalized;
|
|
60
|
+
if ((isLidUser(normalized) || isHostedLidUser(normalized)) && typeof lidMapping.getPNForLID === 'function') {
|
|
61
|
+
const pn = await lidMapping.getPNForLID(normalized);
|
|
62
|
+
return pn ? jidNormalizedUser(pn) : normalized;
|
|
63
|
+
}
|
|
64
|
+
} else if (target === 'lid') {
|
|
65
|
+
if (isLidUser(normalized) || isHostedLidUser(normalized)) return normalized;
|
|
66
|
+
if ((isPnUser(normalized) || isHostedPnUser(normalized)) && typeof lidMapping.getLIDForPN === 'function') {
|
|
67
|
+
const lid = await lidMapping.getLIDForPN(normalized);
|
|
68
|
+
return lid ? jidNormalizedUser(lid) : normalized;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
} catch {
|
|
72
|
+
// Fallback silently to normalized JID so caller handlers never crash
|
|
73
|
+
}
|
|
74
|
+
return normalized;
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const SKIPPED_LOG_CONTENT_TYPES = new Set([
|
|
78
|
+
'protocolMessage',
|
|
79
|
+
'senderKeyDistributionMessage',
|
|
80
|
+
'fastRatchetSenderKeyDistributionMessage',
|
|
81
|
+
'messageContextInfo',
|
|
82
|
+
'historySyncNotification',
|
|
83
|
+
'initialSecurityNotificationSettingSync',
|
|
84
|
+
'appStateSyncKeyShare',
|
|
85
|
+
'appStateFatalExceptionNotification'
|
|
86
|
+
]);
|
|
87
|
+
|
|
88
|
+
const WRAPPER_KEYS = [
|
|
89
|
+
'ephemeralMessage',
|
|
90
|
+
'viewOnceMessage',
|
|
91
|
+
'viewOnceMessageV2',
|
|
92
|
+
'viewOnceMessageV2Extension',
|
|
93
|
+
'documentWithCaptionMessage',
|
|
94
|
+
'editedMessage'
|
|
95
|
+
];
|
|
96
|
+
|
|
97
|
+
const unwrapMessageShape = (message) => {
|
|
98
|
+
let curr = message;
|
|
99
|
+
for (let depth = 0; depth < 4 && curr && typeof curr === 'object'; depth++) {
|
|
100
|
+
let unwrapped = false;
|
|
101
|
+
for (const key of WRAPPER_KEYS) {
|
|
102
|
+
if (curr[key]?.message) {
|
|
103
|
+
curr = curr[key].message;
|
|
104
|
+
unwrapped = true;
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
if (!unwrapped) break;
|
|
109
|
+
}
|
|
110
|
+
return curr;
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
const detectDisplayTypeAndPreview = (message) => {
|
|
114
|
+
const content = unwrapMessageShape(message);
|
|
115
|
+
if (!content || typeof content !== 'object') return null;
|
|
116
|
+
|
|
117
|
+
const keys = Object.keys(content).filter(k => k !== 'messageContextInfo' && content[k] !== undefined && content[k] !== null);
|
|
118
|
+
if (keys.length === 0) return null;
|
|
119
|
+
|
|
120
|
+
const primaryKey = keys.find(k => !SKIPPED_LOG_CONTENT_TYPES.has(k)) || keys[0];
|
|
121
|
+
if (SKIPPED_LOG_CONTENT_TYPES.has(primaryKey)) return null;
|
|
122
|
+
|
|
123
|
+
const val = content[primaryKey];
|
|
124
|
+
let textPreview = '';
|
|
125
|
+
if (primaryKey === 'conversation' && typeof val === 'string') {
|
|
126
|
+
textPreview = val;
|
|
127
|
+
} else if (val && typeof val === 'object') {
|
|
128
|
+
textPreview = val.text || val.caption || val.fileName || val.title || val.body?.text || val.header?.title || val.name || '';
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const cleanPreview = String(textPreview || '').replace(/[\r\n\t]+/g, ' ').trim();
|
|
132
|
+
const byteSize = cleanPreview ? Buffer.byteLength(cleanPreview, 'utf8') : 0;
|
|
133
|
+
const typeLabel = primaryKey
|
|
134
|
+
.replace(/Message$/i, '')
|
|
135
|
+
.replace(/([A-Z])/g, ' $1')
|
|
136
|
+
.replace(/^./, s => s.toUpperCase())
|
|
137
|
+
.trim();
|
|
138
|
+
|
|
139
|
+
return {
|
|
140
|
+
rawType: primaryKey,
|
|
141
|
+
typeLabel: typeLabel || 'Message',
|
|
142
|
+
preview: cleanPreview.length > 48 ? cleanPreview.slice(0, 45) + '...' : cleanPreview,
|
|
143
|
+
byteSize
|
|
144
|
+
};
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
let totalLoggedMessages = 0;
|
|
148
|
+
let burstWindowStart = 0;
|
|
149
|
+
let burstCountInWindow = 0;
|
|
150
|
+
const printedLogIds = new Set();
|
|
151
|
+
const MAX_PRINTS_PER_SECOND = 25;
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Format an iconic CHARAPE terminal chat card inspired by the clean MESSAGE INFO layout.
|
|
155
|
+
*/
|
|
156
|
+
export const formatCharapeChatLog = (direction = 'IN', msg = {}, count = totalLoggedMessages) => {
|
|
157
|
+
const info = detectDisplayTypeAndPreview(msg?.message);
|
|
158
|
+
if (!info) return null;
|
|
159
|
+
|
|
160
|
+
const isOut = String(direction).toUpperCase().startsWith('OUT');
|
|
161
|
+
const key = msg?.key || {};
|
|
162
|
+
const remoteJid = key.remoteJid || '-';
|
|
163
|
+
const senderRaw = key.participantAlt || key.remoteJidAlt || key.participant || key.remoteJid || '-';
|
|
164
|
+
const senderId = String(senderRaw).split('@')[0].split(':')[0] || '-';
|
|
165
|
+
const senderName = msg.pushName || (isOut ? 'CHARAPE BOT' : senderId);
|
|
166
|
+
const tsRaw = Number(msg.messageTimestamp || 0);
|
|
167
|
+
const tsDate = tsRaw > 0 ? new Date(tsRaw > 1e12 ? tsRaw : tsRaw * 1000) : new Date();
|
|
168
|
+
const sentTime = Number.isNaN(tsDate.getTime()) ? new Date().toLocaleString() : tsDate.toLocaleString();
|
|
169
|
+
const sizeInfo = info.preview ? `${info.byteSize} bytes (${info.preview})` : `${info.typeLabel}`;
|
|
170
|
+
|
|
171
|
+
const border = `${ANSI.blue}════════════════════════════════════════════════════${ANSI.reset}`;
|
|
172
|
+
const badgeColor = isOut ? ANSI.magenta : ANSI.green;
|
|
173
|
+
const dirLabel = isOut ? 'OUTGOING CHAT' : 'INCOMING CHAT';
|
|
174
|
+
|
|
175
|
+
return [
|
|
176
|
+
border,
|
|
177
|
+
` ${badgeColor}${ANSI.bold}⚡ CHARAPE${ANSI.reset} ${ANSI.dim}•${ANSI.reset} ${ANSI.magenta}${ANSI.bold}${dirLabel}${ANSI.reset}`,
|
|
178
|
+
border,
|
|
179
|
+
` ${ANSI.cyan}📌 Message Type ${ANSI.reset}: ${ANSI.white}${info.typeLabel}${ANSI.reset}`,
|
|
180
|
+
` ${ANSI.cyan}🆔 Message ID ${ANSI.reset}: ${ANSI.white}${key.id || '-'}${ANSI.reset}`,
|
|
181
|
+
` ${ANSI.cyan}⏰ Sent Time ${ANSI.reset}: ${ANSI.white}${sentTime}${ANSI.reset}`,
|
|
182
|
+
` ${ANSI.cyan}📁 Content/Size ${ANSI.reset}: ${ANSI.white}${sizeInfo}${ANSI.reset}`,
|
|
183
|
+
` ${ANSI.cyan}👤 Sender ID ${ANSI.reset}: ${ANSI.white}${senderId}${ANSI.reset}`,
|
|
184
|
+
` ${ANSI.cyan}🎭 Sender Name ${ANSI.reset}: ${ANSI.white}${senderName}${ANSI.reset}`,
|
|
185
|
+
` ${ANSI.cyan}💬 Chat ID ${ANSI.reset}: ${ANSI.white}${remoteJid}${ANSI.reset}`,
|
|
186
|
+
` ${ANSI.cyan}📊 Total Logs ${ANSI.reset}: ${ANSI.yellow}${count}${ANSI.reset}`,
|
|
187
|
+
border
|
|
188
|
+
].join('\n');
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Safely print iconic CHARAPE terminal chat card without blocking or flooding stdout.
|
|
193
|
+
*/
|
|
194
|
+
export const printCharapeChatLog = (direction = 'IN', msg = {}, options = {}) => {
|
|
195
|
+
try {
|
|
196
|
+
if (options.enabled === false) return false;
|
|
197
|
+
if (!options.ignoreEnvSilent && process.env.CHARAPE_SILENT === 'true') return false;
|
|
198
|
+
if (!msg || typeof msg !== 'object' || !msg.message) return false;
|
|
199
|
+
|
|
200
|
+
const dir = String(direction || 'IN').toUpperCase().startsWith('OUT') ? 'OUT' : 'IN';
|
|
201
|
+
const msgId = msg.key?.id;
|
|
202
|
+
if (msgId && !options.force) {
|
|
203
|
+
const dedupeKey = `${dir}:${msgId}`;
|
|
204
|
+
if (printedLogIds.has(dedupeKey)) return false;
|
|
205
|
+
addBoundedSetEntry(printedLogIds, dedupeKey, 600);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const now = Date.now();
|
|
209
|
+
if (now - burstWindowStart >= 1000) {
|
|
210
|
+
burstWindowStart = now;
|
|
211
|
+
burstCountInWindow = 0;
|
|
212
|
+
}
|
|
213
|
+
if (!options.force && burstCountInWindow >= MAX_PRINTS_PER_SECOND) {
|
|
214
|
+
return false;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const nextCount = totalLoggedMessages + 1;
|
|
218
|
+
const formatted = formatCharapeChatLog(dir, msg, nextCount);
|
|
219
|
+
if (!formatted) return false;
|
|
220
|
+
|
|
221
|
+
totalLoggedMessages = nextCount;
|
|
222
|
+
burstCountInWindow++;
|
|
223
|
+
|
|
224
|
+
const writer = typeof options.writer === 'function' ? options.writer : console.log;
|
|
225
|
+
writer(formatted);
|
|
226
|
+
return true;
|
|
227
|
+
} catch {
|
|
228
|
+
return false;
|
|
229
|
+
}
|
|
230
|
+
};
|
|
@@ -4,6 +4,7 @@ import { areJidsSameUser, isHostedLidUser, isHostedPnUser, isJidBroadcast, isJid
|
|
|
4
4
|
// transferDevice
|
|
5
5
|
} from '../WABinary/index.js';
|
|
6
6
|
import { unpadRandomMax16 } from './generics.js';
|
|
7
|
+
import { setBoundedMapEntry } from './charape-runtime.js';
|
|
7
8
|
export const getDecryptionJid = async (sender, repository) => {
|
|
8
9
|
if (isLidUser(sender) || isHostedLidUser(sender)) {
|
|
9
10
|
return sender;
|
|
@@ -97,6 +98,8 @@ const MAX_SECRETS_PER_CHAT = 20
|
|
|
97
98
|
// Module-level map: outgoing @bot message ID → messageSecret
|
|
98
99
|
// Populated when we receive the outgoing pkmsg/msg to @bot (which contains messageContextInfo.messageSecret)
|
|
99
100
|
// Consumed when the msmsg response from @bot arrives and needs decryption
|
|
101
|
+
const MAX_BOT_MESSAGE_SECRETS = 5000
|
|
102
|
+
const MAX_BOT_RECENT_CHATS = 1000
|
|
100
103
|
const botMessageSecrets = new Map()
|
|
101
104
|
const botRecentSecretsByChat = new Map()
|
|
102
105
|
const pushRecentChatSecret = (chatJid, id, secretBuf) => {
|
|
@@ -107,7 +110,7 @@ const pushRecentChatSecret = (chatJid, id, secretBuf) => {
|
|
|
107
110
|
if (filtered.length > MAX_SECRETS_PER_CHAT) {
|
|
108
111
|
filtered.length = MAX_SECRETS_PER_CHAT
|
|
109
112
|
}
|
|
110
|
-
botRecentSecretsByChat
|
|
113
|
+
setBoundedMapEntry(botRecentSecretsByChat, chatJid, filtered, MAX_BOT_RECENT_CHATS)
|
|
111
114
|
}
|
|
112
115
|
export const setBotMessageSecret = (id, secret, chatJid) => {
|
|
113
116
|
if (!id || !secret) return
|
|
@@ -121,7 +124,7 @@ export const setBotMessageSecret = (id, secret, chatJid) => {
|
|
|
121
124
|
} else {
|
|
122
125
|
return
|
|
123
126
|
}
|
|
124
|
-
botMessageSecrets
|
|
127
|
+
setBoundedMapEntry(botMessageSecrets, id, buf, MAX_BOT_MESSAGE_SECRETS)
|
|
125
128
|
if (chatJid) {
|
|
126
129
|
pushRecentChatSecret(chatJid, id, buf)
|
|
127
130
|
}
|
package/lib/Utils/index.js
CHANGED