gifted-baileys 1.5.0 → 1.5.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 (120) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +1429 -684
  3. package/WAProto/WAProto.proto +969 -88
  4. package/WAProto/index.d.ts +13199 -1260
  5. package/WAProto/index.js +124901 -74525
  6. package/lib/Defaults/baileys-version.json +1 -1
  7. package/lib/Defaults/index.d.ts +2 -2
  8. package/lib/Defaults/index.js +6 -5
  9. package/lib/Defaults/phonenumber-mcc.json +221 -221
  10. package/lib/Signal/libsignal.js +18 -9
  11. package/lib/Socket/Client/abstract-socket-client.d.ts +0 -2
  12. package/lib/Socket/Client/index.d.ts +2 -3
  13. package/lib/Socket/Client/index.js +2 -3
  14. package/lib/Socket/Client/mobile-socket-client.d.ts +0 -1
  15. package/lib/Socket/Client/types.d.ts +17 -0
  16. package/lib/Socket/Client/types.js +13 -0
  17. package/lib/Socket/Client/{web-socket-client.d.ts → websocket.d.ts} +1 -1
  18. package/lib/Socket/Client/{web-socket-client.js → websocket.js} +2 -2
  19. package/lib/Socket/business.d.ts +64 -29
  20. package/lib/Socket/business.js +1 -0
  21. package/lib/Socket/chats.d.ts +10 -8
  22. package/lib/Socket/chats.js +114 -97
  23. package/lib/Socket/groups.d.ts +10 -8
  24. package/lib/Socket/groups.js +4 -2
  25. package/lib/Socket/index.d.ts +70 -35
  26. package/lib/Socket/messages-recv.d.ts +63 -29
  27. package/lib/Socket/messages-recv.js +374 -155
  28. package/lib/Socket/messages-send.d.ts +48 -12
  29. package/lib/Socket/messages-send.js +445 -87
  30. package/lib/Socket/newsletter.d.ts +132 -0
  31. package/lib/Socket/newsletter.js +236 -0
  32. package/lib/Socket/registration.d.ts +73 -41
  33. package/lib/Socket/registration.js +7 -7
  34. package/lib/Socket/socket.d.ts +2 -0
  35. package/lib/Socket/socket.js +56 -15
  36. package/lib/Socket/usync.d.ts +37 -0
  37. package/lib/Socket/usync.js +70 -0
  38. package/lib/Store/make-cache-manager-store.d.ts +2 -1
  39. package/lib/Store/make-in-memory-store.d.ts +2 -1
  40. package/lib/Store/make-in-memory-store.js +40 -46
  41. package/lib/Store/make-ordered-dictionary.d.ts +1 -1
  42. package/lib/Types/Auth.d.ts +2 -1
  43. package/lib/Types/Call.d.ts +1 -1
  44. package/lib/Types/Chat.d.ts +12 -7
  45. package/lib/Types/Events.d.ts +17 -2
  46. package/lib/Types/GroupMetadata.d.ts +6 -2
  47. package/lib/Types/Label.d.ts +11 -0
  48. package/lib/Types/Label.js +1 -1
  49. package/lib/Types/LabelAssociation.js +1 -1
  50. package/lib/Types/Message.d.ts +184 -12
  51. package/lib/Types/Newsletter.d.ts +92 -0
  52. package/lib/Types/Newsletter.js +32 -0
  53. package/lib/Types/Socket.d.ts +7 -2
  54. package/lib/Types/USync.d.ts +25 -0
  55. package/lib/Types/USync.js +2 -0
  56. package/lib/Types/index.d.ts +10 -0
  57. package/lib/Types/index.js +2 -1
  58. package/lib/Utils/auth-utils.js +5 -3
  59. package/lib/Utils/business.d.ts +1 -1
  60. package/lib/Utils/business.js +2 -2
  61. package/lib/Utils/chat-utils.d.ts +11 -12
  62. package/lib/Utils/chat-utils.js +41 -20
  63. package/lib/Utils/crypto.d.ts +15 -16
  64. package/lib/Utils/crypto.js +35 -23
  65. package/lib/Utils/decode-wa-message.d.ts +17 -0
  66. package/lib/Utils/decode-wa-message.js +65 -13
  67. package/lib/Utils/generics.d.ts +11 -17
  68. package/lib/Utils/generics.js +47 -13
  69. package/lib/Utils/history.d.ts +6 -2
  70. package/lib/Utils/history.js +3 -0
  71. package/lib/Utils/link-preview.js +1 -1
  72. package/lib/Utils/logger.d.ts +1 -3
  73. package/lib/Utils/make-mutex.d.ts +2 -2
  74. package/lib/Utils/messages-media.d.ts +31 -25
  75. package/lib/Utils/messages-media.js +95 -53
  76. package/lib/Utils/messages.d.ts +2 -1
  77. package/lib/Utils/messages.js +515 -34
  78. package/lib/Utils/noise-handler.d.ts +6 -6
  79. package/lib/Utils/noise-handler.js +16 -3
  80. package/lib/Utils/process-message.js +4 -3
  81. package/lib/Utils/signal.d.ts +2 -1
  82. package/lib/Utils/signal.js +11 -19
  83. package/lib/Utils/use-multi-file-auth-state.js +11 -3
  84. package/lib/Utils/validate-connection.js +16 -2
  85. package/lib/WABinary/decode.d.ts +1 -2
  86. package/lib/WABinary/decode.js +17 -7
  87. package/lib/WABinary/encode.d.ts +1 -2
  88. package/lib/WABinary/encode.js +33 -17
  89. package/lib/WABinary/generic-utils.d.ts +2 -3
  90. package/lib/WABinary/generic-utils.js +2 -2
  91. package/lib/WABinary/jid-utils.d.ts +4 -2
  92. package/lib/WABinary/jid-utils.js +4 -1
  93. package/lib/WAM/BinaryInfo.d.ts +8 -0
  94. package/lib/WAM/BinaryInfo.js +13 -0
  95. package/lib/WAM/constants.d.ts +38 -0
  96. package/lib/WAM/constants.js +15350 -0
  97. package/lib/WAM/encode.d.ts +2 -0
  98. package/lib/WAM/encode.js +155 -0
  99. package/lib/WAM/index.d.ts +3 -0
  100. package/lib/WAM/index.js +19 -0
  101. package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts +9 -0
  102. package/lib/WAUSync/Protocols/USyncContactProtocol.js +32 -0
  103. package/lib/WAUSync/Protocols/USyncDeviceProtocol.d.ts +22 -0
  104. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +57 -0
  105. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts +12 -0
  106. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +30 -0
  107. package/lib/WAUSync/Protocols/USyncStatusProtocol.d.ts +12 -0
  108. package/lib/WAUSync/Protocols/USyncStatusProtocol.js +42 -0
  109. package/lib/WAUSync/Protocols/index.d.ts +4 -0
  110. package/lib/WAUSync/Protocols/index.js +20 -0
  111. package/lib/WAUSync/USyncQuery.d.ts +26 -0
  112. package/lib/WAUSync/USyncQuery.js +79 -0
  113. package/lib/WAUSync/USyncUser.d.ts +10 -0
  114. package/lib/WAUSync/USyncUser.js +22 -0
  115. package/lib/WAUSync/index.d.ts +3 -0
  116. package/lib/WAUSync/index.js +19 -0
  117. package/lib/gifted +1 -0
  118. package/lib/index.js +2 -0
  119. package/package.json +10 -7
  120. package/lib/index.d.ts +0 -10
@@ -19,39 +19,101 @@ 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, } = 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({
26
- stdTTL: Defaults_1.DEFAULT_CACHE_TTLS.MSG_RETRY,
26
+ stdTTL: Defaults_1.DEFAULT_CACHE_TTLS.MSG_RETRY, // 1 hour
27
27
  useClones: false
28
28
  });
29
29
  const callOfferCache = config.callOfferCache || new node_cache_1.default({
30
- stdTTL: Defaults_1.DEFAULT_CACHE_TTLS.CALL_OFFER,
30
+ stdTTL: Defaults_1.DEFAULT_CACHE_TTLS.CALL_OFFER, // 5 mins
31
+ useClones: false
32
+ });
33
+ const placeholderResendCache = config.placeholderResendCache || new node_cache_1.default({
34
+ stdTTL: Defaults_1.DEFAULT_CACHE_TTLS.MSG_RETRY, // 1 hour
31
35
  useClones: false
32
36
  });
33
37
  let sendActiveReceipts = false;
34
- const sendMessageAck = async ({ tag, attrs }) => {
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 (tag !== 'message' && attrs.type) {
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
  }
59
+ if (tag === 'message' && (0, WABinary_1.getBinaryNodeChild)({ tag, attrs, content }, 'unavailable')) {
60
+ stanza.attrs.from = authState.creds.me.id;
61
+ }
52
62
  logger.debug({ recv: { tag, attrs }, sent: stanza.attrs }, 'sent ack');
53
63
  await sendNode(stanza);
54
64
  };
65
+ const offerCall = async (toJid, isVideo = false) => {
66
+ const callId = (0, crypto_1.randomBytes)(16).toString('hex').toUpperCase().substring(0, 64);
67
+ const offerContent = [];
68
+ offerContent.push({ tag: 'audio', attrs: { enc: 'opus', rate: '16000' }, content: undefined });
69
+ offerContent.push({ tag: 'audio', attrs: { enc: 'opus', rate: '8000' }, content: undefined });
70
+ if (isVideo) {
71
+ offerContent.push({
72
+ tag: 'video',
73
+ attrs: { enc: 'vp8', dec: 'vp8', orientation: '0', 'screen_width': '1920', 'screen_height': '1080', 'device_orientation': '0' },
74
+ content: undefined
75
+ });
76
+ }
77
+ offerContent.push({ tag: 'net', attrs: { medium: '3' }, content: undefined });
78
+ offerContent.push({ tag: 'capability', attrs: { ver: '1' }, content: new Uint8Array([1, 4, 255, 131, 207, 4]) });
79
+ offerContent.push({ tag: 'encopt', attrs: { keygen: '2' }, content: undefined });
80
+ const encKey = (0, crypto_1.randomBytes)(32);
81
+ const devices = (await getUSyncDevices([toJid], true, false)).map(({ user, device }) => (0, WABinary_1.jidEncode)(user, 's.whatsapp.net', device));
82
+ await assertSessions(devices, true);
83
+ const { nodes: destinations, shouldIncludeDeviceIdentity } = await createParticipantNodes(devices, {
84
+ call: {
85
+ callKey: new Uint8Array(encKey)
86
+ }
87
+ }, { count: '0' });
88
+ offerContent.push({ tag: 'destination', attrs: {}, content: destinations });
89
+ if (shouldIncludeDeviceIdentity) {
90
+ offerContent.push({
91
+ tag: 'device-identity',
92
+ attrs: {},
93
+ content: (0, Utils_1.encodeSignedDeviceIdentity)(authState.creds.account, true)
94
+ });
95
+ }
96
+ const stanza = ({
97
+ tag: 'call',
98
+ attrs: {
99
+ id: (0, Utils_1.generateMessageIDV2)(),
100
+ to: toJid,
101
+ },
102
+ content: [{
103
+ tag: 'offer',
104
+ attrs: {
105
+ 'call-id': callId,
106
+ 'call-creator': authState.creds.me.id,
107
+ },
108
+ content: offerContent,
109
+ }],
110
+ });
111
+ await query(stanza);
112
+ return {
113
+ id: callId,
114
+ to: toJid
115
+ };
116
+ };
55
117
  const rejectCall = async (callId, callFrom) => {
56
118
  const stanza = ({
57
119
  tag: 'call',
@@ -72,16 +134,24 @@ const makeMessagesRecvSocket = (config) => {
72
134
  await query(stanza);
73
135
  };
74
136
  const sendRetryRequest = async (node, forceIncludeKeys = false) => {
75
- const msgId = node.attrs.id;
76
- 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;
77
142
  if (retryCount >= maxMsgRetryCount) {
78
143
  logger.debug({ retryCount, msgId }, 'reached retry limit, clearing');
79
- msgRetryCache.del(msgId);
144
+ msgRetryCache.del(key);
80
145
  return;
81
146
  }
82
147
  retryCount += 1;
83
- msgRetryCache.set(msgId, retryCount);
148
+ msgRetryCache.set(key, retryCount);
84
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
+ }
85
155
  const deviceIdentity = (0, Utils_1.encodeSignedDeviceIdentity)(account, true);
86
156
  await authState.keys.transaction(async () => {
87
157
  const receipt = {
@@ -160,6 +230,8 @@ const makeMessagesRecvSocket = (config) => {
160
230
  }
161
231
  };
162
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;
163
235
  switch (child === null || child === void 0 ? void 0 : child.tag) {
164
236
  case 'create':
165
237
  const metadata = (0, groups_1.extractGroupMetadata)(child);
@@ -185,6 +257,11 @@ const makeMessagesRecvSocket = (config) => {
185
257
  }
186
258
  };
187
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;
188
265
  case 'promote':
189
266
  case 'demote':
190
267
  case 'remove':
@@ -206,6 +283,11 @@ const makeMessagesRecvSocket = (config) => {
206
283
  msg.messageStubType = Types_1.WAMessageStubType.GROUP_CHANGE_SUBJECT;
207
284
  msg.messageStubParameters = [child.attrs.subject];
208
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;
209
291
  case 'announcement':
210
292
  case 'not_announcement':
211
293
  msg.messageStubType = Types_1.WAMessageStubType.GROUP_CHANGE_ANNOUNCE;
@@ -234,9 +316,19 @@ const makeMessagesRecvSocket = (config) => {
234
316
  msg.messageStubParameters = [approvalMode.attrs.state];
235
317
  }
236
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;
237
328
  }
238
329
  };
239
330
  const processNotification = async (node) => {
331
+ var _a, _b, _c;
240
332
  const result = {};
241
333
  const [child] = (0, WABinary_1.getAllBinaryNodeChildren)(node);
242
334
  const nodeType = node.attrs.type;
@@ -283,8 +375,8 @@ const makeMessagesRecvSocket = (config) => {
283
375
  const setPicture = (0, WABinary_1.getBinaryNodeChild)(node, 'set');
284
376
  const delPicture = (0, WABinary_1.getBinaryNodeChild)(node, 'delete');
285
377
  ev.emit('contacts.update', [{
286
- id: from,
287
- imgUrl: setPicture ? 'changed' : null
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) || '',
379
+ imgUrl: setPicture ? 'changed' : 'removed'
288
380
  }]);
289
381
  if ((0, WABinary_1.isJidGroup)(from)) {
290
382
  const node = setPicture || delPicture;
@@ -328,7 +420,7 @@ const makeMessagesRecvSocket = (config) => {
328
420
  const ref = toRequiredBuffer((0, WABinary_1.getBinaryNodeChildBuffer)(linkCodeCompanionReg, 'link_code_pairing_ref'));
329
421
  const primaryIdentityPublicKey = toRequiredBuffer((0, WABinary_1.getBinaryNodeChildBuffer)(linkCodeCompanionReg, 'primary_identity_pub'));
330
422
  const primaryEphemeralPublicKeyWrapped = toRequiredBuffer((0, WABinary_1.getBinaryNodeChildBuffer)(linkCodeCompanionReg, 'link_code_pairing_wrapped_primary_ephemeral_pub'));
331
- const codePairingPublicKey = decipherLinkPublicKey(primaryEphemeralPublicKeyWrapped);
423
+ const codePairingPublicKey = await decipherLinkPublicKey(primaryEphemeralPublicKeyWrapped);
332
424
  const companionSharedKey = Utils_1.Curve.sharedKey(authState.creds.pairingEphemeralKeyPair.private, codePairingPublicKey);
333
425
  const random = (0, crypto_1.randomBytes)(32);
334
426
  const linkCodeSalt = (0, crypto_1.randomBytes)(32);
@@ -385,10 +477,10 @@ const makeMessagesRecvSocket = (config) => {
385
477
  return result;
386
478
  }
387
479
  };
388
- function decipherLinkPublicKey(data) {
480
+ async function decipherLinkPublicKey(data) {
389
481
  const buffer = toRequiredBuffer(data);
390
482
  const salt = buffer.slice(0, 32);
391
- const secretKey = (0, Utils_1.derivePairingCodeKey)(authState.creds.pairingCode, salt);
483
+ const secretKey = await (0, Utils_1.derivePairingCodeKey)(authState.creds.pairingCode, salt);
392
484
  const iv = buffer.slice(32, 48);
393
485
  const payload = buffer.slice(48, 80);
394
486
  return (0, Utils_1.aesDecryptCTR)(payload, secretKey, iv);
@@ -423,8 +515,7 @@ const makeMessagesRecvSocket = (config) => {
423
515
  await authState.keys.set({ 'sender-key-memory': { [remoteJid]: null } });
424
516
  }
425
517
  logger.debug({ participant, sendToAll }, 'forced new session for retry recp');
426
- for (let i = 0; i < msgs.length; i++) {
427
- const msg = msgs[i];
518
+ for (const [i, msg] of msgs.entries()) {
428
519
  if (msg) {
429
520
  updateSendMessageAgainCount(ids[i], participant);
430
521
  const msgRelayOpts = { messageId: ids[i] };
@@ -457,7 +548,7 @@ const makeMessagesRecvSocket = (config) => {
457
548
  fromMe,
458
549
  participant: attrs.participant
459
550
  };
460
- if (shouldIgnoreJid(remoteJid)) {
551
+ if (shouldIgnoreJid(remoteJid) && remoteJid !== '@s.whatsapp.net') {
461
552
  logger.debug({ remoteJid }, 'ignoring receipt from jid');
462
553
  await sendMessageAck(node);
463
554
  return;
@@ -467,150 +558,234 @@ const makeMessagesRecvSocket = (config) => {
467
558
  const items = (0, WABinary_1.getBinaryNodeChildren)(content[0], 'item');
468
559
  ids.push(...items.map(i => i.attrs.id));
469
560
  }
470
- await Promise.all([
471
- processingMutex.mutex(async () => {
472
- const status = (0, Utils_1.getStatusFromReceiptType)(attrs.type);
473
- if (typeof status !== 'undefined' &&
474
- (
475
- // basically, we only want to know when a message from us has been delivered to/read by the other person
476
- // or another device of ours has read some messages
477
- status > WAProto_1.proto.WebMessageInfo.Status.DELIVERY_ACK ||
478
- !isNodeFromMe)) {
479
- if ((0, WABinary_1.isJidGroup)(remoteJid)) {
480
- if (attrs.participant) {
481
- const updateKey = status === WAProto_1.proto.WebMessageInfo.Status.DELIVERY_ACK ? 'receiptTimestamp' : 'readTimestamp';
482
- 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 => ({
483
585
  key: { ...key, id },
484
- receipt: {
485
- userJid: (0, WABinary_1.jidNormalizedUser)(attrs.participant),
486
- [updateKey]: +attrs.t
487
- }
586
+ update: { status }
488
587
  })));
489
588
  }
490
589
  }
491
- else {
492
- ev.emit('messages.update', ids.map(id => ({
493
- key: { ...key, id },
494
- update: { status }
495
- })));
496
- }
497
- }
498
- if (attrs.type === 'retry') {
499
- // correctly set who is asking for the retry
500
- key.participant = key.participant || attrs.from;
501
- const retryNode = (0, WABinary_1.getBinaryNodeChild)(node, 'retry');
502
- if (willSendMessageAgain(ids[0], key.participant)) {
503
- if (key.fromMe) {
504
- try {
505
- logger.debug({ attrs, key }, 'recv retry request');
506
- 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
+ }
507
603
  }
508
- catch (error) {
509
- 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');
510
606
  }
511
607
  }
512
608
  else {
513
- 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');
514
610
  }
515
611
  }
516
- else {
517
- logger.info({ attrs, key }, 'will not send message again, as sent too many times');
518
- }
519
- }
520
- }),
521
- sendMessageAck(node)
522
- ]);
612
+ })
613
+ ]);
614
+ }
615
+ finally {
616
+ await sendMessageAck(node);
617
+ }
523
618
  };
524
619
  const handleNotification = async (node) => {
525
620
  const remoteJid = node.attrs.from;
526
- if (shouldIgnoreJid(remoteJid)) {
621
+ if (shouldIgnoreJid(remoteJid) && remoteJid !== '@s.whatsapp.net') {
527
622
  logger.debug({ remoteJid, id: node.attrs.id }, 'ignored notification');
528
623
  await sendMessageAck(node);
529
624
  return;
530
625
  }
531
- await Promise.all([
532
- processingMutex.mutex(async () => {
533
- var _a;
534
- const msg = await processNotification(node);
535
- if (msg) {
536
- const fromMe = (0, WABinary_1.areJidsSameUser)(node.attrs.participant || remoteJid, authState.creds.me.id);
537
- msg.key = {
538
- remoteJid,
539
- fromMe,
540
- participant: node.attrs.participant,
541
- id: node.attrs.id,
542
- ...(msg.key || {})
543
- };
544
- (_a = msg.participant) !== null && _a !== void 0 ? _a : (msg.participant = node.attrs.participant);
545
- msg.messageTimestamp = +node.attrs.t;
546
- const fullMsg = WAProto_1.proto.WebMessageInfo.fromObject(msg);
547
- await upsertMessage(fullMsg, 'append');
548
- }
549
- }),
550
- sendMessageAck(node)
551
- ]);
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
+ }
552
651
  };
553
652
  const handleMessage = async (node) => {
554
- var _a, _b;
555
- const { fullMessage: msg, category, author, decrypt } = (0, Utils_1.decryptMessageNode)(node, authState.creds.me.id, authState.creds.me.lid || '', signalRepository, logger);
556
- 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) {
557
- if (node.attrs.sender_pn) {
558
- ev.emit('chats.phoneNumberShare', { lid: node.attrs.from, jid: node.attrs.sender_pn });
559
- }
560
- }
561
- if (shouldIgnoreJid(msg.key.remoteJid)) {
562
- logger.debug({ key: msg.key }, 'ignored message');
653
+ var _a, _b, _c;
654
+ if (shouldIgnoreJid(node.attrs.from) && node.attrs.from !== '@s.whatsapp.net') {
655
+ logger.debug({ key: node.attrs.key }, 'ignored message');
563
656
  await sendMessageAck(node);
564
657
  return;
565
658
  }
566
- await Promise.all([
567
- processingMutex.mutex(async () => {
568
- await decrypt();
569
- // message failed to decrypt
570
- if (msg.messageStubType === WAProto_1.proto.WebMessageInfo.StubType.CIPHERTEXT) {
571
- retryMutex.mutex(async () => {
572
- if (ws.isOpen) {
573
- const encNode = (0, WABinary_1.getBinaryNodeChild)(node, 'enc');
574
- await sendRetryRequest(node, !encNode);
575
- if (retryRequestDelayMs) {
576
- await (0, Utils_1.delay)(retryRequestDelayMs);
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);
672
+ }
673
+ }
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
+ }
701
+ }
702
+ else {
703
+ logger.debug({ node }, 'connection closed, ignoring retry req');
577
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';
578
713
  }
579
- else {
580
- 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
+ }
581
720
  }
582
- });
583
- }
584
- else {
585
- // no type in the receipt => message delivered
586
- let type = undefined;
587
- let participant = msg.key.participant;
588
- if (category === 'peer') { // special peer message
589
- type = 'peer_msg';
590
- }
591
- else if (msg.key.fromMe) { // message was sent by us from a different device
592
- type = 'sender';
593
- // need to specially handle this case
594
- if ((0, WABinary_1.isJidUser)(msg.key.remoteJid)) {
595
- 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');
596
730
  }
597
731
  }
598
- else if (!sendActiveReceipts) {
599
- type = 'inactive';
600
- }
601
- await sendReceipt(msg.key.remoteJid, participant, [msg.key.id], type);
602
- // send ack for history message
603
- const isAnyHistoryMsg = (0, Utils_1.getHistoryMsg)(msg.message);
604
- if (isAnyHistoryMsg) {
605
- const jid = (0, WABinary_1.jidNormalizedUser)(msg.key.remoteJid);
606
- await sendReceipt(jid, undefined, [msg.key.id], 'hist_sync');
607
- }
608
- }
609
- (0, Utils_2.cleanMessage)(msg, authState.creds.me.id);
610
- await upsertMessage(msg, node.attrs.offline ? 'append' : 'notify');
611
- }),
612
- sendMessageAck(node)
613
- ]);
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);
614
789
  };
615
790
  const handleCall = async (node) => {
616
791
  const { attrs } = node;
@@ -639,7 +814,7 @@ const makeMessagesRecvSocket = (config) => {
639
814
  call.isGroup = existingCall.isGroup;
640
815
  }
641
816
  // delete data once call has ended
642
- if (status === 'reject' || status === 'accept' || status === 'timeout') {
817
+ if (status === 'reject' || status === 'accept' || status === 'timeout' || status === 'terminate') {
643
818
  callOfferCache.del(call.id);
644
819
  }
645
820
  ev.emit('call', [call]);
@@ -647,19 +822,19 @@ const makeMessagesRecvSocket = (config) => {
647
822
  };
648
823
  const handleBadAck = async ({ attrs }) => {
649
824
  const key = { remoteJid: attrs.from, fromMe: true, id: attrs.id };
650
- // current hypothesis is that if pash is sent in the ack
651
- // it means -- the message hasn't reached all devices yet
652
- // we'll retry sending the message here
653
- if (attrs.phash) {
654
- logger.info({ attrs }, 'received phash in ack, resending message...');
655
- const msg = await getMessage(key);
656
- if (msg) {
657
- await relayMessage(key.remoteJid, msg, { messageId: key.id, useUserDevicesCache: false });
658
- }
659
- else {
660
- logger.warn({ attrs }, 'could not send message again, as it was not found');
661
- }
662
- }
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
+ // }
663
838
  // error in acknowledgement,
664
839
  // device could not display the message
665
840
  if (attrs.error) {
@@ -684,22 +859,63 @@ const makeMessagesRecvSocket = (config) => {
684
859
  await execTask();
685
860
  ev.flush();
686
861
  function execTask() {
687
- return exec(node)
862
+ return exec(node, false)
688
863
  .catch(err => onUnexpectedError(err, identifier));
689
864
  }
690
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
+ };
691
907
  // recv a message
692
908
  ws.on('CB:message', (node) => {
693
- processNodeWithBuffer(node, 'processing message', handleMessage);
909
+ processNode('message', node, 'processing message', handleMessage);
694
910
  });
695
911
  ws.on('CB:call', async (node) => {
696
- processNodeWithBuffer(node, 'handling call', handleCall);
912
+ processNode('call', node, 'handling call', handleCall);
697
913
  });
698
914
  ws.on('CB:receipt', node => {
699
- processNodeWithBuffer(node, 'handling receipt', handleReceipt);
915
+ processNode('receipt', node, 'handling receipt', handleReceipt);
700
916
  });
701
917
  ws.on('CB:notification', async (node) => {
702
- processNodeWithBuffer(node, 'handling notification', handleNotification);
918
+ processNode('notification', node, 'handling notification', handleNotification);
703
919
  });
704
920
  ws.on('CB:ack,class:message', (node) => {
705
921
  handleBadAck(node)
@@ -741,7 +957,10 @@ const makeMessagesRecvSocket = (config) => {
741
957
  ...sock,
742
958
  sendMessageAck,
743
959
  sendRetryRequest,
744
- rejectCall
960
+ offerCall,
961
+ rejectCall,
962
+ fetchMessageHistory,
963
+ requestPlaceholderResend,
745
964
  };
746
965
  };
747
966
  exports.makeMessagesRecvSocket = makeMessagesRecvSocket;