zapo-js 0.1.2 → 0.3.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 (630) hide show
  1. package/README.md +16 -4
  2. package/dist/appstate/WaAppStateCrypto.js +50 -42
  3. package/dist/appstate/WaAppStateSyncClient.js +215 -133
  4. package/dist/appstate/{store/sqlite.js → encoding.js} +13 -8
  5. package/dist/appstate/index.js +9 -7
  6. package/dist/appstate/utils.js +0 -5
  7. package/dist/auth/WaAuthClient.js +55 -57
  8. package/dist/auth/credentials-flow.js +195 -0
  9. package/dist/auth/index.js +1 -6
  10. package/dist/auth/pairing/WaPairingFlow.js +39 -32
  11. package/dist/auth/pairing/{WaPairingCodeCrypto.js → pairing-code-crypto.js} +35 -17
  12. package/dist/client/WaClient.js +338 -174
  13. package/dist/client/WaClientFactory.js +399 -66
  14. package/dist/client/connection/WaConnectionManager.js +23 -11
  15. package/dist/client/coordinators/WaAbPropsCoordinator.js +141 -0
  16. package/dist/client/coordinators/WaBusinessCoordinator.js +232 -0
  17. package/dist/client/coordinators/WaEmailCoordinator.js +63 -0
  18. package/dist/client/coordinators/WaGroupCoordinator.js +11 -7
  19. package/dist/client/coordinators/WaIncomingNodeCoordinator.js +34 -8
  20. package/dist/client/coordinators/WaMessageDispatchCoordinator.js +341 -118
  21. package/dist/client/coordinators/WaOfflineResumeCoordinator.js +114 -0
  22. package/dist/client/coordinators/WaPassiveTasksCoordinator.js +97 -36
  23. package/dist/client/coordinators/WaPrivacyCoordinator.js +134 -0
  24. package/dist/client/coordinators/WaProfileCoordinator.js +214 -0
  25. package/dist/client/coordinators/WaRetryCoordinator.js +184 -30
  26. package/dist/client/coordinators/WaStreamControlCoordinator.js +18 -11
  27. package/dist/client/coordinators/WaTrustedContactTokenCoordinator.js +184 -0
  28. package/dist/client/dirty.js +41 -21
  29. package/dist/client/events/abprops.js +43 -0
  30. package/dist/client/events/devices.js +72 -0
  31. package/dist/client/events/group.js +3 -11
  32. package/dist/client/events/identity.js +22 -0
  33. package/dist/client/events/privacy-token.js +38 -0
  34. package/dist/client/events/registration.js +42 -0
  35. package/dist/client/history-sync.js +50 -9
  36. package/dist/client/incoming.js +74 -7
  37. package/dist/client/mailbox.js +40 -23
  38. package/dist/client/media.js +243 -0
  39. package/dist/client/messages.js +245 -92
  40. package/dist/client/messaging/fanout.js +21 -11
  41. package/dist/client/messaging/participants.js +6 -4
  42. package/dist/client/persistence/WriteBehindPersistence.js +129 -0
  43. package/dist/client/tokens/cs-token.js +50 -0
  44. package/dist/client/tokens/tc-token.js +25 -0
  45. package/dist/crypto/core/index.js +5 -2
  46. package/dist/crypto/core/keys.js +4 -4
  47. package/dist/crypto/core/nonce.js +2 -0
  48. package/dist/crypto/core/primitives.js +0 -8
  49. package/dist/crypto/core/random.js +24 -8
  50. package/dist/crypto/core/xeddsa.js +57 -0
  51. package/dist/crypto/curves/X25519.js +43 -6
  52. package/dist/crypto/curves/constants.js +2 -1
  53. package/dist/crypto/index.js +3 -0
  54. package/dist/crypto/math/constants.js +13 -36
  55. package/dist/crypto/math/edwards.js +171 -44
  56. package/dist/crypto/math/fe.js +706 -0
  57. package/dist/crypto/math/mod.js +10 -3
  58. package/dist/esm/appstate/WaAppStateCrypto.js +40 -32
  59. package/dist/esm/appstate/WaAppStateSyncClient.js +206 -124
  60. package/dist/esm/appstate/{store/sqlite.js → encoding.js} +13 -8
  61. package/dist/esm/appstate/index.js +2 -2
  62. package/dist/esm/appstate/{WaAppStateSyncResponseParser.js → response-parser.js} +1 -1
  63. package/dist/esm/appstate/utils.js +2 -5
  64. package/dist/esm/auth/WaAuthClient.js +52 -54
  65. package/dist/esm/auth/credentials-flow.js +190 -0
  66. package/dist/esm/auth/index.js +0 -2
  67. package/dist/esm/auth/pairing/WaPairingFlow.js +39 -32
  68. package/dist/esm/auth/pairing/{WaPairingCodeCrypto.js → pairing-code-crypto.js} +26 -10
  69. package/dist/esm/client/WaClient.js +339 -175
  70. package/dist/esm/client/WaClientFactory.js +401 -68
  71. package/dist/esm/client/connection/WaConnectionManager.js +23 -11
  72. package/dist/esm/client/coordinators/WaAbPropsCoordinator.js +137 -0
  73. package/dist/esm/client/coordinators/WaBusinessCoordinator.js +229 -0
  74. package/dist/esm/client/coordinators/WaEmailCoordinator.js +60 -0
  75. package/dist/esm/client/coordinators/WaGroupCoordinator.js +11 -7
  76. package/dist/esm/client/coordinators/WaIncomingNodeCoordinator.js +36 -10
  77. package/dist/esm/client/coordinators/WaMessageDispatchCoordinator.js +337 -114
  78. package/dist/esm/client/coordinators/WaOfflineResumeCoordinator.js +110 -0
  79. package/dist/esm/client/coordinators/WaPassiveTasksCoordinator.js +97 -36
  80. package/dist/esm/client/coordinators/WaPrivacyCoordinator.js +131 -0
  81. package/dist/esm/client/coordinators/WaProfileCoordinator.js +211 -0
  82. package/dist/esm/client/coordinators/WaRetryCoordinator.js +186 -32
  83. package/dist/esm/client/coordinators/WaStreamControlCoordinator.js +19 -12
  84. package/dist/esm/client/coordinators/WaTrustedContactTokenCoordinator.js +180 -0
  85. package/dist/esm/client/dirty.js +41 -21
  86. package/dist/esm/client/events/abprops.js +40 -0
  87. package/dist/esm/client/events/devices.js +68 -0
  88. package/dist/esm/client/events/group.js +3 -11
  89. package/dist/esm/client/events/identity.js +19 -0
  90. package/dist/esm/client/events/privacy-token.js +35 -0
  91. package/dist/esm/client/events/registration.js +39 -0
  92. package/dist/esm/client/history-sync.js +50 -9
  93. package/dist/esm/client/incoming.js +74 -8
  94. package/dist/esm/client/mailbox.js +40 -23
  95. package/dist/esm/client/media.js +234 -0
  96. package/dist/esm/client/messages.js +244 -91
  97. package/dist/esm/client/messaging/fanout.js +22 -12
  98. package/dist/esm/client/messaging/participants.js +6 -4
  99. package/dist/esm/client/persistence/WriteBehindPersistence.js +125 -0
  100. package/dist/esm/client/tokens/cs-token.js +46 -0
  101. package/dist/esm/client/tokens/tc-token.js +18 -0
  102. package/dist/esm/crypto/core/index.js +3 -2
  103. package/dist/esm/crypto/core/keys.js +1 -1
  104. package/dist/esm/crypto/core/nonce.js +2 -0
  105. package/dist/esm/crypto/core/primitives.js +0 -7
  106. package/dist/esm/crypto/core/random.js +23 -7
  107. package/dist/esm/crypto/core/xeddsa.js +53 -0
  108. package/dist/esm/crypto/curves/X25519.js +45 -8
  109. package/dist/esm/crypto/curves/constants.js +1 -0
  110. package/dist/esm/crypto/index.js +1 -0
  111. package/dist/esm/crypto/math/constants.js +12 -35
  112. package/dist/esm/crypto/math/edwards.js +174 -47
  113. package/dist/esm/crypto/math/fe.js +691 -0
  114. package/dist/esm/crypto/math/mod.js +10 -1
  115. package/dist/esm/index.js +1 -1
  116. package/dist/esm/infra/perf/BackgroundQueue.js +478 -0
  117. package/dist/esm/infra/perf/BoundedTaskQueue.js +3 -1
  118. package/dist/esm/infra/perf/PromiseDedup.js +20 -0
  119. package/dist/esm/infra/perf/SharedExclusiveGate.js +109 -0
  120. package/dist/esm/infra/perf/StoreLock.js +80 -0
  121. package/dist/esm/media/WaMediaCrypto.js +332 -55
  122. package/dist/esm/media/WaMediaTransferClient.js +69 -220
  123. package/dist/esm/media/constants.js +4 -1
  124. package/dist/esm/media/processor.js +1 -0
  125. package/dist/esm/message/WaMessageClient.js +26 -19
  126. package/dist/esm/message/addon-crypto.js +130 -3
  127. package/dist/esm/message/content.js +206 -14
  128. package/dist/esm/message/icdc.js +76 -0
  129. package/dist/esm/message/incoming.js +38 -24
  130. package/dist/esm/message/phash.js +35 -13
  131. package/dist/esm/message/reporting-token.js +17 -30
  132. package/dist/esm/message/use-case-secret.js +1 -1
  133. package/dist/esm/protocol/abprops.js +159 -0
  134. package/dist/esm/protocol/appstate.js +9 -40
  135. package/dist/esm/protocol/browser.js +24 -18
  136. package/dist/esm/protocol/constants.js +8 -4
  137. package/dist/esm/protocol/defaults.js +6 -0
  138. package/dist/esm/protocol/email.js +30 -0
  139. package/dist/esm/protocol/index.js +1 -2
  140. package/dist/esm/protocol/jid.js +142 -39
  141. package/dist/esm/protocol/message.js +61 -1
  142. package/dist/esm/protocol/nodes.js +8 -2
  143. package/dist/esm/protocol/notification.js +9 -1
  144. package/dist/esm/protocol/privacy-token.js +17 -0
  145. package/dist/esm/protocol/privacy.js +55 -0
  146. package/dist/esm/protocol/stream.js +26 -1
  147. package/dist/esm/retry/codec.js +216 -0
  148. package/dist/esm/retry/constants.js +1 -1
  149. package/dist/esm/retry/index.js +2 -2
  150. package/dist/esm/retry/parse.js +50 -30
  151. package/dist/esm/retry/reason.js +1 -1
  152. package/dist/esm/retry/replay.js +11 -7
  153. package/dist/esm/retry/tracker.js +50 -12
  154. package/dist/esm/signal/api/SignalDeviceSyncApi.js +52 -32
  155. package/dist/esm/signal/api/SignalDigestSyncApi.js +21 -15
  156. package/dist/esm/signal/api/SignalIdentitySyncApi.js +30 -15
  157. package/dist/esm/signal/api/SignalMissingPreKeysSyncApi.js +19 -8
  158. package/dist/esm/signal/api/SignalRotateKeyApi.js +4 -2
  159. package/dist/esm/signal/api/SignalSessionSyncApi.js +17 -8
  160. package/dist/esm/signal/api/result-map.js +10 -0
  161. package/dist/esm/signal/constants.js +0 -4
  162. package/dist/esm/signal/crypto/WaAdvSignature.js +5 -45
  163. package/dist/esm/signal/crypto/constants.js +0 -4
  164. package/dist/esm/signal/{store/sqlite.js → encoding.js} +40 -29
  165. package/dist/esm/signal/group/SenderKeyChain.js +3 -3
  166. package/dist/esm/signal/group/SenderKeyCodec.js +8 -8
  167. package/dist/esm/signal/group/SenderKeyManager.js +131 -109
  168. package/dist/esm/signal/index.js +1 -0
  169. package/dist/esm/signal/registration/keygen.js +8 -5
  170. package/dist/esm/signal/registration/utils.js +3 -2
  171. package/dist/esm/signal/session/SignalProtocol.js +158 -81
  172. package/dist/esm/signal/session/SignalRatchet.js +21 -10
  173. package/dist/esm/signal/session/SignalSerializer.js +5 -6
  174. package/dist/esm/signal/session/SignalSession.js +11 -9
  175. package/dist/esm/signal/session/resolver.js +140 -105
  176. package/dist/esm/store/contracts/identity.store.js +1 -0
  177. package/dist/esm/store/contracts/message-secret.store.js +1 -0
  178. package/dist/esm/store/contracts/pre-key.store.js +1 -0
  179. package/dist/esm/store/contracts/privacy-token.store.js +1 -0
  180. package/dist/esm/store/contracts/session.store.js +1 -0
  181. package/dist/esm/store/createStore.js +143 -193
  182. package/dist/esm/store/index.js +5 -10
  183. package/dist/esm/store/locks/appstate.lock.js +26 -0
  184. package/dist/esm/store/locks/auth.lock.js +15 -0
  185. package/dist/esm/store/locks/contact.lock.js +20 -0
  186. package/dist/esm/store/locks/device-list.lock.js +20 -0
  187. package/dist/esm/store/locks/identity.lock.js +16 -0
  188. package/dist/esm/store/locks/message-secret.lock.js +17 -0
  189. package/dist/esm/store/locks/message.lock.js +21 -0
  190. package/dist/esm/store/locks/participants.lock.js +20 -0
  191. package/dist/esm/store/locks/pre-key.lock.js +27 -0
  192. package/dist/esm/store/locks/privacy-token.lock.js +18 -0
  193. package/dist/esm/store/locks/retry.lock.js +29 -0
  194. package/dist/esm/store/locks/sender-key.lock.js +52 -0
  195. package/dist/esm/store/locks/session.lock.js +19 -0
  196. package/dist/esm/store/locks/signal.lock.js +39 -0
  197. package/dist/esm/store/locks/thread.lock.js +21 -0
  198. package/dist/esm/store/noop.store.js +21 -1
  199. package/dist/esm/store/providers/memory/appstate.store.js +22 -24
  200. package/dist/esm/store/providers/memory/device-list.store.js +13 -5
  201. package/dist/esm/store/providers/memory/identity.store.js +31 -0
  202. package/dist/esm/store/providers/memory/message-secret.store.js +81 -0
  203. package/dist/esm/store/providers/memory/participants.store.js +3 -0
  204. package/dist/esm/store/providers/memory/pre-key.store.js +97 -0
  205. package/dist/esm/store/providers/memory/privacy-token.store.js +43 -0
  206. package/dist/esm/store/providers/memory/retry.store.js +99 -10
  207. package/dist/esm/store/providers/memory/sender-key.store.js +6 -1
  208. package/dist/esm/store/providers/memory/session.store.js +45 -0
  209. package/dist/esm/store/providers/memory/signal.store.js +1 -147
  210. package/dist/esm/transport/WaComms.js +7 -4
  211. package/dist/esm/transport/WaWebSocket.js +9 -7
  212. package/dist/esm/transport/binary/constants.js +0 -30
  213. package/dist/esm/transport/binary/decoder.js +4 -4
  214. package/dist/esm/transport/binary/encoder.js +8 -15
  215. package/dist/esm/transport/binary/index.js +0 -1
  216. package/dist/esm/transport/index.js +6 -0
  217. package/dist/esm/transport/keepalive/WaKeepAlive.js +17 -8
  218. package/dist/esm/transport/node/WaMobileTcpSocket.js +114 -0
  219. package/dist/esm/transport/node/WaNodeOrchestrator.js +37 -22
  220. package/dist/esm/transport/node/builders/abprops.js +20 -0
  221. package/dist/esm/transport/node/builders/business.js +129 -0
  222. package/dist/esm/transport/node/builders/device.js +11 -0
  223. package/dist/esm/transport/node/builders/email.js +65 -0
  224. package/dist/esm/transport/node/builders/global.js +370 -0
  225. package/dist/esm/transport/node/builders/message.js +63 -239
  226. package/dist/esm/transport/node/builders/offline.js +14 -0
  227. package/dist/esm/transport/node/builders/pairing.js +0 -24
  228. package/dist/esm/transport/node/builders/prekeys.js +37 -40
  229. package/dist/esm/transport/node/builders/presence.js +13 -0
  230. package/dist/esm/transport/node/builders/privacy-token.js +37 -0
  231. package/dist/esm/transport/node/builders/privacy.js +48 -0
  232. package/dist/esm/transport/node/builders/profile.js +70 -0
  233. package/dist/esm/transport/node/builders/retry.js +11 -23
  234. package/dist/esm/transport/node/builders/usync.js +6 -2
  235. package/dist/esm/transport/node/helpers.js +43 -1
  236. package/dist/esm/transport/node/mex/argo-decoder.js +152 -0
  237. package/dist/esm/transport/node/mex/client.js +83 -0
  238. package/dist/esm/transport/node/mex/persist-ids.js +10 -0
  239. package/dist/esm/transport/node/usync.js +3 -33
  240. package/dist/esm/transport/node/xml.js +35 -14
  241. package/dist/esm/transport/noise/WaClientPayload.js +24 -19
  242. package/dist/esm/transport/noise/WaFrameCodec.js +2 -2
  243. package/dist/esm/transport/noise/WaMobileClientPayload.js +53 -0
  244. package/dist/esm/transport/noise/WaNoiseCert.js +9 -27
  245. package/dist/esm/transport/noise/WaNoiseSession.js +76 -34
  246. package/dist/esm/transport/noise/WaNoiseSocket.js +8 -4
  247. package/dist/esm/transport/stream/parse.js +8 -4
  248. package/dist/esm/util/bytes.js +22 -18
  249. package/dist/esm/util/index.js +5 -0
  250. package/dist/esm/util/primitives.js +3 -2
  251. package/dist/index.js +7 -1
  252. package/dist/infra/perf/BackgroundQueue.js +482 -0
  253. package/dist/infra/perf/BoundedTaskQueue.js +3 -1
  254. package/dist/infra/perf/PromiseDedup.js +24 -0
  255. package/dist/infra/perf/SharedExclusiveGate.js +113 -0
  256. package/dist/infra/perf/StoreLock.js +84 -0
  257. package/dist/media/WaMediaCrypto.js +328 -51
  258. package/dist/media/WaMediaTransferClient.js +72 -253
  259. package/dist/media/constants.js +5 -2
  260. package/dist/media/processor.js +2 -0
  261. package/dist/message/WaMessageClient.js +26 -19
  262. package/dist/message/addon-crypto.js +131 -0
  263. package/dist/message/content.js +211 -14
  264. package/dist/message/icdc.js +81 -0
  265. package/dist/message/incoming.js +38 -24
  266. package/dist/message/phash.js +35 -13
  267. package/dist/message/reporting-token.js +16 -30
  268. package/dist/message/use-case-secret.js +1 -1
  269. package/dist/protocol/abprops.js +163 -0
  270. package/dist/protocol/appstate.js +10 -41
  271. package/dist/protocol/browser.js +25 -18
  272. package/dist/protocol/constants.js +33 -2
  273. package/dist/protocol/defaults.js +6 -0
  274. package/dist/protocol/email.js +33 -0
  275. package/dist/protocol/index.js +8 -5
  276. package/dist/protocol/jid.js +149 -39
  277. package/dist/protocol/message.js +62 -2
  278. package/dist/protocol/nodes.js +8 -2
  279. package/dist/protocol/notification.js +10 -2
  280. package/dist/protocol/privacy-token.js +20 -0
  281. package/dist/protocol/privacy.js +58 -0
  282. package/dist/protocol/stream.js +27 -2
  283. package/dist/retry/codec.js +220 -0
  284. package/dist/retry/constants.js +1 -1
  285. package/dist/retry/index.js +5 -5
  286. package/dist/retry/parse.js +51 -30
  287. package/dist/retry/reason.js +1 -1
  288. package/dist/retry/replay.js +10 -6
  289. package/dist/retry/tracker.js +50 -12
  290. package/dist/signal/api/SignalDeviceSyncApi.js +51 -31
  291. package/dist/signal/api/SignalDigestSyncApi.js +21 -15
  292. package/dist/signal/api/SignalIdentitySyncApi.js +29 -14
  293. package/dist/signal/api/SignalMissingPreKeysSyncApi.js +17 -6
  294. package/dist/signal/api/SignalRotateKeyApi.js +4 -2
  295. package/dist/signal/api/SignalSessionSyncApi.js +16 -7
  296. package/dist/signal/api/result-map.js +13 -0
  297. package/dist/signal/constants.js +1 -5
  298. package/dist/signal/crypto/WaAdvSignature.js +2 -44
  299. package/dist/signal/crypto/constants.js +1 -5
  300. package/dist/signal/{store/sqlite.js → encoding.js} +41 -25
  301. package/dist/signal/group/SenderKeyChain.js +2 -2
  302. package/dist/signal/group/SenderKeyCodec.js +8 -8
  303. package/dist/signal/group/SenderKeyManager.js +130 -108
  304. package/dist/signal/index.js +13 -1
  305. package/dist/signal/registration/keygen.js +7 -4
  306. package/dist/signal/registration/utils.js +3 -2
  307. package/dist/signal/session/SignalProtocol.js +158 -81
  308. package/dist/signal/session/SignalRatchet.js +19 -8
  309. package/dist/signal/session/SignalSerializer.js +5 -6
  310. package/dist/signal/session/SignalSession.js +11 -9
  311. package/dist/signal/session/resolver.js +138 -103
  312. package/dist/store/contracts/identity.store.js +2 -0
  313. package/dist/store/contracts/message-secret.store.js +2 -0
  314. package/dist/store/contracts/pre-key.store.js +2 -0
  315. package/dist/store/contracts/privacy-token.store.js +2 -0
  316. package/dist/store/contracts/session.store.js +2 -0
  317. package/dist/store/createStore.js +142 -192
  318. package/dist/store/index.js +23 -33
  319. package/dist/store/locks/appstate.lock.js +29 -0
  320. package/dist/store/locks/auth.lock.js +18 -0
  321. package/dist/store/locks/contact.lock.js +23 -0
  322. package/dist/store/locks/device-list.lock.js +23 -0
  323. package/dist/store/locks/identity.lock.js +19 -0
  324. package/dist/store/locks/message-secret.lock.js +20 -0
  325. package/dist/store/locks/message.lock.js +24 -0
  326. package/dist/store/locks/participants.lock.js +23 -0
  327. package/dist/store/locks/pre-key.lock.js +30 -0
  328. package/dist/store/locks/privacy-token.lock.js +21 -0
  329. package/dist/store/locks/retry.lock.js +32 -0
  330. package/dist/store/locks/sender-key.lock.js +55 -0
  331. package/dist/store/locks/session.lock.js +22 -0
  332. package/dist/store/locks/signal.lock.js +42 -0
  333. package/dist/store/locks/thread.lock.js +24 -0
  334. package/dist/store/noop.store.js +22 -2
  335. package/dist/store/providers/memory/appstate.store.js +22 -24
  336. package/dist/store/providers/memory/device-list.store.js +13 -5
  337. package/dist/store/providers/memory/identity.store.js +35 -0
  338. package/dist/store/providers/memory/message-secret.store.js +85 -0
  339. package/dist/store/providers/memory/participants.store.js +3 -0
  340. package/dist/store/providers/memory/pre-key.store.js +101 -0
  341. package/dist/store/providers/memory/privacy-token.store.js +47 -0
  342. package/dist/store/providers/memory/retry.store.js +98 -9
  343. package/dist/store/providers/memory/sender-key.store.js +6 -1
  344. package/dist/store/providers/memory/session.store.js +49 -0
  345. package/dist/store/providers/memory/signal.store.js +1 -147
  346. package/dist/transport/WaComms.js +7 -4
  347. package/dist/transport/WaWebSocket.js +9 -7
  348. package/dist/transport/binary/constants.js +1 -31
  349. package/dist/transport/binary/decoder.js +4 -4
  350. package/dist/transport/binary/encoder.js +8 -15
  351. package/dist/transport/binary/index.js +0 -4
  352. package/dist/transport/index.js +17 -1
  353. package/dist/transport/keepalive/WaKeepAlive.js +17 -8
  354. package/dist/transport/node/WaMobileTcpSocket.js +118 -0
  355. package/dist/transport/node/WaNodeOrchestrator.js +36 -21
  356. package/dist/transport/node/builders/abprops.js +23 -0
  357. package/dist/transport/node/builders/business.js +137 -0
  358. package/dist/transport/node/builders/device.js +14 -0
  359. package/dist/transport/node/builders/email.js +72 -0
  360. package/dist/transport/node/builders/global.js +375 -0
  361. package/dist/transport/node/builders/message.js +64 -245
  362. package/dist/transport/node/builders/offline.js +17 -0
  363. package/dist/transport/node/builders/pairing.js +0 -26
  364. package/dist/transport/node/builders/prekeys.js +36 -39
  365. package/dist/transport/node/builders/presence.js +16 -0
  366. package/dist/transport/node/builders/privacy-token.js +42 -0
  367. package/dist/transport/node/builders/privacy.js +55 -0
  368. package/dist/transport/node/builders/profile.js +78 -0
  369. package/dist/transport/node/builders/retry.js +10 -22
  370. package/dist/transport/node/builders/usync.js +6 -2
  371. package/dist/transport/node/helpers.js +46 -1
  372. package/dist/transport/node/mex/argo-decoder.js +189 -0
  373. package/dist/transport/node/mex/client.js +86 -0
  374. package/dist/transport/node/mex/persist-ids.js +13 -0
  375. package/dist/transport/node/usync.js +2 -32
  376. package/dist/transport/node/xml.js +35 -14
  377. package/dist/transport/noise/WaClientPayload.js +26 -21
  378. package/dist/transport/noise/WaFrameCodec.js +1 -1
  379. package/dist/transport/noise/WaMobileClientPayload.js +56 -0
  380. package/dist/transport/noise/WaNoiseCert.js +8 -26
  381. package/dist/transport/noise/WaNoiseSession.js +75 -33
  382. package/dist/transport/noise/WaNoiseSocket.js +8 -4
  383. package/dist/transport/stream/parse.js +7 -3
  384. package/dist/types/appstate/WaAppStateCrypto.d.ts +11 -8
  385. package/dist/types/appstate/WaAppStateSyncClient.d.ts +6 -2
  386. package/dist/types/appstate/encoding.d.ts +7 -0
  387. package/dist/types/appstate/index.d.ts +3 -3
  388. package/dist/types/appstate/{WaAppStateSyncResponseParser.d.ts → response-parser.d.ts} +1 -1
  389. package/dist/types/appstate/types.d.ts +1 -1
  390. package/dist/types/appstate/utils.d.ts +0 -2
  391. package/dist/types/auth/WaAuthClient.d.ts +9 -3
  392. package/dist/types/auth/credentials-flow.d.ts +20 -0
  393. package/dist/types/auth/index.d.ts +0 -2
  394. package/dist/types/auth/pairing/WaPairingFlow.d.ts +3 -2
  395. package/dist/types/auth/pairing/{WaPairingCodeCrypto.d.ts → pairing-code-crypto.d.ts} +6 -1
  396. package/dist/types/auth/types.d.ts +41 -0
  397. package/dist/types/client/WaClient.d.ts +44 -18
  398. package/dist/types/client/WaClientFactory.d.ts +22 -8
  399. package/dist/types/client/connection/WaConnectionManager.d.ts +2 -0
  400. package/dist/types/client/coordinators/WaAbPropsCoordinator.d.ts +26 -0
  401. package/dist/types/client/coordinators/WaBusinessCoordinator.d.ts +57 -0
  402. package/dist/types/client/coordinators/WaEmailCoordinator.d.ts +24 -0
  403. package/dist/types/client/coordinators/WaIncomingNodeCoordinator.d.ts +9 -2
  404. package/dist/types/client/coordinators/WaMessageDispatchCoordinator.d.ts +29 -2
  405. package/dist/types/client/coordinators/WaOfflineResumeCoordinator.d.ts +31 -0
  406. package/dist/types/client/coordinators/WaPassiveTasksCoordinator.d.ts +16 -1
  407. package/dist/types/client/coordinators/WaPrivacyCoordinator.d.ts +26 -0
  408. package/dist/types/client/coordinators/WaProfileCoordinator.d.ts +38 -0
  409. package/dist/types/client/coordinators/WaRetryCoordinator.d.ts +12 -0
  410. package/dist/types/client/coordinators/WaStreamControlCoordinator.d.ts +3 -2
  411. package/dist/types/client/coordinators/WaTrustedContactTokenCoordinator.d.ts +55 -0
  412. package/dist/types/client/dirty.d.ts +3 -1
  413. package/dist/types/client/events/abprops.d.ts +14 -0
  414. package/dist/types/client/events/devices.d.ts +20 -0
  415. package/dist/types/client/events/identity.d.ts +9 -0
  416. package/dist/types/client/events/privacy-token.d.ts +7 -0
  417. package/dist/types/client/events/registration.d.ts +17 -0
  418. package/dist/types/client/history-sync.d.ts +9 -6
  419. package/dist/types/client/incoming.d.ts +9 -2
  420. package/dist/types/client/index.d.ts +1 -1
  421. package/dist/types/client/mailbox.d.ts +5 -5
  422. package/dist/types/client/media.d.ts +31 -0
  423. package/dist/types/client/messages.d.ts +3 -2
  424. package/dist/types/client/persistence/WriteBehindPersistence.d.ts +34 -0
  425. package/dist/types/client/tokens/cs-token.d.ts +10 -0
  426. package/dist/types/client/tokens/tc-token.d.ts +5 -0
  427. package/dist/types/client/types.d.ts +151 -4
  428. package/dist/types/crypto/core/index.d.ts +3 -2
  429. package/dist/types/crypto/core/nonce.d.ts +2 -0
  430. package/dist/types/crypto/core/primitives.d.ts +1 -2
  431. package/dist/types/crypto/core/random.d.ts +2 -1
  432. package/dist/types/crypto/core/xeddsa.d.ts +2 -0
  433. package/dist/types/crypto/curves/constants.d.ts +1 -0
  434. package/dist/types/crypto/index.d.ts +2 -0
  435. package/dist/types/crypto/math/constants.d.ts +4 -2
  436. package/dist/types/crypto/math/fe.d.ts +30 -0
  437. package/dist/types/crypto/math/mod.d.ts +0 -2
  438. package/dist/types/crypto/math/types.d.ts +11 -4
  439. package/dist/types/index.d.ts +6 -3
  440. package/dist/types/infra/log/ConsoleLogger.d.ts +1 -1
  441. package/dist/types/infra/log/PinoLogger.d.ts +1 -1
  442. package/dist/types/infra/perf/BackgroundQueue.d.ts +58 -0
  443. package/dist/types/infra/perf/PromiseDedup.d.ts +4 -0
  444. package/dist/types/infra/perf/SharedExclusiveGate.d.ts +17 -0
  445. package/dist/types/infra/perf/StoreLock.d.ts +11 -0
  446. package/dist/types/media/WaMediaCrypto.d.ts +16 -6
  447. package/dist/types/media/WaMediaTransferClient.d.ts +6 -23
  448. package/dist/types/media/constants.d.ts +3 -1
  449. package/dist/types/media/index.d.ts +2 -1
  450. package/dist/types/media/processor.d.ts +28 -0
  451. package/dist/types/media/types.d.ts +19 -5
  452. package/dist/types/message/addon-crypto.d.ts +34 -3
  453. package/dist/types/message/content.d.ts +11 -1
  454. package/dist/types/message/icdc.d.ts +13 -0
  455. package/dist/types/message/reporting-token.d.ts +0 -1
  456. package/dist/types/message/types.d.ts +42 -11
  457. package/dist/types/protocol/abprops.d.ts +142 -0
  458. package/dist/types/protocol/appstate.d.ts +0 -11
  459. package/dist/types/protocol/browser.d.ts +1 -0
  460. package/dist/types/protocol/constants.d.ts +12 -4
  461. package/dist/types/protocol/defaults.d.ts +6 -0
  462. package/dist/types/protocol/email.d.ts +32 -0
  463. package/dist/types/protocol/index.d.ts +1 -2
  464. package/dist/types/protocol/jid.d.ts +20 -2
  465. package/dist/types/protocol/message.d.ts +60 -0
  466. package/dist/types/protocol/nodes.d.ts +6 -0
  467. package/dist/types/protocol/notification.d.ts +8 -0
  468. package/dist/types/protocol/privacy-token.d.ts +17 -0
  469. package/dist/types/protocol/privacy.d.ts +75 -0
  470. package/dist/types/protocol/stream.d.ts +31 -0
  471. package/dist/types/retry/codec.d.ts +3 -0
  472. package/dist/types/retry/index.d.ts +3 -3
  473. package/dist/types/retry/parse.d.ts +5 -2
  474. package/dist/types/retry/reason.d.ts +1 -1
  475. package/dist/types/retry/tracker.d.ts +1 -0
  476. package/dist/types/retry/types.d.ts +6 -1
  477. package/dist/types/signal/api/SignalDeviceSyncApi.d.ts +2 -1
  478. package/dist/types/signal/api/SignalDigestSyncApi.d.ts +9 -0
  479. package/dist/types/signal/api/SignalIdentitySyncApi.d.ts +5 -3
  480. package/dist/types/signal/api/SignalRotateKeyApi.d.ts +4 -5
  481. package/dist/types/signal/api/SignalSessionSyncApi.d.ts +8 -6
  482. package/dist/types/signal/api/result-map.d.ts +1 -0
  483. package/dist/types/signal/constants.d.ts +0 -3
  484. package/dist/types/signal/crypto/WaAdvSignature.d.ts +0 -2
  485. package/dist/types/signal/crypto/constants.d.ts +0 -1
  486. package/dist/types/signal/{store/sqlite.d.ts → encoding.d.ts} +9 -3
  487. package/dist/types/signal/group/SenderKeyChain.d.ts +1 -1
  488. package/dist/types/signal/group/SenderKeyManager.d.ts +17 -7
  489. package/dist/types/signal/index.d.ts +2 -0
  490. package/dist/types/signal/registration/utils.d.ts +2 -1
  491. package/dist/types/signal/session/SignalProtocol.d.ts +21 -6
  492. package/dist/types/signal/session/SignalSerializer.d.ts +2 -1
  493. package/dist/types/signal/session/resolver.d.ts +11 -4
  494. package/dist/types/signal/types.d.ts +16 -4
  495. package/dist/types/store/contracts/appstate.store.d.ts +1 -1
  496. package/dist/types/store/contracts/identity.store.d.ts +11 -0
  497. package/dist/types/store/contracts/message-secret.store.d.ts +16 -0
  498. package/dist/types/store/contracts/pre-key.store.d.ts +13 -0
  499. package/dist/types/store/contracts/privacy-token.store.d.ts +16 -0
  500. package/dist/types/store/contracts/retry.store.d.ts +7 -0
  501. package/dist/types/store/contracts/session.store.d.ts +14 -0
  502. package/dist/types/store/contracts/signal.store.d.ts +1 -27
  503. package/dist/types/store/createStore.d.ts +1 -1
  504. package/dist/types/store/index.d.ts +12 -12
  505. package/dist/types/store/locks/appstate.lock.d.ts +3 -0
  506. package/dist/types/store/locks/auth.lock.d.ts +3 -0
  507. package/dist/types/store/locks/contact.lock.d.ts +3 -0
  508. package/dist/types/store/locks/device-list.lock.d.ts +2 -0
  509. package/dist/types/store/locks/identity.lock.d.ts +3 -0
  510. package/dist/types/store/locks/message-secret.lock.d.ts +3 -0
  511. package/dist/types/store/locks/message.lock.d.ts +3 -0
  512. package/dist/types/store/locks/participants.lock.d.ts +2 -0
  513. package/dist/types/store/locks/pre-key.lock.d.ts +3 -0
  514. package/dist/types/store/locks/privacy-token.lock.d.ts +2 -0
  515. package/dist/types/store/locks/retry.lock.d.ts +2 -0
  516. package/dist/types/store/locks/sender-key.lock.d.ts +3 -0
  517. package/dist/types/store/locks/session.lock.d.ts +3 -0
  518. package/dist/types/store/locks/signal.lock.d.ts +3 -0
  519. package/dist/types/store/locks/thread.lock.d.ts +3 -0
  520. package/dist/types/store/noop.store.d.ts +4 -0
  521. package/dist/types/store/providers/memory/appstate.store.d.ts +1 -1
  522. package/dist/types/store/providers/memory/identity.store.d.ts +18 -0
  523. package/dist/types/store/providers/memory/message-secret.store.d.ts +21 -0
  524. package/dist/types/store/providers/memory/pre-key.store.d.ts +23 -0
  525. package/dist/types/store/providers/memory/privacy-token.store.d.ts +13 -0
  526. package/dist/types/store/providers/memory/retry.store.d.ts +15 -1
  527. package/dist/types/store/providers/memory/session.store.d.ts +21 -0
  528. package/dist/types/store/providers/memory/signal.store.d.ts +2 -43
  529. package/dist/types/store/providers/memory/thread.store.d.ts +1 -1
  530. package/dist/types/store/types.d.ts +69 -61
  531. package/dist/types/transport/WaWebSocket.d.ts +1 -1
  532. package/dist/types/transport/binary/constants.d.ts +0 -30
  533. package/dist/types/transport/binary/index.d.ts +0 -1
  534. package/dist/types/transport/index.d.ts +8 -1
  535. package/dist/types/transport/keepalive/WaKeepAlive.d.ts +4 -1
  536. package/dist/types/transport/node/WaMobileTcpSocket.d.ts +18 -0
  537. package/dist/types/transport/node/WaNodeOrchestrator.d.ts +9 -6
  538. package/dist/types/transport/node/builders/abprops.d.ts +5 -0
  539. package/dist/types/transport/node/builders/business.d.ts +29 -0
  540. package/dist/types/transport/node/builders/device.d.ts +2 -0
  541. package/dist/types/transport/node/builders/email.d.ts +11 -0
  542. package/dist/types/transport/node/builders/global.d.ts +102 -0
  543. package/dist/types/transport/node/builders/message.d.ts +8 -7
  544. package/dist/types/transport/node/builders/offline.d.ts +2 -0
  545. package/dist/types/transport/node/builders/pairing.d.ts +0 -2
  546. package/dist/types/transport/node/builders/prekeys.d.ts +4 -3
  547. package/dist/types/transport/node/builders/presence.d.ts +6 -0
  548. package/dist/types/transport/node/builders/privacy-token.d.ts +9 -0
  549. package/dist/types/transport/node/builders/privacy.d.ts +7 -0
  550. package/dist/types/transport/node/builders/profile.d.ts +8 -0
  551. package/dist/types/transport/node/builders/retry.d.ts +0 -1
  552. package/dist/types/transport/node/helpers.d.ts +8 -0
  553. package/dist/types/transport/node/mex/argo-decoder.d.ts +11 -0
  554. package/dist/types/transport/node/mex/client.d.ts +18 -0
  555. package/dist/types/transport/node/mex/persist-ids.d.ts +14 -0
  556. package/dist/types/transport/noise/WaMobileClientPayload.d.ts +29 -0
  557. package/dist/types/transport/noise/WaNoiseCert.d.ts +7 -1
  558. package/dist/types/transport/noise/WaNoiseSession.d.ts +4 -2
  559. package/dist/types/transport/noise/WaNoiseSocket.d.ts +4 -2
  560. package/dist/types/transport/types.d.ts +8 -0
  561. package/dist/types/util/bytes.d.ts +1 -1
  562. package/dist/types/util/index.d.ts +5 -0
  563. package/dist/types/util/primitives.d.ts +0 -1
  564. package/dist/util/bytes.js +22 -18
  565. package/dist/util/index.js +23 -0
  566. package/dist/util/primitives.js +2 -2
  567. package/package.json +34 -10
  568. package/proto/index.js +1 -1
  569. package/dist/auth/flow/WaAuthCredentialsFlow.js +0 -130
  570. package/dist/auth/pairing/constants.js +0 -5
  571. package/dist/client/connection/WaKeyShareCoordinator.js +0 -63
  572. package/dist/crypto/core/constants.js +0 -4
  573. package/dist/esm/auth/flow/WaAuthCredentialsFlow.js +0 -125
  574. package/dist/esm/auth/pairing/constants.js +0 -2
  575. package/dist/esm/client/connection/WaKeyShareCoordinator.js +0 -59
  576. package/dist/esm/crypto/core/constants.js +0 -1
  577. package/dist/esm/retry/outbound.js +0 -82
  578. package/dist/esm/store/providers/sqlite/BaseSqliteStore.js +0 -37
  579. package/dist/esm/store/providers/sqlite/appstate.store.js +0 -250
  580. package/dist/esm/store/providers/sqlite/auth.store.js +0 -176
  581. package/dist/esm/store/providers/sqlite/connection.js +0 -245
  582. package/dist/esm/store/providers/sqlite/contact.store.js +0 -74
  583. package/dist/esm/store/providers/sqlite/device-list.store.js +0 -127
  584. package/dist/esm/store/providers/sqlite/message.store.js +0 -132
  585. package/dist/esm/store/providers/sqlite/migrations.js +0 -347
  586. package/dist/esm/store/providers/sqlite/participants.store.js +0 -77
  587. package/dist/esm/store/providers/sqlite/retry.store.js +0 -141
  588. package/dist/esm/store/providers/sqlite/sender-key.store.js +0 -198
  589. package/dist/esm/store/providers/sqlite/signal.store.js +0 -435
  590. package/dist/esm/store/providers/sqlite/table-names.js +0 -107
  591. package/dist/esm/store/providers/sqlite/thread.store.js +0 -85
  592. package/dist/esm/transport/node/builders/index.js +0 -8
  593. package/dist/retry/outbound.js +0 -87
  594. package/dist/store/providers/sqlite/BaseSqliteStore.js +0 -41
  595. package/dist/store/providers/sqlite/appstate.store.js +0 -254
  596. package/dist/store/providers/sqlite/auth.store.js +0 -180
  597. package/dist/store/providers/sqlite/connection.js +0 -281
  598. package/dist/store/providers/sqlite/contact.store.js +0 -78
  599. package/dist/store/providers/sqlite/device-list.store.js +0 -131
  600. package/dist/store/providers/sqlite/message.store.js +0 -136
  601. package/dist/store/providers/sqlite/migrations.js +0 -350
  602. package/dist/store/providers/sqlite/participants.store.js +0 -81
  603. package/dist/store/providers/sqlite/retry.store.js +0 -145
  604. package/dist/store/providers/sqlite/sender-key.store.js +0 -202
  605. package/dist/store/providers/sqlite/signal.store.js +0 -439
  606. package/dist/store/providers/sqlite/table-names.js +0 -113
  607. package/dist/store/providers/sqlite/thread.store.js +0 -89
  608. package/dist/transport/node/builders/index.js +0 -42
  609. package/dist/types/appstate/store/sqlite.d.ts +0 -7
  610. package/dist/types/auth/flow/WaAuthCredentialsFlow.d.ts +0 -14
  611. package/dist/types/auth/pairing/constants.d.ts +0 -2
  612. package/dist/types/client/connection/WaKeyShareCoordinator.d.ts +0 -14
  613. package/dist/types/crypto/core/constants.d.ts +0 -1
  614. package/dist/types/retry/outbound.d.ts +0 -4
  615. package/dist/types/store/providers/sqlite/BaseSqliteStore.d.ts +0 -12
  616. package/dist/types/store/providers/sqlite/appstate.store.d.ts +0 -17
  617. package/dist/types/store/providers/sqlite/auth.store.d.ts +0 -10
  618. package/dist/types/store/providers/sqlite/connection.d.ts +0 -10
  619. package/dist/types/store/providers/sqlite/contact.store.d.ts +0 -12
  620. package/dist/types/store/providers/sqlite/device-list.store.d.ts +0 -15
  621. package/dist/types/store/providers/sqlite/message.store.d.ts +0 -13
  622. package/dist/types/store/providers/sqlite/migrations.d.ts +0 -3
  623. package/dist/types/store/providers/sqlite/participants.store.d.ts +0 -12
  624. package/dist/types/store/providers/sqlite/retry.store.d.ts +0 -15
  625. package/dist/types/store/providers/sqlite/sender-key.store.d.ts +0 -24
  626. package/dist/types/store/providers/sqlite/signal.store.d.ts +0 -53
  627. package/dist/types/store/providers/sqlite/table-names.d.ts +0 -5
  628. package/dist/types/store/providers/sqlite/thread.store.d.ts +0 -13
  629. package/dist/types/transport/node/builders/index.d.ts +0 -8
  630. /package/dist/appstate/{WaAppStateSyncResponseParser.js → response-parser.js} +0 -0
@@ -1,16 +1,18 @@
1
1
  import { proto } from '../../proto.js';
2
2
  import { WA_MESSAGE_TAGS } from '../../protocol/constants.js';
3
- import { isGroupOrBroadcastJid, normalizeDeviceJid, parseSignalAddressFromJid } 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';
13
14
  const RETRY_CLEANUP_INTERVAL_MS = 30000;
15
+ const RETRY_SESSION_BASE_KEY_CACHE_MAX_ENTRIES = 8192;
14
16
  function getRetryReasonName(code) {
15
17
  if (code === undefined) {
16
18
  return undefined;
@@ -35,6 +37,8 @@ export class WaRetryCoordinator {
35
37
  this.retryStore = options.retryStore;
36
38
  this.retryTtlMs = this.retryStore.getTtlMs?.() ?? RETRY_OUTBOUND_TTL_MS;
37
39
  this.signalStore = options.signalStore;
40
+ this.preKeyStore = options.preKeyStore;
41
+ this.sessionStore = options.sessionStore;
38
42
  this.senderKeyStore = options.senderKeyStore;
39
43
  this.signalProtocol = options.signalProtocol;
40
44
  this.signalDeviceSync = options.signalDeviceSync;
@@ -52,6 +56,7 @@ export class WaRetryCoordinator {
52
56
  getCurrentSignedIdentity: this.getCurrentSignedIdentity
53
57
  });
54
58
  this.retryProcessingByMessageId = new Map();
59
+ this.retrySessionBaseKeys = new Map();
55
60
  }
56
61
  async onDecryptFailure(context, error) {
57
62
  try {
@@ -76,12 +81,23 @@ export class WaRetryCoordinator {
76
81
  if (!this.isRetryReceiptNode(receiptNode)) {
77
82
  return;
78
83
  }
84
+ let shouldAck = false;
79
85
  try {
80
86
  await this.maybeCleanupRetryStore(Date.now());
81
- const request = parseRetryReceiptRequest(receiptNode);
87
+ const expectedToJids = [];
88
+ const meJid = this.getCurrentMeJid()?.trim();
89
+ const meLid = this.getCurrentMeLid()?.trim();
90
+ if (meJid) {
91
+ expectedToJids.push(meJid);
92
+ }
93
+ if (meLid) {
94
+ expectedToJids.push(meLid);
95
+ }
96
+ const request = parseRetryReceiptRequest(receiptNode, expectedToJids.length > 0 ? { expectedToJids } : undefined);
82
97
  if (!request) {
83
98
  return;
84
99
  }
100
+ shouldAck = true;
85
101
  await this.handleParsedRetryRequest(receiptNode, request);
86
102
  }
87
103
  catch (error) {
@@ -93,7 +109,9 @@ export class WaRetryCoordinator {
93
109
  });
94
110
  }
95
111
  finally {
96
- await this.sendRetryAckSafe(receiptNode);
112
+ if (shouldAck) {
113
+ await this.sendRetryAckSafe(receiptNode);
114
+ }
97
115
  }
98
116
  }
99
117
  isRetryReceiptNode(node) {
@@ -129,7 +147,6 @@ export class WaRetryCoordinator {
129
147
  to: context.from,
130
148
  participant: context.participant,
131
149
  recipient: context.recipient,
132
- from: this.getCurrentMeJid() ?? undefined,
133
150
  originalMsgId: context.stanzaId,
134
151
  retryCount: prepared.retryCount,
135
152
  t: prepared.timestamp,
@@ -200,8 +217,9 @@ export class WaRetryCoordinator {
200
217
  let requesterAddress;
201
218
  let requesterNormalizedDeviceJid;
202
219
  try {
203
- requesterAddress = parseSignalAddressFromJid(requesterJid);
204
- requesterNormalizedDeviceJid = normalizeDeviceJid(requesterJid);
220
+ const requesterParsed = parseJidFull(requesterJid);
221
+ requesterAddress = requesterParsed.address;
222
+ requesterNormalizedDeviceJid = requesterParsed.normalizedJid;
205
223
  }
206
224
  catch (error) {
207
225
  this.logger.info('retry request rejected: invalid requester jid', {
@@ -277,20 +295,36 @@ export class WaRetryCoordinator {
277
295
  if (!nextState) {
278
296
  return;
279
297
  }
280
- const current = await this.retryStore.getOutboundMessage(messageId);
281
- if (!current) {
282
- return;
283
- }
284
- const merged = pickRetryStateMax(current.state, nextState);
285
- if (merged === current.state) {
286
- return;
287
- }
288
- const nowMs = Date.now();
289
- await this.retryStore.updateOutboundMessageState(messageId, merged, nowMs, nowMs + this.retryTtlMs);
298
+ await this.runRetryTaskSerialized(messageId, async () => {
299
+ const current = await this.retryStore.getOutboundMessage(messageId);
300
+ if (!current) {
301
+ return;
302
+ }
303
+ const nowMs = Date.now();
304
+ const expiresAtMs = nowMs + this.retryTtlMs;
305
+ const merged = pickRetryStateMax(current.state, nextState);
306
+ if (merged !== current.state) {
307
+ await this.retryStore.updateOutboundMessageState(messageId, merged, nowMs, expiresAtMs);
308
+ }
309
+ const requesterJid = receiptNode.attrs.participant ?? receiptNode.attrs.from;
310
+ if (!requesterJid) {
311
+ return;
312
+ }
313
+ try {
314
+ await this.retryStore.markOutboundRequesterDelivered(messageId, normalizeDeviceJid(requesterJid), nowMs, expiresAtMs);
315
+ }
316
+ catch (error) {
317
+ this.logger.warn('failed to update outbound requester delivery state', {
318
+ id: messageId,
319
+ requester: requesterJid,
320
+ message: toError(error).message
321
+ });
322
+ }
323
+ });
290
324
  }
291
325
  async runRetryTaskSerialized(messageId, task) {
292
326
  const previous = this.retryProcessingByMessageId.get(messageId) ?? Promise.resolve();
293
- const current = previous.then(task, task);
327
+ const current = previous.then(task);
294
328
  const tracker = current.then(() => undefined, () => undefined);
295
329
  this.retryProcessingByMessageId.set(messageId, tracker);
296
330
  try {
@@ -306,13 +340,13 @@ export class WaRetryCoordinator {
306
340
  async buildRetryKeysSection(identity) {
307
341
  const [signedPreKey, preKey] = await Promise.all([
308
342
  this.signalStore.getSignedPreKey(),
309
- this.signalStore.getOrGenSinglePreKey(generatePreKeyPair)
343
+ this.preKeyStore.getOrGenSinglePreKey(generatePreKeyPair)
310
344
  ]);
311
345
  if (!signedPreKey) {
312
346
  this.logger.warn('retry keys section skipped: signed prekey unavailable');
313
347
  return undefined;
314
348
  }
315
- await this.signalStore.markKeyAsUploaded(preKey.keyId);
349
+ await this.preKeyStore.markKeyAsUploaded(preKey.keyId);
316
350
  const signedIdentity = this.getCurrentSignedIdentity();
317
351
  return {
318
352
  identity,
@@ -331,15 +365,45 @@ export class WaRetryCoordinator {
331
365
  };
332
366
  }
333
367
  async updateLocalSessionFromRetryRequest(request, requesterJid, requesterAddress, requesterNormalizedDeviceJid) {
334
- await this.markRetryRequesterSenderKeyAsStale(request, requesterJid, requesterAddress);
335
- const currentSession = await this.signalStore.getSession(requesterAddress);
336
- if (currentSession && request.regId > 0 && currentSession.remote.regId !== request.regId) {
337
- await this.signalStore.deleteSession(requesterAddress);
368
+ const [, currentSession] = await Promise.all([
369
+ this.markRetryRequesterSenderKeyAsStale(request, requesterJid, requesterAddress),
370
+ this.sessionStore.getSession(requesterAddress)
371
+ ]);
372
+ const regIdMismatch = !!currentSession && request.regId > 0 && currentSession.remote.regId !== request.regId;
373
+ if (regIdMismatch && !request.keyBundle) {
374
+ await this.sessionStore.deleteSession(requesterAddress);
338
375
  }
339
376
  if (request.keyBundle) {
340
377
  if (!request.keyBundle.key || !request.keyBundle.skey.signature) {
341
378
  return false;
342
379
  }
380
+ if (request.offline) {
381
+ if (!currentSession) {
382
+ this.logger.info('retry request rejected: offline retry missing existing session', {
383
+ id: request.stanzaId,
384
+ originalMsgId: request.originalMsgId,
385
+ requester: requesterJid,
386
+ remoteRetryCount: request.retryCount,
387
+ ...getRemoteRetryReasonLogFields(request.retryReason)
388
+ });
389
+ await this.sessionStore.deleteSession(requesterAddress);
390
+ return false;
391
+ }
392
+ if (regIdMismatch) {
393
+ this.logger.info('retry request rejected: offline retry registration id mismatch', {
394
+ id: request.stanzaId,
395
+ originalMsgId: request.originalMsgId,
396
+ requester: requesterJid,
397
+ remoteRetryCount: request.retryCount,
398
+ ...getRemoteRetryReasonLogFields(request.retryReason)
399
+ });
400
+ await this.sessionStore.deleteSession(requesterAddress);
401
+ return false;
402
+ }
403
+ }
404
+ else if (regIdMismatch) {
405
+ await this.sessionStore.deleteSession(requesterAddress);
406
+ }
343
407
  await this.signalProtocol.establishOutgoingSession(requesterAddress, {
344
408
  regId: request.regId,
345
409
  identity: request.keyBundle.identity,
@@ -353,12 +417,45 @@ export class WaRetryCoordinator {
353
417
  publicKey: request.keyBundle.key.publicKey
354
418
  }
355
419
  });
420
+ return this.applySessionBaseKeyPolicy(request, requesterJid, requesterAddress, requesterNormalizedDeviceJid);
421
+ }
422
+ const sessionStillExists = currentSession !== null && !regIdMismatch;
423
+ if (sessionStillExists) {
424
+ return this.applySessionBaseKeyPolicy(request, requesterJid, requesterAddress, requesterNormalizedDeviceJid);
425
+ }
426
+ const fetched = await this.fetchMissingPreKeysSession(requesterJid, requesterAddress, requesterNormalizedDeviceJid, request.regId);
427
+ if (!fetched) {
428
+ return false;
429
+ }
430
+ await this.signalProtocol.establishOutgoingSession(requesterAddress, fetched);
431
+ return this.applySessionBaseKeyPolicy(request, requesterJid, requesterAddress, requesterNormalizedDeviceJid);
432
+ }
433
+ async applySessionBaseKeyPolicy(request, requesterJid, requesterAddress, requesterNormalizedDeviceJid) {
434
+ if (request.retryCount < 2) {
356
435
  return true;
357
436
  }
358
- const hasSession = await this.signalProtocol.hasSession(requesterAddress);
359
- if (hasSession) {
437
+ const currentSession = await this.sessionStore.getSession(requesterAddress);
438
+ const sessionBaseKey = currentSession?.aliceBaseKey ?? null;
439
+ if (!sessionBaseKey) {
360
440
  return true;
361
441
  }
442
+ const expiresAtMs = Date.now() + this.retryTtlMs;
443
+ if (request.retryCount === 2) {
444
+ this.setRetrySessionBaseKey(request.originalMsgId, requesterNormalizedDeviceJid, sessionBaseKey, expiresAtMs);
445
+ return true;
446
+ }
447
+ const saved = this.getRetrySessionBaseKey(request.originalMsgId, requesterNormalizedDeviceJid);
448
+ if (!saved || !uint8Equal(saved.baseKey, sessionBaseKey)) {
449
+ return true;
450
+ }
451
+ await this.sessionStore.deleteSession(requesterAddress);
452
+ this.logger.info('retry request forcing session refresh due to repeated base key', {
453
+ id: request.stanzaId,
454
+ originalMsgId: request.originalMsgId,
455
+ requester: requesterJid,
456
+ remoteRetryCount: request.retryCount,
457
+ ...getRemoteRetryReasonLogFields(request.retryReason)
458
+ });
362
459
  const fetched = await this.fetchMissingPreKeysSession(requesterJid, requesterAddress, requesterNormalizedDeviceJid, request.regId);
363
460
  if (!fetched) {
364
461
  return false;
@@ -431,13 +528,35 @@ export class WaRetryCoordinator {
431
528
  if (outbound.state === 'ineligible') {
432
529
  return { authorized: false, reason: `state_${outbound.state}` };
433
530
  }
531
+ let requesterStatus = null;
532
+ try {
533
+ requesterStatus = await this.retryStore.getOutboundRequesterStatus(outbound.messageId, requesterNormalizedDeviceJid);
534
+ }
535
+ catch (error) {
536
+ this.logger.warn('failed to resolve outbound requester status from retry store', {
537
+ id: request.stanzaId,
538
+ originalMsgId: request.originalMsgId,
539
+ requester: requesterJid,
540
+ message: toError(error).message
541
+ });
542
+ }
543
+ if (requesterStatus) {
544
+ if (!requesterStatus.eligible) {
545
+ return { authorized: false, reason: 'requester_device_not_eligible' };
546
+ }
547
+ if (requesterStatus.delivered) {
548
+ return { authorized: false, reason: 'requester_already_delivered' };
549
+ }
550
+ }
434
551
  const isGroupOutbound = isGroupOrBroadcastJid(outbound.toJid);
435
552
  if (!isGroupOutbound && (outbound.state === 'read' || outbound.state === 'played')) {
436
553
  return { authorized: false, reason: `state_${outbound.state}` };
437
554
  }
438
- const requesterAuthorized = await this.isRequesterAuthorizedDevice(requesterJid, requesterAddress, requesterNormalizedDeviceJid);
439
- if (!requesterAuthorized) {
440
- return { authorized: false, reason: 'requester_device_not_authorized' };
555
+ if (!requesterStatus) {
556
+ const requesterAuthorized = await this.isRequesterAuthorizedDevice(requesterJid, requesterAddress, requesterNormalizedDeviceJid);
557
+ if (!requesterAuthorized) {
558
+ return { authorized: false, reason: 'requester_device_not_authorized' };
559
+ }
441
560
  }
442
561
  return { authorized: true };
443
562
  }
@@ -495,7 +614,11 @@ export class WaRetryCoordinator {
495
614
  return;
496
615
  }
497
616
  try {
498
- await this.sendNode(buildInboundRetryReceiptAckNode(receiptNode));
617
+ await this.sendNode(buildAckNode({
618
+ kind: 'receipt',
619
+ node: receiptNode,
620
+ retryType: true
621
+ }));
499
622
  }
500
623
  catch (error) {
501
624
  this.logger.warn('failed to send retry ack', {
@@ -511,6 +634,7 @@ export class WaRetryCoordinator {
511
634
  return;
512
635
  }
513
636
  this.nextRetryCleanupAtMs = nowMs + RETRY_CLEANUP_INTERVAL_MS;
637
+ this.cleanupRetrySessionBaseKeys(nowMs);
514
638
  try {
515
639
  await this.retryStore.cleanupExpired(nowMs);
516
640
  }
@@ -520,4 +644,34 @@ export class WaRetryCoordinator {
520
644
  });
521
645
  }
522
646
  }
647
+ retrySessionBaseKeyMapKey(originalMsgId, requesterNormalizedDeviceJid) {
648
+ return `${originalMsgId}|${requesterNormalizedDeviceJid}`;
649
+ }
650
+ setRetrySessionBaseKey(originalMsgId, requesterNormalizedDeviceJid, baseKey, expiresAtMs) {
651
+ const key = this.retrySessionBaseKeyMapKey(originalMsgId, requesterNormalizedDeviceJid);
652
+ setBoundedMapEntry(this.retrySessionBaseKeys, key, {
653
+ baseKey: Uint8Array.from(baseKey),
654
+ expiresAtMs
655
+ }, RETRY_SESSION_BASE_KEY_CACHE_MAX_ENTRIES);
656
+ }
657
+ getRetrySessionBaseKey(originalMsgId, requesterNormalizedDeviceJid) {
658
+ const key = this.retrySessionBaseKeyMapKey(originalMsgId, requesterNormalizedDeviceJid);
659
+ const entry = this.retrySessionBaseKeys.get(key);
660
+ if (!entry) {
661
+ return null;
662
+ }
663
+ if (entry.expiresAtMs <= Date.now()) {
664
+ this.retrySessionBaseKeys.delete(key);
665
+ return null;
666
+ }
667
+ return entry;
668
+ }
669
+ cleanupRetrySessionBaseKeys(nowMs) {
670
+ for (const [key, entry] of this.retrySessionBaseKeys) {
671
+ if (entry.expiresAtMs > nowMs) {
672
+ continue;
673
+ }
674
+ this.retrySessionBaseKeys.delete(key);
675
+ }
676
+ }
523
677
  }
@@ -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 });
@@ -0,0 +1,180 @@
1
+ import { CsTokenGenerator } from '../tokens/cs-token.js';
2
+ import { clampDuration, isTokenExpired, shouldSendNewToken } from '../tokens/tc-token.js';
3
+ import { PromiseDedup } from '../../infra/perf/PromiseDedup.js';
4
+ import { WA_PRIVACY_TOKEN_TYPES, WA_TC_TOKEN_DEFAULTS } from '../../protocol/privacy-token.js';
5
+ import { buildCsTokenMessageNode, buildPrivacyTokenIqNode, buildTcTokenMessageNode } from '../../transport/node/builders/privacy-token.js';
6
+ import { toError } from '../../util/primitives.js';
7
+ const NCT_SALT_SENTINEL_JID = '__nct_salt__';
8
+ export class WaTrustedContactTokenCoordinator {
9
+ constructor(options) {
10
+ this.logger = options.logger;
11
+ this.store = options.store;
12
+ this.runtime = options.runtime;
13
+ const maxDurationS = options.maxDurationS ?? WA_TC_TOKEN_DEFAULTS.MAX_DURATION_S;
14
+ this.baseConfig = {
15
+ durationS: clampDuration(options.durationS ?? WA_TC_TOKEN_DEFAULTS.DURATION_S, maxDurationS),
16
+ numBuckets: options.numBuckets ?? WA_TC_TOKEN_DEFAULTS.NUM_BUCKETS,
17
+ senderDurationS: clampDuration(options.senderDurationS ?? WA_TC_TOKEN_DEFAULTS.SENDER_DURATION_S, maxDurationS),
18
+ senderNumBuckets: options.senderNumBuckets ?? WA_TC_TOKEN_DEFAULTS.SENDER_NUM_BUCKETS,
19
+ maxDurationS
20
+ };
21
+ this.getConfigOverrides = options.getConfigOverrides;
22
+ this.csTokenGenerator = new CsTokenGenerator();
23
+ this.senderTokenDedup = new PromiseDedup();
24
+ this.cachedNctSalt = null;
25
+ this.nctSaltHydrated = false;
26
+ }
27
+ resolveConfig() {
28
+ const overrides = this.getConfigOverrides?.();
29
+ if (!overrides) {
30
+ return this.baseConfig;
31
+ }
32
+ const maxDurationS = overrides.maxDurationS ?? this.baseConfig.maxDurationS;
33
+ return {
34
+ durationS: clampDuration(overrides.durationS ?? this.baseConfig.durationS, maxDurationS),
35
+ numBuckets: overrides.numBuckets ?? this.baseConfig.numBuckets,
36
+ senderDurationS: clampDuration(overrides.senderDurationS ?? this.baseConfig.senderDurationS, maxDurationS),
37
+ senderNumBuckets: overrides.senderNumBuckets ?? this.baseConfig.senderNumBuckets,
38
+ maxDurationS
39
+ };
40
+ }
41
+ async resolveTokenForMessage(recipientJid) {
42
+ const record = await this.store.getByJid(recipientJid);
43
+ const nowS = Math.floor(Date.now() / 1000);
44
+ const config = this.resolveConfig();
45
+ if (record?.tcToken &&
46
+ record.tcTokenTimestamp !== undefined &&
47
+ !isTokenExpired(record.tcTokenTimestamp, nowS, config.durationS, config.numBuckets)) {
48
+ return buildTcTokenMessageNode(record.tcToken);
49
+ }
50
+ const nctSalt = await this.getNctSalt();
51
+ if (!nctSalt) {
52
+ return null;
53
+ }
54
+ const meLid = this.runtime.getCurrentMeLid();
55
+ if (!meLid) {
56
+ return null;
57
+ }
58
+ const hash = await this.csTokenGenerator.generate(nctSalt, meLid);
59
+ return buildCsTokenMessageNode(hash);
60
+ }
61
+ async handleIncomingToken(fromJid, tokens) {
62
+ const nowMs = Date.now();
63
+ for (let i = 0; i < tokens.length; i += 1) {
64
+ const token = tokens[i];
65
+ if (token.type !== WA_PRIVACY_TOKEN_TYPES.TRUSTED_CONTACT) {
66
+ this.logger.warn('ignoring unknown privacy token type', { type: token.type });
67
+ continue;
68
+ }
69
+ await this.store.upsert({
70
+ jid: fromJid,
71
+ tcToken: token.tokenBytes,
72
+ tcTokenTimestamp: token.timestampS,
73
+ updatedAtMs: nowMs
74
+ });
75
+ this.runtime.emitEvent('privacy_token_update', {
76
+ jid: fromJid,
77
+ timestampS: token.timestampS,
78
+ type: token.type,
79
+ source: 'notification'
80
+ });
81
+ }
82
+ }
83
+ async maybeIssueSenderToken(recipientJid) {
84
+ return this.senderTokenDedup.run(recipientJid, async () => {
85
+ const nowS = Math.floor(Date.now() / 1000);
86
+ const record = await this.store.getByJid(recipientJid);
87
+ const senderTimestampS = record?.tcTokenSenderTimestamp;
88
+ const config = this.resolveConfig();
89
+ if (senderTimestampS !== undefined && senderTimestampS > 0) {
90
+ if (!shouldSendNewToken(senderTimestampS, nowS, config.senderDurationS)) {
91
+ return;
92
+ }
93
+ }
94
+ await this.issuePrivacyToken(recipientJid, nowS);
95
+ await this.store.upsert({
96
+ jid: recipientJid,
97
+ tcTokenSenderTimestamp: nowS,
98
+ updatedAtMs: Date.now()
99
+ });
100
+ });
101
+ }
102
+ async reissueOnIdentityChange(jid) {
103
+ const record = await this.store.getByJid(jid);
104
+ if (!record?.tcTokenSenderTimestamp) {
105
+ return;
106
+ }
107
+ const nowS = Math.floor(Date.now() / 1000);
108
+ const config = this.resolveConfig();
109
+ if (isTokenExpired(record.tcTokenSenderTimestamp, nowS, config.senderDurationS, config.senderNumBuckets)) {
110
+ return;
111
+ }
112
+ try {
113
+ await this.issuePrivacyToken(jid, record.tcTokenSenderTimestamp);
114
+ }
115
+ catch (error) {
116
+ this.logger.warn('send-tc-token-device-identity-change-failed', {
117
+ jid,
118
+ message: toError(error).message
119
+ });
120
+ }
121
+ }
122
+ async hydrateFromHistorySync(conversations) {
123
+ const nowMs = Date.now();
124
+ const records = [];
125
+ for (let i = 0; i < conversations.length; i += 1) {
126
+ const conv = conversations[i];
127
+ if (!conv.tcToken && !conv.tcTokenTimestamp && !conv.tcTokenSenderTimestamp) {
128
+ continue;
129
+ }
130
+ records[records.length] = {
131
+ jid: conv.jid,
132
+ tcToken: conv.tcToken ?? undefined,
133
+ tcTokenTimestamp: conv.tcTokenTimestamp ?? undefined,
134
+ tcTokenSenderTimestamp: conv.tcTokenSenderTimestamp ?? undefined,
135
+ updatedAtMs: nowMs
136
+ };
137
+ }
138
+ if (records.length > 0) {
139
+ await this.store.upsertBatch(records);
140
+ }
141
+ }
142
+ async handleNctSaltSync(salt) {
143
+ if (salt) {
144
+ await this.store.upsert({
145
+ jid: NCT_SALT_SENTINEL_JID,
146
+ nctSalt: salt,
147
+ updatedAtMs: Date.now()
148
+ });
149
+ this.cachedNctSalt = salt;
150
+ }
151
+ else {
152
+ await this.store.deleteByJid(NCT_SALT_SENTINEL_JID);
153
+ this.cachedNctSalt = null;
154
+ }
155
+ this.nctSaltHydrated = true;
156
+ this.csTokenGenerator.invalidate();
157
+ }
158
+ async hydrateNctSaltFromHistorySync(salt) {
159
+ await this.store.upsert({
160
+ jid: NCT_SALT_SENTINEL_JID,
161
+ nctSalt: salt,
162
+ updatedAtMs: Date.now()
163
+ });
164
+ this.cachedNctSalt = salt;
165
+ this.nctSaltHydrated = true;
166
+ }
167
+ async getNctSalt() {
168
+ if (this.nctSaltHydrated) {
169
+ return this.cachedNctSalt;
170
+ }
171
+ const record = await this.store.getByJid(NCT_SALT_SENTINEL_JID);
172
+ this.cachedNctSalt = record?.nctSalt ?? null;
173
+ this.nctSaltHydrated = true;
174
+ return this.cachedNctSalt;
175
+ }
176
+ async issuePrivacyToken(jid, timestampS) {
177
+ const node = buildPrivacyTokenIqNode({ jid, timestampS });
178
+ await this.runtime.queryWithContext('issue-privacy-token', node);
179
+ }
180
+ }