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.
- package/CHANGELOG.md +11 -0
- package/README.md +1 -1
- package/lib/@types/AESEncryptedSecretStoragePayload.js +3 -1
- package/lib/@types/IIdentityServerProvider.js +3 -1
- package/lib/@types/PushRules.js +7 -7
- package/lib/@types/PushRules.js.map +1 -1
- package/lib/@types/auth.js +4 -4
- package/lib/@types/auth.js.map +1 -1
- package/lib/@types/beacon.js +2 -2
- package/lib/@types/beacon.js.map +1 -1
- package/lib/@types/common.js +3 -1
- package/lib/@types/crypto.js +3 -1
- package/lib/@types/event.js +20 -20
- package/lib/@types/event.js.map +1 -1
- package/lib/@types/events.js +3 -1
- package/lib/@types/extensible_events.js +6 -6
- package/lib/@types/extensible_events.js.map +1 -1
- package/lib/@types/global.d.js.map +1 -1
- package/lib/@types/json.js +3 -1
- package/lib/@types/local_notifications.js +3 -1
- package/lib/@types/location.js +4 -4
- package/lib/@types/location.js.map +1 -1
- package/lib/@types/matrix-sdk-crypto-wasm.d.js +3 -1
- package/lib/@types/media.js +3 -1
- package/lib/@types/membership.js +1 -1
- package/lib/@types/membership.js.map +1 -1
- package/lib/@types/partials.js +6 -6
- package/lib/@types/partials.js.map +1 -1
- package/lib/@types/polls.js +5 -5
- package/lib/@types/polls.js.map +1 -1
- package/lib/@types/read_receipts.js +2 -2
- package/lib/@types/read_receipts.js.map +1 -1
- package/lib/@types/registration.js +3 -1
- package/lib/@types/requests.js +1 -1
- package/lib/@types/requests.js.map +1 -1
- package/lib/@types/retention.js +1 -1
- package/lib/@types/retention.js.map +1 -1
- package/lib/@types/search.js +1 -1
- package/lib/@types/search.js.map +1 -1
- package/lib/@types/signed.js +3 -1
- package/lib/@types/spaces.js +3 -1
- package/lib/@types/state_events.js +3 -1
- package/lib/@types/synapse.js +3 -1
- package/lib/@types/sync.js +1 -1
- package/lib/@types/sync.js.map +1 -1
- package/lib/@types/threepids.js +1 -1
- package/lib/@types/threepids.js.map +1 -1
- package/lib/@types/topic.js +1 -1
- package/lib/@types/topic.js.map +1 -1
- package/lib/@types/uia.js +3 -1
- package/lib/NamespacedValue.js +8 -8
- package/lib/NamespacedValue.js.map +1 -1
- package/lib/ReEmitter.js +9 -16
- package/lib/ReEmitter.js.map +1 -1
- package/lib/ToDeviceMessageQueue.js +49 -57
- package/lib/ToDeviceMessageQueue.js.map +1 -1
- package/lib/autodiscovery.js +232 -247
- package/lib/autodiscovery.js.map +1 -1
- package/lib/base64.js +1 -1
- package/lib/base64.js.map +1 -1
- package/lib/browser-index.d.ts +2 -2
- package/lib/browser-index.d.ts.map +1 -1
- package/lib/browser-index.js +5 -5
- package/lib/browser-index.js.map +1 -1
- package/lib/capabilityPoller.js +19 -22
- package/lib/capabilityPoller.js.map +1 -1
- package/lib/client.d.ts +2 -8
- package/lib/client.d.ts.map +1 -1
- package/lib/client.js +2043 -2487
- package/lib/client.js.map +1 -1
- package/lib/common-crypto/CryptoBackend.js +2 -2
- package/lib/common-crypto/CryptoBackend.js.map +1 -1
- package/lib/common-crypto/key-passphrase.js.map +1 -1
- package/lib/content-helpers.js +43 -48
- package/lib/content-helpers.js.map +1 -1
- package/lib/content-repo.js +14 -24
- package/lib/content-repo.js.map +1 -1
- package/lib/crypto/store/base.js +6 -6
- package/lib/crypto/store/base.js.map +1 -1
- package/lib/crypto/store/indexeddb-crypto-store-backend.js +190 -238
- package/lib/crypto/store/indexeddb-crypto-store-backend.js.map +1 -1
- package/lib/crypto/store/indexeddb-crypto-store.js +25 -30
- package/lib/crypto/store/indexeddb-crypto-store.js.map +1 -1
- package/lib/crypto/store/localStorage-crypto-store.js +113 -145
- package/lib/crypto/store/localStorage-crypto-store.js.map +1 -1
- package/lib/crypto/store/memory-crypto-store.js +74 -105
- package/lib/crypto/store/memory-crypto-store.js.map +1 -1
- package/lib/crypto-api/CryptoEvent.js +1 -1
- package/lib/crypto-api/CryptoEvent.js.map +1 -1
- package/lib/crypto-api/CryptoEventHandlerMap.js +3 -1
- package/lib/crypto-api/index.d.ts +15 -6
- package/lib/crypto-api/index.d.ts.map +1 -1
- package/lib/crypto-api/index.js +22 -22
- package/lib/crypto-api/index.js.map +1 -1
- package/lib/crypto-api/key-passphrase.js +15 -23
- package/lib/crypto-api/key-passphrase.js.map +1 -1
- package/lib/crypto-api/keybackup.js +3 -1
- package/lib/crypto-api/recovery-key.js +11 -12
- package/lib/crypto-api/recovery-key.js.map +1 -1
- package/lib/crypto-api/verification.js +3 -3
- package/lib/crypto-api/verification.js.map +1 -1
- package/lib/digest.js +7 -14
- package/lib/digest.js.map +1 -1
- package/lib/embedded.d.ts.map +1 -1
- package/lib/embedded.js +380 -505
- package/lib/embedded.js.map +1 -1
- package/lib/errors.js +2 -2
- package/lib/errors.js.map +1 -1
- package/lib/event-mapper.js +10 -12
- package/lib/event-mapper.js.map +1 -1
- package/lib/extensible_events_v1/ExtensibleEvent.js.map +1 -1
- package/lib/extensible_events_v1/InvalidEventError.js.map +1 -1
- package/lib/extensible_events_v1/MessageEvent.js +11 -13
- package/lib/extensible_events_v1/MessageEvent.js.map +1 -1
- package/lib/extensible_events_v1/PollEndEvent.js +3 -4
- package/lib/extensible_events_v1/PollEndEvent.js.map +1 -1
- package/lib/extensible_events_v1/PollResponseEvent.js +5 -6
- package/lib/extensible_events_v1/PollResponseEvent.js.map +1 -1
- package/lib/extensible_events_v1/PollStartEvent.js +8 -10
- package/lib/extensible_events_v1/PollStartEvent.js.map +1 -1
- package/lib/extensible_events_v1/utilities.js.map +1 -1
- package/lib/feature.js +18 -31
- package/lib/feature.js.map +1 -1
- package/lib/filter-component.d.ts.map +1 -1
- package/lib/filter-component.js +20 -26
- package/lib/filter-component.js.map +1 -1
- package/lib/filter.js +14 -17
- package/lib/filter.js.map +1 -1
- package/lib/http-api/errors.js +28 -43
- package/lib/http-api/errors.js.map +1 -1
- package/lib/http-api/fetch.js +141 -159
- package/lib/http-api/fetch.js.map +1 -1
- package/lib/http-api/index.js +17 -20
- package/lib/http-api/index.js.map +1 -1
- package/lib/http-api/interface.js +1 -1
- package/lib/http-api/interface.js.map +1 -1
- package/lib/http-api/method.js +1 -1
- package/lib/http-api/method.js.map +1 -1
- package/lib/http-api/prefix.js +3 -3
- package/lib/http-api/prefix.js.map +1 -1
- package/lib/http-api/refresh.js +74 -94
- package/lib/http-api/refresh.js.map +1 -1
- package/lib/http-api/utils.d.ts +1 -1
- package/lib/http-api/utils.d.ts.map +1 -1
- package/lib/http-api/utils.js +34 -42
- package/lib/http-api/utils.js.map +1 -1
- package/lib/index.js.map +1 -1
- package/lib/indexeddb-helpers.js +3 -3
- package/lib/indexeddb-helpers.js.map +1 -1
- package/lib/indexeddb-worker.js.map +1 -1
- package/lib/interactive-auth.d.ts +5 -5
- package/lib/interactive-auth.d.ts.map +1 -1
- package/lib/interactive-auth.js +172 -204
- package/lib/interactive-auth.js.map +1 -1
- package/lib/logger.js +21 -57
- package/lib/logger.js.map +1 -1
- package/lib/matrix.js +7 -11
- package/lib/matrix.js.map +1 -1
- package/lib/matrixrtc/CallMembership.js +80 -74
- package/lib/matrixrtc/CallMembership.js.map +1 -1
- package/lib/matrixrtc/EncryptionManager.js +1 -1
- package/lib/matrixrtc/EncryptionManager.js.map +1 -1
- package/lib/matrixrtc/IKeyTransport.js +1 -1
- package/lib/matrixrtc/IKeyTransport.js.map +1 -1
- package/lib/matrixrtc/IMembershipManager.js +1 -1
- package/lib/matrixrtc/IMembershipManager.js.map +1 -1
- package/lib/matrixrtc/LivekitTransport.d.ts +1 -1
- package/lib/matrixrtc/LivekitTransport.js +4 -4
- package/lib/matrixrtc/LivekitTransport.js.map +1 -1
- package/lib/matrixrtc/MatrixRTCSession.js +137 -187
- package/lib/matrixrtc/MatrixRTCSession.js.map +1 -1
- package/lib/matrixrtc/MatrixRTCSessionManager.js +36 -41
- package/lib/matrixrtc/MatrixRTCSessionManager.js.map +1 -1
- package/lib/matrixrtc/MembershipManager.js +332 -378
- package/lib/matrixrtc/MembershipManager.js.map +1 -1
- package/lib/matrixrtc/MembershipManagerActionScheduler.js +54 -63
- package/lib/matrixrtc/MembershipManagerActionScheduler.js.map +1 -1
- package/lib/matrixrtc/RTCEncryptionManager.js +119 -143
- package/lib/matrixrtc/RTCEncryptionManager.js.map +1 -1
- package/lib/matrixrtc/ToDeviceKeyTransport.js +53 -58
- package/lib/matrixrtc/ToDeviceKeyTransport.js.map +1 -1
- package/lib/matrixrtc/index.js.map +1 -1
- package/lib/matrixrtc/membershipData/common.js +1 -1
- package/lib/matrixrtc/membershipData/common.js.map +1 -1
- package/lib/matrixrtc/membershipData/index.js.map +1 -1
- package/lib/matrixrtc/membershipData/rtc.js +15 -23
- package/lib/matrixrtc/membershipData/rtc.js.map +1 -1
- package/lib/matrixrtc/membershipData/session.js +4 -5
- package/lib/matrixrtc/membershipData/session.js.map +1 -1
- package/lib/matrixrtc/types.js +4 -6
- package/lib/matrixrtc/types.js.map +1 -1
- package/lib/matrixrtc/utils.js +4 -11
- package/lib/matrixrtc/utils.js.map +1 -1
- package/lib/models/MSC3089Branch.js +91 -116
- package/lib/models/MSC3089Branch.js.map +1 -1
- package/lib/models/MSC3089TreeSpace.js +209 -245
- package/lib/models/MSC3089TreeSpace.js.map +1 -1
- package/lib/models/ToDeviceMessage.js +3 -1
- package/lib/models/beacon.js +14 -13
- package/lib/models/beacon.js.map +1 -1
- package/lib/models/compare-event-ordering.js +13 -13
- package/lib/models/compare-event-ordering.js.map +1 -1
- package/lib/models/device.js +3 -3
- package/lib/models/device.js.map +1 -1
- package/lib/models/event-context.js +5 -8
- package/lib/models/event-context.js.map +1 -1
- package/lib/models/event-status.js +1 -1
- package/lib/models/event-status.js.map +1 -1
- package/lib/models/event-timeline-set.js +88 -94
- package/lib/models/event-timeline-set.js.map +1 -1
- package/lib/models/event-timeline.js +28 -30
- package/lib/models/event-timeline.js.map +1 -1
- package/lib/models/event.js +182 -226
- package/lib/models/event.js.map +1 -1
- package/lib/models/invites-ignorer-types.js +4 -4
- package/lib/models/invites-ignorer-types.js.map +1 -1
- package/lib/models/invites-ignorer.js +159 -179
- package/lib/models/invites-ignorer.js.map +1 -1
- package/lib/models/poll.js +71 -81
- package/lib/models/poll.js.map +1 -1
- package/lib/models/profile-keys.js +2 -2
- package/lib/models/profile-keys.js.map +1 -1
- package/lib/models/read-receipt.js +40 -56
- package/lib/models/read-receipt.js.map +1 -1
- package/lib/models/related-relations.js.map +1 -1
- package/lib/models/relations-container.js +22 -23
- package/lib/models/relations-container.js.map +1 -1
- package/lib/models/relations.js +133 -159
- package/lib/models/relations.js.map +1 -1
- package/lib/models/room-member.js +24 -29
- package/lib/models/room-member.js.map +1 -1
- package/lib/models/room-receipts.js +29 -43
- package/lib/models/room-receipts.js.map +1 -1
- package/lib/models/room-retention.js +74 -83
- package/lib/models/room-retention.js.map +1 -1
- package/lib/models/room-state.js +143 -172
- package/lib/models/room-state.js.map +1 -1
- package/lib/models/room-sticky-events.d.ts +1 -0
- package/lib/models/room-sticky-events.d.ts.map +1 -1
- package/lib/models/room-sticky-events.js +45 -65
- package/lib/models/room-sticky-events.js.map +1 -1
- package/lib/models/room-summary.js.map +1 -1
- package/lib/models/room.d.ts.map +1 -1
- package/lib/models/room.js +765 -909
- package/lib/models/room.js.map +1 -1
- package/lib/models/search-result.js +5 -5
- package/lib/models/search-result.js.map +1 -1
- package/lib/models/thread.js +225 -285
- package/lib/models/thread.js.map +1 -1
- package/lib/models/typed-event-emitter.js +7 -18
- package/lib/models/typed-event-emitter.js.map +1 -1
- package/lib/models/user.js +8 -8
- package/lib/models/user.js.map +1 -1
- package/lib/oidc/authorize.js +208 -241
- package/lib/oidc/authorize.js.map +1 -1
- package/lib/oidc/discovery.js +23 -36
- package/lib/oidc/discovery.js.map +1 -1
- package/lib/oidc/error.js +1 -1
- package/lib/oidc/error.js.map +1 -1
- package/lib/oidc/index.js +1 -0
- package/lib/oidc/index.js.map +1 -1
- package/lib/oidc/register.js +60 -66
- package/lib/oidc/register.js.map +1 -1
- package/lib/oidc/tokenRefresher.js +77 -91
- package/lib/oidc/tokenRefresher.js.map +1 -1
- package/lib/oidc/validate.js +18 -18
- package/lib/oidc/validate.js.map +1 -1
- package/lib/pushprocessor.js +71 -82
- package/lib/pushprocessor.js.map +1 -1
- package/lib/randomstring.js +9 -9
- package/lib/randomstring.js.map +1 -1
- package/lib/realtime-callbacks.js +25 -28
- package/lib/realtime-callbacks.js.map +1 -1
- package/lib/receipt-accumulator.d.ts +2 -0
- package/lib/receipt-accumulator.d.ts.map +1 -1
- package/lib/receipt-accumulator.js +14 -22
- package/lib/receipt-accumulator.js.map +1 -1
- package/lib/rendezvous/MSC4108SignInWithQR.js +271 -302
- package/lib/rendezvous/MSC4108SignInWithQR.js.map +1 -1
- package/lib/rendezvous/RendezvousChannel.js +3 -1
- package/lib/rendezvous/RendezvousCode.js +3 -1
- package/lib/rendezvous/RendezvousError.js.map +1 -1
- package/lib/rendezvous/RendezvousFailureReason.js +2 -2
- package/lib/rendezvous/RendezvousFailureReason.js.map +1 -1
- package/lib/rendezvous/RendezvousIntent.js +1 -1
- package/lib/rendezvous/RendezvousIntent.js.map +1 -1
- package/lib/rendezvous/RendezvousTransport.js +3 -1
- package/lib/rendezvous/channels/MSC4108SecureChannel.js +123 -147
- package/lib/rendezvous/channels/MSC4108SecureChannel.js.map +1 -1
- package/lib/rendezvous/index.js +44 -69
- package/lib/rendezvous/index.js.map +1 -1
- package/lib/rendezvous/transports/MSC4108RendezvousSession.d.ts +1 -1
- package/lib/rendezvous/transports/MSC4108RendezvousSession.js +134 -152
- package/lib/rendezvous/transports/MSC4108RendezvousSession.js.map +1 -1
- package/lib/retentionPolicy.js +6 -9
- package/lib/retentionPolicy.js.map +1 -1
- package/lib/room-hierarchy.js +52 -60
- package/lib/room-hierarchy.js.map +1 -1
- package/lib/rust-crypto/CrossSigningIdentity.js +94 -104
- package/lib/rust-crypto/CrossSigningIdentity.js.map +1 -1
- package/lib/rust-crypto/DehydratedDeviceManager.js +157 -190
- package/lib/rust-crypto/DehydratedDeviceManager.js.map +1 -1
- package/lib/rust-crypto/KeyClaimManager.js +18 -22
- package/lib/rust-crypto/KeyClaimManager.js.map +1 -1
- package/lib/rust-crypto/OutgoingRequestProcessor.js +109 -139
- package/lib/rust-crypto/OutgoingRequestProcessor.js.map +1 -1
- package/lib/rust-crypto/OutgoingRequestsManager.js +66 -80
- package/lib/rust-crypto/OutgoingRequestsManager.js.map +1 -1
- package/lib/rust-crypto/PerSessionKeyBackupDownloader.d.ts +1 -1
- package/lib/rust-crypto/PerSessionKeyBackupDownloader.js +196 -224
- package/lib/rust-crypto/PerSessionKeyBackupDownloader.js.map +1 -1
- package/lib/rust-crypto/RoomEncryptor.js +127 -143
- package/lib/rust-crypto/RoomEncryptor.js.map +1 -1
- package/lib/rust-crypto/backup.js +453 -549
- package/lib/rust-crypto/backup.js.map +1 -1
- package/lib/rust-crypto/constants.js +1 -1
- package/lib/rust-crypto/constants.js.map +1 -1
- package/lib/rust-crypto/device-converter.js +15 -28
- package/lib/rust-crypto/device-converter.js.map +1 -1
- package/lib/rust-crypto/index.js +103 -116
- package/lib/rust-crypto/index.js.map +1 -1
- package/lib/rust-crypto/libolm_migration.js +303 -365
- package/lib/rust-crypto/libolm_migration.js.map +1 -1
- package/lib/rust-crypto/rust-crypto.d.ts +5 -1
- package/lib/rust-crypto/rust-crypto.d.ts.map +1 -1
- package/lib/rust-crypto/rust-crypto.js +1067 -1332
- package/lib/rust-crypto/rust-crypto.js.map +1 -1
- package/lib/rust-crypto/secret-storage.js +12 -25
- package/lib/rust-crypto/secret-storage.js.map +1 -1
- package/lib/rust-crypto/verification.js +137 -189
- package/lib/rust-crypto/verification.js.map +1 -1
- package/lib/scheduler.js +44 -19
- package/lib/scheduler.js.map +1 -1
- package/lib/secret-storage.js +179 -213
- package/lib/secret-storage.js.map +1 -1
- package/lib/serverCapabilities.js +6 -9
- package/lib/serverCapabilities.js.map +1 -1
- package/lib/service-types.js +1 -1
- package/lib/service-types.js.map +1 -1
- package/lib/sliding-sync-sdk.d.ts.map +1 -1
- package/lib/sliding-sync-sdk.js +368 -424
- package/lib/sliding-sync-sdk.js.map +1 -1
- package/lib/sliding-sync.js +135 -171
- package/lib/sliding-sync.js.map +1 -1
- package/lib/store/index.js +3 -1
- package/lib/store/indexeddb-backend.js +3 -1
- package/lib/store/indexeddb-local-backend.js +194 -253
- package/lib/store/indexeddb-local-backend.js.map +1 -1
- package/lib/store/indexeddb-remote-backend.js +33 -63
- package/lib/store/indexeddb-remote-backend.js.map +1 -1
- package/lib/store/indexeddb-store-worker.js +22 -23
- package/lib/store/indexeddb-store-worker.js.map +1 -1
- package/lib/store/indexeddb.js +44 -71
- package/lib/store/indexeddb.js.map +1 -1
- package/lib/store/local-storage-events-emitter.js +2 -2
- package/lib/store/local-storage-events-emitter.js.map +1 -1
- package/lib/store/memory.js +34 -57
- package/lib/store/memory.js.map +1 -1
- package/lib/store/stub.js +22 -35
- package/lib/store/stub.js.map +1 -1
- package/lib/sync-accumulator.js +54 -66
- package/lib/sync-accumulator.js.map +1 -1
- package/lib/sync.d.ts.map +1 -1
- package/lib/sync.js +905 -998
- package/lib/sync.js.map +1 -1
- package/lib/testing.js +63 -105
- package/lib/testing.js.map +1 -1
- package/lib/thread-utils.js +1 -4
- package/lib/thread-utils.js.map +1 -1
- package/lib/timeline-window.js +89 -102
- package/lib/timeline-window.js.map +1 -1
- package/lib/types.js +1 -1
- package/lib/types.js.map +1 -1
- package/lib/utils/decryptAESSecretStorageItem.js +14 -25
- package/lib/utils/decryptAESSecretStorageItem.js.map +1 -1
- package/lib/utils/encryptAESSecretStorageItem.js +27 -38
- package/lib/utils/encryptAESSecretStorageItem.js.map +1 -1
- package/lib/utils/internal/deriveKeys.js +25 -32
- package/lib/utils/internal/deriveKeys.js.map +1 -1
- package/lib/utils/roomVersion.js +1 -1
- package/lib/utils/roomVersion.js.map +1 -1
- package/lib/utils.js +83 -135
- package/lib/utils.js.map +1 -1
- package/lib/version-support.js +3 -3
- package/lib/version-support.js.map +1 -1
- package/lib/webrtc/audioContext.js +5 -6
- package/lib/webrtc/audioContext.js.map +1 -1
- package/lib/webrtc/call.js +1081 -1250
- package/lib/webrtc/call.js.map +1 -1
- package/lib/webrtc/callEventHandler.js +202 -214
- package/lib/webrtc/callEventHandler.js.map +1 -1
- package/lib/webrtc/callEventTypes.js +2 -2
- package/lib/webrtc/callEventTypes.js.map +1 -1
- package/lib/webrtc/callFeed.js +18 -20
- package/lib/webrtc/callFeed.js.map +1 -1
- package/lib/webrtc/groupCall.js +513 -602
- package/lib/webrtc/groupCall.js.map +1 -1
- package/lib/webrtc/groupCallEventHandler.js +59 -62
- package/lib/webrtc/groupCallEventHandler.js.map +1 -1
- package/lib/webrtc/mediaHandler.js +198 -232
- package/lib/webrtc/mediaHandler.js.map +1 -1
- package/lib/webrtc/stats/callFeedStatsReporter.js +16 -20
- package/lib/webrtc/stats/callFeedStatsReporter.js.map +1 -1
- package/lib/webrtc/stats/callStatsReportGatherer.js +67 -75
- package/lib/webrtc/stats/callStatsReportGatherer.js.map +1 -1
- package/lib/webrtc/stats/callStatsReportSummary.js +3 -1
- package/lib/webrtc/stats/connectionStats.js.map +1 -1
- package/lib/webrtc/stats/connectionStatsBuilder.js +2 -2
- package/lib/webrtc/stats/connectionStatsBuilder.js.map +1 -1
- package/lib/webrtc/stats/connectionStatsReportBuilder.js +20 -24
- package/lib/webrtc/stats/connectionStatsReportBuilder.js.map +1 -1
- package/lib/webrtc/stats/groupCallStats.js +6 -8
- package/lib/webrtc/stats/groupCallStats.js.map +1 -1
- package/lib/webrtc/stats/media/mediaSsrcHandler.js +7 -8
- package/lib/webrtc/stats/media/mediaSsrcHandler.js.map +1 -1
- package/lib/webrtc/stats/media/mediaTrackHandler.js +7 -9
- package/lib/webrtc/stats/media/mediaTrackHandler.js.map +1 -1
- package/lib/webrtc/stats/media/mediaTrackStats.js +3 -3
- package/lib/webrtc/stats/media/mediaTrackStats.js.map +1 -1
- package/lib/webrtc/stats/media/mediaTrackStatsHandler.js +7 -7
- package/lib/webrtc/stats/media/mediaTrackStatsHandler.js.map +1 -1
- package/lib/webrtc/stats/statsReport.js +1 -1
- package/lib/webrtc/stats/statsReport.js.map +1 -1
- package/lib/webrtc/stats/statsReportEmitter.js.map +1 -1
- package/lib/webrtc/stats/summaryStatsReportGatherer.js +14 -14
- package/lib/webrtc/stats/summaryStatsReportGatherer.js.map +1 -1
- package/lib/webrtc/stats/trackStatsBuilder.js +32 -34
- package/lib/webrtc/stats/trackStatsBuilder.js.map +1 -1
- package/lib/webrtc/stats/transportStats.js +3 -1
- package/lib/webrtc/stats/transportStatsBuilder.js +9 -9
- package/lib/webrtc/stats/transportStatsBuilder.js.map +1 -1
- package/lib/webrtc/stats/valueFormatter.js +1 -1
- package/lib/webrtc/stats/valueFormatter.js.map +1 -1
- package/package.json +18 -33
- package/src/@types/global.d.ts +2 -2
- package/src/ToDeviceMessageQueue.ts +2 -2
- package/src/browser-index.ts +4 -4
- package/src/client.ts +15 -20
- package/src/crypto-api/index.ts +17 -6
- package/src/embedded.ts +4 -6
- package/src/filter-component.ts +1 -0
- package/src/http-api/utils.ts +1 -1
- package/src/interactive-auth.ts +11 -5
- package/src/matrixrtc/LivekitTransport.ts +1 -1
- package/src/matrixrtc/MatrixRTCSession.ts +1 -1
- package/src/models/MSC3089Branch.ts +1 -1
- package/src/models/room-sticky-events.ts +1 -0
- package/src/models/room.ts +9 -11
- package/src/receipt-accumulator.ts +2 -0
- package/src/rendezvous/index.ts +1 -1
- package/src/rendezvous/transports/MSC4108RendezvousSession.ts +2 -2
- package/src/rust-crypto/PerSessionKeyBackupDownloader.ts +1 -1
- package/src/rust-crypto/index.ts +6 -6
- package/src/rust-crypto/rust-crypto.ts +31 -7
- package/src/rust-crypto/verification.ts +1 -1
- package/src/sliding-sync-sdk.ts +5 -7
- package/src/store/indexeddb-local-backend.ts +3 -3
- package/src/sync.ts +6 -8
package/lib/models/room.js
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
|
|
1
|
+
import _objectSpread from "@babel/runtime/helpers/objectSpread2";
|
|
3
2
|
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; }
|
|
6
3
|
/*
|
|
7
4
|
Copyright 2015 - 2023 The Matrix.org Foundation C.I.C.
|
|
8
5
|
|
|
@@ -54,8 +51,8 @@ import { RoomRetentionPolicy } from "./room-retention.js";
|
|
|
54
51
|
// room versions which are considered okay for people to run without being asked
|
|
55
52
|
// to upgrade (ie: "stable"). Eventually, we should remove these when all homeservers
|
|
56
53
|
// return an m.room_versions capability.
|
|
57
|
-
export
|
|
58
|
-
|
|
54
|
+
export const KNOWN_SAFE_ROOM_VERSION = "10";
|
|
55
|
+
const SAFE_ROOM_VERSIONS = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"];
|
|
59
56
|
// When inserting a visibility event affecting event `eventId`, we
|
|
60
57
|
// need to scan through existing visibility events for `eventId`.
|
|
61
58
|
// In theory, this could take an unlimited amount of time if:
|
|
@@ -70,13 +67,13 @@ var SAFE_ROOM_VERSIONS = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"];
|
|
|
70
67
|
// expecting that a broken visibility change for a single event in
|
|
71
68
|
// an extremely uncommon case (possibly a DoS) is a small
|
|
72
69
|
// price to pay to keep matrix-js-sdk responsive.
|
|
73
|
-
|
|
74
|
-
export
|
|
70
|
+
const MAX_NUMBER_OF_VISIBILITY_EVENTS_TO_SCAN_THROUGH = 30;
|
|
71
|
+
export let NotificationCountType = /*#__PURE__*/function (NotificationCountType) {
|
|
75
72
|
NotificationCountType["Highlight"] = "highlight";
|
|
76
73
|
NotificationCountType["Total"] = "total";
|
|
77
74
|
return NotificationCountType;
|
|
78
75
|
}({});
|
|
79
|
-
export
|
|
76
|
+
export let RoomEvent = /*#__PURE__*/function (RoomEvent) {
|
|
80
77
|
RoomEvent["MyMembership"] = "Room.myMembership";
|
|
81
78
|
RoomEvent["Tags"] = "Room.tags";
|
|
82
79
|
RoomEvent["AccountData"] = "Room.accountData";
|
|
@@ -119,17 +116,11 @@ export class Room extends ReadReceipt {
|
|
|
119
116
|
* @param myUserId - Required. The ID of the syncing user.
|
|
120
117
|
* @param opts - Configuration options
|
|
121
118
|
*/
|
|
122
|
-
constructor(roomId, client, myUserId) {
|
|
123
|
-
|
|
124
|
-
|
|
119
|
+
constructor(roomId, client, myUserId, opts = {}) {
|
|
120
|
+
super();
|
|
121
|
+
|
|
125
122
|
// In some cases, we add listeners for every displayed Matrix event, so it's
|
|
126
123
|
// common to have quite a few more than the default limit.
|
|
127
|
-
super();
|
|
128
|
-
_this = this;
|
|
129
|
-
this.roomId = roomId;
|
|
130
|
-
this.client = client;
|
|
131
|
-
this.myUserId = myUserId;
|
|
132
|
-
this.opts = opts;
|
|
133
124
|
_defineProperty(this, "reEmitter", void 0);
|
|
134
125
|
_defineProperty(this, "txnToEvent", new Map());
|
|
135
126
|
// Pending in-flight requests { string: MatrixEvent }
|
|
@@ -246,14 +237,36 @@ export class Room extends ReadReceipt {
|
|
|
246
237
|
_defineProperty(this, "stickyEvents", new RoomStickyEventsStore());
|
|
247
238
|
_defineProperty(this, "retention", void 0);
|
|
248
239
|
_defineProperty(this, "threadTimelineSetsPromise", null);
|
|
240
|
+
_defineProperty(this, "onReceipt", event => {
|
|
241
|
+
if (this.hasEncryptionStateEvent()) {
|
|
242
|
+
this.clearNotificationsOnReceipt(event);
|
|
243
|
+
}
|
|
244
|
+
});
|
|
249
245
|
_defineProperty(this, "threadsReady", false);
|
|
246
|
+
_defineProperty(this, "onThreadUpdate", thread => {
|
|
247
|
+
this.updateThreadRootEvents(thread, false, false);
|
|
248
|
+
});
|
|
249
|
+
_defineProperty(this, "onThreadReply", thread => {
|
|
250
|
+
this.updateThreadRootEvents(thread, false, true);
|
|
251
|
+
});
|
|
252
|
+
_defineProperty(this, "onThreadDelete", thread => {
|
|
253
|
+
this.threads.delete(thread.id);
|
|
254
|
+
const timeline = this.getTimelineForEvent(thread.id);
|
|
255
|
+
const roomEvent = timeline?.getEvents()?.find(it => it.getId() === thread.id);
|
|
256
|
+
if (roomEvent) {
|
|
257
|
+
thread.clearEventMetadata(roomEvent);
|
|
258
|
+
} else {
|
|
259
|
+
logger.debug("onThreadDelete: Could not find root event in room timeline");
|
|
260
|
+
}
|
|
261
|
+
for (const timelineSet of this.threadsTimelineSets) {
|
|
262
|
+
timelineSet.removeEvent(thread.id);
|
|
263
|
+
}
|
|
264
|
+
});
|
|
250
265
|
_defineProperty(this, "updateThreadRootEvents", (thread, toStartOfTimeline, recreateEvent) => {
|
|
251
266
|
if (thread.length) {
|
|
252
|
-
|
|
253
|
-
this.updateThreadRootEvent((_this$threadsTimeline = this.threadsTimelineSets) === null || _this$threadsTimeline === void 0 ? void 0 : _this$threadsTimeline[0], thread, toStartOfTimeline, recreateEvent);
|
|
267
|
+
this.updateThreadRootEvent(this.threadsTimelineSets?.[0], thread, toStartOfTimeline, recreateEvent);
|
|
254
268
|
if (thread.hasCurrentUserParticipated) {
|
|
255
|
-
|
|
256
|
-
this.updateThreadRootEvent((_this$threadsTimeline2 = this.threadsTimelineSets) === null || _this$threadsTimeline2 === void 0 ? void 0 : _this$threadsTimeline2[1], thread, toStartOfTimeline, recreateEvent);
|
|
269
|
+
this.updateThreadRootEvent(this.threadsTimelineSets?.[1], thread, toStartOfTimeline, recreateEvent);
|
|
257
270
|
}
|
|
258
271
|
}
|
|
259
272
|
});
|
|
@@ -285,10 +298,10 @@ export class Room extends ReadReceipt {
|
|
|
285
298
|
// if they wish to. Also this may be needed to trigger an update.
|
|
286
299
|
|
|
287
300
|
if (event.isRedaction()) {
|
|
288
|
-
|
|
301
|
+
const redactId = event.event.redacts;
|
|
289
302
|
|
|
290
303
|
// if we know about this event, redact its contents now.
|
|
291
|
-
|
|
304
|
+
const redactedEvent = redactId ? this.findEventById(redactId) : undefined;
|
|
292
305
|
if (redactId) {
|
|
293
306
|
try {
|
|
294
307
|
this.stickyEvents.handleRedaction(redactedEvent || redactId);
|
|
@@ -301,17 +314,17 @@ export class Room extends ReadReceipt {
|
|
|
301
314
|
this.applyEventAsRedaction(event, redactedEvent);
|
|
302
315
|
}
|
|
303
316
|
} else if (event.getType() === EventType.RoomMember) {
|
|
304
|
-
|
|
317
|
+
const membership = event.getContent()["membership"];
|
|
305
318
|
if (membership !== KnownMembership.Ban && !(membership === KnownMembership.Leave && event.getStateKey() !== event.getSender())) {
|
|
306
319
|
// Not a ban or kick, therefore not a membership event we care about here.
|
|
307
320
|
return;
|
|
308
321
|
}
|
|
309
|
-
|
|
322
|
+
const redactEvents = event.getContent()["org.matrix.msc4293.redact_events"];
|
|
310
323
|
if (redactEvents !== true) {
|
|
311
324
|
// Invalid or not set - nothing to redact.
|
|
312
325
|
return;
|
|
313
326
|
}
|
|
314
|
-
|
|
327
|
+
const state = this.getLiveTimeline().getState(Direction.Forward);
|
|
315
328
|
if (!state.maySendRedactionForEvent(event, event.getSender())) {
|
|
316
329
|
// If the sender can't redact the membership event, then they won't be able to
|
|
317
330
|
// redact any of the target's events either, so skip.
|
|
@@ -319,18 +332,22 @@ export class Room extends ReadReceipt {
|
|
|
319
332
|
}
|
|
320
333
|
|
|
321
334
|
// The redaction is possible, so let's find all the events and apply it.
|
|
322
|
-
|
|
335
|
+
const events = this.getTimelineSets().map(s => s.getTimelines()).reduce((p, c) => {
|
|
323
336
|
p.push(...c);
|
|
324
337
|
return p;
|
|
325
338
|
}, []).map(t => t.getEvents().filter(e => e.getSender() === event.getStateKey())).reduce((p, c) => {
|
|
326
339
|
p.push(...c);
|
|
327
340
|
return c;
|
|
328
341
|
}, []);
|
|
329
|
-
for (
|
|
342
|
+
for (const toRedact of events) {
|
|
330
343
|
this.applyEventAsRedaction(event, toRedact);
|
|
331
344
|
}
|
|
332
345
|
}
|
|
333
346
|
});
|
|
347
|
+
this.roomId = roomId;
|
|
348
|
+
this.client = client;
|
|
349
|
+
this.myUserId = myUserId;
|
|
350
|
+
this.opts = opts;
|
|
334
351
|
this.setMaxListeners(100);
|
|
335
352
|
this.reEmitter = new TypedReEmitter(this);
|
|
336
353
|
opts.pendingEventOrdering = opts.pendingEventOrdering || PendingEventOrdering.Chronological;
|
|
@@ -351,20 +368,15 @@ export class Room extends ReadReceipt {
|
|
|
351
368
|
if (this.opts.pendingEventOrdering === PendingEventOrdering.Detached) {
|
|
352
369
|
this.pendingEventList = [];
|
|
353
370
|
this.client.store.getPendingEvents(this.roomId).then(events => {
|
|
354
|
-
|
|
371
|
+
const mapper = this.client.getEventMapper({
|
|
355
372
|
decrypt: false
|
|
356
373
|
});
|
|
357
|
-
events.forEach(
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
});
|
|
364
|
-
return function (_x) {
|
|
365
|
-
return _ref.apply(this, arguments);
|
|
366
|
-
};
|
|
367
|
-
}());
|
|
374
|
+
events.forEach(async serializedEvent => {
|
|
375
|
+
const event = mapper(serializedEvent);
|
|
376
|
+
await client.decryptEventIfNeeded(event);
|
|
377
|
+
event.setStatus(EventStatus.NOT_SENT);
|
|
378
|
+
this.addPendingEvent(event, event.getTxnId());
|
|
379
|
+
});
|
|
368
380
|
});
|
|
369
381
|
}
|
|
370
382
|
|
|
@@ -374,31 +386,27 @@ export class Room extends ReadReceipt {
|
|
|
374
386
|
} else {
|
|
375
387
|
this.membersPromise = undefined;
|
|
376
388
|
}
|
|
377
|
-
if (
|
|
389
|
+
if (this.client?._unstable_shouldApplyMessageRetention) {
|
|
378
390
|
this.retention = new RoomRetentionPolicy(this, client.retentionPolicyService, client.store);
|
|
379
391
|
}
|
|
380
392
|
}
|
|
381
|
-
createThreadsTimelineSets() {
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
} catch (_unused) {
|
|
396
|
-
_this2.threadTimelineSetsPromise = null;
|
|
397
|
-
return null;
|
|
398
|
-
}
|
|
393
|
+
async createThreadsTimelineSets() {
|
|
394
|
+
if (this.threadTimelineSetsPromise) {
|
|
395
|
+
return this.threadTimelineSetsPromise;
|
|
396
|
+
}
|
|
397
|
+
if (this.client?.supportsThreads()) {
|
|
398
|
+
try {
|
|
399
|
+
this.threadTimelineSetsPromise = Promise.all([this.createThreadTimelineSet(), this.createThreadTimelineSet(ThreadFilterType.My)]);
|
|
400
|
+
const timelineSets = await this.threadTimelineSetsPromise;
|
|
401
|
+
this.threadsTimelineSets[0] = timelineSets[0];
|
|
402
|
+
this.threadsTimelineSets[1] = timelineSets[1];
|
|
403
|
+
return timelineSets;
|
|
404
|
+
} catch {
|
|
405
|
+
this.threadTimelineSetsPromise = null;
|
|
406
|
+
return null;
|
|
399
407
|
}
|
|
400
|
-
|
|
401
|
-
|
|
408
|
+
}
|
|
409
|
+
return null;
|
|
402
410
|
}
|
|
403
411
|
|
|
404
412
|
/**
|
|
@@ -412,18 +420,15 @@ export class Room extends ReadReceipt {
|
|
|
412
420
|
*
|
|
413
421
|
* @returns Signals when all events have been decrypted
|
|
414
422
|
*/
|
|
415
|
-
decryptCriticalEvents() {
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
var decryptionPromises = events.slice(readReceiptTimelineIndex).reverse().map(event => _this3.client.decryptEventIfNeeded(event));
|
|
425
|
-
yield Promise.allSettled(decryptionPromises);
|
|
426
|
-
})();
|
|
423
|
+
async decryptCriticalEvents() {
|
|
424
|
+
if (!this.client.getCrypto()) return;
|
|
425
|
+
const readReceiptEventId = this.getEventReadUpTo(this.client.getUserId(), true);
|
|
426
|
+
const events = this.getLiveTimeline().getEvents();
|
|
427
|
+
const readReceiptTimelineIndex = events.findIndex(matrixEvent => {
|
|
428
|
+
return matrixEvent.event.event_id === readReceiptEventId;
|
|
429
|
+
});
|
|
430
|
+
const decryptionPromises = events.slice(readReceiptTimelineIndex).reverse().map(event => this.client.decryptEventIfNeeded(event));
|
|
431
|
+
await Promise.allSettled(decryptionPromises);
|
|
427
432
|
}
|
|
428
433
|
|
|
429
434
|
/**
|
|
@@ -431,14 +436,11 @@ export class Room extends ReadReceipt {
|
|
|
431
436
|
*
|
|
432
437
|
* @returns Signals when all events have been decrypted
|
|
433
438
|
*/
|
|
434
|
-
decryptAllEvents() {
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
.reverse().map(event => _this4.client.decryptEventIfNeeded(event));
|
|
440
|
-
yield Promise.allSettled(decryptionPromises);
|
|
441
|
-
})();
|
|
439
|
+
async decryptAllEvents() {
|
|
440
|
+
if (!this.client.getCrypto()) return;
|
|
441
|
+
const decryptionPromises = this.getUnfilteredTimelineSet().getLiveTimeline().getEvents().slice(0) // copy before reversing
|
|
442
|
+
.reverse().map(event => this.client.decryptEventIfNeeded(event));
|
|
443
|
+
await Promise.allSettled(decryptionPromises);
|
|
442
444
|
}
|
|
443
445
|
|
|
444
446
|
/**
|
|
@@ -446,9 +448,8 @@ export class Room extends ReadReceipt {
|
|
|
446
448
|
* @returns The creator of the room, or null if it could not be determined
|
|
447
449
|
*/
|
|
448
450
|
getCreator() {
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
return (_createEvent$getSende = createEvent === null || createEvent === void 0 ? void 0 : createEvent.getSender()) !== null && _createEvent$getSende !== void 0 ? _createEvent$getSende : null;
|
|
451
|
+
const createEvent = this.currentState.getStateEvents(EventType.RoomCreate, "");
|
|
452
|
+
return createEvent?.getSender() ?? null;
|
|
452
453
|
}
|
|
453
454
|
|
|
454
455
|
/**
|
|
@@ -470,53 +471,50 @@ export class Room extends ReadReceipt {
|
|
|
470
471
|
* @returns
|
|
471
472
|
* Resolves to the version the room should be upgraded to.
|
|
472
473
|
*/
|
|
473
|
-
getRecommendedVersion() {
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
474
|
+
async getRecommendedVersion() {
|
|
475
|
+
let capabilities = {};
|
|
476
|
+
try {
|
|
477
|
+
capabilities = await this.client.getCapabilities();
|
|
478
|
+
} catch {}
|
|
479
|
+
let versionCap = capabilities["m.room_versions"];
|
|
480
|
+
if (!versionCap) {
|
|
481
|
+
versionCap = {
|
|
482
|
+
default: KNOWN_SAFE_ROOM_VERSION,
|
|
483
|
+
available: {}
|
|
484
|
+
};
|
|
485
|
+
for (const safeVer of SAFE_ROOM_VERSIONS) {
|
|
486
|
+
versionCap.available[safeVer] = RoomVersionStability.Stable;
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
let result = this.checkVersionAgainstCapability(versionCap);
|
|
490
|
+
if (result.urgent && result.needsUpgrade) {
|
|
491
|
+
// Something doesn't feel right: we shouldn't need to update
|
|
492
|
+
// because the version we're on should be in the protocol's
|
|
493
|
+
// namespace. This usually means that the server was updated
|
|
494
|
+
// before the client was, making us think the newest possible
|
|
495
|
+
// room version is not stable. As a solution, we'll refresh
|
|
496
|
+
// the capability we're using to determine this.
|
|
497
|
+
logger.warn("Refreshing room version capability because the server looks " + "to be supporting a newer room version we don't know about.");
|
|
477
498
|
try {
|
|
478
|
-
capabilities =
|
|
479
|
-
} catch (
|
|
480
|
-
|
|
481
|
-
if (!versionCap) {
|
|
482
|
-
versionCap = {
|
|
483
|
-
default: KNOWN_SAFE_ROOM_VERSION,
|
|
484
|
-
available: {}
|
|
485
|
-
};
|
|
486
|
-
for (var safeVer of SAFE_ROOM_VERSIONS) {
|
|
487
|
-
versionCap.available[safeVer] = RoomVersionStability.Stable;
|
|
488
|
-
}
|
|
499
|
+
capabilities = await this.client.fetchCapabilities();
|
|
500
|
+
} catch (e) {
|
|
501
|
+
logger.warn("Failed to refresh room version capabilities", e);
|
|
489
502
|
}
|
|
490
|
-
|
|
491
|
-
if (
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
// room version is not stable. As a solution, we'll refresh
|
|
497
|
-
// the capability we're using to determine this.
|
|
498
|
-
logger.warn("Refreshing room version capability because the server looks " + "to be supporting a newer room version we don't know about.");
|
|
499
|
-
try {
|
|
500
|
-
capabilities = yield _this5.client.fetchCapabilities();
|
|
501
|
-
} catch (e) {
|
|
502
|
-
logger.warn("Failed to refresh room version capabilities", e);
|
|
503
|
-
}
|
|
504
|
-
versionCap = capabilities["m.room_versions"];
|
|
505
|
-
if (!versionCap) {
|
|
506
|
-
logger.warn("No room version capability - assuming upgrade required.");
|
|
507
|
-
return result;
|
|
508
|
-
} else {
|
|
509
|
-
result = _this5.checkVersionAgainstCapability(versionCap);
|
|
510
|
-
}
|
|
503
|
+
versionCap = capabilities["m.room_versions"];
|
|
504
|
+
if (!versionCap) {
|
|
505
|
+
logger.warn("No room version capability - assuming upgrade required.");
|
|
506
|
+
return result;
|
|
507
|
+
} else {
|
|
508
|
+
result = this.checkVersionAgainstCapability(versionCap);
|
|
511
509
|
}
|
|
512
|
-
|
|
513
|
-
|
|
510
|
+
}
|
|
511
|
+
return result;
|
|
514
512
|
}
|
|
515
513
|
checkVersionAgainstCapability(versionCap) {
|
|
516
|
-
|
|
517
|
-
logger.log(
|
|
518
|
-
logger.log(
|
|
519
|
-
|
|
514
|
+
const currentVersion = this.getVersion();
|
|
515
|
+
logger.log(`[${this.roomId}] Current version: ${currentVersion}`);
|
|
516
|
+
logger.log(`[${this.roomId}] Version capability: `, versionCap);
|
|
517
|
+
const result = {
|
|
520
518
|
version: currentVersion,
|
|
521
519
|
needsUpgrade: false,
|
|
522
520
|
urgent: false
|
|
@@ -524,7 +522,7 @@ export class Room extends ReadReceipt {
|
|
|
524
522
|
|
|
525
523
|
// If the room is on the default version then nothing needs to change
|
|
526
524
|
if (currentVersion === versionCap.default) return result;
|
|
527
|
-
|
|
525
|
+
const stableVersions = Object.keys(versionCap.available).filter(v => versionCap.available[v] === "stable");
|
|
528
526
|
|
|
529
527
|
// Check if the room is on an unstable version. We determine urgency based
|
|
530
528
|
// off the version being in the Matrix spec namespace or not (if the version
|
|
@@ -534,9 +532,9 @@ export class Room extends ReadReceipt {
|
|
|
534
532
|
result.needsUpgrade = true;
|
|
535
533
|
result.urgent = !!this.getVersion().match(/^[0-9]+[0-9.]*$/g);
|
|
536
534
|
if (result.urgent) {
|
|
537
|
-
logger.warn(
|
|
535
|
+
logger.warn(`URGENT upgrade required on ${this.roomId}`);
|
|
538
536
|
} else {
|
|
539
|
-
logger.warn(
|
|
537
|
+
logger.warn(`Non-urgent upgrade required on ${this.roomId}`);
|
|
540
538
|
}
|
|
541
539
|
return result;
|
|
542
540
|
}
|
|
@@ -579,7 +577,7 @@ export class Room extends ReadReceipt {
|
|
|
579
577
|
if (!this.pendingEventList) {
|
|
580
578
|
throw new Error("Cannot call removePendingEvent with pendingEventOrdering == " + this.opts.pendingEventOrdering);
|
|
581
579
|
}
|
|
582
|
-
|
|
580
|
+
const removed = removeElement(this.pendingEventList, function (ev) {
|
|
583
581
|
return ev.getId() == eventId;
|
|
584
582
|
}, false);
|
|
585
583
|
this.savePendingEvents();
|
|
@@ -593,8 +591,7 @@ export class Room extends ReadReceipt {
|
|
|
593
591
|
* @param eventId - The event ID to check for.
|
|
594
592
|
*/
|
|
595
593
|
hasPendingEvent(eventId) {
|
|
596
|
-
|
|
597
|
-
return (_this$pendingEventLis = (_this$pendingEventLis2 = this.pendingEventList) === null || _this$pendingEventLis2 === void 0 ? void 0 : _this$pendingEventLis2.some(event => event.getId() === eventId)) !== null && _this$pendingEventLis !== void 0 ? _this$pendingEventLis : false;
|
|
594
|
+
return this.pendingEventList?.some(event => event.getId() === eventId) ?? false;
|
|
598
595
|
}
|
|
599
596
|
|
|
600
597
|
/**
|
|
@@ -603,8 +600,7 @@ export class Room extends ReadReceipt {
|
|
|
603
600
|
* @param eventId - The event ID to check for.
|
|
604
601
|
*/
|
|
605
602
|
getPendingEvent(eventId) {
|
|
606
|
-
|
|
607
|
-
return (_this$pendingEventLis3 = (_this$pendingEventLis4 = this.pendingEventList) === null || _this$pendingEventLis4 === void 0 ? void 0 : _this$pendingEventLis4.find(event => event.getId() === eventId)) !== null && _this$pendingEventLis3 !== void 0 ? _this$pendingEventLis3 : null;
|
|
603
|
+
return this.pendingEventList?.find(event => event.getId() === eventId) ?? null;
|
|
608
604
|
}
|
|
609
605
|
|
|
610
606
|
/**
|
|
@@ -632,10 +628,10 @@ export class Room extends ReadReceipt {
|
|
|
632
628
|
* @returns the timestamp of the last message in the room
|
|
633
629
|
*/
|
|
634
630
|
getLastActiveTimestamp() {
|
|
635
|
-
|
|
636
|
-
|
|
631
|
+
const timeline = this.getLiveTimeline();
|
|
632
|
+
const events = timeline.getEvents();
|
|
637
633
|
if (events.length) {
|
|
638
|
-
|
|
634
|
+
const lastEvent = events[events.length - 1];
|
|
639
635
|
return lastEvent.getTs();
|
|
640
636
|
} else {
|
|
641
637
|
return Number.MIN_SAFE_INTEGER;
|
|
@@ -653,13 +649,12 @@ export class Room extends ReadReceipt {
|
|
|
653
649
|
* @returns MatrixEvent if there is a last event; else undefined.
|
|
654
650
|
*/
|
|
655
651
|
getLastLiveEvent() {
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
var lastThread = this.getLastThread();
|
|
652
|
+
const roomEvents = this.getLiveTimeline().getEvents();
|
|
653
|
+
const lastRoomEvent = roomEvents[roomEvents.length - 1];
|
|
654
|
+
const lastThread = this.getLastThread();
|
|
660
655
|
if (!lastThread) return lastRoomEvent;
|
|
661
|
-
|
|
662
|
-
return (
|
|
656
|
+
const lastThreadEvent = lastThread.events[lastThread.events.length - 1];
|
|
657
|
+
return (lastRoomEvent?.getTs() ?? 0) > (lastThreadEvent?.getTs() ?? 0) ? lastRoomEvent : lastThreadEvent;
|
|
663
658
|
}
|
|
664
659
|
|
|
665
660
|
/**
|
|
@@ -673,11 +668,10 @@ export class Room extends ReadReceipt {
|
|
|
673
668
|
*/
|
|
674
669
|
getLastThread() {
|
|
675
670
|
return this.getThreads().reduce((lastThread, thread) => {
|
|
676
|
-
var _threadEvent$getTs, _lastThreadEvent$getT2;
|
|
677
671
|
if (!lastThread) return thread;
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
if ((
|
|
672
|
+
const threadEvent = thread.events[thread.events.length - 1];
|
|
673
|
+
const lastThreadEvent = lastThread.events[lastThread.events.length - 1];
|
|
674
|
+
if ((threadEvent?.getTs() ?? 0) >= (lastThreadEvent?.getTs() ?? 0)) {
|
|
681
675
|
// Last message of current thread is newer → new last thread.
|
|
682
676
|
// Equal also means newer, because it was added to the thread map later.
|
|
683
677
|
return thread;
|
|
@@ -690,8 +684,7 @@ export class Room extends ReadReceipt {
|
|
|
690
684
|
* @returns the membership type (join | leave | invite | knock) for the logged in user
|
|
691
685
|
*/
|
|
692
686
|
getMyMembership() {
|
|
693
|
-
|
|
694
|
-
return (_this$selfMembership = this.selfMembership) !== null && _this$selfMembership !== void 0 ? _this$selfMembership : KnownMembership.Leave;
|
|
687
|
+
return this.selfMembership ?? KnownMembership.Leave;
|
|
695
688
|
}
|
|
696
689
|
|
|
697
690
|
/**
|
|
@@ -700,16 +693,15 @@ export class Room extends ReadReceipt {
|
|
|
700
693
|
* @returns user id of the inviter
|
|
701
694
|
*/
|
|
702
695
|
getDMInviter() {
|
|
703
|
-
|
|
696
|
+
const me = this.getMember(this.myUserId);
|
|
704
697
|
if (me) {
|
|
705
698
|
return me.getDMInviter();
|
|
706
699
|
}
|
|
707
700
|
if (this.selfMembership === KnownMembership.Invite) {
|
|
708
701
|
// fall back to summary information
|
|
709
|
-
|
|
702
|
+
const memberCount = this.getInvitedAndJoinedMemberCount();
|
|
710
703
|
if (memberCount === 2) {
|
|
711
|
-
|
|
712
|
-
return (_this$heroes = this.heroes) === null || _this$heroes === void 0 || (_this$heroes = _this$heroes[0]) === null || _this$heroes === void 0 ? void 0 : _this$heroes.userId;
|
|
704
|
+
return this.heroes?.[0]?.userId;
|
|
713
705
|
}
|
|
714
706
|
}
|
|
715
707
|
}
|
|
@@ -719,9 +711,9 @@ export class Room extends ReadReceipt {
|
|
|
719
711
|
* @returns user id of the other member (could be syncing user)
|
|
720
712
|
*/
|
|
721
713
|
guessDMUserId() {
|
|
722
|
-
|
|
714
|
+
const me = this.getMember(this.myUserId);
|
|
723
715
|
if (me) {
|
|
724
|
-
|
|
716
|
+
const inviterId = me.getDMInviter();
|
|
725
717
|
if (inviterId) {
|
|
726
718
|
return inviterId;
|
|
727
719
|
}
|
|
@@ -730,8 +722,8 @@ export class Room extends ReadReceipt {
|
|
|
730
722
|
if (Array.isArray(this.heroes) && this.heroes.length) {
|
|
731
723
|
return this.heroes[0].userId;
|
|
732
724
|
}
|
|
733
|
-
|
|
734
|
-
|
|
725
|
+
const members = this.currentState.getMembers();
|
|
726
|
+
const anyMember = members.find(m => m.userId !== this.myUserId);
|
|
735
727
|
if (anyMember) {
|
|
736
728
|
return anyMember.userId;
|
|
737
729
|
}
|
|
@@ -750,18 +742,17 @@ export class Room extends ReadReceipt {
|
|
|
750
742
|
* @see https://github.com/element-hq/element-meta/blob/develop/spec/functional_members.md.
|
|
751
743
|
*/
|
|
752
744
|
getFunctionalMembers() {
|
|
753
|
-
|
|
754
|
-
if (Array.isArray(mFunctionalMembers
|
|
745
|
+
const mFunctionalMembers = this.currentState.getStateEvents(UNSTABLE_ELEMENT_FUNCTIONAL_USERS.name, "");
|
|
746
|
+
if (Array.isArray(mFunctionalMembers?.getContent().service_members)) {
|
|
755
747
|
return mFunctionalMembers.getContent().service_members;
|
|
756
748
|
}
|
|
757
749
|
return [];
|
|
758
750
|
}
|
|
759
751
|
getAvatarFallbackMember() {
|
|
760
|
-
|
|
761
|
-
var functionalMembers = this.getFunctionalMembers();
|
|
752
|
+
const functionalMembers = this.getFunctionalMembers();
|
|
762
753
|
|
|
763
754
|
// Only generate a fallback avatar if the conversation is with a single specific other user (a "DM").
|
|
764
|
-
|
|
755
|
+
let nonFunctionalMemberCount = 0;
|
|
765
756
|
this.getMembers().forEach(m => {
|
|
766
757
|
if (m.membership !== "join" && m.membership !== "invite") return;
|
|
767
758
|
if (functionalMembers.includes(m.userId)) return;
|
|
@@ -770,17 +761,17 @@ export class Room extends ReadReceipt {
|
|
|
770
761
|
if (nonFunctionalMemberCount > 2) return;
|
|
771
762
|
|
|
772
763
|
// Prefer the list of heroes, if present. It should only include the single other user in the DM.
|
|
773
|
-
|
|
774
|
-
|
|
764
|
+
const nonFunctionalHeroes = this.heroes?.filter(h => !functionalMembers.includes(h.userId));
|
|
765
|
+
const hasHeroes = Array.isArray(nonFunctionalHeroes) && nonFunctionalHeroes.length;
|
|
775
766
|
if (hasHeroes) {
|
|
776
767
|
// use first hero that has a display name or avatar url, or whose user ID
|
|
777
768
|
// can be looked up as a member of the room
|
|
778
|
-
for (
|
|
769
|
+
for (const hero of nonFunctionalHeroes) {
|
|
779
770
|
// If the hero was from a legacy sync (`/v3/sync`), we will need to look the user ID up in the room
|
|
780
771
|
// the display name and avatar URL will not be set.
|
|
781
772
|
if (!hero.fromMSC4186) {
|
|
782
773
|
// attempt to look up renderable fields from the m.room.member event if it exists
|
|
783
|
-
|
|
774
|
+
const member = this.getMember(hero.userId);
|
|
784
775
|
if (member) {
|
|
785
776
|
return member;
|
|
786
777
|
}
|
|
@@ -789,7 +780,7 @@ export class Room extends ReadReceipt {
|
|
|
789
780
|
// TODO: It's unfortunate that this function, which clearly only cares about the
|
|
790
781
|
// avatar url, returns the entire RoomMember event. We need to fake an event
|
|
791
782
|
// to meet this API shape.
|
|
792
|
-
|
|
783
|
+
const heroMember = new RoomMember(this.roomId, hero.userId);
|
|
793
784
|
// set the display name and avatar url
|
|
794
785
|
heroMember.setMembershipEvent(new MatrixEvent({
|
|
795
786
|
// ensure it's unique even if we hit the same millisecond
|
|
@@ -804,7 +795,7 @@ export class Room extends ReadReceipt {
|
|
|
804
795
|
return heroMember;
|
|
805
796
|
}
|
|
806
797
|
}
|
|
807
|
-
|
|
798
|
+
const availableMember = nonFunctionalHeroes.map(hero => {
|
|
808
799
|
return this.getMember(hero.userId);
|
|
809
800
|
}).find(member => !!member);
|
|
810
801
|
if (availableMember) {
|
|
@@ -814,27 +805,27 @@ export class Room extends ReadReceipt {
|
|
|
814
805
|
|
|
815
806
|
// Consider *all*, including previous, members, to generate the avatar for DMs where the other user left.
|
|
816
807
|
// Needed to generate a matching avatar for rooms named "Empty Room (was Alice)".
|
|
817
|
-
|
|
818
|
-
|
|
808
|
+
const members = this.getMembers();
|
|
809
|
+
const nonFunctionalMembers = members?.filter(m => !functionalMembers.includes(m.userId));
|
|
819
810
|
if (nonFunctionalMembers.length <= 2) {
|
|
820
|
-
|
|
811
|
+
const availableMember = nonFunctionalMembers.find(m => {
|
|
821
812
|
return m.userId !== this.myUserId;
|
|
822
813
|
});
|
|
823
|
-
if (
|
|
824
|
-
return
|
|
814
|
+
if (availableMember) {
|
|
815
|
+
return availableMember;
|
|
825
816
|
}
|
|
826
817
|
}
|
|
827
818
|
|
|
828
819
|
// If all else failed, but the homeserver gave us heroes that previously could not be found in the room members,
|
|
829
820
|
// trust and try falling back to a hero, creating a one-off member for it
|
|
830
821
|
if (hasHeroes) {
|
|
831
|
-
|
|
822
|
+
const availableUser = nonFunctionalHeroes.map(hero => {
|
|
832
823
|
return this.client.getUser(hero.userId);
|
|
833
824
|
}).find(user => !!user);
|
|
834
825
|
if (availableUser) {
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
return
|
|
826
|
+
const member = new RoomMember(this.roomId, availableUser.userId);
|
|
827
|
+
member.user = availableUser;
|
|
828
|
+
return member;
|
|
838
829
|
}
|
|
839
830
|
}
|
|
840
831
|
}
|
|
@@ -844,7 +835,7 @@ export class Room extends ReadReceipt {
|
|
|
844
835
|
* @param membership - join | leave | invite
|
|
845
836
|
*/
|
|
846
837
|
updateMyMembership(membership) {
|
|
847
|
-
|
|
838
|
+
const prevMembership = this.selfMembership;
|
|
848
839
|
this.selfMembership = membership;
|
|
849
840
|
if (prevMembership !== membership) {
|
|
850
841
|
if (membership === KnownMembership.Leave) {
|
|
@@ -853,36 +844,30 @@ export class Room extends ReadReceipt {
|
|
|
853
844
|
this.emit(RoomEvent.MyMembership, this, membership, prevMembership);
|
|
854
845
|
}
|
|
855
846
|
}
|
|
856
|
-
loadMembersFromServer() {
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
var memberEvents = rawMembersEvents.filter(noUnsafeEventProps).map(_this7.client.getEventMapper());
|
|
881
|
-
return {
|
|
882
|
-
memberEvents,
|
|
883
|
-
fromServer
|
|
884
|
-
};
|
|
885
|
-
})();
|
|
847
|
+
async loadMembersFromServer() {
|
|
848
|
+
const lastSyncToken = this.client.store.getSyncToken();
|
|
849
|
+
const response = await this.client.members(this.roomId, undefined, KnownMembership.Leave, lastSyncToken ?? undefined);
|
|
850
|
+
return response.chunk;
|
|
851
|
+
}
|
|
852
|
+
async loadMembers() {
|
|
853
|
+
// were the members loaded from the server?
|
|
854
|
+
let fromServer = false;
|
|
855
|
+
let rawMembersEvents = await this.client.store.getOutOfBandMembers(this.roomId);
|
|
856
|
+
// If the room is encrypted, we always fetch members from the server at
|
|
857
|
+
// least once, in case the latest state wasn't persisted properly. Note
|
|
858
|
+
// that this function is only called once (unless loading the members
|
|
859
|
+
// fails), since loadMembersIfNeeded always returns this.membersPromise
|
|
860
|
+
// if set, which will be the result of the first (successful) call.
|
|
861
|
+
if (rawMembersEvents === null || this.hasEncryptionStateEvent()) {
|
|
862
|
+
fromServer = true;
|
|
863
|
+
rawMembersEvents = await this.loadMembersFromServer();
|
|
864
|
+
logger.log(`LL: got ${rawMembersEvents.length} ` + `members from server for room ${this.roomId}`);
|
|
865
|
+
}
|
|
866
|
+
const memberEvents = rawMembersEvents.filter(noUnsafeEventProps).map(this.client.getEventMapper());
|
|
867
|
+
return {
|
|
868
|
+
memberEvents,
|
|
869
|
+
fromServer
|
|
870
|
+
};
|
|
886
871
|
}
|
|
887
872
|
|
|
888
873
|
/**
|
|
@@ -915,7 +900,7 @@ export class Room extends ReadReceipt {
|
|
|
915
900
|
// the request is in flight get marked as superseding
|
|
916
901
|
// the OOB members
|
|
917
902
|
this.currentState.markOutOfBandMembersStarted();
|
|
918
|
-
|
|
903
|
+
const inMemoryUpdate = this.loadMembers().then(result => {
|
|
919
904
|
this.currentState.setOutOfBandMembers(result.memberEvents);
|
|
920
905
|
// recalculate the room name: it may have been based on members, so may have changed
|
|
921
906
|
this.recalculate();
|
|
@@ -929,12 +914,9 @@ export class Room extends ReadReceipt {
|
|
|
929
914
|
// update members in storage, but don't wait for it
|
|
930
915
|
inMemoryUpdate.then(fromServer => {
|
|
931
916
|
if (fromServer) {
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
});
|
|
936
|
-
logger.log("LL: telling store to write ".concat(oobMembers.length) + " members for room ".concat(this.roomId));
|
|
937
|
-
var store = this.client.store;
|
|
917
|
+
const oobMembers = this.currentState.getMembers().filter(m => m.isOutOfBand()).map(m => m.events.member?.event);
|
|
918
|
+
logger.log(`LL: telling store to write ${oobMembers.length}` + ` members for room ${this.roomId}`);
|
|
919
|
+
const store = this.client.store;
|
|
938
920
|
return store.setOutOfBandMembers(this.roomId, oobMembers)
|
|
939
921
|
// swallow any IDB error as we don't want to fail
|
|
940
922
|
// because of this
|
|
@@ -954,16 +936,13 @@ export class Room extends ReadReceipt {
|
|
|
954
936
|
/**
|
|
955
937
|
* Removes the lazily loaded members from storage if needed
|
|
956
938
|
*/
|
|
957
|
-
clearLoadedMembersIfNeeded() {
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
_this8.membersPromise = undefined;
|
|
965
|
-
}
|
|
966
|
-
})();
|
|
939
|
+
async clearLoadedMembersIfNeeded() {
|
|
940
|
+
if (this.opts.lazyLoadMembers && this.membersPromise) {
|
|
941
|
+
await this.loadMembersIfNeeded();
|
|
942
|
+
await this.client.store.clearOutOfBandMembers(this.roomId);
|
|
943
|
+
this.currentState.clearOutOfBandMembers();
|
|
944
|
+
this.membersPromise = undefined;
|
|
945
|
+
}
|
|
967
946
|
}
|
|
968
947
|
|
|
969
948
|
/**
|
|
@@ -972,7 +951,7 @@ export class Room extends ReadReceipt {
|
|
|
972
951
|
*/
|
|
973
952
|
cleanupAfterLeaving() {
|
|
974
953
|
this.clearLoadedMembersIfNeeded().catch(err => {
|
|
975
|
-
logger.error(
|
|
954
|
+
logger.error(`error after clearing loaded members from ` + `room ${this.roomId} after leaving`);
|
|
976
955
|
logger.log(err);
|
|
977
956
|
});
|
|
978
957
|
}
|
|
@@ -990,81 +969,78 @@ export class Room extends ReadReceipt {
|
|
|
990
969
|
* valid marker and can check the needs refresh status via
|
|
991
970
|
* `room.getTimelineNeedsRefresh()`.
|
|
992
971
|
*/
|
|
993
|
-
refreshLiveTimeline() {
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
logger.log("[refreshLiveTimeline for ".concat(_this9.roomId, "] `/sync` or some other request beat us to creating a new ") + "live timeline after we reset it. We'll use that instead since any events in the scrollback from " + "this timeline will include the history.");
|
|
1059
|
-
}
|
|
972
|
+
async refreshLiveTimeline() {
|
|
973
|
+
const liveTimelineBefore = this.getLiveTimeline();
|
|
974
|
+
const forwardPaginationToken = liveTimelineBefore.getPaginationToken(EventTimeline.FORWARDS);
|
|
975
|
+
const backwardPaginationToken = liveTimelineBefore.getPaginationToken(EventTimeline.BACKWARDS);
|
|
976
|
+
const eventsBefore = liveTimelineBefore.getEvents();
|
|
977
|
+
const mostRecentEventInTimeline = eventsBefore[eventsBefore.length - 1];
|
|
978
|
+
logger.log(`[refreshLiveTimeline for ${this.roomId}] at ` + `mostRecentEventInTimeline=${mostRecentEventInTimeline && mostRecentEventInTimeline.getId()} ` + `liveTimelineBefore=${liveTimelineBefore.toString()} ` + `forwardPaginationToken=${forwardPaginationToken} ` + `backwardPaginationToken=${backwardPaginationToken}`);
|
|
979
|
+
|
|
980
|
+
// Get the main TimelineSet
|
|
981
|
+
const timelineSet = this.getUnfilteredTimelineSet();
|
|
982
|
+
let newTimeline = null;
|
|
983
|
+
// If there isn't any event in the timeline, let's go fetch the latest
|
|
984
|
+
// event and construct a timeline from it.
|
|
985
|
+
//
|
|
986
|
+
// This should only really happen if the user ran into an error
|
|
987
|
+
// with refreshing the timeline before which left them in a blank
|
|
988
|
+
// timeline from `resetLiveTimeline`.
|
|
989
|
+
if (!mostRecentEventInTimeline) {
|
|
990
|
+
newTimeline = await this.client.getLatestTimeline(timelineSet);
|
|
991
|
+
} else {
|
|
992
|
+
// Empty out all of `this.timelineSets`. But we also need to keep the
|
|
993
|
+
// same `timelineSet` references around so the React code updates
|
|
994
|
+
// properly and doesn't ignore the room events we emit because it checks
|
|
995
|
+
// that the `timelineSet` references are the same. We need the
|
|
996
|
+
// `timelineSet` empty so that the `client.getEventTimeline(...)` call
|
|
997
|
+
// later, will call `/context` and create a new timeline instead of
|
|
998
|
+
// returning the same one.
|
|
999
|
+
this.resetLiveTimeline(null, null);
|
|
1000
|
+
|
|
1001
|
+
// Make the UI timeline show the new blank live timeline we just
|
|
1002
|
+
// reset so that if the network fails below it's showing the
|
|
1003
|
+
// accurate state of what we're working with instead of the
|
|
1004
|
+
// disconnected one in the TimelineWindow which is just hanging
|
|
1005
|
+
// around by reference.
|
|
1006
|
+
this.emit(RoomEvent.TimelineRefresh, this, timelineSet);
|
|
1007
|
+
|
|
1008
|
+
// Use `client.getEventTimeline(...)` to construct a new timeline from a
|
|
1009
|
+
// `/context` response state and events for the most recent event before
|
|
1010
|
+
// we reset everything. The `timelineSet` we pass in needs to be empty
|
|
1011
|
+
// in order for this function to call `/context` and generate a new
|
|
1012
|
+
// timeline.
|
|
1013
|
+
newTimeline = await this.client.getEventTimeline(timelineSet, mostRecentEventInTimeline.getId());
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
// If a racing `/sync` beat us to creating a new timeline, use that
|
|
1017
|
+
// instead because it's the latest in the room and any new messages in
|
|
1018
|
+
// the scrollback will include the history.
|
|
1019
|
+
const liveTimeline = timelineSet.getLiveTimeline();
|
|
1020
|
+
if (!liveTimeline || liveTimeline.getPaginationToken(Direction.Forward) === null && liveTimeline.getPaginationToken(Direction.Backward) === null && liveTimeline.getEvents().length === 0) {
|
|
1021
|
+
logger.log(`[refreshLiveTimeline for ${this.roomId}] using our new live timeline`);
|
|
1022
|
+
// Set the pagination token back to the live sync token (`null`) instead
|
|
1023
|
+
// of using the `/context` historical token (ex. `t12-13_0_0_0_0_0_0_0_0`)
|
|
1024
|
+
// so that it matches the next response from `/sync` and we can properly
|
|
1025
|
+
// continue the timeline.
|
|
1026
|
+
newTimeline.setPaginationToken(forwardPaginationToken, EventTimeline.FORWARDS);
|
|
1027
|
+
|
|
1028
|
+
// Set our new fresh timeline as the live timeline to continue syncing
|
|
1029
|
+
// forwards and back paginating from.
|
|
1030
|
+
timelineSet.setLiveTimeline(newTimeline);
|
|
1031
|
+
// Fixup `this.oldstate` so that `scrollback` has the pagination tokens
|
|
1032
|
+
// available
|
|
1033
|
+
this.fixUpLegacyTimelineFields();
|
|
1034
|
+
} else {
|
|
1035
|
+
logger.log(`[refreshLiveTimeline for ${this.roomId}] \`/sync\` or some other request beat us to creating a new ` + `live timeline after we reset it. We'll use that instead since any events in the scrollback from ` + `this timeline will include the history.`);
|
|
1036
|
+
}
|
|
1060
1037
|
|
|
1061
|
-
|
|
1062
|
-
|
|
1038
|
+
// The timeline has now been refreshed ✅
|
|
1039
|
+
this.setTimelineNeedsRefresh(false);
|
|
1063
1040
|
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
})();
|
|
1041
|
+
// Emit an event which clients can react to and re-load the timeline
|
|
1042
|
+
// from the SDK
|
|
1043
|
+
this.emit(RoomEvent.TimelineRefresh, this, timelineSet);
|
|
1068
1044
|
}
|
|
1069
1045
|
|
|
1070
1046
|
/**
|
|
@@ -1079,10 +1055,10 @@ export class Room extends ReadReceipt {
|
|
|
1079
1055
|
* Removing just the old live timeline whilst preserving previous ones is not supported.
|
|
1080
1056
|
*/
|
|
1081
1057
|
resetLiveTimeline(backPaginationToken, forwardPaginationToken) {
|
|
1082
|
-
for (
|
|
1083
|
-
timelineSet.resetLiveTimeline(backPaginationToken
|
|
1058
|
+
for (const timelineSet of this.timelineSets) {
|
|
1059
|
+
timelineSet.resetLiveTimeline(backPaginationToken ?? undefined, forwardPaginationToken ?? undefined);
|
|
1084
1060
|
}
|
|
1085
|
-
for (
|
|
1061
|
+
for (const thread of this.threads.values()) {
|
|
1086
1062
|
thread.resetLiveTimeline(backPaginationToken, forwardPaginationToken);
|
|
1087
1063
|
}
|
|
1088
1064
|
this.fixUpLegacyTimelineFields();
|
|
@@ -1094,8 +1070,8 @@ export class Room extends ReadReceipt {
|
|
|
1094
1070
|
* @internal
|
|
1095
1071
|
*/
|
|
1096
1072
|
fixUpLegacyTimelineFields() {
|
|
1097
|
-
|
|
1098
|
-
|
|
1073
|
+
const previousOldState = this.oldState;
|
|
1074
|
+
const previousCurrentState = this.currentState;
|
|
1099
1075
|
|
|
1100
1076
|
// maintain this.oldState and this.currentState as references to the
|
|
1101
1077
|
// state at the start and end of that timeline. These are more
|
|
@@ -1119,11 +1095,6 @@ export class Room extends ReadReceipt {
|
|
|
1119
1095
|
this.reEmitter.reEmit(this.currentState, [RoomStateEvent.Events, RoomStateEvent.Members, RoomStateEvent.NewMember, RoomStateEvent.Update, RoomStateEvent.Marker, BeaconEvent.New, BeaconEvent.Update, BeaconEvent.Destroy, BeaconEvent.LivenessChange]);
|
|
1120
1096
|
}
|
|
1121
1097
|
}
|
|
1122
|
-
onReceipt(event) {
|
|
1123
|
-
if (this.hasEncryptionStateEvent()) {
|
|
1124
|
-
this.clearNotificationsOnReceipt(event);
|
|
1125
|
-
}
|
|
1126
|
-
}
|
|
1127
1098
|
clearNotificationsOnReceipt(event) {
|
|
1128
1099
|
// Like above, we have to listen for read receipts from ourselves in order to
|
|
1129
1100
|
// correctly handle notification counts on encrypted rooms.
|
|
@@ -1133,22 +1104,16 @@ export class Room extends ReadReceipt {
|
|
|
1133
1104
|
// We need to work out what threads we've just recieved receipts for, so we
|
|
1134
1105
|
// know which ones to update. If we've received an unthreaded receipt, we'll
|
|
1135
1106
|
// need to update all threads.
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
for (
|
|
1140
|
-
for (
|
|
1141
|
-
var _ref3 = _slicedToArray(_ref4, 2);
|
|
1142
|
-
var receiptType = _ref3[0];
|
|
1143
|
-
var userReceipt = _ref3[1];
|
|
1107
|
+
let threadIds = [];
|
|
1108
|
+
let hasUnthreadedReceipt = false;
|
|
1109
|
+
const content = event.getContent();
|
|
1110
|
+
for (const receiptGroup of Object.values(content)) {
|
|
1111
|
+
for (const [receiptType, userReceipt] of Object.entries(receiptGroup)) {
|
|
1144
1112
|
if (!utils.isSupportedReceiptType(receiptType)) continue;
|
|
1145
1113
|
if (!userReceipt) continue;
|
|
1146
|
-
for (
|
|
1147
|
-
var _ref6 = _slicedToArray(_ref7, 2);
|
|
1148
|
-
var userId = _ref6[0];
|
|
1149
|
-
var singleReceipt = _ref6[1];
|
|
1114
|
+
for (const [userId, singleReceipt] of Object.entries(userReceipt)) {
|
|
1150
1115
|
if (!singleReceipt || typeof singleReceipt !== "object") continue;
|
|
1151
|
-
|
|
1116
|
+
const typedSingleReceipt = singleReceipt;
|
|
1152
1117
|
if (userId !== this.client.getUserId()) continue;
|
|
1153
1118
|
if (typedSingleReceipt.thread_id === undefined) {
|
|
1154
1119
|
hasUnthreadedReceipt = true;
|
|
@@ -1165,30 +1130,28 @@ export class Room extends ReadReceipt {
|
|
|
1165
1130
|
threadIds = this.getThreads().filter(thread => this.getThreadUnreadNotificationCount(thread.id, NotificationCountType.Total) > 0 || this.getThreadUnreadNotificationCount(thread.id, NotificationCountType.Highlight) > 0).map(thread => thread.id);
|
|
1166
1131
|
threadIds.push("main");
|
|
1167
1132
|
}
|
|
1168
|
-
for (
|
|
1169
|
-
var _this$getThread;
|
|
1133
|
+
for (const threadId of threadIds) {
|
|
1170
1134
|
// Work backwards to determine how many events are unread. We also set
|
|
1171
1135
|
// a limit for how back we'll look to avoid spinning CPU for too long.
|
|
1172
1136
|
// If we hit the limit, we assume the count is unchanged.
|
|
1173
|
-
|
|
1174
|
-
|
|
1137
|
+
const maxHistory = 20;
|
|
1138
|
+
const timeline = threadId === "main" ? this.getLiveTimeline() : this.getThread(threadId)?.liveTimeline;
|
|
1175
1139
|
if (!timeline) {
|
|
1176
|
-
logger.warn(
|
|
1140
|
+
logger.warn(`Couldn't find timeline for thread ID ${threadId} in room ${this.roomId}`);
|
|
1177
1141
|
continue;
|
|
1178
1142
|
}
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
for (
|
|
1182
|
-
var _pushActions$tweaks;
|
|
1143
|
+
const events = timeline.getEvents();
|
|
1144
|
+
let highlightCount = 0;
|
|
1145
|
+
for (let i = events.length - 1; i >= 0; i--) {
|
|
1183
1146
|
if (i === events.length - maxHistory) return; // limit reached
|
|
1184
1147
|
|
|
1185
|
-
|
|
1186
|
-
if (this.hasUserReadEvent(this.client.getUserId(),
|
|
1148
|
+
const event = events[i];
|
|
1149
|
+
if (this.hasUserReadEvent(this.client.getUserId(), event.getId())) {
|
|
1187
1150
|
// If the user has read the event, then the counting is done.
|
|
1188
1151
|
break;
|
|
1189
1152
|
}
|
|
1190
|
-
|
|
1191
|
-
highlightCount += pushActions
|
|
1153
|
+
const pushActions = this.client.getPushActionsForEvent(event);
|
|
1154
|
+
highlightCount += pushActions?.tweaks?.highlight ? 1 : 0;
|
|
1192
1155
|
}
|
|
1193
1156
|
|
|
1194
1157
|
// Note: we don't need to handle 'total' notifications because the counts
|
|
@@ -1225,8 +1188,8 @@ export class Room extends ReadReceipt {
|
|
|
1225
1188
|
* the given event, or null if unknown
|
|
1226
1189
|
*/
|
|
1227
1190
|
getTimelineForEvent(eventId) {
|
|
1228
|
-
|
|
1229
|
-
|
|
1191
|
+
const event = this.findEventById(eventId);
|
|
1192
|
+
const thread = this.findThreadForEvent(event);
|
|
1230
1193
|
if (thread) {
|
|
1231
1194
|
return thread.timelineSet.getTimelineForEvent(eventId);
|
|
1232
1195
|
} else {
|
|
@@ -1268,11 +1231,11 @@ export class Room extends ReadReceipt {
|
|
|
1268
1231
|
* @returns the given event, or undefined if unknown
|
|
1269
1232
|
*/
|
|
1270
1233
|
findEventById(eventId) {
|
|
1271
|
-
|
|
1234
|
+
let event = this.getUnfilteredTimelineSet().findEventById(eventId);
|
|
1272
1235
|
if (!event) {
|
|
1273
|
-
|
|
1274
|
-
for (
|
|
1275
|
-
|
|
1236
|
+
const threads = this.getThreads();
|
|
1237
|
+
for (let i = 0; i < threads.length; i++) {
|
|
1238
|
+
const thread = threads[i];
|
|
1276
1239
|
event = thread.findEventById(eventId);
|
|
1277
1240
|
if (event) {
|
|
1278
1241
|
return event;
|
|
@@ -1288,12 +1251,10 @@ export class Room extends ReadReceipt {
|
|
|
1288
1251
|
* @returns The notification count, or undefined if there is no count
|
|
1289
1252
|
* for this type.
|
|
1290
1253
|
*/
|
|
1291
|
-
getUnreadNotificationCount() {
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
var _threadNotification$t;
|
|
1296
|
-
count += (_threadNotification$t = threadNotification[type]) !== null && _threadNotification$t !== void 0 ? _threadNotification$t : 0;
|
|
1254
|
+
getUnreadNotificationCount(type = NotificationCountType.Total) {
|
|
1255
|
+
let count = this.getRoomUnreadNotificationCount(type);
|
|
1256
|
+
for (const threadNotification of this.threadNotifications.values()) {
|
|
1257
|
+
count += threadNotification[type] ?? 0;
|
|
1297
1258
|
}
|
|
1298
1259
|
return count;
|
|
1299
1260
|
}
|
|
@@ -1301,12 +1262,9 @@ export class Room extends ReadReceipt {
|
|
|
1301
1262
|
/**
|
|
1302
1263
|
* Get the notification for the event context (room or thread timeline)
|
|
1303
1264
|
*/
|
|
1304
|
-
getUnreadCountForEventContext() {
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
var event = arguments.length > 1 ? arguments[1] : undefined;
|
|
1308
|
-
var isThreadEvent = !!event.threadRootId && !event.isThreadRoot;
|
|
1309
|
-
return (_ref8 = isThreadEvent ? this.getThreadUnreadNotificationCount(event.threadRootId, type) : this.getRoomUnreadNotificationCount(type)) !== null && _ref8 !== void 0 ? _ref8 : 0;
|
|
1265
|
+
getUnreadCountForEventContext(type = NotificationCountType.Total, event) {
|
|
1266
|
+
const isThreadEvent = !!event.threadRootId && !event.isThreadRoot;
|
|
1267
|
+
return (isThreadEvent ? this.getThreadUnreadNotificationCount(event.threadRootId, type) : this.getRoomUnreadNotificationCount(type)) ?? 0;
|
|
1310
1268
|
}
|
|
1311
1269
|
|
|
1312
1270
|
/**
|
|
@@ -1315,10 +1273,8 @@ export class Room extends ReadReceipt {
|
|
|
1315
1273
|
* @returns The notification count, or undefined if there is no count
|
|
1316
1274
|
* for this type.
|
|
1317
1275
|
*/
|
|
1318
|
-
getRoomUnreadNotificationCount() {
|
|
1319
|
-
|
|
1320
|
-
var type = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : NotificationCountType.Total;
|
|
1321
|
-
return (_this$notificationCou = this.notificationCounts[type]) !== null && _this$notificationCou !== void 0 ? _this$notificationCou : 0;
|
|
1276
|
+
getRoomUnreadNotificationCount(type = NotificationCountType.Total) {
|
|
1277
|
+
return this.notificationCounts[type] ?? 0;
|
|
1322
1278
|
}
|
|
1323
1279
|
|
|
1324
1280
|
/**
|
|
@@ -1328,10 +1284,8 @@ export class Room extends ReadReceipt {
|
|
|
1328
1284
|
* @returns The notification count, or undefined if there is no count
|
|
1329
1285
|
* for this type.
|
|
1330
1286
|
*/
|
|
1331
|
-
getThreadUnreadNotificationCount(threadId) {
|
|
1332
|
-
|
|
1333
|
-
var type = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : NotificationCountType.Total;
|
|
1334
|
-
return (_this$threadNotificat = (_this$threadNotificat2 = this.threadNotifications.get(threadId)) === null || _this$threadNotificat2 === void 0 ? void 0 : _this$threadNotificat2[type]) !== null && _this$threadNotificat !== void 0 ? _this$threadNotificat : 0;
|
|
1287
|
+
getThreadUnreadNotificationCount(threadId, type = NotificationCountType.Total) {
|
|
1288
|
+
return this.threadNotifications.get(threadId)?.[type] ?? 0;
|
|
1335
1289
|
}
|
|
1336
1290
|
|
|
1337
1291
|
/**
|
|
@@ -1339,9 +1293,8 @@ export class Room extends ReadReceipt {
|
|
|
1339
1293
|
* @returns
|
|
1340
1294
|
*/
|
|
1341
1295
|
hasThreadUnreadNotification() {
|
|
1342
|
-
for (
|
|
1343
|
-
|
|
1344
|
-
if (((_notification$highlig = notification.highlight) !== null && _notification$highlig !== void 0 ? _notification$highlig : 0) > 0 || ((_notification$total = notification.total) !== null && _notification$total !== void 0 ? _notification$total : 0) > 0) {
|
|
1296
|
+
for (const notification of this.threadNotifications.values()) {
|
|
1297
|
+
if ((notification.highlight ?? 0) > 0 || (notification.total ?? 0) > 0) {
|
|
1345
1298
|
return true;
|
|
1346
1299
|
}
|
|
1347
1300
|
}
|
|
@@ -1355,13 +1308,11 @@ export class Room extends ReadReceipt {
|
|
|
1355
1308
|
* @returns
|
|
1356
1309
|
*/
|
|
1357
1310
|
setThreadUnreadNotificationCount(threadId, type, count) {
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
total: (_this$threadNotificat4 = this.threadNotifications.get(threadId)) === null || _this$threadNotificat4 === void 0 ? void 0 : _this$threadNotificat4.total
|
|
1362
|
-
}, {
|
|
1311
|
+
const notification = {
|
|
1312
|
+
highlight: this.threadNotifications.get(threadId)?.highlight,
|
|
1313
|
+
total: this.threadNotifications.get(threadId)?.total,
|
|
1363
1314
|
[type]: count
|
|
1364
|
-
}
|
|
1315
|
+
};
|
|
1365
1316
|
this.threadNotifications.set(threadId, notification);
|
|
1366
1317
|
this.emit(RoomEvent.UnreadNotifications, notification, threadId);
|
|
1367
1318
|
}
|
|
@@ -1370,12 +1321,11 @@ export class Room extends ReadReceipt {
|
|
|
1370
1321
|
* @returns the notification count type for all the threads in the room
|
|
1371
1322
|
*/
|
|
1372
1323
|
get threadsAggregateNotificationType() {
|
|
1373
|
-
|
|
1374
|
-
for (
|
|
1375
|
-
|
|
1376
|
-
if (((_threadNotification$h = threadNotification.highlight) !== null && _threadNotification$h !== void 0 ? _threadNotification$h : 0) > 0) {
|
|
1324
|
+
let type = null;
|
|
1325
|
+
for (const threadNotification of this.threadNotifications.values()) {
|
|
1326
|
+
if ((threadNotification.highlight ?? 0) > 0) {
|
|
1377
1327
|
return NotificationCountType.Highlight;
|
|
1378
|
-
} else if ((
|
|
1328
|
+
} else if ((threadNotification.total ?? 0) > 0 && !type) {
|
|
1379
1329
|
type = NotificationCountType.Total;
|
|
1380
1330
|
}
|
|
1381
1331
|
}
|
|
@@ -1396,13 +1346,9 @@ export class Room extends ReadReceipt {
|
|
|
1396
1346
|
*
|
|
1397
1347
|
* @param exceptThreadIds - The thread IDs to exclude from the reset.
|
|
1398
1348
|
*/
|
|
1399
|
-
resetThreadUnreadNotificationCountFromSync() {
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
for (var _ref1 of this.threadNotifications) {
|
|
1403
|
-
var _ref0 = _slicedToArray(_ref1, 2);
|
|
1404
|
-
var threadId = _ref0[0];
|
|
1405
|
-
var notifs = _ref0[1];
|
|
1349
|
+
resetThreadUnreadNotificationCountFromSync(exceptThreadIds = []) {
|
|
1350
|
+
const isEncrypted = this.hasEncryptionStateEvent();
|
|
1351
|
+
for (const [threadId, notifs] of this.threadNotifications) {
|
|
1406
1352
|
if (!exceptThreadIds.includes(threadId)) {
|
|
1407
1353
|
notifs.total = 0;
|
|
1408
1354
|
if (!isEncrypted) {
|
|
@@ -1450,13 +1396,12 @@ export class Room extends ReadReceipt {
|
|
|
1450
1396
|
* @param summary - The room summary to update the room with
|
|
1451
1397
|
*/
|
|
1452
1398
|
setSummary(summary) {
|
|
1453
|
-
|
|
1454
|
-
var heroes = (_summary$mHeroes = summary["m.heroes"]) === null || _summary$mHeroes === void 0 ? void 0 : _summary$mHeroes.map(h => ({
|
|
1399
|
+
const heroes = summary["m.heroes"]?.map(h => ({
|
|
1455
1400
|
userId: h,
|
|
1456
1401
|
fromMSC4186: false
|
|
1457
1402
|
}));
|
|
1458
|
-
|
|
1459
|
-
|
|
1403
|
+
const joinedCount = summary["m.joined_member_count"];
|
|
1404
|
+
const invitedCount = summary["m.invited_member_count"];
|
|
1460
1405
|
if (Number.isInteger(joinedCount)) {
|
|
1461
1406
|
this.currentState.setJoinedMemberCount(joinedCount);
|
|
1462
1407
|
}
|
|
@@ -1540,10 +1485,8 @@ export class Room extends ReadReceipt {
|
|
|
1540
1485
|
* implies allowRedirects. Defaults to false (unauthenticated endpoints).
|
|
1541
1486
|
* @returns the avatar URL or null.
|
|
1542
1487
|
*/
|
|
1543
|
-
getAvatarUrl(baseUrl, width, height, resizeMethod) {
|
|
1544
|
-
|
|
1545
|
-
var useAuthentication = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : false;
|
|
1546
|
-
var mainUrl = this.getMxcAvatarUrl();
|
|
1488
|
+
getAvatarUrl(baseUrl, width, height, resizeMethod, allowDefault = true, useAuthentication = false) {
|
|
1489
|
+
const mainUrl = this.getMxcAvatarUrl();
|
|
1547
1490
|
if (!mainUrl && !allowDefault) {
|
|
1548
1491
|
return null;
|
|
1549
1492
|
}
|
|
@@ -1558,8 +1501,7 @@ export class Room extends ReadReceipt {
|
|
|
1558
1501
|
* @returns the mxc avatar url or falsy
|
|
1559
1502
|
*/
|
|
1560
1503
|
getMxcAvatarUrl() {
|
|
1561
|
-
|
|
1562
|
-
var url = (_this$currentState$ge = this.currentState.getStateEvents(EventType.RoomAvatar, "")) === null || _this$currentState$ge === void 0 ? void 0 : _this$currentState$ge.getContent().url;
|
|
1504
|
+
const url = this.currentState.getStateEvents(EventType.RoomAvatar, "")?.getContent().url;
|
|
1563
1505
|
return url && typeof url === "string" ? url : null;
|
|
1564
1506
|
}
|
|
1565
1507
|
|
|
@@ -1570,8 +1512,7 @@ export class Room extends ReadReceipt {
|
|
|
1570
1512
|
* @returns The room's canonical alias, or null if there is none
|
|
1571
1513
|
*/
|
|
1572
1514
|
getCanonicalAlias() {
|
|
1573
|
-
|
|
1574
|
-
var canonicalAlias = (_this$currentState$ge2 = this.currentState.getStateEvents(EventType.RoomCanonicalAlias, "")) === null || _this$currentState$ge2 === void 0 ? void 0 : _this$currentState$ge2.getContent().alias;
|
|
1515
|
+
const canonicalAlias = this.currentState.getStateEvents(EventType.RoomCanonicalAlias, "")?.getContent().alias;
|
|
1575
1516
|
return canonicalAlias && typeof canonicalAlias === "string" ? canonicalAlias : null;
|
|
1576
1517
|
}
|
|
1577
1518
|
|
|
@@ -1580,8 +1521,7 @@ export class Room extends ReadReceipt {
|
|
|
1580
1521
|
* @returns The room's alternative aliases, or an empty array
|
|
1581
1522
|
*/
|
|
1582
1523
|
getAltAliases() {
|
|
1583
|
-
|
|
1584
|
-
var altAliases = (_this$currentState$ge3 = this.currentState.getStateEvents(EventType.RoomCanonicalAlias, "")) === null || _this$currentState$ge3 === void 0 ? void 0 : _this$currentState$ge3.getContent().alt_aliases;
|
|
1524
|
+
const altAliases = this.currentState.getStateEvents(EventType.RoomCanonicalAlias, "")?.getContent().alt_aliases;
|
|
1585
1525
|
if (Array.isArray(altAliases)) {
|
|
1586
1526
|
return altAliases.filter(alias => typeof alias === "string");
|
|
1587
1527
|
}
|
|
@@ -1609,10 +1549,7 @@ export class Room extends ReadReceipt {
|
|
|
1609
1549
|
*/
|
|
1610
1550
|
addEventsToTimeline(events, toStartOfTimeline, addToState, timeline, paginationToken) {
|
|
1611
1551
|
// ALWAYS filter out any events that are past retention
|
|
1612
|
-
events = events.filter(e =>
|
|
1613
|
-
var _this$retention$shoul, _this$retention;
|
|
1614
|
-
return (_this$retention$shoul = (_this$retention = this.retention) === null || _this$retention === void 0 ? void 0 : _this$retention.shouldEventBeRetained(e)) !== null && _this$retention$shoul !== void 0 ? _this$retention$shoul : true;
|
|
1615
|
-
});
|
|
1552
|
+
events = events.filter(e => this.retention?.shouldEventBeRetained(e) ?? true);
|
|
1616
1553
|
timeline.getTimelineSet().addEventsToTimeline(events, toStartOfTimeline, addToState, timeline, paginationToken);
|
|
1617
1554
|
}
|
|
1618
1555
|
|
|
@@ -1622,8 +1559,7 @@ export class Room extends ReadReceipt {
|
|
|
1622
1559
|
* @returns a thread instance if known
|
|
1623
1560
|
*/
|
|
1624
1561
|
getThread(eventId) {
|
|
1625
|
-
|
|
1626
|
-
return (_this$threads$get = this.threads.get(eventId)) !== null && _this$threads$get !== void 0 ? _this$threads$get : null;
|
|
1562
|
+
return this.threads.get(eventId) ?? null;
|
|
1627
1563
|
}
|
|
1628
1564
|
|
|
1629
1565
|
/**
|
|
@@ -1702,16 +1638,13 @@ export class Room extends ReadReceipt {
|
|
|
1702
1638
|
* @returns A list of members who
|
|
1703
1639
|
* we should encrypt messages for in this room.
|
|
1704
1640
|
*/
|
|
1705
|
-
getEncryptionTargetMembers() {
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
}
|
|
1713
|
-
return members;
|
|
1714
|
-
})();
|
|
1641
|
+
async getEncryptionTargetMembers() {
|
|
1642
|
+
await this.loadMembersIfNeeded();
|
|
1643
|
+
let members = this.getMembersWithMembership(KnownMembership.Join);
|
|
1644
|
+
if (this.shouldEncryptForInvitedMembers()) {
|
|
1645
|
+
members = members.concat(this.getMembersWithMembership(KnownMembership.Invite));
|
|
1646
|
+
}
|
|
1647
|
+
return members;
|
|
1715
1648
|
}
|
|
1716
1649
|
|
|
1717
1650
|
/**
|
|
@@ -1719,9 +1652,8 @@ export class Room extends ReadReceipt {
|
|
|
1719
1652
|
* @returns if we should encrypt messages for invited users
|
|
1720
1653
|
*/
|
|
1721
1654
|
shouldEncryptForInvitedMembers() {
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
return (ev === null || ev === void 0 || (_ev$getContent = ev.getContent()) === null || _ev$getContent === void 0 ? void 0 : _ev$getContent.history_visibility) !== "joined";
|
|
1655
|
+
const ev = this.currentState.getStateEvents(EventType.RoomHistoryVisibility, "");
|
|
1656
|
+
return ev?.getContent()?.history_visibility !== "joined";
|
|
1725
1657
|
}
|
|
1726
1658
|
|
|
1727
1659
|
/**
|
|
@@ -1742,7 +1674,7 @@ export class Room extends ReadReceipt {
|
|
|
1742
1674
|
* @returns True if this user_id has the given membership state.
|
|
1743
1675
|
*/
|
|
1744
1676
|
hasMembershipState(userId, membership) {
|
|
1745
|
-
|
|
1677
|
+
const member = this.getMember(userId);
|
|
1746
1678
|
if (!member) {
|
|
1747
1679
|
return false;
|
|
1748
1680
|
}
|
|
@@ -1755,28 +1687,25 @@ export class Room extends ReadReceipt {
|
|
|
1755
1687
|
* @param opts - Configuration options
|
|
1756
1688
|
* @returns The timelineSet
|
|
1757
1689
|
*/
|
|
1758
|
-
getOrCreateFilteredTimelineSet(filter
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
useSyncEvents = _ref10$useSyncEvents === void 0 ? true : _ref10$useSyncEvents,
|
|
1764
|
-
_ref10$pendingEvents = _ref10.pendingEvents,
|
|
1765
|
-
pendingEvents = _ref10$pendingEvents === void 0 ? true : _ref10$pendingEvents;
|
|
1690
|
+
getOrCreateFilteredTimelineSet(filter, {
|
|
1691
|
+
prepopulateTimeline = true,
|
|
1692
|
+
useSyncEvents = true,
|
|
1693
|
+
pendingEvents = true
|
|
1694
|
+
} = {}) {
|
|
1766
1695
|
if (this.filteredTimelineSets[filter.filterId]) {
|
|
1767
1696
|
return this.filteredTimelineSets[filter.filterId];
|
|
1768
1697
|
}
|
|
1769
|
-
|
|
1698
|
+
const opts = Object.assign({
|
|
1770
1699
|
filter,
|
|
1771
1700
|
pendingEvents
|
|
1772
1701
|
}, this.opts);
|
|
1773
|
-
|
|
1702
|
+
const timelineSet = new EventTimelineSet(this, opts);
|
|
1774
1703
|
this.reEmitter.reEmit(timelineSet, [RoomEvent.Timeline, RoomEvent.TimelineReset]);
|
|
1775
1704
|
if (useSyncEvents) {
|
|
1776
1705
|
this.filteredTimelineSets[filter.filterId] = timelineSet;
|
|
1777
1706
|
this.timelineSets.push(timelineSet);
|
|
1778
1707
|
}
|
|
1779
|
-
|
|
1708
|
+
const unfilteredLiveTimeline = this.getLiveTimeline();
|
|
1780
1709
|
// Not all filter are possible to replicate client-side only
|
|
1781
1710
|
// When that's the case we do not want to prepopulate from the live timeline
|
|
1782
1711
|
// as we would get incorrect results compared to what the server would send back
|
|
@@ -1795,13 +1724,13 @@ export class Room extends ReadReceipt {
|
|
|
1795
1724
|
});
|
|
1796
1725
|
|
|
1797
1726
|
// find the earliest unfiltered timeline
|
|
1798
|
-
|
|
1727
|
+
let timeline = unfilteredLiveTimeline;
|
|
1799
1728
|
while (timeline.getNeighbouringTimeline(EventTimeline.BACKWARDS)) {
|
|
1800
1729
|
timeline = timeline.getNeighbouringTimeline(EventTimeline.BACKWARDS);
|
|
1801
1730
|
}
|
|
1802
1731
|
timelineSet.getLiveTimeline().setPaginationToken(timeline.getPaginationToken(EventTimeline.BACKWARDS), EventTimeline.BACKWARDS);
|
|
1803
1732
|
} else if (useSyncEvents) {
|
|
1804
|
-
|
|
1733
|
+
const livePaginationToken = unfilteredLiveTimeline.getPaginationToken(Direction.Forward);
|
|
1805
1734
|
timelineSet.getLiveTimeline().setPaginationToken(livePaginationToken, Direction.Backward);
|
|
1806
1735
|
}
|
|
1807
1736
|
|
|
@@ -1815,73 +1744,63 @@ export class Room extends ReadReceipt {
|
|
|
1815
1744
|
|
|
1816
1745
|
return timelineSet;
|
|
1817
1746
|
}
|
|
1818
|
-
getThreadListFilter() {
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
var definition = {
|
|
1826
|
-
room: {
|
|
1827
|
-
timeline: {
|
|
1828
|
-
[FILTER_RELATED_BY_REL_TYPES.name]: [THREAD_RELATION_TYPE.name]
|
|
1829
|
-
}
|
|
1747
|
+
async getThreadListFilter(filterType = ThreadFilterType.All) {
|
|
1748
|
+
const myUserId = this.client.getUserId();
|
|
1749
|
+
const filter = new Filter(myUserId);
|
|
1750
|
+
const definition = {
|
|
1751
|
+
room: {
|
|
1752
|
+
timeline: {
|
|
1753
|
+
[FILTER_RELATED_BY_REL_TYPES.name]: [THREAD_RELATION_TYPE.name]
|
|
1830
1754
|
}
|
|
1831
|
-
}
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
}
|
|
1841
|
-
createThreadTimelineSet(filterType) {
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1755
|
+
}
|
|
1756
|
+
};
|
|
1757
|
+
if (filterType === ThreadFilterType.My) {
|
|
1758
|
+
definition.room.timeline[FILTER_RELATED_BY_SENDERS.name] = [myUserId];
|
|
1759
|
+
}
|
|
1760
|
+
filter.setDefinition(definition);
|
|
1761
|
+
const filterId = await this.client.getOrCreateFilter(`THREAD_PANEL_${this.roomId}_${filterType}`, filter);
|
|
1762
|
+
filter.filterId = filterId;
|
|
1763
|
+
return filter;
|
|
1764
|
+
}
|
|
1765
|
+
async createThreadTimelineSet(filterType) {
|
|
1766
|
+
let timelineSet;
|
|
1767
|
+
if (Thread.hasServerSideListSupport) {
|
|
1768
|
+
timelineSet = new EventTimelineSet(this, _objectSpread(_objectSpread({}, this.opts), {}, {
|
|
1769
|
+
pendingEvents: false
|
|
1770
|
+
}), undefined, undefined, filterType ?? ThreadFilterType.All);
|
|
1771
|
+
this.reEmitter.reEmit(timelineSet, [RoomEvent.Timeline, RoomEvent.TimelineReset]);
|
|
1772
|
+
} else if (Thread.hasServerSideSupport) {
|
|
1773
|
+
const filter = await this.getThreadListFilter(filterType);
|
|
1774
|
+
timelineSet = this.getOrCreateFilteredTimelineSet(filter, {
|
|
1775
|
+
prepopulateTimeline: false,
|
|
1776
|
+
useSyncEvents: false,
|
|
1777
|
+
pendingEvents: false
|
|
1778
|
+
});
|
|
1779
|
+
} else {
|
|
1780
|
+
timelineSet = new EventTimelineSet(this, {
|
|
1781
|
+
pendingEvents: false
|
|
1782
|
+
});
|
|
1783
|
+
Array.from(this.threads).forEach(([, thread]) => {
|
|
1784
|
+
if (thread.length === 0) return;
|
|
1785
|
+
const currentUserParticipated = thread.timeline.some(event => {
|
|
1786
|
+
return event.getSender() === this.client.getUserId();
|
|
1860
1787
|
});
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
var currentUserParticipated = thread.timeline.some(event => {
|
|
1866
|
-
return event.getSender() === _this10.client.getUserId();
|
|
1788
|
+
if (filterType !== ThreadFilterType.My || currentUserParticipated) {
|
|
1789
|
+
timelineSet.getLiveTimeline().addEvent(thread.rootEvent, {
|
|
1790
|
+
toStartOfTimeline: false,
|
|
1791
|
+
addToState: false
|
|
1867
1792
|
});
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
});
|
|
1873
|
-
}
|
|
1874
|
-
});
|
|
1875
|
-
}
|
|
1876
|
-
return timelineSet;
|
|
1877
|
-
})();
|
|
1793
|
+
}
|
|
1794
|
+
});
|
|
1795
|
+
}
|
|
1796
|
+
return timelineSet;
|
|
1878
1797
|
}
|
|
1879
1798
|
/**
|
|
1880
1799
|
* Takes the given thread root events and creates threads for them.
|
|
1881
1800
|
*/
|
|
1882
1801
|
processThreadRoots(events, toStartOfTimeline) {
|
|
1883
1802
|
if (!this.client.supportsThreads()) return;
|
|
1884
|
-
for (
|
|
1803
|
+
for (const rootEvent of events) {
|
|
1885
1804
|
EventTimeline.setEventMetadata(rootEvent, this.currentState, toStartOfTimeline);
|
|
1886
1805
|
if (!this.getThread(rootEvent.getId())) {
|
|
1887
1806
|
this.createThread(rootEvent.getId(), rootEvent, [], toStartOfTimeline);
|
|
@@ -1894,61 +1813,57 @@ export class Room extends ReadReceipt {
|
|
|
1894
1813
|
* With server support that means fetching one page.
|
|
1895
1814
|
* Without server support that means fetching as much at once as the server allows us to.
|
|
1896
1815
|
*/
|
|
1897
|
-
fetchRoomThreads() {
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
var _this11$threadsTimeli2;
|
|
1937
|
-
(_this11$threadsTimeli2 = _this11.threadsTimelineSets[1]) === null || _this11$threadsTimeli2 === void 0 || _this11$threadsTimeli2.addLiveEvent(rootEvent, _opts);
|
|
1938
|
-
latestMyThreadsRootEvent = rootEvent;
|
|
1939
|
-
}
|
|
1940
|
-
}
|
|
1941
|
-
_this11.processThreadRoots(threadRoots, true);
|
|
1942
|
-
_this11.client.decryptEventIfNeeded(threadRoots[threadRoots.length - 1]);
|
|
1943
|
-
if (latestMyThreadsRootEvent) {
|
|
1944
|
-
_this11.client.decryptEventIfNeeded(latestMyThreadsRootEvent);
|
|
1816
|
+
async fetchRoomThreads() {
|
|
1817
|
+
if (this.threadsReady || !this.client.supportsThreads()) {
|
|
1818
|
+
return;
|
|
1819
|
+
}
|
|
1820
|
+
if (Thread.hasServerSideListSupport) {
|
|
1821
|
+
await Promise.all([this.fetchRoomThreadList(ThreadFilterType.All), this.fetchRoomThreadList(ThreadFilterType.My)]);
|
|
1822
|
+
} else {
|
|
1823
|
+
const allThreadsFilter = await this.getThreadListFilter();
|
|
1824
|
+
const {
|
|
1825
|
+
chunk: events
|
|
1826
|
+
} = await this.client.createMessagesRequest(this.roomId, "", Number.MAX_SAFE_INTEGER, Direction.Backward, allThreadsFilter);
|
|
1827
|
+
if (!events.length) return;
|
|
1828
|
+
|
|
1829
|
+
// Sorted by last_reply origin_server_ts
|
|
1830
|
+
const threadRoots = events.map(this.client.getEventMapper()).sort((eventA, eventB) => {
|
|
1831
|
+
/**
|
|
1832
|
+
* `origin_server_ts` in a decentralised world is far from ideal
|
|
1833
|
+
* but for lack of any better, we will have to use this
|
|
1834
|
+
* Long term the sorting should be handled by homeservers and this
|
|
1835
|
+
* is only meant as a short term patch
|
|
1836
|
+
*/
|
|
1837
|
+
const threadAMetadata = eventA.getServerAggregatedRelation(THREAD_RELATION_TYPE.name);
|
|
1838
|
+
const threadBMetadata = eventB.getServerAggregatedRelation(THREAD_RELATION_TYPE.name);
|
|
1839
|
+
return threadAMetadata.latest_event.origin_server_ts - threadBMetadata.latest_event.origin_server_ts;
|
|
1840
|
+
});
|
|
1841
|
+
let latestMyThreadsRootEvent;
|
|
1842
|
+
const roomState = this.getLiveTimeline().getState(EventTimeline.FORWARDS);
|
|
1843
|
+
for (const rootEvent of threadRoots) {
|
|
1844
|
+
const opts = {
|
|
1845
|
+
duplicateStrategy: DuplicateStrategy.Ignore,
|
|
1846
|
+
fromCache: false,
|
|
1847
|
+
addToState: false,
|
|
1848
|
+
roomState
|
|
1849
|
+
};
|
|
1850
|
+
this.threadsTimelineSets[0]?.addLiveEvent(rootEvent, opts);
|
|
1851
|
+
const threadRelationship = rootEvent.getServerAggregatedRelation(THREAD_RELATION_TYPE.name);
|
|
1852
|
+
if (threadRelationship?.current_user_participated) {
|
|
1853
|
+
this.threadsTimelineSets[1]?.addLiveEvent(rootEvent, opts);
|
|
1854
|
+
latestMyThreadsRootEvent = rootEvent;
|
|
1945
1855
|
}
|
|
1946
1856
|
}
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1857
|
+
this.processThreadRoots(threadRoots, true);
|
|
1858
|
+
this.client.decryptEventIfNeeded(threadRoots[threadRoots.length - 1]);
|
|
1859
|
+
if (latestMyThreadsRootEvent) {
|
|
1860
|
+
this.client.decryptEventIfNeeded(latestMyThreadsRootEvent);
|
|
1861
|
+
}
|
|
1862
|
+
}
|
|
1863
|
+
this.on(ThreadEvent.NewReply, this.onThreadReply);
|
|
1864
|
+
this.on(ThreadEvent.Update, this.onThreadUpdate);
|
|
1865
|
+
this.on(ThreadEvent.Delete, this.onThreadDelete);
|
|
1866
|
+
this.threadsReady = true;
|
|
1952
1867
|
}
|
|
1953
1868
|
|
|
1954
1869
|
/**
|
|
@@ -1956,25 +1871,22 @@ export class Room extends ReadReceipt {
|
|
|
1956
1871
|
*
|
|
1957
1872
|
* @param events - List of events
|
|
1958
1873
|
*/
|
|
1959
|
-
processPollEvents(events) {
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
} catch (err) {
|
|
1974
|
-
logger.warn("Error processing poll event", event.getId(), err);
|
|
1975
|
-
}
|
|
1874
|
+
async processPollEvents(events) {
|
|
1875
|
+
for (const event of events) {
|
|
1876
|
+
try {
|
|
1877
|
+
// Continue if the event is a clear text, non-poll event.
|
|
1878
|
+
if (!event.isEncrypted() && !isPollEvent(event)) continue;
|
|
1879
|
+
|
|
1880
|
+
/**
|
|
1881
|
+
* Try to decrypt the event. Promise resolution does not guarantee a successful decryption.
|
|
1882
|
+
* Retry is handled in {@link processPollEvent}.
|
|
1883
|
+
*/
|
|
1884
|
+
await this.client.decryptEventIfNeeded(event);
|
|
1885
|
+
this.processPollEvent(event);
|
|
1886
|
+
} catch (err) {
|
|
1887
|
+
logger.warn("Error processing poll event", event.getId(), err);
|
|
1976
1888
|
}
|
|
1977
|
-
}
|
|
1889
|
+
}
|
|
1978
1890
|
}
|
|
1979
1891
|
|
|
1980
1892
|
/**
|
|
@@ -1987,95 +1899,69 @@ export class Room extends ReadReceipt {
|
|
|
1987
1899
|
*
|
|
1988
1900
|
* @param event - Event that could be a poll event
|
|
1989
1901
|
*/
|
|
1990
|
-
processPollEvent(event) {
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
_this13.polls.set(event.getId(), poll);
|
|
2003
|
-
_this13.emit(PollEvent.New, poll);
|
|
1902
|
+
async processPollEvent(event) {
|
|
1903
|
+
if (event.isDecryptionFailure()) {
|
|
1904
|
+
event.once(MatrixEventEvent.Decrypted, maybeDecryptedEvent => {
|
|
1905
|
+
this.processPollEvent(maybeDecryptedEvent);
|
|
1906
|
+
});
|
|
1907
|
+
return;
|
|
1908
|
+
}
|
|
1909
|
+
if (M_POLL_START.matches(event.getType())) {
|
|
1910
|
+
try {
|
|
1911
|
+
const poll = new Poll(event, this.client, this);
|
|
1912
|
+
this.polls.set(event.getId(), poll);
|
|
1913
|
+
this.emit(PollEvent.New, poll);
|
|
2004
1914
|
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
})();
|
|
1915
|
+
// remove the poll when redacted
|
|
1916
|
+
event.once(MatrixEventEvent.BeforeRedaction, redactedEvent => {
|
|
1917
|
+
this.polls.delete(redactedEvent.getId());
|
|
1918
|
+
});
|
|
1919
|
+
} catch {}
|
|
1920
|
+
// poll creation can fail for malformed poll start events
|
|
1921
|
+
return;
|
|
1922
|
+
}
|
|
1923
|
+
const relationEventId = event.relationEventId;
|
|
1924
|
+
if (relationEventId && this.polls.has(relationEventId)) {
|
|
1925
|
+
const poll = this.polls.get(relationEventId);
|
|
1926
|
+
poll?.onNewRelation(event);
|
|
1927
|
+
}
|
|
2019
1928
|
}
|
|
2020
1929
|
|
|
2021
1930
|
/**
|
|
2022
1931
|
* Fetch a single page of threadlist messages for the specific thread filter
|
|
2023
1932
|
* @internal
|
|
2024
1933
|
*/
|
|
2025
|
-
fetchRoomThreadList(filter) {
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
});
|
|
2046
|
-
}
|
|
2047
|
-
})();
|
|
2048
|
-
}
|
|
2049
|
-
onThreadUpdate(thread) {
|
|
2050
|
-
this.updateThreadRootEvents(thread, false, false);
|
|
2051
|
-
}
|
|
2052
|
-
onThreadReply(thread) {
|
|
2053
|
-
this.updateThreadRootEvents(thread, false, true);
|
|
2054
|
-
}
|
|
2055
|
-
onThreadDelete(thread) {
|
|
2056
|
-
var _timeline$getEvents;
|
|
2057
|
-
this.threads.delete(thread.id);
|
|
2058
|
-
var timeline = this.getTimelineForEvent(thread.id);
|
|
2059
|
-
var roomEvent = timeline === null || timeline === void 0 || (_timeline$getEvents = timeline.getEvents()) === null || _timeline$getEvents === void 0 ? void 0 : _timeline$getEvents.find(it => it.getId() === thread.id);
|
|
2060
|
-
if (roomEvent) {
|
|
2061
|
-
thread.clearEventMetadata(roomEvent);
|
|
2062
|
-
} else {
|
|
2063
|
-
logger.debug("onThreadDelete: Could not find root event in room timeline");
|
|
2064
|
-
}
|
|
2065
|
-
for (var timelineSet of this.threadsTimelineSets) {
|
|
2066
|
-
timelineSet.removeEvent(thread.id);
|
|
1934
|
+
async fetchRoomThreadList(filter) {
|
|
1935
|
+
if (!this.client.supportsThreads()) return;
|
|
1936
|
+
if (this.threadsTimelineSets.length === 0) return;
|
|
1937
|
+
const timelineSet = filter === ThreadFilterType.My ? this.threadsTimelineSets[1] : this.threadsTimelineSets[0];
|
|
1938
|
+
const {
|
|
1939
|
+
chunk: events,
|
|
1940
|
+
end
|
|
1941
|
+
} = await this.client.createThreadListMessagesRequest(this.roomId, null, undefined, Direction.Backward, timelineSet.threadListType, timelineSet.getFilter());
|
|
1942
|
+
timelineSet.getLiveTimeline().setPaginationToken(end ?? null, Direction.Backward);
|
|
1943
|
+
if (!events.length) return;
|
|
1944
|
+
const matrixEvents = events.map(this.client.getEventMapper());
|
|
1945
|
+
this.processThreadRoots(matrixEvents, true);
|
|
1946
|
+
const roomState = this.getLiveTimeline().getState(EventTimeline.FORWARDS);
|
|
1947
|
+
for (const rootEvent of matrixEvents) {
|
|
1948
|
+
timelineSet.addLiveEvent(rootEvent, {
|
|
1949
|
+
duplicateStrategy: DuplicateStrategy.Replace,
|
|
1950
|
+
fromCache: false,
|
|
1951
|
+
roomState,
|
|
1952
|
+
addToState: false
|
|
1953
|
+
});
|
|
2067
1954
|
}
|
|
2068
1955
|
}
|
|
2069
|
-
|
|
2070
1956
|
/**
|
|
2071
1957
|
* Forget the timelineSet for this room with the given filter
|
|
2072
1958
|
*
|
|
2073
1959
|
* @param filter - the filter whose timelineSet is to be forgotten
|
|
2074
1960
|
*/
|
|
2075
1961
|
removeFilteredTimelineSet(filter) {
|
|
2076
|
-
|
|
1962
|
+
const timelineSet = this.filteredTimelineSets[filter.filterId];
|
|
2077
1963
|
delete this.filteredTimelineSets[filter.filterId];
|
|
2078
|
-
|
|
1964
|
+
const i = this.timelineSets.indexOf(timelineSet);
|
|
2079
1965
|
if (i > -1) {
|
|
2080
1966
|
this.timelineSets.splice(i, 1);
|
|
2081
1967
|
}
|
|
@@ -2096,8 +1982,7 @@ export class Room extends ReadReceipt {
|
|
|
2096
1982
|
* This will change if MSC3389 is merged.
|
|
2097
1983
|
*/
|
|
2098
1984
|
eventShouldLiveIn(event, events, roots) {
|
|
2099
|
-
|
|
2100
|
-
if (!((_this$client2 = this.client) !== null && _this$client2 !== void 0 && _this$client2.supportsThreads())) {
|
|
1985
|
+
if (!this.client?.supportsThreads()) {
|
|
2101
1986
|
return {
|
|
2102
1987
|
shouldLiveInRoom: true,
|
|
2103
1988
|
shouldLiveInThread: false
|
|
@@ -2105,28 +1990,27 @@ export class Room extends ReadReceipt {
|
|
|
2105
1990
|
}
|
|
2106
1991
|
|
|
2107
1992
|
// A thread root is the only event shown in both timelines
|
|
2108
|
-
if (event.isThreadRoot || roots
|
|
1993
|
+
if (event.isThreadRoot || roots?.has(event.getId())) {
|
|
2109
1994
|
return {
|
|
2110
1995
|
shouldLiveInRoom: true,
|
|
2111
1996
|
shouldLiveInThread: true,
|
|
2112
1997
|
threadId: event.getId()
|
|
2113
1998
|
};
|
|
2114
1999
|
}
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2000
|
+
const isThreadRelation = event.isRelation(THREAD_RELATION_TYPE.name);
|
|
2001
|
+
const parentEventId = event.getAssociatedId();
|
|
2002
|
+
const threadRootId = event.threadRootId;
|
|
2118
2003
|
|
|
2119
2004
|
// Where the parent is the thread root and this is a non-thread relation this should live only in the main timeline
|
|
2120
|
-
if (!!parentEventId && !isThreadRelation && (threadRootId === parentEventId || roots
|
|
2005
|
+
if (!!parentEventId && !isThreadRelation && (threadRootId === parentEventId || roots?.has(parentEventId))) {
|
|
2121
2006
|
return {
|
|
2122
2007
|
shouldLiveInRoom: true,
|
|
2123
2008
|
shouldLiveInThread: false
|
|
2124
2009
|
};
|
|
2125
2010
|
}
|
|
2126
|
-
|
|
2011
|
+
let parentEvent;
|
|
2127
2012
|
if (parentEventId) {
|
|
2128
|
-
|
|
2129
|
-
parentEvent = (_this$findEventById = this.findEventById(parentEventId)) !== null && _this$findEventById !== void 0 ? _this$findEventById : events === null || events === void 0 ? void 0 : events.find(e => e.getId() === parentEventId);
|
|
2013
|
+
parentEvent = this.findEventById(parentEventId) ?? events?.find(e => e.getId() === parentEventId);
|
|
2130
2014
|
}
|
|
2131
2015
|
|
|
2132
2016
|
// Treat non-thread-relations, redactions, and replies as extensions of their parents so evaluate parentEvent instead
|
|
@@ -2163,18 +2047,17 @@ export class Room extends ReadReceipt {
|
|
|
2163
2047
|
}
|
|
2164
2048
|
findThreadForEvent(event) {
|
|
2165
2049
|
if (!event) return null;
|
|
2166
|
-
|
|
2167
|
-
threadId
|
|
2050
|
+
const {
|
|
2051
|
+
threadId
|
|
2052
|
+
} = this.eventShouldLiveIn(event);
|
|
2168
2053
|
return threadId ? this.getThread(threadId) : null;
|
|
2169
2054
|
}
|
|
2170
|
-
addThreadedEvents(threadId, events) {
|
|
2171
|
-
|
|
2172
|
-
var thread = this.getThread(threadId);
|
|
2055
|
+
addThreadedEvents(threadId, events, toStartOfTimeline = false) {
|
|
2056
|
+
const thread = this.getThread(threadId);
|
|
2173
2057
|
if (thread) {
|
|
2174
2058
|
thread.addEvents(events, toStartOfTimeline);
|
|
2175
2059
|
} else {
|
|
2176
|
-
|
|
2177
|
-
var rootEvent = (_this$findEventById2 = this.findEventById(threadId)) !== null && _this$findEventById2 !== void 0 ? _this$findEventById2 : events.find(e => e.getId() === threadId);
|
|
2060
|
+
const rootEvent = this.findEventById(threadId) ?? events.find(e => e.getId() === threadId);
|
|
2178
2061
|
this.createThread(threadId, rootEvent, events, toStartOfTimeline);
|
|
2179
2062
|
}
|
|
2180
2063
|
}
|
|
@@ -2184,49 +2067,38 @@ export class Room extends ReadReceipt {
|
|
|
2184
2067
|
*/
|
|
2185
2068
|
processThreadedEvents(events, toStartOfTimeline) {
|
|
2186
2069
|
// ALWAYS filter out any events that are past retention
|
|
2187
|
-
events = events.filter(e =>
|
|
2188
|
-
var _this$retention$shoul2, _this$retention2;
|
|
2189
|
-
return (_this$retention$shoul2 = (_this$retention2 = this.retention) === null || _this$retention2 === void 0 ? void 0 : _this$retention2.shouldEventBeRetained(e)) !== null && _this$retention$shoul2 !== void 0 ? _this$retention$shoul2 : true;
|
|
2190
|
-
});
|
|
2070
|
+
events = events.filter(e => this.retention?.shouldEventBeRetained(e) ?? true);
|
|
2191
2071
|
events.forEach(this.tryApplyRedaction);
|
|
2192
|
-
|
|
2193
|
-
for (
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2072
|
+
const eventsByThread = {};
|
|
2073
|
+
for (const event of events) {
|
|
2074
|
+
const {
|
|
2075
|
+
threadId,
|
|
2076
|
+
shouldLiveInThread
|
|
2077
|
+
} = this.eventShouldLiveIn(event);
|
|
2198
2078
|
if (shouldLiveInThread && !eventsByThread[threadId]) {
|
|
2199
2079
|
eventsByThread[threadId] = [];
|
|
2200
2080
|
}
|
|
2201
|
-
|
|
2081
|
+
eventsByThread[threadId]?.push(event);
|
|
2202
2082
|
}
|
|
2203
|
-
Object.entries(eventsByThread).map(
|
|
2204
|
-
var _ref14 = _slicedToArray(_ref13, 2),
|
|
2205
|
-
threadId = _ref14[0],
|
|
2206
|
-
threadEvents = _ref14[1];
|
|
2207
|
-
return this.addThreadedEvents(threadId, threadEvents, toStartOfTimeline);
|
|
2208
|
-
});
|
|
2083
|
+
Object.entries(eventsByThread).map(([threadId, threadEvents]) => this.addThreadedEvents(threadId, threadEvents, toStartOfTimeline));
|
|
2209
2084
|
}
|
|
2210
|
-
createThread(threadId, rootEvent) {
|
|
2211
|
-
var _this$cachedThreadRea;
|
|
2212
|
-
var events = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];
|
|
2213
|
-
var toStartOfTimeline = arguments.length > 3 ? arguments[3] : undefined;
|
|
2085
|
+
createThread(threadId, rootEvent, events = [], toStartOfTimeline) {
|
|
2214
2086
|
if (this.threads.has(threadId)) {
|
|
2215
2087
|
return this.threads.get(threadId);
|
|
2216
2088
|
}
|
|
2217
2089
|
if (rootEvent) {
|
|
2218
|
-
|
|
2219
|
-
if (relatedEvents
|
|
2090
|
+
const relatedEvents = this.relations.getAllChildEventsForEvent(rootEvent.getId());
|
|
2091
|
+
if (relatedEvents?.length) {
|
|
2220
2092
|
// Include all relations of the root event, given it'll be visible in both timelines,
|
|
2221
2093
|
// except `m.replace` as that will already be applied atop the event using `MatrixEvent::makeReplaced`
|
|
2222
2094
|
events = events.concat(relatedEvents.filter(e => !e.isRelation(RelationType.Replace)));
|
|
2223
2095
|
}
|
|
2224
2096
|
}
|
|
2225
|
-
|
|
2097
|
+
const thread = new Thread(threadId, rootEvent, {
|
|
2226
2098
|
room: this,
|
|
2227
2099
|
client: this.client,
|
|
2228
2100
|
pendingEventOrdering: this.opts.pendingEventOrdering,
|
|
2229
|
-
receipts:
|
|
2101
|
+
receipts: this.cachedThreadReadReceipts.get(threadId) ?? []
|
|
2230
2102
|
});
|
|
2231
2103
|
|
|
2232
2104
|
// Add the re-emitter before we start adding events to the thread so we don't miss events
|
|
@@ -2267,13 +2139,13 @@ export class Room extends ReadReceipt {
|
|
|
2267
2139
|
* @private
|
|
2268
2140
|
*/
|
|
2269
2141
|
applyEventAsRedaction(redactionEvent, redactedEvent) {
|
|
2270
|
-
|
|
2142
|
+
const threadRootId = redactedEvent.threadRootId;
|
|
2271
2143
|
redactedEvent.makeRedacted(redactionEvent, this);
|
|
2272
2144
|
|
|
2273
2145
|
// If this is in the current state, replace it with the redacted version
|
|
2274
2146
|
if (redactedEvent.isState()) {
|
|
2275
|
-
|
|
2276
|
-
if (
|
|
2147
|
+
const currentStateEvent = this.currentState.getStateEvents(redactedEvent.getType(), redactedEvent.getStateKey());
|
|
2148
|
+
if (currentStateEvent?.getId() === redactedEvent.getId()) {
|
|
2277
2149
|
this.currentState.setStateEvents([redactedEvent]);
|
|
2278
2150
|
}
|
|
2279
2151
|
}
|
|
@@ -2311,17 +2183,14 @@ export class Room extends ReadReceipt {
|
|
|
2311
2183
|
// to check the event ID against the list of pending events if there is no transaction ID
|
|
2312
2184
|
// field. Only do this for events sent by us though as it's potentially expensive to loop
|
|
2313
2185
|
// the pending events map.
|
|
2314
|
-
|
|
2186
|
+
const txnId = event.getUnsigned().transaction_id;
|
|
2315
2187
|
if (!txnId && event.getSender() === this.myUserId) {
|
|
2316
2188
|
// check the txn map for a matching event ID
|
|
2317
|
-
for (
|
|
2318
|
-
var _ref16 = _slicedToArray(_ref17, 2);
|
|
2319
|
-
var tid = _ref16[0];
|
|
2320
|
-
var localEvent = _ref16[1];
|
|
2189
|
+
for (const [tid, localEvent] of this.txnToEvent) {
|
|
2321
2190
|
if (localEvent.getId() === event.getId()) {
|
|
2322
2191
|
logger.debug("processLiveEvent: found sent event without txn ID: ", tid, event.getId());
|
|
2323
2192
|
// update the unsigned field so we can re-use the same codepaths
|
|
2324
|
-
|
|
2193
|
+
const unsigned = event.getUnsigned();
|
|
2325
2194
|
unsigned.transaction_id = tid;
|
|
2326
2195
|
event.setUnsigned(unsigned);
|
|
2327
2196
|
break;
|
|
@@ -2342,13 +2211,15 @@ export class Room extends ReadReceipt {
|
|
|
2342
2211
|
* Fires {@link RoomEvent.Timeline}
|
|
2343
2212
|
*/
|
|
2344
2213
|
addLiveEvent(event, addLiveEventOptions) {
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2214
|
+
const {
|
|
2215
|
+
duplicateStrategy,
|
|
2216
|
+
timelineWasEmpty,
|
|
2217
|
+
fromCache,
|
|
2218
|
+
addToState
|
|
2219
|
+
} = addLiveEventOptions;
|
|
2349
2220
|
|
|
2350
2221
|
// add to our timeline sets
|
|
2351
|
-
for (
|
|
2222
|
+
for (const timelineSet of this.timelineSets) {
|
|
2352
2223
|
timelineSet.addLiveEvent(event, {
|
|
2353
2224
|
duplicateStrategy,
|
|
2354
2225
|
fromCache,
|
|
@@ -2418,8 +2289,8 @@ export class Room extends ReadReceipt {
|
|
|
2418
2289
|
this.aggregateNonLiveRelation(event);
|
|
2419
2290
|
}
|
|
2420
2291
|
if (event.isRedaction()) {
|
|
2421
|
-
|
|
2422
|
-
|
|
2292
|
+
const redactId = event.event.redacts;
|
|
2293
|
+
let redactedEvent = this.pendingEventList.find(e => e.getId() === redactId);
|
|
2423
2294
|
if (!redactedEvent && redactId) {
|
|
2424
2295
|
redactedEvent = this.findEventById(redactId);
|
|
2425
2296
|
}
|
|
@@ -2429,7 +2300,7 @@ export class Room extends ReadReceipt {
|
|
|
2429
2300
|
}
|
|
2430
2301
|
}
|
|
2431
2302
|
} else {
|
|
2432
|
-
for (
|
|
2303
|
+
for (const timelineSet of this.timelineSets) {
|
|
2433
2304
|
if (timelineSet.getFilter()) {
|
|
2434
2305
|
if (timelineSet.getFilter().filterRoomTimeline([event]).length) {
|
|
2435
2306
|
timelineSet.addEventToTimeline(event, timelineSet.getLiveTimeline(), {
|
|
@@ -2463,14 +2334,14 @@ export class Room extends ReadReceipt {
|
|
|
2463
2334
|
*/
|
|
2464
2335
|
savePendingEvents() {
|
|
2465
2336
|
if (this.pendingEventList) {
|
|
2466
|
-
|
|
2337
|
+
const pendingEvents = this.pendingEventList.map(event => {
|
|
2467
2338
|
return _objectSpread(_objectSpread({}, event.event), {}, {
|
|
2468
2339
|
txn_id: event.getTxnId()
|
|
2469
2340
|
});
|
|
2470
2341
|
}).filter(event => {
|
|
2471
2342
|
// Filter out the unencrypted messages if the room is encrypted
|
|
2472
|
-
|
|
2473
|
-
|
|
2343
|
+
const isEventEncrypted = event.type === EventType.RoomMessageEncrypted;
|
|
2344
|
+
const isRoomEncrypted = this.hasEncryptionStateEvent();
|
|
2474
2345
|
return isEventEncrypted || !isRoomEncrypted;
|
|
2475
2346
|
});
|
|
2476
2347
|
this.client.store.setPendingEvents(this.roomId, pendingEvents);
|
|
@@ -2511,10 +2382,10 @@ export class Room extends ReadReceipt {
|
|
|
2511
2382
|
* Fires {@link RoomEvent.LocalEchoUpdated}
|
|
2512
2383
|
*/
|
|
2513
2384
|
handleRemoteEcho(remoteEvent, localEvent) {
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
logger.debug(
|
|
2385
|
+
const oldEventId = localEvent.getId();
|
|
2386
|
+
const newEventId = remoteEvent.getId();
|
|
2387
|
+
const oldStatus = localEvent.status;
|
|
2388
|
+
logger.debug(`Got remote echo for event ${oldEventId} -> ${newEventId} old status ${oldStatus}`);
|
|
2518
2389
|
|
|
2519
2390
|
// no longer pending
|
|
2520
2391
|
this.txnToEvent.delete(remoteEvent.getUnsigned().transaction_id);
|
|
@@ -2527,14 +2398,15 @@ export class Room extends ReadReceipt {
|
|
|
2527
2398
|
// replace the event source (this will preserve the plaintext payload if
|
|
2528
2399
|
// any, which is good, because we don't want to try decoding it again).
|
|
2529
2400
|
localEvent.handleRemoteEcho(remoteEvent.event);
|
|
2530
|
-
|
|
2531
|
-
shouldLiveInRoom
|
|
2532
|
-
threadId
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
thread
|
|
2401
|
+
const {
|
|
2402
|
+
shouldLiveInRoom,
|
|
2403
|
+
threadId
|
|
2404
|
+
} = this.eventShouldLiveIn(remoteEvent);
|
|
2405
|
+
const thread = threadId ? this.getThread(threadId) : null;
|
|
2406
|
+
thread?.setEventMetadata(localEvent);
|
|
2407
|
+
thread?.timelineSet.handleRemoteEcho(localEvent, oldEventId, newEventId);
|
|
2536
2408
|
if (shouldLiveInRoom) {
|
|
2537
|
-
for (
|
|
2409
|
+
for (const timelineSet of this.timelineSets) {
|
|
2538
2410
|
// if it's already in the timeline, update the timeline map. If it's not, add it.
|
|
2539
2411
|
timelineSet.handleRemoteEcho(localEvent, oldEventId, newEventId);
|
|
2540
2412
|
}
|
|
@@ -2556,7 +2428,7 @@ export class Room extends ReadReceipt {
|
|
|
2556
2428
|
* Fires {@link RoomEvent.LocalEchoUpdated}
|
|
2557
2429
|
*/
|
|
2558
2430
|
updatePendingEvent(event, newStatus, newEventId) {
|
|
2559
|
-
logger.log(
|
|
2431
|
+
logger.log(`setting pendingEvent status to ${newStatus} in ${event.getRoomId()} ` + `event ID ${event.getId()} -> ${newEventId}`);
|
|
2560
2432
|
|
|
2561
2433
|
// if the message was sent, we expect an event id
|
|
2562
2434
|
if (newStatus == EventStatus.SENT && !newEventId) {
|
|
@@ -2565,18 +2437,18 @@ export class Room extends ReadReceipt {
|
|
|
2565
2437
|
|
|
2566
2438
|
// SENT races against /sync, so we have to special-case it.
|
|
2567
2439
|
if (newStatus == EventStatus.SENT) {
|
|
2568
|
-
|
|
2440
|
+
const timeline = this.getTimelineForEvent(newEventId);
|
|
2569
2441
|
if (timeline) {
|
|
2570
2442
|
// we've already received the event via the event stream.
|
|
2571
2443
|
// nothing more to do here, assuming the transaction ID was correctly matched.
|
|
2572
2444
|
// Let's check that.
|
|
2573
|
-
|
|
2574
|
-
|
|
2445
|
+
const remoteEvent = this.findEventById(newEventId);
|
|
2446
|
+
const remoteTxnId = remoteEvent?.getUnsigned().transaction_id;
|
|
2575
2447
|
if (!remoteTxnId && remoteEvent) {
|
|
2576
2448
|
// This code path is mostly relevant for the Sliding Sync proxy.
|
|
2577
2449
|
// The remote event did not contain a transaction ID, so we did not handle
|
|
2578
2450
|
// the remote echo yet. Handle it now.
|
|
2579
|
-
|
|
2451
|
+
const unsigned = remoteEvent.getUnsigned();
|
|
2580
2452
|
unsigned.transaction_id = event.getTxnId();
|
|
2581
2453
|
remoteEvent.setUnsigned(unsigned);
|
|
2582
2454
|
// the remote event is _already_ in the timeline, so we need to remove it so
|
|
@@ -2587,39 +2459,40 @@ export class Room extends ReadReceipt {
|
|
|
2587
2459
|
return;
|
|
2588
2460
|
}
|
|
2589
2461
|
}
|
|
2590
|
-
|
|
2591
|
-
|
|
2462
|
+
const oldStatus = event.status;
|
|
2463
|
+
const oldEventId = event.getId();
|
|
2592
2464
|
if (!oldStatus) {
|
|
2593
2465
|
throw new Error("updatePendingEventStatus called on an event which is not a local echo.");
|
|
2594
2466
|
}
|
|
2595
|
-
|
|
2596
|
-
if (!
|
|
2597
|
-
throw new Error(
|
|
2467
|
+
const allowed = ALLOWED_TRANSITIONS[oldStatus];
|
|
2468
|
+
if (!allowed?.includes(newStatus)) {
|
|
2469
|
+
throw new Error(`Invalid EventStatus transition ${oldStatus}->${newStatus}`);
|
|
2598
2470
|
}
|
|
2599
2471
|
event.setStatus(newStatus);
|
|
2600
2472
|
if (newStatus == EventStatus.SENT) {
|
|
2601
2473
|
// update the event id
|
|
2602
2474
|
event.replaceLocalEventId(newEventId);
|
|
2603
|
-
|
|
2604
|
-
shouldLiveInRoom
|
|
2605
|
-
threadId
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
thread
|
|
2475
|
+
const {
|
|
2476
|
+
shouldLiveInRoom,
|
|
2477
|
+
threadId
|
|
2478
|
+
} = this.eventShouldLiveIn(event);
|
|
2479
|
+
const thread = threadId ? this.getThread(threadId) : undefined;
|
|
2480
|
+
thread?.setEventMetadata(event);
|
|
2481
|
+
thread?.timelineSet.replaceEventId(oldEventId, newEventId);
|
|
2609
2482
|
if (shouldLiveInRoom) {
|
|
2610
2483
|
// if the event was already in the timeline (which will be the case if
|
|
2611
2484
|
// opts.pendingEventOrdering==chronological), we need to update the
|
|
2612
2485
|
// timeline map.
|
|
2613
|
-
for (
|
|
2486
|
+
for (const timelineSet of this.timelineSets) {
|
|
2614
2487
|
timelineSet.replaceEventId(oldEventId, newEventId);
|
|
2615
2488
|
}
|
|
2616
2489
|
}
|
|
2617
2490
|
} else if (newStatus == EventStatus.CANCELLED) {
|
|
2618
2491
|
// remove it from the pending event list, or the timeline.
|
|
2619
2492
|
if (this.pendingEventList) {
|
|
2620
|
-
|
|
2493
|
+
const removedEvent = this.getPendingEvent(oldEventId);
|
|
2621
2494
|
this.removePendingEvent(oldEventId);
|
|
2622
|
-
if (removedEvent
|
|
2495
|
+
if (removedEvent?.isRedaction()) {
|
|
2623
2496
|
this.revertRedactionLocalEcho(removedEvent);
|
|
2624
2497
|
}
|
|
2625
2498
|
}
|
|
@@ -2629,11 +2502,11 @@ export class Room extends ReadReceipt {
|
|
|
2629
2502
|
this.emit(RoomEvent.LocalEchoUpdated, event, this, oldEventId, oldStatus);
|
|
2630
2503
|
}
|
|
2631
2504
|
revertRedactionLocalEcho(redactionEvent) {
|
|
2632
|
-
|
|
2505
|
+
const redactId = redactionEvent.event.redacts;
|
|
2633
2506
|
if (!redactId) {
|
|
2634
2507
|
return;
|
|
2635
2508
|
}
|
|
2636
|
-
|
|
2509
|
+
const redactedEvent = this.getUnfilteredTimelineSet().findEventById(redactId);
|
|
2637
2510
|
if (redactedEvent) {
|
|
2638
2511
|
redactedEvent.unmarkLocallyRedacted();
|
|
2639
2512
|
// re-render after undoing redaction
|
|
@@ -2645,13 +2518,13 @@ export class Room extends ReadReceipt {
|
|
|
2645
2518
|
}
|
|
2646
2519
|
}
|
|
2647
2520
|
assertTimelineSetsAreLive() {
|
|
2648
|
-
for (
|
|
2649
|
-
|
|
2521
|
+
for (let i = 0; i < this.timelineSets.length; i++) {
|
|
2522
|
+
const liveTimeline = this.timelineSets[i].getLiveTimeline();
|
|
2650
2523
|
if (liveTimeline.getPaginationToken(EventTimeline.FORWARDS)) {
|
|
2651
2524
|
throw new Error("live timeline " + i + " is no longer live - it has a pagination token " + "(" + liveTimeline.getPaginationToken(EventTimeline.FORWARDS) + ")");
|
|
2652
2525
|
}
|
|
2653
2526
|
if (liveTimeline.getNeighbouringTimeline(EventTimeline.FORWARDS)) {
|
|
2654
|
-
throw new Error(
|
|
2527
|
+
throw new Error(`live timeline ${i} is no longer live - it has a neighbouring timeline`);
|
|
2655
2528
|
}
|
|
2656
2529
|
}
|
|
2657
2530
|
}
|
|
@@ -2665,108 +2538,100 @@ export class Room extends ReadReceipt {
|
|
|
2665
2538
|
* @param addLiveEventOptions - addLiveEvent options
|
|
2666
2539
|
* @throws If `duplicateStrategy` is not falsey, 'replace' or 'ignore'.
|
|
2667
2540
|
*/
|
|
2668
|
-
addLiveEvents(events, addLiveEventOptions) {
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
}
|
|
2679
|
-
|
|
2680
|
-
// ALWAYS filter out any events that are past retention
|
|
2681
|
-
events = events.filter(e => {
|
|
2682
|
-
var _this15$retention$sho, _this15$retention;
|
|
2683
|
-
return (_this15$retention$sho = (_this15$retention = _this15.retention) === null || _this15$retention === void 0 ? void 0 : _this15$retention.shouldEventBeRetained(e)) !== null && _this15$retention$sho !== void 0 ? _this15$retention$sho : true;
|
|
2684
|
-
});
|
|
2541
|
+
async addLiveEvents(events, addLiveEventOptions) {
|
|
2542
|
+
const {
|
|
2543
|
+
duplicateStrategy,
|
|
2544
|
+
fromCache,
|
|
2545
|
+
timelineWasEmpty = false,
|
|
2546
|
+
addToState
|
|
2547
|
+
} = addLiveEventOptions;
|
|
2548
|
+
if (duplicateStrategy && ["replace", "ignore"].indexOf(duplicateStrategy) === -1) {
|
|
2549
|
+
throw new Error("duplicateStrategy MUST be either 'replace' or 'ignore'");
|
|
2550
|
+
}
|
|
2685
2551
|
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2552
|
+
// ALWAYS filter out any events that are past retention
|
|
2553
|
+
events = events.filter(e => this.retention?.shouldEventBeRetained(e) ?? true);
|
|
2554
|
+
|
|
2555
|
+
// sanity check that the live timeline is still live
|
|
2556
|
+
this.assertTimelineSetsAreLive();
|
|
2557
|
+
const threadRoots = this.findThreadRoots(events);
|
|
2558
|
+
const eventsByThread = {};
|
|
2559
|
+
const options = {
|
|
2560
|
+
duplicateStrategy,
|
|
2561
|
+
fromCache,
|
|
2562
|
+
timelineWasEmpty,
|
|
2563
|
+
addToState
|
|
2564
|
+
};
|
|
2696
2565
|
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
continue; // we can skip adding the event to the timeline sets, it is already there
|
|
2709
|
-
}
|
|
2566
|
+
// List of extra events to check for being parents of any relations encountered
|
|
2567
|
+
const neighbouringEvents = [...events];
|
|
2568
|
+
for (const event of events) {
|
|
2569
|
+
// TODO: We should have a filter to say "only add state event types X Y Z to the timeline".
|
|
2570
|
+
this.processLiveEvent(event);
|
|
2571
|
+
if (event.getUnsigned().transaction_id) {
|
|
2572
|
+
const existingEvent = this.txnToEvent.get(event.getUnsigned().transaction_id);
|
|
2573
|
+
if (existingEvent) {
|
|
2574
|
+
// remote echo of an event we sent earlier
|
|
2575
|
+
this.handleRemoteEcho(event, existingEvent);
|
|
2576
|
+
continue; // we can skip adding the event to the timeline sets, it is already there
|
|
2710
2577
|
}
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
var _this15$eventShouldLi3 = _this15.eventShouldLiveIn(event, neighbouringEvents, threadRoots);
|
|
2727
|
-
shouldLiveInRoom = _this15$eventShouldLi3.shouldLiveInRoom;
|
|
2728
|
-
shouldLiveInThread = _this15$eventShouldLi3.shouldLiveInThread;
|
|
2729
|
-
var _this15$eventShouldLi4 = _this15$eventShouldLi3.threadId;
|
|
2730
|
-
threadId = _this15$eventShouldLi4 === void 0 ? "" : _this15$eventShouldLi4;
|
|
2731
|
-
} catch (e) {
|
|
2732
|
-
logger.error("Failed to load parent event of unhandled relation", e);
|
|
2578
|
+
}
|
|
2579
|
+
let {
|
|
2580
|
+
shouldLiveInRoom,
|
|
2581
|
+
shouldLiveInThread,
|
|
2582
|
+
threadId = ""
|
|
2583
|
+
} = this.eventShouldLiveIn(event, neighbouringEvents, threadRoots);
|
|
2584
|
+
if (!shouldLiveInThread && !shouldLiveInRoom && event.isRelation()) {
|
|
2585
|
+
try {
|
|
2586
|
+
const parentEvent = new MatrixEvent(await this.client.fetchRoomEvent(this.roomId, event.relationEventId));
|
|
2587
|
+
neighbouringEvents.push(parentEvent);
|
|
2588
|
+
if (parentEvent.threadRootId) {
|
|
2589
|
+
threadRoots.add(parentEvent.threadRootId);
|
|
2590
|
+
const unsigned = event.getUnsigned();
|
|
2591
|
+
unsigned[UNSIGNED_THREAD_ID_FIELD.name] = parentEvent.threadRootId;
|
|
2592
|
+
event.setUnsigned(unsigned);
|
|
2733
2593
|
}
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
} else if (!shouldLiveInThread && event.isRelation()) {
|
|
2742
|
-
_this15.relations.aggregateChildEvent(event);
|
|
2594
|
+
({
|
|
2595
|
+
shouldLiveInRoom,
|
|
2596
|
+
shouldLiveInThread,
|
|
2597
|
+
threadId = ""
|
|
2598
|
+
} = this.eventShouldLiveIn(event, neighbouringEvents, threadRoots));
|
|
2599
|
+
} catch (e) {
|
|
2600
|
+
logger.error("Failed to load parent event of unhandled relation", e);
|
|
2743
2601
|
}
|
|
2744
2602
|
}
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2603
|
+
if (shouldLiveInThread && !eventsByThread[threadId]) {
|
|
2604
|
+
eventsByThread[threadId] = [];
|
|
2605
|
+
}
|
|
2606
|
+
eventsByThread[threadId]?.push(event);
|
|
2607
|
+
if (shouldLiveInRoom) {
|
|
2608
|
+
this.addLiveEvent(event, options);
|
|
2609
|
+
} else if (!shouldLiveInThread && event.isRelation()) {
|
|
2610
|
+
this.relations.aggregateChildEvent(event);
|
|
2611
|
+
}
|
|
2612
|
+
}
|
|
2613
|
+
Object.entries(eventsByThread).forEach(([threadId, threadEvents]) => {
|
|
2614
|
+
this.addThreadedEvents(threadId, threadEvents, false);
|
|
2615
|
+
});
|
|
2752
2616
|
}
|
|
2753
2617
|
partitionThreadedEvents(events) {
|
|
2754
2618
|
// Indices to the events array, for readability
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2619
|
+
const ROOM = 0;
|
|
2620
|
+
const THREAD = 1;
|
|
2621
|
+
const UNKNOWN_RELATION = 2;
|
|
2758
2622
|
if (this.client.supportsThreads()) {
|
|
2759
|
-
|
|
2623
|
+
const threadRoots = this.findThreadRoots(events);
|
|
2760
2624
|
return events.reduce((memo, event) => {
|
|
2761
|
-
|
|
2762
|
-
shouldLiveInRoom
|
|
2763
|
-
shouldLiveInThread
|
|
2764
|
-
threadId
|
|
2625
|
+
const {
|
|
2626
|
+
shouldLiveInRoom,
|
|
2627
|
+
shouldLiveInThread,
|
|
2628
|
+
threadId
|
|
2629
|
+
} = this.eventShouldLiveIn(event, events, threadRoots);
|
|
2765
2630
|
if (shouldLiveInRoom) {
|
|
2766
2631
|
memo[ROOM].push(event);
|
|
2767
2632
|
}
|
|
2768
2633
|
if (shouldLiveInThread) {
|
|
2769
|
-
event.setThreadId(threadId
|
|
2634
|
+
event.setThreadId(threadId ?? "");
|
|
2770
2635
|
memo[THREAD].push(event);
|
|
2771
2636
|
}
|
|
2772
2637
|
if (!shouldLiveInThread && !shouldLiveInRoom) {
|
|
@@ -2784,9 +2649,9 @@ export class Room extends ReadReceipt {
|
|
|
2784
2649
|
* Given some events, find the IDs of all the thread roots that are referred to by them.
|
|
2785
2650
|
*/
|
|
2786
2651
|
findThreadRoots(events) {
|
|
2787
|
-
|
|
2788
|
-
for (
|
|
2789
|
-
|
|
2652
|
+
const threadRoots = new Set();
|
|
2653
|
+
for (const event of events) {
|
|
2654
|
+
const threadRootId = event.threadRootId;
|
|
2790
2655
|
if (threadRootId != undefined) {
|
|
2791
2656
|
threadRoots.add(threadRootId);
|
|
2792
2657
|
}
|
|
@@ -2799,19 +2664,17 @@ export class Room extends ReadReceipt {
|
|
|
2799
2664
|
* @param event - The m.receipt event.
|
|
2800
2665
|
* @param synthetic - True if this event is implicit.
|
|
2801
2666
|
*/
|
|
2802
|
-
addReceipt(event) {
|
|
2803
|
-
|
|
2804
|
-
var content = event.getContent();
|
|
2667
|
+
addReceipt(event, synthetic = false) {
|
|
2668
|
+
const content = event.getContent();
|
|
2805
2669
|
this.roomReceipts.add(content, synthetic);
|
|
2806
2670
|
|
|
2807
2671
|
// TODO: delete the following code when it has been replaced by RoomReceipts
|
|
2808
2672
|
Object.keys(content).forEach(eventId => {
|
|
2809
2673
|
Object.keys(content[eventId]).forEach(receiptType => {
|
|
2810
2674
|
Object.keys(content[eventId][receiptType]).forEach(userId => {
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
var receiptDestination = receiptForMainTimeline ? this : this.threads.get((_receipt$thread_id = receipt.thread_id) !== null && _receipt$thread_id !== void 0 ? _receipt$thread_id : "");
|
|
2675
|
+
const receipt = content[eventId][receiptType][userId];
|
|
2676
|
+
const receiptForMainTimeline = !receipt.thread_id || receipt.thread_id === MAIN_ROOM_TIMELINE;
|
|
2677
|
+
const receiptDestination = receiptForMainTimeline ? this : this.threads.get(receipt.thread_id ?? "");
|
|
2815
2678
|
if (receiptDestination) {
|
|
2816
2679
|
receiptDestination.addReceiptToStructure(eventId, receiptType, userId, receipt, synthetic);
|
|
2817
2680
|
|
|
@@ -2829,18 +2692,17 @@ export class Room extends ReadReceipt {
|
|
|
2829
2692
|
// an event during the sync. More explanation at:
|
|
2830
2693
|
// https://github.com/matrix-org/matrix-js-sdk/issues/3684
|
|
2831
2694
|
if (!synthetic && this.client.isInitialSyncComplete() && userId === this.client.getUserId()) {
|
|
2832
|
-
|
|
2695
|
+
const lastEvent = receiptDestination.timeline[receiptDestination.timeline.length - 1];
|
|
2833
2696
|
if (lastEvent && eventId === lastEvent.getId() && userId === lastEvent.getSender()) {
|
|
2834
2697
|
receiptDestination.setUnread(NotificationCountType.Total, 0);
|
|
2835
2698
|
receiptDestination.setUnread(NotificationCountType.Highlight, 0);
|
|
2836
2699
|
}
|
|
2837
2700
|
}
|
|
2838
2701
|
} else {
|
|
2839
|
-
var _this$cachedThreadRea2;
|
|
2840
2702
|
// The thread does not exist locally, keep the read receipt
|
|
2841
2703
|
// in a cache locally, and re-apply the `addReceipt` logic
|
|
2842
2704
|
// when the thread is created
|
|
2843
|
-
this.cachedThreadReadReceipts.set(receipt.thread_id, [...(
|
|
2705
|
+
this.cachedThreadReadReceipts.set(receipt.thread_id, [...(this.cachedThreadReadReceipts.get(receipt.thread_id) ?? []), {
|
|
2844
2706
|
eventId,
|
|
2845
2707
|
receiptType,
|
|
2846
2708
|
userId,
|
|
@@ -2848,14 +2710,14 @@ export class Room extends ReadReceipt {
|
|
|
2848
2710
|
synthetic
|
|
2849
2711
|
}]);
|
|
2850
2712
|
}
|
|
2851
|
-
|
|
2713
|
+
const me = this.client.getUserId();
|
|
2852
2714
|
// Track the time of the current user's oldest threaded receipt in the room.
|
|
2853
2715
|
if (userId === me && !receiptForMainTimeline && receipt.ts < this.oldestThreadedReceiptTs) {
|
|
2854
2716
|
this.oldestThreadedReceiptTs = receipt.ts;
|
|
2855
2717
|
}
|
|
2856
2718
|
|
|
2857
2719
|
// Track each user's unthreaded read receipt.
|
|
2858
|
-
if (!receipt.thread_id && receipt.ts > (
|
|
2720
|
+
if (!receipt.thread_id && receipt.ts > (this.unthreadedReceipts.get(userId)?.ts ?? 0)) {
|
|
2859
2721
|
this.unthreadedReceipts.set(userId, receipt);
|
|
2860
2722
|
}
|
|
2861
2723
|
});
|
|
@@ -2873,7 +2735,7 @@ export class Room extends ReadReceipt {
|
|
|
2873
2735
|
* @param events - A list of events to process
|
|
2874
2736
|
*/
|
|
2875
2737
|
addEphemeralEvents(events) {
|
|
2876
|
-
for (
|
|
2738
|
+
for (const event of events) {
|
|
2877
2739
|
if (event.getType() === EventType.Typing) {
|
|
2878
2740
|
this.currentState.setTypingEvent(event);
|
|
2879
2741
|
} else if (event.getType() === EventType.Receipt) {
|
|
@@ -2887,7 +2749,7 @@ export class Room extends ReadReceipt {
|
|
|
2887
2749
|
* @param eventIds - A list of eventIds to remove.
|
|
2888
2750
|
*/
|
|
2889
2751
|
removeEvents(eventIds) {
|
|
2890
|
-
for (
|
|
2752
|
+
for (const eventId of eventIds) {
|
|
2891
2753
|
this.removeEvent(eventId);
|
|
2892
2754
|
}
|
|
2893
2755
|
}
|
|
@@ -2900,9 +2762,9 @@ export class Room extends ReadReceipt {
|
|
|
2900
2762
|
* @returns true if the event was removed from any of the room's timeline sets
|
|
2901
2763
|
*/
|
|
2902
2764
|
removeEvent(eventId) {
|
|
2903
|
-
|
|
2904
|
-
for (
|
|
2905
|
-
|
|
2765
|
+
let removedAny = false;
|
|
2766
|
+
for (const timelineSet of this.timelineSets) {
|
|
2767
|
+
const removed = timelineSet.removeEvent(eventId);
|
|
2906
2768
|
if (removed) {
|
|
2907
2769
|
if (removed.isRedaction()) {
|
|
2908
2770
|
this.revertRedactionLocalEcho(removed);
|
|
@@ -2924,14 +2786,14 @@ export class Room extends ReadReceipt {
|
|
|
2924
2786
|
recalculate() {
|
|
2925
2787
|
// set fake stripped state events if this is an invite room so logic remains
|
|
2926
2788
|
// consistent elsewhere.
|
|
2927
|
-
|
|
2789
|
+
const membershipEvent = this.currentState.getStateEvents(EventType.RoomMember, this.myUserId);
|
|
2928
2790
|
if (membershipEvent) {
|
|
2929
|
-
|
|
2791
|
+
const membership = membershipEvent.getContent().membership;
|
|
2930
2792
|
this.updateMyMembership(membership);
|
|
2931
2793
|
if (membership === KnownMembership.Invite) {
|
|
2932
|
-
|
|
2794
|
+
const strippedStateEvents = membershipEvent.getUnsigned().invite_room_state || [];
|
|
2933
2795
|
strippedStateEvents.forEach(strippedEvent => {
|
|
2934
|
-
|
|
2796
|
+
const existingEvent = this.currentState.getStateEvents(strippedEvent.type, strippedEvent.state_key);
|
|
2935
2797
|
if (!existingEvent) {
|
|
2936
2798
|
// set the fake stripped event instead
|
|
2937
2799
|
this.currentState.setStateEvents([new MatrixEvent({
|
|
@@ -2946,7 +2808,7 @@ export class Room extends ReadReceipt {
|
|
|
2946
2808
|
});
|
|
2947
2809
|
}
|
|
2948
2810
|
}
|
|
2949
|
-
|
|
2811
|
+
const oldName = this.name;
|
|
2950
2812
|
this.name = this.calculateRoomName(this.myUserId);
|
|
2951
2813
|
this.normalizedName = normalize(this.name);
|
|
2952
2814
|
this.summary = new RoomSummary(this.roomId, {
|
|
@@ -2983,12 +2845,12 @@ export class Room extends ReadReceipt {
|
|
|
2983
2845
|
* @param events - an array of account_data events to add
|
|
2984
2846
|
*/
|
|
2985
2847
|
addAccountData(events) {
|
|
2986
|
-
for (
|
|
2848
|
+
for (const event of events) {
|
|
2987
2849
|
if (event.getType() === "m.tag") {
|
|
2988
2850
|
this.addTags(event);
|
|
2989
2851
|
}
|
|
2990
|
-
|
|
2991
|
-
|
|
2852
|
+
const eventType = event.getType();
|
|
2853
|
+
const lastEvent = this.accountData.get(eventType);
|
|
2992
2854
|
this.accountData.set(eventType, event);
|
|
2993
2855
|
this.emit(RoomEvent.AccountData, event, this, lastEvent);
|
|
2994
2856
|
}
|
|
@@ -3043,10 +2905,7 @@ export class Room extends ReadReceipt {
|
|
|
3043
2905
|
// eslint-disable-next-line
|
|
3044
2906
|
_unstable_addStickyEvents(events) {
|
|
3045
2907
|
// ALWAYS filter out any events that are past retention
|
|
3046
|
-
events = events.filter(e =>
|
|
3047
|
-
var _this$retention$shoul3, _this$retention3;
|
|
3048
|
-
return (_this$retention$shoul3 = (_this$retention3 = this.retention) === null || _this$retention3 === void 0 ? void 0 : _this$retention3.shouldEventBeRetained(e)) !== null && _this$retention$shoul3 !== void 0 ? _this$retention$shoul3 : true;
|
|
3049
|
-
});
|
|
2908
|
+
events = events.filter(e => this.retention?.shouldEventBeRetained(e) ?? true);
|
|
3050
2909
|
return this.stickyEvents.addStickyEvents(events);
|
|
3051
2910
|
}
|
|
3052
2911
|
|
|
@@ -3065,10 +2924,10 @@ export class Room extends ReadReceipt {
|
|
|
3065
2924
|
* @returns true if the user should be permitted to issue invites for this room.
|
|
3066
2925
|
*/
|
|
3067
2926
|
canInvite(userId) {
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
|
|
2927
|
+
let canInvite = this.getMyMembership() === KnownMembership.Join;
|
|
2928
|
+
const powerLevelsEvent = this.currentState.getStateEvents(EventType.RoomPowerLevels, "");
|
|
2929
|
+
const powerLevels = powerLevelsEvent && powerLevelsEvent.getContent();
|
|
2930
|
+
const me = this.getMember(userId);
|
|
3072
2931
|
if (powerLevels && me && powerLevels.invite > me.powerLevel) {
|
|
3073
2932
|
canInvite = false;
|
|
3074
2933
|
}
|
|
@@ -3104,7 +2963,7 @@ export class Room extends ReadReceipt {
|
|
|
3104
2963
|
* @returns the type of the room.
|
|
3105
2964
|
*/
|
|
3106
2965
|
getType() {
|
|
3107
|
-
|
|
2966
|
+
const createEvent = this.currentState.getStateEvents(EventType.RoomCreate, "");
|
|
3108
2967
|
if (!createEvent) {
|
|
3109
2968
|
if (!this.getTypeWarning) {
|
|
3110
2969
|
logger.warn("[getType] Room " + this.roomId + " does not have an m.room.create event");
|
|
@@ -3157,9 +3016,8 @@ export class Room extends ReadReceipt {
|
|
|
3157
3016
|
* this predecessor comes from a RoomCreate event (rather than a
|
|
3158
3017
|
* RoomPredecessor, which has the optional via_servers property).
|
|
3159
3018
|
*/
|
|
3160
|
-
findPredecessor() {
|
|
3161
|
-
|
|
3162
|
-
var currentState = this.getLiveTimeline().getState(EventTimeline.FORWARDS);
|
|
3019
|
+
findPredecessor(msc3946ProcessDynamicPredecessor = false) {
|
|
3020
|
+
const currentState = this.getLiveTimeline().getState(EventTimeline.FORWARDS);
|
|
3163
3021
|
if (!currentState) {
|
|
3164
3022
|
return null;
|
|
3165
3023
|
}
|
|
@@ -3167,7 +3025,7 @@ export class Room extends ReadReceipt {
|
|
|
3167
3025
|
}
|
|
3168
3026
|
roomNameGenerator(state) {
|
|
3169
3027
|
if (this.client.roomNameGenerator) {
|
|
3170
|
-
|
|
3028
|
+
const name = this.client.roomNameGenerator(this.roomId, state);
|
|
3171
3029
|
if (name !== null) {
|
|
3172
3030
|
return name;
|
|
3173
3031
|
}
|
|
@@ -3178,13 +3036,13 @@ export class Room extends ReadReceipt {
|
|
|
3178
3036
|
case RoomNameType.Generated:
|
|
3179
3037
|
switch (state.subtype) {
|
|
3180
3038
|
case "Inviting":
|
|
3181
|
-
return
|
|
3039
|
+
return `Inviting ${memberNamesToRoomName(state.names, state.count)}`;
|
|
3182
3040
|
default:
|
|
3183
3041
|
return memberNamesToRoomName(state.names, state.count);
|
|
3184
3042
|
}
|
|
3185
3043
|
case RoomNameType.EmptyRoom:
|
|
3186
3044
|
if (state.oldName) {
|
|
3187
|
-
return
|
|
3045
|
+
return `Empty room (was ${state.oldName})`;
|
|
3188
3046
|
} else {
|
|
3189
3047
|
return "Empty room";
|
|
3190
3048
|
}
|
|
@@ -3200,11 +3058,9 @@ export class Room extends ReadReceipt {
|
|
|
3200
3058
|
* was no m.room.name event.
|
|
3201
3059
|
* @returns The calculated room name.
|
|
3202
3060
|
*/
|
|
3203
|
-
calculateRoomName(userId) {
|
|
3204
|
-
var ignoreRoomNameEvent = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
|
|
3061
|
+
calculateRoomName(userId, ignoreRoomNameEvent = false) {
|
|
3205
3062
|
if (!ignoreRoomNameEvent) {
|
|
3206
|
-
|
|
3207
|
-
var name = (_this$currentState$ge4 = this.currentState.getStateEvents(EventType.RoomName, "")) === null || _this$currentState$ge4 === void 0 ? void 0 : _this$currentState$ge4.getContent().name;
|
|
3063
|
+
const name = this.currentState.getStateEvents(EventType.RoomName, "")?.getContent().name;
|
|
3208
3064
|
if (name && typeof name === "string") {
|
|
3209
3065
|
return this.roomNameGenerator({
|
|
3210
3066
|
type: RoomNameType.Actual,
|
|
@@ -3212,23 +3068,23 @@ export class Room extends ReadReceipt {
|
|
|
3212
3068
|
});
|
|
3213
3069
|
}
|
|
3214
3070
|
}
|
|
3215
|
-
|
|
3071
|
+
const alias = this.getCanonicalAlias();
|
|
3216
3072
|
if (alias) {
|
|
3217
3073
|
return this.roomNameGenerator({
|
|
3218
3074
|
type: RoomNameType.Actual,
|
|
3219
3075
|
name: alias
|
|
3220
3076
|
});
|
|
3221
3077
|
}
|
|
3222
|
-
|
|
3223
|
-
|
|
3078
|
+
const joinedMemberCount = this.currentState.getJoinedMemberCount();
|
|
3079
|
+
const invitedMemberCount = this.currentState.getInvitedMemberCount();
|
|
3224
3080
|
// -1 because these numbers include the syncing user
|
|
3225
|
-
|
|
3081
|
+
let inviteJoinCount = joinedMemberCount + invitedMemberCount - 1;
|
|
3226
3082
|
|
|
3227
3083
|
// get service members (e.g. helper bots) for exclusion
|
|
3228
|
-
|
|
3084
|
+
const excludedUserIds = this.getFunctionalMembers();
|
|
3229
3085
|
|
|
3230
3086
|
// get members from heroes that are NOT ourselves
|
|
3231
|
-
|
|
3087
|
+
let otherNames = [];
|
|
3232
3088
|
if (this.heroes) {
|
|
3233
3089
|
// if we have heroes, use those as the names
|
|
3234
3090
|
this.heroes.forEach(hero => {
|
|
@@ -3243,16 +3099,17 @@ export class Room extends ReadReceipt {
|
|
|
3243
3099
|
if (hero.displayName) {
|
|
3244
3100
|
otherNames.push(hero.displayName);
|
|
3245
3101
|
} else {
|
|
3246
|
-
|
|
3102
|
+
const member = this.getMember(hero.userId);
|
|
3247
3103
|
otherNames.push(member ? member.name : hero.userId);
|
|
3248
3104
|
}
|
|
3249
3105
|
});
|
|
3250
3106
|
} else {
|
|
3251
|
-
|
|
3107
|
+
let otherMembers = this.currentState.getMembers().filter(m => {
|
|
3252
3108
|
return m.userId !== userId && (m.membership === KnownMembership.Invite || m.membership === KnownMembership.Join);
|
|
3253
3109
|
});
|
|
3254
|
-
otherMembers = otherMembers.filter(
|
|
3255
|
-
|
|
3110
|
+
otherMembers = otherMembers.filter(({
|
|
3111
|
+
userId
|
|
3112
|
+
}) => {
|
|
3256
3113
|
// filter service members
|
|
3257
3114
|
if (excludedUserIds.includes(userId)) {
|
|
3258
3115
|
inviteJoinCount--;
|
|
@@ -3261,7 +3118,7 @@ export class Room extends ReadReceipt {
|
|
|
3261
3118
|
return true;
|
|
3262
3119
|
});
|
|
3263
3120
|
// make sure members have stable order
|
|
3264
|
-
|
|
3121
|
+
const collator = new Intl.Collator();
|
|
3265
3122
|
otherMembers.sort((a, b) => collator.compare(a.userId, b.userId));
|
|
3266
3123
|
// only 5 first members, immitate summaryHeroes
|
|
3267
3124
|
otherMembers = otherMembers.slice(0, 5);
|
|
@@ -3274,13 +3131,13 @@ export class Room extends ReadReceipt {
|
|
|
3274
3131
|
count: inviteJoinCount
|
|
3275
3132
|
});
|
|
3276
3133
|
}
|
|
3277
|
-
|
|
3134
|
+
const myMembership = this.getMyMembership();
|
|
3278
3135
|
// if I have created a room and invited people through
|
|
3279
3136
|
// 3rd party invites
|
|
3280
3137
|
if (myMembership == KnownMembership.Join) {
|
|
3281
|
-
|
|
3282
|
-
if (thirdPartyInvites
|
|
3283
|
-
|
|
3138
|
+
const thirdPartyInvites = this.currentState.getStateEvents(EventType.RoomThirdPartyInvite);
|
|
3139
|
+
if (thirdPartyInvites?.length) {
|
|
3140
|
+
const thirdPartyNames = thirdPartyInvites.map(i => {
|
|
3284
3141
|
return i.getContent().display_name;
|
|
3285
3142
|
});
|
|
3286
3143
|
return this.roomNameGenerator({
|
|
@@ -3293,14 +3150,14 @@ export class Room extends ReadReceipt {
|
|
|
3293
3150
|
}
|
|
3294
3151
|
|
|
3295
3152
|
// let's try to figure out who was here before
|
|
3296
|
-
|
|
3153
|
+
let leftNames = otherNames;
|
|
3297
3154
|
// if we didn't have heroes, try finding them in the room state
|
|
3298
3155
|
if (!leftNames.length) {
|
|
3299
3156
|
leftNames = this.currentState.getMembers().filter(m => {
|
|
3300
3157
|
return m.userId !== userId && m.membership !== KnownMembership.Invite && m.membership !== KnownMembership.Join;
|
|
3301
3158
|
}).map(m => m.name);
|
|
3302
3159
|
}
|
|
3303
|
-
|
|
3160
|
+
let oldName;
|
|
3304
3161
|
if (leftNames.length) {
|
|
3305
3162
|
oldName = this.roomNameGenerator({
|
|
3306
3163
|
type: RoomNameType.Generated,
|
|
@@ -3323,18 +3180,18 @@ export class Room extends ReadReceipt {
|
|
|
3323
3180
|
* patch it to reflect the visibility change and inform listeners.
|
|
3324
3181
|
*/
|
|
3325
3182
|
applyNewVisibilityEvent(event) {
|
|
3326
|
-
|
|
3183
|
+
const visibilityChange = event.asVisibilityChange();
|
|
3327
3184
|
if (!visibilityChange) {
|
|
3328
3185
|
// The event is ill-formed.
|
|
3329
3186
|
return;
|
|
3330
3187
|
}
|
|
3331
3188
|
|
|
3332
3189
|
// Ignore visibility change events that are not emitted by moderators.
|
|
3333
|
-
|
|
3190
|
+
const userId = event.getSender();
|
|
3334
3191
|
if (!userId) {
|
|
3335
3192
|
return;
|
|
3336
3193
|
}
|
|
3337
|
-
|
|
3194
|
+
const isPowerSufficient = EVENT_VISIBILITY_CHANGE_TYPE.name && this.currentState.maySendStateEvent(EVENT_VISIBILITY_CHANGE_TYPE.name, userId) || EVENT_VISIBILITY_CHANGE_TYPE.altName && this.currentState.maySendStateEvent(EVENT_VISIBILITY_CHANGE_TYPE.altName, userId);
|
|
3338
3195
|
if (!isPowerSufficient) {
|
|
3339
3196
|
// Powerlevel is insufficient.
|
|
3340
3197
|
return;
|
|
@@ -3344,7 +3201,7 @@ export class Room extends ReadReceipt {
|
|
|
3344
3201
|
// If the event is not in our timeline and we only receive it later,
|
|
3345
3202
|
// we may need to apply the visibility change at a later date.
|
|
3346
3203
|
|
|
3347
|
-
|
|
3204
|
+
const visibilityEventsOnOriginalEvent = this.visibilityEvents.get(visibilityChange.eventId);
|
|
3348
3205
|
if (visibilityEventsOnOriginalEvent) {
|
|
3349
3206
|
// It would be tempting to simply erase the latest visibility change
|
|
3350
3207
|
// but we need to record all of the changes in case the latest change
|
|
@@ -3353,10 +3210,10 @@ export class Room extends ReadReceipt {
|
|
|
3353
3210
|
// In practice, linear scans through `visibilityEvents` should be fast.
|
|
3354
3211
|
// However, to protect against a potential DoS attack, we limit the
|
|
3355
3212
|
// number of iterations in this loop.
|
|
3356
|
-
|
|
3357
|
-
|
|
3213
|
+
let index = visibilityEventsOnOriginalEvent.length - 1;
|
|
3214
|
+
const min = Math.max(0, visibilityEventsOnOriginalEvent.length - MAX_NUMBER_OF_VISIBILITY_EVENTS_TO_SCAN_THROUGH);
|
|
3358
3215
|
for (; index >= min; --index) {
|
|
3359
|
-
|
|
3216
|
+
const target = visibilityEventsOnOriginalEvent[index];
|
|
3360
3217
|
if (target.getTs() < event.getTs()) {
|
|
3361
3218
|
break;
|
|
3362
3219
|
}
|
|
@@ -3373,7 +3230,7 @@ export class Room extends ReadReceipt {
|
|
|
3373
3230
|
// Finally, let's check if the event is already in our timeline.
|
|
3374
3231
|
// If so, we need to patch it and inform listeners.
|
|
3375
3232
|
|
|
3376
|
-
|
|
3233
|
+
const originalEvent = this.findEventById(visibilityChange.eventId);
|
|
3377
3234
|
if (!originalEvent) {
|
|
3378
3235
|
return;
|
|
3379
3236
|
}
|
|
@@ -3384,16 +3241,16 @@ export class Room extends ReadReceipt {
|
|
|
3384
3241
|
if (!event.isVisibilityEvent) {
|
|
3385
3242
|
throw new Error("expected a visibility change event");
|
|
3386
3243
|
}
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
|
|
3244
|
+
const relation = event.getRelation();
|
|
3245
|
+
const originalEventId = relation?.event_id;
|
|
3246
|
+
const visibilityEventsOnOriginalEvent = this.visibilityEvents.get(originalEventId);
|
|
3390
3247
|
if (!visibilityEventsOnOriginalEvent) {
|
|
3391
3248
|
// No visibility changes on the original event.
|
|
3392
3249
|
// In particular, this change event was not recorded,
|
|
3393
3250
|
// most likely because it was ill-formed.
|
|
3394
3251
|
return;
|
|
3395
3252
|
}
|
|
3396
|
-
|
|
3253
|
+
const index = visibilityEventsOnOriginalEvent.findIndex(change => change.getId() === event.getId());
|
|
3397
3254
|
if (index === -1) {
|
|
3398
3255
|
// This change event was not recorded, most likely because
|
|
3399
3256
|
// it was ill-formed.
|
|
@@ -3404,7 +3261,7 @@ export class Room extends ReadReceipt {
|
|
|
3404
3261
|
|
|
3405
3262
|
// If we removed the latest visibility change event, propagate changes.
|
|
3406
3263
|
if (index === visibilityEventsOnOriginalEvent.length) {
|
|
3407
|
-
|
|
3264
|
+
const originalEvent = this.findEventById(originalEventId);
|
|
3408
3265
|
if (!originalEvent) {
|
|
3409
3266
|
return;
|
|
3410
3267
|
}
|
|
@@ -3413,8 +3270,8 @@ export class Room extends ReadReceipt {
|
|
|
3413
3270
|
this.visibilityEvents.delete(originalEventId);
|
|
3414
3271
|
originalEvent.applyVisibilityEvent();
|
|
3415
3272
|
} else {
|
|
3416
|
-
|
|
3417
|
-
|
|
3273
|
+
const newEvent = visibilityEventsOnOriginalEvent[visibilityEventsOnOriginalEvent.length - 1];
|
|
3274
|
+
const newVisibility = newEvent.asVisibilityChange();
|
|
3418
3275
|
if (!newVisibility) {
|
|
3419
3276
|
// Event is ill-formed.
|
|
3420
3277
|
// This breaks our invariant.
|
|
@@ -3435,13 +3292,13 @@ export class Room extends ReadReceipt {
|
|
|
3435
3292
|
* change event.
|
|
3436
3293
|
*/
|
|
3437
3294
|
applyPendingVisibilityEvents(event) {
|
|
3438
|
-
|
|
3295
|
+
const visibilityEvents = this.visibilityEvents.get(event.getId());
|
|
3439
3296
|
if (!visibilityEvents || visibilityEvents.length == 0) {
|
|
3440
3297
|
// No pending visibility change in store.
|
|
3441
3298
|
return;
|
|
3442
3299
|
}
|
|
3443
|
-
|
|
3444
|
-
|
|
3300
|
+
const visibilityEvent = visibilityEvents[visibilityEvents.length - 1];
|
|
3301
|
+
const visibilityChange = visibilityEvent.asVisibilityChange();
|
|
3445
3302
|
if (!visibilityChange) {
|
|
3446
3303
|
return;
|
|
3447
3304
|
}
|
|
@@ -3505,8 +3362,8 @@ export class Room extends ReadReceipt {
|
|
|
3505
3362
|
*/
|
|
3506
3363
|
fixupNotifications(userId) {
|
|
3507
3364
|
super.fixupNotifications(userId);
|
|
3508
|
-
|
|
3509
|
-
for (
|
|
3365
|
+
const unreadThreads = this.getThreads().filter(thread => this.getThreadUnreadNotificationCount(thread.id, NotificationCountType.Total) > 0);
|
|
3366
|
+
for (const thread of unreadThreads) {
|
|
3510
3367
|
thread.fixupNotifications(userId);
|
|
3511
3368
|
}
|
|
3512
3369
|
}
|
|
@@ -3541,13 +3398,12 @@ export class Room extends ReadReceipt {
|
|
|
3541
3398
|
* will encrypt outgoing events).
|
|
3542
3399
|
*/
|
|
3543
3400
|
hasEncryptionStateEvent() {
|
|
3544
|
-
|
|
3545
|
-
return Boolean((_this$getLiveTimeline = this.getLiveTimeline().getState(EventTimeline.FORWARDS)) === null || _this$getLiveTimeline === void 0 ? void 0 : _this$getLiveTimeline.getStateEvents(EventType.RoomEncryption, ""));
|
|
3401
|
+
return Boolean(this.getLiveTimeline().getState(EventTimeline.FORWARDS)?.getStateEvents(EventType.RoomEncryption, ""));
|
|
3546
3402
|
}
|
|
3547
3403
|
}
|
|
3548
3404
|
|
|
3549
3405
|
// a map from current event status to a list of allowed next statuses
|
|
3550
|
-
|
|
3406
|
+
const ALLOWED_TRANSITIONS = {
|
|
3551
3407
|
[EventStatus.ENCRYPTING]: [EventStatus.SENDING, EventStatus.NOT_SENT, EventStatus.CANCELLED],
|
|
3552
3408
|
[EventStatus.SENDING]: [EventStatus.ENCRYPTING, EventStatus.QUEUED, EventStatus.NOT_SENT, EventStatus.SENT],
|
|
3553
3409
|
[EventStatus.QUEUED]: [EventStatus.SENDING, EventStatus.NOT_SENT, EventStatus.CANCELLED],
|
|
@@ -3555,7 +3411,7 @@ var ALLOWED_TRANSITIONS = {
|
|
|
3555
3411
|
[EventStatus.NOT_SENT]: [EventStatus.SENDING, EventStatus.QUEUED, EventStatus.CANCELLED],
|
|
3556
3412
|
[EventStatus.CANCELLED]: []
|
|
3557
3413
|
};
|
|
3558
|
-
export
|
|
3414
|
+
export let RoomNameType = /*#__PURE__*/function (RoomNameType) {
|
|
3559
3415
|
RoomNameType[RoomNameType["EmptyRoom"] = 0] = "EmptyRoom";
|
|
3560
3416
|
RoomNameType[RoomNameType["Generated"] = 1] = "Generated";
|
|
3561
3417
|
RoomNameType[RoomNameType["Actual"] = 2] = "Actual";
|
|
@@ -3563,19 +3419,19 @@ export var RoomNameType = /*#__PURE__*/function (RoomNameType) {
|
|
|
3563
3419
|
}({});
|
|
3564
3420
|
// Can be overriden by IMatrixClientCreateOpts::memberNamesToRoomNameFn
|
|
3565
3421
|
function memberNamesToRoomName(names, count) {
|
|
3566
|
-
|
|
3422
|
+
const countWithoutMe = count - 1;
|
|
3567
3423
|
if (!names.length) {
|
|
3568
3424
|
return "Empty room";
|
|
3569
3425
|
} else if (names.length === 1 && countWithoutMe <= 1) {
|
|
3570
3426
|
return names[0];
|
|
3571
3427
|
} else if (names.length === 2 && countWithoutMe <= 2) {
|
|
3572
|
-
return
|
|
3428
|
+
return `${names[0]} and ${names[1]}`;
|
|
3573
3429
|
} else {
|
|
3574
|
-
|
|
3430
|
+
const plural = countWithoutMe > 1;
|
|
3575
3431
|
if (plural) {
|
|
3576
|
-
return
|
|
3432
|
+
return `${names[0]} and ${countWithoutMe} others`;
|
|
3577
3433
|
} else {
|
|
3578
|
-
return
|
|
3434
|
+
return `${names[0]} and 1 other`;
|
|
3579
3435
|
}
|
|
3580
3436
|
}
|
|
3581
3437
|
}
|