zapo-js 0.1.0 → 0.1.2

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 (366) hide show
  1. package/README.md +12 -7
  2. package/dist/appstate/WaAppStateCrypto.js +18 -25
  3. package/dist/appstate/WaAppStateSyncClient.js +181 -114
  4. package/dist/appstate/WaAppStateSyncResponseParser.js +16 -5
  5. package/dist/appstate/constants.js +4 -3
  6. package/dist/appstate/utils.js +10 -30
  7. package/dist/auth/WaAuthClient.js +48 -55
  8. package/dist/auth/flow/WaAuthCredentialsFlow.js +21 -14
  9. package/dist/auth/index.js +1 -3
  10. package/dist/auth/pairing/WaPairingFlow.js +21 -23
  11. package/dist/auth/pairing/WaQrFlow.js +37 -24
  12. package/dist/client/WaClient.js +103 -276
  13. package/dist/client/WaClientFactory.js +227 -110
  14. package/dist/client/connection/WaConnectionManager.js +292 -0
  15. package/dist/client/connection/WaKeyShareCoordinator.js +63 -0
  16. package/dist/client/connection/WaReceiptQueue.js +51 -0
  17. package/dist/client/coordinators/WaAppStateMutationCoordinator.js +471 -0
  18. package/dist/client/coordinators/WaGroupCoordinator.js +27 -17
  19. package/dist/client/coordinators/WaIncomingNodeCoordinator.js +20 -27
  20. package/dist/client/coordinators/WaMessageDispatchCoordinator.js +231 -686
  21. package/dist/client/coordinators/WaRetryCoordinator.js +70 -37
  22. package/dist/client/dirty.js +35 -29
  23. package/dist/client/events/chat.js +4 -3
  24. package/dist/client/events/group.js +59 -36
  25. package/dist/client/history-sync.js +53 -63
  26. package/dist/client/incoming.js +23 -20
  27. package/dist/client/mailbox.js +8 -8
  28. package/dist/client/messages.js +4 -4
  29. package/dist/client/messaging/fanout.js +189 -0
  30. package/dist/client/messaging/key-protocol.js +130 -0
  31. package/dist/client/messaging/participants.js +191 -0
  32. package/dist/crypto/core/hkdf.js +3 -8
  33. package/dist/crypto/core/index.js +1 -4
  34. package/dist/crypto/core/keys.js +2 -3
  35. package/dist/crypto/core/primitives.js +12 -15
  36. package/dist/crypto/core/random.js +7 -26
  37. package/dist/crypto/curves/Ed25519.js +7 -8
  38. package/dist/crypto/curves/X25519.js +13 -16
  39. package/dist/crypto/index.js +0 -5
  40. package/dist/esm/appstate/WaAppStateCrypto.js +6 -13
  41. package/dist/esm/appstate/WaAppStateSyncClient.js +174 -107
  42. package/dist/esm/appstate/WaAppStateSyncResponseParser.js +17 -6
  43. package/dist/esm/appstate/constants.js +3 -2
  44. package/dist/esm/appstate/utils.js +8 -27
  45. package/dist/esm/auth/WaAuthClient.js +48 -55
  46. package/dist/esm/auth/flow/WaAuthCredentialsFlow.js +21 -14
  47. package/dist/esm/auth/index.js +0 -1
  48. package/dist/esm/auth/pairing/WaPairingFlow.js +14 -16
  49. package/dist/esm/auth/pairing/WaQrFlow.js +37 -24
  50. package/dist/esm/client/WaClient.js +103 -276
  51. package/dist/esm/client/WaClientFactory.js +227 -110
  52. package/dist/esm/client/connection/WaConnectionManager.js +288 -0
  53. package/dist/esm/client/connection/WaKeyShareCoordinator.js +59 -0
  54. package/dist/esm/client/connection/WaReceiptQueue.js +47 -0
  55. package/dist/esm/client/coordinators/WaAppStateMutationCoordinator.js +467 -0
  56. package/dist/esm/client/coordinators/WaGroupCoordinator.js +20 -10
  57. package/dist/esm/client/coordinators/WaIncomingNodeCoordinator.js +20 -27
  58. package/dist/esm/client/coordinators/WaMessageDispatchCoordinator.js +232 -687
  59. package/dist/esm/client/coordinators/WaRetryCoordinator.js +71 -38
  60. package/dist/esm/client/dirty.js +30 -24
  61. package/dist/esm/client/events/chat.js +4 -3
  62. package/dist/esm/client/events/group.js +50 -28
  63. package/dist/esm/client/history-sync.js +50 -60
  64. package/dist/esm/client/incoming.js +23 -20
  65. package/dist/esm/client/mailbox.js +8 -8
  66. package/dist/esm/client/messages.js +1 -1
  67. package/dist/esm/client/messaging/fanout.js +186 -0
  68. package/dist/esm/client/messaging/key-protocol.js +127 -0
  69. package/dist/esm/client/messaging/participants.js +188 -0
  70. package/dist/esm/crypto/core/hkdf.js +3 -8
  71. package/dist/esm/crypto/core/index.js +0 -1
  72. package/dist/esm/crypto/core/keys.js +2 -3
  73. package/dist/esm/crypto/core/primitives.js +12 -15
  74. package/dist/esm/crypto/core/random.js +6 -25
  75. package/dist/esm/crypto/curves/Ed25519.js +4 -5
  76. package/dist/esm/crypto/curves/X25519.js +10 -13
  77. package/dist/esm/crypto/index.js +0 -2
  78. package/dist/esm/infra/log/ConsoleLogger.js +18 -17
  79. package/dist/esm/infra/log/PinoLogger.js +15 -9
  80. package/dist/esm/infra/log/types.js +11 -1
  81. package/dist/esm/infra/perf/BoundedTaskQueue.js +13 -17
  82. package/dist/esm/media/WaMediaCrypto.js +2 -4
  83. package/dist/esm/media/WaMediaTransferClient.js +226 -58
  84. package/dist/esm/media/conn.js +10 -6
  85. package/dist/esm/media/constants.js +4 -1
  86. package/dist/esm/message/WaMessageClient.js +4 -13
  87. package/dist/esm/message/ack.js +6 -6
  88. package/dist/esm/message/addon-crypto.js +59 -0
  89. package/dist/esm/message/incoming.js +106 -111
  90. package/dist/esm/message/index.js +2 -0
  91. package/dist/esm/message/reporting-token.js +438 -0
  92. package/dist/esm/message/use-case-secret.js +49 -0
  93. package/dist/esm/protocol/appstate.js +58 -0
  94. package/dist/esm/protocol/constants.js +2 -1
  95. package/dist/esm/protocol/index.js +2 -10
  96. package/dist/esm/protocol/jid.js +63 -51
  97. package/dist/esm/protocol/media.js +3 -3
  98. package/dist/esm/protocol/nodes.js +2 -0
  99. package/dist/esm/protocol/usync.js +11 -0
  100. package/dist/esm/retry/index.js +1 -0
  101. package/dist/esm/retry/outbound.js +4 -5
  102. package/dist/esm/retry/parse.js +58 -76
  103. package/dist/esm/retry/replay.js +48 -49
  104. package/dist/esm/retry/tracker.js +56 -0
  105. package/dist/esm/signal/api/SignalDeviceSyncApi.js +249 -82
  106. package/dist/esm/signal/api/SignalDigestSyncApi.js +6 -1
  107. package/dist/esm/signal/api/SignalIdentitySyncApi.js +49 -34
  108. package/dist/esm/signal/api/SignalMissingPreKeysSyncApi.js +70 -62
  109. package/dist/esm/signal/api/SignalSessionSyncApi.js +23 -30
  110. package/dist/esm/signal/crypto/WaAdvSignature.js +3 -5
  111. package/dist/esm/signal/group/SenderKeyChain.js +28 -23
  112. package/dist/esm/signal/group/SenderKeyCodec.js +2 -4
  113. package/dist/esm/signal/group/SenderKeyManager.js +26 -16
  114. package/dist/esm/signal/index.js +1 -0
  115. package/dist/esm/signal/session/SignalProtocol.js +49 -14
  116. package/dist/esm/signal/session/SignalRatchet.js +24 -15
  117. package/dist/esm/signal/session/SignalSession.js +14 -9
  118. package/dist/esm/signal/session/resolver.js +186 -0
  119. package/dist/esm/signal/store/sqlite.js +16 -37
  120. package/dist/esm/store/createStore.js +16 -18
  121. package/dist/esm/store/noop.store.js +3 -6
  122. package/dist/esm/store/providers/memory/appstate.store.js +30 -6
  123. package/dist/esm/store/providers/memory/contact.store.js +5 -0
  124. package/dist/esm/store/providers/memory/device-list.store.js +3 -30
  125. package/dist/esm/store/providers/memory/message.store.js +11 -5
  126. package/dist/esm/store/providers/memory/participants.store.js +1 -8
  127. package/dist/esm/store/providers/memory/sender-key.store.js +5 -7
  128. package/dist/esm/store/providers/memory/signal.store.js +13 -1
  129. package/dist/esm/store/providers/memory/thread.store.js +5 -0
  130. package/dist/esm/store/providers/sqlite/appstate.store.js +82 -1
  131. package/dist/esm/store/providers/sqlite/connection.js +18 -13
  132. package/dist/esm/store/providers/sqlite/contact.store.js +31 -18
  133. package/dist/esm/store/providers/sqlite/device-list.store.js +7 -35
  134. package/dist/esm/store/providers/sqlite/message.store.js +45 -32
  135. package/dist/esm/store/providers/sqlite/migrations.js +1 -1
  136. package/dist/esm/store/providers/sqlite/participants.store.js +1 -9
  137. package/dist/esm/store/providers/sqlite/retry.store.js +8 -11
  138. package/dist/esm/store/providers/sqlite/sender-key.store.js +25 -30
  139. package/dist/esm/store/providers/sqlite/signal.store.js +104 -22
  140. package/dist/esm/store/providers/sqlite/table-names.js +107 -0
  141. package/dist/esm/store/providers/sqlite/thread.store.js +35 -22
  142. package/dist/esm/transport/WaComms.js +25 -23
  143. package/dist/esm/transport/WaWebSocket.js +115 -12
  144. package/dist/esm/transport/binary/decoder.js +4 -4
  145. package/dist/esm/transport/binary/encoder.js +12 -4
  146. package/dist/esm/transport/index.js +1 -0
  147. package/dist/esm/transport/keepalive/WaKeepAlive.js +2 -8
  148. package/dist/esm/transport/node/WaNodeOrchestrator.js +2 -4
  149. package/dist/esm/transport/node/WaNodeTransport.js +0 -3
  150. package/dist/esm/transport/node/builders/{accountSync.js → account-sync.js} +16 -36
  151. package/dist/esm/transport/node/builders/index.js +2 -1
  152. package/dist/esm/transport/node/builders/message.js +9 -0
  153. package/dist/esm/transport/node/builders/pairing.js +4 -5
  154. package/dist/esm/transport/node/builders/usync.js +41 -0
  155. package/dist/esm/transport/node/helpers.js +107 -5
  156. package/dist/esm/transport/node/usync.js +35 -0
  157. package/dist/esm/transport/noise/WaFrameCodec.js +48 -33
  158. package/dist/esm/transport/noise/WaNoiseCert.js +3 -6
  159. package/dist/esm/transport/noise/WaNoiseSession.js +17 -10
  160. package/dist/esm/transport/proxy.js +27 -0
  161. package/dist/esm/transport/stream/parse.js +13 -48
  162. package/dist/esm/util/bytes.js +50 -32
  163. package/dist/esm/util/coercion.js +6 -14
  164. package/dist/esm/util/primitives.js +39 -14
  165. package/dist/infra/log/ConsoleLogger.js +18 -17
  166. package/dist/infra/log/PinoLogger.js +15 -9
  167. package/dist/infra/log/types.js +12 -0
  168. package/dist/infra/perf/BoundedTaskQueue.js +13 -17
  169. package/dist/media/WaMediaCrypto.js +1 -3
  170. package/dist/media/WaMediaTransferClient.js +259 -58
  171. package/dist/media/conn.js +10 -6
  172. package/dist/media/constants.js +4 -1
  173. package/dist/message/WaMessageClient.js +5 -14
  174. package/dist/message/ack.js +6 -6
  175. package/dist/message/addon-crypto.js +65 -0
  176. package/dist/message/incoming.js +104 -109
  177. package/dist/message/index.js +2 -0
  178. package/dist/message/reporting-token.js +443 -0
  179. package/dist/message/use-case-secret.js +55 -0
  180. package/dist/protocol/appstate.js +59 -1
  181. package/dist/protocol/constants.js +7 -1
  182. package/dist/protocol/index.js +20 -42
  183. package/dist/protocol/jid.js +64 -51
  184. package/dist/protocol/media.js +3 -3
  185. package/dist/protocol/nodes.js +2 -0
  186. package/dist/protocol/usync.js +14 -0
  187. package/dist/retry/index.js +3 -1
  188. package/dist/retry/outbound.js +6 -7
  189. package/dist/retry/parse.js +57 -75
  190. package/dist/retry/replay.js +46 -47
  191. package/dist/retry/tracker.js +59 -0
  192. package/dist/signal/api/SignalDeviceSyncApi.js +247 -80
  193. package/dist/signal/api/SignalDigestSyncApi.js +6 -1
  194. package/dist/signal/api/SignalIdentitySyncApi.js +49 -34
  195. package/dist/signal/api/SignalMissingPreKeysSyncApi.js +67 -59
  196. package/dist/signal/api/SignalSessionSyncApi.js +23 -30
  197. package/dist/signal/crypto/WaAdvSignature.js +2 -4
  198. package/dist/signal/group/SenderKeyChain.js +27 -22
  199. package/dist/signal/group/SenderKeyCodec.js +1 -3
  200. package/dist/signal/group/SenderKeyManager.js +26 -16
  201. package/dist/signal/index.js +3 -1
  202. package/dist/signal/session/SignalProtocol.js +49 -14
  203. package/dist/signal/session/SignalRatchet.js +24 -15
  204. package/dist/signal/session/SignalSession.js +14 -9
  205. package/dist/signal/session/resolver.js +189 -0
  206. package/dist/signal/store/sqlite.js +16 -37
  207. package/dist/store/createStore.js +16 -18
  208. package/dist/store/noop.store.js +3 -6
  209. package/dist/store/providers/memory/appstate.store.js +28 -4
  210. package/dist/store/providers/memory/contact.store.js +5 -0
  211. package/dist/store/providers/memory/device-list.store.js +3 -30
  212. package/dist/store/providers/memory/message.store.js +11 -5
  213. package/dist/store/providers/memory/participants.store.js +1 -8
  214. package/dist/store/providers/memory/sender-key.store.js +8 -10
  215. package/dist/store/providers/memory/signal.store.js +21 -9
  216. package/dist/store/providers/memory/thread.store.js +5 -0
  217. package/dist/store/providers/sqlite/appstate.store.js +81 -0
  218. package/dist/store/providers/sqlite/connection.js +18 -13
  219. package/dist/store/providers/sqlite/contact.store.js +31 -18
  220. package/dist/store/providers/sqlite/device-list.store.js +7 -35
  221. package/dist/store/providers/sqlite/message.store.js +45 -32
  222. package/dist/store/providers/sqlite/migrations.js +1 -1
  223. package/dist/store/providers/sqlite/participants.store.js +1 -9
  224. package/dist/store/providers/sqlite/retry.store.js +8 -11
  225. package/dist/store/providers/sqlite/sender-key.store.js +24 -29
  226. package/dist/store/providers/sqlite/signal.store.js +105 -23
  227. package/dist/store/providers/sqlite/table-names.js +113 -0
  228. package/dist/store/providers/sqlite/thread.store.js +35 -22
  229. package/dist/transport/WaComms.js +27 -25
  230. package/dist/transport/WaWebSocket.js +148 -12
  231. package/dist/transport/binary/decoder.js +4 -4
  232. package/dist/transport/binary/encoder.js +12 -4
  233. package/dist/transport/index.js +7 -1
  234. package/dist/transport/keepalive/WaKeepAlive.js +1 -7
  235. package/dist/transport/node/WaNodeOrchestrator.js +2 -4
  236. package/dist/transport/node/WaNodeTransport.js +0 -3
  237. package/dist/transport/node/builders/{accountSync.js → account-sync.js} +15 -35
  238. package/dist/transport/node/builders/index.js +12 -9
  239. package/dist/transport/node/builders/message.js +9 -0
  240. package/dist/transport/node/builders/pairing.js +4 -5
  241. package/dist/transport/node/builders/usync.js +45 -0
  242. package/dist/transport/node/helpers.js +112 -4
  243. package/dist/transport/node/usync.js +38 -0
  244. package/dist/transport/noise/WaFrameCodec.js +47 -32
  245. package/dist/transport/noise/WaNoiseCert.js +5 -8
  246. package/dist/transport/noise/WaNoiseSession.js +17 -10
  247. package/dist/transport/proxy.js +34 -0
  248. package/dist/transport/stream/parse.js +17 -53
  249. package/dist/types/appstate/WaAppStateCrypto.d.ts +0 -1
  250. package/dist/types/appstate/WaAppStateSyncClient.d.ts +5 -2
  251. package/dist/types/appstate/constants.d.ts +1 -0
  252. package/dist/types/appstate/store/sqlite.d.ts +4 -18
  253. package/dist/types/appstate/utils.d.ts +0 -1
  254. package/dist/types/auth/WaAuthClient.d.ts +10 -12
  255. package/dist/types/auth/index.d.ts +0 -2
  256. package/dist/types/auth/pairing/WaQrFlow.d.ts +1 -1
  257. package/dist/types/auth/types.d.ts +6 -9
  258. package/dist/types/client/WaClient.d.ts +27 -25
  259. package/dist/types/client/WaClientFactory.d.ts +22 -23
  260. package/dist/types/client/connection/WaConnectionManager.d.ts +64 -0
  261. package/dist/types/client/connection/WaKeyShareCoordinator.d.ts +14 -0
  262. package/dist/types/client/connection/WaReceiptQueue.d.ts +13 -0
  263. package/dist/types/client/coordinators/WaAppStateMutationCoordinator.d.ts +46 -0
  264. package/dist/types/client/coordinators/WaIncomingNodeCoordinator.d.ts +0 -1
  265. package/dist/types/client/coordinators/WaMessageDispatchCoordinator.d.ts +18 -41
  266. package/dist/types/client/coordinators/WaRetryCoordinator.d.ts +2 -0
  267. package/dist/types/client/dirty.d.ts +1 -0
  268. package/dist/types/client/events/group.d.ts +2 -1
  269. package/dist/types/client/index.d.ts +1 -1
  270. package/dist/types/client/messaging/fanout.d.ts +14 -0
  271. package/dist/types/client/messaging/key-protocol.d.ts +18 -0
  272. package/dist/types/client/messaging/participants.d.ts +13 -0
  273. package/dist/types/client/types.d.ts +24 -1
  274. package/dist/types/crypto/core/hkdf.d.ts +0 -6
  275. package/dist/types/crypto/core/index.d.ts +0 -1
  276. package/dist/types/crypto/core/random.d.ts +1 -7
  277. package/dist/types/crypto/index.d.ts +0 -2
  278. package/dist/types/index.d.ts +1 -1
  279. package/dist/types/infra/log/ConsoleLogger.d.ts +2 -1
  280. package/dist/types/infra/log/PinoLogger.d.ts +1 -1
  281. package/dist/types/infra/log/types.d.ts +1 -0
  282. package/dist/types/infra/perf/BoundedTaskQueue.d.ts +1 -1
  283. package/dist/types/media/WaMediaTransferClient.d.ts +13 -3
  284. package/dist/types/media/types.d.ts +5 -0
  285. package/dist/types/message/addon-crypto.d.ts +25 -0
  286. package/dist/types/message/index.d.ts +2 -0
  287. package/dist/types/message/reporting-token.d.ts +19 -0
  288. package/dist/types/message/use-case-secret.d.ts +20 -0
  289. package/dist/types/protocol/appstate.d.ts +58 -0
  290. package/dist/types/protocol/constants.d.ts +2 -1
  291. package/dist/types/protocol/index.d.ts +2 -10
  292. package/dist/types/protocol/jid.d.ts +3 -3
  293. package/dist/types/protocol/nodes.d.ts +2 -0
  294. package/dist/types/protocol/usync.d.ts +11 -0
  295. package/dist/types/retry/index.d.ts +1 -0
  296. package/dist/types/retry/replay.d.ts +0 -4
  297. package/dist/types/retry/tracker.d.ts +19 -0
  298. package/dist/types/retry/types.d.ts +4 -3
  299. package/dist/types/signal/api/SignalDeviceSyncApi.d.ts +13 -1
  300. package/dist/types/signal/group/SenderKeyCodec.d.ts +4 -6
  301. package/dist/types/signal/index.d.ts +1 -0
  302. package/dist/types/signal/session/SignalProtocol.d.ts +9 -0
  303. package/dist/types/signal/session/resolver.d.ts +17 -0
  304. package/dist/types/store/contracts/appstate.store.d.ts +3 -0
  305. package/dist/types/store/contracts/contact.store.d.ts +1 -0
  306. package/dist/types/store/contracts/device-list.store.d.ts +0 -3
  307. package/dist/types/store/contracts/message.store.d.ts +1 -0
  308. package/dist/types/store/contracts/participants.store.d.ts +0 -1
  309. package/dist/types/store/contracts/sender-key.store.d.ts +0 -1
  310. package/dist/types/store/contracts/signal.store.d.ts +6 -0
  311. package/dist/types/store/contracts/thread.store.d.ts +1 -0
  312. package/dist/types/store/index.d.ts +1 -1
  313. package/dist/types/store/providers/memory/appstate.store.d.ts +2 -0
  314. package/dist/types/store/providers/memory/contact.store.d.ts +1 -0
  315. package/dist/types/store/providers/memory/device-list.store.d.ts +0 -3
  316. package/dist/types/store/providers/memory/message.store.d.ts +1 -0
  317. package/dist/types/store/providers/memory/participants.store.d.ts +0 -1
  318. package/dist/types/store/providers/memory/sender-key.store.d.ts +0 -1
  319. package/dist/types/store/providers/memory/signal.store.d.ts +6 -0
  320. package/dist/types/store/providers/memory/thread.store.d.ts +1 -0
  321. package/dist/types/store/providers/sqlite/appstate.store.d.ts +2 -0
  322. package/dist/types/store/providers/sqlite/contact.store.d.ts +2 -0
  323. package/dist/types/store/providers/sqlite/device-list.store.d.ts +0 -3
  324. package/dist/types/store/providers/sqlite/message.store.d.ts +2 -0
  325. package/dist/types/store/providers/sqlite/participants.store.d.ts +0 -1
  326. package/dist/types/store/providers/sqlite/retry.store.d.ts +0 -1
  327. package/dist/types/store/providers/sqlite/sender-key.store.d.ts +0 -1
  328. package/dist/types/store/providers/sqlite/signal.store.d.ts +7 -0
  329. package/dist/types/store/providers/sqlite/table-names.d.ts +5 -0
  330. package/dist/types/store/providers/sqlite/thread.store.d.ts +2 -0
  331. package/dist/types/store/types.d.ts +3 -0
  332. package/dist/types/transport/WaWebSocket.d.ts +3 -0
  333. package/dist/types/transport/index.d.ts +2 -1
  334. package/dist/types/transport/keepalive/WaKeepAlive.d.ts +0 -1
  335. package/dist/types/transport/node/WaNodeTransport.d.ts +0 -9
  336. package/dist/types/transport/node/builders/group.d.ts +4 -6
  337. package/dist/types/transport/node/builders/index.d.ts +2 -1
  338. package/dist/types/transport/node/builders/message.d.ts +14 -25
  339. package/dist/types/transport/node/builders/retry.d.ts +2 -4
  340. package/dist/types/transport/node/builders/usync.d.ts +21 -0
  341. package/dist/types/transport/node/helpers.d.ts +8 -0
  342. package/dist/types/transport/node/usync.d.ts +2 -0
  343. package/dist/types/transport/noise/WaFrameCodec.d.ts +3 -0
  344. package/dist/types/transport/noise/WaNoiseSession.d.ts +1 -0
  345. package/dist/types/transport/proxy.d.ts +6 -0
  346. package/dist/types/transport/stream/parse.d.ts +0 -1
  347. package/dist/types/transport/types.d.ts +18 -1
  348. package/dist/types/util/bytes.d.ts +5 -0
  349. package/dist/types/util/primitives.d.ts +3 -0
  350. package/dist/util/bytes.js +55 -33
  351. package/dist/util/coercion.js +6 -14
  352. package/dist/util/primitives.js +42 -14
  353. package/package.json +27 -9
  354. package/proto/index.d.ts +1090 -1048
  355. package/proto/index.js +1 -1
  356. package/scripts/check-node-version.cjs +0 -1
  357. package/dist/crypto/core/encoding.js +0 -29
  358. package/dist/esm/crypto/core/encoding.js +0 -25
  359. package/dist/esm/util/base64.js +0 -18
  360. package/dist/esm/util/signal-address.js +0 -5
  361. package/dist/types/crypto/core/encoding.d.ts +0 -11
  362. package/dist/types/util/base64.d.ts +0 -4
  363. package/dist/types/util/signal-address.d.ts +0 -2
  364. package/dist/util/base64.js +0 -24
  365. package/dist/util/signal-address.js +0 -8
  366. /package/dist/types/transport/node/builders/{accountSync.d.ts → account-sync.d.ts} +0 -0
@@ -1,11 +1,12 @@
1
- import { APP_STATE_DEFAULT_COLLECTIONS, APP_STATE_EMPTY_LT_HASH } from './constants.js';
2
- import { keyIdToHex } from './utils.js';
1
+ import { APP_STATE_DEFAULT_COLLECTIONS, APP_STATE_DEFAULT_COLLECTION_VERSION, APP_STATE_EMPTY_LT_HASH } from './constants.js';
3
2
  import { WaAppStateCrypto } from './WaAppStateCrypto.js';
4
3
  import { parseSyncResponse } from './WaAppStateSyncResponseParser.js';
5
4
  import { proto } from '../proto.js';
6
5
  import { WA_APP_STATE_COLLECTION_STATES, WA_DEFAULTS, WA_IQ_TYPES, WA_NODE_TAGS, WA_XMLNS } from '../protocol/constants.js';
7
- import { decodeProtoBytes } from '../util/base64.js';
8
- import { uint8Equal } from '../util/bytes.js';
6
+ import { parseSignalAddressFromJid } from '../protocol/jid.js';
7
+ import { assertIqResult } from '../transport/node/query.js';
8
+ import { decodeProtoBytes } from '../util/bytes.js';
9
+ import { bytesToHex, uint8Equal } from '../util/bytes.js';
9
10
  import { longToNumber } from '../util/primitives.js';
10
11
  export class WaAppStateMissingKeyError extends Error {
11
12
  constructor(message, keyId, collection) {
@@ -20,6 +21,7 @@ export class WaAppStateSyncClient {
20
21
  this.logger = options.logger;
21
22
  this.query = options.query;
22
23
  this.store = options.store;
24
+ this.getCurrentMeJid = options.getCurrentMeJid;
23
25
  this.hostDomain = options.hostDomain ?? WA_DEFAULTS.HOST_DOMAIN;
24
26
  this.defaultTimeoutMs = options.defaultTimeoutMs ?? WA_DEFAULTS.APP_STATE_SYNC_TIMEOUT_MS;
25
27
  this.onMissingKeys = options.onMissingKeys;
@@ -46,7 +48,7 @@ export class WaAppStateSyncClient {
46
48
  const keyId = decodeProtoBytes(item.keyId?.keyId, 'appStateSyncKeyShare.keys[].keyId.keyId');
47
49
  if (!item.keyData?.keyData) {
48
50
  this.logger.debug('app-state sync key share entry missing key data', {
49
- keyId: keyIdToHex(keyId)
51
+ keyId: bytesToHex(keyId)
50
52
  });
51
53
  continue;
52
54
  }
@@ -89,6 +91,10 @@ export class WaAppStateSyncClient {
89
91
  ...new Set(options.collections ?? APP_STATE_DEFAULT_COLLECTIONS)
90
92
  ];
91
93
  try {
94
+ const initialCollectionStates = await this.store.getCollectionStates(collections);
95
+ for (let index = 0; index < collections.length; index += 1) {
96
+ context.collections.set(collections[index], initialCollectionStates[index]);
97
+ }
92
98
  this.logger.info('app-state sync start', {
93
99
  collections: collections.length,
94
100
  pendingMutations: options.pendingMutations?.length ?? 0
@@ -158,36 +164,13 @@ export class WaAppStateSyncClient {
158
164
  }
159
165
  }
160
166
  async syncCollectionsRound(collections, pendingByCollection, options) {
161
- const prepared = await this.prepareSyncRoundRequest(collections, pendingByCollection);
162
- const iqNode = this.buildSyncIqNode(prepared.collectionNodes);
163
- const payloadByCollection = await this.fetchSyncPayloadByCollection(iqNode, options.timeoutMs ?? this.defaultTimeoutMs);
164
- const collectionOutcomes = await Promise.all(collections.map((collection) => this.processCollectionRound({
165
- collection,
166
- payloadByCollection,
167
- pendingByCollection,
168
- options,
169
- outgoingContexts: prepared.outgoingContexts,
170
- skippedUploadCollections: prepared.skippedUploadCollections
171
- })));
172
- return {
173
- results: collectionOutcomes.map((entry) => entry.result),
174
- collectionsToRefetch: collectionOutcomes
175
- .filter((entry) => entry.shouldRefetch)
176
- .map((entry) => entry.collection),
177
- stateChanged: collectionOutcomes.some((entry) => entry.stateChanged),
178
- missingKeyIds: this.collectDistinctMissingKeyIds(collectionOutcomes
179
- .map((entry) => entry.missingKeyId)
180
- .filter((value) => value !== null)),
181
- blockedCollections: collectionOutcomes
182
- .filter((entry) => entry.result.state === WA_APP_STATE_COLLECTION_STATES.BLOCKED)
183
- .map((entry) => entry.collection)
184
- };
185
- }
186
- async prepareSyncRoundRequest(collections, pendingByCollection) {
187
167
  const requests = await Promise.all(collections.map((collection) => this.buildCollectionSyncRequest(collection, pendingByCollection)));
168
+ const collectionNodes = new Array(requests.length);
188
169
  const outgoingContexts = new Map();
189
170
  const skippedUploadCollections = new Set();
190
- for (const request of requests) {
171
+ for (let index = 0; index < requests.length; index += 1) {
172
+ const request = requests[index];
173
+ collectionNodes[index] = request.node;
191
174
  if (request.outgoingContext) {
192
175
  outgoingContexts.set(request.collection, request.outgoingContext);
193
176
  }
@@ -195,26 +178,57 @@ export class WaAppStateSyncClient {
195
178
  skippedUploadCollections.add(request.collection);
196
179
  }
197
180
  }
198
- return {
199
- collectionNodes: requests.map((request) => request.node),
181
+ const iqNode = this.buildSyncIqNode(collectionNodes);
182
+ const payloadByCollection = await this.fetchSyncPayloadByCollection(iqNode, options.timeoutMs ?? this.defaultTimeoutMs);
183
+ const collectionOutcomes = await Promise.all(collections.map((collection) => this.processCollectionRound({
184
+ collection,
185
+ payloadByCollection,
186
+ pendingByCollection,
187
+ options,
200
188
  outgoingContexts,
201
189
  skippedUploadCollections
190
+ })));
191
+ const results = [];
192
+ const collectionsToRefetch = [];
193
+ const blockedCollections = [];
194
+ const missingKeyIds = [];
195
+ const missingKeyIdHexes = new Set();
196
+ let stateChanged = false;
197
+ for (const entry of collectionOutcomes) {
198
+ results.push(entry.result);
199
+ if (entry.shouldRefetch) {
200
+ collectionsToRefetch.push(entry.collection);
201
+ }
202
+ if (entry.stateChanged) {
203
+ stateChanged = true;
204
+ }
205
+ if (entry.result.state === WA_APP_STATE_COLLECTION_STATES.BLOCKED) {
206
+ blockedCollections.push(entry.collection);
207
+ }
208
+ if (entry.missingKeyId) {
209
+ const keyHex = bytesToHex(entry.missingKeyId);
210
+ if (!missingKeyIdHexes.has(keyHex)) {
211
+ missingKeyIdHexes.add(keyHex);
212
+ missingKeyIds.push(entry.missingKeyId);
213
+ }
214
+ }
215
+ }
216
+ return {
217
+ results,
218
+ collectionsToRefetch,
219
+ stateChanged,
220
+ missingKeyIds,
221
+ blockedCollections
202
222
  };
203
223
  }
204
224
  async buildCollectionSyncRequest(collection, pendingByCollection) {
205
225
  const collectionState = await this.getCollectionState(collection);
206
- const hasPersistedState = collectionState.version > 0 ||
207
- collectionState.indexValueMap.size > 0 ||
208
- !uint8Equal(collectionState.hash, APP_STATE_EMPTY_LT_HASH);
226
+ const hasPersistedState = collectionState.initialized;
209
227
  const attrs = {
210
- name: collection
228
+ name: collection,
229
+ version: String(hasPersistedState ? collectionState.version : APP_STATE_DEFAULT_COLLECTION_VERSION),
230
+ return_snapshot: hasPersistedState ? 'false' : 'true'
211
231
  };
212
- if (hasPersistedState) {
213
- attrs.version = String(collectionState.version);
214
- }
215
- else {
216
- attrs.return_snapshot = 'true';
217
- }
218
232
  const children = [];
219
233
  const pendingMutations = pendingByCollection.get(collection) ?? [];
220
234
  let outgoingContext;
@@ -271,6 +285,7 @@ export class WaAppStateSyncClient {
271
285
  tag: responseNode.tag,
272
286
  type: responseNode.attrs.type
273
287
  });
288
+ assertIqResult(responseNode, 'app-state sync');
274
289
  const payloads = parseSyncResponse(responseNode);
275
290
  this.logger.debug('app-state sync payloads parsed', { count: payloads.length });
276
291
  const payloadByCollection = new Map();
@@ -292,20 +307,16 @@ export class WaAppStateSyncClient {
292
307
  return this.createCollectionOutcome(collection, payload.state, payload.version);
293
308
  }
294
309
  const pendingMutationsCount = pendingByCollection.get(collection)?.length ?? 0;
295
- if (payload.state === WA_APP_STATE_COLLECTION_STATES.CONFLICT_HAS_MORE) {
296
- shouldRefetch = true;
297
- }
298
- else if (payload.state === WA_APP_STATE_COLLECTION_STATES.CONFLICT &&
299
- pendingMutationsCount > 0) {
300
- shouldRefetch = true;
301
- }
302
- if (payload.state === WA_APP_STATE_COLLECTION_STATES.CONFLICT) {
303
- return this.createCollectionOutcome(collection, pendingMutationsCount > 0
304
- ? WA_APP_STATE_COLLECTION_STATES.CONFLICT
305
- : WA_APP_STATE_COLLECTION_STATES.SUCCESS, payload.version, shouldRefetch);
306
- }
307
- if (payload.state === WA_APP_STATE_COLLECTION_STATES.CONFLICT_HAS_MORE) {
308
- return this.createCollectionOutcome(collection, payload.state, payload.version, shouldRefetch);
310
+ if (payload.state === WA_APP_STATE_COLLECTION_STATES.CONFLICT ||
311
+ payload.state === WA_APP_STATE_COLLECTION_STATES.CONFLICT_HAS_MORE) {
312
+ shouldRefetch =
313
+ payload.state === WA_APP_STATE_COLLECTION_STATES.CONFLICT_HAS_MORE ||
314
+ pendingMutationsCount > 0;
315
+ return this.createCollectionOutcome(collection, payload.state === WA_APP_STATE_COLLECTION_STATES.CONFLICT
316
+ ? pendingMutationsCount > 0
317
+ ? WA_APP_STATE_COLLECTION_STATES.CONFLICT
318
+ : WA_APP_STATE_COLLECTION_STATES.SUCCESS
319
+ : payload.state, payload.version, shouldRefetch);
309
320
  }
310
321
  try {
311
322
  let appliedMutations = [];
@@ -337,13 +348,17 @@ export class WaAppStateSyncClient {
337
348
  collectionStateChanged = true;
338
349
  }
339
350
  }
340
- if (payload.state === WA_APP_STATE_COLLECTION_STATES.SUCCESS_HAS_MORE) {
341
- shouldRefetch = true;
342
- }
343
- if (payload.state === WA_APP_STATE_COLLECTION_STATES.SUCCESS &&
344
- skippedUploadCollections.has(collection)) {
345
- shouldRefetch = true;
351
+ const currentCollectionState = await this.getCollectionState(collection);
352
+ if (!currentCollectionState.initialized &&
353
+ payload.state === WA_APP_STATE_COLLECTION_STATES.SUCCESS) {
354
+ this.setCollectionState(collection, payload.version ?? currentCollectionState.version, currentCollectionState.hash, currentCollectionState.indexValueMap);
355
+ collectionStateChanged = true;
346
356
  }
357
+ shouldRefetch =
358
+ shouldRefetch ||
359
+ payload.state === WA_APP_STATE_COLLECTION_STATES.SUCCESS_HAS_MORE ||
360
+ (payload.state === WA_APP_STATE_COLLECTION_STATES.SUCCESS &&
361
+ skippedUploadCollections.has(collection));
347
362
  this.logger.debug('app-state collection processed', {
348
363
  collection: payload.collection,
349
364
  state: payload.state,
@@ -382,24 +397,13 @@ export class WaAppStateSyncClient {
382
397
  }
383
398
  };
384
399
  }
385
- collectDistinctMissingKeyIds(keyIds) {
386
- const byHex = new Map();
387
- for (const keyId of keyIds) {
388
- const keyHex = keyIdToHex(keyId);
389
- if (byHex.has(keyHex)) {
390
- continue;
391
- }
392
- byHex.set(keyHex, keyId);
393
- }
394
- return [...byHex.values()];
395
- }
396
400
  async notifyMissingKeys(input) {
397
- const keyIds = this.collectDistinctMissingKeyIds(input.keyIds);
398
- const collections = [...new Set(input.collections)];
401
+ const keyIds = input.keyIds;
402
+ const collections = input.collections;
399
403
  if (keyIds.length === 0 || collections.length === 0) {
400
404
  return;
401
405
  }
402
- const keyIdsHex = keyIds.map((keyId) => keyIdToHex(keyId));
406
+ const keyIdsHex = keyIds.map((keyId) => bytesToHex(keyId));
403
407
  this.logger.info('app-state requesting missing sync keys', {
404
408
  keys: keyIdsHex.length,
405
409
  keyIds: keyIdsHex.join(','),
@@ -492,13 +496,13 @@ export class WaAppStateSyncClient {
492
496
  const keyId = decodeProtoBytes(snapshot.keyId?.id, `snapshot.keyId.id (${collection})`);
493
497
  const keyData = await this.getKeyData(keyId);
494
498
  if (!keyData) {
495
- throw new WaAppStateMissingKeyError(`missing snapshot key ${keyIdToHex(keyId)} for ${collection}`, keyId, collection);
499
+ throw new WaAppStateMissingKeyError(`missing snapshot key ${bytesToHex(keyId)} for ${collection}`, keyId, collection);
496
500
  }
497
501
  const indexValueMap = new Map();
498
502
  const mutations = [];
499
503
  const decryptedRecords = await this.decryptSnapshotRecords(collection, snapshot);
500
504
  for (const { decrypted, recordKeyId } of decryptedRecords) {
501
- const indexMacHex = keyIdToHex(decrypted.indexMac);
505
+ const indexMacHex = bytesToHex(decrypted.indexMac);
502
506
  indexValueMap.set(indexMacHex, decrypted.valueMac);
503
507
  mutations.push({
504
508
  collection,
@@ -530,29 +534,36 @@ export class WaAppStateSyncClient {
530
534
  const patchKeyId = decodeProtoBytes(patch.keyId?.id, `patch.keyId.id (${collection})`);
531
535
  const patchKeyData = await this.getKeyData(patchKeyId);
532
536
  if (!patchKeyData) {
533
- throw new WaAppStateMissingKeyError(`missing patch key ${keyIdToHex(patchKeyId)} for ${collection}`, patchKeyId, collection);
537
+ throw new WaAppStateMissingKeyError(`missing patch key ${bytesToHex(patchKeyId)} for ${collection}`, patchKeyId, collection);
534
538
  }
535
539
  const decryptedMutations = await this.decryptPatchMutations(collection, patch);
536
- const nextState = await this.computeNextCollectionState(current.hash, current.indexValueMap, decryptedMutations.map((mutation) => ({
537
- operation: mutation.operationCode,
538
- indexMac: mutation.indexMac,
539
- valueMac: mutation.valueMac
540
- })), collection);
541
- await this.assertPatchMacsMatch(patch, collection, patchKeyData, patchVersion, nextState.hash, decryptedMutations);
540
+ const macMutations = new Array(decryptedMutations.length);
541
+ const valueMacs = new Array(decryptedMutations.length);
542
+ for (let index = 0; index < decryptedMutations.length; index += 1) {
543
+ const mutation = decryptedMutations[index];
544
+ valueMacs[index] = mutation.valueMac;
545
+ macMutations[index] = {
546
+ operation: mutation.operationCode,
547
+ indexMac: mutation.indexMac,
548
+ valueMac: mutation.valueMac
549
+ };
550
+ }
551
+ const nextState = await this.computeNextCollectionState(current.hash, current.indexValueMap, macMutations, collection);
552
+ await this.assertPatchMacsMatch(patch, collection, patchKeyData, patchVersion, nextState.hash, valueMacs);
542
553
  this.setCollectionState(collection, patchVersion, nextState.hash, nextState.indexValueMap);
543
- return decryptedMutations.map(({ operationCode, ...mutation }) => {
544
- void operationCode;
545
- return mutation;
546
- });
554
+ return decryptedMutations.slice();
547
555
  }
548
556
  async decryptSnapshotRecords(collection, snapshot) {
549
- return Promise.all((snapshot.records ?? []).map(async (record) => {
550
- const indexMac = decodeProtoBytes(record.index?.blob, `snapshot.record.index.blob (${collection})`);
551
- const valueBlob = decodeProtoBytes(record.value?.blob, `snapshot.record.value.blob (${collection})`);
552
- const recordKeyId = decodeProtoBytes(record.keyId?.id, `snapshot.record.keyId.id (${collection})`);
557
+ const records = (snapshot.records ?? []).map((record) => ({
558
+ indexMac: decodeProtoBytes(record.index?.blob, `snapshot.record.index.blob (${collection})`),
559
+ valueBlob: decodeProtoBytes(record.value?.blob, `snapshot.record.value.blob (${collection})`),
560
+ recordKeyId: decodeProtoBytes(record.keyId?.id, `snapshot.record.keyId.id (${collection})`)
561
+ }));
562
+ await this.preloadKeyData(records.map((record) => record.recordKeyId));
563
+ return Promise.all(records.map(async ({ indexMac, valueBlob, recordKeyId }) => {
553
564
  const recordKeyData = await this.getKeyData(recordKeyId);
554
565
  if (!recordKeyData) {
555
- throw new WaAppStateMissingKeyError(`missing snapshot mutation key ${keyIdToHex(recordKeyId)} for ${collection}`, recordKeyId, collection);
566
+ throw new WaAppStateMissingKeyError(`missing snapshot mutation key ${bytesToHex(recordKeyId)} for ${collection}`, recordKeyId, collection);
556
567
  }
557
568
  const decrypted = await this.crypto.decryptMutation({
558
569
  operation: proto.SyncdMutation.SyncdOperation.SET,
@@ -568,7 +579,7 @@ export class WaAppStateSyncClient {
568
579
  }));
569
580
  }
570
581
  async decryptPatchMutations(collection, patch) {
571
- return Promise.all((patch.mutations ?? []).map(async (mutation) => {
582
+ const parsedMutations = (patch.mutations ?? []).map((mutation) => {
572
583
  const operationCode = mutation.operation;
573
584
  if (operationCode === null || operationCode === undefined) {
574
585
  throw new Error(`patch mutation is missing operation (${collection})`);
@@ -577,12 +588,18 @@ export class WaAppStateSyncClient {
577
588
  if (!record) {
578
589
  throw new Error(`patch mutation is missing record (${collection})`);
579
590
  }
580
- const indexMac = decodeProtoBytes(record.index?.blob, `patch.record.index.blob (${collection})`);
581
- const valueBlob = decodeProtoBytes(record.value?.blob, `patch.record.value.blob (${collection})`);
582
- const recordKeyId = decodeProtoBytes(record.keyId?.id, `patch.record.keyId.id (${collection})`);
591
+ return {
592
+ operationCode,
593
+ indexMac: decodeProtoBytes(record.index?.blob, `patch.record.index.blob (${collection})`),
594
+ valueBlob: decodeProtoBytes(record.value?.blob, `patch.record.value.blob (${collection})`),
595
+ recordKeyId: decodeProtoBytes(record.keyId?.id, `patch.record.keyId.id (${collection})`)
596
+ };
597
+ });
598
+ await this.preloadKeyData(parsedMutations.map((mutation) => mutation.recordKeyId));
599
+ return Promise.all(parsedMutations.map(async ({ operationCode, indexMac, valueBlob, recordKeyId }) => {
583
600
  const recordKeyData = await this.getKeyData(recordKeyId);
584
601
  if (!recordKeyData) {
585
- throw new WaAppStateMissingKeyError(`missing mutation key ${keyIdToHex(recordKeyId)} for ${collection}`, recordKeyId, collection);
602
+ throw new WaAppStateMissingKeyError(`missing mutation key ${bytesToHex(recordKeyId)} for ${collection}`, recordKeyId, collection);
586
603
  }
587
604
  const decrypted = await this.crypto.decryptMutation({
588
605
  operation: operationCode,
@@ -608,14 +625,14 @@ export class WaAppStateSyncClient {
608
625
  };
609
626
  }));
610
627
  }
611
- async assertPatchMacsMatch(patch, collection, patchKeyData, patchVersion, nextHash, decryptedMutations) {
628
+ async assertPatchMacsMatch(patch, collection, patchKeyData, patchVersion, nextHash, valueMacs) {
612
629
  const snapshotMac = decodeProtoBytes(patch.snapshotMac, `patch.snapshotMac (${collection})`);
613
630
  const expectedSnapshotMac = await this.crypto.generateSnapshotMac(patchKeyData, nextHash, patchVersion, collection);
614
631
  if (!uint8Equal(expectedSnapshotMac, snapshotMac)) {
615
632
  throw new Error(`patch snapshot MAC mismatch for ${collection}`);
616
633
  }
617
634
  const patchMac = decodeProtoBytes(patch.patchMac, `patch.patchMac (${collection})`);
618
- const expectedPatchMac = await this.crypto.generatePatchMac(patchKeyData, snapshotMac, decryptedMutations.map((mutation) => mutation.valueMac), patchVersion, collection);
635
+ const expectedPatchMac = await this.crypto.generatePatchMac(patchKeyData, snapshotMac, valueMacs, patchVersion, collection);
619
636
  if (!uint8Equal(expectedPatchMac, patchMac)) {
620
637
  throw new Error(`patch MAC mismatch for ${collection}`);
621
638
  }
@@ -657,12 +674,15 @@ export class WaAppStateSyncClient {
657
674
  const patchVersion = snapshot.version + 1;
658
675
  const snapshotMac = await this.crypto.generateSnapshotMac(activeKey.keyData, nextState.hash, patchVersion, collection);
659
676
  const patchMac = await this.crypto.generatePatchMac(activeKey.keyData, snapshotMac, macMutations.map((item) => item.valueMac), patchVersion, collection);
677
+ const deviceIndex = this.resolveDeviceIndex();
678
+ const clientDebugData = this.buildPatchClientDebugData();
660
679
  const encodedPatch = proto.SyncdPatch.encode({
661
- version: { version: patchVersion },
662
680
  mutations: encryptedMutations,
663
681
  snapshotMac,
664
682
  patchMac,
665
- keyId: { id: activeKey.keyId }
683
+ keyId: { id: activeKey.keyId },
684
+ ...(deviceIndex === undefined ? {} : { deviceIndex }),
685
+ clientDebugData
666
686
  }).finish();
667
687
  return {
668
688
  encodedPatch,
@@ -674,13 +694,35 @@ export class WaAppStateSyncClient {
674
694
  }
675
695
  };
676
696
  }
697
+ resolveDeviceIndex() {
698
+ const meJid = this.getCurrentMeJid?.();
699
+ if (!meJid) {
700
+ return undefined;
701
+ }
702
+ try {
703
+ return parseSignalAddressFromJid(meJid).device;
704
+ }
705
+ catch (error) {
706
+ this.logger.debug('app-state could not parse device index from me jid', {
707
+ meJid
708
+ });
709
+ void error;
710
+ return undefined;
711
+ }
712
+ }
713
+ buildPatchClientDebugData() {
714
+ return proto.PatchDebugData.encode({
715
+ isSenderPrimary: false,
716
+ senderPlatform: proto.PatchDebugData.Platform.WEB
717
+ }).finish();
718
+ }
677
719
  async computeNextCollectionState(baseHash, baseMap, mutations, collection) {
678
720
  const indexValueMap = new Map(baseMap);
679
721
  const addValues = [];
680
722
  const removeValues = [];
681
723
  let missingRemoveCount = 0;
682
724
  for (const mutation of mutations) {
683
- const indexMacHex = keyIdToHex(mutation.indexMac);
725
+ const indexMacHex = bytesToHex(mutation.indexMac);
684
726
  const existing = indexValueMap.get(indexMacHex);
685
727
  if (mutation.operation === proto.SyncdMutation.SyncdOperation.REMOVE) {
686
728
  if (!existing) {
@@ -745,9 +787,33 @@ export class WaAppStateSyncClient {
745
787
  }
746
788
  return compacted;
747
789
  }
790
+ async preloadKeyData(keyIds) {
791
+ if (keyIds.length === 0) {
792
+ return;
793
+ }
794
+ const context = this.requireSyncContext();
795
+ const missingKeyIds = [];
796
+ const missingKeyHexes = new Set();
797
+ for (let index = 0; index < keyIds.length; index += 1) {
798
+ const keyId = keyIds[index];
799
+ const keyHex = bytesToHex(keyId);
800
+ if (context.keys.has(keyHex) || missingKeyHexes.has(keyHex)) {
801
+ continue;
802
+ }
803
+ missingKeyHexes.add(keyHex);
804
+ missingKeyIds.push(keyId);
805
+ }
806
+ if (missingKeyIds.length === 0) {
807
+ return;
808
+ }
809
+ const loadedKeyData = await this.store.getSyncKeyDataBatch(missingKeyIds);
810
+ for (let index = 0; index < missingKeyIds.length; index += 1) {
811
+ context.keys.set(bytesToHex(missingKeyIds[index]), loadedKeyData[index] ?? null);
812
+ }
813
+ }
748
814
  async getKeyData(keyId) {
749
815
  const context = this.requireSyncContext();
750
- const keyHex = keyIdToHex(keyId);
816
+ const keyHex = bytesToHex(keyId);
751
817
  if (context.keys.has(keyHex)) {
752
818
  return context.keys.get(keyHex) ?? null;
753
819
  }
@@ -768,6 +834,7 @@ export class WaAppStateSyncClient {
768
834
  setCollectionState(collection, version, hash, indexValueMap) {
769
835
  const context = this.requireSyncContext();
770
836
  context.collections.set(collection, {
837
+ initialized: true,
771
838
  version,
772
839
  hash,
773
840
  indexValueMap
@@ -1,13 +1,19 @@
1
1
  import { parseCollectionName } from './utils.js';
2
2
  import { proto } from '../proto.js';
3
3
  import { WA_APP_STATE_COLLECTION_STATES, WA_APP_STATE_ERROR_CODES, WA_IQ_TYPES, WA_NODE_TAGS } from '../protocol/constants.js';
4
- import { decodeNodeContentBase64OrBytes, findNodeChild, getNodeChildrenByTag } from '../transport/node/helpers.js';
4
+ import { decodeNodeContentBase64OrBytes, findNodeChildrenByTags, findNodeChild, getNodeChildrenByTag } from '../transport/node/helpers.js';
5
5
  export function parseSyncResponse(iqNode) {
6
6
  if (iqNode.tag !== WA_NODE_TAGS.IQ) {
7
7
  throw new Error(`invalid sync response tag ${iqNode.tag}`);
8
8
  }
9
9
  const syncNode = findNodeChild(iqNode, WA_NODE_TAGS.SYNC);
10
10
  if (!syncNode) {
11
+ if (iqNode.attrs.type === WA_IQ_TYPES.ERROR) {
12
+ const errorNode = findNodeChild(iqNode, WA_NODE_TAGS.ERROR);
13
+ const code = errorNode?.attrs.code ?? 'unknown';
14
+ const text = errorNode?.attrs.text ?? 'unknown';
15
+ throw new Error(`sync iq failed (${code}: ${text})`);
16
+ }
11
17
  throw new Error('sync response is missing <sync> node');
12
18
  }
13
19
  const payloads = [];
@@ -26,11 +32,16 @@ export function parseSyncResponse(iqNode) {
26
32
  }
27
33
  version = parsedVersion;
28
34
  }
29
- const patchesNode = findNodeChild(collectionNode, WA_NODE_TAGS.PATCHES);
30
- const patches = patchesNode
31
- ? getNodeChildrenByTag(patchesNode, WA_NODE_TAGS.PATCH).map((node) => proto.SyncdPatch.decode(decodeNodeContentBase64OrBytes(node.content, 'collection.patches.patch')))
32
- : [];
33
- const snapshotNode = findNodeChild(collectionNode, WA_NODE_TAGS.SNAPSHOT);
35
+ const [patchesNode, snapshotNode] = findNodeChildrenByTags(collectionNode, [
36
+ WA_NODE_TAGS.PATCHES,
37
+ WA_NODE_TAGS.SNAPSHOT
38
+ ]);
39
+ const patches = [];
40
+ if (patchesNode) {
41
+ for (const patchNode of getNodeChildrenByTag(patchesNode, WA_NODE_TAGS.PATCH)) {
42
+ patches.push(proto.SyncdPatch.decode(decodeNodeContentBase64OrBytes(patchNode.content, 'collection.patches.patch')));
43
+ }
44
+ }
34
45
  const snapshotReference = snapshotNode
35
46
  ? proto.ExternalBlobReference.decode(decodeNodeContentBase64OrBytes(snapshotNode.content, 'collection.snapshot'))
36
47
  : undefined;
@@ -11,10 +11,11 @@ export const APP_STATE_IV_LENGTH = 16;
11
11
  export const APP_STATE_LT_HASH_SIZE = 128;
12
12
  export const APP_STATE_POINT_SIZE = 2;
13
13
  export const APP_STATE_EMPTY_LT_HASH = new Uint8Array(APP_STATE_LT_HASH_SIZE);
14
- export const APP_STATE_DEFAULT_COLLECTIONS = [
14
+ export const APP_STATE_DEFAULT_COLLECTION_VERSION = 0;
15
+ export const APP_STATE_DEFAULT_COLLECTIONS = Object.freeze([
15
16
  WA_APP_STATE_COLLECTIONS.CRITICAL_UNBLOCK_LOW,
16
17
  WA_APP_STATE_COLLECTIONS.CRITICAL_BLOCK,
17
18
  WA_APP_STATE_COLLECTIONS.REGULAR_LOW,
18
19
  WA_APP_STATE_COLLECTIONS.REGULAR,
19
20
  WA_APP_STATE_COLLECTIONS.REGULAR_HIGH
20
- ];
21
+ ]);
@@ -1,31 +1,16 @@
1
1
  import { WA_APP_STATE_COLLECTIONS, WA_APP_STATE_KEY_TYPES } from '../protocol/constants.js';
2
- import { decodeProtoBytes } from '../util/base64.js';
3
- import { bytesToHex } from '../util/bytes.js';
4
- export function keyIdToHex(keyId) {
5
- return bytesToHex(keyId);
6
- }
2
+ import { decodeProtoBytes, intToBytes } from '../util/bytes.js';
3
+ const APP_STATE_COLLECTION_NAMES = new Set(Object.values(WA_APP_STATE_COLLECTIONS));
7
4
  export function parseCollectionName(value) {
8
- if (!value) {
9
- return null;
10
- }
11
- for (const collection of Object.values(WA_APP_STATE_COLLECTIONS)) {
12
- if (collection === value) {
13
- return collection;
14
- }
15
- }
16
- return null;
5
+ return value && APP_STATE_COLLECTION_NAMES.has(value) ? value : null;
17
6
  }
18
7
  export function keyDeviceId(keyId) {
19
- if (keyId.byteLength < 6) {
20
- return null;
21
- }
22
- return (keyId[0] << 8) | keyId[1];
8
+ return keyId.byteLength < 6 ? null : (keyId[0] << 8) | keyId[1];
23
9
  }
24
10
  export function keyEpoch(keyId) {
25
- if (keyId.byteLength < 6) {
26
- return -1;
27
- }
28
- return new DataView(keyId.buffer, keyId.byteOffset, keyId.byteLength).getUint32(2, false);
11
+ return keyId.byteLength < 6
12
+ ? -1
13
+ : keyId[2] * 16777216 + keyId[3] * 65536 + keyId[4] * 256 + keyId[5];
29
14
  }
30
15
  export function pickActiveSyncKey(keys) {
31
16
  let active = null;
@@ -52,11 +37,7 @@ export function pickActiveSyncKey(keys) {
52
37
  return active;
53
38
  }
54
39
  export function toNetworkOrder64(value) {
55
- const out = new Uint8Array(8);
56
- const view = new DataView(out.buffer);
57
- view.setUint32(0, Math.floor(value / 4294967296), false);
58
- view.setUint32(4, value >>> 0, false);
59
- return out;
40
+ return intToBytes(8, value);
60
41
  }
61
42
  export async function downloadExternalBlobReference(mediaTransfer, reference) {
62
43
  if (!reference.directPath) {