whatsapp-store-db 1.3.64 → 1.3.65

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "whatsapp-store-db",
3
- "version": "1.3.64",
3
+ "version": "1.3.65",
4
4
  "description": "Minimal Baileys data storage for your favorite DBMS built with Prisma",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -1,11 +1,13 @@
1
1
  diff --git a/node_modules/baileys/lib/Socket/messages-recv.js b/node_modules/baileys/lib/Socket/messages-recv.js
2
- index f2e2e10..476c2dc 100644
2
+ index f2e2e10..1535b62 100644
3
3
  --- a/node_modules/baileys/lib/Socket/messages-recv.js
4
4
  +++ b/node_modules/baileys/lib/Socket/messages-recv.js
5
- @@ -51,19 +51,21 @@ export const makeMessagesRecvSocket = (config) => {
5
+ @@ -50,20 +50,24 @@ export const makeMessagesRecvSocket = (config) => {
6
+ };
6
7
  return sendPeerDataOperationMessage(pdoMessage);
7
8
  };
8
- const requestPlaceholderResend = async (messageKey) => {
9
+ - const requestPlaceholderResend = async (messageKey) => {
10
+ + const requestPlaceholderResend = async (messageKey, msgData) => {
9
11
  + const sessionJid = authState.creds.me?.id || 'unknown';
10
12
  if (!authState.creds.me?.id) {
11
13
  throw new Boom('Not authenticated');
@@ -16,17 +18,21 @@ index f2e2e10..476c2dc 100644
16
18
  return;
17
19
  }
18
20
  else {
19
- await placeholderResendCache.set(messageKey?.id, true);
21
+ - await placeholderResendCache.set(messageKey?.id, true);
22
+ + // Store original message data so PDO response handler can preserve
23
+ + // metadata (LID details, timestamps, pushName, etc.) that the phone may omit
24
+ + await placeholderResendCache.set(messageKey?.id, msgData || true);
20
25
  }
21
- + logger.error({ session: sessionJid, msgId: messageKey?.id, remoteJid: messageKey?.remoteJid }, 'CTWA_TRACE: Waiting 5s before sending PDO request');
22
- await delay(5000);
26
+ - await delay(5000);
27
+ + logger.error({ session: sessionJid, msgId: messageKey?.id, remoteJid: messageKey?.remoteJid }, 'CTWA_TRACE: Waiting 2s before sending PDO request');
28
+ + await delay(2000);
23
29
  if (!placeholderResendCache.get(messageKey?.id)) {
24
30
  - logger.debug({ messageKey }, 'message received while resend requested');
25
31
  + logger.error({ session: sessionJid, msgId: messageKey?.id, remoteJid: messageKey?.remoteJid }, 'CTWA_TRACE: Message arrived during 5s wait, no PDO needed');
26
32
  return 'RESOLVED';
27
33
  }
28
34
  const pdoMessage = {
29
- @@ -74,13 +76,51 @@ export const makeMessagesRecvSocket = (config) => {
35
+ @@ -74,13 +78,51 @@ export const makeMessagesRecvSocket = (config) => {
30
36
  ],
31
37
  peerDataOperationRequestType: proto.Message.PeerDataOperationRequestType.PLACEHOLDER_MESSAGE_RESEND
32
38
  };
@@ -85,13 +91,14 @@ index f2e2e10..476c2dc 100644
85
91
  };
86
92
  // Handles mex newsletter notifications
87
93
  const handleMexNewsletterNotification = async (node) => {
88
- @@ -987,53 +1027,85 @@ export const makeMessagesRecvSocket = (config) => {
94
+ @@ -987,53 +1029,125 @@ export const makeMessagesRecvSocket = (config) => {
89
95
  await processingMutex.mutex(async () => {
90
96
  await decrypt();
91
97
  // message failed to decrypt
92
98
  - if (msg.messageStubType === proto.WebMessageInfo.StubType.CIPHERTEXT && msg.category !== 'peer') {
93
99
  - if (msg?.messageStubParameters?.[0] === MISSING_KEYS_ERROR_TEXT ||
94
100
  - msg.messageStubParameters?.[0] === NO_MESSAGE_FOUND_ERROR_TEXT) {
101
+ - return sendMessageAck(node);
95
102
  + if (msg.messageStubType === proto.WebMessageInfo.StubType.CIPHERTEXT) {
96
103
  + const sessionJid = authState.creds.me?.id || 'unknown';
97
104
  + const stubParam = msg?.messageStubParameters?.[0] || '';
@@ -102,15 +109,53 @@ index f2e2e10..476c2dc 100644
102
109
  + // regardless of message category, because CTWA messages may arrive with any
103
110
  + // category value including 'peer'.
104
111
  + if (stubParam === NO_MESSAGE_FOUND_ERROR_TEXT) {
112
+ + // Filter out unavailable types that shouldn't trigger PDO (from official fix)
113
+ + const unavailableNode = getBinaryNodeChild(node, 'unavailable');
114
+ + const unavailableType = unavailableNode?.attrs?.type;
115
+ + if (
116
+ + unavailableType === 'bot_unavailable_fanout' ||
117
+ + unavailableType === 'hosted_unavailable_fanout' ||
118
+ + unavailableType === 'view_once_unavailable_fanout'
119
+ + ) {
120
+ + logger.error({ session: sessionJid, msgId: msg.key?.id, unavailableType }, 'CTWA_TRACE: Skipping placeholder resend for excluded unavailable type');
121
+ + return sendMessageAck(node);
122
+ + }
123
+ + // Skip PDO for messages older than 14 days (WA Web enforces this limit)
124
+ + const PLACEHOLDER_MAX_AGE_SECONDS = 14 * 24 * 60 * 60;
125
+ + const messageAge = unixTimestampSeconds() - (typeof msg.messageTimestamp === 'number' ? msg.messageTimestamp : Number(msg.messageTimestamp || 0));
126
+ + if (messageAge > PLACEHOLDER_MAX_AGE_SECONDS) {
127
+ + logger.error({ session: sessionJid, msgId: msg.key?.id, messageAge }, 'CTWA_TRACE: Skipping placeholder resend for old message (>14 days)');
128
+ + return sendMessageAck(node);
129
+ + }
105
130
  + if (msg.key) {
106
131
  + logger.error({ session: sessionJid, msgId: msg.key.id, remoteJid: msg.key.remoteJid, fromMe: msg.key.fromMe, category, msgCategory: msg.category }, 'CTWA: Message absent from node detected, requesting placeholder resend from phone');
107
- + requestPlaceholderResend(msg.key)
132
+ + // Build clean key and cache original metadata (from official fix)
133
+ + // so PDO response handler can preserve LID details, timestamps, etc.
134
+ + const cleanKey = {
135
+ + remoteJid: msg.key.remoteJid,
136
+ + fromMe: msg.key.fromMe,
137
+ + id: msg.key.id,
138
+ + participant: msg.key.participant
139
+ + };
140
+ + const msgData = {
141
+ + key: msg.key,
142
+ + messageTimestamp: msg.messageTimestamp,
143
+ + pushName: msg.pushName,
144
+ + participant: msg.participant,
145
+ + verifiedBizName: msg.verifiedBizName
146
+ + };
147
+ + requestPlaceholderResend(cleanKey, msgData)
108
148
  + .then((result) => {
109
149
  + if (result === 'RESOLVED') {
110
150
  + logger.error({ session: sessionJid, msgId: msg.key.id, remoteJid: msg.key.remoteJid }, 'CTWA: Message received during resend delay');
111
151
  + }
112
152
  + else if (result) {
113
153
  + logger.error({ session: sessionJid, msgId: msg.key.id, remoteJid: msg.key.remoteJid, requestId: result }, 'CTWA: Placeholder resend PDO request sent');
154
+ + // Store requestId in stubParameters for correlation (from official fix)
155
+ + ev.emit('messages.update', [{
156
+ + key: msg.key,
157
+ + update: { messageStubParameters: [NO_MESSAGE_FOUND_ERROR_TEXT, result] }
158
+ + }]);
114
159
  + }
115
160
  + else {
116
161
  + logger.error({ session: sessionJid, msgId: msg.key.id, remoteJid: msg.key.remoteJid }, 'CTWA: Placeholder resend skipped (already requested or dedup)');
@@ -120,7 +165,9 @@ index f2e2e10..476c2dc 100644
120
165
  + logger.error({ session: sessionJid, error, msgId: msg.key.id }, 'CTWA: Failed to request placeholder resend');
121
166
  + });
122
167
  + }
123
- return sendMessageAck(node);
168
+ + // ACK but DON'T return — fall through to upsertMessage so the
169
+ + // CIPHERTEXT stub is emitted as a placeholder (from official fix)
170
+ + await sendMessageAck(node);
124
171
  }
125
172
  - const errorMessage = msg?.messageStubParameters?.[0] || '';
126
173
  - const isPreKeyError = errorMessage.includes('PreKey');
@@ -152,7 +199,7 @@ index f2e2e10..476c2dc 100644
152
199
  - }
153
200
  + // For all other CIPHERTEXT errors, apply the category gate
154
201
  + // (peer category messages use a different retry mechanism)
155
- + if (msg.category !== 'peer') {
202
+ + else if (msg.category !== 'peer') {
156
203
  + if (stubParam === MISSING_KEYS_ERROR_TEXT) {
157
204
  + return sendMessageAck(node);
158
205
  }
@@ -211,46 +258,74 @@ index f2e2e10..476c2dc 100644
211
258
  else {
212
259
  const isNewsletter = isJidNewsletter(msg.key.remoteJid);
213
260
  diff --git a/node_modules/baileys/lib/Utils/process-message.js b/node_modules/baileys/lib/Utils/process-message.js
214
- index 7927483..76913a2 100644
261
+ index 7927483..7111219 100644
215
262
  --- a/node_modules/baileys/lib/Utils/process-message.js
216
263
  +++ b/node_modules/baileys/lib/Utils/process-message.js
217
- @@ -215,7 +215,19 @@ const processMessage = async (message, { shouldProcessHistoryMsg, placeholderRes
264
+ @@ -215,23 +215,99 @@ const processMessage = async (message, { shouldProcessHistoryMsg, placeholderRes
218
265
  case proto.Message.ProtocolMessage.Type.PEER_DATA_OPERATION_REQUEST_RESPONSE_MESSAGE:
219
266
  const response = protocolMsg.peerDataOperationRequestResponseMessage;
220
267
  if (response) {
221
268
  - await placeholderResendCache?.del(response.stanzaId);
222
- + // Fix cache key mismatch: response.stanzaId is the PDO request stanza ID,
223
- + // but the cache stores entries by original messageKey.id.
224
- + // Look up the original message ID from the pdo_ mapping, then delete both.
225
- + const originalMsgId = placeholderResendCache?.get(`pdo_${response.stanzaId}`);
226
- + if (originalMsgId) {
227
- + await placeholderResendCache?.del(originalMsgId);
228
- + await placeholderResendCache?.del(`pdo_${response.stanzaId}`);
229
- + logger.error({ session: meId, stanzaId: response.stanzaId, originalMsgId }, 'CTWA_TRACE: Cleared cache for PDO response (mapped key)');
230
- + }
231
- + else {
232
- + // Fallback: try deleting by stanzaId directly (original behavior)
233
- + await placeholderResendCache?.del(response.stanzaId);
234
- + }
235
269
  // TODO: IMPLEMENT HISTORY SYNC ETC (sticker uploads etc.).
236
- const { peerDataOperationResult } = response;
270
+ - const { peerDataOperationResult } = response;
271
+ + const peerDataOperationResult = response.peerDataOperationResult || [];
237
272
  for (const result of peerDataOperationResult) {
238
- @@ -223,8 +235,54 @@ const processMessage = async (message, { shouldProcessHistoryMsg, placeholderRes
273
+ - const { placeholderMessageResendResponse: retryResponse } = result;
274
+ + const retryResponse = result?.placeholderMessageResendResponse;
239
275
  //eslint-disable-next-line max-depth
240
- if (retryResponse) {
276
+ - if (retryResponse) {
277
+ + if (!retryResponse?.webMessageInfoBytes) {
278
+ + continue;
279
+ + }
280
+ + //eslint-disable-next-line max-depth
281
+ + try {
241
282
  const webMessageInfo = proto.WebMessageInfo.decode(retryResponse.webMessageInfoBytes);
242
283
  - // wait till another upsert event is available, don't want it to be part of the PDO response message
243
284
  - // TODO: parse through proper message handling utilities (to add relevant key fields)
244
- + if (webMessageInfo.key?.remoteJid) {
245
- + const rawJid = webMessageInfo.key.remoteJid;
285
+ - setTimeout(() => {
286
+ - ev.emit('messages.upsert', {
287
+ - messages: [webMessageInfo],
288
+ - type: 'notify',
289
+ - requestId: response.stanzaId
290
+ - });
291
+ - }, 500);
292
+ + const msgId = webMessageInfo.key?.id;
293
+ + // Retrieve cached original message data (from official fix)
294
+ + // Preserves LID details, timestamps, pushName, etc. that the phone may omit
295
+ + const cachedData = msgId ? placeholderResendCache?.get(msgId) : undefined;
296
+ + //eslint-disable-next-line max-depth
297
+ + if (msgId) {
298
+ + await placeholderResendCache?.del(msgId);
299
+ + // Also clean up pdo_ mapping entries
300
+ + await placeholderResendCache?.del(`pdo_${response.stanzaId}`);
301
+ + logger.error({ session: meId, stanzaId: response.stanzaId, msgId }, 'CTWA_TRACE: Cleared cache for PDO response');
302
+ + }
303
+ + let finalMsg;
304
+ + //eslint-disable-next-line max-depth
305
+ + if (cachedData && typeof cachedData === 'object') {
306
+ + // Apply decoded message content onto cached metadata (from official fix)
307
+ + // This preserves LID details, timestamps, pushName, etc.
308
+ + cachedData.message = webMessageInfo.message;
309
+ + if (webMessageInfo.messageTimestamp) {
310
+ + cachedData.messageTimestamp = webMessageInfo.messageTimestamp;
311
+ + }
312
+ + finalMsg = cachedData;
313
+ + logger.error({ session: meId, msgId }, 'CTWA_TRACE: Merged PDO content with cached metadata');
314
+ + }
315
+ + else {
316
+ + finalMsg = webMessageInfo;
317
+ + }
318
+ + // Apply LID resolution and JID normalization (our enhancement)
319
+ + if (finalMsg.key?.remoteJid) {
320
+ + const rawJid = finalMsg.key.remoteJid;
246
321
  + if (isLidUser(rawJid)) {
247
322
  + try {
248
323
  + const pn = await signalRepository.lidMapping.getPNForLID(rawJid);
249
324
  + if (pn) {
250
325
  + const phoneJid = jidNormalizedUser(pn.includes('@') ? pn : `${pn}@s.whatsapp.net`);
251
326
  + logger.error({ session: meId, lid: rawJid, resolved: phoneJid }, 'CTWA: Resolved LID to phone number for recovered message');
252
- + webMessageInfo.key.remoteJidAlt = rawJid;
253
- + webMessageInfo.key.remoteJid = phoneJid;
327
+ + finalMsg.key.remoteJidAlt = rawJid;
328
+ + finalMsg.key.remoteJid = phoneJid;
254
329
  + }
255
330
  + else {
256
331
  + logger.error({ session: meId, lid: rawJid }, 'CTWA: Could not resolve LID to phone number - no mapping found');
@@ -264,34 +339,41 @@ index 7927483..76913a2 100644
264
339
  + const normalized = jidNormalizedUser(rawJid);
265
340
  + if (normalized !== rawJid) {
266
341
  + logger.error({ session: meId, rawJid, normalized }, 'CTWA: Normalized remoteJid (stripped device suffix)');
267
- + webMessageInfo.key.remoteJid = normalized;
342
+ + finalMsg.key.remoteJid = normalized;
268
343
  + }
269
344
  + }
270
345
  + }
271
- + // Apply cleanMessage normalization (same as normal messages)
272
346
  + // Normalize participant JID if present
273
- + if (webMessageInfo.key?.participant) {
274
- + const normalizedParticipant = jidNormalizedUser(webMessageInfo.key.participant);
275
- + if (normalizedParticipant !== webMessageInfo.key.participant) {
276
- + webMessageInfo.key.participant = normalizedParticipant;
347
+ + if (finalMsg.key?.participant) {
348
+ + const normalizedParticipant = jidNormalizedUser(finalMsg.key.participant);
349
+ + if (normalizedParticipant !== finalMsg.key.participant) {
350
+ + finalMsg.key.participant = normalizedParticipant;
277
351
  + }
278
352
  + }
279
- + const recoveredContent = webMessageInfo.message?.conversation
280
- + || webMessageInfo.message?.extendedTextMessage?.text
281
- + || webMessageInfo.message?.imageMessage?.caption
282
- + || webMessageInfo.message?.videoMessage?.caption
283
- + || (webMessageInfo.message?.imageMessage ? '[image]' : '')
284
- + || (webMessageInfo.message?.videoMessage ? '[video]' : '')
285
- + || (webMessageInfo.message?.audioMessage ? '[audio]' : '')
286
- + || (webMessageInfo.message?.documentMessage ? '[document]' : '')
287
- + || (webMessageInfo.message?.stickerMessage ? '[sticker]' : '')
288
- + || (webMessageInfo.message?.contactMessage ? '[contact]' : '')
289
- + || (webMessageInfo.message?.locationMessage ? '[location]' : '')
353
+ + const recoveredContent = finalMsg.message?.conversation
354
+ + || finalMsg.message?.extendedTextMessage?.text
355
+ + || finalMsg.message?.imageMessage?.caption
356
+ + || finalMsg.message?.videoMessage?.caption
357
+ + || (finalMsg.message?.imageMessage ? '[image]' : '')
358
+ + || (finalMsg.message?.videoMessage ? '[video]' : '')
359
+ + || (finalMsg.message?.audioMessage ? '[audio]' : '')
360
+ + || (finalMsg.message?.documentMessage ? '[document]' : '')
361
+ + || (finalMsg.message?.stickerMessage ? '[sticker]' : '')
362
+ + || (finalMsg.message?.contactMessage ? '[contact]' : '')
363
+ + || (finalMsg.message?.locationMessage ? '[location]' : '')
290
364
  + || '[unknown type]';
291
- + logger.error({ session: meId, msgId: webMessageInfo.key?.id, remoteJid: webMessageInfo.key?.remoteJid, recoveredContent, requestId: response.stanzaId }, 'CTWA: Message recovered from phone via PDO');
292
- setTimeout(() => {
293
- ev.emit('messages.upsert', {
294
- messages: [webMessageInfo],
365
+ + logger.error({ session: meId, msgId: finalMsg.key?.id, remoteJid: finalMsg.key?.remoteJid, recoveredContent, requestId: response.stanzaId }, 'CTWA: Message recovered from phone via PDO');
366
+ + ev.emit('messages.upsert', {
367
+ + messages: [finalMsg],
368
+ + type: 'notify',
369
+ + requestId: response.stanzaId
370
+ + });
371
+ + }
372
+ + catch (err) {
373
+ + logger.error({ session: meId, err, stanzaId: response.stanzaId }, 'CTWA: Failed to decode placeholder resend response');
374
+ }
375
+ }
376
+ }
295
377
  diff --git a/node_modules/baileys/lib/Utils/validate-connection.js b/node_modules/baileys/lib/Utils/validate-connection.js
296
378
  index 42fb902..38a2e0c 100644
297
379
  --- a/node_modules/baileys/lib/Utils/validate-connection.js