diff --git a/src/ContentMessages.ts b/src/ContentMessages.ts index 2764f5fa2d..f7f6b148e2 100644 --- a/src/ContentMessages.ts +++ b/src/ContentMessages.ts @@ -436,15 +436,18 @@ export default class ContentMessages { } } - promBefore = doMaybeLocalRoomAction(roomId, (actualRoomId) => - this.sendContentToRoom( - file, - actualRoomId, - relation, - matrixClient, - replyToEvent ?? undefined, - loopPromiseBefore, - ), + promBefore = doMaybeLocalRoomAction( + roomId, + (actualRoomId) => + this.sendContentToRoom( + file, + actualRoomId, + relation, + matrixClient, + replyToEvent ?? undefined, + loopPromiseBefore, + ), + matrixClient, ); } diff --git a/src/DeviceListener.ts b/src/DeviceListener.ts index e01bc54b60..43ec33bb11 100644 --- a/src/DeviceListener.ts +++ b/src/DeviceListener.ts @@ -301,7 +301,7 @@ export default class DeviceListener { } else { // No cross-signing or key backup on account (set up encryption) await cli.waitForClientWellKnown(); - if (isSecureBackupRequired() && isLoggedIn()) { + if (isSecureBackupRequired(cli) && isLoggedIn()) { // If we're meant to set up, and Secure Backup is required, // trigger the flow directly without a toast once logged in. hideSetupEncryptionToast(); diff --git a/src/IdentityAuthClient.tsx b/src/IdentityAuthClient.tsx index 0eed6fb7f8..cb38679ee8 100644 --- a/src/IdentityAuthClient.tsx +++ b/src/IdentityAuthClient.tsx @@ -133,8 +133,8 @@ export default class IdentityAuthClient { if ( !this.tempClient && - !doesAccountDataHaveIdentityServer() && - !(await doesIdentityServerHaveTerms(identityServerUrl)) + !doesAccountDataHaveIdentityServer(this.matrixClient) && + !(await doesIdentityServerHaveTerms(this.matrixClient, identityServerUrl)) ) { const { finished } = Modal.createDialog(QuestionDialog, { title: _t("Identity server has no terms of service"), @@ -158,7 +158,7 @@ export default class IdentityAuthClient { }); const [confirmed] = await finished; if (confirmed) { - setToDefaultIdentityServer(); + setToDefaultIdentityServer(this.matrixClient); } else { throw new AbortedIdentityActionError("User aborted identity server action without terms"); } diff --git a/src/LegacyCallHandler.tsx b/src/LegacyCallHandler.tsx index f8096ae561..3dc7fcc483 100644 --- a/src/LegacyCallHandler.tsx +++ b/src/LegacyCallHandler.tsx @@ -1209,7 +1209,7 @@ export default class LegacyCallHandler extends EventEmitter { } try { - await WidgetUtils.addJitsiWidget(roomId, type, "Jitsi", false); + await WidgetUtils.addJitsiWidget(client, roomId, type, "Jitsi", false); logger.log("Jitsi widget added"); } catch (e) { if (e instanceof MatrixError && e.errcode === "M_FORBIDDEN") { diff --git a/src/Lifecycle.ts b/src/Lifecycle.ts index 417309eb64..889684814c 100644 --- a/src/Lifecycle.ts +++ b/src/Lifecycle.ts @@ -636,7 +636,7 @@ async function doSetLoggedIn(credentials: IMatrixClientCreds, clearStorageEnable } dis.fire(Action.OnLoggedIn); - await startMatrixClient(/*startSyncing=*/ !softLogout); + await startMatrixClient(client, /*startSyncing=*/ !softLogout); return client; } @@ -780,10 +780,11 @@ export function isLoggingOut(): boolean { /** * Starts the matrix client and all other react-sdk services that * listen for events while a session is logged in. + * @param client the matrix client to start * @param {boolean} startSyncing True (default) to actually start * syncing the client. */ -async function startMatrixClient(startSyncing = true): Promise { +async function startMatrixClient(client: MatrixClient, startSyncing = true): Promise { logger.log(`Lifecycle: Starting MatrixClient`); // dispatch this before starting the matrix client: it's used @@ -796,10 +797,10 @@ async function startMatrixClient(startSyncing = true): Promise { SdkContextClass.instance.typingStore.reset(); ToastStore.sharedInstance().reset(); - DialogOpener.instance.prepare(); + DialogOpener.instance.prepare(client); Notifier.start(); UserActivity.sharedInstance().start(); - DMRoomMap.makeShared().start(); + DMRoomMap.makeShared(client).start(); IntegrationManagers.sharedInstance().startWatching(); ActiveWidgetStore.instance.start(); LegacyCallHandler.instance.start(); diff --git a/src/RoomInvite.tsx b/src/RoomInvite.tsx index 0d2b64f244..4e84b4a48a 100644 --- a/src/RoomInvite.tsx +++ b/src/RoomInvite.tsx @@ -20,6 +20,7 @@ import { MatrixEvent } from "matrix-js-sdk/src/models/event"; import { User } from "matrix-js-sdk/src/models/user"; import { logger } from "matrix-js-sdk/src/logger"; import { EventType } from "matrix-js-sdk/src/@types/event"; +import { MatrixClient } from "matrix-js-sdk/src/matrix"; import { MatrixClientPeg } from "./MatrixClientPeg"; import MultiInviter, { CompletionStates } from "./utils/MultiInviter"; @@ -49,12 +50,13 @@ export interface IInviteResult { * @returns {Promise} Promise */ export function inviteMultipleToRoom( + client: MatrixClient, roomId: string, addresses: string[], sendSharedHistoryKeys = false, progressCallback?: () => void, ): Promise { - const inviter = new MultiInviter(roomId, progressCallback); + const inviter = new MultiInviter(client, roomId, progressCallback); return inviter .invite(addresses, undefined, sendSharedHistoryKeys) .then((states) => Promise.resolve({ states, inviter })); @@ -105,12 +107,13 @@ export function isValid3pidInvite(event: MatrixEvent): boolean { } export function inviteUsersToRoom( + client: MatrixClient, roomId: string, userIds: string[], sendSharedHistoryKeys = false, progressCallback?: () => void, ): Promise { - return inviteMultipleToRoom(roomId, userIds, sendSharedHistoryKeys, progressCallback) + return inviteMultipleToRoom(client, roomId, userIds, sendSharedHistoryKeys, progressCallback) .then((result) => { const room = MatrixClientPeg.get().getRoom(roomId)!; showAnyInviteErrors(result.states, room, result.inviter); diff --git a/src/ScalarMessaging.ts b/src/ScalarMessaging.ts index 9afa10a90a..08cdbff70e 100644 --- a/src/ScalarMessaging.ts +++ b/src/ScalarMessaging.ts @@ -411,6 +411,7 @@ function kickUser(event: MessageEvent, roomId: string, userId: string): voi } function setWidget(event: MessageEvent, roomId: string | null): void { + const client = MatrixClientPeg.get(); const widgetId = event.data.widget_id; let widgetType = event.data.type; const widgetUrl = event.data.url; @@ -458,7 +459,7 @@ function setWidget(event: MessageEvent, roomId: string | null): void { widgetType = WidgetType.fromString(widgetType); if (userWidget) { - WidgetUtils.setUserWidget(widgetId, widgetType, widgetUrl, widgetName, widgetData) + WidgetUtils.setUserWidget(client, widgetId, widgetType, widgetUrl, widgetName, widgetData) .then(() => { sendResponse(event, { success: true, @@ -476,6 +477,7 @@ function setWidget(event: MessageEvent, roomId: string | null): void { return; } WidgetUtils.setRoomWidget( + client, roomId, widgetId, widgetType, @@ -516,7 +518,7 @@ function getWidgets(event: MessageEvent, roomId: string | null): void { } // Add user widgets (not linked to a specific room) - const userWidgets = WidgetUtils.getUserWidgetsArray(); + const userWidgets = WidgetUtils.getUserWidgetsArray(client); widgetStateEvents = widgetStateEvents.concat(userWidgets); sendResponse(event, widgetStateEvents); diff --git a/src/SecurityManager.ts b/src/SecurityManager.ts index 34bfc44f07..c1a59bce74 100644 --- a/src/SecurityManager.ts +++ b/src/SecurityManager.ts @@ -344,7 +344,7 @@ export async function accessSecretStorage(func = async (): Promise => {}, onBeforeClose: async (reason): Promise => { // If Secure Backup is required, you cannot leave the modal. if (reason === "backgroundClick") { - return !isSecureBackupRequired(); + return !isSecureBackupRequired(cli); } return true; }, diff --git a/src/SlashCommands.tsx b/src/SlashCommands.tsx index 3615e1a8a3..3d195716dc 100644 --- a/src/SlashCommands.tsx +++ b/src/SlashCommands.tsx @@ -576,7 +576,7 @@ export const Commands = [ prom = finished.then(([useDefault]) => { if (useDefault) { - setToDefaultIdentityServer(); + setToDefaultIdentityServer(MatrixClientPeg.get()); return; } throw new UserFriendlyError( @@ -589,7 +589,7 @@ export const Commands = [ ); } } - const inviter = new MultiInviter(roomId); + const inviter = new MultiInviter(MatrixClientPeg.get(), roomId); return success( prom .then(() => { @@ -765,7 +765,7 @@ export const Commands = [ } if (!targetRoomId) targetRoomId = roomId; - return success(leaveRoomBehaviour(targetRoomId)); + return success(leaveRoomBehaviour(cli, targetRoomId)); }, category: CommandCategories.actions, renderingTypes: [TimelineRenderingType.Room], @@ -1018,7 +1018,7 @@ export const Commands = [ if (!widgetUrl.startsWith("https://") && !widgetUrl.startsWith("http://")) { return reject(new UserFriendlyError("Please supply a https:// or http:// widget URL")); } - if (WidgetUtils.canUserModifyWidgets(roomId)) { + if (WidgetUtils.canUserModifyWidgets(MatrixClientPeg.get(), roomId)) { const userId = MatrixClientPeg.get().getUserId(); const nowMs = new Date().getTime(); const widgetId = encodeURIComponent(`${roomId}_${userId}_${nowMs}`); @@ -1036,7 +1036,9 @@ export const Commands = [ widgetUrl = WidgetUtils.getLocalJitsiWrapperUrl(); } - return success(WidgetUtils.setRoomWidget(roomId, widgetId, type, widgetUrl, name, data)); + return success( + WidgetUtils.setRoomWidget(MatrixClientPeg.get(), roomId, widgetId, type, widgetUrl, name, data), + ); } else { return reject(new UserFriendlyError("You cannot modify widgets in this room.")); } diff --git a/src/async-components/views/dialogs/security/CreateSecretStorageDialog.tsx b/src/async-components/views/dialogs/security/CreateSecretStorageDialog.tsx index 35b90c484c..5c401122b5 100644 --- a/src/async-components/views/dialogs/security/CreateSecretStorageDialog.tsx +++ b/src/async-components/views/dialogs/security/CreateSecretStorageDialog.tsx @@ -110,8 +110,10 @@ export default class CreateSecretStorageDialog extends React.PureComponent>; - public constructor(room: Room, renderingType?: TimelineRenderingType) { + public constructor(private readonly room: Room, renderingType?: TimelineRenderingType) { super({ commandRegex: ROOM_REGEX, renderingType }); this.matcher = new QueryMatcher>([], { keys: ["displayedAlias", "matchName"], @@ -119,7 +119,7 @@ export default class RoomProvider extends AutocompleteProvider { completionId: room.room.roomId, type: "room", suffix: " ", - href: makeRoomPermalink(room.displayedAlias), + href: makeRoomPermalink(this.room.client, room.displayedAlias), component: ( diff --git a/src/components/structures/HomePage.tsx b/src/components/structures/HomePage.tsx index bb2fbc068d..115da05118 100644 --- a/src/components/structures/HomePage.tsx +++ b/src/components/structures/HomePage.tsx @@ -28,7 +28,7 @@ import { OwnProfileStore } from "../../stores/OwnProfileStore"; import AccessibleButton, { ButtonEvent } from "../views/elements/AccessibleButton"; import { UPDATE_EVENT } from "../../stores/AsyncStore"; import { useEventEmitter } from "../../hooks/useEventEmitter"; -import MatrixClientContext from "../../contexts/MatrixClientContext"; +import MatrixClientContext, { useMatrixClientContext } from "../../contexts/MatrixClientContext"; import MiniAvatarUploader, { AVATAR_SIZE } from "../views/elements/MiniAvatarUploader"; import PosthogTrackers from "../../PosthogTrackers"; import EmbeddedPage from "./EmbeddedPage"; @@ -97,8 +97,9 @@ const UserWelcomeTop: React.FC = () => { }; const HomePage: React.FC = ({ justRegistered = false }) => { + const cli = useMatrixClientContext(); const config = SdkConfig.get(); - const pageUrl = getHomePageUrl(config); + const pageUrl = getHomePageUrl(config, cli); if (pageUrl) { return ; diff --git a/src/components/structures/MatrixChat.tsx b/src/components/structures/MatrixChat.tsx index 4aea34870c..a9f5c54279 100644 --- a/src/components/structures/MatrixChat.tsx +++ b/src/components/structures/MatrixChat.tsx @@ -1154,7 +1154,8 @@ export default class MatrixChat extends React.PureComponent { } private leaveRoom(roomId: string): void { - const roomToLeave = MatrixClientPeg.get().getRoom(roomId); + const cli = MatrixClientPeg.get(); + const roomToLeave = cli.getRoom(roomId); const warnings = this.leaveRoomWarnings(roomId); const isSpace = roomToLeave?.isSpaceRoom(); @@ -1173,9 +1174,9 @@ export default class MatrixChat extends React.PureComponent { ), button: _t("Leave"), - onFinished: (shouldLeave) => { + onFinished: async (shouldLeave) => { if (shouldLeave) { - leaveRoomBehaviour(roomId); + await leaveRoomBehaviour(cli, roomId); dis.dispatch({ action: Action.AfterLeaveRoom, @@ -1211,7 +1212,7 @@ export default class MatrixChat extends React.PureComponent { } private async copyRoom(roomId: string): Promise { - const roomLink = makeRoomPermalink(roomId); + const roomLink = makeRoomPermalink(MatrixClientPeg.get(), roomId); const success = await copyPlaintext(roomLink); if (!success) { Modal.createDialog(ErrorDialog, { diff --git a/src/components/structures/MessagePanel.tsx b/src/components/structures/MessagePanel.tsx index 6981b9bc31..9ed934d6ca 100644 --- a/src/components/structures/MessagePanel.tsx +++ b/src/components/structures/MessagePanel.tsx @@ -743,7 +743,7 @@ export default class MessagePanel extends React.Component { lastInSection = willWantDateSeparator || mxEv.getSender() !== nextEv.getSender() || - getEventDisplayInfo(nextEv, this.showHiddenEvents).isInfoMessage || + getEventDisplayInfo(MatrixClientPeg.get(), nextEv, this.showHiddenEvents).isInfoMessage || !shouldFormContinuation(mxEv, nextEv, this.showHiddenEvents, this.context.timelineRenderingType); } diff --git a/src/components/structures/RoomView.tsx b/src/components/structures/RoomView.tsx index b4a38ee2eb..04377575d4 100644 --- a/src/components/structures/RoomView.tsx +++ b/src/components/structures/RoomView.tsx @@ -561,7 +561,7 @@ export class RoomView extends React.Component { createdByCurrentUserTs - lastCreatedByOtherTs < PREVENT_MULTIPLE_JITSI_WITHIN ) { // more than one Jitsi widget with the last one from the current user → remove it - WidgetUtils.setRoomWidget(this.state.roomId, createdByCurrentUser.id); + WidgetUtils.setRoomWidget(this.context.client, this.state.roomId, createdByCurrentUser.id); } } diff --git a/src/components/structures/SpaceRoomView.tsx b/src/components/structures/SpaceRoomView.tsx index c1614b4e0e..1e582add9d 100644 --- a/src/components/structures/SpaceRoomView.tsx +++ b/src/components/structures/SpaceRoomView.tsx @@ -549,7 +549,7 @@ const SpaceSetupPrivateInvite: React.FC<{ setBusy(true); const targetIds = emailAddresses.map((name) => name.trim()).filter(Boolean); try { - const result = await inviteMultipleToRoom(space.roomId, targetIds); + const result = await inviteMultipleToRoom(space.client, space.roomId, targetIds); const failedUsers = Object.keys(result.states).filter((a) => result.states[a] === "error"); if (failedUsers.length > 0) { diff --git a/src/components/structures/UserMenu.tsx b/src/components/structures/UserMenu.tsx index 8a2d08f6cc..99325da99b 100644 --- a/src/components/structures/UserMenu.tsx +++ b/src/components/structures/UserMenu.tsx @@ -110,7 +110,7 @@ export default class UserMenu extends React.Component { } private get hasHomePage(): boolean { - return !!getHomePageUrl(SdkConfig.get()); + return !!getHomePageUrl(SdkConfig.get(), this.context.client!); } private onCurrentVoiceBroadcastRecordingChanged = (recording: VoiceBroadcastRecording | null): void => { diff --git a/src/components/structures/ViewSource.tsx b/src/components/structures/ViewSource.tsx index a0a500810f..a4e10e12e0 100644 --- a/src/components/structures/ViewSource.tsx +++ b/src/components/structures/ViewSource.tsx @@ -153,7 +153,9 @@ export default class ViewSource extends React.Component { const isEditing = this.state.isEditing; const roomId = mxEvent.getRoomId()!; const eventId = mxEvent.getId()!; - const canEdit = mxEvent.isState() ? this.canSendStateEvent(mxEvent) : canEditContent(this.props.mxEvent); + const canEdit = mxEvent.isState() + ? this.canSendStateEvent(mxEvent) + : canEditContent(MatrixClientPeg.get(), this.props.mxEvent); return (
diff --git a/src/components/views/auth/PassphraseField.tsx b/src/components/views/auth/PassphraseField.tsx index 3f232923cc..599723aba7 100644 --- a/src/components/views/auth/PassphraseField.tsx +++ b/src/components/views/auth/PassphraseField.tsx @@ -22,6 +22,7 @@ import SdkConfig from "../../../SdkConfig"; import withValidation, { IFieldState, IValidationResult } from "../elements/Validation"; import { _t, _td } from "../../../languageHandler"; import Field, { IInputProps } from "../elements/Field"; +import { MatrixClientPeg } from "../../../MatrixClientPeg"; interface IProps extends Omit { autoFocus?: boolean; @@ -56,7 +57,7 @@ class PassphraseField extends PureComponent { deriveData: async ({ value }): Promise => { if (!value) return null; const { scorePassword } = await import("../../../utils/PasswordScorer"); - return scorePassword(value); + return scorePassword(MatrixClientPeg.get(), value); }, rules: [ { diff --git a/src/components/views/avatars/DecoratedRoomAvatar.tsx b/src/components/views/avatars/DecoratedRoomAvatar.tsx index 3756e7c41a..508285d07e 100644 --- a/src/components/views/avatars/DecoratedRoomAvatar.tsx +++ b/src/components/views/avatars/DecoratedRoomAvatar.tsx @@ -165,7 +165,7 @@ export default class DecoratedRoomAvatar extends React.PureComponent }; private onEditClick = (): void => { - editEvent(this.props.mxEvent, this.context.timelineRenderingType, this.props.getRelationsForEvent); + editEvent( + MatrixClientPeg.get(), + this.props.mxEvent, + this.context.timelineRenderingType, + this.props.getRelationsForEvent, + ); this.closeMenu(); }; @@ -617,7 +622,7 @@ export default class MessageContextMenu extends React.Component } let editButton: JSX.Element | undefined; - if (rightClick && canEditContent(mxEvent)) { + if (rightClick && canEditContent(cli, mxEvent)) { editButton = ( = ({ const { room, roomId } = useContext(RoomContext); const widgetMessaging = WidgetMessagingStore.instance.getMessagingForUid(WidgetUtils.getWidgetUid(app)); - const canModify = userWidget || WidgetUtils.canUserModifyWidgets(roomId); + const canModify = userWidget || WidgetUtils.canUserModifyWidgets(cli, roomId); let streamAudioStreamButton: JSX.Element | undefined; if (roomId && getConfigLivestreamUrl() && WidgetType.JITSI.matches(app.type)) { @@ -138,7 +138,7 @@ export const WidgetContextMenu: React.FC = ({ button: _t("Delete widget"), onFinished: (confirmed) => { if (!confirmed) return; - WidgetUtils.setRoomWidget(roomId, app.id); + WidgetUtils.setRoomWidget(cli, roomId, app.id); }, }); } diff --git a/src/components/views/dialogs/CreateRoomDialog.tsx b/src/components/views/dialogs/CreateRoomDialog.tsx index 9f46328396..2484d5fd7e 100644 --- a/src/components/views/dialogs/CreateRoomDialog.tsx +++ b/src/components/views/dialogs/CreateRoomDialog.tsx @@ -75,9 +75,10 @@ export default class CreateRoomDialog extends React.Component { joinRule = JoinRule.Restricted; } + const cli = MatrixClientPeg.get(); this.state = { isPublic: this.props.defaultPublic || false, - isEncrypted: this.props.defaultEncrypted ?? privateShouldBeEncrypted(), + isEncrypted: this.props.defaultEncrypted ?? privateShouldBeEncrypted(cli), joinRule, name: this.props.defaultName || "", topic: "", @@ -88,9 +89,9 @@ export default class CreateRoomDialog extends React.Component { canChangeEncryption: true, }; - MatrixClientPeg.get() - .doesServerForceEncryptionForPreset(Preset.PrivateChat) - .then((isForced) => this.setState({ canChangeEncryption: !isForced })); + cli.doesServerForceEncryptionForPreset(Preset.PrivateChat).then((isForced) => + this.setState({ canChangeEncryption: !isForced }), + ); } private roomCreateOptions(): IOpts { @@ -284,7 +285,7 @@ export default class CreateRoomDialog extends React.Component { let e2eeSection: JSX.Element | undefined; if (this.state.joinRule !== JoinRule.Public) { let microcopy: string; - if (privateShouldBeEncrypted()) { + if (privateShouldBeEncrypted(MatrixClientPeg.get())) { if (this.state.canChangeEncryption) { microcopy = isVideoRoom ? _t("You can't disable this later. The room will be encrypted but the embedded call will not.") diff --git a/src/components/views/dialogs/InviteDialog.tsx b/src/components/views/dialogs/InviteDialog.tsx index 6a50955073..30dc15e5cc 100644 --- a/src/components/views/dialogs/InviteDialog.tsx +++ b/src/components/views/dialogs/InviteDialog.tsx @@ -407,7 +407,7 @@ export default class InviteDialog extends React.PureComponent ), a: (sub) => ( - + {sub} ), diff --git a/src/components/views/location/LocationPicker.tsx b/src/components/views/location/LocationPicker.tsx index 9660457099..ada89f169c 100644 --- a/src/components/views/location/LocationPicker.tsx +++ b/src/components/views/location/LocationPicker.tsx @@ -76,7 +76,7 @@ class LocationPicker extends React.Component { try { this.map = new maplibregl.Map({ container: "mx_LocationPicker_map", - style: findMapStyleUrl(), + style: findMapStyleUrl(this.context), center: [0, 0], zoom: 1, }); diff --git a/src/components/views/messages/EditHistoryMessage.tsx b/src/components/views/messages/EditHistoryMessage.tsx index 88bac95e68..3531e6e5fa 100644 --- a/src/components/views/messages/EditHistoryMessage.tsx +++ b/src/components/views/messages/EditHistoryMessage.tsx @@ -101,7 +101,7 @@ export default class EditHistoryMessage extends React.PureComponent if (request.done) { title = _t("You verified %(name)s", { - name: getNameForEventRoom(request.otherUserId, mxEvent.getRoomId()!), + name: getNameForEventRoom(client, request.otherUserId, mxEvent.getRoomId()!), }); } else if (request.cancelled) { const userId = request.cancellingUserId; if (userId === myUserId) { title = _t("You cancelled verifying %(name)s", { - name: getNameForEventRoom(request.otherUserId, mxEvent.getRoomId()!), + name: getNameForEventRoom(client, request.otherUserId, mxEvent.getRoomId()!), }); } else if (userId) { - title = _t("%(name)s cancelled verifying", { name: getNameForEventRoom(userId, mxEvent.getRoomId()!) }); + title = _t("%(name)s cancelled verifying", { + name: getNameForEventRoom(client, userId, mxEvent.getRoomId()!), + }); } } @@ -135,7 +137,7 @@ export default class MKeyVerificationConclusion extends React.Component ); diff --git a/src/components/views/messages/MKeyVerificationRequest.tsx b/src/components/views/messages/MKeyVerificationRequest.tsx index 13bb4405ac..7ed44d9199 100644 --- a/src/components/views/messages/MKeyVerificationRequest.tsx +++ b/src/components/views/messages/MKeyVerificationRequest.tsx @@ -93,7 +93,9 @@ export default class MKeyVerificationRequest extends React.Component { if (userId === myUserId) { return _t("You accepted"); } else { - return _t("%(name)s accepted", { name: getNameForEventRoom(userId, this.props.mxEvent.getRoomId()!) }); + return _t("%(name)s accepted", { + name: getNameForEventRoom(client, userId, this.props.mxEvent.getRoomId()!), + }); } } @@ -110,14 +112,19 @@ export default class MKeyVerificationRequest extends React.Component { } } else { if (declined) { - return _t("%(name)s declined", { name: getNameForEventRoom(userId, this.props.mxEvent.getRoomId()!) }); + return _t("%(name)s declined", { + name: getNameForEventRoom(client, userId, this.props.mxEvent.getRoomId()!), + }); } else { - return _t("%(name)s cancelled", { name: getNameForEventRoom(userId, this.props.mxEvent.getRoomId()!) }); + return _t("%(name)s cancelled", { + name: getNameForEventRoom(client, userId, this.props.mxEvent.getRoomId()!), + }); } } } public render(): React.ReactNode { + const client = MatrixClientPeg.get(); const { mxEvent } = this.props; const request = mxEvent.verificationRequest; @@ -149,9 +156,9 @@ export default class MKeyVerificationRequest extends React.Component { } if (!request.initiatedByMe) { - const name = getNameForEventRoom(request.requestingUserId, mxEvent.getRoomId()!); + const name = getNameForEventRoom(client, request.requestingUserId, mxEvent.getRoomId()!); title = _t("%(name)s wants to verify", { name }); - subtitle = userLabelForEventRoom(request.requestingUserId, mxEvent.getRoomId()!); + subtitle = userLabelForEventRoom(client, request.requestingUserId, mxEvent.getRoomId()!); if (request.canAccept) { stateNode = (
@@ -167,7 +174,7 @@ export default class MKeyVerificationRequest extends React.Component { } else { // request sent by us title = _t("You sent a verification request"); - subtitle = userLabelForEventRoom(request.receivingUserId, mxEvent.getRoomId()!); + subtitle = userLabelForEventRoom(client, request.receivingUserId, mxEvent.getRoomId()!); } if (title) { diff --git a/src/components/views/messages/MessageActionBar.tsx b/src/components/views/messages/MessageActionBar.tsx index f94bdf5f16..4cc643c25e 100644 --- a/src/components/views/messages/MessageActionBar.tsx +++ b/src/components/views/messages/MessageActionBar.tsx @@ -363,7 +363,12 @@ export default class MessageActionBar extends React.PureComponent { this.activateSpoilers([content]); HtmlUtils.linkifyElement(content); - pillifyLinks([content], this.props.mxEvent, this.pills); + pillifyLinks(MatrixClientPeg.get(), [content], this.props.mxEvent, this.pills); this.calculateUrlPreview(); diff --git a/src/components/views/right_panel/RoomSummaryCard.tsx b/src/components/views/right_panel/RoomSummaryCard.tsx index 4e69d7ccce..acc4662a82 100644 --- a/src/components/views/right_panel/RoomSummaryCard.tsx +++ b/src/components/views/right_panel/RoomSummaryCard.tsx @@ -108,8 +108,8 @@ const AppRow: React.FC = ({ app, room }) => { const [canModifyWidget, setCanModifyWidget] = useState(); useEffect(() => { - setCanModifyWidget(WidgetUtils.canUserModifyWidgets(room.roomId)); - }, [room.roomId]); + setCanModifyWidget(WidgetUtils.canUserModifyWidgets(room.client, room.roomId)); + }, [room.client, room.roomId]); const onOpenWidgetClick = (): void => { RightPanelStore.instance.pushCard({ diff --git a/src/components/views/right_panel/UserInfo.tsx b/src/components/views/right_panel/UserInfo.tsx index 99498c1fe9..dcd447b344 100644 --- a/src/components/views/right_panel/UserInfo.tsx +++ b/src/components/views/right_panel/UserInfo.tsx @@ -456,7 +456,7 @@ export const UserOptionsSection: React.FC<{ const onInviteUserButton = async (ev: ButtonEvent): Promise => { try { // We use a MultiInviter to re-use the invite logic, even though we're only inviting one user. - const inviter = new MultiInviter(roomId || ""); + const inviter = new MultiInviter(cli, roomId || ""); await inviter.invite([member.userId]).then(() => { if (inviter.getCompletionState(member.userId) !== "invited") { const errorStringFromInviterUtility = inviter.getErrorText(member.userId); diff --git a/src/components/views/rooms/EditMessageComposer.tsx b/src/components/views/rooms/EditMessageComposer.tsx index 6d561d3cd2..9043a5662f 100644 --- a/src/components/views/rooms/EditMessageComposer.tsx +++ b/src/components/views/rooms/EditMessageComposer.tsx @@ -50,6 +50,7 @@ import { editorRoomKey, editorStateKey } from "../../../Editing"; import DocumentOffset from "../../../editor/offset"; import { attachMentions, attachRelation } from "./SendMessageComposer"; import { filterBoolean } from "../../../utils/arrays"; +import { MatrixClientPeg } from "../../../MatrixClientPeg"; function getHtmlReplyFallback(mxEvent: MatrixEvent): string { const html = mxEvent.getContent().formatted_body; @@ -184,6 +185,7 @@ class EditMessageComposer extends React.Component private unmounted = false; - public constructor(props: EventTileProps, context: React.ContextType) { + public constructor(props: EventTileProps, context: React.ContextType) { super(props, context); const thread = this.thread; @@ -904,7 +903,12 @@ export class UnwrappedEventTile extends React.Component isLeftAlignedBubbleMessage, noBubbleEvent, isSeeingThroughMessageHiddenForModeration, - } = getEventDisplayInfo(this.props.mxEvent, this.context.showHiddenEvents, this.shouldHideEvent()); + } = getEventDisplayInfo( + MatrixClientPeg.get(), + this.props.mxEvent, + this.context.showHiddenEvents, + this.shouldHideEvent(), + ); const { isQuoteExpanded } = this.state; // This shouldn't happen: the caller should check we support this type // before trying to instantiate us diff --git a/src/components/views/rooms/MessageComposer.tsx b/src/components/views/rooms/MessageComposer.tsx index 4025954f64..55742d8c7e 100644 --- a/src/components/views/rooms/MessageComposer.tsx +++ b/src/components/views/rooms/MessageComposer.tsx @@ -527,7 +527,7 @@ export class MessageComposer extends React.Component { const continuesLink = replacementRoomId ? ( diff --git a/src/components/views/rooms/NewRoomIntro.tsx b/src/components/views/rooms/NewRoomIntro.tsx index b01a703683..b1186a6d45 100644 --- a/src/components/views/rooms/NewRoomIntro.tsx +++ b/src/components/views/rooms/NewRoomIntro.tsx @@ -44,7 +44,7 @@ import { shouldEncryptRoomWithSingle3rdPartyInvite } from "../../../utils/room/s function hasExpectedEncryptionSettings(matrixClient: MatrixClient, room: Room): boolean { const isEncrypted: boolean = matrixClient.isRoomEncrypted(room.roomId); const isPublic: boolean = room.getJoinRule() === "public"; - return isPublic || !privateShouldBeEncrypted() || isEncrypted; + return isPublic || !privateShouldBeEncrypted(matrixClient) || isEncrypted; } const determineIntroMessage = (room: Room, encryptedSingle3rdPartyInvite: boolean): string => { diff --git a/src/components/views/rooms/ReplyTile.tsx b/src/components/views/rooms/ReplyTile.tsx index f3fbf73db8..05997eb78b 100644 --- a/src/components/views/rooms/ReplyTile.tsx +++ b/src/components/views/rooms/ReplyTile.tsx @@ -34,6 +34,7 @@ import MVoiceMessageBody from "../messages/MVoiceMessageBody"; import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload"; import { renderReplyTile } from "../../../events/EventTileFactory"; import { GetRelationsForEvent } from "../rooms/EventTile"; +import { MatrixClientPeg } from "../../../MatrixClientPeg"; interface IProps { mxEvent: MatrixEvent; @@ -110,6 +111,7 @@ export default class ReplyTile extends React.PureComponent { const evType = mxEvent.getType(); const { hasRenderer, isInfoMessage, isSeeingThroughMessageHiddenForModeration } = getEventDisplayInfo( + MatrixClientPeg.get(), mxEvent, false /* Replies are never hidden, so this should be fine */, ); diff --git a/src/components/views/rooms/SendMessageComposer.tsx b/src/components/views/rooms/SendMessageComposer.tsx index 0789c41905..74a3b91a6e 100644 --- a/src/components/views/rooms/SendMessageComposer.tsx +++ b/src/components/views/rooms/SendMessageComposer.tsx @@ -335,6 +335,7 @@ export class SendMessageComposer extends React.Component { } this.props.setStickerPickerOpen(false); - WidgetUtils.removeStickerpickerWidgets() + WidgetUtils.removeStickerpickerWidgets(this.props.room.client) .then(() => { this.forceUpdate(); }) @@ -169,7 +169,7 @@ export default class Stickerpicker extends React.PureComponent { } private updateWidget = (): void => { - const stickerpickerWidget = WidgetUtils.getStickerpickerWidgets()[0]; + const stickerpickerWidget = WidgetUtils.getStickerpickerWidgets(this.props.room.client)[0]; if (!stickerpickerWidget) { Stickerpicker.currentWidget = undefined; this.setState({ stickerpickerWidget: null, widgetId: null }); diff --git a/src/components/views/rooms/VoiceRecordComposerTile.tsx b/src/components/views/rooms/VoiceRecordComposerTile.tsx index 0549f2a2a9..fb90e17609 100644 --- a/src/components/views/rooms/VoiceRecordComposerTile.tsx +++ b/src/components/views/rooms/VoiceRecordComposerTile.tsx @@ -146,8 +146,10 @@ export default class VoiceRecordComposerTile extends React.PureComponent - MatrixClientPeg.get().sendMessage(actualRoomId, content), + doMaybeLocalRoomAction( + this.props.room.roomId, + (actualRoomId: string) => MatrixClientPeg.get().sendMessage(actualRoomId, content), + this.props.room.client, ); } catch (e) { logger.error("Error sending voice message:", e); diff --git a/src/components/views/rooms/wysiwyg_composer/hooks/useInputEventProcessor.ts b/src/components/views/rooms/wysiwyg_composer/hooks/useInputEventProcessor.ts index 9fcad115f2..9b41227ba3 100644 --- a/src/components/views/rooms/wysiwyg_composer/hooks/useInputEventProcessor.ts +++ b/src/components/views/rooms/wysiwyg_composer/hooks/useInputEventProcessor.ts @@ -185,6 +185,7 @@ function dispatchEditEvent( events: foundEvents, isForward, fromEventId: editorStateTransfer?.getEvent().getId(), + matrixClient: mxClient, }); if (newEvent) { dis.dispatch({ diff --git a/src/components/views/settings/SecureBackupPanel.tsx b/src/components/views/settings/SecureBackupPanel.tsx index 2f2ecb42f5..7f988d8d41 100644 --- a/src/components/views/settings/SecureBackupPanel.tsx +++ b/src/components/views/settings/SecureBackupPanel.tsx @@ -419,7 +419,7 @@ export default class SecureBackupPanel extends React.PureComponent<{}, IState> { , ); - if (!isSecureBackupRequired()) { + if (!isSecureBackupRequired(MatrixClientPeg.get())) { actions.push( {_t("Delete Backup")} diff --git a/src/components/views/settings/SetIdServer.tsx b/src/components/views/settings/SetIdServer.tsx index 0f1742a8d4..9b3ad376cd 100644 --- a/src/components/views/settings/SetIdServer.tsx +++ b/src/components/views/settings/SetIdServer.tsx @@ -179,7 +179,7 @@ export default class SetIdServer extends React.Component { let save = true; // Double check that the identity server even has terms of service. - const hasTerms = await doesIdentityServerHaveTerms(fullUrl); + const hasTerms = await doesIdentityServerHaveTerms(MatrixClientPeg.get(), fullUrl); if (!hasTerms) { const [confirmed] = await this.showNoTermsWarning(fullUrl); save = !!confirmed; diff --git a/src/components/views/settings/tabs/user/SecurityUserSettingsTab.tsx b/src/components/views/settings/tabs/user/SecurityUserSettingsTab.tsx index 8e94ca6988..535f4ccc2a 100644 --- a/src/components/views/settings/tabs/user/SecurityUserSettingsTab.tsx +++ b/src/components/views/settings/tabs/user/SecurityUserSettingsTab.tsx @@ -316,7 +316,7 @@ export default class SecurityUserSettingsTab extends React.Component {_t( diff --git a/src/components/views/toasts/VerificationRequestToast.tsx b/src/components/views/toasts/VerificationRequestToast.tsx index 5432909d30..aeb12379c4 100644 --- a/src/components/views/toasts/VerificationRequestToast.tsx +++ b/src/components/views/toasts/VerificationRequestToast.tsx @@ -165,7 +165,7 @@ export default class VerificationRequestToast extends React.PureComponent("FTUE.useCaseSelection"); const context = useUserOnboardingContext(); diff --git a/src/contexts/MatrixClientContext.tsx b/src/contexts/MatrixClientContext.tsx index da351b1574..4830e29198 100644 --- a/src/contexts/MatrixClientContext.tsx +++ b/src/contexts/MatrixClientContext.tsx @@ -36,7 +36,7 @@ export interface MatrixClientProps { mxClient: MatrixClient; } -export function useMatrixClientContext(): MatrixClient | undefined { +export function useMatrixClientContext(): MatrixClient { return useContext(MatrixClientContext); } diff --git a/src/createRoom.ts b/src/createRoom.ts index 1b600657cf..1001b262aa 100644 --- a/src/createRoom.ts +++ b/src/createRoom.ts @@ -462,7 +462,7 @@ export async function ensureDMExists(client: MatrixClient, userId: string): Prom roomId = existingDMRoom.roomId; } else { let encryption: boolean | undefined; - if (privateShouldBeEncrypted()) { + if (privateShouldBeEncrypted(client)) { encryption = await canEncryptToAllUsers(client, [userId]); } diff --git a/src/integrations/IntegrationManagers.ts b/src/integrations/IntegrationManagers.ts index 5defc09746..38e5bcb96f 100644 --- a/src/integrations/IntegrationManagers.ts +++ b/src/integrations/IntegrationManagers.ts @@ -115,7 +115,7 @@ export class IntegrationManagers { private setupAccountManagers(): void { if (!this.client || !this.client.getUserId()) return; // not logged in - const widgets = WidgetUtils.getIntegrationManagerWidgets(); + const widgets = WidgetUtils.getIntegrationManagerWidgets(this.client); widgets.forEach((w) => { const data = w.content["data"]; if (!data) return; @@ -180,14 +180,6 @@ export class IntegrationManagers { Modal.createDialog(IntegrationsDisabledDialog); } - public async overwriteManagerOnAccount(manager: IntegrationManagerInstance): Promise { - // TODO: TravisR - We should be logging out of scalar clients. - await WidgetUtils.removeIntegrationManagerWidgets(); - - // TODO: TravisR - We should actually be carrying over the discovery response verbatim. - await WidgetUtils.addIntegrationManagerWidget(manager.name, manager.uiUrl, manager.apiUrl); - } - /** * Attempts to discover an integration manager using only its name. This will not validate that * the integration manager is functional - that is the caller's responsibility. diff --git a/src/linkify-matrix.ts b/src/linkify-matrix.ts index f48bbe1514..d753bc21d7 100644 --- a/src/linkify-matrix.ts +++ b/src/linkify-matrix.ts @@ -30,6 +30,7 @@ import dis from "./dispatcher/dispatcher"; import { Action } from "./dispatcher/actions"; import { ViewUserPayload } from "./dispatcher/payloads/ViewUserPayload"; import { ViewRoomPayload } from "./dispatcher/payloads/ViewRoomPayload"; +import { MatrixClientPeg } from "./MatrixClientPeg"; export enum Type { URL = "url", @@ -196,7 +197,7 @@ export const options: Opts = { case Type.RoomAlias: case Type.UserId: default: { - return tryTransformEntityToPermalink(href) ?? ""; + return tryTransformEntityToPermalink(MatrixClientPeg.get(), href) ?? ""; } } }, diff --git a/src/models/Call.ts b/src/models/Call.ts index c78aed3a40..e77612d664 100644 --- a/src/models/Call.ts +++ b/src/models/Call.ts @@ -342,7 +342,7 @@ export class JitsiCall extends Call { } public static async create(room: Room): Promise { - await WidgetUtils.addJitsiWidget(room.roomId, CallType.Video, "Group call", true, room.name); + await WidgetUtils.addJitsiWidget(room.client, room.roomId, CallType.Video, "Group call", true, room.name); } private updateParticipants(): void { diff --git a/src/utils/DMRoomMap.ts b/src/utils/DMRoomMap.ts index 5aab198e62..d282596b7f 100644 --- a/src/utils/DMRoomMap.ts +++ b/src/utils/DMRoomMap.ts @@ -22,7 +22,6 @@ import { EventType } from "matrix-js-sdk/src/@types/event"; import { MatrixEvent } from "matrix-js-sdk/src/models/event"; import { Optional } from "matrix-events-sdk"; -import { MatrixClientPeg } from "../MatrixClientPeg"; import { filterValidMDirect } from "./dm/filterValidMDirect"; /** @@ -53,8 +52,8 @@ export default class DMRoomMap { * Makes and returns a new shared instance that can then be accessed * with shared(). This returned instance is not automatically started. */ - public static makeShared(): DMRoomMap { - DMRoomMap.sharedInstance = new DMRoomMap(MatrixClientPeg.get()); + public static makeShared(matrixClient: MatrixClient): DMRoomMap { + DMRoomMap.sharedInstance = new DMRoomMap(matrixClient); return DMRoomMap.sharedInstance; } @@ -175,7 +174,7 @@ export default class DMRoomMap { } const joinedRooms = commonRooms - .map((r) => MatrixClientPeg.get().getRoom(r)) + .map((r) => this.matrixClient.getRoom(r)) .filter((r) => r && r.getMyMembership() === "join"); return joinedRooms[0]; diff --git a/src/utils/DialogOpener.ts b/src/utils/DialogOpener.ts index c02ccf2841..0dc39b92e6 100644 --- a/src/utils/DialogOpener.ts +++ b/src/utils/DialogOpener.ts @@ -16,13 +16,13 @@ limitations under the License. import classnames from "classnames"; import { ComponentProps } from "react"; +import { MatrixClient } from "matrix-js-sdk/src/matrix"; import defaultDispatcher from "../dispatcher/dispatcher"; import { ActionPayload } from "../dispatcher/payloads"; import Modal from "../Modal"; import RoomSettingsDialog from "../components/views/dialogs/RoomSettingsDialog"; import ForwardDialog from "../components/views/dialogs/ForwardDialog"; -import { MatrixClientPeg } from "../MatrixClientPeg"; import { Action } from "../dispatcher/actions"; import ReportEventDialog from "../components/views/dialogs/ReportEventDialog"; import SpacePreferencesDialog from "../components/views/dialogs/SpacePreferencesDialog"; @@ -43,18 +43,21 @@ export class DialogOpener { public static readonly instance = new DialogOpener(); private isRegistered = false; + private matrixClient?: MatrixClient; private constructor() {} // We could do this in the constructor, but then we wouldn't have // a function to call from Lifecycle to capture the class. - public prepare(): void { + public prepare(matrixClient: MatrixClient): void { + this.matrixClient = matrixClient; if (this.isRegistered) return; defaultDispatcher.register(this.onDispatch); this.isRegistered = true; } private onDispatch = (payload: ActionPayload): void => { + if (!this.matrixClient) return; switch (payload.action) { case "open_room_settings": Modal.createDialog( @@ -70,7 +73,7 @@ export class DialogOpener { break; case Action.OpenForwardDialog: Modal.createDialog(ForwardDialog, { - matrixClient: MatrixClientPeg.get(), + matrixClient: this.matrixClient, event: payload.event, permalinkCreator: payload.permalinkCreator, }); diff --git a/src/utils/EventRenderingUtils.ts b/src/utils/EventRenderingUtils.ts index ccb0c25c90..eda5a14320 100644 --- a/src/utils/EventRenderingUtils.ts +++ b/src/utils/EventRenderingUtils.ts @@ -18,11 +18,10 @@ import { MatrixEvent } from "matrix-js-sdk/src/models/event"; import { EventType, MsgType } from "matrix-js-sdk/src/@types/event"; import { M_POLL_END, M_POLL_START } from "matrix-js-sdk/src/@types/polls"; import { M_BEACON_INFO } from "matrix-js-sdk/src/@types/beacon"; -import { IContent } from "matrix-js-sdk/src/matrix"; +import { IContent, MatrixClient } from "matrix-js-sdk/src/matrix"; import SettingsStore from "../settings/SettingsStore"; import { haveRendererForEvent, JitsiEventFactory, JSONEventFactory, pickFactory } from "../events/EventTileFactory"; -import { MatrixClientPeg } from "../MatrixClientPeg"; import { getMessageModerationState, isLocationEvent, MessageModerationState } from "./EventUtils"; import { ElementCall } from "../models/Call"; import { VoiceBroadcastInfoEventType, VoiceBroadcastInfoState } from "../voice-broadcast"; @@ -48,6 +47,7 @@ const calcIsInfoMessage = ( }; export function getEventDisplayInfo( + matrixClient: MatrixClient, mxEvent: MatrixEvent, showHiddenEvents: boolean, hideEvent?: boolean, @@ -65,7 +65,7 @@ export function getEventDisplayInfo( let isSeeingThroughMessageHiddenForModeration = false; if (SettingsStore.getValue("feature_msc3531_hide_messages_pending_moderation")) { - switch (getMessageModerationState(mxEvent)) { + switch (getMessageModerationState(mxEvent, matrixClient)) { case MessageModerationState.VISIBLE_FOR_ALL: case MessageModerationState.HIDDEN_TO_CURRENT_USER: // Nothing specific to do here @@ -77,8 +77,7 @@ export function getEventDisplayInfo( } } - // TODO: Thread a MatrixClient through to here - let factory = pickFactory(mxEvent, MatrixClientPeg.get(), showHiddenEvents); + let factory = pickFactory(mxEvent, matrixClient, showHiddenEvents); // Info messages are basically information about commands processed on a room let isBubbleMessage = @@ -103,10 +102,8 @@ export function getEventDisplayInfo( // replace relations (which otherwise would display as a confusing // duplicate of the thing they are replacing). if (hideEvent || !haveRendererForEvent(mxEvent, showHiddenEvents)) { - // forcefully ask for a factory for a hidden event (hidden event - // setting is checked internally) - // TODO: Thread a MatrixClient through to here - factory = pickFactory(mxEvent, MatrixClientPeg.get(), showHiddenEvents, true); + // forcefully ask for a factory for a hidden event (hidden event setting is checked internally) + factory = pickFactory(mxEvent, matrixClient, showHiddenEvents, true); if (factory === JSONEventFactory) { isBubbleMessage = false; // Reuse info message avatar and sender profile styling diff --git a/src/utils/EventUtils.ts b/src/utils/EventUtils.ts index 6f1b1a64fa..4a1762a1c0 100644 --- a/src/utils/EventUtils.ts +++ b/src/utils/EventUtils.ts @@ -23,7 +23,6 @@ import { M_LOCATION } from "matrix-js-sdk/src/@types/location"; import { M_BEACON_INFO } from "matrix-js-sdk/src/@types/beacon"; import { THREAD_RELATION_TYPE } from "matrix-js-sdk/src/models/thread"; -import { MatrixClientPeg } from "../MatrixClientPeg"; import shouldHideEvent from "../shouldHideEvent"; import { GetRelationsForEvent } from "../components/views/rooms/EventTile"; import SettingsStore from "../settings/SettingsStore"; @@ -69,7 +68,7 @@ export function isContentActionable(mxEvent: MatrixEvent): boolean { return false; } -export function canEditContent(mxEvent: MatrixEvent): boolean { +export function canEditContent(matrixClient: MatrixClient, mxEvent: MatrixEvent): boolean { const isCancellable = mxEvent.getType() === EventType.RoomMessage || M_POLL_START.matches(mxEvent.getType()); if ( @@ -77,7 +76,7 @@ export function canEditContent(mxEvent: MatrixEvent): boolean { mxEvent.status === EventStatus.CANCELLED || mxEvent.isRedacted() || mxEvent.isRelation(RelationType.Replace) || - mxEvent.getSender() !== MatrixClientPeg.get().getUserId() + mxEvent.getSender() !== matrixClient.getUserId() ) { return false; } @@ -89,22 +88,24 @@ export function canEditContent(mxEvent: MatrixEvent): boolean { ); } -export function canEditOwnEvent(mxEvent: MatrixEvent): boolean { +export function canEditOwnEvent(matrixClient: MatrixClient, mxEvent: MatrixEvent): boolean { // for now we only allow editing // your own events. So this just call through // In the future though, moderators will be able to // edit other people's messages as well but we don't // want findEditableEvent to return other people's events // hence this method. - return canEditContent(mxEvent); + return canEditContent(matrixClient, mxEvent); } const MAX_JUMP_DISTANCE = 100; export function findEditableEvent({ + matrixClient, events, isForward, fromEventId, }: { + matrixClient: MatrixClient; events: MatrixEvent[]; isForward: boolean; fromEventId?: string; @@ -126,7 +127,7 @@ export function findEditableEvent({ // don't look further than MAX_JUMP_DISTANCE events from `fromEventId` // to not iterate potentially 1000nds of events on key up/down endIdx = Math.min(Math.max(0, i + inc * MAX_JUMP_DISTANCE), maxIdx); - } else if (foundFromEventId && !shouldHideEvent(e) && canEditOwnEvent(e)) { + } else if (foundFromEventId && !shouldHideEvent(e) && canEditOwnEvent(matrixClient, e)) { // otherwise look for editable event return e; } @@ -170,9 +171,7 @@ const getMsc3531Enabled = (): boolean => { * If MSC3531 is deactivated in settings, all messages are considered visible * to all. */ -export function getMessageModerationState(mxEvent: MatrixEvent, client?: MatrixClient): MessageModerationState { - client = client ?? MatrixClientPeg.get(); // because param defaults don't do the correct thing - +export function getMessageModerationState(mxEvent: MatrixEvent, client: MatrixClient): MessageModerationState { if (!getMsc3531Enabled()) { return MessageModerationState.VISIBLE_FOR_ALL; } @@ -246,11 +245,12 @@ export async function fetchInitialEvent( } export function editEvent( + matrixClient: MatrixClient, mxEvent: MatrixEvent, timelineRenderingType: TimelineRenderingType, getRelationsForEvent?: GetRelationsForEvent, ): void { - if (!canEditContent(mxEvent)) return; + if (!canEditContent(matrixClient, mxEvent)) return; if (M_POLL_START.matches(mxEvent.getType())) { launchPollEditor(mxEvent, getRelationsForEvent); diff --git a/src/utils/IdentityServerUtils.ts b/src/utils/IdentityServerUtils.ts index 96a0021e3b..d51d554ae4 100644 --- a/src/utils/IdentityServerUtils.ts +++ b/src/utils/IdentityServerUtils.ts @@ -17,27 +17,27 @@ limitations under the License. import { SERVICE_TYPES } from "matrix-js-sdk/src/service-types"; import { logger } from "matrix-js-sdk/src/logger"; import { HTTPError } from "matrix-js-sdk/src/http-api"; +import { MatrixClient } from "matrix-js-sdk/src/matrix"; import SdkConfig from "../SdkConfig"; -import { MatrixClientPeg } from "../MatrixClientPeg"; import { Policies } from "../Terms"; export function getDefaultIdentityServerUrl(): string | undefined { return SdkConfig.get("validated_server_config")?.isUrl; } -export function setToDefaultIdentityServer(): void { +export function setToDefaultIdentityServer(matrixClient: MatrixClient): void { const url = getDefaultIdentityServerUrl(); // Account data change will update localstorage, client, etc through dispatcher - MatrixClientPeg.get().setAccountData("m.identity_server", { + matrixClient.setAccountData("m.identity_server", { base_url: url, }); } -export async function doesIdentityServerHaveTerms(fullUrl: string): Promise { +export async function doesIdentityServerHaveTerms(matrixClient: MatrixClient, fullUrl: string): Promise { let terms: { policies?: Policies } | null; try { - terms = await MatrixClientPeg.get().getTerms(SERVICE_TYPES.IS, fullUrl); + terms = await matrixClient.getTerms(SERVICE_TYPES.IS, fullUrl); } catch (e) { logger.error(e); if (e.cors === "rejected" || (e instanceof HTTPError && e.httpStatus === 404)) { @@ -50,7 +50,7 @@ export async function doesIdentityServerHaveTerms(fullUrl: string): Promise 0; } -export function doesAccountDataHaveIdentityServer(): boolean { - const event = MatrixClientPeg.get().getAccountData("m.identity_server"); - return event && event.getContent() && event.getContent()["base_url"]; +export function doesAccountDataHaveIdentityServer(matrixClient: MatrixClient): boolean { + const event = matrixClient.getAccountData("m.identity_server"); + return event?.getContent()["base_url"]; } diff --git a/src/utils/KeyVerificationStateObserver.ts b/src/utils/KeyVerificationStateObserver.ts index d388345eac..73f1076416 100644 --- a/src/utils/KeyVerificationStateObserver.ts +++ b/src/utils/KeyVerificationStateObserver.ts @@ -14,18 +14,18 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { MatrixClientPeg } from "../MatrixClientPeg"; +import { MatrixClient } from "matrix-js-sdk/src/matrix"; + import { _t } from "../languageHandler"; -export function getNameForEventRoom(userId: string, roomId: string): string { - const client = MatrixClientPeg.get(); - const room = client.getRoom(roomId); +export function getNameForEventRoom(matrixClient: MatrixClient, userId: string, roomId: string): string { + const room = matrixClient.getRoom(roomId); const member = room && room.getMember(userId); return member ? member.name : userId; } -export function userLabelForEventRoom(userId: string, roomId: string): string { - const name = getNameForEventRoom(userId, roomId); +export function userLabelForEventRoom(matrixClient: MatrixClient, userId: string, roomId: string): string { + const name = getNameForEventRoom(matrixClient, userId, roomId); if (name !== userId) { return _t("%(name)s (%(userId)s)", { name, userId }); } else { diff --git a/src/utils/MultiInviter.ts b/src/utils/MultiInviter.ts index a4c2657140..1cff080a63 100644 --- a/src/utils/MultiInviter.ts +++ b/src/utils/MultiInviter.ts @@ -21,7 +21,6 @@ import { MatrixClient } from "matrix-js-sdk/src/client"; import { EventType } from "matrix-js-sdk/src/@types/event"; import { HistoryVisibility } from "matrix-js-sdk/src/@types/partials"; -import { MatrixClientPeg } from "../MatrixClientPeg"; import { AddressType, getAddressType } from "../UserAddress"; import { _t } from "../languageHandler"; import Modal from "../Modal"; @@ -54,8 +53,6 @@ const USER_ALREADY_INVITED = "IO.ELEMENT.ALREADY_INVITED"; * Invites multiple addresses to a room, handling rate limiting from the server */ export default class MultiInviter { - private readonly matrixClient: MatrixClient; - private canceled = false; private addresses: string[] = []; private busy = false; @@ -66,12 +63,15 @@ export default class MultiInviter { private reason: string | undefined; /** + * @param matrixClient the client of the logged in user * @param {string} roomId The ID of the room to invite to * @param {function} progressCallback optional callback, fired after each invite. */ - public constructor(private roomId: string, private readonly progressCallback?: () => void) { - this.matrixClient = MatrixClientPeg.get(); - } + public constructor( + private readonly matrixClient: MatrixClient, + private roomId: string, + private readonly progressCallback?: () => void, + ) {} public get fatal(): boolean { return this._fatal; diff --git a/src/utils/PasswordScorer.ts b/src/utils/PasswordScorer.ts index 53dea3c78c..fa2ef92058 100644 --- a/src/utils/PasswordScorer.ts +++ b/src/utils/PasswordScorer.ts @@ -15,8 +15,8 @@ limitations under the License. */ import zxcvbn, { ZXCVBNFeedbackWarning } from "zxcvbn"; +import { MatrixClient } from "matrix-js-sdk/src/matrix"; -import { MatrixClientPeg } from "../MatrixClientPeg"; import { _t, _td } from "../languageHandler"; const ZXCVBN_USER_INPUTS = ["riot", "matrix"]; @@ -58,14 +58,15 @@ _td("Short keyboard patterns are easy to guess"); * (obviously) which is large. * * @param {string} password Password to score + * @param matrixClient the client of the logged in user, if any * @returns {object} Score result with `score` and `feedback` properties */ -export function scorePassword(password: string): zxcvbn.ZXCVBNResult | null { +export function scorePassword(matrixClient: MatrixClient | undefined, password: string): zxcvbn.ZXCVBNResult | null { if (password.length === 0) return null; const userInputs = ZXCVBN_USER_INPUTS.slice(); - if (MatrixClientPeg.get()) { - userInputs.push(MatrixClientPeg.get().getUserIdLocalpart()!); + if (matrixClient) { + userInputs.push(matrixClient.getUserIdLocalpart()!); } let zxcvbnResult = zxcvbn(password, userInputs); diff --git a/src/utils/RoomUpgrade.ts b/src/utils/RoomUpgrade.ts index 669a8e8bfe..040bfbd515 100644 --- a/src/utils/RoomUpgrade.ts +++ b/src/utils/RoomUpgrade.ts @@ -118,7 +118,7 @@ export async function upgradeRoom( if (toInvite.length > 0) { // Errors are handled internally to this function - await inviteUsersToRoom(newRoomId, toInvite, false, () => { + await inviteUsersToRoom(cli, newRoomId, toInvite, false, () => { progress.inviteUsersProgress!++; progressCallback?.(progress); }); diff --git a/src/utils/WellKnownUtils.ts b/src/utils/WellKnownUtils.ts index d65550516e..369de6c6b0 100644 --- a/src/utils/WellKnownUtils.ts +++ b/src/utils/WellKnownUtils.ts @@ -14,11 +14,9 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { IClientWellKnown } from "matrix-js-sdk/src/client"; +import { IClientWellKnown, MatrixClient } from "matrix-js-sdk/src/client"; import { UnstableValue } from "matrix-js-sdk/src/NamespacedValue"; -import { MatrixClientPeg } from "../MatrixClientPeg"; - const CALL_BEHAVIOUR_WK_KEY = "io.element.call_behaviour"; const E2EE_WK_KEY = "io.element.e2ee"; const E2EE_WK_KEY_DEPRECATED = "im.vector.riot.e2ee"; @@ -45,13 +43,13 @@ export interface IEmbeddedPagesWellKnown { } /* eslint-enable camelcase */ -export function getCallBehaviourWellKnown(): ICallBehaviourWellKnown { - const clientWellKnown = MatrixClientPeg.get().getClientWellKnown(); +export function getCallBehaviourWellKnown(matrixClient: MatrixClient): ICallBehaviourWellKnown { + const clientWellKnown = matrixClient.getClientWellKnown(); return clientWellKnown?.[CALL_BEHAVIOUR_WK_KEY]; } -export function getE2EEWellKnown(): IE2EEWellKnown | null { - const clientWellKnown = MatrixClientPeg.get().getClientWellKnown(); +export function getE2EEWellKnown(matrixClient: MatrixClient): IE2EEWellKnown | null { + const clientWellKnown = matrixClient.getClientWellKnown(); if (clientWellKnown?.[E2EE_WK_KEY]) { return clientWellKnown[E2EE_WK_KEY]; } @@ -61,24 +59,24 @@ export function getE2EEWellKnown(): IE2EEWellKnown | null { return null; } -export function getTileServerWellKnown(): ITileServerWellKnown | undefined { - return tileServerFromWellKnown(MatrixClientPeg.get().getClientWellKnown()); +export function getTileServerWellKnown(matrixClient: MatrixClient): ITileServerWellKnown | undefined { + return tileServerFromWellKnown(matrixClient.getClientWellKnown()); } export function tileServerFromWellKnown(clientWellKnown?: IClientWellKnown | undefined): ITileServerWellKnown { return clientWellKnown?.[TILE_SERVER_WK_KEY.name] ?? clientWellKnown?.[TILE_SERVER_WK_KEY.altName]; } -export function getEmbeddedPagesWellKnown(): IEmbeddedPagesWellKnown | undefined { - return embeddedPagesFromWellKnown(MatrixClientPeg.get()?.getClientWellKnown()); +export function getEmbeddedPagesWellKnown(matrixClient: MatrixClient | undefined): IEmbeddedPagesWellKnown | undefined { + return embeddedPagesFromWellKnown(matrixClient?.getClientWellKnown()); } export function embeddedPagesFromWellKnown(clientWellKnown?: IClientWellKnown): IEmbeddedPagesWellKnown { return clientWellKnown?.[EMBEDDED_PAGES_WK_PROPERTY]; } -export function isSecureBackupRequired(): boolean { - return getE2EEWellKnown()?.["secure_backup_required"] === true; +export function isSecureBackupRequired(matrixClient: MatrixClient): boolean { + return getE2EEWellKnown(matrixClient)?.["secure_backup_required"] === true; } export enum SecureBackupSetupMethod { @@ -86,8 +84,8 @@ export enum SecureBackupSetupMethod { Passphrase = "passphrase", } -export function getSecureBackupSetupMethods(): SecureBackupSetupMethod[] { - const wellKnown = getE2EEWellKnown(); +export function getSecureBackupSetupMethods(matrixClient: MatrixClient): SecureBackupSetupMethod[] { + const wellKnown = getE2EEWellKnown(matrixClient); if ( !wellKnown || !wellKnown["secure_backup_setup_methods"] || diff --git a/src/utils/WidgetUtils.ts b/src/utils/WidgetUtils.ts index 6a47d591f8..6028b64700 100644 --- a/src/utils/WidgetUtils.ts +++ b/src/utils/WidgetUtils.ts @@ -20,11 +20,10 @@ import { IWidget, IWidgetData } from "matrix-widget-api"; import { Room } from "matrix-js-sdk/src/models/room"; import { MatrixEvent } from "matrix-js-sdk/src/models/event"; import { logger } from "matrix-js-sdk/src/logger"; -import { ClientEvent, RoomStateEvent } from "matrix-js-sdk/src/matrix"; +import { ClientEvent, MatrixClient, RoomStateEvent } from "matrix-js-sdk/src/matrix"; import { CallType } from "matrix-js-sdk/src/webrtc/call"; import { randomString, randomLowercaseString, randomUppercaseString } from "matrix-js-sdk/src/randomstring"; -import { MatrixClientPeg } from "../MatrixClientPeg"; import PlatformPeg from "../PlatformPeg"; import SdkConfig from "../SdkConfig"; import dis from "../dispatcher/dispatcher"; @@ -55,19 +54,20 @@ export interface UserWidget extends Omit { } export default class WidgetUtils { - /* Returns true if user is able to send state events to modify widgets in this room + /** + * Returns true if user is able to send state events to modify widgets in this room * (Does not apply to non-room-based / user widgets) + * @param client The matrix client of the logged-in user * @param roomId -- The ID of the room to check * @return Boolean -- true if the user can modify widgets in this room * @throws Error -- specifies the error reason */ - public static canUserModifyWidgets(roomId?: string): boolean { + public static canUserModifyWidgets(client: MatrixClient, roomId?: string): boolean { if (!roomId) { logger.warn("No room ID specified"); return false; } - const client = MatrixClientPeg.get(); if (!client) { logger.warn("User must be be logged in"); return false; @@ -79,7 +79,7 @@ export default class WidgetUtils { return false; } - const me = client.credentials.userId; + const me = client.getUserId(); if (!me) { logger.warn("Failed to get user ID"); return false; @@ -97,6 +97,7 @@ export default class WidgetUtils { // TODO: Generify the name of this function. It's not just scalar. /** * Returns true if specified url is a scalar URL, typically https://scalar.vector.im/api + * @param matrixClient The matrix client of the logged-in user * @param {[type]} testUrlString URL to check * @return {Boolean} True if specified URL is a scalar URL */ @@ -138,13 +139,14 @@ export default class WidgetUtils { * ID has been added as a user widget (ie. the accountData event * arrives) or rejects after a timeout * - * @param {string} widgetId The ID of the widget to wait for - * @param {boolean} add True to wait for the widget to be added, + * @param client The matrix client of the logged-in user + * @param widgetId The ID of the widget to wait for + * @param add True to wait for the widget to be added, * false to wait for it to be deleted. * @returns {Promise} that resolves when the widget is in the * requested state according to the `add` param */ - public static waitForUserWidget(widgetId: string, add: boolean): Promise { + public static waitForUserWidget(client: MatrixClient, widgetId: string, add: boolean): Promise { return new Promise((resolve, reject) => { // Tests an account data event, returning true if it's in the state // we're waiting for it to be in @@ -157,25 +159,25 @@ export default class WidgetUtils { } } - const startingAccountDataEvent = MatrixClientPeg.get().getAccountData("m.widgets"); + const startingAccountDataEvent = client.getAccountData("m.widgets"); if (eventInIntendedState(startingAccountDataEvent)) { resolve(); return; } function onAccountData(ev: MatrixEvent): void { - const currentAccountDataEvent = MatrixClientPeg.get().getAccountData("m.widgets"); + const currentAccountDataEvent = client.getAccountData("m.widgets"); if (eventInIntendedState(currentAccountDataEvent)) { - MatrixClientPeg.get().removeListener(ClientEvent.AccountData, onAccountData); + client.removeListener(ClientEvent.AccountData, onAccountData); clearTimeout(timerId); resolve(); } } const timerId = window.setTimeout(() => { - MatrixClientPeg.get().removeListener(ClientEvent.AccountData, onAccountData); + client.removeListener(ClientEvent.AccountData, onAccountData); reject(new Error("Timed out waiting for widget ID " + widgetId + " to appear")); }, WIDGET_WAIT_TIME); - MatrixClientPeg.get().on(ClientEvent.AccountData, onAccountData); + client.on(ClientEvent.AccountData, onAccountData); }); } @@ -184,6 +186,7 @@ export default class WidgetUtils { * ID has been added as a room widget in the given room (ie. the * room state event arrives) or rejects after a timeout * + * @param client The matrix client of the logged-in user * @param {string} widgetId The ID of the widget to wait for * @param {string} roomId The ID of the room to wait for the widget in * @param {boolean} add True to wait for the widget to be added, @@ -191,7 +194,12 @@ export default class WidgetUtils { * @returns {Promise} that resolves when the widget is in the * requested state according to the `add` param */ - public static waitForRoomWidget(widgetId: string, roomId: string, add: boolean): Promise { + public static waitForRoomWidget( + client: MatrixClient, + widgetId: string, + roomId: string, + add: boolean, + ): Promise { return new Promise((resolve, reject) => { // Tests a list of state events, returning true if it's in the state // we're waiting for it to be in @@ -206,7 +214,7 @@ export default class WidgetUtils { } } - const room = MatrixClientPeg.get().getRoom(roomId); + const room = client.getRoom(roomId); // TODO: Enable support for m.widget event type (https://github.com/vector-im/element-web/issues/13111) const startingWidgetEvents = room?.currentState.getStateEvents("im.vector.modular.widgets"); if (eventsInIntendedState(startingWidgetEvents)) { @@ -221,30 +229,30 @@ export default class WidgetUtils { const currentWidgetEvents = room?.currentState.getStateEvents("im.vector.modular.widgets"); if (eventsInIntendedState(currentWidgetEvents)) { - MatrixClientPeg.get().removeListener(RoomStateEvent.Events, onRoomStateEvents); + client.removeListener(RoomStateEvent.Events, onRoomStateEvents); clearTimeout(timerId); resolve(); } } const timerId = window.setTimeout(() => { - MatrixClientPeg.get().removeListener(RoomStateEvent.Events, onRoomStateEvents); + client.removeListener(RoomStateEvent.Events, onRoomStateEvents); reject(new Error("Timed out waiting for widget ID " + widgetId + " to appear")); }, WIDGET_WAIT_TIME); - MatrixClientPeg.get().on(RoomStateEvent.Events, onRoomStateEvents); + client.on(RoomStateEvent.Events, onRoomStateEvents); }); } public static setUserWidget( + client: MatrixClient, widgetId: string, widgetType: WidgetType, widgetUrl: string, widgetName: string, widgetData: IWidgetData, ): Promise { - const client = MatrixClientPeg.get(); // Get the current widgets and clone them before we modify them, otherwise // we'll modify the content of the old event. - const userWidgets = objectClone(WidgetUtils.getUserWidgets()); + const userWidgets = objectClone(WidgetUtils.getUserWidgets(client)); // Delete existing widget with ID try { @@ -284,7 +292,7 @@ export default class WidgetUtils { return client .setAccountData("m.widgets", userWidgets) .then(() => { - return WidgetUtils.waitForUserWidget(widgetId, addingWidget); + return WidgetUtils.waitForUserWidget(client, widgetId, addingWidget); }) .then(() => { dis.dispatch({ action: "user_widget_updated" }); @@ -292,6 +300,7 @@ export default class WidgetUtils { } public static setRoomWidget( + client: MatrixClient, roomId: string, widgetId: string, widgetType?: WidgetType, @@ -318,20 +327,24 @@ export default class WidgetUtils { content = {}; } - return WidgetUtils.setRoomWidgetContent(roomId, widgetId, content as IWidget); + return WidgetUtils.setRoomWidgetContent(client, roomId, widgetId, content as IWidget); } - public static setRoomWidgetContent(roomId: string, widgetId: string, content: IWidget): Promise { + public static setRoomWidgetContent( + client: MatrixClient, + roomId: string, + widgetId: string, + content: IWidget, + ): Promise { const addingWidget = !!content.url; WidgetEchoStore.setRoomWidgetEcho(roomId, widgetId, content); - const client = MatrixClientPeg.get(); // TODO: Enable support for m.widget event type (https://github.com/vector-im/element-web/issues/13111) return client .sendStateEvent(roomId, "im.vector.modular.widgets", content, widgetId) .then(() => { - return WidgetUtils.waitForRoomWidget(widgetId, roomId, addingWidget); + return WidgetUtils.waitForRoomWidget(client, widgetId, roomId, addingWidget); }) .finally(() => { WidgetEchoStore.removeRoomWidgetEcho(roomId, widgetId); @@ -357,10 +370,10 @@ export default class WidgetUtils { /** * Get user specific widgets (not linked to a specific room) + * @param client The matrix client of the logged-in user * @return {object} Event content object containing current / active user widgets */ - public static getUserWidgets(): Record { - const client = MatrixClientPeg.get(); + public static getUserWidgets(client: MatrixClient | undefined): Record { if (!client) { throw new Error("User not logged in"); } @@ -373,27 +386,30 @@ export default class WidgetUtils { /** * Get user specific widgets (not linked to a specific room) as an array + * @param client The matrix client of the logged-in user * @return {[object]} Array containing current / active user widgets */ - public static getUserWidgetsArray(): UserWidget[] { - return Object.values(WidgetUtils.getUserWidgets()); + public static getUserWidgetsArray(client: MatrixClient | undefined): UserWidget[] { + return Object.values(WidgetUtils.getUserWidgets(client)); } /** * Get active stickerpicker widgets (stickerpickers are user widgets by nature) + * @param client The matrix client of the logged-in user * @return {[object]} Array containing current / active stickerpicker widgets */ - public static getStickerpickerWidgets(): UserWidget[] { - const widgets = WidgetUtils.getUserWidgetsArray(); + public static getStickerpickerWidgets(client: MatrixClient | undefined): UserWidget[] { + const widgets = WidgetUtils.getUserWidgetsArray(client); return widgets.filter((widget) => widget.content?.type === "m.stickerpicker"); } /** * Get all integration manager widgets for this user. + * @param client The matrix client of the logged-in user * @returns {Object[]} An array of integration manager user widgets. */ - public static getIntegrationManagerWidgets(): UserWidget[] { - const widgets = WidgetUtils.getUserWidgetsArray(); + public static getIntegrationManagerWidgets(client: MatrixClient | undefined): UserWidget[] { + const widgets = WidgetUtils.getUserWidgetsArray(client); return widgets.filter((w) => w.content?.type === "m.integration_manager"); } @@ -405,8 +421,7 @@ export default class WidgetUtils { }); } - public static async removeIntegrationManagerWidgets(): Promise { - const client = MatrixClientPeg.get(); + public static async removeIntegrationManagerWidgets(client: MatrixClient | undefined): Promise { if (!client) { throw new Error("User not logged in"); } @@ -421,8 +436,14 @@ export default class WidgetUtils { await client.setAccountData("m.widgets", userWidgets); } - public static addIntegrationManagerWidget(name: string, uiUrl: string, apiUrl: string): Promise { + public static addIntegrationManagerWidget( + client: MatrixClient, + name: string, + uiUrl: string, + apiUrl: string, + ): Promise { return WidgetUtils.setUserWidget( + client, "integration_manager_" + new Date().getTime(), WidgetType.INTEGRATION_MANAGER, uiUrl, @@ -433,10 +454,10 @@ export default class WidgetUtils { /** * Remove all stickerpicker widgets (stickerpickers are user widgets by nature) + * @param client The matrix client of the logged-in user * @return {Promise} Resolves on account data updated */ - public static async removeStickerpickerWidgets(): Promise { - const client = MatrixClientPeg.get(); + public static async removeStickerpickerWidgets(client: MatrixClient | undefined): Promise { if (!client) { throw new Error("User not logged in"); } @@ -452,6 +473,7 @@ export default class WidgetUtils { } public static async addJitsiWidget( + client: MatrixClient, roomId: string, type: CallType, name: string, @@ -462,7 +484,7 @@ export default class WidgetUtils { const auth = (await Jitsi.getInstance().getJitsiAuth()) ?? undefined; const widgetId = randomString(24); // Must be globally unique - let confId; + let confId: string; if (auth === "openidtoken-jwt") { // Create conference ID from room ID // For compatibility with Jitsi, use base32 without padding. @@ -479,9 +501,9 @@ export default class WidgetUtils { widgetUrl.search = ""; // Causes the URL class use searchParams instead widgetUrl.searchParams.set("confId", confId); - await WidgetUtils.setRoomWidget(roomId, widgetId, WidgetType.JITSI, widgetUrl.toString(), name, { + await WidgetUtils.setRoomWidget(client, roomId, widgetId, WidgetType.JITSI, widgetUrl.toString(), name, { conferenceId: confId, - roomName: oobRoomName ?? MatrixClientPeg.get().getRoom(roomId)?.name, + roomName: oobRoomName ?? client.getRoom(roomId)?.name, isAudioOnly: type === CallType.Voice, isVideoChannel, domain, diff --git a/src/utils/direct-messages.ts b/src/utils/direct-messages.ts index 070685d2f2..42f1febf8f 100644 --- a/src/utils/direct-messages.ts +++ b/src/utils/direct-messages.ts @@ -51,7 +51,7 @@ export async function startDmOnFirstMessage(client: MatrixClient, targets: Membe return existingRoom.roomId; } - if (targets.length === 1 && targets[0] instanceof ThreepidMember && privateShouldBeEncrypted()) { + if (targets.length === 1 && targets[0] instanceof ThreepidMember && privateShouldBeEncrypted(client)) { // Single 3rd-party invite and well-known promotes encryption: // Directly create a room and invite the other. return await startDm(client, targets); @@ -192,7 +192,7 @@ export interface IDMUserTileProps { * @returns {Promise} */ export async function determineCreateRoomEncryptionOption(client: MatrixClient, targets: Member[]): Promise { - if (privateShouldBeEncrypted()) { + if (privateShouldBeEncrypted(client)) { // Enable encryption for a single 3rd party invite. if (targets.length === 1 && targets[0] instanceof ThreepidMember) return true; diff --git a/src/utils/exportUtils/Exporter.ts b/src/utils/exportUtils/Exporter.ts index aaee41ff96..52dbe96ac3 100644 --- a/src/utils/exportUtils/Exporter.ts +++ b/src/utils/exportUtils/Exporter.ts @@ -16,13 +16,11 @@ limitations under the License. import { MatrixEvent } from "matrix-js-sdk/src/models/event"; import { Room } from "matrix-js-sdk/src/models/room"; -import { MatrixClient } from "matrix-js-sdk/src/client"; import { Direction } from "matrix-js-sdk/src/models/event-timeline"; import { saveAs } from "file-saver"; import { logger } from "matrix-js-sdk/src/logger"; import sanitizeFilename from "sanitize-filename"; -import { MatrixClientPeg } from "../../MatrixClientPeg"; import { ExportType, IExportOptions } from "./exportUtils"; import { decryptFile } from "../DecryptFile"; import { mediaFromContent } from "../../customisations/Media"; @@ -39,7 +37,6 @@ type BlobFile = { export default abstract class Exporter { protected files: BlobFile[] = []; - protected client: MatrixClient; protected cancelled = false; protected constructor( @@ -56,7 +53,6 @@ export default abstract class Exporter { ) { throw new Error("Invalid export options"); } - this.client = MatrixClientPeg.get(); window.addEventListener("beforeunload", this.onBeforeUnload); } @@ -124,7 +120,7 @@ export default abstract class Exporter { } protected setEventMetadata(event: MatrixEvent): MatrixEvent { - const roomState = this.client.getRoom(this.room.roomId)?.currentState; + const roomState = this.room.currentState; const sender = event.getSender(); event.sender = (!!sender && roomState?.getSentinelMember(sender)) || null; if (event.getType() === "m.room.member") { @@ -151,7 +147,7 @@ export default abstract class Exporter { } protected async getRequiredEvents(): Promise { - const eventMapper = this.client.getEventMapper(); + const eventMapper = this.room.client.getEventMapper(); let prevToken: string | null = null; let limit = this.getLimit(); @@ -159,7 +155,7 @@ export default abstract class Exporter { while (limit) { const eventsPerCrawl = Math.min(limit, 1000); - const res = await this.client.createMessagesRequest( + const res = await this.room.client.createMessagesRequest( this.room.roomId, prevToken, eventsPerCrawl, @@ -211,7 +207,7 @@ export default abstract class Exporter { const decryptionPromises = events .filter((event) => event.isEncrypted()) .map((event) => { - return this.client.decryptEventIfNeeded(event, { + return this.room.client.decryptEventIfNeeded(event, { isRetry: true, emit: false, }); diff --git a/src/utils/exportUtils/HtmlExport.tsx b/src/utils/exportUtils/HtmlExport.tsx index d18a380625..471d7b28e4 100644 --- a/src/utils/exportUtils/HtmlExport.tsx +++ b/src/utils/exportUtils/HtmlExport.tsx @@ -94,7 +94,7 @@ export default class HTMLExporter extends Exporter { const exportDate = formatFullDateNoDayNoTime(new Date()); const creator = this.room.currentState.getStateEvents(EventType.RoomCreate, "")?.getSender(); const creatorName = (creator ? this.room.getMember(creator)?.rawDisplayName : creator) || creator; - const exporter = this.client.getUserId()!; + const exporter = this.room.client.getSafeUserId(); const exporterName = this.room.getMember(exporter)?.rawDisplayName; const topic = this.room.currentState.getStateEvents(EventType.RoomTopic, "")?.getContent()?.topic || ""; const createdText = _t("%(creatorName)s created this room.", { @@ -282,7 +282,7 @@ export default class HTMLExporter extends Exporter { public getEventTile(mxEv: MatrixEvent, continuation: boolean): JSX.Element { return (
- + { +export async function leaveRoomBehaviour( + matrixClient: MatrixClient, + roomId: string, + retry = true, + spinner = true, +): Promise { let spinnerModal: IHandle | undefined; if (spinner) { spinnerModal = Modal.createDialog(Spinner, undefined, "mx_Dialog_spinner"); } - const cli = MatrixClientPeg.get(); let leavingAllVersions = true; - const history = cli.getRoomUpgradeHistory( + const history = matrixClient.getRoomUpgradeHistory( roomId, false, SettingsStore.getValue("feature_dynamic_room_predecessors"), @@ -60,7 +63,7 @@ export async function leaveRoomBehaviour(roomId: string, retry = true, spinner = } } - const room = cli.getRoom(roomId); + const room = matrixClient.getRoom(roomId); // should not encounter this if (!room) { @@ -97,9 +100,9 @@ export async function leaveRoomBehaviour(roomId: string, retry = true, spinner = let results: { [roomId: string]: Error | MatrixError | null } = {}; if (!leavingAllVersions) { try { - await cli.leave(roomId); + await matrixClient.leave(roomId); } catch (e) { - if (e?.data?.errcode) { + if (e instanceof MatrixError) { const message = e.data.error || _t("Unexpected server error trying to leave the room"); results[roomId] = Object.assign(new Error(message), { errcode: e.data.errcode, data: e.data }); } else { @@ -107,7 +110,7 @@ export async function leaveRoomBehaviour(roomId: string, retry = true, spinner = } } } else { - results = await cli.leaveRoomChain(roomId, retry); + results = await matrixClient.leaveRoomChain(roomId, retry); } if (retry) { @@ -116,7 +119,7 @@ export async function leaveRoomBehaviour(roomId: string, retry = true, spinner = ) as MatrixError; if (limitExceededError) { await sleep(limitExceededError.data.retry_after_ms ?? 100); - return leaveRoomBehaviour(roomId, false, false); + return leaveRoomBehaviour(matrixClient, roomId, false, false); } } @@ -186,7 +189,7 @@ export const leaveSpace = (space: Room): void => { space, onFinished: async (leave: boolean, rooms: Room[]): Promise => { if (!leave) return; - await bulkSpaceBehaviour(space, rooms, (room) => leaveRoomBehaviour(room.roomId)); + await bulkSpaceBehaviour(space, rooms, (room) => leaveRoomBehaviour(space.client, room.roomId)); dis.dispatch({ action: Action.AfterLeaveRoom, diff --git a/src/utils/local-room.ts b/src/utils/local-room.ts index 2199e44340..fbfa050800 100644 --- a/src/utils/local-room.ts +++ b/src/utils/local-room.ts @@ -18,7 +18,6 @@ import { logger } from "matrix-js-sdk/src/logger"; import { ClientEvent, MatrixClient } from "matrix-js-sdk/src/matrix"; import defaultDispatcher from "../dispatcher/dispatcher"; -import { MatrixClientPeg } from "../MatrixClientPeg"; import { LocalRoom, LocalRoomState } from "../models/LocalRoom"; import { isLocalRoom } from "./localRoom/isLocalRoom"; import { isRoomReady } from "./localRoom/isRoomReady"; @@ -39,10 +38,9 @@ import { isRoomReady } from "./localRoom/isRoomReady"; export async function doMaybeLocalRoomAction( roomId: string, fn: (actualRoomId: string) => Promise, - client?: MatrixClient, + client: MatrixClient, ): Promise { if (isLocalRoom(roomId)) { - client = client ?? MatrixClientPeg.get(); const room = client.getRoom(roomId) as LocalRoom; if (room.isCreated) { diff --git a/src/utils/location/findMapStyleUrl.ts b/src/utils/location/findMapStyleUrl.ts index 02ff401b14..48bd644e52 100644 --- a/src/utils/location/findMapStyleUrl.ts +++ b/src/utils/location/findMapStyleUrl.ts @@ -15,6 +15,7 @@ limitations under the License. */ import { logger } from "matrix-js-sdk/src/logger"; +import { MatrixClient } from "matrix-js-sdk/src/matrix"; import SdkConfig from "../../SdkConfig"; import { getTileServerWellKnown } from "../WellKnownUtils"; @@ -25,8 +26,8 @@ import { LocationShareError } from "./LocationShareErrors"; * .well-known location, or, failing that, in our local config, or, failing * that, defaults to the same tile server listed by matrix.org. */ -export function findMapStyleUrl(): string { - const mapStyleUrl = getTileServerWellKnown()?.map_style_url ?? SdkConfig.get().map_style_url; +export function findMapStyleUrl(matrixClient: MatrixClient): string { + const mapStyleUrl = getTileServerWellKnown(matrixClient)?.map_style_url ?? SdkConfig.get().map_style_url; if (!mapStyleUrl) { logger.error("'map_style_url' missing from homeserver .well-known area, and missing from from config.json."); diff --git a/src/utils/location/map.ts b/src/utils/location/map.ts index 061f5068c0..b39331b949 100644 --- a/src/utils/location/map.ts +++ b/src/utils/location/map.ts @@ -15,7 +15,7 @@ limitations under the License. */ import * as maplibregl from "maplibre-gl"; -import { MatrixEvent } from "matrix-js-sdk/src/matrix"; +import { MatrixClient, MatrixEvent } from "matrix-js-sdk/src/matrix"; import { M_LOCATION } from "matrix-js-sdk/src/@types/location"; import { logger } from "matrix-js-sdk/src/logger"; @@ -24,9 +24,14 @@ import { parseGeoUri } from "./parseGeoUri"; import { findMapStyleUrl } from "./findMapStyleUrl"; import { LocationShareError } from "./LocationShareErrors"; -export const createMap = (interactive: boolean, bodyId: string, onError?: (error: Error) => void): maplibregl.Map => { +export const createMap = ( + client: MatrixClient, + interactive: boolean, + bodyId: string, + onError?: (error: Error) => void, +): maplibregl.Map => { try { - const styleUrl = findMapStyleUrl(); + const styleUrl = findMapStyleUrl(client); const map = new maplibregl.Map({ container: bodyId, diff --git a/src/utils/location/useMap.ts b/src/utils/location/useMap.ts index edc48f9e17..ba15fff308 100644 --- a/src/utils/location/useMap.ts +++ b/src/utils/location/useMap.ts @@ -18,6 +18,7 @@ import { useEffect, useState } from "react"; import { Map as MapLibreMap } from "maplibre-gl"; import { createMap } from "./map"; +import { useMatrixClientContext } from "../../contexts/MatrixClientContext"; interface UseMapProps { bodyId: string; @@ -32,12 +33,13 @@ interface UseMapProps { * As map is recreated on changes to it */ export const useMap = ({ interactive, bodyId, onError }: UseMapProps): MapLibreMap | undefined => { + const cli = useMatrixClientContext(); const [map, setMap] = useState(); useEffect( () => { try { - setMap(createMap(!!interactive, bodyId, onError)); + setMap(createMap(cli, !!interactive, bodyId, onError)); } catch (error) { onError?.(error); } diff --git a/src/utils/pages.ts b/src/utils/pages.ts index c5ddc288da..63458c0daa 100644 --- a/src/utils/pages.ts +++ b/src/utils/pages.ts @@ -15,12 +15,13 @@ limitations under the License. */ import { logger } from "matrix-js-sdk/src/logger"; +import { MatrixClient } from "matrix-js-sdk/src/matrix"; import { IConfigOptions } from "../IConfigOptions"; import { getEmbeddedPagesWellKnown } from "../utils/WellKnownUtils"; import { SnakedObject } from "./SnakedObject"; -export function getHomePageUrl(appConfig: IConfigOptions): string | undefined { +export function getHomePageUrl(appConfig: IConfigOptions, matrixClient: MatrixClient): string | undefined { const config = new SnakedObject(appConfig); const pagesConfig = config.get("embedded_pages"); @@ -40,7 +41,7 @@ export function getHomePageUrl(appConfig: IConfigOptions): string | undefined { } if (!pageUrl) { - pageUrl = getEmbeddedPagesWellKnown()?.home_url; + pageUrl = getEmbeddedPagesWellKnown(matrixClient)?.home_url; } return pageUrl; diff --git a/src/utils/permalinks/Permalinks.ts b/src/utils/permalinks/Permalinks.ts index c4e15f3918..6a76f66b0e 100644 --- a/src/utils/permalinks/Permalinks.ts +++ b/src/utils/permalinks/Permalinks.ts @@ -20,8 +20,8 @@ import { Room } from "matrix-js-sdk/src/models/room"; import { logger } from "matrix-js-sdk/src/logger"; import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state"; import { EventType } from "matrix-js-sdk/src/@types/event"; +import { MatrixClient } from "matrix-js-sdk/src/matrix"; -import { MatrixClientPeg } from "../../MatrixClientPeg"; import MatrixToPermalinkConstructor, { baseUrl as matrixtoBaseUrl, baseUrlPattern as matrixToBaseUrlPattern, @@ -284,7 +284,7 @@ export function makeUserPermalink(userId: string): string { return getPermalinkConstructor().forUser(userId); } -export function makeRoomPermalink(roomId: string): string { +export function makeRoomPermalink(matrixClient: MatrixClient, roomId: string): string { if (!roomId) { throw new Error("can't permalink a falsy roomId"); } @@ -293,8 +293,7 @@ export function makeRoomPermalink(roomId: string): string { // Aliases are already routable, and don't need extra information. if (roomId[0] !== "!") return getPermalinkConstructor().forRoom(roomId, []); - const client = MatrixClientPeg.get(); - const room = client.getRoom(roomId); + const room = matrixClient.getRoom(roomId); if (!room) { return getPermalinkConstructor().forRoom(roomId, []); } @@ -317,11 +316,11 @@ export function isPermalinkHost(host: string): boolean { * @param {string} entity The entity to transform. * @returns {string|null} The transformed permalink or null if unable. */ -export function tryTransformEntityToPermalink(entity: string): string | null { +export function tryTransformEntityToPermalink(matrixClient: MatrixClient, entity: string): string | null { if (!entity) return null; // Check to see if it is a bare entity for starters - if (entity[0] === "#" || entity[0] === "!") return makeRoomPermalink(entity); + if (entity[0] === "#" || entity[0] === "!") return makeRoomPermalink(matrixClient, entity); if (entity[0] === "@") return makeUserPermalink(entity); if (entity.slice(0, 7) === "matrix:") { diff --git a/src/utils/pillify.tsx b/src/utils/pillify.tsx index 5d52ea53b9..bac0138bc0 100644 --- a/src/utils/pillify.tsx +++ b/src/utils/pillify.tsx @@ -18,8 +18,8 @@ import React from "react"; import ReactDOM from "react-dom"; import { PushProcessor } from "matrix-js-sdk/src/pushprocessor"; import { MatrixEvent } from "matrix-js-sdk/src/models/event"; +import { MatrixClient } from "matrix-js-sdk/src/matrix"; -import { MatrixClientPeg } from "../MatrixClientPeg"; import SettingsStore from "../settings/SettingsStore"; import { Pill, PillType, pillRoomNotifLen, pillRoomNotifPos } from "../components/views/elements/Pill"; import { parsePermalink } from "./permalinks/Permalinks"; @@ -51,6 +51,7 @@ const shouldBePillified = (node: Element, href: string, parts: PermalinkParts | * into pills based on the context of a given room. Returns a list of * the resulting React nodes so they can be unmounted rather than leaking. * + * @param matrixClient the client of the logged-in user * @param {Element[]} nodes - a list of sibling DOM nodes to traverse to try * to turn into pills. * @param {MatrixEvent} mxEvent - the matrix event which the DOM nodes are @@ -59,8 +60,13 @@ const shouldBePillified = (node: Element, href: string, parts: PermalinkParts | * React components which have been mounted as part of this. * The initial caller should pass in an empty array to seed the accumulator. */ -export function pillifyLinks(nodes: ArrayLike, mxEvent: MatrixEvent, pills: Element[]): void { - const room = MatrixClientPeg.get().getRoom(mxEvent.getRoomId()) ?? undefined; +export function pillifyLinks( + matrixClient: MatrixClient, + nodes: ArrayLike, + mxEvent: MatrixEvent, + pills: Element[], +): void { + const room = matrixClient.getRoom(mxEvent.getRoomId()) ?? undefined; const shouldShowPillAvatar = SettingsStore.getValue("Pill.shouldShowPillAvatar"); let node = nodes[0]; while (node) { @@ -118,7 +124,7 @@ export function pillifyLinks(nodes: ArrayLike, mxEvent: MatrixEvent, pi } if (roomNotifTextNodes.length > 0) { - const pushProcessor = new PushProcessor(MatrixClientPeg.get()); + const pushProcessor = new PushProcessor(matrixClient); const atRoomRule = pushProcessor.getPushRuleById(".m.rule.roomnotif"); if (atRoomRule && pushProcessor.ruleMatchesEvent(atRoomRule, mxEvent)) { // Now replace all those nodes with Pills @@ -151,7 +157,7 @@ export function pillifyLinks(nodes: ArrayLike, mxEvent: MatrixEvent, pi } if (node.childNodes && node.childNodes.length && !pillified) { - pillifyLinks(node.childNodes as NodeListOf, mxEvent, pills); + pillifyLinks(matrixClient, node.childNodes as NodeListOf, mxEvent, pills); } node = node.nextSibling as Element; diff --git a/src/utils/presence.ts b/src/utils/presence.ts index 88251606ed..0164b17bf5 100644 --- a/src/utils/presence.ts +++ b/src/utils/presence.ts @@ -14,11 +14,12 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { MatrixClientPeg } from "../MatrixClientPeg"; +import { MatrixClient } from "matrix-js-sdk/src/matrix"; + import SdkConfig from "../SdkConfig"; -export function isPresenceEnabled(): boolean { - const hsUrl = MatrixClientPeg.get().baseUrl; +export function isPresenceEnabled(matrixClient: MatrixClient): boolean { + const hsUrl = matrixClient.baseUrl; const urls = SdkConfig.get("enable_presence_by_hs_url"); if (!urls) return true; if (urls[hsUrl] || urls[hsUrl] === undefined) return true; diff --git a/src/utils/room/shouldEncryptRoomWithSingle3rdPartyInvite.ts b/src/utils/room/shouldEncryptRoomWithSingle3rdPartyInvite.ts index a3a1abe212..c142c3341a 100644 --- a/src/utils/room/shouldEncryptRoomWithSingle3rdPartyInvite.ts +++ b/src/utils/room/shouldEncryptRoomWithSingle3rdPartyInvite.ts @@ -27,7 +27,7 @@ export const shouldEncryptRoomWithSingle3rdPartyInvite = ( room: Room, ): { shouldEncrypt: true; inviteEvent: MatrixEvent } | { shouldEncrypt: false; inviteEvent?: undefined } => { // encryption not promoted via .well-known - if (!privateShouldBeEncrypted()) return { shouldEncrypt: false }; + if (!privateShouldBeEncrypted(room.client)) return { shouldEncrypt: false }; // not a DM room if (!DMRoomMap.shared().getRoomIds().has(room.roomId)) return { shouldEncrypt: false }; diff --git a/src/utils/rooms.ts b/src/utils/rooms.ts index bd6fcf9d97..13823288dd 100644 --- a/src/utils/rooms.ts +++ b/src/utils/rooms.ts @@ -14,10 +14,12 @@ See the License for the specific language governing permissions and limitations under the License. */ +import { MatrixClient } from "matrix-js-sdk/src/matrix"; + import { getE2EEWellKnown } from "./WellKnownUtils"; -export function privateShouldBeEncrypted(): boolean { - const e2eeWellKnown = getE2EEWellKnown(); +export function privateShouldBeEncrypted(client: MatrixClient): boolean { + const e2eeWellKnown = getE2EEWellKnown(client); if (e2eeWellKnown) { const defaultDisabled = e2eeWellKnown["default"] === false; return !defaultDisabled; diff --git a/src/widgets/ManagedHybrid.ts b/src/widgets/ManagedHybrid.ts index 9a2a6b961d..c820fee668 100644 --- a/src/widgets/ManagedHybrid.ts +++ b/src/widgets/ManagedHybrid.ts @@ -38,7 +38,7 @@ function getWidgetBuildUrl(): string | undefined { return SdkConfig.get().widget_build_url; } /* eslint-disable-next-line camelcase */ - return getCallBehaviourWellKnown()?.widget_build_url; + return getCallBehaviourWellKnown(MatrixClientPeg.get())?.widget_build_url; } export function isManagedHybridWidgetEnabled(): boolean { @@ -53,7 +53,7 @@ export async function addManagedHybridWidget(roomId: string): Promise { } // Check for permission - if (!WidgetUtils.canUserModifyWidgets(roomId)) { + if (!WidgetUtils.canUserModifyWidgets(cli, roomId)) { logger.error(`User not allowed to modify widgets in ${roomId}`); return; } @@ -87,7 +87,7 @@ export async function addManagedHybridWidget(roomId: string): Promise { // Add the widget try { - await WidgetUtils.setRoomWidgetContent(roomId, widgetId, widgetContent); + await WidgetUtils.setRoomWidgetContent(cli, roomId, widgetId, widgetContent); } catch (e) { logger.error(`Unable to add managed hybrid widget in room ${roomId}`, e); return; diff --git a/test/components/structures/MessagePanel-test.tsx b/test/components/structures/MessagePanel-test.tsx index feef37bb78..ec7382f5e7 100644 --- a/test/components/structures/MessagePanel-test.tsx +++ b/test/components/structures/MessagePanel-test.tsx @@ -112,7 +112,7 @@ describe("MessagePanel", function () { return arg === "showDisplaynameChanges"; }); - DMRoomMap.makeShared(); + DMRoomMap.makeShared(client); }); afterEach(function () { diff --git a/test/components/structures/PipContainer-test.tsx b/test/components/structures/PipContainer-test.tsx index 5ca118c451..90b3477027 100644 --- a/test/components/structures/PipContainer-test.tsx +++ b/test/components/structures/PipContainer-test.tsx @@ -91,7 +91,7 @@ describe("PipContainer", () => { stubClient(); client = mocked(MatrixClientPeg.get()); - DMRoomMap.makeShared(); + DMRoomMap.makeShared(client); room = new Room("!1:example.org", client, "@alice:example.org", { pendingEventOrdering: PendingEventOrdering.Detached, diff --git a/test/components/structures/RightPanel-test.tsx b/test/components/structures/RightPanel-test.tsx index 03b0a1cc08..6be6693ed4 100644 --- a/test/components/structures/RightPanel-test.tsx +++ b/test/components/structures/RightPanel-test.tsx @@ -48,7 +48,7 @@ describe("RightPanel", () => { beforeEach(() => { stubClient(); cli = mocked(MatrixClientPeg.get()); - DMRoomMap.makeShared(); + DMRoomMap.makeShared(cli); context = new SdkContextClass(); context.client = cli; RightPanel = wrapInSdkContext(RightPanelBase, context); diff --git a/test/components/structures/RoomView-test.tsx b/test/components/structures/RoomView-test.tsx index bad6f27c66..2d3857a8cb 100644 --- a/test/components/structures/RoomView-test.tsx +++ b/test/components/structures/RoomView-test.tsx @@ -83,7 +83,7 @@ describe("RoomView", () => { room.on(RoomEvent.Timeline, (...args) => cli.emit(RoomEvent.Timeline, ...args)); room.on(RoomEvent.TimelineReset, (...args) => cli.emit(RoomEvent.TimelineReset, ...args)); - DMRoomMap.makeShared(); + DMRoomMap.makeShared(cli); stores = new SdkContextClass(); stores.client = cli; stores.rightPanelStore.useUnitTestClient(cli); @@ -457,7 +457,7 @@ describe("RoomView", () => { }); it("the last Jitsi widget should be removed", () => { - expect(WidgetUtils.setRoomWidget).toHaveBeenCalledWith(room.roomId, widget2Id); + expect(WidgetUtils.setRoomWidget).toHaveBeenCalledWith(cli, room.roomId, widget2Id); }); }); diff --git a/test/components/structures/ThreadView-test.tsx b/test/components/structures/ThreadView-test.tsx index 94cfc66096..7ca5ca9d75 100644 --- a/test/components/structures/ThreadView-test.tsx +++ b/test/components/structures/ThreadView-test.tsx @@ -131,7 +131,7 @@ describe("ThreadView", () => { rootEvent = res.rootEvent; - DMRoomMap.makeShared(); + DMRoomMap.makeShared(mockClient); jest.spyOn(DMRoomMap.shared(), "getUserIdForRoomId").mockReturnValue(SENDER); }); diff --git a/test/components/views/dialogs/ForwardDialog-test.tsx b/test/components/views/dialogs/ForwardDialog-test.tsx index 036e98b038..7476918310 100644 --- a/test/components/views/dialogs/ForwardDialog-test.tsx +++ b/test/components/views/dialogs/ForwardDialog-test.tsx @@ -90,7 +90,7 @@ describe("ForwardDialog", () => { }; beforeEach(() => { - DMRoomMap.makeShared(); + DMRoomMap.makeShared(mockClient); jest.clearAllMocks(); mockClient.getUserId.mockReturnValue("@bob:example.org"); mockClient.getSafeUserId.mockReturnValue("@bob:example.org"); diff --git a/test/components/views/dialogs/InviteDialog-test.tsx b/test/components/views/dialogs/InviteDialog-test.tsx index 9b13d9fc77..61718fcd3c 100644 --- a/test/components/views/dialogs/InviteDialog-test.tsx +++ b/test/components/views/dialogs/InviteDialog-test.tsx @@ -143,7 +143,7 @@ describe("InviteDialog", () => { getClientWellKnown: jest.fn().mockResolvedValue({}), }); SdkConfig.put({ validated_server_config: {} as ValidatedServerConfig } as IConfigOptions); - DMRoomMap.makeShared(); + DMRoomMap.makeShared(mockClient); jest.clearAllMocks(); room = new Room(roomId, mockClient, mockClient.getSafeUserId()); diff --git a/test/components/views/elements/AppTile-test.tsx b/test/components/views/elements/AppTile-test.tsx index 2cd413f2eb..4c052a9e92 100644 --- a/test/components/views/elements/AppTile-test.tsx +++ b/test/components/views/elements/AppTile-test.tsx @@ -86,7 +86,7 @@ describe("AppTile", () => { cli.hasLazyLoadMembersEnabled = () => false; // Init misc. startup deps - DMRoomMap.makeShared(); + DMRoomMap.makeShared(cli); r1 = new Room("r1", cli, "@name:example.com"); r2 = new Room("r2", cli, "@name:example.com"); diff --git a/test/components/views/elements/Pill-test.tsx b/test/components/views/elements/Pill-test.tsx index cddd0ed4e0..fcd417d61e 100644 --- a/test/components/views/elements/Pill-test.tsx +++ b/test/components/views/elements/Pill-test.tsx @@ -75,7 +75,7 @@ describe("", () => { beforeEach(() => { client = mocked(stubClient()); SdkContextClass.instance.client = client; - DMRoomMap.makeShared(); + DMRoomMap.makeShared(client); room1 = new Room(room1Id, client, user1Id); room1.name = "Room 1"; const user1JoinRoom1Event = mkRoomMemberJoinEvent(user1Id, room1Id, { diff --git a/test/components/views/messages/TextualBody-test.tsx b/test/components/views/messages/TextualBody-test.tsx index 027b4e1875..4641881626 100644 --- a/test/components/views/messages/TextualBody-test.tsx +++ b/test/components/views/messages/TextualBody-test.tsx @@ -120,7 +120,7 @@ describe("", () => { ); it("renders m.emote correctly", () => { - DMRoomMap.makeShared(); + DMRoomMap.makeShared(defaultMatrixClient); const ev = mkEvent({ type: "m.room.message", @@ -140,7 +140,7 @@ describe("", () => { }); it("renders m.notice correctly", () => { - DMRoomMap.makeShared(); + DMRoomMap.makeShared(defaultMatrixClient); const ev = mkEvent({ type: "m.room.message", @@ -161,7 +161,7 @@ describe("", () => { describe("renders plain-text m.text correctly", () => { beforeEach(() => { - DMRoomMap.makeShared(); + DMRoomMap.makeShared(defaultMatrixClient); }); it("simple message renders as expected", () => { @@ -264,7 +264,7 @@ describe("", () => { isGuest: () => false, mxcUrlToHttp: (s: string) => s, }); - DMRoomMap.makeShared(); + DMRoomMap.makeShared(defaultMatrixClient); }); it("italics, bold, underline and strikethrough render as expected", () => { @@ -408,7 +408,7 @@ describe("", () => { isGuest: () => false, mxcUrlToHttp: (s: string) => s, }); - DMRoomMap.makeShared(); + DMRoomMap.makeShared(defaultMatrixClient); const ev = mkRoomTextMessage("Visit https://matrix.org/"); const { container, rerender } = getComponent( diff --git a/test/components/views/right_panel/RoomSummaryCard-test.tsx b/test/components/views/right_panel/RoomSummaryCard-test.tsx index bb1318cd4d..7661cbc277 100644 --- a/test/components/views/right_panel/RoomSummaryCard-test.tsx +++ b/test/components/views/right_panel/RoomSummaryCard-test.tsx @@ -71,7 +71,7 @@ describe("", () => { beforeEach(() => { jest.clearAllMocks(); - DMRoomMap.makeShared(); + DMRoomMap.makeShared(mockClient); mockClient.getRoom.mockReturnValue(room); jest.spyOn(room, "isElementVideoRoom").mockRestore(); diff --git a/test/components/views/rooms/EditMessageComposer-test.tsx b/test/components/views/rooms/EditMessageComposer-test.tsx index 478830e3ba..da96e31b01 100644 --- a/test/components/views/rooms/EditMessageComposer-test.tsx +++ b/test/components/views/rooms/EditMessageComposer-test.tsx @@ -97,7 +97,7 @@ describe("", () => { userEvent.setup(); - DMRoomMap.makeShared(); + DMRoomMap.makeShared(mockClient); jest.spyOn(Autocompleter.prototype, "getCompletions").mockResolvedValue([ { diff --git a/test/components/views/rooms/NewRoomIntro-test.tsx b/test/components/views/rooms/NewRoomIntro-test.tsx index 5694aeb501..9142f1ce5e 100644 --- a/test/components/views/rooms/NewRoomIntro-test.tsx +++ b/test/components/views/rooms/NewRoomIntro-test.tsx @@ -47,7 +47,7 @@ describe("NewRoomIntro", () => { beforeAll(() => { client = stubClient(); - DMRoomMap.makeShared(); + DMRoomMap.makeShared(client); }); describe("for a DM Room", () => { diff --git a/test/components/views/rooms/RoomHeader-test.tsx b/test/components/views/rooms/RoomHeader-test.tsx index c74d856a85..d5d3c68b3f 100644 --- a/test/components/views/rooms/RoomHeader-test.tsx +++ b/test/components/views/rooms/RoomHeader-test.tsx @@ -112,7 +112,7 @@ describe("RoomHeader", () => { [MediaDeviceKindEnum.AudioOutput]: [], }); - DMRoomMap.makeShared(); + DMRoomMap.makeShared(client); jest.spyOn(DMRoomMap.shared(), "getUserIdForRoomId").mockReturnValue(carol.userId); }); @@ -761,7 +761,7 @@ function createRoom(info: IRoomCreationInfo) { }; } - DMRoomMap.makeShared().start(); + DMRoomMap.makeShared(client).start(); const room = new Room(roomId, client, userId, { pendingEventOrdering: PendingEventOrdering.Detached, diff --git a/test/components/views/rooms/RoomPreviewBar-test.tsx b/test/components/views/rooms/RoomPreviewBar-test.tsx index 9bdde45192..9e58888f92 100644 --- a/test/components/views/rooms/RoomPreviewBar-test.tsx +++ b/test/components/views/rooms/RoomPreviewBar-test.tsx @@ -33,8 +33,9 @@ jest.mock("../../../../src/IdentityAuthClient", () => { jest.useRealTimers(); const createRoom = (roomId: string, userId: string): Room => { - const newRoom = new Room(roomId, MatrixClientPeg.get(), userId, {}); - DMRoomMap.makeShared().start(); + const cli = MatrixClientPeg.get(); + const newRoom = new Room(roomId, cli, userId, {}); + DMRoomMap.makeShared(cli).start(); return newRoom; }; diff --git a/test/components/views/rooms/RoomPreviewCard-test.tsx b/test/components/views/rooms/RoomPreviewCard-test.tsx index 19ad62e0d2..3064337697 100644 --- a/test/components/views/rooms/RoomPreviewCard-test.tsx +++ b/test/components/views/rooms/RoomPreviewCard-test.tsx @@ -42,7 +42,7 @@ describe("RoomPreviewCard", () => { stubClient(); client = mocked(MatrixClientPeg.get()); client.getUserId.mockReturnValue("@alice:example.org"); - DMRoomMap.makeShared(); + DMRoomMap.makeShared(client); room = new Room("!1:example.org", client, "@alice:example.org", { pendingEventOrdering: PendingEventOrdering.Detached, diff --git a/test/components/views/rooms/RoomTile-test.tsx b/test/components/views/rooms/RoomTile-test.tsx index b4bfde243c..b581171c97 100644 --- a/test/components/views/rooms/RoomTile-test.tsx +++ b/test/components/views/rooms/RoomTile-test.tsx @@ -90,7 +90,7 @@ describe("RoomTile", () => { client = mocked(stubClient()); sdkContext.client = client; - DMRoomMap.makeShared(); + DMRoomMap.makeShared(client); room = new Room("!1:example.org", client, "@alice:example.org", { pendingEventOrdering: PendingEventOrdering.Detached, diff --git a/test/components/views/spaces/SpacePanel-test.tsx b/test/components/views/spaces/SpacePanel-test.tsx index ad306298dc..fc798abbb2 100644 --- a/test/components/views/spaces/SpacePanel-test.tsx +++ b/test/components/views/spaces/SpacePanel-test.tsx @@ -159,7 +159,7 @@ describe("", () => { mkStubRoom("!room2:server", "Room 2", mockClient), mkStubRoom("!room3:server", "Room 3", mockClient), ]; - DMRoomMap.makeShared(); + DMRoomMap.makeShared(mockClient); jest.useFakeTimers(); const { getByLabelText } = render(); diff --git a/test/components/views/spaces/SpaceTreeLevel-test.tsx b/test/components/views/spaces/SpaceTreeLevel-test.tsx index 633cc13c3f..db10ef3fba 100644 --- a/test/components/views/spaces/SpaceTreeLevel-test.tsx +++ b/test/components/views/spaces/SpaceTreeLevel-test.tsx @@ -40,7 +40,7 @@ jest.mock("../../../../src/stores/spaces/SpaceStore", () => { describe("SpaceButton", () => { stubClient(); const space = mkRoom(MatrixClientPeg.get(), "!1:example.org"); - DMRoomMap.makeShared(); + DMRoomMap.makeShared(MatrixClientPeg.get()); const dispatchSpy = jest.spyOn(defaultDispatcher, "dispatch"); diff --git a/test/stores/right-panel/RightPanelStore-test.ts b/test/stores/right-panel/RightPanelStore-test.ts index e05e6e39a0..5b937e52ad 100644 --- a/test/stores/right-panel/RightPanelStore-test.ts +++ b/test/stores/right-panel/RightPanelStore-test.ts @@ -37,7 +37,7 @@ describe("RightPanelStore", () => { beforeEach(() => { stubClient(); cli = mocked(MatrixClientPeg.get()); - DMRoomMap.makeShared(); + DMRoomMap.makeShared(cli); // Make sure we start with a clean store store.reset(); diff --git a/test/stores/room-list/RoomListStore-test.ts b/test/stores/room-list/RoomListStore-test.ts index 5493ef8927..4c00ac11b6 100644 --- a/test/stores/room-list/RoomListStore-test.ts +++ b/test/stores/room-list/RoomListStore-test.ts @@ -162,7 +162,7 @@ describe("RoomListStore", () => { room1.updateMyMembership("join"); room2.updateMyMembership("join"); room3.updateMyMembership("join"); - DMRoomMap.makeShared(); + DMRoomMap.makeShared(client); const { store } = createStore(); client.getVisibleRooms = jest.fn().mockReturnValue([room1, room2, room3]); @@ -274,7 +274,7 @@ describe("RoomListStore", () => { it("Passes the feature flag on to the client when asking for visible rooms", () => { // Given a store that we can ask for a room list - DMRoomMap.makeShared(); + DMRoomMap.makeShared(client); const { store } = createStore(); client.getVisibleRooms = jest.fn().mockReturnValue([]); diff --git a/test/stores/room-list/algorithms/Algorithm-test.ts b/test/stores/room-list/algorithms/Algorithm-test.ts index efd33cad0f..078b92690c 100644 --- a/test/stores/room-list/algorithms/Algorithm-test.ts +++ b/test/stores/room-list/algorithms/Algorithm-test.ts @@ -41,7 +41,7 @@ describe("Algorithm", () => { beforeEach(() => { stubClient(); client = mocked(MatrixClientPeg.get()); - DMRoomMap.makeShared(); + DMRoomMap.makeShared(client); algorithm = new Algorithm(); algorithm.start(); diff --git a/test/utils/EventRenderingUtils-test.ts b/test/utils/EventRenderingUtils-test.ts index 4416a58386..532325ab01 100644 --- a/test/utils/EventRenderingUtils-test.ts +++ b/test/utils/EventRenderingUtils-test.ts @@ -17,6 +17,7 @@ limitations under the License. import { getEventDisplayInfo } from "../../src/utils/EventRenderingUtils"; import { VoiceBroadcastInfoState } from "../../src/voice-broadcast"; import { mkVoiceBroadcastInfoStateEvent } from "../voice-broadcast/utils/test-utils"; +import { createTestClient } from "../test-utils"; describe("getEventDisplayInfo", () => { const mkBroadcastInfoEvent = (state: VoiceBroadcastInfoState) => { @@ -24,7 +25,7 @@ describe("getEventDisplayInfo", () => { }; it("should return the expected value for a broadcast started event", () => { - expect(getEventDisplayInfo(mkBroadcastInfoEvent(VoiceBroadcastInfoState.Started), false)) + expect(getEventDisplayInfo(createTestClient(), mkBroadcastInfoEvent(VoiceBroadcastInfoState.Started), false)) .toMatchInlineSnapshot(` { "hasRenderer": true, @@ -38,7 +39,7 @@ describe("getEventDisplayInfo", () => { }); it("should return the expected value for a broadcast stopped event", () => { - expect(getEventDisplayInfo(mkBroadcastInfoEvent(VoiceBroadcastInfoState.Stopped), false)) + expect(getEventDisplayInfo(createTestClient(), mkBroadcastInfoEvent(VoiceBroadcastInfoState.Stopped), false)) .toMatchInlineSnapshot(` { "hasRenderer": true, diff --git a/test/utils/EventUtils-test.ts b/test/utils/EventUtils-test.ts index 5b03d82378..e6fdf7eb4b 100644 --- a/test/utils/EventUtils-test.ts +++ b/test/utils/EventUtils-test.ts @@ -253,20 +253,20 @@ describe("EventUtils", () => { describe("canEditContent()", () => { it.each(uneditableCases)("returns false for %s", (_description, event) => { - expect(canEditContent(event)).toBe(false); + expect(canEditContent(mockClient, event)).toBe(false); }); it.each(editableCases)("returns true for %s", (_description, event) => { - expect(canEditContent(event)).toBe(true); + expect(canEditContent(mockClient, event)).toBe(true); }); }); describe("canEditOwnContent()", () => { it.each(uneditableCases)("returns false for %s", (_description, event) => { - expect(canEditOwnEvent(event)).toBe(false); + expect(canEditOwnEvent(mockClient, event)).toBe(false); }); it.each(editableCases)("returns true for %s", (_description, event) => { - expect(canEditOwnEvent(event)).toBe(true); + expect(canEditOwnEvent(mockClient, event)).toBe(true); }); }); }); @@ -460,6 +460,7 @@ describe("EventUtils", () => { findEditableEvent({ events: [], isForward: true, + matrixClient: mockClient, }), ).toBeUndefined(); }); diff --git a/test/utils/MultiInviter-test.ts b/test/utils/MultiInviter-test.ts index d9f4a9bf44..8bdc772ab1 100644 --- a/test/utils/MultiInviter-test.ts +++ b/test/utils/MultiInviter-test.ts @@ -90,7 +90,7 @@ describe("MultiInviter", () => { return MXID_PROFILE_STATES[userId] || Promise.reject(); }); - inviter = new MultiInviter(ROOMID); + inviter = new MultiInviter(client, ROOMID); }); describe("invite", () => { diff --git a/test/utils/exportUtils/HTMLExport-test.ts b/test/utils/exportUtils/HTMLExport-test.ts index 90715929a4..f81764170c 100644 --- a/test/utils/exportUtils/HTMLExport-test.ts +++ b/test/utils/exportUtils/HTMLExport-test.ts @@ -94,7 +94,7 @@ describe("HTMLExport", () => { jest.setSystemTime(REPEATABLE_DATE); client = stubClient() as jest.Mocked; - DMRoomMap.makeShared(); + DMRoomMap.makeShared(client); room = new Room("!myroom:example.org", client, "@me:example.org"); client.getRoom.mockReturnValue(room); diff --git a/test/utils/leave-behaviour-test.ts b/test/utils/leave-behaviour-test.ts index 97d7349534..7bf6c2e47d 100644 --- a/test/utils/leave-behaviour-test.ts +++ b/test/utils/leave-behaviour-test.ts @@ -41,7 +41,7 @@ describe("leaveRoomBehaviour", () => { beforeEach(async () => { stubClient(); client = mocked(MatrixClientPeg.get()); - DMRoomMap.makeShared(); + DMRoomMap.makeShared(client); room = mkRoom(client, "!1:example.org"); space = mkRoom(client, "!2:example.org"); @@ -87,7 +87,7 @@ describe("leaveRoomBehaviour", () => { it("returns to the home page after leaving a room outside of a space that was being viewed", async () => { viewRoom(room); - await leaveRoomBehaviour(room.roomId); + await leaveRoomBehaviour(client, room.roomId); await expectDispatch({ action: Action.ViewHomePage }); }); @@ -98,7 +98,7 @@ describe("leaveRoomBehaviour", () => { viewRoom(room); SpaceStore.instance.setActiveSpace(space.roomId, false); - await leaveRoomBehaviour(room.roomId); + await leaveRoomBehaviour(client, room.roomId); await expectDispatch({ action: Action.ViewRoom, room_id: space.roomId, @@ -110,7 +110,7 @@ describe("leaveRoomBehaviour", () => { viewRoom(space); SpaceStore.instance.setActiveSpace(space.roomId, false); - await leaveRoomBehaviour(space.roomId); + await leaveRoomBehaviour(client, space.roomId); await expectDispatch({ action: Action.ViewHomePage }); }); @@ -122,7 +122,7 @@ describe("leaveRoomBehaviour", () => { viewRoom(room); SpaceStore.instance.setActiveSpace(room.roomId, false); - await leaveRoomBehaviour(room.roomId); + await leaveRoomBehaviour(client, room.roomId); await expectDispatch({ action: Action.ViewRoom, room_id: space.roomId, @@ -136,7 +136,7 @@ describe("leaveRoomBehaviour", () => { }); it("Passes through the dynamic predecessor setting", async () => { - await leaveRoomBehaviour(room.roomId); + await leaveRoomBehaviour(client, room.roomId); expect(client.getRoomUpgradeHistory).toHaveBeenCalledWith(room.roomId, false, false); }); }); @@ -150,7 +150,7 @@ describe("leaveRoomBehaviour", () => { }); it("Passes through the dynamic predecessor setting", async () => { - await leaveRoomBehaviour(room.roomId); + await leaveRoomBehaviour(client, room.roomId); expect(client.getRoomUpgradeHistory).toHaveBeenCalledWith(room.roomId, false, true); }); }); diff --git a/test/utils/permalinks/Permalinks-test.ts b/test/utils/permalinks/Permalinks-test.ts index 36b38a5c0d..6f885a8121 100644 --- a/test/utils/permalinks/Permalinks-test.ts +++ b/test/utils/permalinks/Permalinks-test.ts @@ -342,13 +342,13 @@ describe("Permalinks", function () { makeMemberWithPL(roomId, "@bob:second", 0), ]); }); - const result = makeRoomPermalink("!somewhere:example.org"); + const result = makeRoomPermalink(mockClient, "!somewhere:example.org"); expect(result).toBe("https://matrix.to/#/!somewhere:example.org?via=first&via=second"); }); it("should generate a room permalink for room aliases with no candidate servers", function () { mockClient.getRoom.mockReturnValue(null); - const result = makeRoomPermalink("#somewhere:example.org"); + const result = makeRoomPermalink(mockClient, "#somewhere:example.org"); expect(result).toBe("https://matrix.to/#/#somewhere:example.org"); }); @@ -359,7 +359,7 @@ describe("Permalinks", function () { makeMemberWithPL(roomId, "@bob:second", 0), ]); }); - const result = makeRoomPermalink("#somewhere:example.org"); + const result = makeRoomPermalink(mockClient, "#somewhere:example.org"); expect(result).toBe("https://matrix.to/#/#somewhere:example.org"); }); diff --git a/test/utils/pillify-test.tsx b/test/utils/pillify-test.tsx index 5ee8b280de..f33e9f966f 100644 --- a/test/utils/pillify-test.tsx +++ b/test/utils/pillify-test.tsx @@ -62,14 +62,14 @@ describe("pillify", () => { ], }; - DMRoomMap.makeShared(); + DMRoomMap.makeShared(cli); }); it("should do nothing for empty element", () => { const { container } = render(
); const originalHtml = container.outerHTML; const containers: Element[] = []; - pillifyLinks([container], event, containers); + pillifyLinks(MatrixClientPeg.get(), [container], event, containers); expect(containers).toHaveLength(0); expect(container.outerHTML).toEqual(originalHtml); }); @@ -77,7 +77,7 @@ describe("pillify", () => { it("should pillify @room", () => { const { container } = render(
@room
); const containers: Element[] = []; - pillifyLinks([container], event, containers); + pillifyLinks(MatrixClientPeg.get(), [container], event, containers); expect(containers).toHaveLength(1); expect(container.querySelector(".mx_Pill.mx_AtRoomPill")?.textContent).toBe("!@room"); }); @@ -85,10 +85,10 @@ describe("pillify", () => { it("should not double up pillification on repeated calls", () => { const { container } = render(
@room
); const containers: Element[] = []; - pillifyLinks([container], event, containers); - pillifyLinks([container], event, containers); - pillifyLinks([container], event, containers); - pillifyLinks([container], event, containers); + pillifyLinks(MatrixClientPeg.get(), [container], event, containers); + pillifyLinks(MatrixClientPeg.get(), [container], event, containers); + pillifyLinks(MatrixClientPeg.get(), [container], event, containers); + pillifyLinks(MatrixClientPeg.get(), [container], event, containers); expect(containers).toHaveLength(1); expect(container.querySelector(".mx_Pill.mx_AtRoomPill")?.textContent).toBe("!@room"); }); diff --git a/test/utils/room/shouldEncryptRoomWithSingle3rdPartyInvite-test.ts b/test/utils/room/shouldEncryptRoomWithSingle3rdPartyInvite-test.ts index 1b74621254..d52f3ca1e8 100644 --- a/test/utils/room/shouldEncryptRoomWithSingle3rdPartyInvite-test.ts +++ b/test/utils/room/shouldEncryptRoomWithSingle3rdPartyInvite-test.ts @@ -33,7 +33,7 @@ describe("shouldEncryptRoomWithSingle3rdPartyInvite", () => { beforeAll(() => { client = stubClient(); - DMRoomMap.makeShared(); + DMRoomMap.makeShared(client); }); beforeEach(() => {