Conform more of the codebase to strictNullChecks (#10518

* Conform more of the codebase to `strictNullChecks`

* Iterate

* Fix tests
This commit is contained in:
Michael Telatynski
2023-04-06 11:10:14 +01:00
committed by GitHub
parent e9cc88b872
commit 55d3548330
23 changed files with 107 additions and 99 deletions
+2 -2
View File
@@ -30,7 +30,7 @@ export abstract class AsyncStoreWithClient<T extends Object> extends AsyncStore<
// Create an anonymous class to avoid code duplication
const asyncStore = this; // eslint-disable-line @typescript-eslint/no-this-alias
this.readyStore = new (class extends ReadyWatchingStore {
public get mxClient(): MatrixClient {
public get mxClient(): MatrixClient | null {
return this.matrixClient;
}
@@ -48,7 +48,7 @@ export abstract class AsyncStoreWithClient<T extends Object> extends AsyncStore<
await this.readyStore.start();
}
public get matrixClient(): MatrixClient {
public get matrixClient(): MatrixClient | null {
return this.readyStore.mxClient;
}
+1 -1
View File
@@ -135,7 +135,7 @@ export default class AutoRageshakeStore extends AsyncStoreWithClient<IState> {
...eventInfo,
recipient_rageshake: rageshakeURL,
};
this.matrixClient.sendToDevice(
this.matrixClient?.sendToDevice(
AUTO_RS_REQUEST,
new Map([["messageContent.user_id", new Map([[messageContent.device_id, messageContent]])]]),
);
+13 -9
View File
@@ -21,7 +21,7 @@ import { ClientEvent } from "matrix-js-sdk/src/client";
import SettingsStore from "../settings/SettingsStore";
import { AsyncStoreWithClient } from "./AsyncStoreWithClient";
import defaultDispatcher from "../dispatcher/dispatcher";
import { arrayHasDiff } from "../utils/arrays";
import { arrayHasDiff, filterBoolean } from "../utils/arrays";
import { SettingLevel } from "../settings/SettingLevel";
import { Action } from "../dispatcher/actions";
import { SettingUpdatedPayload } from "../dispatcher/payloads/SettingUpdatedPayload";
@@ -75,7 +75,7 @@ export class BreadcrumbsStore extends AsyncStoreWithClient<IState> {
public get meetsRoomRequirement(): boolean {
if (SettingsStore.getValue("feature_breadcrumbs_v2")) return true;
const msc3946ProcessDynamicPredecessor = SettingsStore.getValue("feature_dynamic_room_predecessors");
return this.matrixClient?.getVisibleRooms(msc3946ProcessDynamicPredecessor).length >= 20;
return !!this.matrixClient && this.matrixClient.getVisibleRooms(msc3946ProcessDynamicPredecessor).length >= 20;
}
protected async onAction(payload: SettingUpdatedPayload | ViewRoomPayload | JoinRoomPayload): Promise<void> {
@@ -107,13 +107,17 @@ export class BreadcrumbsStore extends AsyncStoreWithClient<IState> {
await this.updateRooms();
await this.updateState({ enabled: SettingsStore.getValue("breadcrumbs", null) });
this.matrixClient.on(RoomEvent.MyMembership, this.onMyMembership);
this.matrixClient.on(ClientEvent.Room, this.onRoom);
if (this.matrixClient) {
this.matrixClient.on(RoomEvent.MyMembership, this.onMyMembership);
this.matrixClient.on(ClientEvent.Room, this.onRoom);
}
}
protected async onNotReady(): Promise<void> {
this.matrixClient.removeListener(RoomEvent.MyMembership, this.onMyMembership);
this.matrixClient.removeListener(ClientEvent.Room, this.onRoom);
if (this.matrixClient) {
this.matrixClient.removeListener(RoomEvent.MyMembership, this.onMyMembership);
this.matrixClient.removeListener(ClientEvent.Room, this.onRoom);
}
}
private onMyMembership = async (room: Room): Promise<void> => {
@@ -137,7 +141,7 @@ export class BreadcrumbsStore extends AsyncStoreWithClient<IState> {
let roomIds = SettingsStore.getValue<string[]>("breadcrumb_rooms");
if (!roomIds || roomIds.length === 0) roomIds = [];
const rooms = roomIds.map((r) => this.matrixClient.getRoom(r)).filter((r) => !!r);
const rooms = filterBoolean(roomIds.map((r) => this.matrixClient?.getRoom(r)));
const currentRooms = this.state.rooms || [];
if (!arrayHasDiff(rooms, currentRooms)) return; // no change (probably echo)
await this.updateState({ rooms });
@@ -150,8 +154,8 @@ export class BreadcrumbsStore extends AsyncStoreWithClient<IState> {
// If the room is upgraded, use that room instead. We'll also splice out
// any children of the room.
const history = this.matrixClient.getRoomUpgradeHistory(room.roomId, false, msc3946ProcessDynamicPredecessor);
if (history.length > 1) {
const history = this.matrixClient?.getRoomUpgradeHistory(room.roomId, false, msc3946ProcessDynamicPredecessor);
if (history && history.length > 1) {
room = history[history.length - 1]; // Last room is most recent in history
// Take out any room that isn't the most recent room
+7 -3
View File
@@ -53,6 +53,7 @@ export class CallStore extends AsyncStoreWithClient<{}> {
}
protected async onReady(): Promise<any> {
if (!this.matrixClient) return;
// We assume that the calls present in a room are a function of room
// widgets and group calls, so we initialize the room map here and then
// update it whenever those change
@@ -90,9 +91,11 @@ export class CallStore extends AsyncStoreWithClient<{}> {
this.calls.clear();
this._activeCalls.clear();
this.matrixClient.off(GroupCallEventHandlerEvent.Incoming, this.onGroupCall);
this.matrixClient.off(GroupCallEventHandlerEvent.Outgoing, this.onGroupCall);
this.matrixClient.off(GroupCallEventHandlerEvent.Ended, this.onGroupCall);
if (this.matrixClient) {
this.matrixClient.off(GroupCallEventHandlerEvent.Incoming, this.onGroupCall);
this.matrixClient.off(GroupCallEventHandlerEvent.Outgoing, this.onGroupCall);
this.matrixClient.off(GroupCallEventHandlerEvent.Ended, this.onGroupCall);
}
WidgetStore.instance.off(UPDATE_EVENT, this.onWidgets);
}
@@ -174,6 +177,7 @@ export class CallStore extends AsyncStoreWithClient<{}> {
}
private onWidgets = (roomId: string | null): void => {
if (!this.matrixClient) return;
if (roomId === null) {
// This store happened to start before the widget store was done
// loading all rooms, so we need to initialize each room again
+25 -15
View File
@@ -142,11 +142,13 @@ export class OwnBeaconStore extends AsyncStoreWithClient<OwnBeaconStoreState> {
}
protected async onNotReady(): Promise<void> {
this.matrixClient.removeListener(BeaconEvent.LivenessChange, this.onBeaconLiveness);
this.matrixClient.removeListener(BeaconEvent.New, this.onNewBeacon);
this.matrixClient.removeListener(BeaconEvent.Update, this.onUpdateBeacon);
this.matrixClient.removeListener(BeaconEvent.Destroy, this.onDestroyBeacon);
this.matrixClient.removeListener(RoomStateEvent.Members, this.onRoomStateMembers);
if (this.matrixClient) {
this.matrixClient.removeListener(BeaconEvent.LivenessChange, this.onBeaconLiveness);
this.matrixClient.removeListener(BeaconEvent.New, this.onNewBeacon);
this.matrixClient.removeListener(BeaconEvent.Update, this.onUpdateBeacon);
this.matrixClient.removeListener(BeaconEvent.Destroy, this.onDestroyBeacon);
this.matrixClient.removeListener(RoomStateEvent.Members, this.onRoomStateMembers);
}
SettingsStore.unwatchSetting(this.dynamicWatcherRef ?? "");
this.clearBeacons();
@@ -164,11 +166,13 @@ export class OwnBeaconStore extends AsyncStoreWithClient<OwnBeaconStoreState> {
}
protected async onReady(): Promise<void> {
this.matrixClient.on(BeaconEvent.LivenessChange, this.onBeaconLiveness);
this.matrixClient.on(BeaconEvent.New, this.onNewBeacon);
this.matrixClient.on(BeaconEvent.Update, this.onUpdateBeacon);
this.matrixClient.on(BeaconEvent.Destroy, this.onDestroyBeacon);
this.matrixClient.on(RoomStateEvent.Members, this.onRoomStateMembers);
if (this.matrixClient) {
this.matrixClient.on(BeaconEvent.LivenessChange, this.onBeaconLiveness);
this.matrixClient.on(BeaconEvent.New, this.onNewBeacon);
this.matrixClient.on(BeaconEvent.Update, this.onUpdateBeacon);
this.matrixClient.on(BeaconEvent.Destroy, this.onDestroyBeacon);
this.matrixClient.on(RoomStateEvent.Members, this.onRoomStateMembers);
}
this.dynamicWatcherRef = SettingsStore.watchSetting(
"feature_dynamic_room_predecessors",
null,
@@ -200,7 +204,8 @@ export class OwnBeaconStore extends AsyncStoreWithClient<OwnBeaconStoreState> {
* Then consider it to have an error
*/
public beaconHasLocationPublishError = (beaconId: string): boolean => {
return this.beaconLocationPublishErrorCounts.get(beaconId) >= BAIL_AFTER_CONSECUTIVE_ERROR_COUNT;
const counts = this.beaconLocationPublishErrorCounts.get(beaconId);
return counts !== undefined && counts >= BAIL_AFTER_CONSECUTIVE_ERROR_COUNT;
};
public resetLocationPublishError = (beaconId: string): void => {
@@ -246,7 +251,7 @@ export class OwnBeaconStore extends AsyncStoreWithClient<OwnBeaconStoreState> {
*/
private onNewBeacon = (_event: MatrixEvent, beacon: Beacon): void => {
if (!isOwnBeacon(beacon, this.matrixClient.getUserId()!)) {
if (!this.matrixClient || !isOwnBeacon(beacon, this.matrixClient.getUserId()!)) {
return;
}
this.addBeacon(beacon);
@@ -257,7 +262,7 @@ export class OwnBeaconStore extends AsyncStoreWithClient<OwnBeaconStoreState> {
* This will be called when a beacon is replaced
*/
private onUpdateBeacon = (_event: MatrixEvent, beacon: Beacon): void => {
if (!isOwnBeacon(beacon, this.matrixClient.getUserId()!)) {
if (!this.matrixClient || !isOwnBeacon(beacon, this.matrixClient.getUserId()!)) {
return;
}
@@ -296,7 +301,11 @@ export class OwnBeaconStore extends AsyncStoreWithClient<OwnBeaconStoreState> {
*/
private onRoomStateMembers = (_event: MatrixEvent, roomState: RoomState, member: RoomMember): void => {
// no beacons for this room, ignore
if (!this.beaconsByRoomId.has(roomState.roomId) || member.userId !== this.matrixClient.getUserId()) {
if (
!this.matrixClient ||
!this.beaconsByRoomId.has(roomState.roomId) ||
member.userId !== this.matrixClient.getUserId()
) {
return;
}
@@ -332,7 +341,8 @@ export class OwnBeaconStore extends AsyncStoreWithClient<OwnBeaconStoreState> {
};
private initialiseBeaconState = (): void => {
const userId = this.matrixClient.getUserId()!;
if (!this.matrixClient) return;
const userId = this.matrixClient.getSafeUserId();
const visibleRooms = this.matrixClient.getVisibleRooms(
SettingsStore.getValue("feature_dynamic_room_predecessors"),
);
+4 -2
View File
@@ -112,7 +112,8 @@ export class OwnProfileStore extends AsyncStoreWithClient<IState> {
}
protected async onReady(): Promise<void> {
const myUserId = this.matrixClient.getUserId()!;
if (!this.matrixClient) return;
const myUserId = this.matrixClient.getSafeUserId();
this.monitoredUser = this.matrixClient.getUser(myUserId);
if (this.monitoredUser) {
this.monitoredUser.on(UserEvent.DisplayName, this.onProfileUpdate);
@@ -132,9 +133,10 @@ export class OwnProfileStore extends AsyncStoreWithClient<IState> {
private onProfileUpdate = throttle(
async (): Promise<void> => {
if (!this.matrixClient) return;
// We specifically do not use the User object we stored for profile info as it
// could easily be wrong (such as per-room instead of global profile).
const profileInfo = await this.matrixClient.getProfileInfo(this.matrixClient.getUserId()!);
const profileInfo = await this.matrixClient.getProfileInfo(this.matrixClient.getSafeUserId());
if (profileInfo.displayname) {
window.localStorage.setItem(KEY_DISPLAY_NAME, profileInfo.displayname);
} else {
+8 -24
View File
@@ -27,7 +27,6 @@ import defaultDispatcher from "../dispatcher/dispatcher";
import WidgetEchoStore from "../stores/WidgetEchoStore";
import ActiveWidgetStore from "../stores/ActiveWidgetStore";
import WidgetUtils from "../utils/WidgetUtils";
import { WidgetType } from "../widgets/WidgetType";
import { UPDATE_EVENT } from "./AsyncStore";
interface IState {}
@@ -74,6 +73,7 @@ export default class WidgetStore extends AsyncStoreWithClient<IState> {
}
protected async onReady(): Promise<any> {
if (!this.matrixClient) return;
this.matrixClient.on(ClientEvent.Room, this.onRoom);
this.matrixClient.on(RoomStateEvent.Events, this.onRoomStateEvents);
this.matrixClient.getRooms().forEach((room: Room) => {
@@ -83,8 +83,10 @@ export default class WidgetStore extends AsyncStoreWithClient<IState> {
}
protected async onNotReady(): Promise<any> {
this.matrixClient.off(ClientEvent.Room, this.onRoom);
this.matrixClient.off(RoomStateEvent.Events, this.onRoomStateEvents);
if (this.matrixClient) {
this.matrixClient.off(ClientEvent.Room, this.onRoom);
this.matrixClient.off(RoomStateEvent.Events, this.onRoomStateEvents);
}
this.widgetMap = new Map();
this.roomMap = new Map();
await this.reset({});
@@ -95,9 +97,9 @@ export default class WidgetStore extends AsyncStoreWithClient<IState> {
return;
}
private onWidgetEchoStoreUpdate = (roomId: string, widgetId: string): void => {
private onWidgetEchoStoreUpdate = (roomId: string): void => {
this.initRoom(roomId);
this.loadRoomWidgets(this.matrixClient.getRoom(roomId));
this.loadRoomWidgets(this.matrixClient?.getRoom(roomId) ?? null);
this.emit(UPDATE_EVENT, roomId);
};
@@ -174,7 +176,7 @@ export default class WidgetStore extends AsyncStoreWithClient<IState> {
if (ev.getType() !== "im.vector.modular.widgets") return; // TODO: Support m.widget too
const roomId = ev.getRoomId()!;
this.initRoom(roomId);
this.loadRoomWidgets(this.matrixClient.getRoom(roomId));
this.loadRoomWidgets(this.matrixClient?.getRoom(roomId) ?? null);
this.emit(UPDATE_EVENT, roomId);
};
@@ -207,24 +209,6 @@ export default class WidgetStore extends AsyncStoreWithClient<IState> {
roomApps.widgets = roomApps.widgets.filter((app) => !(app.id === widgetId && app.roomId === roomId));
}
}
public doesRoomHaveConference(room: Room): boolean {
const roomInfo = this.getRoom(room.roomId);
if (!roomInfo) return false;
const currentWidgets = roomInfo.widgets.filter((w) => WidgetType.JITSI.matches(w.type));
const hasPendingWidgets = WidgetEchoStore.roomHasPendingWidgetsOfType(room.roomId, [], WidgetType.JITSI);
return currentWidgets.length > 0 || hasPendingWidgets;
}
public isJoinedToConferenceIn(room: Room): boolean {
const roomInfo = this.getRoom(room.roomId);
if (!roomInfo) return false;
// A persistent conference widget indicates that we're participating
const widgets = roomInfo.widgets.filter((w) => WidgetType.JITSI.matches(w.type));
return widgets.some((w) => ActiveWidgetStore.instance.getWidgetPersistence(w.id, room.roomId));
}
}
window.mxWidgetStore = WidgetStore.instance;
+1
View File
@@ -47,6 +47,7 @@ export class RoomEchoChamber extends GenericEchoChamber<RoomEchoContext, CachedR
}
private onAccountData = (event: MatrixEvent): void => {
if (!this.matrixClient) return;
if (event.getType() === EventType.PushRules) {
const currentVolume = this.properties.get(CachedRoomKey.NotificationVolume);
const newVolume = getRoomNotifsState(this.matrixClient, this.context.room.roomId);
@@ -119,6 +119,7 @@ export class RoomNotificationStateStore extends AsyncStoreWithClient<IState> {
* @internal public for test
*/
public emitUpdateIfStateChanged = (state: SyncState, forceEmit: boolean): void => {
if (!this.matrixClient) return;
// Only count visible rooms to not torment the user with notification counts in rooms they can't see.
// This will include highlights from the previous version of the room internally
const msc3946ProcessDynamicPredecessor = SettingsStore.getValue("feature_dynamic_room_predecessors");
@@ -149,7 +150,7 @@ export class RoomNotificationStateStore extends AsyncStoreWithClient<IState> {
};
protected async onReady(): Promise<void> {
this.matrixClient.on(ClientEvent.Sync, this.onSync);
this.matrixClient?.on(ClientEvent.Sync, this.onSync);
}
protected async onNotReady(): Promise<any> {
@@ -77,7 +77,8 @@ export class SpaceNotificationState extends NotificationState {
this._count = 0;
this._color = NotificationColor.None;
for (const [roomId, state] of Object.entries(this.states)) {
const roomTags = RoomListStore.instance.getTagsForRoom(this.rooms.find((r) => r.roomId === roomId));
const room = this.rooms.find((r) => r.roomId === roomId);
const roomTags = room ? RoomListStore.instance.getTagsForRoom(room) : [];
// We ignore unreads in LowPriority rooms, see https://github.com/vector-im/element-web/issues/16836
if (roomTags.includes(DefaultTagID.LowPriority) && state.color === NotificationColor.Bold) continue;
+1 -1
View File
@@ -165,7 +165,7 @@ export class MessagePreviewStore extends AsyncStoreWithClient<IState> {
const event = events[i];
await this.matrixClient.decryptEventIfNeeded(event);
await this.matrixClient?.decryptEventIfNeeded(event);
const previewDef = PREVIEWS[event.getType()];
if (!previewDef) continue;
+4 -5
View File
@@ -189,8 +189,7 @@ export class RoomListStoreClass extends AsyncStoreWithClient<IState> implements
protected async onDispatchAsync(payload: ActionPayload): Promise<void> {
// Everything here requires a MatrixClient or some sort of logical readiness.
const logicallyReady = this.matrixClient && this.initialListsGenerated;
if (!logicallyReady) return;
if (!this.matrixClient || !this.initialListsGenerated) return;
if (!this.algorithm) {
// This shouldn't happen because `initialListsGenerated` implies we have an algorithm.
@@ -229,7 +228,7 @@ export class RoomListStoreClass extends AsyncStoreWithClient<IState> implements
eventPayload.event.getType() === EventType.RoomTombstone &&
eventPayload.event.getStateKey() === ""
) {
const newRoom = this.matrixClient.getRoom(eventPayload.event.getContent()["replacement_room"]);
const newRoom = this.matrixClient?.getRoom(eventPayload.event.getContent()["replacement_room"]);
if (newRoom) {
// If we have the new room, then the new room check will have seen the predecessor
// and did the required updates, so do nothing here.
@@ -243,7 +242,7 @@ export class RoomListStoreClass extends AsyncStoreWithClient<IState> implements
logger.warn(`Live timeline event ${eventPayload.event.getId()} received without associated room`);
logger.warn(`Queuing failed room update for retry as a result.`);
window.setTimeout(async (): Promise<void> => {
const updatedRoom = this.matrixClient.getRoom(roomId);
const updatedRoom = this.matrixClient?.getRoom(roomId);
if (updatedRoom) {
await tryUpdate(updatedRoom);
@@ -307,7 +306,7 @@ export class RoomListStoreClass extends AsyncStoreWithClient<IState> implements
const roomState: RoomState = membershipPayload.room.currentState;
const predecessor = roomState.findPredecessor(this.msc3946ProcessDynamicPredecessor);
if (predecessor) {
const prevRoom = this.matrixClient.getRoom(predecessor.roomId);
const prevRoom = this.matrixClient?.getRoom(predecessor.roomId);
if (prevRoom) {
const isSticky = this.algorithm.stickyRoom === prevRoom;
if (isSticky) {
+1 -1
View File
@@ -252,7 +252,7 @@ export class SlidingRoomListStoreClass extends AsyncStoreWithClient<IState> impl
// now set the rooms
const rooms: Room[] = [];
orderedRoomIds.forEach((roomId) => {
const room = this.matrixClient.getRoom(roomId);
const room = this.matrixClient?.getRoom(roomId);
if (!room) {
return;
}
+9 -8
View File
@@ -178,7 +178,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
public get activeSpaceRoom(): Room | null {
if (isMetaSpace(this._activeSpace)) return null;
return this.matrixClient?.getRoom(this._activeSpace);
return this.matrixClient?.getRoom(this._activeSpace) ?? null;
}
public get suggestedRooms(): ISuggestedRoom[] {
@@ -290,7 +290,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
SpaceStore.instance.traverseSpace(
space,
(roomId) => {
this.matrixClient.getRoom(roomId)?.loadMembersIfNeeded();
this.matrixClient?.getRoom(roomId)?.loadMembersIfNeeded();
},
false,
);
@@ -324,7 +324,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
.filter((roomInfo) => {
return (
roomInfo.room_type !== RoomType.Space &&
this.matrixClient.getRoom(roomInfo.room_id)?.getMyMembership() !== "join"
this.matrixClient?.getRoom(roomInfo.room_id)?.getMyMembership() !== "join"
);
})
.map((roomInfo) => ({
@@ -396,7 +396,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
// only respect the relationship if the sender has sufficient permissions in the parent to set
// child relations, as per MSC1772.
// https://github.com/matrix-org/matrix-doc/blob/main/proposals/1772-groups-as-rooms.md#relationship-between-rooms-and-spaces
const parent = this.matrixClient.getRoom(ev.getStateKey());
const parent = this.matrixClient?.getRoom(ev.getStateKey());
const relation = parent?.currentState.getStateEvents(EventType.SpaceChild, roomId);
if (
!parent?.currentState.maySendStateEvent(EventType.SpaceChild, userId) ||
@@ -877,7 +877,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
private switchSpaceIfNeeded = (roomId = SdkContextClass.instance.roomViewStore.getRoomId()): void => {
if (!roomId) return;
if (!this.isRoomInSpace(this.activeSpace, roomId) && !this.matrixClient.getRoom(roomId)?.isSpaceRoom()) {
if (!this.isRoomInSpace(this.activeSpace, roomId) && !this.matrixClient?.getRoom(roomId)?.isSpaceRoom()) {
this.switchToRelatedSpace(roomId);
}
};
@@ -972,7 +972,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
}
private onRoomState = (ev: MatrixEvent): void => {
const room = this.matrixClient.getRoom(ev.getRoomId());
const room = this.matrixClient?.getRoom(ev.getRoomId());
if (!room) return;
@@ -1022,7 +1022,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
// listening for m.room.member events in onRoomState above doesn't work as the Member object isn't updated by then
private onRoomStateMembers = (ev: MatrixEvent): void => {
const room = this.matrixClient.getRoom(ev.getRoomId());
const room = this.matrixClient?.getRoom(ev.getRoomId());
const userId = ev.getStateKey()!;
if (
@@ -1135,6 +1135,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
}
protected async onReady(): Promise<void> {
if (!this.matrixClient) return;
this.matrixClient.on(ClientEvent.Room, this.onRoom);
this.matrixClient.on(RoomEvent.MyMembership, this.onRoom);
this.matrixClient.on(RoomEvent.AccountData, this.onRoomAccountData);
@@ -1350,7 +1351,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
private async setRootSpaceOrder(space: Room, order: string): Promise<void> {
this.spaceOrderLocalEchoMap.set(space.roomId, order);
try {
await this.matrixClient.setRoomAccountData(space.roomId, EventType.SpaceOrder, { order });
await this.matrixClient?.setRoomAccountData(space.roomId, EventType.SpaceOrder, { order });
} catch (e) {
logger.warn("Failed to set root space order", e);
if (this.spaceOrderLocalEchoMap.get(space.roomId) === order) {