matrix-js-sdk 41.8.0 → 41.9.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 (458) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/README.md +1 -1
  3. package/lib/@types/AESEncryptedSecretStoragePayload.js +3 -1
  4. package/lib/@types/IIdentityServerProvider.js +3 -1
  5. package/lib/@types/PushRules.js +7 -7
  6. package/lib/@types/PushRules.js.map +1 -1
  7. package/lib/@types/auth.js +4 -4
  8. package/lib/@types/auth.js.map +1 -1
  9. package/lib/@types/beacon.js +2 -2
  10. package/lib/@types/beacon.js.map +1 -1
  11. package/lib/@types/common.js +3 -1
  12. package/lib/@types/crypto.js +3 -1
  13. package/lib/@types/event.js +20 -20
  14. package/lib/@types/event.js.map +1 -1
  15. package/lib/@types/events.js +3 -1
  16. package/lib/@types/extensible_events.js +6 -6
  17. package/lib/@types/extensible_events.js.map +1 -1
  18. package/lib/@types/global.d.js.map +1 -1
  19. package/lib/@types/json.js +3 -1
  20. package/lib/@types/local_notifications.js +3 -1
  21. package/lib/@types/location.js +4 -4
  22. package/lib/@types/location.js.map +1 -1
  23. package/lib/@types/matrix-sdk-crypto-wasm.d.js +3 -1
  24. package/lib/@types/media.js +3 -1
  25. package/lib/@types/membership.js +1 -1
  26. package/lib/@types/membership.js.map +1 -1
  27. package/lib/@types/partials.js +6 -6
  28. package/lib/@types/partials.js.map +1 -1
  29. package/lib/@types/polls.js +5 -5
  30. package/lib/@types/polls.js.map +1 -1
  31. package/lib/@types/read_receipts.js +2 -2
  32. package/lib/@types/read_receipts.js.map +1 -1
  33. package/lib/@types/registration.js +3 -1
  34. package/lib/@types/requests.js +1 -1
  35. package/lib/@types/requests.js.map +1 -1
  36. package/lib/@types/retention.js +1 -1
  37. package/lib/@types/retention.js.map +1 -1
  38. package/lib/@types/search.js +1 -1
  39. package/lib/@types/search.js.map +1 -1
  40. package/lib/@types/signed.js +3 -1
  41. package/lib/@types/spaces.js +3 -1
  42. package/lib/@types/state_events.js +3 -1
  43. package/lib/@types/synapse.js +3 -1
  44. package/lib/@types/sync.js +1 -1
  45. package/lib/@types/sync.js.map +1 -1
  46. package/lib/@types/threepids.js +1 -1
  47. package/lib/@types/threepids.js.map +1 -1
  48. package/lib/@types/topic.js +1 -1
  49. package/lib/@types/topic.js.map +1 -1
  50. package/lib/@types/uia.js +3 -1
  51. package/lib/NamespacedValue.js +8 -8
  52. package/lib/NamespacedValue.js.map +1 -1
  53. package/lib/ReEmitter.js +9 -16
  54. package/lib/ReEmitter.js.map +1 -1
  55. package/lib/ToDeviceMessageQueue.js +49 -57
  56. package/lib/ToDeviceMessageQueue.js.map +1 -1
  57. package/lib/autodiscovery.js +232 -247
  58. package/lib/autodiscovery.js.map +1 -1
  59. package/lib/base64.js +1 -1
  60. package/lib/base64.js.map +1 -1
  61. package/lib/browser-index.d.ts +2 -2
  62. package/lib/browser-index.d.ts.map +1 -1
  63. package/lib/browser-index.js +5 -5
  64. package/lib/browser-index.js.map +1 -1
  65. package/lib/capabilityPoller.js +19 -22
  66. package/lib/capabilityPoller.js.map +1 -1
  67. package/lib/client.d.ts +2 -8
  68. package/lib/client.d.ts.map +1 -1
  69. package/lib/client.js +2043 -2487
  70. package/lib/client.js.map +1 -1
  71. package/lib/common-crypto/CryptoBackend.js +2 -2
  72. package/lib/common-crypto/CryptoBackend.js.map +1 -1
  73. package/lib/common-crypto/key-passphrase.js.map +1 -1
  74. package/lib/content-helpers.js +43 -48
  75. package/lib/content-helpers.js.map +1 -1
  76. package/lib/content-repo.js +14 -24
  77. package/lib/content-repo.js.map +1 -1
  78. package/lib/crypto/store/base.js +6 -6
  79. package/lib/crypto/store/base.js.map +1 -1
  80. package/lib/crypto/store/indexeddb-crypto-store-backend.js +190 -238
  81. package/lib/crypto/store/indexeddb-crypto-store-backend.js.map +1 -1
  82. package/lib/crypto/store/indexeddb-crypto-store.js +25 -30
  83. package/lib/crypto/store/indexeddb-crypto-store.js.map +1 -1
  84. package/lib/crypto/store/localStorage-crypto-store.js +113 -145
  85. package/lib/crypto/store/localStorage-crypto-store.js.map +1 -1
  86. package/lib/crypto/store/memory-crypto-store.js +74 -105
  87. package/lib/crypto/store/memory-crypto-store.js.map +1 -1
  88. package/lib/crypto-api/CryptoEvent.js +1 -1
  89. package/lib/crypto-api/CryptoEvent.js.map +1 -1
  90. package/lib/crypto-api/CryptoEventHandlerMap.js +3 -1
  91. package/lib/crypto-api/index.d.ts +15 -6
  92. package/lib/crypto-api/index.d.ts.map +1 -1
  93. package/lib/crypto-api/index.js +22 -22
  94. package/lib/crypto-api/index.js.map +1 -1
  95. package/lib/crypto-api/key-passphrase.js +15 -23
  96. package/lib/crypto-api/key-passphrase.js.map +1 -1
  97. package/lib/crypto-api/keybackup.js +3 -1
  98. package/lib/crypto-api/recovery-key.js +11 -12
  99. package/lib/crypto-api/recovery-key.js.map +1 -1
  100. package/lib/crypto-api/verification.js +3 -3
  101. package/lib/crypto-api/verification.js.map +1 -1
  102. package/lib/digest.js +7 -14
  103. package/lib/digest.js.map +1 -1
  104. package/lib/embedded.d.ts.map +1 -1
  105. package/lib/embedded.js +380 -505
  106. package/lib/embedded.js.map +1 -1
  107. package/lib/errors.js +2 -2
  108. package/lib/errors.js.map +1 -1
  109. package/lib/event-mapper.js +10 -12
  110. package/lib/event-mapper.js.map +1 -1
  111. package/lib/extensible_events_v1/ExtensibleEvent.js.map +1 -1
  112. package/lib/extensible_events_v1/InvalidEventError.js.map +1 -1
  113. package/lib/extensible_events_v1/MessageEvent.js +11 -13
  114. package/lib/extensible_events_v1/MessageEvent.js.map +1 -1
  115. package/lib/extensible_events_v1/PollEndEvent.js +3 -4
  116. package/lib/extensible_events_v1/PollEndEvent.js.map +1 -1
  117. package/lib/extensible_events_v1/PollResponseEvent.js +5 -6
  118. package/lib/extensible_events_v1/PollResponseEvent.js.map +1 -1
  119. package/lib/extensible_events_v1/PollStartEvent.js +8 -10
  120. package/lib/extensible_events_v1/PollStartEvent.js.map +1 -1
  121. package/lib/extensible_events_v1/utilities.js.map +1 -1
  122. package/lib/feature.js +18 -31
  123. package/lib/feature.js.map +1 -1
  124. package/lib/filter-component.d.ts.map +1 -1
  125. package/lib/filter-component.js +20 -26
  126. package/lib/filter-component.js.map +1 -1
  127. package/lib/filter.js +14 -17
  128. package/lib/filter.js.map +1 -1
  129. package/lib/http-api/errors.js +28 -43
  130. package/lib/http-api/errors.js.map +1 -1
  131. package/lib/http-api/fetch.js +141 -159
  132. package/lib/http-api/fetch.js.map +1 -1
  133. package/lib/http-api/index.js +17 -20
  134. package/lib/http-api/index.js.map +1 -1
  135. package/lib/http-api/interface.js +1 -1
  136. package/lib/http-api/interface.js.map +1 -1
  137. package/lib/http-api/method.js +1 -1
  138. package/lib/http-api/method.js.map +1 -1
  139. package/lib/http-api/prefix.js +3 -3
  140. package/lib/http-api/prefix.js.map +1 -1
  141. package/lib/http-api/refresh.js +74 -94
  142. package/lib/http-api/refresh.js.map +1 -1
  143. package/lib/http-api/utils.d.ts +1 -1
  144. package/lib/http-api/utils.d.ts.map +1 -1
  145. package/lib/http-api/utils.js +34 -42
  146. package/lib/http-api/utils.js.map +1 -1
  147. package/lib/index.js.map +1 -1
  148. package/lib/indexeddb-helpers.js +3 -3
  149. package/lib/indexeddb-helpers.js.map +1 -1
  150. package/lib/indexeddb-worker.js.map +1 -1
  151. package/lib/interactive-auth.d.ts +5 -5
  152. package/lib/interactive-auth.d.ts.map +1 -1
  153. package/lib/interactive-auth.js +172 -204
  154. package/lib/interactive-auth.js.map +1 -1
  155. package/lib/logger.js +21 -57
  156. package/lib/logger.js.map +1 -1
  157. package/lib/matrix.js +7 -11
  158. package/lib/matrix.js.map +1 -1
  159. package/lib/matrixrtc/CallMembership.js +80 -74
  160. package/lib/matrixrtc/CallMembership.js.map +1 -1
  161. package/lib/matrixrtc/EncryptionManager.js +1 -1
  162. package/lib/matrixrtc/EncryptionManager.js.map +1 -1
  163. package/lib/matrixrtc/IKeyTransport.js +1 -1
  164. package/lib/matrixrtc/IKeyTransport.js.map +1 -1
  165. package/lib/matrixrtc/IMembershipManager.js +1 -1
  166. package/lib/matrixrtc/IMembershipManager.js.map +1 -1
  167. package/lib/matrixrtc/LivekitTransport.d.ts +1 -1
  168. package/lib/matrixrtc/LivekitTransport.js +4 -4
  169. package/lib/matrixrtc/LivekitTransport.js.map +1 -1
  170. package/lib/matrixrtc/MatrixRTCSession.js +137 -187
  171. package/lib/matrixrtc/MatrixRTCSession.js.map +1 -1
  172. package/lib/matrixrtc/MatrixRTCSessionManager.js +36 -41
  173. package/lib/matrixrtc/MatrixRTCSessionManager.js.map +1 -1
  174. package/lib/matrixrtc/MembershipManager.js +332 -378
  175. package/lib/matrixrtc/MembershipManager.js.map +1 -1
  176. package/lib/matrixrtc/MembershipManagerActionScheduler.js +54 -63
  177. package/lib/matrixrtc/MembershipManagerActionScheduler.js.map +1 -1
  178. package/lib/matrixrtc/RTCEncryptionManager.js +119 -143
  179. package/lib/matrixrtc/RTCEncryptionManager.js.map +1 -1
  180. package/lib/matrixrtc/ToDeviceKeyTransport.js +53 -58
  181. package/lib/matrixrtc/ToDeviceKeyTransport.js.map +1 -1
  182. package/lib/matrixrtc/index.js.map +1 -1
  183. package/lib/matrixrtc/membershipData/common.js +1 -1
  184. package/lib/matrixrtc/membershipData/common.js.map +1 -1
  185. package/lib/matrixrtc/membershipData/index.js.map +1 -1
  186. package/lib/matrixrtc/membershipData/rtc.js +15 -23
  187. package/lib/matrixrtc/membershipData/rtc.js.map +1 -1
  188. package/lib/matrixrtc/membershipData/session.js +4 -5
  189. package/lib/matrixrtc/membershipData/session.js.map +1 -1
  190. package/lib/matrixrtc/types.js +4 -6
  191. package/lib/matrixrtc/types.js.map +1 -1
  192. package/lib/matrixrtc/utils.js +4 -11
  193. package/lib/matrixrtc/utils.js.map +1 -1
  194. package/lib/models/MSC3089Branch.js +91 -116
  195. package/lib/models/MSC3089Branch.js.map +1 -1
  196. package/lib/models/MSC3089TreeSpace.js +209 -245
  197. package/lib/models/MSC3089TreeSpace.js.map +1 -1
  198. package/lib/models/ToDeviceMessage.js +3 -1
  199. package/lib/models/beacon.js +14 -13
  200. package/lib/models/beacon.js.map +1 -1
  201. package/lib/models/compare-event-ordering.js +13 -13
  202. package/lib/models/compare-event-ordering.js.map +1 -1
  203. package/lib/models/device.js +3 -3
  204. package/lib/models/device.js.map +1 -1
  205. package/lib/models/event-context.js +5 -8
  206. package/lib/models/event-context.js.map +1 -1
  207. package/lib/models/event-status.js +1 -1
  208. package/lib/models/event-status.js.map +1 -1
  209. package/lib/models/event-timeline-set.js +88 -94
  210. package/lib/models/event-timeline-set.js.map +1 -1
  211. package/lib/models/event-timeline.js +28 -30
  212. package/lib/models/event-timeline.js.map +1 -1
  213. package/lib/models/event.js +182 -226
  214. package/lib/models/event.js.map +1 -1
  215. package/lib/models/invites-ignorer-types.js +4 -4
  216. package/lib/models/invites-ignorer-types.js.map +1 -1
  217. package/lib/models/invites-ignorer.js +159 -179
  218. package/lib/models/invites-ignorer.js.map +1 -1
  219. package/lib/models/poll.js +71 -81
  220. package/lib/models/poll.js.map +1 -1
  221. package/lib/models/profile-keys.js +2 -2
  222. package/lib/models/profile-keys.js.map +1 -1
  223. package/lib/models/read-receipt.js +40 -56
  224. package/lib/models/read-receipt.js.map +1 -1
  225. package/lib/models/related-relations.js.map +1 -1
  226. package/lib/models/relations-container.js +22 -23
  227. package/lib/models/relations-container.js.map +1 -1
  228. package/lib/models/relations.js +133 -159
  229. package/lib/models/relations.js.map +1 -1
  230. package/lib/models/room-member.js +24 -29
  231. package/lib/models/room-member.js.map +1 -1
  232. package/lib/models/room-receipts.js +29 -43
  233. package/lib/models/room-receipts.js.map +1 -1
  234. package/lib/models/room-retention.js +74 -83
  235. package/lib/models/room-retention.js.map +1 -1
  236. package/lib/models/room-state.js +143 -172
  237. package/lib/models/room-state.js.map +1 -1
  238. package/lib/models/room-sticky-events.d.ts +1 -0
  239. package/lib/models/room-sticky-events.d.ts.map +1 -1
  240. package/lib/models/room-sticky-events.js +45 -65
  241. package/lib/models/room-sticky-events.js.map +1 -1
  242. package/lib/models/room-summary.js.map +1 -1
  243. package/lib/models/room.d.ts.map +1 -1
  244. package/lib/models/room.js +765 -909
  245. package/lib/models/room.js.map +1 -1
  246. package/lib/models/search-result.js +5 -5
  247. package/lib/models/search-result.js.map +1 -1
  248. package/lib/models/thread.js +225 -285
  249. package/lib/models/thread.js.map +1 -1
  250. package/lib/models/typed-event-emitter.js +7 -18
  251. package/lib/models/typed-event-emitter.js.map +1 -1
  252. package/lib/models/user.js +8 -8
  253. package/lib/models/user.js.map +1 -1
  254. package/lib/oidc/authorize.js +208 -241
  255. package/lib/oidc/authorize.js.map +1 -1
  256. package/lib/oidc/discovery.js +23 -36
  257. package/lib/oidc/discovery.js.map +1 -1
  258. package/lib/oidc/error.js +1 -1
  259. package/lib/oidc/error.js.map +1 -1
  260. package/lib/oidc/index.js +1 -0
  261. package/lib/oidc/index.js.map +1 -1
  262. package/lib/oidc/register.js +60 -66
  263. package/lib/oidc/register.js.map +1 -1
  264. package/lib/oidc/tokenRefresher.js +77 -91
  265. package/lib/oidc/tokenRefresher.js.map +1 -1
  266. package/lib/oidc/validate.js +18 -18
  267. package/lib/oidc/validate.js.map +1 -1
  268. package/lib/pushprocessor.js +71 -82
  269. package/lib/pushprocessor.js.map +1 -1
  270. package/lib/randomstring.js +9 -9
  271. package/lib/randomstring.js.map +1 -1
  272. package/lib/realtime-callbacks.js +25 -28
  273. package/lib/realtime-callbacks.js.map +1 -1
  274. package/lib/receipt-accumulator.d.ts +2 -0
  275. package/lib/receipt-accumulator.d.ts.map +1 -1
  276. package/lib/receipt-accumulator.js +14 -22
  277. package/lib/receipt-accumulator.js.map +1 -1
  278. package/lib/rendezvous/MSC4108SignInWithQR.js +271 -302
  279. package/lib/rendezvous/MSC4108SignInWithQR.js.map +1 -1
  280. package/lib/rendezvous/RendezvousChannel.js +3 -1
  281. package/lib/rendezvous/RendezvousCode.js +3 -1
  282. package/lib/rendezvous/RendezvousError.js.map +1 -1
  283. package/lib/rendezvous/RendezvousFailureReason.js +2 -2
  284. package/lib/rendezvous/RendezvousFailureReason.js.map +1 -1
  285. package/lib/rendezvous/RendezvousIntent.js +1 -1
  286. package/lib/rendezvous/RendezvousIntent.js.map +1 -1
  287. package/lib/rendezvous/RendezvousTransport.js +3 -1
  288. package/lib/rendezvous/channels/MSC4108SecureChannel.js +123 -147
  289. package/lib/rendezvous/channels/MSC4108SecureChannel.js.map +1 -1
  290. package/lib/rendezvous/index.js +44 -69
  291. package/lib/rendezvous/index.js.map +1 -1
  292. package/lib/rendezvous/transports/MSC4108RendezvousSession.d.ts +1 -1
  293. package/lib/rendezvous/transports/MSC4108RendezvousSession.js +134 -152
  294. package/lib/rendezvous/transports/MSC4108RendezvousSession.js.map +1 -1
  295. package/lib/retentionPolicy.js +6 -9
  296. package/lib/retentionPolicy.js.map +1 -1
  297. package/lib/room-hierarchy.js +52 -60
  298. package/lib/room-hierarchy.js.map +1 -1
  299. package/lib/rust-crypto/CrossSigningIdentity.js +94 -104
  300. package/lib/rust-crypto/CrossSigningIdentity.js.map +1 -1
  301. package/lib/rust-crypto/DehydratedDeviceManager.js +157 -190
  302. package/lib/rust-crypto/DehydratedDeviceManager.js.map +1 -1
  303. package/lib/rust-crypto/KeyClaimManager.js +18 -22
  304. package/lib/rust-crypto/KeyClaimManager.js.map +1 -1
  305. package/lib/rust-crypto/OutgoingRequestProcessor.js +109 -139
  306. package/lib/rust-crypto/OutgoingRequestProcessor.js.map +1 -1
  307. package/lib/rust-crypto/OutgoingRequestsManager.js +66 -80
  308. package/lib/rust-crypto/OutgoingRequestsManager.js.map +1 -1
  309. package/lib/rust-crypto/PerSessionKeyBackupDownloader.d.ts +1 -1
  310. package/lib/rust-crypto/PerSessionKeyBackupDownloader.js +196 -224
  311. package/lib/rust-crypto/PerSessionKeyBackupDownloader.js.map +1 -1
  312. package/lib/rust-crypto/RoomEncryptor.js +127 -143
  313. package/lib/rust-crypto/RoomEncryptor.js.map +1 -1
  314. package/lib/rust-crypto/backup.js +453 -549
  315. package/lib/rust-crypto/backup.js.map +1 -1
  316. package/lib/rust-crypto/constants.js +1 -1
  317. package/lib/rust-crypto/constants.js.map +1 -1
  318. package/lib/rust-crypto/device-converter.js +15 -28
  319. package/lib/rust-crypto/device-converter.js.map +1 -1
  320. package/lib/rust-crypto/index.js +103 -116
  321. package/lib/rust-crypto/index.js.map +1 -1
  322. package/lib/rust-crypto/libolm_migration.js +303 -365
  323. package/lib/rust-crypto/libolm_migration.js.map +1 -1
  324. package/lib/rust-crypto/rust-crypto.d.ts +5 -1
  325. package/lib/rust-crypto/rust-crypto.d.ts.map +1 -1
  326. package/lib/rust-crypto/rust-crypto.js +1067 -1332
  327. package/lib/rust-crypto/rust-crypto.js.map +1 -1
  328. package/lib/rust-crypto/secret-storage.js +12 -25
  329. package/lib/rust-crypto/secret-storage.js.map +1 -1
  330. package/lib/rust-crypto/verification.js +137 -189
  331. package/lib/rust-crypto/verification.js.map +1 -1
  332. package/lib/scheduler.js +44 -19
  333. package/lib/scheduler.js.map +1 -1
  334. package/lib/secret-storage.js +179 -213
  335. package/lib/secret-storage.js.map +1 -1
  336. package/lib/serverCapabilities.js +6 -9
  337. package/lib/serverCapabilities.js.map +1 -1
  338. package/lib/service-types.js +1 -1
  339. package/lib/service-types.js.map +1 -1
  340. package/lib/sliding-sync-sdk.d.ts.map +1 -1
  341. package/lib/sliding-sync-sdk.js +368 -424
  342. package/lib/sliding-sync-sdk.js.map +1 -1
  343. package/lib/sliding-sync.js +135 -171
  344. package/lib/sliding-sync.js.map +1 -1
  345. package/lib/store/index.js +3 -1
  346. package/lib/store/indexeddb-backend.js +3 -1
  347. package/lib/store/indexeddb-local-backend.js +194 -253
  348. package/lib/store/indexeddb-local-backend.js.map +1 -1
  349. package/lib/store/indexeddb-remote-backend.js +33 -63
  350. package/lib/store/indexeddb-remote-backend.js.map +1 -1
  351. package/lib/store/indexeddb-store-worker.js +22 -23
  352. package/lib/store/indexeddb-store-worker.js.map +1 -1
  353. package/lib/store/indexeddb.js +44 -71
  354. package/lib/store/indexeddb.js.map +1 -1
  355. package/lib/store/local-storage-events-emitter.js +2 -2
  356. package/lib/store/local-storage-events-emitter.js.map +1 -1
  357. package/lib/store/memory.js +34 -57
  358. package/lib/store/memory.js.map +1 -1
  359. package/lib/store/stub.js +22 -35
  360. package/lib/store/stub.js.map +1 -1
  361. package/lib/sync-accumulator.js +54 -66
  362. package/lib/sync-accumulator.js.map +1 -1
  363. package/lib/sync.d.ts.map +1 -1
  364. package/lib/sync.js +905 -998
  365. package/lib/sync.js.map +1 -1
  366. package/lib/testing.js +63 -105
  367. package/lib/testing.js.map +1 -1
  368. package/lib/thread-utils.js +1 -4
  369. package/lib/thread-utils.js.map +1 -1
  370. package/lib/timeline-window.js +89 -102
  371. package/lib/timeline-window.js.map +1 -1
  372. package/lib/types.js +1 -1
  373. package/lib/types.js.map +1 -1
  374. package/lib/utils/decryptAESSecretStorageItem.js +14 -25
  375. package/lib/utils/decryptAESSecretStorageItem.js.map +1 -1
  376. package/lib/utils/encryptAESSecretStorageItem.js +27 -38
  377. package/lib/utils/encryptAESSecretStorageItem.js.map +1 -1
  378. package/lib/utils/internal/deriveKeys.js +25 -32
  379. package/lib/utils/internal/deriveKeys.js.map +1 -1
  380. package/lib/utils/roomVersion.js +1 -1
  381. package/lib/utils/roomVersion.js.map +1 -1
  382. package/lib/utils.js +83 -135
  383. package/lib/utils.js.map +1 -1
  384. package/lib/version-support.js +3 -3
  385. package/lib/version-support.js.map +1 -1
  386. package/lib/webrtc/audioContext.js +5 -6
  387. package/lib/webrtc/audioContext.js.map +1 -1
  388. package/lib/webrtc/call.js +1081 -1250
  389. package/lib/webrtc/call.js.map +1 -1
  390. package/lib/webrtc/callEventHandler.js +202 -214
  391. package/lib/webrtc/callEventHandler.js.map +1 -1
  392. package/lib/webrtc/callEventTypes.js +2 -2
  393. package/lib/webrtc/callEventTypes.js.map +1 -1
  394. package/lib/webrtc/callFeed.js +18 -20
  395. package/lib/webrtc/callFeed.js.map +1 -1
  396. package/lib/webrtc/groupCall.js +513 -602
  397. package/lib/webrtc/groupCall.js.map +1 -1
  398. package/lib/webrtc/groupCallEventHandler.js +59 -62
  399. package/lib/webrtc/groupCallEventHandler.js.map +1 -1
  400. package/lib/webrtc/mediaHandler.js +198 -232
  401. package/lib/webrtc/mediaHandler.js.map +1 -1
  402. package/lib/webrtc/stats/callFeedStatsReporter.js +16 -20
  403. package/lib/webrtc/stats/callFeedStatsReporter.js.map +1 -1
  404. package/lib/webrtc/stats/callStatsReportGatherer.js +67 -75
  405. package/lib/webrtc/stats/callStatsReportGatherer.js.map +1 -1
  406. package/lib/webrtc/stats/callStatsReportSummary.js +3 -1
  407. package/lib/webrtc/stats/connectionStats.js.map +1 -1
  408. package/lib/webrtc/stats/connectionStatsBuilder.js +2 -2
  409. package/lib/webrtc/stats/connectionStatsBuilder.js.map +1 -1
  410. package/lib/webrtc/stats/connectionStatsReportBuilder.js +20 -24
  411. package/lib/webrtc/stats/connectionStatsReportBuilder.js.map +1 -1
  412. package/lib/webrtc/stats/groupCallStats.js +6 -8
  413. package/lib/webrtc/stats/groupCallStats.js.map +1 -1
  414. package/lib/webrtc/stats/media/mediaSsrcHandler.js +7 -8
  415. package/lib/webrtc/stats/media/mediaSsrcHandler.js.map +1 -1
  416. package/lib/webrtc/stats/media/mediaTrackHandler.js +7 -9
  417. package/lib/webrtc/stats/media/mediaTrackHandler.js.map +1 -1
  418. package/lib/webrtc/stats/media/mediaTrackStats.js +3 -3
  419. package/lib/webrtc/stats/media/mediaTrackStats.js.map +1 -1
  420. package/lib/webrtc/stats/media/mediaTrackStatsHandler.js +7 -7
  421. package/lib/webrtc/stats/media/mediaTrackStatsHandler.js.map +1 -1
  422. package/lib/webrtc/stats/statsReport.js +1 -1
  423. package/lib/webrtc/stats/statsReport.js.map +1 -1
  424. package/lib/webrtc/stats/statsReportEmitter.js.map +1 -1
  425. package/lib/webrtc/stats/summaryStatsReportGatherer.js +14 -14
  426. package/lib/webrtc/stats/summaryStatsReportGatherer.js.map +1 -1
  427. package/lib/webrtc/stats/trackStatsBuilder.js +32 -34
  428. package/lib/webrtc/stats/trackStatsBuilder.js.map +1 -1
  429. package/lib/webrtc/stats/transportStats.js +3 -1
  430. package/lib/webrtc/stats/transportStatsBuilder.js +9 -9
  431. package/lib/webrtc/stats/transportStatsBuilder.js.map +1 -1
  432. package/lib/webrtc/stats/valueFormatter.js +1 -1
  433. package/lib/webrtc/stats/valueFormatter.js.map +1 -1
  434. package/package.json +18 -33
  435. package/src/@types/global.d.ts +2 -2
  436. package/src/ToDeviceMessageQueue.ts +2 -2
  437. package/src/browser-index.ts +4 -4
  438. package/src/client.ts +15 -20
  439. package/src/crypto-api/index.ts +17 -6
  440. package/src/embedded.ts +4 -6
  441. package/src/filter-component.ts +1 -0
  442. package/src/http-api/utils.ts +1 -1
  443. package/src/interactive-auth.ts +11 -5
  444. package/src/matrixrtc/LivekitTransport.ts +1 -1
  445. package/src/matrixrtc/MatrixRTCSession.ts +1 -1
  446. package/src/models/MSC3089Branch.ts +1 -1
  447. package/src/models/room-sticky-events.ts +1 -0
  448. package/src/models/room.ts +9 -11
  449. package/src/receipt-accumulator.ts +2 -0
  450. package/src/rendezvous/index.ts +1 -1
  451. package/src/rendezvous/transports/MSC4108RendezvousSession.ts +2 -2
  452. package/src/rust-crypto/PerSessionKeyBackupDownloader.ts +1 -1
  453. package/src/rust-crypto/index.ts +6 -6
  454. package/src/rust-crypto/rust-crypto.ts +31 -7
  455. package/src/rust-crypto/verification.ts +1 -1
  456. package/src/sliding-sync-sdk.ts +5 -7
  457. package/src/store/indexeddb-local-backend.ts +3 -3
  458. package/src/sync.ts +6 -8
package/lib/sync.js CHANGED
@@ -1,8 +1,5 @@
1
- import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
2
- import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
3
1
  import _defineProperty from "@babel/runtime/helpers/defineProperty";
4
- function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
5
- function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
2
+ import _objectSpread from "@babel/runtime/helpers/objectSpread2";
6
3
  /*
7
4
  Copyright 2015 - 2023 The Matrix.org Foundation C.I.C.
8
5
 
@@ -49,13 +46,13 @@ import { KnownMembership } from "./@types/membership.js";
49
46
  // beyond that and wedge forever, so we need to track how long we are willing
50
47
  // to keep open the connection. This constant is *ADDED* to the timeout= value
51
48
  // to determine the max time we're willing to wait.
52
- var BUFFER_PERIOD_MS = 80 * 1000;
49
+ const BUFFER_PERIOD_MS = 80 * 1000;
53
50
 
54
51
  // Number of consecutive failed syncs that will lead to a syncState of ERROR as opposed
55
52
  // to RECONNECTING. This is needed to inform the client of server issues when the
56
53
  // keepAlive is successful but the server /sync fails.
57
- var FAILED_SYNC_ERROR_THRESHOLD = 3;
58
- export var SyncState = /*#__PURE__*/function (SyncState) {
54
+ const FAILED_SYNC_ERROR_THRESHOLD = 3;
55
+ export let SyncState = /*#__PURE__*/function (SyncState) {
59
56
  /** Emitted after we try to sync more than `FAILED_SYNC_ERROR_THRESHOLD`
60
57
  * times and are still failing. Or when we enounter a hard error like the
61
58
  * token being invalid. */
@@ -79,18 +76,18 @@ export var SyncState = /*#__PURE__*/function (SyncState) {
79
76
  // Room versions where "insertion", "batch", and "marker" events are controlled
80
77
  // by power-levels. MSC2716 is supported in existing room versions but they
81
78
  // should only have special meaning when the room creator sends them.
82
- var MSC2716_ROOM_VERSIONS = ["org.matrix.msc2716v3"];
79
+ const MSC2716_ROOM_VERSIONS = ["org.matrix.msc2716v3"];
83
80
  function getFilterName(userId, suffix) {
84
81
  // scope this on the user ID because people may login on many accounts
85
82
  // and they all need to be stored!
86
- return "FILTER_SYNC_".concat(userId) + (suffix ? "_" + suffix : "");
83
+ return `FILTER_SYNC_${userId}` + (suffix ? "_" + suffix : "");
87
84
  }
88
85
 
89
86
  /**
90
87
  * Options passed into the constructor of SyncApi by MatrixClient
91
88
  */
92
89
 
93
- export var SetPresence = /*#__PURE__*/function (SetPresence) {
90
+ export let SetPresence = /*#__PURE__*/function (SetPresence) {
94
91
  SetPresence["Offline"] = "offline";
95
92
  SetPresence["Online"] = "online";
96
93
  SetPresence["Unavailable"] = "unavailable";
@@ -120,8 +117,6 @@ export class SyncApi {
120
117
  * @internal
121
118
  */
122
119
  constructor(client, opts, syncOpts) {
123
- var _this = this;
124
- this.client = client;
125
120
  _defineProperty(this, "opts", void 0);
126
121
  _defineProperty(this, "syncOpts", void 0);
127
122
  _defineProperty(this, "_peekRoom", null);
@@ -141,24 +136,24 @@ export class SyncApi {
141
136
  _defineProperty(this, "storeIsInvalid", false);
142
137
  // flag set if the store needs to be cleared before we can start
143
138
  _defineProperty(this, "presence", void 0);
144
- _defineProperty(this, "getPushRules", /*#__PURE__*/_asyncToGenerator(function* () {
139
+ _defineProperty(this, "getPushRules", async () => {
145
140
  try {
146
- _this.syncOpts.logger.debug("Getting push rules...");
147
- var result = yield _this.client.getPushRules();
148
- _this.syncOpts.logger.debug("Got push rules");
149
- _this.client.pushRules = result;
141
+ this.syncOpts.logger.debug("Getting push rules...");
142
+ const result = await this.client.getPushRules();
143
+ this.syncOpts.logger.debug("Got push rules");
144
+ this.client.pushRules = result;
150
145
  } catch (err) {
151
- _this.syncOpts.logger.error("Getting push rules failed", err);
152
- if (_this.shouldAbortSync(err)) return;
146
+ this.syncOpts.logger.error("Getting push rules failed", err);
147
+ if (this.shouldAbortSync(err)) return;
153
148
  // wait for saved sync to complete before doing anything else,
154
149
  // otherwise the sync state will end up being incorrect
155
- _this.syncOpts.logger.debug("Waiting for saved sync before retrying push rules...");
156
- yield _this.recoverFromSyncStartupError(_this.savedSyncPromise, err);
157
- return _this.getPushRules(); // try again
150
+ this.syncOpts.logger.debug("Waiting for saved sync before retrying push rules...");
151
+ await this.recoverFromSyncStartupError(this.savedSyncPromise, err);
152
+ return this.getPushRules(); // try again
158
153
  }
159
- }));
154
+ });
160
155
  _defineProperty(this, "buildDefaultFilter", () => {
161
- var filter = new Filter(this.client.credentials.userId);
156
+ const filter = new Filter(this.client.credentials.userId);
162
157
  if (this.client.canSupport.get(Feature.ThreadUnreadNotifications) !== ServerSupport.Unsupported) {
163
158
  filter.setUnreadThreadNotifications(true);
164
159
  }
@@ -184,51 +179,50 @@ export class SyncApi {
184
179
  /**
185
180
  * Preare sync filter options for the unstable MSC4429 user profile fields if enabled.
186
181
  */
187
- _defineProperty(this, "prepareSyncFilterUserProfiles", /*#__PURE__*/_asyncToGenerator(function* () {
188
- var _this$opts$unstableMS;
189
- if ((_this$opts$unstableMS = _this.opts.unstableMSC4429SyncUserProfileFields) !== null && _this$opts$unstableMS !== void 0 && _this$opts$unstableMS.length) {
190
- _this.syncOpts.logger.debug("Enabling EXPERIMENTAL user profiles on sync filter...");
191
- if (!_this.opts.filter) {
192
- _this.opts.filter = _this.buildDefaultFilter();
182
+ _defineProperty(this, "prepareSyncFilterUserProfiles", async () => {
183
+ if (this.opts.unstableMSC4429SyncUserProfileFields?.length) {
184
+ this.syncOpts.logger.debug("Enabling EXPERIMENTAL user profiles on sync filter...");
185
+ if (!this.opts.filter) {
186
+ this.opts.filter = this.buildDefaultFilter();
193
187
  }
194
- _this.opts.filter.setUnstableMSC4429SyncUserProfiles(_this.opts.unstableMSC4429SyncUserProfileFields, yield _this.client.doesServerSupportUnstableFeature("org.matrix.msc4429.stable"));
188
+ this.opts.filter.setUnstableMSC4429SyncUserProfiles(this.opts.unstableMSC4429SyncUserProfileFields, await this.client.doesServerSupportUnstableFeature("org.matrix.msc4429.stable"));
195
189
  }
196
- }));
197
- _defineProperty(this, "storeClientOptions", /*#__PURE__*/_asyncToGenerator(function* () {
190
+ });
191
+ _defineProperty(this, "storeClientOptions", async () => {
198
192
  try {
199
- _this.syncOpts.logger.debug("Storing client options...");
200
- yield _this.client.storeClientOptions();
201
- _this.syncOpts.logger.debug("Stored client options");
193
+ this.syncOpts.logger.debug("Storing client options...");
194
+ await this.client.storeClientOptions();
195
+ this.syncOpts.logger.debug("Stored client options");
202
196
  } catch (err) {
203
- _this.syncOpts.logger.error("Storing client options failed", err);
197
+ this.syncOpts.logger.error("Storing client options failed", err);
204
198
  throw err;
205
199
  }
206
- }));
207
- _defineProperty(this, "getFilter", /*#__PURE__*/_asyncToGenerator(function* () {
208
- _this.syncOpts.logger.debug("Getting filter...");
209
- var filter;
210
- if (_this.opts.filter) {
211
- filter = _this.opts.filter;
200
+ });
201
+ _defineProperty(this, "getFilter", async () => {
202
+ this.syncOpts.logger.debug("Getting filter...");
203
+ let filter;
204
+ if (this.opts.filter) {
205
+ filter = this.opts.filter;
212
206
  } else {
213
- filter = _this.buildDefaultFilter();
207
+ filter = this.buildDefaultFilter();
214
208
  }
215
- var filterId;
209
+ let filterId;
216
210
  try {
217
- filterId = yield _this.client.getOrCreateFilter(getFilterName(_this.client.credentials.userId), filter);
211
+ filterId = await this.client.getOrCreateFilter(getFilterName(this.client.credentials.userId), filter);
218
212
  } catch (err) {
219
- _this.syncOpts.logger.error("Getting filter failed", err);
220
- if (_this.shouldAbortSync(err)) return {};
213
+ this.syncOpts.logger.error("Getting filter failed", err);
214
+ if (this.shouldAbortSync(err)) return {};
221
215
  // wait for saved sync to complete before doing anything else,
222
216
  // otherwise the sync state will end up being incorrect
223
- _this.syncOpts.logger.debug("Waiting for saved sync before retrying filter...");
224
- yield _this.recoverFromSyncStartupError(_this.savedSyncPromise, err);
225
- return _this.getFilter(); // try again
217
+ this.syncOpts.logger.debug("Waiting for saved sync before retrying filter...");
218
+ await this.recoverFromSyncStartupError(this.savedSyncPromise, err);
219
+ return this.getFilter(); // try again
226
220
  }
227
221
  return {
228
222
  filter,
229
223
  filterId
230
224
  };
231
- }));
225
+ });
232
226
  _defineProperty(this, "savedSyncPromise", void 0);
233
227
  /**
234
228
  * Event handler for the 'online' event
@@ -240,6 +234,7 @@ export class SyncApi {
240
234
  this.syncOpts.logger.debug("Browser thinks we are back online");
241
235
  this.startKeepAlives(0);
242
236
  });
237
+ this.client = client;
243
238
  this.opts = defaultClientOpts(opts);
244
239
  this.syncOpts = defaultSyncApiOpts(syncOpts);
245
240
  if (client.getNotifTimelineSet()) {
@@ -247,7 +242,7 @@ export class SyncApi {
247
242
  }
248
243
  }
249
244
  createRoom(roomId) {
250
- var room = _createAndReEmitRoom(this.client, roomId, this.opts);
245
+ const room = _createAndReEmitRoom(this.client, roomId, this.opts);
251
246
  room.on(RoomStateEvent.Marker, (markerEvent, markerFoundOptions) => {
252
247
  this.onMarkerStateEvent(room, markerEvent, markerFoundOptions);
253
248
  });
@@ -263,19 +258,19 @@ export class SyncApi {
263
258
  * @param setStateOptions - When `timelineWasEmpty` is set
264
259
  * as `true`, the given marker event will be ignored
265
260
  */
266
- onMarkerStateEvent(room, markerEvent) {
267
- var _ref5 = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {},
268
- timelineWasEmpty = _ref5.timelineWasEmpty;
261
+ onMarkerStateEvent(room, markerEvent, {
262
+ timelineWasEmpty
263
+ } = {}) {
269
264
  // We don't need to refresh the timeline if it was empty before the
270
265
  // marker arrived. This could be happen in a variety of cases:
271
266
  // 1. From the initial sync
272
267
  // 2. If it's from the first state we're seeing after joining the room
273
268
  // 3. Or whether it's coming from `syncFromCache`
274
269
  if (timelineWasEmpty) {
275
- this.syncOpts.logger.debug("MarkerState: Ignoring markerEventId=".concat(markerEvent.getId(), " in roomId=").concat(room.roomId, " ") + "because the timeline was empty before the marker arrived which means there is nothing to refresh.");
270
+ this.syncOpts.logger.debug(`MarkerState: Ignoring markerEventId=${markerEvent.getId()} in roomId=${room.roomId} ` + `because the timeline was empty before the marker arrived which means there is nothing to refresh.`);
276
271
  return;
277
272
  }
278
- var isValidMsc2716Event =
273
+ const isValidMsc2716Event =
279
274
  // Check whether the room version directly supports MSC2716, in
280
275
  // which case, "marker" events are already auth'ed by
281
276
  // power_levels
@@ -300,11 +295,11 @@ export class SyncApi {
300
295
  if (isValidMsc2716Event) {
301
296
  // Saw new marker event, let's let the clients know they should
302
297
  // refresh the timeline.
303
- this.syncOpts.logger.debug("MarkerState: Timeline needs to be refreshed because " + "a new markerEventId=".concat(markerEvent.getId(), " was sent in roomId=").concat(room.roomId));
298
+ this.syncOpts.logger.debug(`MarkerState: Timeline needs to be refreshed because ` + `a new markerEventId=${markerEvent.getId()} was sent in roomId=${room.roomId}`);
304
299
  room.setTimelineNeedsRefresh(true);
305
300
  room.emit(RoomEvent.HistoryImportedWithinTimeline, markerEvent, room);
306
301
  } else {
307
- this.syncOpts.logger.debug("MarkerState: Ignoring markerEventId=".concat(markerEvent.getId(), " in roomId=").concat(room.roomId, " because ") + "MSC2716 is not supported in the room version or for any room version, the marker wasn't sent " + "by the room creator.");
302
+ this.syncOpts.logger.debug(`MarkerState: Ignoring markerEventId=${markerEvent.getId()} in roomId=${room.roomId} because ` + `MSC2716 is not supported in the room version or for any room version, the marker wasn't sent ` + `by the room creator.`);
308
303
  }
309
304
  }
310
305
 
@@ -312,67 +307,59 @@ export class SyncApi {
312
307
  * Sync rooms the user has left.
313
308
  * @returns Resolved when they've been added to the store.
314
309
  */
315
- syncLeftRooms() {
316
- var _this2 = this;
317
- return _asyncToGenerator(function* () {
318
- var _data$rooms;
319
- var client = _this2.client;
320
-
321
- // grab a filter with limit=1 and include_leave=true
322
- var filter = new Filter(_this2.client.credentials.userId);
323
- filter.setTimelineLimit(1);
324
- filter.setIncludeLeaveRooms(true);
325
- var localTimeoutMs = _this2.opts.pollTimeout + BUFFER_PERIOD_MS;
326
- var filterId = yield client.getOrCreateFilter(getFilterName(client.credentials.userId, "LEFT_ROOMS"), filter);
327
- var qps = {
328
- "timeout": 0,
329
- // don't want to block since this is a single isolated req
330
- "filter": filterId,
331
- "org.matrix.msc4222.use_state_after": true
332
- };
333
- var data = yield client.http.authedRequest(Method.Get, "/sync", qps, undefined, {
334
- localTimeoutMs
335
- });
336
- var leaveRooms = [];
337
- if ((_data$rooms = data.rooms) !== null && _data$rooms !== void 0 && _data$rooms.leave) {
338
- leaveRooms = _this2.mapSyncResponseToRoomArray(data.rooms.leave);
310
+ async syncLeftRooms() {
311
+ const client = this.client;
312
+
313
+ // grab a filter with limit=1 and include_leave=true
314
+ const filter = new Filter(this.client.credentials.userId);
315
+ filter.setTimelineLimit(1);
316
+ filter.setIncludeLeaveRooms(true);
317
+ const localTimeoutMs = this.opts.pollTimeout + BUFFER_PERIOD_MS;
318
+ const filterId = await client.getOrCreateFilter(getFilterName(client.credentials.userId, "LEFT_ROOMS"), filter);
319
+ const qps = {
320
+ "timeout": 0,
321
+ // don't want to block since this is a single isolated req
322
+ "filter": filterId,
323
+ "org.matrix.msc4222.use_state_after": true
324
+ };
325
+ const data = await client.http.authedRequest(Method.Get, "/sync", qps, undefined, {
326
+ localTimeoutMs
327
+ });
328
+ let leaveRooms = [];
329
+ if (data.rooms?.leave) {
330
+ leaveRooms = this.mapSyncResponseToRoomArray(data.rooms.leave);
331
+ }
332
+ const rooms = await Promise.all(leaveRooms.map(async leaveObj => {
333
+ const room = leaveObj.room;
334
+ if (!leaveObj.isBrandNewRoom) {
335
+ // the intention behind syncLeftRooms is to add in rooms which were
336
+ // *omitted* from the initial /sync. Rooms the user were joined to
337
+ // but then left whilst the app is running will appear in this list
338
+ // and we do not want to bother with them since they will have the
339
+ // current state already (and may get dupe messages if we add
340
+ // yet more timeline events!), so skip them.
341
+ // NB: When we persist rooms to localStorage this will be more
342
+ // complicated...
343
+ return;
339
344
  }
340
- var rooms = yield Promise.all(leaveRooms.map(/*#__PURE__*/function () {
341
- var _ref6 = _asyncToGenerator(function* (leaveObj) {
342
- var room = leaveObj.room;
343
- if (!leaveObj.isBrandNewRoom) {
344
- // the intention behind syncLeftRooms is to add in rooms which were
345
- // *omitted* from the initial /sync. Rooms the user were joined to
346
- // but then left whilst the app is running will appear in this list
347
- // and we do not want to bother with them since they will have the
348
- // current state already (and may get dupe messages if we add
349
- // yet more timeline events!), so skip them.
350
- // NB: When we persist rooms to localStorage this will be more
351
- // complicated...
352
- return;
353
- }
354
- leaveObj.timeline = leaveObj.timeline || {
355
- prev_batch: null,
356
- events: []
357
- };
358
-
359
- // set the back-pagination token. Do this *before* adding any
360
- // events so that clients can start back-paginating.
361
- room.getLiveTimeline().setPaginationToken(leaveObj.timeline.prev_batch, EventTimeline.BACKWARDS);
362
- var _yield$_this2$mapAndI = yield _this2.mapAndInjectRoomEvents(leaveObj),
363
- timelineEvents = _yield$_this2$mapAndI.timelineEvents;
364
- room.recalculate();
365
- client.store.storeRoom(room);
366
- client.emit(ClientEvent.Room, room);
367
- _this2.processEventsForNotifs(room, timelineEvents);
368
- return room;
369
- });
370
- return function (_x) {
371
- return _ref6.apply(this, arguments);
372
- };
373
- }()));
374
- return rooms.filter(Boolean);
375
- })();
345
+ leaveObj.timeline = leaveObj.timeline || {
346
+ prev_batch: null,
347
+ events: []
348
+ };
349
+
350
+ // set the back-pagination token. Do this *before* adding any
351
+ // events so that clients can start back-paginating.
352
+ room.getLiveTimeline().setPaginationToken(leaveObj.timeline.prev_batch, EventTimeline.BACKWARDS);
353
+ const {
354
+ timelineEvents
355
+ } = await this.mapAndInjectRoomEvents(leaveObj);
356
+ room.recalculate();
357
+ client.store.storeRoom(room);
358
+ client.emit(ClientEvent.Room, room);
359
+ this.processEventsForNotifs(room, timelineEvents);
360
+ return room;
361
+ }));
362
+ return rooms.filter(Boolean);
376
363
  }
377
364
 
378
365
  /**
@@ -383,17 +370,14 @@ export class SyncApi {
383
370
  * @returns A promise which resolves once the room has been added to the
384
371
  * store.
385
372
  */
386
- peek(roomId) {
387
- var _this$_peekRoom;
388
- var limit = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 20;
389
- if (((_this$_peekRoom = this._peekRoom) === null || _this$_peekRoom === void 0 ? void 0 : _this$_peekRoom.roomId) === roomId) {
373
+ peek(roomId, limit = 20) {
374
+ if (this._peekRoom?.roomId === roomId) {
390
375
  return Promise.resolve(this._peekRoom);
391
376
  }
392
- var client = this.client;
377
+ const client = this.client;
393
378
  this._peekRoom = this.createRoom(roomId);
394
379
  return this.client.roomInitialSync(roomId, limit).then(response => {
395
- var _this$_peekRoom2;
396
- if (((_this$_peekRoom2 = this._peekRoom) === null || _this$_peekRoom2 === void 0 ? void 0 : _this$_peekRoom2.roomId) !== roomId) {
380
+ if (this._peekRoom?.roomId !== roomId) {
397
381
  throw new Error("Peeking aborted");
398
382
  }
399
383
 
@@ -406,15 +390,15 @@ export class SyncApi {
406
390
 
407
391
  // FIXME: Mostly duplicated from injectRoomEvents but not entirely
408
392
  // because "state" in this API is at the BEGINNING of the chunk
409
- var oldStateEvents = deepCopy(response.state).map(client.getEventMapper());
410
- var stateEvents = response.state.map(client.getEventMapper());
411
- var messages = response.messages.chunk.map(client.getEventMapper());
393
+ const oldStateEvents = deepCopy(response.state).map(client.getEventMapper());
394
+ const stateEvents = response.state.map(client.getEventMapper());
395
+ const messages = response.messages.chunk.map(client.getEventMapper());
412
396
 
413
397
  // XXX: copypasted from /sync until we kill off this minging v1 API stuff)
414
398
  // handle presence events (User objects)
415
399
  if (Array.isArray(response.presence)) {
416
400
  response.presence.map(client.getEventMapper()).forEach(function (presenceEvent) {
417
- var user = client.store.getUser(presenceEvent.getContent().user_id);
401
+ let user = client.store.getUser(presenceEvent.getContent().user_id);
418
402
  if (user) {
419
403
  user.setPresenceEvent(presenceEvent);
420
404
  } else {
@@ -463,8 +447,6 @@ export class SyncApi {
463
447
  * @param token - from= token
464
448
  */
465
449
  peekPoll(peekRoom, token) {
466
- var _this$abortController,
467
- _this3 = this;
468
450
  if (this._peekRoom !== peekRoom) {
469
451
  this.syncOpts.logger.debug("Stopped peeking in room %s", peekRoom.roomId);
470
452
  return;
@@ -477,51 +459,46 @@ export class SyncApi {
477
459
  from: token
478
460
  }, undefined, {
479
461
  localTimeoutMs: 50 * 1000,
480
- abortSignal: (_this$abortController = this.abortController) === null || _this$abortController === void 0 ? void 0 : _this$abortController.signal
481
- }).then(/*#__PURE__*/function () {
482
- var _ref7 = _asyncToGenerator(function* (res) {
483
- if (_this3._peekRoom !== peekRoom) {
484
- _this3.syncOpts.logger.debug("Stopped peeking in room %s", peekRoom.roomId);
485
- return;
462
+ abortSignal: this.abortController?.signal
463
+ }).then(async res => {
464
+ if (this._peekRoom !== peekRoom) {
465
+ this.syncOpts.logger.debug("Stopped peeking in room %s", peekRoom.roomId);
466
+ return;
467
+ }
468
+ // We have a problem that we get presence both from /events and /sync
469
+ // however, /sync only returns presence for users in rooms
470
+ // you're actually joined to.
471
+ // in order to be sure to get presence for all of the users in the
472
+ // peeked room, we handle presence explicitly here. This may result
473
+ // in duplicate presence events firing for some users, which is a
474
+ // performance drain, but such is life.
475
+ // XXX: copypasted from /sync until we can kill this minging v1 stuff.
476
+
477
+ res.chunk.filter(function (e) {
478
+ return e.type === "m.presence";
479
+ }).map(this.client.getEventMapper()).forEach(presenceEvent => {
480
+ let user = this.client.store.getUser(presenceEvent.getContent().user_id);
481
+ if (user) {
482
+ user.setPresenceEvent(presenceEvent);
483
+ } else {
484
+ user = User.createUser(presenceEvent.getContent().user_id, this.client);
485
+ user.setPresenceEvent(presenceEvent);
486
+ this.client.store.storeUser(user);
486
487
  }
487
- // We have a problem that we get presence both from /events and /sync
488
- // however, /sync only returns presence for users in rooms
489
- // you're actually joined to.
490
- // in order to be sure to get presence for all of the users in the
491
- // peeked room, we handle presence explicitly here. This may result
492
- // in duplicate presence events firing for some users, which is a
493
- // performance drain, but such is life.
494
- // XXX: copypasted from /sync until we can kill this minging v1 stuff.
495
-
496
- res.chunk.filter(function (e) {
497
- return e.type === "m.presence";
498
- }).map(_this3.client.getEventMapper()).forEach(presenceEvent => {
499
- var user = _this3.client.store.getUser(presenceEvent.getContent().user_id);
500
- if (user) {
501
- user.setPresenceEvent(presenceEvent);
502
- } else {
503
- user = User.createUser(presenceEvent.getContent().user_id, _this3.client);
504
- user.setPresenceEvent(presenceEvent);
505
- _this3.client.store.storeUser(user);
506
- }
507
- _this3.client.emit(ClientEvent.Event, presenceEvent);
508
- });
488
+ this.client.emit(ClientEvent.Event, presenceEvent);
489
+ });
509
490
 
510
- // strip out events which aren't for the given room_id (e.g presence)
511
- // and also ephemeral events (which we're assuming is anything without
512
- // and event ID because the /events API doesn't separate them).
513
- var events = res.chunk.filter(function (e) {
514
- return e.room_id === peekRoom.roomId && e.event_id;
515
- }).map(_this3.client.getEventMapper());
516
- yield peekRoom.addLiveEvents(events, {
517
- addToState: true
518
- });
519
- _this3.peekPoll(peekRoom, res.end);
491
+ // strip out events which aren't for the given room_id (e.g presence)
492
+ // and also ephemeral events (which we're assuming is anything without
493
+ // and event ID because the /events API doesn't separate them).
494
+ const events = res.chunk.filter(function (e) {
495
+ return e.room_id === peekRoom.roomId && e.event_id;
496
+ }).map(this.client.getEventMapper());
497
+ await peekRoom.addLiveEvents(events, {
498
+ addToState: true
520
499
  });
521
- return function (_x2) {
522
- return _ref7.apply(this, arguments);
523
- };
524
- }(), err => {
500
+ this.peekPoll(peekRoom, res.end);
501
+ }, err => {
525
502
  this.syncOpts.logger.error("[%s] Peek poll failed: %s", peekRoom.roomId, err);
526
503
  setTimeout(() => {
527
504
  this.peekPoll(peekRoom, token);
@@ -545,23 +522,19 @@ export class SyncApi {
545
522
  * this object.
546
523
  */
547
524
  getSyncStateData() {
548
- var _this$syncStateData;
549
- return (_this$syncStateData = this.syncStateData) !== null && _this$syncStateData !== void 0 ? _this$syncStateData : null;
525
+ return this.syncStateData ?? null;
550
526
  }
551
- recoverFromSyncStartupError(savedSyncPromise, error) {
552
- var _this4 = this;
553
- return _asyncToGenerator(function* () {
554
- // Wait for the saved sync to complete - we send the pushrules and filter requests
555
- // before the saved sync has finished so they can run in parallel, but only process
556
- // the results after the saved sync is done. Equivalently, we wait for it to finish
557
- // before reporting failures from these functions.
558
- yield savedSyncPromise;
559
- var keepaliveProm = _this4.startKeepAlives();
560
- _this4.updateSyncState(SyncState.Error, {
561
- error
562
- });
563
- yield keepaliveProm;
564
- })();
527
+ async recoverFromSyncStartupError(savedSyncPromise, error) {
528
+ // Wait for the saved sync to complete - we send the pushrules and filter requests
529
+ // before the saved sync has finished so they can run in parallel, but only process
530
+ // the results after the saved sync is done. Equivalently, we wait for it to finish
531
+ // before reporting failures from these functions.
532
+ await savedSyncPromise;
533
+ const keepaliveProm = this.startKeepAlives();
534
+ this.updateSyncState(SyncState.Error, {
535
+ error
536
+ });
537
+ await keepaliveProm;
565
538
  }
566
539
  shouldAbortSync(error) {
567
540
  if (error.errcode === "M_UNKNOWN_TOKEN") {
@@ -578,104 +551,100 @@ export class SyncApi {
578
551
  /**
579
552
  * Main entry point
580
553
  */
581
- sync() {
582
- var _this5 = this;
583
- return _asyncToGenerator(function* () {
584
- var _globalThis$window, _globalThis$window$ad;
585
- _this5.running = true;
586
- _this5.abortController = new AbortController();
587
- (_globalThis$window = globalThis.window) === null || _globalThis$window === void 0 || (_globalThis$window$ad = _globalThis$window.addEventListener) === null || _globalThis$window$ad === void 0 || _globalThis$window$ad.call(_globalThis$window, "online", _this5.onOnline, false);
588
- if (_this5.client.isGuest()) {
589
- // no push rules for guests, no access to POST filter for guests.
590
- return _this5.doSync({});
591
- }
592
-
593
- // Pull the saved sync token out first, before the worker starts sending
594
- // all the sync data which could take a while. This will let us send our
595
- // first incremental sync request before we've processed our saved data.
596
- _this5.syncOpts.logger.debug("Getting saved sync token...");
597
- var savedSyncTokenPromise = _this5.client.store.getSavedSyncToken().then(tok => {
598
- _this5.syncOpts.logger.debug("Got saved sync token");
599
- return tok;
600
- });
601
- _this5.savedSyncPromise = _this5.client.store.getSavedSync().then(savedSync => {
602
- _this5.syncOpts.logger.debug("Got reply from saved sync, exists? ".concat(!!savedSync));
603
- if (savedSync) {
604
- return _this5.syncFromCache(savedSync);
605
- }
606
- }).catch(err => {
607
- _this5.syncOpts.logger.error("Getting saved sync failed", err);
608
- });
554
+ async sync() {
555
+ this.running = true;
556
+ this.abortController = new AbortController();
557
+ globalThis.window?.addEventListener?.("online", this.onOnline, false);
558
+ if (this.client.isGuest()) {
559
+ // no push rules for guests, no access to POST filter for guests.
560
+ return this.doSync({});
561
+ }
609
562
 
610
- // We need to do one-off checks before we can begin the /sync loop.
611
- // These are:
612
- // 1) We need to get push rules so we can check if events should bing as we get
613
- // them from /sync.
614
- // 2) We need to get/create a filter which we can use for /sync.
615
- // 3) We need to prepare lazy loading for sync
616
- // 4) We need to store the client options
617
-
618
- // Now start the first incremental sync request: this can also
619
- // take a while so if we set it going now, we can wait for it
620
- // to finish while we process our saved sync data.
621
- yield _this5.getPushRules();
622
- _this5.prepareSyncFilterLazyLoading();
623
- yield _this5.prepareSyncFilterUserProfiles();
624
- yield _this5.storeClientOptions();
625
- var _yield$_this5$getFilt = yield _this5.getFilter(),
626
- filterId = _yield$_this5$getFilt.filterId,
627
- filter = _yield$_this5$getFilt.filter;
628
- if (!filter) return; // bail, getFilter failed
629
-
630
- // reset the notifications timeline to prepare it to paginate from
631
- // the current point in time.
632
- // The right solution would be to tie /sync pagination tokens into
633
- // /notifications API somehow.
634
- _this5.client.resetNotifTimelineSet();
635
- if (!_this5.currentSyncRequest) {
636
- var firstSyncFilter = filterId;
637
- var savedSyncToken = yield savedSyncTokenPromise;
638
- if (savedSyncToken) {
639
- _this5.syncOpts.logger.debug("Sending first sync request...");
640
- } else {
641
- _this5.syncOpts.logger.debug("Sending initial sync request...");
642
- var initialFilter = _this5.buildDefaultFilter();
643
- initialFilter.setDefinition(filter.getDefinition());
644
- initialFilter.setTimelineLimit(_this5.opts.initialSyncLimit);
645
- // Use an inline filter, no point uploading it for a single usage
646
- firstSyncFilter = JSON.stringify(initialFilter.getDefinition());
647
- }
563
+ // Pull the saved sync token out first, before the worker starts sending
564
+ // all the sync data which could take a while. This will let us send our
565
+ // first incremental sync request before we've processed our saved data.
566
+ this.syncOpts.logger.debug("Getting saved sync token...");
567
+ const savedSyncTokenPromise = this.client.store.getSavedSyncToken().then(tok => {
568
+ this.syncOpts.logger.debug("Got saved sync token");
569
+ return tok;
570
+ });
571
+ this.savedSyncPromise = this.client.store.getSavedSync().then(savedSync => {
572
+ this.syncOpts.logger.debug(`Got reply from saved sync, exists? ${!!savedSync}`);
573
+ if (savedSync) {
574
+ return this.syncFromCache(savedSync);
575
+ }
576
+ }).catch(err => {
577
+ this.syncOpts.logger.error("Getting saved sync failed", err);
578
+ });
648
579
 
649
- // Send this first sync request here so we can then wait for the saved
650
- // sync data to finish processing before we process the results of this one.
651
- _this5.currentSyncRequest = _this5.doSyncRequest({
652
- filter: firstSyncFilter
653
- }, savedSyncToken);
580
+ // We need to do one-off checks before we can begin the /sync loop.
581
+ // These are:
582
+ // 1) We need to get push rules so we can check if events should bing as we get
583
+ // them from /sync.
584
+ // 2) We need to get/create a filter which we can use for /sync.
585
+ // 3) We need to prepare lazy loading for sync
586
+ // 4) We need to store the client options
587
+
588
+ // Now start the first incremental sync request: this can also
589
+ // take a while so if we set it going now, we can wait for it
590
+ // to finish while we process our saved sync data.
591
+ await this.getPushRules();
592
+ this.prepareSyncFilterLazyLoading();
593
+ await this.prepareSyncFilterUserProfiles();
594
+ await this.storeClientOptions();
595
+ const {
596
+ filterId,
597
+ filter
598
+ } = await this.getFilter();
599
+ if (!filter) return; // bail, getFilter failed
600
+
601
+ // reset the notifications timeline to prepare it to paginate from
602
+ // the current point in time.
603
+ // The right solution would be to tie /sync pagination tokens into
604
+ // /notifications API somehow.
605
+ this.client.resetNotifTimelineSet();
606
+ if (!this.currentSyncRequest) {
607
+ let firstSyncFilter = filterId;
608
+ const savedSyncToken = await savedSyncTokenPromise;
609
+ if (savedSyncToken) {
610
+ this.syncOpts.logger.debug("Sending first sync request...");
611
+ } else {
612
+ this.syncOpts.logger.debug("Sending initial sync request...");
613
+ const initialFilter = this.buildDefaultFilter();
614
+ initialFilter.setDefinition(filter.getDefinition());
615
+ initialFilter.setTimelineLimit(this.opts.initialSyncLimit);
616
+ // Use an inline filter, no point uploading it for a single usage
617
+ firstSyncFilter = JSON.stringify(initialFilter.getDefinition());
654
618
  }
655
619
 
656
- // Now wait for the saved sync to finish...
657
- _this5.syncOpts.logger.debug("Waiting for saved sync before starting sync processing...");
658
- yield _this5.savedSyncPromise;
659
- // process the first sync request and continue syncing with the normal filterId
660
- return _this5.doSync({
661
- filter: filterId
662
- });
663
- })();
620
+ // Send this first sync request here so we can then wait for the saved
621
+ // sync data to finish processing before we process the results of this one.
622
+ this.currentSyncRequest = this.doSyncRequest({
623
+ filter: firstSyncFilter
624
+ }, savedSyncToken);
625
+ }
626
+
627
+ // Now wait for the saved sync to finish...
628
+ this.syncOpts.logger.debug("Waiting for saved sync before starting sync processing...");
629
+ await this.savedSyncPromise;
630
+ // process the first sync request and continue syncing with the normal filterId
631
+ return this.doSync({
632
+ filter: filterId
633
+ });
664
634
  }
665
635
 
666
636
  /**
667
637
  * Stops the sync object from syncing.
668
638
  */
669
639
  stop() {
670
- var _globalThis$window2, _globalThis$window2$r, _this$abortController2;
671
640
  this.syncOpts.logger.debug("SyncApi.stop");
672
641
  // It is necessary to check for the existance of
673
642
  // globalThis.window AND globalThis.window.removeEventListener.
674
643
  // Some platforms (e.g. React Native) register globalThis.window,
675
644
  // but do not have globalThis.window.removeEventListener.
676
- (_globalThis$window2 = globalThis.window) === null || _globalThis$window2 === void 0 || (_globalThis$window2$r = _globalThis$window2.removeEventListener) === null || _globalThis$window2$r === void 0 || _globalThis$window2$r.call(_globalThis$window2, "online", this.onOnline, false);
645
+ globalThis.window?.removeEventListener?.("online", this.onOnline, false);
677
646
  this.running = false;
678
- (_this$abortController2 = this.abortController) === null || _this$abortController2 === void 0 || _this$abortController2.abort();
647
+ this.abortController?.abort();
679
648
  if (this.keepAliveTimer) {
680
649
  clearTimeout(this.keepAliveTimer);
681
650
  this.keepAliveTimer = undefined;
@@ -699,134 +668,127 @@ export class SyncApi {
699
668
  * @param savedSync - a saved sync that was persisted by a store. This
700
669
  * should have been acquired via client.store.getSavedSync().
701
670
  */
702
- syncFromCache(savedSync) {
703
- var _this6 = this;
704
- return _asyncToGenerator(function* () {
705
- _this6.syncOpts.logger.debug("sync(): not doing HTTP hit, instead returning stored /sync data");
706
- var nextSyncToken = savedSync.nextBatch;
707
-
708
- // Set sync token for future incremental syncing
709
- _this6.client.store.setSyncToken(nextSyncToken);
710
-
711
- // No previous sync, set old token to null
712
- var syncEventData = {
713
- nextSyncToken,
714
- catchingUp: false,
715
- fromCache: true
716
- };
717
- var data = {
718
- next_batch: nextSyncToken,
719
- rooms: savedSync.roomsData,
720
- account_data: {
721
- events: savedSync.accountData
722
- }
723
- };
724
- try {
725
- yield _this6.processSyncResponse(syncEventData, data);
726
- } catch (e) {
727
- _this6.syncOpts.logger.error("Error processing cached sync", e);
671
+ async syncFromCache(savedSync) {
672
+ this.syncOpts.logger.debug("sync(): not doing HTTP hit, instead returning stored /sync data");
673
+ const nextSyncToken = savedSync.nextBatch;
674
+
675
+ // Set sync token for future incremental syncing
676
+ this.client.store.setSyncToken(nextSyncToken);
677
+
678
+ // No previous sync, set old token to null
679
+ const syncEventData = {
680
+ nextSyncToken,
681
+ catchingUp: false,
682
+ fromCache: true
683
+ };
684
+ const data = {
685
+ next_batch: nextSyncToken,
686
+ rooms: savedSync.roomsData,
687
+ account_data: {
688
+ events: savedSync.accountData
728
689
  }
690
+ };
691
+ try {
692
+ await this.processSyncResponse(syncEventData, data);
693
+ } catch (e) {
694
+ this.syncOpts.logger.error("Error processing cached sync", e);
695
+ }
729
696
 
730
- // Don't emit a prepared if we've bailed because the store is invalid:
731
- // in this case the client will not be usable until stopped & restarted
732
- // so this would be useless and misleading.
733
- if (!_this6.storeIsInvalid) {
734
- _this6.updateSyncState(SyncState.Prepared, syncEventData);
735
- }
736
- })();
697
+ // Don't emit a prepared if we've bailed because the store is invalid:
698
+ // in this case the client will not be usable until stopped & restarted
699
+ // so this would be useless and misleading.
700
+ if (!this.storeIsInvalid) {
701
+ this.updateSyncState(SyncState.Prepared, syncEventData);
702
+ }
737
703
  }
738
704
 
739
705
  /**
740
706
  * Invoke me to do /sync calls
741
707
  */
742
- doSync(syncOptions) {
743
- var _this7 = this;
744
- return _asyncToGenerator(function* () {
745
- while (_this7.running) {
746
- var syncToken = _this7.client.store.getSyncToken();
747
- var data = void 0;
748
- try {
749
- if (!_this7.currentSyncRequest) {
750
- _this7.currentSyncRequest = _this7.doSyncRequest(syncOptions, syncToken);
751
- }
752
- data = yield _this7.currentSyncRequest;
753
- } catch (e) {
754
- var abort = yield _this7.onSyncError(e);
755
- if (abort) return;
756
- continue;
757
- } finally {
758
- _this7.currentSyncRequest = undefined;
708
+ async doSync(syncOptions) {
709
+ while (this.running) {
710
+ const syncToken = this.client.store.getSyncToken();
711
+ let data;
712
+ try {
713
+ if (!this.currentSyncRequest) {
714
+ this.currentSyncRequest = this.doSyncRequest(syncOptions, syncToken);
759
715
  }
716
+ data = await this.currentSyncRequest;
717
+ } catch (e) {
718
+ const abort = await this.onSyncError(e);
719
+ if (abort) return;
720
+ continue;
721
+ } finally {
722
+ this.currentSyncRequest = undefined;
723
+ }
760
724
 
761
- // set the sync token NOW *before* processing the events. We do this so
762
- // if something barfs on an event we can skip it rather than constantly
763
- // polling with the same token.
764
- _this7.client.store.setSyncToken(data.next_batch);
765
-
766
- // Reset after a successful sync
767
- _this7.failedSyncCount = 0;
768
- var syncEventData = {
769
- oldSyncToken: syncToken !== null && syncToken !== void 0 ? syncToken : undefined,
770
- nextSyncToken: data.next_batch,
771
- catchingUp: _this7.catchingUp
772
- };
773
- try {
774
- yield _this7.processSyncResponse(syncEventData, data);
775
- } catch (e) {
776
- // log the exception with stack if we have it, else fall back
777
- // to the plain description
778
- _this7.syncOpts.logger.error("Caught /sync error", e);
779
-
780
- // Emit the exception for client handling
781
- _this7.client.emit(ClientEvent.SyncUnexpectedError, e);
782
- }
725
+ // set the sync token NOW *before* processing the events. We do this so
726
+ // if something barfs on an event we can skip it rather than constantly
727
+ // polling with the same token.
728
+ this.client.store.setSyncToken(data.next_batch);
729
+
730
+ // Reset after a successful sync
731
+ this.failedSyncCount = 0;
732
+ const syncEventData = {
733
+ oldSyncToken: syncToken ?? undefined,
734
+ nextSyncToken: data.next_batch,
735
+ catchingUp: this.catchingUp
736
+ };
737
+ try {
738
+ await this.processSyncResponse(syncEventData, data);
739
+ } catch (e) {
740
+ // log the exception with stack if we have it, else fall back
741
+ // to the plain description
742
+ this.syncOpts.logger.error("Caught /sync error", e);
783
743
 
784
- // Persist after processing as `unsigned` may get mutated
785
- // with an `org.matrix.msc4023.thread_id`
786
- yield _this7.client.store.setSyncData(data);
744
+ // Emit the exception for client handling
745
+ this.client.emit(ClientEvent.SyncUnexpectedError, e);
746
+ }
787
747
 
788
- // update this as it may have changed
789
- syncEventData.catchingUp = _this7.catchingUp;
748
+ // Persist after processing as `unsigned` may get mutated
749
+ // with an `org.matrix.msc4023.thread_id`
750
+ await this.client.store.setSyncData(data);
790
751
 
791
- // emit synced events
792
- if (!syncOptions.hasSyncedBefore) {
793
- _this7.updateSyncState(SyncState.Prepared, syncEventData);
794
- syncOptions.hasSyncedBefore = true;
795
- }
752
+ // update this as it may have changed
753
+ syncEventData.catchingUp = this.catchingUp;
796
754
 
797
- // tell the crypto module to do its processing. It may block (to do a
798
- // /keys/changes request).
799
- if (_this7.syncOpts.cryptoCallbacks) {
800
- yield _this7.syncOpts.cryptoCallbacks.onSyncCompleted(syncEventData);
801
- }
755
+ // emit synced events
756
+ if (!syncOptions.hasSyncedBefore) {
757
+ this.updateSyncState(SyncState.Prepared, syncEventData);
758
+ syncOptions.hasSyncedBefore = true;
759
+ }
802
760
 
803
- // keep emitting SYNCING -> SYNCING for clients who want to do bulk updates
804
- _this7.updateSyncState(SyncState.Syncing, syncEventData);
805
- if (_this7.client.store.wantsSave()) {
806
- // tell databases that everything is now in a consistent state and can be saved.
807
- yield _this7.client.store.save();
808
- }
761
+ // tell the crypto module to do its processing. It may block (to do a
762
+ // /keys/changes request).
763
+ if (this.syncOpts.cryptoCallbacks) {
764
+ this.syncOpts.cryptoCallbacks.onSyncCompleted(syncEventData);
809
765
  }
810
- if (!_this7.running) {
811
- _this7.syncOpts.logger.debug("Sync no longer running: exiting.");
812
- if (_this7.connectionReturnedResolvers) {
813
- _this7.connectionReturnedResolvers.reject();
814
- _this7.connectionReturnedResolvers = undefined;
815
- }
816
- _this7.updateSyncState(SyncState.Stopped);
766
+
767
+ // keep emitting SYNCING -> SYNCING for clients who want to do bulk updates
768
+ this.updateSyncState(SyncState.Syncing, syncEventData);
769
+ if (this.client.store.wantsSave()) {
770
+ // tell databases that everything is now in a consistent state and can be saved.
771
+ await this.client.store.save();
772
+ }
773
+ }
774
+ if (!this.running) {
775
+ this.syncOpts.logger.debug("Sync no longer running: exiting.");
776
+ if (this.connectionReturnedResolvers) {
777
+ this.connectionReturnedResolvers.reject();
778
+ this.connectionReturnedResolvers = undefined;
817
779
  }
818
- })();
780
+ this.updateSyncState(SyncState.Stopped);
781
+ }
819
782
  }
820
783
  doSyncRequest(syncOptions, syncToken) {
821
- var _this$abortController3;
822
- var qps = this.getSyncParams(syncOptions, syncToken);
784
+ const qps = this.getSyncParams(syncOptions, syncToken);
823
785
  return this.client.http.authedRequest(Method.Get, "/sync", qps, undefined, {
824
786
  localTimeoutMs: qps.timeout + BUFFER_PERIOD_MS,
825
- abortSignal: (_this$abortController3 = this.abortController) === null || _this$abortController3 === void 0 ? void 0 : _this$abortController3.signal
787
+ abortSignal: this.abortController?.signal
826
788
  });
827
789
  }
828
790
  getSyncParams(syncOptions, syncToken) {
829
- var timeout = this.opts.pollTimeout;
791
+ let timeout = this.opts.pollTimeout;
830
792
  if (this.getSyncState() !== SyncState.Syncing || this.catchingUp) {
831
793
  // unless we are happily syncing already, we want the server to return
832
794
  // as quickly as possible, even if there are no events queued. This
@@ -842,11 +804,11 @@ export class SyncApi {
842
804
  this.catchingUp = true;
843
805
  timeout = 0;
844
806
  }
845
- var filter = syncOptions.filter;
807
+ let filter = syncOptions.filter;
846
808
  if (this.client.isGuest() && !filter) {
847
809
  filter = this.getGuestFilter();
848
810
  }
849
- var qps = {
811
+ const qps = {
850
812
  filter,
851
813
  timeout,
852
814
  "org.matrix.msc4222.use_state_after": true
@@ -881,51 +843,48 @@ export class SyncApi {
881
843
  setPresence(presence) {
882
844
  this.presence = presence;
883
845
  }
884
- onSyncError(err) {
885
- var _this8 = this;
886
- return _asyncToGenerator(function* () {
887
- if (!_this8.running) {
888
- _this8.syncOpts.logger.debug("Sync no longer running: exiting");
889
- if (_this8.connectionReturnedResolvers) {
890
- _this8.connectionReturnedResolvers.reject();
891
- _this8.connectionReturnedResolvers = undefined;
892
- }
893
- _this8.updateSyncState(SyncState.Stopped);
894
- return true; // abort
895
- }
896
- _this8.syncOpts.logger.error("/sync error %s", err);
897
- if (_this8.shouldAbortSync(err)) {
898
- return true; // abort
846
+ async onSyncError(err) {
847
+ if (!this.running) {
848
+ this.syncOpts.logger.debug("Sync no longer running: exiting");
849
+ if (this.connectionReturnedResolvers) {
850
+ this.connectionReturnedResolvers.reject();
851
+ this.connectionReturnedResolvers = undefined;
899
852
  }
900
- _this8.failedSyncCount++;
901
- _this8.syncOpts.logger.debug("Number of consecutive failed sync requests:", _this8.failedSyncCount);
902
- _this8.syncOpts.logger.debug("Starting keep-alive");
903
- // Note that we do *not* mark the sync connection as
904
- // lost yet: we only do this if a keepalive poke
905
- // fails, since long lived HTTP connections will
906
- // go away sometimes and we shouldn't treat this as
907
- // erroneous. We set the state to 'reconnecting'
908
- // instead, so that clients can observe this state
909
- // if they wish.
910
- var keepAlivePromise = _this8.startKeepAlives();
911
- _this8.currentSyncRequest = undefined;
912
- // Transition from RECONNECTING to ERROR after a given number of failed syncs
913
- _this8.updateSyncState(_this8.failedSyncCount >= FAILED_SYNC_ERROR_THRESHOLD ? SyncState.Error : SyncState.Reconnecting, {
914
- error: err
853
+ this.updateSyncState(SyncState.Stopped);
854
+ return true; // abort
855
+ }
856
+ this.syncOpts.logger.error("/sync error %s", err);
857
+ if (this.shouldAbortSync(err)) {
858
+ return true; // abort
859
+ }
860
+ this.failedSyncCount++;
861
+ this.syncOpts.logger.debug("Number of consecutive failed sync requests:", this.failedSyncCount);
862
+ this.syncOpts.logger.debug("Starting keep-alive");
863
+ // Note that we do *not* mark the sync connection as
864
+ // lost yet: we only do this if a keepalive poke
865
+ // fails, since long lived HTTP connections will
866
+ // go away sometimes and we shouldn't treat this as
867
+ // erroneous. We set the state to 'reconnecting'
868
+ // instead, so that clients can observe this state
869
+ // if they wish.
870
+ const keepAlivePromise = this.startKeepAlives();
871
+ this.currentSyncRequest = undefined;
872
+ // Transition from RECONNECTING to ERROR after a given number of failed syncs
873
+ this.updateSyncState(this.failedSyncCount >= FAILED_SYNC_ERROR_THRESHOLD ? SyncState.Error : SyncState.Reconnecting, {
874
+ error: err
875
+ });
876
+ const connDidFail = await keepAlivePromise;
877
+
878
+ // Only emit CATCHUP if we detected a connectivity error: if we didn't,
879
+ // it's quite likely the sync will fail again for the same reason and we
880
+ // want to stay in ERROR rather than keep flip-flopping between ERROR
881
+ // and CATCHUP.
882
+ if (connDidFail && this.getSyncState() === SyncState.Error) {
883
+ this.updateSyncState(SyncState.Catchup, {
884
+ catchingUp: true
915
885
  });
916
- var connDidFail = yield keepAlivePromise;
917
-
918
- // Only emit CATCHUP if we detected a connectivity error: if we didn't,
919
- // it's quite likely the sync will fail again for the same reason and we
920
- // want to stay in ERROR rather than keep flip-flopping between ERROR
921
- // and CATCHUP.
922
- if (connDidFail && _this8.getSyncState() === SyncState.Error) {
923
- _this8.updateSyncState(SyncState.Catchup, {
924
- catchingUp: true
925
- });
926
- }
927
- return false;
928
- })();
886
+ }
887
+ return false;
929
888
  }
930
889
 
931
890
  /**
@@ -935,491 +894,450 @@ export class SyncApi {
935
894
  * @param syncEventData - Object containing sync tokens associated with this sync
936
895
  * @param data - The response from /sync
937
896
  */
938
- processSyncResponse(syncEventData, data) {
939
- var _this9 = this;
940
- return _asyncToGenerator(function* () {
941
- var _data$presence, _data$account_data, _data$users, _this9$syncOpts$crypt, _data$device_unused_f;
942
- var client = _this9.client;
943
-
944
- // data looks like:
945
- // {
946
- // next_batch: $token,
947
- // presence: { events: [] },
948
- // account_data: { events: [] },
949
- // device_lists: { changed: ["@user:server", ... ]},
950
- // to_device: { events: [] },
951
- // device_one_time_keys_count: { signed_curve25519: 42 },
952
- // rooms: {
953
- // invite: {
954
- // $roomid: {
955
- // invite_state: { events: [] }
956
- // }
957
- // },
958
- // join: {
959
- // $roomid: {
960
- // state: { events: [] },
961
- // timeline: { events: [], prev_batch: $token, limited: true },
962
- // ephemeral: { events: [] },
963
- // summary: {
964
- // m.heroes: [ $user_id ],
965
- // m.joined_member_count: $count,
966
- // m.invited_member_count: $count
967
- // },
968
- // account_data: { events: [] },
969
- // unread_notifications: {
970
- // highlight_count: 0,
971
- // notification_count: 0,
972
- // }
973
- // "org.matrix.msc4222.state_after": { events: [] }, // only if "org.matrix.msc4222.use_state_after" is true
974
- // msc4354_sticky: { events: [] }, // only if "org.matrix.msc4354.sticky" is true
975
- // }
976
- // },
977
- // leave: {
978
- // $roomid: {
979
- // state: { events: [] },
980
- // timeline: { events: [], prev_batch: $token }
981
- // }
982
- // }
983
- // }
984
- // }
985
-
986
- // TODO-arch:
987
- // - Each event we pass through needs to be emitted via 'event', can we
988
- // do this in one place?
989
- // - The isBrandNewRoom boilerplate is boilerplatey.
897
+ async processSyncResponse(syncEventData, data) {
898
+ const client = this.client;
899
+
900
+ // data looks like:
901
+ // {
902
+ // next_batch: $token,
903
+ // presence: { events: [] },
904
+ // account_data: { events: [] },
905
+ // device_lists: { changed: ["@user:server", ... ]},
906
+ // to_device: { events: [] },
907
+ // device_one_time_keys_count: { signed_curve25519: 42 },
908
+ // rooms: {
909
+ // invite: {
910
+ // $roomid: {
911
+ // invite_state: { events: [] }
912
+ // }
913
+ // },
914
+ // join: {
915
+ // $roomid: {
916
+ // state: { events: [] },
917
+ // timeline: { events: [], prev_batch: $token, limited: true },
918
+ // ephemeral: { events: [] },
919
+ // summary: {
920
+ // m.heroes: [ $user_id ],
921
+ // m.joined_member_count: $count,
922
+ // m.invited_member_count: $count
923
+ // },
924
+ // account_data: { events: [] },
925
+ // unread_notifications: {
926
+ // highlight_count: 0,
927
+ // notification_count: 0,
928
+ // }
929
+ // "org.matrix.msc4222.state_after": { events: [] }, // only if "org.matrix.msc4222.use_state_after" is true
930
+ // msc4354_sticky: { events: [] }, // only if "org.matrix.msc4354.sticky" is true
931
+ // }
932
+ // },
933
+ // leave: {
934
+ // $roomid: {
935
+ // state: { events: [] },
936
+ // timeline: { events: [], prev_batch: $token }
937
+ // }
938
+ // }
939
+ // }
940
+ // }
941
+
942
+ // TODO-arch:
943
+ // - Each event we pass through needs to be emitted via 'event', can we
944
+ // do this in one place?
945
+ // - The isBrandNewRoom boilerplate is boilerplatey.
946
+
947
+ // handle presence events (User objects)
948
+ if (Array.isArray(data.presence?.events)) {
949
+ data.presence.events.filter(noUnsafeEventProps).map(client.getEventMapper()).forEach(function (presenceEvent) {
950
+ let user = client.store.getUser(presenceEvent.getSender());
951
+ if (user) {
952
+ user.setPresenceEvent(presenceEvent);
953
+ } else {
954
+ user = User.createUser(presenceEvent.getSender(), client);
955
+ user.setPresenceEvent(presenceEvent);
956
+ client.store.storeUser(user);
957
+ }
958
+ client.emit(ClientEvent.Event, presenceEvent);
959
+ });
960
+ }
990
961
 
991
- // handle presence events (User objects)
992
- if (Array.isArray((_data$presence = data.presence) === null || _data$presence === void 0 ? void 0 : _data$presence.events)) {
993
- data.presence.events.filter(noUnsafeEventProps).map(client.getEventMapper()).forEach(function (presenceEvent) {
994
- var user = client.store.getUser(presenceEvent.getSender());
995
- if (user) {
996
- user.setPresenceEvent(presenceEvent);
997
- } else {
998
- user = User.createUser(presenceEvent.getSender(), client);
999
- user.setPresenceEvent(presenceEvent);
1000
- client.store.storeUser(user);
1001
- }
1002
- client.emit(ClientEvent.Event, presenceEvent);
1003
- });
1004
- }
962
+ // handle non-room account_data
963
+ if (Array.isArray(data.account_data?.events)) {
964
+ const events = data.account_data.events.filter(noUnsafeEventProps).map(client.getEventMapper());
965
+ const prevEventsMap = events.reduce((m, c) => {
966
+ m[c.getType()] = client.store.getAccountData(c.getType());
967
+ return m;
968
+ }, {});
969
+ client.store.storeAccountDataEvents(events);
970
+ events.forEach(function (accountDataEvent) {
971
+ // Honour push rules that come down the sync stream but also
972
+ // honour push rules that were previously cached. Base rules
973
+ // will be updated when we receive push rules via getPushRules
974
+ // (see sync) before syncing over the network.
975
+ if (accountDataEvent.getType() === EventType.PushRules) {
976
+ const rules = accountDataEvent.getContent();
977
+ client.setPushRules(rules);
978
+ }
979
+ const prevEvent = prevEventsMap[accountDataEvent.getType()];
980
+ client.emit(ClientEvent.AccountData, accountDataEvent, prevEvent);
981
+ return accountDataEvent;
982
+ });
983
+ }
1005
984
 
1006
- // handle non-room account_data
1007
- if (Array.isArray((_data$account_data = data.account_data) === null || _data$account_data === void 0 ? void 0 : _data$account_data.events)) {
1008
- var events = data.account_data.events.filter(noUnsafeEventProps).map(client.getEventMapper());
1009
- var prevEventsMap = events.reduce((m, c) => {
1010
- m[c.getType()] = client.store.getAccountData(c.getType());
1011
- return m;
1012
- }, {});
1013
- client.store.storeAccountDataEvents(events);
1014
- events.forEach(function (accountDataEvent) {
1015
- // Honour push rules that come down the sync stream but also
1016
- // honour push rules that were previously cached. Base rules
1017
- // will be updated when we receive push rules via getPushRules
1018
- // (see sync) before syncing over the network.
1019
- if (accountDataEvent.getType() === EventType.PushRules) {
1020
- var rules = accountDataEvent.getContent();
1021
- client.setPushRules(rules);
1022
- }
1023
- var prevEvent = prevEventsMap[accountDataEvent.getType()];
1024
- client.emit(ClientEvent.AccountData, accountDataEvent, prevEvent);
1025
- return accountDataEvent;
1026
- });
985
+ // handle user profile updates (MSC4429)
986
+ const userUpdate = data["users"] ?? data["org.matrix.msc4429.users"];
987
+ if (typeof userUpdate === "object" && userUpdate !== null) {
988
+ const usersToRemove = [];
989
+ const profilesToAmend = new Map();
990
+ for (const [userId, userData] of Object.entries(userUpdate)) {
991
+ logger.info(`Storing user profile ${userId}`, userData);
992
+ if (userData.profile_updates) {
993
+ const existingProfile = await client.store.getUserProfile(userId);
994
+ profilesToAmend.set(userId, _objectSpread(_objectSpread({}, existingProfile), userData.profile_updates));
995
+ } else if (userData.profile_updates === null) {
996
+ usersToRemove.push(userId);
997
+ }
998
+ }
999
+ if (usersToRemove.length) {
1000
+ await client.store.removeUserProfiles(usersToRemove);
1001
+ }
1002
+ if (profilesToAmend.size) {
1003
+ await client.store.storeUserProfiles(profilesToAmend);
1027
1004
  }
1028
1005
 
1029
- // handle user profile updates (MSC4429)
1030
- var userUpdate = (_data$users = data["users"]) !== null && _data$users !== void 0 ? _data$users : data["org.matrix.msc4429.users"];
1031
- if (typeof userUpdate === "object" && userUpdate !== null) {
1032
- var usersToRemove = [];
1033
- var profilesToAmend = new Map();
1034
- for (var _ref0 of Object.entries(userUpdate)) {
1035
- var _ref9 = _slicedToArray(_ref0, 2);
1036
- var userId = _ref9[0];
1037
- var userData = _ref9[1];
1038
- logger.info("Storing user profile ".concat(userId), userData);
1039
- if (userData.profile_updates) {
1040
- var existingProfile = yield client.store.getUserProfile(userId);
1041
- profilesToAmend.set(userId, _objectSpread(_objectSpread({}, existingProfile), userData.profile_updates));
1042
- } else if (userData.profile_updates === null) {
1043
- usersToRemove.push(userId);
1044
- }
1045
- }
1046
- if (usersToRemove.length) {
1047
- yield client.store.removeUserProfiles(usersToRemove);
1048
- }
1049
- if (profilesToAmend.size) {
1050
- yield client.store.storeUserProfiles(profilesToAmend);
1051
- }
1006
+ // emit after we've update the store so that clients can get the updated profile if they want to
1007
+ for (const [userId, userData] of Object.entries(userUpdate)) {
1008
+ client.emit(ClientEvent.UserProfileUpdate, userId, userData.profile_updates ?? null);
1009
+ }
1010
+ }
1052
1011
 
1053
- // emit after we've update the store so that clients can get the updated profile if they want to
1054
- for (var _ref11 of Object.entries(userUpdate)) {
1055
- var _userData$profile_upd;
1056
- var _ref10 = _slicedToArray(_ref11, 2);
1057
- var _userId = _ref10[0];
1058
- var _userData = _ref10[1];
1059
- client.emit(ClientEvent.UserProfileUpdate, _userId, (_userData$profile_upd = _userData.profile_updates) !== null && _userData$profile_upd !== void 0 ? _userData$profile_upd : null);
1060
- }
1012
+ // handle to-device events
1013
+ if (data.to_device && Array.isArray(data.to_device.events) && data.to_device.events.length > 0) {
1014
+ const toDeviceMessages = data.to_device.events.filter(noUnsafeEventProps);
1015
+ let receivedToDeviceMessages;
1016
+ if (this.syncOpts.cryptoCallbacks) {
1017
+ receivedToDeviceMessages = await this.syncOpts.cryptoCallbacks.preprocessToDeviceMessages(toDeviceMessages);
1018
+ } else {
1019
+ // Crypto is not enabled, so we just return the events.
1020
+ receivedToDeviceMessages = toDeviceMessages.map(rawEvent => ({
1021
+ message: rawEvent,
1022
+ encryptionInfo: null
1023
+ }));
1061
1024
  }
1025
+ processToDeviceMessages(receivedToDeviceMessages, client);
1026
+ } else {
1027
+ // no more to-device events: we can stop polling with a short timeout.
1028
+ this.catchingUp = false;
1029
+ }
1062
1030
 
1063
- // handle to-device events
1064
- if (data.to_device && Array.isArray(data.to_device.events) && data.to_device.events.length > 0) {
1065
- var toDeviceMessages = data.to_device.events.filter(noUnsafeEventProps);
1066
- var receivedToDeviceMessages;
1067
- if (_this9.syncOpts.cryptoCallbacks) {
1068
- receivedToDeviceMessages = yield _this9.syncOpts.cryptoCallbacks.preprocessToDeviceMessages(toDeviceMessages);
1069
- } else {
1070
- receivedToDeviceMessages = toDeviceMessages.map(rawEvent => (
1071
- // Crypto is not enabled, so we just return the events.
1072
- {
1073
- message: rawEvent,
1074
- encryptionInfo: null
1075
- }));
1076
- }
1077
- processToDeviceMessages(receivedToDeviceMessages, client);
1031
+ // the returned json structure is a bit crap, so make it into a
1032
+ // nicer form (array) after applying sanity to make sure we don't fail
1033
+ // on missing keys (on the off chance)
1034
+ let inviteRooms = [];
1035
+ let joinRooms = [];
1036
+ let leaveRooms = [];
1037
+ let knockRooms = [];
1038
+ if (data.rooms) {
1039
+ if (data.rooms.invite) {
1040
+ inviteRooms = this.mapSyncResponseToRoomArray(data.rooms.invite);
1041
+ }
1042
+ if (data.rooms.join) {
1043
+ joinRooms = this.mapSyncResponseToRoomArray(data.rooms.join);
1044
+ }
1045
+ if (data.rooms.leave) {
1046
+ leaveRooms = this.mapSyncResponseToRoomArray(data.rooms.leave);
1047
+ }
1048
+ if (data.rooms.knock) {
1049
+ knockRooms = this.mapSyncResponseToRoomArray(data.rooms.knock);
1050
+ }
1051
+ }
1052
+ this.notifEvents = [];
1053
+
1054
+ // Handle invites
1055
+ await Promise.all(inviteRooms.map(async inviteObj => {
1056
+ const room = inviteObj.room;
1057
+ const stateEvents = this.mapSyncEventsFormat(inviteObj.invite_state, room);
1058
+ await this.injectRoomEvents(room, stateEvents, undefined);
1059
+ if (inviteObj.isBrandNewRoom) {
1060
+ room.recalculate();
1061
+ client.store.storeRoom(room);
1062
+ client.emit(ClientEvent.Room, room);
1078
1063
  } else {
1079
- // no more to-device events: we can stop polling with a short timeout.
1080
- _this9.catchingUp = false;
1064
+ // Update room state for invite->reject->invite cycles
1065
+ room.recalculate();
1081
1066
  }
1067
+ stateEvents.forEach(function (e) {
1068
+ client.emit(ClientEvent.Event, e);
1069
+ });
1070
+ }));
1082
1071
 
1083
- // the returned json structure is a bit crap, so make it into a
1084
- // nicer form (array) after applying sanity to make sure we don't fail
1085
- // on missing keys (on the off chance)
1086
- var inviteRooms = [];
1087
- var joinRooms = [];
1088
- var leaveRooms = [];
1089
- var knockRooms = [];
1090
- if (data.rooms) {
1091
- if (data.rooms.invite) {
1092
- inviteRooms = _this9.mapSyncResponseToRoomArray(data.rooms.invite);
1093
- }
1094
- if (data.rooms.join) {
1095
- joinRooms = _this9.mapSyncResponseToRoomArray(data.rooms.join);
1072
+ // Handle joins
1073
+ await Promise.all(joinRooms.map(async joinObj => {
1074
+ const room = joinObj.room;
1075
+ const stateEvents = this.mapSyncEventsFormat(joinObj.state, room);
1076
+ const stateAfterEvents = this.mapSyncEventsFormat(joinObj["org.matrix.msc4222.state_after"], room);
1077
+ // Prevent events from being decrypted ahead of time
1078
+ // this helps large account to speed up faster
1079
+ // room::decryptCriticalEvent is in charge of decrypting all the events
1080
+ // required for a client to function properly
1081
+ const timelineEvents = this.mapSyncEventsFormat(joinObj.timeline, room, false);
1082
+ const ephemeralEvents = this.mapSyncEventsFormat(joinObj.ephemeral);
1083
+ const accountDataEvents = this.mapSyncEventsFormat(joinObj.account_data);
1084
+ const stickyEvents = this.mapSyncEventsFormat(joinObj.msc4354_sticky);
1085
+
1086
+ // If state_after is present, this is the events that form the state at the end of the timeline block and
1087
+ // regular timeline events do *not* count towards state. If it's not present, then the state is formed by
1088
+ // the state events plus the timeline events. Note mapSyncEventsFormat returns an empty array if the field
1089
+ // is absent so we explicitly check the field on the original object.
1090
+ const eventsFormingFinalState = joinObj["org.matrix.msc4222.state_after"] ? stateAfterEvents : stateEvents.concat(timelineEvents);
1091
+ const encrypted = this.isRoomEncrypted(room, eventsFormingFinalState);
1092
+ // We store the server-provided value first so it's correct when any of the events fire.
1093
+ if (joinObj.unread_notifications) {
1094
+ /**
1095
+ * We track unread notifications ourselves in encrypted rooms, so don't
1096
+ * bother setting it here. We trust our calculations better than the
1097
+ * server's for this case, and therefore will assume that our non-zero
1098
+ * count is accurate.
1099
+ * XXX: this is known faulty as the push rule for `.m.room.encrypted` may be disabled so server
1100
+ * may issue notification counts of 0 which we wrongly trust.
1101
+ * https://github.com/matrix-org/matrix-spec-proposals/pull/2654 would fix this
1102
+ *
1103
+ * @see import("./client").fixNotificationCountOnDecryption
1104
+ */
1105
+ if (!encrypted || joinObj.unread_notifications.notification_count === 0) {
1106
+ // In an encrypted room, if the room has notifications enabled then it's typical for
1107
+ // the server to flag all new messages as notifying. However, some push rules calculate
1108
+ // events as ignored based on their event contents (e.g. ignoring msgtype=m.notice messages)
1109
+ // so we want to calculate this figure on the client in all cases.
1110
+ room.setUnreadNotificationCount(NotificationCountType.Total, joinObj.unread_notifications.notification_count ?? 0);
1096
1111
  }
1097
- if (data.rooms.leave) {
1098
- leaveRooms = _this9.mapSyncResponseToRoomArray(data.rooms.leave);
1099
- }
1100
- if (data.rooms.knock) {
1101
- knockRooms = _this9.mapSyncResponseToRoomArray(data.rooms.knock);
1112
+ if (!encrypted || room.getUnreadNotificationCount(NotificationCountType.Highlight) <= 0) {
1113
+ // If the locally stored highlight count is zero, use the server provided value.
1114
+ room.setUnreadNotificationCount(NotificationCountType.Highlight, joinObj.unread_notifications.highlight_count ?? 0);
1102
1115
  }
1103
1116
  }
1104
- _this9.notifEvents = [];
1105
-
1106
- // Handle invites
1107
- yield Promise.all(inviteRooms.map(/*#__PURE__*/function () {
1108
- var _ref12 = _asyncToGenerator(function* (inviteObj) {
1109
- var room = inviteObj.room;
1110
- var stateEvents = _this9.mapSyncEventsFormat(inviteObj.invite_state, room);
1111
- yield _this9.injectRoomEvents(room, stateEvents, undefined);
1112
- if (inviteObj.isBrandNewRoom) {
1113
- room.recalculate();
1114
- client.store.storeRoom(room);
1115
- client.emit(ClientEvent.Room, room);
1116
- } else {
1117
- // Update room state for invite->reject->invite cycles
1118
- room.recalculate();
1119
- }
1120
- stateEvents.forEach(function (e) {
1121
- client.emit(ClientEvent.Event, e);
1122
- });
1123
- });
1124
- return function (_x3) {
1125
- return _ref12.apply(this, arguments);
1126
- };
1127
- }()));
1128
-
1129
- // Handle joins
1130
- yield Promise.all(joinRooms.map(/*#__PURE__*/function () {
1131
- var _ref13 = _asyncToGenerator(function* (joinObj) {
1132
- var _joinObj$UNREAD_THREA;
1133
- var room = joinObj.room;
1134
- var stateEvents = _this9.mapSyncEventsFormat(joinObj.state, room);
1135
- var stateAfterEvents = _this9.mapSyncEventsFormat(joinObj["org.matrix.msc4222.state_after"], room);
1136
- // Prevent events from being decrypted ahead of time
1137
- // this helps large account to speed up faster
1138
- // room::decryptCriticalEvent is in charge of decrypting all the events
1139
- // required for a client to function properly
1140
- var timelineEvents = _this9.mapSyncEventsFormat(joinObj.timeline, room, false);
1141
- var ephemeralEvents = _this9.mapSyncEventsFormat(joinObj.ephemeral);
1142
- var accountDataEvents = _this9.mapSyncEventsFormat(joinObj.account_data);
1143
- var stickyEvents = _this9.mapSyncEventsFormat(joinObj.msc4354_sticky);
1144
-
1145
- // If state_after is present, this is the events that form the state at the end of the timeline block and
1146
- // regular timeline events do *not* count towards state. If it's not present, then the state is formed by
1147
- // the state events plus the timeline events. Note mapSyncEventsFormat returns an empty array if the field
1148
- // is absent so we explicitly check the field on the original object.
1149
- var eventsFormingFinalState = joinObj["org.matrix.msc4222.state_after"] ? stateAfterEvents : stateEvents.concat(timelineEvents);
1150
- var encrypted = _this9.isRoomEncrypted(room, eventsFormingFinalState);
1151
- // We store the server-provided value first so it's correct when any of the events fire.
1152
- if (joinObj.unread_notifications) {
1153
- /**
1154
- * We track unread notifications ourselves in encrypted rooms, so don't
1155
- * bother setting it here. We trust our calculations better than the
1156
- * server's for this case, and therefore will assume that our non-zero
1157
- * count is accurate.
1158
- * XXX: this is known faulty as the push rule for `.m.room.encrypted` may be disabled so server
1159
- * may issue notification counts of 0 which we wrongly trust.
1160
- * https://github.com/matrix-org/matrix-spec-proposals/pull/2654 would fix this
1161
- *
1162
- * @see import("./client").fixNotificationCountOnDecryption
1163
- */
1164
- if (!encrypted || joinObj.unread_notifications.notification_count === 0) {
1165
- var _joinObj$unread_notif;
1166
- // In an encrypted room, if the room has notifications enabled then it's typical for
1167
- // the server to flag all new messages as notifying. However, some push rules calculate
1168
- // events as ignored based on their event contents (e.g. ignoring msgtype=m.notice messages)
1169
- // so we want to calculate this figure on the client in all cases.
1170
- room.setUnreadNotificationCount(NotificationCountType.Total, (_joinObj$unread_notif = joinObj.unread_notifications.notification_count) !== null && _joinObj$unread_notif !== void 0 ? _joinObj$unread_notif : 0);
1171
- }
1172
- if (!encrypted || room.getUnreadNotificationCount(NotificationCountType.Highlight) <= 0) {
1173
- var _joinObj$unread_notif2;
1174
- // If the locally stored highlight count is zero, use the server provided value.
1175
- room.setUnreadNotificationCount(NotificationCountType.Highlight, (_joinObj$unread_notif2 = joinObj.unread_notifications.highlight_count) !== null && _joinObj$unread_notif2 !== void 0 ? _joinObj$unread_notif2 : 0);
1176
- }
1177
- }
1178
- var unreadThreadNotifications = (_joinObj$UNREAD_THREA = joinObj[UNREAD_THREAD_NOTIFICATIONS.name]) !== null && _joinObj$UNREAD_THREA !== void 0 ? _joinObj$UNREAD_THREA : joinObj[UNREAD_THREAD_NOTIFICATIONS.altName];
1179
- if (unreadThreadNotifications) {
1180
- // This mirrors the logic above for rooms: take the *total* notification count from
1181
- // the server for unencrypted rooms or is it's zero. Any threads not present in this
1182
- // object implicitly have zero notifications, so start by clearing the total counts
1183
- // for all such threads.
1184
- room.resetThreadUnreadNotificationCountFromSync(Object.keys(unreadThreadNotifications));
1185
- for (var _ref16 of Object.entries(unreadThreadNotifications)) {
1186
- var _ref15 = _slicedToArray(_ref16, 2);
1187
- var threadId = _ref15[0];
1188
- var unreadNotification = _ref15[1];
1189
- if (!encrypted || unreadNotification.notification_count === 0) {
1190
- var _unreadNotification$n;
1191
- room.setThreadUnreadNotificationCount(threadId, NotificationCountType.Total, (_unreadNotification$n = unreadNotification.notification_count) !== null && _unreadNotification$n !== void 0 ? _unreadNotification$n : 0);
1192
- }
1193
- var hasNoNotifications = room.getThreadUnreadNotificationCount(threadId, NotificationCountType.Highlight) <= 0;
1194
- if (!encrypted || encrypted && hasNoNotifications) {
1195
- var _unreadNotification$h;
1196
- room.setThreadUnreadNotificationCount(threadId, NotificationCountType.Highlight, (_unreadNotification$h = unreadNotification.highlight_count) !== null && _unreadNotification$h !== void 0 ? _unreadNotification$h : 0);
1197
- }
1198
- }
1199
- } else {
1200
- room.resetThreadUnreadNotificationCountFromSync();
1117
+ const unreadThreadNotifications = joinObj[UNREAD_THREAD_NOTIFICATIONS.name] ?? joinObj[UNREAD_THREAD_NOTIFICATIONS.altName];
1118
+ if (unreadThreadNotifications) {
1119
+ // This mirrors the logic above for rooms: take the *total* notification count from
1120
+ // the server for unencrypted rooms or is it's zero. Any threads not present in this
1121
+ // object implicitly have zero notifications, so start by clearing the total counts
1122
+ // for all such threads.
1123
+ room.resetThreadUnreadNotificationCountFromSync(Object.keys(unreadThreadNotifications));
1124
+ for (const [threadId, unreadNotification] of Object.entries(unreadThreadNotifications)) {
1125
+ if (!encrypted || unreadNotification.notification_count === 0) {
1126
+ room.setThreadUnreadNotificationCount(threadId, NotificationCountType.Total, unreadNotification.notification_count ?? 0);
1201
1127
  }
1202
- joinObj.timeline = joinObj.timeline || {};
1203
- if (joinObj.isBrandNewRoom) {
1204
- // set the back-pagination token. Do this *before* adding any
1205
- // events so that clients can start back-paginating.
1206
- if (joinObj.timeline.prev_batch !== null) {
1207
- room.getLiveTimeline().setPaginationToken(joinObj.timeline.prev_batch, EventTimeline.BACKWARDS);
1208
- }
1209
- } else if (joinObj.timeline.limited) {
1210
- var limited = true;
1211
-
1212
- // we've got a limited sync, so we *probably* have a gap in the
1213
- // timeline, so should reset. But we might have been peeking or
1214
- // paginating and already have some of the events, in which
1215
- // case we just want to append any subsequent events to the end
1216
- // of the existing timeline.
1217
- //
1218
- // This is particularly important in the case that we already have
1219
- // *all* of the events in the timeline - in that case, if we reset
1220
- // the timeline, we'll end up with an entirely empty timeline,
1221
- // which we'll try to paginate but not get any new events (which
1222
- // will stop us linking the empty timeline into the chain).
1223
- //
1224
- for (var i = timelineEvents.length - 1; i >= 0; i--) {
1225
- var eventId = timelineEvents[i].getId();
1226
- if (room.getTimelineForEvent(eventId)) {
1227
- _this9.syncOpts.logger.debug("Already have event ".concat(eventId, " in limited sync - not resetting"));
1228
- limited = false;
1229
-
1230
- // we might still be missing some of the events before i;
1231
- // we don't want to be adding them to the end of the
1232
- // timeline because that would put them out of order.
1233
- timelineEvents.splice(0, i);
1234
-
1235
- // XXX: there's a problem here if the skipped part of the
1236
- // timeline modifies the state set in stateEvents, because
1237
- // we'll end up using the state from stateEvents rather
1238
- // than the later state from timelineEvents. We probably
1239
- // need to wind stateEvents forward over the events we're
1240
- // skipping.
1241
-
1242
- break;
1243
- }
1244
- }
1245
- if (limited) {
1246
- var _syncEventData$oldSyn;
1247
- room.resetLiveTimeline(joinObj.timeline.prev_batch, _this9.syncOpts.canResetEntireTimeline(room.roomId) ? null : (_syncEventData$oldSyn = syncEventData.oldSyncToken) !== null && _syncEventData$oldSyn !== void 0 ? _syncEventData$oldSyn : null);
1248
-
1249
- // We have to assume any gap in any timeline is
1250
- // reason to stop incrementally tracking notifications and
1251
- // reset the timeline.
1252
- client.resetNotifTimelineSet();
1253
- }
1128
+ const hasNoNotifications = room.getThreadUnreadNotificationCount(threadId, NotificationCountType.Highlight) <= 0;
1129
+ if (!encrypted || encrypted && hasNoNotifications) {
1130
+ room.setThreadUnreadNotificationCount(threadId, NotificationCountType.Highlight, unreadNotification.highlight_count ?? 0);
1254
1131
  }
1255
-
1256
- // process any crypto events *before* emitting the RoomStateEvent events. This
1257
- // avoids a race condition if the application tries to send a message after the
1258
- // state event is processed, but before crypto is enabled, which then causes the
1259
- // crypto layer to complain.
1260
-
1261
- if (_this9.syncOpts.cryptoCallbacks) {
1262
- for (var e of eventsFormingFinalState) {
1263
- if (e.isState() && e.getType() === EventType.RoomEncryption && e.getStateKey() === "") {
1264
- yield _this9.syncOpts.cryptoCallbacks.onCryptoEvent(room, e);
1265
- }
1266
- }
1132
+ }
1133
+ } else {
1134
+ room.resetThreadUnreadNotificationCountFromSync();
1135
+ }
1136
+ joinObj.timeline = joinObj.timeline || {};
1137
+ if (joinObj.isBrandNewRoom) {
1138
+ // set the back-pagination token. Do this *before* adding any
1139
+ // events so that clients can start back-paginating.
1140
+ if (joinObj.timeline.prev_batch !== null) {
1141
+ room.getLiveTimeline().setPaginationToken(joinObj.timeline.prev_batch, EventTimeline.BACKWARDS);
1142
+ }
1143
+ } else if (joinObj.timeline.limited) {
1144
+ let limited = true;
1145
+
1146
+ // we've got a limited sync, so we *probably* have a gap in the
1147
+ // timeline, so should reset. But we might have been peeking or
1148
+ // paginating and already have some of the events, in which
1149
+ // case we just want to append any subsequent events to the end
1150
+ // of the existing timeline.
1151
+ //
1152
+ // This is particularly important in the case that we already have
1153
+ // *all* of the events in the timeline - in that case, if we reset
1154
+ // the timeline, we'll end up with an entirely empty timeline,
1155
+ // which we'll try to paginate but not get any new events (which
1156
+ // will stop us linking the empty timeline into the chain).
1157
+ //
1158
+ for (let i = timelineEvents.length - 1; i >= 0; i--) {
1159
+ const eventId = timelineEvents[i].getId();
1160
+ if (room.getTimelineForEvent(eventId)) {
1161
+ this.syncOpts.logger.debug(`Already have event ${eventId} in limited sync - not resetting`);
1162
+ limited = false;
1163
+
1164
+ // we might still be missing some of the events before i;
1165
+ // we don't want to be adding them to the end of the
1166
+ // timeline because that would put them out of order.
1167
+ timelineEvents.splice(0, i);
1168
+
1169
+ // XXX: there's a problem here if the skipped part of the
1170
+ // timeline modifies the state set in stateEvents, because
1171
+ // we'll end up using the state from stateEvents rather
1172
+ // than the later state from timelineEvents. We probably
1173
+ // need to wind stateEvents forward over the events we're
1174
+ // skipping.
1175
+
1176
+ break;
1267
1177
  }
1178
+ }
1179
+ if (limited) {
1180
+ room.resetLiveTimeline(joinObj.timeline.prev_batch, this.syncOpts.canResetEntireTimeline(room.roomId) ? null : syncEventData.oldSyncToken ?? null);
1268
1181
 
1269
- // Proactively decrypt state events: normally we decrypt on demand, but for state
1270
- // events we need them immediately, so we handle them here. Specifically, consumers
1271
- // (e.g. Element Web) expect state events to be unencrypted upon receipt.
1272
- for (var ev of timelineEvents.filter(ev => ev.isState())) {
1273
- yield _this9.client.decryptEventIfNeeded(ev);
1274
- }
1275
- try {
1276
- if ("org.matrix.msc4222.state_after" in joinObj) {
1277
- yield _this9.injectRoomEvents(room, undefined, stateAfterEvents, timelineEvents, syncEventData.fromCache);
1278
- } else {
1279
- yield _this9.injectRoomEvents(room, stateEvents, undefined, timelineEvents, syncEventData.fromCache);
1280
- }
1281
- } catch (e) {
1282
- _this9.syncOpts.logger.error("Failed to process events on room ".concat(room.roomId, ":"), e);
1283
- }
1182
+ // We have to assume any gap in any timeline is
1183
+ // reason to stop incrementally tracking notifications and
1184
+ // reset the timeline.
1185
+ client.resetNotifTimelineSet();
1186
+ }
1187
+ }
1284
1188
 
1285
- // set summary after processing events,
1286
- // because it will trigger a name calculation
1287
- // which needs the room state to be up to date
1288
- if (joinObj.summary) {
1289
- room.setSummary(joinObj.summary);
1290
- }
1189
+ // process any crypto events *before* emitting the RoomStateEvent events. This
1190
+ // avoids a race condition if the application tries to send a message after the
1191
+ // state event is processed, but before crypto is enabled, which then causes the
1192
+ // crypto layer to complain.
1291
1193
 
1292
- // we deliberately don't add ephemeral events to the timeline
1293
- room.addEphemeralEvents(ephemeralEvents);
1294
-
1295
- // we deliberately don't add accountData to the timeline
1296
- room.addAccountData(accountDataEvents);
1297
-
1298
- // Sticky events primarily come via the `timeline` field, with the
1299
- // sticky info field marking them as sticky.
1300
- // If the sync is "gappy" (meaning it is skipping events to catch up) then
1301
- // sticky events will instead come down the sticky section.
1302
- // This ensures we collect sticky events from both places.
1303
- var stickyEventsAndStickyEventsFromTheTimeline = stickyEvents.concat(timelineEvents.filter(e => e.unstableStickyInfo !== undefined));
1304
- // Note: We calculate sticky events before emitting `.Room` as it's nice to have
1305
- // sticky events calculated and ready to go.
1306
- room._unstable_addStickyEvents(stickyEventsAndStickyEventsFromTheTimeline);
1307
- room.recalculate();
1308
- if (joinObj.isBrandNewRoom) {
1309
- client.store.storeRoom(room);
1310
- client.emit(ClientEvent.Room, room);
1311
- }
1312
- _this9.processEventsForNotifs(room, timelineEvents);
1313
- var emitEvent = e => client.emit(ClientEvent.Event, e);
1314
- // this fires a couple of times for some events. (eg state events are in the timeline and the state)
1315
- // should this get a sync section as an additional event emission param (e, syncSection))?
1316
- stateEvents.forEach(emitEvent);
1317
- timelineEvents.forEach(emitEvent);
1318
- ephemeralEvents.forEach(emitEvent);
1319
- accountDataEvents.forEach(emitEvent);
1320
- stickyEvents.filter(stickyEvent =>
1321
- // This is highly unlikey, but in the case where a sticky event
1322
- // has appeared in the timeline AND the sticky section, we only
1323
- // want to emit the event once.
1324
- !timelineEvents.some(timelineEvent => timelineEvent.getId() === stickyEvent.getId())).forEach(emitEvent);
1325
- // Decrypt only the last message in all rooms to make sure we can generate a preview
1326
- // And decrypt all events after the recorded read receipt to ensure an accurate
1327
- // notification count
1328
- room.decryptCriticalEvents();
1329
- });
1330
- return function (_x4) {
1331
- return _ref13.apply(this, arguments);
1332
- };
1333
- }()));
1334
-
1335
- // Handle leaves (e.g. kicked rooms)
1336
- yield Promise.all(leaveRooms.map(/*#__PURE__*/function () {
1337
- var _ref17 = _asyncToGenerator(function* (leaveObj) {
1338
- var room = leaveObj.room;
1339
- var _yield$_this9$mapAndI = yield _this9.mapAndInjectRoomEvents(leaveObj),
1340
- timelineEvents = _yield$_this9$mapAndI.timelineEvents,
1341
- stateEvents = _yield$_this9$mapAndI.stateEvents,
1342
- stateAfterEvents = _yield$_this9$mapAndI.stateAfterEvents;
1343
- var accountDataEvents = _this9.mapSyncEventsFormat(leaveObj.account_data);
1344
- room.addAccountData(accountDataEvents);
1345
- room.recalculate();
1346
- if (leaveObj.isBrandNewRoom) {
1347
- client.store.storeRoom(room);
1348
- client.emit(ClientEvent.Room, room);
1194
+ if (this.syncOpts.cryptoCallbacks) {
1195
+ for (const e of eventsFormingFinalState) {
1196
+ if (e.isState() && e.getType() === EventType.RoomEncryption && e.getStateKey() === "") {
1197
+ await this.syncOpts.cryptoCallbacks.onCryptoEvent(room, e);
1349
1198
  }
1350
- _this9.processEventsForNotifs(room, timelineEvents);
1351
- stateEvents === null || stateEvents === void 0 || stateEvents.forEach(function (e) {
1352
- client.emit(ClientEvent.Event, e);
1353
- });
1354
- stateAfterEvents === null || stateAfterEvents === void 0 || stateAfterEvents.forEach(function (e) {
1355
- client.emit(ClientEvent.Event, e);
1356
- });
1357
- timelineEvents.forEach(function (e) {
1358
- client.emit(ClientEvent.Event, e);
1359
- });
1360
- accountDataEvents.forEach(function (e) {
1361
- client.emit(ClientEvent.Event, e);
1362
- });
1363
- });
1364
- return function (_x5) {
1365
- return _ref17.apply(this, arguments);
1366
- };
1367
- }()));
1368
-
1369
- // Handle knocks
1370
- yield Promise.all(knockRooms.map(/*#__PURE__*/function () {
1371
- var _ref18 = _asyncToGenerator(function* (knockObj) {
1372
- var room = knockObj.room;
1373
- var stateEvents = _this9.mapSyncEventsFormat(knockObj.knock_state, room);
1374
- yield _this9.injectRoomEvents(room, stateEvents, undefined);
1375
- if (knockObj.isBrandNewRoom) {
1376
- room.recalculate();
1377
- client.store.storeRoom(room);
1378
- client.emit(ClientEvent.Room, room);
1379
- } else {
1380
- // Update room state for knock->leave->knock cycles
1381
- room.recalculate();
1382
- }
1383
- stateEvents.forEach(function (e) {
1384
- client.emit(ClientEvent.Event, e);
1385
- });
1386
- });
1387
- return function (_x6) {
1388
- return _ref18.apply(this, arguments);
1389
- };
1390
- }()));
1391
-
1392
- // update the notification timeline, if appropriate.
1393
- // we only do this for live events, as otherwise we can't order them sanely
1394
- // in the timeline relative to ones paginated in by /notifications.
1395
- // XXX: we could fix this by making EventTimeline support chronological
1396
- // ordering... but it doesn't, right now.
1397
- if (syncEventData.oldSyncToken && _this9.notifEvents.length) {
1398
- _this9.notifEvents.sort(function (a, b) {
1399
- return a.getTs() - b.getTs();
1400
- });
1401
- _this9.notifEvents.forEach(function (event) {
1402
- var _client$getNotifTimel;
1403
- (_client$getNotifTimel = client.getNotifTimelineSet()) === null || _client$getNotifTimel === void 0 || _client$getNotifTimel.addLiveEvent(event, {
1404
- addToState: true
1405
- });
1406
- });
1199
+ }
1407
1200
  }
1408
1201
 
1409
- // Handle device list updates
1410
- if (data.device_lists) {
1411
- if (_this9.syncOpts.cryptoCallbacks) {
1412
- yield _this9.syncOpts.cryptoCallbacks.processDeviceLists(data.device_lists);
1202
+ // Proactively decrypt state events: normally we decrypt on demand, but for state
1203
+ // events we need them immediately, so we handle them here. Specifically, consumers
1204
+ // (e.g. Element Web) expect state events to be unencrypted upon receipt.
1205
+ for (const ev of timelineEvents.filter(ev => ev.isState())) {
1206
+ await this.client.decryptEventIfNeeded(ev);
1207
+ }
1208
+ try {
1209
+ if ("org.matrix.msc4222.state_after" in joinObj) {
1210
+ await this.injectRoomEvents(room, undefined, stateAfterEvents, timelineEvents, syncEventData.fromCache);
1413
1211
  } else {
1414
- // FIXME if we *don't* have a crypto module, we still need to
1415
- // invalidate the device lists. But that would require a
1416
- // substantial bit of rework :/.
1212
+ await this.injectRoomEvents(room, stateEvents, undefined, timelineEvents, syncEventData.fromCache);
1417
1213
  }
1214
+ } catch (e) {
1215
+ this.syncOpts.logger.error(`Failed to process events on room ${room.roomId}:`, e);
1216
+ }
1217
+
1218
+ // set summary after processing events,
1219
+ // because it will trigger a name calculation
1220
+ // which needs the room state to be up to date
1221
+ if (joinObj.summary) {
1222
+ room.setSummary(joinObj.summary);
1223
+ }
1224
+
1225
+ // we deliberately don't add ephemeral events to the timeline
1226
+ room.addEphemeralEvents(ephemeralEvents);
1227
+
1228
+ // we deliberately don't add accountData to the timeline
1229
+ room.addAccountData(accountDataEvents);
1230
+
1231
+ // Sticky events primarily come via the `timeline` field, with the
1232
+ // sticky info field marking them as sticky.
1233
+ // If the sync is "gappy" (meaning it is skipping events to catch up) then
1234
+ // sticky events will instead come down the sticky section.
1235
+ // This ensures we collect sticky events from both places.
1236
+ const stickyEventsAndStickyEventsFromTheTimeline = stickyEvents.concat(timelineEvents.filter(e => e.unstableStickyInfo !== undefined));
1237
+ // Note: We calculate sticky events before emitting `.Room` as it's nice to have
1238
+ // sticky events calculated and ready to go.
1239
+ room._unstable_addStickyEvents(stickyEventsAndStickyEventsFromTheTimeline);
1240
+ room.recalculate();
1241
+ if (joinObj.isBrandNewRoom) {
1242
+ client.store.storeRoom(room);
1243
+ client.emit(ClientEvent.Room, room);
1244
+ }
1245
+ this.processEventsForNotifs(room, timelineEvents);
1246
+ const emitEvent = e => client.emit(ClientEvent.Event, e);
1247
+ // this fires a couple of times for some events. (eg state events are in the timeline and the state)
1248
+ // should this get a sync section as an additional event emission param (e, syncSection))?
1249
+ stateEvents.forEach(emitEvent);
1250
+ timelineEvents.forEach(emitEvent);
1251
+ ephemeralEvents.forEach(emitEvent);
1252
+ accountDataEvents.forEach(emitEvent);
1253
+ stickyEvents.filter(stickyEvent =>
1254
+ // This is highly unlikey, but in the case where a sticky event
1255
+ // has appeared in the timeline AND the sticky section, we only
1256
+ // want to emit the event once.
1257
+ !timelineEvents.some(timelineEvent => timelineEvent.getId() === stickyEvent.getId())).forEach(emitEvent);
1258
+ // Decrypt only the last message in all rooms to make sure we can generate a preview
1259
+ // And decrypt all events after the recorded read receipt to ensure an accurate
1260
+ // notification count
1261
+ room.decryptCriticalEvents();
1262
+ }));
1263
+
1264
+ // Handle leaves (e.g. kicked rooms)
1265
+ await Promise.all(leaveRooms.map(async leaveObj => {
1266
+ const room = leaveObj.room;
1267
+ const {
1268
+ timelineEvents,
1269
+ stateEvents,
1270
+ stateAfterEvents
1271
+ } = await this.mapAndInjectRoomEvents(leaveObj);
1272
+ const accountDataEvents = this.mapSyncEventsFormat(leaveObj.account_data);
1273
+ room.addAccountData(accountDataEvents);
1274
+ room.recalculate();
1275
+ if (leaveObj.isBrandNewRoom) {
1276
+ client.store.storeRoom(room);
1277
+ client.emit(ClientEvent.Room, room);
1278
+ }
1279
+ this.processEventsForNotifs(room, timelineEvents);
1280
+ stateEvents?.forEach(function (e) {
1281
+ client.emit(ClientEvent.Event, e);
1282
+ });
1283
+ stateAfterEvents?.forEach(function (e) {
1284
+ client.emit(ClientEvent.Event, e);
1285
+ });
1286
+ timelineEvents.forEach(function (e) {
1287
+ client.emit(ClientEvent.Event, e);
1288
+ });
1289
+ accountDataEvents.forEach(function (e) {
1290
+ client.emit(ClientEvent.Event, e);
1291
+ });
1292
+ }));
1293
+
1294
+ // Handle knocks
1295
+ await Promise.all(knockRooms.map(async knockObj => {
1296
+ const room = knockObj.room;
1297
+ const stateEvents = this.mapSyncEventsFormat(knockObj.knock_state, room);
1298
+ await this.injectRoomEvents(room, stateEvents, undefined);
1299
+ if (knockObj.isBrandNewRoom) {
1300
+ room.recalculate();
1301
+ client.store.storeRoom(room);
1302
+ client.emit(ClientEvent.Room, room);
1303
+ } else {
1304
+ // Update room state for knock->leave->knock cycles
1305
+ room.recalculate();
1306
+ }
1307
+ stateEvents.forEach(function (e) {
1308
+ client.emit(ClientEvent.Event, e);
1309
+ });
1310
+ }));
1311
+
1312
+ // update the notification timeline, if appropriate.
1313
+ // we only do this for live events, as otherwise we can't order them sanely
1314
+ // in the timeline relative to ones paginated in by /notifications.
1315
+ // XXX: we could fix this by making EventTimeline support chronological
1316
+ // ordering... but it doesn't, right now.
1317
+ if (syncEventData.oldSyncToken && this.notifEvents.length) {
1318
+ this.notifEvents.sort(function (a, b) {
1319
+ return a.getTs() - b.getTs();
1320
+ });
1321
+ this.notifEvents.forEach(function (event) {
1322
+ client.getNotifTimelineSet()?.addLiveEvent(event, {
1323
+ addToState: true
1324
+ });
1325
+ });
1326
+ }
1327
+
1328
+ // Handle device list updates
1329
+ if (data.device_lists) {
1330
+ if (this.syncOpts.cryptoCallbacks) {
1331
+ await this.syncOpts.cryptoCallbacks.processDeviceLists(data.device_lists);
1332
+ } else {
1333
+ // FIXME if we *don't* have a crypto module, we still need to
1334
+ // invalidate the device lists. But that would require a
1335
+ // substantial bit of rework :/.
1418
1336
  }
1337
+ }
1419
1338
 
1420
- // Handle one_time_keys_count and unused fallback keys
1421
- yield (_this9$syncOpts$crypt = _this9.syncOpts.cryptoCallbacks) === null || _this9$syncOpts$crypt === void 0 ? void 0 : _this9$syncOpts$crypt.processKeyCounts(data.device_one_time_keys_count, (_data$device_unused_f = data.device_unused_fallback_key_types) !== null && _data$device_unused_f !== void 0 ? _data$device_unused_f : data["org.matrix.msc2732.device_unused_fallback_key_types"]);
1422
- })();
1339
+ // Handle one_time_keys_count and unused fallback keys
1340
+ await this.syncOpts.cryptoCallbacks?.processKeyCounts(data.device_one_time_keys_count, data.device_unused_fallback_key_types ?? data["org.matrix.msc2732.device_unused_fallback_key_types"]);
1423
1341
  }
1424
1342
 
1425
1343
  /**
@@ -1456,9 +1374,7 @@ export class SyncApi {
1456
1374
  *
1457
1375
  * @param connDidFail - True if a connectivity failure has been detected. Optional.
1458
1376
  */
1459
- pokeKeepAlive() {
1460
- var _this$abortController4;
1461
- var connDidFail = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
1377
+ pokeKeepAlive(connDidFail = false) {
1462
1378
  if (!this.running) {
1463
1379
  // we are in a keepAlive, retrying to connect, but the syncronization
1464
1380
  // was stopped, so we are stopping the retry.
@@ -1469,7 +1385,7 @@ export class SyncApi {
1469
1385
  }
1470
1386
  return;
1471
1387
  }
1472
- var success = () => {
1388
+ const success = () => {
1473
1389
  clearTimeout(this.keepAliveTimer);
1474
1390
  if (this.connectionReturnedResolvers) {
1475
1391
  this.connectionReturnedResolvers.resolve(connDidFail);
@@ -1483,7 +1399,7 @@ export class SyncApi {
1483
1399
  {
1484
1400
  prefix: "",
1485
1401
  localTimeoutMs: 15 * 1000,
1486
- abortSignal: (_this$abortController4 = this.abortController) === null || _this$abortController4 === void 0 ? void 0 : _this$abortController4.signal
1402
+ abortSignal: this.abortController?.signal
1487
1403
  }).then(() => {
1488
1404
  success();
1489
1405
  }, err => {
@@ -1513,10 +1429,10 @@ export class SyncApi {
1513
1429
  // Maps { roomid: {stuff}, roomid: {stuff} }
1514
1430
  // to
1515
1431
  // [{stuff+Room+isBrandNewRoom}, {stuff+Room+isBrandNewRoom}]
1516
- var client = this.client;
1432
+ const client = this.client;
1517
1433
  return Object.keys(obj).filter(k => !unsafeProp(k)).map(roomId => {
1518
- var room = client.store.getRoom(roomId);
1519
- var isBrandNewRoom = false;
1434
+ let room = client.store.getRoom(roomId);
1435
+ let isBrandNewRoom = false;
1520
1436
  if (!room) {
1521
1437
  room = this.createRoom(roomId);
1522
1438
  isBrandNewRoom = true;
@@ -1527,12 +1443,11 @@ export class SyncApi {
1527
1443
  });
1528
1444
  });
1529
1445
  }
1530
- mapSyncEventsFormat(obj, room) {
1531
- var decrypt = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
1446
+ mapSyncEventsFormat(obj, room, decrypt = true) {
1532
1447
  if (!obj || !Array.isArray(obj.events)) {
1533
1448
  return [];
1534
1449
  }
1535
- var mapper = this.client.getEventMapper({
1450
+ const mapper = this.client.getEventMapper({
1536
1451
  decrypt
1537
1452
  });
1538
1453
  return obj.events.filter(noUnsafeEventProps).map(function (e) {
@@ -1549,15 +1464,15 @@ export class SyncApi {
1549
1464
  if (!room || !this.opts.resolveInvitesToProfiles) {
1550
1465
  return;
1551
1466
  }
1552
- var client = this.client;
1467
+ const client = this.client;
1553
1468
  // For each invited room member we want to give them a displayname/avatar url
1554
1469
  // if they have one (the m.room.member invites don't contain this).
1555
1470
  room.getMembersWithMembership(KnownMembership.Invite).forEach(function (member) {
1556
1471
  if (member.requestedProfileInfo) return;
1557
1472
  member.requestedProfileInfo = true;
1558
1473
  // try to get a cached copy first.
1559
- var user = client.getUser(member.userId);
1560
- var promise;
1474
+ const user = client.getUser(member.userId);
1475
+ let promise;
1561
1476
  if (user) {
1562
1477
  promise = Promise.resolve({
1563
1478
  avatar_url: user.avatarUrl,
@@ -1570,8 +1485,8 @@ export class SyncApi {
1570
1485
  // slightly naughty by doctoring the invite event but this means all
1571
1486
  // the code paths remain the same between invite/join display name stuff
1572
1487
  // which is a worthy trade-off for some minor pollution.
1573
- var inviteEvent = member.events.member;
1574
- if ((inviteEvent === null || inviteEvent === void 0 ? void 0 : inviteEvent.getContent().membership) !== KnownMembership.Invite) {
1488
+ const inviteEvent = member.events.member;
1489
+ if (inviteEvent?.getContent().membership !== KnownMembership.Invite) {
1575
1490
  // between resolving and now they have since joined, so don't clobber
1576
1491
  return;
1577
1492
  }
@@ -1585,7 +1500,7 @@ export class SyncApi {
1585
1500
  });
1586
1501
  }
1587
1502
  findEncryptionEvent(events) {
1588
- return events === null || events === void 0 ? void 0 : events.find(e => e.getType() === EventType.RoomEncryption && e.getStateKey() === "");
1503
+ return events?.find(e => e.getType() === EventType.RoomEncryption && e.getStateKey() === "");
1589
1504
  }
1590
1505
 
1591
1506
  // When processing the sync response we cannot rely on Room.hasEncryptionStateEvent we actually
@@ -1593,23 +1508,20 @@ export class SyncApi {
1593
1508
  isRoomEncrypted(room, eventsFormingFinalState) {
1594
1509
  return room.hasEncryptionStateEvent() || !!this.findEncryptionEvent(eventsFormingFinalState);
1595
1510
  }
1596
- mapAndInjectRoomEvents(wrappedRoom) {
1597
- var _this0 = this;
1598
- return _asyncToGenerator(function* () {
1599
- var stateEvents = _this0.mapSyncEventsFormat(wrappedRoom.state, wrappedRoom.room);
1600
- var stateAfterEvents = _this0.mapSyncEventsFormat(wrappedRoom["org.matrix.msc4222.state_after"], wrappedRoom.room);
1601
- var timelineEvents = _this0.mapSyncEventsFormat(wrappedRoom.timeline, wrappedRoom.room);
1602
- if ("org.matrix.msc4222.state_after" in wrappedRoom) {
1603
- yield _this0.injectRoomEvents(wrappedRoom.room, undefined, stateAfterEvents, timelineEvents);
1604
- } else {
1605
- yield _this0.injectRoomEvents(wrappedRoom.room, stateEvents, undefined, timelineEvents);
1606
- }
1607
- return {
1608
- timelineEvents,
1609
- stateEvents,
1610
- stateAfterEvents
1611
- };
1612
- })();
1511
+ async mapAndInjectRoomEvents(wrappedRoom) {
1512
+ const stateEvents = this.mapSyncEventsFormat(wrappedRoom.state, wrappedRoom.room);
1513
+ const stateAfterEvents = this.mapSyncEventsFormat(wrappedRoom["org.matrix.msc4222.state_after"], wrappedRoom.room);
1514
+ const timelineEvents = this.mapSyncEventsFormat(wrappedRoom.timeline, wrappedRoom.room);
1515
+ if ("org.matrix.msc4222.state_after" in wrappedRoom) {
1516
+ await this.injectRoomEvents(wrappedRoom.room, undefined, stateAfterEvents, timelineEvents);
1517
+ } else {
1518
+ await this.injectRoomEvents(wrappedRoom.room, stateEvents, undefined, timelineEvents);
1519
+ }
1520
+ return {
1521
+ timelineEvents,
1522
+ stateEvents,
1523
+ stateAfterEvents
1524
+ };
1613
1525
  }
1614
1526
 
1615
1527
  /**
@@ -1628,76 +1540,71 @@ export class SyncApi {
1628
1540
  * are not added to the state.
1629
1541
  */
1630
1542
 
1631
- injectRoomEvents(room, stateEventList, stateAfterEventList, timelineEventList) {
1632
- var _arguments = arguments,
1633
- _this1 = this;
1634
- return _asyncToGenerator(function* () {
1635
- var fromCache = _arguments.length > 4 && _arguments[4] !== undefined ? _arguments[4] : false;
1636
- var eitherStateEventList = stateAfterEventList !== null && stateAfterEventList !== void 0 ? stateAfterEventList : stateEventList;
1637
-
1638
- // If there are no events in the timeline yet, initialise it with
1639
- // the given state events
1640
- var liveTimeline = room.getLiveTimeline();
1641
- var timelineWasEmpty = liveTimeline.getEvents().length == 0;
1642
- if (timelineWasEmpty) {
1643
- // Passing these events into initialiseState will freeze them, so we need
1644
- // to compute and cache the push actions for them now, otherwise sync dies
1645
- // with an attempt to assign to read only property.
1646
- // XXX: This is pretty horrible and is assuming all sorts of behaviour from
1647
- // these functions that it shouldn't be. We should probably either store the
1648
- // push actions cache elsewhere so we can freeze MatrixEvents, or otherwise
1649
- // find some solution where MatrixEvents are immutable but allow for a cache
1650
- // field.
1651
-
1652
- for (var ev of eitherStateEventList) {
1653
- _this1.client.getPushActionsForEvent(ev);
1654
- }
1655
- liveTimeline.initialiseState(eitherStateEventList, {
1656
- timelineWasEmpty
1657
- });
1658
- }
1659
- _this1.resolveInvites(room);
1660
-
1661
- // recalculate the room name at this point as adding events to the timeline
1662
- // may make notifications appear which should have the right name.
1663
- // XXX: This looks suspect: we'll end up recalculating the room once here
1664
- // and then again after adding events (processSyncResponse calls it after
1665
- // calling us) even if no state events were added. It also means that if
1666
- // one of the room events in timelineEventList is something that needs
1667
- // a recalculation (like m.room.name) we won't recalculate until we've
1668
- // finished adding all the events, which will cause the notification to have
1669
- // the old room name rather than the new one.
1670
- room.recalculate();
1543
+ async injectRoomEvents(room, stateEventList, stateAfterEventList, timelineEventList, fromCache = false) {
1544
+ const eitherStateEventList = stateAfterEventList ?? stateEventList;
1671
1545
 
1672
- // If the timeline wasn't empty, we process the state events here: they're
1673
- // defined as updates to the state before the start of the timeline, so this
1674
- // starts to roll the state forward.
1675
- // XXX: That's what we *should* do, but this can happen if we were previously
1676
- // peeking in a room, in which case we obviously do *not* want to add the
1677
- // state events here onto the end of the timeline. Historically, the js-sdk
1678
- // has just set these new state events on the old and new state. This seems
1679
- // very wrong because there could be events in the timeline that diverge the
1680
- // state, in which case this is going to leave things out of sync. However,
1681
- // for now I think it;s best to behave the same as the code has done previously.
1682
- if (!timelineWasEmpty) {
1683
- // XXX: As above, don't do this...
1684
- //room.addLiveEvents(stateEventList || []);
1685
- // Do this instead...
1686
- room.oldState.setStateEvents(eitherStateEventList);
1687
- room.currentState.setStateEvents(eitherStateEventList);
1546
+ // If there are no events in the timeline yet, initialise it with
1547
+ // the given state events
1548
+ const liveTimeline = room.getLiveTimeline();
1549
+ const timelineWasEmpty = liveTimeline.getEvents().length == 0;
1550
+ if (timelineWasEmpty) {
1551
+ // Passing these events into initialiseState will freeze them, so we need
1552
+ // to compute and cache the push actions for them now, otherwise sync dies
1553
+ // with an attempt to assign to read only property.
1554
+ // XXX: This is pretty horrible and is assuming all sorts of behaviour from
1555
+ // these functions that it shouldn't be. We should probably either store the
1556
+ // push actions cache elsewhere so we can freeze MatrixEvents, or otherwise
1557
+ // find some solution where MatrixEvents are immutable but allow for a cache
1558
+ // field.
1559
+
1560
+ for (const ev of eitherStateEventList) {
1561
+ this.client.getPushActionsForEvent(ev);
1688
1562
  }
1689
-
1690
- // Execute the timeline events. If addToState is true the timeline has any state
1691
- // events in it, this will continue to diverge the current state.
1692
- // This also needs to be done before running push rules on the events as they need
1693
- // to be decorated with sender etc.
1694
- yield room.addLiveEvents(timelineEventList || [], {
1695
- fromCache,
1696
- timelineWasEmpty,
1697
- addToState: stateAfterEventList === undefined
1563
+ liveTimeline.initialiseState(eitherStateEventList, {
1564
+ timelineWasEmpty
1698
1565
  });
1699
- _this1.client.processBeaconEvents(room, timelineEventList);
1700
- })();
1566
+ }
1567
+ this.resolveInvites(room);
1568
+
1569
+ // recalculate the room name at this point as adding events to the timeline
1570
+ // may make notifications appear which should have the right name.
1571
+ // XXX: This looks suspect: we'll end up recalculating the room once here
1572
+ // and then again after adding events (processSyncResponse calls it after
1573
+ // calling us) even if no state events were added. It also means that if
1574
+ // one of the room events in timelineEventList is something that needs
1575
+ // a recalculation (like m.room.name) we won't recalculate until we've
1576
+ // finished adding all the events, which will cause the notification to have
1577
+ // the old room name rather than the new one.
1578
+ room.recalculate();
1579
+
1580
+ // If the timeline wasn't empty, we process the state events here: they're
1581
+ // defined as updates to the state before the start of the timeline, so this
1582
+ // starts to roll the state forward.
1583
+ // XXX: That's what we *should* do, but this can happen if we were previously
1584
+ // peeking in a room, in which case we obviously do *not* want to add the
1585
+ // state events here onto the end of the timeline. Historically, the js-sdk
1586
+ // has just set these new state events on the old and new state. This seems
1587
+ // very wrong because there could be events in the timeline that diverge the
1588
+ // state, in which case this is going to leave things out of sync. However,
1589
+ // for now I think it;s best to behave the same as the code has done previously.
1590
+ if (!timelineWasEmpty) {
1591
+ // XXX: As above, don't do this...
1592
+ //room.addLiveEvents(stateEventList || []);
1593
+ // Do this instead...
1594
+ room.oldState.setStateEvents(eitherStateEventList);
1595
+ room.currentState.setStateEvents(eitherStateEventList);
1596
+ }
1597
+
1598
+ // Execute the timeline events. If addToState is true the timeline has any state
1599
+ // events in it, this will continue to diverge the current state.
1600
+ // This also needs to be done before running push rules on the events as they need
1601
+ // to be decorated with sender etc.
1602
+ await room.addLiveEvents(timelineEventList || [], {
1603
+ fromCache,
1604
+ timelineWasEmpty,
1605
+ addToState: stateAfterEventList === undefined
1606
+ });
1607
+ this.client.processBeaconEvents(room, timelineEventList);
1701
1608
  }
1702
1609
 
1703
1610
  /**
@@ -1711,10 +1618,9 @@ export class SyncApi {
1711
1618
  processEventsForNotifs(room, timelineEventList) {
1712
1619
  // gather our notifications into this.notifEvents
1713
1620
  if (this.client.getNotifTimelineSet()) {
1714
- for (var event of timelineEventList) {
1715
- var _pushActions$tweaks;
1716
- var pushActions = this.client.getPushActionsForEvent(event);
1717
- if (pushActions !== null && pushActions !== void 0 && pushActions.notify && (_pushActions$tweaks = pushActions.tweaks) !== null && _pushActions$tweaks !== void 0 && _pushActions$tweaks.highlight) {
1621
+ for (const event of timelineEventList) {
1622
+ const pushActions = this.client.getPushActionsForEvent(event);
1623
+ if (pushActions?.notify && pushActions.tweaks?.highlight) {
1718
1624
  this.notifEvents.push(event);
1719
1625
  }
1720
1626
  }
@@ -1732,7 +1638,7 @@ export class SyncApi {
1732
1638
  * @param data - Object of additional data to emit in the event
1733
1639
  */
1734
1640
  updateSyncState(newState, data) {
1735
- var old = this.syncState;
1641
+ const old = this.syncState;
1736
1642
  this.syncState = newState;
1737
1643
  this.syncStateData = data;
1738
1644
  this.client.emit(ClientEvent.Sync, this.syncState, old, data);
@@ -1742,8 +1648,10 @@ export class SyncApi {
1742
1648
  // /!\ This function is not intended for public use! It's only exported from
1743
1649
  // here in order to share some common logic with sliding-sync-sdk.ts.
1744
1650
  export function _createAndReEmitRoom(client, roomId, opts) {
1745
- var timelineSupport = client.timelineSupport;
1746
- var room = new Room(roomId, client, client.getUserId(), {
1651
+ const {
1652
+ timelineSupport
1653
+ } = client;
1654
+ const room = new Room(roomId, client, client.getUserId(), {
1747
1655
  lazyLoadMembers: opts.lazyLoadMembers,
1748
1656
  pendingEventOrdering: opts.pendingEventOrdering,
1749
1657
  timelineSupport
@@ -1753,8 +1661,7 @@ export function _createAndReEmitRoom(client, roomId, opts) {
1753
1661
  // We need to add a listener for RoomState.members in order to hook them
1754
1662
  // correctly.
1755
1663
  room.on(RoomStateEvent.NewMember, (event, state, member) => {
1756
- var _client$getUser;
1757
- member.user = (_client$getUser = client.getUser(member.userId)) !== null && _client$getUser !== void 0 ? _client$getUser : undefined;
1664
+ member.user = client.getUser(member.userId) ?? undefined;
1758
1665
  client.reEmitter.reEmit(member, [RoomMemberEvent.Name, RoomMemberEvent.Typing, RoomMemberEvent.PowerLevel, RoomMemberEvent.Membership]);
1759
1666
  });
1760
1667
  return room;
@@ -1767,7 +1674,7 @@ export function _createAndReEmitRoom(client, roomId, opts) {
1767
1674
  * Also converts the events into `MatrixEvent`s, and emits the now deprecated {@link ClientEvent.ToDeviceEvent} events for compatibility.
1768
1675
  * */
1769
1676
  export function processToDeviceMessages(toDeviceMessages, client) {
1770
- var cancelledKeyVerificationTxns = [];
1677
+ const cancelledKeyVerificationTxns = [];
1771
1678
  toDeviceMessages.map(processedMessage => {
1772
1679
  // map is a cheap inline forEach
1773
1680
  // We want to flag m.key.verification.start events as cancelled
@@ -1776,7 +1683,7 @@ export function processToDeviceMessages(toDeviceMessages, client) {
1776
1683
  // so we can flag the verification events as cancelled in the loop
1777
1684
  // below.
1778
1685
  if (processedMessage.message.type === "m.key.verification.cancel") {
1779
- var txnId = processedMessage.message.content["transaction_id"];
1686
+ const txnId = processedMessage.message.content["transaction_id"];
1780
1687
  if (txnId) {
1781
1688
  cancelledKeyVerificationTxns.push(txnId);
1782
1689
  }
@@ -1788,14 +1695,14 @@ export function processToDeviceMessages(toDeviceMessages, client) {
1788
1695
  }).forEach(function (processedEvent) {
1789
1696
  // For backwards compatibility, we also emit the event as a `MatrixEvent` using `ClientEvent.ToDeviceEvent`.
1790
1697
  {
1791
- var toDeviceEvent = processedEvent.message;
1792
- var content = toDeviceEvent.content;
1698
+ const toDeviceEvent = processedEvent.message;
1699
+ const content = toDeviceEvent.content;
1793
1700
  // The message is cloned before being passed to the MatrixEvent constructor, because
1794
1701
  // the `makeEncrypted` method will mutate the type and content properties of the original message and will interfere
1795
1702
  // with the emitted event for `ReceivedToDeviceMessage`.
1796
- var deprecatedCompatibilityEvent = new MatrixEvent(Object.assign({}, toDeviceEvent));
1703
+ const deprecatedCompatibilityEvent = new MatrixEvent(Object.assign({}, toDeviceEvent));
1797
1704
  if (toDeviceEvent.type === "m.key.verification.start" || toDeviceEvent.type === "m.key.verification.request") {
1798
- var txnId = content["transaction_id"];
1705
+ const txnId = content["transaction_id"];
1799
1706
  if (cancelledKeyVerificationTxns.includes(txnId)) {
1800
1707
  deprecatedCompatibilityEvent.flagCancelled();
1801
1708
  }