diff --git a/package.json b/package.json index 4b42a90..02a0590 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,8 @@ "classnames": "^2.3.1", "color-hash": "^2.0.1", "events": "^3.3.0", - "matrix-js-sdk": "github:matrix-org/matrix-js-sdk#8ba2d257ae24bbed61cd7fe99af081324337161c", + "matrix-js-sdk": "github:matrix-org/matrix-js-sdk#3334c01191bcd82b5243916284c9a08d08fd9795", + "matrix-widget-api": "^1.0.0", "mermaid": "^8.13.8", "normalize.css": "^8.0.1", "pako": "^2.0.4", diff --git a/src/ClientContext.tsx b/src/ClientContext.tsx index a1e5813..08eb91e 100644 --- a/src/ClientContext.tsx +++ b/src/ClientContext.tsx @@ -26,9 +26,14 @@ import React, { import { useHistory } from "react-router-dom"; import { MatrixClient, ClientEvent } from "matrix-js-sdk/src/client"; import { MatrixEvent } from "matrix-js-sdk/src/models/event"; +import { logger } from "matrix-js-sdk/src/logger"; import { ErrorView } from "./FullScreenView"; -import { initClient, defaultHomeserver } from "./matrix-utils"; +import { + initClient, + initMatroskaClient, + defaultHomeserver, +} from "./matrix-utils"; declare global { interface Window { @@ -91,40 +96,55 @@ export const ClientProvider: FC = ({ children }) => { }); useEffect(() => { - const restore = async (): Promise< + const init = async (): Promise< Pick > => { - try { - const session = loadSession(); + const query = new URLSearchParams(window.location.search); + const widgetId = query.get("widgetId"); + const parentUrl = query.get("parentUrl"); - if (session) { - /* eslint-disable camelcase */ - const { user_id, device_id, access_token, passwordlessUser } = - session; + if (widgetId && parentUrl) { + // We're inside a widget, so let's engage *Matroska mode* + logger.log("Using a Matroska client"); - const client = await initClient( - { - baseUrl: defaultHomeserver, - accessToken: access_token, - userId: user_id, - deviceId: device_id, - }, - true - ); - /* eslint-enable camelcase */ + return { + client: await initMatroskaClient(widgetId, parentUrl), + isPasswordlessUser: false, + }; + } else { + // We're running as a standalone application + try { + const session = loadSession(); - return { client, isPasswordlessUser: passwordlessUser }; + if (session) { + /* eslint-disable camelcase */ + const { user_id, device_id, access_token, passwordlessUser } = + session; + + logger.log("Using a standalone client"); + const client = await initClient( + { + baseUrl: defaultHomeserver, + accessToken: access_token, + userId: user_id, + deviceId: device_id, + }, + true + ); + /* eslint-enable camelcase */ + + return { client, isPasswordlessUser: passwordlessUser }; + } + + return { client: undefined, isPasswordlessUser: false }; + } catch (err) { + clearSession(); + throw err; } - - return { client: undefined, isPasswordlessUser: false }; - } catch (err) { - console.error(err); - clearSession(); - throw err; } }; - restore() + init() .then(({ client, isPasswordlessUser }) => { setState({ client, @@ -135,7 +155,8 @@ export const ClientProvider: FC = ({ children }) => { error: undefined, }); }) - .catch(() => { + .catch((err) => { + logger.error(err); setState({ client: undefined, loading: false, diff --git a/src/Modal.tsx b/src/Modal.tsx index f259a18..686234a 100644 --- a/src/Modal.tsx +++ b/src/Modal.tsx @@ -37,7 +37,7 @@ import { AriaDialogProps } from "@react-types/dialog"; import { ReactComponent as CloseIcon } from "./icons/Close.svg"; import styles from "./Modal.module.css"; -interface ModalProps extends OverlayProps, AriaDialogProps { +export interface ModalProps extends OverlayProps, AriaDialogProps { title: string; children: ReactNode; className?: string; diff --git a/src/matrix-utils.ts b/src/matrix-utils.ts index 5986954..ed3cde3 100644 --- a/src/matrix-utils.ts +++ b/src/matrix-utils.ts @@ -5,14 +5,21 @@ import { MemoryStore } from "matrix-js-sdk/src/store/memory"; import { IndexedDBCryptoStore } from "matrix-js-sdk/src/crypto/store/indexeddb-crypto-store"; import { LocalStorageCryptoStore } from "matrix-js-sdk/src/crypto/store/localStorage-crypto-store"; import { MemoryCryptoStore } from "matrix-js-sdk/src/crypto/store/memory-crypto-store"; -import { createClient, MatrixClient } from "matrix-js-sdk/src/matrix"; +import { + createClient, + createRoomWidgetClient, + MatrixClient, +} from "matrix-js-sdk/src/matrix"; import { ICreateClientOpts } from "matrix-js-sdk/src/matrix"; import { ClientEvent } from "matrix-js-sdk/src/client"; +import { EventType } from "matrix-js-sdk/src/@types/event"; import { Visibility, Preset } from "matrix-js-sdk/src/@types/partials"; import { ISyncStateData, SyncState } from "matrix-js-sdk/src/sync"; +import { WidgetApi } from "matrix-widget-api"; import { logger } from "matrix-js-sdk/src/logger"; import IndexedDBWorker from "./IndexedDBWorker?worker"; +import { getRoomParams } from "./room/useRoomParams"; export const defaultHomeserver = (import.meta.env.VITE_DEFAULT_HOMESERVER as string) ?? @@ -53,7 +60,74 @@ function waitForSync(client: MatrixClient) { } /** - * Initialises and returns a new Matrix Client + * Initialises and returns a new widget-API-based Matrix Client. + * @param widgetId The ID of the widget that the app is running inside. + * @param parentUrl The URL of the parent client. + * @returns The MatrixClient instance + */ +export async function initMatroskaClient( + widgetId: string, + parentUrl: string +): Promise { + // In this mode, we use a special client which routes all requests through + // the host application via the widget API + + const { roomId, userId, deviceId } = getRoomParams(); + if (!roomId) throw new Error("Room ID must be supplied"); + if (!userId) throw new Error("User ID must be supplied"); + if (!deviceId) throw new Error("Device ID must be supplied"); + + // These are all the event types the app uses + const sendState = [ + { eventType: EventType.GroupCallPrefix }, + { eventType: EventType.GroupCallMemberPrefix, stateKey: userId }, + ]; + const receiveState = [ + { eventType: EventType.RoomMember }, + { eventType: EventType.GroupCallPrefix }, + { eventType: EventType.GroupCallMemberPrefix }, + ]; + const sendRecvToDevice = [ + EventType.CallInvite, + EventType.CallCandidates, + EventType.CallAnswer, + EventType.CallHangup, + EventType.CallReject, + EventType.CallSelectAnswer, + EventType.CallNegotiate, + EventType.CallSDPStreamMetadataChanged, + EventType.CallSDPStreamMetadataChangedPrefix, + EventType.CallReplaces, + "org.matrix.call_duplicate_session", + ]; + + // Since all data should be coming from the host application, there's no + // need to persist anything, and therefore we can use the default stores + // We don't even need to set up crypto + const client = createRoomWidgetClient( + new WidgetApi(widgetId, new URL(parentUrl).origin), + { + sendState, + receiveState, + sendToDevice: sendRecvToDevice, + receiveToDevice: sendRecvToDevice, + turnServers: true, + }, + roomId, + { + baseUrl: "", + userId, + deviceId, + timelineSupport: true, + } + ); + + await client.startClient(); + return client; +} + +/** + * Initialises and returns a new standalone Matrix Client. * If true is passed for the 'restore' parameter, a check will be made * to ensure that corresponding crypto data is stored and recovered. * If the check fails, CryptoStoreIntegrityError will be thrown. @@ -127,16 +201,13 @@ export async function initClient( storeOpts.cryptoStore = new MemoryCryptoStore(); } - // XXX: we read from the URL search params in RoomPage too: + // XXX: we read from the room params in RoomPage too: // it would be much better to read them in one place and pass // the values around, but we initialise the matrix client in // many different places so we'd have to pass it into all of // them. - const params = new URLSearchParams(window.location.search); - // disable e2e only if enableE2e=false is given - const enableE2e = params.get("enableE2e") !== "false"; - - if (!enableE2e) { + const { e2eEnabled } = getRoomParams(); + if (!e2eEnabled) { logger.info("Disabling E2E: group call signalling will NOT be encrypted."); } @@ -144,10 +215,10 @@ export async function initClient( ...storeOpts, ...clientOptions, useAuthorizationHeader: true, - // Use a relatively low timeout for API calls: this is a realtime application + // Use a relatively low timeout for API calls: this is a realtime app // so we don't want API calls taking ages, we'd rather they just fail. localTimeoutMs: 5000, - useE2eForGroupCall: enableE2e, + useE2eForGroupCall: e2eEnabled, }); try { @@ -254,17 +325,17 @@ export async function createRoom( return [fullAliasFromRoomName(name, client), result.room_id]; } -export function getRoomUrl(roomId: string): string { - if (roomId.startsWith("#")) { - const [localPart, host] = roomId.replace("#", "").split(":"); +export function getRoomUrl(roomIdOrAlias: string): string { + if (roomIdOrAlias.startsWith("#")) { + const [localPart, host] = roomIdOrAlias.replace("#", "").split(":"); if (host !== defaultHomeserverHost) { - return `${window.location.protocol}//${window.location.host}/room/${roomId}`; + return `${window.location.protocol}//${window.location.host}/room/${roomIdOrAlias}`; } else { return `${window.location.protocol}//${window.location.host}/${localPart}`; } } else { - return `${window.location.protocol}//${window.location.host}/room/${roomId}`; + return `${window.location.protocol}//${window.location.host}/room/#?roomId=${roomIdOrAlias}`; } } diff --git a/src/room/GroupCallLoader.tsx b/src/room/GroupCallLoader.tsx index 4cc62f1..dcfbf48 100644 --- a/src/room/GroupCallLoader.tsx +++ b/src/room/GroupCallLoader.tsx @@ -23,7 +23,7 @@ import { usePageTitle } from "../usePageTitle"; interface Props { client: MatrixClient; - roomId: string; + roomIdOrAlias: string; viaServers: string[]; children: (groupCall: GroupCall) => ReactNode; createPtt: boolean; @@ -31,14 +31,14 @@ interface Props { export function GroupCallLoader({ client, - roomId, + roomIdOrAlias, viaServers, children, createPtt, }: Props): JSX.Element { const { loading, error, groupCall } = useLoadGroupCall( client, - roomId, + roomIdOrAlias, viaServers, createPtt ); diff --git a/src/room/GroupCallView.tsx b/src/room/GroupCallView.tsx index 92e8ef1..2d5ee92 100644 --- a/src/room/GroupCallView.tsx +++ b/src/room/GroupCallView.tsx @@ -37,14 +37,14 @@ interface Props { client: MatrixClient; isPasswordlessUser: boolean; isEmbedded: boolean; - roomId: string; + roomIdOrAlias: string; groupCall: GroupCall; } export function GroupCallView({ client, isPasswordlessUser, isEmbedded, - roomId, + roomIdOrAlias, groupCall, }: Props) { const { @@ -101,7 +101,7 @@ export function GroupCallView({ return ( ); @@ -164,7 +164,7 @@ export function GroupCallView({ localVideoMuted={localVideoMuted} toggleLocalVideoMuted={toggleLocalVideoMuted} toggleMicrophoneMuted={toggleMicrophoneMuted} - roomId={roomId} + roomIdOrAlias={roomIdOrAlias} isEmbedded={isEmbedded} /> ); diff --git a/src/room/InCallView.tsx b/src/room/InCallView.tsx index 680f9f2..5ff3924 100644 --- a/src/room/InCallView.tsx +++ b/src/room/InCallView.tsx @@ -71,7 +71,7 @@ interface Props { isScreensharing: boolean; screenshareFeeds: CallFeed[]; localScreenshareFeed: CallFeed; - roomId: string; + roomIdOrAlias: string; unencryptedEventsFromUsers: Set; } @@ -99,7 +99,7 @@ export function InCallView({ isScreensharing, screenshareFeeds, localScreenshareFeed, - roomId, + roomIdOrAlias, unencryptedEventsFromUsers, }: Props) { usePreventScroll(); @@ -260,7 +260,7 @@ export function InCallView({ {!fullscreenParticipant && ( )} diff --git a/src/room/InviteModal.tsx b/src/room/InviteModal.tsx index b9c28c5..7c0e759 100644 --- a/src/room/InviteModal.tsx +++ b/src/room/InviteModal.tsx @@ -14,31 +14,30 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React from "react"; +import React, { FC } from "react"; -import { Modal, ModalContent } from "../Modal"; +import { Modal, ModalContent, ModalProps } from "../Modal"; import { CopyButton } from "../button"; import { getRoomUrl } from "../matrix-utils"; import styles from "./InviteModal.module.css"; -export function InviteModal({ - roomId, - ...rest -}: { - roomId: string; - [x: string]: unknown; -}) { - return ( - - -

Copy and share this meeting link

- -
-
- ); +interface Props extends Omit { + roomIdOrAlias: string; } + +export const InviteModal: FC = ({ roomIdOrAlias, ...rest }) => ( + + +

Copy and share this meeting link

+ +
+
+); diff --git a/src/room/LobbyView.tsx b/src/room/LobbyView.tsx index 9b9be3d..9075aac 100644 --- a/src/room/LobbyView.tsx +++ b/src/room/LobbyView.tsx @@ -45,7 +45,7 @@ interface Props { toggleLocalVideoMuted: () => void; toggleMicrophoneMuted: () => void; localVideoMuted: boolean; - roomId: string; + roomIdOrAlias: string; isEmbedded: boolean; } export function LobbyView({ @@ -61,7 +61,7 @@ export function LobbyView({ localVideoMuted, toggleLocalVideoMuted, toggleMicrophoneMuted, - roomId, + roomIdOrAlias, isEmbedded, }: Props) { const { stream } = useCallFeed(localCallFeed); @@ -115,7 +115,7 @@ export function LobbyView({ Or diff --git a/src/room/OverflowMenu.tsx b/src/room/OverflowMenu.tsx index e58f8f0..f973f8b 100644 --- a/src/room/OverflowMenu.tsx +++ b/src/room/OverflowMenu.tsx @@ -32,7 +32,7 @@ import { InviteModal } from "./InviteModal"; import { TooltipTrigger } from "../Tooltip"; import { FeedbackModal } from "./FeedbackModal"; interface Props { - roomId: string; + roomIdOrAlias: string; inCall: boolean; groupCall: GroupCall; showInvite: boolean; @@ -43,7 +43,7 @@ interface Props { }; } export function OverflowMenu({ - roomId, + roomIdOrAlias, inCall, groupCall, showInvite, @@ -119,7 +119,7 @@ export function OverflowMenu({ {settingsModalState.isOpen && } {inviteModalState.isOpen && ( - + )} {feedbackModalState.isOpen && ( = ({ client, - roomId, + roomIdOrAlias, roomName, avatarUrl, groupCall, @@ -205,7 +205,7 @@ export const PTTCallView: React.FC = ({
= ({
{inviteModalState.isOpen && showControls && ( - + )} ); diff --git a/src/room/RageshakeRequestModal.tsx b/src/room/RageshakeRequestModal.tsx index 3313bd1..59b74b3 100644 --- a/src/room/RageshakeRequestModal.tsx +++ b/src/room/RageshakeRequestModal.tsx @@ -14,24 +14,25 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, { useEffect } from "react"; +import React, { FC, useEffect } from "react"; -import { Modal, ModalContent } from "../Modal"; +import { Modal, ModalContent, ModalProps } from "../Modal"; import { Button } from "../button"; import { FieldRow, ErrorMessage } from "../input/Input"; import { useSubmitRageshake } from "../settings/submit-rageshake"; import { Body } from "../typography/Typography"; -export function RageshakeRequestModal({ - rageshakeRequestId, - roomId, - ...rest -}: { +interface Props extends Omit { rageshakeRequestId: string; - roomId: string; + roomIdOrAlias: string; onClose: () => void; - [x: string]: unknown; -}) { +} + +export const RageshakeRequestModal: FC = ({ + rageshakeRequestId, + roomIdOrAlias, + ...rest +}) => { const { submitRageshake, sending, sent, error } = useSubmitRageshake(); useEffect(() => { @@ -53,7 +54,7 @@ export function RageshakeRequestModal({ submitRageshake({ sendLogs: true, rageshakeRequestId, - roomId, + roomId: roomIdOrAlias, // Possibly not a room ID, but oh well }) } disabled={sending} @@ -69,4 +70,4 @@ export function RageshakeRequestModal({ ); -} +}; diff --git a/src/room/RoomPage.tsx b/src/room/RoomPage.tsx index fa9f9c0..c41ac6a 100644 --- a/src/room/RoomPage.tsx +++ b/src/room/RoomPage.tsx @@ -1,5 +1,5 @@ /* -Copyright 2021 New Vector Ltd +Copyright 2021-2022 New Vector Ltd Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -14,33 +14,26 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, { useEffect, useMemo, useState } from "react"; -import { useLocation, useParams } from "react-router-dom"; +import React, { FC, useEffect, useState } from "react"; import { useClient } from "../ClientContext"; import { ErrorView, LoadingView } from "../FullScreenView"; import { RoomAuthView } from "./RoomAuthView"; import { GroupCallLoader } from "./GroupCallLoader"; import { GroupCallView } from "./GroupCallView"; +import { useRoomParams } from "./useRoomParams"; import { MediaHandlerProvider } from "../settings/useMediaHandler"; import { useRegisterPasswordlessUser } from "../auth/useRegisterPasswordlessUser"; -export function RoomPage() { +export const RoomPage: FC = () => { const { loading, isAuthenticated, error, client, isPasswordlessUser } = useClient(); - const { roomId: maybeRoomId } = useParams(); - const { hash, search }: { hash: string; search: string } = useLocation(); - const [viaServers, isEmbedded, isPtt, displayName] = useMemo(() => { - const params = new URLSearchParams(search); - return [ - params.getAll("via"), - params.has("embed"), - params.get("ptt") === "true", - params.get("displayName"), - ]; - }, [search]); - const roomId = (maybeRoomId || hash || "").toLowerCase(); + const { roomAlias, roomId, viaServers, isEmbedded, isPtt, displayName } = + useRoomParams(); + const roomIdOrAlias = roomId ?? roomAlias; + if (!roomIdOrAlias) throw new Error("No room specified"); + const { registerPasswordlessUser } = useRegisterPasswordlessUser(); const [isRegistering, setIsRegistering] = useState(false); @@ -76,14 +69,14 @@ export function RoomPage() { {(groupCall) => ( ); -} +}; diff --git a/src/room/VideoPreview.tsx b/src/room/VideoPreview.tsx index 58f2c92..21b559d 100644 --- a/src/room/VideoPreview.tsx +++ b/src/room/VideoPreview.tsx @@ -32,7 +32,7 @@ import { useModalTriggerState } from "../Modal"; interface Props { client: MatrixClient; state: GroupCallState; - roomId: string; + roomIdOrAlias: string; microphoneMuted: boolean; localVideoMuted: boolean; toggleLocalVideoMuted: () => void; @@ -43,7 +43,7 @@ interface Props { export function VideoPreview({ client, state, - roomId, + roomIdOrAlias, microphoneMuted, localVideoMuted, toggleLocalVideoMuted, @@ -93,7 +93,7 @@ export function VideoPreview({ onPress={toggleLocalVideoMuted} /> { + const fragmentQueryStart = fragment.indexOf("?"); + const fragmentParams = new URLSearchParams( + fragmentQueryStart === -1 ? "" : fragment.substring(fragmentQueryStart) + ); + const queryParams = new URLSearchParams(query); + + // Normally, room params should be encoded in the fragment so as to avoid + // leaking them to the server. However, we also check the normal query + // string for backwards compatibility with versions that only used that. + const hasParam = (name: string): boolean => + fragmentParams.has(name) || queryParams.has(name); + const getParam = (name: string): string | null => + fragmentParams.get(name) ?? queryParams.get(name); + const getAllParams = (name: string): string[] => [ + ...fragmentParams.getAll(name), + ...queryParams.getAll(name), + ]; + + // The part of the fragment before the ? + const fragmentRoute = + fragmentQueryStart === -1 + ? fragment + : fragment.substring(0, fragmentQueryStart); + + return { + roomAlias: fragmentRoute.length > 1 ? fragmentRoute : null, + roomId: getParam("roomId"), + viaServers: getAllParams("via"), + isEmbedded: hasParam("embed"), + isPtt: hasParam("ptt"), + e2eEnabled: getParam("enableE2e") !== "false", // Defaults to true + userId: getParam("userId"), + displayName: getParam("displayName"), + deviceId: getParam("deviceId"), + }; +}; + +/** + * Hook to simplify use of getRoomParams. + * @returns {RoomParams} The room parameters for the current URL + */ +export const useRoomParams = (): RoomParams => { + const { hash, search } = useLocation(); + return useMemo(() => getRoomParams(search, hash), [search, hash]); +}; diff --git a/vite.config.js b/vite.config.js index 95f6c3d..83440ca 100644 --- a/vite.config.js +++ b/vite.config.js @@ -41,6 +41,12 @@ export default defineConfig(({ mode }) => { }, }, resolve: { + alias: { + // matrix-widget-api has its transpiled lib/index.js as its entry point, + // which Vite for some reason refuses to work with, so we point it to + // src/index.ts instead + "matrix-widget-api": "matrix-widget-api/src/index.ts", + }, dedupe: [ "react", "react-dom", diff --git a/yarn.lock b/yarn.lock index cb70c7d..26dcd48 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2754,6 +2754,11 @@ resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.51.tgz#cfd70924a25a3fd32b218e5e420e6897e1ac4f40" integrity sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ== +"@types/events@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7" + integrity sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g== + "@types/glob@*", "@types/glob@^7.1.1", "@types/glob@^7.1.3": version "7.2.0" resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.2.0.tgz#bc1b5bf3aa92f25bd5dd39f35c57361bdce5b2eb" @@ -3863,12 +3868,10 @@ balanced-match@^1.0.0: resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== -base-x@^3.0.2: - version "3.0.9" - resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.9.tgz#6349aaabb58526332de9f60995e548a53fe21320" - integrity sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ== - dependencies: - safe-buffer "^5.0.1" +base-x@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/base-x/-/base-x-4.0.0.tgz#d0e3b7753450c73f8ad2389b5c018a4af7b2224a" + integrity sha512-FuwxlW4H5kh37X/oW59pwTzzTKRzfrrQwhmyspRM7swOEZcHtDZSCt45U6oKgtuFE+WYPblePMVIPR4RZrh/hw== base16@^1.0.0: version "1.0.0" @@ -4105,12 +4108,12 @@ browserslist@^4.12.0, browserslist@^4.14.5, browserslist@^4.20.2, browserslist@^ node-releases "^2.0.5" update-browserslist-db "^1.0.4" -bs58@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a" - integrity sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw== +bs58@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/bs58/-/bs58-5.0.0.tgz#865575b4d13c09ea2a84622df6c8cbeb54ffc279" + integrity sha512-r+ihvQJvahgYT50JD05dyJNKlmmSlMoOGwn1lCcEzanPglg7TxYjioQUYehQ9mAR/+hOSd2jRc/Z2y5UxBymvQ== dependencies: - base-x "^3.0.2" + base-x "^4.0.0" buffer-from@^1.0.0: version "1.1.2" @@ -8387,24 +8390,33 @@ matrix-events-sdk@^0.0.1-beta.7: resolved "https://registry.yarnpkg.com/matrix-events-sdk/-/matrix-events-sdk-0.0.1-beta.7.tgz#5ffe45eba1f67cc8d7c2377736c728b322524934" integrity sha512-9jl4wtWanUFSy2sr2lCjErN/oC8KTAtaeaozJtrgot1JiQcEI4Rda9OLgQ7nLKaqb4Z/QUx/fR3XpDzm5Jy1JA== -"matrix-js-sdk@github:matrix-org/matrix-js-sdk#8ba2d257ae24bbed61cd7fe99af081324337161c": - version "19.0.0" - resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/8ba2d257ae24bbed61cd7fe99af081324337161c" +"matrix-js-sdk@github:matrix-org/matrix-js-sdk#3334c01191bcd82b5243916284c9a08d08fd9795": + version "19.2.0" + resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/3334c01191bcd82b5243916284c9a08d08fd9795" dependencies: "@babel/runtime" "^7.12.5" "@types/sdp-transform" "^2.4.5" another-json "^0.2.0" browser-request "^0.3.3" - bs58 "^4.0.1" + bs58 "^5.0.0" content-type "^1.0.4" loglevel "^1.7.1" matrix-events-sdk "^0.0.1-beta.7" - p-retry "^4.5.0" + matrix-widget-api "^1.0.0" + p-retry "4" qs "^6.9.6" request "^2.88.2" sdp-transform "^2.14.1" unhomoglyph "^1.0.6" +matrix-widget-api@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/matrix-widget-api/-/matrix-widget-api-1.0.0.tgz#0cde6839cca66ad817ab12aca3490ccc8bac97d1" + integrity sha512-cy8p/8EteRPTFIAw7Q9EgPUJc2jD19ZahMR8bMKf2NkILDcjuPMC0UWnsJyB3fSnlGw+VbGepttRpULM31zX8Q== + dependencies: + "@types/events" "^3.0.0" + events "^3.2.0" + md5.js@^1.3.4: version "1.3.5" resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" @@ -9189,7 +9201,7 @@ p-map@^4.0.0: dependencies: aggregate-error "^3.0.0" -p-retry@^4.5.0: +p-retry@4: version "4.6.2" resolved "https://registry.yarnpkg.com/p-retry/-/p-retry-4.6.2.tgz#9baae7184057edd4e17231cee04264106e092a16" integrity sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==