aunubaileys 1.0.8 → 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/README.md +8 -0
- package/lib/Defaults/index.js +1 -1
- package/lib/Socket/index.js +10 -0
- package/lib/Socket/messages-recv.js +2 -1
- package/lib/Socket/messages-send.js +3 -0
- package/lib/Socket/socket.js +13 -0
- package/lib/Types/Socket.d.ts +2 -0
- package/lib/Utils/lid-store.d.ts +32 -0
- package/lib/Utils/lid-store.js +139 -0
- package/lib/Utils/sent-message-cache.d.ts +15 -0
- package/lib/Utils/sent-message-cache.js +59 -0
- package/lib/index.d.ts +3 -0
- package/lib/index.js +3 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -64,6 +64,14 @@ Everything else is pure upstream. When upstream moves, we rebase the patch layer
|
|
|
64
64
|
|
|
65
65
|
|
|
66
66
|
|
|
67
|
+
### 🆕 What's new in 1.0.10 / Baru di 1.0.10
|
|
68
|
+
|
|
69
|
+
- 🛠️ **Reliability hardening against classic upstream weaknesses** — (1) **Retry receipts now get answered even without a custom `getMessage` store:** a built-in per-socket sent-message cache (last 256 relayed messages, whatsmeow-style) backs up your store, ending the silent "message not available" failures behind stuck unreadable/undelivered messages. Disable with `sentMessagesCacheSize: 0`. (2) **Pairing is now single-flight:** `requestPairingCode` refuses to double-fire (double requests invalidate the first code) and refuses outright on already-registered sessions, with clear errors instead of silent corruption. (3) **Handshake timeout raised:** default `connectTimeoutMs` goes 20s → 60s so pairing no longer times out on slow networks.
|
|
70
|
+
|
|
71
|
+
### 🆕 What's new in 1.0.9 / Baru di 1.0.9
|
|
72
|
+
|
|
73
|
+
- 🪪 **LID identity layer** — WhatsApp is migrating identities from phone numbers to LIDs, and incoming stanzas already carry both forms. AunuBaileys now learns the mapping from live traffic: every socket exposes `sock.aunuLid`, a bidirectional PN <-> LID store with local `getLIDForPN()` / `getPNForLID()` lookups (no extra server queries), LRU capping, and optional JSON persistence. Prefer a standalone store? `makeLIDStore()` is exported from the package root, fully typed.
|
|
74
|
+
|
|
67
75
|
### 🆕 What's new in 1.0.8 / Baru di 1.0.8
|
|
68
76
|
|
|
69
77
|
- 🩹 **TypeScript declaration fix** — `NEWSLETTER_MEDIA_PATH_MAP` and `BIZ_BOT_SUPPORT_PAYLOAD` were exported from the runtime but missing from `lib/Defaults/index.d.ts`, so TypeScript consumers got compile errors importing them. Both are now properly declared. Found by the RafaelPivots automation, verified against source, no runtime changes.
|
package/lib/Defaults/index.js
CHANGED
|
@@ -30,7 +30,7 @@ export const DEFAULT_CONNECTION_CONFIG = {
|
|
|
30
30
|
version: version,
|
|
31
31
|
browser: Browsers.ubuntu('Chrome'),
|
|
32
32
|
waWebSocketUrl: 'wss://web.whatsapp.com/ws/chat',
|
|
33
|
-
connectTimeoutMs:
|
|
33
|
+
connectTimeoutMs: 60000,
|
|
34
34
|
keepAliveIntervalMs: 30000,
|
|
35
35
|
logger: logger.child({ class: 'baileys' }),
|
|
36
36
|
emitOwnEvents: true,
|
package/lib/Socket/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { DEFAULT_CONNECTION_CONFIG } from '../Defaults/index.js';
|
|
2
2
|
import { makeCommunitiesSocket } from './communities.js';
|
|
3
3
|
import { AunuHandler } from '../Utils/aunu-handler.js';
|
|
4
|
+
import { makeLIDStore } from '../Utils/lid-store.js';
|
|
4
5
|
// export the last socket layer
|
|
5
6
|
const makeWASocket = (config) => {
|
|
6
7
|
const newConfig = {
|
|
@@ -14,6 +15,15 @@ const makeWASocket = (config) => {
|
|
|
14
15
|
}
|
|
15
16
|
const sock = makeCommunitiesSocket(newConfig);
|
|
16
17
|
sock.aunuHandler = new AunuHandler(sock);
|
|
18
|
+
sock.aunuLid = makeLIDStore();
|
|
19
|
+
sock.ev.on('messages.upsert', (upsert) => {
|
|
20
|
+
try {
|
|
21
|
+
sock.aunuLid.learnFromUpsert(upsert);
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
// identity learning must never break message handling
|
|
25
|
+
}
|
|
26
|
+
});
|
|
17
27
|
return sock;
|
|
18
28
|
};
|
|
19
29
|
export default makeWASocket;
|
|
@@ -7,6 +7,7 @@ import { DEFAULT_CACHE_TTLS, KEY_BUNDLE_TYPE, MIN_PREKEY_COUNT } from '../Defaul
|
|
|
7
7
|
import { WAMessageStatus, WAMessageStubType } from '../Types/index.js';
|
|
8
8
|
import { aesDecryptCTR, aesEncryptGCM, cleanMessage, Curve, decodeMediaRetryNode, decodeMessageNode, decryptMessageNode, delay, derivePairingCodeKey, encodeBigEndian, encodeSignedDeviceIdentity, getCallStatusFromNode, getHistoryMsg, getNextPreKeys, getStatusFromReceiptType, hkdf, MISSING_KEYS_ERROR_TEXT, NACK_REASONS, NO_MESSAGE_FOUND_ERROR_TEXT, unixTimestampSeconds, xmppPreKey, xmppSignedPreKey } from '../Utils/index.js';
|
|
9
9
|
import { makeMutex } from '../Utils/make-mutex.js';
|
|
10
|
+
import { sentMessageCacheFor } from '../Utils/sent-message-cache.js';
|
|
10
11
|
import { areJidsSameUser, getAllBinaryNodeChildren, getBinaryNodeChild, getBinaryNodeChildBuffer, getBinaryNodeChildren, getBinaryNodeChildString, isJidGroup, isJidStatusBroadcast, isJidUser, isLidUser, jidDecode, jidNormalizedUser, S_WHATSAPP_NET } from '../WABinary/index.js';
|
|
11
12
|
import { extractGroupMetadata } from './groups.js';
|
|
12
13
|
import { makeMessagesSocket } from './messages-send.js';
|
|
@@ -465,7 +466,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
465
466
|
};
|
|
466
467
|
const sendMessagesAgain = async (key, ids, retryNode) => {
|
|
467
468
|
// todo: implement a cache to store the last 256 sent messages (copy whatsmeow)
|
|
468
|
-
const msgs = await Promise.all(ids.map(id => getMessage({ ...key, id })));
|
|
469
|
+
const msgs = await Promise.all(ids.map(async (id) => (await getMessage({ ...key, id })) ?? sentMessageCacheFor(config).get(key.remoteJid, id)));
|
|
469
470
|
const remoteJid = key.remoteJid;
|
|
470
471
|
const participant = key.participant || remoteJid;
|
|
471
472
|
// if it's the primary jid sending the request
|
|
@@ -3,6 +3,7 @@ import { Boom } from '@hapi/boom';
|
|
|
3
3
|
import { proto } from '../../WAProto/index.js';
|
|
4
4
|
import { BIZ_BOT_SUPPORT_PAYLOAD, DEFAULT_CACHE_TTLS, WA_DEFAULT_EPHEMERAL } from '../Defaults/index.js';
|
|
5
5
|
import { aggregateMessageKeysNotFromMe, assertMediaContent, bindWaitForEvent, decryptMediaRetryData, encodeNewsletterMessage, encodeSignedDeviceIdentity, encodeWAMessage, encryptMediaRetryRequest, delay, extractDeviceJids, generateMessageIDV2, generateWAMessage, getStatusCodeForMediaRetry, getUrlFromDirectPath, getWAUploadToServer, normalizeMessageContent, parseAndInjectE2ESessions, unixTimestampSeconds } from '../Utils/index.js';
|
|
6
|
+
import { sentMessageCacheFor } from '../Utils/sent-message-cache.js';
|
|
6
7
|
import { getUrlInfo } from '../Utils/link-preview.js';
|
|
7
8
|
import { areJidsSameUser, getBinaryNodeChild, getBinaryNodeChildren, isJidGroup, isJidNewsletter, isJidUser, isLidUser, jidDecode, jidEncode, jidNormalizedUser, S_WHATSAPP_NET } from '../WABinary/index.js';
|
|
8
9
|
import { USyncQuery, USyncUser } from '../WAUSync/index.js';
|
|
@@ -311,6 +312,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
311
312
|
};
|
|
312
313
|
logger.debug({ msgId }, `sending newsletter message to ${jid}`);
|
|
313
314
|
await sendNode(stanza);
|
|
315
|
+
sentMessageCacheFor(config).add(jid, msgId, message);
|
|
314
316
|
return;
|
|
315
317
|
}
|
|
316
318
|
if (normalizeMessageContent(message)?.pinInChatMessage) {
|
|
@@ -486,6 +488,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
486
488
|
logger.debug({ msgId }, `sending message to ${participants.length} devices`);
|
|
487
489
|
await sendNode(stanza);
|
|
488
490
|
});
|
|
491
|
+
sentMessageCacheFor(config).add(jid, msgId, message);
|
|
489
492
|
return msgId;
|
|
490
493
|
};
|
|
491
494
|
const getMessageType = (message) => {
|
package/lib/Socket/socket.js
CHANGED
|
@@ -370,11 +370,20 @@ export const makeSocket = (config) => {
|
|
|
370
370
|
}
|
|
371
371
|
end(new Boom(msg || 'Intentional Logout', { statusCode: DisconnectReason.loggedOut }));
|
|
372
372
|
};
|
|
373
|
+
let pairingCodeRequestInFlight = false;
|
|
373
374
|
const requestPairingCode = async (phoneNumber, customPairingCode) => {
|
|
375
|
+
if (authState.creds.registered) {
|
|
376
|
+
throw new Error('requestPairingCode: this session is already registered — pairing codes are only for new logins');
|
|
377
|
+
}
|
|
378
|
+
if (pairingCodeRequestInFlight) {
|
|
379
|
+
throw new Error('requestPairingCode: a pairing code request is already in flight — wait for it to finish instead of firing another one (double requests invalidate the first code)');
|
|
380
|
+
}
|
|
374
381
|
const pairingCode = customPairingCode ?? bytesToCrockford(randomBytes(5));
|
|
375
382
|
if (customPairingCode && customPairingCode?.length !== 8) {
|
|
376
383
|
throw new Error('Custom pairing code must be exactly 8 chars');
|
|
377
384
|
}
|
|
385
|
+
pairingCodeRequestInFlight = true;
|
|
386
|
+
try {
|
|
378
387
|
authState.creds.pairingCode = pairingCode;
|
|
379
388
|
authState.creds.me = {
|
|
380
389
|
id: jidEncode(phoneNumber, 's.whatsapp.net'),
|
|
@@ -428,6 +437,10 @@ export const makeSocket = (config) => {
|
|
|
428
437
|
]
|
|
429
438
|
});
|
|
430
439
|
return authState.creds.pairingCode;
|
|
440
|
+
}
|
|
441
|
+
finally {
|
|
442
|
+
pairingCodeRequestInFlight = false;
|
|
443
|
+
}
|
|
431
444
|
};
|
|
432
445
|
async function generatePairingKey() {
|
|
433
446
|
const salt = randomBytes(32);
|
package/lib/Types/Socket.d.ts
CHANGED
|
@@ -75,6 +75,8 @@ export type SocketConfig = {
|
|
|
75
75
|
* map to store the retry counts for failed messages;
|
|
76
76
|
* used to determine whether to retry a message or not */
|
|
77
77
|
msgRetryCounterCache?: CacheStore;
|
|
78
|
+
/** AunuBaileys: capacity of the built-in sent-message cache used to answer retry receipts when `getMessage` has no copy. Default 256; set 0 to disable. */
|
|
79
|
+
sentMessagesCacheSize?: number;
|
|
78
80
|
/** provide a cache to store a user's device list */
|
|
79
81
|
userDevicesCache?: CacheStore;
|
|
80
82
|
/** cache to store call offers */
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { WAMessage } from '../Types/index.js';
|
|
2
|
+
export interface LIDStoreOptions {
|
|
3
|
+
/** Maximum PN<->LID pairs kept; least-recently-used pairs are evicted. Default 5000. */
|
|
4
|
+
maxEntries?: number;
|
|
5
|
+
}
|
|
6
|
+
export interface LIDStore {
|
|
7
|
+
/** Store one PN/LID pair. Returns false when either JID is not a user PN JID / LID JID. */
|
|
8
|
+
addPair(pnJid: string, lidJid: string): boolean;
|
|
9
|
+
/** Learn pairs from a message key (senderPn/senderLid, participantPn/participantLid). Returns pairs learned. */
|
|
10
|
+
learnFromKey(key: Record<string, unknown> | undefined): number;
|
|
11
|
+
/** Learn pairs from one message. Returns pairs learned. */
|
|
12
|
+
learnFromMessage(msg: WAMessage | undefined): number;
|
|
13
|
+
/** Learn pairs from a `messages.upsert` payload. Returns pairs learned. */
|
|
14
|
+
learnFromUpsert(upsert: { messages?: WAMessage[] }): number;
|
|
15
|
+
getLIDForPN(pnJid: string): string | undefined;
|
|
16
|
+
getPNForLID(lidJid: string): string | undefined;
|
|
17
|
+
hasPN(pnJid: string): boolean;
|
|
18
|
+
hasLID(lidJid: string): boolean;
|
|
19
|
+
deletePair(jid: string): boolean;
|
|
20
|
+
clear(): void;
|
|
21
|
+
readonly size: number;
|
|
22
|
+
toJSON(): Record<string, string>;
|
|
23
|
+
saveToFile(path: string): void;
|
|
24
|
+
/** Returns the number of pairs loaded; 0 when the file is missing or invalid. */
|
|
25
|
+
loadFromFile(path: string): number;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Create a bidirectional PN <-> LID identity store that learns from
|
|
29
|
+
* live message traffic. Sockets expose an auto-learning instance as
|
|
30
|
+
* `sock.aunuLid`.
|
|
31
|
+
*/
|
|
32
|
+
export declare const makeLIDStore: (options?: LIDStoreOptions) => LIDStore;
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync } from 'fs';
|
|
2
|
+
import { jidNormalizedUser, isJidUser, isLidUser } from '../WABinary/jid-utils.js';
|
|
3
|
+
/**
|
|
4
|
+
* AunuBaileys LID identity store.
|
|
5
|
+
*
|
|
6
|
+
* WhatsApp is migrating identities from phone-number JIDs
|
|
7
|
+
* (`<number>@s.whatsapp.net`) to LIDs (`<id>@lid`). Incoming message
|
|
8
|
+
* stanzas already carry both forms (`sender_pn`/`sender_lid`,
|
|
9
|
+
* `participant_pn`/`participant_lid`), so this store learns the
|
|
10
|
+
* PN <-> LID pairs from live traffic and answers bidirectional
|
|
11
|
+
* lookups locally — no server round-trip, no extra IQ queries.
|
|
12
|
+
*
|
|
13
|
+
* The socket attaches an auto-learning instance as `sock.aunuLid`.
|
|
14
|
+
* A standalone store can also be created with `makeLIDStore()` and
|
|
15
|
+
* fed manually via `learnFromMessage` / `addPair`.
|
|
16
|
+
*/
|
|
17
|
+
export const makeLIDStore = (options = {}) => {
|
|
18
|
+
const maxEntries = options.maxEntries ?? 5000;
|
|
19
|
+
const pnToLid = new Map();
|
|
20
|
+
const lidToPn = new Map();
|
|
21
|
+
const touch = (map, key, value) => {
|
|
22
|
+
// refresh recency for LRU eviction
|
|
23
|
+
map.delete(key);
|
|
24
|
+
map.set(key, value);
|
|
25
|
+
};
|
|
26
|
+
const evictIfNeeded = () => {
|
|
27
|
+
while (pnToLid.size > maxEntries) {
|
|
28
|
+
const oldestPn = pnToLid.keys().next().value;
|
|
29
|
+
const lid = pnToLid.get(oldestPn);
|
|
30
|
+
pnToLid.delete(oldestPn);
|
|
31
|
+
if (lid) {
|
|
32
|
+
lidToPn.delete(lid);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
const addPair = (pnJid, lidJid) => {
|
|
37
|
+
if (!pnJid || !lidJid) {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
const pn = jidNormalizedUser(pnJid);
|
|
41
|
+
const lid = jidNormalizedUser(lidJid);
|
|
42
|
+
if (!isJidUser(pn) || !isLidUser(lid)) {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
// keep both directions consistent if either side was remapped
|
|
46
|
+
const prevLid = pnToLid.get(pn);
|
|
47
|
+
if (prevLid && prevLid !== lid) {
|
|
48
|
+
lidToPn.delete(prevLid);
|
|
49
|
+
}
|
|
50
|
+
const prevPn = lidToPn.get(lid);
|
|
51
|
+
if (prevPn && prevPn !== pn) {
|
|
52
|
+
pnToLid.delete(prevPn);
|
|
53
|
+
}
|
|
54
|
+
touch(pnToLid, pn, lid);
|
|
55
|
+
touch(lidToPn, lid, pn);
|
|
56
|
+
evictIfNeeded();
|
|
57
|
+
return true;
|
|
58
|
+
};
|
|
59
|
+
const learnFromKey = (key) => {
|
|
60
|
+
if (!key) {
|
|
61
|
+
return 0;
|
|
62
|
+
}
|
|
63
|
+
let learned = 0;
|
|
64
|
+
if (key.senderPn && key.senderLid) {
|
|
65
|
+
learned += addPair(key.senderPn, key.senderLid) ? 1 : 0;
|
|
66
|
+
}
|
|
67
|
+
if (key.participantPn && key.participantLid) {
|
|
68
|
+
learned += addPair(key.participantPn, key.participantLid) ? 1 : 0;
|
|
69
|
+
}
|
|
70
|
+
// a DM chat partner: remoteJid may be the PN while the stanza
|
|
71
|
+
// only carried the sender LID (or the reverse)
|
|
72
|
+
if (key.remoteJid && key.senderLid && isJidUser(key.remoteJid) && !key.fromMe) {
|
|
73
|
+
learned += addPair(key.remoteJid, key.senderLid) ? 1 : 0;
|
|
74
|
+
}
|
|
75
|
+
return learned;
|
|
76
|
+
};
|
|
77
|
+
const learnFromMessage = (msg) => learnFromKey(msg?.key);
|
|
78
|
+
const learnFromUpsert = (upsert) => {
|
|
79
|
+
let learned = 0;
|
|
80
|
+
for (const msg of upsert?.messages ?? []) {
|
|
81
|
+
learned += learnFromMessage(msg);
|
|
82
|
+
}
|
|
83
|
+
return learned;
|
|
84
|
+
};
|
|
85
|
+
const store = {
|
|
86
|
+
addPair,
|
|
87
|
+
learnFromKey,
|
|
88
|
+
learnFromMessage,
|
|
89
|
+
learnFromUpsert,
|
|
90
|
+
getLIDForPN: (pnJid) => (pnJid ? pnToLid.get(jidNormalizedUser(pnJid)) : undefined),
|
|
91
|
+
getPNForLID: (lidJid) => (lidJid ? lidToPn.get(jidNormalizedUser(lidJid)) : undefined),
|
|
92
|
+
hasPN: (pnJid) => (pnJid ? pnToLid.has(jidNormalizedUser(pnJid)) : false),
|
|
93
|
+
hasLID: (lidJid) => (lidJid ? lidToPn.has(jidNormalizedUser(lidJid)) : false),
|
|
94
|
+
deletePair: (jid) => {
|
|
95
|
+
if (!jid) {
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
const norm = jidNormalizedUser(jid);
|
|
99
|
+
const lid = pnToLid.get(norm);
|
|
100
|
+
if (lid) {
|
|
101
|
+
pnToLid.delete(norm);
|
|
102
|
+
lidToPn.delete(lid);
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
const pn = lidToPn.get(norm);
|
|
106
|
+
if (pn) {
|
|
107
|
+
lidToPn.delete(norm);
|
|
108
|
+
pnToLid.delete(pn);
|
|
109
|
+
return true;
|
|
110
|
+
}
|
|
111
|
+
return false;
|
|
112
|
+
},
|
|
113
|
+
clear: () => {
|
|
114
|
+
pnToLid.clear();
|
|
115
|
+
lidToPn.clear();
|
|
116
|
+
},
|
|
117
|
+
get size() {
|
|
118
|
+
return pnToLid.size;
|
|
119
|
+
},
|
|
120
|
+
toJSON: () => Object.fromEntries(pnToLid),
|
|
121
|
+
saveToFile: (path) => {
|
|
122
|
+
writeFileSync(path, JSON.stringify(Object.fromEntries(pnToLid)));
|
|
123
|
+
},
|
|
124
|
+
loadFromFile: (path) => {
|
|
125
|
+
try {
|
|
126
|
+
const data = JSON.parse(readFileSync(path, 'utf-8'));
|
|
127
|
+
let loaded = 0;
|
|
128
|
+
for (const [pn, lid] of Object.entries(data)) {
|
|
129
|
+
loaded += addPair(pn, lid) ? 1 : 0;
|
|
130
|
+
}
|
|
131
|
+
return loaded;
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
return 0;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
return store;
|
|
139
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { WAMessageContent } from '../Types/index.js';
|
|
2
|
+
export interface SentMessageCache {
|
|
3
|
+
add(remoteJid: string, id: string, message: WAMessageContent): void;
|
|
4
|
+
get(remoteJid: string, id: string): WAMessageContent | undefined;
|
|
5
|
+
readonly size: number;
|
|
6
|
+
clear(): void;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Create a bounded FIFO cache of recently relayed message contents,
|
|
10
|
+
* used to answer retry receipts when the app's `getMessage` store
|
|
11
|
+
* has no copy. Default capacity 256.
|
|
12
|
+
*/
|
|
13
|
+
export declare const makeSentMessageCache: (maxEntries?: number) => SentMessageCache;
|
|
14
|
+
/** Returns the per-socket cache bound to a socket config object (internal plumbing, also handy in tests). */
|
|
15
|
+
export declare const sentMessageCacheFor: (config: object) => SentMessageCache;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AunuBaileys sent-message cache for retry receipts.
|
|
3
|
+
*
|
|
4
|
+
* When a peer cannot decrypt a message we sent, WhatsApp asks for a
|
|
5
|
+
* resend via a retry receipt. Upstream Baileys can only answer when
|
|
6
|
+
* the app supplied a `getMessage` store; with the default
|
|
7
|
+
* `getMessage: async () => undefined` every retry dies with
|
|
8
|
+
* "message not available" and the peer never receives the message
|
|
9
|
+
* (the classic "read but never delivered / stuck unreadable" bug).
|
|
10
|
+
*
|
|
11
|
+
* This cache keeps the last N relayed message contents per socket
|
|
12
|
+
* (whatsmeow-style, default 256) so `sendMessagesAgain` can fall
|
|
13
|
+
* back to it when the app's own `getMessage` has nothing. The app's
|
|
14
|
+
* store always wins; this is only a fallback. Set
|
|
15
|
+
* `sentMessagesCacheSize: 0` in the socket config to disable.
|
|
16
|
+
*/
|
|
17
|
+
export const makeSentMessageCache = (maxEntries = 256) => {
|
|
18
|
+
const cache = new Map();
|
|
19
|
+
const keyOf = (remoteJid, id) => `${remoteJid}:${id}`;
|
|
20
|
+
return {
|
|
21
|
+
add: (remoteJid, id, message) => {
|
|
22
|
+
if (!remoteJid || !id || !message || maxEntries <= 0) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const key = keyOf(remoteJid, id);
|
|
26
|
+
cache.delete(key);
|
|
27
|
+
cache.set(key, message);
|
|
28
|
+
while (cache.size > maxEntries) {
|
|
29
|
+
cache.delete(cache.keys().next().value);
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
get: (remoteJid, id) => {
|
|
33
|
+
if (!remoteJid || !id) {
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
return cache.get(keyOf(remoteJid, id));
|
|
37
|
+
},
|
|
38
|
+
get size() {
|
|
39
|
+
return cache.size;
|
|
40
|
+
},
|
|
41
|
+
clear: () => cache.clear()
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
const cachesByConfig = new WeakMap();
|
|
45
|
+
/**
|
|
46
|
+
* Returns the per-socket sent-message cache bound to a socket
|
|
47
|
+
* config object. Send and receive layers of the same socket share
|
|
48
|
+
* one config object, so a WeakMap keyed by it gives every socket
|
|
49
|
+
* its own isolated cache without any extra plumbing.
|
|
50
|
+
*/
|
|
51
|
+
export const sentMessageCacheFor = (config) => {
|
|
52
|
+
let cache = cachesByConfig.get(config);
|
|
53
|
+
if (!cache) {
|
|
54
|
+
const size = typeof config?.sentMessagesCacheSize === 'number' ? config.sentMessagesCacheSize : 256;
|
|
55
|
+
cache = makeSentMessageCache(size);
|
|
56
|
+
cachesByConfig.set(config, cache);
|
|
57
|
+
}
|
|
58
|
+
return cache;
|
|
59
|
+
};
|
package/lib/index.d.ts
CHANGED
|
@@ -15,3 +15,6 @@ export { processedMessages, initInMemoryKeyStore } from './Utils/fork-compat.js'
|
|
|
15
15
|
export { PHONENUMBER_MCC } from './Utils/phonenumber-mcc.js';
|
|
16
16
|
export * from './Utils/aunu-handler';
|
|
17
17
|
export * from './Utils/builders';
|
|
18
|
+
export * from './Utils/antiban';
|
|
19
|
+
export * from './Utils/lid-store.js';
|
|
20
|
+
export * from './Utils/sent-message-cache.js';
|
package/lib/index.js
CHANGED
|
@@ -14,3 +14,6 @@ export { processedMessages, initInMemoryKeyStore } from './Utils/fork-compat.js'
|
|
|
14
14
|
export { PHONENUMBER_MCC } from './Utils/phonenumber-mcc.js';
|
|
15
15
|
export * from './Utils/aunu-handler.js';
|
|
16
16
|
export * from './Utils/builders.js';
|
|
17
|
+
export * from './Utils/antiban.js';
|
|
18
|
+
export * from './Utils/lid-store.js';
|
|
19
|
+
export * from './Utils/sent-message-cache.js';
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aunubaileys",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.0.
|
|
5
|
-
"description": "AunuBaileys
|
|
4
|
+
"version": "1.0.10",
|
|
5
|
+
"description": "AunuBaileys \u2014 a WhatsApp Web API for bots that never sleep. Full upstream power with the beloved in-memory store restored and pairing that just works. Forged by AunuCore.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"whatsapp",
|
|
8
8
|
"whatsapp-web",
|