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
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.SignalProtocol = void 0;
4
4
  const _crypto_1 = require("../../crypto/index.js");
5
5
  const ConsoleLogger_1 = require("../../infra/log/ConsoleLogger");
6
+ const StoreLock_1 = require("../../infra/perf/StoreLock");
6
7
  const constants_1 = require("../constants");
7
8
  const SignalRatchet_1 = require("../session/SignalRatchet");
8
9
  const SignalSerializer_1 = require("../session/SignalSerializer");
@@ -11,26 +12,37 @@ const bytes_1 = require("../../util/bytes");
11
12
  function signalAddressMapKey(address) {
12
13
  return `${address.user}\u0001${address.server ?? ''}\u0001${address.device}`;
13
14
  }
15
+ function signalAddressLockKey(address) {
16
+ return `signal:${signalAddressMapKey(address)}`;
17
+ }
14
18
  class SignalProtocol {
15
19
  constructor(store, logger = new ConsoleLogger_1.ConsoleLogger('info')) {
16
20
  this.store = store;
17
21
  this.logger = logger;
22
+ this.sessionMutationLock = new StoreLock_1.StoreLock();
18
23
  }
19
- async hasSession(address) {
20
- return this.store.hasSession(address);
21
- }
22
- async hasSessions(addresses) {
23
- return this.store.hasSessions(addresses);
24
- }
25
- async establishOutgoingSession(address, remoteBundle) {
26
- const [local, localOneTimeBase] = await Promise.all([
27
- (0, SignalSession_1.requireLocalIdentity)(this.store),
28
- (0, SignalSession_1.generateSerializedKeyPair)()
29
- ]);
30
- const session = await (0, SignalSession_1.initiateSessionOutgoing)(local, remoteBundle, localOneTimeBase);
31
- await this.store.setRemoteIdentity(address, session.remote.pubKey);
32
- await this.store.setSession(address, session);
33
- return session;
24
+ async establishOutgoingSession(address, remoteBundle, options = {}) {
25
+ return this.runWithAddressLock(address, async () => {
26
+ if (options.reuseExisting) {
27
+ const existing = await this.store.getSession(address);
28
+ if (existing) {
29
+ const remoteIdentity = (0, _crypto_1.toSerializedPubKey)(remoteBundle.identity);
30
+ if (!(0, bytes_1.uint8Equal)(existing.remote.pubKey, remoteIdentity)) {
31
+ throw new Error('identity mismatch');
32
+ }
33
+ return existing;
34
+ }
35
+ }
36
+ const [local, localOneTimeBase] = await Promise.all([
37
+ (0, SignalSession_1.requireLocalIdentity)(this.store),
38
+ (0, SignalSession_1.generateSerializedKeyPair)()
39
+ ]);
40
+ const session = await (0, SignalSession_1.initiateSessionOutgoing)(local, remoteBundle, localOneTimeBase);
41
+ // Keep writes ordered: a stored session without matching remote identity causes false mismatch checks.
42
+ await this.store.setRemoteIdentity(address, session.remote.pubKey);
43
+ await this.store.setSession(address, session);
44
+ return session;
45
+ });
34
46
  }
35
47
  async encryptMessage(address, plaintext, expectedIdentity) {
36
48
  const [encrypted] = await this.encryptMessagesBatch([
@@ -38,77 +50,140 @@ class SignalProtocol {
38
50
  ]);
39
51
  return encrypted;
40
52
  }
41
- async encryptMessagesBatch(requests) {
53
+ async encryptMessagesBatch(requests, prefetchedSessions) {
42
54
  if (requests.length === 0) {
43
55
  return [];
44
56
  }
45
- const addresses = requests.map((request) => request.address);
46
- const storedSessions = await this.store.getSessionsBatch(addresses);
47
- const latestSessionByAddress = new Map();
48
- const sessionUpdatesByAddress = new Map();
49
- const identityUpdatesByAddress = new Map();
50
- const results = new Array(requests.length);
51
- for (let index = 0; index < requests.length; index += 1) {
52
- const request = requests[index];
53
- const address = request.address;
54
- const addressKey = signalAddressMapKey(address);
55
- const session = latestSessionByAddress.get(addressKey) ?? storedSessions[index];
56
- if (!session) {
57
- throw new Error('signal session not found');
57
+ const lockKeySet = new Set();
58
+ for (let i = 0; i < requests.length; i += 1)
59
+ lockKeySet.add(signalAddressLockKey(requests[i].address));
60
+ const lockKeys = [...lockKeySet];
61
+ return this.sessionMutationLock.runMany(lockKeys, async () => {
62
+ const prefetchedByAddress = new Map();
63
+ if (prefetchedSessions && prefetchedSessions.length > 0) {
64
+ for (let index = 0; index < prefetchedSessions.length; index += 1) {
65
+ const entry = prefetchedSessions[index];
66
+ prefetchedByAddress.set(signalAddressMapKey(entry.address), entry.session);
67
+ }
68
+ }
69
+ const uniqueAddressKeys = new Array(requests.length);
70
+ const uniqueAddresses = new Array(requests.length);
71
+ let uniqueAddressCount = 0;
72
+ for (let index = 0; index < requests.length; index += 1) {
73
+ const address = requests[index].address;
74
+ const addressKey = signalAddressMapKey(address);
75
+ let isDuplicate = false;
76
+ for (let dedupIndex = 0; dedupIndex < uniqueAddressCount; dedupIndex += 1) {
77
+ if (uniqueAddressKeys[dedupIndex] === addressKey) {
78
+ isDuplicate = true;
79
+ break;
80
+ }
81
+ }
82
+ if (isDuplicate) {
83
+ continue;
84
+ }
85
+ uniqueAddressKeys[uniqueAddressCount] = addressKey;
86
+ uniqueAddresses[uniqueAddressCount] = address;
87
+ uniqueAddressCount += 1;
58
88
  }
59
- if (request.expectedIdentity &&
60
- !(0, bytes_1.uint8Equal)((0, _crypto_1.toSerializedPubKey)(request.expectedIdentity), session.remote.pubKey)) {
61
- throw new Error('identity mismatch');
89
+ uniqueAddressKeys.length = uniqueAddressCount;
90
+ uniqueAddresses.length = uniqueAddressCount;
91
+ const currentSessions = await this.store.getSessionsBatch(uniqueAddresses);
92
+ const latestSessionByAddress = new Map();
93
+ for (let index = 0; index < uniqueAddressCount; index += 1) {
94
+ const addressKey = uniqueAddressKeys[index];
95
+ const current = currentSessions[index];
96
+ if (current) {
97
+ latestSessionByAddress.set(addressKey, current);
98
+ continue;
99
+ }
100
+ const prefetched = prefetchedByAddress.get(addressKey);
101
+ if (prefetched) {
102
+ latestSessionByAddress.set(addressKey, prefetched);
103
+ }
62
104
  }
63
- const [updatedSession, encrypted] = await (0, SignalRatchet_1.encryptMsg)(session, request.plaintext);
64
- latestSessionByAddress.set(addressKey, updatedSession);
65
- sessionUpdatesByAddress.set(addressKey, {
66
- address,
67
- session: updatedSession
68
- });
69
- if (!(0, bytes_1.uint8Equal)(updatedSession.remote.pubKey, session.remote.pubKey)) {
70
- identityUpdatesByAddress.set(addressKey, {
105
+ const sessionUpdatesByAddress = new Map();
106
+ const identityUpdatesByAddress = new Map();
107
+ const results = new Array(requests.length);
108
+ for (let index = 0; index < requests.length; index += 1) {
109
+ const request = requests[index];
110
+ const address = request.address;
111
+ const addressKey = signalAddressMapKey(address);
112
+ const session = latestSessionByAddress.get(addressKey);
113
+ if (!session) {
114
+ throw new Error('signal session not found');
115
+ }
116
+ if (request.expectedIdentity &&
117
+ !(0, bytes_1.uint8Equal)((0, _crypto_1.toSerializedPubKey)(request.expectedIdentity), session.remote.pubKey)) {
118
+ throw new Error('identity mismatch');
119
+ }
120
+ const [updatedSession, encrypted] = await (0, SignalRatchet_1.encryptMsg)(session, request.plaintext);
121
+ latestSessionByAddress.set(addressKey, updatedSession);
122
+ sessionUpdatesByAddress.set(addressKey, {
71
123
  address,
72
- identityKey: updatedSession.remote.pubKey
124
+ session: updatedSession
73
125
  });
126
+ if (!(0, bytes_1.uint8Equal)(updatedSession.remote.pubKey, session.remote.pubKey)) {
127
+ identityUpdatesByAddress.set(addressKey, {
128
+ address,
129
+ identityKey: updatedSession.remote.pubKey
130
+ });
131
+ }
132
+ results[index] = {
133
+ ...encrypted,
134
+ baseKey: updatedSession.aliceBaseKey
135
+ };
74
136
  }
75
- results[index] = {
76
- ...encrypted,
77
- baseKey: updatedSession.aliceBaseKey
78
- };
79
- }
80
- await this.store.setSessionsBatch([...sessionUpdatesByAddress.values()]);
81
- if (identityUpdatesByAddress.size > 0) {
82
- await this.store.setRemoteIdentities([...identityUpdatesByAddress.values()]);
83
- }
84
- return results;
137
+ // Persist remote identities first when needed so session writes never commit ahead of identity data.
138
+ if (identityUpdatesByAddress.size > 0) {
139
+ const identityUpdates = new Array(identityUpdatesByAddress.size);
140
+ let identityIndex = 0;
141
+ for (const update of identityUpdatesByAddress.values()) {
142
+ identityUpdates[identityIndex] = update;
143
+ identityIndex += 1;
144
+ }
145
+ await this.store.setRemoteIdentities(identityUpdates);
146
+ }
147
+ const sessionUpdates = new Array(sessionUpdatesByAddress.size);
148
+ let sessionIndex = 0;
149
+ for (const update of sessionUpdatesByAddress.values()) {
150
+ sessionUpdates[sessionIndex] = update;
151
+ sessionIndex += 1;
152
+ }
153
+ await this.store.setSessionsBatch(sessionUpdates);
154
+ return results;
155
+ });
85
156
  }
86
157
  async decryptMessage(address, envelope) {
87
- const currentSession = await this.store.getSession(address);
88
- let outcome;
89
- if (envelope.type === 'pkmsg') {
90
- const parsedPk = (0, SignalSerializer_1.deserializePkMsg)(envelope.ciphertext);
91
- outcome = await this.decryptPkMsg(currentSession, parsedPk);
92
- }
93
- else {
94
- const parsed = (0, SignalSerializer_1.deserializeMsg)(envelope.ciphertext);
95
- outcome = await this.decryptMsgInternal(currentSession, parsed);
96
- }
97
- const nextRemoteIdentity = outcome.newSessionInfo?.newIdentity ?? outcome.updatedSession.remote.pubKey;
98
- if (!currentSession || !(0, bytes_1.uint8Equal)(currentSession.remote.pubKey, nextRemoteIdentity)) {
99
- await this.store.setRemoteIdentity(address, nextRemoteIdentity);
100
- }
101
- await this.store.setSession(address, outcome.updatedSession);
102
- return outcome.plaintext;
103
- }
104
- async decryptMsgInternal(session, parsed) {
105
- return (0, SignalRatchet_1.decryptMsg)(session, parsed, (error, previousSessionIndex) => {
106
- this.logger.debug('signal decrypt fallback session failed', {
107
- previousSessionIndex,
108
- message: error.message
109
- });
158
+ return this.runWithAddressLock(address, async () => {
159
+ const currentSession = await this.store.getSession(address);
160
+ let outcome;
161
+ if (envelope.type === 'pkmsg') {
162
+ const parsedPk = (0, SignalSerializer_1.deserializePkMsg)(envelope.ciphertext);
163
+ outcome = await this.decryptPkMsg(currentSession, parsedPk);
164
+ }
165
+ else {
166
+ const parsed = (0, SignalSerializer_1.deserializeMsg)(envelope.ciphertext);
167
+ outcome = await (0, SignalRatchet_1.decryptMsg)(currentSession, parsed, (error, previousSessionIndex) => {
168
+ this.logger.debug('signal decrypt fallback session failed', {
169
+ previousSessionIndex,
170
+ message: error.message
171
+ });
172
+ });
173
+ }
174
+ const nextRemoteIdentity = outcome.newSessionInfo?.newIdentity ?? outcome.updatedSession.remote.pubKey;
175
+ const identityChanged = !currentSession || !(0, bytes_1.uint8Equal)(currentSession.remote.pubKey, nextRemoteIdentity);
176
+ // Keep writes ordered for consistency with resolver identity checks.
177
+ if (identityChanged) {
178
+ await this.store.setRemoteIdentity(address, nextRemoteIdentity);
179
+ }
180
+ await this.store.setSession(address, outcome.updatedSession);
181
+ return outcome.plaintext;
110
182
  });
111
183
  }
184
+ runWithAddressLock(address, task) {
185
+ return this.sessionMutationLock.run(signalAddressLockKey(address), task);
186
+ }
112
187
  async decryptPkMsg(currentSession, parsed) {
113
188
  const matchingSession = (0, SignalSession_1.findMatchingSession)(currentSession, parsed.sessionBaseKey);
114
189
  if (matchingSession) {
@@ -144,6 +219,7 @@ class SignalProtocol {
144
219
  }
145
220
  : incoming;
146
221
  const [updatedSession, plaintext] = await (0, SignalRatchet_1.decryptMsgFromSession)(baseSession, parsed);
222
+ // Only consume one-time prekeys after successful decrypt/session materialization.
147
223
  if (parsed.localOneTimeKeyId !== null && parsed.localOneTimeKeyId !== undefined) {
148
224
  await this.store.consumePreKeyById(parsed.localOneTimeKeyId);
149
225
  }
@@ -2,32 +2,43 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createSignalSessionResolver = createSignalSessionResolver;
4
4
  const keys_1 = require("../../crypto/core/keys");
5
+ const PromiseDedup_1 = require("../../infra/perf/PromiseDedup");
5
6
  const jid_1 = require("../../protocol/jid");
6
7
  const bytes_1 = require("../../util/bytes");
7
8
  const primitives_1 = require("../../util/primitives");
8
9
  function createSignalSessionResolver(options) {
9
10
  const { signalProtocol, signalStore, signalIdentitySync, signalSessionSync, logger } = options;
10
- const ensureSession = async (address, jid, expectedIdentity, reasonIdentity = false) => {
11
+ const dedup = new PromiseDedup_1.PromiseDedup();
12
+ const ensureSessionInternal = async (address, jid, expectedIdentity, reasonIdentity = false, prefetchedBundle) => {
11
13
  const expectedSerializedIdentity = expectedIdentity
12
14
  ? (0, keys_1.toSerializedPubKey)(expectedIdentity)
13
15
  : null;
14
16
  if (reasonIdentity) {
15
17
  await signalIdentitySync.syncIdentityKeys([jid]);
16
18
  }
17
- if (await signalProtocol.hasSession(address)) {
19
+ if (await signalStore.hasSession(address)) {
18
20
  if (expectedSerializedIdentity) {
19
21
  const storedIdentity = await signalStore.getRemoteIdentity(address);
20
22
  if (!storedIdentity || !(0, bytes_1.uint8Equal)(storedIdentity, expectedSerializedIdentity)) {
21
23
  throw new Error('identity mismatch');
22
24
  }
23
25
  }
24
- return;
26
+ return null;
27
+ }
28
+ let fetched;
29
+ if (prefetchedBundle) {
30
+ fetched = {
31
+ jid,
32
+ bundle: prefetchedBundle
33
+ };
34
+ }
35
+ else {
36
+ logger.info('signal session missing, fetching remote key bundle', { jid });
37
+ fetched = await signalSessionSync.fetchKeyBundle({
38
+ jid,
39
+ reasonIdentity
40
+ });
25
41
  }
26
- logger.info('signal session missing, fetching remote key bundle', { jid });
27
- const fetched = await signalSessionSync.fetchKeyBundle({
28
- jid,
29
- reasonIdentity
30
- });
31
42
  const remoteIdentity = (0, keys_1.toSerializedPubKey)(fetched.bundle.identity);
32
43
  if (reasonIdentity) {
33
44
  const storedIdentity = await signalStore.getRemoteIdentity(address);
@@ -38,35 +49,49 @@ function createSignalSessionResolver(options) {
38
49
  if (expectedSerializedIdentity && !(0, bytes_1.uint8Equal)(remoteIdentity, expectedSerializedIdentity)) {
39
50
  throw new Error('identity mismatch');
40
51
  }
41
- await signalProtocol.establishOutgoingSession(address, fetched.bundle);
52
+ const session = await signalProtocol.establishOutgoingSession(address, fetched.bundle, {
53
+ reuseExisting: true
54
+ });
42
55
  logger.info('signal session synchronized', {
43
56
  jid,
44
57
  regId: fetched.bundle.regId,
45
58
  hasOneTimeKey: fetched.bundle.oneTimeKey !== undefined
46
59
  });
60
+ return session;
61
+ };
62
+ const ensureSessionWithDedup = (address, jid, expectedIdentity, reasonIdentity = false, prefetchedBundle) => {
63
+ const expectedIdentityKey = expectedIdentity ? (0, bytes_1.bytesToHex)(expectedIdentity) : 'none';
64
+ const dedupKey = `signalSession:${(0, jid_1.signalAddressKey)(address)}:${reasonIdentity ? '1' : '0'}:${expectedIdentityKey}`;
65
+ return dedup.run(dedupKey, () => ensureSessionInternal(address, jid, expectedIdentity, reasonIdentity, prefetchedBundle));
47
66
  };
67
+ const ensureSession = (address, jid, expectedIdentity, reasonIdentity = false) => ensureSessionWithDedup(address, jid, expectedIdentity, reasonIdentity).then(() => { });
48
68
  const ensureSessionsBatch = async (targetJids, expectedIdentityByJid) => {
49
69
  const seenTargetJids = new Set();
50
- const normalizedTargetJids = [];
51
- const normalizedTargetAddresses = [];
70
+ const normalizedTargetJids = new Array(targetJids.length);
71
+ const normalizedTargetAddresses = new Array(targetJids.length);
72
+ let normalizedTargetCount = 0;
52
73
  for (let index = 0; index < targetJids.length; index += 1) {
53
74
  const jid = (0, jid_1.normalizeDeviceJid)(targetJids[index]);
54
75
  if (seenTargetJids.has(jid)) {
55
76
  continue;
56
77
  }
57
78
  seenTargetJids.add(jid);
58
- normalizedTargetJids.push(jid);
59
- normalizedTargetAddresses.push((0, jid_1.parseSignalAddressFromJid)(jid));
79
+ normalizedTargetJids[normalizedTargetCount] = jid;
80
+ normalizedTargetAddresses[normalizedTargetCount] = (0, jid_1.parseSignalAddressFromJid)(jid);
81
+ normalizedTargetCount += 1;
60
82
  }
61
- if (normalizedTargetJids.length === 0) {
62
- return;
83
+ if (normalizedTargetCount === 0) {
84
+ return [];
63
85
  }
86
+ normalizedTargetJids.length = normalizedTargetCount;
87
+ normalizedTargetAddresses.length = normalizedTargetCount;
64
88
  const normalizedExpectedIdentityByJid = expectedIdentityByJid && expectedIdentityByJid.size > 0
65
89
  ? new Map()
66
90
  : undefined;
67
91
  if (normalizedExpectedIdentityByJid && expectedIdentityByJid) {
68
92
  for (const [jid, identity] of expectedIdentityByJid.entries()) {
69
93
  try {
94
+ (0, keys_1.toSerializedPubKey)(identity);
70
95
  normalizedExpectedIdentityByJid.set((0, jid_1.normalizeDeviceJid)(jid), identity);
71
96
  }
72
97
  catch (error) {
@@ -74,113 +99,123 @@ function createSignalSessionResolver(options) {
74
99
  }
75
100
  }
76
101
  }
77
- const hasSessions = await signalProtocol.hasSessions(normalizedTargetAddresses);
78
- if (normalizedExpectedIdentityByJid) {
79
- const identityAddresses = [];
80
- const expectedSerializedIdentities = [];
102
+ const resolvedByIndex = (await signalStore.getSessionsBatch(normalizedTargetAddresses));
103
+ const collectResolvedTargets = () => {
104
+ const resolvedTargets = new Array(normalizedTargetJids.length);
105
+ let resolvedTargetCount = 0;
81
106
  for (let index = 0; index < normalizedTargetJids.length; index += 1) {
82
- if (!hasSessions[index]) {
107
+ const session = resolvedByIndex[index];
108
+ if (!session) {
83
109
  continue;
84
110
  }
85
- const expectedIdentity = normalizedExpectedIdentityByJid.get(normalizedTargetJids[index]);
86
- if (!expectedIdentity) {
87
- continue;
88
- }
89
- identityAddresses.push(normalizedTargetAddresses[index]);
90
- expectedSerializedIdentities.push((0, keys_1.toSerializedPubKey)(expectedIdentity));
111
+ resolvedTargets[resolvedTargetCount] = {
112
+ jid: normalizedTargetJids[index],
113
+ address: normalizedTargetAddresses[index],
114
+ session
115
+ };
116
+ resolvedTargetCount += 1;
91
117
  }
92
- const storedIdentities = await signalStore.getRemoteIdentities(identityAddresses);
93
- for (let index = 0; index < storedIdentities.length; index += 1) {
94
- const storedIdentity = storedIdentities[index];
95
- if (!storedIdentity ||
96
- !(0, bytes_1.uint8Equal)(storedIdentity, expectedSerializedIdentities[index])) {
118
+ resolvedTargets.length = resolvedTargetCount;
119
+ return resolvedTargets;
120
+ };
121
+ const missingIndices = [];
122
+ for (let index = 0; index < normalizedTargetJids.length; index += 1) {
123
+ const session = resolvedByIndex[index];
124
+ const expectedIdentity = normalizedExpectedIdentityByJid?.get(normalizedTargetJids[index]);
125
+ if (session && expectedIdentity) {
126
+ if (!(0, bytes_1.uint8Equal)(session.remote.pubKey, (0, keys_1.toSerializedPubKey)(expectedIdentity))) {
97
127
  throw new Error('identity mismatch');
98
128
  }
99
129
  }
100
- }
101
- const missingIndices = [];
102
- for (let index = 0; index < normalizedTargetJids.length; index += 1) {
103
- if (!hasSessions[index]) {
130
+ if (!session) {
104
131
  missingIndices.push(index);
105
132
  }
106
133
  }
107
134
  if (missingIndices.length === 0) {
108
- return;
135
+ return collectResolvedTargets();
136
+ }
137
+ const batchRequest = new Array(missingIndices.length);
138
+ for (let index = 0; index < missingIndices.length; index += 1) {
139
+ batchRequest[index] = { jid: normalizedTargetJids[missingIndices[index]] };
109
140
  }
141
+ let batchResults;
110
142
  try {
111
- const batchRequest = [];
112
- for (let index = 0; index < missingIndices.length; index += 1) {
113
- batchRequest.push({ jid: normalizedTargetJids[missingIndices[index]] });
114
- }
115
- const batchResults = await signalSessionSync.fetchKeyBundles(batchRequest);
116
- const fallbackIndices = [];
117
- const establishedIndices = [];
118
- const establishPromises = [];
119
- for (let index = 0; index < missingIndices.length; index += 1) {
120
- const targetIndex = missingIndices[index];
121
- const result = batchResults[index];
122
- if (!result || !('bundle' in result)) {
123
- fallbackIndices.push(targetIndex);
124
- continue;
125
- }
126
- const targetJid = normalizedTargetJids[targetIndex];
127
- const expectedIdentity = normalizedExpectedIdentityByJid?.get(targetJid);
128
- const remoteIdentity = (0, keys_1.toSerializedPubKey)(result.bundle.identity);
129
- if (expectedIdentity &&
130
- !(0, bytes_1.uint8Equal)(remoteIdentity, (0, keys_1.toSerializedPubKey)(expectedIdentity))) {
131
- throw new Error('identity mismatch');
132
- }
133
- establishedIndices.push(targetIndex);
134
- establishPromises.push(signalProtocol
135
- .establishOutgoingSession(normalizedTargetAddresses[targetIndex], result.bundle)
136
- .then(() => {
137
- logger.debug('signal session synchronized from batch key fetch', {
138
- jid: targetJid,
139
- regId: result.bundle.regId,
140
- hasOneTimeKey: result.bundle.oneTimeKey !== undefined
141
- });
142
- }));
143
+ batchResults = await signalSessionSync.fetchKeyBundles(batchRequest);
144
+ }
145
+ catch (error) {
146
+ logger.warn('signal batch key fetch failed', {
147
+ requested: missingIndices.length,
148
+ message: (0, primitives_1.toError)(error).message
149
+ });
150
+ return collectResolvedTargets();
151
+ }
152
+ const ensuredTargetIndices = new Array(missingIndices.length);
153
+ const ensurePromises = new Array(missingIndices.length);
154
+ let ensureCount = 0;
155
+ for (let index = 0; index < missingIndices.length; index += 1) {
156
+ const targetIndex = missingIndices[index];
157
+ const targetJid = normalizedTargetJids[targetIndex];
158
+ const batchResult = batchResults[index];
159
+ if (!batchResult?.bundle) {
160
+ logger.warn('signal batch key fetch returned target without bundle', {
161
+ jid: targetJid,
162
+ message: batchResult?.errorText ?? 'missing key bundle user in response'
163
+ });
164
+ continue;
143
165
  }
144
- const establishmentResults = await Promise.allSettled(establishPromises);
145
- for (let index = 0; index < establishmentResults.length; index += 1) {
146
- const result = establishmentResults[index];
147
- if (result.status === 'fulfilled') {
148
- continue;
149
- }
150
- const error = (0, primitives_1.toError)(result.reason);
151
- if (error.message === 'identity mismatch') {
152
- throw error;
166
+ const expectedIdentity = normalizedExpectedIdentityByJid?.get(targetJid);
167
+ ensuredTargetIndices[ensureCount] = targetIndex;
168
+ ensurePromises[ensureCount] = ensureSessionWithDedup(normalizedTargetAddresses[targetIndex], targetJid, expectedIdentity, false, batchResult.bundle);
169
+ ensureCount += 1;
170
+ }
171
+ if (ensureCount === 0) {
172
+ return collectResolvedTargets();
173
+ }
174
+ ensuredTargetIndices.length = ensureCount;
175
+ ensurePromises.length = ensureCount;
176
+ const ensureResults = await Promise.allSettled(ensurePromises);
177
+ const fallbackIndices = [];
178
+ for (let index = 0; index < ensuredTargetIndices.length; index += 1) {
179
+ const targetIndex = ensuredTargetIndices[index];
180
+ const ensureResult = ensureResults[index];
181
+ if (ensureResult.status === 'rejected') {
182
+ const normalized = (0, primitives_1.toError)(ensureResult.reason);
183
+ if (normalized.message === 'identity mismatch') {
184
+ throw normalized;
153
185
  }
154
- fallbackIndices.push(establishedIndices[index]);
186
+ logger.warn('signal session ensure failed during batch resolution', {
187
+ jid: normalizedTargetJids[targetIndex],
188
+ message: normalized.message
189
+ });
190
+ continue;
155
191
  }
156
- if (fallbackIndices.length === 0) {
157
- return;
192
+ const session = ensureResult.value;
193
+ if (session) {
194
+ resolvedByIndex[targetIndex] = session;
158
195
  }
159
- logger.warn('signal batch key fetch returned partial errors, falling back to single requests', {
160
- requested: missingIndices.length,
161
- fallbackTargets: fallbackIndices.length
162
- });
163
- for (let index = 0; index < fallbackIndices.length; index += 1) {
164
- const targetIndex = fallbackIndices[index];
165
- const jid = normalizedTargetJids[targetIndex];
166
- await ensureSession(normalizedTargetAddresses[targetIndex], jid, normalizedExpectedIdentityByJid?.get(jid));
196
+ else {
197
+ fallbackIndices.push(targetIndex);
167
198
  }
168
199
  }
169
- catch (error) {
170
- const normalized = (0, primitives_1.toError)(error);
171
- if (normalized.message === 'identity mismatch') {
172
- throw normalized;
200
+ if (fallbackIndices.length > 0) {
201
+ const fallbackAddresses = new Array(fallbackIndices.length);
202
+ for (let i = 0; i < fallbackIndices.length; i++) {
203
+ fallbackAddresses[i] = normalizedTargetAddresses[fallbackIndices[i]];
173
204
  }
174
- logger.warn('signal batch key fetch failed, falling back to single requests', {
175
- requested: missingIndices.length,
176
- message: normalized.message
177
- });
178
- for (let index = 0; index < missingIndices.length; index += 1) {
179
- const targetIndex = missingIndices[index];
180
- const jid = normalizedTargetJids[targetIndex];
181
- await ensureSession(normalizedTargetAddresses[targetIndex], jid, normalizedExpectedIdentityByJid?.get(jid));
205
+ const fallbackSessions = await signalStore.getSessionsBatch(fallbackAddresses);
206
+ for (let i = 0; i < fallbackIndices.length; i++) {
207
+ const session = fallbackSessions[i];
208
+ if (session) {
209
+ resolvedByIndex[fallbackIndices[i]] = session;
210
+ }
211
+ else {
212
+ logger.warn('signal session ensure completed without persisted session', {
213
+ jid: normalizedTargetJids[fallbackIndices[i]]
214
+ });
215
+ }
182
216
  }
183
217
  }
218
+ return collectResolvedTargets();
184
219
  };
185
220
  return {
186
221
  ensureSession,
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });