jagproject 26.3.22 → 26.3.25

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 (206) hide show
  1. package/WAProto/GenerateStatics.sh +3 -4
  2. package/WAProto/WAProto.proto +1215 -511
  3. package/WAProto/fix-imports.js +73 -0
  4. package/WAProto/index.d.ts +14017 -0
  5. package/WAProto/index.js +64857 -145167
  6. package/engine-requirements.js +4 -7
  7. package/lib/Defaults/index.d.ts +74 -0
  8. package/lib/Defaults/index.js +51 -33
  9. package/lib/Defaults/phonenumber-mcc.json +223 -0
  10. package/lib/Defaults/wileys-version.json +2 -2
  11. package/lib/Signal/Group/ciphertext-message.d.ts +10 -0
  12. package/lib/Signal/Group/group-session-builder.d.ts +15 -0
  13. package/lib/Signal/Group/group-session-builder.js +5 -3
  14. package/lib/Signal/Group/group_cipher.d.ts +17 -0
  15. package/lib/Signal/Group/group_cipher.js +35 -46
  16. package/lib/Signal/Group/index.d.ts +12 -0
  17. package/lib/Signal/Group/index.js +21 -21
  18. package/lib/Signal/Group/keyhelper.d.ts +11 -0
  19. package/lib/Signal/Group/keyhelper.js +2 -2
  20. package/lib/Signal/Group/sender-chain-key.d.ts +14 -0
  21. package/lib/Signal/Group/sender-chain-key.js +5 -10
  22. package/lib/Signal/Group/sender-key-distribution-message.d.ts +17 -0
  23. package/lib/Signal/Group/sender-key-distribution-message.js +7 -7
  24. package/lib/Signal/Group/sender-key-message.d.ts +19 -0
  25. package/lib/Signal/Group/sender-key-message.js +8 -8
  26. package/lib/Signal/Group/sender-key-name.d.ts +18 -0
  27. package/lib/Signal/Group/sender-key-record.d.ts +31 -0
  28. package/lib/Signal/Group/sender-key-record.js +7 -16
  29. package/lib/Signal/Group/sender-key-state.d.ts +39 -0
  30. package/lib/Signal/Group/sender-key-state.js +25 -37
  31. package/lib/Signal/Group/sender-message-key.d.ts +12 -0
  32. package/lib/Signal/Group/sender-message-key.js +2 -2
  33. package/lib/Signal/libsignal.d.ts +5 -0
  34. package/lib/Signal/libsignal.js +358 -54
  35. package/lib/Signal/lid-mapping.d.ts +19 -0
  36. package/lib/Signal/lid-mapping.js +274 -0
  37. package/lib/Socket/Client/index.d.ts +3 -0
  38. package/lib/Socket/Client/index.js +2 -2
  39. package/lib/Socket/Client/types.d.ts +16 -0
  40. package/lib/Socket/Client/types.js +1 -0
  41. package/lib/Socket/Client/websocket.d.ts +13 -0
  42. package/lib/Socket/Client/websocket.js +18 -30
  43. package/lib/Socket/business.d.ts +202 -0
  44. package/lib/Socket/business.js +160 -38
  45. package/lib/Socket/chats.d.ts +111 -0
  46. package/lib/Socket/chats.js +497 -314
  47. package/lib/Socket/communities.d.ts +258 -0
  48. package/lib/Socket/communities.js +438 -0
  49. package/lib/Socket/community.js +333 -0
  50. package/lib/Socket/groups.d.ts +150 -0
  51. package/lib/Socket/groups.js +229 -91
  52. package/lib/Socket/index.d.ts +245 -0
  53. package/lib/Socket/index.js +9 -6
  54. package/lib/Socket/messages-recv.d.ts +187 -0
  55. package/lib/Socket/messages-recv.js +1105 -501
  56. package/lib/Socket/messages-send.d.ts +183 -0
  57. package/lib/Socket/messages-send.js +1184 -501
  58. package/lib/Socket/mex.d.ts +3 -0
  59. package/lib/Socket/mex.js +45 -0
  60. package/lib/Socket/newsletter.d.ts +160 -0
  61. package/lib/Socket/newsletter.js +227 -200
  62. package/lib/Socket/socket.d.ts +55 -0
  63. package/lib/Socket/socket.js +507 -206
  64. package/lib/Socket/usync.js +6 -6
  65. package/lib/Store/index.js +17 -5
  66. package/lib/Store/make-cache-manager-store.js +83 -0
  67. package/lib/Store/make-in-memory-store.js +48 -89
  68. package/lib/Store/make-ordered-dictionary.js +1 -1
  69. package/lib/Types/Auth.d.ts +116 -0
  70. package/lib/Types/Bussines.d.ts +25 -0
  71. package/lib/Types/Bussines.js +2 -0
  72. package/lib/Types/Call.d.ts +15 -0
  73. package/lib/Types/Chat.d.ts +123 -0
  74. package/lib/Types/Chat.js +7 -1
  75. package/lib/Types/Contact.d.ts +24 -0
  76. package/lib/Types/Events.d.ts +237 -0
  77. package/lib/Types/Events.js +1 -0
  78. package/lib/Types/GroupMetadata.d.ts +67 -0
  79. package/lib/Types/Label.d.ts +47 -0
  80. package/lib/Types/Label.js +1 -3
  81. package/lib/Types/LabelAssociation.d.ts +30 -0
  82. package/lib/Types/LabelAssociation.js +1 -3
  83. package/lib/Types/Message.d.ts +305 -0
  84. package/lib/Types/Message.js +9 -5
  85. package/lib/Types/MexUpdates.js +11 -0
  86. package/lib/Types/Newsletter.d.ts +135 -0
  87. package/lib/Types/Newsletter.js +36 -11
  88. package/lib/Types/Product.d.ts +79 -0
  89. package/lib/Types/Signal.d.ts +76 -0
  90. package/lib/Types/Signal.js +1 -0
  91. package/lib/Types/Socket.d.ts +133 -0
  92. package/lib/Types/Socket.js +1 -0
  93. package/lib/Types/State.d.ts +39 -0
  94. package/lib/Types/State.js +12 -0
  95. package/lib/Types/USync.d.ts +26 -0
  96. package/lib/Types/USync.js +1 -0
  97. package/lib/Types/index.d.ts +65 -0
  98. package/lib/Types/index.js +14 -14
  99. package/lib/Utils/audioToBuffer.js +31 -0
  100. package/lib/Utils/auth-utils.d.ts +19 -0
  101. package/lib/Utils/auth-utils.js +222 -123
  102. package/lib/Utils/baileys-event-stream.js +60 -0
  103. package/lib/Utils/browser-utils.d.ts +4 -0
  104. package/lib/Utils/browser-utils.js +38 -29
  105. package/lib/Utils/business.d.ts +23 -0
  106. package/lib/Utils/business.js +54 -48
  107. package/lib/Utils/chat-utils.d.ts +70 -0
  108. package/lib/Utils/chat-utils.js +284 -189
  109. package/lib/Utils/crypto.d.ts +37 -0
  110. package/lib/Utils/crypto.js +16 -41
  111. package/lib/Utils/decode-wa-message.d.ts +48 -0
  112. package/lib/Utils/decode-wa-message.js +128 -48
  113. package/lib/Utils/event-buffer.d.ts +34 -0
  114. package/lib/Utils/event-buffer.js +124 -62
  115. package/lib/Utils/generics.d.ts +91 -0
  116. package/lib/Utils/generics.js +154 -138
  117. package/lib/Utils/history.d.ts +22 -0
  118. package/lib/Utils/history.js +77 -34
  119. package/lib/Utils/identity-change-handler.d.ts +37 -0
  120. package/lib/Utils/identity-change-handler.js +54 -0
  121. package/lib/Utils/index.d.ts +22 -0
  122. package/lib/Utils/index.js +32 -19
  123. package/lib/Utils/link-preview.d.ts +21 -0
  124. package/lib/Utils/link-preview.js +12 -17
  125. package/lib/Utils/logger.d.ts +13 -0
  126. package/lib/Utils/lt-hash.d.ts +8 -0
  127. package/lib/Utils/lt-hash.js +2 -43
  128. package/lib/Utils/make-mutex.d.ts +9 -0
  129. package/lib/Utils/make-mutex.js +21 -27
  130. package/lib/Utils/message-retry-manager.d.ts +110 -0
  131. package/lib/Utils/message-retry-manager.js +143 -45
  132. package/lib/Utils/messages-media.d.ts +130 -0
  133. package/lib/Utils/messages-media.js +429 -502
  134. package/lib/Utils/messages-newsletter.d.ts +84 -0
  135. package/lib/Utils/messages-newsletter.js +295 -0
  136. package/lib/Utils/messages.d.ts +92 -0
  137. package/lib/Utils/messages.js +1099 -400
  138. package/lib/Utils/noise-handler.d.ts +20 -0
  139. package/lib/Utils/noise-handler.js +145 -91
  140. package/lib/Utils/pre-key-manager.d.ts +28 -0
  141. package/lib/Utils/pre-key-manager.js +112 -0
  142. package/lib/Utils/process-message.d.ts +60 -0
  143. package/lib/Utils/process-message.js +316 -184
  144. package/lib/Utils/reporting-utils.d.ts +11 -0
  145. package/lib/Utils/reporting-utils.js +262 -0
  146. package/lib/Utils/resolve-jid.d.ts +43 -0
  147. package/lib/Utils/resolve-jid.js +95 -0
  148. package/lib/Utils/serial-task-queue.js +29 -0
  149. package/lib/Utils/signal.d.ts +34 -0
  150. package/lib/Utils/signal.js +56 -39
  151. package/lib/Utils/streamToBuffer.js +17 -0
  152. package/lib/Utils/sync-action-utils.d.ts +19 -0
  153. package/lib/Utils/sync-action-utils.js +52 -0
  154. package/lib/Utils/tc-token-utils.d.ts +12 -0
  155. package/lib/Utils/tc-token-utils.js +20 -0
  156. package/lib/Utils/use-mongo-file-auth-state.js +71 -0
  157. package/lib/Utils/use-multi-file-auth-state.d.ts +13 -0
  158. package/lib/Utils/use-multi-file-auth-state.js +11 -12
  159. package/lib/Utils/use-single-file-auth-state.js +73 -0
  160. package/lib/Utils/validate-connection.d.ts +11 -0
  161. package/lib/Utils/validate-connection.js +59 -82
  162. package/lib/Utils/wileys-event-stream.js +1 -61
  163. package/lib/WABinary/constants.d.ts +28 -0
  164. package/lib/WABinary/decode.d.ts +7 -0
  165. package/lib/WABinary/decode.js +39 -4
  166. package/lib/WABinary/encode.d.ts +3 -0
  167. package/lib/WABinary/encode.js +17 -11
  168. package/lib/WABinary/generic-utils.d.ts +15 -0
  169. package/lib/WABinary/generic-utils.js +46 -18
  170. package/lib/WABinary/index.d.ts +6 -0
  171. package/lib/WABinary/index.js +9 -5
  172. package/lib/WABinary/jid-utils.d.ts +48 -0
  173. package/lib/WABinary/jid-utils.js +67 -37
  174. package/lib/WABinary/types.d.ts +19 -0
  175. package/lib/WABinary/types.js +34 -0
  176. package/lib/WAM/BinaryInfo.d.ts +9 -0
  177. package/lib/WAM/constants.d.ts +40 -0
  178. package/lib/WAM/constants.js +19183 -11678
  179. package/lib/WAM/encode.d.ts +3 -0
  180. package/lib/WAM/encode.js +15 -17
  181. package/lib/WAM/index.d.ts +4 -0
  182. package/lib/WAM/index.js +3 -3
  183. package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts +10 -0
  184. package/lib/WAUSync/Protocols/USyncContactProtocol.js +6 -6
  185. package/lib/WAUSync/Protocols/USyncDeviceProtocol.d.ts +23 -0
  186. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +9 -9
  187. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts +13 -0
  188. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +6 -6
  189. package/lib/WAUSync/Protocols/USyncStatusProtocol.d.ts +13 -0
  190. package/lib/WAUSync/Protocols/USyncStatusProtocol.js +7 -8
  191. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.d.ts +26 -0
  192. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +18 -17
  193. package/lib/WAUSync/Protocols/UsyncLIDProtocol.d.ts +10 -0
  194. package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +11 -3
  195. package/lib/WAUSync/Protocols/index.d.ts +5 -0
  196. package/lib/WAUSync/Protocols/index.js +6 -4
  197. package/lib/WAUSync/USyncQuery.d.ts +29 -0
  198. package/lib/WAUSync/USyncQuery.js +38 -30
  199. package/lib/WAUSync/USyncUser.d.ts +13 -0
  200. package/lib/WAUSync/index.d.ts +4 -0
  201. package/lib/WAUSync/index.js +3 -3
  202. package/lib/index.d.ts +12 -0
  203. package/lib/index.js +3 -5
  204. package/package.json +10 -6
  205. package/readme.md +97 -0
  206. package/LICENSE +0 -21
@@ -4,82 +4,224 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.makeMessagesRecvSocket = void 0;
7
+ const node_cache_1 = __importDefault(require("@cacheable/node-cache"));
7
8
  const boom_1 = require("@hapi/boom");
8
9
  const crypto_1 = require("crypto");
9
- const node_cache_1 = __importDefault(require("@cacheable/node-cache"));
10
- const WAProto_1 = require("../../WAProto");
11
- const Defaults_1 = require("../Defaults");
12
- const Types_1 = require("../Types");
13
- const Utils_1 = require("../Utils");
14
- const make_mutex_1 = require("../Utils/make-mutex");
15
- const WABinary_1 = require("../WABinary");
16
- const groups_1 = require("./groups");
17
- const messages_send_1 = require("./messages-send");
10
+ const long_1 = __importDefault(require("long"));
11
+ const index_js_1 = require("../../WAProto/index.js");
12
+ const index_js_2 = require("../Defaults/index.js");
13
+ const index_js_3 = require("../Types/index.js");
14
+ const index_js_4 = require("../Utils/index.js");
15
+ const make_mutex_js_1 = require("../Utils/make-mutex.js");
16
+ const index_js_5 = require("../WABinary/index.js");
17
+ const groups_js_1 = require("./groups.js");
18
+ const messages_send_js_1 = require("./messages-send.js");
19
+ const index_js_6 = require("../WAUSync/index.js");
18
20
  const makeMessagesRecvSocket = (config) => {
19
- const { logger, retryRequestDelayMs, maxMsgRetryCount, getMessage, shouldIgnoreJid } = config;
20
- const sock = (0, messages_send_1.makeMessagesSocket)(config);
21
- const { ev, authState, ws, processingMutex, signalRepository, query, upsertMessage, resyncAppState, groupMetadata, onUnexpectedError, assertSessions, sendNode, relayMessage, sendReceipt, uploadPreKeys, createParticipantNodes, getUSyncDevices, sendPeerDataOperationMessage, } = sock;
21
+ const { logger, retryRequestDelayMs, maxMsgRetryCount, getMessage, shouldIgnoreJid, enableAutoSessionRecreation } = config;
22
+ const sock = (0, messages_send_js_1.makeMessagesSocket)(config);
23
+ const { ev, authState, ws, messageMutex, notificationMutex, receiptMutex, signalRepository, query, upsertMessage, resyncAppState, onUnexpectedError, assertSessions, sendNode, relayMessage, sendReceipt, uploadPreKeys, sendPeerDataOperationMessage, messageRetryManager } = sock;
22
24
  /** this mutex ensures that each retryRequest will wait for the previous one to finish */
23
- const retryMutex = (0, make_mutex_1.makeMutex)();
24
- const msgRetryCache = config.msgRetryCounterCache || new node_cache_1.default({
25
- stdTTL: Defaults_1.DEFAULT_CACHE_TTLS.MSG_RETRY, // 1 hour
26
- useClones: false
27
- });
28
- const callOfferCache = config.callOfferCache || new node_cache_1.default({
29
- stdTTL: Defaults_1.DEFAULT_CACHE_TTLS.CALL_OFFER, // 5 mins
30
- useClones: false
31
- });
32
- const placeholderResendCache = config.placeholderResendCache || new node_cache_1.default({
33
- stdTTL: Defaults_1.DEFAULT_CACHE_TTLS.MSG_RETRY, // 1 hour
34
- useClones: false
35
- });
36
- const groupParticipantJidCache = new node_cache_1.default({
37
- stdTTL: 10 * 60, // 10 mins
38
- useClones: false
39
- });
40
- const groupMetadataWarmupCache = new node_cache_1.default({
41
- stdTTL: 60, // avoid repeated warmup calls per group
42
- useClones: false
43
- });
25
+ const retryMutex = (0, make_mutex_js_1.makeMutex)();
26
+ const msgRetryCache = config.msgRetryCounterCache ||
27
+ new node_cache_1.default({
28
+ stdTTL: index_js_2.DEFAULT_CACHE_TTLS.MSG_RETRY, // 1 hour
29
+ useClones: false
30
+ });
31
+ const callOfferCache = config.callOfferCache ||
32
+ new node_cache_1.default({
33
+ stdTTL: index_js_2.DEFAULT_CACHE_TTLS.CALL_OFFER, // 5 mins
34
+ useClones: false
35
+ });
36
+ const placeholderResendCache = config.placeholderResendCache ||
37
+ new node_cache_1.default({
38
+ stdTTL: index_js_2.DEFAULT_CACHE_TTLS.MSG_RETRY, // 1 hour
39
+ useClones: false
40
+ });
41
+ // Debounce identity-change session refreshes per JID to avoid bursts
42
+ const identityAssertDebounce = new node_cache_1.default({ stdTTL: 5, useClones: false });
44
43
  let sendActiveReceipts = false;
45
- const cacheGroupParticipants = (metadata) => {
46
- for (const participant of metadata.participants || []) {
47
- if (!participant.id || !participant.jid) {
48
- continue;
49
- }
50
- groupParticipantJidCache.set(`${metadata.id}:${participant.id}`, participant.jid);
51
- if (participant.lid) {
52
- groupParticipantJidCache.set(`${metadata.id}:${participant.lid}`, participant.jid);
53
- }
44
+ const fetchMessageHistory = async (count, oldestMsgKey, oldestMsgTimestamp) => {
45
+ if (!authState.creds.me?.id) {
46
+ throw new boom_1.Boom('Not authenticated');
54
47
  }
48
+ const pdoMessage = {
49
+ historySyncOnDemandRequest: {
50
+ chatJid: oldestMsgKey.remoteJid,
51
+ oldestMsgFromMe: oldestMsgKey.fromMe,
52
+ oldestMsgId: oldestMsgKey.id,
53
+ oldestMsgTimestampMs: oldestMsgTimestamp,
54
+ onDemandMsgCount: count
55
+ },
56
+ peerDataOperationRequestType: index_js_1.proto.Message.PeerDataOperationRequestType.HISTORY_SYNC_ON_DEMAND
57
+ };
58
+ return sendPeerDataOperationMessage(pdoMessage);
55
59
  };
56
- const warmupGroupParticipants = async (groupJid) => {
57
- if (groupMetadataWarmupCache.get(groupJid)) {
60
+ const requestPlaceholderResend = async (messageKey, msgData) => {
61
+ if (!authState.creds.me?.id) {
62
+ throw new boom_1.Boom('Not authenticated');
63
+ }
64
+ if (await placeholderResendCache.get(messageKey?.id)) {
65
+ logger.debug({ messageKey }, 'already requested resend');
58
66
  return;
59
67
  }
60
- groupMetadataWarmupCache.set(groupJid, true);
61
- try {
62
- const metadata = await groupMetadata(groupJid);
63
- cacheGroupParticipants(metadata);
68
+ else {
69
+ // Store original message data so PDO response handler can preserve
70
+ // metadata (LID details, timestamps, etc.) that the phone may omit
71
+ await placeholderResendCache.set(messageKey?.id, msgData || true);
64
72
  }
65
- catch (error) {
66
- logger.debug({ error, groupJid }, 'failed to warm up group participant cache');
73
+ await (0, index_js_4.delay)(2000);
74
+ if (!(await placeholderResendCache.get(messageKey?.id))) {
75
+ logger.debug({ messageKey }, 'message received while resend requested');
76
+ return 'RESOLVED';
67
77
  }
78
+ const pdoMessage = {
79
+ placeholderMessageResendRequest: [
80
+ {
81
+ messageKey
82
+ }
83
+ ],
84
+ peerDataOperationRequestType: index_js_1.proto.Message.PeerDataOperationRequestType.PLACEHOLDER_MESSAGE_RESEND
85
+ };
86
+ setTimeout(async () => {
87
+ if (await placeholderResendCache.get(messageKey?.id)) {
88
+ logger.debug({ messageKey }, 'PDO message without response after 8 seconds. Phone possibly offline');
89
+ await placeholderResendCache.del(messageKey?.id);
90
+ }
91
+ }, 8000);
92
+ return sendPeerDataOperationMessage(pdoMessage);
68
93
  };
69
- const resolveGroupParticipantJid = async (groupJid, participantLid) => {
70
- const cacheKey = `${groupJid}:${participantLid}`;
71
- const cachedParticipant = groupParticipantJidCache.get(cacheKey);
72
- if (cachedParticipant) {
73
- return cachedParticipant;
94
+ // Handles mex newsletter notifications
95
+ const handleMexNewsletterNotification = async (node) => {
96
+ const mexNode = (0, index_js_5.getBinaryNodeChild)(node, 'mex');
97
+ if (!mexNode?.content) {
98
+ logger.warn({ node }, 'Invalid mex newsletter notification');
99
+ return;
74
100
  }
101
+ let data;
75
102
  try {
76
- const metadata = await groupMetadata(groupJid);
77
- cacheGroupParticipants(metadata);
78
- return groupParticipantJidCache.get(cacheKey);
103
+ data = JSON.parse(mexNode.content.toString());
79
104
  }
80
105
  catch (error) {
81
- logger.debug({ error, groupJid, participantLid }, 'failed to resolve group participant jid');
82
- return undefined;
106
+ logger.error({ err: error, node }, 'Failed to parse mex newsletter notification');
107
+ return;
108
+ }
109
+ const operation = data?.operation;
110
+ const updates = data?.updates;
111
+ if (!updates || !operation) {
112
+ logger.warn({ data }, 'Invalid mex newsletter notification content');
113
+ return;
114
+ }
115
+ logger.info({ operation, updates }, 'got mex newsletter notification');
116
+ switch (operation) {
117
+ case 'NotificationNewsletterUpdate':
118
+ for (const update of updates) {
119
+ if (update.jid && update.settings && Object.keys(update.settings).length > 0) {
120
+ ev.emit('newsletter-settings.update', {
121
+ id: update.jid,
122
+ update: update.settings
123
+ });
124
+ }
125
+ }
126
+ break;
127
+ case 'NotificationNewsletterAdminPromote':
128
+ for (const update of updates) {
129
+ if (update.jid && update.user) {
130
+ ev.emit('newsletter-participants.update', {
131
+ id: update.jid,
132
+ author: node.attrs.from,
133
+ user: update.user,
134
+ new_role: 'ADMIN',
135
+ action: 'promote'
136
+ });
137
+ }
138
+ }
139
+ break;
140
+ default:
141
+ logger.info({ operation, data }, 'Unhandled mex newsletter notification');
142
+ break;
143
+ }
144
+ };
145
+ // Handles newsletter notifications
146
+ const handleNewsletterNotification = async (node) => {
147
+ const from = node.attrs.from;
148
+ const child = (0, index_js_5.getAllBinaryNodeChildren)(node)[0];
149
+ const author = node.attrs.participant;
150
+ logger.info({ from, child }, 'got newsletter notification');
151
+ switch (child.tag) {
152
+ case 'reaction':
153
+ const reactionUpdate = {
154
+ id: from,
155
+ server_id: child.attrs.message_id,
156
+ reaction: {
157
+ code: (0, index_js_5.getBinaryNodeChildString)(child, 'reaction'),
158
+ count: 1
159
+ }
160
+ };
161
+ ev.emit('newsletter.reaction', reactionUpdate);
162
+ break;
163
+ case 'view':
164
+ const viewUpdate = {
165
+ id: from,
166
+ server_id: child.attrs.message_id,
167
+ count: parseInt(child.content?.toString() || '0', 10)
168
+ };
169
+ ev.emit('newsletter.view', viewUpdate);
170
+ break;
171
+ case 'participant':
172
+ const participantUpdate = {
173
+ id: from,
174
+ author,
175
+ user: child.attrs.jid,
176
+ action: child.attrs.action,
177
+ new_role: child.attrs.role
178
+ };
179
+ ev.emit('newsletter-participants.update', participantUpdate);
180
+ break;
181
+ case 'update':
182
+ const settingsNode = (0, index_js_5.getBinaryNodeChild)(child, 'settings');
183
+ if (settingsNode) {
184
+ const update = {};
185
+ const nameNode = (0, index_js_5.getBinaryNodeChild)(settingsNode, 'name');
186
+ if (nameNode?.content)
187
+ update.name = nameNode.content.toString();
188
+ const descriptionNode = (0, index_js_5.getBinaryNodeChild)(settingsNode, 'description');
189
+ if (descriptionNode?.content)
190
+ update.description = descriptionNode.content.toString();
191
+ ev.emit('newsletter-settings.update', {
192
+ id: from,
193
+ update
194
+ });
195
+ }
196
+ break;
197
+ case 'message':
198
+ const plaintextNode = (0, index_js_5.getBinaryNodeChild)(child, 'plaintext');
199
+ if (plaintextNode?.content) {
200
+ try {
201
+ const contentBuf = typeof plaintextNode.content === 'string'
202
+ ? Buffer.from(plaintextNode.content, 'binary')
203
+ : Buffer.from(plaintextNode.content);
204
+ const messageProto = index_js_1.proto.Message.decode(contentBuf).toJSON();
205
+ const fullMessage = index_js_1.proto.WebMessageInfo.fromObject({
206
+ key: {
207
+ remoteJid: from,
208
+ id: child.attrs.message_id || child.attrs.server_id,
209
+ fromMe: false // TODO: is this really true though
210
+ },
211
+ message: messageProto,
212
+ messageTimestamp: +child.attrs.t
213
+ }).toJSON();
214
+ await upsertMessage(fullMessage, 'notify');
215
+ logger.info('Processed plaintext newsletter message');
216
+ }
217
+ catch (error) {
218
+ logger.error({ error }, 'Failed to decode plaintext newsletter message');
219
+ }
220
+ }
221
+ break;
222
+ default:
223
+ logger.warn({ node }, 'Unknown newsletter notification');
224
+ break;
83
225
  }
84
226
  };
85
227
  const sendMessageAck = async ({ tag, attrs, content }, errorCode) => {
@@ -100,112 +242,113 @@ const makeMessagesRecvSocket = (config) => {
100
242
  if (!!attrs.recipient) {
101
243
  stanza.attrs.recipient = attrs.recipient;
102
244
  }
103
- if (!!attrs.type && (tag !== 'message' || (0, WABinary_1.getBinaryNodeChild)({ tag, attrs, content }, 'unavailable') || errorCode !== 0)) {
245
+ if (!!attrs.type &&
246
+ (tag !== 'message' || (0, index_js_5.getBinaryNodeChild)({ tag, attrs, content }, 'unavailable') || errorCode !== 0)) {
104
247
  stanza.attrs.type = attrs.type;
105
248
  }
106
- if (tag === 'message' && (0, WABinary_1.getBinaryNodeChild)({ tag, attrs, content }, 'unavailable')) {
249
+ if (tag === 'message' && (0, index_js_5.getBinaryNodeChild)({ tag, attrs, content }, 'unavailable')) {
107
250
  stanza.attrs.from = authState.creds.me.id;
108
251
  }
109
252
  logger.debug({ recv: { tag, attrs }, sent: stanza.attrs }, 'sent ack');
110
253
  await sendNode(stanza);
111
254
  };
112
- const offerCall = async (toJid, isVideo = false) => {
113
- const callId = (0, crypto_1.randomBytes)(16).toString('hex').toUpperCase().substring(0, 64);
114
- const offerContent = [];
115
- offerContent.push({ tag: 'audio', attrs: { enc: 'opus', rate: '16000' }, content: undefined });
116
- offerContent.push({ tag: 'audio', attrs: { enc: 'opus', rate: '8000' }, content: undefined });
117
- if (isVideo) {
118
- offerContent.push({
119
- tag: 'video',
120
- attrs: {
121
- orientation: '0',
122
- 'screen_width': '1920',
123
- 'screen_height': '1080',
124
- 'device_orientation': '0',
125
- enc: 'vp8',
126
- dec: 'vp8',
127
- }
128
- });
129
- }
130
- offerContent.push({ tag: 'net', attrs: { medium: '3' }, content: undefined });
131
- offerContent.push({ tag: 'capability', attrs: { ver: '1' }, content: new Uint8Array([1, 4, 255, 131, 207, 4]) });
132
- offerContent.push({ tag: 'encopt', attrs: { keygen: '2' }, content: undefined });
133
- const encKey = (0, crypto_1.randomBytes)(32);
134
- const devices = (await getUSyncDevices([toJid], true, false)).map(({ user, device }) => (0, WABinary_1.jidEncode)(user, 's.whatsapp.net', device));
135
- await assertSessions(devices, true);
136
- const { nodes: destinations, shouldIncludeDeviceIdentity } = await createParticipantNodes(devices, {
137
- call: {
138
- callKey: encKey
139
- }
140
- });
141
- offerContent.push({ tag: 'destination', attrs: {}, content: destinations });
142
- if (shouldIncludeDeviceIdentity) {
143
- offerContent.push({
144
- tag: 'device-identity',
145
- attrs: {},
146
- content: (0, Utils_1.encodeSignedDeviceIdentity)(authState.creds.account, true)
147
- });
148
- }
149
- const stanza = ({
150
- tag: 'call',
151
- attrs: {
152
- to: toJid,
153
- },
154
- content: [{
155
- tag: 'offer',
156
- attrs: {
157
- 'call-id': callId,
158
- 'call-creator': authState.creds.me.id,
159
- },
160
- content: offerContent,
161
- }],
162
- });
163
- await query(stanza);
164
- return {
165
- callId,
166
- toJid,
167
- isVideo,
168
- };
169
- };
170
255
  const rejectCall = async (callId, callFrom) => {
171
- const stanza = ({
256
+ const stanza = {
172
257
  tag: 'call',
173
258
  attrs: {
174
259
  from: authState.creds.me.id,
175
- to: callFrom,
260
+ to: callFrom
176
261
  },
177
- content: [{
262
+ content: [
263
+ {
178
264
  tag: 'reject',
179
265
  attrs: {
180
266
  'call-id': callId,
181
267
  'call-creator': callFrom,
182
- count: '0',
268
+ count: '0'
183
269
  },
184
- content: undefined,
185
- }],
186
- });
270
+ content: undefined
271
+ }
272
+ ]
273
+ };
187
274
  await query(stanza);
188
275
  };
189
276
  const sendRetryRequest = async (node, forceIncludeKeys = false) => {
190
- const { fullMessage } = (0, Utils_1.decodeMessageNode)(node, authState.creds.me.id, authState.creds.me.lid || '');
277
+ const { fullMessage } = (0, index_js_4.decodeMessageNode)(node, authState.creds.me.id, authState.creds.me.lid || '');
191
278
  const { key: msgKey } = fullMessage;
192
279
  const msgId = msgKey.id;
193
- const key = `${msgId}:${msgKey === null || msgKey === void 0 ? void 0 : msgKey.participant}`;
194
- let retryCount = msgRetryCache.get(key) || 0;
195
- if (retryCount >= maxMsgRetryCount) {
196
- logger.debug({ retryCount, msgId }, 'reached retry limit, clearing');
197
- msgRetryCache.del(key);
198
- return;
280
+ if (messageRetryManager) {
281
+ // Check if we've exceeded max retries using the new system
282
+ if (messageRetryManager.hasExceededMaxRetries(msgId)) {
283
+ logger.debug({ msgId }, 'reached retry limit with new retry manager, clearing');
284
+ messageRetryManager.markRetryFailed(msgId);
285
+ return;
286
+ }
287
+ // Increment retry count using new system
288
+ const retryCount = messageRetryManager.incrementRetryCount(msgId);
289
+ // Use the new retry count for the rest of the logic
290
+ const key = `${msgId}:${msgKey?.participant}`;
291
+ await msgRetryCache.set(key, retryCount);
199
292
  }
200
- retryCount += 1;
201
- msgRetryCache.set(key, retryCount);
293
+ else {
294
+ // Fallback to old system
295
+ const key = `${msgId}:${msgKey?.participant}`;
296
+ let retryCount = (await msgRetryCache.get(key)) || 0;
297
+ if (retryCount >= maxMsgRetryCount) {
298
+ logger.debug({ retryCount, msgId }, 'reached retry limit, clearing');
299
+ await msgRetryCache.del(key);
300
+ return;
301
+ }
302
+ retryCount += 1;
303
+ await msgRetryCache.set(key, retryCount);
304
+ }
305
+ const key = `${msgId}:${msgKey?.participant}`;
306
+ const retryCount = (await msgRetryCache.get(key)) || 1;
202
307
  const { account, signedPreKey, signedIdentityKey: identityKey } = authState.creds;
203
- if (retryCount === 1) {
204
- //request a resend via phone
205
- const msgId = await requestPlaceholderResend(msgKey);
206
- logger.debug(`sendRetryRequest: requested placeholder resend for message ${msgId}`);
308
+ const fromJid = node.attrs.from;
309
+ // Check if we should recreate the session
310
+ let shouldRecreateSession = false;
311
+ let recreateReason = '';
312
+ if (enableAutoSessionRecreation && messageRetryManager && retryCount > 1) {
313
+ try {
314
+ // Check if we have a session with this JID
315
+ const sessionId = signalRepository.jidToSignalProtocolAddress(fromJid);
316
+ const hasSession = await signalRepository.validateSession(fromJid);
317
+ const result = messageRetryManager.shouldRecreateSession(fromJid, hasSession.exists);
318
+ shouldRecreateSession = result.recreate;
319
+ recreateReason = result.reason;
320
+ if (shouldRecreateSession) {
321
+ logger.debug({ fromJid, retryCount, reason: recreateReason }, 'recreating session for retry');
322
+ // Delete existing session to force recreation
323
+ await authState.keys.set({ session: { [sessionId]: null } });
324
+ forceIncludeKeys = true;
325
+ }
326
+ }
327
+ catch (error) {
328
+ logger.warn({ error, fromJid }, 'failed to check session recreation');
329
+ }
330
+ }
331
+ if (retryCount <= 2) {
332
+ // Use new retry manager for phone requests if available
333
+ if (messageRetryManager) {
334
+ // Schedule phone request with delay (like whatsmeow)
335
+ messageRetryManager.schedulePhoneRequest(msgId, async () => {
336
+ try {
337
+ const requestId = await requestPlaceholderResend(msgKey);
338
+ logger.debug(`sendRetryRequest: requested placeholder resend (${requestId}) for message ${msgId} (scheduled)`);
339
+ }
340
+ catch (error) {
341
+ logger.warn({ error, msgId }, 'failed to send scheduled phone request');
342
+ }
343
+ });
344
+ }
345
+ else {
346
+ // Fallback to immediate request
347
+ const msgId = await requestPlaceholderResend(msgKey);
348
+ logger.debug(`sendRetryRequest: requested placeholder resend for message ${msgId}`);
349
+ }
207
350
  }
208
- const deviceIdentity = (0, Utils_1.encodeSignedDeviceIdentity)(account, true);
351
+ const deviceIdentity = (0, index_js_4.encodeSignedDeviceIdentity)(account, true);
209
352
  await authState.keys.transaction(async () => {
210
353
  const receipt = {
211
354
  tag: 'receipt',
@@ -221,13 +364,15 @@ const makeMessagesRecvSocket = (config) => {
221
364
  count: retryCount.toString(),
222
365
  id: node.attrs.id,
223
366
  t: node.attrs.t,
224
- v: '1'
367
+ v: '1',
368
+ // ADD ERROR FIELD
369
+ error: '0'
225
370
  }
226
371
  },
227
372
  {
228
373
  tag: 'registration',
229
374
  attrs: {},
230
- content: (0, Utils_1.encodeBigEndian)(authState.creds.registrationId)
375
+ content: (0, index_js_4.encodeBigEndian)(authState.creds.registrationId)
231
376
  }
232
377
  ]
233
378
  };
@@ -237,8 +382,8 @@ const makeMessagesRecvSocket = (config) => {
237
382
  if (node.attrs.participant) {
238
383
  receipt.attrs.participant = node.attrs.participant;
239
384
  }
240
- if (retryCount > 1 || forceIncludeKeys) {
241
- const { update, preKeys } = await (0, Utils_1.getNextPreKeys)(authState, 1);
385
+ if (retryCount > 1 || forceIncludeKeys || shouldRecreateSession) {
386
+ const { update, preKeys } = await (0, index_js_4.getNextPreKeys)(authState, 1);
242
387
  const [keyId] = Object.keys(preKeys);
243
388
  const key = preKeys[+keyId];
244
389
  const content = receipt.content;
@@ -246,10 +391,10 @@ const makeMessagesRecvSocket = (config) => {
246
391
  tag: 'keys',
247
392
  attrs: {},
248
393
  content: [
249
- { tag: 'type', attrs: {}, content: Buffer.from(Defaults_1.KEY_BUNDLE_TYPE) },
394
+ { tag: 'type', attrs: {}, content: Buffer.from(index_js_2.KEY_BUNDLE_TYPE) },
250
395
  { tag: 'identity', attrs: {}, content: identityKey.public },
251
- (0, Utils_1.xmppPreKey)(key, +keyId),
252
- (0, Utils_1.xmppSignedPreKey)(signedPreKey),
396
+ (0, index_js_4.xmppPreKey)(key, +keyId),
397
+ (0, index_js_4.xmppSignedPreKey)(signedPreKey),
253
398
  { tag: 'device-identity', attrs: {}, content: deviceIdentity }
254
399
  ]
255
400
  });
@@ -257,63 +402,73 @@ const makeMessagesRecvSocket = (config) => {
257
402
  }
258
403
  await sendNode(receipt);
259
404
  logger.info({ msgAttrs: node.attrs, retryCount }, 'sent retry receipt');
260
- });
405
+ }, authState?.creds?.me?.id || 'sendRetryRequest');
261
406
  };
262
407
  const handleEncryptNotification = async (node) => {
263
408
  const from = node.attrs.from;
264
- if (from === WABinary_1.S_WHATSAPP_NET) {
265
- const countChild = (0, WABinary_1.getBinaryNodeChild)(node, 'count');
409
+ if (from === index_js_5.S_WHATSAPP_NET) {
410
+ const countChild = (0, index_js_5.getBinaryNodeChild)(node, 'count');
266
411
  const count = +countChild.attrs.value;
267
- const shouldUploadMorePreKeys = count < Defaults_1.MIN_PREKEY_COUNT;
412
+ const shouldUploadMorePreKeys = count < index_js_2.MIN_PREKEY_COUNT;
268
413
  logger.debug({ count, shouldUploadMorePreKeys }, 'recv pre-key count');
269
414
  if (shouldUploadMorePreKeys) {
270
415
  await uploadPreKeys();
271
416
  }
272
417
  }
273
418
  else {
274
- const identityNode = (0, WABinary_1.getBinaryNodeChild)(node, 'identity');
275
- if (identityNode) {
276
- logger.info({ jid: from }, 'identity changed');
277
- // not handling right now
278
- // signal will override new identity anyway
279
- }
280
- else {
419
+ const result = await (0, index_js_4.handleIdentityChange)(node, {
420
+ meId: authState.creds.me?.id,
421
+ meLid: authState.creds.me?.lid,
422
+ validateSession: signalRepository.validateSession,
423
+ assertSessions,
424
+ debounceCache: identityAssertDebounce,
425
+ logger
426
+ });
427
+ if (result.action === 'no_identity_node') {
281
428
  logger.info({ node }, 'unknown encrypt notification');
282
429
  }
283
430
  }
284
431
  };
285
- const handleGroupNotification = (participant, child, msg) => {
286
- var _a, _b, _c, _d;
287
- 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;
288
- switch (child === null || child === void 0 ? void 0 : child.tag) {
432
+ const handleGroupNotification = (fullNode, child, msg) => {
433
+ // TODO: Support PN/LID (Here is only LID now)
434
+ const actingParticipantLid = fullNode.attrs.participant;
435
+ const actingParticipantPn = fullNode.attrs.participant_pn;
436
+ const affectedParticipantLid = (0, index_js_5.getBinaryNodeChild)(child, 'participant')?.attrs?.jid || actingParticipantLid;
437
+ const affectedParticipantPn = (0, index_js_5.getBinaryNodeChild)(child, 'participant')?.attrs?.phone_number || actingParticipantPn;
438
+ switch (child?.tag) {
289
439
  case 'create':
290
- const metadata = (0, groups_1.extractGroupMetadata)(child);
291
- msg.messageStubType = Types_1.WAMessageStubType.GROUP_CREATE;
440
+ const metadata = (0, groups_js_1.extractGroupMetadata)(child);
441
+ msg.messageStubType = index_js_3.WAMessageStubType.GROUP_CREATE;
292
442
  msg.messageStubParameters = [metadata.subject];
293
- msg.key = { participant: metadata.owner };
294
- ev.emit('chats.upsert', [{
443
+ msg.key = { participant: metadata.owner, participantAlt: metadata.ownerPn };
444
+ ev.emit('chats.upsert', [
445
+ {
295
446
  id: metadata.id,
296
447
  name: metadata.subject,
297
- conversationTimestamp: metadata.creation,
298
- }]);
299
- ev.emit('groups.upsert', [{
448
+ conversationTimestamp: metadata.creation
449
+ }
450
+ ]);
451
+ ev.emit('groups.upsert', [
452
+ {
300
453
  ...metadata,
301
- author: participant
302
- }]);
454
+ author: actingParticipantLid,
455
+ authorPn: actingParticipantPn
456
+ }
457
+ ]);
303
458
  break;
304
459
  case 'ephemeral':
305
460
  case 'not_ephemeral':
306
461
  msg.message = {
307
462
  protocolMessage: {
308
- type: WAProto_1.proto.Message.ProtocolMessage.Type.EPHEMERAL_SETTING,
463
+ type: index_js_1.proto.Message.ProtocolMessage.Type.EPHEMERAL_SETTING,
309
464
  ephemeralExpiration: +(child.attrs.expiration || 0)
310
465
  }
311
466
  };
312
467
  break;
313
468
  case 'modify':
314
- const oldNumber = (0, WABinary_1.getBinaryNodeChildren)(child, 'participant').map(p => p.attrs.jid);
469
+ const oldNumber = (0, index_js_5.getBinaryNodeChildren)(child, 'participant').map(p => p.attrs.jid);
315
470
  msg.messageStubParameters = oldNumber || [];
316
- msg.messageStubType = Types_1.WAMessageStubType.GROUP_PARTICIPANT_CHANGE_NUMBER;
471
+ msg.messageStubType = index_js_3.WAMessageStubType.GROUP_PARTICIPANT_CHANGE_NUMBER;
317
472
  break;
318
473
  case 'promote':
319
474
  case 'demote':
@@ -321,179 +476,141 @@ const makeMessagesRecvSocket = (config) => {
321
476
  case 'add':
322
477
  case 'leave':
323
478
  const stubType = `GROUP_PARTICIPANT_${child.tag.toUpperCase()}`;
324
- msg.messageStubType = Types_1.WAMessageStubType[stubType];
325
- const participants = (0, WABinary_1.getBinaryNodeChildren)(child, 'participant').map(p => p.attrs.jid);
479
+ msg.messageStubType = index_js_3.WAMessageStubType[stubType];
480
+ const participants = (0, index_js_5.getBinaryNodeChildren)(child, 'participant').map(({ attrs }) => {
481
+ // TODO: Store LID MAPPINGS
482
+ return {
483
+ id: attrs.jid,
484
+ phoneNumber: (0, index_js_5.isLidUser)(attrs.jid) && (0, index_js_5.isPnUser)(attrs.phone_number) ? attrs.phone_number : undefined,
485
+ lid: (0, index_js_5.isPnUser)(attrs.jid) && (0, index_js_5.isLidUser)(attrs.lid) ? attrs.lid : undefined,
486
+ admin: (attrs.type || null)
487
+ };
488
+ });
326
489
  if (participants.length === 1 &&
327
490
  // if recv. "remove" message and sender removed themselves
328
491
  // mark as left
329
- (0, WABinary_1.areJidsSameUser)(participants[0], participant) &&
492
+ ((0, index_js_5.areJidsSameUser)(participants[0].id, actingParticipantLid) ||
493
+ (0, index_js_5.areJidsSameUser)(participants[0].id, actingParticipantPn)) &&
330
494
  child.tag === 'remove') {
331
- msg.messageStubType = Types_1.WAMessageStubType.GROUP_PARTICIPANT_LEAVE;
495
+ msg.messageStubType = index_js_3.WAMessageStubType.GROUP_PARTICIPANT_LEAVE;
332
496
  }
333
- msg.messageStubParameters = participants;
497
+ msg.messageStubParameters = participants.map(a => JSON.stringify(a));
334
498
  break;
335
499
  case 'subject':
336
- msg.messageStubType = Types_1.WAMessageStubType.GROUP_CHANGE_SUBJECT;
500
+ msg.messageStubType = index_js_3.WAMessageStubType.GROUP_CHANGE_SUBJECT;
337
501
  msg.messageStubParameters = [child.attrs.subject];
338
502
  break;
339
503
  case 'description':
340
- 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();
341
- msg.messageStubType = Types_1.WAMessageStubType.GROUP_CHANGE_DESCRIPTION;
504
+ const description = (0, index_js_5.getBinaryNodeChild)(child, 'body')?.content?.toString();
505
+ msg.messageStubType = index_js_3.WAMessageStubType.GROUP_CHANGE_DESCRIPTION;
342
506
  msg.messageStubParameters = description ? [description] : undefined;
343
507
  break;
344
508
  case 'announcement':
345
509
  case 'not_announcement':
346
- msg.messageStubType = Types_1.WAMessageStubType.GROUP_CHANGE_ANNOUNCE;
347
- msg.messageStubParameters = [(child.tag === 'announcement') ? 'on' : 'off'];
510
+ msg.messageStubType = index_js_3.WAMessageStubType.GROUP_CHANGE_ANNOUNCE;
511
+ msg.messageStubParameters = [child.tag === 'announcement' ? 'on' : 'off'];
348
512
  break;
349
513
  case 'locked':
350
514
  case 'unlocked':
351
- msg.messageStubType = Types_1.WAMessageStubType.GROUP_CHANGE_RESTRICT;
352
- msg.messageStubParameters = [(child.tag === 'locked') ? 'on' : 'off'];
515
+ msg.messageStubType = index_js_3.WAMessageStubType.GROUP_CHANGE_RESTRICT;
516
+ msg.messageStubParameters = [child.tag === 'locked' ? 'on' : 'off'];
353
517
  break;
354
518
  case 'invite':
355
- msg.messageStubType = Types_1.WAMessageStubType.GROUP_CHANGE_INVITE_LINK;
519
+ msg.messageStubType = index_js_3.WAMessageStubType.GROUP_CHANGE_INVITE_LINK;
356
520
  msg.messageStubParameters = [child.attrs.code];
357
521
  break;
358
522
  case 'member_add_mode':
359
523
  const addMode = child.content;
360
524
  if (addMode) {
361
- msg.messageStubType = Types_1.WAMessageStubType.GROUP_MEMBER_ADD_MODE;
525
+ msg.messageStubType = index_js_3.WAMessageStubType.GROUP_MEMBER_ADD_MODE;
362
526
  msg.messageStubParameters = [addMode.toString()];
363
527
  }
364
528
  break;
365
529
  case 'membership_approval_mode':
366
- const approvalMode = (0, WABinary_1.getBinaryNodeChild)(child, 'group_join');
530
+ const approvalMode = (0, index_js_5.getBinaryNodeChild)(child, 'group_join');
367
531
  if (approvalMode) {
368
- msg.messageStubType = Types_1.WAMessageStubType.GROUP_MEMBERSHIP_JOIN_APPROVAL_MODE;
532
+ msg.messageStubType = index_js_3.WAMessageStubType.GROUP_MEMBERSHIP_JOIN_APPROVAL_MODE;
369
533
  msg.messageStubParameters = [approvalMode.attrs.state];
370
534
  }
371
535
  break;
372
536
  case 'created_membership_requests':
373
- msg.messageStubType = Types_1.WAMessageStubType.GROUP_MEMBERSHIP_JOIN_APPROVAL_REQUEST_NON_ADMIN_ADD;
374
- msg.messageStubParameters = [participantJid, 'created', child.attrs.request_method];
537
+ msg.messageStubType = index_js_3.WAMessageStubType.GROUP_MEMBERSHIP_JOIN_APPROVAL_REQUEST_NON_ADMIN_ADD;
538
+ msg.messageStubParameters = [
539
+ JSON.stringify({ lid: affectedParticipantLid, pn: affectedParticipantPn }),
540
+ 'created',
541
+ child.attrs.request_method
542
+ ];
375
543
  break;
376
544
  case 'revoked_membership_requests':
377
- const isDenied = (0, WABinary_1.areJidsSameUser)(participantJid, participant);
378
- msg.messageStubType = Types_1.WAMessageStubType.GROUP_MEMBERSHIP_JOIN_APPROVAL_REQUEST_NON_ADMIN_ADD;
379
- msg.messageStubParameters = [participantJid, isDenied ? 'revoked' : 'rejected'];
380
- break;
545
+ const isDenied = (0, index_js_5.areJidsSameUser)(affectedParticipantLid, actingParticipantLid);
546
+ // TODO: LIDMAPPING SUPPORT
547
+ msg.messageStubType = index_js_3.WAMessageStubType.GROUP_MEMBERSHIP_JOIN_APPROVAL_REQUEST_NON_ADMIN_ADD;
548
+ msg.messageStubParameters = [
549
+ JSON.stringify({ lid: affectedParticipantLid, pn: affectedParticipantPn }),
550
+ isDenied ? 'revoked' : 'rejected'
551
+ ];
381
552
  break;
382
- default:
383
- // console.log("WILEYS-DEBUG:", JSON.stringify({ ...child, content: Buffer.isBuffer(child.content) ? child.content.toString() : child.content, participant }, null, 2))
384
- }
385
- };
386
- const handleNewsletterNotification = (id, node) => {
387
- const messages = (0, WABinary_1.getBinaryNodeChild)(node, 'messages');
388
- const message = (0, WABinary_1.getBinaryNodeChild)(messages, 'message');
389
- const serverId = message.attrs.server_id;
390
- const reactionsList = (0, WABinary_1.getBinaryNodeChild)(message, 'reactions');
391
- const viewsList = (0, WABinary_1.getBinaryNodeChildren)(message, 'views_count');
392
- if (reactionsList) {
393
- const reactions = (0, WABinary_1.getBinaryNodeChildren)(reactionsList, 'reaction');
394
- if (reactions.length === 0) {
395
- ev.emit('newsletter.reaction', { id, 'server_id': serverId, reaction: { removed: true } });
396
- }
397
- reactions.forEach(item => {
398
- var _a, _b;
399
- ev.emit('newsletter.reaction', { id, 'server_id': serverId, reaction: { code: (_a = item.attrs) === null || _a === void 0 ? void 0 : _a.code, count: +((_b = item.attrs) === null || _b === void 0 ? void 0 : _b.count) } });
400
- });
401
- }
402
- if (viewsList.length) {
403
- viewsList.forEach(item => {
404
- ev.emit('newsletter.view', { id, 'server_id': serverId, count: +item.attrs.count });
405
- });
406
- }
407
- };
408
- const handleMexNewsletterNotification = (id, node) => {
409
- var _a;
410
- const operation = node === null || node === void 0 ? void 0 : node.attrs.op_name;
411
- const content = JSON.parse((_a = node === null || node === void 0 ? void 0 : node.content) === null || _a === void 0 ? void 0 : _a.toString());
412
- let contentPath;
413
- if (operation === Types_1.MexOperations.PROMOTE || operation === Types_1.MexOperations.DEMOTE) {
414
- let action;
415
- if (operation === Types_1.MexOperations.PROMOTE) {
416
- action = 'promote';
417
- contentPath = content.data[Types_1.XWAPaths.PROMOTE];
418
- }
419
- if (operation === Types_1.MexOperations.DEMOTE) {
420
- action = 'demote';
421
- contentPath = content.data[Types_1.XWAPaths.DEMOTE];
422
- }
423
- ev.emit('newsletter-participants.update', { id, author: contentPath.actor.pn, user: contentPath.user.pn, new_role: contentPath.user_new_role, action });
424
- }
425
- if (operation === Types_1.MexOperations.UPDATE) {
426
- contentPath = content.data[Types_1.XWAPaths.METADATA_UPDATE];
427
- ev.emit('newsletter-settings.update', { id, update: contentPath.thread_metadata.settings });
428
553
  }
429
554
  };
430
555
  const processNotification = async (node) => {
431
- var _a, _b;
432
556
  const result = {};
433
- const [child] = (0, WABinary_1.getAllBinaryNodeChildren)(node);
557
+ const [child] = (0, index_js_5.getAllBinaryNodeChildren)(node);
434
558
  const nodeType = node.attrs.type;
435
- const from = (0, WABinary_1.jidNormalizedUser)(node.attrs.from);
559
+ const from = (0, index_js_5.jidNormalizedUser)(node.attrs.from);
436
560
  switch (nodeType) {
437
- case 'privacy_token':
438
- const tokenList = (0, WABinary_1.getBinaryNodeChildren)(child, 'token');
439
- for (const { attrs, content } of tokenList) {
440
- const jid = attrs.jid;
441
- ev.emit('chats.update', [
442
- {
443
- id: jid,
444
- tcToken: content
445
- }
446
- ]);
447
- logger.debug({ jid }, 'got privacy token update');
448
- }
449
- break;
450
561
  case 'newsletter':
451
- handleNewsletterNotification(node.attrs.from, child);
562
+ await handleNewsletterNotification(node);
452
563
  break;
453
564
  case 'mex':
454
- handleMexNewsletterNotification(node.attrs.from, child);
565
+ await handleMexNewsletterNotification(node);
455
566
  break;
456
567
  case 'w:gp2':
457
- handleGroupNotification(node.attrs.participant, child, result);
568
+ // TODO: HANDLE PARTICIPANT_PN
569
+ handleGroupNotification(node, child, result);
458
570
  break;
459
571
  case 'mediaretry':
460
- const event = (0, Utils_1.decodeMediaRetryNode)(node);
572
+ const event = (0, index_js_4.decodeMediaRetryNode)(node);
461
573
  ev.emit('messages.media-update', [event]);
462
574
  break;
463
575
  case 'encrypt':
464
576
  await handleEncryptNotification(node);
465
577
  break;
466
578
  case 'devices':
467
- const devices = (0, WABinary_1.getBinaryNodeChildren)(child, 'device');
468
- if ((0, WABinary_1.areJidsSameUser)(child.attrs.jid, authState.creds.me.id)) {
469
- const deviceJids = devices.map(d => d.attrs.jid);
470
- logger.info({ deviceJids }, 'got my own devices');
579
+ const devices = (0, index_js_5.getBinaryNodeChildren)(child, 'device');
580
+ if ((0, index_js_5.areJidsSameUser)(child.attrs.jid, authState.creds.me.id) ||
581
+ (0, index_js_5.areJidsSameUser)(child.attrs.lid, authState.creds.me.lid)) {
582
+ const deviceData = devices.map(d => ({ id: d.attrs.jid, lid: d.attrs.lid }));
583
+ logger.info({ deviceData }, 'my own devices changed');
471
584
  }
585
+ //TODO: drop a new event, add hashes
472
586
  break;
473
587
  case 'server_sync':
474
- const update = (0, WABinary_1.getBinaryNodeChild)(node, 'collection');
588
+ const update = (0, index_js_5.getBinaryNodeChild)(node, 'collection');
475
589
  if (update) {
476
590
  const name = update.attrs.name;
477
591
  await resyncAppState([name], false);
478
592
  }
479
593
  break;
480
594
  case 'picture':
481
- const setPicture = (0, WABinary_1.getBinaryNodeChild)(node, 'set');
482
- const delPicture = (0, WABinary_1.getBinaryNodeChild)(node, 'delete');
483
- ev.emit('contacts.update', [{
484
- id: from || ((_b = (_a = (setPicture || delPicture)) === null || _a === void 0 ? void 0 : _a.attrs) === null || _b === void 0 ? void 0 : _b.hash) || '',
595
+ const setPicture = (0, index_js_5.getBinaryNodeChild)(node, 'set');
596
+ const delPicture = (0, index_js_5.getBinaryNodeChild)(node, 'delete');
597
+ // TODO: WAJIDHASH stuff proper support inhouse
598
+ ev.emit('contacts.update', [
599
+ {
600
+ id: (0, index_js_5.jidNormalizedUser)(node?.attrs?.from) || (setPicture || delPicture)?.attrs?.hash || '',
485
601
  imgUrl: setPicture ? 'changed' : 'removed'
486
- }]);
487
- if ((0, WABinary_1.isJidGroup)(from)) {
602
+ }
603
+ ]);
604
+ if ((0, index_js_5.isJidGroup)(from)) {
488
605
  const node = setPicture || delPicture;
489
- result.messageStubType = Types_1.WAMessageStubType.GROUP_CHANGE_ICON;
606
+ result.messageStubType = index_js_3.WAMessageStubType.GROUP_CHANGE_ICON;
490
607
  if (setPicture) {
491
608
  result.messageStubParameters = [setPicture.attrs.id];
492
609
  }
493
- result.participant = node === null || node === void 0 ? void 0 : node.attrs.author;
610
+ result.participant = node?.attrs.author;
494
611
  result.key = {
495
- ...result.key || {},
496
- participant: setPicture === null || setPicture === void 0 ? void 0 : setPicture.attrs.author
612
+ ...(result.key || {}),
613
+ participant: setPicture?.attrs.author
497
614
  };
498
615
  }
499
616
  break;
@@ -507,44 +624,48 @@ const makeMessagesRecvSocket = (config) => {
507
624
  ...authState.creds.accountSettings,
508
625
  defaultDisappearingMode: {
509
626
  ephemeralExpiration: newDuration,
510
- ephemeralSettingTimestamp: timestamp,
511
- },
627
+ ephemeralSettingTimestamp: timestamp
628
+ }
512
629
  }
513
630
  });
514
631
  }
515
632
  else if (child.tag === 'blocklist') {
516
- const blocklists = (0, WABinary_1.getBinaryNodeChildren)(child, 'item');
633
+ const blocklists = (0, index_js_5.getBinaryNodeChildren)(child, 'item');
517
634
  for (const { attrs } of blocklists) {
518
635
  const blocklist = [attrs.jid];
519
- const type = (attrs.action === 'block') ? 'add' : 'remove';
636
+ const type = attrs.action === 'block' ? 'add' : 'remove';
520
637
  ev.emit('blocklist.update', { blocklist, type });
521
638
  }
522
639
  }
523
640
  break;
524
641
  case 'link_code_companion_reg':
525
- const linkCodeCompanionReg = (0, WABinary_1.getBinaryNodeChild)(node, 'link_code_companion_reg');
526
- const ref = toRequiredBuffer((0, WABinary_1.getBinaryNodeChildBuffer)(linkCodeCompanionReg, 'link_code_pairing_ref'));
527
- const primaryIdentityPublicKey = toRequiredBuffer((0, WABinary_1.getBinaryNodeChildBuffer)(linkCodeCompanionReg, 'primary_identity_pub'));
528
- const primaryEphemeralPublicKeyWrapped = toRequiredBuffer((0, WABinary_1.getBinaryNodeChildBuffer)(linkCodeCompanionReg, 'link_code_pairing_wrapped_primary_ephemeral_pub'));
642
+ const linkCodeCompanionReg = (0, index_js_5.getBinaryNodeChild)(node, 'link_code_companion_reg');
643
+ const ref = toRequiredBuffer((0, index_js_5.getBinaryNodeChildBuffer)(linkCodeCompanionReg, 'link_code_pairing_ref'));
644
+ const primaryIdentityPublicKey = toRequiredBuffer((0, index_js_5.getBinaryNodeChildBuffer)(linkCodeCompanionReg, 'primary_identity_pub'));
645
+ const primaryEphemeralPublicKeyWrapped = toRequiredBuffer((0, index_js_5.getBinaryNodeChildBuffer)(linkCodeCompanionReg, 'link_code_pairing_wrapped_primary_ephemeral_pub'));
529
646
  const codePairingPublicKey = await decipherLinkPublicKey(primaryEphemeralPublicKeyWrapped);
530
- const companionSharedKey = Utils_1.Curve.sharedKey(authState.creds.pairingEphemeralKeyPair.private, codePairingPublicKey);
647
+ const companionSharedKey = index_js_4.Curve.sharedKey(authState.creds.pairingEphemeralKeyPair.private, codePairingPublicKey);
531
648
  const random = (0, crypto_1.randomBytes)(32);
532
649
  const linkCodeSalt = (0, crypto_1.randomBytes)(32);
533
- const linkCodePairingExpanded = await (0, Utils_1.hkdf)(companionSharedKey, 32, {
650
+ const linkCodePairingExpanded = (0, index_js_4.hkdf)(companionSharedKey, 32, {
534
651
  salt: linkCodeSalt,
535
652
  info: 'link_code_pairing_key_bundle_encryption_key'
536
653
  });
537
- const encryptPayload = Buffer.concat([Buffer.from(authState.creds.signedIdentityKey.public), primaryIdentityPublicKey, random]);
654
+ const encryptPayload = Buffer.concat([
655
+ Buffer.from(authState.creds.signedIdentityKey.public),
656
+ primaryIdentityPublicKey,
657
+ random
658
+ ]);
538
659
  const encryptIv = (0, crypto_1.randomBytes)(12);
539
- const encrypted = (0, Utils_1.aesEncryptGCM)(encryptPayload, linkCodePairingExpanded, encryptIv, Buffer.alloc(0));
660
+ const encrypted = (0, index_js_4.aesEncryptGCM)(encryptPayload, linkCodePairingExpanded, encryptIv, Buffer.alloc(0));
540
661
  const encryptedPayload = Buffer.concat([linkCodeSalt, encryptIv, encrypted]);
541
- const identitySharedKey = Utils_1.Curve.sharedKey(authState.creds.signedIdentityKey.private, primaryIdentityPublicKey);
662
+ const identitySharedKey = index_js_4.Curve.sharedKey(authState.creds.signedIdentityKey.private, primaryIdentityPublicKey);
542
663
  const identityPayload = Buffer.concat([companionSharedKey, identitySharedKey, random]);
543
- authState.creds.advSecretKey = (await (0, Utils_1.hkdf)(identityPayload, 32, { info: 'adv_secret' })).toString('base64');
664
+ authState.creds.advSecretKey = Buffer.from((0, index_js_4.hkdf)(identityPayload, 32, { info: 'adv_secret' })).toString('base64');
544
665
  await query({
545
666
  tag: 'iq',
546
667
  attrs: {
547
- to: WABinary_1.S_WHATSAPP_NET,
668
+ to: index_js_5.S_WHATSAPP_NET,
548
669
  type: 'set',
549
670
  id: sock.generateMessageTag(),
550
671
  xmlns: 'md'
@@ -554,7 +675,7 @@ const makeMessagesRecvSocket = (config) => {
554
675
  tag: 'link_code_companion_reg',
555
676
  attrs: {
556
677
  jid: authState.creds.me.id,
557
- stage: 'companion_finish',
678
+ stage: 'companion_finish'
558
679
  },
559
680
  content: [
560
681
  {
@@ -578,18 +699,44 @@ const makeMessagesRecvSocket = (config) => {
578
699
  });
579
700
  authState.creds.registered = true;
580
701
  ev.emit('creds.update', authState.creds);
702
+ break;
703
+ case 'privacy_token':
704
+ await handlePrivacyTokenNotification(node);
705
+ break;
581
706
  }
582
707
  if (Object.keys(result).length) {
583
708
  return result;
584
709
  }
585
710
  };
711
+ const handlePrivacyTokenNotification = async (node) => {
712
+ const tokensNode = (0, index_js_5.getBinaryNodeChild)(node, 'tokens');
713
+ const from = (0, index_js_5.jidNormalizedUser)(node.attrs.from);
714
+ if (!tokensNode)
715
+ return;
716
+ const tokenNodes = (0, index_js_5.getBinaryNodeChildren)(tokensNode, 'token');
717
+ for (const tokenNode of tokenNodes) {
718
+ const { attrs, content } = tokenNode;
719
+ const type = attrs.type;
720
+ const timestamp = attrs.t;
721
+ if (type === 'trusted_contact' && content instanceof Buffer) {
722
+ logger.debug({
723
+ from,
724
+ timestamp,
725
+ tcToken: content
726
+ }, 'received trusted contact token');
727
+ await authState.keys.set({
728
+ tctoken: { [from]: { token: content, timestamp } }
729
+ });
730
+ }
731
+ }
732
+ };
586
733
  async function decipherLinkPublicKey(data) {
587
734
  const buffer = toRequiredBuffer(data);
588
735
  const salt = buffer.slice(0, 32);
589
- const secretKey = await (0, Utils_1.derivePairingCodeKey)(authState.creds.pairingCode, salt);
736
+ const secretKey = await (0, index_js_4.derivePairingCodeKey)(authState.creds.pairingCode, salt);
590
737
  const iv = buffer.slice(32, 48);
591
738
  const payload = buffer.slice(48, 80);
592
- return (0, Utils_1.aesDecryptCTR)(payload, secretKey, iv);
739
+ return (0, index_js_4.aesDecryptCTR)(payload, secretKey, iv);
593
740
  }
594
741
  function toRequiredBuffer(data) {
595
742
  if (data === undefined) {
@@ -597,34 +744,80 @@ const makeMessagesRecvSocket = (config) => {
597
744
  }
598
745
  return data instanceof Buffer ? data : Buffer.from(data);
599
746
  }
600
- const willSendMessageAgain = (id, participant) => {
747
+ const willSendMessageAgain = async (id, participant) => {
601
748
  const key = `${id}:${participant}`;
602
- const retryCount = msgRetryCache.get(key) || 0;
749
+ const retryCount = (await msgRetryCache.get(key)) || 0;
603
750
  return retryCount < maxMsgRetryCount;
604
751
  };
605
- const updateSendMessageAgainCount = (id, participant) => {
752
+ const updateSendMessageAgainCount = async (id, participant) => {
606
753
  const key = `${id}:${participant}`;
607
- const newValue = (msgRetryCache.get(key) || 0) + 1;
608
- msgRetryCache.set(key, newValue);
754
+ const newValue = ((await msgRetryCache.get(key)) || 0) + 1;
755
+ await msgRetryCache.set(key, newValue);
609
756
  };
610
757
  const sendMessagesAgain = async (key, ids, retryNode) => {
611
- var _a;
612
- // todo: implement a cache to store the last 256 sent messages (copy whatsmeow)
613
- const msgs = await Promise.all(ids.map(id => getMessage({ ...key, id })));
614
758
  const remoteJid = key.remoteJid;
615
759
  const participant = key.participant || remoteJid;
760
+ const retryCount = +retryNode.attrs.count || 1;
761
+ // Try to get messages from cache first, then fallback to getMessage
762
+ const msgs = [];
763
+ for (const id of ids) {
764
+ let msg;
765
+ // Try to get from retry cache first if enabled
766
+ if (messageRetryManager) {
767
+ const cachedMsg = messageRetryManager.getRecentMessage(remoteJid, id);
768
+ if (cachedMsg) {
769
+ msg = cachedMsg.message;
770
+ logger.debug({ jid: remoteJid, id }, 'found message in retry cache');
771
+ // Mark retry as successful since we found the message
772
+ messageRetryManager.markRetrySuccess(id);
773
+ }
774
+ }
775
+ // Fallback to getMessage if not found in cache
776
+ if (!msg) {
777
+ msg = await getMessage({ ...key, id });
778
+ if (msg) {
779
+ logger.debug({ jid: remoteJid, id }, 'found message via getMessage');
780
+ // Also mark as successful if found via getMessage
781
+ if (messageRetryManager) {
782
+ messageRetryManager.markRetrySuccess(id);
783
+ }
784
+ }
785
+ }
786
+ msgs.push(msg);
787
+ }
616
788
  // if it's the primary jid sending the request
617
789
  // just re-send the message to everyone
618
790
  // prevents the first message decryption failure
619
- const sendToAll = !((_a = (0, WABinary_1.jidDecode)(participant)) === null || _a === void 0 ? void 0 : _a.device);
791
+ const sendToAll = !(0, index_js_5.jidDecode)(participant)?.device;
792
+ // Check if we should recreate session for this retry
793
+ let shouldRecreateSession = false;
794
+ let recreateReason = '';
795
+ if (enableAutoSessionRecreation && messageRetryManager && retryCount > 1) {
796
+ try {
797
+ const sessionId = signalRepository.jidToSignalProtocolAddress(participant);
798
+ const hasSession = await signalRepository.validateSession(participant);
799
+ const result = messageRetryManager.shouldRecreateSession(participant, hasSession.exists);
800
+ shouldRecreateSession = result.recreate;
801
+ recreateReason = result.reason;
802
+ if (shouldRecreateSession) {
803
+ logger.debug({ participant, retryCount, reason: recreateReason }, 'recreating session for outgoing retry');
804
+ await authState.keys.set({ session: { [sessionId]: null } });
805
+ }
806
+ }
807
+ catch (error) {
808
+ logger.warn({ error, participant }, 'failed to check session recreation for outgoing retry');
809
+ }
810
+ }
620
811
  await assertSessions([participant], true);
621
- if ((0, WABinary_1.isJidGroup)(remoteJid)) {
812
+ if ((0, index_js_5.isJidGroup)(remoteJid)) {
622
813
  await authState.keys.set({ 'sender-key-memory': { [remoteJid]: null } });
623
814
  }
624
- logger.debug({ participant, sendToAll }, 'forced new session for retry recp');
815
+ logger.debug({ participant, sendToAll, shouldRecreateSession, recreateReason }, 'forced new session for retry recp');
625
816
  for (const [i, msg] of msgs.entries()) {
626
- if (msg) {
627
- updateSendMessageAgainCount(ids[i], participant);
817
+ if (!ids[i])
818
+ continue;
819
+ if (msg && (await willSendMessageAgain(ids[i], participant))) {
820
+ await updateSendMessageAgainCount(ids[i], participant);
628
821
  const msgRelayOpts = { messageId: ids[i] };
629
822
  if (sendToAll) {
630
823
  msgRelayOpts.useUserDevicesCache = false;
@@ -643,11 +836,10 @@ const makeMessagesRecvSocket = (config) => {
643
836
  }
644
837
  };
645
838
  const handleReceipt = async (node) => {
646
- var _a, _b;
647
839
  const { attrs, content } = node;
648
840
  const isLid = attrs.from.includes('lid');
649
- const isNodeFromMe = (0, WABinary_1.areJidsSameUser)(attrs.participant || attrs.from, isLid ? (_a = authState.creds.me) === null || _a === void 0 ? void 0 : _a.lid : (_b = authState.creds.me) === null || _b === void 0 ? void 0 : _b.id);
650
- const remoteJid = !isNodeFromMe || (0, WABinary_1.isJidGroup)(attrs.from) ? attrs.from : attrs.recipient;
841
+ const isNodeFromMe = (0, index_js_5.areJidsSameUser)(attrs.participant || attrs.from, isLid ? authState.creds.me?.lid : authState.creds.me?.id);
842
+ const remoteJid = !isNodeFromMe || (0, index_js_5.isJidGroup)(attrs.from) ? attrs.from : attrs.recipient;
651
843
  const fromMe = !attrs.recipient || ((attrs.type === 'retry' || attrs.type === 'sender') && isNodeFromMe);
652
844
  const key = {
653
845
  remoteJid,
@@ -655,33 +847,31 @@ const makeMessagesRecvSocket = (config) => {
655
847
  fromMe,
656
848
  participant: attrs.participant
657
849
  };
658
- if (shouldIgnoreJid(remoteJid) && remoteJid !== '@s.whatsapp.net') {
850
+ if (shouldIgnoreJid(remoteJid) && remoteJid !== index_js_5.S_WHATSAPP_NET) {
659
851
  logger.debug({ remoteJid }, 'ignoring receipt from jid');
660
852
  await sendMessageAck(node);
661
853
  return;
662
854
  }
663
855
  const ids = [attrs.id];
664
856
  if (Array.isArray(content)) {
665
- const items = (0, WABinary_1.getBinaryNodeChildren)(content[0], 'item');
857
+ const items = (0, index_js_5.getBinaryNodeChildren)(content[0], 'item');
666
858
  ids.push(...items.map(i => i.attrs.id));
667
859
  }
668
860
  try {
669
861
  await Promise.all([
670
- processingMutex.mutex(async () => {
671
- const status = (0, Utils_1.getStatusFromReceiptType)(attrs.type);
862
+ receiptMutex.mutex(async () => {
863
+ const status = (0, index_js_4.getStatusFromReceiptType)(attrs.type);
672
864
  if (typeof status !== 'undefined' &&
673
- (
674
865
  // basically, we only want to know when a message from us has been delivered to/read by the other person
675
866
  // or another device of ours has read some messages
676
- status >= WAProto_1.proto.WebMessageInfo.Status.SERVER_ACK ||
677
- !isNodeFromMe)) {
678
- if ((0, WABinary_1.isJidGroup)(remoteJid) || (0, WABinary_1.isJidStatusBroadcast)(remoteJid)) {
867
+ (status >= index_js_1.proto.WebMessageInfo.Status.SERVER_ACK || !isNodeFromMe)) {
868
+ if ((0, index_js_5.isJidGroup)(remoteJid) || (0, index_js_5.isJidStatusBroadcast)(remoteJid)) {
679
869
  if (attrs.participant) {
680
- const updateKey = status === WAProto_1.proto.WebMessageInfo.Status.DELIVERY_ACK ? 'receiptTimestamp' : 'readTimestamp';
870
+ const updateKey = status === index_js_1.proto.WebMessageInfo.Status.DELIVERY_ACK ? 'receiptTimestamp' : 'readTimestamp';
681
871
  ev.emit('message-receipt.update', ids.map(id => ({
682
872
  key: { ...key, id },
683
873
  receipt: {
684
- userJid: (0, WABinary_1.jidNormalizedUser)(attrs.participant),
874
+ userJid: (0, index_js_5.jidNormalizedUser)(attrs.participant),
685
875
  [updateKey]: +attrs.t
686
876
  }
687
877
  })));
@@ -690,22 +880,23 @@ const makeMessagesRecvSocket = (config) => {
690
880
  else {
691
881
  ev.emit('messages.update', ids.map(id => ({
692
882
  key: { ...key, id },
693
- update: { status }
883
+ update: { status, messageTimestamp: (0, index_js_4.toNumber)(+(attrs.t ?? 0)) }
694
884
  })));
695
885
  }
696
886
  }
697
887
  if (attrs.type === 'retry') {
698
888
  // correctly set who is asking for the retry
699
889
  key.participant = key.participant || attrs.from;
700
- const retryNode = (0, WABinary_1.getBinaryNodeChild)(node, 'retry');
701
- if (willSendMessageAgain(ids[0], key.participant)) {
890
+ const retryNode = (0, index_js_5.getBinaryNodeChild)(node, 'retry');
891
+ if (ids[0] && key.participant && (await willSendMessageAgain(ids[0], key.participant))) {
702
892
  if (key.fromMe) {
703
893
  try {
894
+ await updateSendMessageAgainCount(ids[0], key.participant);
704
895
  logger.debug({ attrs, key }, 'recv retry request');
705
896
  await sendMessagesAgain(key, ids, retryNode);
706
897
  }
707
898
  catch (error) {
708
- logger.error({ key, ids, trace: error.stack }, 'error in sending message again');
899
+ logger.error({ key, ids, trace: error instanceof Error ? error.stack : 'Unknown error' }, 'error in sending message again');
709
900
  }
710
901
  }
711
902
  else {
@@ -725,28 +916,30 @@ const makeMessagesRecvSocket = (config) => {
725
916
  };
726
917
  const handleNotification = async (node) => {
727
918
  const remoteJid = node.attrs.from;
728
- if (shouldIgnoreJid(remoteJid) && remoteJid !== '@s.whatsapp.net') {
919
+ if (shouldIgnoreJid(remoteJid) && remoteJid !== index_js_5.S_WHATSAPP_NET) {
729
920
  logger.debug({ remoteJid, id: node.attrs.id }, 'ignored notification');
730
921
  await sendMessageAck(node);
731
922
  return;
732
923
  }
733
924
  try {
734
925
  await Promise.all([
735
- processingMutex.mutex(async () => {
736
- var _a;
926
+ notificationMutex.mutex(async () => {
737
927
  const msg = await processNotification(node);
738
928
  if (msg) {
739
- const fromMe = (0, WABinary_1.areJidsSameUser)(node.attrs.participant || remoteJid, authState.creds.me.id);
929
+ const fromMe = (0, index_js_5.areJidsSameUser)(node.attrs.participant || remoteJid, authState.creds.me.id);
930
+ const { senderAlt: participantAlt, addressingMode } = (0, index_js_4.extractAddressingContext)(node);
740
931
  msg.key = {
741
932
  remoteJid,
742
933
  fromMe,
743
934
  participant: node.attrs.participant,
935
+ participantAlt,
936
+ addressingMode,
744
937
  id: node.attrs.id,
745
938
  ...(msg.key || {})
746
939
  };
747
- (_a = msg.participant) !== null && _a !== void 0 ? _a : (msg.participant = node.attrs.participant);
940
+ msg.participant ?? (msg.participant = node.attrs.participant);
748
941
  msg.messageTimestamp = +node.attrs.t;
749
- const fullMsg = WAProto_1.proto.WebMessageInfo.fromObject(msg);
942
+ const fullMsg = index_js_1.proto.WebMessageInfo.fromObject(msg);
750
943
  await upsertMessage(fullMsg, 'append');
751
944
  }
752
945
  })
@@ -756,96 +949,420 @@ const makeMessagesRecvSocket = (config) => {
756
949
  await sendMessageAck(node);
757
950
  }
758
951
  };
952
+ const resolveMentionedLIDs = async (msg, lidMapping) => {
953
+ if (msg.key?.participant?.endsWith('@lid')) {
954
+ try {
955
+ const pn = await lidMapping.getPNForLID(msg.key.participant);
956
+ if (pn) {
957
+ logger.debug({ lid: msg.key.participant, pn }, 'resolved key.participant LID → PN');
958
+ msg.key.participant = pn;
959
+ }
960
+ }
961
+ catch { }
962
+ }
963
+ if (msg.key?.remoteJid?.endsWith('@lid')) {
964
+ try {
965
+ const pn = await lidMapping.getPNForLID(msg.key.remoteJid);
966
+ if (pn) {
967
+ logger.debug({ lid: msg.key.remoteJid, pn }, 'resolved key.remoteJid LID → PN');
968
+ msg.key.remoteJid = pn;
969
+ }
970
+ }
971
+ catch { }
972
+ }
973
+ const msgContent = msg.message;
974
+ if (!msgContent)
975
+ return;
976
+ const getContextInfo = (content) => {
977
+ if (!content || typeof content !== 'object')
978
+ return null;
979
+ if (content.contextInfo)
980
+ return content.contextInfo;
981
+ for (const val of Object.values(content)) {
982
+ const found = getContextInfo(val);
983
+ if (found)
984
+ return found;
985
+ }
986
+ return null;
987
+ };
988
+ const getTextField = (content) => {
989
+ if (!content || typeof content !== 'object')
990
+ return null;
991
+ for (const key of ['text', 'caption', 'conversation']) {
992
+ if (typeof content[key] === 'string')
993
+ return { obj: content, key };
994
+ }
995
+ for (const val of Object.values(content)) {
996
+ const found = getTextField(val);
997
+ if (found)
998
+ return found;
999
+ }
1000
+ return null;
1001
+ };
1002
+ // Resolve semua contextInfo termasuk yang ada di dalam quotedMessage
1003
+ const getAllContextInfos = (content, results = []) => {
1004
+ if (!content || typeof content !== 'object')
1005
+ return results;
1006
+ if (content.contextInfo) {
1007
+ results.push(content.contextInfo);
1008
+ // Juga cari di dalam quotedMessage secara rekursif
1009
+ if (content.contextInfo.quotedMessage) {
1010
+ getAllContextInfos(content.contextInfo.quotedMessage, results);
1011
+ }
1012
+ }
1013
+ for (const val of Object.values(content)) {
1014
+ if (val && typeof val === 'object' && !results.includes(val)) {
1015
+ getAllContextInfos(val, results);
1016
+ }
1017
+ }
1018
+ return results;
1019
+ };
1020
+ const contextInfo = getContextInfo(msgContent);
1021
+ // Resolve participant LID di semua contextInfo (termasuk quotedMessage)
1022
+ const allContextInfos = getAllContextInfos(msgContent);
1023
+ for (const ctx of allContextInfos) {
1024
+ if (ctx?.participant?.endsWith('@lid')) {
1025
+ try {
1026
+ const pn = await lidMapping.getPNForLID(ctx.participant);
1027
+ if (pn) {
1028
+ logger.debug({ lid: ctx.participant, pn }, 'resolved nested contextInfo.participant LID → PN');
1029
+ ctx.participant = pn;
1030
+ }
1031
+ }
1032
+ catch { }
1033
+ }
1034
+ // Resolve mentionedJid di quotedMessage contextInfo juga
1035
+ if (ctx !== contextInfo && ctx?.mentionedJid?.length) {
1036
+ const lids = ctx.mentionedJid.filter(j => j?.endsWith('@lid'));
1037
+ for (const lid of lids) {
1038
+ try {
1039
+ const pn = await lidMapping.getPNForLID(lid);
1040
+ if (pn)
1041
+ ctx.mentionedJid = ctx.mentionedJid.map(j => j === lid ? pn : j);
1042
+ }
1043
+ catch { }
1044
+ }
1045
+ }
1046
+ }
1047
+ // resolve contextInfo.participant (sender of quoted message) jika masih LID
1048
+ if (contextInfo?.participant?.endsWith('@lid')) {
1049
+ try {
1050
+ const pn = await lidMapping.getPNForLID(contextInfo.participant);
1051
+ if (pn) {
1052
+ logger.debug({ lid: contextInfo.participant, pn }, 'resolved contextInfo.participant LID → PN');
1053
+ contextInfo.participant = pn;
1054
+ }
1055
+ }
1056
+ catch { }
1057
+ }
1058
+ if (!contextInfo?.mentionedJid?.length)
1059
+ return;
1060
+ // Fix text yang masih mengandung LID number meskipun mentionedJid sudah resolved ke PN
1061
+ // Kasus: mentionedJid sudah jadi @s.whatsapp.net tapi text masih "@165159209271535" (LID num)
1062
+ const textFieldEarly = getTextField(msgContent);
1063
+ if (textFieldEarly) {
1064
+ let earlyText = textFieldEarly.obj[textFieldEarly.key] || '';
1065
+ // Cek apakah text mengandung @angka panjang (>12 digit = kemungkinan LID number bukan nomor HP)
1066
+ const lidNumPattern = /@(\d{13,20})/g;
1067
+ const lidNumMatches = [...earlyText.matchAll(lidNumPattern)];
1068
+ if (lidNumMatches.length > 0) {
1069
+ // Untuk setiap mentionedJid yang sudah resolved, cek apakah ada LID number di text
1070
+ for (const resolvedJid of contextInfo.mentionedJid) {
1071
+ if (resolvedJid?.endsWith('@lid'))
1072
+ continue; // belum resolved, skip dulu
1073
+ const pnNum = resolvedJid.split('@')[0].split(':')[0];
1074
+ if (!pnNum)
1075
+ continue;
1076
+ // Cari LID number di text yang paling mungkin match (berdasarkan urutan)
1077
+ for (const match of lidNumMatches) {
1078
+ const lidNum = match[1];
1079
+ if (earlyText.includes(`@${lidNum}`)) {
1080
+ earlyText = earlyText.split(`@${lidNum}`).join(`@${pnNum}`);
1081
+ logger.debug({ lidNum, pnNum }, 'replaced LID number in text with PN number');
1082
+ break;
1083
+ }
1084
+ }
1085
+ }
1086
+ textFieldEarly.obj[textFieldEarly.key] = earlyText;
1087
+ }
1088
+ }
1089
+ const hasLid = contextInfo.mentionedJid.some((j) => j?.endsWith('@lid'));
1090
+ if (!hasLid)
1091
+ return;
1092
+ const lidJids = contextInfo.mentionedJid.filter((j) => j?.endsWith('@lid'));
1093
+ const resolveMap = new Map();
1094
+ const stillUnresolved = [];
1095
+ for (const lidJid of lidJids) {
1096
+ try {
1097
+ const pn = await lidMapping.getPNForLID(lidJid);
1098
+ if (pn) {
1099
+ resolveMap.set(lidJid, pn);
1100
+ }
1101
+ else {
1102
+ stillUnresolved.push(lidJid);
1103
+ }
1104
+ }
1105
+ catch {
1106
+ stillUnresolved.push(lidJid);
1107
+ }
1108
+ }
1109
+ if (stillUnresolved.length > 0) {
1110
+ try {
1111
+ const usyncQ = new index_js_6.USyncQuery()
1112
+ .withContactProtocol()
1113
+ .withContext('background');
1114
+ for (const lidJid of stillUnresolved) {
1115
+ usyncQ.withUser(new index_js_6.USyncUser().withId(lidJid));
1116
+ }
1117
+ const result = await sock.executeUSyncQuery(usyncQ);
1118
+ if (result?.list) {
1119
+ const mappings = [];
1120
+ for (const item of result.list) {
1121
+ // item.id bisa berupa PN (@s.whatsapp.net) atau LID (@lid)
1122
+ // stillUnresolved berisi LID. Match berdasarkan numeric prefix
1123
+ const itemNum = (item.id ?? '').split('@')[0].split(':')[0];
1124
+ const lidJid = stillUnresolved.find(l => {
1125
+ if (l === item.id)
1126
+ return true;
1127
+ const lNum = l.split('@')[0].split(':')[0];
1128
+ return itemNum && lNum && itemNum === lNum;
1129
+ });
1130
+ if (lidJid && item.id && !item.id.endsWith('@lid')) {
1131
+ resolveMap.set(lidJid, item.id);
1132
+ mappings.push({ lid: lidJid, pn: item.id });
1133
+ logger.debug({ lid: lidJid, pn: item.id }, 'USync resolved LID → PN');
1134
+ }
1135
+ }
1136
+ if (mappings.length > 0) {
1137
+ lidMapping.storeLIDPNMappings(mappings).catch(() => { });
1138
+ }
1139
+ }
1140
+ }
1141
+ catch (e) {
1142
+ logger.debug({ err: e }, 'USync LID resolve failed, using cache only');
1143
+ }
1144
+ }
1145
+ // ── Text-based PN extraction ─────────────────────────────────────────────
1146
+ // WA kadang sudah resolve nomor HP di text (@6285133801810) tapi mentionedJid
1147
+ // masih berisi LID. Kita ekstrak semua @nomor dari text lalu matching ke LID
1148
+ // yang masih unresolved berdasarkan urutan kemunculan di mentionedJid.
1149
+ const textField = getTextField(msgContent);
1150
+ const stillUnresolvedAfterUSync = lidJids.filter(l => !resolveMap.has(l));
1151
+ if (stillUnresolvedAfterUSync.length > 0 && textField) {
1152
+ const rawText = textField.obj[textField.key] || '';
1153
+ // Ekstrak semua mention @nomor dari text (hanya angka, min 7 digit)
1154
+ const mentionMatches = [...rawText.matchAll(/@(\d{7,15})/g)].map(m => m[1]);
1155
+ if (mentionMatches.length > 0) {
1156
+ // Match LID ke nomor berdasarkan urutan index di mentionedJid
1157
+ const lidOrder = contextInfo.mentionedJid
1158
+ .map((jid, idx) => ({ jid, idx }))
1159
+ .filter(({ jid }) => stillUnresolvedAfterUSync.includes(jid));
1160
+ for (let i = 0; i < lidOrder.length && i < mentionMatches.length; i++) {
1161
+ const lidJid = lidOrder[i].jid;
1162
+ const phoneNum = mentionMatches[i];
1163
+ const pnJid = `${phoneNum}@s.whatsapp.net`;
1164
+ resolveMap.set(lidJid, pnJid);
1165
+ // Simpan mapping baru ini ke store untuk request berikutnya
1166
+ lidMapping.storeLIDPNMappings([{ lid: lidJid, pn: pnJid }]).catch(() => { });
1167
+ logger.debug({ lid: lidJid, pn: pnJid }, 'text-extracted PN for LID → PN');
1168
+ }
1169
+ }
1170
+ }
1171
+ // ── End text-based PN extraction ─────────────────────────────────────────
1172
+ contextInfo.mentionedJid = contextInfo.mentionedJid.map((jid) => {
1173
+ if (!jid?.endsWith('@lid'))
1174
+ return jid;
1175
+ const resolved = resolveMap.get(jid);
1176
+ if (resolved) {
1177
+ logger.debug({ lid: jid, pn: resolved }, 'resolved mentionedJid LID → PN');
1178
+ return resolved;
1179
+ }
1180
+ // Tetap kembalikan LID jika benar-benar tidak bisa di-resolve
1181
+ return jid;
1182
+ });
1183
+ if (textField) {
1184
+ let text = textField.obj[textField.key];
1185
+ // Replace LID number di text dengan PN number yang sudah di-resolve
1186
+ for (const [lidJid, pnJid] of resolveMap) {
1187
+ const lidNum = lidJid.split('@')[0].split(':')[0] ?? '';
1188
+ const pnNum = pnJid.replace('@s.whatsapp.net', '').split(':')[0] ?? '';
1189
+ if (lidNum && pnNum && text.includes(lidNum)) {
1190
+ text = text.split(lidNum).join(pnNum);
1191
+ }
1192
+ }
1193
+ textField.obj[textField.key] = text;
1194
+ }
1195
+ };
759
1196
  const handleMessage = async (node) => {
760
- var _a, _b, _c;
761
- if (shouldIgnoreJid(node.attrs.from) && node.attrs.from !== '@s.whatsapp.net') {
1197
+ if (shouldIgnoreJid(node.attrs.from) && node.attrs.from !== index_js_5.S_WHATSAPP_NET) {
762
1198
  logger.debug({ key: node.attrs.key }, 'ignored message');
763
- await sendMessageAck(node);
1199
+ await sendMessageAck(node, index_js_4.NACK_REASONS.UnhandledError);
764
1200
  return;
765
1201
  }
766
- const encNode = (0, WABinary_1.getBinaryNodeChild)(node, 'enc');
1202
+ const encNode = (0, index_js_5.getBinaryNodeChild)(node, 'enc');
767
1203
  // TODO: temporary fix for crashes and issues resulting of failed msmsg decryption
768
- if (encNode && encNode.attrs.type === 'msmsg') {
1204
+ if (encNode?.attrs.type === 'msmsg') {
769
1205
  logger.debug({ key: node.attrs.key }, 'ignored msmsg');
770
- await sendMessageAck(node);
1206
+ await sendMessageAck(node, index_js_4.NACK_REASONS.MissingMessageSecret);
771
1207
  return;
772
1208
  }
773
- let response;
774
- if ((0, WABinary_1.getBinaryNodeChild)(node, 'unavailable') && !encNode) {
775
- await sendMessageAck(node);
776
- const { key } = (0, Utils_1.decodeMessageNode)(node, authState.creds.me.id, authState.creds.me.lid || '').fullMessage;
777
- response = await requestPlaceholderResend(key);
778
- if (response === 'RESOLVED') {
779
- return;
1209
+ const { fullMessage: msg, category, author, decrypt } = (0, index_js_4.decryptMessageNode)(node, authState.creds.me.id, authState.creds.me.lid || '', signalRepository, logger);
1210
+ const alt = msg.key.participantAlt || msg.key.remoteJidAlt;
1211
+ // store new mappings we didn't have before
1212
+ if (!!alt) {
1213
+ const altServer = (0, index_js_5.jidDecode)(alt)?.server;
1214
+ const primaryJid = msg.key.participant || msg.key.remoteJid;
1215
+ if (altServer === 'lid') {
1216
+ if (!(await signalRepository.lidMapping.getPNForLID(alt))) {
1217
+ await signalRepository.lidMapping.storeLIDPNMappings([{ lid: alt, pn: primaryJid }]);
1218
+ await signalRepository.migrateSession(primaryJid, alt);
1219
+ }
780
1220
  }
781
- logger.debug('received unavailable message, acked and requested resend from phone');
782
- }
783
- else {
784
- if (placeholderResendCache.get(node.attrs.id)) {
785
- placeholderResendCache.del(node.attrs.id);
1221
+ else {
1222
+ await signalRepository.lidMapping.storeLIDPNMappings([{ lid: primaryJid, pn: alt }]);
1223
+ await signalRepository.migrateSession(alt, primaryJid);
786
1224
  }
787
1225
  }
788
- const { fullMessage: msg, category, author, decrypt } = (0, Utils_1.decryptMessageNode)(node, authState.creds.me.id, authState.creds.me.lid || '', signalRepository, logger);
789
- 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) {
790
- msg.messageStubParameters = [Utils_1.NO_MESSAGE_FOUND_ERROR_TEXT, response];
791
- }
792
- 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) {
793
- ev.emit('chats.phoneNumberShare', { lid: node.attrs.from, jid: node.attrs.sender_pn });
1226
+ if (msg.key?.remoteJid && msg.key?.id && messageRetryManager) {
1227
+ messageRetryManager.addRecentMessage(msg.key.remoteJid, msg.key.id, msg.message);
1228
+ logger.debug({
1229
+ jid: msg.key.remoteJid,
1230
+ id: msg.key.id
1231
+ }, 'Added message to recent cache for retry receipts');
794
1232
  }
795
1233
  try {
796
- await Promise.all([
797
- processingMutex.mutex(async () => {
798
- var _a, _b, _c, _d, _e, _f;
799
- await decrypt();
800
- // message failed to decrypt
801
- if (msg.messageStubType === WAProto_1.proto.WebMessageInfo.StubType.CIPHERTEXT) {
802
- 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) {
803
- return sendMessageAck(node, Utils_1.NACK_REASONS.ParsingError);
1234
+ await messageMutex.mutex(async () => {
1235
+ await decrypt();
1236
+ // message failed to decrypt
1237
+ if (msg.messageStubType === index_js_1.proto.WebMessageInfo.StubType.CIPHERTEXT && msg.category !== 'peer') {
1238
+ if (msg?.messageStubParameters?.[0] === index_js_4.MISSING_KEYS_ERROR_TEXT) {
1239
+ return sendMessageAck(node, index_js_4.NACK_REASONS.ParsingError);
1240
+ }
1241
+ if (msg.messageStubParameters?.[0] === index_js_4.NO_MESSAGE_FOUND_ERROR_TEXT) {
1242
+ // Message arrived without encryption (e.g. CTWA ads messages).
1243
+ // Check if this is eligible for placeholder resend (matching WA Web filters).
1244
+ const unavailableNode = (0, index_js_5.getBinaryNodeChild)(node, 'unavailable');
1245
+ const unavailableType = unavailableNode?.attrs?.type;
1246
+ if (unavailableType === 'bot_unavailable_fanout' ||
1247
+ unavailableType === 'hosted_unavailable_fanout' ||
1248
+ unavailableType === 'view_once_unavailable_fanout') {
1249
+ logger.debug({ msgId: msg.key.id, unavailableType }, 'skipping placeholder resend for excluded unavailable type');
1250
+ return sendMessageAck(node);
1251
+ }
1252
+ const messageAge = (0, index_js_4.unixTimestampSeconds)() - (0, index_js_4.toNumber)(msg.messageTimestamp);
1253
+ if (messageAge > index_js_2.PLACEHOLDER_MAX_AGE_SECONDS) {
1254
+ logger.debug({ msgId: msg.key.id, messageAge }, 'skipping placeholder resend for old message');
1255
+ return sendMessageAck(node);
1256
+ }
1257
+ // Request the real content from the phone via placeholder resend PDO.
1258
+ // Upsert the CIPHERTEXT stub as a placeholder (like WA Web's processPlaceholderMsg),
1259
+ // and store the requestId in stubParameters[1] so users can correlate
1260
+ // with the incoming PDO response event.
1261
+ const cleanKey = {
1262
+ remoteJid: msg.key.remoteJid,
1263
+ fromMe: msg.key.fromMe,
1264
+ id: msg.key.id,
1265
+ participant: msg.key.participant
1266
+ };
1267
+ // Cache the original message metadata so the PDO response handler
1268
+ // can preserve key fields (LID details etc.) that the phone may omit
1269
+ const msgData = {
1270
+ key: msg.key,
1271
+ messageTimestamp: msg.messageTimestamp,
1272
+ pushName: msg.pushName,
1273
+ participant: msg.participant,
1274
+ verifiedBizName: msg.verifiedBizName
1275
+ };
1276
+ requestPlaceholderResend(cleanKey, msgData)
1277
+ .then(requestId => {
1278
+ if (requestId && requestId !== 'RESOLVED') {
1279
+ logger.debug({ msgId: msg.key.id, requestId }, 'requested placeholder resend for unavailable message');
1280
+ ev.emit('messages.update', [
1281
+ {
1282
+ key: msg.key,
1283
+ update: { messageStubParameters: [index_js_4.NO_MESSAGE_FOUND_ERROR_TEXT, requestId] }
1284
+ }
1285
+ ]);
1286
+ }
1287
+ })
1288
+ .catch(err => {
1289
+ logger.warn({ err, msgId: msg.key.id }, 'failed to request placeholder resend for unavailable message');
1290
+ });
1291
+ await sendMessageAck(node);
1292
+ // Don't return — fall through to upsertMessage so the stub is emitted
1293
+ }
1294
+ else {
1295
+ // Skip retry for expired status messages (>24h old)
1296
+ if ((0, index_js_5.isJidStatusBroadcast)(msg.key.remoteJid)) {
1297
+ const messageAge = (0, index_js_4.unixTimestampSeconds)() - (0, index_js_4.toNumber)(msg.messageTimestamp);
1298
+ if (messageAge > index_js_2.STATUS_EXPIRY_SECONDS) {
1299
+ logger.debug({ msgId: msg.key.id, messageAge, remoteJid: msg.key.remoteJid }, 'skipping retry for expired status message');
1300
+ return sendMessageAck(node);
1301
+ }
804
1302
  }
805
- retryMutex.mutex(async () => {
806
- if (ws.isOpen) {
807
- if ((0, WABinary_1.getBinaryNodeChild)(node, 'unavailable')) {
1303
+ const errorMessage = msg?.messageStubParameters?.[0] || '';
1304
+ const isPreKeyError = errorMessage.includes('PreKey');
1305
+ logger.debug(`[handleMessage] Attempting retry request for failed decryption`);
1306
+ // Handle both pre-key and normal retries in single mutex
1307
+ await retryMutex.mutex(async () => {
1308
+ try {
1309
+ if (!ws.isOpen) {
1310
+ logger.debug({ node }, 'Connection closed, skipping retry');
808
1311
  return;
809
1312
  }
810
- const encNode = (0, WABinary_1.getBinaryNodeChild)(node, 'enc');
1313
+ // Handle pre-key errors with upload and delay
1314
+ if (isPreKeyError) {
1315
+ logger.info({ error: errorMessage }, 'PreKey error detected, uploading and retrying');
1316
+ try {
1317
+ logger.debug('Uploading pre-keys for error recovery');
1318
+ await uploadPreKeys(5);
1319
+ logger.debug('Waiting for server to process new pre-keys');
1320
+ await (0, index_js_4.delay)(1000);
1321
+ }
1322
+ catch (uploadErr) {
1323
+ logger.error({ uploadErr }, 'Pre-key upload failed, proceeding with retry anyway');
1324
+ }
1325
+ }
1326
+ const encNode = (0, index_js_5.getBinaryNodeChild)(node, 'enc');
811
1327
  await sendRetryRequest(node, !encNode);
812
1328
  if (retryRequestDelayMs) {
813
- await (0, Utils_1.delay)(retryRequestDelayMs);
1329
+ await (0, index_js_4.delay)(retryRequestDelayMs);
814
1330
  }
815
1331
  }
816
- else {
817
- logger.debug({ node }, 'connection closed, ignoring retry req');
1332
+ catch (err) {
1333
+ logger.error({ err, isPreKeyError }, 'Failed to handle retry, attempting basic retry');
1334
+ // Still attempt retry even if pre-key upload failed
1335
+ try {
1336
+ const encNode = (0, index_js_5.getBinaryNodeChild)(node, 'enc');
1337
+ await sendRetryRequest(node, !encNode);
1338
+ }
1339
+ catch (retryErr) {
1340
+ logger.error({ retryErr }, 'Failed to send retry after error handling');
1341
+ }
818
1342
  }
1343
+ await sendMessageAck(node, index_js_4.NACK_REASONS.UnhandledError);
819
1344
  });
820
1345
  }
821
- else {
1346
+ }
1347
+ else {
1348
+ if (messageRetryManager && msg.key.id) {
1349
+ messageRetryManager.cancelPendingPhoneRequest(msg.key.id);
1350
+ }
1351
+ const isNewsletter = (0, index_js_5.isJidNewsletter)(msg.key.remoteJid);
1352
+ if (!isNewsletter) {
822
1353
  // no type in the receipt => message delivered
823
1354
  let type = undefined;
824
- if ((_b = msg.key.participant) === null || _b === void 0 ? void 0 : _b.endsWith('@lid')) {
825
- msg.key.participant = node.attrs.participant_pn || authState.creds.me.id;
826
- }
827
- if ((0, WABinary_1.isJidGroup)(msg.key.remoteJid) && ((_f = (_e = (_d = (_c = msg.message) === null || _c === void 0 ? void 0 : _c.extendedTextMessage) === null || _d === void 0 ? void 0 : _d.contextInfo) === null || _e === void 0 ? void 0 : _e.participant) === null || _f === void 0 ? void 0 : _f.endsWith('@lid'))) {
828
- if (msg.message.extendedTextMessage.contextInfo) {
829
- const sender = msg.message.extendedTextMessage.contextInfo.participant;
830
- const resolvedSender = await resolveGroupParticipantJid(msg.key.remoteJid, sender);
831
- msg.message.extendedTextMessage.contextInfo.participant = resolvedSender || sender;
832
- }
833
- }
834
- else if ((0, WABinary_1.isJidGroup)(msg.key.remoteJid)) {
835
- void warmupGroupParticipants(msg.key.remoteJid);
836
- }
837
- if (!(0, WABinary_1.isJidGroup)(msg.key.remoteJid) && (0, WABinary_1.isLidUser)(msg.key.remoteJid)) {
838
- msg.key.remoteJid = node.attrs.sender_pn || node.attrs.peer_recipient_pn;
839
- }
840
1355
  let participant = msg.key.participant;
841
- if (category === 'peer') { // special peer message
1356
+ if (category === 'peer') {
1357
+ // special peer message
842
1358
  type = 'peer_msg';
843
1359
  }
844
- else if (msg.key.fromMe) { // message was sent by us from a different device
1360
+ else if (msg.key.fromMe) {
1361
+ // message was sent by us from a different device
845
1362
  type = 'sender';
846
1363
  // need to specially handle this case
847
- if ((0, WABinary_1.isJidUser)(msg.key.remoteJid)) {
848
- participant = author;
1364
+ if ((0, index_js_5.isLidUser)(msg.key.remoteJid) || (0, index_js_5.isLidUser)(msg.key.remoteJidAlt)) {
1365
+ participant = author; // TODO: investigate sending receipts to LIDs and not PNs
849
1366
  }
850
1367
  }
851
1368
  else if (!sendActiveReceipts) {
@@ -853,126 +1370,185 @@ const makeMessagesRecvSocket = (config) => {
853
1370
  }
854
1371
  await sendReceipt(msg.key.remoteJid, participant, [msg.key.id], type);
855
1372
  // send ack for history message
856
- const isAnyHistoryMsg = (0, Utils_1.getHistoryMsg)(msg.message);
1373
+ const isAnyHistoryMsg = (0, index_js_4.getHistoryMsg)(msg.message);
857
1374
  if (isAnyHistoryMsg) {
858
- const jid = (0, WABinary_1.jidNormalizedUser)(msg.key.remoteJid);
859
- await sendReceipt(jid, undefined, [msg.key.id], 'hist_sync');
1375
+ const jid = (0, index_js_5.jidNormalizedUser)(msg.key.remoteJid);
1376
+ await sendReceipt(jid, undefined, [msg.key.id], 'hist_sync'); // TODO: investigate
860
1377
  }
861
1378
  }
862
- (0, Utils_1.cleanMessage)(msg, authState.creds.me.id);
863
- await sendMessageAck(node);
864
- await upsertMessage(msg, node.attrs.offline ? 'append' : 'notify');
865
- })
866
- ]);
1379
+ else {
1380
+ await sendMessageAck(node);
1381
+ logger.debug({ key: msg.key }, 'processed newsletter message without receipts');
1382
+ }
1383
+ }
1384
+ (0, index_js_4.cleanMessage)(msg, authState.creds.me.id, authState.creds.me.lid);
1385
+ await resolveMentionedLIDs(msg, signalRepository.lidMapping);
1386
+ // ── Post-resolve: fix semua LID yang tersisa di message object ────────
1387
+ // Setelah resolveMentionedLIDs:
1388
+ // 1. Fix text yang masih "@LIDnum" → "@PNnum"
1389
+ // 2. Fix contextInfo.participant yang masih @lid (sender quoted)
1390
+ // 3. Fix mentionedJid & text di dalam quotedMessage
1391
+ try {
1392
+ const _safeSet = (obj, key, val) => {
1393
+ try {
1394
+ obj[key] = val;
1395
+ }
1396
+ catch (_) {
1397
+ // proto readonly fallback
1398
+ const proto = Object.getPrototypeOf(obj);
1399
+ const fresh = Object.assign(Object.create(proto), obj, { [key]: val });
1400
+ // replace reference di parent jika bisa — caller handles
1401
+ return fresh;
1402
+ }
1403
+ return obj;
1404
+ };
1405
+ const _fixTextLid = (innerMsg, mentionedJids, msgTypeLabel) => {
1406
+ const pnNumbers = (mentionedJids || [])
1407
+ .filter(j => j && !j.endsWith('@lid'))
1408
+ .map(j => j.split('@')[0].split(':')[0])
1409
+ .filter(Boolean);
1410
+ if (!pnNumbers.length)
1411
+ return;
1412
+ for (const textKey of ['text', 'caption', 'conversation']) {
1413
+ const originalText = innerMsg[textKey];
1414
+ if (typeof originalText !== 'string')
1415
+ continue;
1416
+ const lidPattern = /@(\d{13,20})/g;
1417
+ let newText = originalText;
1418
+ let match;
1419
+ let pnIdx = 0;
1420
+ while ((match = lidPattern.exec(originalText)) !== null) {
1421
+ if (pnIdx >= pnNumbers.length)
1422
+ break;
1423
+ const lidNum = match[1];
1424
+ const pnNum = pnNumbers[pnIdx++];
1425
+ newText = newText.split(`@${lidNum}`).join(`@${pnNum}`);
1426
+ logger.debug({ lidNum, pnNum, type: msgTypeLabel, textKey }, 'post-resolve: replaced LID num in text');
1427
+ }
1428
+ if (newText !== originalText)
1429
+ _safeSet(innerMsg, textKey, newText);
1430
+ }
1431
+ };
1432
+ const msgObj = msg.message;
1433
+ if (msgObj) {
1434
+ for (const msgType of Object.keys(msgObj)) {
1435
+ const innerMsg = msgObj[msgType];
1436
+ if (!innerMsg || typeof innerMsg !== 'object')
1437
+ continue;
1438
+ const ctxInfo = innerMsg.contextInfo;
1439
+ if (!ctxInfo)
1440
+ continue;
1441
+ // 1. Fix text LID → PN (pesan utama)
1442
+ if (ctxInfo.mentionedJid?.length) {
1443
+ _fixTextLid(innerMsg, ctxInfo.mentionedJid, msgType);
1444
+ }
1445
+ // 2. Fix contextInfo.participant (sender quoted) jika masih LID
1446
+ if (ctxInfo.participant?.endsWith('@lid')) {
1447
+ try {
1448
+ const pn = await signalRepository.lidMapping.getPNForLID(ctxInfo.participant);
1449
+ if (pn) {
1450
+ _safeSet(ctxInfo, 'participant', pn);
1451
+ logger.debug({ lid: ctxInfo.participant, pn }, 'post-resolve: fixed contextInfo.participant LID');
1452
+ }
1453
+ }
1454
+ catch (_) { }
1455
+ }
1456
+ // 3. Fix mentionedJid & text di dalam quotedMessage
1457
+ if (ctxInfo.quotedMessage) {
1458
+ for (const qType of Object.keys(ctxInfo.quotedMessage)) {
1459
+ const qInner = ctxInfo.quotedMessage[qType];
1460
+ if (!qInner || typeof qInner !== 'object')
1461
+ continue;
1462
+ const qCtx = qInner.contextInfo;
1463
+ if (!qCtx?.mentionedJid?.length)
1464
+ continue;
1465
+ // Resolve LID di mentionedJid quoted
1466
+ const resolvedQ = await Promise.all(qCtx.mentionedJid.map(async (jid) => {
1467
+ if (!jid?.endsWith('@lid'))
1468
+ return jid;
1469
+ try {
1470
+ const pn = await signalRepository.lidMapping.getPNForLID(jid);
1471
+ return pn || jid;
1472
+ }
1473
+ catch (_) {
1474
+ return jid;
1475
+ }
1476
+ }));
1477
+ if (resolvedQ.some((j, i) => j !== qCtx.mentionedJid[i])) {
1478
+ _safeSet(qCtx, 'mentionedJid', resolvedQ);
1479
+ logger.debug({ resolvedQ }, 'post-resolve: fixed quotedMessage mentionedJid');
1480
+ }
1481
+ // Fix text LID → PN di quoted
1482
+ _fixTextLid(qInner, resolvedQ, `quoted.${qType}`);
1483
+ }
1484
+ }
1485
+ }
1486
+ }
1487
+ }
1488
+ catch (lidFixErr) {
1489
+ logger.debug({ err: lidFixErr }, 'post-resolve LID fix failed (non-critical)');
1490
+ }
1491
+ // ── End post-resolve fix ──────────────────────────────────────────────
1492
+ await upsertMessage(msg, node.attrs.offline ? 'append' : 'notify');
1493
+ });
867
1494
  }
868
1495
  catch (error) {
869
- logger.error({ error, node }, 'error in handling message');
1496
+ logger.error({ error, node: (0, index_js_5.binaryNodeToString)(node) }, 'error in handling message');
870
1497
  }
871
1498
  };
872
- const fetchMessageHistory = async (count, oldestMsgKey, oldestMsgTimestamp) => {
873
- var _a;
874
- if (!((_a = authState.creds.me) === null || _a === void 0 ? void 0 : _a.id)) {
875
- throw new boom_1.Boom('Not authenticated');
876
- }
877
- const pdoMessage = {
878
- historySyncOnDemandRequest: {
879
- chatJid: oldestMsgKey.remoteJid,
880
- oldestMsgFromMe: oldestMsgKey.fromMe,
881
- oldestMsgId: oldestMsgKey.id,
882
- oldestMsgTimestampMs: oldestMsgTimestamp,
883
- onDemandMsgCount: count
884
- },
885
- peerDataOperationRequestType: WAProto_1.proto.Message.PeerDataOperationRequestType.HISTORY_SYNC_ON_DEMAND
886
- };
887
- return sendPeerDataOperationMessage(pdoMessage);
888
- };
889
- const requestPlaceholderResend = async (messageKey) => {
890
- var _a;
891
- if (!((_a = authState.creds.me) === null || _a === void 0 ? void 0 : _a.id)) {
892
- throw new boom_1.Boom('Not authenticated');
893
- }
894
- if (placeholderResendCache.get(messageKey === null || messageKey === void 0 ? void 0 : messageKey.id)) {
895
- logger.debug({ messageKey }, 'already requested resend');
896
- return;
897
- }
898
- else {
899
- placeholderResendCache.set(messageKey === null || messageKey === void 0 ? void 0 : messageKey.id, true);
900
- }
901
- await (0, Utils_1.delay)(5000);
902
- if (!placeholderResendCache.get(messageKey === null || messageKey === void 0 ? void 0 : messageKey.id)) {
903
- logger.debug({ messageKey }, 'message received while resend requested');
904
- return 'RESOLVED';
905
- }
906
- const pdoMessage = {
907
- placeholderMessageResendRequest: [{
908
- messageKey
909
- }],
910
- peerDataOperationRequestType: WAProto_1.proto.Message.PeerDataOperationRequestType.PLACEHOLDER_MESSAGE_RESEND
911
- };
912
- setTimeout(() => {
913
- if (placeholderResendCache.get(messageKey === null || messageKey === void 0 ? void 0 : messageKey.id)) {
914
- logger.debug({ messageKey }, 'PDO message without response after 15 seconds. Phone possibly offline');
915
- placeholderResendCache.del(messageKey === null || messageKey === void 0 ? void 0 : messageKey.id);
916
- }
917
- }, 15000);
918
- return sendPeerDataOperationMessage(pdoMessage);
919
- };
920
1499
  const handleCall = async (node) => {
921
1500
  const { attrs } = node;
922
- const [infoChild] = (0, WABinary_1.getAllBinaryNodeChildren)(node);
1501
+ const [infoChild] = (0, index_js_5.getAllBinaryNodeChildren)(node);
1502
+ const status = (0, index_js_4.getCallStatusFromNode)(infoChild);
1503
+ if (!infoChild) {
1504
+ throw new boom_1.Boom('Missing call info in call node');
1505
+ }
923
1506
  const callId = infoChild.attrs['call-id'];
924
1507
  const from = infoChild.attrs.from || infoChild.attrs['call-creator'];
925
- const status = (0, Utils_1.getCallStatusFromNode)(infoChild);
926
1508
  const call = {
927
1509
  chatId: attrs.from,
928
1510
  from,
1511
+ callerPn: infoChild.attrs['caller_pn'],
929
1512
  id: callId,
930
1513
  date: new Date(+attrs.t * 1000),
931
1514
  offline: !!attrs.offline,
932
- status,
1515
+ status
933
1516
  };
934
1517
  if (status === 'offer') {
935
- call.isVideo = !!(0, WABinary_1.getBinaryNodeChild)(infoChild, 'video');
1518
+ call.isVideo = !!(0, index_js_5.getBinaryNodeChild)(infoChild, 'video');
936
1519
  call.isGroup = infoChild.attrs.type === 'group' || !!infoChild.attrs['group-jid'];
937
1520
  call.groupJid = infoChild.attrs['group-jid'];
938
- callOfferCache.set(call.id, call);
1521
+ await callOfferCache.set(call.id, call);
939
1522
  }
940
- const existingCall = callOfferCache.get(call.id);
1523
+ const existingCall = await callOfferCache.get(call.id);
941
1524
  // use existing call info to populate this event
942
1525
  if (existingCall) {
943
1526
  call.isVideo = existingCall.isVideo;
944
1527
  call.isGroup = existingCall.isGroup;
1528
+ call.callerPn = call.callerPn || existingCall.callerPn;
945
1529
  }
946
1530
  // delete data once call has ended
947
1531
  if (status === 'reject' || status === 'accept' || status === 'timeout' || status === 'terminate') {
948
- callOfferCache.del(call.id);
1532
+ await callOfferCache.del(call.id);
949
1533
  }
950
1534
  ev.emit('call', [call]);
951
1535
  await sendMessageAck(node);
952
1536
  };
953
1537
  const handleBadAck = async ({ attrs }) => {
954
- const key = { remoteJid: attrs.from, fromMe: true, id: attrs.id, 'server_id': attrs === null || attrs === void 0 ? void 0 : attrs.server_id };
955
- // current hypothesis is that if pash is sent in the ack
956
- // it means -- the message hasn't reached all devices yet
957
- // we'll retry sending the message here
958
- if (attrs.phash) {
959
- logger.info({ attrs }, 'received phash in ack, resending message...');
960
- const cacheKey = `${key.remoteJid}:${key.id}`;
961
- if ((msgRetryCache.get(cacheKey) || 0) >= maxMsgRetryCount) {
962
- logger.warn({ attrs }, 'reached max retry count, not sending message again');
963
- msgRetryCache.del(cacheKey);
964
- return;
965
- }
966
- const retryCount = msgRetryCache.get(cacheKey) || 0;
967
- const msg = await getMessage(key);
968
- if (msg) {
969
- await relayMessage(key.remoteJid, msg, { messageId: key.id, useUserDevicesCache: false });
970
- msgRetryCache.set(cacheKey, retryCount + 1);
971
- }
972
- else {
973
- logger.warn({ attrs }, 'could not send message again, as it was not found');
974
- }
975
- }
1538
+ const key = { remoteJid: attrs.from, fromMe: true, id: attrs.id };
1539
+ // WARNING: REFRAIN FROM ENABLING THIS FOR NOW. IT WILL CAUSE A LOOP
1540
+ // // current hypothesis is that if pash is sent in the ack
1541
+ // // it means -- the message hasn't reached all devices yet
1542
+ // // we'll retry sending the message here
1543
+ // if(attrs.phash) {
1544
+ // logger.info({ attrs }, 'received phash in ack, resending message...')
1545
+ // const msg = await getMessage(key)
1546
+ // if(msg) {
1547
+ // await relayMessage(key.remoteJid!, msg, { messageId: key.id!, useUserDevicesCache: false })
1548
+ // } else {
1549
+ // logger.warn({ attrs }, 'could not send message again, as it was not found')
1550
+ // }
1551
+ // }
976
1552
  // error in acknowledgement,
977
1553
  // device could not display the message
978
1554
  if (attrs.error) {
@@ -981,13 +1557,24 @@ const makeMessagesRecvSocket = (config) => {
981
1557
  {
982
1558
  key,
983
1559
  update: {
984
- status: Types_1.WAMessageStatus.ERROR,
985
- messageStubParameters: [
986
- attrs.error
987
- ]
1560
+ status: index_js_3.WAMessageStatus.ERROR,
1561
+ messageStubParameters: [attrs.error]
988
1562
  }
989
1563
  }
990
1564
  ]);
1565
+ // resend the message with device_fanout=false, use at your own risk
1566
+ // if (attrs.error === '475') {
1567
+ // const msg = await getMessage(key)
1568
+ // if (msg) {
1569
+ // await relayMessage(key.remoteJid!, msg, {
1570
+ // messageId: key.id!,
1571
+ // useUserDevicesCache: false,
1572
+ // additionalAttributes: {
1573
+ // device_fanout: 'false'
1574
+ // }
1575
+ // })
1576
+ // }
1577
+ // }
991
1578
  }
992
1579
  };
993
1580
  /// processes a node with the given function
@@ -997,10 +1584,13 @@ const makeMessagesRecvSocket = (config) => {
997
1584
  await execTask();
998
1585
  ev.flush();
999
1586
  function execTask() {
1000
- return exec(node, false)
1001
- .catch(err => onUnexpectedError(err, identifier));
1587
+ return exec(node, false).catch(err => onUnexpectedError(err, identifier));
1002
1588
  }
1003
1589
  };
1590
+ /** Yields control to the event loop to prevent blocking */
1591
+ const yieldToEventLoop = () => {
1592
+ return new Promise(resolve => setImmediate(resolve));
1593
+ };
1004
1594
  const makeOfflineNodeProcessor = () => {
1005
1595
  const nodeProcessorMap = new Map([
1006
1596
  ['message', handleMessage],
@@ -1010,6 +1600,8 @@ const makeMessagesRecvSocket = (config) => {
1010
1600
  ]);
1011
1601
  const nodes = [];
1012
1602
  let isProcessing = false;
1603
+ // Number of nodes to process before yielding to event loop
1604
+ const BATCH_SIZE = 10;
1013
1605
  const enqueue = (type, node) => {
1014
1606
  nodes.push({ type, node });
1015
1607
  if (isProcessing) {
@@ -1017,6 +1609,7 @@ const makeMessagesRecvSocket = (config) => {
1017
1609
  }
1018
1610
  isProcessing = true;
1019
1611
  const promise = async () => {
1612
+ let processedInBatch = 0;
1020
1613
  while (nodes.length && ws.isOpen) {
1021
1614
  const { type, node } = nodes.shift();
1022
1615
  const nodeProcessor = nodeProcessorMap.get(type);
@@ -1025,6 +1618,13 @@ const makeMessagesRecvSocket = (config) => {
1025
1618
  continue;
1026
1619
  }
1027
1620
  await nodeProcessor(node);
1621
+ processedInBatch++;
1622
+ // Yield to event loop after processing a batch
1623
+ // This prevents blocking the event loop for too long when there are many offline nodes
1624
+ if (processedInBatch >= BATCH_SIZE) {
1625
+ processedInBatch = 0;
1626
+ await yieldToEventLoop();
1627
+ }
1028
1628
  }
1029
1629
  isProcessing = false;
1030
1630
  };
@@ -1033,33 +1633,35 @@ const makeMessagesRecvSocket = (config) => {
1033
1633
  return { enqueue };
1034
1634
  };
1035
1635
  const offlineNodeProcessor = makeOfflineNodeProcessor();
1036
- const processNode = (type, node, identifier, exec) => {
1636
+ const processNode = async (type, node, identifier, exec) => {
1037
1637
  const isOffline = !!node.attrs.offline;
1038
1638
  if (isOffline) {
1039
1639
  offlineNodeProcessor.enqueue(type, node);
1040
1640
  }
1041
1641
  else {
1042
- processNodeWithBuffer(node, identifier, exec);
1642
+ await processNodeWithBuffer(node, identifier, exec);
1043
1643
  }
1044
1644
  };
1045
1645
  // recv a message
1046
- ws.on('CB:message', (node) => {
1047
- processNode('message', node, 'processing message', handleMessage);
1646
+ ws.on('CB:message', async (node) => {
1647
+ await processNode('message', node, 'processing message', handleMessage);
1048
1648
  });
1049
1649
  ws.on('CB:call', async (node) => {
1050
- processNode('call', node, 'handling call', handleCall);
1650
+ await processNode('call', node, 'handling call', handleCall);
1051
1651
  });
1052
- ws.on('CB:receipt', node => {
1053
- processNode('receipt', node, 'handling receipt', handleReceipt);
1652
+ ws.on('CB:receipt', async (node) => {
1653
+ await processNode('receipt', node, 'handling receipt', handleReceipt);
1054
1654
  });
1055
1655
  ws.on('CB:notification', async (node) => {
1056
- processNode('notification', node, 'handling notification', handleNotification);
1656
+ await processNode('notification', node, 'handling notification', handleNotification);
1057
1657
  });
1058
1658
  ws.on('CB:ack,class:message', (node) => {
1059
- handleBadAck(node)
1060
- .catch(error => onUnexpectedError(error, 'handling bad ack'));
1659
+ handleBadAck(node).catch(error => onUnexpectedError(error, 'handling bad ack'));
1061
1660
  });
1062
- ev.on('call', ([call]) => {
1661
+ ev.on('call', async ([call]) => {
1662
+ if (!call) {
1663
+ return;
1664
+ }
1063
1665
  // missed call + group call notification message generation
1064
1666
  if (call.status === 'timeout' || (call.status === 'offer' && call.isGroup)) {
1065
1667
  const msg = {
@@ -1068,21 +1670,23 @@ const makeMessagesRecvSocket = (config) => {
1068
1670
  id: call.id,
1069
1671
  fromMe: false
1070
1672
  },
1071
- messageTimestamp: (0, Utils_1.unixTimestampSeconds)(call.date),
1673
+ messageTimestamp: (0, index_js_4.unixTimestampSeconds)(call.date)
1072
1674
  };
1073
1675
  if (call.status === 'timeout') {
1074
1676
  if (call.isGroup) {
1075
- msg.messageStubType = call.isVideo ? Types_1.WAMessageStubType.CALL_MISSED_GROUP_VIDEO : Types_1.WAMessageStubType.CALL_MISSED_GROUP_VOICE;
1677
+ msg.messageStubType = call.isVideo
1678
+ ? index_js_3.WAMessageStubType.CALL_MISSED_GROUP_VIDEO
1679
+ : index_js_3.WAMessageStubType.CALL_MISSED_GROUP_VOICE;
1076
1680
  }
1077
1681
  else {
1078
- msg.messageStubType = call.isVideo ? Types_1.WAMessageStubType.CALL_MISSED_VIDEO : Types_1.WAMessageStubType.CALL_MISSED_VOICE;
1682
+ msg.messageStubType = call.isVideo ? index_js_3.WAMessageStubType.CALL_MISSED_VIDEO : index_js_3.WAMessageStubType.CALL_MISSED_VOICE;
1079
1683
  }
1080
1684
  }
1081
1685
  else {
1082
1686
  msg.message = { call: { callKey: Buffer.from(call.id) } };
1083
1687
  }
1084
- const protoMsg = WAProto_1.proto.WebMessageInfo.fromObject(msg);
1085
- upsertMessage(protoMsg, call.offline ? 'append' : 'notify');
1688
+ const protoMsg = index_js_1.proto.WebMessageInfo.fromObject(msg);
1689
+ await upsertMessage(protoMsg, call.offline ? 'append' : 'notify');
1086
1690
  }
1087
1691
  });
1088
1692
  ev.on('connection.update', ({ isOnline }) => {
@@ -1096,9 +1700,9 @@ const makeMessagesRecvSocket = (config) => {
1096
1700
  sendMessageAck,
1097
1701
  sendRetryRequest,
1098
1702
  rejectCall,
1099
- offerCall,
1100
1703
  fetchMessageHistory,
1101
1704
  requestPlaceholderResend,
1705
+ messageRetryManager
1102
1706
  };
1103
1707
  };
1104
1708
  exports.makeMessagesRecvSocket = makeMessagesRecvSocket;