@fer2809fl/baileys 7.0.1 → 7.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (350) hide show
  1. package/README.md +322 -578
  2. package/WAProto/WAProto.proto +916 -360
  3. package/WAProto/fix-imports.js +18 -22
  4. package/WAProto/index.d.ts +15471 -8638
  5. package/WAProto/index.js +80576 -45941
  6. package/lib/Defaults/index.d.ts +14 -18
  7. package/lib/Defaults/index.js +111 -115
  8. package/lib/Signal/libsignal.js +22 -31
  9. package/lib/Signal/lid-mapping.d.ts +0 -4
  10. package/lib/Signal/lid-mapping.js +0 -6
  11. package/lib/Socket/business.d.ts +8 -75
  12. package/lib/Socket/business.js +1 -0
  13. package/lib/Socket/chats.d.ts +0 -6
  14. package/lib/Socket/chats.js +3 -67
  15. package/lib/Socket/communities.d.ts +641 -336
  16. package/lib/Socket/communities.js +3 -6
  17. package/lib/Socket/dugong.d.ts +130 -0
  18. package/lib/Socket/dugong.js +772 -0
  19. package/lib/Socket/groups.d.ts +18 -23
  20. package/lib/Socket/groups.js +88 -168
  21. package/lib/Socket/index.d.ts +631 -322
  22. package/lib/Socket/index.js +12 -9
  23. package/lib/Socket/messages-recv.d.ts +52 -84
  24. package/lib/Socket/messages-recv.js +193 -677
  25. package/lib/Socket/messages-send.d.ts +643 -262
  26. package/lib/Socket/messages-send.js +1559 -1359
  27. package/lib/Socket/mex.d.ts +0 -1
  28. package/lib/Socket/mex.js +8 -22
  29. package/lib/Socket/native-buttons.js +231 -0
  30. package/lib/Socket/newsletter.d.ts +27 -42
  31. package/lib/Socket/newsletter.js +439 -402
  32. package/lib/Socket/socket.d.ts +2 -6
  33. package/lib/Socket/socket.js +47 -39
  34. package/lib/Types/Auth.d.ts +0 -1
  35. package/lib/Types/Bussines.d.ts +34 -22
  36. package/lib/Types/Call.d.ts +1 -1
  37. package/lib/Types/Chat.d.ts +0 -1
  38. package/lib/Types/Contact.d.ts +0 -2
  39. package/lib/Types/Events.d.ts +1 -20
  40. package/lib/Types/GroupMetadata.d.ts +1 -4
  41. package/lib/Types/Message.d.ts +348 -354
  42. package/lib/Types/Message.js +0 -4
  43. package/lib/Types/{Mex.d.ts → Newsletter.d.ts} +7 -17
  44. package/lib/Types/{Mex.js → Newsletter.js} +5 -3
  45. package/lib/Types/Signal.d.ts +1 -12
  46. package/lib/Types/Socket.d.ts +148 -135
  47. package/lib/Types/State.d.ts +0 -65
  48. package/lib/Types/State.js +0 -43
  49. package/lib/Types/index.d.ts +52 -52
  50. package/lib/Types/index.js +30 -23
  51. package/lib/Utils/auth-utils.d.ts +0 -5
  52. package/lib/Utils/auth-utils.js +0 -12
  53. package/lib/Utils/browser-utils.js +0 -1
  54. package/lib/Utils/crypto.d.ts +12 -12
  55. package/lib/Utils/decode-wa-message.d.ts +0 -18
  56. package/lib/Utils/decode-wa-message.js +0 -34
  57. package/lib/Utils/event-buffer.d.ts +0 -2
  58. package/lib/Utils/generics.d.ts +2 -3
  59. package/lib/Utils/generics.js +1 -10
  60. package/lib/Utils/history.d.ts +0 -2
  61. package/lib/Utils/history.js +9 -12
  62. package/lib/Utils/identity-change-handler.d.ts +0 -7
  63. package/lib/Utils/identity-change-handler.js +0 -1
  64. package/lib/Utils/index.d.ts +23 -30
  65. package/lib/Utils/index.js +3 -9
  66. package/lib/Utils/link-preview.js +2 -2
  67. package/lib/Utils/message-retry-manager.d.ts +0 -5
  68. package/lib/Utils/message-retry-manager.js +11 -11
  69. package/lib/Utils/messages-media.d.ts +13 -45
  70. package/lib/Utils/messages-media.js +98 -293
  71. package/lib/Utils/messages.d.ts +3 -16
  72. package/lib/Utils/messages.js +1123 -1219
  73. package/lib/Utils/noise-handler.d.ts +1 -1
  74. package/lib/Utils/process-message.js +1 -103
  75. package/lib/Utils/rich-messages.d.ts +277 -0
  76. package/lib/Utils/rich-messages.js +1144 -0
  77. package/lib/Utils/signal.d.ts +0 -13
  78. package/lib/Utils/signal.js +0 -42
  79. package/lib/Utils/sticker-pack.d.ts +10 -0
  80. package/lib/Utils/sticker-pack.js +111 -0
  81. package/lib/Utils/sync-action-utils.js +0 -1
  82. package/lib/Utils/tc-token-utils.d.ts +1 -26
  83. package/lib/Utils/tc-token-utils.js +5 -151
  84. package/lib/Utils/validate-connection.d.ts +0 -1
  85. package/lib/Utils/validate-connection.js +3 -13
  86. package/lib/WABinary/decode.d.ts +1 -1
  87. package/lib/WABinary/generic-utils.d.ts +3 -1
  88. package/lib/WABinary/generic-utils.js +78 -0
  89. package/lib/WABinary/jid-utils.d.ts +0 -11
  90. package/lib/WABinary/jid-utils.js +0 -33
  91. package/lib/WAM/encode.d.ts +1 -1
  92. package/lib/WAUSync/Protocols/USyncContactProtocol.js +3 -26
  93. package/lib/WAUSync/Protocols/index.d.ts +0 -1
  94. package/lib/WAUSync/USyncQuery.d.ts +0 -1
  95. package/lib/WAUSync/USyncQuery.js +1 -1
  96. package/lib/WAUSync/USyncUser.d.ts +0 -4
  97. package/lib/WAUSync/USyncUser.js +0 -8
  98. package/lib/index.d.ts +1 -1
  99. package/lib/index.js +1 -4
  100. package/package.json +27 -31
  101. package/LICENSE +0 -21
  102. package/engine-requirements.js +0 -10
  103. package/lib/Defaults/index.d.ts.map +0 -1
  104. package/lib/Defaults/index.js.map +0 -1
  105. package/lib/Signal/Group/ciphertext-message.d.ts.map +0 -1
  106. package/lib/Signal/Group/ciphertext-message.js.map +0 -1
  107. package/lib/Signal/Group/group-session-builder.d.ts.map +0 -1
  108. package/lib/Signal/Group/group-session-builder.js.map +0 -1
  109. package/lib/Signal/Group/group_cipher.d.ts.map +0 -1
  110. package/lib/Signal/Group/group_cipher.js.map +0 -1
  111. package/lib/Signal/Group/index.d.ts.map +0 -1
  112. package/lib/Signal/Group/index.js.map +0 -1
  113. package/lib/Signal/Group/keyhelper.d.ts.map +0 -1
  114. package/lib/Signal/Group/keyhelper.js.map +0 -1
  115. package/lib/Signal/Group/sender-chain-key.d.ts.map +0 -1
  116. package/lib/Signal/Group/sender-chain-key.js.map +0 -1
  117. package/lib/Signal/Group/sender-key-distribution-message.d.ts.map +0 -1
  118. package/lib/Signal/Group/sender-key-distribution-message.js.map +0 -1
  119. package/lib/Signal/Group/sender-key-message.d.ts.map +0 -1
  120. package/lib/Signal/Group/sender-key-message.js.map +0 -1
  121. package/lib/Signal/Group/sender-key-name.d.ts.map +0 -1
  122. package/lib/Signal/Group/sender-key-name.js.map +0 -1
  123. package/lib/Signal/Group/sender-key-record.d.ts.map +0 -1
  124. package/lib/Signal/Group/sender-key-record.js.map +0 -1
  125. package/lib/Signal/Group/sender-key-state.d.ts.map +0 -1
  126. package/lib/Signal/Group/sender-key-state.js.map +0 -1
  127. package/lib/Signal/Group/sender-message-key.d.ts.map +0 -1
  128. package/lib/Signal/Group/sender-message-key.js.map +0 -1
  129. package/lib/Signal/libsignal.d.ts.map +0 -1
  130. package/lib/Signal/libsignal.js.map +0 -1
  131. package/lib/Signal/lid-mapping.d.ts.map +0 -1
  132. package/lib/Signal/lid-mapping.js.map +0 -1
  133. package/lib/Socket/Client/index.d.ts.map +0 -1
  134. package/lib/Socket/Client/index.js.map +0 -1
  135. package/lib/Socket/Client/types.d.ts.map +0 -1
  136. package/lib/Socket/Client/types.js.map +0 -1
  137. package/lib/Socket/Client/websocket.d.ts.map +0 -1
  138. package/lib/Socket/Client/websocket.js.map +0 -1
  139. package/lib/Socket/business.d.ts.map +0 -1
  140. package/lib/Socket/business.js.map +0 -1
  141. package/lib/Socket/chats.d.ts.map +0 -1
  142. package/lib/Socket/chats.js.map +0 -1
  143. package/lib/Socket/communities.d.ts.map +0 -1
  144. package/lib/Socket/communities.js.map +0 -1
  145. package/lib/Socket/groups.d.ts.map +0 -1
  146. package/lib/Socket/groups.js.map +0 -1
  147. package/lib/Socket/index.d.ts.map +0 -1
  148. package/lib/Socket/index.js.map +0 -1
  149. package/lib/Socket/messages-recv.d.ts.map +0 -1
  150. package/lib/Socket/messages-recv.js.map +0 -1
  151. package/lib/Socket/messages-send.d.ts.map +0 -1
  152. package/lib/Socket/messages-send.js.map +0 -1
  153. package/lib/Socket/mex.d.ts.map +0 -1
  154. package/lib/Socket/mex.js.map +0 -1
  155. package/lib/Socket/newsletter.d.ts.map +0 -1
  156. package/lib/Socket/newsletter.js.map +0 -1
  157. package/lib/Socket/smgss.d.ts +0 -119
  158. package/lib/Socket/smgss.d.ts.map +0 -1
  159. package/lib/Socket/smgss.js +0 -453
  160. package/lib/Socket/smgss.js.map +0 -1
  161. package/lib/Socket/socket.d.ts.map +0 -1
  162. package/lib/Socket/socket.js.map +0 -1
  163. package/lib/Store/index.d.ts +0 -4
  164. package/lib/Store/index.d.ts.map +0 -1
  165. package/lib/Store/index.js +0 -4
  166. package/lib/Store/index.js.map +0 -1
  167. package/lib/Store/make-in-memory-store.d.ts +0 -132
  168. package/lib/Store/make-in-memory-store.d.ts.map +0 -1
  169. package/lib/Store/make-in-memory-store.js +0 -450
  170. package/lib/Store/make-in-memory-store.js.map +0 -1
  171. package/lib/Store/make-ordered-dictionary.d.ts +0 -14
  172. package/lib/Store/make-ordered-dictionary.d.ts.map +0 -1
  173. package/lib/Store/make-ordered-dictionary.js +0 -80
  174. package/lib/Store/make-ordered-dictionary.js.map +0 -1
  175. package/lib/Store/object-repository.d.ts +0 -13
  176. package/lib/Store/object-repository.d.ts.map +0 -1
  177. package/lib/Store/object-repository.js +0 -24
  178. package/lib/Store/object-repository.js.map +0 -1
  179. package/lib/Types/Auth.d.ts.map +0 -1
  180. package/lib/Types/Auth.js.map +0 -1
  181. package/lib/Types/Bussines.d.ts.map +0 -1
  182. package/lib/Types/Bussines.js.map +0 -1
  183. package/lib/Types/Call.d.ts.map +0 -1
  184. package/lib/Types/Call.js.map +0 -1
  185. package/lib/Types/Chat.d.ts.map +0 -1
  186. package/lib/Types/Chat.js.map +0 -1
  187. package/lib/Types/Contact.d.ts.map +0 -1
  188. package/lib/Types/Contact.js.map +0 -1
  189. package/lib/Types/Events.d.ts.map +0 -1
  190. package/lib/Types/Events.js.map +0 -1
  191. package/lib/Types/GroupMetadata.d.ts.map +0 -1
  192. package/lib/Types/GroupMetadata.js.map +0 -1
  193. package/lib/Types/Label.d.ts.map +0 -1
  194. package/lib/Types/Label.js.map +0 -1
  195. package/lib/Types/LabelAssociation.d.ts.map +0 -1
  196. package/lib/Types/LabelAssociation.js.map +0 -1
  197. package/lib/Types/Message.d.ts.map +0 -1
  198. package/lib/Types/Message.js.map +0 -1
  199. package/lib/Types/Mex.d.ts.map +0 -1
  200. package/lib/Types/Mex.js.map +0 -1
  201. package/lib/Types/Product.d.ts.map +0 -1
  202. package/lib/Types/Product.js.map +0 -1
  203. package/lib/Types/Signal.d.ts.map +0 -1
  204. package/lib/Types/Signal.js.map +0 -1
  205. package/lib/Types/Socket.d.ts.map +0 -1
  206. package/lib/Types/Socket.js.map +0 -1
  207. package/lib/Types/State.d.ts.map +0 -1
  208. package/lib/Types/State.js.map +0 -1
  209. package/lib/Types/USync.d.ts.map +0 -1
  210. package/lib/Types/USync.js.map +0 -1
  211. package/lib/Types/index.d.ts.map +0 -1
  212. package/lib/Types/index.js.map +0 -1
  213. package/lib/Utils/auth-utils.d.ts.map +0 -1
  214. package/lib/Utils/auth-utils.js.map +0 -1
  215. package/lib/Utils/browser-utils.d.ts.map +0 -1
  216. package/lib/Utils/browser-utils.js.map +0 -1
  217. package/lib/Utils/business.d.ts.map +0 -1
  218. package/lib/Utils/business.js.map +0 -1
  219. package/lib/Utils/button-handler.d.ts +0 -28
  220. package/lib/Utils/button-handler.d.ts.map +0 -1
  221. package/lib/Utils/button-handler.js +0 -140
  222. package/lib/Utils/button-handler.js.map +0 -1
  223. package/lib/Utils/chat-utils.d.ts.map +0 -1
  224. package/lib/Utils/chat-utils.js.map +0 -1
  225. package/lib/Utils/companion-reg-client-utils.d.ts.map +0 -1
  226. package/lib/Utils/companion-reg-client-utils.js.map +0 -1
  227. package/lib/Utils/crypto.d.ts.map +0 -1
  228. package/lib/Utils/crypto.js.map +0 -1
  229. package/lib/Utils/decode-wa-message.d.ts.map +0 -1
  230. package/lib/Utils/decode-wa-message.js.map +0 -1
  231. package/lib/Utils/event-buffer.d.ts.map +0 -1
  232. package/lib/Utils/event-buffer.js.map +0 -1
  233. package/lib/Utils/generics.d.ts.map +0 -1
  234. package/lib/Utils/generics.js.map +0 -1
  235. package/lib/Utils/history.d.ts.map +0 -1
  236. package/lib/Utils/history.js.map +0 -1
  237. package/lib/Utils/identity-change-handler.d.ts.map +0 -1
  238. package/lib/Utils/identity-change-handler.js.map +0 -1
  239. package/lib/Utils/index.d.ts.map +0 -1
  240. package/lib/Utils/index.js.map +0 -1
  241. package/lib/Utils/interactive.d.ts +0 -60
  242. package/lib/Utils/interactive.d.ts.map +0 -1
  243. package/lib/Utils/interactive.js +0 -224
  244. package/lib/Utils/interactive.js.map +0 -1
  245. package/lib/Utils/link-preview.d.ts.map +0 -1
  246. package/lib/Utils/link-preview.js.map +0 -1
  247. package/lib/Utils/logger.d.ts.map +0 -1
  248. package/lib/Utils/logger.js.map +0 -1
  249. package/lib/Utils/lt-hash.d.ts.map +0 -1
  250. package/lib/Utils/lt-hash.js.map +0 -1
  251. package/lib/Utils/make-mutex.d.ts.map +0 -1
  252. package/lib/Utils/make-mutex.js.map +0 -1
  253. package/lib/Utils/message-composer.d.ts +0 -93
  254. package/lib/Utils/message-composer.d.ts.map +0 -1
  255. package/lib/Utils/message-composer.js +0 -311
  256. package/lib/Utils/message-composer.js.map +0 -1
  257. package/lib/Utils/message-retry-manager.d.ts.map +0 -1
  258. package/lib/Utils/message-retry-manager.js.map +0 -1
  259. package/lib/Utils/messages-media.d.ts.map +0 -1
  260. package/lib/Utils/messages-media.js.map +0 -1
  261. package/lib/Utils/messages-newsletter.d.ts +0 -74
  262. package/lib/Utils/messages-newsletter.d.ts.map +0 -1
  263. package/lib/Utils/messages-newsletter.js +0 -128
  264. package/lib/Utils/messages-newsletter.js.map +0 -1
  265. package/lib/Utils/messages.d.ts.map +0 -1
  266. package/lib/Utils/messages.js.map +0 -1
  267. package/lib/Utils/noise-handler.d.ts.map +0 -1
  268. package/lib/Utils/noise-handler.js.map +0 -1
  269. package/lib/Utils/offline-node-processor.d.ts.map +0 -1
  270. package/lib/Utils/offline-node-processor.js.map +0 -1
  271. package/lib/Utils/pre-key-manager.d.ts.map +0 -1
  272. package/lib/Utils/pre-key-manager.js.map +0 -1
  273. package/lib/Utils/process-message.d.ts.map +0 -1
  274. package/lib/Utils/process-message.js.map +0 -1
  275. package/lib/Utils/reporting-utils.d.ts.map +0 -1
  276. package/lib/Utils/reporting-utils.js.map +0 -1
  277. package/lib/Utils/shortcake-crypto.d.ts +0 -36
  278. package/lib/Utils/shortcake-crypto.d.ts.map +0 -1
  279. package/lib/Utils/shortcake-crypto.js +0 -71
  280. package/lib/Utils/shortcake-crypto.js.map +0 -1
  281. package/lib/Utils/shortcake.d.ts +0 -36
  282. package/lib/Utils/shortcake.d.ts.map +0 -1
  283. package/lib/Utils/shortcake.js +0 -162
  284. package/lib/Utils/shortcake.js.map +0 -1
  285. package/lib/Utils/signal.d.ts.map +0 -1
  286. package/lib/Utils/signal.js.map +0 -1
  287. package/lib/Utils/stanza-ack.d.ts.map +0 -1
  288. package/lib/Utils/stanza-ack.js.map +0 -1
  289. package/lib/Utils/sync-action-utils.d.ts.map +0 -1
  290. package/lib/Utils/sync-action-utils.js.map +0 -1
  291. package/lib/Utils/tc-token-utils.d.ts.map +0 -1
  292. package/lib/Utils/tc-token-utils.js.map +0 -1
  293. package/lib/Utils/use-multi-file-auth-state.d.ts.map +0 -1
  294. package/lib/Utils/use-multi-file-auth-state.js.map +0 -1
  295. package/lib/Utils/use-single-file-auth-state.d.ts +0 -6
  296. package/lib/Utils/use-single-file-auth-state.d.ts.map +0 -1
  297. package/lib/Utils/use-single-file-auth-state.js +0 -111
  298. package/lib/Utils/use-single-file-auth-state.js.map +0 -1
  299. package/lib/Utils/use-sqlite-auth-state.d.ts +0 -14
  300. package/lib/Utils/use-sqlite-auth-state.d.ts.map +0 -1
  301. package/lib/Utils/use-sqlite-auth-state.js +0 -107
  302. package/lib/Utils/use-sqlite-auth-state.js.map +0 -1
  303. package/lib/Utils/validate-connection.d.ts.map +0 -1
  304. package/lib/Utils/validate-connection.js.map +0 -1
  305. package/lib/WABinary/constants.d.ts.map +0 -1
  306. package/lib/WABinary/constants.js.map +0 -1
  307. package/lib/WABinary/decode.d.ts.map +0 -1
  308. package/lib/WABinary/decode.js.map +0 -1
  309. package/lib/WABinary/encode.d.ts.map +0 -1
  310. package/lib/WABinary/encode.js.map +0 -1
  311. package/lib/WABinary/generic-utils.d.ts.map +0 -1
  312. package/lib/WABinary/generic-utils.js.map +0 -1
  313. package/lib/WABinary/index.d.ts.map +0 -1
  314. package/lib/WABinary/index.js.map +0 -1
  315. package/lib/WABinary/jid-utils.d.ts.map +0 -1
  316. package/lib/WABinary/jid-utils.js.map +0 -1
  317. package/lib/WABinary/types.d.ts.map +0 -1
  318. package/lib/WABinary/types.js.map +0 -1
  319. package/lib/WAM/BinaryInfo.d.ts.map +0 -1
  320. package/lib/WAM/BinaryInfo.js.map +0 -1
  321. package/lib/WAM/constants.d.ts.map +0 -1
  322. package/lib/WAM/constants.js.map +0 -1
  323. package/lib/WAM/encode.d.ts.map +0 -1
  324. package/lib/WAM/encode.js.map +0 -1
  325. package/lib/WAM/index.d.ts.map +0 -1
  326. package/lib/WAM/index.js.map +0 -1
  327. package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts.map +0 -1
  328. package/lib/WAUSync/Protocols/USyncContactProtocol.js.map +0 -1
  329. package/lib/WAUSync/Protocols/USyncDeviceProtocol.d.ts.map +0 -1
  330. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js.map +0 -1
  331. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts.map +0 -1
  332. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js.map +0 -1
  333. package/lib/WAUSync/Protocols/USyncStatusProtocol.d.ts.map +0 -1
  334. package/lib/WAUSync/Protocols/USyncStatusProtocol.js.map +0 -1
  335. package/lib/WAUSync/Protocols/USyncUsernameProtocol.d.ts.map +0 -1
  336. package/lib/WAUSync/Protocols/USyncUsernameProtocol.js.map +0 -1
  337. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.d.ts.map +0 -1
  338. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js.map +0 -1
  339. package/lib/WAUSync/Protocols/UsyncLIDProtocol.d.ts.map +0 -1
  340. package/lib/WAUSync/Protocols/UsyncLIDProtocol.js.map +0 -1
  341. package/lib/WAUSync/Protocols/index.d.ts.map +0 -1
  342. package/lib/WAUSync/Protocols/index.js.map +0 -1
  343. package/lib/WAUSync/USyncQuery.d.ts.map +0 -1
  344. package/lib/WAUSync/USyncQuery.js.map +0 -1
  345. package/lib/WAUSync/USyncUser.d.ts.map +0 -1
  346. package/lib/WAUSync/USyncUser.js.map +0 -1
  347. package/lib/WAUSync/index.d.ts.map +0 -1
  348. package/lib/WAUSync/index.js.map +0 -1
  349. package/lib/index.d.ts.map +0 -1
  350. package/lib/index.js.map +0 -1
@@ -4,56 +4,18 @@ import { randomBytes } from 'crypto';
4
4
  import Long from 'long';
5
5
  import { proto } from '../../WAProto/index.js';
6
6
  import { DEFAULT_CACHE_TTLS, KEY_BUNDLE_TYPE, MIN_PREKEY_COUNT, PLACEHOLDER_MAX_AGE_SECONDS, STATUS_EXPIRY_SECONDS } from '../Defaults/index.js';
7
- import { ReachoutTimelockEnforcementType, WAMessageStatus, WAMessageStubType } from '../Types/index.js';
8
- import { ACCOUNT_RESTRICTED_TEXT, aesDecryptCTR, aesEncryptGCM, cleanMessage, Curve, decodeMediaRetryNode, decodeMessageNode, decryptMessageNode, delay, derivePairingCodeKey, encodeBigEndian, encodeSignedDeviceIdentity, extractAddressingContext, extractE2ESessionFromRetryReceipt, getCallStatusFromNode, getHistoryMsg, getNextPreKeys, getPlatformType, getStatusFromReceiptType, handleIdentityChange, hkdf, makeShortcakeFlow, MISSING_KEYS_ERROR_TEXT, NACK_REASONS, NO_MESSAGE_FOUND_ERROR_TEXT, SERVER_ERROR_CODES, toNumber, unixTimestampSeconds, xmppPreKey, xmppSignedPreKey } from '../Utils/index.js';
7
+ import { WAMessageStatus, WAMessageStubType } from '../Types/index.js';
8
+ import { aesDecryptCTR, aesEncryptGCM, cleanMessage, Curve, decodeMediaRetryNode, decodeMessageNode, decryptMessageNode, delay, derivePairingCodeKey, encodeBigEndian, encodeSignedDeviceIdentity, extractAddressingContext, getCallStatusFromNode, getHistoryMsg, getNextPreKeys, getStatusFromReceiptType, handleIdentityChange, hkdf, MISSING_KEYS_ERROR_TEXT, NACK_REASONS, NO_MESSAGE_FOUND_ERROR_TEXT, toNumber, unixTimestampSeconds, xmppPreKey, xmppSignedPreKey } from '../Utils/index.js';
9
9
  import { makeMutex } from '../Utils/make-mutex.js';
10
10
  import { makeOfflineNodeProcessor } from '../Utils/offline-node-processor.js';
11
11
  import { buildAckStanza } from '../Utils/stanza-ack.js';
12
- import { buildMergedTcTokenIndexWrite, isTcTokenExpired, readTcTokenIndex, resolveIssuanceJid, resolveTcTokenJid, storeTcTokensFromIqResult, TC_TOKEN_INDEX_KEY } from '../Utils/tc-token-utils.js';
13
- import { areJidsSameUser, binaryNodeToString, getAllBinaryNodeChildren, getBinaryNodeChild, getBinaryNodeChildBuffer, getBinaryNodeChildren, getBinaryNodeChildString, getBinaryNodeChildUInt, isJidGroup, isJidNewsletter, isJidStatusBroadcast, isLidUser, isPnUser, jidDecode, jidNormalizedUser, S_WHATSAPP_NET } from '../WABinary/index.js';
12
+ import { areJidsSameUser, binaryNodeToString, getAllBinaryNodeChildren, getBinaryNodeChild, getBinaryNodeChildBuffer, getBinaryNodeChildren, getBinaryNodeChildString, isJidGroup, isJidNewsletter, isJidStatusBroadcast, isLidUser, isPnUser, jidDecode, jidNormalizedUser, S_WHATSAPP_NET } from '../WABinary/index.js';
14
13
  import { extractGroupMetadata } from './groups.js';
15
14
  import { makeMessagesSocket } from './messages-send.js';
16
- const ENFORCEMENT_TYPE_VALUES = new Set(Object.values(ReachoutTimelockEnforcementType));
17
- function isValidEnforcementType(value) {
18
- return typeof value === 'string' && ENFORCEMENT_TYPE_VALUES.has(value);
19
- }
20
15
  export const makeMessagesRecvSocket = (config) => {
21
16
  const { logger, retryRequestDelayMs, maxMsgRetryCount, getMessage, shouldIgnoreJid, enableAutoSessionRecreation } = config;
22
17
  const sock = makeMessagesSocket(config);
23
- const { userDevicesCache, devicesMutex, ev, authState, ws, messageMutex, notificationMutex, receiptMutex, signalRepository, query, upsertMessage, resyncAppState, onUnexpectedError, assertSessions, sendNode, relayMessage, sendReceipt, uploadPreKeys, sendPeerDataOperationMessage, messageRetryManager, registerSocketEndHandler, issuePrivacyTokens, fetchAccountReachoutTimelock, placeholderResendCache } = sock;
24
- const getLIDForPN = signalRepository.lidMapping.getLIDForPN.bind(signalRepository.lidMapping);
25
- /** Shortcake passkey-linking flow, only when a `signPasskeyAssertion` is configured. */
26
- const shortcakeFlow = config.signPasskeyAssertion
27
- ? makeShortcakeFlow({
28
- logger,
29
- query,
30
- signAssertion: config.signPasskeyAssertion,
31
- getCreds: () => authState.creds,
32
- updateCreds: patch => ev.emit('creds.update', patch),
33
- deviceType: getPlatformType(config.browser[1]),
34
- emitVerificationCode: code => logger.debug({ code }, 'shortcake verification code')
35
- })
36
- : null;
37
- registerSocketEndHandler(() => shortcakeFlow?.clearSession());
38
- /** Serializes prologue -> continuation off the notification mutex, so the ack isn't blocked by the handshake. */
39
- const shortcakeMutex = makeMutex();
40
- /** Runs the forced-passkey handshake (detached); with no signer, surfaces `passkeyRequired` and warns. */
41
- const handleShortcakeNotification = (node) => {
42
- if (node.attrs.type === 'passkey_prologue_request') {
43
- ev.emit('connection.update', { passkeyRequired: { hasSigner: !!shortcakeFlow } });
44
- }
45
- if (!shortcakeFlow) {
46
- if (node.attrs.type === 'passkey_prologue_request') {
47
- logger.warn({ id: node.attrs.id }, 'server requested passkey prologue but no signPasskeyAssertion configured');
48
- }
49
- return;
50
- }
51
- // run detached + serialized: the notification is acked immediately, and the
52
- // handshake (external signer + follow-up IQs) never blocks other notifications
53
- shortcakeMutex
54
- .mutex(() => shortcakeFlow.handleIncomingNotification(node))
55
- .catch(err => logger.error({ err, id: node.attrs.id }, 'shortcake handshake failed'));
56
- };
18
+ const { ev, authState, ws, messageMutex, notificationMutex, receiptMutex, signalRepository, query, upsertMessage, resyncAppState, onUnexpectedError, assertSessions, sendNode, relayMessage, sendReceipt, uploadPreKeys, sendPeerDataOperationMessage, messageRetryManager } = sock;
57
19
  /** this mutex ensures that each retryRequest will wait for the previous one to finish */
58
20
  const retryMutex = makeMutex();
59
21
  const msgRetryCache = config.msgRetryCounterCache ||
@@ -66,6 +28,11 @@ export const makeMessagesRecvSocket = (config) => {
66
28
  stdTTL: DEFAULT_CACHE_TTLS.CALL_OFFER, // 5 mins
67
29
  useClones: false
68
30
  });
31
+ const placeholderResendCache = config.placeholderResendCache ||
32
+ new NodeCache({
33
+ stdTTL: DEFAULT_CACHE_TTLS.MSG_RETRY, // 1 hour
34
+ useClones: false
35
+ });
69
36
  // Debounce identity-change session refreshes per JID to avoid bursts
70
37
  const identityAssertDebounce = new NodeCache({ stdTTL: 5, useClones: false });
71
38
  let sendActiveReceipts = false;
@@ -119,140 +86,25 @@ export const makeMessagesRecvSocket = (config) => {
119
86
  }, 8000);
120
87
  return sendPeerDataOperationMessage(pdoMessage);
121
88
  };
122
- const handleMexNotification = async (node) => {
123
- const updateNode = getBinaryNodeChild(node, 'update');
124
- if (updateNode) {
125
- const opName = updateNode.attrs?.op_name;
126
- if (!opName) {
127
- logger.warn({ node: binaryNodeToString(node) }, 'mex notification missing op_name, fallback to legacy');
128
- await handleLegacyMexNewsletterNotification(node);
129
- return;
130
- }
131
- let mexResponse;
132
- try {
133
- mexResponse = JSON.parse(updateNode.content.toString());
134
- }
135
- catch (error) {
136
- logger.error({ err: error, opName }, 'failed to parse mex notification JSON');
137
- return;
138
- }
139
- if (mexResponse.errors?.length) {
140
- logger.warn({ errors: mexResponse.errors, opName }, 'mex notification has GQL errors');
141
- return;
142
- }
143
- const data = mexResponse.data;
144
- if (!data) {
145
- logger.warn({ opName }, 'mex notification has null data');
146
- return;
147
- }
148
- logger.debug({ opName }, 'processing mex notification');
149
- switch (opName) {
150
- case 'NotificationUserReachoutTimelockUpdate':
151
- handleReachoutTimelockNotification(data);
152
- break;
153
- case 'MessageCappingInfoNotification':
154
- handleMessageCappingNotification(data);
155
- break;
156
- // newsletter ops still use the legacy <mex> child structure
157
- case 'NotificationNewsletterUpdate':
158
- case 'NotificationLinkedProfilesUpdates':
159
- case 'NotificationNewsletterAdminPromote':
160
- case 'NotificationNewsletterAdminDemote':
161
- case 'NotificationNewsletterUserSettingChange':
162
- case 'NotificationNewsletterJoin':
163
- case 'NotificationNewsletterLeave':
164
- case 'NotificationNewsletterStateChange':
165
- case 'NotificationNewsletterAdminMetadataUpdate':
166
- case 'NotificationNewsletterOwnerUpdate':
167
- case 'NotificationNewsletterAdminInviteRevoke':
168
- case 'NotificationNewsletterWamoSubStatusChange':
169
- case 'NotificationNewsletterBlockUser':
170
- case 'NotificationNewsletterPaidPartnership':
171
- case 'NotificationNewsletterMilestone':
172
- case 'NewsletterResponseStateUpdate':
173
- await handleLegacyMexNewsletterNotification(node);
174
- break;
175
- default:
176
- logger.debug({ opName }, 'unhandled mex notification');
177
- break;
178
- }
179
- return;
180
- }
181
- await handleLegacyMexNewsletterNotification(node);
182
- };
183
- const handleReachoutTimelockNotification = (data) => {
184
- const payload = data.xwa2_notify_account_reachout_timelock;
185
- if (!payload) {
186
- logger.warn('reachout timelock notification missing payload');
187
- return;
188
- }
189
- if (!payload.is_active) {
190
- logger.info('reachout timelock restriction lifted');
191
- ev.emit('connection.update', {
192
- reachoutTimeLock: {
193
- isActive: false,
194
- enforcementType: ReachoutTimelockEnforcementType.DEFAULT
195
- }
196
- });
197
- return;
198
- }
199
- // WA Web defaults to now+60s when the server omits the expiry
200
- const timeEnforcementEnds = payload.time_enforcement_ends
201
- ? new Date(parseInt(payload.time_enforcement_ends, 10) * 1000)
202
- : new Date(Date.now() + 60000);
203
- const enforcementType = isValidEnforcementType(payload.enforcement_type)
204
- ? payload.enforcement_type
205
- : ReachoutTimelockEnforcementType.DEFAULT;
206
- logger.info({ enforcementType, timeEnforcementEnds }, 'reachout timelock restriction set');
207
- ev.emit('connection.update', {
208
- reachoutTimeLock: {
209
- isActive: true,
210
- timeEnforcementEnds,
211
- enforcementType
212
- }
213
- });
214
- };
215
- const handleMessageCappingNotification = (data) => {
216
- const payload = data.xwa2_notify_new_chat_messages_capping_info_update;
217
- if (!payload) {
218
- logger.warn('message capping notification missing payload');
219
- return;
220
- }
221
- logger.info({ payload }, 'received message capping update');
222
- ev.emit('message-capping.update', payload);
223
- };
224
- const handleLegacyMexNewsletterNotification = async (node) => {
89
+ // Handles mex newsletter notifications
90
+ const handleMexNewsletterNotification = async (node) => {
225
91
  const mexNode = getBinaryNodeChild(node, 'mex');
226
- const updateNode = mexNode?.content ? null : getBinaryNodeChild(node, 'update') || getAllBinaryNodeChildren(node)[0];
227
- const payloadNode = mexNode?.content ? mexNode : updateNode;
228
- if (!payloadNode?.content) {
229
- logger.warn({ node: binaryNodeToString(node) }, 'invalid mex newsletter notification');
92
+ if (!mexNode?.content) {
93
+ logger.warn({ node }, 'Invalid mex newsletter notification');
230
94
  return;
231
95
  }
232
96
  let data;
233
97
  try {
234
- const payloadContent = payloadNode.content;
235
- if (Array.isArray(payloadContent)) {
236
- logger.warn({ payloadNode }, 'invalid mex newsletter notification payload format');
237
- return;
238
- }
239
- const contentBuf = typeof payloadContent === 'string' ? Buffer.from(payloadContent, 'binary') : Buffer.from(payloadContent);
240
- data = JSON.parse(contentBuf.toString());
98
+ data = JSON.parse(mexNode.content.toString());
241
99
  }
242
100
  catch (error) {
243
- logger.error({ err: error, node: binaryNodeToString(node) }, 'failed to parse mex newsletter notification');
101
+ logger.error({ err: error, node }, 'Failed to parse mex newsletter notification');
244
102
  return;
245
103
  }
246
- const operation = data?.operation ?? payloadNode?.attrs?.op_name;
247
- let updates = data?.updates;
248
- if (!updates) {
249
- const linkedProfiles = data?.data?.xwa2_notify_linked_profiles;
250
- if (linkedProfiles) {
251
- updates = [linkedProfiles];
252
- }
253
- }
104
+ const operation = data?.operation;
105
+ const updates = data?.updates;
254
106
  if (!updates || !operation) {
255
- logger.warn({ data }, 'invalid mex newsletter notification content');
107
+ logger.warn({ data }, 'Invalid mex newsletter notification content');
256
108
  return;
257
109
  }
258
110
  logger.info({ operation, updates }, 'got mex newsletter notification');
@@ -280,114 +132,91 @@ export const makeMessagesRecvSocket = (config) => {
280
132
  }
281
133
  }
282
134
  break;
283
- case 'NotificationLinkedProfilesUpdates':
284
- for (const update of updates) {
285
- const lid = update?.jid;
286
- const addedProfiles = Array.isArray(update?.added_profiles) ? update.added_profiles : [];
287
- const mappings = [];
288
- for (const profile of addedProfiles) {
289
- const pn = typeof profile === 'string' ? profile : (profile?.pn ?? profile?.jid ?? null);
290
- if (lid && pn) {
291
- const mapping = { lid, pn };
292
- ev.emit('lid-mapping.update', mapping);
293
- mappings.push(mapping);
294
- }
295
- }
296
- await signalRepository.lidMapping.storeLIDPNMappings(mappings);
297
- }
298
- break;
299
135
  default:
300
- logger.info({ operation, data }, 'unhandled mex newsletter notification');
136
+ logger.info({ operation, data }, 'Unhandled mex newsletter notification');
301
137
  break;
302
138
  }
303
139
  };
304
140
  // Handles newsletter notifications
305
141
  const handleNewsletterNotification = async (node) => {
306
142
  const from = node.attrs.from;
307
- const children = getAllBinaryNodeChildren(node);
143
+ const child = getAllBinaryNodeChildren(node)[0];
308
144
  const author = node.attrs.participant;
309
- for (const child of children) {
310
- logger.debug({ from, child }, 'got newsletter notification');
311
- switch (child.tag) {
312
- case 'reaction': {
313
- const reactionUpdate = {
314
- id: from,
315
- server_id: child.attrs.message_id,
316
- reaction: {
317
- code: getBinaryNodeChildString(child, 'reaction'),
318
- count: 1
319
- }
320
- };
321
- ev.emit('newsletter.reaction', reactionUpdate);
322
- break;
323
- }
324
- case 'view': {
325
- const viewUpdate = {
326
- id: from,
327
- server_id: child.attrs.message_id,
328
- count: parseInt(child.content?.toString() || '0', 10)
329
- };
330
- ev.emit('newsletter.view', viewUpdate);
331
- break;
332
- }
333
- case 'participant': {
334
- const participantUpdate = {
145
+ logger.info({ from, child }, 'got newsletter notification');
146
+ switch (child.tag) {
147
+ case 'reaction':
148
+ const reactionUpdate = {
149
+ id: from,
150
+ server_id: child.attrs.message_id,
151
+ reaction: {
152
+ code: getBinaryNodeChildString(child, 'reaction'),
153
+ count: 1
154
+ }
155
+ };
156
+ ev.emit('newsletter.reaction', reactionUpdate);
157
+ break;
158
+ case 'view':
159
+ const viewUpdate = {
160
+ id: from,
161
+ server_id: child.attrs.message_id,
162
+ count: parseInt(child.content?.toString() || '0', 10)
163
+ };
164
+ ev.emit('newsletter.view', viewUpdate);
165
+ break;
166
+ case 'participant':
167
+ const participantUpdate = {
168
+ id: from,
169
+ author,
170
+ user: child.attrs.jid,
171
+ action: child.attrs.action,
172
+ new_role: child.attrs.role
173
+ };
174
+ ev.emit('newsletter-participants.update', participantUpdate);
175
+ break;
176
+ case 'update':
177
+ const settingsNode = getBinaryNodeChild(child, 'settings');
178
+ if (settingsNode) {
179
+ const update = {};
180
+ const nameNode = getBinaryNodeChild(settingsNode, 'name');
181
+ if (nameNode?.content)
182
+ update.name = nameNode.content.toString();
183
+ const descriptionNode = getBinaryNodeChild(settingsNode, 'description');
184
+ if (descriptionNode?.content)
185
+ update.description = descriptionNode.content.toString();
186
+ ev.emit('newsletter-settings.update', {
335
187
  id: from,
336
- author,
337
- user: child.attrs.jid,
338
- action: child.attrs.action,
339
- new_role: child.attrs.role
340
- };
341
- ev.emit('newsletter-participants.update', participantUpdate);
342
- break;
188
+ update
189
+ });
343
190
  }
344
- case 'update': {
345
- const settingsNode = getBinaryNodeChild(child, 'settings');
346
- if (settingsNode) {
347
- const update = {};
348
- const nameNode = getBinaryNodeChild(settingsNode, 'name');
349
- if (nameNode?.content)
350
- update.name = nameNode.content.toString();
351
- const descriptionNode = getBinaryNodeChild(settingsNode, 'description');
352
- if (descriptionNode?.content)
353
- update.description = descriptionNode.content.toString();
354
- ev.emit('newsletter-settings.update', {
355
- id: from,
356
- update
357
- });
191
+ break;
192
+ case 'message':
193
+ const plaintextNode = getBinaryNodeChild(child, 'plaintext');
194
+ if (plaintextNode?.content) {
195
+ try {
196
+ const contentBuf = typeof plaintextNode.content === 'string'
197
+ ? Buffer.from(plaintextNode.content, 'binary')
198
+ : Buffer.from(plaintextNode.content);
199
+ const messageProto = proto.Message.decode(contentBuf).toJSON();
200
+ const fullMessage = proto.WebMessageInfo.fromObject({
201
+ key: {
202
+ remoteJid: from,
203
+ id: child.attrs.message_id || child.attrs.server_id,
204
+ fromMe: false // TODO: is this really true though
205
+ },
206
+ message: messageProto,
207
+ messageTimestamp: +child.attrs.t
208
+ }).toJSON();
209
+ await upsertMessage(fullMessage, 'append');
210
+ logger.info('Processed plaintext newsletter message');
358
211
  }
359
- break;
360
- }
361
- case 'message': {
362
- const plaintextNode = getBinaryNodeChild(child, 'plaintext');
363
- if (plaintextNode?.content) {
364
- try {
365
- const contentBuf = typeof plaintextNode.content === 'string'
366
- ? Buffer.from(plaintextNode.content, 'binary')
367
- : Buffer.from(plaintextNode.content);
368
- const messageProto = proto.Message.decode(contentBuf).toJSON();
369
- const fullMessage = proto.WebMessageInfo.fromObject({
370
- key: {
371
- remoteJid: from,
372
- id: child.attrs.message_id || child.attrs.server_id,
373
- fromMe: false // TODO: is this really true though
374
- },
375
- message: messageProto,
376
- messageTimestamp: +child.attrs.t
377
- }).toJSON();
378
- await upsertMessage(fullMessage, 'append');
379
- logger.debug('Processed plaintext newsletter message');
380
- }
381
- catch (error) {
382
- logger.error({ error }, 'Failed to decode plaintext newsletter message');
383
- }
212
+ catch (error) {
213
+ logger.error({ error }, 'Failed to decode plaintext newsletter message');
384
214
  }
385
- break;
386
215
  }
387
- default:
388
- logger.warn({ node, child }, 'Unknown newsletter notification child');
389
- break;
390
- }
216
+ break;
217
+ default:
218
+ logger.warn({ node }, 'Unknown newsletter notification');
219
+ break;
391
220
  }
392
221
  };
393
222
  const sendMessageAck = async (node, errorCode) => {
@@ -547,58 +376,15 @@ export const makeMessagesRecvSocket = (config) => {
547
376
  logger.info({ msgAttrs: node.attrs, retryCount }, 'sent retry receipt');
548
377
  }, authState?.creds?.me?.id || 'sendRetryRequest');
549
378
  };
550
- // Mirrors WAWeb/Handle/PreKeyLow.js: skip a re-issued notification with the same stanza id.
551
- const inFlightPreKeyLow = new Set();
552
- /**
553
- * Fire-and-forget tctoken re-issuance after a peer's device identity changed.
554
- * Mirrors WAWebSendTcTokenWhenDeviceIdentityChange — runs in parallel with
555
- * the session refresh (not after it).
556
- */
557
- const reissueTcTokenAfterIdentityChange = (from) => {
558
- void (async () => {
559
- const normalizedJid = jidNormalizedUser(from);
560
- const tcJid = await resolveTcTokenJid(normalizedJid, getLIDForPN);
561
- const tcTokenData = await authState.keys.get('tctoken', [tcJid]);
562
- const senderTs = tcTokenData?.[tcJid]?.senderTimestamp;
563
- if (senderTs === null || senderTs === undefined || isTcTokenExpired(senderTs)) {
564
- return;
565
- }
566
- logger.debug({ jid: normalizedJid, senderTimestamp: senderTs }, 'identity changed, re-issuing tctoken');
567
- const getPNForLID = signalRepository.lidMapping.getPNForLID.bind(signalRepository.lidMapping);
568
- const issueJid = await resolveIssuanceJid(normalizedJid, sock.serverProps.lidTrustedTokenIssueToLid, getLIDForPN, getPNForLID);
569
- const result = await issuePrivacyTokens([issueJid], senderTs);
570
- await storeTcTokensFromIqResult({
571
- result,
572
- fallbackJid: tcJid,
573
- keys: authState.keys,
574
- getLIDForPN,
575
- onNewJidStored: trackTcTokenJid
576
- });
577
- })().catch(err => {
578
- logger.debug({ jid: from, err: err?.message }, 'failed to re-issue tctoken after identity change');
579
- });
580
- };
581
379
  const handleEncryptNotification = async (node) => {
582
380
  const from = node.attrs.from;
583
381
  if (from === S_WHATSAPP_NET) {
584
- const stanzaId = node.attrs.id;
585
- if (stanzaId && inFlightPreKeyLow.has(stanzaId)) {
586
- return;
587
- }
588
382
  const countChild = getBinaryNodeChild(node, 'count');
589
383
  const count = +countChild.attrs.value;
590
384
  const shouldUploadMorePreKeys = count < MIN_PREKEY_COUNT;
591
385
  logger.debug({ count, shouldUploadMorePreKeys }, 'recv pre-key count');
592
386
  if (shouldUploadMorePreKeys) {
593
- if (stanzaId)
594
- inFlightPreKeyLow.add(stanzaId);
595
- try {
596
- await uploadPreKeys();
597
- }
598
- finally {
599
- if (stanzaId)
600
- inFlightPreKeyLow.delete(stanzaId);
601
- }
387
+ await uploadPreKeys();
602
388
  }
603
389
  }
604
390
  else {
@@ -608,8 +394,7 @@ export const makeMessagesRecvSocket = (config) => {
608
394
  validateSession: signalRepository.validateSession,
609
395
  assertSessions,
610
396
  debounceCache: identityAssertDebounce,
611
- logger,
612
- onBeforeSessionRefresh: reissueTcTokenAfterIdentityChange
397
+ logger
613
398
  });
614
399
  if (result.action === 'no_identity_node') {
615
400
  logger.info({ node }, 'unknown encrypt notification');
@@ -620,7 +405,6 @@ export const makeMessagesRecvSocket = (config) => {
620
405
  // TODO: Support PN/LID (Here is only LID now)
621
406
  const actingParticipantLid = fullNode.attrs.participant;
622
407
  const actingParticipantPn = fullNode.attrs.participant_pn;
623
- const actingParticipantUsername = fullNode.attrs.participant_username;
624
408
  const affectedParticipantLid = getBinaryNodeChild(child, 'participant')?.attrs?.jid || actingParticipantLid;
625
409
  const affectedParticipantPn = getBinaryNodeChild(child, 'participant')?.attrs?.phone_number || actingParticipantPn;
626
410
  switch (child?.tag) {
@@ -640,8 +424,7 @@ export const makeMessagesRecvSocket = (config) => {
640
424
  {
641
425
  ...metadata,
642
426
  author: actingParticipantLid,
643
- authorPn: actingParticipantPn,
644
- authorUsername: actingParticipantUsername
427
+ authorPn: actingParticipantPn
645
428
  }
646
429
  ]);
647
430
  break;
@@ -667,13 +450,11 @@ export const makeMessagesRecvSocket = (config) => {
667
450
  const stubType = `GROUP_PARTICIPANT_${child.tag.toUpperCase()}`;
668
451
  msg.messageStubType = WAMessageStubType[stubType];
669
452
  const participants = getBinaryNodeChildren(child, 'participant').map(({ attrs }) => {
670
- const isLid = isLidUser(attrs.jid);
671
- const hasPn = isPnUser(attrs.phone_number);
453
+ // TODO: Store LID MAPPINGS
672
454
  return {
673
- id: isLid && hasPn ? attrs.phone_number : attrs.jid,
674
- phoneNumber: isLid && hasPn ? attrs.phone_number : undefined,
675
- lid: isLid ? attrs.jid : isPnUser(attrs.jid) && isLidUser(attrs.lid) ? attrs.lid : undefined,
676
- username: attrs.participant_username || attrs.username || undefined,
455
+ id: attrs.jid,
456
+ phoneNumber: isLidUser(attrs.jid) && isPnUser(attrs.phone_number) ? attrs.phone_number : undefined,
457
+ lid: isPnUser(attrs.jid) && isLidUser(attrs.lid) ? attrs.lid : undefined,
677
458
  admin: (attrs.type || null)
678
459
  };
679
460
  });
@@ -743,89 +524,6 @@ export const makeMessagesRecvSocket = (config) => {
743
524
  break;
744
525
  }
745
526
  };
746
- const handleDevicesNotification = async (node) => {
747
- const [child] = getAllBinaryNodeChildren(node);
748
- const from = jidNormalizedUser(node.attrs.from);
749
- if (!child) {
750
- logger.debug({ from }, 'devices notification missing child, skipping');
751
- return;
752
- }
753
- const tag = child.tag;
754
- const deviceHash = child.attrs.device_hash;
755
- const devices = getBinaryNodeChildren(child, 'device');
756
- if (areJidsSameUser(from, authState.creds.me.id) || areJidsSameUser(from, authState.creds.me.lid)) {
757
- const deviceJids = devices.map(d => d.attrs.jid);
758
- logger.info({ deviceJids }, 'got my own devices');
759
- }
760
- if (!devices.length) {
761
- logger.debug({ from, tag }, 'no devices in notification, skipping');
762
- return;
763
- }
764
- const decoded = [];
765
- for (const d of devices) {
766
- const jid = d.attrs.jid;
767
- if (!jid)
768
- continue;
769
- const parts = jidDecode(jid);
770
- if (!parts) {
771
- logger.debug({ jid }, 'failed to decode device jid, skipping');
772
- continue;
773
- }
774
- decoded.push({ jid, user: parts.user, server: parts.server, device: parts.device });
775
- }
776
- if (!decoded.length)
777
- return;
778
- await devicesMutex.mutex(async () => {
779
- const byUser = new Map();
780
- for (const d of decoded) {
781
- const list = byUser.get(d.user) || [];
782
- list.push(d);
783
- byUser.set(d.user, list);
784
- }
785
- for (const [user, entries] of byUser) {
786
- if (tag === 'update') {
787
- logger.debug({ user }, `${user}'s device list updated, dropping cached devices`);
788
- await userDevicesCache?.del(user);
789
- continue;
790
- }
791
- if (tag === 'remove') {
792
- await signalRepository.deleteSession(entries.map(e => e.jid));
793
- }
794
- const existingCache = (await userDevicesCache?.get(user)) || [];
795
- if (!existingCache.length) {
796
- // No baseline yet; skip applying the delta so getUSyncDevices can
797
- // later fetch the full device list. Caching just the notification
798
- // entries would make a partial list look authoritative.
799
- logger.debug({ user, tag }, 'device list not cached, deferring to USync refresh');
800
- continue;
801
- }
802
- const affected = new Set(entries.map(e => e.device));
803
- let updatedDevices;
804
- switch (tag) {
805
- case 'add':
806
- logger.info({ deviceHash, count: entries.length }, 'devices added');
807
- updatedDevices = [
808
- ...existingCache.filter(d => !affected.has(d.device)),
809
- ...entries.map(e => ({ user: e.user, server: e.server, device: e.device }))
810
- ];
811
- break;
812
- case 'remove':
813
- logger.info({ deviceHash, count: entries.length }, 'devices removed');
814
- updatedDevices = existingCache.filter(d => !affected.has(d.device));
815
- break;
816
- default:
817
- logger.debug({ tag }, 'Unknown device list change tag');
818
- continue;
819
- }
820
- if (updatedDevices.length === 0) {
821
- await userDevicesCache?.del(user);
822
- }
823
- else {
824
- await userDevicesCache?.set(user, updatedDevices);
825
- }
826
- }
827
- });
828
- };
829
527
  const processNotification = async (node) => {
830
528
  const result = {};
831
529
  const [child] = getAllBinaryNodeChildren(node);
@@ -836,7 +534,7 @@ export const makeMessagesRecvSocket = (config) => {
836
534
  await handleNewsletterNotification(node);
837
535
  break;
838
536
  case 'mex':
839
- await handleMexNotification(node);
537
+ await handleMexNewsletterNotification(node);
840
538
  break;
841
539
  case 'w:gp2':
842
540
  // TODO: HANDLE PARTICIPANT_PN
@@ -850,12 +548,13 @@ export const makeMessagesRecvSocket = (config) => {
850
548
  await handleEncryptNotification(node);
851
549
  break;
852
550
  case 'devices':
853
- try {
854
- await handleDevicesNotification(node);
855
- }
856
- catch (error) {
857
- logger.error({ error, node }, 'failed to handle devices notification');
551
+ const devices = getBinaryNodeChildren(child, 'device');
552
+ if (areJidsSameUser(child.attrs.jid, authState.creds.me.id) ||
553
+ areJidsSameUser(child.attrs.lid, authState.creds.me.lid)) {
554
+ const deviceData = devices.map(d => ({ id: d.attrs.jid, lid: d.attrs.lid }));
555
+ logger.info({ deviceData }, 'my own devices changed');
858
556
  }
557
+ //TODO: drop a new event, add hashes
859
558
  break;
860
559
  case 'server_sync':
861
560
  const update = getBinaryNodeChild(node, 'collection');
@@ -973,10 +672,6 @@ export const makeMessagesRecvSocket = (config) => {
973
672
  authState.creds.registered = true;
974
673
  ev.emit('creds.update', authState.creds);
975
674
  break;
976
- case 'passkey_prologue_request':
977
- case 'crsc_continuation':
978
- handleShortcakeNotification(node);
979
- break;
980
675
  case 'privacy_token':
981
676
  await handlePrivacyTokenNotification(node);
982
677
  break;
@@ -985,70 +680,27 @@ export const makeMessagesRecvSocket = (config) => {
985
680
  return result;
986
681
  }
987
682
  };
988
- /**
989
- * In-memory cache of storage JIDs with stored tctokens, seeded from the persisted index.
990
- * Used to coalesce writes during a session; pruning always re-reads the persisted index
991
- * to cover writes made by other layers (e.g. history sync).
992
- */
993
- const tcTokenKnownJids = new Set();
994
- const tcTokenIndexLoaded = (async () => {
995
- try {
996
- const jids = await readTcTokenIndex(authState.keys);
997
- for (const jid of jids)
998
- tcTokenKnownJids.add(jid);
999
- logger.debug({ count: tcTokenKnownJids.size }, 'loaded tctoken index');
1000
- }
1001
- catch (err) {
1002
- logger.warn({ err: err?.message }, 'failed to load tctoken index');
1003
- }
1004
- })();
1005
- let tcTokenIndexTimer;
1006
- async function flushTcTokenIndex() {
1007
- if (tcTokenIndexTimer) {
1008
- clearTimeout(tcTokenIndexTimer);
1009
- tcTokenIndexTimer = undefined;
1010
- }
1011
- // Merge with whatever is already persisted so we don't clobber writes from other
1012
- // paths (history sync, concurrent sessions on the same store).
1013
- const write = await buildMergedTcTokenIndexWrite(authState.keys, tcTokenKnownJids);
1014
- return authState.keys.set({ tctoken: write });
1015
- }
1016
- function scheduleTcTokenIndexSave() {
1017
- if (tcTokenIndexTimer) {
1018
- clearTimeout(tcTokenIndexTimer);
1019
- }
1020
- tcTokenIndexTimer = setTimeout(() => {
1021
- tcTokenIndexTimer = undefined;
1022
- flushTcTokenIndex().catch(err => {
1023
- logger.warn({ err: err?.message }, 'failed to save tctoken index');
1024
- });
1025
- }, 5000);
1026
- }
1027
- function trackTcTokenJid(jid) {
1028
- if (jid && jid !== TC_TOKEN_INDEX_KEY && !tcTokenKnownJids.has(jid)) {
1029
- tcTokenKnownJids.add(jid);
1030
- scheduleTcTokenIndexSave();
1031
- }
1032
- }
1033
683
  const handlePrivacyTokenNotification = async (node) => {
1034
684
  const tokensNode = getBinaryNodeChild(node, 'tokens');
685
+ const from = jidNormalizedUser(node.attrs.from);
1035
686
  if (!tokensNode)
1036
687
  return;
1037
- const from = jidNormalizedUser(node.attrs.from);
1038
- // WA Web uses: senderLid ?? toLid(from) for the storage key
1039
- // The sender_lid attribute provides the LID directly when available
1040
- const senderLid = node.attrs.sender_lid && isLidUser(jidNormalizedUser(node.attrs.sender_lid))
1041
- ? jidNormalizedUser(node.attrs.sender_lid)
1042
- : undefined;
1043
- const fallbackJid = senderLid ?? (await resolveTcTokenJid(from, getLIDForPN));
1044
- logger.debug({ from, storageJid: fallbackJid }, 'processing privacy token notification');
1045
- await storeTcTokensFromIqResult({
1046
- result: node,
1047
- fallbackJid,
1048
- keys: authState.keys,
1049
- getLIDForPN,
1050
- onNewJidStored: trackTcTokenJid
1051
- });
688
+ const tokenNodes = getBinaryNodeChildren(tokensNode, 'token');
689
+ for (const tokenNode of tokenNodes) {
690
+ const { attrs, content } = tokenNode;
691
+ const type = attrs.type;
692
+ const timestamp = attrs.t;
693
+ if (type === 'trusted_contact' && content instanceof Buffer) {
694
+ logger.debug({
695
+ from,
696
+ timestamp,
697
+ tcToken: content
698
+ }, 'received trusted contact token');
699
+ await authState.keys.set({
700
+ tctoken: { [from]: { token: content, timestamp } }
701
+ });
702
+ }
703
+ }
1052
704
  };
1053
705
  async function decipherLinkPublicKey(data) {
1054
706
  const buffer = toRequiredBuffer(data);
@@ -1074,11 +726,10 @@ export const makeMessagesRecvSocket = (config) => {
1074
726
  const newValue = ((await msgRetryCache.get(key)) || 0) + 1;
1075
727
  await msgRetryCache.set(key, newValue);
1076
728
  };
1077
- const sendMessagesAgain = async (key, ids, retryNode, receiptNode) => {
729
+ const sendMessagesAgain = async (key, ids, retryNode) => {
1078
730
  const remoteJid = key.remoteJid;
1079
731
  const participant = key.participant || remoteJid;
1080
732
  const retryCount = +retryNode.attrs.count || 1;
1081
- const msgId = ids[0];
1082
733
  // Try to get messages from cache first, then fallback to getMessage
1083
734
  const msgs = [];
1084
735
  for (const id of ids) {
@@ -1110,48 +761,28 @@ export const makeMessagesRecvSocket = (config) => {
1110
761
  // just re-send the message to everyone
1111
762
  // prevents the first message decryption failure
1112
763
  const sendToAll = !jidDecode(participant)?.device;
764
+ // Check if we should recreate session for this retry
765
+ let shouldRecreateSession = false;
766
+ let recreateReason = '';
1113
767
  const sessionId = signalRepository.jidToSignalProtocolAddress(participant);
1114
- let injectedFromBundle = false;
1115
- const bundle = extractE2ESessionFromRetryReceipt(receiptNode);
1116
- if (bundle) {
1117
- try {
1118
- await signalRepository.injectE2ESession({ jid: participant, session: bundle });
1119
- injectedFromBundle = true;
1120
- logger.debug({ participant, retryCount }, 'injected session from retry receipt key bundle');
1121
- }
1122
- catch (error) {
1123
- logger.warn({ error, participant }, 'failed to inject session from retry receipt');
1124
- }
1125
- }
1126
- if (!injectedFromBundle) {
1127
- const receivedRegId = getBinaryNodeChildUInt(receiptNode, 'registration', 4);
1128
- if (typeof receivedRegId === 'number' && Number.isInteger(receivedRegId)) {
1129
- const info = await signalRepository.getSessionInfo(participant);
1130
- if (info && info.registrationId !== 0 && info.registrationId !== receivedRegId) {
1131
- logger.info({ participant, stored: info.registrationId, received: receivedRegId }, 'reg id mismatch on retry without bundle, deleting session');
1132
- await authState.keys.set({ session: { [sessionId]: null } });
1133
- }
1134
- }
1135
- }
1136
768
  const BASE_KEY_CHECK_RETRY = 2;
1137
- if (msgId && messageRetryManager) {
1138
- const info = await signalRepository.getSessionInfo(participant);
1139
- if (info) {
769
+ const primaryMsgId = ids[0];
770
+ if (primaryMsgId && messageRetryManager) {
771
+ const baseKeyInfo = await signalRepository.getSessionInfo(participant);
772
+ if (baseKeyInfo) {
1140
773
  if (retryCount === BASE_KEY_CHECK_RETRY) {
1141
- messageRetryManager.saveBaseKey(sessionId, msgId, info.baseKey);
774
+ messageRetryManager.saveBaseKey(sessionId, primaryMsgId, baseKeyInfo.baseKey);
1142
775
  }
1143
776
  else if (retryCount > BASE_KEY_CHECK_RETRY) {
1144
- if (messageRetryManager.hasSameBaseKey(sessionId, msgId, info.baseKey)) {
777
+ if (messageRetryManager.hasSameBaseKey(sessionId, primaryMsgId, baseKeyInfo.baseKey)) {
1145
778
  logger.warn({ participant, retryCount }, 'base key collision on retry, forcing fresh session');
1146
779
  await authState.keys.set({ session: { [sessionId]: null } });
1147
780
  }
1148
- messageRetryManager.deleteBaseKey(sessionId, msgId);
781
+ messageRetryManager.deleteBaseKey(sessionId, primaryMsgId);
1149
782
  }
1150
783
  }
1151
784
  }
1152
- let shouldRecreateSession = false;
1153
- let recreateReason = '';
1154
- if (enableAutoSessionRecreation && messageRetryManager && retryCount > 1 && !injectedFromBundle) {
785
+ if (enableAutoSessionRecreation && messageRetryManager && retryCount > 1) {
1155
786
  try {
1156
787
  const hasSession = await signalRepository.validateSession(participant);
1157
788
  const result = messageRetryManager.shouldRecreateSession(participant, hasSession.exists);
@@ -1166,13 +797,11 @@ export const makeMessagesRecvSocket = (config) => {
1166
797
  logger.warn({ error, participant }, 'failed to check session recreation for outgoing retry');
1167
798
  }
1168
799
  }
1169
- if (!injectedFromBundle) {
1170
- await assertSessions([participant], true);
1171
- }
800
+ await assertSessions([participant], true);
1172
801
  if (isJidGroup(remoteJid)) {
1173
802
  await authState.keys.set({ 'sender-key-memory': { [remoteJid]: null } });
1174
803
  }
1175
- logger.debug({ participant, sendToAll, shouldRecreateSession, recreateReason, injectedFromBundle }, 'prepared session for retry resend');
804
+ logger.debug({ participant, sendToAll, shouldRecreateSession, recreateReason }, 'forced new session for retry recp');
1176
805
  for (const [i, msg] of msgs.entries()) {
1177
806
  if (!ids[i])
1178
807
  continue;
@@ -1207,6 +836,11 @@ export const makeMessagesRecvSocket = (config) => {
1207
836
  fromMe,
1208
837
  participant: attrs.participant
1209
838
  };
839
+ if (shouldIgnoreJid(remoteJid) && remoteJid !== S_WHATSAPP_NET) {
840
+ logger.debug({ remoteJid }, 'ignoring receipt from jid');
841
+ await sendMessageAck(node);
842
+ return;
843
+ }
1210
844
  const ids = [attrs.id];
1211
845
  if (Array.isArray(content)) {
1212
846
  const items = getBinaryNodeChildren(content[0], 'item');
@@ -1248,7 +882,7 @@ export const makeMessagesRecvSocket = (config) => {
1248
882
  try {
1249
883
  await updateSendMessageAgainCount(ids[0], key.participant);
1250
884
  logger.debug({ attrs, key }, 'recv retry request');
1251
- await sendMessagesAgain(key, ids, retryNode, node);
885
+ await sendMessagesAgain(key, ids, retryNode);
1252
886
  }
1253
887
  catch (error) {
1254
888
  logger.error({ key, ids, trace: error instanceof Error ? error.stack : 'Unknown error' }, 'error in sending message again');
@@ -1271,6 +905,11 @@ export const makeMessagesRecvSocket = (config) => {
1271
905
  };
1272
906
  const handleNotification = async (node) => {
1273
907
  const remoteJid = node.attrs.from;
908
+ if (shouldIgnoreJid(remoteJid) && remoteJid !== S_WHATSAPP_NET) {
909
+ logger.debug({ remoteJid, id: node.attrs.id }, 'ignored notification');
910
+ await sendMessageAck(node);
911
+ return;
912
+ }
1274
913
  try {
1275
914
  await Promise.all([
1276
915
  notificationMutex.mutex(async () => {
@@ -1283,7 +922,6 @@ export const makeMessagesRecvSocket = (config) => {
1283
922
  fromMe,
1284
923
  participant: node.attrs.participant,
1285
924
  participantAlt,
1286
- participantUsername: node.attrs.participant_username,
1287
925
  addressingMode,
1288
926
  id: node.attrs.id,
1289
927
  ...(msg.key || {})
@@ -1301,6 +939,11 @@ export const makeMessagesRecvSocket = (config) => {
1301
939
  }
1302
940
  };
1303
941
  const handleMessage = async (node) => {
942
+ if (shouldIgnoreJid(node.attrs.from) && node.attrs.from !== S_WHATSAPP_NET) {
943
+ logger.debug({ key: node.attrs.key }, 'ignored message');
944
+ await sendMessageAck(node, NACK_REASONS.UnhandledError);
945
+ return;
946
+ }
1304
947
  const encNode = getBinaryNodeChild(node, 'enc');
1305
948
  // TODO: temporary fix for crashes and issues resulting of failed msmsg decryption
1306
949
  if (encNode?.attrs.type === 'msmsg') {
@@ -1404,14 +1047,29 @@ export const makeMessagesRecvSocket = (config) => {
1404
1047
  return sendMessageAck(node);
1405
1048
  }
1406
1049
  }
1407
- logger.debug('[handleMessage] Attempting retry request for failed decryption');
1408
- // WAWeb only retry-receipts here; server emits PreKeyLow if prekeys run low.
1050
+ const errorMessage = msg?.messageStubParameters?.[0] || '';
1051
+ const isPreKeyError = errorMessage.includes('PreKey');
1052
+ logger.debug(`[handleMessage] Attempting retry request for failed decryption`);
1053
+ // Handle both pre-key and normal retries in single mutex
1409
1054
  await retryMutex.mutex(async () => {
1410
1055
  try {
1411
1056
  if (!ws.isOpen) {
1412
1057
  logger.debug({ node }, 'Connection closed, skipping retry');
1413
1058
  return;
1414
1059
  }
1060
+ // Handle pre-key errors with upload and delay
1061
+ if (isPreKeyError) {
1062
+ logger.info({ error: errorMessage }, 'PreKey error detected, uploading and retrying');
1063
+ try {
1064
+ logger.debug('Uploading pre-keys for error recovery');
1065
+ await uploadPreKeys(5);
1066
+ logger.debug('Waiting for server to process new pre-keys');
1067
+ await delay(1000);
1068
+ }
1069
+ catch (uploadErr) {
1070
+ logger.error({ uploadErr }, 'Pre-key upload failed, proceeding with retry anyway');
1071
+ }
1072
+ }
1415
1073
  const encNode = getBinaryNodeChild(node, 'enc');
1416
1074
  await sendRetryRequest(node, !encNode);
1417
1075
  if (retryRequestDelayMs) {
@@ -1419,7 +1077,15 @@ export const makeMessagesRecvSocket = (config) => {
1419
1077
  }
1420
1078
  }
1421
1079
  catch (err) {
1422
- logger.error({ err }, 'Failed to send retry');
1080
+ logger.error({ err, isPreKeyError }, 'Failed to handle retry, attempting basic retry');
1081
+ // Still attempt retry even if pre-key upload failed
1082
+ try {
1083
+ const encNode = getBinaryNodeChild(node, 'enc');
1084
+ await sendRetryRequest(node, !encNode);
1085
+ }
1086
+ catch (retryErr) {
1087
+ logger.error({ retryErr }, 'Failed to send retry after error handling');
1088
+ }
1423
1089
  }
1424
1090
  acked = true;
1425
1091
  await sendMessageAck(node, NACK_REASONS.UnhandledError);
@@ -1495,13 +1161,6 @@ export const makeMessagesRecvSocket = (config) => {
1495
1161
  offline: !!attrs.offline,
1496
1162
  status
1497
1163
  };
1498
- if (status === 'relaylatency') {
1499
- const latencyValue = infoChild.attrs.latency || infoChild.attrs['latency_ms'] || infoChild.attrs['latency-ms'];
1500
- const latencyMs = latencyValue ? Number(latencyValue) : undefined;
1501
- if (Number.isFinite(latencyMs)) {
1502
- call.latencyMs = latencyMs;
1503
- }
1504
- }
1505
1164
  if (status === 'offer') {
1506
1165
  call.isVideo = !!getBinaryNodeChild(infoChild, 'video');
1507
1166
  call.isGroup = infoChild.attrs.type === 'group' || !!infoChild.attrs['group-jid'];
@@ -1546,61 +1205,29 @@ export const makeMessagesRecvSocket = (config) => {
1546
1205
  // error in acknowledgement,
1547
1206
  // device could not display the message
1548
1207
  if (attrs.error) {
1549
- const isReachoutTimelocked = attrs.error === String(NACK_REASONS.SenderReachoutTimelocked);
1550
- if (attrs.error === SERVER_ERROR_CODES.MessageAccountRestriction) {
1551
- // 463 = 1:1 message missing privacy token (tctoken). Usually means the
1552
- // account is restricted: WhatsApp blocks starting new chats but preserves
1553
- // existing ones, since established chats already carry a tctoken.
1554
- // WA Web prevents this client-side (disables the compose bar).
1555
- // No retry — retrying counts as another "reach out" and worsens the restriction.
1556
- logger.warn({ msgId: attrs.id, from: attrs.from }, 'error 463: account restricted or missing tctoken for contact');
1557
- const ackFrom = attrs.from;
1558
- if (ackFrom && !inFlight463Recoveries.has(ackFrom)) {
1559
- inFlight463Recoveries.add(ackFrom);
1560
- void (async () => {
1561
- try {
1562
- const getPNForLID = signalRepository.lidMapping.getPNForLID.bind(signalRepository.lidMapping);
1563
- const tcStorageJid = await resolveTcTokenJid(ackFrom, getLIDForPN);
1564
- const issueJid = await resolveIssuanceJid(ackFrom, sock.serverProps.lidTrustedTokenIssueToLid, getLIDForPN, getPNForLID);
1565
- const result = await issuePrivacyTokens([issueJid], unixTimestampSeconds());
1566
- await storeTcTokensFromIqResult({
1567
- result,
1568
- fallbackJid: tcStorageJid,
1569
- keys: authState.keys,
1570
- getLIDForPN,
1571
- onNewJidStored: trackTcTokenJid
1572
- });
1573
- logger.debug({ from: ackFrom }, 'completed 463 token recovery issuance');
1574
- }
1575
- catch (err) {
1576
- logger.debug({ from: ackFrom, err: err?.message }, 'failed 463 token recovery issuance');
1577
- }
1578
- finally {
1579
- inFlight463Recoveries.delete(ackFrom);
1580
- }
1581
- })();
1582
- }
1583
- }
1584
- else if (attrs.error === SERVER_ERROR_CODES.SmaxInvalid) {
1585
- logger.warn({ msgId: attrs.id, from: attrs.from }, 'smax-invalid (479): stanza rejected by server — likely stale device session or malformed addressing');
1586
- }
1587
- else if (isReachoutTimelocked) {
1588
- // user is temporarily restricted, fetch current restriction details
1589
- await fetchAccountReachoutTimelock().catch(err => logger.warn({ err }, 'failed to fetch reachout timelock'));
1590
- logger.warn({ attrs }, 'received error in ack');
1591
- }
1592
- else {
1593
- logger.warn({ attrs }, 'received error in ack');
1594
- }
1208
+ logger.warn({ attrs }, 'received error in ack');
1595
1209
  ev.emit('messages.update', [
1596
1210
  {
1597
1211
  key,
1598
1212
  update: {
1599
1213
  status: WAMessageStatus.ERROR,
1600
- messageStubParameters: isReachoutTimelocked ? [attrs.error, ACCOUNT_RESTRICTED_TEXT] : [attrs.error]
1214
+ messageStubParameters: [attrs.error]
1601
1215
  }
1602
1216
  }
1603
1217
  ]);
1218
+ // resend the message with device_fanout=false, use at your own risk
1219
+ // if (attrs.error === '475') {
1220
+ // const msg = await getMessage(key)
1221
+ // if (msg) {
1222
+ // await relayMessage(key.remoteJid!, msg, {
1223
+ // messageId: key.id!,
1224
+ // useUserDevicesCache: false,
1225
+ // additionalAttributes: {
1226
+ // device_fanout: 'false'
1227
+ // }
1228
+ // })
1229
+ // }
1230
+ // }
1604
1231
  }
1605
1232
  };
1606
1233
  /// processes a node with the given function
@@ -1624,19 +1251,6 @@ export const makeMessagesRecvSocket = (config) => {
1624
1251
  yieldToEventLoop: () => new Promise(resolve => setImmediate(resolve))
1625
1252
  });
1626
1253
  const processNode = async (type, node, identifier, exec) => {
1627
- // Fast path: ack and drop ignored JIDs before entering the buffer/queue
1628
- const from = node.attrs.from;
1629
- let ignoreJid = from;
1630
- if (type === 'receipt' && from) {
1631
- const attrs = node.attrs;
1632
- const isLid = attrs.from.includes('lid');
1633
- const isNodeFromMe = areJidsSameUser(attrs.participant || attrs.from, isLid ? authState.creds.me?.lid : authState.creds.me?.id);
1634
- ignoreJid = !isNodeFromMe || isJidGroup(attrs.from) ? attrs.from : attrs.recipient;
1635
- }
1636
- if (ignoreJid && ignoreJid !== S_WHATSAPP_NET && shouldIgnoreJid(ignoreJid)) {
1637
- await sendMessageAck(node, type === 'message' ? NACK_REASONS.UnhandledError : undefined);
1638
- return;
1639
- }
1640
1254
  const isOffline = !!node.attrs.offline;
1641
1255
  if (isOffline) {
1642
1256
  offlineNodeProcessor.enqueue(type, node);
@@ -1692,110 +1306,12 @@ export const makeMessagesRecvSocket = (config) => {
1692
1306
  await upsertMessage(protoMsg, call.offline ? 'append' : 'notify');
1693
1307
  }
1694
1308
  });
1695
- /** timestamp of last tctoken prune run — throttles to once per 24h */
1696
- let lastTcTokenPruneTs = 0;
1697
- /** dedupe in-flight 463 recovery token issuance by target JID */
1698
- const inFlight463Recoveries = new Set();
1699
- ev.on('connection.update', ({ isOnline, connection }) => {
1309
+ ev.on('connection.update', ({ isOnline }) => {
1700
1310
  if (typeof isOnline !== 'undefined') {
1701
1311
  sendActiveReceipts = isOnline;
1702
1312
  logger.trace(`sendActiveReceipts set to "${sendActiveReceipts}"`);
1703
1313
  }
1704
- // Flush pending tctoken index save on disconnect to avoid writing after close
1705
- if (connection === 'close' && tcTokenIndexTimer) {
1706
- clearTimeout(tcTokenIndexTimer);
1707
- tcTokenIndexTimer = undefined;
1708
- // Best-effort flush — may fail if store is already closed
1709
- try {
1710
- void Promise.resolve(flushTcTokenIndex()).catch(() => { });
1711
- }
1712
- catch {
1713
- /* ignore sync errors */
1714
- }
1715
- }
1716
- // Prune expired tctokens when coming online, at most once per 24 hours
1717
- // Matches WA Web's CLEAN_TC_TOKENS task
1718
- // Note: don't gate on tcTokenKnownJids.size — the index may still be loading
1719
- if (isOnline) {
1720
- const now = Date.now();
1721
- const DAY_MS = 24 * 60 * 60 * 1000;
1722
- if (now - lastTcTokenPruneTs >= DAY_MS) {
1723
- lastTcTokenPruneTs = now;
1724
- void pruneExpiredTcTokens();
1725
- }
1726
- }
1727
- });
1728
- registerSocketEndHandler(() => {
1729
- if (!config.msgRetryCounterCache && msgRetryCache.close) {
1730
- msgRetryCache.close();
1731
- }
1732
- if (!config.callOfferCache && callOfferCache.close) {
1733
- callOfferCache.close();
1734
- }
1735
- identityAssertDebounce.close();
1736
- sendActiveReceipts = false;
1737
1314
  });
1738
- async function pruneExpiredTcTokens() {
1739
- try {
1740
- await tcTokenIndexLoaded;
1741
- // Union with the persisted index picks up JIDs added by other layers
1742
- // (history sync) without needing inter-module wiring.
1743
- const persisted = await readTcTokenIndex(authState.keys);
1744
- const allJids = new Set(tcTokenKnownJids);
1745
- for (const jid of persisted)
1746
- allJids.add(jid);
1747
- if (!allJids.size)
1748
- return;
1749
- const jids = [...allJids];
1750
- const allTokens = await authState.keys.get('tctoken', jids);
1751
- const writes = {};
1752
- const survivors = new Set();
1753
- let mutated = 0;
1754
- for (const jid of jids) {
1755
- const entry = allTokens[jid];
1756
- if (!entry) {
1757
- // Tracked but nothing in store — drop from index.
1758
- mutated++;
1759
- continue;
1760
- }
1761
- const hasPeerToken = !!entry.token?.length;
1762
- const peerTokenExpired = hasPeerToken && isTcTokenExpired(entry.timestamp);
1763
- const hasSenderTs = entry.senderTimestamp !== undefined;
1764
- const senderTsExpired = hasSenderTs && isTcTokenExpired(entry.senderTimestamp);
1765
- const keepPeerToken = hasPeerToken && !peerTokenExpired;
1766
- const keepSenderTs = hasSenderTs && !senderTsExpired;
1767
- if (!keepPeerToken && !keepSenderTs) {
1768
- writes[jid] = null;
1769
- mutated++;
1770
- }
1771
- else if (peerTokenExpired && keepSenderTs) {
1772
- writes[jid] = { token: Buffer.alloc(0), senderTimestamp: entry.senderTimestamp };
1773
- survivors.add(jid);
1774
- mutated++;
1775
- }
1776
- else {
1777
- survivors.add(jid);
1778
- }
1779
- }
1780
- if (mutated === 0)
1781
- return;
1782
- await authState.keys.set({
1783
- tctoken: {
1784
- ...writes,
1785
- [TC_TOKEN_INDEX_KEY]: {
1786
- token: Buffer.from(JSON.stringify([...survivors]))
1787
- }
1788
- }
1789
- });
1790
- tcTokenKnownJids.clear();
1791
- for (const jid of survivors)
1792
- tcTokenKnownJids.add(jid);
1793
- logger.debug({ mutated, remaining: survivors.size }, 'pruned expired tctokens');
1794
- }
1795
- catch (err) {
1796
- logger.warn({ err: err?.message }, 'failed to prune expired tctokens');
1797
- }
1798
- }
1799
1315
  return {
1800
1316
  ...sock,
1801
1317
  sendMessageAck,