zapo-js 0.1.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 (585) hide show
  1. package/README.md +235 -0
  2. package/dist/appstate/WaAppStateCrypto.js +202 -0
  3. package/dist/appstate/WaAppStateSyncClient.js +808 -0
  4. package/dist/appstate/WaAppStateSyncResponseParser.js +71 -0
  5. package/dist/appstate/constants.js +23 -0
  6. package/dist/appstate/index.js +28 -0
  7. package/dist/appstate/store/sqlite.js +55 -0
  8. package/dist/appstate/types.js +2 -0
  9. package/dist/appstate/utils.js +84 -0
  10. package/dist/auth/WaAuthClient.js +266 -0
  11. package/dist/auth/flow/WaAuthCredentialsFlow.js +123 -0
  12. package/dist/auth/index.js +27 -0
  13. package/dist/auth/pairing/WaPairingCodeCrypto.js +75 -0
  14. package/dist/auth/pairing/WaPairingFlow.js +328 -0
  15. package/dist/auth/pairing/WaQrFlow.js +86 -0
  16. package/dist/auth/pairing/constants.js +5 -0
  17. package/dist/auth/types.js +2 -0
  18. package/dist/client/WaClient.js +749 -0
  19. package/dist/client/WaClientFactory.js +381 -0
  20. package/dist/client/coordinators/WaGroupCoordinator.js +191 -0
  21. package/dist/client/coordinators/WaIncomingNodeCoordinator.js +315 -0
  22. package/dist/client/coordinators/WaMessageDispatchCoordinator.js +1061 -0
  23. package/dist/client/coordinators/WaPassiveTasksCoordinator.js +200 -0
  24. package/dist/client/coordinators/WaRetryCoordinator.js +494 -0
  25. package/dist/client/coordinators/WaStreamControlCoordinator.js +123 -0
  26. package/dist/client/dirty.js +254 -0
  27. package/dist/client/events/chat.js +226 -0
  28. package/dist/client/events/group.js +410 -0
  29. package/dist/client/history-sync.js +122 -0
  30. package/dist/client/incoming.js +236 -0
  31. package/dist/client/index.js +5 -0
  32. package/dist/client/mailbox.js +49 -0
  33. package/dist/client/messages.js +152 -0
  34. package/dist/client/types.js +2 -0
  35. package/dist/crypto/core/constants.js +4 -0
  36. package/dist/crypto/core/encoding.js +29 -0
  37. package/dist/crypto/core/hkdf.js +26 -0
  38. package/dist/crypto/core/index.js +43 -0
  39. package/dist/crypto/core/keys.js +73 -0
  40. package/dist/crypto/core/nonce.js +18 -0
  41. package/dist/crypto/core/primitives.js +121 -0
  42. package/dist/crypto/core/random.js +32 -0
  43. package/dist/crypto/curves/Ed25519.js +42 -0
  44. package/dist/crypto/curves/X25519.js +64 -0
  45. package/dist/crypto/curves/constants.js +6 -0
  46. package/dist/crypto/curves/types.js +9 -0
  47. package/dist/crypto/index.js +22 -0
  48. package/dist/crypto/math/constants.js +44 -0
  49. package/dist/crypto/math/edwards.js +64 -0
  50. package/dist/crypto/math/le.js +20 -0
  51. package/dist/crypto/math/mod.js +38 -0
  52. package/dist/crypto/math/types.js +2 -0
  53. package/dist/esm/appstate/WaAppStateCrypto.js +198 -0
  54. package/dist/esm/appstate/WaAppStateSyncClient.js +803 -0
  55. package/dist/esm/appstate/WaAppStateSyncResponseParser.js +67 -0
  56. package/dist/esm/appstate/constants.js +20 -0
  57. package/dist/esm/appstate/index.js +6 -0
  58. package/dist/esm/appstate/store/sqlite.js +49 -0
  59. package/dist/esm/appstate/types.js +1 -0
  60. package/dist/esm/appstate/utils.js +75 -0
  61. package/dist/esm/auth/WaAuthClient.js +262 -0
  62. package/dist/esm/auth/flow/WaAuthCredentialsFlow.js +118 -0
  63. package/dist/esm/auth/index.js +5 -0
  64. package/dist/esm/auth/pairing/WaPairingCodeCrypto.js +71 -0
  65. package/dist/esm/auth/pairing/WaPairingFlow.js +324 -0
  66. package/dist/esm/auth/pairing/WaQrFlow.js +82 -0
  67. package/dist/esm/auth/pairing/constants.js +2 -0
  68. package/dist/esm/auth/types.js +1 -0
  69. package/dist/esm/client/WaClient.js +745 -0
  70. package/dist/esm/client/WaClientFactory.js +377 -0
  71. package/dist/esm/client/coordinators/WaGroupCoordinator.js +188 -0
  72. package/dist/esm/client/coordinators/WaIncomingNodeCoordinator.js +311 -0
  73. package/dist/esm/client/coordinators/WaMessageDispatchCoordinator.js +1057 -0
  74. package/dist/esm/client/coordinators/WaPassiveTasksCoordinator.js +196 -0
  75. package/dist/esm/client/coordinators/WaRetryCoordinator.js +490 -0
  76. package/dist/esm/client/coordinators/WaStreamControlCoordinator.js +120 -0
  77. package/dist/esm/client/dirty.js +250 -0
  78. package/dist/esm/client/events/chat.js +223 -0
  79. package/dist/esm/client/events/group.js +407 -0
  80. package/dist/esm/client/history-sync.js +119 -0
  81. package/dist/esm/client/incoming.js +227 -0
  82. package/dist/esm/client/index.js +1 -0
  83. package/dist/esm/client/mailbox.js +46 -0
  84. package/dist/esm/client/messages.js +148 -0
  85. package/dist/esm/client/types.js +1 -0
  86. package/dist/esm/crypto/core/constants.js +1 -0
  87. package/dist/esm/crypto/core/encoding.js +25 -0
  88. package/dist/esm/crypto/core/hkdf.js +22 -0
  89. package/dist/esm/crypto/core/index.js +11 -0
  90. package/dist/esm/crypto/core/keys.js +66 -0
  91. package/dist/esm/crypto/core/nonce.js +15 -0
  92. package/dist/esm/crypto/core/primitives.js +102 -0
  93. package/dist/esm/crypto/core/random.js +28 -0
  94. package/dist/esm/crypto/curves/Ed25519.js +38 -0
  95. package/dist/esm/crypto/curves/X25519.js +58 -0
  96. package/dist/esm/crypto/curves/constants.js +3 -0
  97. package/dist/esm/crypto/curves/types.js +6 -0
  98. package/dist/esm/crypto/index.js +3 -0
  99. package/dist/esm/crypto/math/constants.js +41 -0
  100. package/dist/esm/crypto/math/edwards.js +60 -0
  101. package/dist/esm/crypto/math/le.js +16 -0
  102. package/dist/esm/crypto/math/mod.js +31 -0
  103. package/dist/esm/crypto/math/types.js +1 -0
  104. package/dist/esm/index.js +6 -0
  105. package/dist/esm/infra/log/ConsoleLogger.js +40 -0
  106. package/dist/esm/infra/log/PinoLogger.js +73 -0
  107. package/dist/esm/infra/log/types.js +1 -0
  108. package/dist/esm/infra/perf/BoundedTaskQueue.js +62 -0
  109. package/dist/esm/media/WaMediaCrypto.js +224 -0
  110. package/dist/esm/media/WaMediaTransferClient.js +361 -0
  111. package/dist/esm/media/conn.js +33 -0
  112. package/dist/esm/media/constants.js +18 -0
  113. package/dist/esm/media/index.js +3 -0
  114. package/dist/esm/media/types.js +1 -0
  115. package/dist/esm/message/WaMessageClient.js +210 -0
  116. package/dist/esm/message/ack.js +46 -0
  117. package/dist/esm/message/content.js +20 -0
  118. package/dist/esm/message/device-sent.js +49 -0
  119. package/dist/esm/message/incoming.js +318 -0
  120. package/dist/esm/message/index.js +2 -0
  121. package/dist/esm/message/padding.js +20 -0
  122. package/dist/esm/message/phash.js +25 -0
  123. package/dist/esm/message/types.js +1 -0
  124. package/dist/esm/package.json +3 -0
  125. package/dist/esm/proto.js +3 -0
  126. package/dist/esm/protocol/appstate.js +34 -0
  127. package/dist/esm/protocol/auth.js +12 -0
  128. package/dist/esm/protocol/browser.js +41 -0
  129. package/dist/esm/protocol/constants.js +11 -0
  130. package/dist/esm/protocol/defaults.js +27 -0
  131. package/dist/esm/protocol/dirty.js +26 -0
  132. package/dist/esm/protocol/group.js +5 -0
  133. package/dist/esm/protocol/index.js +11 -0
  134. package/dist/esm/protocol/jid.js +94 -0
  135. package/dist/esm/protocol/media.js +20 -0
  136. package/dist/esm/protocol/message.js +16 -0
  137. package/dist/esm/protocol/nodes.js +83 -0
  138. package/dist/esm/protocol/notification.js +50 -0
  139. package/dist/esm/protocol/stream.js +60 -0
  140. package/dist/esm/retry/constants.js +20 -0
  141. package/dist/esm/retry/index.js +5 -0
  142. package/dist/esm/retry/outbound.js +83 -0
  143. package/dist/esm/retry/parse.js +130 -0
  144. package/dist/esm/retry/reason.js +50 -0
  145. package/dist/esm/retry/replay.js +177 -0
  146. package/dist/esm/retry/types.js +1 -0
  147. package/dist/esm/signal/api/SignalDeviceSyncApi.js +185 -0
  148. package/dist/esm/signal/api/SignalDigestSyncApi.js +179 -0
  149. package/dist/esm/signal/api/SignalIdentitySyncApi.js +111 -0
  150. package/dist/esm/signal/api/SignalMissingPreKeysSyncApi.js +141 -0
  151. package/dist/esm/signal/api/SignalRotateKeyApi.js +59 -0
  152. package/dist/esm/signal/api/SignalSessionSyncApi.js +187 -0
  153. package/dist/esm/signal/api/codec.js +23 -0
  154. package/dist/esm/signal/api/constants.js +9 -0
  155. package/dist/esm/signal/api/prekeys.js +9 -0
  156. package/dist/esm/signal/constants.js +16 -0
  157. package/dist/esm/signal/crypto/WaAdvSignature.js +60 -0
  158. package/dist/esm/signal/crypto/constants.js +8 -0
  159. package/dist/esm/signal/group/SenderKeyChain.js +97 -0
  160. package/dist/esm/signal/group/SenderKeyCodec.js +46 -0
  161. package/dist/esm/signal/group/SenderKeyManager.js +176 -0
  162. package/dist/esm/signal/index.js +11 -0
  163. package/dist/esm/signal/registration/keygen.js +31 -0
  164. package/dist/esm/signal/registration/utils.js +16 -0
  165. package/dist/esm/signal/session/SignalProtocol.js +122 -0
  166. package/dist/esm/signal/session/SignalRatchet.js +260 -0
  167. package/dist/esm/signal/session/SignalSerializer.js +63 -0
  168. package/dist/esm/signal/session/SignalSession.js +153 -0
  169. package/dist/esm/signal/store/sqlite.js +310 -0
  170. package/dist/esm/signal/types.js +1 -0
  171. package/dist/esm/store/contracts/appstate.store.js +1 -0
  172. package/dist/esm/store/contracts/auth.store.js +1 -0
  173. package/dist/esm/store/contracts/contact.store.js +1 -0
  174. package/dist/esm/store/contracts/device-list.store.js +1 -0
  175. package/dist/esm/store/contracts/message.store.js +1 -0
  176. package/dist/esm/store/contracts/participants.store.js +1 -0
  177. package/dist/esm/store/contracts/retry.store.js +1 -0
  178. package/dist/esm/store/contracts/sender-key.store.js +1 -0
  179. package/dist/esm/store/contracts/signal.store.js +1 -0
  180. package/dist/esm/store/contracts/thread.store.js +1 -0
  181. package/dist/esm/store/createStore.js +278 -0
  182. package/dist/esm/store/index.js +20 -0
  183. package/dist/esm/store/noop.store.js +43 -0
  184. package/dist/esm/store/providers/memory/appstate.store.js +101 -0
  185. package/dist/esm/store/providers/memory/contact.store.js +23 -0
  186. package/dist/esm/store/providers/memory/device-list.store.js +86 -0
  187. package/dist/esm/store/providers/memory/message.store.js +40 -0
  188. package/dist/esm/store/providers/memory/participants.store.js +61 -0
  189. package/dist/esm/store/providers/memory/retry.store.js +71 -0
  190. package/dist/esm/store/providers/memory/sender-key.store.js +88 -0
  191. package/dist/esm/store/providers/memory/signal.store.js +170 -0
  192. package/dist/esm/store/providers/memory/thread.store.js +34 -0
  193. package/dist/esm/store/providers/sqlite/BaseSqliteStore.js +37 -0
  194. package/dist/esm/store/providers/sqlite/appstate.store.js +169 -0
  195. package/dist/esm/store/providers/sqlite/auth.store.js +176 -0
  196. package/dist/esm/store/providers/sqlite/connection.js +240 -0
  197. package/dist/esm/store/providers/sqlite/contact.store.js +61 -0
  198. package/dist/esm/store/providers/sqlite/device-list.store.js +155 -0
  199. package/dist/esm/store/providers/sqlite/message.store.js +119 -0
  200. package/dist/esm/store/providers/sqlite/migrations.js +347 -0
  201. package/dist/esm/store/providers/sqlite/participants.store.js +85 -0
  202. package/dist/esm/store/providers/sqlite/retry.store.js +144 -0
  203. package/dist/esm/store/providers/sqlite/sender-key.store.js +203 -0
  204. package/dist/esm/store/providers/sqlite/signal.store.js +353 -0
  205. package/dist/esm/store/providers/sqlite/thread.store.js +72 -0
  206. package/dist/esm/store/types.js +1 -0
  207. package/dist/esm/transport/WaComms.js +527 -0
  208. package/dist/esm/transport/WaWebSocket.js +361 -0
  209. package/dist/esm/transport/binary/constants.js +96 -0
  210. package/dist/esm/transport/binary/decoder.js +275 -0
  211. package/dist/esm/transport/binary/encoder.js +210 -0
  212. package/dist/esm/transport/binary/index.js +4 -0
  213. package/dist/esm/transport/binary/tokens.js +1280 -0
  214. package/dist/esm/transport/index.js +6 -0
  215. package/dist/esm/transport/keepalive/WaKeepAlive.js +141 -0
  216. package/dist/esm/transport/node/WaNodeOrchestrator.js +143 -0
  217. package/dist/esm/transport/node/WaNodeTransport.js +64 -0
  218. package/dist/esm/transport/node/builders/accountSync.js +101 -0
  219. package/dist/esm/transport/node/builders/group.js +47 -0
  220. package/dist/esm/transport/node/builders/index.js +7 -0
  221. package/dist/esm/transport/node/builders/media.js +10 -0
  222. package/dist/esm/transport/node/builders/message.js +317 -0
  223. package/dist/esm/transport/node/builders/pairing.js +130 -0
  224. package/dist/esm/transport/node/builders/prekeys.js +102 -0
  225. package/dist/esm/transport/node/builders/retry.js +116 -0
  226. package/dist/esm/transport/node/helpers.js +37 -0
  227. package/dist/esm/transport/node/query.js +53 -0
  228. package/dist/esm/transport/node/xml.js +39 -0
  229. package/dist/esm/transport/noise/WaClientPayload.js +162 -0
  230. package/dist/esm/transport/noise/WaFrameCodec.js +121 -0
  231. package/dist/esm/transport/noise/WaNoiseCert.js +74 -0
  232. package/dist/esm/transport/noise/WaNoiseHandshake.js +57 -0
  233. package/dist/esm/transport/noise/WaNoiseSession.js +322 -0
  234. package/dist/esm/transport/noise/WaNoiseSocket.js +17 -0
  235. package/dist/esm/transport/noise/constants.js +8 -0
  236. package/dist/esm/transport/noise/types.js +1 -0
  237. package/dist/esm/transport/stream/parse.js +91 -0
  238. package/dist/esm/transport/types.js +1 -0
  239. package/dist/esm/util/async.js +5 -0
  240. package/dist/esm/util/base64.js +18 -0
  241. package/dist/esm/util/bytes.js +275 -0
  242. package/dist/esm/util/coercion.js +56 -0
  243. package/dist/esm/util/collections.js +27 -0
  244. package/dist/esm/util/primitives.js +32 -0
  245. package/dist/esm/util/runtime.js +15 -0
  246. package/dist/esm/util/signal-address.js +5 -0
  247. package/dist/index.js +52 -0
  248. package/dist/infra/log/ConsoleLogger.js +44 -0
  249. package/dist/infra/log/PinoLogger.js +111 -0
  250. package/dist/infra/log/types.js +2 -0
  251. package/dist/infra/perf/BoundedTaskQueue.js +67 -0
  252. package/dist/media/WaMediaCrypto.js +228 -0
  253. package/dist/media/WaMediaTransferClient.js +365 -0
  254. package/dist/media/conn.js +36 -0
  255. package/dist/media/constants.js +21 -0
  256. package/dist/media/index.js +9 -0
  257. package/dist/media/types.js +2 -0
  258. package/dist/message/WaMessageClient.js +214 -0
  259. package/dist/message/ack.js +52 -0
  260. package/dist/message/content.js +24 -0
  261. package/dist/message/device-sent.js +53 -0
  262. package/dist/message/incoming.js +321 -0
  263. package/dist/message/index.js +20 -0
  264. package/dist/message/padding.js +24 -0
  265. package/dist/message/phash.js +28 -0
  266. package/dist/message/types.js +2 -0
  267. package/dist/proto.js +5 -0
  268. package/dist/protocol/appstate.js +37 -0
  269. package/dist/protocol/auth.js +15 -0
  270. package/dist/protocol/browser.js +45 -0
  271. package/dist/protocol/constants.js +46 -0
  272. package/dist/protocol/defaults.js +30 -0
  273. package/dist/protocol/dirty.js +29 -0
  274. package/dist/protocol/group.js +8 -0
  275. package/dist/protocol/index.js +53 -0
  276. package/dist/protocol/jid.js +107 -0
  277. package/dist/protocol/media.js +24 -0
  278. package/dist/protocol/message.js +19 -0
  279. package/dist/protocol/nodes.js +86 -0
  280. package/dist/protocol/notification.js +53 -0
  281. package/dist/protocol/stream.js +63 -0
  282. package/dist/retry/constants.js +23 -0
  283. package/dist/retry/index.js +19 -0
  284. package/dist/retry/outbound.js +88 -0
  285. package/dist/retry/parse.js +133 -0
  286. package/dist/retry/reason.js +53 -0
  287. package/dist/retry/replay.js +181 -0
  288. package/dist/retry/types.js +2 -0
  289. package/dist/signal/api/SignalDeviceSyncApi.js +189 -0
  290. package/dist/signal/api/SignalDigestSyncApi.js +183 -0
  291. package/dist/signal/api/SignalIdentitySyncApi.js +115 -0
  292. package/dist/signal/api/SignalMissingPreKeysSyncApi.js +145 -0
  293. package/dist/signal/api/SignalRotateKeyApi.js +63 -0
  294. package/dist/signal/api/SignalSessionSyncApi.js +191 -0
  295. package/dist/signal/api/codec.js +27 -0
  296. package/dist/signal/api/constants.js +12 -0
  297. package/dist/signal/api/prekeys.js +16 -0
  298. package/dist/signal/constants.js +19 -0
  299. package/dist/signal/crypto/WaAdvSignature.js +72 -0
  300. package/dist/signal/crypto/constants.js +11 -0
  301. package/dist/signal/group/SenderKeyChain.js +101 -0
  302. package/dist/signal/group/SenderKeyCodec.js +50 -0
  303. package/dist/signal/group/SenderKeyManager.js +180 -0
  304. package/dist/signal/index.js +29 -0
  305. package/dist/signal/registration/keygen.js +37 -0
  306. package/dist/signal/registration/utils.js +19 -0
  307. package/dist/signal/session/SignalProtocol.js +126 -0
  308. package/dist/signal/session/SignalRatchet.js +268 -0
  309. package/dist/signal/session/SignalSerializer.js +69 -0
  310. package/dist/signal/session/SignalSession.js +165 -0
  311. package/dist/signal/store/sqlite.js +324 -0
  312. package/dist/signal/types.js +2 -0
  313. package/dist/store/contracts/appstate.store.js +2 -0
  314. package/dist/store/contracts/auth.store.js +2 -0
  315. package/dist/store/contracts/contact.store.js +2 -0
  316. package/dist/store/contracts/device-list.store.js +2 -0
  317. package/dist/store/contracts/message.store.js +2 -0
  318. package/dist/store/contracts/participants.store.js +2 -0
  319. package/dist/store/contracts/retry.store.js +2 -0
  320. package/dist/store/contracts/sender-key.store.js +2 -0
  321. package/dist/store/contracts/signal.store.js +2 -0
  322. package/dist/store/contracts/thread.store.js +2 -0
  323. package/dist/store/createStore.js +281 -0
  324. package/dist/store/index.js +43 -0
  325. package/dist/store/noop.store.js +46 -0
  326. package/dist/store/providers/memory/appstate.store.js +105 -0
  327. package/dist/store/providers/memory/contact.store.js +27 -0
  328. package/dist/store/providers/memory/device-list.store.js +90 -0
  329. package/dist/store/providers/memory/message.store.js +44 -0
  330. package/dist/store/providers/memory/participants.store.js +65 -0
  331. package/dist/store/providers/memory/retry.store.js +75 -0
  332. package/dist/store/providers/memory/sender-key.store.js +92 -0
  333. package/dist/store/providers/memory/signal.store.js +174 -0
  334. package/dist/store/providers/memory/thread.store.js +38 -0
  335. package/dist/store/providers/sqlite/BaseSqliteStore.js +41 -0
  336. package/dist/store/providers/sqlite/appstate.store.js +173 -0
  337. package/dist/store/providers/sqlite/auth.store.js +180 -0
  338. package/dist/store/providers/sqlite/connection.js +276 -0
  339. package/dist/store/providers/sqlite/contact.store.js +65 -0
  340. package/dist/store/providers/sqlite/device-list.store.js +159 -0
  341. package/dist/store/providers/sqlite/message.store.js +123 -0
  342. package/dist/store/providers/sqlite/migrations.js +350 -0
  343. package/dist/store/providers/sqlite/participants.store.js +89 -0
  344. package/dist/store/providers/sqlite/retry.store.js +148 -0
  345. package/dist/store/providers/sqlite/sender-key.store.js +207 -0
  346. package/dist/store/providers/sqlite/signal.store.js +357 -0
  347. package/dist/store/providers/sqlite/thread.store.js +76 -0
  348. package/dist/store/types.js +2 -0
  349. package/dist/transport/WaComms.js +531 -0
  350. package/dist/transport/WaWebSocket.js +365 -0
  351. package/dist/transport/binary/constants.js +99 -0
  352. package/dist/transport/binary/decoder.js +279 -0
  353. package/dist/transport/binary/encoder.js +214 -0
  354. package/dist/transport/binary/index.js +23 -0
  355. package/dist/transport/binary/tokens.js +1283 -0
  356. package/dist/transport/index.js +18 -0
  357. package/dist/transport/keepalive/WaKeepAlive.js +145 -0
  358. package/dist/transport/node/WaNodeOrchestrator.js +147 -0
  359. package/dist/transport/node/WaNodeTransport.js +68 -0
  360. package/dist/transport/node/builders/accountSync.js +110 -0
  361. package/dist/transport/node/builders/group.js +52 -0
  362. package/dist/transport/node/builders/index.js +39 -0
  363. package/dist/transport/node/builders/media.js +13 -0
  364. package/dist/transport/node/builders/message.js +328 -0
  365. package/dist/transport/node/builders/pairing.js +137 -0
  366. package/dist/transport/node/builders/prekeys.js +107 -0
  367. package/dist/transport/node/builders/retry.js +119 -0
  368. package/dist/transport/node/helpers.js +46 -0
  369. package/dist/transport/node/query.js +59 -0
  370. package/dist/transport/node/xml.js +42 -0
  371. package/dist/transport/noise/WaClientPayload.js +166 -0
  372. package/dist/transport/noise/WaFrameCodec.js +125 -0
  373. package/dist/transport/noise/WaNoiseCert.js +77 -0
  374. package/dist/transport/noise/WaNoiseHandshake.js +61 -0
  375. package/dist/transport/noise/WaNoiseSession.js +326 -0
  376. package/dist/transport/noise/WaNoiseSocket.js +21 -0
  377. package/dist/transport/noise/constants.js +11 -0
  378. package/dist/transport/noise/types.js +2 -0
  379. package/dist/transport/stream/parse.js +97 -0
  380. package/dist/transport/types.js +2 -0
  381. package/dist/types/appstate/WaAppStateCrypto.d.ts +59 -0
  382. package/dist/types/appstate/WaAppStateSyncClient.d.ts +63 -0
  383. package/dist/types/appstate/WaAppStateSyncResponseParser.d.ts +12 -0
  384. package/dist/types/appstate/constants.d.ts +14 -0
  385. package/dist/types/appstate/index.d.ts +7 -0
  386. package/dist/types/appstate/store/sqlite.d.ts +21 -0
  387. package/dist/types/appstate/types.d.ts +66 -0
  388. package/dist/types/appstate/utils.d.ts +10 -0
  389. package/dist/types/auth/WaAuthClient.d.ts +61 -0
  390. package/dist/types/auth/flow/WaAuthCredentialsFlow.d.ts +14 -0
  391. package/dist/types/auth/index.d.ts +6 -0
  392. package/dist/types/auth/pairing/WaPairingCodeCrypto.d.ts +17 -0
  393. package/dist/types/auth/pairing/WaPairingFlow.d.ts +48 -0
  394. package/dist/types/auth/pairing/WaQrFlow.d.ts +23 -0
  395. package/dist/types/auth/pairing/constants.d.ts +2 -0
  396. package/dist/types/auth/types.d.ts +48 -0
  397. package/dist/types/client/WaClient.d.ts +97 -0
  398. package/dist/types/client/WaClientFactory.d.ts +83 -0
  399. package/dist/types/client/coordinators/WaGroupCoordinator.d.ts +48 -0
  400. package/dist/types/client/coordinators/WaIncomingNodeCoordinator.d.ts +60 -0
  401. package/dist/types/client/coordinators/WaMessageDispatchCoordinator.d.ts +90 -0
  402. package/dist/types/client/coordinators/WaPassiveTasksCoordinator.d.ts +43 -0
  403. package/dist/types/client/coordinators/WaRetryCoordinator.d.ts +61 -0
  404. package/dist/types/client/coordinators/WaStreamControlCoordinator.d.ts +17 -0
  405. package/dist/types/client/dirty.d.ts +17 -0
  406. package/dist/types/client/events/chat.d.ts +3 -0
  407. package/dist/types/client/events/group.d.ts +7 -0
  408. package/dist/types/client/history-sync.d.ts +17 -0
  409. package/dist/types/client/incoming.d.ts +35 -0
  410. package/dist/types/client/index.d.ts +2 -0
  411. package/dist/types/client/mailbox.d.ts +12 -0
  412. package/dist/types/client/messages.d.ts +17 -0
  413. package/dist/types/client/types.d.ts +235 -0
  414. package/dist/types/crypto/core/constants.d.ts +1 -0
  415. package/dist/types/crypto/core/encoding.d.ts +11 -0
  416. package/dist/types/crypto/core/hkdf.d.ts +8 -0
  417. package/dist/types/crypto/core/index.d.ts +11 -0
  418. package/dist/types/crypto/core/keys.d.ts +20 -0
  419. package/dist/types/crypto/core/nonce.d.ts +5 -0
  420. package/dist/types/crypto/core/primitives.d.ts +25 -0
  421. package/dist/types/crypto/core/random.d.ts +8 -0
  422. package/dist/types/crypto/curves/Ed25519.d.ts +7 -0
  423. package/dist/types/crypto/curves/X25519.d.ts +8 -0
  424. package/dist/types/crypto/curves/constants.d.ts +2 -0
  425. package/dist/types/crypto/curves/types.d.ts +10 -0
  426. package/dist/types/crypto/index.d.ts +3 -0
  427. package/dist/types/crypto/math/constants.d.ts +7 -0
  428. package/dist/types/crypto/math/edwards.d.ts +3 -0
  429. package/dist/types/crypto/math/le.d.ts +2 -0
  430. package/dist/types/crypto/math/mod.d.ts +5 -0
  431. package/dist/types/crypto/math/types.d.ts +6 -0
  432. package/dist/types/index.d.ts +10 -0
  433. package/dist/types/infra/log/ConsoleLogger.d.ts +11 -0
  434. package/dist/types/infra/log/PinoLogger.d.ts +30 -0
  435. package/dist/types/infra/log/types.d.ts +9 -0
  436. package/dist/types/infra/perf/BoundedTaskQueue.d.ts +19 -0
  437. package/dist/types/media/WaMediaCrypto.d.ts +12 -0
  438. package/dist/types/media/WaMediaTransferClient.d.ts +81 -0
  439. package/dist/types/media/conn.d.ts +3 -0
  440. package/dist/types/media/constants.d.ts +10 -0
  441. package/dist/types/media/index.d.ts +4 -0
  442. package/dist/types/media/types.d.ts +56 -0
  443. package/dist/types/message/WaMessageClient.d.ts +29 -0
  444. package/dist/types/message/ack.d.ts +5 -0
  445. package/dist/types/message/content.d.ts +4 -0
  446. package/dist/types/message/device-sent.d.ts +3 -0
  447. package/dist/types/message/incoming.d.ts +18 -0
  448. package/dist/types/message/index.d.ts +2 -0
  449. package/dist/types/message/padding.d.ts +2 -0
  450. package/dist/types/message/phash.d.ts +1 -0
  451. package/dist/types/message/types.d.ts +58 -0
  452. package/dist/types/proto.d.ts +2 -0
  453. package/dist/types/protocol/appstate.d.ts +34 -0
  454. package/dist/types/protocol/auth.d.ts +12 -0
  455. package/dist/types/protocol/browser.d.ts +22 -0
  456. package/dist/types/protocol/constants.d.ts +11 -0
  457. package/dist/types/protocol/defaults.d.ts +26 -0
  458. package/dist/types/protocol/dirty.d.ts +15 -0
  459. package/dist/types/protocol/group.d.ts +6 -0
  460. package/dist/types/protocol/index.d.ts +11 -0
  461. package/dist/types/protocol/jid.d.ts +19 -0
  462. package/dist/types/protocol/media.d.ts +15 -0
  463. package/dist/types/protocol/message.d.ts +16 -0
  464. package/dist/types/protocol/nodes.d.ts +83 -0
  465. package/dist/types/protocol/notification.d.ts +50 -0
  466. package/dist/types/protocol/stream.d.ts +60 -0
  467. package/dist/types/retry/constants.d.ts +21 -0
  468. package/dist/types/retry/index.d.ts +7 -0
  469. package/dist/types/retry/outbound.d.ts +4 -0
  470. package/dist/types/retry/parse.d.ts +3 -0
  471. package/dist/types/retry/reason.d.ts +2 -0
  472. package/dist/types/retry/replay.d.ts +30 -0
  473. package/dist/types/retry/types.d.ts +70 -0
  474. package/dist/types/signal/api/SignalDeviceSyncApi.d.ts +31 -0
  475. package/dist/types/signal/api/SignalDigestSyncApi.d.ts +27 -0
  476. package/dist/types/signal/api/SignalIdentitySyncApi.d.ts +26 -0
  477. package/dist/types/signal/api/SignalMissingPreKeysSyncApi.d.ts +39 -0
  478. package/dist/types/signal/api/SignalRotateKeyApi.d.ts +22 -0
  479. package/dist/types/signal/api/SignalSessionSyncApi.d.ts +38 -0
  480. package/dist/types/signal/api/codec.d.ts +3 -0
  481. package/dist/types/signal/api/constants.d.ts +9 -0
  482. package/dist/types/signal/api/prekeys.d.ts +6 -0
  483. package/dist/types/signal/constants.d.ts +14 -0
  484. package/dist/types/signal/crypto/WaAdvSignature.d.ts +7 -0
  485. package/dist/types/signal/crypto/constants.d.ts +5 -0
  486. package/dist/types/signal/group/SenderKeyChain.d.ts +11 -0
  487. package/dist/types/signal/group/SenderKeyCodec.d.ts +14 -0
  488. package/dist/types/signal/group/SenderKeyManager.d.ts +22 -0
  489. package/dist/types/signal/index.d.ts +12 -0
  490. package/dist/types/signal/registration/keygen.d.ts +5 -0
  491. package/dist/types/signal/registration/utils.d.ts +9 -0
  492. package/dist/types/signal/session/SignalProtocol.d.ts +22 -0
  493. package/dist/types/signal/session/SignalRatchet.d.ts +25 -0
  494. package/dist/types/signal/session/SignalSerializer.d.ts +6 -0
  495. package/dist/types/signal/session/SignalSession.d.ts +43 -0
  496. package/dist/types/signal/store/sqlite.d.ts +72 -0
  497. package/dist/types/signal/types.d.ts +110 -0
  498. package/dist/types/store/contracts/appstate.store.d.ts +22 -0
  499. package/dist/types/store/contracts/auth.store.d.ts +6 -0
  500. package/dist/types/store/contracts/contact.store.d.ts +14 -0
  501. package/dist/types/store/contracts/device-list.store.d.ts +16 -0
  502. package/dist/types/store/contracts/message.store.d.ts +18 -0
  503. package/dist/types/store/contracts/participants.store.d.ts +14 -0
  504. package/dist/types/store/contracts/retry.store.d.ts +11 -0
  505. package/dist/types/store/contracts/sender-key.store.d.ts +16 -0
  506. package/dist/types/store/contracts/signal.store.d.ts +31 -0
  507. package/dist/types/store/contracts/thread.store.d.ts +17 -0
  508. package/dist/types/store/createStore.d.ts +2 -0
  509. package/dist/types/store/index.d.ts +31 -0
  510. package/dist/types/store/noop.store.d.ts +10 -0
  511. package/dist/types/store/providers/memory/appstate.store.d.ts +21 -0
  512. package/dist/types/store/providers/memory/contact.store.d.ts +13 -0
  513. package/dist/types/store/providers/memory/device-list.store.d.ts +20 -0
  514. package/dist/types/store/providers/memory/message.store.d.ts +14 -0
  515. package/dist/types/store/providers/memory/participants.store.d.ts +18 -0
  516. package/dist/types/store/providers/memory/retry.store.d.ts +18 -0
  517. package/dist/types/store/providers/memory/sender-key.store.d.ts +28 -0
  518. package/dist/types/store/providers/memory/signal.store.d.ts +51 -0
  519. package/dist/types/store/providers/memory/thread.store.d.ts +14 -0
  520. package/dist/types/store/providers/sqlite/BaseSqliteStore.d.ts +12 -0
  521. package/dist/types/store/providers/sqlite/appstate.store.d.ts +15 -0
  522. package/dist/types/store/providers/sqlite/auth.store.d.ts +10 -0
  523. package/dist/types/store/providers/sqlite/connection.d.ts +10 -0
  524. package/dist/types/store/providers/sqlite/contact.store.d.ts +10 -0
  525. package/dist/types/store/providers/sqlite/device-list.store.d.ts +18 -0
  526. package/dist/types/store/providers/sqlite/message.store.d.ts +11 -0
  527. package/dist/types/store/providers/sqlite/migrations.d.ts +3 -0
  528. package/dist/types/store/providers/sqlite/participants.store.d.ts +13 -0
  529. package/dist/types/store/providers/sqlite/retry.store.d.ts +16 -0
  530. package/dist/types/store/providers/sqlite/sender-key.store.d.ts +25 -0
  531. package/dist/types/store/providers/sqlite/signal.store.d.ts +46 -0
  532. package/dist/types/store/providers/sqlite/thread.store.d.ts +11 -0
  533. package/dist/types/store/types.d.ts +103 -0
  534. package/dist/types/transport/WaComms.d.ts +61 -0
  535. package/dist/types/transport/WaWebSocket.d.ts +36 -0
  536. package/dist/types/transport/binary/constants.d.ts +49 -0
  537. package/dist/types/transport/binary/decoder.d.ts +3 -0
  538. package/dist/types/transport/binary/encoder.d.ts +3 -0
  539. package/dist/types/transport/binary/index.d.ts +4 -0
  540. package/dist/types/transport/binary/tokens.d.ts +11 -0
  541. package/dist/types/transport/index.d.ts +7 -0
  542. package/dist/types/transport/keepalive/WaKeepAlive.d.ts +39 -0
  543. package/dist/types/transport/node/WaNodeOrchestrator.d.ts +28 -0
  544. package/dist/types/transport/node/WaNodeTransport.d.ts +22 -0
  545. package/dist/types/transport/node/builders/accountSync.d.ts +11 -0
  546. package/dist/types/transport/node/builders/group.d.ts +16 -0
  547. package/dist/types/transport/node/builders/index.d.ts +7 -0
  548. package/dist/types/transport/node/builders/media.d.ts +2 -0
  549. package/dist/types/transport/node/builders/message.d.ts +52 -0
  550. package/dist/types/transport/node/builders/pairing.d.ts +18 -0
  551. package/dist/types/transport/node/builders/prekeys.d.ts +5 -0
  552. package/dist/types/transport/node/builders/retry.d.ts +18 -0
  553. package/dist/types/transport/node/helpers.d.ts +8 -0
  554. package/dist/types/transport/node/query.d.ts +10 -0
  555. package/dist/types/transport/node/xml.d.ts +2 -0
  556. package/dist/types/transport/noise/WaClientPayload.d.ts +3 -0
  557. package/dist/types/transport/noise/WaFrameCodec.d.ts +9 -0
  558. package/dist/types/transport/noise/WaNoiseCert.d.ts +1 -0
  559. package/dist/types/transport/noise/WaNoiseHandshake.d.ts +14 -0
  560. package/dist/types/transport/noise/WaNoiseSession.d.ts +33 -0
  561. package/dist/types/transport/noise/WaNoiseSocket.d.ts +10 -0
  562. package/dist/types/transport/noise/constants.d.ts +7 -0
  563. package/dist/types/transport/noise/types.d.ts +23 -0
  564. package/dist/types/transport/stream/parse.d.ts +23 -0
  565. package/dist/types/transport/types.d.ts +71 -0
  566. package/dist/types/util/async.d.ts +1 -0
  567. package/dist/types/util/base64.d.ts +4 -0
  568. package/dist/types/util/bytes.d.ts +28 -0
  569. package/dist/types/util/coercion.d.ts +8 -0
  570. package/dist/types/util/collections.d.ts +3 -0
  571. package/dist/types/util/primitives.d.ts +7 -0
  572. package/dist/types/util/runtime.d.ts +2 -0
  573. package/dist/types/util/signal-address.d.ts +2 -0
  574. package/dist/util/async.js +8 -0
  575. package/dist/util/base64.js +24 -0
  576. package/dist/util/bytes.js +291 -0
  577. package/dist/util/coercion.js +66 -0
  578. package/dist/util/collections.js +32 -0
  579. package/dist/util/primitives.js +37 -0
  580. package/dist/util/runtime.js +19 -0
  581. package/dist/util/signal-address.js +8 -0
  582. package/package.json +150 -0
  583. package/proto/index.d.ts +10861 -0
  584. package/proto/index.js +1 -0
  585. package/scripts/check-node-version.cjs +55 -0
@@ -0,0 +1,808 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.WaAppStateSyncClient = exports.WaAppStateMissingKeyError = void 0;
4
+ const constants_1 = require("./constants");
5
+ const utils_1 = require("./utils");
6
+ const WaAppStateCrypto_1 = require("./WaAppStateCrypto");
7
+ const WaAppStateSyncResponseParser_1 = require("./WaAppStateSyncResponseParser");
8
+ const _proto_1 = require("../proto.js");
9
+ const constants_2 = require("../protocol/constants");
10
+ const base64_1 = require("../util/base64");
11
+ const bytes_1 = require("../util/bytes");
12
+ const primitives_1 = require("../util/primitives");
13
+ class WaAppStateMissingKeyError extends Error {
14
+ constructor(message, keyId, collection) {
15
+ super(message);
16
+ this.keyId = keyId;
17
+ this.collection = collection;
18
+ this.name = 'WaAppStateMissingKeyError';
19
+ }
20
+ }
21
+ exports.WaAppStateMissingKeyError = WaAppStateMissingKeyError;
22
+ class WaAppStateSyncClient {
23
+ constructor(options) {
24
+ this.logger = options.logger;
25
+ this.query = options.query;
26
+ this.store = options.store;
27
+ this.hostDomain = options.hostDomain ?? constants_2.WA_DEFAULTS.HOST_DOMAIN;
28
+ this.defaultTimeoutMs = options.defaultTimeoutMs ?? constants_2.WA_DEFAULTS.APP_STATE_SYNC_TIMEOUT_MS;
29
+ this.onMissingKeys = options.onMissingKeys;
30
+ this.crypto = new WaAppStateCrypto_1.WaAppStateCrypto();
31
+ this.syncContext = null;
32
+ this.syncPromise = null;
33
+ }
34
+ async exportState() {
35
+ this.logger.trace('app-state export requested');
36
+ return this.store.exportData();
37
+ }
38
+ async importSyncKeys(keys) {
39
+ this.logger.debug('app-state importing sync keys', { count: keys.length });
40
+ const inserted = await this.store.upsertSyncKeys(keys);
41
+ if (inserted > 0) {
42
+ this.crypto.clearCache();
43
+ this.logger.info('app-state sync keys persisted', { inserted });
44
+ }
45
+ return inserted;
46
+ }
47
+ async importSyncKeyShare(share) {
48
+ const keys = [];
49
+ for (const item of share.keys ?? []) {
50
+ const keyId = (0, base64_1.decodeProtoBytes)(item.keyId?.keyId, 'appStateSyncKeyShare.keys[].keyId.keyId');
51
+ if (!item.keyData?.keyData) {
52
+ this.logger.debug('app-state sync key share entry missing key data', {
53
+ keyId: (0, utils_1.keyIdToHex)(keyId)
54
+ });
55
+ continue;
56
+ }
57
+ const keyData = (0, base64_1.decodeProtoBytes)(item.keyData?.keyData, 'appStateSyncKeyShare.keys[].keyData.keyData');
58
+ keys.push({
59
+ keyId,
60
+ keyData,
61
+ timestamp: item.keyData?.timestamp === null || item.keyData?.timestamp === undefined
62
+ ? Date.now()
63
+ : this.normalizeProtoLong(item.keyData?.timestamp, 'appStateSyncKeyShare.keys[].keyData.timestamp'),
64
+ fingerprint: item.keyData?.fingerprint ?? undefined
65
+ });
66
+ }
67
+ return this.importSyncKeys(keys);
68
+ }
69
+ async sync(options = {}) {
70
+ if (this.syncPromise) {
71
+ this.logger.debug('app-state sync already in flight, joining existing run');
72
+ return this.syncPromise;
73
+ }
74
+ const inFlight = this.syncOnce(options);
75
+ this.syncPromise = inFlight;
76
+ try {
77
+ return await inFlight;
78
+ }
79
+ finally {
80
+ if (this.syncPromise === inFlight) {
81
+ this.syncPromise = null;
82
+ }
83
+ }
84
+ }
85
+ async syncOnce(options = {}) {
86
+ const context = {
87
+ keys: new Map(),
88
+ collections: new Map(),
89
+ dirtyCollections: new Set()
90
+ };
91
+ this.syncContext = context;
92
+ const collections = [
93
+ ...new Set(options.collections ?? constants_1.APP_STATE_DEFAULT_COLLECTIONS)
94
+ ];
95
+ try {
96
+ this.logger.info('app-state sync start', {
97
+ collections: collections.length,
98
+ pendingMutations: options.pendingMutations?.length ?? 0
99
+ });
100
+ const pendingByCollection = this.groupPendingMutations(options.pendingMutations ?? []);
101
+ const resultMap = new Map();
102
+ let stateChanged = false;
103
+ let collectionsToSync = [...collections];
104
+ const missingKeysHandler = options.onMissingKeys ?? this.onMissingKeys;
105
+ const maxSyncIterations = 5;
106
+ let syncIteration = 0;
107
+ while (collectionsToSync.length > 0) {
108
+ syncIteration += 1;
109
+ if (syncIteration > maxSyncIterations) {
110
+ this.logger.warn('app-state sync reached max iterations', {
111
+ maxSyncIterations,
112
+ remainingCollections: collectionsToSync
113
+ });
114
+ for (const collection of collectionsToSync) {
115
+ resultMap.set(collection, {
116
+ collection,
117
+ state: constants_2.WA_APP_STATE_COLLECTION_STATES.ERROR_RETRY
118
+ });
119
+ }
120
+ break;
121
+ }
122
+ const round = await this.syncCollectionsRound(collectionsToSync, pendingByCollection, options);
123
+ stateChanged = stateChanged || round.stateChanged;
124
+ for (const result of round.results) {
125
+ resultMap.set(result.collection, result);
126
+ }
127
+ if (missingKeysHandler &&
128
+ round.missingKeyIds.length > 0 &&
129
+ round.blockedCollections.length > 0) {
130
+ await this.notifyMissingKeys({
131
+ onMissingKeys: missingKeysHandler,
132
+ keyIds: round.missingKeyIds,
133
+ collections: round.blockedCollections
134
+ });
135
+ }
136
+ collectionsToSync = [...round.collectionsToRefetch];
137
+ if (collectionsToSync.length > 0) {
138
+ this.logger.debug('app-state scheduling refetch for collections', {
139
+ iteration: syncIteration,
140
+ collections: collectionsToSync
141
+ });
142
+ }
143
+ }
144
+ if (stateChanged && context.dirtyCollections.size > 0) {
145
+ await this.persistCollectionUpdates();
146
+ this.logger.info('app-state sync persisted updated state');
147
+ }
148
+ const orderedResults = collections.map((collection) => resultMap.get(collection) ?? {
149
+ collection,
150
+ state: constants_2.WA_APP_STATE_COLLECTION_STATES.ERROR_RETRY
151
+ });
152
+ this.logger.info('app-state sync finished', {
153
+ collections: orderedResults.length,
154
+ stateChanged
155
+ });
156
+ return { collections: orderedResults };
157
+ }
158
+ finally {
159
+ if (this.syncContext === context) {
160
+ this.syncContext = null;
161
+ }
162
+ }
163
+ }
164
+ async syncCollectionsRound(collections, pendingByCollection, options) {
165
+ const prepared = await this.prepareSyncRoundRequest(collections, pendingByCollection);
166
+ const iqNode = this.buildSyncIqNode(prepared.collectionNodes);
167
+ const payloadByCollection = await this.fetchSyncPayloadByCollection(iqNode, options.timeoutMs ?? this.defaultTimeoutMs);
168
+ const collectionOutcomes = await Promise.all(collections.map((collection) => this.processCollectionRound({
169
+ collection,
170
+ payloadByCollection,
171
+ pendingByCollection,
172
+ options,
173
+ outgoingContexts: prepared.outgoingContexts,
174
+ skippedUploadCollections: prepared.skippedUploadCollections
175
+ })));
176
+ return {
177
+ results: collectionOutcomes.map((entry) => entry.result),
178
+ collectionsToRefetch: collectionOutcomes
179
+ .filter((entry) => entry.shouldRefetch)
180
+ .map((entry) => entry.collection),
181
+ stateChanged: collectionOutcomes.some((entry) => entry.stateChanged),
182
+ missingKeyIds: this.collectDistinctMissingKeyIds(collectionOutcomes
183
+ .map((entry) => entry.missingKeyId)
184
+ .filter((value) => value !== null)),
185
+ blockedCollections: collectionOutcomes
186
+ .filter((entry) => entry.result.state === constants_2.WA_APP_STATE_COLLECTION_STATES.BLOCKED)
187
+ .map((entry) => entry.collection)
188
+ };
189
+ }
190
+ async prepareSyncRoundRequest(collections, pendingByCollection) {
191
+ const requests = await Promise.all(collections.map((collection) => this.buildCollectionSyncRequest(collection, pendingByCollection)));
192
+ const outgoingContexts = new Map();
193
+ const skippedUploadCollections = new Set();
194
+ for (const request of requests) {
195
+ if (request.outgoingContext) {
196
+ outgoingContexts.set(request.collection, request.outgoingContext);
197
+ }
198
+ if (request.skippedUpload) {
199
+ skippedUploadCollections.add(request.collection);
200
+ }
201
+ }
202
+ return {
203
+ collectionNodes: requests.map((request) => request.node),
204
+ outgoingContexts,
205
+ skippedUploadCollections
206
+ };
207
+ }
208
+ async buildCollectionSyncRequest(collection, pendingByCollection) {
209
+ const collectionState = await this.getCollectionState(collection);
210
+ const hasPersistedState = collectionState.version > 0 ||
211
+ collectionState.indexValueMap.size > 0 ||
212
+ !(0, bytes_1.uint8Equal)(collectionState.hash, constants_1.APP_STATE_EMPTY_LT_HASH);
213
+ const attrs = {
214
+ name: collection
215
+ };
216
+ if (hasPersistedState) {
217
+ attrs.version = String(collectionState.version);
218
+ }
219
+ else {
220
+ attrs.return_snapshot = 'true';
221
+ }
222
+ const children = [];
223
+ const pendingMutations = pendingByCollection.get(collection) ?? [];
224
+ let outgoingContext;
225
+ let skippedUpload = false;
226
+ if (pendingMutations.length > 0) {
227
+ if (!hasPersistedState) {
228
+ skippedUpload = true;
229
+ this.logger.debug('app-state skipped outgoing patch upload until snapshot bootstrap', {
230
+ collection,
231
+ pendingMutations: pendingMutations.length
232
+ });
233
+ }
234
+ else {
235
+ const outgoing = await this.buildOutgoingPatch(collection, collectionState, pendingMutations);
236
+ outgoingContext = outgoing.context;
237
+ children.push({
238
+ tag: constants_2.WA_NODE_TAGS.PATCH,
239
+ attrs: {},
240
+ content: outgoing.encodedPatch
241
+ });
242
+ }
243
+ }
244
+ return {
245
+ collection,
246
+ outgoingContext,
247
+ skippedUpload,
248
+ node: {
249
+ tag: constants_2.WA_NODE_TAGS.COLLECTION,
250
+ attrs,
251
+ content: children.length > 0 ? children : undefined
252
+ }
253
+ };
254
+ }
255
+ buildSyncIqNode(collectionNodes) {
256
+ return {
257
+ tag: constants_2.WA_NODE_TAGS.IQ,
258
+ attrs: {
259
+ to: this.hostDomain,
260
+ type: constants_2.WA_IQ_TYPES.SET,
261
+ xmlns: constants_2.WA_XMLNS.APP_STATE_SYNC
262
+ },
263
+ content: [
264
+ {
265
+ tag: constants_2.WA_NODE_TAGS.SYNC,
266
+ attrs: {},
267
+ content: collectionNodes
268
+ }
269
+ ]
270
+ };
271
+ }
272
+ async fetchSyncPayloadByCollection(iqNode, timeoutMs) {
273
+ const responseNode = await this.query(iqNode, timeoutMs);
274
+ this.logger.debug('app-state sync iq response received', {
275
+ tag: responseNode.tag,
276
+ type: responseNode.attrs.type
277
+ });
278
+ const payloads = (0, WaAppStateSyncResponseParser_1.parseSyncResponse)(responseNode);
279
+ this.logger.debug('app-state sync payloads parsed', { count: payloads.length });
280
+ const payloadByCollection = new Map();
281
+ for (const payload of payloads) {
282
+ payloadByCollection.set(payload.collection, payload);
283
+ }
284
+ return payloadByCollection;
285
+ }
286
+ async processCollectionRound({ collection, payloadByCollection, pendingByCollection, options, outgoingContexts, skippedUploadCollections }) {
287
+ const payload = payloadByCollection.get(collection);
288
+ let shouldRefetch = false;
289
+ let collectionStateChanged = false;
290
+ if (!payload) {
291
+ this.logger.warn('app-state sync response missing collection payload', { collection });
292
+ return this.createCollectionOutcome(collection, constants_2.WA_APP_STATE_COLLECTION_STATES.ERROR_RETRY);
293
+ }
294
+ if (payload.state === constants_2.WA_APP_STATE_COLLECTION_STATES.ERROR_FATAL ||
295
+ payload.state === constants_2.WA_APP_STATE_COLLECTION_STATES.ERROR_RETRY) {
296
+ return this.createCollectionOutcome(collection, payload.state, payload.version);
297
+ }
298
+ const pendingMutationsCount = pendingByCollection.get(collection)?.length ?? 0;
299
+ if (payload.state === constants_2.WA_APP_STATE_COLLECTION_STATES.CONFLICT_HAS_MORE) {
300
+ shouldRefetch = true;
301
+ }
302
+ else if (payload.state === constants_2.WA_APP_STATE_COLLECTION_STATES.CONFLICT &&
303
+ pendingMutationsCount > 0) {
304
+ shouldRefetch = true;
305
+ }
306
+ if (payload.state === constants_2.WA_APP_STATE_COLLECTION_STATES.CONFLICT) {
307
+ return this.createCollectionOutcome(collection, pendingMutationsCount > 0
308
+ ? constants_2.WA_APP_STATE_COLLECTION_STATES.CONFLICT
309
+ : constants_2.WA_APP_STATE_COLLECTION_STATES.SUCCESS, payload.version, shouldRefetch);
310
+ }
311
+ if (payload.state === constants_2.WA_APP_STATE_COLLECTION_STATES.CONFLICT_HAS_MORE) {
312
+ return this.createCollectionOutcome(collection, payload.state, payload.version, shouldRefetch);
313
+ }
314
+ try {
315
+ let appliedMutations = [];
316
+ if (payload.snapshotReference) {
317
+ const downloader = options.downloadExternalBlob;
318
+ if (!downloader) {
319
+ throw new Error(`snapshot for ${payload.collection} requires external blob downloader`);
320
+ }
321
+ const snapshotBytes = await downloader(payload.collection, 'snapshot', payload.snapshotReference);
322
+ const snapshot = this.validateSnapshot(payload.collection, _proto_1.proto.SyncdSnapshot.decode(snapshotBytes));
323
+ const snapshotMutations = await this.applySnapshot(payload.collection, snapshot);
324
+ appliedMutations = appliedMutations.concat(snapshotMutations);
325
+ collectionStateChanged = true;
326
+ }
327
+ if (payload.patches.length > 0) {
328
+ const readyPatches = await this.resolveReadyPatches(payload, options);
329
+ for (const readyPatch of readyPatches) {
330
+ const patchMutations = await this.applyPatch(payload.collection, readyPatch);
331
+ appliedMutations = appliedMutations.concat(patchMutations);
332
+ collectionStateChanged = true;
333
+ }
334
+ }
335
+ else {
336
+ const outgoingContext = outgoingContexts.get(payload.collection);
337
+ if (outgoingContext &&
338
+ payload.state === constants_2.WA_APP_STATE_COLLECTION_STATES.SUCCESS &&
339
+ payload.version === outgoingContext.patchVersion) {
340
+ this.setCollectionState(payload.collection, outgoingContext.patchVersion, outgoingContext.nextHash, outgoingContext.nextIndexValueMap);
341
+ collectionStateChanged = true;
342
+ }
343
+ }
344
+ if (payload.state === constants_2.WA_APP_STATE_COLLECTION_STATES.SUCCESS_HAS_MORE) {
345
+ shouldRefetch = true;
346
+ }
347
+ if (payload.state === constants_2.WA_APP_STATE_COLLECTION_STATES.SUCCESS &&
348
+ skippedUploadCollections.has(collection)) {
349
+ shouldRefetch = true;
350
+ }
351
+ this.logger.debug('app-state collection processed', {
352
+ collection: payload.collection,
353
+ state: payload.state,
354
+ version: payload.version,
355
+ appliedMutations: appliedMutations.length
356
+ });
357
+ return this.createCollectionOutcome(collection, payload.state, payload.version, shouldRefetch, collectionStateChanged, appliedMutations);
358
+ }
359
+ catch (error) {
360
+ if (error instanceof WaAppStateMissingKeyError) {
361
+ this.logger.warn('app-state blocked by missing key', {
362
+ collection: payload.collection,
363
+ message: error.message
364
+ });
365
+ return this.createCollectionOutcome(collection, constants_2.WA_APP_STATE_COLLECTION_STATES.BLOCKED, payload.version, shouldRefetch, collectionStateChanged, undefined, error.keyId);
366
+ }
367
+ const message = error instanceof Error ? error.message : String(error);
368
+ this.logger.warn('app-state collection processing failed', {
369
+ collection: payload.collection,
370
+ message
371
+ });
372
+ return this.createCollectionOutcome(collection, constants_2.WA_APP_STATE_COLLECTION_STATES.ERROR_RETRY, payload.version, true, collectionStateChanged);
373
+ }
374
+ }
375
+ createCollectionOutcome(collection, state, version, shouldRefetch = false, stateChanged = false, mutations, missingKeyId = null) {
376
+ return {
377
+ collection,
378
+ shouldRefetch,
379
+ stateChanged,
380
+ missingKeyId,
381
+ result: {
382
+ collection,
383
+ state,
384
+ version,
385
+ ...(mutations ? { mutations } : {})
386
+ }
387
+ };
388
+ }
389
+ collectDistinctMissingKeyIds(keyIds) {
390
+ const byHex = new Map();
391
+ for (const keyId of keyIds) {
392
+ const keyHex = (0, utils_1.keyIdToHex)(keyId);
393
+ if (byHex.has(keyHex)) {
394
+ continue;
395
+ }
396
+ byHex.set(keyHex, keyId);
397
+ }
398
+ return [...byHex.values()];
399
+ }
400
+ async notifyMissingKeys(input) {
401
+ const keyIds = this.collectDistinctMissingKeyIds(input.keyIds);
402
+ const collections = [...new Set(input.collections)];
403
+ if (keyIds.length === 0 || collections.length === 0) {
404
+ return;
405
+ }
406
+ const keyIdsHex = keyIds.map((keyId) => (0, utils_1.keyIdToHex)(keyId));
407
+ this.logger.info('app-state requesting missing sync keys', {
408
+ keys: keyIdsHex.length,
409
+ keyIds: keyIdsHex.join(','),
410
+ collections: collections.join(',')
411
+ });
412
+ try {
413
+ await input.onMissingKeys({
414
+ keyIds,
415
+ collections
416
+ });
417
+ }
418
+ catch (error) {
419
+ this.logger.warn('app-state missing key callback failed', {
420
+ keys: keyIdsHex.length,
421
+ collections: collections.join(','),
422
+ message: error instanceof Error ? error.message : String(error)
423
+ });
424
+ }
425
+ }
426
+ async resolveReadyPatches(payload, options) {
427
+ const sortedPatches = payload.patches
428
+ .map((patch) => ({
429
+ patch,
430
+ sortVersion: this.parseCollectionPatchVersion(payload.collection, patch)
431
+ }))
432
+ .sort((left, right) => left.sortVersion - right.sortVersion)
433
+ .map((entry) => entry.patch);
434
+ return Promise.all(sortedPatches.map(async (patch) => {
435
+ let readyPatch = patch;
436
+ if ((!readyPatch.mutations || readyPatch.mutations.length === 0) &&
437
+ readyPatch.externalMutations) {
438
+ const downloader = options.downloadExternalBlob;
439
+ if (!downloader) {
440
+ throw new Error(`external patch for ${payload.collection} requires external blob downloader`);
441
+ }
442
+ const patchBytes = await downloader(payload.collection, 'patch', readyPatch.externalMutations);
443
+ const decodedMutations = _proto_1.proto.SyncdMutations.decode(patchBytes);
444
+ readyPatch = {
445
+ ...readyPatch,
446
+ mutations: decodedMutations.mutations ?? []
447
+ };
448
+ }
449
+ return this.validatePatch(payload.collection, readyPatch);
450
+ }));
451
+ }
452
+ validateSnapshot(collection, snapshot) {
453
+ if (!snapshot.version?.version) {
454
+ throw new Error(`snapshot for ${collection} is missing version`);
455
+ }
456
+ if (!snapshot.mac) {
457
+ throw new Error(`snapshot for ${collection} is missing mac`);
458
+ }
459
+ if (!snapshot.keyId?.id) {
460
+ throw new Error(`snapshot for ${collection} is missing keyId`);
461
+ }
462
+ return snapshot;
463
+ }
464
+ parseCollectionPatchVersion(collection, patch) {
465
+ const parsed = this.normalizeProtoLong(patch.version?.version, `patch.version.version (${collection})`);
466
+ if (!Number.isSafeInteger(parsed) || parsed <= 0) {
467
+ throw new Error(`patch for ${collection} has invalid version ${parsed}`);
468
+ }
469
+ return parsed;
470
+ }
471
+ validatePatch(collection, patch) {
472
+ if (!patch.version?.version) {
473
+ throw new Error(`patch for ${collection} is missing version`);
474
+ }
475
+ if (!patch.snapshotMac) {
476
+ throw new Error(`patch for ${collection} is missing snapshotMac`);
477
+ }
478
+ if (!patch.patchMac) {
479
+ throw new Error(`patch for ${collection} is missing patchMac`);
480
+ }
481
+ if (!patch.keyId?.id) {
482
+ throw new Error(`patch for ${collection} is missing keyId`);
483
+ }
484
+ if (patch.mutations && patch.mutations.length > 0 && patch.externalMutations) {
485
+ throw new Error(`patch for ${collection} has inline and external mutations together`);
486
+ }
487
+ if (patch.exitCode?.code !== null &&
488
+ patch.exitCode?.code !== undefined &&
489
+ patch.exitCode.code !== 0) {
490
+ throw new Error(`patch for ${collection} has terminal exitCode ${patch.exitCode.code}: ${patch.exitCode.text ?? ''}`);
491
+ }
492
+ return patch;
493
+ }
494
+ async applySnapshot(collection, snapshot) {
495
+ const version = this.normalizeProtoLong(snapshot.version?.version, `snapshot.version.version (${collection})`);
496
+ const keyId = (0, base64_1.decodeProtoBytes)(snapshot.keyId?.id, `snapshot.keyId.id (${collection})`);
497
+ const keyData = await this.getKeyData(keyId);
498
+ if (!keyData) {
499
+ throw new WaAppStateMissingKeyError(`missing snapshot key ${(0, utils_1.keyIdToHex)(keyId)} for ${collection}`, keyId, collection);
500
+ }
501
+ const indexValueMap = new Map();
502
+ const mutations = [];
503
+ const decryptedRecords = await this.decryptSnapshotRecords(collection, snapshot);
504
+ for (const { decrypted, recordKeyId } of decryptedRecords) {
505
+ const indexMacHex = (0, utils_1.keyIdToHex)(decrypted.indexMac);
506
+ indexValueMap.set(indexMacHex, decrypted.valueMac);
507
+ mutations.push({
508
+ collection,
509
+ operation: 'set',
510
+ source: 'snapshot',
511
+ index: decrypted.index,
512
+ value: decrypted.value,
513
+ version: decrypted.version,
514
+ indexMac: decrypted.indexMac,
515
+ valueMac: decrypted.valueMac,
516
+ keyId: recordKeyId,
517
+ timestamp: this.normalizeProtoLong(decrypted.value?.timestamp, `snapshot.record.value.timestamp (${collection})`)
518
+ });
519
+ }
520
+ const ltHash = await this.crypto.ltHashAdd(constants_1.APP_STATE_EMPTY_LT_HASH, Array.from(indexValueMap.values()));
521
+ const expectedSnapshotMac = await this.crypto.generateSnapshotMac(keyData, ltHash, version, collection);
522
+ if (!(0, bytes_1.uint8Equal)(expectedSnapshotMac, snapshot.mac)) {
523
+ throw new Error(`snapshot MAC mismatch for ${collection}`);
524
+ }
525
+ this.setCollectionState(collection, version, ltHash, indexValueMap);
526
+ return mutations;
527
+ }
528
+ async applyPatch(collection, patch) {
529
+ const patchVersion = this.normalizeProtoLong(patch.version?.version, `patch.version.version (${collection})`);
530
+ const current = await this.getCollectionState(collection);
531
+ if (current.version !== patchVersion - 1) {
532
+ throw new Error(`patch version mismatch for ${collection}: local=${current.version}, incoming=${patchVersion}`);
533
+ }
534
+ const patchKeyId = (0, base64_1.decodeProtoBytes)(patch.keyId?.id, `patch.keyId.id (${collection})`);
535
+ const patchKeyData = await this.getKeyData(patchKeyId);
536
+ if (!patchKeyData) {
537
+ throw new WaAppStateMissingKeyError(`missing patch key ${(0, utils_1.keyIdToHex)(patchKeyId)} for ${collection}`, patchKeyId, collection);
538
+ }
539
+ const decryptedMutations = await this.decryptPatchMutations(collection, patch);
540
+ const nextState = await this.computeNextCollectionState(current.hash, current.indexValueMap, decryptedMutations.map((mutation) => ({
541
+ operation: mutation.operationCode,
542
+ indexMac: mutation.indexMac,
543
+ valueMac: mutation.valueMac
544
+ })), collection);
545
+ await this.assertPatchMacsMatch(patch, collection, patchKeyData, patchVersion, nextState.hash, decryptedMutations);
546
+ this.setCollectionState(collection, patchVersion, nextState.hash, nextState.indexValueMap);
547
+ return decryptedMutations.map(({ operationCode, ...mutation }) => {
548
+ void operationCode;
549
+ return mutation;
550
+ });
551
+ }
552
+ async decryptSnapshotRecords(collection, snapshot) {
553
+ return Promise.all((snapshot.records ?? []).map(async (record) => {
554
+ const indexMac = (0, base64_1.decodeProtoBytes)(record.index?.blob, `snapshot.record.index.blob (${collection})`);
555
+ const valueBlob = (0, base64_1.decodeProtoBytes)(record.value?.blob, `snapshot.record.value.blob (${collection})`);
556
+ const recordKeyId = (0, base64_1.decodeProtoBytes)(record.keyId?.id, `snapshot.record.keyId.id (${collection})`);
557
+ const recordKeyData = await this.getKeyData(recordKeyId);
558
+ if (!recordKeyData) {
559
+ throw new WaAppStateMissingKeyError(`missing snapshot mutation key ${(0, utils_1.keyIdToHex)(recordKeyId)} for ${collection}`, recordKeyId, collection);
560
+ }
561
+ const decrypted = await this.crypto.decryptMutation({
562
+ operation: _proto_1.proto.SyncdMutation.SyncdOperation.SET,
563
+ keyId: recordKeyId,
564
+ keyData: recordKeyData,
565
+ indexMac,
566
+ valueBlob
567
+ });
568
+ return {
569
+ decrypted,
570
+ recordKeyId
571
+ };
572
+ }));
573
+ }
574
+ async decryptPatchMutations(collection, patch) {
575
+ return Promise.all((patch.mutations ?? []).map(async (mutation) => {
576
+ const operationCode = mutation.operation;
577
+ if (operationCode === null || operationCode === undefined) {
578
+ throw new Error(`patch mutation is missing operation (${collection})`);
579
+ }
580
+ const record = mutation.record;
581
+ if (!record) {
582
+ throw new Error(`patch mutation is missing record (${collection})`);
583
+ }
584
+ const indexMac = (0, base64_1.decodeProtoBytes)(record.index?.blob, `patch.record.index.blob (${collection})`);
585
+ const valueBlob = (0, base64_1.decodeProtoBytes)(record.value?.blob, `patch.record.value.blob (${collection})`);
586
+ const recordKeyId = (0, base64_1.decodeProtoBytes)(record.keyId?.id, `patch.record.keyId.id (${collection})`);
587
+ const recordKeyData = await this.getKeyData(recordKeyId);
588
+ if (!recordKeyData) {
589
+ throw new WaAppStateMissingKeyError(`missing mutation key ${(0, utils_1.keyIdToHex)(recordKeyId)} for ${collection}`, recordKeyId, collection);
590
+ }
591
+ const decrypted = await this.crypto.decryptMutation({
592
+ operation: operationCode,
593
+ keyId: recordKeyId,
594
+ keyData: recordKeyData,
595
+ indexMac,
596
+ valueBlob
597
+ });
598
+ return {
599
+ collection,
600
+ operation: operationCode === _proto_1.proto.SyncdMutation.SyncdOperation.REMOVE
601
+ ? 'remove'
602
+ : 'set',
603
+ source: 'patch',
604
+ operationCode,
605
+ index: decrypted.index,
606
+ value: decrypted.value,
607
+ version: decrypted.version,
608
+ indexMac: decrypted.indexMac,
609
+ valueMac: decrypted.valueMac,
610
+ keyId: recordKeyId,
611
+ timestamp: this.normalizeProtoLong(decrypted.value?.timestamp, `patch.record.value.timestamp (${collection})`)
612
+ };
613
+ }));
614
+ }
615
+ async assertPatchMacsMatch(patch, collection, patchKeyData, patchVersion, nextHash, decryptedMutations) {
616
+ const snapshotMac = (0, base64_1.decodeProtoBytes)(patch.snapshotMac, `patch.snapshotMac (${collection})`);
617
+ const expectedSnapshotMac = await this.crypto.generateSnapshotMac(patchKeyData, nextHash, patchVersion, collection);
618
+ if (!(0, bytes_1.uint8Equal)(expectedSnapshotMac, snapshotMac)) {
619
+ throw new Error(`patch snapshot MAC mismatch for ${collection}`);
620
+ }
621
+ const patchMac = (0, base64_1.decodeProtoBytes)(patch.patchMac, `patch.patchMac (${collection})`);
622
+ const expectedPatchMac = await this.crypto.generatePatchMac(patchKeyData, snapshotMac, decryptedMutations.map((mutation) => mutation.valueMac), patchVersion, collection);
623
+ if (!(0, bytes_1.uint8Equal)(expectedPatchMac, patchMac)) {
624
+ throw new Error(`patch MAC mismatch for ${collection}`);
625
+ }
626
+ }
627
+ async buildOutgoingPatch(collection, snapshot, pendingMutations) {
628
+ const activeKey = await this.store.getActiveSyncKey();
629
+ if (!activeKey) {
630
+ throw new WaAppStateMissingKeyError(`no sync key available to upload ${collection}`, null, collection);
631
+ }
632
+ const encryptedResults = await Promise.all(pendingMutations.map(async (mutation) => {
633
+ const value = mutation.operation === 'set' ? mutation.value : mutation.previousValue;
634
+ const operationCode = mutation.operation === 'remove'
635
+ ? _proto_1.proto.SyncdMutation.SyncdOperation.REMOVE
636
+ : _proto_1.proto.SyncdMutation.SyncdOperation.SET;
637
+ const encrypted = await this.crypto.encryptMutation({
638
+ operation: operationCode,
639
+ keyId: activeKey.keyId,
640
+ keyData: activeKey.keyData,
641
+ index: mutation.index,
642
+ value,
643
+ version: mutation.version
644
+ });
645
+ return { operationCode, encrypted };
646
+ }));
647
+ const encryptedMutations = encryptedResults.map(({ operationCode, encrypted }) => ({
648
+ operation: operationCode,
649
+ record: {
650
+ keyId: { id: activeKey.keyId },
651
+ index: { blob: encrypted.indexMac },
652
+ value: { blob: encrypted.valueBlob }
653
+ }
654
+ }));
655
+ const macMutations = encryptedResults.map(({ operationCode, encrypted }) => ({
656
+ operation: operationCode,
657
+ indexMac: encrypted.indexMac,
658
+ valueMac: encrypted.valueMac
659
+ }));
660
+ const nextState = await this.computeNextCollectionState(snapshot.hash, snapshot.indexValueMap, macMutations, collection);
661
+ const patchVersion = snapshot.version + 1;
662
+ const snapshotMac = await this.crypto.generateSnapshotMac(activeKey.keyData, nextState.hash, patchVersion, collection);
663
+ const patchMac = await this.crypto.generatePatchMac(activeKey.keyData, snapshotMac, macMutations.map((item) => item.valueMac), patchVersion, collection);
664
+ const encodedPatch = _proto_1.proto.SyncdPatch.encode({
665
+ version: { version: patchVersion },
666
+ mutations: encryptedMutations,
667
+ snapshotMac,
668
+ patchMac,
669
+ keyId: { id: activeKey.keyId }
670
+ }).finish();
671
+ return {
672
+ encodedPatch,
673
+ context: {
674
+ collection,
675
+ patchVersion,
676
+ nextHash: nextState.hash,
677
+ nextIndexValueMap: nextState.indexValueMap
678
+ }
679
+ };
680
+ }
681
+ async computeNextCollectionState(baseHash, baseMap, mutations, collection) {
682
+ const indexValueMap = new Map(baseMap);
683
+ const addValues = [];
684
+ const removeValues = [];
685
+ let missingRemoveCount = 0;
686
+ for (const mutation of mutations) {
687
+ const indexMacHex = (0, utils_1.keyIdToHex)(mutation.indexMac);
688
+ const existing = indexValueMap.get(indexMacHex);
689
+ if (mutation.operation === _proto_1.proto.SyncdMutation.SyncdOperation.REMOVE) {
690
+ if (!existing) {
691
+ missingRemoveCount += 1;
692
+ continue;
693
+ }
694
+ indexValueMap.delete(indexMacHex);
695
+ removeValues.push(existing);
696
+ continue;
697
+ }
698
+ if (existing) {
699
+ removeValues.push(existing);
700
+ }
701
+ indexValueMap.set(indexMacHex, mutation.valueMac);
702
+ addValues.push(mutation.valueMac);
703
+ }
704
+ if (missingRemoveCount > 0) {
705
+ this.logger.warn('app-state mutation remove index mac not found', {
706
+ collection,
707
+ missingRemoveCount
708
+ });
709
+ }
710
+ const nextHash = await this.crypto.ltHashSubtractThenAdd(baseHash, addValues, removeValues);
711
+ return {
712
+ hash: nextHash.hash,
713
+ indexValueMap
714
+ };
715
+ }
716
+ normalizeProtoLong(value, field) {
717
+ try {
718
+ return (0, primitives_1.longToNumber)(value);
719
+ }
720
+ catch (error) {
721
+ const reason = error instanceof Error ? error.message : String(error);
722
+ throw new Error(`invalid ${field}: ${reason}`);
723
+ }
724
+ }
725
+ groupPendingMutations(pendingMutations) {
726
+ const grouped = new Map();
727
+ for (const mutation of pendingMutations) {
728
+ const list = grouped.get(mutation.collection);
729
+ if (list) {
730
+ list.push(mutation);
731
+ }
732
+ else {
733
+ grouped.set(mutation.collection, [mutation]);
734
+ }
735
+ }
736
+ const compacted = new Map();
737
+ for (const [collection, list] of grouped.entries()) {
738
+ const seenIndexes = new Set();
739
+ const reversed = [];
740
+ for (let index = list.length - 1; index >= 0; index -= 1) {
741
+ const mutation = list[index];
742
+ if (seenIndexes.has(mutation.index)) {
743
+ continue;
744
+ }
745
+ seenIndexes.add(mutation.index);
746
+ reversed.push(mutation);
747
+ }
748
+ compacted.set(collection, reversed.reverse());
749
+ }
750
+ return compacted;
751
+ }
752
+ async getKeyData(keyId) {
753
+ const context = this.requireSyncContext();
754
+ const keyHex = (0, utils_1.keyIdToHex)(keyId);
755
+ if (context.keys.has(keyHex)) {
756
+ return context.keys.get(keyHex) ?? null;
757
+ }
758
+ const value = await this.store.getSyncKeyData(keyId);
759
+ context.keys.set(keyHex, value);
760
+ return value;
761
+ }
762
+ async getCollectionState(collection) {
763
+ const context = this.requireSyncContext();
764
+ const cached = context.collections.get(collection);
765
+ if (cached) {
766
+ return cached;
767
+ }
768
+ const state = await this.store.getCollectionState(collection);
769
+ context.collections.set(collection, state);
770
+ return state;
771
+ }
772
+ setCollectionState(collection, version, hash, indexValueMap) {
773
+ const context = this.requireSyncContext();
774
+ context.collections.set(collection, {
775
+ version,
776
+ hash,
777
+ indexValueMap
778
+ });
779
+ context.dirtyCollections.add(collection);
780
+ }
781
+ async persistCollectionUpdates() {
782
+ const context = this.requireSyncContext();
783
+ const updates = [];
784
+ for (const collection of context.dirtyCollections.values()) {
785
+ const state = context.collections.get(collection);
786
+ if (!state) {
787
+ continue;
788
+ }
789
+ updates.push({
790
+ collection,
791
+ version: state.version,
792
+ hash: state.hash,
793
+ indexValueMap: state.indexValueMap
794
+ });
795
+ }
796
+ if (updates.length === 0) {
797
+ return;
798
+ }
799
+ await this.store.setCollectionStates(updates);
800
+ }
801
+ requireSyncContext() {
802
+ if (!this.syncContext) {
803
+ throw new Error('app-state sync context is not initialized');
804
+ }
805
+ return this.syncContext;
806
+ }
807
+ }
808
+ exports.WaAppStateSyncClient = WaAppStateSyncClient;