@jkt48connect-corp/baileys 7.3.2 → 7.3.4

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.
Files changed (80) hide show
  1. package/README.md +459 -143
  2. package/WAProto/WAProto.proto +227 -2
  3. package/lib/Defaults/baileys-version.json +1 -1
  4. package/lib/Defaults/index.d.ts +9 -7
  5. package/lib/Defaults/index.js +6 -4
  6. package/lib/Socket/Client/index.d.ts +2 -3
  7. package/lib/Socket/Client/index.js +2 -3
  8. package/lib/Socket/Client/types.d.ts +17 -0
  9. package/lib/Socket/Client/types.js +13 -0
  10. package/lib/Socket/Client/{web-socket-client.d.ts → websocket.d.ts} +1 -1
  11. package/lib/Socket/Client/{web-socket-client.js → websocket.js} +2 -2
  12. package/lib/Socket/business.d.ts +8 -3
  13. package/lib/Socket/chats.d.ts +21 -19
  14. package/lib/Socket/chats.js +51 -48
  15. package/lib/Socket/groups.d.ts +28 -26
  16. package/lib/Socket/groups.js +2 -1
  17. package/lib/Socket/index.d.ts +6 -3
  18. package/lib/Socket/messages-recv.d.ts +8 -3
  19. package/lib/Socket/messages-recv.js +308 -149
  20. package/lib/Socket/messages-send.d.ts +23 -26
  21. package/lib/Socket/messages-send.js +193 -166
  22. package/lib/Socket/newsletter.d.ts +2 -2
  23. package/lib/Socket/newsletter.js +3 -3
  24. package/lib/Socket/registration.d.ts +8 -3
  25. package/lib/Socket/socket.d.ts +8 -6
  26. package/lib/Socket/socket.js +19 -14
  27. package/lib/Socket/usync.d.ts +37 -0
  28. package/lib/Socket/usync.js +70 -0
  29. package/lib/Store/make-cache-manager-store.d.ts +2 -2
  30. package/lib/Store/make-ordered-dictionary.d.ts +1 -1
  31. package/lib/Types/Call.d.ts +1 -1
  32. package/lib/Types/Chat.d.ts +12 -7
  33. package/lib/Types/Events.d.ts +17 -2
  34. package/lib/Types/GroupMetadata.d.ts +3 -1
  35. package/lib/Types/Label.d.ts +11 -0
  36. package/lib/Types/Message.d.ts +324 -328
  37. package/lib/Types/Socket.d.ts +7 -0
  38. package/lib/Types/USync.d.ts +25 -0
  39. package/lib/Types/USync.js +2 -0
  40. package/lib/Types/index.d.ts +9 -0
  41. package/lib/Utils/chat-utils.d.ts +4 -4
  42. package/lib/Utils/chat-utils.js +41 -20
  43. package/lib/Utils/crypto.d.ts +1 -1
  44. package/lib/Utils/crypto.js +4 -2
  45. package/lib/Utils/decode-wa-message.d.ts +17 -0
  46. package/lib/Utils/decode-wa-message.js +42 -14
  47. package/lib/Utils/generics.d.ts +4 -10
  48. package/lib/Utils/generics.js +30 -14
  49. package/lib/Utils/history.d.ts +6 -2
  50. package/lib/Utils/history.js +3 -0
  51. package/lib/Utils/messages.d.ts +0 -1
  52. package/lib/Utils/messages.js +247 -39
  53. package/lib/Utils/signal.d.ts +2 -1
  54. package/lib/Utils/signal.js +11 -19
  55. package/lib/Utils/use-multi-file-auth-state.js +11 -3
  56. package/lib/Utils/validate-connection.d.ts +2 -2
  57. package/lib/Utils/validate-connection.js +1 -1
  58. package/lib/WABinary/encode.d.ts +1 -1
  59. package/lib/WABinary/encode.js +16 -10
  60. package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts +9 -0
  61. package/lib/WAUSync/Protocols/USyncContactProtocol.js +32 -0
  62. package/lib/WAUSync/Protocols/USyncDeviceProtocol.d.ts +22 -0
  63. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +57 -0
  64. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts +12 -0
  65. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +30 -0
  66. package/lib/WAUSync/Protocols/USyncStatusProtocol.d.ts +12 -0
  67. package/lib/WAUSync/Protocols/USyncStatusProtocol.js +42 -0
  68. package/lib/WAUSync/Protocols/index.d.ts +4 -0
  69. package/lib/WAUSync/Protocols/index.js +20 -0
  70. package/lib/WAUSync/USyncQuery.d.ts +26 -0
  71. package/lib/WAUSync/USyncQuery.js +79 -0
  72. package/lib/WAUSync/USyncUser.d.ts +10 -0
  73. package/lib/WAUSync/USyncUser.js +22 -0
  74. package/lib/WAUSync/index.d.ts +3 -0
  75. package/lib/WAUSync/index.js +19 -0
  76. package/lib/index.d.ts +1 -0
  77. package/lib/index.js +1 -0
  78. package/package.json +23 -18
  79. package/LICENSE +0 -21
  80. package/lib/index.ts +0 -13
@@ -19,7 +19,7 @@ const messages_send_1 = require("./messages-send");
19
19
  const makeMessagesRecvSocket = (config) => {
20
20
  const { logger, retryRequestDelayMs, maxMsgRetryCount, getMessage, shouldIgnoreJid } = config;
21
21
  const sock = (0, messages_send_1.makeMessagesSocket)(config);
22
- const { ev, authState, ws, processingMutex, signalRepository, query, upsertMessage, resyncAppState, onUnexpectedError, assertSessions, sendNode, relayMessage, sendReceipt, uploadPreKeys, getUSyncDevices, createParticipantNodes } = sock;
22
+ const { ev, authState, ws, processingMutex, signalRepository, query, upsertMessage, resyncAppState, onUnexpectedError, assertSessions, sendNode, relayMessage, sendReceipt, uploadPreKeys, getUSyncDevices, sendPeerDataOperationMessage, createParticipantNodes } = sock;
23
23
  /** this mutex ensures that each retryRequest will wait for the previous one to finish */
24
24
  const retryMutex = (0, make_mutex_1.makeMutex)();
25
25
  const msgRetryCache = config.msgRetryCounterCache || new node_cache_1.default({
@@ -30,23 +30,30 @@ const makeMessagesRecvSocket = (config) => {
30
30
  stdTTL: Defaults_1.DEFAULT_CACHE_TTLS.CALL_OFFER, // 5 mins
31
31
  useClones: false
32
32
  });
33
+ const placeholderResendCache = config.placeholderResendCache || new node_cache_1.default({
34
+ stdTTL: Defaults_1.DEFAULT_CACHE_TTLS.MSG_RETRY, // 1 hour
35
+ useClones: false
36
+ });
33
37
  let sendActiveReceipts = false;
34
- const sendMessageAck = async ({ tag, attrs, content }) => {
38
+ const sendMessageAck = async ({ tag, attrs, content }, errorCode) => {
35
39
  const stanza = {
36
40
  tag: 'ack',
37
41
  attrs: {
38
42
  id: attrs.id,
39
43
  to: attrs.from,
40
- class: tag,
44
+ class: tag
41
45
  }
42
46
  };
47
+ if (!!errorCode) {
48
+ stanza.attrs.error = errorCode.toString();
49
+ }
43
50
  if (!!attrs.participant) {
44
51
  stanza.attrs.participant = attrs.participant;
45
52
  }
46
53
  if (!!attrs.recipient) {
47
54
  stanza.attrs.recipient = attrs.recipient;
48
55
  }
49
- if (!!attrs.type && (tag !== 'message' || (0, WABinary_1.getBinaryNodeChild)({ tag, attrs, content }, 'unavailable'))) {
56
+ if (!!attrs.type && (tag !== 'message' || (0, WABinary_1.getBinaryNodeChild)({ tag, attrs, content }, 'unavailable') || errorCode !== 0)) {
50
57
  stanza.attrs.type = attrs.type;
51
58
  }
52
59
  if (tag === 'message' && (0, WABinary_1.getBinaryNodeChild)({ tag, attrs, content }, 'unavailable')) {
@@ -127,16 +134,24 @@ const makeMessagesRecvSocket = (config) => {
127
134
  await query(stanza);
128
135
  };
129
136
  const sendRetryRequest = async (node, forceIncludeKeys = false) => {
130
- const msgId = node.attrs.id;
131
- let retryCount = msgRetryCache.get(msgId) || 0;
137
+ const { fullMessage } = (0, Utils_1.decodeMessageNode)(node, authState.creds.me.id, authState.creds.me.lid || '');
138
+ const { key: msgKey } = fullMessage;
139
+ const msgId = msgKey.id;
140
+ const key = `${msgId}:${msgKey === null || msgKey === void 0 ? void 0 : msgKey.participant}`;
141
+ let retryCount = msgRetryCache.get(key) || 0;
132
142
  if (retryCount >= maxMsgRetryCount) {
133
143
  logger.debug({ retryCount, msgId }, 'reached retry limit, clearing');
134
- msgRetryCache.del(msgId);
144
+ msgRetryCache.del(key);
135
145
  return;
136
146
  }
137
147
  retryCount += 1;
138
- msgRetryCache.set(msgId, retryCount);
148
+ msgRetryCache.set(key, retryCount);
139
149
  const { account, signedPreKey, signedIdentityKey: identityKey } = authState.creds;
150
+ if (retryCount === 1) {
151
+ //request a resend via phone
152
+ const msgId = await requestPlaceholderResend(msgKey);
153
+ logger.debug(`sendRetryRequest: requested placeholder resend for message ${msgId}`);
154
+ }
140
155
  const deviceIdentity = (0, Utils_1.encodeSignedDeviceIdentity)(account, true);
141
156
  await authState.keys.transaction(async () => {
142
157
  const receipt = {
@@ -215,6 +230,8 @@ const makeMessagesRecvSocket = (config) => {
215
230
  }
216
231
  };
217
232
  const handleGroupNotification = (participant, child, msg) => {
233
+ var _a, _b, _c, _d;
234
+ const participantJid = ((_b = (_a = (0, WABinary_1.getBinaryNodeChild)(child, 'participant')) === null || _a === void 0 ? void 0 : _a.attrs) === null || _b === void 0 ? void 0 : _b.jid) || participant;
218
235
  switch (child === null || child === void 0 ? void 0 : child.tag) {
219
236
  case 'create':
220
237
  const metadata = (0, groups_1.extractGroupMetadata)(child);
@@ -240,6 +257,11 @@ const makeMessagesRecvSocket = (config) => {
240
257
  }
241
258
  };
242
259
  break;
260
+ case 'modify':
261
+ const oldNumber = (0, WABinary_1.getBinaryNodeChildren)(child, 'participant').map(p => p.attrs.jid);
262
+ msg.messageStubParameters = oldNumber || [];
263
+ msg.messageStubType = Types_1.WAMessageStubType.GROUP_PARTICIPANT_CHANGE_NUMBER;
264
+ break;
243
265
  case 'promote':
244
266
  case 'demote':
245
267
  case 'remove':
@@ -261,6 +283,11 @@ const makeMessagesRecvSocket = (config) => {
261
283
  msg.messageStubType = Types_1.WAMessageStubType.GROUP_CHANGE_SUBJECT;
262
284
  msg.messageStubParameters = [child.attrs.subject];
263
285
  break;
286
+ case 'description':
287
+ const description = (_d = (_c = (0, WABinary_1.getBinaryNodeChild)(child, 'body')) === null || _c === void 0 ? void 0 : _c.content) === null || _d === void 0 ? void 0 : _d.toString();
288
+ msg.messageStubType = Types_1.WAMessageStubType.GROUP_CHANGE_DESCRIPTION;
289
+ msg.messageStubParameters = description ? [description] : undefined;
290
+ break;
264
291
  case 'announcement':
265
292
  case 'not_announcement':
266
293
  msg.messageStubType = Types_1.WAMessageStubType.GROUP_CHANGE_ANNOUNCE;
@@ -289,6 +316,15 @@ const makeMessagesRecvSocket = (config) => {
289
316
  msg.messageStubParameters = [approvalMode.attrs.state];
290
317
  }
291
318
  break;
319
+ case 'created_membership_requests':
320
+ msg.messageStubType = Types_1.WAMessageStubType.GROUP_MEMBERSHIP_JOIN_APPROVAL_REQUEST_NON_ADMIN_ADD;
321
+ msg.messageStubParameters = [participantJid, 'created', child.attrs.request_method];
322
+ break;
323
+ case 'revoked_membership_requests':
324
+ const isDenied = (0, WABinary_1.areJidsSameUser)(participantJid, participant);
325
+ msg.messageStubType = Types_1.WAMessageStubType.GROUP_MEMBERSHIP_JOIN_APPROVAL_REQUEST_NON_ADMIN_ADD;
326
+ msg.messageStubParameters = [participantJid, isDenied ? 'revoked' : 'rejected'];
327
+ break;
292
328
  }
293
329
  };
294
330
  const processNotification = async (node) => {
@@ -321,9 +357,6 @@ const makeMessagesRecvSocket = (config) => {
321
357
  case 'encrypt':
322
358
  await handleEncryptNotification(node);
323
359
  break;
324
- case 'newsletter':
325
- // TO DO
326
- break;
327
360
  case 'devices':
328
361
  const devices = (0, WABinary_1.getBinaryNodeChildren)(child, 'device');
329
362
  if ((0, WABinary_1.areJidsSameUser)(child.attrs.jid, authState.creds.me.id)) {
@@ -342,7 +375,7 @@ const makeMessagesRecvSocket = (config) => {
342
375
  const setPicture = (0, WABinary_1.getBinaryNodeChild)(node, 'set');
343
376
  const delPicture = (0, WABinary_1.getBinaryNodeChild)(node, 'delete');
344
377
  ev.emit('contacts.update', [{
345
- id: (0, WABinary_1.jidNormalizedUser)((_a = node === null || node === void 0 ? void 0 : node.attrs) === null || _a === void 0 ? void 0 : _a.jid) || ((_c = (_b = (setPicture || delPicture)) === null || _b === void 0 ? void 0 : _b.attrs) === null || _c === void 0 ? void 0 : _c.hash) || '',
378
+ id: (0, WABinary_1.jidNormalizedUser)((_a = node === null || node === void 0 ? void 0 : node.attrs) === null || _a === void 0 ? void 0 : _a.from) || ((_c = (_b = (setPicture || delPicture)) === null || _b === void 0 ? void 0 : _b.attrs) === null || _c === void 0 ? void 0 : _c.hash) || '',
346
379
  imgUrl: setPicture ? 'changed' : 'removed'
347
380
  }]);
348
381
  if ((0, WABinary_1.isJidGroup)(from)) {
@@ -387,7 +420,7 @@ const makeMessagesRecvSocket = (config) => {
387
420
  const ref = toRequiredBuffer((0, WABinary_1.getBinaryNodeChildBuffer)(linkCodeCompanionReg, 'link_code_pairing_ref'));
388
421
  const primaryIdentityPublicKey = toRequiredBuffer((0, WABinary_1.getBinaryNodeChildBuffer)(linkCodeCompanionReg, 'primary_identity_pub'));
389
422
  const primaryEphemeralPublicKeyWrapped = toRequiredBuffer((0, WABinary_1.getBinaryNodeChildBuffer)(linkCodeCompanionReg, 'link_code_pairing_wrapped_primary_ephemeral_pub'));
390
- const codePairingPublicKey = decipherLinkPublicKey(primaryEphemeralPublicKeyWrapped);
423
+ const codePairingPublicKey = await decipherLinkPublicKey(primaryEphemeralPublicKeyWrapped);
391
424
  const companionSharedKey = Utils_1.Curve.sharedKey(authState.creds.pairingEphemeralKeyPair.private, codePairingPublicKey);
392
425
  const random = (0, crypto_1.randomBytes)(32);
393
426
  const linkCodeSalt = (0, crypto_1.randomBytes)(32);
@@ -444,10 +477,10 @@ const makeMessagesRecvSocket = (config) => {
444
477
  return result;
445
478
  }
446
479
  };
447
- function decipherLinkPublicKey(data) {
480
+ async function decipherLinkPublicKey(data) {
448
481
  const buffer = toRequiredBuffer(data);
449
482
  const salt = buffer.slice(0, 32);
450
- const secretKey = (0, Utils_1.derivePairingCodeKey)(authState.creds.pairingCode, salt);
483
+ const secretKey = await (0, Utils_1.derivePairingCodeKey)(authState.creds.pairingCode, salt);
451
484
  const iv = buffer.slice(32, 48);
452
485
  const payload = buffer.slice(48, 80);
453
486
  return (0, Utils_1.aesDecryptCTR)(payload, secretKey, iv);
@@ -482,8 +515,7 @@ const makeMessagesRecvSocket = (config) => {
482
515
  await authState.keys.set({ 'sender-key-memory': { [remoteJid]: null } });
483
516
  }
484
517
  logger.debug({ participant, sendToAll }, 'forced new session for retry recp');
485
- for (let i = 0; i < msgs.length; i++) {
486
- const msg = msgs[i];
518
+ for (const [i, msg] of msgs.entries()) {
487
519
  if (msg) {
488
520
  updateSendMessageAgainCount(ids[i], participant);
489
521
  const msgRelayOpts = { messageId: ids[i] };
@@ -526,59 +558,63 @@ const makeMessagesRecvSocket = (config) => {
526
558
  const items = (0, WABinary_1.getBinaryNodeChildren)(content[0], 'item');
527
559
  ids.push(...items.map(i => i.attrs.id));
528
560
  }
529
- await Promise.all([
530
- processingMutex.mutex(async () => {
531
- const status = (0, Utils_1.getStatusFromReceiptType)(attrs.type);
532
- if (typeof status !== 'undefined' &&
533
- (
534
- // basically, we only want to know when a message from us has been delivered to/read by the other person
535
- // or another device of ours has read some messages
536
- status > WAProto_1.proto.WebMessageInfo.Status.DELIVERY_ACK ||
537
- !isNodeFromMe)) {
538
- if ((0, WABinary_1.isJidGroup)(remoteJid)) {
539
- if (attrs.participant) {
540
- const updateKey = status === WAProto_1.proto.WebMessageInfo.Status.DELIVERY_ACK ? 'receiptTimestamp' : 'readTimestamp';
541
- ev.emit('message-receipt.update', ids.map(id => ({
561
+ try {
562
+ await Promise.all([
563
+ processingMutex.mutex(async () => {
564
+ const status = (0, Utils_1.getStatusFromReceiptType)(attrs.type);
565
+ if (typeof status !== 'undefined' &&
566
+ (
567
+ // basically, we only want to know when a message from us has been delivered to/read by the other person
568
+ // or another device of ours has read some messages
569
+ status > WAProto_1.proto.WebMessageInfo.Status.DELIVERY_ACK ||
570
+ !isNodeFromMe)) {
571
+ if ((0, WABinary_1.isJidGroup)(remoteJid) || (0, WABinary_1.isJidStatusBroadcast)(remoteJid)) {
572
+ if (attrs.participant) {
573
+ const updateKey = status === WAProto_1.proto.WebMessageInfo.Status.DELIVERY_ACK ? 'receiptTimestamp' : 'readTimestamp';
574
+ ev.emit('message-receipt.update', ids.map(id => ({
575
+ key: { ...key, id },
576
+ receipt: {
577
+ userJid: (0, WABinary_1.jidNormalizedUser)(attrs.participant),
578
+ [updateKey]: +attrs.t
579
+ }
580
+ })));
581
+ }
582
+ }
583
+ else {
584
+ ev.emit('messages.update', ids.map(id => ({
542
585
  key: { ...key, id },
543
- receipt: {
544
- userJid: (0, WABinary_1.jidNormalizedUser)(attrs.participant),
545
- [updateKey]: +attrs.t
546
- }
586
+ update: { status }
547
587
  })));
548
588
  }
549
589
  }
550
- else {
551
- ev.emit('messages.update', ids.map(id => ({
552
- key: { ...key, id },
553
- update: { status }
554
- })));
555
- }
556
- }
557
- if (attrs.type === 'retry') {
558
- // correctly set who is asking for the retry
559
- key.participant = key.participant || attrs.from;
560
- const retryNode = (0, WABinary_1.getBinaryNodeChild)(node, 'retry');
561
- if (willSendMessageAgain(ids[0], key.participant)) {
562
- if (key.fromMe) {
563
- try {
564
- logger.debug({ attrs, key }, 'recv retry request');
565
- await sendMessagesAgain(key, ids, retryNode);
590
+ if (attrs.type === 'retry') {
591
+ // correctly set who is asking for the retry
592
+ key.participant = key.participant || attrs.from;
593
+ const retryNode = (0, WABinary_1.getBinaryNodeChild)(node, 'retry');
594
+ if (willSendMessageAgain(ids[0], key.participant)) {
595
+ if (key.fromMe) {
596
+ try {
597
+ logger.debug({ attrs, key }, 'recv retry request');
598
+ await sendMessagesAgain(key, ids, retryNode);
599
+ }
600
+ catch (error) {
601
+ logger.error({ key, ids, trace: error.stack }, 'error in sending message again');
602
+ }
566
603
  }
567
- catch (error) {
568
- logger.error({ key, ids, trace: error.stack }, 'error in sending message again');
604
+ else {
605
+ logger.info({ attrs, key }, 'recv retry for not fromMe message');
569
606
  }
570
607
  }
571
608
  else {
572
- logger.info({ attrs, key }, 'recv retry for not fromMe message');
609
+ logger.info({ attrs, key }, 'will not send message again, as sent too many times');
573
610
  }
574
611
  }
575
- else {
576
- logger.info({ attrs, key }, 'will not send message again, as sent too many times');
577
- }
578
- }
579
- }),
580
- sendMessageAck(node)
581
- ]);
612
+ })
613
+ ]);
614
+ }
615
+ finally {
616
+ await sendMessageAck(node);
617
+ }
582
618
  };
583
619
  const handleNotification = async (node) => {
584
620
  const remoteJid = node.attrs.from;
@@ -587,89 +623,169 @@ const makeMessagesRecvSocket = (config) => {
587
623
  await sendMessageAck(node);
588
624
  return;
589
625
  }
590
- await Promise.all([
591
- processingMutex.mutex(async () => {
592
- var _a;
593
- const msg = await processNotification(node);
594
- if (msg) {
595
- const fromMe = (0, WABinary_1.areJidsSameUser)(node.attrs.participant || remoteJid, authState.creds.me.id);
596
- msg.key = {
597
- remoteJid,
598
- fromMe,
599
- participant: node.attrs.participant,
600
- id: node.attrs.id,
601
- ...(msg.key || {})
602
- };
603
- (_a = msg.participant) !== null && _a !== void 0 ? _a : (msg.participant = node.attrs.participant);
604
- msg.messageTimestamp = +node.attrs.t;
605
- const fullMsg = WAProto_1.proto.WebMessageInfo.fromObject(msg);
606
- await upsertMessage(fullMsg, 'append');
607
- }
608
- }),
609
- sendMessageAck(node)
610
- ]);
626
+ try {
627
+ await Promise.all([
628
+ processingMutex.mutex(async () => {
629
+ var _a;
630
+ const msg = await processNotification(node);
631
+ if (msg) {
632
+ const fromMe = (0, WABinary_1.areJidsSameUser)(node.attrs.participant || remoteJid, authState.creds.me.id);
633
+ msg.key = {
634
+ remoteJid,
635
+ fromMe,
636
+ participant: node.attrs.participant,
637
+ id: node.attrs.id,
638
+ ...(msg.key || {})
639
+ };
640
+ (_a = msg.participant) !== null && _a !== void 0 ? _a : (msg.participant = node.attrs.participant);
641
+ msg.messageTimestamp = +node.attrs.t;
642
+ const fullMsg = WAProto_1.proto.WebMessageInfo.fromObject(msg);
643
+ await upsertMessage(fullMsg, 'append');
644
+ }
645
+ })
646
+ ]);
647
+ }
648
+ finally {
649
+ await sendMessageAck(node);
650
+ }
611
651
  };
612
652
  const handleMessage = async (node) => {
613
- var _a, _b;
653
+ var _a, _b, _c;
614
654
  if (shouldIgnoreJid(node.attrs.from) && node.attrs.from !== '@s.whatsapp.net') {
615
655
  logger.debug({ key: node.attrs.key }, 'ignored message');
616
656
  await sendMessageAck(node);
617
657
  return;
618
658
  }
619
- const { fullMessage: msg, category, author, decrypt } = (0, Utils_1.decryptMessageNode)(node, authState.creds.me.id, authState.creds.me.lid || '', signalRepository, logger);
620
- if (((_b = (_a = msg.message) === null || _a === void 0 ? void 0 : _a.protocolMessage) === null || _b === void 0 ? void 0 : _b.type) === WAProto_1.proto.Message.ProtocolMessage.Type.SHARE_PHONE_NUMBER) {
621
- if (node.attrs.sender_pn) {
622
- ev.emit('chats.phoneNumberShare', { lid: node.attrs.from, jid: node.attrs.sender_pn });
659
+ let response;
660
+ if ((0, WABinary_1.getBinaryNodeChild)(node, 'unavailable') && !(0, WABinary_1.getBinaryNodeChild)(node, 'enc')) {
661
+ await sendMessageAck(node);
662
+ const { key } = (0, Utils_1.decodeMessageNode)(node, authState.creds.me.id, authState.creds.me.lid || '').fullMessage;
663
+ response = await requestPlaceholderResend(key);
664
+ if (response === 'RESOLVED') {
665
+ return;
666
+ }
667
+ logger.debug('received unavailable message, acked and requested resend from phone');
668
+ }
669
+ else {
670
+ if (placeholderResendCache.get(node.attrs.id)) {
671
+ placeholderResendCache.del(node.attrs.id);
623
672
  }
624
673
  }
625
- await Promise.all([
626
- processingMutex.mutex(async () => {
627
- await decrypt();
628
- // message failed to decrypt
629
- if (msg.messageStubType === WAProto_1.proto.WebMessageInfo.StubType.CIPHERTEXT) {
630
- retryMutex.mutex(async () => {
631
- if (ws.isOpen) {
632
- const encNode = (0, WABinary_1.getBinaryNodeChild)(node, 'enc');
633
- await sendRetryRequest(node, !encNode);
634
- if (retryRequestDelayMs) {
635
- await (0, Utils_1.delay)(retryRequestDelayMs);
674
+ const { fullMessage: msg, category, author, decrypt } = (0, Utils_1.decryptMessageNode)(node, authState.creds.me.id, authState.creds.me.lid || '', signalRepository, logger);
675
+ if (response && ((_a = msg === null || msg === void 0 ? void 0 : msg.messageStubParameters) === null || _a === void 0 ? void 0 : _a[0]) === Utils_1.NO_MESSAGE_FOUND_ERROR_TEXT) {
676
+ msg.messageStubParameters = [Utils_1.NO_MESSAGE_FOUND_ERROR_TEXT, response];
677
+ }
678
+ if (((_c = (_b = msg.message) === null || _b === void 0 ? void 0 : _b.protocolMessage) === null || _c === void 0 ? void 0 : _c.type) === WAProto_1.proto.Message.ProtocolMessage.Type.SHARE_PHONE_NUMBER && node.attrs.sender_pn) {
679
+ ev.emit('chats.phoneNumberShare', { lid: node.attrs.from, jid: node.attrs.sender_pn });
680
+ }
681
+ try {
682
+ await Promise.all([
683
+ processingMutex.mutex(async () => {
684
+ var _a;
685
+ await decrypt();
686
+ // message failed to decrypt
687
+ if (msg.messageStubType === WAProto_1.proto.WebMessageInfo.StubType.CIPHERTEXT) {
688
+ if (((_a = msg === null || msg === void 0 ? void 0 : msg.messageStubParameters) === null || _a === void 0 ? void 0 : _a[0]) === Utils_1.MISSING_KEYS_ERROR_TEXT) {
689
+ return sendMessageAck(node, Utils_1.NACK_REASONS.ParsingError);
690
+ }
691
+ retryMutex.mutex(async () => {
692
+ if (ws.isOpen) {
693
+ if ((0, WABinary_1.getBinaryNodeChild)(node, 'unavailable')) {
694
+ return;
695
+ }
696
+ const encNode = (0, WABinary_1.getBinaryNodeChild)(node, 'enc');
697
+ await sendRetryRequest(node, !encNode);
698
+ if (retryRequestDelayMs) {
699
+ await (0, Utils_1.delay)(retryRequestDelayMs);
700
+ }
636
701
  }
702
+ else {
703
+ logger.debug({ node }, 'connection closed, ignoring retry req');
704
+ }
705
+ });
706
+ }
707
+ else {
708
+ // no type in the receipt => message delivered
709
+ let type = undefined;
710
+ let participant = msg.key.participant;
711
+ if (category === 'peer') { // special peer message
712
+ type = 'peer_msg';
637
713
  }
638
- else {
639
- logger.debug({ node }, 'connection closed, ignoring retry req');
714
+ else if (msg.key.fromMe) { // message was sent by us from a different device
715
+ type = 'sender';
716
+ // need to specially handle this case
717
+ if ((0, WABinary_1.isJidUser)(msg.key.remoteJid)) {
718
+ participant = author;
719
+ }
640
720
  }
641
- });
642
- }
643
- else {
644
- // no type in the receipt => message delivered
645
- let type = undefined;
646
- let participant = msg.key.participant;
647
- if (category === 'peer') { // special peer message
648
- type = 'peer_msg';
649
- }
650
- else if (msg.key.fromMe) { // message was sent by us from a different device
651
- type = 'sender';
652
- // need to specially handle this case
653
- if ((0, WABinary_1.isJidUser)(msg.key.remoteJid)) {
654
- participant = author;
721
+ else if (!sendActiveReceipts) {
722
+ type = 'inactive';
723
+ }
724
+ await sendReceipt(msg.key.remoteJid, participant, [msg.key.id], type);
725
+ // send ack for history message
726
+ const isAnyHistoryMsg = (0, Utils_1.getHistoryMsg)(msg.message);
727
+ if (isAnyHistoryMsg) {
728
+ const jid = (0, WABinary_1.jidNormalizedUser)(msg.key.remoteJid);
729
+ await sendReceipt(jid, undefined, [msg.key.id], 'hist_sync');
655
730
  }
656
731
  }
657
- else if (!sendActiveReceipts) {
658
- type = 'inactive';
659
- }
660
- await sendReceipt(msg.key.remoteJid, participant, [msg.key.id], type);
661
- // send ack for history message
662
- const isAnyHistoryMsg = (0, Utils_1.getHistoryMsg)(msg.message);
663
- if (isAnyHistoryMsg) {
664
- const jid = (0, WABinary_1.jidNormalizedUser)(msg.key.remoteJid);
665
- await sendReceipt(jid, undefined, [msg.key.id], 'hist_sync');
666
- }
667
- }
668
- (0, Utils_2.cleanMessage)(msg, authState.creds.me.id);
669
- await upsertMessage(msg, node.attrs.offline ? 'append' : 'notify');
670
- }),
671
- sendMessageAck(node)
672
- ]);
732
+ (0, Utils_2.cleanMessage)(msg, authState.creds.me.id);
733
+ await sendMessageAck(node);
734
+ await upsertMessage(msg, node.attrs.offline ? 'append' : 'notify');
735
+ })
736
+ ]);
737
+ }
738
+ catch (error) {
739
+ logger.error({ error, node }, 'error in handling message');
740
+ }
741
+ };
742
+ const fetchMessageHistory = async (count, oldestMsgKey, oldestMsgTimestamp) => {
743
+ var _a;
744
+ if (!((_a = authState.creds.me) === null || _a === void 0 ? void 0 : _a.id)) {
745
+ throw new boom_1.Boom('Not authenticated');
746
+ }
747
+ const pdoMessage = {
748
+ historySyncOnDemandRequest: {
749
+ chatJid: oldestMsgKey.remoteJid,
750
+ oldestMsgFromMe: oldestMsgKey.fromMe,
751
+ oldestMsgId: oldestMsgKey.id,
752
+ oldestMsgTimestampMs: oldestMsgTimestamp,
753
+ onDemandMsgCount: count
754
+ },
755
+ peerDataOperationRequestType: WAProto_1.proto.Message.PeerDataOperationRequestType.HISTORY_SYNC_ON_DEMAND
756
+ };
757
+ return sendPeerDataOperationMessage(pdoMessage);
758
+ };
759
+ const requestPlaceholderResend = async (messageKey) => {
760
+ var _a;
761
+ if (!((_a = authState.creds.me) === null || _a === void 0 ? void 0 : _a.id)) {
762
+ throw new boom_1.Boom('Not authenticated');
763
+ }
764
+ if (placeholderResendCache.get(messageKey === null || messageKey === void 0 ? void 0 : messageKey.id)) {
765
+ logger.debug('already requested resend', { messageKey });
766
+ return;
767
+ }
768
+ else {
769
+ placeholderResendCache.set(messageKey === null || messageKey === void 0 ? void 0 : messageKey.id, true);
770
+ }
771
+ await (0, Utils_1.delay)(5000);
772
+ if (!placeholderResendCache.get(messageKey === null || messageKey === void 0 ? void 0 : messageKey.id)) {
773
+ logger.debug('message received while resend requested', { messageKey });
774
+ return 'RESOLVED';
775
+ }
776
+ const pdoMessage = {
777
+ placeholderMessageResendRequest: [{
778
+ messageKey
779
+ }],
780
+ peerDataOperationRequestType: WAProto_1.proto.Message.PeerDataOperationRequestType.PLACEHOLDER_MESSAGE_RESEND
781
+ };
782
+ setTimeout(() => {
783
+ if (placeholderResendCache.get(messageKey === null || messageKey === void 0 ? void 0 : messageKey.id)) {
784
+ logger.debug('PDO message without response after 15 seconds. Phone possibly offline', { messageKey });
785
+ placeholderResendCache.del(messageKey === null || messageKey === void 0 ? void 0 : messageKey.id);
786
+ }
787
+ }, 15000);
788
+ return sendPeerDataOperationMessage(pdoMessage);
673
789
  };
674
790
  const handleCall = async (node) => {
675
791
  const { attrs } = node;
@@ -698,7 +814,7 @@ const makeMessagesRecvSocket = (config) => {
698
814
  call.isGroup = existingCall.isGroup;
699
815
  }
700
816
  // delete data once call has ended
701
- if (status === 'reject' || status === 'accept' || status === 'timeout') {
817
+ if (status === 'reject' || status === 'accept' || status === 'timeout' || status === 'terminate') {
702
818
  callOfferCache.del(call.id);
703
819
  }
704
820
  ev.emit('call', [call]);
@@ -706,19 +822,19 @@ const makeMessagesRecvSocket = (config) => {
706
822
  };
707
823
  const handleBadAck = async ({ attrs }) => {
708
824
  const key = { remoteJid: attrs.from, fromMe: true, id: attrs.id };
709
- // current hypothesis is that if pash is sent in the ack
710
- // it means -- the message hasn't reached all devices yet
711
- // we'll retry sending the message here
712
- if (attrs.phash) {
713
- logger.info({ attrs }, 'received phash in ack, resending message...');
714
- const msg = await getMessage(key);
715
- if (msg) {
716
- await relayMessage(key.remoteJid, msg, { messageId: key.id, useUserDevicesCache: false });
717
- }
718
- else {
719
- logger.warn({ attrs }, 'could not send message again, as it was not found');
720
- }
721
- }
825
+ // WARNING: REFRAIN FROM ENABLING THIS FOR NOW. IT WILL CAUSE A LOOP
826
+ // // current hypothesis is that if pash is sent in the ack
827
+ // // it means -- the message hasn't reached all devices yet
828
+ // // we'll retry sending the message here
829
+ // if(attrs.phash) {
830
+ // logger.info({ attrs }, 'received phash in ack, resending message...')
831
+ // const msg = await getMessage(key)
832
+ // if(msg) {
833
+ // await relayMessage(key.remoteJid!, msg, { messageId: key.id!, useUserDevicesCache: false })
834
+ // } else {
835
+ // logger.warn({ attrs }, 'could not send message again, as it was not found')
836
+ // }
837
+ // }
722
838
  // error in acknowledgement,
723
839
  // device could not display the message
724
840
  if (attrs.error) {
@@ -743,22 +859,63 @@ const makeMessagesRecvSocket = (config) => {
743
859
  await execTask();
744
860
  ev.flush();
745
861
  function execTask() {
746
- return exec(node)
862
+ return exec(node, false)
747
863
  .catch(err => onUnexpectedError(err, identifier));
748
864
  }
749
865
  };
866
+ const makeOfflineNodeProcessor = () => {
867
+ const nodeProcessorMap = new Map([
868
+ ['message', handleMessage],
869
+ ['call', handleCall],
870
+ ['receipt', handleReceipt],
871
+ ['notification', handleNotification]
872
+ ]);
873
+ const nodes = [];
874
+ let isProcessing = false;
875
+ const enqueue = (type, node) => {
876
+ nodes.push({ type, node });
877
+ if (isProcessing) {
878
+ return;
879
+ }
880
+ isProcessing = true;
881
+ const promise = async () => {
882
+ while (nodes.length && ws.isOpen) {
883
+ const { type, node } = nodes.shift();
884
+ const nodeProcessor = nodeProcessorMap.get(type);
885
+ if (!nodeProcessor) {
886
+ onUnexpectedError(new Error(`unknown offline node type: ${type}`), 'processing offline node');
887
+ continue;
888
+ }
889
+ await nodeProcessor(node);
890
+ }
891
+ isProcessing = false;
892
+ };
893
+ promise().catch(error => onUnexpectedError(error, 'processing offline nodes'));
894
+ };
895
+ return { enqueue };
896
+ };
897
+ const offlineNodeProcessor = makeOfflineNodeProcessor();
898
+ const processNode = (type, node, identifier, exec) => {
899
+ const isOffline = !!node.attrs.offline;
900
+ if (isOffline) {
901
+ offlineNodeProcessor.enqueue(type, node);
902
+ }
903
+ else {
904
+ processNodeWithBuffer(node, identifier, exec);
905
+ }
906
+ };
750
907
  // recv a message
751
908
  ws.on('CB:message', (node) => {
752
- processNodeWithBuffer(node, 'processing message', handleMessage);
909
+ processNode('message', node, 'processing message', handleMessage);
753
910
  });
754
911
  ws.on('CB:call', async (node) => {
755
- processNodeWithBuffer(node, 'handling call', handleCall);
912
+ processNode('call', node, 'handling call', handleCall);
756
913
  });
757
914
  ws.on('CB:receipt', node => {
758
- processNodeWithBuffer(node, 'handling receipt', handleReceipt);
915
+ processNode('receipt', node, 'handling receipt', handleReceipt);
759
916
  });
760
917
  ws.on('CB:notification', async (node) => {
761
- processNodeWithBuffer(node, 'handling notification', handleNotification);
918
+ processNode('notification', node, 'handling notification', handleNotification);
762
919
  });
763
920
  ws.on('CB:ack,class:message', (node) => {
764
921
  handleBadAck(node)
@@ -801,7 +958,9 @@ const makeMessagesRecvSocket = (config) => {
801
958
  sendMessageAck,
802
959
  sendRetryRequest,
803
960
  offerCall,
804
- rejectCall
961
+ rejectCall,
962
+ fetchMessageHistory,
963
+ requestPlaceholderResend,
805
964
  };
806
965
  };
807
966
  exports.makeMessagesRecvSocket = makeMessagesRecvSocket;