zapo-js 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (468) hide show
  1. package/README.md +12 -4
  2. package/dist/appstate/WaAppStateCrypto.js +1 -1
  3. package/dist/appstate/WaAppStateSyncClient.js +138 -93
  4. package/dist/appstate/{store/sqlite.js → encoding.js} +13 -8
  5. package/dist/appstate/index.js +8 -6
  6. package/dist/appstate/utils.js +0 -5
  7. package/dist/auth/WaAuthClient.js +36 -47
  8. package/dist/auth/flow/WaAuthCredentialsFlow.js +7 -7
  9. package/dist/auth/index.js +1 -6
  10. package/dist/auth/pairing/WaPairingCodeCrypto.js +6 -4
  11. package/dist/auth/pairing/WaPairingFlow.js +13 -3
  12. package/dist/client/WaClient.js +225 -101
  13. package/dist/client/WaClientFactory.js +294 -44
  14. package/dist/client/connection/WaConnectionManager.js +19 -10
  15. package/dist/client/coordinators/WaBusinessCoordinator.js +241 -0
  16. package/dist/client/coordinators/WaGroupCoordinator.js +11 -7
  17. package/dist/client/coordinators/WaIncomingNodeCoordinator.js +1 -0
  18. package/dist/client/coordinators/WaMessageDispatchCoordinator.js +292 -99
  19. package/dist/client/coordinators/WaPassiveTasksCoordinator.js +74 -31
  20. package/dist/client/coordinators/WaPrivacyCoordinator.js +134 -0
  21. package/dist/client/coordinators/WaProfileCoordinator.js +212 -0
  22. package/dist/client/coordinators/WaRetryCoordinator.js +179 -27
  23. package/dist/client/coordinators/WaStreamControlCoordinator.js +18 -11
  24. package/dist/client/coordinators/WaTrustedContactTokenCoordinator.js +166 -0
  25. package/dist/client/dirty.js +40 -20
  26. package/dist/client/events/devices.js +72 -0
  27. package/dist/client/events/group.js +3 -11
  28. package/dist/client/events/identity.js +22 -0
  29. package/dist/client/events/privacy-token.js +39 -0
  30. package/dist/client/history-sync.js +50 -9
  31. package/dist/client/incoming.js +37 -7
  32. package/dist/client/mailbox.js +24 -23
  33. package/dist/client/messages.js +107 -31
  34. package/dist/client/messaging/fanout.js +21 -11
  35. package/dist/client/messaging/participants.js +6 -4
  36. package/dist/client/persistence/WriteBehindPersistence.js +129 -0
  37. package/dist/client/tokens/cs-token.js +50 -0
  38. package/dist/client/tokens/tc-token.js +25 -0
  39. package/dist/crypto/core/index.js +2 -2
  40. package/dist/crypto/core/keys.js +4 -4
  41. package/dist/crypto/core/nonce.js +2 -0
  42. package/dist/crypto/core/primitives.js +0 -8
  43. package/dist/crypto/core/random.js +22 -0
  44. package/dist/crypto/curves/X25519.js +25 -6
  45. package/dist/crypto/index.js +3 -0
  46. package/dist/crypto/math/constants.js +13 -36
  47. package/dist/crypto/math/edwards.js +171 -44
  48. package/dist/crypto/math/fe.js +706 -0
  49. package/dist/crypto/math/mod.js +10 -3
  50. package/dist/esm/appstate/WaAppStateCrypto.js +1 -1
  51. package/dist/esm/appstate/WaAppStateSyncClient.js +138 -93
  52. package/dist/esm/appstate/{store/sqlite.js → encoding.js} +13 -8
  53. package/dist/esm/appstate/index.js +2 -2
  54. package/dist/esm/appstate/utils.js +2 -5
  55. package/dist/esm/auth/WaAuthClient.js +36 -47
  56. package/dist/esm/auth/flow/WaAuthCredentialsFlow.js +7 -7
  57. package/dist/esm/auth/index.js +0 -2
  58. package/dist/esm/auth/pairing/WaPairingCodeCrypto.js +6 -4
  59. package/dist/esm/auth/pairing/WaPairingFlow.js +14 -4
  60. package/dist/esm/client/WaClient.js +225 -101
  61. package/dist/esm/client/WaClientFactory.js +295 -45
  62. package/dist/esm/client/connection/WaConnectionManager.js +19 -10
  63. package/dist/esm/client/coordinators/WaBusinessCoordinator.js +238 -0
  64. package/dist/esm/client/coordinators/WaGroupCoordinator.js +11 -7
  65. package/dist/esm/client/coordinators/WaIncomingNodeCoordinator.js +1 -0
  66. package/dist/esm/client/coordinators/WaMessageDispatchCoordinator.js +295 -102
  67. package/dist/esm/client/coordinators/WaPassiveTasksCoordinator.js +74 -31
  68. package/dist/esm/client/coordinators/WaPrivacyCoordinator.js +131 -0
  69. package/dist/esm/client/coordinators/WaProfileCoordinator.js +209 -0
  70. package/dist/esm/client/coordinators/WaRetryCoordinator.js +181 -29
  71. package/dist/esm/client/coordinators/WaStreamControlCoordinator.js +19 -12
  72. package/dist/esm/client/coordinators/WaTrustedContactTokenCoordinator.js +162 -0
  73. package/dist/esm/client/dirty.js +40 -20
  74. package/dist/esm/client/events/devices.js +68 -0
  75. package/dist/esm/client/events/group.js +3 -11
  76. package/dist/esm/client/events/identity.js +19 -0
  77. package/dist/esm/client/events/privacy-token.js +36 -0
  78. package/dist/esm/client/history-sync.js +50 -9
  79. package/dist/esm/client/incoming.js +38 -8
  80. package/dist/esm/client/mailbox.js +24 -23
  81. package/dist/esm/client/messages.js +108 -32
  82. package/dist/esm/client/messaging/fanout.js +22 -12
  83. package/dist/esm/client/messaging/participants.js +6 -4
  84. package/dist/esm/client/persistence/WriteBehindPersistence.js +125 -0
  85. package/dist/esm/client/tokens/cs-token.js +46 -0
  86. package/dist/esm/client/tokens/tc-token.js +18 -0
  87. package/dist/esm/crypto/core/index.js +2 -2
  88. package/dist/esm/crypto/core/keys.js +1 -1
  89. package/dist/esm/crypto/core/nonce.js +2 -0
  90. package/dist/esm/crypto/core/primitives.js +0 -7
  91. package/dist/esm/crypto/core/random.js +22 -1
  92. package/dist/esm/crypto/curves/X25519.js +25 -6
  93. package/dist/esm/crypto/index.js +1 -0
  94. package/dist/esm/crypto/math/constants.js +12 -35
  95. package/dist/esm/crypto/math/edwards.js +174 -47
  96. package/dist/esm/crypto/math/fe.js +691 -0
  97. package/dist/esm/crypto/math/mod.js +10 -1
  98. package/dist/esm/index.js +1 -1
  99. package/dist/esm/infra/perf/BackgroundQueue.js +478 -0
  100. package/dist/esm/infra/perf/BoundedTaskQueue.js +3 -1
  101. package/dist/esm/infra/perf/PromiseDedup.js +20 -0
  102. package/dist/esm/infra/perf/SharedExclusiveGate.js +109 -0
  103. package/dist/esm/infra/perf/StoreLock.js +77 -0
  104. package/dist/esm/media/WaMediaCrypto.js +95 -13
  105. package/dist/esm/media/WaMediaTransferClient.js +39 -47
  106. package/dist/esm/media/constants.js +2 -1
  107. package/dist/esm/message/WaMessageClient.js +26 -19
  108. package/dist/esm/message/content.js +195 -9
  109. package/dist/esm/message/icdc.js +76 -0
  110. package/dist/esm/message/incoming.js +24 -12
  111. package/dist/esm/message/phash.js +3 -1
  112. package/dist/esm/message/reporting-token.js +14 -27
  113. package/dist/esm/protocol/appstate.js +9 -40
  114. package/dist/esm/protocol/browser.js +10 -18
  115. package/dist/esm/protocol/constants.js +5 -3
  116. package/dist/esm/protocol/defaults.js +6 -0
  117. package/dist/esm/protocol/index.js +1 -2
  118. package/dist/esm/protocol/jid.js +105 -36
  119. package/dist/esm/protocol/message.js +61 -1
  120. package/dist/esm/protocol/nodes.js +2 -0
  121. package/dist/esm/protocol/notification.js +3 -1
  122. package/dist/esm/protocol/privacy-token.js +17 -0
  123. package/dist/esm/protocol/privacy.js +55 -0
  124. package/dist/esm/protocol/stream.js +26 -1
  125. package/dist/esm/retry/codec.js +216 -0
  126. package/dist/esm/retry/constants.js +1 -1
  127. package/dist/esm/retry/index.js +2 -2
  128. package/dist/esm/retry/parse.js +50 -30
  129. package/dist/esm/retry/replay.js +11 -7
  130. package/dist/esm/retry/tracker.js +50 -12
  131. package/dist/esm/signal/api/SignalDeviceSyncApi.js +49 -32
  132. package/dist/esm/signal/api/SignalDigestSyncApi.js +13 -9
  133. package/dist/esm/signal/api/SignalIdentitySyncApi.js +26 -11
  134. package/dist/esm/signal/api/SignalMissingPreKeysSyncApi.js +18 -7
  135. package/dist/esm/signal/api/SignalRotateKeyApi.js +4 -2
  136. package/dist/esm/signal/api/SignalSessionSyncApi.js +16 -7
  137. package/dist/esm/signal/api/result-map.js +10 -0
  138. package/dist/esm/signal/constants.js +0 -4
  139. package/dist/esm/signal/crypto/WaAdvSignature.js +12 -6
  140. package/dist/esm/signal/{store/sqlite.js → encoding.js} +78 -24
  141. package/dist/esm/signal/group/SenderKeyCodec.js +3 -2
  142. package/dist/esm/signal/group/SenderKeyManager.js +125 -106
  143. package/dist/esm/signal/index.js +1 -0
  144. package/dist/esm/signal/registration/keygen.js +6 -2
  145. package/dist/esm/signal/registration/utils.js +1 -0
  146. package/dist/esm/signal/session/SignalProtocol.js +150 -74
  147. package/dist/esm/signal/session/resolver.js +137 -102
  148. package/dist/esm/store/contracts/privacy-token.store.js +1 -0
  149. package/dist/esm/store/createStore.js +101 -187
  150. package/dist/esm/store/index.js +1 -10
  151. package/dist/esm/store/locks/appstate.lock.js +26 -0
  152. package/dist/esm/store/locks/auth.lock.js +15 -0
  153. package/dist/esm/store/locks/contact.lock.js +20 -0
  154. package/dist/esm/store/locks/device-list.lock.js +20 -0
  155. package/dist/esm/store/locks/message.lock.js +21 -0
  156. package/dist/esm/store/locks/participants.lock.js +20 -0
  157. package/dist/esm/store/locks/privacy-token.lock.js +18 -0
  158. package/dist/esm/store/locks/retry.lock.js +29 -0
  159. package/dist/esm/store/locks/sender-key.lock.js +52 -0
  160. package/dist/esm/store/locks/signal.lock.js +63 -0
  161. package/dist/esm/store/locks/thread.lock.js +21 -0
  162. package/dist/esm/store/noop.store.js +1 -1
  163. package/dist/esm/store/providers/memory/appstate.store.js +22 -24
  164. package/dist/esm/store/providers/memory/device-list.store.js +10 -5
  165. package/dist/esm/store/providers/memory/privacy-token.store.js +43 -0
  166. package/dist/esm/store/providers/memory/retry.store.js +77 -2
  167. package/dist/esm/store/providers/memory/sender-key.store.js +6 -1
  168. package/dist/esm/store/providers/memory/signal.store.js +36 -19
  169. package/dist/esm/transport/WaComms.js +3 -1
  170. package/dist/esm/transport/WaWebSocket.js +0 -6
  171. package/dist/esm/transport/binary/constants.js +0 -30
  172. package/dist/esm/transport/binary/decoder.js +4 -4
  173. package/dist/esm/transport/binary/encoder.js +8 -15
  174. package/dist/esm/transport/binary/index.js +0 -1
  175. package/dist/esm/transport/node/WaNodeOrchestrator.js +25 -19
  176. package/dist/esm/transport/node/builders/business.js +129 -0
  177. package/dist/esm/transport/node/builders/global.js +370 -0
  178. package/dist/esm/transport/node/builders/index.js +5 -2
  179. package/dist/esm/transport/node/builders/message.js +63 -239
  180. package/dist/esm/transport/node/builders/pairing.js +0 -24
  181. package/dist/esm/transport/node/builders/privacy-token.js +41 -0
  182. package/dist/esm/transport/node/builders/privacy.js +48 -0
  183. package/dist/esm/transport/node/builders/profile.js +70 -0
  184. package/dist/esm/transport/node/builders/retry.js +10 -22
  185. package/dist/esm/transport/node/builders/usync.js +6 -2
  186. package/dist/esm/transport/node/helpers.js +19 -1
  187. package/dist/esm/transport/node/usync.js +3 -33
  188. package/dist/esm/transport/node/xml.js +35 -14
  189. package/dist/esm/transport/noise/WaClientPayload.js +10 -10
  190. package/dist/esm/transport/noise/WaNoiseCert.js +3 -3
  191. package/dist/esm/transport/noise/WaNoiseSession.js +64 -23
  192. package/dist/esm/transport/noise/WaNoiseSocket.js +8 -4
  193. package/dist/esm/transport/stream/parse.js +8 -4
  194. package/dist/esm/util/bytes.js +22 -18
  195. package/dist/esm/util/index.js +5 -0
  196. package/dist/esm/util/primitives.js +3 -2
  197. package/dist/index.js +7 -1
  198. package/dist/infra/perf/BackgroundQueue.js +482 -0
  199. package/dist/infra/perf/BoundedTaskQueue.js +3 -1
  200. package/dist/infra/perf/PromiseDedup.js +24 -0
  201. package/dist/infra/perf/SharedExclusiveGate.js +113 -0
  202. package/dist/infra/perf/StoreLock.js +81 -0
  203. package/dist/media/WaMediaCrypto.js +94 -12
  204. package/dist/media/WaMediaTransferClient.js +39 -47
  205. package/dist/media/constants.js +2 -1
  206. package/dist/message/WaMessageClient.js +26 -19
  207. package/dist/message/content.js +198 -9
  208. package/dist/message/icdc.js +81 -0
  209. package/dist/message/incoming.js +24 -12
  210. package/dist/message/phash.js +3 -1
  211. package/dist/message/reporting-token.js +14 -28
  212. package/dist/protocol/appstate.js +10 -41
  213. package/dist/protocol/browser.js +10 -18
  214. package/dist/protocol/constants.js +21 -2
  215. package/dist/protocol/defaults.js +6 -0
  216. package/dist/protocol/index.js +8 -5
  217. package/dist/protocol/jid.js +111 -36
  218. package/dist/protocol/message.js +62 -2
  219. package/dist/protocol/nodes.js +2 -0
  220. package/dist/protocol/notification.js +3 -1
  221. package/dist/protocol/privacy-token.js +20 -0
  222. package/dist/protocol/privacy.js +58 -0
  223. package/dist/protocol/stream.js +27 -2
  224. package/dist/retry/codec.js +220 -0
  225. package/dist/retry/constants.js +1 -1
  226. package/dist/retry/index.js +5 -5
  227. package/dist/retry/parse.js +51 -30
  228. package/dist/retry/replay.js +10 -6
  229. package/dist/retry/tracker.js +50 -12
  230. package/dist/signal/api/SignalDeviceSyncApi.js +48 -31
  231. package/dist/signal/api/SignalDigestSyncApi.js +13 -9
  232. package/dist/signal/api/SignalIdentitySyncApi.js +25 -10
  233. package/dist/signal/api/SignalMissingPreKeysSyncApi.js +17 -6
  234. package/dist/signal/api/SignalRotateKeyApi.js +4 -2
  235. package/dist/signal/api/SignalSessionSyncApi.js +16 -7
  236. package/dist/signal/api/result-map.js +13 -0
  237. package/dist/signal/constants.js +1 -5
  238. package/dist/signal/crypto/WaAdvSignature.js +11 -5
  239. package/dist/signal/{store/sqlite.js → encoding.js} +79 -25
  240. package/dist/signal/group/SenderKeyCodec.js +4 -3
  241. package/dist/signal/group/SenderKeyManager.js +125 -106
  242. package/dist/signal/index.js +13 -1
  243. package/dist/signal/registration/keygen.js +6 -2
  244. package/dist/signal/registration/utils.js +1 -0
  245. package/dist/signal/session/SignalProtocol.js +150 -74
  246. package/dist/signal/session/resolver.js +135 -100
  247. package/dist/store/contracts/privacy-token.store.js +2 -0
  248. package/dist/store/createStore.js +101 -187
  249. package/dist/store/index.js +15 -33
  250. package/dist/store/locks/appstate.lock.js +29 -0
  251. package/dist/store/locks/auth.lock.js +18 -0
  252. package/dist/store/locks/contact.lock.js +23 -0
  253. package/dist/store/locks/device-list.lock.js +23 -0
  254. package/dist/store/locks/message.lock.js +24 -0
  255. package/dist/store/locks/participants.lock.js +23 -0
  256. package/dist/store/locks/privacy-token.lock.js +21 -0
  257. package/dist/store/locks/retry.lock.js +32 -0
  258. package/dist/store/locks/sender-key.lock.js +55 -0
  259. package/dist/store/locks/signal.lock.js +66 -0
  260. package/dist/store/locks/thread.lock.js +24 -0
  261. package/dist/store/noop.store.js +1 -1
  262. package/dist/store/providers/memory/appstate.store.js +22 -24
  263. package/dist/store/providers/memory/device-list.store.js +10 -5
  264. package/dist/store/providers/memory/privacy-token.store.js +47 -0
  265. package/dist/store/providers/memory/retry.store.js +77 -2
  266. package/dist/store/providers/memory/sender-key.store.js +6 -1
  267. package/dist/store/providers/memory/signal.store.js +36 -19
  268. package/dist/transport/WaComms.js +3 -1
  269. package/dist/transport/WaWebSocket.js +0 -6
  270. package/dist/transport/binary/constants.js +1 -31
  271. package/dist/transport/binary/decoder.js +4 -4
  272. package/dist/transport/binary/encoder.js +8 -15
  273. package/dist/transport/binary/index.js +0 -4
  274. package/dist/transport/node/WaNodeOrchestrator.js +24 -18
  275. package/dist/transport/node/builders/business.js +137 -0
  276. package/dist/transport/node/builders/global.js +375 -0
  277. package/dist/transport/node/builders/index.js +18 -9
  278. package/dist/transport/node/builders/message.js +64 -245
  279. package/dist/transport/node/builders/pairing.js +0 -26
  280. package/dist/transport/node/builders/privacy-token.js +46 -0
  281. package/dist/transport/node/builders/privacy.js +55 -0
  282. package/dist/transport/node/builders/profile.js +78 -0
  283. package/dist/transport/node/builders/retry.js +9 -21
  284. package/dist/transport/node/builders/usync.js +6 -2
  285. package/dist/transport/node/helpers.js +20 -1
  286. package/dist/transport/node/usync.js +2 -32
  287. package/dist/transport/node/xml.js +35 -14
  288. package/dist/transport/noise/WaClientPayload.js +13 -13
  289. package/dist/transport/noise/WaNoiseCert.js +2 -2
  290. package/dist/transport/noise/WaNoiseSession.js +64 -23
  291. package/dist/transport/noise/WaNoiseSocket.js +8 -4
  292. package/dist/transport/stream/parse.js +7 -3
  293. package/dist/types/appstate/encoding.d.ts +7 -0
  294. package/dist/types/appstate/index.d.ts +3 -3
  295. package/dist/types/appstate/utils.d.ts +0 -2
  296. package/dist/types/auth/flow/WaAuthCredentialsFlow.d.ts +1 -1
  297. package/dist/types/auth/index.d.ts +0 -2
  298. package/dist/types/auth/types.d.ts +1 -0
  299. package/dist/types/client/WaClient.d.ts +27 -12
  300. package/dist/types/client/WaClientFactory.d.ts +12 -4
  301. package/dist/types/client/connection/WaConnectionManager.d.ts +2 -0
  302. package/dist/types/client/coordinators/WaBusinessCoordinator.d.ts +57 -0
  303. package/dist/types/client/coordinators/WaIncomingNodeCoordinator.d.ts +3 -1
  304. package/dist/types/client/coordinators/WaMessageDispatchCoordinator.d.ts +14 -0
  305. package/dist/types/client/coordinators/WaPassiveTasksCoordinator.d.ts +4 -0
  306. package/dist/types/client/coordinators/WaPrivacyCoordinator.d.ts +26 -0
  307. package/dist/types/client/coordinators/WaProfileCoordinator.d.ts +36 -0
  308. package/dist/types/client/coordinators/WaRetryCoordinator.d.ts +6 -0
  309. package/dist/types/client/coordinators/WaStreamControlCoordinator.d.ts +3 -2
  310. package/dist/types/client/coordinators/WaTrustedContactTokenCoordinator.d.ts +45 -0
  311. package/dist/types/client/events/devices.d.ts +20 -0
  312. package/dist/types/client/events/identity.d.ts +9 -0
  313. package/dist/types/client/events/privacy-token.d.ts +7 -0
  314. package/dist/types/client/history-sync.d.ts +9 -6
  315. package/dist/types/client/incoming.d.ts +3 -1
  316. package/dist/types/client/index.d.ts +1 -1
  317. package/dist/types/client/mailbox.d.ts +3 -5
  318. package/dist/types/client/messages.d.ts +1 -2
  319. package/dist/types/client/persistence/WriteBehindPersistence.d.ts +34 -0
  320. package/dist/types/client/tokens/cs-token.d.ts +10 -0
  321. package/dist/types/client/tokens/tc-token.d.ts +5 -0
  322. package/dist/types/client/types.d.ts +51 -3
  323. package/dist/types/crypto/core/index.d.ts +2 -2
  324. package/dist/types/crypto/core/nonce.d.ts +2 -0
  325. package/dist/types/crypto/core/primitives.d.ts +0 -1
  326. package/dist/types/crypto/core/random.d.ts +1 -0
  327. package/dist/types/crypto/index.d.ts +1 -0
  328. package/dist/types/crypto/math/constants.d.ts +4 -2
  329. package/dist/types/crypto/math/fe.d.ts +30 -0
  330. package/dist/types/crypto/math/mod.d.ts +0 -2
  331. package/dist/types/crypto/math/types.d.ts +11 -4
  332. package/dist/types/index.d.ts +5 -3
  333. package/dist/types/infra/perf/BackgroundQueue.d.ts +58 -0
  334. package/dist/types/infra/perf/PromiseDedup.d.ts +4 -0
  335. package/dist/types/infra/perf/SharedExclusiveGate.d.ts +17 -0
  336. package/dist/types/infra/perf/StoreLock.d.ts +10 -0
  337. package/dist/types/media/WaMediaCrypto.d.ts +3 -2
  338. package/dist/types/media/WaMediaTransferClient.d.ts +3 -12
  339. package/dist/types/media/constants.d.ts +1 -1
  340. package/dist/types/media/index.d.ts +1 -1
  341. package/dist/types/media/types.d.ts +10 -2
  342. package/dist/types/message/content.d.ts +8 -0
  343. package/dist/types/message/icdc.d.ts +13 -0
  344. package/dist/types/message/reporting-token.d.ts +0 -1
  345. package/dist/types/message/types.d.ts +45 -6
  346. package/dist/types/protocol/appstate.d.ts +0 -11
  347. package/dist/types/protocol/constants.d.ts +7 -3
  348. package/dist/types/protocol/defaults.d.ts +6 -0
  349. package/dist/types/protocol/index.d.ts +1 -2
  350. package/dist/types/protocol/jid.d.ts +19 -2
  351. package/dist/types/protocol/message.d.ts +60 -0
  352. package/dist/types/protocol/nodes.d.ts +2 -0
  353. package/dist/types/protocol/notification.d.ts +2 -0
  354. package/dist/types/protocol/privacy-token.d.ts +17 -0
  355. package/dist/types/protocol/privacy.d.ts +75 -0
  356. package/dist/types/protocol/stream.d.ts +30 -0
  357. package/dist/types/retry/codec.d.ts +3 -0
  358. package/dist/types/retry/index.d.ts +3 -3
  359. package/dist/types/retry/parse.d.ts +5 -2
  360. package/dist/types/retry/tracker.d.ts +1 -0
  361. package/dist/types/retry/types.d.ts +6 -1
  362. package/dist/types/signal/api/SignalDeviceSyncApi.d.ts +2 -1
  363. package/dist/types/signal/api/SignalDigestSyncApi.d.ts +6 -0
  364. package/dist/types/signal/api/SignalIdentitySyncApi.d.ts +2 -0
  365. package/dist/types/signal/api/SignalRotateKeyApi.d.ts +4 -5
  366. package/dist/types/signal/api/SignalSessionSyncApi.d.ts +8 -6
  367. package/dist/types/signal/api/result-map.d.ts +1 -0
  368. package/dist/types/signal/constants.d.ts +0 -3
  369. package/dist/types/signal/{store/sqlite.d.ts → encoding.d.ts} +3 -3
  370. package/dist/types/signal/group/SenderKeyManager.d.ts +10 -5
  371. package/dist/types/signal/index.d.ts +2 -0
  372. package/dist/types/signal/session/SignalProtocol.d.ts +10 -4
  373. package/dist/types/signal/session/resolver.d.ts +7 -2
  374. package/dist/types/store/contracts/appstate.store.d.ts +1 -1
  375. package/dist/types/store/contracts/privacy-token.store.d.ts +16 -0
  376. package/dist/types/store/contracts/retry.store.d.ts +7 -0
  377. package/dist/types/store/contracts/signal.store.d.ts +7 -0
  378. package/dist/types/store/createStore.d.ts +1 -1
  379. package/dist/types/store/index.d.ts +5 -13
  380. package/dist/types/store/locks/appstate.lock.d.ts +3 -0
  381. package/dist/types/store/locks/auth.lock.d.ts +3 -0
  382. package/dist/types/store/locks/contact.lock.d.ts +3 -0
  383. package/dist/types/store/locks/device-list.lock.d.ts +2 -0
  384. package/dist/types/store/locks/message.lock.d.ts +3 -0
  385. package/dist/types/store/locks/participants.lock.d.ts +2 -0
  386. package/dist/types/store/locks/privacy-token.lock.d.ts +2 -0
  387. package/dist/types/store/locks/retry.lock.d.ts +2 -0
  388. package/dist/types/store/locks/sender-key.lock.d.ts +3 -0
  389. package/dist/types/store/locks/signal.lock.d.ts +3 -0
  390. package/dist/types/store/locks/thread.lock.d.ts +3 -0
  391. package/dist/types/store/providers/memory/appstate.store.d.ts +1 -1
  392. package/dist/types/store/providers/memory/privacy-token.store.d.ts +13 -0
  393. package/dist/types/store/providers/memory/retry.store.d.ts +8 -0
  394. package/dist/types/store/providers/memory/signal.store.d.ts +2 -1
  395. package/dist/types/store/types.d.ts +49 -61
  396. package/dist/types/transport/WaWebSocket.d.ts +0 -1
  397. package/dist/types/transport/binary/constants.d.ts +0 -30
  398. package/dist/types/transport/binary/index.d.ts +0 -1
  399. package/dist/types/transport/node/WaNodeOrchestrator.d.ts +3 -4
  400. package/dist/types/transport/node/builders/business.d.ts +29 -0
  401. package/dist/types/transport/node/builders/global.d.ts +102 -0
  402. package/dist/types/transport/node/builders/index.d.ts +5 -2
  403. package/dist/types/transport/node/builders/message.d.ts +8 -7
  404. package/dist/types/transport/node/builders/pairing.d.ts +0 -2
  405. package/dist/types/transport/node/builders/privacy-token.d.ts +9 -0
  406. package/dist/types/transport/node/builders/privacy.d.ts +7 -0
  407. package/dist/types/transport/node/builders/profile.d.ts +8 -0
  408. package/dist/types/transport/node/builders/retry.d.ts +0 -1
  409. package/dist/types/transport/node/helpers.d.ts +5 -0
  410. package/dist/types/transport/noise/WaNoiseSession.d.ts +3 -2
  411. package/dist/types/transport/noise/WaNoiseSocket.d.ts +4 -2
  412. package/dist/types/util/bytes.d.ts +1 -1
  413. package/dist/types/util/index.d.ts +5 -0
  414. package/dist/types/util/primitives.d.ts +0 -1
  415. package/dist/util/bytes.js +22 -18
  416. package/dist/util/index.js +23 -0
  417. package/dist/util/primitives.js +2 -2
  418. package/package.json +29 -7
  419. package/proto/index.js +1 -1
  420. package/dist/crypto/core/constants.js +0 -4
  421. package/dist/esm/crypto/core/constants.js +0 -1
  422. package/dist/esm/retry/outbound.js +0 -82
  423. package/dist/esm/store/providers/sqlite/BaseSqliteStore.js +0 -37
  424. package/dist/esm/store/providers/sqlite/appstate.store.js +0 -250
  425. package/dist/esm/store/providers/sqlite/auth.store.js +0 -176
  426. package/dist/esm/store/providers/sqlite/connection.js +0 -245
  427. package/dist/esm/store/providers/sqlite/contact.store.js +0 -74
  428. package/dist/esm/store/providers/sqlite/device-list.store.js +0 -127
  429. package/dist/esm/store/providers/sqlite/message.store.js +0 -132
  430. package/dist/esm/store/providers/sqlite/migrations.js +0 -347
  431. package/dist/esm/store/providers/sqlite/participants.store.js +0 -77
  432. package/dist/esm/store/providers/sqlite/retry.store.js +0 -141
  433. package/dist/esm/store/providers/sqlite/sender-key.store.js +0 -198
  434. package/dist/esm/store/providers/sqlite/signal.store.js +0 -435
  435. package/dist/esm/store/providers/sqlite/table-names.js +0 -107
  436. package/dist/esm/store/providers/sqlite/thread.store.js +0 -85
  437. package/dist/retry/outbound.js +0 -87
  438. package/dist/store/providers/sqlite/BaseSqliteStore.js +0 -41
  439. package/dist/store/providers/sqlite/appstate.store.js +0 -254
  440. package/dist/store/providers/sqlite/auth.store.js +0 -180
  441. package/dist/store/providers/sqlite/connection.js +0 -281
  442. package/dist/store/providers/sqlite/contact.store.js +0 -78
  443. package/dist/store/providers/sqlite/device-list.store.js +0 -131
  444. package/dist/store/providers/sqlite/message.store.js +0 -136
  445. package/dist/store/providers/sqlite/migrations.js +0 -350
  446. package/dist/store/providers/sqlite/participants.store.js +0 -81
  447. package/dist/store/providers/sqlite/retry.store.js +0 -145
  448. package/dist/store/providers/sqlite/sender-key.store.js +0 -202
  449. package/dist/store/providers/sqlite/signal.store.js +0 -439
  450. package/dist/store/providers/sqlite/table-names.js +0 -113
  451. package/dist/store/providers/sqlite/thread.store.js +0 -89
  452. package/dist/types/appstate/store/sqlite.d.ts +0 -7
  453. package/dist/types/crypto/core/constants.d.ts +0 -1
  454. package/dist/types/retry/outbound.d.ts +0 -4
  455. package/dist/types/store/providers/sqlite/BaseSqliteStore.d.ts +0 -12
  456. package/dist/types/store/providers/sqlite/appstate.store.d.ts +0 -17
  457. package/dist/types/store/providers/sqlite/auth.store.d.ts +0 -10
  458. package/dist/types/store/providers/sqlite/connection.d.ts +0 -10
  459. package/dist/types/store/providers/sqlite/contact.store.d.ts +0 -12
  460. package/dist/types/store/providers/sqlite/device-list.store.d.ts +0 -15
  461. package/dist/types/store/providers/sqlite/message.store.d.ts +0 -13
  462. package/dist/types/store/providers/sqlite/migrations.d.ts +0 -3
  463. package/dist/types/store/providers/sqlite/participants.store.d.ts +0 -12
  464. package/dist/types/store/providers/sqlite/retry.store.d.ts +0 -15
  465. package/dist/types/store/providers/sqlite/sender-key.store.d.ts +0 -24
  466. package/dist/types/store/providers/sqlite/signal.store.d.ts +0 -53
  467. package/dist/types/store/providers/sqlite/table-names.d.ts +0 -5
  468. package/dist/types/store/providers/sqlite/thread.store.d.ts +0 -13
@@ -1,20 +1,25 @@
1
1
  import { randomBytesAsync, sha256 } from '../../crypto/index.js';
2
+ import { PromiseDedup } from '../../infra/perf/PromiseDedup.js';
2
3
  import { ensureMessageSecret } from '../../message/index.js';
3
- import { resolveMessageTypeAttr } from '../../message/content.js';
4
+ import { resolveEditAttr, resolveEncMediaType, resolveMessageTypeAttr, resolveMetaAttrs } from '../../message/content.js';
4
5
  import { wrapDeviceSentMessage } from '../../message/device-sent.js';
6
+ import { injectDeviceListMetadata, resolveIcdcMeta } from '../../message/icdc.js';
5
7
  import { writeRandomPadMax16 } from '../../message/padding.js';
6
8
  import { computePhashV2 } from '../../message/phash.js';
7
9
  import { buildReportingTokenArtifacts } from '../../message/reporting-token.js';
8
10
  import { proto } from '../../proto.js';
9
11
  import { WA_DEFAULTS } from '../../protocol/constants.js';
10
- import { isGroupJid, normalizeDeviceJid, normalizeRecipientJid, parseSignalAddressFromJid, splitJid, toUserJid } from '../../protocol/jid.js';
12
+ import { isGroupJid, normalizeDeviceJid, normalizeRecipientJid, parseJidFull, parseSignalAddressFromJid, splitJid, toUserJid } from '../../protocol/jid.js';
11
13
  import { signalAddressKey } from '../../protocol/jid.js';
12
14
  import { encodeBinaryNode } from '../../transport/binary/index.js';
13
- import { buildDirectMessageFanoutNode, buildGroupDirectMessageNode, buildGroupSenderKeyMessageNode } from '../../transport/node/builders/message.js';
15
+ import { buildDirectMessageFanoutNode, buildGroupSenderKeyMessageNode, buildMetaNode } from '../../transport/node/builders/message.js';
14
16
  import { bytesToHex, concatBytes, TEXT_ENCODER } from '../../util/bytes.js';
15
17
  import { toError } from '../../util/primitives.js';
16
18
  export class WaMessageDispatchCoordinator {
17
19
  constructor(options) {
20
+ this.icdcDedup = new PromiseDedup();
21
+ this.privacyTokenDedup = new PromiseDedup();
22
+ this.distributionDedup = new PromiseDedup();
18
23
  this.logger = options.logger;
19
24
  this.messageClient = options.messageClient;
20
25
  this.retryTracker = options.retryTracker;
@@ -25,9 +30,13 @@ export class WaMessageDispatchCoordinator {
25
30
  this.buildMessageContent = options.buildMessageContent;
26
31
  this.senderKeyManager = options.senderKeyManager;
27
32
  this.signalProtocol = options.signalProtocol;
33
+ this.signalStore = options.signalStore;
34
+ this.deviceListStore = options.deviceListStore;
28
35
  this.getCurrentMeJid = options.getCurrentMeJid;
29
36
  this.getCurrentMeLid = options.getCurrentMeLid;
30
37
  this.getCurrentSignedIdentity = options.getCurrentSignedIdentity;
38
+ this.resolvePrivacyTokenNode = options.resolvePrivacyTokenNode;
39
+ this.onDirectMessageSent = options.onDirectMessageSent;
31
40
  }
32
41
  async publishMessageNode(node, options = {}) {
33
42
  this.logger.debug('wa client publish message node', {
@@ -68,7 +77,8 @@ export class WaMessageDispatchCoordinator {
68
77
  toJid: input.to,
69
78
  type: input.type ?? 'text',
70
79
  replayPayload,
71
- participantJid: input.participant
80
+ participantJid: input.participant,
81
+ eligibleRequesterDeviceJids: [input.to]
72
82
  }, async () => this.messageClient.publishEncrypted(input, options));
73
83
  }
74
84
  async publishSignalMessage(input, options = {}) {
@@ -98,7 +108,8 @@ export class WaMessageDispatchCoordinator {
98
108
  toJid: input.to,
99
109
  type: messageType,
100
110
  replayPayload,
101
- participantJid: input.participant
111
+ participantJid: input.participant,
112
+ eligibleRequesterDeviceJids: [input.to]
102
113
  }, async () => this.messageClient.publishEncrypted({
103
114
  to: input.to,
104
115
  encType: encrypted.type,
@@ -118,16 +129,32 @@ export class WaMessageDispatchCoordinator {
118
129
  this.withResolvedMessageId(options)
119
130
  ]);
120
131
  const messageWithSecret = await ensureMessageSecret(message);
121
- const plaintext = await writeRandomPadMax16(proto.Message.encode(messageWithSecret).finish());
122
- const type = resolveMessageTypeAttr(messageWithSecret);
123
- if (isGroupJid(recipientJid)) {
124
- if (this.shouldUseGroupDirectPath(messageWithSecret)) {
125
- return this.publishGroupDirectMessage(recipientJid, messageWithSecret, plaintext, type, sendOptions);
132
+ const meJid = this.getCurrentMeJid();
133
+ const regInfo = meJid ? await this.signalStore.getRegistrationInfo() : null;
134
+ const localPubKey = regInfo?.identityKeyPair.pubKey;
135
+ const meParsed = meJid ? parseJidFull(meJid) : undefined;
136
+ const meUserJid = meParsed?.userJid;
137
+ const localIdentity = meParsed && localPubKey ? { address: meParsed.address, pubKey: localPubKey } : undefined;
138
+ const isGroup = isGroupJid(recipientJid);
139
+ const [senderIcdc, recipientIcdc] = await Promise.all([
140
+ meUserJid ? this.resolveUserIcdc(meUserJid, localIdentity) : null,
141
+ !isGroup ? this.resolveUserIcdc(toUserJid(recipientJid)) : null
142
+ ]);
143
+ const messageWithIcdc = injectDeviceListMetadata(messageWithSecret, senderIcdc, recipientIcdc);
144
+ const plaintext = await writeRandomPadMax16(proto.Message.encode(messageWithIcdc).finish());
145
+ const type = resolveMessageTypeAttr(messageWithIcdc);
146
+ const edit = resolveEditAttr(messageWithIcdc, sendOptions.subtype) ?? undefined;
147
+ const mediatype = resolveEncMediaType(messageWithIcdc) ?? undefined;
148
+ const metaAttrs = resolveMetaAttrs(messageWithIcdc);
149
+ const metaNode = metaAttrs ? buildMetaNode(metaAttrs) : undefined;
150
+ if (isGroup) {
151
+ if (this.shouldUseGroupDirectPath(messageWithIcdc)) {
152
+ return this.publishGroupDirectMessage(recipientJid, messageWithIcdc, plaintext, type, sendOptions, {}, edit, mediatype, metaNode);
126
153
  }
127
- return this.publishGroupSenderKeyMessage(recipientJid, messageWithSecret, plaintext, type, sendOptions);
154
+ return this.publishGroupSenderKeyMessage(recipientJid, messageWithIcdc, plaintext, type, sendOptions, {}, edit, mediatype, metaNode);
128
155
  }
129
156
  const directRecipientJid = toUserJid(recipientJid);
130
- return this.publishDirectSignalMessageWithFanout(directRecipientJid, messageWithSecret, plaintext, type, sendOptions);
157
+ return this.publishDirectSignalMessageWithFanout(directRecipientJid, messageWithIcdc, plaintext, type, sendOptions, edit, mediatype, metaNode);
131
158
  }
132
159
  async syncSignalSession(jid, reasonIdentity = false) {
133
160
  const address = parseSignalAddressFromJid(jid);
@@ -156,7 +183,7 @@ export class WaMessageDispatchCoordinator {
156
183
  }
157
184
  return message.keepInChatMessage?.keepType === proto.KeepType.UNDO_KEEP_FOR_ALL;
158
185
  }
159
- async publishGroupDirectMessage(groupJid, message, plaintext, type, options, retryContext = {}) {
186
+ async publishGroupDirectMessage(groupJid, message, plaintext, type, options, retryContext = {}, edit, mediatype, metaNode) {
160
187
  const sendOptions = await this.withResolvedMessageId(options);
161
188
  const meJid = this.requireCurrentMeJid('sendMessage');
162
189
  const participantUserJids = retryContext.forceRefreshParticipants
@@ -169,37 +196,68 @@ export class WaMessageDispatchCoordinator {
169
196
  if (fanoutDeviceJids.length === 0) {
170
197
  throw new Error('group direct send resolved no target devices');
171
198
  }
172
- await this.sessionResolver.ensureSessionsBatch(fanoutDeviceJids);
173
- const participantAddresses = fanoutDeviceJids.map((targetJid) => parseSignalAddressFromJid(targetJid));
174
- const encryptedParticipants = await this.signalProtocol.encryptMessagesBatch(participantAddresses.map((address) => ({
175
- address,
176
- plaintext
177
- })));
178
- const participants = fanoutDeviceJids.map((targetJid, index) => ({
179
- jid: targetJid,
180
- encType: encryptedParticipants[index].type,
181
- ciphertext: encryptedParticipants[index].ciphertext
182
- }));
183
- const shouldAttachDeviceIdentity = participants.some((participant) => participant.encType === 'pkmsg');
184
- const localPhash = await computePhashV2([...fanoutDeviceJids, senderForPhash]);
185
- const reportingArtifacts = await this.tryBuildReportingTokenArtifacts({
186
- message,
187
- stanzaId: sendOptions.id,
188
- senderUserJid: toUserJid(senderForPhash),
189
- remoteJid: groupJid,
190
- context: 'group_direct'
191
- });
192
- const messageNode = buildGroupDirectMessageNode({
199
+ const resolvedFanoutTargets = await this.sessionResolver.ensureSessionsBatch(fanoutDeviceJids);
200
+ const uniqueNormalizedFanoutJids = new Set();
201
+ for (let index = 0; index < fanoutDeviceJids.length; index += 1) {
202
+ uniqueNormalizedFanoutJids.add(normalizeDeviceJid(fanoutDeviceJids[index]));
203
+ }
204
+ if (resolvedFanoutTargets.length !== uniqueNormalizedFanoutJids.size) {
205
+ throw new Error('group direct send resolved incomplete signal sessions');
206
+ }
207
+ const participantEncryptRequests = new Array(resolvedFanoutTargets.length);
208
+ for (let index = 0; index < resolvedFanoutTargets.length; index += 1) {
209
+ const target = resolvedFanoutTargets[index];
210
+ participantEncryptRequests[index] = {
211
+ address: target.address,
212
+ plaintext
213
+ };
214
+ }
215
+ const encryptedParticipants = await this.signalProtocol.encryptMessagesBatch(participantEncryptRequests, resolvedFanoutTargets);
216
+ const participants = new Array(resolvedFanoutTargets.length);
217
+ for (let index = 0; index < resolvedFanoutTargets.length; index += 1) {
218
+ const target = resolvedFanoutTargets[index];
219
+ participants[index] = {
220
+ jid: target.jid,
221
+ encType: encryptedParticipants[index].type,
222
+ ciphertext: encryptedParticipants[index].ciphertext
223
+ };
224
+ }
225
+ let shouldAttachDeviceIdentity = false;
226
+ for (let index = 0; index < participants.length; index += 1) {
227
+ if (participants[index].encType === 'pkmsg') {
228
+ shouldAttachDeviceIdentity = true;
229
+ break;
230
+ }
231
+ }
232
+ const phashTargets = new Array(resolvedFanoutTargets.length + 1);
233
+ for (let index = 0; index < resolvedFanoutTargets.length; index += 1) {
234
+ phashTargets[index] = resolvedFanoutTargets[index].jid;
235
+ }
236
+ phashTargets[resolvedFanoutTargets.length] = senderForPhash;
237
+ const [localPhash, reportingArtifacts] = await Promise.all([
238
+ computePhashV2(phashTargets),
239
+ this.tryBuildReportingTokenArtifacts({
240
+ message,
241
+ stanzaId: sendOptions.id,
242
+ senderUserJid: toUserJid(senderForPhash),
243
+ remoteJid: groupJid,
244
+ context: 'group_direct'
245
+ })
246
+ ]);
247
+ const messageNode = buildDirectMessageFanoutNode({
193
248
  to: groupJid,
194
249
  type,
195
250
  id: sendOptions.id,
251
+ edit,
196
252
  phash: localPhash,
197
253
  addressingMode,
198
254
  participants,
199
255
  deviceIdentity: shouldAttachDeviceIdentity
200
256
  ? this.getEncodedSignedDeviceIdentity()
201
257
  : undefined,
202
- reportingNode: reportingArtifacts?.node ?? undefined
258
+ reportingNode: reportingArtifacts?.node ?? undefined,
259
+ metaNode,
260
+ mediatype
203
261
  });
204
262
  const replayPayload = {
205
263
  mode: 'plaintext',
@@ -211,7 +269,8 @@ export class WaMessageDispatchCoordinator {
211
269
  messageIdHint: sendOptions.id ?? messageNode.attrs.id,
212
270
  toJid: groupJid,
213
271
  type,
214
- replayPayload
272
+ replayPayload,
273
+ eligibleRequesterDeviceJids: undefined
215
274
  }, async () => this.messageClient.publishNode(messageNode, sendOptions));
216
275
  const ackError = result.ack.error;
217
276
  const serverPhash = result.ack.phash;
@@ -237,11 +296,11 @@ export class WaMessageDispatchCoordinator {
237
296
  retried: true,
238
297
  forceRefreshParticipants: true,
239
298
  forceAddressingMode: serverAddressingMode
240
- });
299
+ }, edit, mediatype, metaNode);
241
300
  }
242
301
  return result;
243
302
  }
244
- async publishGroupSenderKeyMessage(groupJid, message, plaintext, type, options, retryContext = {}) {
303
+ async publishGroupSenderKeyMessage(groupJid, message, plaintext, type, options, retryContext = {}, edit, mediatype, metaNode) {
245
304
  const sendOptions = await this.withResolvedMessageId(options);
246
305
  const meJid = this.requireCurrentMeJid('sendMessage');
247
306
  const participantUserJids = retryContext.forceRefreshParticipants
@@ -251,23 +310,36 @@ export class WaMessageDispatchCoordinator {
251
310
  this.resolveGroupAddressingMode(participantUserJids, groupJid);
252
311
  const senderJid = this.resolveSenderForAddressingMode(addressingMode, meJid);
253
312
  const sender = parseSignalAddressFromJid(senderJid);
254
- const senderKeyDistributionMessage = await this.senderKeyManager.createSenderKeyDistributionMessage(groupJid, sender);
255
- const groupCiphertext = await this.senderKeyManager.encryptGroupMessage(groupJid, sender, plaintext);
256
- const distributionData = await this.encryptGroupDistributionParticipants(groupJid, sender, senderKeyDistributionMessage, participantUserJids);
313
+ const { distributionMessage: senderKeyDistributionMessage, ciphertext: groupCiphertext, keyId: senderKeyId } = await this.senderKeyManager.prepareGroupEncryption(groupJid, sender, plaintext);
314
+ const distributionData = await this.distributionDedup.run(`dist:${groupJid}:${senderKeyId}`, () => this.encryptGroupDistributionParticipants(groupJid, senderKeyId, senderKeyDistributionMessage, participantUserJids));
257
315
  const { fanoutDeviceJids, distributionParticipants } = distributionData;
258
- const shouldAttachDeviceIdentity = distributionParticipants.some((participant) => participant.encType === 'pkmsg');
259
- const localPhash = await computePhashV2([...fanoutDeviceJids, senderJid]);
260
- const reportingArtifacts = await this.tryBuildReportingTokenArtifacts({
261
- message,
262
- stanzaId: sendOptions.id,
263
- senderUserJid: toUserJid(senderJid),
264
- remoteJid: groupJid,
265
- context: 'group_sender_key'
266
- });
316
+ let shouldAttachDeviceIdentity = false;
317
+ for (let index = 0; index < distributionParticipants.length; index += 1) {
318
+ if (distributionParticipants[index].encType === 'pkmsg') {
319
+ shouldAttachDeviceIdentity = true;
320
+ break;
321
+ }
322
+ }
323
+ const phashTargets = new Array(fanoutDeviceJids.length + 1);
324
+ for (let index = 0; index < fanoutDeviceJids.length; index += 1) {
325
+ phashTargets[index] = fanoutDeviceJids[index];
326
+ }
327
+ phashTargets[fanoutDeviceJids.length] = senderJid;
328
+ const [localPhash, reportingArtifacts] = await Promise.all([
329
+ computePhashV2(phashTargets),
330
+ this.tryBuildReportingTokenArtifacts({
331
+ message,
332
+ stanzaId: sendOptions.id,
333
+ senderUserJid: toUserJid(senderJid),
334
+ remoteJid: groupJid,
335
+ context: 'group_sender_key'
336
+ })
337
+ ]);
267
338
  const messageNode = buildGroupSenderKeyMessageNode({
268
339
  to: groupJid,
269
340
  type,
270
341
  id: sendOptions.id,
342
+ edit,
271
343
  phash: localPhash,
272
344
  addressingMode,
273
345
  groupCiphertext: groupCiphertext.ciphertext,
@@ -275,7 +347,9 @@ export class WaMessageDispatchCoordinator {
275
347
  deviceIdentity: shouldAttachDeviceIdentity
276
348
  ? this.getEncodedSignedDeviceIdentity()
277
349
  : undefined,
278
- reportingNode: reportingArtifacts?.node ?? undefined
350
+ reportingNode: reportingArtifacts?.node ?? undefined,
351
+ metaNode,
352
+ mediatype
279
353
  });
280
354
  const replayPayload = {
281
355
  mode: 'plaintext',
@@ -287,11 +361,15 @@ export class WaMessageDispatchCoordinator {
287
361
  messageIdHint: sendOptions.id ?? messageNode.attrs.id,
288
362
  toJid: groupJid,
289
363
  type,
290
- replayPayload
364
+ replayPayload,
365
+ eligibleRequesterDeviceJids: undefined
291
366
  }, async () => this.messageClient.publishNode(messageNode, sendOptions));
292
- const distributedAddresses = distributionParticipants.map((participant) => participant.address);
367
+ const distributedAddresses = new Array(distributionParticipants.length);
368
+ for (let index = 0; index < distributionParticipants.length; index += 1) {
369
+ distributedAddresses[index] = distributionParticipants[index].address;
370
+ }
293
371
  try {
294
- await this.senderKeyManager.markSenderKeyDistributed(groupJid, sender, distributedAddresses);
372
+ await this.senderKeyManager.markSenderKeyDistributed(groupJid, senderKeyId, distributedAddresses);
295
373
  }
296
374
  catch (error) {
297
375
  this.logger.warn('failed to mark sender key distribution targets', {
@@ -324,12 +402,13 @@ export class WaMessageDispatchCoordinator {
324
402
  retried: true,
325
403
  forceRefreshParticipants: true,
326
404
  forceAddressingMode: serverAddressingMode
327
- });
405
+ }, edit, mediatype, metaNode);
328
406
  }
329
407
  return result;
330
408
  }
331
409
  resolveGroupAddressingMode(participantUserJids, groupJid) {
332
- for (const participantJid of participantUserJids) {
410
+ for (let index = 0; index < participantUserJids.length; index += 1) {
411
+ const participantJid = participantUserJids[index];
333
412
  try {
334
413
  if (splitJid(participantJid).server === 'lid') {
335
414
  return 'lid';
@@ -362,7 +441,7 @@ export class WaMessageDispatchCoordinator {
362
441
  }
363
442
  return normalizeDeviceJid(meJid);
364
443
  }
365
- async encryptGroupDistributionParticipants(groupJid, sender, senderKeyDistributionMessage, participantUserJids) {
444
+ async encryptGroupDistributionParticipants(groupJid, senderKeyId, senderKeyDistributionMessage, participantUserJids) {
366
445
  const distributionPayload = await writeRandomPadMax16(proto.Message.encode({
367
446
  senderKeyDistributionMessage
368
447
  }).finish());
@@ -381,7 +460,7 @@ export class WaMessageDispatchCoordinator {
381
460
  fanoutAddresses[index] = address;
382
461
  fanoutTargetsByAddressKey.set(signalAddressKey(address), { jid, address });
383
462
  }
384
- const pendingAddresses = await this.senderKeyManager.filterParticipantsNeedingDistribution(groupJid, sender, fanoutAddresses);
463
+ const pendingAddresses = await this.senderKeyManager.filterParticipantsNeedingDistribution(groupJid, senderKeyId, fanoutAddresses);
385
464
  if (pendingAddresses.length === 0) {
386
465
  return {
387
466
  fanoutDeviceJids,
@@ -411,50 +490,82 @@ export class WaMessageDispatchCoordinator {
411
490
  for (let index = 0; index < pendingTargets.length; index += 1) {
412
491
  pendingTargetJids[index] = pendingTargets[index].jid;
413
492
  }
493
+ let availableTargets = [];
494
+ let prefetchedAvailableTargets;
414
495
  try {
415
- await this.sessionResolver.ensureSessionsBatch(pendingTargetJids);
496
+ const resolvedTargets = await this.sessionResolver.ensureSessionsBatch(pendingTargetJids);
497
+ availableTargets = resolvedTargets;
498
+ prefetchedAvailableTargets = resolvedTargets;
416
499
  }
417
500
  catch (error) {
501
+ const normalized = toError(error);
502
+ if (normalized.message === 'identity mismatch') {
503
+ throw normalized;
504
+ }
418
505
  this.logger.warn('group sender-key distribution session sync failed, continuing with available sessions', {
419
506
  groupJid,
420
507
  requested: pendingTargetJids.length,
421
- message: toError(error).message
508
+ message: normalized.message
422
509
  });
510
+ const pendingTargetAddresses = new Array(pendingTargets.length);
511
+ for (let index = 0; index < pendingTargets.length; index += 1) {
512
+ pendingTargetAddresses[index] = pendingTargets[index].address;
513
+ }
514
+ const hasPendingSessions = await this.signalStore.hasSessions(pendingTargetAddresses);
515
+ const nextAvailableTargets = [];
516
+ for (let index = 0; index < pendingTargets.length; index += 1) {
517
+ if (hasPendingSessions[index]) {
518
+ nextAvailableTargets.push(pendingTargets[index]);
519
+ }
520
+ }
521
+ availableTargets = nextAvailableTargets;
423
522
  }
424
- const hasPendingSessions = await this.signalProtocol.hasSessions(pendingTargets.map((target) => target.address));
425
- const availableTargets = pendingTargets.filter((_target, index) => hasPendingSessions[index]);
426
523
  if (availableTargets.length === 0) {
427
524
  return {
428
525
  fanoutDeviceJids,
429
526
  distributionParticipants: []
430
527
  };
431
528
  }
432
- const encryptedDistributionParticipants = await this.signalProtocol.encryptMessagesBatch(availableTargets.map((target) => ({
433
- address: target.address,
434
- plaintext: distributionPayload
435
- })));
436
- const distributionParticipants = availableTargets.map((target, index) => ({
437
- jid: target.jid,
438
- address: target.address,
439
- encType: encryptedDistributionParticipants[index].type,
440
- ciphertext: encryptedDistributionParticipants[index].ciphertext
441
- }));
529
+ const distributionEncryptRequests = new Array(availableTargets.length);
530
+ for (let index = 0; index < availableTargets.length; index += 1) {
531
+ const target = availableTargets[index];
532
+ distributionEncryptRequests[index] = {
533
+ address: target.address,
534
+ plaintext: distributionPayload
535
+ };
536
+ }
537
+ const encryptedDistributionParticipants = await this.signalProtocol.encryptMessagesBatch(distributionEncryptRequests, prefetchedAvailableTargets);
538
+ const distributionParticipants = new Array(availableTargets.length);
539
+ for (let index = 0; index < availableTargets.length; index += 1) {
540
+ const target = availableTargets[index];
541
+ distributionParticipants[index] = {
542
+ jid: target.jid,
543
+ address: target.address,
544
+ encType: encryptedDistributionParticipants[index].type,
545
+ ciphertext: encryptedDistributionParticipants[index].ciphertext
546
+ };
547
+ }
442
548
  return {
443
549
  fanoutDeviceJids,
444
550
  distributionParticipants
445
551
  };
446
552
  }
447
- async publishDirectSignalMessageWithFanout(recipientJid, message, plaintext, type, options) {
553
+ async publishDirectSignalMessageWithFanout(recipientJid, message, plaintext, type, options, edit, mediatype, metaNode) {
448
554
  const sendOptions = await this.withResolvedMessageId(options);
449
555
  const meJid = this.requireCurrentMeJid('sendMessage');
450
556
  const meLid = this.getCurrentMeLid();
451
557
  const selfDeviceJidForRecipient = this.fanoutResolver.resolveSelfDeviceJidForRecipient(recipientJid, meJid, meLid);
452
558
  const deviceJids = await this.fanoutResolver.resolveDirectFanoutDeviceJids(recipientJid, selfDeviceJidForRecipient);
453
- const targets = deviceJids.map((jid) => ({
454
- jid,
455
- normalizedJid: normalizeDeviceJid(jid),
456
- userJid: toUserJid(jid)
457
- }));
559
+ const targets = new Array(deviceJids.length);
560
+ for (let index = 0; index < deviceJids.length; index += 1) {
561
+ const jid = deviceJids[index];
562
+ const parsed = parseJidFull(jid);
563
+ targets[index] = {
564
+ jid,
565
+ normalizedJid: parsed.normalizedJid,
566
+ userJid: parsed.userJid
567
+ };
568
+ }
458
569
  const recipientUserJid = toUserJid(recipientJid);
459
570
  const meUserJid = toUserJid(selfDeviceJidForRecipient);
460
571
  this.logger.debug('wa client publish signal fanout', {
@@ -471,30 +582,75 @@ export class WaMessageDispatchCoordinator {
471
582
  }
472
583
  }
473
584
  }
474
- await this.sessionResolver.ensureSessionsBatch(deviceJids, expectedIdentityByJid);
475
- const hasSelfDeviceFanout = targets.some((target) => target.userJid === meUserJid);
585
+ const resolvedFanoutTargets = await this.sessionResolver.ensureSessionsBatch(deviceJids, expectedIdentityByJid);
586
+ const resolvedFanoutTargetsByJid = new Map();
587
+ for (let index = 0; index < resolvedFanoutTargets.length; index += 1) {
588
+ const target = resolvedFanoutTargets[index];
589
+ resolvedFanoutTargetsByJid.set(normalizeDeviceJid(target.jid), target);
590
+ }
591
+ for (let index = 0; index < targets.length; index += 1) {
592
+ if (!resolvedFanoutTargetsByJid.has(targets[index].normalizedJid)) {
593
+ throw new Error('direct fanout missing signal sessions for one or more targets');
594
+ }
595
+ }
596
+ let hasSelfDeviceFanout = false;
597
+ for (let index = 0; index < targets.length; index += 1) {
598
+ if (targets[index].userJid === meUserJid) {
599
+ hasSelfDeviceFanout = true;
600
+ break;
601
+ }
602
+ }
476
603
  const selfDevicePlaintext = hasSelfDeviceFanout
477
604
  ? await writeRandomPadMax16(proto.Message.encode(wrapDeviceSentMessage(message, recipientUserJid)).finish())
478
605
  : null;
479
- const participantRequests = targets.map((target) => ({
480
- target,
481
- address: parseSignalAddressFromJid(target.jid),
482
- expectedIdentity: target.userJid === recipientUserJid ? sendOptions.expectedIdentity : undefined,
483
- plaintext: selfDevicePlaintext && target.userJid === meUserJid
484
- ? selfDevicePlaintext
485
- : plaintext
486
- }));
487
- const encryptedParticipants = await this.signalProtocol.encryptMessagesBatch(participantRequests.map((request) => ({
488
- address: request.address,
489
- plaintext: request.plaintext,
490
- expectedIdentity: request.expectedIdentity
491
- })));
492
- const participants = participantRequests.map((request, index) => ({
493
- jid: request.target.jid,
494
- encType: encryptedParticipants[index].type,
495
- ciphertext: encryptedParticipants[index].ciphertext
496
- }));
497
- const shouldAttachDeviceIdentity = participants.some((participant) => participant.encType === 'pkmsg');
606
+ const participantRequests = new Array(targets.length);
607
+ for (let index = 0; index < targets.length; index += 1) {
608
+ const target = targets[index];
609
+ const resolvedTarget = resolvedFanoutTargetsByJid.get(target.normalizedJid);
610
+ if (!resolvedTarget) {
611
+ throw new Error('direct fanout missing signal session for target');
612
+ }
613
+ participantRequests[index] = {
614
+ target,
615
+ address: resolvedTarget.address,
616
+ session: resolvedTarget.session,
617
+ expectedIdentity: target.userJid === recipientUserJid ? sendOptions.expectedIdentity : undefined,
618
+ plaintext: selfDevicePlaintext && target.userJid === meUserJid
619
+ ? selfDevicePlaintext
620
+ : plaintext
621
+ };
622
+ }
623
+ const encryptRequests = new Array(participantRequests.length);
624
+ const prefetchedSessions = new Array(participantRequests.length);
625
+ for (let index = 0; index < participantRequests.length; index += 1) {
626
+ const request = participantRequests[index];
627
+ encryptRequests[index] = {
628
+ address: request.address,
629
+ plaintext: request.plaintext,
630
+ expectedIdentity: request.expectedIdentity
631
+ };
632
+ prefetchedSessions[index] = {
633
+ address: request.address,
634
+ session: request.session
635
+ };
636
+ }
637
+ const encryptedParticipants = await this.signalProtocol.encryptMessagesBatch(encryptRequests, prefetchedSessions);
638
+ const participants = new Array(participantRequests.length);
639
+ for (let index = 0; index < participantRequests.length; index += 1) {
640
+ const request = participantRequests[index];
641
+ participants[index] = {
642
+ jid: request.target.jid,
643
+ encType: encryptedParticipants[index].type,
644
+ ciphertext: encryptedParticipants[index].ciphertext
645
+ };
646
+ }
647
+ let shouldAttachDeviceIdentity = false;
648
+ for (let index = 0; index < participants.length; index += 1) {
649
+ if (participants[index].encType === 'pkmsg') {
650
+ shouldAttachDeviceIdentity = true;
651
+ break;
652
+ }
653
+ }
498
654
  const deviceIdentity = shouldAttachDeviceIdentity
499
655
  ? this.getEncodedSignedDeviceIdentity()
500
656
  : undefined;
@@ -505,13 +661,28 @@ export class WaMessageDispatchCoordinator {
505
661
  remoteJid: recipientUserJid,
506
662
  context: 'direct_fanout'
507
663
  });
664
+ let privacyTokenNode;
665
+ try {
666
+ privacyTokenNode =
667
+ (await this.privacyTokenDedup.run(`pt:${recipientUserJid}`, () => this.resolvePrivacyTokenNode(recipientUserJid))) ?? undefined;
668
+ }
669
+ catch (error) {
670
+ this.logger.warn('privacy token resolution failed', {
671
+ to: recipientUserJid,
672
+ message: toError(error).message
673
+ });
674
+ }
508
675
  const messageNode = buildDirectMessageFanoutNode({
509
676
  to: recipientJid,
510
677
  type,
511
678
  id: sendOptions.id,
679
+ edit,
512
680
  participants,
513
681
  deviceIdentity,
514
- reportingNode: reportingArtifacts?.node ?? undefined
682
+ reportingNode: reportingArtifacts?.node ?? undefined,
683
+ privacyTokenNode,
684
+ metaNode,
685
+ mediatype
515
686
  });
516
687
  const replayPayload = {
517
688
  mode: 'plaintext',
@@ -519,12 +690,15 @@ export class WaMessageDispatchCoordinator {
519
690
  type,
520
691
  plaintext
521
692
  };
522
- return this.retryTracker.track({
693
+ const result = await this.retryTracker.track({
523
694
  messageIdHint: sendOptions.id ?? messageNode.attrs.id,
524
695
  toJid: recipientJid,
525
696
  type,
526
- replayPayload
697
+ replayPayload,
698
+ eligibleRequesterDeviceJids: deviceJids
527
699
  }, async () => this.messageClient.publishNode(messageNode, sendOptions));
700
+ this.onDirectMessageSent(recipientUserJid);
701
+ return result;
528
702
  }
529
703
  async withResolvedMessageId(options) {
530
704
  const normalizedId = options.id?.trim();
@@ -592,6 +766,25 @@ export class WaMessageDispatchCoordinator {
592
766
  }
593
767
  return proto.ADVSignedDeviceIdentity.encode(signedIdentity).finish();
594
768
  }
769
+ resolveUserIcdc(userJid, localIdentity) {
770
+ return this.icdcDedup.run(`icdc:${userJid}:${localIdentity ? '1' : '0'}`, async () => {
771
+ try {
772
+ const snapshots = await this.deviceListStore.getUserDevicesBatch([userJid]);
773
+ const snapshot = snapshots[0];
774
+ if (!snapshot || snapshot.deviceJids.length === 0) {
775
+ return null;
776
+ }
777
+ return resolveIcdcMeta(snapshot.deviceJids, this.signalStore, snapshot.updatedAtMs, localIdentity);
778
+ }
779
+ catch (error) {
780
+ this.logger.trace('icdc resolution failed', {
781
+ userJid,
782
+ message: toError(error).message
783
+ });
784
+ return null;
785
+ }
786
+ });
787
+ }
595
788
  requireCurrentMeJid(context) {
596
789
  const meJid = this.getCurrentMeJid();
597
790
  if (meJid) {