aunubaileys 1.0.26 → 1.0.28
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/Socket/messages-recv.js +16 -2
- package/lib/Socket/messages-send.js +5 -0
- package/lib/Utils/antiban.d.ts +3 -0
- package/lib/Utils/antiban.js +35 -0
- package/package.json +1 -1
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.28 / Baru di 1.0.28
|
|
68
|
+
|
|
69
|
+
- 📱 **Device lists no longer go stale after a device is linked or unlinked** — the server pushes a `devices` notification on such changes, but upstream only logged its own list and ignored everyone else's, so sends kept encrypting for the cached device set until the 5-minute TTL expired: a newly linked device received nothing and a removed device kept getting ciphertext. The notification now invalidates that user's cached entry, so the next send re-queries USync for the fresh list. The cache is also exposed as `sock.userDevicesCache` for explicit invalidation.
|
|
70
|
+
|
|
71
|
+
### 🆕 What's new in 1.0.27 / Baru di 1.0.27
|
|
72
|
+
|
|
73
|
+
- ⏱️ **New `getReconnectDelay(attempt, reason)` helper** — the companion to AunuAntiBan's `classifyDisconnect`: it turns a disconnect reason (Boom error, status code, or a classification result) into a suggested wait in milliseconds, or `null` when the connection must NOT be re-established automatically (logged out, replaced, bad session, 403). Server-requested restarts return 0; transient failures back off exponentially with Gaussian jitter (1s base, 60s cap); rate limits back off much longer (30s base, 15 min cap). `baseDelayMs` / `maxDelayMs` overrides available.
|
|
74
|
+
|
|
67
75
|
### 🆕 What's new in 1.0.26 / Baru di 1.0.26
|
|
68
76
|
|
|
69
77
|
- 📡 **`fetchLatestBaileysVersion` now remembers the last-good fetched version** — it is called on every reconnect and used to hit the network every time; a mid-session fetch failure silently downgraded to the bundled version, even though the endpoint value is the only server-accepted truth (see 1.0.13). Successful fetches are now cached for 10 minutes, and a later failure returns the last fetched version instead of the bundled one. New `forceRefresh` / `cacheTtlMs` options.
|
|
@@ -14,7 +14,7 @@ import { makeMessagesSocket } from './messages-send.js';
|
|
|
14
14
|
export const makeMessagesRecvSocket = (config) => {
|
|
15
15
|
const { logger, retryRequestDelayMs, maxMsgRetryCount, getMessage, shouldIgnoreJid } = config;
|
|
16
16
|
const sock = makeMessagesSocket(config);
|
|
17
|
-
const { ev, authState, ws, processingMutex, signalRepository, query, upsertMessage, resyncAppState, onUnexpectedError, assertSessions, sendNode, relayMessage, sendReceipt, uploadPreKeys, sendPeerDataOperationMessage } = sock;
|
|
17
|
+
const { ev, authState, ws, processingMutex, signalRepository, query, upsertMessage, resyncAppState, onUnexpectedError, assertSessions, sendNode, relayMessage, sendReceipt, uploadPreKeys, sendPeerDataOperationMessage, userDevicesCache } = sock;
|
|
18
18
|
/** AunuBaileys: consecutive decrypt failures per signal address.
|
|
19
19
|
* WhatsApp clients heal a rotten (Bad MAC) session by dropping it and
|
|
20
20
|
* letting the peer re-initiate from the key bundle in our retry receipt;
|
|
@@ -331,13 +331,27 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
331
331
|
case 'encrypt':
|
|
332
332
|
await handleEncryptNotification(node);
|
|
333
333
|
break;
|
|
334
|
-
case 'devices':
|
|
334
|
+
case 'devices': {
|
|
335
335
|
const devices = getBinaryNodeChildren(child, 'device');
|
|
336
336
|
if (areJidsSameUser(child.attrs.jid, authState.creds.me.id)) {
|
|
337
337
|
const deviceJids = devices.map(d => d.attrs.jid);
|
|
338
338
|
logger.info({ deviceJids }, 'got my own devices');
|
|
339
339
|
}
|
|
340
|
+
// AunuBaileys: this notification means a device list
|
|
341
|
+
// CHANGED (device linked or unlinked). Upstream logged
|
|
342
|
+
// its own list and ignored everyone else's, so the send
|
|
343
|
+
// path kept encrypting for the cached device set until
|
|
344
|
+
// the cache TTL (5 min) expired — a newly linked device
|
|
345
|
+
// received nothing meanwhile and a removed device kept
|
|
346
|
+
// getting ciphertext. Drop the cached entry so the next
|
|
347
|
+
// send re-queries USync for the fresh list.
|
|
348
|
+
const changedUser = jidDecode(child.attrs.jid)?.user;
|
|
349
|
+
if (changedUser) {
|
|
350
|
+
userDevicesCache?.del(changedUser);
|
|
351
|
+
logger.debug({ changedUser }, 'aunu: device cache invalidated on devices notification');
|
|
352
|
+
}
|
|
340
353
|
break;
|
|
354
|
+
}
|
|
341
355
|
case 'server_sync':
|
|
342
356
|
const update = getBinaryNodeChild(node, 'collection');
|
|
343
357
|
if (update) {
|
|
@@ -616,6 +616,11 @@ export const makeMessagesSocket = (config) => {
|
|
|
616
616
|
sendPeerDataOperationMessage,
|
|
617
617
|
createParticipantNodes,
|
|
618
618
|
getUSyncDevices,
|
|
619
|
+
// AunuBaileys: exposed so the notification layer can invalidate a
|
|
620
|
+
// user's entry when the server pushes a device-list change
|
|
621
|
+
// (upstream kept the cache private to this closure, so nothing
|
|
622
|
+
// could ever invalidate it before its TTL expired).
|
|
623
|
+
userDevicesCache,
|
|
619
624
|
updateMediaMessage: async (message) => {
|
|
620
625
|
const content = assertMediaContent(message.message);
|
|
621
626
|
const mediaKey = content.mediaKey;
|
package/lib/Utils/antiban.d.ts
CHANGED
|
@@ -7,6 +7,9 @@ export declare class RateLimiter {
|
|
|
7
7
|
}
|
|
8
8
|
export interface DisconnectClassification { category: string; action: 'stop' | 'restart' | 'reconnect' | 'backoff'; detail: string; }
|
|
9
9
|
export declare const classifyDisconnect: (error: unknown) => DisconnectClassification;
|
|
10
|
+
export interface ReconnectDelayOptions { baseDelayMs?: number; maxDelayMs?: number; }
|
|
11
|
+
/** Suggested reconnect delay in ms for a disconnect reason (error, status code, or a classifyDisconnect result); null when the connection must NOT be re-established automatically. */
|
|
12
|
+
export declare const getReconnectDelay: (attempt: number, reason: unknown, options?: ReconnectDelayOptions) => number | null;
|
|
10
13
|
export interface AunuAntiBanOptions {
|
|
11
14
|
perChatPerMinute?: number; globalPerMinute?: number; minDelayMs?: number; jitterMs?: number;
|
|
12
15
|
warmupDays?: number; warmupStart?: number; typingSimulation?: boolean;
|
package/lib/Utils/antiban.js
CHANGED
|
@@ -166,5 +166,40 @@ export class AunuAntiBan {
|
|
|
166
166
|
}
|
|
167
167
|
}
|
|
168
168
|
|
|
169
|
+
/**
|
|
170
|
+
* Jeda reconnect yang disarankan, pendamping classifyDisconnect.
|
|
171
|
+
* Mengembalikan milidetik untuk menunggu sebelum reconnect, atau null
|
|
172
|
+
* bila koneksi TIDAK boleh disambung ulang otomatis (sesi logout,
|
|
173
|
+
* digantikan, rusak, atau 403). `reason` boleh berupa error Boom,
|
|
174
|
+
* kode status numerik, atau hasil classifyDisconnect ({ action } /
|
|
175
|
+
* { category }). Backoff eksponensial + jitter Gaussian; kategori
|
|
176
|
+
* rate_limited memakai basis dan plafon jauh lebih besar karena
|
|
177
|
+
* reconnect terlalu cepat pada 429 memperburuk pembatasan.
|
|
178
|
+
*/
|
|
179
|
+
export const getReconnectDelay = (attempt, reason, options = {}) => {
|
|
180
|
+
const a = Math.max(0, Math.floor(+attempt) || 0);
|
|
181
|
+
let action;
|
|
182
|
+
if (reason && typeof reason === 'object' && typeof reason.action === 'string') {
|
|
183
|
+
action = reason.action;
|
|
184
|
+
}
|
|
185
|
+
else if (reason && typeof reason === 'object' && typeof reason.category === 'string') {
|
|
186
|
+
action = { logged_out: 'stop', replaced: 'stop', bad_session: 'stop', mismatch: 'stop', forbidden: 'stop', restart_required: 'restart', rate_limited: 'backoff', transient: 'reconnect' }[reason.category] ?? 'reconnect';
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
action = classifyDisconnect(reason).action;
|
|
190
|
+
}
|
|
191
|
+
if (action === 'stop') {
|
|
192
|
+
return null;
|
|
193
|
+
}
|
|
194
|
+
if (action === 'restart') {
|
|
195
|
+
return 0;
|
|
196
|
+
}
|
|
197
|
+
const isRateLimited = action === 'backoff';
|
|
198
|
+
const base = options.baseDelayMs ?? (isRateLimited ? 30000 : 1000);
|
|
199
|
+
const cap = options.maxDelayMs ?? (isRateLimited ? 900000 : 60000);
|
|
200
|
+
const grown = Math.min(cap, base * 2 ** a);
|
|
201
|
+
return Math.round(grown + gaussianJitter(0, grown * 0.1));
|
|
202
|
+
};
|
|
203
|
+
|
|
169
204
|
/** Bungkus socket dengan AunuAntiBan (jalan pintas). */
|
|
170
205
|
export const wrapAntiBan = (sock, options) => new AunuAntiBan(options).wrap(sock);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aunubaileys",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.28",
|
|
5
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",
|