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
@@ -2,9 +2,8 @@ import { parseGroupNotificationEvents } from './events/group.js';
2
2
  import { WA_NODE_TAGS, WA_NOTIFICATION_TYPES } from '../protocol/constants.js';
3
3
  import { buildInboundReceiptAckNode, buildInboundRetryReceiptAckNode } from '../transport/node/builders/message.js';
4
4
  import { buildNotificationAckNode } from '../transport/node/builders/pairing.js';
5
- import { getFirstNodeChild, getNodeChildrenByTag } from '../transport/node/helpers.js';
6
- import { parseOptionalInt } from '../transport/stream/parse.js';
7
- import { toError } from '../util/primitives.js';
5
+ import { getFirstNodeChild, getNodeChildrenNonEmptyAttrValuesByTag } from '../transport/node/helpers.js';
6
+ import { parseOptionalInt, toError } from '../util/primitives.js';
8
7
  const LOGOUT_FAILURE_REASONS = new Set([401, 403, 406]);
9
8
  const DISCONNECT_FAILURE_REASONS = new Set([405, 409, 503]);
10
9
  const CORE_NOTIFICATION_TYPES = new Set([
@@ -141,47 +140,50 @@ export function createIncomingNotificationHandler(options) {
141
140
  const notificationType = node.attrs.type ?? '';
142
141
  const classification = classifyNotificationType(notificationType);
143
142
  const firstChildTag = getFirstNodeChild(node)?.tag;
143
+ const baseEvent = createIncomingBaseEvent(node);
144
144
  const serverSyncCollections = notificationType === 'server_sync'
145
- ? getNodeChildrenByTag(node, WA_NODE_TAGS.COLLECTION)
146
- .map((collectionNode) => collectionNode.attrs.name)
147
- .filter((name) => typeof name === 'string' && name.length > 0)
145
+ ? getNodeChildrenNonEmptyAttrValuesByTag(node, WA_NODE_TAGS.COLLECTION, 'name')
148
146
  : [];
147
+ let details;
148
+ if (firstChildTag || serverSyncCollections.length > 0) {
149
+ details = {};
150
+ if (firstChildTag) {
151
+ details.firstChildTag = firstChildTag;
152
+ }
153
+ if (serverSyncCollections.length > 0) {
154
+ details.collections = serverSyncCollections;
155
+ }
156
+ }
149
157
  options.emitIncomingNotification({
150
- ...createIncomingBaseEvent(node),
158
+ ...baseEvent,
151
159
  notificationType,
152
160
  classification,
153
- details: firstChildTag || serverSyncCollections.length > 0
154
- ? {
155
- ...(firstChildTag ? { firstChildTag } : {}),
156
- ...(serverSyncCollections.length > 0
157
- ? { collections: serverSyncCollections }
158
- : {})
159
- }
160
- : undefined
161
+ details
161
162
  });
162
163
  if (classification === 'out_of_scope') {
163
164
  options.emitUnhandledStanza({
164
- ...createIncomingBaseEvent(node),
165
+ ...baseEvent,
165
166
  reason: `notification.${notificationType}.out_of_scope`
166
167
  });
167
168
  }
168
169
  else if (classification === 'unknown') {
169
170
  options.emitUnhandledStanza({
170
- ...createIncomingBaseEvent(node),
171
+ ...baseEvent,
171
172
  reason: `notification.${notificationType || 'unknown'}.not_supported`
172
173
  });
173
174
  }
174
175
  await sendSafeAck(options.logger, options.sendNode, buildNotificationAckNode(node));
175
176
  if (notificationType === 'server_sync' && serverSyncCollections.length > 0) {
177
+ const collectionsCsv = serverSyncCollections.join(',');
176
178
  if (!options.syncAppState) {
177
179
  options.logger.warn('received server_sync notification without app-state sync runtime', {
178
- collections: serverSyncCollections.join(',')
180
+ collections: collectionsCsv
179
181
  });
180
182
  return true;
181
183
  }
182
184
  void options.syncAppState().catch((error) => {
183
185
  options.logger.warn('failed to sync app-state after server_sync notification', {
184
- collections: serverSyncCollections.join(','),
186
+ collections: collectionsCsv,
185
187
  message: toError(error).message
186
188
  });
187
189
  });
@@ -194,6 +196,7 @@ export function createIncomingGroupNotificationHandler(options) {
194
196
  if (node.attrs.type !== WA_NOTIFICATION_TYPES.GROUP) {
195
197
  return false;
196
198
  }
199
+ const baseEvent = createIncomingBaseEvent(node);
197
200
  const parsed = parseGroupNotificationEvents(node);
198
201
  for (const event of parsed.events) {
199
202
  options.emitGroupEvent(event);
@@ -203,7 +206,7 @@ export function createIncomingGroupNotificationHandler(options) {
203
206
  }
204
207
  if (parsed.events.length === 0 && parsed.unhandled.length === 0) {
205
208
  options.emitUnhandledStanza({
206
- ...createIncomingBaseEvent(node),
209
+ ...baseEvent,
207
210
  reason: `notification.${WA_NOTIFICATION_TYPES.GROUP}.empty`
208
211
  });
209
212
  }
@@ -1,14 +1,12 @@
1
1
  import { proto } from '../proto.js';
2
2
  import { toError } from '../util/primitives.js';
3
3
  async function persistContacts(contactStore, event, nowMs) {
4
- const candidateJids = new Set();
5
- if (event.senderJid) {
6
- candidateJids.add(event.senderJid);
7
- }
8
- if (event.rawNode.attrs.participant) {
9
- candidateJids.add(event.rawNode.attrs.participant);
4
+ const candidateJids = [event.senderJid, event.rawNode.attrs.participant].filter((jid) => !!jid);
5
+ if (candidateJids.length === 0) {
6
+ return;
10
7
  }
11
- await Promise.all(Array.from(candidateJids, (jid) => contactStore.upsert({ jid, lastUpdatedMs: nowMs })));
8
+ const contacts = [...new Set(candidateJids)].map((jid) => ({ jid, lastUpdatedMs: nowMs }));
9
+ await contactStore.upsertBatch(contacts);
12
10
  }
13
11
  export async function persistIncomingMailboxEntities(options) {
14
12
  const { logger, contactStore, messageStore, event } = options;
@@ -28,7 +26,9 @@ export async function persistIncomingMailboxEntities(options) {
28
26
  senderJid: event.senderJid,
29
27
  participantJid: event.rawNode.attrs.participant,
30
28
  fromMe: false,
31
- timestampMs: event.timestampSeconds === undefined ? undefined : event.timestampSeconds * 1000,
29
+ timestampMs: event.timestampSeconds === undefined
30
+ ? undefined
31
+ : event.timestampSeconds * 1000,
32
32
  encType: event.encryptionType,
33
33
  plaintext: event.plaintext,
34
34
  messageBytes
@@ -4,7 +4,7 @@ import { WaMediaCrypto } from '../media/WaMediaCrypto.js';
4
4
  import { isSendMediaMessage } from '../message/content.js';
5
5
  import { WA_DEFAULTS } from '../protocol/constants.js';
6
6
  import { buildMediaConnIq } from '../transport/node/builders/media.js';
7
- import { bytesToBase64UrlSafe } from '../util/base64.js';
7
+ import { bytesToBase64UrlSafe } from '../util/bytes.js';
8
8
  import { TEXT_DECODER, toBytesView } from '../util/bytes.js';
9
9
  import { toError } from '../util/primitives.js';
10
10
  export async function buildMediaMessageContent(options, content) {
@@ -0,0 +1,186 @@
1
+ import { normalizeDeviceJid, splitJid, toUserJid } from '../../protocol/jid.js';
2
+ import { toError } from '../../util/primitives.js';
3
+ export function createDeviceFanoutResolver(options) {
4
+ const { signalDeviceSync, getCurrentMeJid, getCurrentMeLid, logger } = options;
5
+ const requireCurrentMeJid = (context) => {
6
+ const meJid = getCurrentMeJid();
7
+ if (meJid) {
8
+ return meJid;
9
+ }
10
+ throw new Error(`${context} requires registered meJid`);
11
+ };
12
+ const resolveDirectFanoutDeviceJids = async (recipientJid, selfDeviceJidForRecipient) => {
13
+ const recipientUserJid = toUserJid(recipientJid);
14
+ const meUserJid = toUserJid(selfDeviceJidForRecipient);
15
+ const targets = recipientUserJid === meUserJid ? [recipientUserJid] : [recipientUserJid, meUserJid];
16
+ try {
17
+ const synced = await signalDeviceSync.syncDeviceList(targets);
18
+ const byUser = new Map(synced.map((entry) => [toUserJid(entry.jid), entry.deviceJids]));
19
+ const fanout = new Set();
20
+ const recipientDevices = byUser.get(recipientUserJid) ?? [];
21
+ if (recipientDevices.length === 0) {
22
+ fanout.add(recipientUserJid);
23
+ }
24
+ else {
25
+ for (let index = 0; index < recipientDevices.length; index += 1) {
26
+ fanout.add(recipientDevices[index]);
27
+ }
28
+ }
29
+ const meDevices = byUser.get(meUserJid) ?? [];
30
+ const normalizedMeJid = normalizeDeviceJid(selfDeviceJidForRecipient);
31
+ for (let index = 0; index < meDevices.length; index += 1) {
32
+ const deviceJid = meDevices[index];
33
+ if (normalizeDeviceJid(deviceJid) === normalizedMeJid) {
34
+ continue;
35
+ }
36
+ fanout.add(deviceJid);
37
+ }
38
+ return [...fanout];
39
+ }
40
+ catch (error) {
41
+ logger.warn('signal device fanout sync failed, falling back to direct recipient', {
42
+ to: recipientJid,
43
+ message: toError(error).message
44
+ });
45
+ return [recipientUserJid];
46
+ }
47
+ };
48
+ const resolveGroupParticipantDeviceJids = async (participantUserJids) => {
49
+ const meDeviceJids = new Set();
50
+ const meJid = getCurrentMeJid();
51
+ if (meJid) {
52
+ try {
53
+ meDeviceJids.add(normalizeDeviceJid(meJid));
54
+ }
55
+ catch (error) {
56
+ logger.trace('ignoring malformed me jid', {
57
+ meJid,
58
+ message: toError(error).message
59
+ });
60
+ }
61
+ }
62
+ const meLid = getCurrentMeLid();
63
+ if (meLid && meLid.includes('@')) {
64
+ try {
65
+ meDeviceJids.add(normalizeDeviceJid(meLid));
66
+ }
67
+ catch (error) {
68
+ logger.trace('ignoring malformed me lid jid', {
69
+ meLid,
70
+ message: toError(error).message
71
+ });
72
+ }
73
+ }
74
+ const candidateUsers = [...new Set(participantUserJids)];
75
+ if (candidateUsers.length === 0) {
76
+ return [];
77
+ }
78
+ try {
79
+ const synced = await signalDeviceSync.syncDeviceList(candidateUsers);
80
+ const fanout = new Set();
81
+ for (const entry of synced) {
82
+ if (entry.deviceJids.length === 0) {
83
+ const normalizedEntryJid = normalizeDeviceJid(entry.jid);
84
+ if (meDeviceJids.has(normalizedEntryJid)) {
85
+ continue;
86
+ }
87
+ fanout.add(normalizedEntryJid);
88
+ continue;
89
+ }
90
+ for (const deviceJid of entry.deviceJids) {
91
+ const normalizedDeviceJid = normalizeDeviceJid(deviceJid);
92
+ if (meDeviceJids.has(normalizedDeviceJid)) {
93
+ continue;
94
+ }
95
+ fanout.add(normalizedDeviceJid);
96
+ }
97
+ }
98
+ return [...fanout];
99
+ }
100
+ catch (error) {
101
+ logger.warn('group participant device sync failed, falling back to participant user jids', {
102
+ participants: candidateUsers.length,
103
+ message: toError(error).message
104
+ });
105
+ const fallbackJids = new Set();
106
+ for (const candidateJid of candidateUsers) {
107
+ try {
108
+ const normalizedCandidateJid = normalizeDeviceJid(candidateJid);
109
+ if (meDeviceJids.has(normalizedCandidateJid)) {
110
+ continue;
111
+ }
112
+ fallbackJids.add(normalizedCandidateJid);
113
+ }
114
+ catch (fallbackError) {
115
+ logger.trace('ignoring malformed participant jid in fallback fanout resolution', {
116
+ participantJid: candidateJid,
117
+ message: toError(fallbackError).message
118
+ });
119
+ }
120
+ }
121
+ return [...fallbackJids];
122
+ }
123
+ };
124
+ const resolveOwnPeerDeviceJids = async () => {
125
+ const meJid = requireCurrentMeJid('resolveOwnPeerDeviceJids');
126
+ const meUserJid = toUserJid(meJid);
127
+ const meDevices = new Set();
128
+ meDevices.add(normalizeDeviceJid(meJid));
129
+ const meLid = getCurrentMeLid();
130
+ if (meLid && meLid.includes('@')) {
131
+ try {
132
+ meDevices.add(normalizeDeviceJid(meLid));
133
+ }
134
+ catch (error) {
135
+ logger.trace('ignoring malformed me lid jid while resolving peer devices', {
136
+ meLid,
137
+ message: toError(error).message
138
+ });
139
+ }
140
+ }
141
+ try {
142
+ const synced = await signalDeviceSync.syncDeviceList([meUserJid]);
143
+ const peerDevices = new Set();
144
+ for (const entry of synced) {
145
+ const sourceDevices = entry.deviceJids.length > 0 ? entry.deviceJids : [entry.jid];
146
+ for (const deviceJid of sourceDevices) {
147
+ try {
148
+ const normalized = normalizeDeviceJid(deviceJid);
149
+ if (meDevices.has(normalized)) {
150
+ continue;
151
+ }
152
+ peerDevices.add(normalized);
153
+ }
154
+ catch (error) {
155
+ logger.trace('ignoring malformed peer device jid while resolving app-state peers', {
156
+ deviceJid,
157
+ message: toError(error).message
158
+ });
159
+ }
160
+ }
161
+ }
162
+ return [...peerDevices];
163
+ }
164
+ catch (error) {
165
+ logger.warn('failed to resolve peer devices for app-state key request', {
166
+ message: toError(error).message
167
+ });
168
+ return [];
169
+ }
170
+ };
171
+ const resolveSelfDeviceJidForRecipient = (recipientJid, meJid, meLid) => {
172
+ if (splitJid(recipientJid).server !== 'lid') {
173
+ return meJid;
174
+ }
175
+ if (!meLid || !meLid.includes('@')) {
176
+ return meJid;
177
+ }
178
+ return meLid;
179
+ };
180
+ return {
181
+ resolveDirectFanoutDeviceJids,
182
+ resolveGroupParticipantDeviceJids,
183
+ resolveOwnPeerDeviceJids,
184
+ resolveSelfDeviceJidForRecipient
185
+ };
186
+ }
@@ -0,0 +1,127 @@
1
+ import { writeRandomPadMax16 } from '../../message/padding.js';
2
+ import { proto } from '../../proto.js';
3
+ import { normalizeDeviceJid } from '../../protocol/jid.js';
4
+ import { bytesToHex } from '../../util/bytes.js';
5
+ export function createAppStateSyncKeyProtocol(options) {
6
+ const { publishSignalMessage, fanoutResolver, getCurrentMeJid, getCurrentMeLid, logger } = options;
7
+ const requireCurrentIdentity = (context) => {
8
+ const meJid = getCurrentMeJid();
9
+ const meLid = getCurrentMeLid();
10
+ if (meJid || meLid) {
11
+ return;
12
+ }
13
+ throw new Error(`${context} requires registered identity`);
14
+ };
15
+ const publishProtocolMessageToDevice = async (deviceJid, protocolMessage) => {
16
+ const plaintext = await writeRandomPadMax16(proto.Message.encode({
17
+ protocolMessage
18
+ }).finish());
19
+ await publishSignalMessage({
20
+ to: deviceJid,
21
+ plaintext,
22
+ type: 'protocol',
23
+ category: 'peer',
24
+ pushPriority: 'high'
25
+ });
26
+ };
27
+ const requestKeys = async (keyIds) => {
28
+ requireCurrentIdentity('requestKeys');
29
+ const normalizedKeyIds = [];
30
+ const seenKeyIds = new Set();
31
+ for (const keyId of keyIds) {
32
+ if (keyId.byteLength === 0) {
33
+ continue;
34
+ }
35
+ const keyHex = bytesToHex(keyId);
36
+ if (seenKeyIds.has(keyHex)) {
37
+ continue;
38
+ }
39
+ seenKeyIds.add(keyHex);
40
+ normalizedKeyIds.push(keyId);
41
+ }
42
+ if (normalizedKeyIds.length === 0) {
43
+ return [];
44
+ }
45
+ const peerDeviceJids = await fanoutResolver.resolveOwnPeerDeviceJids();
46
+ if (peerDeviceJids.length === 0) {
47
+ logger.warn('app-state sync key request skipped: no peer devices available', {
48
+ keys: normalizedKeyIds.length
49
+ });
50
+ return [];
51
+ }
52
+ const protocolMessage = {
53
+ type: proto.Message.ProtocolMessage.Type.APP_STATE_SYNC_KEY_REQUEST,
54
+ appStateSyncKeyRequest: {
55
+ keyIds: normalizedKeyIds.map((keyId) => ({
56
+ keyId
57
+ }))
58
+ }
59
+ };
60
+ const publishResults = await Promise.allSettled(peerDeviceJids.map((deviceJid) => publishProtocolMessageToDevice(deviceJid, protocolMessage)));
61
+ const failedPublishes = publishResults.filter((result) => result.status === 'rejected').length;
62
+ if (failedPublishes > 0) {
63
+ logger.warn('some app-state sync key requests failed', {
64
+ total: peerDeviceJids.length,
65
+ failed: failedPublishes
66
+ });
67
+ }
68
+ logger.info('app-state sync key request sent to peer devices', {
69
+ devices: peerDeviceJids.length,
70
+ keys: normalizedKeyIds.length,
71
+ keyIds: normalizedKeyIds.map((keyId) => bytesToHex(keyId)).join(',')
72
+ });
73
+ return peerDeviceJids;
74
+ };
75
+ const sendKeyShare = async (toDeviceJid, keys, missingKeyIds = []) => {
76
+ requireCurrentIdentity('sendKeyShare');
77
+ const normalizedTo = normalizeDeviceJid(toDeviceJid);
78
+ const seenKeyIds = new Set();
79
+ const keyShareEntries = [];
80
+ let sharedKeyCount = 0;
81
+ for (const key of keys) {
82
+ const keyHex = bytesToHex(key.keyId);
83
+ if (seenKeyIds.has(keyHex)) {
84
+ continue;
85
+ }
86
+ seenKeyIds.add(keyHex);
87
+ sharedKeyCount += 1;
88
+ keyShareEntries.push({
89
+ keyId: { keyId: key.keyId },
90
+ keyData: {
91
+ keyData: key.keyData,
92
+ timestamp: key.timestamp,
93
+ ...(key.fingerprint ? { fingerprint: key.fingerprint } : {})
94
+ }
95
+ });
96
+ }
97
+ for (const keyId of missingKeyIds) {
98
+ if (keyId.byteLength === 0) {
99
+ continue;
100
+ }
101
+ const keyHex = bytesToHex(keyId);
102
+ if (seenKeyIds.has(keyHex)) {
103
+ continue;
104
+ }
105
+ seenKeyIds.add(keyHex);
106
+ keyShareEntries.push({
107
+ keyId: { keyId }
108
+ });
109
+ }
110
+ const protocolMessage = {
111
+ type: proto.Message.ProtocolMessage.Type.APP_STATE_SYNC_KEY_SHARE,
112
+ appStateSyncKeyShare: {
113
+ keys: keyShareEntries
114
+ }
115
+ };
116
+ await publishProtocolMessageToDevice(normalizedTo, protocolMessage);
117
+ logger.info('app-state sync key share sent', {
118
+ to: normalizedTo,
119
+ keys: sharedKeyCount,
120
+ orphanKeys: keyShareEntries.length - sharedKeyCount
121
+ });
122
+ };
123
+ return {
124
+ requestKeys,
125
+ sendKeyShare
126
+ };
127
+ }
@@ -0,0 +1,188 @@
1
+ import { toUserJid } from '../../protocol/jid.js';
2
+ import { toError } from '../../util/primitives.js';
3
+ export function createGroupParticipantsCache(options) {
4
+ const { participantsStore, queryGroupParticipantJids, logger } = options;
5
+ const sanitizeParticipantUsers = (participants) => {
6
+ const deduped = new Set();
7
+ for (const participant of participants) {
8
+ if (!participant || !participant.includes('@')) {
9
+ continue;
10
+ }
11
+ try {
12
+ deduped.add(toUserJid(participant));
13
+ }
14
+ catch (error) {
15
+ logger.trace('ignoring malformed participant jid', {
16
+ participant,
17
+ message: toError(error).message
18
+ });
19
+ }
20
+ }
21
+ return [...deduped];
22
+ };
23
+ const areParticipantListsEqual = (left, right) => {
24
+ if (left.length !== right.length) {
25
+ return false;
26
+ }
27
+ for (let index = 0; index < left.length; index += 1) {
28
+ if (left[index] !== right[index]) {
29
+ return false;
30
+ }
31
+ }
32
+ return true;
33
+ };
34
+ const mergeParticipantUsersIntoCache = async (groupJid, cachedParticipants, participantsToAdd) => {
35
+ if (participantsToAdd.length === 0) {
36
+ return;
37
+ }
38
+ const nextParticipants = [...cachedParticipants];
39
+ const existing = new Set(cachedParticipants);
40
+ for (const participant of participantsToAdd) {
41
+ if (existing.has(participant)) {
42
+ continue;
43
+ }
44
+ existing.add(participant);
45
+ nextParticipants.push(participant);
46
+ }
47
+ if (nextParticipants.length === cachedParticipants.length) {
48
+ return;
49
+ }
50
+ await participantsStore.upsertGroupParticipants({
51
+ groupJid,
52
+ participants: nextParticipants,
53
+ updatedAtMs: Date.now()
54
+ });
55
+ };
56
+ const removeParticipantUsersFromCache = async (groupJid, cachedParticipants, participantsToRemove) => {
57
+ if (participantsToRemove.length === 0) {
58
+ return;
59
+ }
60
+ const removed = new Set(participantsToRemove);
61
+ const nextParticipants = cachedParticipants.filter((participant) => !removed.has(participant));
62
+ if (nextParticipants.length === cachedParticipants.length) {
63
+ return;
64
+ }
65
+ if (nextParticipants.length === 0) {
66
+ await participantsStore.deleteGroupParticipants(groupJid);
67
+ return;
68
+ }
69
+ await participantsStore.upsertGroupParticipants({
70
+ groupJid,
71
+ participants: nextParticipants,
72
+ updatedAtMs: Date.now()
73
+ });
74
+ };
75
+ const replaceParticipantUsersInCache = async (groupJid, cachedParticipants, participantsToReplace, replacementParticipants) => {
76
+ const toReplace = new Set(participantsToReplace);
77
+ const nextParticipants = cachedParticipants.filter((participant) => !toReplace.has(participant));
78
+ const existing = new Set(nextParticipants);
79
+ for (const participant of replacementParticipants) {
80
+ if (existing.has(participant)) {
81
+ continue;
82
+ }
83
+ existing.add(participant);
84
+ nextParticipants.push(participant);
85
+ }
86
+ if (areParticipantListsEqual(cachedParticipants, nextParticipants)) {
87
+ return;
88
+ }
89
+ if (nextParticipants.length === 0) {
90
+ await participantsStore.deleteGroupParticipants(groupJid);
91
+ return;
92
+ }
93
+ await participantsStore.upsertGroupParticipants({
94
+ groupJid,
95
+ participants: nextParticipants,
96
+ updatedAtMs: Date.now()
97
+ });
98
+ };
99
+ const resolveGroupJidForParticipantCacheEvent = (event) => {
100
+ if (event.action === 'linked_group_promote' || event.action === 'linked_group_demote') {
101
+ return event.contextGroupJid ?? event.groupJid ?? null;
102
+ }
103
+ return event.groupJid ?? null;
104
+ };
105
+ const extractParticipantUsersFromGroupEvent = (event) => {
106
+ const candidates = [];
107
+ for (const participant of event.participants ?? []) {
108
+ if (participant.jid) {
109
+ candidates.push(participant.jid);
110
+ }
111
+ if (participant.lidJid) {
112
+ candidates.push(participant.lidJid);
113
+ }
114
+ if (participant.phoneJid) {
115
+ candidates.push(participant.phoneJid);
116
+ }
117
+ }
118
+ return sanitizeParticipantUsers(candidates);
119
+ };
120
+ const refreshParticipantUsers = async (groupJid) => {
121
+ const queried = await queryGroupParticipantJids(groupJid);
122
+ const participants = sanitizeParticipantUsers(queried);
123
+ await participantsStore.upsertGroupParticipants({
124
+ groupJid,
125
+ participants,
126
+ updatedAtMs: Date.now()
127
+ });
128
+ return participants;
129
+ };
130
+ const resolveParticipantUsers = async (groupJid) => {
131
+ const cached = await participantsStore.getGroupParticipants(groupJid);
132
+ if (cached && cached.participants.length > 0) {
133
+ return sanitizeParticipantUsers(cached.participants);
134
+ }
135
+ return refreshParticipantUsers(groupJid);
136
+ };
137
+ const mutateFromGroupEvent = async (event) => {
138
+ const groupJid = resolveGroupJidForParticipantCacheEvent(event);
139
+ if (!groupJid) {
140
+ return;
141
+ }
142
+ if (event.action === 'delete') {
143
+ await participantsStore.deleteGroupParticipants(groupJid);
144
+ return;
145
+ }
146
+ const participantUsers = extractParticipantUsersFromGroupEvent(event);
147
+ if (event.action === 'create') {
148
+ if (participantUsers.length === 0) {
149
+ return;
150
+ }
151
+ await participantsStore.upsertGroupParticipants({
152
+ groupJid,
153
+ participants: participantUsers,
154
+ updatedAtMs: Date.now()
155
+ });
156
+ return;
157
+ }
158
+ const cached = await participantsStore.getGroupParticipants(groupJid);
159
+ if (!cached || cached.participants.length === 0) {
160
+ return;
161
+ }
162
+ const cachedParticipants = sanitizeParticipantUsers(cached.participants);
163
+ if (cachedParticipants.length === 0) {
164
+ return;
165
+ }
166
+ if (event.action === 'add' ||
167
+ event.action === 'promote' ||
168
+ event.action === 'demote' ||
169
+ event.action === 'linked_group_promote' ||
170
+ event.action === 'linked_group_demote') {
171
+ await mergeParticipantUsersIntoCache(groupJid, cachedParticipants, participantUsers);
172
+ return;
173
+ }
174
+ if (event.action === 'remove') {
175
+ await removeParticipantUsersFromCache(groupJid, cachedParticipants, participantUsers);
176
+ return;
177
+ }
178
+ if (event.action === 'modify') {
179
+ const authorUsers = event.authorJid ? sanitizeParticipantUsers([event.authorJid]) : [];
180
+ await replaceParticipantUsersInCache(groupJid, cachedParticipants, authorUsers, participantUsers);
181
+ }
182
+ };
183
+ return {
184
+ resolveParticipantUsers,
185
+ refreshParticipantUsers,
186
+ mutateFromGroupEvent
187
+ };
188
+ }
@@ -1,22 +1,17 @@
1
1
  import { webcrypto } from 'node:crypto';
2
2
  import { EMPTY_BYTES, TEXT_ENCODER, toBytesView } from '../../util/bytes.js';
3
- /**
4
- * HKDF key derivation using SHA-256
5
- */
6
3
  export async function hkdf(ikm, salt, info, outLength) {
7
4
  const key = await webcrypto.subtle.importKey('raw', ikm, 'HKDF', false, ['deriveBits']);
5
+ const infoBytes = typeof info === 'string' ? (info === '' ? EMPTY_BYTES : TEXT_ENCODER.encode(info)) : info;
8
6
  const bits = await webcrypto.subtle.deriveBits({
9
7
  name: 'HKDF',
10
8
  hash: 'SHA-256',
11
9
  salt: salt ?? EMPTY_BYTES,
12
- info: typeof info === 'string' ? TEXT_ENCODER.encode(info) : info
10
+ info: infoBytes
13
11
  }, key, outLength * 8);
14
12
  return toBytesView(bits);
15
13
  }
16
- /**
17
- * HKDF key derivation that outputs two 32-byte keys
18
- */
19
14
  export async function hkdfSplit(ikm, salt, info) {
20
15
  const out = await hkdf(ikm, salt, info, 64);
21
- return [out.subarray(0, 32), out.subarray(32, 64)];
16
+ return [out.subarray(0, 32), out.subarray(32)];
22
17
  }
@@ -3,7 +3,6 @@
3
3
  */
4
4
  export { Ed25519 } from '../curves/Ed25519.js';
5
5
  export { X25519 } from '../curves/X25519.js';
6
- export { decodeBase64Url, assert32 } from '../core/encoding.js';
7
6
  export { hkdf, hkdfSplit } from '../core/hkdf.js';
8
7
  export { toSerializedPubKey, toRawPubKey, prependVersion, readVersionedContent } from '../core/keys.js';
9
8
  export { buildNonce } from '../core/nonce.js';