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