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,9 +1,33 @@
1
+ import { isGroupOrBroadcastJid, normalizeDeviceJid } from '../protocol/jid.js';
2
+ import { encodeRetryReplayPayload } from './codec.js';
1
3
  import { RETRY_OUTBOUND_TTL_MS } from './constants.js';
2
- import { encodeRetryReplayPayload } from './outbound.js';
3
4
  import { toError } from '../util/primitives.js';
4
5
  export function createOutboundRetryTracker(options) {
5
6
  const { retryStore, logger } = options;
6
7
  const retryTtlMs = retryStore.getTtlMs?.() ?? RETRY_OUTBOUND_TTL_MS;
8
+ const supportsRawReplayPayload = retryStore.supportsRawReplayPayload?.() ?? false;
9
+ const normalizeEligibleRequesterDeviceJids = (values) => {
10
+ if (!values || values.length === 0) {
11
+ return undefined;
12
+ }
13
+ const deduped = new Set();
14
+ for (let index = 0; index < values.length; index += 1) {
15
+ const raw = values[index]?.trim();
16
+ if (!raw) {
17
+ continue;
18
+ }
19
+ try {
20
+ deduped.add(normalizeDeviceJid(raw));
21
+ }
22
+ catch {
23
+ continue;
24
+ }
25
+ }
26
+ if (deduped.size === 0) {
27
+ return undefined;
28
+ }
29
+ return Array.from(deduped);
30
+ };
7
31
  const safeUpsertRetryOutboundRecord = async (record) => {
8
32
  try {
9
33
  await retryStore.upsertOutboundMessage(record);
@@ -22,34 +46,48 @@ export function createOutboundRetryTracker(options) {
22
46
  return {
23
47
  track: async (hint, publish) => {
24
48
  const nowMs = Date.now();
25
- const expiresAtMs = nowMs + retryTtlMs;
26
- const hintedMessageId = hint.messageIdHint?.trim();
27
49
  const replayMode = hint.replayPayload.mode;
28
50
  const resolvedToJid = hint.toJid ?? (replayMode === 'opaque_node' ? '' : hint.replayPayload.to);
29
- const replayPayload = encodeRetryReplayPayload(hint.replayPayload);
30
- let hintedPersisted = false;
31
- const createRetryOutboundRecord = (messageId, createdAtMs, updatedAtMs, expiresAtMs) => ({
51
+ const replayPayload = supportsRawReplayPayload
52
+ ? hint.replayPayload
53
+ : encodeRetryReplayPayload(hint.replayPayload);
54
+ let eligibleRequesterDeviceJids = normalizeEligibleRequesterDeviceJids(hint.eligibleRequesterDeviceJids);
55
+ if (!eligibleRequesterDeviceJids &&
56
+ resolvedToJid &&
57
+ !isGroupOrBroadcastJid(resolvedToJid)) {
58
+ try {
59
+ eligibleRequesterDeviceJids = [normalizeDeviceJid(resolvedToJid)];
60
+ }
61
+ catch {
62
+ eligibleRequesterDeviceJids = undefined;
63
+ }
64
+ }
65
+ const createRetryOutboundRecord = (messageId, updatedAtMs, expiresAtMs) => ({
32
66
  messageId,
33
67
  toJid: resolvedToJid,
34
68
  participantJid: hint.participantJid,
35
69
  recipientJid: hint.recipientJid,
70
+ eligibleRequesterDeviceJids,
71
+ deliveredRequesterDeviceJids: [],
36
72
  messageType: hint.type,
37
73
  replayMode,
38
74
  replayPayload,
39
75
  state: 'pending',
40
- createdAtMs,
76
+ createdAtMs: nowMs,
41
77
  updatedAtMs,
42
78
  expiresAtMs
43
79
  });
44
- if (hintedMessageId) {
45
- hintedPersisted = await safeUpsertRetryOutboundRecord(createRetryOutboundRecord(hintedMessageId, nowMs, nowMs, expiresAtMs));
46
- }
47
80
  const result = await publish();
48
- if (hintedPersisted && hintedMessageId && result.id === hintedMessageId) {
81
+ const persistedMessageId = result.id.trim();
82
+ if (!persistedMessageId) {
83
+ logger.warn('retry outbound record skipped: publish returned empty message id', {
84
+ to: resolvedToJid,
85
+ mode: replayMode
86
+ });
49
87
  return result;
50
88
  }
51
89
  const persistedNowMs = Date.now();
52
- await safeUpsertRetryOutboundRecord(createRetryOutboundRecord(result.id, hintedMessageId ? nowMs : persistedNowMs, persistedNowMs, persistedNowMs + retryTtlMs));
90
+ await safeUpsertRetryOutboundRecord(createRetryOutboundRecord(persistedMessageId, persistedNowMs, persistedNowMs + retryTtlMs));
53
91
  return result;
54
92
  }
55
93
  };
@@ -1,11 +1,13 @@
1
+ import { PromiseDedup } from '../../infra/perf/PromiseDedup.js';
1
2
  import { WA_DEFAULTS, WA_NODE_TAGS, WA_USYNC_CONTEXTS } from '../../protocol/constants.js';
2
- import { parseSignalAddressFromJid, splitJid } from '../../protocol/jid.js';
3
+ import { buildDeviceJid, isHostedDeviceId, splitJid, toUserJid } from '../../protocol/jid.js';
3
4
  import { buildUsyncIq } from '../../transport/node/builders/usync.js';
4
5
  import { findNodeChild, getNodeChildrenByTag } from '../../transport/node/helpers.js';
5
6
  import { assertIqResult } from '../../transport/node/query.js';
6
7
  import { createUsyncSidGenerator } from '../../transport/node/usync.js';
7
8
  export class SignalDeviceSyncApi {
8
9
  constructor(options) {
10
+ this.syncDedup = new PromiseDedup();
9
11
  this.logger = options.logger;
10
12
  this.query = options.query;
11
13
  this.deviceListStore = options.deviceListStore;
@@ -14,11 +16,15 @@ export class SignalDeviceSyncApi {
14
16
  this.hostDomain = options.hostDomain ?? WA_DEFAULTS.HOST_DOMAIN;
15
17
  this.generateSid = options.generateSid ?? createUsyncSidGenerator();
16
18
  }
17
- async syncDeviceList(userJids, timeoutMs = this.defaultTimeoutMs) {
19
+ syncDeviceList(userJids, timeoutMs = this.defaultTimeoutMs) {
18
20
  const normalizedUsers = this.normalizeUsers(userJids);
19
21
  if (normalizedUsers.length === 0) {
20
- return [];
22
+ return Promise.resolve([]);
21
23
  }
24
+ const dedupKey = normalizedUsers.join(',');
25
+ return this.syncDedup.run(dedupKey, () => this.syncDeviceListInternal(normalizedUsers, timeoutMs));
26
+ }
27
+ async syncDeviceListInternal(normalizedUsers, timeoutMs) {
22
28
  const nowMs = Date.now();
23
29
  const cachedByUser = new Map();
24
30
  const usersToQuery = this.deviceListStore
@@ -123,16 +129,19 @@ export class SignalDeviceSyncApi {
123
129
  }
124
130
  async collectUsersToQuery(normalizedUsers, nowMs, cachedByUser, store) {
125
131
  const records = await store.getUserDevicesBatch(normalizedUsers, nowMs);
126
- const usersToQuery = [];
132
+ const usersToQuery = new Array(normalizedUsers.length);
133
+ let usersToQueryCount = 0;
127
134
  for (let index = 0; index < normalizedUsers.length; index += 1) {
128
135
  const userJid = normalizedUsers[index];
129
136
  const record = records[index];
130
137
  if (!record) {
131
- usersToQuery.push(userJid);
138
+ usersToQuery[usersToQueryCount] = userJid;
139
+ usersToQueryCount += 1;
132
140
  continue;
133
141
  }
134
142
  cachedByUser.set(userJid, record.deviceJids);
135
143
  }
144
+ usersToQuery.length = usersToQueryCount;
136
145
  return usersToQuery;
137
146
  }
138
147
  makeDeviceSyncRequest(userJids, sid) {
@@ -201,7 +210,8 @@ export class SignalDeviceSyncApi {
201
210
  }
202
211
  const requestedSet = new Set(requestedUsers);
203
212
  const userNodes = getNodeChildrenByTag(listNode, WA_NODE_TAGS.USER);
204
- const parsed = [];
213
+ const parsed = new Array(userNodes.length);
214
+ let parsedCount = 0;
205
215
  for (let index = 0; index < userNodes.length; index += 1) {
206
216
  const userNode = userNodes[index];
207
217
  const userJid = userNode.attrs.jid;
@@ -212,11 +222,13 @@ export class SignalDeviceSyncApi {
212
222
  if (!requestedSet.has(normalizedUserJid)) {
213
223
  continue;
214
224
  }
215
- parsed.push({
225
+ parsed[parsedCount] = {
216
226
  jid: normalizedUserJid,
217
- deviceJids: this.parseUserDeviceJids(userNode, normalizedUserJid)
218
- });
227
+ deviceJids: this.parseUserDeviceJids(userNode, userJid, normalizedUserJid)
228
+ };
229
+ parsedCount += 1;
219
230
  }
231
+ parsed.length = parsedCount;
220
232
  return parsed;
221
233
  }
222
234
  parseLidSyncResponse(node, requestedUsers) {
@@ -231,7 +243,8 @@ export class SignalDeviceSyncApi {
231
243
  }
232
244
  const requestedSet = new Set(requestedUsers);
233
245
  const userNodes = getNodeChildrenByTag(listNode, WA_NODE_TAGS.USER);
234
- const parsed = [];
246
+ const parsed = new Array(userNodes.length);
247
+ let parsedCount = 0;
235
248
  for (let index = 0; index < userNodes.length; index += 1) {
236
249
  const userNode = userNodes[index];
237
250
  const userJid = userNode.attrs.jid;
@@ -250,7 +263,8 @@ export class SignalDeviceSyncApi {
250
263
  const lidNode = findNodeChild(userNode, WA_NODE_TAGS.LID);
251
264
  const contactNode = findNodeChild(userNode, WA_NODE_TAGS.CONTACT);
252
265
  if (!lidNode) {
253
- parsed.push(this.buildLidSyncResult(normalizedUserJid, normalizedPhoneJid, contactNode, null));
266
+ parsed[parsedCount] = this.buildLidSyncResult(normalizedUserJid, normalizedPhoneJid, contactNode, null);
267
+ parsedCount += 1;
254
268
  continue;
255
269
  }
256
270
  const errorNode = findNodeChild(lidNode, WA_NODE_TAGS.ERROR);
@@ -260,12 +274,15 @@ export class SignalDeviceSyncApi {
260
274
  code: errorNode.attrs.code,
261
275
  text: errorNode.attrs.text
262
276
  });
263
- parsed.push(this.buildLidSyncResult(normalizedUserJid, normalizedPhoneJid, contactNode, null));
277
+ parsed[parsedCount] = this.buildLidSyncResult(normalizedUserJid, normalizedPhoneJid, contactNode, null);
278
+ parsedCount += 1;
264
279
  continue;
265
280
  }
266
281
  const lidJid = lidNode.attrs.val ? this.normalizeUserJid(lidNode.attrs.val) : null;
267
- parsed.push(this.buildLidSyncResult(normalizedUserJid, normalizedPhoneJid, contactNode, lidJid));
282
+ parsed[parsedCount] = this.buildLidSyncResult(normalizedUserJid, normalizedPhoneJid, contactNode, lidJid);
283
+ parsedCount += 1;
268
284
  }
285
+ parsed.length = parsedCount;
269
286
  return parsed;
270
287
  }
271
288
  buildLidSyncResult(jid, phoneJid, contactNode, lidJid) {
@@ -291,7 +308,7 @@ export class SignalDeviceSyncApi {
291
308
  }
292
309
  return contactNode.attrs.type === 'in';
293
310
  }
294
- parseUserDeviceJids(userNode, userJid) {
311
+ parseUserDeviceJids(userNode, rawUserJid, normalizedUserJid) {
295
312
  const devicesNode = findNodeChild(userNode, WA_NODE_TAGS.DEVICES);
296
313
  if (!devicesNode) {
297
314
  return [];
@@ -299,7 +316,7 @@ export class SignalDeviceSyncApi {
299
316
  const errorNode = findNodeChild(devicesNode, WA_NODE_TAGS.ERROR);
300
317
  if (errorNode) {
301
318
  this.logger.warn('signal device sync user error', {
302
- jid: userJid,
319
+ jid: normalizedUserJid,
303
320
  code: errorNode.attrs.code,
304
321
  text: errorNode.attrs.text
305
322
  });
@@ -309,7 +326,8 @@ export class SignalDeviceSyncApi {
309
326
  if (!deviceListNode) {
310
327
  return [];
311
328
  }
312
- const parsedUser = splitJid(userJid);
329
+ const parsedNormalizedUser = splitJid(normalizedUserJid);
330
+ const parsedRawUser = splitJid(rawUserJid);
313
331
  const dedup = new Set();
314
332
  for (const deviceNode of getNodeChildrenByTag(deviceListNode, 'device')) {
315
333
  const parsedId = deviceNode.attrs.id
@@ -318,16 +336,17 @@ export class SignalDeviceSyncApi {
318
336
  if (!Number.isSafeInteger(parsedId) || parsedId < 0) {
319
337
  continue;
320
338
  }
321
- dedup.add(this.toDeviceJid(parsedUser.user, parsedUser.server, parsedId));
322
- }
323
- const deviceJids = [];
324
- for (const jid of dedup.values()) {
325
- deviceJids.push(jid);
339
+ const isHostedDevice = isHostedDeviceId(parsedId) || deviceNode.attrs.is_hosted === 'true';
340
+ dedup.add(buildDeviceJid(parsedNormalizedUser.user, parsedNormalizedUser.server, parsedId, {
341
+ rawServer: parsedRawUser.server,
342
+ isHosted: isHostedDevice
343
+ }));
326
344
  }
327
- return deviceJids;
345
+ return Array.from(dedup);
328
346
  }
329
347
  normalizeUsers(userJids) {
330
- const normalized = [];
348
+ const normalized = new Array(userJids.length);
349
+ let normalizedCount = 0;
331
350
  const dedup = new Set();
332
351
  for (let index = 0; index < userJids.length; index += 1) {
333
352
  const normalizedJid = this.normalizeUserJid(userJids[index]);
@@ -335,18 +354,16 @@ export class SignalDeviceSyncApi {
335
354
  continue;
336
355
  }
337
356
  dedup.add(normalizedJid);
338
- normalized.push(normalizedJid);
357
+ normalized[normalizedCount] = normalizedJid;
358
+ normalizedCount += 1;
339
359
  }
360
+ normalized.length = normalizedCount;
340
361
  return normalized;
341
362
  }
342
363
  normalizeUserJid(jid) {
343
- const address = parseSignalAddressFromJid(jid);
344
- return `${address.user}@${address.server}`;
345
- }
346
- toDeviceJid(user, server, deviceId) {
347
- if (deviceId === 0) {
348
- return `${user}@${server}`;
349
- }
350
- return `${user}:${deviceId}@${server}`;
364
+ return toUserJid(jid, {
365
+ canonicalizeSignalServer: true,
366
+ hostDomain: this.hostDomain
367
+ });
351
368
  }
352
369
  }
@@ -14,8 +14,10 @@ export class SignalDigestSyncApi {
14
14
  options.defaultTimeoutMs ?? WA_DEFAULTS.SIGNAL_FETCH_KEY_BUNDLES_TIMEOUT_MS;
15
15
  this.hostDomain = options.hostDomain ?? WA_DEFAULTS.HOST_DOMAIN;
16
16
  }
17
- async validateLocalKeyBundle(timeoutMs = this.defaultTimeoutMs) {
18
- this.logger.debug('signal digest query request', { timeoutMs });
17
+ async validateLocalKeyBundle(prefetchedOrTimeout, timeoutMs = this.defaultTimeoutMs) {
18
+ const prefetched = typeof prefetchedOrTimeout === 'number' ? undefined : prefetchedOrTimeout;
19
+ const effectiveTimeoutMs = typeof prefetchedOrTimeout === 'number' ? prefetchedOrTimeout : timeoutMs;
20
+ this.logger.debug('signal digest query request', { timeoutMs: effectiveTimeoutMs });
19
21
  const response = await this.query({
20
22
  tag: WA_NODE_TAGS.IQ,
21
23
  attrs: {
@@ -29,7 +31,7 @@ export class SignalDigestSyncApi {
29
31
  attrs: {}
30
32
  }
31
33
  ]
32
- }, timeoutMs);
34
+ }, effectiveTimeoutMs);
33
35
  if (response.tag !== WA_NODE_TAGS.IQ) {
34
36
  throw new Error(`invalid signal digest response tag: ${response.tag}`);
35
37
  }
@@ -58,10 +60,12 @@ export class SignalDigestSyncApi {
58
60
  preKeyCount: digest.preKeyIds.length
59
61
  };
60
62
  }
61
- const [registrationInfo, signedPreKey] = await Promise.all([
62
- this.signalStore.getRegistrationInfo(),
63
- this.signalStore.getSignedPreKey()
64
- ]);
63
+ const [registrationInfo, signedPreKey] = prefetched
64
+ ? [prefetched.registrationInfo, prefetched.signedPreKey]
65
+ : await Promise.all([
66
+ this.signalStore.getRegistrationInfo(),
67
+ this.signalStore.getSignedPreKey()
68
+ ]);
65
69
  if (!registrationInfo || !signedPreKey) {
66
70
  return {
67
71
  valid: false,
@@ -161,11 +165,11 @@ export class SignalDigestSyncApi {
161
165
  const signedKeyId = parseUint(decodeExactLength(signedKeyIdNode.content, 'signal digest skey.id', SIGNAL_KEY_ID_LENGTH), 'signal digest skey.id');
162
166
  const signedKeyPublicKey = decodeExactLength(signedKeyValueNode.content, 'signal digest skey.value', SIGNAL_KEY_DATA_LENGTH);
163
167
  const signedKeySignature = decodeExactLength(signedKeySignatureNode.content, 'signal digest skey.signature', SIGNAL_SIGNATURE_LENGTH);
164
- const preKeyIds = [];
165
168
  const listChildren = getNodeChildren(listNode);
169
+ const preKeyIds = new Array(listChildren.length);
166
170
  for (let index = 0; index < listChildren.length; index += 1) {
167
171
  const child = listChildren[index];
168
- preKeyIds.push(parseUint(decodeExactLength(child.content, `signal digest list[${index}]`, SIGNAL_KEY_ID_LENGTH), `signal digest list[${index}]`));
172
+ preKeyIds[index] = parseUint(decodeExactLength(child.content, `signal digest list[${index}]`, SIGNAL_KEY_ID_LENGTH), `signal digest list[${index}]`);
169
173
  }
170
174
  const hash = decodeNodeContentBase64OrBytes(hashNode.content, 'signal digest hash');
171
175
  return {
@@ -1,12 +1,14 @@
1
1
  import { toSerializedPubKey } from '../../crypto/core/keys.js';
2
+ import { PromiseDedup } from '../../infra/perf/PromiseDedup.js';
2
3
  import { WA_DEFAULTS, WA_IQ_TYPES, WA_NODE_TAGS, WA_XMLNS } from '../../protocol/constants.js';
3
- import { normalizeDeviceJid, parseSignalAddressFromJid } from '../../protocol/jid.js';
4
+ import { canonicalizeSignalJid, parseSignalAddressFromJid } from '../../protocol/jid.js';
4
5
  import { decodeExactLength, parseUint } from '../api/codec.js';
5
6
  import { SIGNAL_KEY_BUNDLE_TYPE_LENGTH, SIGNAL_KEY_DATA_LENGTH } from '../api/constants.js';
6
7
  import { findNodeChild, getNodeChildrenByTag } from '../../transport/node/helpers.js';
7
8
  import { assertIqResult } from '../../transport/node/query.js';
8
9
  export class SignalIdentitySyncApi {
9
10
  constructor(options) {
11
+ this.syncDedup = new PromiseDedup();
10
12
  this.logger = options.logger;
11
13
  this.query = options.query;
12
14
  this.signalStore = options.signalStore;
@@ -14,17 +16,24 @@ export class SignalIdentitySyncApi {
14
16
  options.defaultTimeoutMs ?? WA_DEFAULTS.SIGNAL_FETCH_KEY_BUNDLES_TIMEOUT_MS;
15
17
  this.hostDomain = options.hostDomain ?? WA_DEFAULTS.HOST_DOMAIN;
16
18
  }
17
- async syncIdentityKeys(targetJids, timeoutMs = this.defaultTimeoutMs) {
18
- const normalizedTargets = [];
19
+ syncIdentityKeys(targetJids, timeoutMs = this.defaultTimeoutMs) {
20
+ const dedupKey = `${timeoutMs}:${targetJids.join(',')}`;
21
+ return this.syncDedup.run(dedupKey, () => this.syncIdentityKeysInternal(targetJids, timeoutMs));
22
+ }
23
+ async syncIdentityKeysInternal(targetJids, timeoutMs) {
24
+ const normalizedTargets = new Array(targetJids.length);
25
+ let normalizedTargetsCount = 0;
19
26
  const dedup = new Set();
20
27
  for (let index = 0; index < targetJids.length; index += 1) {
21
- const normalized = normalizeDeviceJid(targetJids[index]);
28
+ const normalized = canonicalizeSignalJid(targetJids[index], this.hostDomain);
22
29
  if (dedup.has(normalized)) {
23
30
  continue;
24
31
  }
25
32
  dedup.add(normalized);
26
- normalizedTargets.push(normalized);
33
+ normalizedTargets[normalizedTargetsCount] = normalized;
34
+ normalizedTargetsCount += 1;
27
35
  }
36
+ normalizedTargets.length = normalizedTargetsCount;
28
37
  if (normalizedTargets.length === 0) {
29
38
  return [];
30
39
  }
@@ -83,10 +92,13 @@ export class SignalIdentitySyncApi {
83
92
  }
84
93
  const requested = new Set(requestedJids);
85
94
  const userNodes = getNodeChildrenByTag(listNode, WA_NODE_TAGS.USER);
86
- const parsed = [];
95
+ const parsed = new Array(userNodes.length);
96
+ let parsedCount = 0;
87
97
  for (let index = 0; index < userNodes.length; index += 1) {
88
98
  const userNode = userNodes[index];
89
- const jid = userNode.attrs.jid ? normalizeDeviceJid(userNode.attrs.jid) : '';
99
+ const jid = userNode.attrs.jid
100
+ ? canonicalizeSignalJid(userNode.attrs.jid, this.hostDomain)
101
+ : '';
90
102
  if (!jid || !requested.has(jid)) {
91
103
  continue;
92
104
  }
@@ -109,18 +121,21 @@ export class SignalIdentitySyncApi {
109
121
  ? parseUint(decodeExactLength(typeNode.content, 'identity sync type', SIGNAL_KEY_BUNDLE_TYPE_LENGTH), 'identity sync type')
110
122
  : undefined;
111
123
  if (parsedType === undefined) {
112
- parsed.push({
124
+ parsed[parsedCount] = {
113
125
  jid,
114
126
  identity
115
- });
127
+ };
128
+ parsedCount += 1;
116
129
  continue;
117
130
  }
118
- parsed.push({
131
+ parsed[parsedCount] = {
119
132
  jid,
120
133
  identity,
121
134
  type: parsedType
122
- });
135
+ };
136
+ parsedCount += 1;
123
137
  }
138
+ parsed.length = parsedCount;
124
139
  return parsed;
125
140
  }
126
141
  }
@@ -1,10 +1,14 @@
1
1
  import { WA_DEFAULTS, WA_NODE_TAGS } from '../../protocol/constants.js';
2
- import { splitJid } from '../../protocol/jid.js';
2
+ import { splitJid, toUserJid } from '../../protocol/jid.js';
3
3
  import { decodeExactLength, parseUint } from '../api/codec.js';
4
4
  import { SIGNAL_KEY_DATA_LENGTH, SIGNAL_KEY_ID_LENGTH, SIGNAL_REGISTRATION_ID_LENGTH, SIGNAL_SIGNATURE_LENGTH } from '../api/constants.js';
5
5
  import { buildMissingPreKeysFetchIq } from '../api/prekeys.js';
6
+ import { registerParsedResultByRawAndCanonicalKey } from '../api/result-map.js';
6
7
  import { decodeNodeContentBase64OrBytes, findNodeChildrenByTags, findNodeChild, getNodeChildrenByTag } from '../../transport/node/helpers.js';
7
8
  import { assertIqResult } from '../../transport/node/query.js';
9
+ function isMissingPreKeysUserResultPreferred(result) {
10
+ return 'devices' in result;
11
+ }
8
12
  export class SignalMissingPreKeysSyncApi {
9
13
  constructor(options) {
10
14
  this.logger = options.logger;
@@ -35,31 +39,38 @@ export class SignalMissingPreKeysSyncApi {
35
39
  }
36
40
  const users = getNodeChildrenByTag(listNode, WA_NODE_TAGS.USER);
37
41
  const parsedByJid = new Map();
42
+ const parsedByCanonicalJid = new Map();
38
43
  for (let index = 0; index < users.length; index += 1) {
39
44
  const userNode = users[index];
40
45
  const userJid = userNode.attrs.jid;
41
46
  if (!userJid) {
42
47
  continue;
43
48
  }
49
+ const canonicalUserJid = toUserJid(userJid, {
50
+ canonicalizeSignalServer: true
51
+ });
44
52
  const userErrorNode = findNodeChild(userNode, WA_NODE_TAGS.ERROR);
45
53
  if (userErrorNode) {
46
54
  const parsedCode = Number.parseInt(userErrorNode.attrs.code ?? '', 10);
47
- parsedByJid.set(userJid, {
55
+ registerParsedResultByRawAndCanonicalKey(parsedByJid, parsedByCanonicalJid, userJid, canonicalUserJid, {
48
56
  userJid,
49
57
  errorCode: Number.isSafeInteger(parsedCode) ? parsedCode : undefined,
50
58
  errorText: userErrorNode.attrs.text ?? userErrorNode.attrs.type ?? 'unknown'
51
- });
59
+ }, isMissingPreKeysUserResultPreferred);
52
60
  continue;
53
61
  }
54
- parsedByJid.set(userJid, {
62
+ registerParsedResultByRawAndCanonicalKey(parsedByJid, parsedByCanonicalJid, userJid, canonicalUserJid, {
55
63
  userJid,
56
- devices: this.parseUserDevices(userNode, userJid)
57
- });
64
+ devices: this.parseUserDevices(userNode, canonicalUserJid)
65
+ }, isMissingPreKeysUserResultPreferred);
58
66
  }
59
67
  const results = new Array(requestedTargets.length);
60
68
  for (let index = 0; index < requestedTargets.length; index += 1) {
61
69
  const target = requestedTargets[index];
62
- results[index] = parsedByJid.get(target.userJid) ?? {
70
+ results[index] = parsedByJid.get(target.userJid) ??
71
+ parsedByCanonicalJid.get(toUserJid(target.userJid, {
72
+ canonicalizeSignalServer: true
73
+ })) ?? {
63
74
  userJid: target.userJid,
64
75
  errorText: 'missing user in key_fetch response'
65
76
  };
@@ -10,11 +10,13 @@ export class SignalRotateKeyApi {
10
10
  this.defaultTimeoutMs = options.defaultTimeoutMs ?? WA_DEFAULTS.IQ_TIMEOUT_MS;
11
11
  }
12
12
  async rotateSignedPreKey(timeoutMs = this.defaultTimeoutMs) {
13
- const registrationInfo = await this.signalStore.getRegistrationInfo();
13
+ const [registrationInfo, currentSignedPreKey] = await Promise.all([
14
+ this.signalStore.getRegistrationInfo(),
15
+ this.signalStore.getSignedPreKey()
16
+ ]);
14
17
  if (!registrationInfo) {
15
18
  throw new Error('signal rotate key requires registration info');
16
19
  }
17
- const currentSignedPreKey = await this.signalStore.getSignedPreKey();
18
20
  const nextSignedPreKey = await generateSignedPreKey(currentSignedPreKey ? currentSignedPreKey.keyId + 1 : 1, registrationInfo.identityKeyPair.privKey);
19
21
  await this.signalStore.setSignedPreKey(nextSignedPreKey);
20
22
  this.logger.info('signal signed prekey uploading', {
@@ -1,8 +1,13 @@
1
1
  import { WA_DEFAULTS, WA_IQ_TYPES, WA_NODE_TAGS, WA_XMLNS } from '../../protocol/constants.js';
2
+ import { canonicalizeSignalJid } from '../../protocol/jid.js';
2
3
  import { decodeExactLength, parseUint } from '../api/codec.js';
3
4
  import { SIGNAL_KEY_DATA_LENGTH, SIGNAL_KEY_ID_LENGTH, SIGNAL_REGISTRATION_ID_LENGTH, SIGNAL_SIGNATURE_LENGTH } from '../api/constants.js';
5
+ import { registerParsedResultByRawAndCanonicalKey } from '../api/result-map.js';
4
6
  import { findNodeChild, getNodeChildrenByTag, decodeNodeContentBase64OrBytes } from '../../transport/node/helpers.js';
5
7
  import { assertIqResult } from '../../transport/node/query.js';
8
+ function isKeyBundleResultPreferred(result) {
9
+ return 'bundle' in result;
10
+ }
6
11
  export class SignalSessionSyncApi {
7
12
  constructor(options) {
8
13
  this.logger = options.logger;
@@ -41,9 +46,11 @@ export class SignalSessionSyncApi {
41
46
  reasonIdentity: (previous?.reasonIdentity ?? false) || target.reasonIdentity === true
42
47
  });
43
48
  }
44
- const mergedTargets = [];
49
+ const mergedTargets = new Array(targetByJid.size);
50
+ let mergedTargetsCount = 0;
45
51
  for (const target of targetByJid.values()) {
46
- mergedTargets.push(target);
52
+ mergedTargets[mergedTargetsCount] = target;
53
+ mergedTargetsCount += 1;
47
54
  }
48
55
  const userNodes = new Array(mergedTargets.length);
49
56
  for (let index = 0; index < mergedTargets.length; index += 1) {
@@ -87,6 +94,7 @@ export class SignalSessionSyncApi {
87
94
  throw new Error('key bundle response list is empty');
88
95
  }
89
96
  const parsedByJid = new Map();
97
+ const parsedByCanonicalJid = new Map();
90
98
  for (let index = 0; index < userNodes.length; index += 1) {
91
99
  const userNode = userNodes[index];
92
100
  const jid = userNode.attrs.jid;
@@ -95,24 +103,25 @@ export class SignalSessionSyncApi {
95
103
  }
96
104
  const userErrorNode = findNodeChild(userNode, WA_NODE_TAGS.ERROR);
97
105
  if (userErrorNode) {
98
- parsedByJid.set(jid, {
106
+ registerParsedResultByRawAndCanonicalKey(parsedByJid, parsedByCanonicalJid, jid, canonicalizeSignalJid(jid, this.hostDomain), {
99
107
  jid,
100
108
  errorCode: userErrorNode.attrs.code,
101
109
  errorText: userErrorNode.attrs.text ?? 'unknown'
102
- });
110
+ }, isKeyBundleResultPreferred);
103
111
  continue;
104
112
  }
105
113
  const parsed = this.parseUserKeyBundle(userNode);
106
- parsedByJid.set(jid, {
114
+ registerParsedResultByRawAndCanonicalKey(parsedByJid, parsedByCanonicalJid, jid, canonicalizeSignalJid(jid, this.hostDomain), {
107
115
  jid,
108
116
  bundle: parsed.bundle,
109
117
  ...(parsed.deviceIdentity ? { deviceIdentity: parsed.deviceIdentity } : {})
110
- });
118
+ }, isKeyBundleResultPreferred);
111
119
  }
112
120
  const output = new Array(requestedTargets.length);
113
121
  for (let index = 0; index < requestedTargets.length; index += 1) {
114
122
  const target = requestedTargets[index];
115
- output[index] = parsedByJid.get(target.jid) ?? {
123
+ output[index] = parsedByJid.get(target.jid) ??
124
+ parsedByCanonicalJid.get(canonicalizeSignalJid(target.jid, this.hostDomain)) ?? {
116
125
  jid: target.jid,
117
126
  errorText: 'missing key bundle user in response'
118
127
  };
@@ -0,0 +1,10 @@
1
+ function mergePreferredParsedResult(target, key, next, isPreferred) {
2
+ const current = target.get(key);
3
+ if (!current || !isPreferred(current)) {
4
+ target.set(key, next);
5
+ }
6
+ }
7
+ export function registerParsedResultByRawAndCanonicalKey(parsedByRawKey, parsedByCanonicalKey, rawKey, canonicalKey, result, isPreferred) {
8
+ mergePreferredParsedResult(parsedByRawKey, rawKey, result, isPreferred);
9
+ mergePreferredParsedResult(parsedByCanonicalKey, canonicalKey, result, isPreferred);
10
+ }
@@ -1,11 +1,7 @@
1
- import { SERIALIZED_PUB_KEY_PREFIX as CORE_SERIALIZED_PUB_KEY_PREFIX } from '../crypto/core/constants.js';
2
1
  import { TEXT_ENCODER } from '../util/bytes.js';
3
2
  export const SIGNAL_VERSION = 3;
4
3
  export const SIGNAL_GROUP_VERSION = 3;
5
- export const SERIALIZED_PUB_KEY_PREFIX = CORE_SERIALIZED_PUB_KEY_PREFIX;
6
- export const KEY_TYPE_CURVE25519 = 5;
7
4
  export const SIGNAL_MAC_SIZE = 8;
8
- export const SIGNATURE_SIZE = 64;
9
5
  export const MAX_PREV_SESSIONS = 40;
10
6
  export const MAX_UNUSED_KEYS = 2000;
11
7
  export const FUTURE_MESSAGES_MAX = 2000;
@@ -1,4 +1,4 @@
1
- import { ed25519VerifyRaw, importHmacKey, hmacSign, randomBytesAsync, sha512, toRawPubKey } from '../../crypto/index.js';
1
+ import { Ed25519, importHmacKey, hmacSign, randomBytesAsync, sha512, toRawPubKey } from '../../crypto/index.js';
2
2
  import { clampCurvePrivateKeyInPlace, montgomeryToEdwardsPublic } from '../../crypto/curves/X25519.js';
3
3
  import { encodeExtendedPoint, scalarMultBase } from '../../crypto/math/edwards.js';
4
4
  import { bytesToBigIntLE, bigIntToBytesLE } from '../../crypto/math/le.js';
@@ -7,18 +7,24 @@ import { ADV_PREFIX_ACCOUNT_SIGNATURE, ADV_PREFIX_DEVICE_SIGNATURE, ADV_PREFIX_H
7
7
  import { assertByteLength, concatBytes } from '../../util/bytes.js';
8
8
  export { ADV_PREFIX_ACCOUNT_SIGNATURE, ADV_PREFIX_DEVICE_SIGNATURE, ADV_PREFIX_HOSTED_ACCOUNT_SIGNATURE, ADV_PREFIX_HOSTED_DEVICE_SIGNATURE } from '../crypto/constants.js';
9
9
  export async function verifySignalSignature(publicKey, message, signature) {
10
- if (!assertByteLength(signature, 64, 'invalid signal signature length', false)) {
10
+ if (signature.length !== 64) {
11
11
  return false;
12
12
  }
13
13
  if ((signature[63] & 0x60) !== 0) {
14
14
  return false;
15
15
  }
16
- const signalSignature = new Uint8Array(signature);
17
- const signBit = signalSignature[63] & 0x80;
18
- signalSignature[63] &= 0x7f;
16
+ const signatureLastByteIndex = 63;
17
+ const originalSignatureLastByte = signature[signatureLastByteIndex];
18
+ const signBit = originalSignatureLastByte & 0x80;
19
+ signature[signatureLastByteIndex] = originalSignatureLastByte & 0x7f;
19
20
  const curvePublic = toRawPubKey(publicKey);
20
21
  const edPublic = montgomeryToEdwardsPublic(curvePublic, signBit);
21
- return ed25519VerifyRaw(edPublic, signalSignature, message);
22
+ try {
23
+ return await Ed25519.verify(message, signature, edPublic);
24
+ }
25
+ finally {
26
+ signature[signatureLastByteIndex] = originalSignatureLastByte;
27
+ }
22
28
  }
23
29
  export async function signSignalMessage(privateKey, message) {
24
30
  assertByteLength(privateKey, 32, `invalid curve25519 private key length ${privateKey.length}`);