zapo-js 0.1.1 → 0.2.0

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 (589) hide show
  1. package/README.md +20 -4
  2. package/dist/appstate/WaAppStateCrypto.js +19 -26
  3. package/dist/appstate/WaAppStateSyncClient.js +293 -181
  4. package/dist/appstate/WaAppStateSyncResponseParser.js +16 -5
  5. package/dist/appstate/constants.js +4 -3
  6. package/dist/appstate/{store/sqlite.js → encoding.js} +13 -8
  7. package/dist/appstate/index.js +8 -6
  8. package/dist/appstate/utils.js +9 -34
  9. package/dist/auth/WaAuthClient.js +43 -61
  10. package/dist/auth/flow/WaAuthCredentialsFlow.js +22 -15
  11. package/dist/auth/index.js +1 -8
  12. package/dist/auth/pairing/WaPairingCodeCrypto.js +6 -4
  13. package/dist/auth/pairing/WaPairingFlow.js +34 -26
  14. package/dist/auth/pairing/WaQrFlow.js +37 -24
  15. package/dist/client/WaClient.js +275 -324
  16. package/dist/client/WaClientFactory.js +500 -133
  17. package/dist/client/connection/WaConnectionManager.js +301 -0
  18. package/dist/client/connection/WaKeyShareCoordinator.js +63 -0
  19. package/dist/client/connection/WaReceiptQueue.js +51 -0
  20. package/dist/client/coordinators/WaAppStateMutationCoordinator.js +471 -0
  21. package/dist/client/coordinators/WaBusinessCoordinator.js +241 -0
  22. package/dist/client/coordinators/WaGroupCoordinator.js +30 -16
  23. package/dist/client/coordinators/WaIncomingNodeCoordinator.js +21 -27
  24. package/dist/client/coordinators/WaMessageDispatchCoordinator.js +439 -701
  25. package/dist/client/coordinators/WaPassiveTasksCoordinator.js +74 -31
  26. package/dist/client/coordinators/WaPrivacyCoordinator.js +134 -0
  27. package/dist/client/coordinators/WaProfileCoordinator.js +212 -0
  28. package/dist/client/coordinators/WaRetryCoordinator.js +242 -57
  29. package/dist/client/coordinators/WaStreamControlCoordinator.js +18 -11
  30. package/dist/client/coordinators/WaTrustedContactTokenCoordinator.js +166 -0
  31. package/dist/client/dirty.js +74 -48
  32. package/dist/client/events/chat.js +4 -3
  33. package/dist/client/events/devices.js +72 -0
  34. package/dist/client/events/group.js +62 -47
  35. package/dist/client/events/identity.js +22 -0
  36. package/dist/client/events/privacy-token.js +39 -0
  37. package/dist/client/history-sync.js +94 -63
  38. package/dist/client/incoming.js +60 -27
  39. package/dist/client/mailbox.js +24 -23
  40. package/dist/client/messages.js +107 -31
  41. package/dist/client/messaging/fanout.js +199 -0
  42. package/dist/client/messaging/key-protocol.js +130 -0
  43. package/dist/client/messaging/participants.js +193 -0
  44. package/dist/client/persistence/WriteBehindPersistence.js +129 -0
  45. package/dist/client/tokens/cs-token.js +50 -0
  46. package/dist/client/tokens/tc-token.js +25 -0
  47. package/dist/crypto/core/hkdf.js +3 -8
  48. package/dist/crypto/core/index.js +2 -5
  49. package/dist/crypto/core/keys.js +6 -7
  50. package/dist/crypto/core/nonce.js +2 -0
  51. package/dist/crypto/core/primitives.js +12 -23
  52. package/dist/crypto/core/random.js +26 -23
  53. package/dist/crypto/curves/Ed25519.js +7 -8
  54. package/dist/crypto/curves/X25519.js +38 -22
  55. package/dist/crypto/index.js +1 -3
  56. package/dist/crypto/math/constants.js +13 -36
  57. package/dist/crypto/math/edwards.js +171 -44
  58. package/dist/crypto/math/fe.js +706 -0
  59. package/dist/crypto/math/mod.js +10 -3
  60. package/dist/esm/appstate/WaAppStateCrypto.js +7 -14
  61. package/dist/esm/appstate/WaAppStateSyncClient.js +284 -172
  62. package/dist/esm/appstate/WaAppStateSyncResponseParser.js +17 -6
  63. package/dist/esm/appstate/constants.js +3 -2
  64. package/dist/esm/appstate/{store/sqlite.js → encoding.js} +13 -8
  65. package/dist/esm/appstate/index.js +2 -2
  66. package/dist/esm/appstate/utils.js +8 -30
  67. package/dist/esm/auth/WaAuthClient.js +43 -61
  68. package/dist/esm/auth/flow/WaAuthCredentialsFlow.js +22 -15
  69. package/dist/esm/auth/index.js +0 -3
  70. package/dist/esm/auth/pairing/WaPairingCodeCrypto.js +6 -4
  71. package/dist/esm/auth/pairing/WaPairingFlow.js +28 -20
  72. package/dist/esm/auth/pairing/WaQrFlow.js +37 -24
  73. package/dist/esm/client/WaClient.js +275 -324
  74. package/dist/esm/client/WaClientFactory.js +501 -134
  75. package/dist/esm/client/connection/WaConnectionManager.js +297 -0
  76. package/dist/esm/client/connection/WaKeyShareCoordinator.js +59 -0
  77. package/dist/esm/client/connection/WaReceiptQueue.js +47 -0
  78. package/dist/esm/client/coordinators/WaAppStateMutationCoordinator.js +467 -0
  79. package/dist/esm/client/coordinators/WaBusinessCoordinator.js +238 -0
  80. package/dist/esm/client/coordinators/WaGroupCoordinator.js +23 -9
  81. package/dist/esm/client/coordinators/WaIncomingNodeCoordinator.js +21 -27
  82. package/dist/esm/client/coordinators/WaMessageDispatchCoordinator.js +443 -705
  83. package/dist/esm/client/coordinators/WaPassiveTasksCoordinator.js +74 -31
  84. package/dist/esm/client/coordinators/WaPrivacyCoordinator.js +131 -0
  85. package/dist/esm/client/coordinators/WaProfileCoordinator.js +209 -0
  86. package/dist/esm/client/coordinators/WaRetryCoordinator.js +244 -59
  87. package/dist/esm/client/coordinators/WaStreamControlCoordinator.js +19 -12
  88. package/dist/esm/client/coordinators/WaTrustedContactTokenCoordinator.js +162 -0
  89. package/dist/esm/client/dirty.js +69 -43
  90. package/dist/esm/client/events/chat.js +4 -3
  91. package/dist/esm/client/events/devices.js +68 -0
  92. package/dist/esm/client/events/group.js +53 -39
  93. package/dist/esm/client/events/identity.js +19 -0
  94. package/dist/esm/client/events/privacy-token.js +36 -0
  95. package/dist/esm/client/history-sync.js +91 -60
  96. package/dist/esm/client/incoming.js +61 -28
  97. package/dist/esm/client/mailbox.js +24 -23
  98. package/dist/esm/client/messages.js +108 -32
  99. package/dist/esm/client/messaging/fanout.js +196 -0
  100. package/dist/esm/client/messaging/key-protocol.js +127 -0
  101. package/dist/esm/client/messaging/participants.js +190 -0
  102. package/dist/esm/client/persistence/WriteBehindPersistence.js +125 -0
  103. package/dist/esm/client/tokens/cs-token.js +46 -0
  104. package/dist/esm/client/tokens/tc-token.js +18 -0
  105. package/dist/esm/crypto/core/hkdf.js +3 -8
  106. package/dist/esm/crypto/core/index.js +2 -3
  107. package/dist/esm/crypto/core/keys.js +3 -4
  108. package/dist/esm/crypto/core/nonce.js +2 -0
  109. package/dist/esm/crypto/core/primitives.js +12 -22
  110. package/dist/esm/crypto/core/random.js +25 -23
  111. package/dist/esm/crypto/curves/Ed25519.js +4 -5
  112. package/dist/esm/crypto/curves/X25519.js +35 -19
  113. package/dist/esm/crypto/index.js +0 -1
  114. package/dist/esm/crypto/math/constants.js +12 -35
  115. package/dist/esm/crypto/math/edwards.js +174 -47
  116. package/dist/esm/crypto/math/fe.js +691 -0
  117. package/dist/esm/crypto/math/mod.js +10 -1
  118. package/dist/esm/index.js +1 -1
  119. package/dist/esm/infra/log/ConsoleLogger.js +18 -17
  120. package/dist/esm/infra/log/PinoLogger.js +15 -9
  121. package/dist/esm/infra/log/types.js +11 -1
  122. package/dist/esm/infra/perf/BackgroundQueue.js +478 -0
  123. package/dist/esm/infra/perf/BoundedTaskQueue.js +16 -18
  124. package/dist/esm/infra/perf/PromiseDedup.js +20 -0
  125. package/dist/esm/infra/perf/SharedExclusiveGate.js +109 -0
  126. package/dist/esm/infra/perf/StoreLock.js +77 -0
  127. package/dist/esm/media/WaMediaCrypto.js +96 -16
  128. package/dist/esm/media/WaMediaTransferClient.js +251 -91
  129. package/dist/esm/media/conn.js +10 -6
  130. package/dist/esm/media/constants.js +6 -2
  131. package/dist/esm/message/WaMessageClient.js +30 -32
  132. package/dist/esm/message/ack.js +6 -6
  133. package/dist/esm/message/addon-crypto.js +59 -0
  134. package/dist/esm/message/content.js +195 -9
  135. package/dist/esm/message/icdc.js +76 -0
  136. package/dist/esm/message/incoming.js +129 -122
  137. package/dist/esm/message/index.js +2 -0
  138. package/dist/esm/message/phash.js +3 -1
  139. package/dist/esm/message/reporting-token.js +425 -0
  140. package/dist/esm/message/use-case-secret.js +49 -0
  141. package/dist/esm/protocol/appstate.js +27 -0
  142. package/dist/esm/protocol/browser.js +10 -18
  143. package/dist/esm/protocol/constants.js +6 -3
  144. package/dist/esm/protocol/defaults.js +6 -0
  145. package/dist/esm/protocol/index.js +2 -11
  146. package/dist/esm/protocol/jid.js +133 -52
  147. package/dist/esm/protocol/media.js +3 -3
  148. package/dist/esm/protocol/message.js +61 -1
  149. package/dist/esm/protocol/nodes.js +4 -0
  150. package/dist/esm/protocol/notification.js +3 -1
  151. package/dist/esm/protocol/privacy-token.js +17 -0
  152. package/dist/esm/protocol/privacy.js +55 -0
  153. package/dist/esm/protocol/stream.js +26 -1
  154. package/dist/esm/protocol/usync.js +11 -0
  155. package/dist/esm/retry/codec.js +216 -0
  156. package/dist/esm/retry/constants.js +1 -1
  157. package/dist/esm/retry/index.js +3 -2
  158. package/dist/esm/retry/parse.js +88 -86
  159. package/dist/esm/retry/replay.js +54 -51
  160. package/dist/esm/retry/tracker.js +94 -0
  161. package/dist/esm/signal/api/SignalDeviceSyncApi.js +276 -92
  162. package/dist/esm/signal/api/SignalDigestSyncApi.js +17 -8
  163. package/dist/esm/signal/api/SignalIdentitySyncApi.js +67 -37
  164. package/dist/esm/signal/api/SignalMissingPreKeysSyncApi.js +86 -67
  165. package/dist/esm/signal/api/SignalRotateKeyApi.js +4 -2
  166. package/dist/esm/signal/api/SignalSessionSyncApi.js +36 -34
  167. package/dist/esm/signal/api/result-map.js +10 -0
  168. package/dist/esm/signal/constants.js +0 -4
  169. package/dist/esm/signal/crypto/WaAdvSignature.js +13 -9
  170. package/dist/esm/signal/{store/sqlite.js → encoding.js} +93 -60
  171. package/dist/esm/signal/group/SenderKeyChain.js +28 -23
  172. package/dist/esm/signal/group/SenderKeyCodec.js +5 -6
  173. package/dist/esm/signal/group/SenderKeyManager.js +144 -115
  174. package/dist/esm/signal/index.js +2 -0
  175. package/dist/esm/signal/registration/keygen.js +6 -2
  176. package/dist/esm/signal/registration/utils.js +1 -0
  177. package/dist/esm/signal/session/SignalProtocol.js +164 -53
  178. package/dist/esm/signal/session/SignalRatchet.js +24 -15
  179. package/dist/esm/signal/session/SignalSession.js +14 -9
  180. package/dist/esm/signal/session/resolver.js +221 -0
  181. package/dist/esm/store/contracts/privacy-token.store.js +1 -0
  182. package/dist/esm/store/createStore.js +100 -188
  183. package/dist/esm/store/index.js +1 -10
  184. package/dist/esm/store/locks/appstate.lock.js +26 -0
  185. package/dist/esm/store/locks/auth.lock.js +15 -0
  186. package/dist/esm/store/locks/contact.lock.js +20 -0
  187. package/dist/esm/store/locks/device-list.lock.js +20 -0
  188. package/dist/esm/store/locks/message.lock.js +21 -0
  189. package/dist/esm/store/locks/participants.lock.js +20 -0
  190. package/dist/esm/store/locks/privacy-token.lock.js +18 -0
  191. package/dist/esm/store/locks/retry.lock.js +29 -0
  192. package/dist/esm/store/locks/sender-key.lock.js +52 -0
  193. package/dist/esm/store/locks/signal.lock.js +63 -0
  194. package/dist/esm/store/locks/thread.lock.js +21 -0
  195. package/dist/esm/store/noop.store.js +4 -7
  196. package/dist/esm/store/providers/memory/appstate.store.js +38 -16
  197. package/dist/esm/store/providers/memory/contact.store.js +5 -0
  198. package/dist/esm/store/providers/memory/device-list.store.js +12 -34
  199. package/dist/esm/store/providers/memory/message.store.js +11 -5
  200. package/dist/esm/store/providers/memory/participants.store.js +1 -8
  201. package/dist/esm/store/providers/memory/privacy-token.store.js +43 -0
  202. package/dist/esm/store/providers/memory/retry.store.js +77 -2
  203. package/dist/esm/store/providers/memory/sender-key.store.js +11 -8
  204. package/dist/esm/store/providers/memory/signal.store.js +47 -18
  205. package/dist/esm/store/providers/memory/thread.store.js +5 -0
  206. package/dist/esm/transport/WaComms.js +28 -24
  207. package/dist/esm/transport/WaWebSocket.js +115 -18
  208. package/dist/esm/transport/binary/constants.js +0 -30
  209. package/dist/esm/transport/binary/decoder.js +8 -8
  210. package/dist/esm/transport/binary/encoder.js +10 -9
  211. package/dist/esm/transport/binary/index.js +0 -1
  212. package/dist/esm/transport/index.js +1 -0
  213. package/dist/esm/transport/keepalive/WaKeepAlive.js +2 -8
  214. package/dist/esm/transport/node/WaNodeOrchestrator.js +25 -21
  215. package/dist/esm/transport/node/WaNodeTransport.js +0 -3
  216. package/dist/esm/transport/node/builders/{accountSync.js → account-sync.js} +16 -36
  217. package/dist/esm/transport/node/builders/business.js +129 -0
  218. package/dist/esm/transport/node/builders/global.js +370 -0
  219. package/dist/esm/transport/node/builders/index.js +7 -3
  220. package/dist/esm/transport/node/builders/message.js +63 -230
  221. package/dist/esm/transport/node/builders/pairing.js +2 -27
  222. package/dist/esm/transport/node/builders/privacy-token.js +41 -0
  223. package/dist/esm/transport/node/builders/privacy.js +48 -0
  224. package/dist/esm/transport/node/builders/profile.js +70 -0
  225. package/dist/esm/transport/node/builders/retry.js +10 -22
  226. package/dist/esm/transport/node/builders/usync.js +45 -0
  227. package/dist/esm/transport/node/helpers.js +125 -5
  228. package/dist/esm/transport/node/usync.js +5 -0
  229. package/dist/esm/transport/node/xml.js +35 -14
  230. package/dist/esm/transport/noise/WaClientPayload.js +10 -10
  231. package/dist/esm/transport/noise/WaFrameCodec.js +48 -33
  232. package/dist/esm/transport/noise/WaNoiseCert.js +4 -7
  233. package/dist/esm/transport/noise/WaNoiseSession.js +77 -29
  234. package/dist/esm/transport/noise/WaNoiseSocket.js +8 -4
  235. package/dist/esm/transport/proxy.js +27 -0
  236. package/dist/esm/transport/stream/parse.js +17 -48
  237. package/dist/esm/util/bytes.js +67 -45
  238. package/dist/esm/util/coercion.js +6 -14
  239. package/dist/esm/util/index.js +5 -0
  240. package/dist/esm/util/primitives.js +40 -14
  241. package/dist/index.js +7 -1
  242. package/dist/infra/log/ConsoleLogger.js +18 -17
  243. package/dist/infra/log/PinoLogger.js +15 -9
  244. package/dist/infra/log/types.js +12 -0
  245. package/dist/infra/perf/BackgroundQueue.js +482 -0
  246. package/dist/infra/perf/BoundedTaskQueue.js +16 -18
  247. package/dist/infra/perf/PromiseDedup.js +24 -0
  248. package/dist/infra/perf/SharedExclusiveGate.js +113 -0
  249. package/dist/infra/perf/StoreLock.js +81 -0
  250. package/dist/media/WaMediaCrypto.js +95 -15
  251. package/dist/media/WaMediaTransferClient.js +284 -91
  252. package/dist/media/conn.js +10 -6
  253. package/dist/media/constants.js +6 -2
  254. package/dist/message/WaMessageClient.js +31 -33
  255. package/dist/message/ack.js +6 -6
  256. package/dist/message/addon-crypto.js +65 -0
  257. package/dist/message/content.js +198 -9
  258. package/dist/message/icdc.js +81 -0
  259. package/dist/message/incoming.js +127 -120
  260. package/dist/message/index.js +2 -0
  261. package/dist/message/phash.js +3 -1
  262. package/dist/message/reporting-token.js +429 -0
  263. package/dist/message/use-case-secret.js +55 -0
  264. package/dist/protocol/appstate.js +28 -1
  265. package/dist/protocol/browser.js +10 -18
  266. package/dist/protocol/constants.js +26 -1
  267. package/dist/protocol/defaults.js +6 -0
  268. package/dist/protocol/index.js +23 -42
  269. package/dist/protocol/jid.js +140 -52
  270. package/dist/protocol/media.js +3 -3
  271. package/dist/protocol/message.js +62 -2
  272. package/dist/protocol/nodes.js +4 -0
  273. package/dist/protocol/notification.js +3 -1
  274. package/dist/protocol/privacy-token.js +20 -0
  275. package/dist/protocol/privacy.js +58 -0
  276. package/dist/protocol/stream.js +27 -2
  277. package/dist/protocol/usync.js +14 -0
  278. package/dist/retry/codec.js +220 -0
  279. package/dist/retry/constants.js +1 -1
  280. package/dist/retry/index.js +7 -5
  281. package/dist/retry/parse.js +88 -85
  282. package/dist/retry/replay.js +52 -49
  283. package/dist/retry/tracker.js +97 -0
  284. package/dist/signal/api/SignalDeviceSyncApi.js +273 -89
  285. package/dist/signal/api/SignalDigestSyncApi.js +17 -8
  286. package/dist/signal/api/SignalIdentitySyncApi.js +66 -36
  287. package/dist/signal/api/SignalMissingPreKeysSyncApi.js +82 -63
  288. package/dist/signal/api/SignalRotateKeyApi.js +4 -2
  289. package/dist/signal/api/SignalSessionSyncApi.js +36 -34
  290. package/dist/signal/api/result-map.js +13 -0
  291. package/dist/signal/constants.js +1 -5
  292. package/dist/signal/crypto/WaAdvSignature.js +11 -7
  293. package/dist/signal/{store/sqlite.js → encoding.js} +94 -61
  294. package/dist/signal/group/SenderKeyChain.js +27 -22
  295. package/dist/signal/group/SenderKeyCodec.js +5 -6
  296. package/dist/signal/group/SenderKeyManager.js +144 -115
  297. package/dist/signal/index.js +15 -1
  298. package/dist/signal/registration/keygen.js +6 -2
  299. package/dist/signal/registration/utils.js +1 -0
  300. package/dist/signal/session/SignalProtocol.js +164 -53
  301. package/dist/signal/session/SignalRatchet.js +24 -15
  302. package/dist/signal/session/SignalSession.js +14 -9
  303. package/dist/signal/session/resolver.js +224 -0
  304. package/dist/store/contracts/privacy-token.store.js +2 -0
  305. package/dist/store/createStore.js +100 -188
  306. package/dist/store/index.js +15 -33
  307. package/dist/store/locks/appstate.lock.js +29 -0
  308. package/dist/store/locks/auth.lock.js +18 -0
  309. package/dist/store/locks/contact.lock.js +23 -0
  310. package/dist/store/locks/device-list.lock.js +23 -0
  311. package/dist/store/locks/message.lock.js +24 -0
  312. package/dist/store/locks/participants.lock.js +23 -0
  313. package/dist/store/locks/privacy-token.lock.js +21 -0
  314. package/dist/store/locks/retry.lock.js +32 -0
  315. package/dist/store/locks/sender-key.lock.js +55 -0
  316. package/dist/store/locks/signal.lock.js +66 -0
  317. package/dist/store/locks/thread.lock.js +24 -0
  318. package/dist/store/noop.store.js +4 -7
  319. package/dist/store/providers/memory/appstate.store.js +36 -14
  320. package/dist/store/providers/memory/contact.store.js +5 -0
  321. package/dist/store/providers/memory/device-list.store.js +12 -34
  322. package/dist/store/providers/memory/message.store.js +11 -5
  323. package/dist/store/providers/memory/participants.store.js +1 -8
  324. package/dist/store/providers/memory/privacy-token.store.js +47 -0
  325. package/dist/store/providers/memory/retry.store.js +77 -2
  326. package/dist/store/providers/memory/sender-key.store.js +14 -11
  327. package/dist/store/providers/memory/signal.store.js +54 -25
  328. package/dist/store/providers/memory/thread.store.js +5 -0
  329. package/dist/transport/WaComms.js +30 -26
  330. package/dist/transport/WaWebSocket.js +148 -18
  331. package/dist/transport/binary/constants.js +1 -31
  332. package/dist/transport/binary/decoder.js +8 -8
  333. package/dist/transport/binary/encoder.js +10 -9
  334. package/dist/transport/binary/index.js +0 -4
  335. package/dist/transport/index.js +7 -1
  336. package/dist/transport/keepalive/WaKeepAlive.js +1 -7
  337. package/dist/transport/node/WaNodeOrchestrator.js +25 -21
  338. package/dist/transport/node/WaNodeTransport.js +0 -3
  339. package/dist/transport/node/builders/{accountSync.js → account-sync.js} +15 -35
  340. package/dist/transport/node/builders/business.js +137 -0
  341. package/dist/transport/node/builders/global.js +375 -0
  342. package/dist/transport/node/builders/index.js +29 -17
  343. package/dist/transport/node/builders/message.js +64 -236
  344. package/dist/transport/node/builders/pairing.js +2 -29
  345. package/dist/transport/node/builders/privacy-token.js +46 -0
  346. package/dist/transport/node/builders/privacy.js +55 -0
  347. package/dist/transport/node/builders/profile.js +78 -0
  348. package/dist/transport/node/builders/retry.js +9 -21
  349. package/dist/transport/node/builders/usync.js +49 -0
  350. package/dist/transport/node/helpers.js +131 -4
  351. package/dist/transport/node/usync.js +8 -0
  352. package/dist/transport/node/xml.js +35 -14
  353. package/dist/transport/noise/WaClientPayload.js +13 -13
  354. package/dist/transport/noise/WaFrameCodec.js +47 -32
  355. package/dist/transport/noise/WaNoiseCert.js +5 -8
  356. package/dist/transport/noise/WaNoiseSession.js +77 -29
  357. package/dist/transport/noise/WaNoiseSocket.js +8 -4
  358. package/dist/transport/proxy.js +34 -0
  359. package/dist/transport/stream/parse.js +20 -52
  360. package/dist/types/appstate/WaAppStateCrypto.d.ts +0 -1
  361. package/dist/types/appstate/WaAppStateSyncClient.d.ts +5 -2
  362. package/dist/types/appstate/constants.d.ts +1 -0
  363. package/dist/types/appstate/encoding.d.ts +7 -0
  364. package/dist/types/appstate/index.d.ts +3 -3
  365. package/dist/types/appstate/utils.d.ts +0 -3
  366. package/dist/types/auth/WaAuthClient.d.ts +10 -12
  367. package/dist/types/auth/flow/WaAuthCredentialsFlow.d.ts +1 -1
  368. package/dist/types/auth/index.d.ts +0 -4
  369. package/dist/types/auth/pairing/WaQrFlow.d.ts +1 -1
  370. package/dist/types/auth/types.d.ts +7 -9
  371. package/dist/types/client/WaClient.d.ts +42 -25
  372. package/dist/types/client/WaClientFactory.d.ts +33 -26
  373. package/dist/types/client/connection/WaConnectionManager.d.ts +66 -0
  374. package/dist/types/client/connection/WaKeyShareCoordinator.d.ts +14 -0
  375. package/dist/types/client/connection/WaReceiptQueue.d.ts +13 -0
  376. package/dist/types/client/coordinators/WaAppStateMutationCoordinator.d.ts +46 -0
  377. package/dist/types/client/coordinators/WaBusinessCoordinator.d.ts +57 -0
  378. package/dist/types/client/coordinators/WaIncomingNodeCoordinator.d.ts +3 -2
  379. package/dist/types/client/coordinators/WaMessageDispatchCoordinator.d.ts +29 -38
  380. package/dist/types/client/coordinators/WaPassiveTasksCoordinator.d.ts +4 -0
  381. package/dist/types/client/coordinators/WaPrivacyCoordinator.d.ts +26 -0
  382. package/dist/types/client/coordinators/WaProfileCoordinator.d.ts +36 -0
  383. package/dist/types/client/coordinators/WaRetryCoordinator.d.ts +8 -0
  384. package/dist/types/client/coordinators/WaStreamControlCoordinator.d.ts +3 -2
  385. package/dist/types/client/coordinators/WaTrustedContactTokenCoordinator.d.ts +45 -0
  386. package/dist/types/client/dirty.d.ts +1 -0
  387. package/dist/types/client/events/devices.d.ts +20 -0
  388. package/dist/types/client/events/group.d.ts +2 -1
  389. package/dist/types/client/events/identity.d.ts +9 -0
  390. package/dist/types/client/events/privacy-token.d.ts +7 -0
  391. package/dist/types/client/history-sync.d.ts +9 -6
  392. package/dist/types/client/incoming.d.ts +3 -1
  393. package/dist/types/client/index.d.ts +1 -1
  394. package/dist/types/client/mailbox.d.ts +3 -5
  395. package/dist/types/client/messages.d.ts +1 -2
  396. package/dist/types/client/messaging/fanout.d.ts +14 -0
  397. package/dist/types/client/messaging/key-protocol.d.ts +18 -0
  398. package/dist/types/client/messaging/participants.d.ts +13 -0
  399. package/dist/types/client/persistence/WriteBehindPersistence.d.ts +34 -0
  400. package/dist/types/client/tokens/cs-token.d.ts +10 -0
  401. package/dist/types/client/tokens/tc-token.d.ts +5 -0
  402. package/dist/types/client/types.d.ts +75 -4
  403. package/dist/types/crypto/core/hkdf.d.ts +0 -6
  404. package/dist/types/crypto/core/index.d.ts +2 -3
  405. package/dist/types/crypto/core/nonce.d.ts +2 -0
  406. package/dist/types/crypto/core/primitives.d.ts +0 -1
  407. package/dist/types/crypto/core/random.d.ts +2 -7
  408. package/dist/types/crypto/index.d.ts +0 -1
  409. package/dist/types/crypto/math/constants.d.ts +4 -2
  410. package/dist/types/crypto/math/fe.d.ts +30 -0
  411. package/dist/types/crypto/math/mod.d.ts +0 -2
  412. package/dist/types/crypto/math/types.d.ts +11 -4
  413. package/dist/types/index.d.ts +5 -3
  414. package/dist/types/infra/log/ConsoleLogger.d.ts +2 -1
  415. package/dist/types/infra/log/PinoLogger.d.ts +1 -1
  416. package/dist/types/infra/log/types.d.ts +1 -0
  417. package/dist/types/infra/perf/BackgroundQueue.d.ts +58 -0
  418. package/dist/types/infra/perf/BoundedTaskQueue.d.ts +1 -1
  419. package/dist/types/infra/perf/PromiseDedup.d.ts +4 -0
  420. package/dist/types/infra/perf/SharedExclusiveGate.d.ts +17 -0
  421. package/dist/types/infra/perf/StoreLock.d.ts +10 -0
  422. package/dist/types/media/WaMediaCrypto.d.ts +3 -2
  423. package/dist/types/media/WaMediaTransferClient.d.ts +16 -15
  424. package/dist/types/media/constants.d.ts +1 -1
  425. package/dist/types/media/index.d.ts +1 -1
  426. package/dist/types/media/types.d.ts +15 -2
  427. package/dist/types/message/addon-crypto.d.ts +25 -0
  428. package/dist/types/message/content.d.ts +8 -0
  429. package/dist/types/message/icdc.d.ts +13 -0
  430. package/dist/types/message/index.d.ts +2 -0
  431. package/dist/types/message/reporting-token.d.ts +18 -0
  432. package/dist/types/message/types.d.ts +45 -6
  433. package/dist/types/message/use-case-secret.d.ts +20 -0
  434. package/dist/types/protocol/appstate.d.ts +47 -0
  435. package/dist/types/protocol/constants.d.ts +8 -3
  436. package/dist/types/protocol/defaults.d.ts +6 -0
  437. package/dist/types/protocol/index.d.ts +2 -11
  438. package/dist/types/protocol/jid.d.ts +22 -5
  439. package/dist/types/protocol/message.d.ts +60 -0
  440. package/dist/types/protocol/nodes.d.ts +4 -0
  441. package/dist/types/protocol/notification.d.ts +2 -0
  442. package/dist/types/protocol/privacy-token.d.ts +17 -0
  443. package/dist/types/protocol/privacy.d.ts +75 -0
  444. package/dist/types/protocol/stream.d.ts +30 -0
  445. package/dist/types/protocol/usync.d.ts +11 -0
  446. package/dist/types/retry/codec.d.ts +3 -0
  447. package/dist/types/retry/index.d.ts +4 -3
  448. package/dist/types/retry/parse.d.ts +5 -2
  449. package/dist/types/retry/replay.d.ts +0 -4
  450. package/dist/types/retry/tracker.d.ts +20 -0
  451. package/dist/types/retry/types.d.ts +10 -4
  452. package/dist/types/signal/api/SignalDeviceSyncApi.d.ts +15 -2
  453. package/dist/types/signal/api/SignalDigestSyncApi.d.ts +6 -0
  454. package/dist/types/signal/api/SignalIdentitySyncApi.d.ts +2 -0
  455. package/dist/types/signal/api/SignalRotateKeyApi.d.ts +4 -5
  456. package/dist/types/signal/api/SignalSessionSyncApi.d.ts +8 -6
  457. package/dist/types/signal/api/result-map.d.ts +1 -0
  458. package/dist/types/signal/constants.d.ts +0 -3
  459. package/dist/types/signal/{store/sqlite.d.ts → encoding.d.ts} +3 -3
  460. package/dist/types/signal/group/SenderKeyCodec.d.ts +4 -6
  461. package/dist/types/signal/group/SenderKeyManager.d.ts +10 -5
  462. package/dist/types/signal/index.d.ts +3 -0
  463. package/dist/types/signal/session/SignalProtocol.d.ts +19 -4
  464. package/dist/types/signal/session/resolver.d.ts +22 -0
  465. package/dist/types/store/contracts/appstate.store.d.ts +4 -1
  466. package/dist/types/store/contracts/contact.store.d.ts +1 -0
  467. package/dist/types/store/contracts/device-list.store.d.ts +0 -3
  468. package/dist/types/store/contracts/message.store.d.ts +1 -0
  469. package/dist/types/store/contracts/participants.store.d.ts +0 -1
  470. package/dist/types/store/contracts/privacy-token.store.d.ts +16 -0
  471. package/dist/types/store/contracts/retry.store.d.ts +7 -0
  472. package/dist/types/store/contracts/sender-key.store.d.ts +0 -1
  473. package/dist/types/store/contracts/signal.store.d.ts +13 -0
  474. package/dist/types/store/contracts/thread.store.d.ts +1 -0
  475. package/dist/types/store/createStore.d.ts +1 -1
  476. package/dist/types/store/index.d.ts +5 -13
  477. package/dist/types/store/locks/appstate.lock.d.ts +3 -0
  478. package/dist/types/store/locks/auth.lock.d.ts +3 -0
  479. package/dist/types/store/locks/contact.lock.d.ts +3 -0
  480. package/dist/types/store/locks/device-list.lock.d.ts +2 -0
  481. package/dist/types/store/locks/message.lock.d.ts +3 -0
  482. package/dist/types/store/locks/participants.lock.d.ts +2 -0
  483. package/dist/types/store/locks/privacy-token.lock.d.ts +2 -0
  484. package/dist/types/store/locks/retry.lock.d.ts +2 -0
  485. package/dist/types/store/locks/sender-key.lock.d.ts +3 -0
  486. package/dist/types/store/locks/signal.lock.d.ts +3 -0
  487. package/dist/types/store/locks/thread.lock.d.ts +3 -0
  488. package/dist/types/store/providers/memory/appstate.store.d.ts +3 -1
  489. package/dist/types/store/providers/memory/contact.store.d.ts +1 -0
  490. package/dist/types/store/providers/memory/device-list.store.d.ts +0 -3
  491. package/dist/types/store/providers/memory/message.store.d.ts +1 -0
  492. package/dist/types/store/providers/memory/participants.store.d.ts +0 -1
  493. package/dist/types/store/providers/memory/privacy-token.store.d.ts +13 -0
  494. package/dist/types/store/providers/memory/retry.store.d.ts +8 -0
  495. package/dist/types/store/providers/memory/sender-key.store.d.ts +0 -1
  496. package/dist/types/store/providers/memory/signal.store.d.ts +8 -1
  497. package/dist/types/store/providers/memory/thread.store.d.ts +1 -0
  498. package/dist/types/store/types.d.ts +49 -58
  499. package/dist/types/transport/WaWebSocket.d.ts +3 -1
  500. package/dist/types/transport/binary/constants.d.ts +0 -30
  501. package/dist/types/transport/binary/index.d.ts +0 -1
  502. package/dist/types/transport/index.d.ts +2 -1
  503. package/dist/types/transport/keepalive/WaKeepAlive.d.ts +0 -1
  504. package/dist/types/transport/node/WaNodeOrchestrator.d.ts +3 -4
  505. package/dist/types/transport/node/WaNodeTransport.d.ts +0 -9
  506. package/dist/types/transport/node/builders/business.d.ts +29 -0
  507. package/dist/types/transport/node/builders/global.d.ts +102 -0
  508. package/dist/types/transport/node/builders/group.d.ts +4 -6
  509. package/dist/types/transport/node/builders/index.d.ts +7 -3
  510. package/dist/types/transport/node/builders/message.d.ts +20 -30
  511. package/dist/types/transport/node/builders/pairing.d.ts +0 -2
  512. package/dist/types/transport/node/builders/privacy-token.d.ts +9 -0
  513. package/dist/types/transport/node/builders/privacy.d.ts +7 -0
  514. package/dist/types/transport/node/builders/profile.d.ts +8 -0
  515. package/dist/types/transport/node/builders/retry.d.ts +2 -5
  516. package/dist/types/transport/node/builders/usync.d.ts +21 -0
  517. package/dist/types/transport/node/helpers.d.ts +13 -0
  518. package/dist/types/transport/node/usync.d.ts +2 -0
  519. package/dist/types/transport/noise/WaFrameCodec.d.ts +3 -0
  520. package/dist/types/transport/noise/WaNoiseSession.d.ts +4 -2
  521. package/dist/types/transport/noise/WaNoiseSocket.d.ts +4 -2
  522. package/dist/types/transport/proxy.d.ts +6 -0
  523. package/dist/types/transport/stream/parse.d.ts +0 -1
  524. package/dist/types/transport/types.d.ts +18 -1
  525. package/dist/types/util/bytes.d.ts +5 -0
  526. package/dist/types/util/index.d.ts +5 -0
  527. package/dist/types/util/primitives.d.ts +2 -0
  528. package/dist/util/bytes.js +72 -46
  529. package/dist/util/coercion.js +6 -14
  530. package/dist/util/index.js +23 -0
  531. package/dist/util/primitives.js +42 -14
  532. package/package.json +52 -9
  533. package/proto/index.js +1 -1
  534. package/dist/crypto/core/constants.js +0 -4
  535. package/dist/crypto/core/encoding.js +0 -29
  536. package/dist/esm/crypto/core/constants.js +0 -1
  537. package/dist/esm/crypto/core/encoding.js +0 -25
  538. package/dist/esm/retry/outbound.js +0 -83
  539. package/dist/esm/store/providers/sqlite/BaseSqliteStore.js +0 -37
  540. package/dist/esm/store/providers/sqlite/appstate.store.js +0 -169
  541. package/dist/esm/store/providers/sqlite/auth.store.js +0 -176
  542. package/dist/esm/store/providers/sqlite/connection.js +0 -240
  543. package/dist/esm/store/providers/sqlite/contact.store.js +0 -61
  544. package/dist/esm/store/providers/sqlite/device-list.store.js +0 -155
  545. package/dist/esm/store/providers/sqlite/message.store.js +0 -119
  546. package/dist/esm/store/providers/sqlite/migrations.js +0 -347
  547. package/dist/esm/store/providers/sqlite/participants.store.js +0 -85
  548. package/dist/esm/store/providers/sqlite/retry.store.js +0 -144
  549. package/dist/esm/store/providers/sqlite/sender-key.store.js +0 -203
  550. package/dist/esm/store/providers/sqlite/signal.store.js +0 -353
  551. package/dist/esm/store/providers/sqlite/thread.store.js +0 -72
  552. package/dist/esm/util/base64.js +0 -18
  553. package/dist/esm/util/signal-address.js +0 -5
  554. package/dist/retry/outbound.js +0 -88
  555. package/dist/store/providers/sqlite/BaseSqliteStore.js +0 -41
  556. package/dist/store/providers/sqlite/appstate.store.js +0 -173
  557. package/dist/store/providers/sqlite/auth.store.js +0 -180
  558. package/dist/store/providers/sqlite/connection.js +0 -276
  559. package/dist/store/providers/sqlite/contact.store.js +0 -65
  560. package/dist/store/providers/sqlite/device-list.store.js +0 -159
  561. package/dist/store/providers/sqlite/message.store.js +0 -123
  562. package/dist/store/providers/sqlite/migrations.js +0 -350
  563. package/dist/store/providers/sqlite/participants.store.js +0 -89
  564. package/dist/store/providers/sqlite/retry.store.js +0 -148
  565. package/dist/store/providers/sqlite/sender-key.store.js +0 -207
  566. package/dist/store/providers/sqlite/signal.store.js +0 -357
  567. package/dist/store/providers/sqlite/thread.store.js +0 -76
  568. package/dist/types/appstate/store/sqlite.d.ts +0 -21
  569. package/dist/types/crypto/core/constants.d.ts +0 -1
  570. package/dist/types/crypto/core/encoding.d.ts +0 -11
  571. package/dist/types/retry/outbound.d.ts +0 -4
  572. package/dist/types/store/providers/sqlite/BaseSqliteStore.d.ts +0 -12
  573. package/dist/types/store/providers/sqlite/appstate.store.d.ts +0 -15
  574. package/dist/types/store/providers/sqlite/auth.store.d.ts +0 -10
  575. package/dist/types/store/providers/sqlite/connection.d.ts +0 -10
  576. package/dist/types/store/providers/sqlite/contact.store.d.ts +0 -10
  577. package/dist/types/store/providers/sqlite/device-list.store.d.ts +0 -18
  578. package/dist/types/store/providers/sqlite/message.store.d.ts +0 -11
  579. package/dist/types/store/providers/sqlite/migrations.d.ts +0 -3
  580. package/dist/types/store/providers/sqlite/participants.store.d.ts +0 -13
  581. package/dist/types/store/providers/sqlite/retry.store.d.ts +0 -16
  582. package/dist/types/store/providers/sqlite/sender-key.store.d.ts +0 -25
  583. package/dist/types/store/providers/sqlite/signal.store.d.ts +0 -46
  584. package/dist/types/store/providers/sqlite/thread.store.d.ts +0 -11
  585. package/dist/types/util/base64.d.ts +0 -4
  586. package/dist/types/util/signal-address.d.ts +0 -2
  587. package/dist/util/base64.js +0 -24
  588. package/dist/util/signal-address.js +0 -8
  589. /package/dist/types/transport/node/builders/{accountSync.d.ts → account-sync.d.ts} +0 -0
@@ -1,21 +1,27 @@
1
1
  import { proto } from '../../proto.js';
2
2
  import { WA_MESSAGE_TAGS } from '../../protocol/constants.js';
3
- import { isGroupOrBroadcastJid, normalizeDeviceJid, parseSignalAddressFromJid, toUserJid } from '../../protocol/jid.js';
3
+ import { isGroupOrBroadcastJid, normalizeDeviceJid, parseJidFull } from '../../protocol/jid.js';
4
4
  import { MAX_RETRY_ATTEMPTS, RETRY_KEYS_MIN_COUNT, RETRY_OUTBOUND_TTL_MS, RETRY_REASON } from '../../retry/constants.js';
5
- import { pickRetryStateMax } from '../../retry/outbound.js';
6
- import { parseRetryReceiptRequest } from '../../retry/parse.js';
5
+ import { parseRetryReceiptRequest, pickRetryStateMax } from '../../retry/parse.js';
7
6
  import { mapRetryReasonFromError } from '../../retry/reason.js';
8
7
  import { WaRetryReplayService } from '../../retry/replay.js';
9
8
  import { generatePreKeyPair } from '../../signal/registration/keygen.js';
10
- import { buildInboundRetryReceiptAckNode } from '../../transport/node/builders/message.js';
9
+ import { buildAckNode } from '../../transport/node/builders/global.js';
11
10
  import { buildRetryReceiptNode } from '../../transport/node/builders/retry.js';
11
+ import { uint8Equal } from '../../util/bytes.js';
12
+ import { setBoundedMapEntry } from '../../util/collections.js';
12
13
  import { toError } from '../../util/primitives.js';
14
+ const RETRY_CLEANUP_INTERVAL_MS = 30000;
15
+ const RETRY_SESSION_BASE_KEY_CACHE_MAX_ENTRIES = 8192;
13
16
  function getRetryReasonName(code) {
14
17
  if (code === undefined) {
15
18
  return undefined;
16
19
  }
17
- const entry = Object.entries(RETRY_REASON).find(([, value]) => value === code);
18
- return entry ? entry[0] : 'unknown';
20
+ for (const reasonName in RETRY_REASON) {
21
+ if (RETRY_REASON[reasonName] === code)
22
+ return reasonName;
23
+ }
24
+ return 'unknown';
19
25
  }
20
26
  function getRemoteRetryReasonLogFields(reason) {
21
27
  return {
@@ -26,6 +32,7 @@ function getRemoteRetryReasonLogFields(reason) {
26
32
  }
27
33
  export class WaRetryCoordinator {
28
34
  constructor(options) {
35
+ this.nextRetryCleanupAtMs = 0;
29
36
  this.logger = options.logger;
30
37
  this.retryStore = options.retryStore;
31
38
  this.retryTtlMs = this.retryStore.getTtlMs?.() ?? RETRY_OUTBOUND_TTL_MS;
@@ -47,6 +54,7 @@ export class WaRetryCoordinator {
47
54
  getCurrentSignedIdentity: this.getCurrentSignedIdentity
48
55
  });
49
56
  this.retryProcessingByMessageId = new Map();
57
+ this.retrySessionBaseKeys = new Map();
50
58
  }
51
59
  async onDecryptFailure(context, error) {
52
60
  try {
@@ -71,12 +79,23 @@ export class WaRetryCoordinator {
71
79
  if (!this.isRetryReceiptNode(receiptNode)) {
72
80
  return;
73
81
  }
82
+ let shouldAck = false;
74
83
  try {
75
- await this.retryStore.cleanupExpired(Date.now());
76
- const request = parseRetryReceiptRequest(receiptNode);
84
+ await this.maybeCleanupRetryStore(Date.now());
85
+ const expectedToJids = [];
86
+ const meJid = this.getCurrentMeJid()?.trim();
87
+ const meLid = this.getCurrentMeLid()?.trim();
88
+ if (meJid) {
89
+ expectedToJids.push(meJid);
90
+ }
91
+ if (meLid) {
92
+ expectedToJids.push(meLid);
93
+ }
94
+ const request = parseRetryReceiptRequest(receiptNode, expectedToJids.length > 0 ? { expectedToJids } : undefined);
77
95
  if (!request) {
78
96
  return;
79
97
  }
98
+ shouldAck = true;
80
99
  await this.handleParsedRetryRequest(receiptNode, request);
81
100
  }
82
101
  catch (error) {
@@ -88,7 +107,9 @@ export class WaRetryCoordinator {
88
107
  });
89
108
  }
90
109
  finally {
91
- await this.sendRetryAckSafe(receiptNode);
110
+ if (shouldAck) {
111
+ await this.sendRetryAckSafe(receiptNode);
112
+ }
92
113
  }
93
114
  }
94
115
  isRetryReceiptNode(node) {
@@ -97,10 +118,7 @@ export class WaRetryCoordinator {
97
118
  }
98
119
  async prepareDecryptFailureRetry(context, error) {
99
120
  const nowMs = Date.now();
100
- const [, registrationInfo] = await Promise.all([
101
- this.retryStore.cleanupExpired(nowMs),
102
- this.signalStore.getRegistrationInfo()
103
- ]);
121
+ const registrationInfo = await this.signalStore.getRegistrationInfo();
104
122
  if (!registrationInfo) {
105
123
  this.logger.warn('retry receipt skipped: missing local registration info', {
106
124
  id: context.stanzaId,
@@ -127,7 +145,6 @@ export class WaRetryCoordinator {
127
145
  to: context.from,
128
146
  participant: context.participant,
129
147
  recipient: context.recipient,
130
- from: this.getCurrentMeJid() ?? undefined,
131
148
  originalMsgId: context.stanzaId,
132
149
  retryCount: prepared.retryCount,
133
150
  t: prepared.timestamp,
@@ -195,6 +212,22 @@ export class WaRetryCoordinator {
195
212
  });
196
213
  return null;
197
214
  }
215
+ let requesterAddress;
216
+ let requesterNormalizedDeviceJid;
217
+ try {
218
+ const requesterParsed = parseJidFull(requesterJid);
219
+ requesterAddress = requesterParsed.address;
220
+ requesterNormalizedDeviceJid = requesterParsed.normalizedJid;
221
+ }
222
+ catch (error) {
223
+ this.logger.info('retry request rejected: invalid requester jid', {
224
+ id: request.stanzaId,
225
+ originalMsgId: request.originalMsgId,
226
+ requester: requesterJid,
227
+ message: toError(error).message
228
+ });
229
+ return null;
230
+ }
198
231
  if (request.retryCount >= MAX_RETRY_ATTEMPTS) {
199
232
  this.logger.info('retry request rejected: retry count exceeded', {
200
233
  id: request.stanzaId,
@@ -214,7 +247,7 @@ export class WaRetryCoordinator {
214
247
  });
215
248
  return null;
216
249
  }
217
- const sessionReady = await this.updateLocalSessionFromRetryRequest(request, requesterJid);
250
+ const sessionReady = await this.updateLocalSessionFromRetryRequest(request, requesterJid, requesterAddress, requesterNormalizedDeviceJid);
218
251
  if (!sessionReady) {
219
252
  this.logger.info('retry request rejected: missing compatible session', {
220
253
  id: request.stanzaId,
@@ -225,7 +258,7 @@ export class WaRetryCoordinator {
225
258
  });
226
259
  return null;
227
260
  }
228
- const authorization = await this.authorizeRetryRequest(request, outbound, requesterJid);
261
+ const authorization = await this.authorizeRetryRequest(request, outbound, requesterJid, requesterAddress, requesterNormalizedDeviceJid);
229
262
  if (!authorization.authorized) {
230
263
  this.logger.info('retry request rejected', {
231
264
  id: request.stanzaId,
@@ -239,6 +272,8 @@ export class WaRetryCoordinator {
239
272
  }
240
273
  return {
241
274
  requesterJid,
275
+ requesterAddress,
276
+ requesterNormalizedDeviceJid,
242
277
  outbound
243
278
  };
244
279
  }
@@ -258,20 +293,36 @@ export class WaRetryCoordinator {
258
293
  if (!nextState) {
259
294
  return;
260
295
  }
261
- const current = await this.retryStore.getOutboundMessage(messageId);
262
- if (!current) {
263
- return;
264
- }
265
- const merged = pickRetryStateMax(current.state, nextState);
266
- if (merged === current.state) {
267
- return;
268
- }
269
- const nowMs = Date.now();
270
- await this.retryStore.updateOutboundMessageState(messageId, merged, nowMs, nowMs + this.retryTtlMs);
296
+ await this.runRetryTaskSerialized(messageId, async () => {
297
+ const current = await this.retryStore.getOutboundMessage(messageId);
298
+ if (!current) {
299
+ return;
300
+ }
301
+ const nowMs = Date.now();
302
+ const expiresAtMs = nowMs + this.retryTtlMs;
303
+ const merged = pickRetryStateMax(current.state, nextState);
304
+ if (merged !== current.state) {
305
+ await this.retryStore.updateOutboundMessageState(messageId, merged, nowMs, expiresAtMs);
306
+ }
307
+ const requesterJid = receiptNode.attrs.participant ?? receiptNode.attrs.from;
308
+ if (!requesterJid) {
309
+ return;
310
+ }
311
+ try {
312
+ await this.retryStore.markOutboundRequesterDelivered(messageId, normalizeDeviceJid(requesterJid), nowMs, expiresAtMs);
313
+ }
314
+ catch (error) {
315
+ this.logger.warn('failed to update outbound requester delivery state', {
316
+ id: messageId,
317
+ requester: requesterJid,
318
+ message: toError(error).message
319
+ });
320
+ }
321
+ });
271
322
  }
272
323
  async runRetryTaskSerialized(messageId, task) {
273
324
  const previous = this.retryProcessingByMessageId.get(messageId) ?? Promise.resolve();
274
- const current = previous.catch(() => undefined).then(async () => task());
325
+ const current = previous.then(task);
275
326
  const tracker = current.then(() => undefined, () => undefined);
276
327
  this.retryProcessingByMessageId.set(messageId, tracker);
277
328
  try {
@@ -311,18 +362,47 @@ export class WaRetryCoordinator {
311
362
  : undefined
312
363
  };
313
364
  }
314
- async updateLocalSessionFromRetryRequest(request, requesterJid) {
315
- await this.markRetryRequesterSenderKeyAsStale(request, requesterJid);
316
- const address = parseSignalAddressFromJid(requesterJid);
317
- const currentSession = await this.signalStore.getSession(address);
318
- if (currentSession && request.regId > 0 && currentSession.remote.regId !== request.regId) {
319
- await this.signalStore.deleteSession(address);
365
+ async updateLocalSessionFromRetryRequest(request, requesterJid, requesterAddress, requesterNormalizedDeviceJid) {
366
+ const [, currentSession] = await Promise.all([
367
+ this.markRetryRequesterSenderKeyAsStale(request, requesterJid, requesterAddress),
368
+ this.signalStore.getSession(requesterAddress)
369
+ ]);
370
+ const regIdMismatch = !!currentSession && request.regId > 0 && currentSession.remote.regId !== request.regId;
371
+ if (regIdMismatch && !request.keyBundle) {
372
+ await this.signalStore.deleteSession(requesterAddress);
320
373
  }
321
374
  if (request.keyBundle) {
322
- if (!request.keyBundle.key) {
375
+ if (!request.keyBundle.key || !request.keyBundle.skey.signature) {
323
376
  return false;
324
377
  }
325
- await this.signalProtocol.establishOutgoingSession(address, {
378
+ if (request.offline) {
379
+ if (!currentSession) {
380
+ this.logger.info('retry request rejected: offline retry missing existing session', {
381
+ id: request.stanzaId,
382
+ originalMsgId: request.originalMsgId,
383
+ requester: requesterJid,
384
+ remoteRetryCount: request.retryCount,
385
+ ...getRemoteRetryReasonLogFields(request.retryReason)
386
+ });
387
+ await this.signalStore.deleteSession(requesterAddress);
388
+ return false;
389
+ }
390
+ if (regIdMismatch) {
391
+ this.logger.info('retry request rejected: offline retry registration id mismatch', {
392
+ id: request.stanzaId,
393
+ originalMsgId: request.originalMsgId,
394
+ requester: requesterJid,
395
+ remoteRetryCount: request.retryCount,
396
+ ...getRemoteRetryReasonLogFields(request.retryReason)
397
+ });
398
+ await this.signalStore.deleteSession(requesterAddress);
399
+ return false;
400
+ }
401
+ }
402
+ else if (regIdMismatch) {
403
+ await this.signalStore.deleteSession(requesterAddress);
404
+ }
405
+ await this.signalProtocol.establishOutgoingSession(requesterAddress, {
326
406
  regId: request.regId,
327
407
  identity: request.keyBundle.identity,
328
408
  signedKey: {
@@ -335,25 +415,57 @@ export class WaRetryCoordinator {
335
415
  publicKey: request.keyBundle.key.publicKey
336
416
  }
337
417
  });
418
+ return this.applySessionBaseKeyPolicy(request, requesterJid, requesterAddress, requesterNormalizedDeviceJid);
419
+ }
420
+ const sessionStillExists = currentSession !== null && !regIdMismatch;
421
+ if (sessionStillExists) {
422
+ return this.applySessionBaseKeyPolicy(request, requesterJid, requesterAddress, requesterNormalizedDeviceJid);
423
+ }
424
+ const fetched = await this.fetchMissingPreKeysSession(requesterJid, requesterAddress, requesterNormalizedDeviceJid, request.regId);
425
+ if (!fetched) {
426
+ return false;
427
+ }
428
+ await this.signalProtocol.establishOutgoingSession(requesterAddress, fetched);
429
+ return this.applySessionBaseKeyPolicy(request, requesterJid, requesterAddress, requesterNormalizedDeviceJid);
430
+ }
431
+ async applySessionBaseKeyPolicy(request, requesterJid, requesterAddress, requesterNormalizedDeviceJid) {
432
+ if (request.retryCount < 2) {
433
+ return true;
434
+ }
435
+ const currentSession = await this.signalStore.getSession(requesterAddress);
436
+ const sessionBaseKey = currentSession?.aliceBaseKey ?? null;
437
+ if (!sessionBaseKey) {
338
438
  return true;
339
439
  }
340
- const hasSession = await this.signalProtocol.hasSession(address);
341
- if (hasSession) {
440
+ const expiresAtMs = Date.now() + this.retryTtlMs;
441
+ if (request.retryCount === 2) {
442
+ this.setRetrySessionBaseKey(request.originalMsgId, requesterNormalizedDeviceJid, sessionBaseKey, expiresAtMs);
342
443
  return true;
343
444
  }
344
- const fetched = await this.fetchMissingPreKeysSession(requesterJid, request.regId);
445
+ const saved = this.getRetrySessionBaseKey(request.originalMsgId, requesterNormalizedDeviceJid);
446
+ if (!saved || !uint8Equal(saved.baseKey, sessionBaseKey)) {
447
+ return true;
448
+ }
449
+ await this.signalStore.deleteSession(requesterAddress);
450
+ this.logger.info('retry request forcing session refresh due to repeated base key', {
451
+ id: request.stanzaId,
452
+ originalMsgId: request.originalMsgId,
453
+ requester: requesterJid,
454
+ remoteRetryCount: request.retryCount,
455
+ ...getRemoteRetryReasonLogFields(request.retryReason)
456
+ });
457
+ const fetched = await this.fetchMissingPreKeysSession(requesterJid, requesterAddress, requesterNormalizedDeviceJid, request.regId);
345
458
  if (!fetched) {
346
459
  return false;
347
460
  }
348
- await this.signalProtocol.establishOutgoingSession(address, fetched);
461
+ await this.signalProtocol.establishOutgoingSession(requesterAddress, fetched);
349
462
  return true;
350
463
  }
351
- async markRetryRequesterSenderKeyAsStale(request, requesterJid) {
464
+ async markRetryRequesterSenderKeyAsStale(request, requesterJid, requesterAddress) {
352
465
  if (!isGroupOrBroadcastJid(request.from)) {
353
466
  return;
354
467
  }
355
468
  try {
356
- const requesterAddress = parseSignalAddressFromJid(requesterJid);
357
469
  const deleted = await this.senderKeyStore.markForgetSenderKey(request.from, [
358
470
  requesterAddress
359
471
  ]);
@@ -371,12 +483,11 @@ export class WaRetryCoordinator {
371
483
  });
372
484
  }
373
485
  }
374
- async fetchMissingPreKeysSession(requesterJid, requesterRegistrationId) {
486
+ async fetchMissingPreKeysSession(requesterJid, requesterAddress, requesterNormalizedDeviceJid, requesterRegistrationId) {
375
487
  try {
376
- const requesterAddress = parseSignalAddressFromJid(requesterJid);
377
488
  const results = await this.signalMissingPreKeysSync.fetchMissingPreKeys([
378
489
  {
379
- userJid: toUserJid(requesterJid),
490
+ userJid: `${requesterAddress.user}@${requesterAddress.server}`,
380
491
  devices: [
381
492
  {
382
493
  deviceId: requesterAddress.device,
@@ -393,8 +504,7 @@ export class WaRetryCoordinator {
393
504
  });
394
505
  return null;
395
506
  }
396
- const requesterDeviceJid = normalizeDeviceJid(requesterJid);
397
- const matched = first.devices.find((device) => normalizeDeviceJid(device.deviceJid) === requesterDeviceJid);
507
+ const matched = first.devices.find((device) => normalizeDeviceJid(device.deviceJid) === requesterNormalizedDeviceJid);
398
508
  if (!matched) {
399
509
  this.logger.warn('missing prekeys fetch did not return requested device', {
400
510
  requester: requesterJid,
@@ -412,33 +522,59 @@ export class WaRetryCoordinator {
412
522
  return null;
413
523
  }
414
524
  }
415
- async authorizeRetryRequest(request, outbound, requesterJid) {
525
+ async authorizeRetryRequest(request, outbound, requesterJid, requesterAddress, requesterNormalizedDeviceJid) {
416
526
  if (outbound.state === 'ineligible') {
417
527
  return { authorized: false, reason: `state_${outbound.state}` };
418
528
  }
529
+ let requesterStatus = null;
530
+ try {
531
+ requesterStatus = await this.retryStore.getOutboundRequesterStatus(outbound.messageId, requesterNormalizedDeviceJid);
532
+ }
533
+ catch (error) {
534
+ this.logger.warn('failed to resolve outbound requester status from retry store', {
535
+ id: request.stanzaId,
536
+ originalMsgId: request.originalMsgId,
537
+ requester: requesterJid,
538
+ message: toError(error).message
539
+ });
540
+ }
541
+ if (requesterStatus) {
542
+ if (!requesterStatus.eligible) {
543
+ return { authorized: false, reason: 'requester_device_not_eligible' };
544
+ }
545
+ if (requesterStatus.delivered) {
546
+ return { authorized: false, reason: 'requester_already_delivered' };
547
+ }
548
+ }
419
549
  const isGroupOutbound = isGroupOrBroadcastJid(outbound.toJid);
420
550
  if (!isGroupOutbound && (outbound.state === 'read' || outbound.state === 'played')) {
421
551
  return { authorized: false, reason: `state_${outbound.state}` };
422
552
  }
423
- const requesterAuthorized = await this.isRequesterAuthorizedDevice(requesterJid);
424
- if (!requesterAuthorized) {
425
- return { authorized: false, reason: 'requester_device_not_authorized' };
553
+ if (!requesterStatus) {
554
+ const requesterAuthorized = await this.isRequesterAuthorizedDevice(requesterJid, requesterAddress, requesterNormalizedDeviceJid);
555
+ if (!requesterAuthorized) {
556
+ return { authorized: false, reason: 'requester_device_not_authorized' };
557
+ }
426
558
  }
427
559
  return { authorized: true };
428
560
  }
429
- async isRequesterAuthorizedDevice(requesterJid) {
561
+ async isRequesterAuthorizedDevice(requesterJid, requesterAddress, requesterNormalizedDeviceJid) {
430
562
  try {
431
- const requesterUser = toUserJid(requesterJid);
563
+ const requesterUser = `${requesterAddress.user}@${requesterAddress.server}`;
564
+ if (requesterNormalizedDeviceJid === normalizeDeviceJid(requesterUser)) {
565
+ return true;
566
+ }
432
567
  const synced = await this.signalDeviceSync.syncDeviceList([requesterUser]);
433
568
  const target = synced.find((entry) => entry.jid === requesterUser);
434
- const authorized = new Set();
435
- authorized.add(normalizeDeviceJid(requesterUser));
436
- if (target) {
437
- for (let index = 0; index < target.deviceJids.length; index += 1) {
438
- authorized.add(normalizeDeviceJid(target.deviceJids[index]));
569
+ if (!target) {
570
+ return false;
571
+ }
572
+ for (let index = 0; index < target.deviceJids.length; index += 1) {
573
+ if (normalizeDeviceJid(target.deviceJids[index]) === requesterNormalizedDeviceJid) {
574
+ return true;
439
575
  }
440
576
  }
441
- return authorized.has(normalizeDeviceJid(requesterJid));
577
+ return false;
442
578
  }
443
579
  catch (error) {
444
580
  this.logger.warn('retry authorization failed while syncing requester device list', {
@@ -476,7 +612,11 @@ export class WaRetryCoordinator {
476
612
  return;
477
613
  }
478
614
  try {
479
- await this.sendNode(buildInboundRetryReceiptAckNode(receiptNode));
615
+ await this.sendNode(buildAckNode({
616
+ kind: 'receipt',
617
+ node: receiptNode,
618
+ retryType: true
619
+ }));
480
620
  }
481
621
  catch (error) {
482
622
  this.logger.warn('failed to send retry ack', {
@@ -487,4 +627,49 @@ export class WaRetryCoordinator {
487
627
  });
488
628
  }
489
629
  }
630
+ async maybeCleanupRetryStore(nowMs) {
631
+ if (nowMs < this.nextRetryCleanupAtMs) {
632
+ return;
633
+ }
634
+ this.nextRetryCleanupAtMs = nowMs + RETRY_CLEANUP_INTERVAL_MS;
635
+ this.cleanupRetrySessionBaseKeys(nowMs);
636
+ try {
637
+ await this.retryStore.cleanupExpired(nowMs);
638
+ }
639
+ catch (error) {
640
+ this.logger.warn('retry store cleanup failed', {
641
+ message: toError(error).message
642
+ });
643
+ }
644
+ }
645
+ retrySessionBaseKeyMapKey(originalMsgId, requesterNormalizedDeviceJid) {
646
+ return `${originalMsgId}|${requesterNormalizedDeviceJid}`;
647
+ }
648
+ setRetrySessionBaseKey(originalMsgId, requesterNormalizedDeviceJid, baseKey, expiresAtMs) {
649
+ const key = this.retrySessionBaseKeyMapKey(originalMsgId, requesterNormalizedDeviceJid);
650
+ setBoundedMapEntry(this.retrySessionBaseKeys, key, {
651
+ baseKey: Uint8Array.from(baseKey),
652
+ expiresAtMs
653
+ }, RETRY_SESSION_BASE_KEY_CACHE_MAX_ENTRIES);
654
+ }
655
+ getRetrySessionBaseKey(originalMsgId, requesterNormalizedDeviceJid) {
656
+ const key = this.retrySessionBaseKeyMapKey(originalMsgId, requesterNormalizedDeviceJid);
657
+ const entry = this.retrySessionBaseKeys.get(key);
658
+ if (!entry) {
659
+ return null;
660
+ }
661
+ if (entry.expiresAtMs <= Date.now()) {
662
+ this.retrySessionBaseKeys.delete(key);
663
+ return null;
664
+ }
665
+ return entry;
666
+ }
667
+ cleanupRetrySessionBaseKeys(nowMs) {
668
+ for (const [key, entry] of this.retrySessionBaseKeys) {
669
+ if (entry.expiresAtMs > nowMs) {
670
+ continue;
671
+ }
672
+ this.retrySessionBaseKeys.delete(key);
673
+ }
674
+ }
490
675
  }
@@ -1,4 +1,4 @@
1
- import { WA_DISCONNECT_REASONS, WA_STREAM_SIGNALING } from '../../protocol/constants.js';
1
+ import { WA_CONNECTION_REASONS, WA_DISCONNECT_REASONS, WA_STREAM_SIGNALING } from '../../protocol/constants.js';
2
2
  import { toError } from '../../util/primitives.js';
3
3
  export function createStreamControlHandler(options) {
4
4
  const { logger, getComms, clearPendingQueries, clearMediaConnCache, disconnect, clearStoredCredentials, connect } = options;
@@ -16,7 +16,7 @@ export function createStreamControlHandler(options) {
16
16
  const restartBackendAfterStreamControl = async (reason) => {
17
17
  logger.info('restarting backend after stream control', { reason });
18
18
  try {
19
- await connect();
19
+ await connect(WA_CONNECTION_REASONS.RECONNECTED);
20
20
  }
21
21
  catch (error) {
22
22
  logger.warn('failed to restart backend after stream control', {
@@ -43,29 +43,36 @@ export function createStreamControlHandler(options) {
43
43
  });
44
44
  }
45
45
  };
46
+ const stopCommsImmediately = () => {
47
+ void getComms()?.stopComms();
48
+ };
46
49
  const forceLoginDueToStreamError = async (code) => {
47
- await runStreamControlLifecycle(`stream_error_code_${code}`, async () => {
50
+ const reason = WA_DISCONNECT_REASONS.STREAM_ERROR_FORCE_LOGIN;
51
+ stopCommsImmediately();
52
+ await runStreamControlLifecycle(reason, async () => {
48
53
  logger.warn('received forced login stream error; starting login lifecycle', {
49
54
  code
50
55
  });
51
- await disconnect();
56
+ await disconnect(reason, true, code);
52
57
  await clearStoredCredentials();
53
- await restartBackendAfterStreamControl(`stream_error_code_${code}`);
58
+ await restartBackendAfterStreamControl(reason);
54
59
  });
55
60
  };
56
- const disconnectDueToStreamError = async (reason) => {
61
+ const disconnectDueToStreamError = async (reason, code) => {
62
+ stopCommsImmediately();
57
63
  await runStreamControlLifecycle(reason, async () => {
58
64
  logger.warn('disconnecting due to stream control node', { reason });
59
- await disconnect();
65
+ await disconnect(reason, false, code);
60
66
  });
61
67
  };
62
- const logoutDueToStreamError = async (reason, shouldRestartBackend) => {
68
+ const logoutDueToStreamError = async (reason, code, shouldRestartBackend) => {
69
+ stopCommsImmediately();
63
70
  await runStreamControlLifecycle(reason, async () => {
64
71
  logger.warn('logging out due to stream control node', {
65
72
  reason,
66
73
  shouldRestartBackend
67
74
  });
68
- await disconnect();
75
+ await disconnect(reason, true, code);
69
76
  await clearStoredCredentials();
70
77
  if (shouldRestartBackend) {
71
78
  await restartBackendAfterStreamControl(reason);
@@ -86,7 +93,7 @@ export function createStreamControlHandler(options) {
86
93
  return;
87
94
  }
88
95
  if (result.code === WA_STREAM_SIGNALING.FORCE_LOGOUT_CODE) {
89
- await logoutDueToStreamError(`stream_error_code_${WA_STREAM_SIGNALING.FORCE_LOGOUT_CODE}`, true);
96
+ await logoutDueToStreamError(WA_DISCONNECT_REASONS.STREAM_ERROR_FORCE_LOGOUT, result.code, true);
90
97
  return;
91
98
  }
92
99
  }
@@ -94,11 +101,11 @@ export function createStreamControlHandler(options) {
94
101
  return;
95
102
  case 'stream_error_replaced':
96
103
  logger.warn('received stream:error replaced, stopping client');
97
- await disconnectDueToStreamError(WA_DISCONNECT_REASONS.STREAM_ERROR_REPLACED);
104
+ await disconnectDueToStreamError(WA_DISCONNECT_REASONS.STREAM_ERROR_REPLACED, null);
98
105
  return;
99
106
  case 'stream_error_device_removed':
100
107
  logger.warn('received stream:error device removed, logging out');
101
- await logoutDueToStreamError(WA_DISCONNECT_REASONS.STREAM_ERROR_DEVICE_REMOVED, false);
108
+ await logoutDueToStreamError(WA_DISCONNECT_REASONS.STREAM_ERROR_DEVICE_REMOVED, null, false);
102
109
  return;
103
110
  case 'stream_error_ack':
104
111
  logger.warn('received stream:error ack', { id: result.id });