atagen

matrix-rust-sdk

public
Star0
Watch0

Commit cc2b13ea185c

tarball

atagen <boss@atagen.co>2026-10-24 07:01 UTC

1 file changed+25-2
indexeddb: clear the other half of a room's state when its RoomInfo is saved

Reads take stripped user ids and state over the real ones whenever any exist, and save_changes only removed stripped entries per user, so one invite leftover pinned a joined room's roster to invitee and inviter. This matches SqliteStateStore::save_changes, which already calls remove_maybe_stripped_room_data for every saved RoomInfo.
Modified file: crates/matrix-sdk-indexeddb/src/state_store/mod.rs+25 additions−2 deletions
@@ -28,7 +28,7 @@ use indexed_db_futures::{
2828 };
2929 use matrix_sdk_base::{
3030 MinimalRoomMemberEvent, ROOM_VERSION_FALLBACK, ROOM_VERSION_RULES_FALLBACK, RoomInfo,
31- RoomMemberships, StateStoreDataKey, StateStoreDataValue, ThreadSubscriptionCatchupToken,
31+ RoomMemberships, RoomState, StateStoreDataKey, StateStoreDataValue, ThreadSubscriptionCatchupToken,
3232 deserialized_responses::{DisplayName, RawAnySyncOrStrippedState},
3333 store::{
3434 ChildTransactionId, ComposerDraft, DependentQueuedRequest, DependentQueuedRequestKind,
@@ -791,7 +791,13 @@ impl_state_store!({
791791 }
792792
793793 if !changes.room_infos.is_empty() {
794- stores.insert(keys::ROOM_INFOS);
794+ stores.extend([
795+ keys::ROOM_INFOS,
796+ keys::ROOM_STATE,
797+ keys::USER_IDS,
798+ keys::STRIPPED_ROOM_STATE,
799+ keys::STRIPPED_USER_IDS,
800+ ]);
795801 }
796802
797803 if !changes.stripped_state.is_empty() {
@@ -856,6 +862,23 @@ impl_state_store!({
856862 }
857863 }
858864
865+ // Reads prefer stripped data when any exists, so a single leftover invite
866+ // entry would shadow a joined room's whole roster. Matches SQLite.
867+ for (room_id, room_info) in &changes.room_infos {
868+ let stale_stores = if room_info.state() == RoomState::Invited {
869+ [keys::ROOM_STATE, keys::USER_IDS]
870+ } else {
871+ [keys::STRIPPED_ROOM_STATE, keys::STRIPPED_USER_IDS]
872+ };
873+ for store_name in stale_stores {
874+ let store = tx.object_store(store_name)?;
875+ let range = self.encode_to_range(store_name, room_id);
876+ for key in store.get_all_keys::<JsValue>().with_query(&range).await? {
877+ store.delete(&key?).build()?;
878+ }
879+ }
880+ }
881+
859882 if !changes.state.is_empty() {
860883 let state = tx.object_store(keys::ROOM_STATE)?;
861884 let profiles = tx.object_store(keys::PROFILES)?;