@queenanya/baileys 9.2.4 → 9.4.3

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 (301) hide show
  1. package/README.md +329 -1237
  2. package/WAProto/fix-imports.js +22 -18
  3. package/WAProto/index.js +22 -18
  4. package/lib/Defaults/index.d.ts +17 -0
  5. package/lib/Defaults/index.d.ts.map +1 -1
  6. package/lib/Defaults/index.js +29 -3
  7. package/lib/Defaults/index.js.map +1 -1
  8. package/lib/Signal/libsignal.d.ts.map +1 -1
  9. package/lib/Signal/libsignal.js +61 -2
  10. package/lib/Signal/libsignal.js.map +1 -1
  11. package/lib/Signal/lid-mapping.d.ts +5 -9
  12. package/lib/Signal/lid-mapping.d.ts.map +1 -1
  13. package/lib/Signal/lid-mapping.js +170 -70
  14. package/lib/Signal/lid-mapping.js.map +1 -1
  15. package/lib/Socket/business.d.ts +114 -2
  16. package/lib/Socket/business.d.ts.map +1 -1
  17. package/lib/Socket/chats.d.ts +14 -1
  18. package/lib/Socket/chats.d.ts.map +1 -1
  19. package/lib/Socket/chats.js +253 -38
  20. package/lib/Socket/chats.js.map +1 -1
  21. package/lib/Socket/communities.d.ts +114 -2
  22. package/lib/Socket/communities.d.ts.map +1 -1
  23. package/lib/Socket/groups.d.ts +9 -0
  24. package/lib/Socket/groups.d.ts.map +1 -1
  25. package/lib/Socket/groups.js +6 -0
  26. package/lib/Socket/groups.js.map +1 -1
  27. package/lib/Socket/index.d.ts +114 -2
  28. package/lib/Socket/index.d.ts.map +1 -1
  29. package/lib/Socket/index.js +0 -6
  30. package/lib/Socket/index.js.map +1 -1
  31. package/lib/Socket/messages-recv.d.ts +115 -3
  32. package/lib/Socket/messages-recv.d.ts.map +1 -1
  33. package/lib/Socket/messages-recv.js +739 -150
  34. package/lib/Socket/messages-recv.js.map +1 -1
  35. package/lib/Socket/messages-send.d.ts +118 -4
  36. package/lib/Socket/messages-send.d.ts.map +1 -1
  37. package/lib/Socket/messages-send.js +328 -86
  38. package/lib/Socket/messages-send.js.map +1 -1
  39. package/lib/Socket/newsletter.d.ts +9 -0
  40. package/lib/Socket/newsletter.d.ts.map +1 -1
  41. package/lib/Socket/newsletter.js +2 -2
  42. package/lib/Socket/newsletter.js.map +1 -1
  43. package/lib/Socket/socket.d.ts +2 -0
  44. package/lib/Socket/socket.d.ts.map +1 -1
  45. package/lib/Socket/socket.js +143 -17
  46. package/lib/Socket/socket.js.map +1 -1
  47. package/lib/Types/Auth.d.ts +2 -0
  48. package/lib/Types/Auth.d.ts.map +1 -1
  49. package/lib/Types/Call.d.ts +10 -1
  50. package/lib/Types/Call.d.ts.map +1 -1
  51. package/lib/Types/Contact.d.ts +2 -0
  52. package/lib/Types/Contact.d.ts.map +1 -1
  53. package/lib/Types/Events.d.ts +21 -1
  54. package/lib/Types/Events.d.ts.map +1 -1
  55. package/lib/Types/GroupMetadata.d.ts +4 -0
  56. package/lib/Types/GroupMetadata.d.ts.map +1 -1
  57. package/lib/Types/Message.d.ts +530 -16
  58. package/lib/Types/Message.d.ts.map +1 -1
  59. package/lib/Types/Message.js.map +1 -1
  60. package/lib/Types/Newsletter.d.ts +37 -31
  61. package/lib/Types/Newsletter.d.ts.map +1 -1
  62. package/lib/Types/Newsletter.js +27 -23
  63. package/lib/Types/Newsletter.js.map +1 -1
  64. package/lib/Types/State.d.ts +54 -0
  65. package/lib/Types/State.d.ts.map +1 -1
  66. package/lib/Types/State.js +42 -0
  67. package/lib/Types/State.js.map +1 -1
  68. package/lib/Types/index.d.ts +9 -0
  69. package/lib/Types/index.d.ts.map +1 -1
  70. package/lib/Types/index.js.map +1 -1
  71. package/lib/Utils/browser-utils.d.ts +13 -0
  72. package/lib/Utils/browser-utils.d.ts.map +1 -1
  73. package/lib/Utils/browser-utils.js +90 -10
  74. package/lib/Utils/browser-utils.js.map +1 -1
  75. package/lib/Utils/chat-utils.d.ts +30 -0
  76. package/lib/Utils/chat-utils.d.ts.map +1 -1
  77. package/lib/Utils/chat-utils.js +81 -52
  78. package/lib/Utils/chat-utils.js.map +1 -1
  79. package/lib/Utils/companion-reg-client-utils.d.ts +17 -0
  80. package/lib/Utils/companion-reg-client-utils.d.ts.map +1 -0
  81. package/lib/Utils/companion-reg-client-utils.js +34 -0
  82. package/lib/Utils/companion-reg-client-utils.js.map +1 -0
  83. package/lib/Utils/crypto.d.ts +4 -8
  84. package/lib/Utils/crypto.d.ts.map +1 -1
  85. package/lib/Utils/crypto.js +2 -26
  86. package/lib/Utils/crypto.js.map +1 -1
  87. package/lib/Utils/decode-wa-message.d.ts +12 -0
  88. package/lib/Utils/decode-wa-message.d.ts.map +1 -1
  89. package/lib/Utils/decode-wa-message.js +16 -0
  90. package/lib/Utils/decode-wa-message.js.map +1 -1
  91. package/lib/Utils/event-buffer.js +10 -1
  92. package/lib/Utils/event-buffer.js.map +1 -1
  93. package/lib/Utils/generics.d.ts +3 -1
  94. package/lib/Utils/generics.d.ts.map +1 -1
  95. package/lib/Utils/generics.js +16 -3
  96. package/lib/Utils/generics.js.map +1 -1
  97. package/lib/Utils/history.d.ts +5 -2
  98. package/lib/Utils/history.d.ts.map +1 -1
  99. package/lib/Utils/history.js +53 -17
  100. package/lib/Utils/history.js.map +1 -1
  101. package/lib/Utils/identity-change-handler.d.ts +44 -0
  102. package/lib/Utils/identity-change-handler.d.ts.map +1 -0
  103. package/lib/Utils/identity-change-handler.js +50 -0
  104. package/lib/Utils/identity-change-handler.js.map +1 -0
  105. package/lib/Utils/index.d.ts +6 -0
  106. package/lib/Utils/index.d.ts.map +1 -1
  107. package/lib/Utils/index.js +6 -0
  108. package/lib/Utils/index.js.map +1 -1
  109. package/lib/Utils/interactive-message.d.ts +201 -0
  110. package/lib/Utils/interactive-message.d.ts.map +1 -0
  111. package/lib/Utils/interactive-message.js +256 -0
  112. package/lib/Utils/interactive-message.js.map +1 -0
  113. package/lib/Utils/lt-hash.d.ts +7 -12
  114. package/lib/Utils/lt-hash.d.ts.map +1 -1
  115. package/lib/Utils/lt-hash.js +2 -42
  116. package/lib/Utils/lt-hash.js.map +1 -1
  117. package/lib/Utils/message-composer.d.ts +5 -0
  118. package/lib/Utils/message-composer.d.ts.map +1 -0
  119. package/lib/Utils/message-composer.js +5 -0
  120. package/lib/Utils/message-composer.js.map +1 -0
  121. package/lib/Utils/message-retry-manager.d.ts +30 -2
  122. package/lib/Utils/message-retry-manager.d.ts.map +1 -1
  123. package/lib/Utils/message-retry-manager.js +59 -2
  124. package/lib/Utils/message-retry-manager.js.map +1 -1
  125. package/lib/Utils/messages-media.d.ts +19 -5
  126. package/lib/Utils/messages-media.d.ts.map +1 -1
  127. package/lib/Utils/messages-media.js +26 -17
  128. package/lib/Utils/messages-media.js.map +1 -1
  129. package/lib/Utils/messages.d.ts.map +1 -1
  130. package/lib/Utils/messages.js +433 -13
  131. package/lib/Utils/messages.js.map +1 -1
  132. package/lib/Utils/noise-handler.d.ts +2 -2
  133. package/lib/Utils/noise-handler.d.ts.map +1 -1
  134. package/lib/Utils/noise-handler.js +10 -10
  135. package/lib/Utils/noise-handler.js.map +1 -1
  136. package/lib/Utils/offline-node-processor.d.ts +17 -0
  137. package/lib/Utils/offline-node-processor.d.ts.map +1 -0
  138. package/lib/Utils/offline-node-processor.js +40 -0
  139. package/lib/Utils/offline-node-processor.js.map +1 -0
  140. package/lib/Utils/process-message.d.ts.map +1 -1
  141. package/lib/Utils/process-message.js +96 -16
  142. package/lib/Utils/process-message.js.map +1 -1
  143. package/lib/Utils/reporting-utils.js +2 -2
  144. package/lib/Utils/reporting-utils.js.map +1 -1
  145. package/lib/Utils/stanza-ack.d.ts +11 -0
  146. package/lib/Utils/stanza-ack.d.ts.map +1 -0
  147. package/lib/Utils/stanza-ack.js +38 -0
  148. package/lib/Utils/stanza-ack.js.map +1 -0
  149. package/lib/Utils/sync-action-utils.d.ts.map +1 -1
  150. package/lib/Utils/sync-action-utils.js +2 -1
  151. package/lib/Utils/sync-action-utils.js.map +1 -1
  152. package/lib/Utils/tc-token-utils.d.ts +26 -1
  153. package/lib/Utils/tc-token-utils.d.ts.map +1 -1
  154. package/lib/Utils/tc-token-utils.js +149 -4
  155. package/lib/Utils/tc-token-utils.js.map +1 -1
  156. package/lib/Utils/use-mongo-file-auth-state.d.ts +16 -0
  157. package/lib/Utils/use-mongo-file-auth-state.d.ts.map +1 -0
  158. package/lib/Utils/use-mongo-file-auth-state.js +60 -0
  159. package/lib/Utils/use-mongo-file-auth-state.js.map +1 -0
  160. package/lib/Utils/use-multi-file-auth-state.js +1 -1
  161. package/lib/Utils/use-multi-file-auth-state.js.map +1 -1
  162. package/lib/Utils/validate-connection.d.ts.map +1 -1
  163. package/lib/Utils/validate-connection.js +11 -1
  164. package/lib/Utils/validate-connection.js.map +1 -1
  165. package/lib/WABinary/generic-utils.d.ts +9 -0
  166. package/lib/WABinary/generic-utils.d.ts.map +1 -1
  167. package/lib/WABinary/generic-utils.js +23 -0
  168. package/lib/WABinary/generic-utils.js.map +1 -1
  169. package/lib/WABinary/jid-utils.js.map +1 -1
  170. package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts.map +1 -1
  171. package/lib/WAUSync/Protocols/USyncContactProtocol.js +26 -3
  172. package/lib/WAUSync/Protocols/USyncContactProtocol.js.map +1 -1
  173. package/lib/WAUSync/Protocols/USyncUsernameProtocol.d.ts +10 -0
  174. package/lib/WAUSync/Protocols/USyncUsernameProtocol.d.ts.map +1 -0
  175. package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +25 -0
  176. package/lib/WAUSync/Protocols/USyncUsernameProtocol.js.map +1 -0
  177. package/lib/WAUSync/Protocols/index.d.ts +1 -0
  178. package/lib/WAUSync/Protocols/index.d.ts.map +1 -1
  179. package/lib/WAUSync/Protocols/index.js +1 -0
  180. package/lib/WAUSync/Protocols/index.js.map +1 -1
  181. package/lib/WAUSync/USyncQuery.d.ts +1 -0
  182. package/lib/WAUSync/USyncQuery.d.ts.map +1 -1
  183. package/lib/WAUSync/USyncQuery.js +5 -1
  184. package/lib/WAUSync/USyncQuery.js.map +1 -1
  185. package/lib/WAUSync/USyncUser.d.ts +4 -0
  186. package/lib/WAUSync/USyncUser.d.ts.map +1 -1
  187. package/lib/WAUSync/USyncUser.js +8 -0
  188. package/lib/WAUSync/USyncUser.js.map +1 -1
  189. package/lib/addons/anti-delete.d.ts +72 -0
  190. package/lib/addons/anti-delete.d.ts.map +1 -0
  191. package/lib/addons/anti-delete.js +165 -0
  192. package/lib/addons/anti-delete.js.map +1 -0
  193. package/lib/addons/auto-reply.d.ts +67 -0
  194. package/lib/addons/auto-reply.d.ts.map +1 -0
  195. package/lib/addons/auto-reply.js +145 -0
  196. package/lib/addons/auto-reply.js.map +1 -0
  197. package/lib/addons/browser-presets.d.ts +16 -0
  198. package/lib/addons/browser-presets.d.ts.map +1 -0
  199. package/lib/addons/browser-presets.js +24 -0
  200. package/lib/addons/browser-presets.js.map +1 -0
  201. package/lib/addons/button-sender.d.ts +260 -0
  202. package/lib/addons/button-sender.d.ts.map +1 -0
  203. package/lib/addons/button-sender.js +771 -0
  204. package/lib/addons/button-sender.js.map +1 -0
  205. package/lib/addons/call-handler.d.ts +79 -0
  206. package/lib/addons/call-handler.d.ts.map +1 -0
  207. package/lib/addons/call-handler.js +342 -0
  208. package/lib/addons/call-handler.js.map +1 -0
  209. package/lib/addons/from-chats.d.ts +30 -0
  210. package/lib/addons/from-chats.d.ts.map +1 -0
  211. package/lib/addons/from-chats.js +38 -0
  212. package/lib/addons/from-chats.js.map +1 -0
  213. package/lib/addons/from-messages-recv.d.ts +59 -0
  214. package/lib/addons/from-messages-recv.d.ts.map +1 -0
  215. package/lib/addons/from-messages-recv.js +326 -0
  216. package/lib/addons/from-messages-recv.js.map +1 -0
  217. package/lib/addons/from-messages-send.d.ts +50 -0
  218. package/lib/addons/from-messages-send.d.ts.map +1 -0
  219. package/lib/addons/from-messages-send.js +148 -0
  220. package/lib/addons/from-messages-send.js.map +1 -0
  221. package/lib/addons/from-messages.d.ts +52 -0
  222. package/lib/addons/from-messages.d.ts.map +1 -0
  223. package/lib/addons/from-messages.js +304 -0
  224. package/lib/addons/from-messages.js.map +1 -0
  225. package/lib/addons/index.d.ts +67 -0
  226. package/lib/addons/index.d.ts.map +1 -0
  227. package/lib/addons/index.js +86 -0
  228. package/lib/addons/index.js.map +1 -0
  229. package/lib/addons/interactive-message.d.ts +201 -0
  230. package/lib/addons/interactive-message.d.ts.map +1 -0
  231. package/lib/addons/interactive-message.js +256 -0
  232. package/lib/addons/interactive-message.js.map +1 -0
  233. package/lib/addons/jid-plot.d.ts +49 -0
  234. package/lib/addons/jid-plot.d.ts.map +1 -0
  235. package/lib/addons/jid-plot.js +84 -0
  236. package/lib/addons/jid-plot.js.map +1 -0
  237. package/lib/addons/jid-plotting.d.ts +54 -0
  238. package/lib/addons/jid-plotting.d.ts.map +1 -0
  239. package/lib/addons/jid-plotting.js +150 -0
  240. package/lib/addons/jid-plotting.js.map +1 -0
  241. package/lib/addons/lid-support.d.ts +41 -0
  242. package/lib/addons/lid-support.d.ts.map +1 -0
  243. package/lib/addons/lid-support.js +42 -0
  244. package/lib/addons/lid-support.js.map +1 -0
  245. package/lib/addons/message-composer.d.ts +142 -0
  246. package/lib/addons/message-composer.d.ts.map +1 -0
  247. package/lib/addons/message-composer.js +377 -0
  248. package/lib/addons/message-composer.js.map +1 -0
  249. package/lib/addons/message-scheduler.d.ts +77 -0
  250. package/lib/addons/message-scheduler.d.ts.map +1 -0
  251. package/lib/addons/message-scheduler.js +108 -0
  252. package/lib/addons/message-scheduler.js.map +1 -0
  253. package/lib/addons/message-search.d.ts +51 -0
  254. package/lib/addons/message-search.d.ts.map +1 -0
  255. package/lib/addons/message-search.js +171 -0
  256. package/lib/addons/message-search.js.map +1 -0
  257. package/lib/addons/message-utils.d.ts +88 -0
  258. package/lib/addons/message-utils.d.ts.map +1 -0
  259. package/lib/addons/message-utils.js +292 -0
  260. package/lib/addons/message-utils.js.map +1 -0
  261. package/lib/addons/outgoing-calls.d.ts +64 -0
  262. package/lib/addons/outgoing-calls.d.ts.map +1 -0
  263. package/lib/addons/outgoing-calls.js +139 -0
  264. package/lib/addons/outgoing-calls.js.map +1 -0
  265. package/lib/addons/pairing-fix.d.ts +31 -0
  266. package/lib/addons/pairing-fix.d.ts.map +1 -0
  267. package/lib/addons/pairing-fix.js +74 -0
  268. package/lib/addons/pairing-fix.js.map +1 -0
  269. package/lib/addons/past-participants.d.ts +42 -0
  270. package/lib/addons/past-participants.d.ts.map +1 -0
  271. package/lib/addons/past-participants.js +41 -0
  272. package/lib/addons/past-participants.js.map +1 -0
  273. package/lib/addons/rich-response.d.ts +111 -0
  274. package/lib/addons/rich-response.d.ts.map +1 -0
  275. package/lib/addons/rich-response.js +152 -0
  276. package/lib/addons/rich-response.js.map +1 -0
  277. package/lib/addons/scheduling.d.ts +41 -0
  278. package/lib/addons/scheduling.d.ts.map +1 -0
  279. package/lib/addons/scheduling.js +110 -0
  280. package/lib/addons/scheduling.js.map +1 -0
  281. package/lib/addons/status-posting.d.ts +177 -0
  282. package/lib/addons/status-posting.d.ts.map +1 -0
  283. package/lib/addons/status-posting.js +240 -0
  284. package/lib/addons/status-posting.js.map +1 -0
  285. package/lib/addons/stickerpack.d.ts +37 -0
  286. package/lib/addons/stickerpack.d.ts.map +1 -0
  287. package/lib/addons/stickerpack.js +39 -0
  288. package/lib/addons/stickerpack.js.map +1 -0
  289. package/lib/addons/templates.d.ts +72 -0
  290. package/lib/addons/templates.d.ts.map +1 -0
  291. package/lib/addons/templates.js +145 -0
  292. package/lib/addons/templates.js.map +1 -0
  293. package/lib/addons/vcard.d.ts +59 -0
  294. package/lib/addons/vcard.d.ts.map +1 -0
  295. package/lib/addons/vcard.js +88 -0
  296. package/lib/addons/vcard.js.map +1 -0
  297. package/lib/index.d.ts +1 -0
  298. package/lib/index.d.ts.map +1 -1
  299. package/lib/index.js +1 -0
  300. package/lib/index.js.map +1 -1
  301. package/package.json +5 -3
@@ -1,22 +1,32 @@
1
1
  import NodeCache from '@cacheable/node-cache';
2
2
  import { Boom } from '@hapi/boom';
3
+ import Long from 'long';
3
4
  import { proto } from '../../WAProto/index.js';
4
- import { DEFAULT_CACHE_TTLS, PROCESSABLE_HISTORY_TYPES } from '../Defaults/index.js';
5
+ import { DEFAULT_CACHE_TTLS, HISTORY_SYNC_PAUSED_TIMEOUT_MS, PROCESSABLE_HISTORY_TYPES } from '../Defaults/index.js';
5
6
  import { ALL_WA_PATCH_NAMES } from '../Types/index.js';
6
7
  import { SyncState } from '../Types/State.js';
7
- import { chatModificationToAppPatch, decodePatches, decodeSyncdSnapshot, encodeSyncdPatch, extractSyncdPatches, generateProfilePicture, getHistoryMsg, newLTHashState, processSyncAction } from '../Utils/index.js';
8
+ import { chatModificationToAppPatch, decodePatches, decodeSyncdSnapshot, encodeSyncdPatch, ensureLTHashStateVersion, extractSyncdPatches, generateProfilePicture, getHistoryMsg, isAppStateSyncIrrecoverable, isMissingKeyError, MAX_SYNC_ATTEMPTS, newLTHashState, processSyncAction } from '../Utils/index.js';
8
9
  import { makeMutex } from '../Utils/make-mutex.js';
9
10
  import processMessage from '../Utils/process-message.js';
10
11
  import { buildTcTokenFromJid } from '../Utils/tc-token-utils.js';
11
- import { getBinaryNodeChild, getBinaryNodeChildren, jidDecode, jidNormalizedUser, reduceBinaryNodeToDictionary, S_WHATSAPP_NET } from '../WABinary/index.js';
12
+ import { getBinaryNodeChild, getBinaryNodeChildren, isHostedLidUser, isHostedPnUser, isLidUser, isPnUser, jidDecode, jidNormalizedUser, reduceBinaryNodeToDictionary, S_WHATSAPP_NET } from '../WABinary/index.js';
12
13
  import { USyncQuery, USyncUser } from '../WAUSync/index.js';
13
14
  import { makeSocket } from './socket.js';
14
- const MAX_SYNC_ATTEMPTS = 2;
15
15
  export const makeChatsSocket = (config) => {
16
16
  const { logger, markOnlineOnConnect, fireInitQueries, appStateMacVerification, shouldIgnoreJid, shouldSyncHistoryMessage, getMessage } = config;
17
17
  const sock = makeSocket(config);
18
- const { ev, ws, authState, generateMessageTag, sendNode, query, signalRepository, onUnexpectedError } = sock;
18
+ const { ev, ws, authState, generateMessageTag, sendNode, query, signalRepository, onUnexpectedError, sendUnifiedSession } = sock;
19
+ const getLIDForPN = signalRepository.lidMapping.getLIDForPN.bind(signalRepository.lidMapping);
19
20
  let privacySettings;
21
+ /** Server-assigned AB props for protocol behavior. */
22
+ const serverProps = {
23
+ /** AB prop 10518: gate tctoken on 1:1 messages. Default true (safe: avoids 463). */
24
+ privacyTokenOn1to1: true,
25
+ /** AB prop 9666: gate tctoken on profile picture IQs. WA Web default: true. */
26
+ profilePicPrivacyToken: true,
27
+ /** AB prop 14303: issue tctokens to LID instead of PN. WA Web default: false. */
28
+ lidTrustedTokenIssueToLid: false
29
+ };
20
30
  let syncState = SyncState.Connecting;
21
31
  /** this mutex ensures that messages are processed in order */
22
32
  const messageMutex = makeMutex();
@@ -28,6 +38,15 @@ export const makeChatsSocket = (config) => {
28
38
  const notificationMutex = makeMutex();
29
39
  // Timeout for AwaitingInitialSync state
30
40
  let awaitingSyncTimeout;
41
+ // In-memory history sync completion tracking (resets on reconnection)
42
+ const historySyncStatus = {
43
+ initialBootstrapComplete: false,
44
+ recentSyncComplete: false
45
+ };
46
+ let historySyncPausedTimeout;
47
+ // Collections blocked on missing app state sync keys (mirrors WA Web's "Blocked" state).
48
+ // When a key arrives via APP_STATE_SYNC_KEY_SHARE, these are re-synced.
49
+ const blockedCollections = new Set();
31
50
  const placeholderResendCache = config.placeholderResendCache ||
32
51
  new NodeCache({
33
52
  stdTTL: DEFAULT_CACHE_TTLS.MSG_RETRY, // 1 hour
@@ -258,6 +277,42 @@ export const makeChatsSocket = (config) => {
258
277
  return getBinaryNodeChildren(listNode, 'item').map(n => n.attrs.jid);
259
278
  };
260
279
  const updateBlockStatus = async (jid, action) => {
280
+ const normalizedJid = jidNormalizedUser(jid);
281
+ let lid;
282
+ let pn_jid;
283
+ if (isLidUser(normalizedJid) || isHostedLidUser(normalizedJid)) {
284
+ lid = normalizedJid;
285
+ if (action === 'block') {
286
+ const pn = await signalRepository.lidMapping.getPNForLID(normalizedJid);
287
+ if (!pn) {
288
+ throw new Boom(`Unable to resolve PN JID for LID: ${jid}`, { statusCode: 400 });
289
+ }
290
+ pn_jid = jidNormalizedUser(pn);
291
+ }
292
+ }
293
+ else if (isPnUser(normalizedJid) || isHostedPnUser(normalizedJid)) {
294
+ const mapped = await signalRepository.lidMapping.getLIDForPN(normalizedJid);
295
+ if (!mapped) {
296
+ throw new Boom(`Unable to resolve LID for PN JID: ${jid}`, { statusCode: 400 });
297
+ }
298
+ lid = mapped;
299
+ if (action === 'block') {
300
+ pn_jid = jidNormalizedUser(normalizedJid);
301
+ }
302
+ }
303
+ else {
304
+ throw new Boom(`Invalid jid: ${jid}`, { statusCode: 400 });
305
+ }
306
+ const itemAttrs = {
307
+ action,
308
+ jid: lid
309
+ };
310
+ if (action === 'block') {
311
+ if (!pn_jid) {
312
+ throw new Boom(`pn_jid required for block: ${jid}`, { statusCode: 400 });
313
+ }
314
+ itemAttrs.pn_jid = pn_jid;
315
+ }
261
316
  await query({
262
317
  tag: 'iq',
263
318
  attrs: {
@@ -268,10 +323,7 @@ export const makeChatsSocket = (config) => {
268
323
  content: [
269
324
  {
270
325
  tag: 'item',
271
- attrs: {
272
- action,
273
- jid
274
- }
326
+ attrs: itemAttrs
275
327
  }
276
328
  ]
277
329
  });
@@ -353,6 +405,15 @@ export const makeChatsSocket = (config) => {
353
405
  };
354
406
  };
355
407
  const resyncAppState = ev.createBufferedFunction(async (collections, isInitialSync) => {
408
+ const appStateSyncKeyCache = new Map();
409
+ const getCachedAppStateSyncKey = async (keyId) => {
410
+ if (appStateSyncKeyCache.has(keyId)) {
411
+ return appStateSyncKeyCache.get(keyId) ?? undefined;
412
+ }
413
+ const key = await getAppStateSyncKey(keyId);
414
+ appStateSyncKeyCache.set(keyId, key ?? null);
415
+ return key;
416
+ };
356
417
  // we use this to determine which events to fire
357
418
  // otherwise when we resync from scratch -- all notifications will fire
358
419
  const initialVersionMap = {};
@@ -361,6 +422,9 @@ export const makeChatsSocket = (config) => {
361
422
  const collectionsToHandle = new Set(collections);
362
423
  // in case something goes wrong -- ensure we don't enter a loop that cannot be exited from
363
424
  const attemptsMap = {};
425
+ // collections that failed and need a full snapshot on retry
426
+ // mirrors WA Web's ErrorFatal -> force snapshot behavior
427
+ const forceSnapshotCollections = new Set();
364
428
  // keep executing till all collections are done
365
429
  // sometimes a single patch request will not return all the patches (God knows why)
366
430
  // so we fetch till they're all done (this is determined by the "has_more_patches" flag)
@@ -371,6 +435,7 @@ export const makeChatsSocket = (config) => {
371
435
  const result = await authState.keys.get('app-state-sync-version', [name]);
372
436
  let state = result[name];
373
437
  if (state) {
438
+ state = ensureLTHashStateVersion(state);
374
439
  if (typeof initialVersionMap[name] === 'undefined') {
375
440
  initialVersionMap[name] = state.version;
376
441
  }
@@ -379,14 +444,18 @@ export const makeChatsSocket = (config) => {
379
444
  state = newLTHashState();
380
445
  }
381
446
  states[name] = state;
382
- logger.info(`resyncing ${name} from v${state.version}`);
447
+ const shouldForceSnapshot = forceSnapshotCollections.has(name);
448
+ if (shouldForceSnapshot) {
449
+ forceSnapshotCollections.delete(name);
450
+ }
451
+ logger.info(`resyncing ${name} from v${state.version}${shouldForceSnapshot ? ' (forcing snapshot)' : ''}`);
383
452
  nodes.push({
384
453
  tag: 'collection',
385
454
  attrs: {
386
455
  name,
387
456
  version: state.version.toString(),
388
- // return snapshot if being synced from scratch
389
- return_snapshot: (!state.version).toString()
457
+ // return snapshot if syncing from scratch or forcing after a failed attempt
458
+ return_snapshot: (shouldForceSnapshot || !state.version).toString()
390
459
  }
391
460
  });
392
461
  }
@@ -412,7 +481,7 @@ export const makeChatsSocket = (config) => {
412
481
  const { patches, hasMorePatches, snapshot } = decoded[name];
413
482
  try {
414
483
  if (snapshot) {
415
- const { state: newState, mutationMap } = await decodeSyncdSnapshot(name, snapshot, getAppStateSyncKey, initialVersionMap[name], appStateMacVerification.snapshot);
484
+ const { state: newState, mutationMap } = await decodeSyncdSnapshot(name, snapshot, getCachedAppStateSyncKey, initialVersionMap[name], appStateMacVerification.snapshot);
416
485
  states[name] = newState;
417
486
  Object.assign(globalMutationMap, mutationMap);
418
487
  logger.info(`restored state of ${name} from snapshot to v${newState.version} with mutations`);
@@ -420,7 +489,7 @@ export const makeChatsSocket = (config) => {
420
489
  }
421
490
  // only process if there are syncd patches
422
491
  if (patches.length) {
423
- const { state: newState, mutationMap } = await decodePatches(name, patches, states[name], getAppStateSyncKey, config.options, initialVersionMap[name], logger, appStateMacVerification.patch);
492
+ const { state: newState, mutationMap } = await decodePatches(name, patches, states[name], getCachedAppStateSyncKey, config.options, initialVersionMap[name], logger, appStateMacVerification.patch);
424
493
  await authState.keys.set({ 'app-state-sync-version': { [name]: newState } });
425
494
  logger.info(`synced ${name} to v${newState.version}`);
426
495
  initialVersionMap[name] = newState.version;
@@ -435,19 +504,37 @@ export const makeChatsSocket = (config) => {
435
504
  }
436
505
  }
437
506
  catch (error) {
438
- // if retry attempts overshoot
439
- // or key not found
440
- const isIrrecoverableError = attemptsMap[name] >= MAX_SYNC_ATTEMPTS ||
441
- error.output?.statusCode === 404 ||
442
- error.name === 'TypeError';
443
- logger.info({ name, error: error.stack }, `failed to sync state from version${isIrrecoverableError ? '' : ', removing and trying from scratch'}`);
444
- await authState.keys.set({ 'app-state-sync-version': { [name]: null } });
445
- // increment number of retries
446
507
  attemptsMap[name] = (attemptsMap[name] || 0) + 1;
447
- if (isIrrecoverableError) {
448
- // stop retrying
508
+ const logData = {
509
+ name,
510
+ attempt: attemptsMap[name],
511
+ version: states[name].version,
512
+ statusCode: error.output?.statusCode,
513
+ errorType: error.name,
514
+ error: error.stack
515
+ };
516
+ if (isMissingKeyError(error) && attemptsMap[name] >= MAX_SYNC_ATTEMPTS) {
517
+ // WA Web treats missing keys as "Blocked" — park the collection
518
+ // until the key arrives via APP_STATE_SYNC_KEY_SHARE.
519
+ logger.warn(logData, `${name} blocked on missing key from v${states[name].version}, parking after ${attemptsMap[name]} attempts`);
520
+ blockedCollections.add(name);
449
521
  collectionsToHandle.delete(name);
450
522
  }
523
+ else if (isMissingKeyError(error)) {
524
+ // Retry with a snapshot which may use a different key.
525
+ logger.info(logData, `${name} blocked on missing key from v${states[name].version}, retrying with snapshot`);
526
+ forceSnapshotCollections.add(name);
527
+ }
528
+ else if (isAppStateSyncIrrecoverable(error, attemptsMap[name])) {
529
+ logger.warn(logData, `failed to sync ${name} from v${states[name].version}, giving up`);
530
+ collectionsToHandle.delete(name);
531
+ }
532
+ else {
533
+ logger.info(logData, `failed to sync ${name} from v${states[name].version}, forcing snapshot retry`);
534
+ // force a full snapshot on retry to recover from
535
+ // corrupted local state (e.g. LTHash MAC mismatch)
536
+ forceSnapshotCollections.add(name);
537
+ }
451
538
  }
452
539
  }
453
540
  }
@@ -464,7 +551,22 @@ export const makeChatsSocket = (config) => {
464
551
  */
465
552
  const profilePictureUrl = async (jid, type = 'preview', timeoutMs) => {
466
553
  const baseContent = [{ tag: 'picture', attrs: { type, query: 'url' } }];
467
- const tcTokenContent = await buildTcTokenFromJid({ authState, jid, baseContent });
554
+ // WA Web only includes tctoken for user JIDs (not groups/newsletters)
555
+ // and never for own profile pic (Chat model for self has no tcToken).
556
+ // Including tctoken for own JID causes the server to never respond.
557
+ const normalizedJid = jidNormalizedUser(jid);
558
+ const isUserJid = isPnUser(normalizedJid) || isLidUser(normalizedJid);
559
+ const me = authState.creds.me;
560
+ const isSelf = me && (normalizedJid === jidNormalizedUser(me.id) || (me.lid && normalizedJid === jidNormalizedUser(me.lid)));
561
+ let content = baseContent;
562
+ if (serverProps.profilePicPrivacyToken && isUserJid && !isSelf) {
563
+ content = await buildTcTokenFromJid({
564
+ authState,
565
+ jid: normalizedJid,
566
+ baseContent,
567
+ getLIDForPN
568
+ });
569
+ }
468
570
  jid = jidNormalizedUser(jid);
469
571
  const result = await query({
470
572
  tag: 'iq',
@@ -474,7 +576,7 @@ export const makeChatsSocket = (config) => {
474
576
  type: 'get',
475
577
  xmlns: 'w:profile:picture'
476
578
  },
477
- content: tcTokenContent
579
+ content
478
580
  }, timeoutMs);
479
581
  const child = getBinaryNodeChild(result, 'picture');
480
582
  return child?.attrs?.url;
@@ -499,12 +601,16 @@ export const makeChatsSocket = (config) => {
499
601
  };
500
602
  const sendPresenceUpdate = async (type, toJid) => {
501
603
  const me = authState.creds.me;
502
- if (type === 'available' || type === 'unavailable') {
604
+ const isAvailableType = type === 'available';
605
+ if (isAvailableType || type === 'unavailable') {
503
606
  if (!me.name) {
504
607
  logger.warn('no name present, ignoring presence update request...');
505
608
  return;
506
609
  }
507
- ev.emit('connection.update', { isOnline: type === 'available' });
610
+ ev.emit('connection.update', { isOnline: isAvailableType });
611
+ if (isAvailableType) {
612
+ void sendUnifiedSession();
613
+ }
508
614
  await sendNode({
509
615
  tag: 'presence',
510
616
  attrs: {
@@ -536,7 +642,12 @@ export const makeChatsSocket = (config) => {
536
642
  * @param tcToken token for subscription, use if present
537
643
  */
538
644
  const presenceSubscribe = async (toJid) => {
539
- const tcTokenContent = await buildTcTokenFromJid({ authState, jid: toJid });
645
+ // Only include tctoken for user JIDs groups/newsletters don't use tctokens
646
+ const normalizedToJid = jidNormalizedUser(toJid);
647
+ const isUserJid = isPnUser(normalizedToJid) || isLidUser(normalizedToJid);
648
+ const tcTokenContent = isUserJid
649
+ ? await buildTcTokenFromJid({ authState, jid: normalizedToJid, getLIDForPN })
650
+ : undefined;
540
651
  return sendNode({
541
652
  tag: 'presence',
542
653
  attrs: {
@@ -591,7 +702,7 @@ export const makeChatsSocket = (config) => {
591
702
  logger.debug({ patch: patchCreate }, 'applying app patch');
592
703
  await resyncAppState([name], false);
593
704
  const { [name]: currentSyncVersion } = await authState.keys.get('app-state-sync-version', [name]);
594
- initial = currentSyncVersion || newLTHashState();
705
+ initial = currentSyncVersion ? ensureLTHashStateVersion(currentSyncVersion) : newLTHashState();
595
706
  encodeResult = await encodeSyncdPatch(patchCreate, myAppStateKeyId, initial, getAppStateSyncKey);
596
707
  const { patch, state } = encodeResult;
597
708
  const node = {
@@ -637,22 +748,21 @@ export const makeChatsSocket = (config) => {
637
748
  }
638
749
  }
639
750
  };
640
- /** sending non-abt props may fix QR scan fail if server expects */
751
+ /** fetch AB props */
641
752
  const fetchProps = async () => {
642
- //TODO: implement both protocol 1 and protocol 2 prop fetching, specially for abKey for WM
643
753
  const resultNode = await query({
644
754
  tag: 'iq',
645
755
  attrs: {
646
756
  to: S_WHATSAPP_NET,
647
- xmlns: 'w',
757
+ xmlns: 'abt',
648
758
  type: 'get'
649
759
  },
650
760
  content: [
651
761
  {
652
762
  tag: 'props',
653
763
  attrs: {
654
- protocol: '2',
655
- hash: authState?.creds?.lastPropHash || ''
764
+ protocol: '1',
765
+ ...(authState?.creds?.lastPropHash ? { hash: authState.creds.lastPropHash } : {})
656
766
  }
657
767
  }
658
768
  ]
@@ -667,7 +777,20 @@ export const makeChatsSocket = (config) => {
667
777
  }
668
778
  props = reduceBinaryNodeToDictionary(propsNode, 'prop');
669
779
  }
670
- logger.debug('fetched props');
780
+ // Extract protocol-relevant AB props (only the ones we need)
781
+ const privacyTokenProp = props['10518'] ?? props['privacy_token_sending_on_all_1_on_1_messages'];
782
+ if (privacyTokenProp !== undefined) {
783
+ serverProps.privacyTokenOn1to1 = privacyTokenProp === 'true' || privacyTokenProp === '1';
784
+ }
785
+ const profilePicProp = props['9666'] ?? props['profile_scraping_privacy_token_in_photo_iq'];
786
+ if (profilePicProp !== undefined) {
787
+ serverProps.profilePicPrivacyToken = profilePicProp === 'true' || profilePicProp === '1';
788
+ }
789
+ const lidIssueProp = props['14303'] ?? props['lid_trusted_token_issue_to_lid'];
790
+ if (lidIssueProp !== undefined) {
791
+ serverProps.lidTrustedTokenIssueToLid = lidIssueProp === 'true' || lidIssueProp === '1';
792
+ }
793
+ logger.debug({ serverProps }, 'fetched props');
671
794
  return props;
672
795
  };
673
796
  /**
@@ -782,6 +905,13 @@ export const makeChatsSocket = (config) => {
782
905
  quickReply: { timestamp, deleted: true }
783
906
  }, '');
784
907
  };
908
+ /**
909
+ * Clear a message from chat (delete for me)
910
+ */
911
+ const clearMessage = (jid, key, timeStamp) => {
912
+ return chatModify({ delete: true, lastMessages: [{ key, messageTimestamp: timeStamp }] }, jid);
913
+ };
914
+ const deleteChat = clearMessage;
785
915
  /**
786
916
  * queries need to be fired on connection open
787
917
  * help ensure parity with WA Web
@@ -807,6 +937,47 @@ export const makeChatsSocket = (config) => {
807
937
  ? shouldSyncHistoryMessage(historyMsg) &&
808
938
  PROCESSABLE_HISTORY_TYPES.includes(historyMsg.syncType)
809
939
  : false;
940
+ if (historyMsg && shouldProcessHistoryMsg) {
941
+ const syncType = historyMsg.syncType;
942
+ // INITIAL_BOOTSTRAP — fire immediately, no progress check (same as WA Web K function)
943
+ if (syncType === proto.HistorySync.HistorySyncType.INITIAL_BOOTSTRAP &&
944
+ !historySyncStatus.initialBootstrapComplete) {
945
+ historySyncStatus.initialBootstrapComplete = true;
946
+ ev.emit('messaging-history.status', {
947
+ syncType,
948
+ status: 'complete',
949
+ explicit: true
950
+ });
951
+ }
952
+ // RECENT with progress === 100 — explicit completion
953
+ if (syncType === proto.HistorySync.HistorySyncType.RECENT &&
954
+ historyMsg.progress === 100 &&
955
+ !historySyncStatus.recentSyncComplete) {
956
+ historySyncStatus.recentSyncComplete = true;
957
+ clearTimeout(historySyncPausedTimeout);
958
+ historySyncPausedTimeout = undefined;
959
+ ev.emit('messaging-history.status', {
960
+ syncType,
961
+ status: 'complete',
962
+ explicit: true
963
+ });
964
+ }
965
+ // Reset 120s paused timeout on any RECENT chunk (like WA Web's handleChunkProgress)
966
+ if (syncType === proto.HistorySync.HistorySyncType.RECENT && !historySyncStatus.recentSyncComplete) {
967
+ clearTimeout(historySyncPausedTimeout);
968
+ historySyncPausedTimeout = setTimeout(() => {
969
+ if (!historySyncStatus.recentSyncComplete) {
970
+ historySyncStatus.recentSyncComplete = true;
971
+ ev.emit('messaging-history.status', {
972
+ syncType: proto.HistorySync.HistorySyncType.RECENT,
973
+ status: 'paused',
974
+ explicit: false
975
+ });
976
+ }
977
+ historySyncPausedTimeout = undefined;
978
+ }, HISTORY_SYNC_PAUSED_TIMEOUT_MS);
979
+ }
980
+ }
810
981
  // State machine: decide on sync and flush
811
982
  if (historyMsg && syncState === SyncState.AwaitingInitialSync) {
812
983
  if (awaitingSyncTimeout) {
@@ -826,6 +997,8 @@ export const makeChatsSocket = (config) => {
826
997
  }
827
998
  const doAppStateSync = async () => {
828
999
  if (syncState === SyncState.Syncing) {
1000
+ // All collections will be synced, so clear any blocked ones
1001
+ blockedCollections.clear();
829
1002
  logger.info('Doing app state sync');
830
1003
  await resyncAppState(ALL_WA_PATCH_NAMES, true);
831
1004
  // Sync is complete, go online and flush everything
@@ -885,6 +1058,11 @@ export const makeChatsSocket = (config) => {
885
1058
  }
886
1059
  });
887
1060
  ev.on('connection.update', ({ connection, receivedPendingNotifications }) => {
1061
+ if (connection === 'close') {
1062
+ blockedCollections.clear();
1063
+ clearTimeout(historySyncPausedTimeout);
1064
+ historySyncPausedTimeout = undefined;
1065
+ }
888
1066
  if (connection === 'open') {
889
1067
  if (fireInitQueries) {
890
1068
  executeInitQueries().catch(error => onUnexpectedError(error, 'init queries'));
@@ -894,6 +1072,10 @@ export const makeChatsSocket = (config) => {
894
1072
  if (!receivedPendingNotifications || syncState !== SyncState.Connecting) {
895
1073
  return;
896
1074
  }
1075
+ historySyncStatus.initialBootstrapComplete = false;
1076
+ historySyncStatus.recentSyncComplete = false;
1077
+ clearTimeout(historySyncPausedTimeout);
1078
+ historySyncPausedTimeout = undefined;
897
1079
  syncState = SyncState.AwaitingInitialSync;
898
1080
  logger.info('Connection is now AwaitingInitialSync, buffering events');
899
1081
  ev.buffer();
@@ -906,19 +1088,49 @@ export const makeChatsSocket = (config) => {
906
1088
  setTimeout(() => ev.flush(), 0);
907
1089
  return;
908
1090
  }
909
- logger.info('History sync is enabled, awaiting notification with a 20s timeout.');
1091
+ // On reconnection (accountSyncCounter > 0), the server does not push
1092
+ // history sync notifications — the device already has its data.
1093
+ // Skip the 20s wait and go online immediately.
1094
+ if (authState.creds.accountSyncCounter > 0) {
1095
+ logger.info('Reconnection with existing sync data, skipping history sync wait. Transitioning to Online.');
1096
+ syncState = SyncState.Online;
1097
+ setTimeout(() => ev.flush(), 0);
1098
+ return;
1099
+ }
1100
+ logger.info('First connection, awaiting history sync notification with a 20s timeout.');
910
1101
  if (awaitingSyncTimeout) {
911
1102
  clearTimeout(awaitingSyncTimeout);
912
1103
  }
913
1104
  awaitingSyncTimeout = setTimeout(() => {
914
1105
  if (syncState === SyncState.AwaitingInitialSync) {
915
- // TODO: investigate
916
1106
  logger.warn('Timeout in AwaitingInitialSync, forcing state to Online and flushing buffer');
917
1107
  syncState = SyncState.Online;
918
1108
  ev.flush();
1109
+ // Increment so subsequent reconnections skip the 20s wait.
1110
+ // Late-arriving history is still processed via processMessage
1111
+ // regardless of the state machine phase.
1112
+ const accountSyncCounter = (authState.creds.accountSyncCounter || 0) + 1;
1113
+ ev.emit('creds.update', { accountSyncCounter });
919
1114
  }
920
1115
  }, 20000);
921
1116
  });
1117
+ // When an app state sync key arrives (myAppStateKeyId is set) and there are
1118
+ // collections blocked on a missing key, trigger a re-sync for just those collections.
1119
+ // This mirrors WA Web's Blocked → retry-on-key-arrival behavior.
1120
+ ev.on('creds.update', ({ myAppStateKeyId }) => {
1121
+ if (!myAppStateKeyId || blockedCollections.size === 0) {
1122
+ return;
1123
+ }
1124
+ // If we're in the middle of a full sync, doAppStateSync handles all collections
1125
+ if (syncState === SyncState.Syncing) {
1126
+ blockedCollections.clear();
1127
+ return;
1128
+ }
1129
+ const collections = [...blockedCollections];
1130
+ blockedCollections.clear();
1131
+ logger.info({ collections }, 'app state sync key arrived, re-syncing blocked collections');
1132
+ resyncAppState(collections, false).catch(error => onUnexpectedError(error, 'blocked collections resync'));
1133
+ });
922
1134
  ev.on('lid-mapping.update', async ({ lid, pn }) => {
923
1135
  try {
924
1136
  await signalRepository.lidMapping.storeLIDPNMappings([{ lid, pn }]);
@@ -929,6 +1141,7 @@ export const makeChatsSocket = (config) => {
929
1141
  });
930
1142
  return {
931
1143
  ...sock,
1144
+ serverProps,
932
1145
  createCallLink,
933
1146
  getBotListV2,
934
1147
  messageMutex,
@@ -962,6 +1175,8 @@ export const makeChatsSocket = (config) => {
962
1175
  getBusinessProfile,
963
1176
  resyncAppState,
964
1177
  chatModify,
1178
+ clearMessage,
1179
+ deleteChat,
965
1180
  cleanDirtyBits,
966
1181
  addOrEditContact,
967
1182
  removeContact,