diff --git a/src/IdentityAuthClient.tsx b/src/IdentityAuthClient.tsx index 12f42a3add1..4df9959511f 100644 --- a/src/IdentityAuthClient.tsx +++ b/src/IdentityAuthClient.tsx @@ -118,7 +118,7 @@ export default class IdentityAuthClient { } private async checkToken(token: string): Promise { - const identityServerUrl = this.matrixClient.getIdentityServerUrl(); + const identityServerUrl = this.matrixClient.getIdentityServerUrl()!; try { await this.matrixClient.getIdentityAccount(token); diff --git a/src/LegacyCallHandler.tsx b/src/LegacyCallHandler.tsx index f84509238b7..71891a3e130 100644 --- a/src/LegacyCallHandler.tsx +++ b/src/LegacyCallHandler.tsx @@ -579,7 +579,7 @@ export default class LegacyCallHandler extends EventEmitter { }); }); call.on(CallEvent.Hangup, () => { - if (!this.matchesCallForThisRoom(call)) return; + if (!mappedRoomId || !this.matchesCallForThisRoom(call)) return; this.removeCallForRoom(mappedRoomId); }); @@ -587,7 +587,7 @@ export default class LegacyCallHandler extends EventEmitter { this.onCallStateChanged(newState, oldState, call); }); call.on(CallEvent.Replaced, (newCall: MatrixCall) => { - if (!this.matchesCallForThisRoom(call)) return; + if (!mappedRoomId || !this.matchesCallForThisRoom(call)) return; logger.log(`Call ID ${call.callId} is being replaced by call ID ${newCall.callId}`); @@ -603,7 +603,7 @@ export default class LegacyCallHandler extends EventEmitter { this.setCallState(newCall, newCall.state); }); call.on(CallEvent.AssertedIdentityChanged, async (): Promise => { - if (!this.matchesCallForThisRoom(call)) return; + if (!mappedRoomId || !this.matchesCallForThisRoom(call)) return; logger.log(`Call ID ${call.callId} got new asserted identity:`, call.getRemoteAssertedIdentity()); @@ -634,7 +634,7 @@ export default class LegacyCallHandler extends EventEmitter { const newMappedRoomId = this.roomIdForCall(call); logger.log(`Old room ID: ${mappedRoomId}, new room ID: ${newMappedRoomId}`); - if (newMappedRoomId !== mappedRoomId) { + if (newMappedRoomId && newMappedRoomId !== mappedRoomId) { this.removeCallForRoom(mappedRoomId); mappedRoomId = newMappedRoomId; logger.log("Moving call to room " + mappedRoomId); @@ -1116,6 +1116,14 @@ export default class LegacyCallHandler extends EventEmitter { public async startTransferToMatrixID(call: MatrixCall, destination: string, consultFirst: boolean): Promise { if (consultFirst) { const dmRoomId = await ensureDMExists(MatrixClientPeg.get(), destination); + if (!dmRoomId) { + logger.log("Failed to transfer call, could not ensure dm exists"); + Modal.createDialog(ErrorDialog, { + title: _t("Transfer Failed"), + description: _t("Failed to transfer call"), + }); + return; + } this.placeCall(dmRoomId, call.type, call); dis.dispatch({ diff --git a/src/Lifecycle.ts b/src/Lifecycle.ts index 6c2fbec8219..3c679c8a6d8 100644 --- a/src/Lifecycle.ts +++ b/src/Lifecycle.ts @@ -176,7 +176,7 @@ export async function loadSession(opts: ILoadSessionOpts = {}): Promise */ export async function getStoredSessionOwner(): Promise<[string, boolean] | [null, null]> { const { hsUrl, userId, hasAccessToken, isGuest } = await getStoredSessionVars(); - return hsUrl && userId && hasAccessToken ? [userId, isGuest] : [null, null]; + return hsUrl && userId && hasAccessToken ? [userId, !!isGuest] : [null, null]; } /** @@ -343,9 +343,9 @@ export interface IStoredSession { * may not be valid, as it is not tested for consistency here. * @returns {Object} Information about the session - see implementation for variables. */ -export async function getStoredSessionVars(): Promise { - const hsUrl = localStorage.getItem(HOMESERVER_URL_KEY); - const isUrl = localStorage.getItem(ID_SERVER_URL_KEY); +export async function getStoredSessionVars(): Promise> { + const hsUrl = localStorage.getItem(HOMESERVER_URL_KEY) ?? undefined; + const isUrl = localStorage.getItem(ID_SERVER_URL_KEY) ?? undefined; let accessToken: string | undefined; try { accessToken = await StorageManager.idbLoad("account", "mx_access_token"); @@ -367,8 +367,8 @@ export async function getStoredSessionVars(): Promise { // if we pre-date storing "mx_has_access_token", but we retrieved an access // token, then we should say we have an access token const hasAccessToken = localStorage.getItem("mx_has_access_token") === "true" || !!accessToken; - const userId = localStorage.getItem("mx_user_id"); - const deviceId = localStorage.getItem("mx_device_id"); + const userId = localStorage.getItem("mx_user_id") ?? undefined; + const deviceId = localStorage.getItem("mx_device_id") ?? undefined; let isGuest: boolean; if (localStorage.getItem("mx_is_guest") !== null) { @@ -447,7 +447,7 @@ export async function restoreFromLocalStorage(opts?: { ignoreGuest?: boolean }): } let decryptedAccessToken = accessToken; - const pickleKey = await PlatformPeg.get()?.getPickleKey(userId, deviceId); + const pickleKey = await PlatformPeg.get()?.getPickleKey(userId, deviceId ?? ""); if (pickleKey) { logger.log("Got pickle key"); if (typeof accessToken !== "string") { @@ -740,7 +740,7 @@ export function logout(): void { _isLoggingOut = true; const client = MatrixClientPeg.get(); - PlatformPeg.get()?.destroyPickleKey(client.getSafeUserId(), client.getDeviceId()); + PlatformPeg.get()?.destroyPickleKey(client.getSafeUserId(), client.getDeviceId() ?? ""); client.logout(true).then(onLoggedOut, (err) => { // Just throwing an error here is going to be very unhelpful // if you're trying to log out because your server's down and diff --git a/src/ScalarAuthClient.ts b/src/ScalarAuthClient.ts index 558e6362b9f..5a57729e53b 100644 --- a/src/ScalarAuthClient.ts +++ b/src/ScalarAuthClient.ts @@ -50,7 +50,7 @@ export default class ScalarAuthClient { } private writeTokenToStore(): void { - window.localStorage.setItem("mx_scalar_token_at_" + this.apiUrl, this.scalarToken); + window.localStorage.setItem("mx_scalar_token_at_" + this.apiUrl, this.scalarToken ?? ""); if (this.isDefaultManager) { // We remove the old token from storage to migrate upwards. This is safe // to do because even if the user switches to /app when this is on /develop @@ -260,7 +260,7 @@ export default class ScalarAuthClient { const roomId = room.roomId; const roomName = room.name; let url = this.uiUrl; - url += "?scalar_token=" + encodeURIComponent(this.scalarToken); + if (this.scalarToken) url += "?scalar_token=" + encodeURIComponent(this.scalarToken); url += "&room_id=" + encodeURIComponent(roomId); url += "&room_name=" + encodeURIComponent(roomName); url += "&theme=" + encodeURIComponent(SettingsStore.getValue("theme")); @@ -274,6 +274,7 @@ export default class ScalarAuthClient { } public getStarterLink(starterLinkUrl: string): string { + if (!this.scalarToken) return starterLinkUrl; return starterLinkUrl + "?scalar_token=" + encodeURIComponent(this.scalarToken); } } diff --git a/src/components/views/auth/CountryDropdown.tsx b/src/components/views/auth/CountryDropdown.tsx index a9061f6e5af..dc8ff2e1a3c 100644 --- a/src/components/views/auth/CountryDropdown.tsx +++ b/src/components/views/auth/CountryDropdown.tsx @@ -69,7 +69,7 @@ export default class CountryDropdown extends React.Component { const locale = new Intl.Locale(navigator.language ?? navigator.languages[0]); const code = locale.region ?? locale.language ?? locale.baseName; const displayNames = new Intl.DisplayNames(["en"], { type: "region" }); - const displayName = displayNames.of(code).toUpperCase(); + const displayName = displayNames.of(code)?.toUpperCase(); defaultCountry = COUNTRIES.find( (c) => c.iso2 === code.toUpperCase() || c.name.toUpperCase() === displayName, ); diff --git a/src/components/views/dialogs/ServerPickerDialog.tsx b/src/components/views/dialogs/ServerPickerDialog.tsx index 2b208b29f3f..d7469b86946 100644 --- a/src/components/views/dialogs/ServerPickerDialog.tsx +++ b/src/components/views/dialogs/ServerPickerDialog.tsx @@ -49,7 +49,7 @@ export default class ServerPickerDialog extends React.PureComponent => { ev.preventDefault(); - const valid = await this.fieldRef.current.validate({ allowEmpty: false }); + const valid = await this.fieldRef.current?.validate({ allowEmpty: false }); if (!valid && !this.state.defaultChosen) { - this.fieldRef.current.focus(); - this.fieldRef.current.validate({ allowEmpty: false, focused: true }); + this.fieldRef.current?.focus(); + this.fieldRef.current?.validate({ allowEmpty: false, focused: true }); return; } diff --git a/src/components/views/dialogs/spotlight/SpotlightDialog.tsx b/src/components/views/dialogs/spotlight/SpotlightDialog.tsx index 05ab8c1749a..2939d7f46d1 100644 --- a/src/components/views/dialogs/spotlight/SpotlightDialog.tsx +++ b/src/components/views/dialogs/spotlight/SpotlightDialog.tsx @@ -1089,7 +1089,7 @@ const SpotlightDialog: React.FC = ({ initialText = "", initialFilter = n ev.stopPropagation(); ev.preventDefault(); - if (rovingContext.state.refs.length > 0) { + if (rovingContext.state.activeRef && rovingContext.state.refs.length > 0) { let refs = rovingContext.state.refs; if (!query && !filter !== null) { // If the current selection is not in the recently viewed row then only include the @@ -1112,6 +1112,7 @@ const SpotlightDialog: React.FC = ({ initialText = "", initialFilter = n if ( !query && !filter !== null && + rovingContext.state.activeRef && rovingContext.state.refs.length > 0 && refIsForRecentlyViewed(rovingContext.state.activeRef) ) { diff --git a/src/components/views/elements/CopyableText.tsx b/src/components/views/elements/CopyableText.tsx index e1783013cb8..36da6cb4a21 100644 --- a/src/components/views/elements/CopyableText.tsx +++ b/src/components/views/elements/CopyableText.tsx @@ -25,7 +25,7 @@ import AccessibleTooltipButton from "./AccessibleTooltipButton"; interface IProps { children?: React.ReactNode; - getTextToCopy: () => string; + getTextToCopy: () => string | null; border?: boolean; className?: string; } @@ -35,7 +35,8 @@ const CopyableText: React.FC = ({ children, getTextToCopy, border = true const onCopyClickInternal = async (e: ButtonEvent): Promise => { e.preventDefault(); - const successful = await copyPlaintext(getTextToCopy()); + const text = getTextToCopy(); + const successful = !!text && (await copyPlaintext(text)); setTooltip(successful ? _t("Copied!") : _t("Failed to copy")); }; diff --git a/src/components/views/emojipicker/EmojiPicker.tsx b/src/components/views/emojipicker/EmojiPicker.tsx index 7a62c4dd079..45464a2a74f 100644 --- a/src/components/views/emojipicker/EmojiPicker.tsx +++ b/src/components/views/emojipicker/EmojiPicker.tsx @@ -162,9 +162,9 @@ class EmojiPicker extends React.Component { }; private keyboardNavigation(ev: React.KeyboardEvent, state: RovingState, dispatch: Dispatch): void { - const node = state.activeRef.current; - const parent = node.parentElement; - if (!parent) return; + const node = state.activeRef?.current; + const parent = node?.parentElement; + if (!parent || !state.activeRef) return; const rowIndex = Array.from(parent.children).indexOf(node); const refIndex = state.refs.indexOf(state.activeRef); @@ -173,12 +173,12 @@ class EmojiPicker extends React.Component { switch (ev.key) { case Key.ARROW_LEFT: focusRef = state.refs[refIndex - 1]; - newParent = focusRef?.current?.parentElement; + newParent = focusRef?.current?.parentElement ?? undefined; break; case Key.ARROW_RIGHT: focusRef = state.refs[refIndex + 1]; - newParent = focusRef?.current?.parentElement; + newParent = focusRef?.current?.parentElement ?? undefined; break; case Key.ARROW_UP: @@ -188,7 +188,7 @@ class EmojiPicker extends React.Component { ev.key === Key.ARROW_UP ? state.refs[refIndex - rowIndex - 1] : state.refs[refIndex - rowIndex + EMOJIS_PER_ROW]; - newParent = ref?.current?.parentElement; + newParent = ref?.current?.parentElement ?? undefined; const newTarget = newParent?.children[clamp(rowIndex, 0, newParent.children.length - 1)]; focusRef = state.refs.find((r) => r.current === newTarget); break; diff --git a/src/components/views/rooms/EditMessageComposer.tsx b/src/components/views/rooms/EditMessageComposer.tsx index 96c66dddfb6..c1fdecdd475 100644 --- a/src/components/views/rooms/EditMessageComposer.tsx +++ b/src/components/views/rooms/EditMessageComposer.tsx @@ -386,8 +386,8 @@ class EditMessageComposer extends React.Component ; -const auxButtonContextMenuPosition = (handle: RefObject): MenuProps => { - const rect = handle.current.getBoundingClientRect(); +const auxButtonContextMenuPosition = (handle: HTMLDivElement): MenuProps => { + const rect = handle.getBoundingClientRect(); return { chevronFace: ChevronFace.None, left: rect.left - 7, @@ -126,11 +126,11 @@ const DmAuxButton: React.FC = ({ tabIndex, dispatcher = default if (activeSpace && (showCreateRooms || showInviteUsers)) { let contextMenu: JSX.Element | undefined; - if (menuDisplayed) { + if (menuDisplayed && handle.current) { const canInvite = shouldShowSpaceInvite(activeSpace); contextMenu = ( - + {showCreateRooms && ( = ({ tabIndex }) => { } let contextMenu: JSX.Element | null = null; - if (menuDisplayed) { + if (menuDisplayed && handle.current) { contextMenu = ( - + {contextMenuContent} ); @@ -491,6 +491,7 @@ export default class RoomList extends React.PureComponent { if (payload.action === Action.ViewRoomDelta) { const viewRoomDeltaPayload = payload as ViewRoomDeltaPayload; const currentRoomId = SdkContextClass.instance.roomViewStore.getRoomId(); + if (!currentRoomId) return; const room = this.getRoomDelta(currentRoomId, viewRoomDeltaPayload.delta, viewRoomDeltaPayload.unread); if (room) { defaultDispatcher.dispatch({ diff --git a/src/components/views/rooms/RoomTile.tsx b/src/components/views/rooms/RoomTile.tsx index 87166c94a19..58664951df0 100644 --- a/src/components/views/rooms/RoomTile.tsx +++ b/src/components/views/rooms/RoomTile.tsx @@ -207,7 +207,8 @@ export class RoomTile extends React.PureComponent { return; } - const messagePreview = await MessagePreviewStore.instance.getPreviewForRoom(this.props.room, this.props.tag); + const messagePreview = + (await MessagePreviewStore.instance.getPreviewForRoom(this.props.room, this.props.tag)) ?? undefined; this.setState({ messagePreview }); } diff --git a/src/components/views/rooms/wysiwyg_composer/hooks/usePlainTextListeners.ts b/src/components/views/rooms/wysiwyg_composer/hooks/usePlainTextListeners.ts index f8b045ad657..f918ceb50df 100644 --- a/src/components/views/rooms/wysiwyg_composer/hooks/usePlainTextListeners.ts +++ b/src/components/views/rooms/wysiwyg_composer/hooks/usePlainTextListeners.ts @@ -38,7 +38,7 @@ export function usePlainTextListeners( onChange?: (content: string) => void, onSend?: () => void, ): { - ref: RefObject; + ref: RefObject; content?: string; onInput(event: SyntheticEvent): void; onPaste(event: SyntheticEvent): void; diff --git a/src/components/views/settings/SecureBackupPanel.tsx b/src/components/views/settings/SecureBackupPanel.tsx index 2b19a8af583..da67d6a919e 100644 --- a/src/components/views/settings/SecureBackupPanel.tsx +++ b/src/components/views/settings/SecureBackupPanel.tsx @@ -295,7 +295,7 @@ export default class SecureBackupPanel extends React.PureComponent<{}, IState> { const verify = (sub: string): JSX.Element => ( { {}, { validity }, ); - } else if (sig.valid && sig.deviceTrust.isVerified()) { + } else if (sig.valid && sig.deviceTrust?.isVerified()) { sigStatus = _t( "Backup has a valid signature from " + "verified session ", @@ -361,7 +361,7 @@ export default class SecureBackupPanel extends React.PureComponent<{}, IState> { {}, { validity, verify, device }, ); - } else if (!sig.valid && sig.deviceTrust.isVerified()) { + } else if (!sig.valid && sig.deviceTrust?.isVerified()) { sigStatus = _t( "Backup has an invalid signature from " + "verified session ", diff --git a/src/components/views/settings/tabs/user/LabsUserSettingsTab.tsx b/src/components/views/settings/tabs/user/LabsUserSettingsTab.tsx index 498aaf03317..f505ebb76f9 100644 --- a/src/components/views/settings/tabs/user/LabsUserSettingsTab.tsx +++ b/src/components/views/settings/tabs/user/LabsUserSettingsTab.tsx @@ -67,7 +67,7 @@ export default class LabsUserSettingsTab extends React.Component<{}> { const groups = new EnhancedMap(); this.labs.forEach((f) => { groups - .getOrCreate(SettingsStore.getLabGroup(f), []) + .getOrCreate(SettingsStore.getLabGroup(f)!, []) .push(); }); diff --git a/src/components/views/spaces/QuickSettingsButton.tsx b/src/components/views/spaces/QuickSettingsButton.tsx index 4f9529466b0..458dcaeac49 100644 --- a/src/components/views/spaces/QuickSettingsButton.tsx +++ b/src/components/views/spaces/QuickSettingsButton.tsx @@ -68,14 +68,14 @@ const QuickSettingsButton: React.FC<{ {_t("All settings")} - {SettingsStore.getValue("developerMode") && ( + {SettingsStore.getValue("developerMode") && SdkContextClass.instance.roomViewStore.getRoomId() && ( { closeMenu(); Modal.createDialog( DevtoolsDialog, { - roomId: SdkContextClass.instance.roomViewStore.getRoomId(), + roomId: SdkContextClass.instance.roomViewStore.getRoomId()!, }, "mx_DevtoolsDialog_wrapper", ); diff --git a/src/components/views/spaces/SpaceTreeLevel.tsx b/src/components/views/spaces/SpaceTreeLevel.tsx index a2f8719add0..1d31e9d141f 100644 --- a/src/components/views/spaces/SpaceTreeLevel.tsx +++ b/src/components/views/spaces/SpaceTreeLevel.tsx @@ -122,7 +122,7 @@ export const SpaceButton = forwardRef( } let contextMenu: JSX.Element | undefined; - if (menuDisplayed && handle.current && ContextMenuComponent) { + if (space && menuDisplayed && handle.current && ContextMenuComponent) { contextMenu = ( { +function getDehydrationKey( + keyInfo: ISecretStorageKeyInfo, + checkFunc: (key: Uint8Array) => void, +): Promise { return Promise.resolve(null); } diff --git a/src/integrations/IntegrationManagers.ts b/src/integrations/IntegrationManagers.ts index 9adcb561623..da1bb62ba98 100644 --- a/src/integrations/IntegrationManagers.ts +++ b/src/integrations/IntegrationManagers.ts @@ -153,7 +153,7 @@ export class IntegrationManagers { if (kind === Kind.Account) { // Order by state_keys (IDs) - managers.sort((a, b) => compare(a.id, b.id)); + managers.sort((a, b) => compare(a.id ?? "", b.id ?? "")); } ordered.push(...managers); @@ -199,7 +199,7 @@ export class IntegrationManagers { logger.log("Looking up integration manager via .well-known"); if (domainName.startsWith("http:") || domainName.startsWith("https:")) { // trim off the scheme and just use the domain - domainName = url.parse(domainName).host; + domainName = url.parse(domainName).host!; } let wkConfig: IClientWellKnown; diff --git a/src/linkify-matrix.ts b/src/linkify-matrix.ts index 3369a18157b..6f921469c76 100644 --- a/src/linkify-matrix.ts +++ b/src/linkify-matrix.ts @@ -16,7 +16,7 @@ limitations under the License. */ import * as linkifyjs from "linkifyjs"; -import { Opts, registerCustomProtocol, registerPlugin } from "linkifyjs"; +import { EventListeners, Opts, registerCustomProtocol, registerPlugin } from "linkifyjs"; import linkifyElement from "linkify-element"; import linkifyString from "linkify-string"; import { User } from "matrix-js-sdk/src/matrix"; @@ -136,7 +136,7 @@ export const ELEMENT_URL_PATTERN = ")(#.*)"; export const options: Opts = { - events: function (href: string, type: string): Partial { + events: function (href: string, type: string): EventListeners { switch (type as Type) { case Type.URL: { // intercept local permalinks to users and show them like userids (in userinfo of current room) @@ -185,9 +185,11 @@ export const options: Opts = { }, }; } + + return {}; }, - formatHref: function (href: string, type: Type | string): string { + formatHref: function (href: string, type: Type | string): string | null { switch (type) { case Type.RoomAlias: case Type.UserId: @@ -205,7 +207,7 @@ export const options: Opts = { className: "linkified", - target: function (href: string, type: Type | string): string { + target: function (href: string, type: Type | string): string | null { if (type === Type.URL) { try { const transformed = tryTransformPermalinkToLocalHref(href); diff --git a/src/stores/RoomViewStore.tsx b/src/stores/RoomViewStore.tsx index dd87a97a57e..7713e3f005a 100644 --- a/src/stores/RoomViewStore.tsx +++ b/src/stores/RoomViewStore.tsx @@ -228,6 +228,7 @@ export class RoomViewStore extends EventEmitter { } private doMaybeSetCurrentVoiceBroadcastPlayback(room: Room): void { + if (!this.stores.client) return; doMaybeSetCurrentVoiceBroadcastPlayback( room, this.stores.client, @@ -532,8 +533,8 @@ export class RoomViewStore extends EventEmitter { const cli = MatrixClientPeg.get(); // take a copy of roomAlias & roomId as they may change by the time the join is complete - const { roomAlias, roomId } = this.state; - const address = roomAlias || roomId; + const { roomAlias, roomId = payload.roomId } = this.state; + const address = roomAlias || roomId!; const viaServers = this.state.viaServers || []; try { await retry( @@ -554,7 +555,7 @@ export class RoomViewStore extends EventEmitter { // room. this.dis.dispatch({ action: Action.JoinRoomReady, - roomId, + roomId: roomId!, metricsTrigger: payload.metricsTrigger, }); } catch (err) { diff --git a/src/stores/ThreepidInviteStore.ts b/src/stores/ThreepidInviteStore.ts index 6dfb7d05610..c62974378f1 100644 --- a/src/stores/ThreepidInviteStore.ts +++ b/src/stores/ThreepidInviteStore.ts @@ -83,7 +83,11 @@ export default class ThreepidInviteStore extends EventEmitter { for (let i = 0; i < localStorage.length; i++) { const keyName = localStorage.key(i); if (!keyName?.startsWith(STORAGE_PREFIX)) continue; - results.push(JSON.parse(localStorage.getItem(keyName)) as IPersistedThreepidInvite); + try { + results.push(JSON.parse(localStorage.getItem(keyName)!) as IPersistedThreepidInvite); + } catch (e) { + console.warn("Failed to parse 3pid invite", e); + } } return results; } diff --git a/src/stores/spaces/SpaceStore.ts b/src/stores/spaces/SpaceStore.ts index 4251826f81c..73ec56556d7 100644 --- a/src/stores/spaces/SpaceStore.ts +++ b/src/stores/spaces/SpaceStore.ts @@ -144,7 +144,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient { private _activeSpace: SpaceKey = MetaSpace.Home; // set properly by onReady private _suggestedRooms: ISuggestedRoom[] = []; private _invitedSpaces = new Set(); - private spaceOrderLocalEchoMap = new Map(); + private spaceOrderLocalEchoMap = new Map(); // The following properties are set by onReady as they live in account_data private _allRoomsInHome = false; private _enabledMetaSpaces: MetaSpace[] = []; @@ -338,7 +338,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient { }; public addRoomToSpace(space: Room, roomId: string, via: string[], suggested = false): Promise { - return this.matrixClient.sendStateEvent( + return this.matrixClient!.sendStateEvent( space.roomId, EventType.SpaceChild, { @@ -359,7 +359,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient { return getChildOrder(ev.getContent().order, ev.getTs(), ev.getStateKey()!); }) .map((ev) => { - const history = this.matrixClient.getRoomUpgradeHistory( + const history = this.matrixClient!.getRoomUpgradeHistory( ev.getStateKey()!, true, this._msc3946ProcessDynamicPredecessor, @@ -463,7 +463,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient { ): Set => { if (space === MetaSpace.Home && this.allRoomsInHome) { return new Set( - this.matrixClient.getVisibleRooms(this._msc3946ProcessDynamicPredecessor).map((r) => r.roomId), + this.matrixClient!.getVisibleRooms(this._msc3946ProcessDynamicPredecessor).map((r) => r.roomId), ); } @@ -612,8 +612,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient { this.roomIdsBySpace.delete(MetaSpace.Home); } else { const rooms = new Set( - this.matrixClient - .getVisibleRooms(this._msc3946ProcessDynamicPredecessor) + this.matrixClient!.getVisibleRooms(this._msc3946ProcessDynamicPredecessor) .filter(this.showInHomeSpace) .map((r) => r.roomId), ); @@ -813,9 +812,11 @@ export class SpaceStoreClass extends AsyncStoreWithClient { // Expand room IDs to all known versions of the given rooms const expandedRoomIds = new Set( Array.from(roomIds).flatMap((roomId) => { - return this.matrixClient - .getRoomUpgradeHistory(roomId, true, this._msc3946ProcessDynamicPredecessor) - .map((r) => r.roomId); + return this.matrixClient!.getRoomUpgradeHistory( + roomId, + true, + this._msc3946ProcessDynamicPredecessor, + ).map((r) => r.roomId); }), ); @@ -1217,7 +1218,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient { // Persist last viewed room from a space // we don't await setActiveSpace above as we only care about this.activeSpace being up to date // synchronously for the below code - everything else can and should be async. - window.localStorage.setItem(getSpaceContextKey(this.activeSpace), payload.room_id); + window.localStorage.setItem(getSpaceContextKey(this.activeSpace), payload.room_id ?? ""); break; } @@ -1294,10 +1295,12 @@ export class SpaceStoreClass extends AsyncStoreWithClient { } case "Spaces.showPeopleInSpace": - // getSpaceFilteredUserIds will return the appropriate value - this.emit(payload.roomId); - if (!this.enabledMetaSpaces.some((s) => s === MetaSpace.Home || s === MetaSpace.People)) { - this.updateNotificationStates([payload.roomId]); + if (payload.roomId) { + // getSpaceFilteredUserIds will return the appropriate value + this.emit(payload.roomId); + if (!this.enabledMetaSpaces.some((s) => s === MetaSpace.Home || s === MetaSpace.People)) { + this.updateNotificationStates([payload.roomId]); + } } break; @@ -1353,7 +1356,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient { return sortBy(spaces, [this.getSpaceTagOrdering, "roomId"]); } - private async setRootSpaceOrder(space: Room, order: string): Promise { + private async setRootSpaceOrder(space: Room, order?: string): Promise { this.spaceOrderLocalEchoMap.set(space.roomId, order); try { await this.matrixClient?.setRoomAccountData(space.roomId, EventType.SpaceOrder, { order });