zapo-js 0.1.2 → 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 (468) hide show
  1. package/README.md +12 -4
  2. package/dist/appstate/WaAppStateCrypto.js +1 -1
  3. package/dist/appstate/WaAppStateSyncClient.js +138 -93
  4. package/dist/appstate/{store/sqlite.js → encoding.js} +13 -8
  5. package/dist/appstate/index.js +8 -6
  6. package/dist/appstate/utils.js +0 -5
  7. package/dist/auth/WaAuthClient.js +36 -47
  8. package/dist/auth/flow/WaAuthCredentialsFlow.js +7 -7
  9. package/dist/auth/index.js +1 -6
  10. package/dist/auth/pairing/WaPairingCodeCrypto.js +6 -4
  11. package/dist/auth/pairing/WaPairingFlow.js +13 -3
  12. package/dist/client/WaClient.js +225 -101
  13. package/dist/client/WaClientFactory.js +294 -44
  14. package/dist/client/connection/WaConnectionManager.js +19 -10
  15. package/dist/client/coordinators/WaBusinessCoordinator.js +241 -0
  16. package/dist/client/coordinators/WaGroupCoordinator.js +11 -7
  17. package/dist/client/coordinators/WaIncomingNodeCoordinator.js +1 -0
  18. package/dist/client/coordinators/WaMessageDispatchCoordinator.js +292 -99
  19. package/dist/client/coordinators/WaPassiveTasksCoordinator.js +74 -31
  20. package/dist/client/coordinators/WaPrivacyCoordinator.js +134 -0
  21. package/dist/client/coordinators/WaProfileCoordinator.js +212 -0
  22. package/dist/client/coordinators/WaRetryCoordinator.js +179 -27
  23. package/dist/client/coordinators/WaStreamControlCoordinator.js +18 -11
  24. package/dist/client/coordinators/WaTrustedContactTokenCoordinator.js +166 -0
  25. package/dist/client/dirty.js +40 -20
  26. package/dist/client/events/devices.js +72 -0
  27. package/dist/client/events/group.js +3 -11
  28. package/dist/client/events/identity.js +22 -0
  29. package/dist/client/events/privacy-token.js +39 -0
  30. package/dist/client/history-sync.js +50 -9
  31. package/dist/client/incoming.js +37 -7
  32. package/dist/client/mailbox.js +24 -23
  33. package/dist/client/messages.js +107 -31
  34. package/dist/client/messaging/fanout.js +21 -11
  35. package/dist/client/messaging/participants.js +6 -4
  36. package/dist/client/persistence/WriteBehindPersistence.js +129 -0
  37. package/dist/client/tokens/cs-token.js +50 -0
  38. package/dist/client/tokens/tc-token.js +25 -0
  39. package/dist/crypto/core/index.js +2 -2
  40. package/dist/crypto/core/keys.js +4 -4
  41. package/dist/crypto/core/nonce.js +2 -0
  42. package/dist/crypto/core/primitives.js +0 -8
  43. package/dist/crypto/core/random.js +22 -0
  44. package/dist/crypto/curves/X25519.js +25 -6
  45. package/dist/crypto/index.js +3 -0
  46. package/dist/crypto/math/constants.js +13 -36
  47. package/dist/crypto/math/edwards.js +171 -44
  48. package/dist/crypto/math/fe.js +706 -0
  49. package/dist/crypto/math/mod.js +10 -3
  50. package/dist/esm/appstate/WaAppStateCrypto.js +1 -1
  51. package/dist/esm/appstate/WaAppStateSyncClient.js +138 -93
  52. package/dist/esm/appstate/{store/sqlite.js → encoding.js} +13 -8
  53. package/dist/esm/appstate/index.js +2 -2
  54. package/dist/esm/appstate/utils.js +2 -5
  55. package/dist/esm/auth/WaAuthClient.js +36 -47
  56. package/dist/esm/auth/flow/WaAuthCredentialsFlow.js +7 -7
  57. package/dist/esm/auth/index.js +0 -2
  58. package/dist/esm/auth/pairing/WaPairingCodeCrypto.js +6 -4
  59. package/dist/esm/auth/pairing/WaPairingFlow.js +14 -4
  60. package/dist/esm/client/WaClient.js +225 -101
  61. package/dist/esm/client/WaClientFactory.js +295 -45
  62. package/dist/esm/client/connection/WaConnectionManager.js +19 -10
  63. package/dist/esm/client/coordinators/WaBusinessCoordinator.js +238 -0
  64. package/dist/esm/client/coordinators/WaGroupCoordinator.js +11 -7
  65. package/dist/esm/client/coordinators/WaIncomingNodeCoordinator.js +1 -0
  66. package/dist/esm/client/coordinators/WaMessageDispatchCoordinator.js +295 -102
  67. package/dist/esm/client/coordinators/WaPassiveTasksCoordinator.js +74 -31
  68. package/dist/esm/client/coordinators/WaPrivacyCoordinator.js +131 -0
  69. package/dist/esm/client/coordinators/WaProfileCoordinator.js +209 -0
  70. package/dist/esm/client/coordinators/WaRetryCoordinator.js +181 -29
  71. package/dist/esm/client/coordinators/WaStreamControlCoordinator.js +19 -12
  72. package/dist/esm/client/coordinators/WaTrustedContactTokenCoordinator.js +162 -0
  73. package/dist/esm/client/dirty.js +40 -20
  74. package/dist/esm/client/events/devices.js +68 -0
  75. package/dist/esm/client/events/group.js +3 -11
  76. package/dist/esm/client/events/identity.js +19 -0
  77. package/dist/esm/client/events/privacy-token.js +36 -0
  78. package/dist/esm/client/history-sync.js +50 -9
  79. package/dist/esm/client/incoming.js +38 -8
  80. package/dist/esm/client/mailbox.js +24 -23
  81. package/dist/esm/client/messages.js +108 -32
  82. package/dist/esm/client/messaging/fanout.js +22 -12
  83. package/dist/esm/client/messaging/participants.js +6 -4
  84. package/dist/esm/client/persistence/WriteBehindPersistence.js +125 -0
  85. package/dist/esm/client/tokens/cs-token.js +46 -0
  86. package/dist/esm/client/tokens/tc-token.js +18 -0
  87. package/dist/esm/crypto/core/index.js +2 -2
  88. package/dist/esm/crypto/core/keys.js +1 -1
  89. package/dist/esm/crypto/core/nonce.js +2 -0
  90. package/dist/esm/crypto/core/primitives.js +0 -7
  91. package/dist/esm/crypto/core/random.js +22 -1
  92. package/dist/esm/crypto/curves/X25519.js +25 -6
  93. package/dist/esm/crypto/index.js +1 -0
  94. package/dist/esm/crypto/math/constants.js +12 -35
  95. package/dist/esm/crypto/math/edwards.js +174 -47
  96. package/dist/esm/crypto/math/fe.js +691 -0
  97. package/dist/esm/crypto/math/mod.js +10 -1
  98. package/dist/esm/index.js +1 -1
  99. package/dist/esm/infra/perf/BackgroundQueue.js +478 -0
  100. package/dist/esm/infra/perf/BoundedTaskQueue.js +3 -1
  101. package/dist/esm/infra/perf/PromiseDedup.js +20 -0
  102. package/dist/esm/infra/perf/SharedExclusiveGate.js +109 -0
  103. package/dist/esm/infra/perf/StoreLock.js +77 -0
  104. package/dist/esm/media/WaMediaCrypto.js +95 -13
  105. package/dist/esm/media/WaMediaTransferClient.js +39 -47
  106. package/dist/esm/media/constants.js +2 -1
  107. package/dist/esm/message/WaMessageClient.js +26 -19
  108. package/dist/esm/message/content.js +195 -9
  109. package/dist/esm/message/icdc.js +76 -0
  110. package/dist/esm/message/incoming.js +24 -12
  111. package/dist/esm/message/phash.js +3 -1
  112. package/dist/esm/message/reporting-token.js +14 -27
  113. package/dist/esm/protocol/appstate.js +9 -40
  114. package/dist/esm/protocol/browser.js +10 -18
  115. package/dist/esm/protocol/constants.js +5 -3
  116. package/dist/esm/protocol/defaults.js +6 -0
  117. package/dist/esm/protocol/index.js +1 -2
  118. package/dist/esm/protocol/jid.js +105 -36
  119. package/dist/esm/protocol/message.js +61 -1
  120. package/dist/esm/protocol/nodes.js +2 -0
  121. package/dist/esm/protocol/notification.js +3 -1
  122. package/dist/esm/protocol/privacy-token.js +17 -0
  123. package/dist/esm/protocol/privacy.js +55 -0
  124. package/dist/esm/protocol/stream.js +26 -1
  125. package/dist/esm/retry/codec.js +216 -0
  126. package/dist/esm/retry/constants.js +1 -1
  127. package/dist/esm/retry/index.js +2 -2
  128. package/dist/esm/retry/parse.js +50 -30
  129. package/dist/esm/retry/replay.js +11 -7
  130. package/dist/esm/retry/tracker.js +50 -12
  131. package/dist/esm/signal/api/SignalDeviceSyncApi.js +49 -32
  132. package/dist/esm/signal/api/SignalDigestSyncApi.js +13 -9
  133. package/dist/esm/signal/api/SignalIdentitySyncApi.js +26 -11
  134. package/dist/esm/signal/api/SignalMissingPreKeysSyncApi.js +18 -7
  135. package/dist/esm/signal/api/SignalRotateKeyApi.js +4 -2
  136. package/dist/esm/signal/api/SignalSessionSyncApi.js +16 -7
  137. package/dist/esm/signal/api/result-map.js +10 -0
  138. package/dist/esm/signal/constants.js +0 -4
  139. package/dist/esm/signal/crypto/WaAdvSignature.js +12 -6
  140. package/dist/esm/signal/{store/sqlite.js → encoding.js} +78 -24
  141. package/dist/esm/signal/group/SenderKeyCodec.js +3 -2
  142. package/dist/esm/signal/group/SenderKeyManager.js +125 -106
  143. package/dist/esm/signal/index.js +1 -0
  144. package/dist/esm/signal/registration/keygen.js +6 -2
  145. package/dist/esm/signal/registration/utils.js +1 -0
  146. package/dist/esm/signal/session/SignalProtocol.js +150 -74
  147. package/dist/esm/signal/session/resolver.js +137 -102
  148. package/dist/esm/store/contracts/privacy-token.store.js +1 -0
  149. package/dist/esm/store/createStore.js +101 -187
  150. package/dist/esm/store/index.js +1 -10
  151. package/dist/esm/store/locks/appstate.lock.js +26 -0
  152. package/dist/esm/store/locks/auth.lock.js +15 -0
  153. package/dist/esm/store/locks/contact.lock.js +20 -0
  154. package/dist/esm/store/locks/device-list.lock.js +20 -0
  155. package/dist/esm/store/locks/message.lock.js +21 -0
  156. package/dist/esm/store/locks/participants.lock.js +20 -0
  157. package/dist/esm/store/locks/privacy-token.lock.js +18 -0
  158. package/dist/esm/store/locks/retry.lock.js +29 -0
  159. package/dist/esm/store/locks/sender-key.lock.js +52 -0
  160. package/dist/esm/store/locks/signal.lock.js +63 -0
  161. package/dist/esm/store/locks/thread.lock.js +21 -0
  162. package/dist/esm/store/noop.store.js +1 -1
  163. package/dist/esm/store/providers/memory/appstate.store.js +22 -24
  164. package/dist/esm/store/providers/memory/device-list.store.js +10 -5
  165. package/dist/esm/store/providers/memory/privacy-token.store.js +43 -0
  166. package/dist/esm/store/providers/memory/retry.store.js +77 -2
  167. package/dist/esm/store/providers/memory/sender-key.store.js +6 -1
  168. package/dist/esm/store/providers/memory/signal.store.js +36 -19
  169. package/dist/esm/transport/WaComms.js +3 -1
  170. package/dist/esm/transport/WaWebSocket.js +0 -6
  171. package/dist/esm/transport/binary/constants.js +0 -30
  172. package/dist/esm/transport/binary/decoder.js +4 -4
  173. package/dist/esm/transport/binary/encoder.js +8 -15
  174. package/dist/esm/transport/binary/index.js +0 -1
  175. package/dist/esm/transport/node/WaNodeOrchestrator.js +25 -19
  176. package/dist/esm/transport/node/builders/business.js +129 -0
  177. package/dist/esm/transport/node/builders/global.js +370 -0
  178. package/dist/esm/transport/node/builders/index.js +5 -2
  179. package/dist/esm/transport/node/builders/message.js +63 -239
  180. package/dist/esm/transport/node/builders/pairing.js +0 -24
  181. package/dist/esm/transport/node/builders/privacy-token.js +41 -0
  182. package/dist/esm/transport/node/builders/privacy.js +48 -0
  183. package/dist/esm/transport/node/builders/profile.js +70 -0
  184. package/dist/esm/transport/node/builders/retry.js +10 -22
  185. package/dist/esm/transport/node/builders/usync.js +6 -2
  186. package/dist/esm/transport/node/helpers.js +19 -1
  187. package/dist/esm/transport/node/usync.js +3 -33
  188. package/dist/esm/transport/node/xml.js +35 -14
  189. package/dist/esm/transport/noise/WaClientPayload.js +10 -10
  190. package/dist/esm/transport/noise/WaNoiseCert.js +3 -3
  191. package/dist/esm/transport/noise/WaNoiseSession.js +64 -23
  192. package/dist/esm/transport/noise/WaNoiseSocket.js +8 -4
  193. package/dist/esm/transport/stream/parse.js +8 -4
  194. package/dist/esm/util/bytes.js +22 -18
  195. package/dist/esm/util/index.js +5 -0
  196. package/dist/esm/util/primitives.js +3 -2
  197. package/dist/index.js +7 -1
  198. package/dist/infra/perf/BackgroundQueue.js +482 -0
  199. package/dist/infra/perf/BoundedTaskQueue.js +3 -1
  200. package/dist/infra/perf/PromiseDedup.js +24 -0
  201. package/dist/infra/perf/SharedExclusiveGate.js +113 -0
  202. package/dist/infra/perf/StoreLock.js +81 -0
  203. package/dist/media/WaMediaCrypto.js +94 -12
  204. package/dist/media/WaMediaTransferClient.js +39 -47
  205. package/dist/media/constants.js +2 -1
  206. package/dist/message/WaMessageClient.js +26 -19
  207. package/dist/message/content.js +198 -9
  208. package/dist/message/icdc.js +81 -0
  209. package/dist/message/incoming.js +24 -12
  210. package/dist/message/phash.js +3 -1
  211. package/dist/message/reporting-token.js +14 -28
  212. package/dist/protocol/appstate.js +10 -41
  213. package/dist/protocol/browser.js +10 -18
  214. package/dist/protocol/constants.js +21 -2
  215. package/dist/protocol/defaults.js +6 -0
  216. package/dist/protocol/index.js +8 -5
  217. package/dist/protocol/jid.js +111 -36
  218. package/dist/protocol/message.js +62 -2
  219. package/dist/protocol/nodes.js +2 -0
  220. package/dist/protocol/notification.js +3 -1
  221. package/dist/protocol/privacy-token.js +20 -0
  222. package/dist/protocol/privacy.js +58 -0
  223. package/dist/protocol/stream.js +27 -2
  224. package/dist/retry/codec.js +220 -0
  225. package/dist/retry/constants.js +1 -1
  226. package/dist/retry/index.js +5 -5
  227. package/dist/retry/parse.js +51 -30
  228. package/dist/retry/replay.js +10 -6
  229. package/dist/retry/tracker.js +50 -12
  230. package/dist/signal/api/SignalDeviceSyncApi.js +48 -31
  231. package/dist/signal/api/SignalDigestSyncApi.js +13 -9
  232. package/dist/signal/api/SignalIdentitySyncApi.js +25 -10
  233. package/dist/signal/api/SignalMissingPreKeysSyncApi.js +17 -6
  234. package/dist/signal/api/SignalRotateKeyApi.js +4 -2
  235. package/dist/signal/api/SignalSessionSyncApi.js +16 -7
  236. package/dist/signal/api/result-map.js +13 -0
  237. package/dist/signal/constants.js +1 -5
  238. package/dist/signal/crypto/WaAdvSignature.js +11 -5
  239. package/dist/signal/{store/sqlite.js → encoding.js} +79 -25
  240. package/dist/signal/group/SenderKeyCodec.js +4 -3
  241. package/dist/signal/group/SenderKeyManager.js +125 -106
  242. package/dist/signal/index.js +13 -1
  243. package/dist/signal/registration/keygen.js +6 -2
  244. package/dist/signal/registration/utils.js +1 -0
  245. package/dist/signal/session/SignalProtocol.js +150 -74
  246. package/dist/signal/session/resolver.js +135 -100
  247. package/dist/store/contracts/privacy-token.store.js +2 -0
  248. package/dist/store/createStore.js +101 -187
  249. package/dist/store/index.js +15 -33
  250. package/dist/store/locks/appstate.lock.js +29 -0
  251. package/dist/store/locks/auth.lock.js +18 -0
  252. package/dist/store/locks/contact.lock.js +23 -0
  253. package/dist/store/locks/device-list.lock.js +23 -0
  254. package/dist/store/locks/message.lock.js +24 -0
  255. package/dist/store/locks/participants.lock.js +23 -0
  256. package/dist/store/locks/privacy-token.lock.js +21 -0
  257. package/dist/store/locks/retry.lock.js +32 -0
  258. package/dist/store/locks/sender-key.lock.js +55 -0
  259. package/dist/store/locks/signal.lock.js +66 -0
  260. package/dist/store/locks/thread.lock.js +24 -0
  261. package/dist/store/noop.store.js +1 -1
  262. package/dist/store/providers/memory/appstate.store.js +22 -24
  263. package/dist/store/providers/memory/device-list.store.js +10 -5
  264. package/dist/store/providers/memory/privacy-token.store.js +47 -0
  265. package/dist/store/providers/memory/retry.store.js +77 -2
  266. package/dist/store/providers/memory/sender-key.store.js +6 -1
  267. package/dist/store/providers/memory/signal.store.js +36 -19
  268. package/dist/transport/WaComms.js +3 -1
  269. package/dist/transport/WaWebSocket.js +0 -6
  270. package/dist/transport/binary/constants.js +1 -31
  271. package/dist/transport/binary/decoder.js +4 -4
  272. package/dist/transport/binary/encoder.js +8 -15
  273. package/dist/transport/binary/index.js +0 -4
  274. package/dist/transport/node/WaNodeOrchestrator.js +24 -18
  275. package/dist/transport/node/builders/business.js +137 -0
  276. package/dist/transport/node/builders/global.js +375 -0
  277. package/dist/transport/node/builders/index.js +18 -9
  278. package/dist/transport/node/builders/message.js +64 -245
  279. package/dist/transport/node/builders/pairing.js +0 -26
  280. package/dist/transport/node/builders/privacy-token.js +46 -0
  281. package/dist/transport/node/builders/privacy.js +55 -0
  282. package/dist/transport/node/builders/profile.js +78 -0
  283. package/dist/transport/node/builders/retry.js +9 -21
  284. package/dist/transport/node/builders/usync.js +6 -2
  285. package/dist/transport/node/helpers.js +20 -1
  286. package/dist/transport/node/usync.js +2 -32
  287. package/dist/transport/node/xml.js +35 -14
  288. package/dist/transport/noise/WaClientPayload.js +13 -13
  289. package/dist/transport/noise/WaNoiseCert.js +2 -2
  290. package/dist/transport/noise/WaNoiseSession.js +64 -23
  291. package/dist/transport/noise/WaNoiseSocket.js +8 -4
  292. package/dist/transport/stream/parse.js +7 -3
  293. package/dist/types/appstate/encoding.d.ts +7 -0
  294. package/dist/types/appstate/index.d.ts +3 -3
  295. package/dist/types/appstate/utils.d.ts +0 -2
  296. package/dist/types/auth/flow/WaAuthCredentialsFlow.d.ts +1 -1
  297. package/dist/types/auth/index.d.ts +0 -2
  298. package/dist/types/auth/types.d.ts +1 -0
  299. package/dist/types/client/WaClient.d.ts +27 -12
  300. package/dist/types/client/WaClientFactory.d.ts +12 -4
  301. package/dist/types/client/connection/WaConnectionManager.d.ts +2 -0
  302. package/dist/types/client/coordinators/WaBusinessCoordinator.d.ts +57 -0
  303. package/dist/types/client/coordinators/WaIncomingNodeCoordinator.d.ts +3 -1
  304. package/dist/types/client/coordinators/WaMessageDispatchCoordinator.d.ts +14 -0
  305. package/dist/types/client/coordinators/WaPassiveTasksCoordinator.d.ts +4 -0
  306. package/dist/types/client/coordinators/WaPrivacyCoordinator.d.ts +26 -0
  307. package/dist/types/client/coordinators/WaProfileCoordinator.d.ts +36 -0
  308. package/dist/types/client/coordinators/WaRetryCoordinator.d.ts +6 -0
  309. package/dist/types/client/coordinators/WaStreamControlCoordinator.d.ts +3 -2
  310. package/dist/types/client/coordinators/WaTrustedContactTokenCoordinator.d.ts +45 -0
  311. package/dist/types/client/events/devices.d.ts +20 -0
  312. package/dist/types/client/events/identity.d.ts +9 -0
  313. package/dist/types/client/events/privacy-token.d.ts +7 -0
  314. package/dist/types/client/history-sync.d.ts +9 -6
  315. package/dist/types/client/incoming.d.ts +3 -1
  316. package/dist/types/client/index.d.ts +1 -1
  317. package/dist/types/client/mailbox.d.ts +3 -5
  318. package/dist/types/client/messages.d.ts +1 -2
  319. package/dist/types/client/persistence/WriteBehindPersistence.d.ts +34 -0
  320. package/dist/types/client/tokens/cs-token.d.ts +10 -0
  321. package/dist/types/client/tokens/tc-token.d.ts +5 -0
  322. package/dist/types/client/types.d.ts +51 -3
  323. package/dist/types/crypto/core/index.d.ts +2 -2
  324. package/dist/types/crypto/core/nonce.d.ts +2 -0
  325. package/dist/types/crypto/core/primitives.d.ts +0 -1
  326. package/dist/types/crypto/core/random.d.ts +1 -0
  327. package/dist/types/crypto/index.d.ts +1 -0
  328. package/dist/types/crypto/math/constants.d.ts +4 -2
  329. package/dist/types/crypto/math/fe.d.ts +30 -0
  330. package/dist/types/crypto/math/mod.d.ts +0 -2
  331. package/dist/types/crypto/math/types.d.ts +11 -4
  332. package/dist/types/index.d.ts +5 -3
  333. package/dist/types/infra/perf/BackgroundQueue.d.ts +58 -0
  334. package/dist/types/infra/perf/PromiseDedup.d.ts +4 -0
  335. package/dist/types/infra/perf/SharedExclusiveGate.d.ts +17 -0
  336. package/dist/types/infra/perf/StoreLock.d.ts +10 -0
  337. package/dist/types/media/WaMediaCrypto.d.ts +3 -2
  338. package/dist/types/media/WaMediaTransferClient.d.ts +3 -12
  339. package/dist/types/media/constants.d.ts +1 -1
  340. package/dist/types/media/index.d.ts +1 -1
  341. package/dist/types/media/types.d.ts +10 -2
  342. package/dist/types/message/content.d.ts +8 -0
  343. package/dist/types/message/icdc.d.ts +13 -0
  344. package/dist/types/message/reporting-token.d.ts +0 -1
  345. package/dist/types/message/types.d.ts +45 -6
  346. package/dist/types/protocol/appstate.d.ts +0 -11
  347. package/dist/types/protocol/constants.d.ts +7 -3
  348. package/dist/types/protocol/defaults.d.ts +6 -0
  349. package/dist/types/protocol/index.d.ts +1 -2
  350. package/dist/types/protocol/jid.d.ts +19 -2
  351. package/dist/types/protocol/message.d.ts +60 -0
  352. package/dist/types/protocol/nodes.d.ts +2 -0
  353. package/dist/types/protocol/notification.d.ts +2 -0
  354. package/dist/types/protocol/privacy-token.d.ts +17 -0
  355. package/dist/types/protocol/privacy.d.ts +75 -0
  356. package/dist/types/protocol/stream.d.ts +30 -0
  357. package/dist/types/retry/codec.d.ts +3 -0
  358. package/dist/types/retry/index.d.ts +3 -3
  359. package/dist/types/retry/parse.d.ts +5 -2
  360. package/dist/types/retry/tracker.d.ts +1 -0
  361. package/dist/types/retry/types.d.ts +6 -1
  362. package/dist/types/signal/api/SignalDeviceSyncApi.d.ts +2 -1
  363. package/dist/types/signal/api/SignalDigestSyncApi.d.ts +6 -0
  364. package/dist/types/signal/api/SignalIdentitySyncApi.d.ts +2 -0
  365. package/dist/types/signal/api/SignalRotateKeyApi.d.ts +4 -5
  366. package/dist/types/signal/api/SignalSessionSyncApi.d.ts +8 -6
  367. package/dist/types/signal/api/result-map.d.ts +1 -0
  368. package/dist/types/signal/constants.d.ts +0 -3
  369. package/dist/types/signal/{store/sqlite.d.ts → encoding.d.ts} +3 -3
  370. package/dist/types/signal/group/SenderKeyManager.d.ts +10 -5
  371. package/dist/types/signal/index.d.ts +2 -0
  372. package/dist/types/signal/session/SignalProtocol.d.ts +10 -4
  373. package/dist/types/signal/session/resolver.d.ts +7 -2
  374. package/dist/types/store/contracts/appstate.store.d.ts +1 -1
  375. package/dist/types/store/contracts/privacy-token.store.d.ts +16 -0
  376. package/dist/types/store/contracts/retry.store.d.ts +7 -0
  377. package/dist/types/store/contracts/signal.store.d.ts +7 -0
  378. package/dist/types/store/createStore.d.ts +1 -1
  379. package/dist/types/store/index.d.ts +5 -13
  380. package/dist/types/store/locks/appstate.lock.d.ts +3 -0
  381. package/dist/types/store/locks/auth.lock.d.ts +3 -0
  382. package/dist/types/store/locks/contact.lock.d.ts +3 -0
  383. package/dist/types/store/locks/device-list.lock.d.ts +2 -0
  384. package/dist/types/store/locks/message.lock.d.ts +3 -0
  385. package/dist/types/store/locks/participants.lock.d.ts +2 -0
  386. package/dist/types/store/locks/privacy-token.lock.d.ts +2 -0
  387. package/dist/types/store/locks/retry.lock.d.ts +2 -0
  388. package/dist/types/store/locks/sender-key.lock.d.ts +3 -0
  389. package/dist/types/store/locks/signal.lock.d.ts +3 -0
  390. package/dist/types/store/locks/thread.lock.d.ts +3 -0
  391. package/dist/types/store/providers/memory/appstate.store.d.ts +1 -1
  392. package/dist/types/store/providers/memory/privacy-token.store.d.ts +13 -0
  393. package/dist/types/store/providers/memory/retry.store.d.ts +8 -0
  394. package/dist/types/store/providers/memory/signal.store.d.ts +2 -1
  395. package/dist/types/store/types.d.ts +49 -61
  396. package/dist/types/transport/WaWebSocket.d.ts +0 -1
  397. package/dist/types/transport/binary/constants.d.ts +0 -30
  398. package/dist/types/transport/binary/index.d.ts +0 -1
  399. package/dist/types/transport/node/WaNodeOrchestrator.d.ts +3 -4
  400. package/dist/types/transport/node/builders/business.d.ts +29 -0
  401. package/dist/types/transport/node/builders/global.d.ts +102 -0
  402. package/dist/types/transport/node/builders/index.d.ts +5 -2
  403. package/dist/types/transport/node/builders/message.d.ts +8 -7
  404. package/dist/types/transport/node/builders/pairing.d.ts +0 -2
  405. package/dist/types/transport/node/builders/privacy-token.d.ts +9 -0
  406. package/dist/types/transport/node/builders/privacy.d.ts +7 -0
  407. package/dist/types/transport/node/builders/profile.d.ts +8 -0
  408. package/dist/types/transport/node/builders/retry.d.ts +0 -1
  409. package/dist/types/transport/node/helpers.d.ts +5 -0
  410. package/dist/types/transport/noise/WaNoiseSession.d.ts +3 -2
  411. package/dist/types/transport/noise/WaNoiseSocket.d.ts +4 -2
  412. package/dist/types/util/bytes.d.ts +1 -1
  413. package/dist/types/util/index.d.ts +5 -0
  414. package/dist/types/util/primitives.d.ts +0 -1
  415. package/dist/util/bytes.js +22 -18
  416. package/dist/util/index.js +23 -0
  417. package/dist/util/primitives.js +2 -2
  418. package/package.json +29 -7
  419. package/proto/index.js +1 -1
  420. package/dist/crypto/core/constants.js +0 -4
  421. package/dist/esm/crypto/core/constants.js +0 -1
  422. package/dist/esm/retry/outbound.js +0 -82
  423. package/dist/esm/store/providers/sqlite/BaseSqliteStore.js +0 -37
  424. package/dist/esm/store/providers/sqlite/appstate.store.js +0 -250
  425. package/dist/esm/store/providers/sqlite/auth.store.js +0 -176
  426. package/dist/esm/store/providers/sqlite/connection.js +0 -245
  427. package/dist/esm/store/providers/sqlite/contact.store.js +0 -74
  428. package/dist/esm/store/providers/sqlite/device-list.store.js +0 -127
  429. package/dist/esm/store/providers/sqlite/message.store.js +0 -132
  430. package/dist/esm/store/providers/sqlite/migrations.js +0 -347
  431. package/dist/esm/store/providers/sqlite/participants.store.js +0 -77
  432. package/dist/esm/store/providers/sqlite/retry.store.js +0 -141
  433. package/dist/esm/store/providers/sqlite/sender-key.store.js +0 -198
  434. package/dist/esm/store/providers/sqlite/signal.store.js +0 -435
  435. package/dist/esm/store/providers/sqlite/table-names.js +0 -107
  436. package/dist/esm/store/providers/sqlite/thread.store.js +0 -85
  437. package/dist/retry/outbound.js +0 -87
  438. package/dist/store/providers/sqlite/BaseSqliteStore.js +0 -41
  439. package/dist/store/providers/sqlite/appstate.store.js +0 -254
  440. package/dist/store/providers/sqlite/auth.store.js +0 -180
  441. package/dist/store/providers/sqlite/connection.js +0 -281
  442. package/dist/store/providers/sqlite/contact.store.js +0 -78
  443. package/dist/store/providers/sqlite/device-list.store.js +0 -131
  444. package/dist/store/providers/sqlite/message.store.js +0 -136
  445. package/dist/store/providers/sqlite/migrations.js +0 -350
  446. package/dist/store/providers/sqlite/participants.store.js +0 -81
  447. package/dist/store/providers/sqlite/retry.store.js +0 -145
  448. package/dist/store/providers/sqlite/sender-key.store.js +0 -202
  449. package/dist/store/providers/sqlite/signal.store.js +0 -439
  450. package/dist/store/providers/sqlite/table-names.js +0 -113
  451. package/dist/store/providers/sqlite/thread.store.js +0 -89
  452. package/dist/types/appstate/store/sqlite.d.ts +0 -7
  453. package/dist/types/crypto/core/constants.d.ts +0 -1
  454. package/dist/types/retry/outbound.d.ts +0 -4
  455. package/dist/types/store/providers/sqlite/BaseSqliteStore.d.ts +0 -12
  456. package/dist/types/store/providers/sqlite/appstate.store.d.ts +0 -17
  457. package/dist/types/store/providers/sqlite/auth.store.d.ts +0 -10
  458. package/dist/types/store/providers/sqlite/connection.d.ts +0 -10
  459. package/dist/types/store/providers/sqlite/contact.store.d.ts +0 -12
  460. package/dist/types/store/providers/sqlite/device-list.store.d.ts +0 -15
  461. package/dist/types/store/providers/sqlite/message.store.d.ts +0 -13
  462. package/dist/types/store/providers/sqlite/migrations.d.ts +0 -3
  463. package/dist/types/store/providers/sqlite/participants.store.d.ts +0 -12
  464. package/dist/types/store/providers/sqlite/retry.store.d.ts +0 -15
  465. package/dist/types/store/providers/sqlite/sender-key.store.d.ts +0 -24
  466. package/dist/types/store/providers/sqlite/signal.store.d.ts +0 -53
  467. package/dist/types/store/providers/sqlite/table-names.d.ts +0 -5
  468. package/dist/types/store/providers/sqlite/thread.store.d.ts +0 -13
@@ -5,15 +5,17 @@ const _proto_1 = require("../../proto.js");
5
5
  const constants_1 = require("../../protocol/constants");
6
6
  const jid_1 = require("../../protocol/jid");
7
7
  const constants_2 = require("../../retry/constants");
8
- const outbound_1 = require("../../retry/outbound");
9
8
  const parse_1 = require("../../retry/parse");
10
9
  const reason_1 = require("../../retry/reason");
11
10
  const replay_1 = require("../../retry/replay");
12
11
  const keygen_1 = require("../../signal/registration/keygen");
13
- const message_1 = require("../../transport/node/builders/message");
12
+ const global_1 = require("../../transport/node/builders/global");
14
13
  const retry_1 = require("../../transport/node/builders/retry");
14
+ const bytes_1 = require("../../util/bytes");
15
+ const collections_1 = require("../../util/collections");
15
16
  const primitives_1 = require("../../util/primitives");
16
17
  const RETRY_CLEANUP_INTERVAL_MS = 30000;
18
+ const RETRY_SESSION_BASE_KEY_CACHE_MAX_ENTRIES = 8192;
17
19
  function getRetryReasonName(code) {
18
20
  if (code === undefined) {
19
21
  return undefined;
@@ -55,6 +57,7 @@ class WaRetryCoordinator {
55
57
  getCurrentSignedIdentity: this.getCurrentSignedIdentity
56
58
  });
57
59
  this.retryProcessingByMessageId = new Map();
60
+ this.retrySessionBaseKeys = new Map();
58
61
  }
59
62
  async onDecryptFailure(context, error) {
60
63
  try {
@@ -79,12 +82,23 @@ class WaRetryCoordinator {
79
82
  if (!this.isRetryReceiptNode(receiptNode)) {
80
83
  return;
81
84
  }
85
+ let shouldAck = false;
82
86
  try {
83
87
  await this.maybeCleanupRetryStore(Date.now());
84
- const request = (0, parse_1.parseRetryReceiptRequest)(receiptNode);
88
+ const expectedToJids = [];
89
+ const meJid = this.getCurrentMeJid()?.trim();
90
+ const meLid = this.getCurrentMeLid()?.trim();
91
+ if (meJid) {
92
+ expectedToJids.push(meJid);
93
+ }
94
+ if (meLid) {
95
+ expectedToJids.push(meLid);
96
+ }
97
+ const request = (0, parse_1.parseRetryReceiptRequest)(receiptNode, expectedToJids.length > 0 ? { expectedToJids } : undefined);
85
98
  if (!request) {
86
99
  return;
87
100
  }
101
+ shouldAck = true;
88
102
  await this.handleParsedRetryRequest(receiptNode, request);
89
103
  }
90
104
  catch (error) {
@@ -96,7 +110,9 @@ class WaRetryCoordinator {
96
110
  });
97
111
  }
98
112
  finally {
99
- await this.sendRetryAckSafe(receiptNode);
113
+ if (shouldAck) {
114
+ await this.sendRetryAckSafe(receiptNode);
115
+ }
100
116
  }
101
117
  }
102
118
  isRetryReceiptNode(node) {
@@ -132,7 +148,6 @@ class WaRetryCoordinator {
132
148
  to: context.from,
133
149
  participant: context.participant,
134
150
  recipient: context.recipient,
135
- from: this.getCurrentMeJid() ?? undefined,
136
151
  originalMsgId: context.stanzaId,
137
152
  retryCount: prepared.retryCount,
138
153
  t: prepared.timestamp,
@@ -203,8 +218,9 @@ class WaRetryCoordinator {
203
218
  let requesterAddress;
204
219
  let requesterNormalizedDeviceJid;
205
220
  try {
206
- requesterAddress = (0, jid_1.parseSignalAddressFromJid)(requesterJid);
207
- requesterNormalizedDeviceJid = (0, jid_1.normalizeDeviceJid)(requesterJid);
221
+ const requesterParsed = (0, jid_1.parseJidFull)(requesterJid);
222
+ requesterAddress = requesterParsed.address;
223
+ requesterNormalizedDeviceJid = requesterParsed.normalizedJid;
208
224
  }
209
225
  catch (error) {
210
226
  this.logger.info('retry request rejected: invalid requester jid', {
@@ -280,20 +296,36 @@ class WaRetryCoordinator {
280
296
  if (!nextState) {
281
297
  return;
282
298
  }
283
- const current = await this.retryStore.getOutboundMessage(messageId);
284
- if (!current) {
285
- return;
286
- }
287
- const merged = (0, outbound_1.pickRetryStateMax)(current.state, nextState);
288
- if (merged === current.state) {
289
- return;
290
- }
291
- const nowMs = Date.now();
292
- await this.retryStore.updateOutboundMessageState(messageId, merged, nowMs, nowMs + this.retryTtlMs);
299
+ await this.runRetryTaskSerialized(messageId, async () => {
300
+ const current = await this.retryStore.getOutboundMessage(messageId);
301
+ if (!current) {
302
+ return;
303
+ }
304
+ const nowMs = Date.now();
305
+ const expiresAtMs = nowMs + this.retryTtlMs;
306
+ const merged = (0, parse_1.pickRetryStateMax)(current.state, nextState);
307
+ if (merged !== current.state) {
308
+ await this.retryStore.updateOutboundMessageState(messageId, merged, nowMs, expiresAtMs);
309
+ }
310
+ const requesterJid = receiptNode.attrs.participant ?? receiptNode.attrs.from;
311
+ if (!requesterJid) {
312
+ return;
313
+ }
314
+ try {
315
+ await this.retryStore.markOutboundRequesterDelivered(messageId, (0, jid_1.normalizeDeviceJid)(requesterJid), nowMs, expiresAtMs);
316
+ }
317
+ catch (error) {
318
+ this.logger.warn('failed to update outbound requester delivery state', {
319
+ id: messageId,
320
+ requester: requesterJid,
321
+ message: (0, primitives_1.toError)(error).message
322
+ });
323
+ }
324
+ });
293
325
  }
294
326
  async runRetryTaskSerialized(messageId, task) {
295
327
  const previous = this.retryProcessingByMessageId.get(messageId) ?? Promise.resolve();
296
- const current = previous.then(task, task);
328
+ const current = previous.then(task);
297
329
  const tracker = current.then(() => undefined, () => undefined);
298
330
  this.retryProcessingByMessageId.set(messageId, tracker);
299
331
  try {
@@ -334,15 +366,45 @@ class WaRetryCoordinator {
334
366
  };
335
367
  }
336
368
  async updateLocalSessionFromRetryRequest(request, requesterJid, requesterAddress, requesterNormalizedDeviceJid) {
337
- await this.markRetryRequesterSenderKeyAsStale(request, requesterJid, requesterAddress);
338
- const currentSession = await this.signalStore.getSession(requesterAddress);
339
- if (currentSession && request.regId > 0 && currentSession.remote.regId !== request.regId) {
369
+ const [, currentSession] = await Promise.all([
370
+ this.markRetryRequesterSenderKeyAsStale(request, requesterJid, requesterAddress),
371
+ this.signalStore.getSession(requesterAddress)
372
+ ]);
373
+ const regIdMismatch = !!currentSession && request.regId > 0 && currentSession.remote.regId !== request.regId;
374
+ if (regIdMismatch && !request.keyBundle) {
340
375
  await this.signalStore.deleteSession(requesterAddress);
341
376
  }
342
377
  if (request.keyBundle) {
343
378
  if (!request.keyBundle.key || !request.keyBundle.skey.signature) {
344
379
  return false;
345
380
  }
381
+ if (request.offline) {
382
+ if (!currentSession) {
383
+ this.logger.info('retry request rejected: offline retry missing existing session', {
384
+ id: request.stanzaId,
385
+ originalMsgId: request.originalMsgId,
386
+ requester: requesterJid,
387
+ remoteRetryCount: request.retryCount,
388
+ ...getRemoteRetryReasonLogFields(request.retryReason)
389
+ });
390
+ await this.signalStore.deleteSession(requesterAddress);
391
+ return false;
392
+ }
393
+ if (regIdMismatch) {
394
+ this.logger.info('retry request rejected: offline retry registration id mismatch', {
395
+ id: request.stanzaId,
396
+ originalMsgId: request.originalMsgId,
397
+ requester: requesterJid,
398
+ remoteRetryCount: request.retryCount,
399
+ ...getRemoteRetryReasonLogFields(request.retryReason)
400
+ });
401
+ await this.signalStore.deleteSession(requesterAddress);
402
+ return false;
403
+ }
404
+ }
405
+ else if (regIdMismatch) {
406
+ await this.signalStore.deleteSession(requesterAddress);
407
+ }
346
408
  await this.signalProtocol.establishOutgoingSession(requesterAddress, {
347
409
  regId: request.regId,
348
410
  identity: request.keyBundle.identity,
@@ -356,12 +418,45 @@ class WaRetryCoordinator {
356
418
  publicKey: request.keyBundle.key.publicKey
357
419
  }
358
420
  });
421
+ return this.applySessionBaseKeyPolicy(request, requesterJid, requesterAddress, requesterNormalizedDeviceJid);
422
+ }
423
+ const sessionStillExists = currentSession !== null && !regIdMismatch;
424
+ if (sessionStillExists) {
425
+ return this.applySessionBaseKeyPolicy(request, requesterJid, requesterAddress, requesterNormalizedDeviceJid);
426
+ }
427
+ const fetched = await this.fetchMissingPreKeysSession(requesterJid, requesterAddress, requesterNormalizedDeviceJid, request.regId);
428
+ if (!fetched) {
429
+ return false;
430
+ }
431
+ await this.signalProtocol.establishOutgoingSession(requesterAddress, fetched);
432
+ return this.applySessionBaseKeyPolicy(request, requesterJid, requesterAddress, requesterNormalizedDeviceJid);
433
+ }
434
+ async applySessionBaseKeyPolicy(request, requesterJid, requesterAddress, requesterNormalizedDeviceJid) {
435
+ if (request.retryCount < 2) {
359
436
  return true;
360
437
  }
361
- const hasSession = await this.signalProtocol.hasSession(requesterAddress);
362
- if (hasSession) {
438
+ const currentSession = await this.signalStore.getSession(requesterAddress);
439
+ const sessionBaseKey = currentSession?.aliceBaseKey ?? null;
440
+ if (!sessionBaseKey) {
363
441
  return true;
364
442
  }
443
+ const expiresAtMs = Date.now() + this.retryTtlMs;
444
+ if (request.retryCount === 2) {
445
+ this.setRetrySessionBaseKey(request.originalMsgId, requesterNormalizedDeviceJid, sessionBaseKey, expiresAtMs);
446
+ return true;
447
+ }
448
+ const saved = this.getRetrySessionBaseKey(request.originalMsgId, requesterNormalizedDeviceJid);
449
+ if (!saved || !(0, bytes_1.uint8Equal)(saved.baseKey, sessionBaseKey)) {
450
+ return true;
451
+ }
452
+ await this.signalStore.deleteSession(requesterAddress);
453
+ this.logger.info('retry request forcing session refresh due to repeated base key', {
454
+ id: request.stanzaId,
455
+ originalMsgId: request.originalMsgId,
456
+ requester: requesterJid,
457
+ remoteRetryCount: request.retryCount,
458
+ ...getRemoteRetryReasonLogFields(request.retryReason)
459
+ });
365
460
  const fetched = await this.fetchMissingPreKeysSession(requesterJid, requesterAddress, requesterNormalizedDeviceJid, request.regId);
366
461
  if (!fetched) {
367
462
  return false;
@@ -434,13 +529,35 @@ class WaRetryCoordinator {
434
529
  if (outbound.state === 'ineligible') {
435
530
  return { authorized: false, reason: `state_${outbound.state}` };
436
531
  }
532
+ let requesterStatus = null;
533
+ try {
534
+ requesterStatus = await this.retryStore.getOutboundRequesterStatus(outbound.messageId, requesterNormalizedDeviceJid);
535
+ }
536
+ catch (error) {
537
+ this.logger.warn('failed to resolve outbound requester status from retry store', {
538
+ id: request.stanzaId,
539
+ originalMsgId: request.originalMsgId,
540
+ requester: requesterJid,
541
+ message: (0, primitives_1.toError)(error).message
542
+ });
543
+ }
544
+ if (requesterStatus) {
545
+ if (!requesterStatus.eligible) {
546
+ return { authorized: false, reason: 'requester_device_not_eligible' };
547
+ }
548
+ if (requesterStatus.delivered) {
549
+ return { authorized: false, reason: 'requester_already_delivered' };
550
+ }
551
+ }
437
552
  const isGroupOutbound = (0, jid_1.isGroupOrBroadcastJid)(outbound.toJid);
438
553
  if (!isGroupOutbound && (outbound.state === 'read' || outbound.state === 'played')) {
439
554
  return { authorized: false, reason: `state_${outbound.state}` };
440
555
  }
441
- const requesterAuthorized = await this.isRequesterAuthorizedDevice(requesterJid, requesterAddress, requesterNormalizedDeviceJid);
442
- if (!requesterAuthorized) {
443
- return { authorized: false, reason: 'requester_device_not_authorized' };
556
+ if (!requesterStatus) {
557
+ const requesterAuthorized = await this.isRequesterAuthorizedDevice(requesterJid, requesterAddress, requesterNormalizedDeviceJid);
558
+ if (!requesterAuthorized) {
559
+ return { authorized: false, reason: 'requester_device_not_authorized' };
560
+ }
444
561
  }
445
562
  return { authorized: true };
446
563
  }
@@ -498,7 +615,11 @@ class WaRetryCoordinator {
498
615
  return;
499
616
  }
500
617
  try {
501
- await this.sendNode((0, message_1.buildInboundRetryReceiptAckNode)(receiptNode));
618
+ await this.sendNode((0, global_1.buildAckNode)({
619
+ kind: 'receipt',
620
+ node: receiptNode,
621
+ retryType: true
622
+ }));
502
623
  }
503
624
  catch (error) {
504
625
  this.logger.warn('failed to send retry ack', {
@@ -514,6 +635,7 @@ class WaRetryCoordinator {
514
635
  return;
515
636
  }
516
637
  this.nextRetryCleanupAtMs = nowMs + RETRY_CLEANUP_INTERVAL_MS;
638
+ this.cleanupRetrySessionBaseKeys(nowMs);
517
639
  try {
518
640
  await this.retryStore.cleanupExpired(nowMs);
519
641
  }
@@ -523,5 +645,35 @@ class WaRetryCoordinator {
523
645
  });
524
646
  }
525
647
  }
648
+ retrySessionBaseKeyMapKey(originalMsgId, requesterNormalizedDeviceJid) {
649
+ return `${originalMsgId}|${requesterNormalizedDeviceJid}`;
650
+ }
651
+ setRetrySessionBaseKey(originalMsgId, requesterNormalizedDeviceJid, baseKey, expiresAtMs) {
652
+ const key = this.retrySessionBaseKeyMapKey(originalMsgId, requesterNormalizedDeviceJid);
653
+ (0, collections_1.setBoundedMapEntry)(this.retrySessionBaseKeys, key, {
654
+ baseKey: Uint8Array.from(baseKey),
655
+ expiresAtMs
656
+ }, RETRY_SESSION_BASE_KEY_CACHE_MAX_ENTRIES);
657
+ }
658
+ getRetrySessionBaseKey(originalMsgId, requesterNormalizedDeviceJid) {
659
+ const key = this.retrySessionBaseKeyMapKey(originalMsgId, requesterNormalizedDeviceJid);
660
+ const entry = this.retrySessionBaseKeys.get(key);
661
+ if (!entry) {
662
+ return null;
663
+ }
664
+ if (entry.expiresAtMs <= Date.now()) {
665
+ this.retrySessionBaseKeys.delete(key);
666
+ return null;
667
+ }
668
+ return entry;
669
+ }
670
+ cleanupRetrySessionBaseKeys(nowMs) {
671
+ for (const [key, entry] of this.retrySessionBaseKeys) {
672
+ if (entry.expiresAtMs > nowMs) {
673
+ continue;
674
+ }
675
+ this.retrySessionBaseKeys.delete(key);
676
+ }
677
+ }
526
678
  }
527
679
  exports.WaRetryCoordinator = WaRetryCoordinator;
@@ -19,7 +19,7 @@ function createStreamControlHandler(options) {
19
19
  const restartBackendAfterStreamControl = async (reason) => {
20
20
  logger.info('restarting backend after stream control', { reason });
21
21
  try {
22
- await connect();
22
+ await connect(constants_1.WA_CONNECTION_REASONS.RECONNECTED);
23
23
  }
24
24
  catch (error) {
25
25
  logger.warn('failed to restart backend after stream control', {
@@ -46,29 +46,36 @@ function createStreamControlHandler(options) {
46
46
  });
47
47
  }
48
48
  };
49
+ const stopCommsImmediately = () => {
50
+ void getComms()?.stopComms();
51
+ };
49
52
  const forceLoginDueToStreamError = async (code) => {
50
- await runStreamControlLifecycle(`stream_error_code_${code}`, async () => {
53
+ const reason = constants_1.WA_DISCONNECT_REASONS.STREAM_ERROR_FORCE_LOGIN;
54
+ stopCommsImmediately();
55
+ await runStreamControlLifecycle(reason, async () => {
51
56
  logger.warn('received forced login stream error; starting login lifecycle', {
52
57
  code
53
58
  });
54
- await disconnect();
59
+ await disconnect(reason, true, code);
55
60
  await clearStoredCredentials();
56
- await restartBackendAfterStreamControl(`stream_error_code_${code}`);
61
+ await restartBackendAfterStreamControl(reason);
57
62
  });
58
63
  };
59
- const disconnectDueToStreamError = async (reason) => {
64
+ const disconnectDueToStreamError = async (reason, code) => {
65
+ stopCommsImmediately();
60
66
  await runStreamControlLifecycle(reason, async () => {
61
67
  logger.warn('disconnecting due to stream control node', { reason });
62
- await disconnect();
68
+ await disconnect(reason, false, code);
63
69
  });
64
70
  };
65
- const logoutDueToStreamError = async (reason, shouldRestartBackend) => {
71
+ const logoutDueToStreamError = async (reason, code, shouldRestartBackend) => {
72
+ stopCommsImmediately();
66
73
  await runStreamControlLifecycle(reason, async () => {
67
74
  logger.warn('logging out due to stream control node', {
68
75
  reason,
69
76
  shouldRestartBackend
70
77
  });
71
- await disconnect();
78
+ await disconnect(reason, true, code);
72
79
  await clearStoredCredentials();
73
80
  if (shouldRestartBackend) {
74
81
  await restartBackendAfterStreamControl(reason);
@@ -89,7 +96,7 @@ function createStreamControlHandler(options) {
89
96
  return;
90
97
  }
91
98
  if (result.code === constants_1.WA_STREAM_SIGNALING.FORCE_LOGOUT_CODE) {
92
- await logoutDueToStreamError(`stream_error_code_${constants_1.WA_STREAM_SIGNALING.FORCE_LOGOUT_CODE}`, true);
99
+ await logoutDueToStreamError(constants_1.WA_DISCONNECT_REASONS.STREAM_ERROR_FORCE_LOGOUT, result.code, true);
93
100
  return;
94
101
  }
95
102
  }
@@ -97,11 +104,11 @@ function createStreamControlHandler(options) {
97
104
  return;
98
105
  case 'stream_error_replaced':
99
106
  logger.warn('received stream:error replaced, stopping client');
100
- await disconnectDueToStreamError(constants_1.WA_DISCONNECT_REASONS.STREAM_ERROR_REPLACED);
107
+ await disconnectDueToStreamError(constants_1.WA_DISCONNECT_REASONS.STREAM_ERROR_REPLACED, null);
101
108
  return;
102
109
  case 'stream_error_device_removed':
103
110
  logger.warn('received stream:error device removed, logging out');
104
- await logoutDueToStreamError(constants_1.WA_DISCONNECT_REASONS.STREAM_ERROR_DEVICE_REMOVED, false);
111
+ await logoutDueToStreamError(constants_1.WA_DISCONNECT_REASONS.STREAM_ERROR_DEVICE_REMOVED, null, false);
105
112
  return;
106
113
  case 'stream_error_ack':
107
114
  logger.warn('received stream:error ack', { id: result.id });
@@ -0,0 +1,166 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.WaTrustedContactTokenCoordinator = void 0;
4
+ const cs_token_1 = require("../tokens/cs-token");
5
+ const tc_token_1 = require("../tokens/tc-token");
6
+ const PromiseDedup_1 = require("../../infra/perf/PromiseDedup");
7
+ const privacy_token_1 = require("../../protocol/privacy-token");
8
+ const privacy_token_2 = require("../../transport/node/builders/privacy-token");
9
+ const primitives_1 = require("../../util/primitives");
10
+ const NCT_SALT_SENTINEL_JID = '__nct_salt__';
11
+ class WaTrustedContactTokenCoordinator {
12
+ constructor(options) {
13
+ this.logger = options.logger;
14
+ this.store = options.store;
15
+ this.runtime = options.runtime;
16
+ const maxDurationS = options.maxDurationS ?? privacy_token_1.WA_TC_TOKEN_DEFAULTS.MAX_DURATION_S;
17
+ this.config = {
18
+ durationS: (0, tc_token_1.clampDuration)(options.durationS ?? privacy_token_1.WA_TC_TOKEN_DEFAULTS.DURATION_S, maxDurationS),
19
+ numBuckets: options.numBuckets ?? privacy_token_1.WA_TC_TOKEN_DEFAULTS.NUM_BUCKETS,
20
+ senderDurationS: (0, tc_token_1.clampDuration)(options.senderDurationS ?? privacy_token_1.WA_TC_TOKEN_DEFAULTS.SENDER_DURATION_S, maxDurationS),
21
+ senderNumBuckets: options.senderNumBuckets ?? privacy_token_1.WA_TC_TOKEN_DEFAULTS.SENDER_NUM_BUCKETS,
22
+ maxDurationS
23
+ };
24
+ this.csTokenGenerator = new cs_token_1.CsTokenGenerator();
25
+ this.senderTokenDedup = new PromiseDedup_1.PromiseDedup();
26
+ this.cachedNctSalt = null;
27
+ this.nctSaltHydrated = false;
28
+ }
29
+ async resolveTokenForMessage(recipientJid) {
30
+ const record = await this.store.getByJid(recipientJid);
31
+ const nowS = Math.floor(Date.now() / 1000);
32
+ if (record?.tcToken &&
33
+ record.tcTokenTimestamp !== undefined &&
34
+ !(0, tc_token_1.isTokenExpired)(record.tcTokenTimestamp, nowS, this.config.durationS, this.config.numBuckets)) {
35
+ return (0, privacy_token_2.buildTcTokenMessageNode)(record.tcToken);
36
+ }
37
+ const nctSalt = await this.getNctSalt();
38
+ if (!nctSalt) {
39
+ return null;
40
+ }
41
+ const meLid = this.runtime.getCurrentMeLid();
42
+ if (!meLid) {
43
+ return null;
44
+ }
45
+ const hash = await this.csTokenGenerator.generate(nctSalt, meLid);
46
+ return (0, privacy_token_2.buildCsTokenMessageNode)(hash);
47
+ }
48
+ async handleIncomingToken(fromJid, tokens) {
49
+ const nowMs = Date.now();
50
+ for (let i = 0; i < tokens.length; i += 1) {
51
+ const token = tokens[i];
52
+ if (token.type !== privacy_token_1.WA_PRIVACY_TOKEN_TYPES.TRUSTED_CONTACT) {
53
+ this.logger.warn('ignoring unknown privacy token type', { type: token.type });
54
+ continue;
55
+ }
56
+ await this.store.upsert({
57
+ jid: fromJid,
58
+ tcToken: token.tokenBytes,
59
+ tcTokenTimestamp: token.timestampS,
60
+ updatedAtMs: nowMs
61
+ });
62
+ this.runtime.emitEvent('privacy_token_update', {
63
+ jid: fromJid,
64
+ timestampS: token.timestampS,
65
+ type: token.type,
66
+ source: 'notification'
67
+ });
68
+ }
69
+ }
70
+ async maybeIssueSenderToken(recipientJid) {
71
+ return this.senderTokenDedup.run(recipientJid, async () => {
72
+ const nowS = Math.floor(Date.now() / 1000);
73
+ const record = await this.store.getByJid(recipientJid);
74
+ const senderTimestampS = record?.tcTokenSenderTimestamp;
75
+ if (senderTimestampS !== undefined && senderTimestampS > 0) {
76
+ if (!(0, tc_token_1.shouldSendNewToken)(senderTimestampS, nowS, this.config.senderDurationS)) {
77
+ return;
78
+ }
79
+ }
80
+ await this.issuePrivacyToken(recipientJid, nowS);
81
+ await this.store.upsert({
82
+ jid: recipientJid,
83
+ tcTokenSenderTimestamp: nowS,
84
+ updatedAtMs: Date.now()
85
+ });
86
+ });
87
+ }
88
+ async reissueOnIdentityChange(jid) {
89
+ const record = await this.store.getByJid(jid);
90
+ if (!record?.tcTokenSenderTimestamp) {
91
+ return;
92
+ }
93
+ const nowS = Math.floor(Date.now() / 1000);
94
+ if ((0, tc_token_1.isTokenExpired)(record.tcTokenSenderTimestamp, nowS, this.config.senderDurationS, this.config.senderNumBuckets)) {
95
+ return;
96
+ }
97
+ try {
98
+ await this.issuePrivacyToken(jid, record.tcTokenSenderTimestamp);
99
+ }
100
+ catch (error) {
101
+ this.logger.warn('send-tc-token-device-identity-change-failed', {
102
+ jid,
103
+ message: (0, primitives_1.toError)(error).message
104
+ });
105
+ }
106
+ }
107
+ async hydrateFromHistorySync(conversations) {
108
+ const nowMs = Date.now();
109
+ const records = [];
110
+ for (let i = 0; i < conversations.length; i += 1) {
111
+ const conv = conversations[i];
112
+ if (!conv.tcToken && !conv.tcTokenTimestamp && !conv.tcTokenSenderTimestamp) {
113
+ continue;
114
+ }
115
+ records[records.length] = {
116
+ jid: conv.jid,
117
+ tcToken: conv.tcToken ?? undefined,
118
+ tcTokenTimestamp: conv.tcTokenTimestamp ?? undefined,
119
+ tcTokenSenderTimestamp: conv.tcTokenSenderTimestamp ?? undefined,
120
+ updatedAtMs: nowMs
121
+ };
122
+ }
123
+ if (records.length > 0) {
124
+ await this.store.upsertBatch(records);
125
+ }
126
+ }
127
+ async handleNctSaltSync(salt) {
128
+ if (salt) {
129
+ await this.store.upsert({
130
+ jid: NCT_SALT_SENTINEL_JID,
131
+ nctSalt: salt,
132
+ updatedAtMs: Date.now()
133
+ });
134
+ this.cachedNctSalt = salt;
135
+ }
136
+ else {
137
+ await this.store.deleteByJid(NCT_SALT_SENTINEL_JID);
138
+ this.cachedNctSalt = null;
139
+ }
140
+ this.nctSaltHydrated = true;
141
+ this.csTokenGenerator.invalidate();
142
+ }
143
+ async hydrateNctSaltFromHistorySync(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
+ this.nctSaltHydrated = true;
151
+ }
152
+ async getNctSalt() {
153
+ if (this.nctSaltHydrated) {
154
+ return this.cachedNctSalt;
155
+ }
156
+ const record = await this.store.getByJid(NCT_SALT_SENTINEL_JID);
157
+ this.cachedNctSalt = record?.nctSalt ?? null;
158
+ this.nctSaltHydrated = true;
159
+ return this.cachedNctSalt;
160
+ }
161
+ async issuePrivacyToken(jid, timestampS) {
162
+ const node = (0, privacy_token_2.buildPrivacyTokenIqNode)({ jid, timestampS });
163
+ await this.runtime.queryWithContext('issue-privacy-token', node);
164
+ }
165
+ }
166
+ exports.WaTrustedContactTokenCoordinator = WaTrustedContactTokenCoordinator;
@@ -28,7 +28,13 @@ function parseDirtyBitNode(node, logger) {
28
28
  };
29
29
  }
30
30
  function resolveAccountSyncProtocols(protocols) {
31
- const selected = protocols.filter((protocol) => ACCOUNT_SYNC_PROTOCOL_SET.has(protocol));
31
+ const selected = [];
32
+ for (let index = 0; index < protocols.length; index += 1) {
33
+ const protocol = protocols[index];
34
+ if (ACCOUNT_SYNC_PROTOCOL_SET.has(protocol)) {
35
+ selected.push(protocol);
36
+ }
37
+ }
32
38
  if (selected.length > 0) {
33
39
  return selected;
34
40
  }
@@ -60,12 +66,24 @@ async function handleDirtyBits(runtime, dirtyBits) {
60
66
  }
61
67
  unsupported.push(dirtyBit);
62
68
  }
69
+ const supportedTypes = new Array(supported.length);
70
+ for (let index = 0; index < supported.length; index += 1) {
71
+ supportedTypes[index] = supported[index].type;
72
+ }
73
+ const unsupportedTypes = new Array(unsupported.length);
74
+ for (let index = 0; index < unsupported.length; index += 1) {
75
+ unsupportedTypes[index] = unsupported[index].type;
76
+ }
63
77
  runtime.logger.info('handling dirty bits from info bulletin', {
64
- supported: supported.map((entry) => entry.type).join(','),
65
- unsupported: unsupported.map((entry) => entry.type).join(',')
78
+ supported: supportedTypes.join(','),
79
+ unsupported: unsupportedTypes.join(',')
66
80
  });
67
81
  const clearableDirtyBits = [...unsupported];
68
- const settledSupported = await Promise.allSettled(supported.map(async (dirtyBit) => handleDirtyBit(runtime, dirtyBit)));
82
+ const supportedPromises = new Array(supported.length);
83
+ for (let index = 0; index < supported.length; index += 1) {
84
+ supportedPromises[index] = handleDirtyBit(runtime, supported[index]);
85
+ }
86
+ const settledSupported = await Promise.allSettled(supportedPromises);
69
87
  for (let index = 0; index < settledSupported.length; index += 1) {
70
88
  const result = settledSupported[index];
71
89
  if (result.status === 'fulfilled') {
@@ -105,18 +123,23 @@ async function handleAccountSyncDirtyBit(runtime, protocols) {
105
123
  protocols: selectedProtocols.join(',')
106
124
  });
107
125
  const failures = [];
108
- await Promise.all(selectedProtocols.map(async (protocol) => {
109
- try {
110
- await runAccountSyncProtocol(runtime, protocol);
111
- }
112
- catch (error) {
113
- failures.push(protocol);
114
- runtime.logger.warn('account_sync protocol failed', {
115
- protocol,
116
- message: (0, primitives_1.toError)(error).message
117
- });
118
- }
119
- }));
126
+ const protocolPromises = new Array(selectedProtocols.length);
127
+ for (let index = 0; index < selectedProtocols.length; index += 1) {
128
+ const protocol = selectedProtocols[index];
129
+ protocolPromises[index] = (async () => {
130
+ try {
131
+ await runAccountSyncProtocol(runtime, protocol);
132
+ }
133
+ catch (error) {
134
+ failures.push(protocol);
135
+ runtime.logger.warn('account_sync protocol failed', {
136
+ protocol,
137
+ message: (0, primitives_1.toError)(error).message
138
+ });
139
+ }
140
+ })();
141
+ }
142
+ await Promise.all(protocolPromises);
120
143
  if (failures.length > 0) {
121
144
  throw new Error(`account_sync protocols failed: ${failures.join(',')}`);
122
145
  }
@@ -136,7 +159,7 @@ async function runAccountSyncProtocol(runtime, protocol) {
136
159
  await syncAccountBlocklistDirtyBit(runtime);
137
160
  return;
138
161
  case constants_1.WA_DIRTY_PROTOCOLS.NOTICE:
139
- await syncAccountNoticeDirtyBit(runtime);
162
+ runtime.logger.info('account_sync notice protocol received (no GraphQL/MEX job configured)');
140
163
  return;
141
164
  default:
142
165
  runtime.logger.debug('unsupported account_sync protocol', {
@@ -211,9 +234,6 @@ async function syncAccountBlocklistDirtyBit(runtime) {
211
234
  logMessage: 'account_sync blocklist synchronized'
212
235
  });
213
236
  }
214
- async function syncAccountNoticeDirtyBit(runtime) {
215
- runtime.logger.info('account_sync notice protocol received (no GraphQL/MEX job configured)');
216
- }
217
237
  async function syncGroupsDirtyBit(runtime) {
218
238
  await runSyncQuery(runtime, {
219
239
  queryContext: 'dirty.groups',