aunubaileys 1.0.27 โ†’ 1.0.29

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 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.29 / Baru di 1.0.29
68
+
69
+ - ๐Ÿงน **Resend counters are now cleared when the retry limit is reached** โ€” every message a peer asked us to resend left a permanent counter entry in the retry cache, removed only by the cache TTL (1h on the default cache โ€” nothing at all on a consumer store without TTL), so entries accumulated without bound in a long-lived bot. The entry is now deleted when its count hits the limit, exactly like `sendRetryRequest` already does on the decrypt-retry path.
70
+
71
+ ### ๐Ÿ†• What's new in 1.0.28 / Baru di 1.0.28
72
+
73
+ - ๐Ÿ“ฑ **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.
74
+
67
75
  ### ๐Ÿ†• What's new in 1.0.27 / Baru di 1.0.27
68
76
 
69
77
  - โฑ๏ธ **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.
@@ -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) {
@@ -479,7 +493,19 @@ export const makeMessagesRecvSocket = (config) => {
479
493
  const updateSendMessageAgainCount = (id, participant) => {
480
494
  const key = `${id}:${participant}`;
481
495
  const newValue = (msgRetryCache.get(key) || 0) + 1;
482
- msgRetryCache.set(key, newValue);
496
+ // AunuBaileys: clear the entry when the limit is reached, exactly
497
+ // like sendRetryRequest already does on its path. This path never
498
+ // deleted anything, so every message a peer ever asked us to
499
+ // resend left a permanent counter entry that only the cache TTL
500
+ // (1h on the default cache โ€” and nothing at all on a consumer
501
+ // store without TTL) ever removed: unbounded growth in a
502
+ // long-lived bot process.
503
+ if (newValue >= maxMsgRetryCount) {
504
+ msgRetryCache.del(key);
505
+ }
506
+ else {
507
+ msgRetryCache.set(key, newValue);
508
+ }
483
509
  };
484
510
  const sendMessagesAgain = async (key, ids, retryNode, sessionPreInjected = false) => {
485
511
  const msgs = await Promise.all(ids.map(async (id) => (await getMessage({ ...key, id })) ?? sentMessageCacheFor(config).get(key.remoteJid, id)));
@@ -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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "aunubaileys",
3
3
  "type": "module",
4
- "version": "1.0.27",
4
+ "version": "1.0.29",
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",