aunubaileys 1.0.19 → 1.0.21

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.21 / Baru di 1.0.21
68
+
69
+ - 💾 **saveCreds writes are coalesced** — during pairing, `creds.update` fires many times per second and every event used to queue a full atomic creds.json write. Concurrent `saveCreds()` calls now share one in-flight write, and a call landing mid-write schedules exactly one follow-up, so the file always ends with the latest creds — verified: a 30-call burst produced only ~2–3 real writes instead of 30.
70
+
71
+ ### 🆕 What's new in 1.0.20 / Baru di 1.0.20
72
+
73
+ - ⏳ **Sends survive reconnect blips** — calling `sendMessage` while the connection is re-establishing used to fail instantly with a 428 from the first internal query, and the message was simply lost. `relayMessage` now waits for the transport to reopen (bounded by `connectTimeoutMs`; a permanently closed connection still fails fast, and a wait that expires raises a clear 408). When the connection is open, behaviour is unchanged.
74
+
67
75
  ### 🆕 What's new in 1.0.19 / Baru di 1.0.19
68
76
 
69
77
  - 🛟 **A failed retry request can no longer kill your bot** — the retry-receipt path after a decrypt failure runs fire-and-forget (by design), but its promise had no error handler at all: one failure inside it became an unhandled rejection, and Node's default policy terminates the whole process. It now routes to the standard error handler — logged, contained, and the bot keeps processing messages.
@@ -12,7 +12,7 @@ import { makeNewsletterSocket } from './newsletter.js';
12
12
  export const makeMessagesSocket = (config) => {
13
13
  const { logger, linkPreviewImageThumbnailWidth, generateHighQualityLinkPreview, options: axiosOptions, patchMessageBeforeSending, cachedGroupMetadata } = config;
14
14
  const sock = makeNewsletterSocket(makeGroupsSocket(config));
15
- const { ev, authState, processingMutex, signalRepository, upsertMessage, query, fetchPrivacySettings, sendNode, groupMetadata, groupToggleEphemeral } = sock;
15
+ const { ev, authState, processingMutex, signalRepository, upsertMessage, query, fetchPrivacySettings, sendNode, groupMetadata, groupToggleEphemeral, ws, waitForSocketOpen } = sock;
16
16
  const userDevicesCache = config.userDevicesCache ||
17
17
  new NodeCache({
18
18
  stdTTL: DEFAULT_CACHE_TTLS.USER_DEVICES, // 5 minutes
@@ -269,6 +269,20 @@ export const makeMessagesSocket = (config) => {
269
269
  return { nodes, shouldIncludeDeviceIdentity };
270
270
  };
271
271
  const relayMessage = async (jid, message, { messageId: msgId, participant, additionalAttributes, additionalNodes, useUserDevicesCache, useCachedGroupMetadata, statusJidList }) => {
272
+ if (!ws.isOpen) {
273
+ // AunuBaileys: a send attempted during a reconnect window used to die
274
+ // instantly with Boom 428 from the first internal query — the message
275
+ // was simply lost unless the consumer retried. Now the send waits for
276
+ // the transport to reopen, bounded by connectTimeoutMs; a connection
277
+ // that closes for good still fails fast via waitForSocketOpen itself.
278
+ const waitMs = config.connectTimeoutMs ?? 60000;
279
+ await Promise.race([
280
+ waitForSocketOpen(),
281
+ delay(waitMs).then(() => {
282
+ throw new Boom(`Timed out waiting ${waitMs}ms for the connection to open before sending`, { statusCode: 408 }); // 408 = DisconnectReason.timedOut
283
+ })
284
+ ]);
285
+ }
272
286
  const meId = authState.creds.me.id;
273
287
  let shouldIncludeDeviceIdentity = false;
274
288
  const { user, server } = jidDecode(jid);
@@ -88,6 +88,8 @@ export const useMultiFileAuthState = async (folder) => {
88
88
  }
89
89
  const fixFileName = (file) => file?.replace(/\//g, '__')?.replace(/:/g, '-');
90
90
  const creds = (await readData('creds.json')) || initAuthCreds();
91
+ let credsWriteInFlight = null;
92
+ let credsWriteQueued = false;
91
93
  return {
92
94
  state: {
93
95
  creds,
@@ -117,7 +119,29 @@ export const useMultiFileAuthState = async (folder) => {
117
119
  }
118
120
  },
119
121
  saveCreds: async () => {
120
- return writeData(creds, 'creds.json');
122
+ // AunuBaileys: coalesce the write bursts. creds.update fires many
123
+ // times per second during pairing (registration, pre-key uploads,
124
+ // identity pushes); upstream queued one full atomic write per call
125
+ // on the file mutex, so pairing did dozens of redundant full-file
126
+ // writes. Concurrent callers now share one in-flight write, and a
127
+ // call landing mid-write schedules exactly ONE follow-up write so
128
+ // the file always ends with the LATEST creds.
129
+ if (credsWriteInFlight) {
130
+ credsWriteQueued = true;
131
+ return credsWriteInFlight;
132
+ }
133
+ credsWriteInFlight = (async () => {
134
+ try {
135
+ do {
136
+ credsWriteQueued = false;
137
+ await writeData(creds, 'creds.json');
138
+ } while (credsWriteQueued);
139
+ }
140
+ finally {
141
+ credsWriteInFlight = null;
142
+ }
143
+ })();
144
+ return credsWriteInFlight;
121
145
  }
122
146
  };
123
147
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "aunubaileys",
3
3
  "type": "module",
4
- "version": "1.0.19",
4
+ "version": "1.0.21",
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",