diff --git a/README.md b/README.md index cedf9ec2..086447d1 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,28 @@ experimental_features: MSC3266 allows to request a room summary of rooms you are not joined. The summary contains the room join rules. We need that to decide if the user gets prompted with the option to knock ("ask to join"), a cannot join error or the join view. +Element Call requires a Livekit SFU behind a Livekit jwt service to work. The url to the Livekit jwt service can either be configured in the config of Element Call (fallback/legacy configuration) or be configured by your homeserver via the `.well-known`. +This is the recommended method. + +The configuration is a list of Foci configs: + +```json +"org.matrix.msc4143.rtc_foci": [ + { + "type": "livekit", + "livekit_service_url": "https://someurl.com" + }, + { + "type": "livekit", + "livekit_service_url": "https://livekit2.com" + }, + { + "type": "another_foci", + "props_for_another_foci": "val" + }, +] +``` + ## Translation If you'd like to help translate Element Call, head over to [Localazy](https://localazy.com/p/element-call). You're also encouraged to join the [Element Translators](https://matrix.to/#/#translators:element.io) space to discuss and coordinate translation efforts. @@ -103,7 +125,9 @@ service for development. These use a test 'secret' published in this repository, so this must be used only for local development and **_never be exposed to the public Internet._** -To use it, add SFU parameter in your local config `./public/config.json`: +To use it, add a SFU parameter in your local config `./public/config.json`: +(Be aware, that this is only the fallback Livekit SFU. If the homeserver +advertises one in the client well-known, this will not be used.) ```json "livekit": { diff --git a/package.json b/package.json index 5ebe9fcc..deb4ed04 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "i18next-http-backend": "^2.0.0", "livekit-client": "^2.0.2", "lodash": "^4.17.21", - "matrix-js-sdk": "github:matrix-org/matrix-js-sdk#e874468ba3e84819cf4b342d2e66af67ab4cf804", + "matrix-js-sdk": "github:matrix-org/matrix-js-sdk#d754392410a23526ce65fd2fd6b04bfac989b666", "matrix-widget-api": "^1.3.1", "normalize.css": "^8.0.1", "pako": "^2.0.4", diff --git a/src/ClientContext.tsx b/src/ClientContext.tsx index 619626f7..8d13e315 100644 --- a/src/ClientContext.tsx +++ b/src/ClientContext.tsx @@ -25,7 +25,11 @@ import { useMemo, } from "react"; import { useHistory } from "react-router-dom"; -import { ClientEvent, MatrixClient } from "matrix-js-sdk/src/client"; +import { + ClientEvent, + ICreateClientOpts, + MatrixClient, +} from "matrix-js-sdk/src/client"; import { logger } from "matrix-js-sdk/src/logger"; import { useTranslation } from "react-i18next"; import { ISyncStateData, SyncState } from "matrix-js-sdk/src/sync"; @@ -360,13 +364,13 @@ async function loadClient(): Promise { /* eslint-disable camelcase */ const { user_id, device_id, access_token, passwordlessUser } = session; - const initClientParams = { + const initClientParams: ICreateClientOpts = { baseUrl: Config.defaultHomeserverUrl()!, accessToken: access_token, userId: user_id, deviceId: device_id, fallbackICEServerAllowed: fallbackICEServerAllowed, - livekitServiceURL: Config.get().livekit!.livekit_service_url, + livekitServiceURL: Config.get().livekit?.livekit_service_url, }; try { diff --git a/src/config/ConfigOptions.ts b/src/config/ConfigOptions.ts index cbbc107c..29c5230e 100644 --- a/src/config/ConfigOptions.ts +++ b/src/config/ConfigOptions.ts @@ -55,7 +55,12 @@ export interface ConfigOptions { // Describes the LiveKit configuration to be used. livekit?: { - // The link to the service that returns a livekit url and token to use it + // The link to the service that returns a livekit url and token to use it. + // This is a fallback link in case the homeserver in use does not advertise + // a livekit service url in the client well-known. + // The well known needs to be formatted like so: + // {"type":"livekit", "livekit_service_url":"https://livekit.example.com"} + // and stored under the key: "livekit_focus" livekit_service_url: string; }; diff --git a/src/livekit/LivekitFocus.ts b/src/livekit/LivekitFocus.ts index f3a1e532..e69de29b 100644 --- a/src/livekit/LivekitFocus.ts +++ b/src/livekit/LivekitFocus.ts @@ -1,23 +0,0 @@ -/* -Copyright 2023 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. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -import { Focus } from "matrix-js-sdk/src/matrixrtc/focus"; - -export interface LivekitFocus extends Focus { - type: "livekit"; - livekit_service_url: string; - livekit_alias: string; -} diff --git a/src/livekit/openIDSFU.ts b/src/livekit/openIDSFU.ts index 8b447485..ca45a081 100644 --- a/src/livekit/openIDSFU.ts +++ b/src/livekit/openIDSFU.ts @@ -18,9 +18,9 @@ import { IOpenIDToken, MatrixClient } from "matrix-js-sdk"; import { logger } from "matrix-js-sdk/src/logger"; import { MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession"; import { useEffect, useState } from "react"; +import { LivekitFocus } from "matrix-js-sdk/src/matrixrtc/LivekitFocus"; -import { LivekitFocus } from "./LivekitFocus"; -import { useActiveFocus } from "../room/useActiveFocus"; +import { useActiveLivekitFocus } from "../room/useActiveFocus"; export interface SFUConfig { url: string; @@ -46,7 +46,7 @@ export function useOpenIDSFU( ): SFUConfig | undefined { const [sfuConfig, setSFUConfig] = useState(undefined); - const activeFocus = useActiveFocus(rtcSession); + const activeFocus = useActiveLivekitFocus(rtcSession); useEffect(() => { (async (): Promise => { diff --git a/src/matrix-utils.ts b/src/matrix-utils.ts index 4a3b84fc..c6fe954d 100644 --- a/src/matrix-utils.ts +++ b/src/matrix-utils.ts @@ -206,7 +206,7 @@ export async function initClient( // Otherwise, a sync may complete before the listener gets applied, // and we will miss it. const syncPromise = waitForSync(client); - await client.startClient(); + await client.startClient({ clientWellKnownPollPeriod: 60 * 10 }); await syncPromise; return client; diff --git a/src/room/GroupCallView.tsx b/src/room/GroupCallView.tsx index 2052a649..dfc4ff19 100644 --- a/src/room/GroupCallView.tsx +++ b/src/room/GroupCallView.tsx @@ -196,7 +196,7 @@ export const GroupCallView: FC = ({ ev: CustomEvent, ): Promise => { defaultDeviceSetup(ev.detail.data as unknown as JoinCallData); - enterRTCSession(rtcSession, perParticipantE2EE); + await enterRTCSession(rtcSession, perParticipantE2EE); await widget!.api.transport.reply(ev.detail, {}); }; widget.lazyActions.on(ElementWidgetActions.JoinCall, onJoin); @@ -318,7 +318,7 @@ export const GroupCallView: FC = ({ client={client} matrixInfo={matrixInfo} muteStates={muteStates} - onEnter={(): void => enterRTCSession(rtcSession, perParticipantE2EE)} + onEnter={() => void enterRTCSession(rtcSession, perParticipantE2EE)} confineToRoom={confineToRoom} hideHeader={hideHeader} participantCount={participantCount} diff --git a/src/room/useActiveFocus.ts b/src/room/useActiveFocus.ts index 5a7b1743..8f70d870 100644 --- a/src/room/useActiveFocus.ts +++ b/src/room/useActiveFocus.ts @@ -21,33 +21,28 @@ import { import { useCallback, useEffect, useState } from "react"; import { deepCompare } from "matrix-js-sdk/src/utils"; import { logger } from "matrix-js-sdk/src/logger"; - -import { LivekitFocus } from "../livekit/LivekitFocus"; - -function getActiveFocus( - rtcSession: MatrixRTCSession, -): LivekitFocus | undefined { - const oldestMembership = rtcSession.getOldestMembership(); - const focus = oldestMembership?.getActiveFoci()[0] as LivekitFocus; - - return focus; -} +import { + LivekitFocus, + isLivekitFocus, +} from "matrix-js-sdk/src/matrixrtc/LivekitFocus"; /** * Gets the currently active (livekit) focus for a MatrixRTC session * This logic is specific to livekit foci where the whole call must use one * and the same focus. */ -export function useActiveFocus( +export function useActiveLivekitFocus( rtcSession: MatrixRTCSession, ): LivekitFocus | undefined { - const [activeFocus, setActiveFocus] = useState(() => - getActiveFocus(rtcSession), - ); + const [activeFocus, setActiveFocus] = useState(() => { + const f = rtcSession.getActiveFocus(); + // Only handle foci with type="livekit" for now. + return !!f && isLivekitFocus(f) ? f : undefined; + }); const onMembershipsChanged = useCallback(() => { - const newActiveFocus = getActiveFocus(rtcSession); - + const newActiveFocus = rtcSession.getActiveFocus(); + if (!!newActiveFocus && !isLivekitFocus(newActiveFocus)) return; if (!deepCompare(activeFocus, newActiveFocus)) { const oldestMembership = rtcSession.getOldestMembership(); logger.warn( diff --git a/src/room/useLoadGroupCall.ts b/src/room/useLoadGroupCall.ts index d913c3c9..d9a3d7ed 100644 --- a/src/room/useLoadGroupCall.ts +++ b/src/room/useLoadGroupCall.ts @@ -217,8 +217,6 @@ export const useLoadGroupCall = ( "Room not found. The widget-api did not pass over the relevant room events/information.", ); - // If the room does not exist we first search for it with viaServers - const roomSummary = await client.getRoomSummary(roomId, viaServers); if (membership === KnownMembership.Ban) { throw bannedError(); } else if (membership === KnownMembership.Invite) { @@ -226,6 +224,8 @@ export const useLoadGroupCall = ( viaServers, }); } else { + // If the room does not exist we first search for it with viaServers + const roomSummary = await client.getRoomSummary(roomId, viaServers); if (roomSummary.join_rule === JoinRule.Public) { room = await client.joinRoom(roomSummary.room_id, { viaServers, diff --git a/src/rtcSessionHelpers.ts b/src/rtcSessionHelpers.ts index 2291e80c..0b1730f6 100644 --- a/src/rtcSessionHelpers.ts +++ b/src/rtcSessionHelpers.ts @@ -15,29 +15,90 @@ limitations under the License. */ import { MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession"; +import { logger } from "matrix-js-sdk/src/logger"; +import { + LivekitFocus, + LivekitFocusActive, + isLivekitFocus, + isLivekitFocusConfig, +} from "matrix-js-sdk/src/matrixrtc/LivekitFocus"; import { PosthogAnalytics } from "./analytics/PosthogAnalytics"; -import { LivekitFocus } from "./livekit/LivekitFocus"; import { Config } from "./config/Config"; import { ElementWidgetActions, WidgetHelpers, widget } from "./widget"; -function makeFocus(livekitAlias: string): LivekitFocus { - const urlFromConf = Config.get().livekit!.livekit_service_url; - if (!urlFromConf) { - throw new Error("No livekit_service_url is configured!"); - } +const FOCI_WK_KEY = "org.matrix.msc4143.rtc_foci"; +export function makeActiveFocus(): LivekitFocusActive { return { type: "livekit", - livekit_service_url: urlFromConf, - livekit_alias: livekitAlias, + focus_selection: "oldest_membership", }; } -export function enterRTCSession( +async function makePreferredLivekitFoci( + rtcSession: MatrixRTCSession, + livekitAlias: string, +): Promise { + logger.log("Start building foci_preferred list: ", rtcSession.room.roomId); + + const preferredFoci: LivekitFocus[] = []; + + // Make the Focus from the running rtc session the highest priority one + // This minimizes how often we need to switch foci during a call. + const focusInUse = rtcSession.getFocusInUse(); + if (focusInUse && isLivekitFocus(focusInUse)) { + logger.log("Adding livekit focus from oldest member: ", focusInUse); + preferredFoci.push(focusInUse); + } + + // Prioritize the client well known over the configured sfu. + const wellKnownFoci = + rtcSession.room.client.getClientWellKnown()?.[FOCI_WK_KEY]; + if (Array.isArray(wellKnownFoci)) { + preferredFoci.push( + ...wellKnownFoci + .filter((f) => !!f) + .filter(isLivekitFocusConfig) + .map((wellKnownFocus) => { + logger.log("Adding livekit focus from well known: ", wellKnownFocus); + return { ...wellKnownFocus, livekit_alias: livekitAlias }; + }), + ); + } + + const urlFromConf = Config.get().livekit?.livekit_service_url; + if (urlFromConf) { + const focusFormConf: LivekitFocus = { + type: "livekit", + livekit_service_url: urlFromConf, + livekit_alias: livekitAlias, + }; + logger.log("Adding livekit focus from config: ", focusFormConf); + preferredFoci.push(focusFormConf); + } + + if (preferredFoci.length === 0) + throw new Error( + `No livekit_service_url is configured so we could not create a focus. + Currently we skip computing a focus based on other users in the room.`, + ); + + return preferredFoci; + + // TODO: we want to do something like this: + // + // const focusOtherMembers = await focusFromOtherMembers( + // rtcSession, + // livekitAlias, + // ); + // if (focusOtherMembers) preferredFoci.push(focusOtherMembers); +} + +export async function enterRTCSession( rtcSession: MatrixRTCSession, encryptMedia: boolean, -): void { +): Promise { PosthogAnalytics.instance.eventCallEnded.cacheStartCall(new Date()); PosthogAnalytics.instance.eventCallStarted.track(rtcSession.room.roomId); @@ -47,8 +108,11 @@ export function enterRTCSession( // right now we assume everything is a room-scoped call const livekitAlias = rtcSession.room.roomId; - - rtcSession.joinRoomSession([makeFocus(livekitAlias)], encryptMedia); + rtcSession.joinRoomSession( + await makePreferredLivekitFoci(rtcSession, livekitAlias), + makeActiveFocus(), + { manageMediaKeys: encryptMedia }, + ); } const widgetPostHangupProcedure = async ( diff --git a/src/useMatrixRTCSessionJoinState.ts b/src/useMatrixRTCSessionJoinState.ts index af7618df..3e9cabb2 100644 --- a/src/useMatrixRTCSessionJoinState.ts +++ b/src/useMatrixRTCSessionJoinState.ts @@ -26,14 +26,17 @@ export function useMatrixRTCSessionJoinState( ): boolean { const [isJoined, setJoined] = useState(rtcSession.isJoined()); - const onJoinStateChanged = useCallback(() => { - logger.info( - `Session in room ${rtcSession.room.roomId} changed to ${ - rtcSession.isJoined() ? "joined" : "left" - }`, - ); - setJoined(rtcSession.isJoined()); - }, [rtcSession]); + const onJoinStateChanged = useCallback( + (isJoined: boolean) => { + logger.info( + `Session in room ${rtcSession.room.roomId} changed to ${ + isJoined ? "joined" : "left" + }`, + ); + setJoined(isJoined); + }, + [rtcSession], + ); useEffect(() => { rtcSession.on(MatrixRTCSessionEvent.JoinStateChanged, onJoinStateChanged); diff --git a/src/widget.ts b/src/widget.ts index a066b57d..060718db 100644 --- a/src/widget.ts +++ b/src/widget.ts @@ -77,8 +77,6 @@ export const widget = ((): WidgetHelpers | null => { logger.info("Widget API is available"); const api = new WidgetApi(widgetId, parentOrigin); api.requestCapability(MatrixCapabilities.AlwaysOnScreen); - api.requestCapabilityToSendEvent(EventType.CallEncryptionKeysPrefix); - api.requestCapabilityToReceiveEvent(EventType.CallEncryptionKeysPrefix); // Set up the lazy action emitter, but only for select actions that we // intend for the app to handle @@ -116,9 +114,15 @@ export const widget = ((): WidgetHelpers | null => { if (!baseUrl) throw new Error("Base URL must be supplied"); // These are all the event types the app uses - const sendRecvEvent = ["org.matrix.rageshake_request"]; + const sendRecvEvent = [ + "org.matrix.rageshake_request", + EventType.CallEncryptionKeysPrefix, + ]; const sendState = [ - { eventType: EventType.GroupCallMemberPrefix, stateKey: userId }, + { + eventType: EventType.GroupCallMemberPrefix, + stateKey: userId, // TODO: based on if we use the new format we want the key to be: `_${userId}_${deviceId}` + }, ]; const receiveState = [ { eventType: EventType.RoomMember }, @@ -167,7 +171,7 @@ export const widget = ((): WidgetHelpers | null => { // wait for the config file to be ready (we load very early on so it might not // be otherwise) await Config.init(); - await client.startClient(); + await client.startClient({ clientWellKnownPollPeriod: 60 * 10 }); resolve(client); })(); }); diff --git a/test/rtcSessionHelper-test.ts b/test/rtcSessionHelper-test.ts new file mode 100644 index 00000000..f9c85964 --- /dev/null +++ b/test/rtcSessionHelper-test.ts @@ -0,0 +1,93 @@ +/* +Copyright 2024 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. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession"; + +import { enterRTCSession } from "../src/rtcSessionHelpers"; +import { Config } from "../src/config/Config"; + +test("It joins the correct Session", async () => { + const focusFromOlderMembership = { + type: "livekit", + livekit_service_url: "http://my-oldest-member-service-url.com", + livekit_alias: "my-oldest-member-service-alias", + }; + + const focusConfigFromWellKnown = { + type: "livekit", + livekit_service_url: "http://my-well-known-service-url.com", + }; + const focusConfigFromWellKnown2 = { + type: "livekit", + livekit_service_url: "http://my-well-known-service-url2.com", + }; + const clientWellKnown = { + "org.matrix.msc4143.rtc_foci": [ + focusConfigFromWellKnown, + focusConfigFromWellKnown2, + ], + }; + + vi.spyOn(Config, "get").mockReturnValue({ + livekit: { livekit_service_url: "http://my-default-service-url.com" }, + eula: "", + }); + const mockedSession = vi.mocked({ + room: { + roomId: "roomId", + client: { + getClientWellKnown: vi.fn().mockReturnValue(clientWellKnown), + }, + }, + memberships: [], + getFocusInUse: vi.fn().mockReturnValue(focusFromOlderMembership), + getOldestMembership: vi.fn().mockReturnValue({ + getPreferredFoci: vi.fn().mockReturnValue([focusFromOlderMembership]), + }), + joinRoomSession: vi.fn(), + }) as unknown as MatrixRTCSession; + await enterRTCSession(mockedSession, false); + + expect(mockedSession.joinRoomSession).toHaveBeenLastCalledWith( + [ + { + livekit_alias: "my-oldest-member-service-alias", + livekit_service_url: "http://my-oldest-member-service-url.com", + type: "livekit", + }, + { + livekit_alias: "roomId", + livekit_service_url: "http://my-well-known-service-url.com", + type: "livekit", + }, + { + livekit_alias: "roomId", + livekit_service_url: "http://my-well-known-service-url2.com", + type: "livekit", + }, + { + livekit_alias: "roomId", + livekit_service_url: "http://my-default-service-url.com", + type: "livekit", + }, + ], + { + focus_selection: "oldest_membership", + type: "livekit", + }, + { manageMediaKeys: false }, + ); +}); diff --git a/yarn.lock b/yarn.lock index 828bd389..4f082f59 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1738,10 +1738,10 @@ dependencies: "@bufbuild/protobuf" "^1.7.2" -"@matrix-org/matrix-sdk-crypto-wasm@^4.9.0": - version "4.9.0" - resolved "https://registry.yarnpkg.com/@matrix-org/matrix-sdk-crypto-wasm/-/matrix-sdk-crypto-wasm-4.9.0.tgz#9dfed83e33f760650596c4e5c520e5e4c53355d2" - integrity sha512-/bgA4QfE7qkK6GFr9hnhjAvRSebGrmEJxukU0ukbudZcYvbzymoBBM8j3HeULXZT8kbw8WH6z63txYTMCBSDOA== +"@matrix-org/matrix-sdk-crypto-wasm@^5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@matrix-org/matrix-sdk-crypto-wasm/-/matrix-sdk-crypto-wasm-5.0.0.tgz#f45a7bccaad218c05bcf9e7c8ca783c9d9a07af4" + integrity sha512-37ASjCKSTU5ycGfkP+LUXG4Ok6OAf6vE+1qU6uwWhe6FwadCS3vVWzJYd/3d9BQFwsx4GhFTIAXrW4iLG85rmQ== "@matrix-org/olm@https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.14.tgz": version "3.2.14" @@ -3513,44 +3513,44 @@ "@types/babel__core" "^7.20.5" react-refresh "^0.14.0" -"@vitest/expect@1.3.1": - version "1.3.1" - resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-1.3.1.tgz#d4c14b89c43a25fd400a6b941f51ba27fe0cb918" - integrity sha512-xofQFwIzfdmLLlHa6ag0dPV8YsnKOCP1KdAeVVh34vSjN2dcUiXYCD9htu/9eM7t8Xln4v03U9HLxLpPlsXdZw== +"@vitest/expect@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-1.6.0.tgz#0b3ba0914f738508464983f4d811bc122b51fb30" + integrity sha512-ixEvFVQjycy/oNgHjqsL6AZCDduC+tflRluaHIzKIsdbzkLn2U/iBnVeJwB6HsIjQBdfMR8Z0tRxKUsvFJEeWQ== dependencies: - "@vitest/spy" "1.3.1" - "@vitest/utils" "1.3.1" + "@vitest/spy" "1.6.0" + "@vitest/utils" "1.6.0" chai "^4.3.10" -"@vitest/runner@1.3.1": - version "1.3.1" - resolved "https://registry.yarnpkg.com/@vitest/runner/-/runner-1.3.1.tgz#e7f96cdf74842934782bfd310eef4b8695bbfa30" - integrity sha512-5FzF9c3jG/z5bgCnjr8j9LNq/9OxV2uEBAITOXfoe3rdZJTdO7jzThth7FXv/6b+kdY65tpRQB7WaKhNZwX+Kg== +"@vitest/runner@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@vitest/runner/-/runner-1.6.0.tgz#a6de49a96cb33b0e3ba0d9064a3e8d6ce2f08825" + integrity sha512-P4xgwPjwesuBiHisAVz/LSSZtDjOTPYZVmNAnpHHSR6ONrf8eCJOFRvUwdHn30F5M1fxhqtl7QZQUk2dprIXAg== dependencies: - "@vitest/utils" "1.3.1" + "@vitest/utils" "1.6.0" p-limit "^5.0.0" pathe "^1.1.1" -"@vitest/snapshot@1.3.1": - version "1.3.1" - resolved "https://registry.yarnpkg.com/@vitest/snapshot/-/snapshot-1.3.1.tgz#193a5d7febf6ec5d22b3f8c5a093f9e4322e7a88" - integrity sha512-EF++BZbt6RZmOlE3SuTPu/NfwBF6q4ABS37HHXzs2LUVPBLx2QoY/K0fKpRChSo8eLiuxcbCVfqKgx/dplCDuQ== +"@vitest/snapshot@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@vitest/snapshot/-/snapshot-1.6.0.tgz#deb7e4498a5299c1198136f56e6e0f692e6af470" + integrity sha512-+Hx43f8Chus+DCmygqqfetcAZrDJwvTj0ymqjQq4CvmpKFSTVteEOBzCusu1x2tt4OJcvBflyHUE0DZSLgEMtQ== dependencies: magic-string "^0.30.5" pathe "^1.1.1" pretty-format "^29.7.0" -"@vitest/spy@1.3.1": - version "1.3.1" - resolved "https://registry.yarnpkg.com/@vitest/spy/-/spy-1.3.1.tgz#814245d46d011b99edd1c7528f5725c64e85a88b" - integrity sha512-xAcW+S099ylC9VLU7eZfdT9myV67Nor9w9zhf0mGCYJSO+zM2839tOeROTdikOi/8Qeusffvxb/MyBSOja1Uig== +"@vitest/spy@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@vitest/spy/-/spy-1.6.0.tgz#362cbd42ccdb03f1613798fde99799649516906d" + integrity sha512-leUTap6B/cqi/bQkXUu6bQV5TZPx7pmMBKBQiI0rJA8c3pB56ZsaTbREnF7CJfmvAS4V2cXIBAh/3rVwrrCYgw== dependencies: tinyspy "^2.2.0" -"@vitest/utils@1.3.1": - version "1.3.1" - resolved "https://registry.yarnpkg.com/@vitest/utils/-/utils-1.3.1.tgz#7b05838654557544f694a372de767fcc9594d61a" - integrity sha512-d3Waie/299qqRyHTm2DjADeTaNdNSVsnwHPWrs20JMpjh6eiVq7ggggweO8rc4arhf6rRkWuHKwvxGvejUXZZQ== +"@vitest/utils@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@vitest/utils/-/utils-1.6.0.tgz#5c5675ca7d6f546a7b4337de9ae882e6c57896a1" + integrity sha512-21cPiuGMoMZwiOHa2i4LXkMkMkCGzA+MVFV70jRwHo95dL4x/ts5GZhML1QWuy7yfp3WzK3lRvZi3JnXTYqrBw== dependencies: diff-sequences "^29.6.3" estree-walker "^3.0.3" @@ -4258,6 +4258,11 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== +confbox@^0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/confbox/-/confbox-0.1.7.tgz#ccfc0a2bcae36a84838e83a3b7f770fb17d6c579" + integrity sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA== + content-type@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" @@ -6088,10 +6093,10 @@ jaeger-client@^3.15.0: resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== -js-tokens@^8.0.2: - version "8.0.3" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-8.0.3.tgz#1c407ec905643603b38b6be6977300406ec48775" - integrity sha512-UfJMcSJc+SEXEl9lH/VLHSZbThQyLpw1vLO1Lb+j4RWDvG3N2f7yj3PVQA3cmkTBNldJ9eFnM+xEXxHIXrYiJw== +js-tokens@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-9.0.0.tgz#0f893996d6f3ed46df7f0a3b12a03f5fd84223c1" + integrity sha512-WriZw1luRMlmV3LGJaR6QOJjWwgLUTf89OwT2lUOyjX2dJGBwgmIkbcz+7WFZjrZM635JOIR517++e/67CP9dQ== js-yaml@4.1.0, js-yaml@^4.1.0: version "4.1.0" @@ -6179,11 +6184,6 @@ json5@^2.2.3: resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== -jsonc-parser@^3.2.0: - version "3.2.1" - resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.2.1.tgz#031904571ccf929d7670ee8c547545081cb37f1a" - integrity sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA== - jsonfile@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" @@ -6383,9 +6383,9 @@ magic-string@0.30.8: "@jridgewell/sourcemap-codec" "^1.4.15" magic-string@^0.30.5: - version "0.30.7" - resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.7.tgz#0cecd0527d473298679da95a2d7aeb8c64048505" - integrity sha512-8vBuFF/I/+OSLRmdf2wwFCJCz+nSn0m6DPvGH1fS/KiQoSaR+sETbov0eIk9KhEKy8CYqIkIAnbohxT/4H0kuA== + version "0.30.10" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.10.tgz#123d9c41a0cb5640c892b041d4cfb3bd0aa4b39e" + integrity sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ== dependencies: "@jridgewell/sourcemap-codec" "^1.4.15" @@ -6402,13 +6402,12 @@ matrix-events-sdk@0.0.1: resolved "https://registry.yarnpkg.com/matrix-events-sdk/-/matrix-events-sdk-0.0.1.tgz#c8c38911e2cb29023b0bbac8d6f32e0de2c957dd" integrity sha512-1QEOsXO+bhyCroIe2/A5OwaxHvBm7EsSQ46DEDn8RBIfQwN5HWBpFvyWWR4QY0KHPPnnJdI99wgRiAl7Ad5qaA== -"matrix-js-sdk@github:matrix-org/matrix-js-sdk#e874468ba3e84819cf4b342d2e66af67ab4cf804": - version "32.0.0" - uid e874468ba3e84819cf4b342d2e66af67ab4cf804 - resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/e874468ba3e84819cf4b342d2e66af67ab4cf804" +"matrix-js-sdk@github:matrix-org/matrix-js-sdk#d754392410a23526ce65fd2fd6b04bfac989b666": + version "33.0.0" + resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/d754392410a23526ce65fd2fd6b04bfac989b666" dependencies: "@babel/runtime" "^7.12.5" - "@matrix-org/matrix-sdk-crypto-wasm" "^4.9.0" + "@matrix-org/matrix-sdk-crypto-wasm" "^5.0.0" another-json "^0.2.0" bs58 "^5.0.0" content-type "^1.0.4" @@ -6420,7 +6419,7 @@ matrix-events-sdk@0.0.1: p-retry "4" sdp-transform "^2.14.1" unhomoglyph "^1.0.6" - uuid "9" + uuid "10" matrix-widget-api@^1.3.1, matrix-widget-api@^1.6.0: version "1.6.0" @@ -6521,15 +6520,15 @@ mktemp@~0.4.0: resolved "https://registry.yarnpkg.com/mktemp/-/mktemp-0.4.0.tgz#6d0515611c8a8c84e484aa2000129b98e981ff0b" integrity sha512-IXnMcJ6ZyTuhRmJSjzvHSRhlVPiN9Jwc6e59V0bEJ0ba6OBeX2L0E+mRN1QseeOF4mM+F1Rit6Nh7o+rl2Yn/A== -mlly@^1.2.0, mlly@^1.4.2: - version "1.5.0" - resolved "https://registry.yarnpkg.com/mlly/-/mlly-1.5.0.tgz#8428a4617d54cc083d3009030ac79739a0e5447a" - integrity sha512-NPVQvAY1xr1QoVeG0cy8yUYC7FQcOx6evl/RjT1wL5FvzPnzOysoqB/jmx/DhssT2dYa8nxECLAaFI/+gVLhDQ== +mlly@^1.4.2, mlly@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/mlly/-/mlly-1.7.0.tgz#587383ae40dda23cadb11c3c3cc972b277724271" + integrity sha512-U9SDaXGEREBYQgfejV97coK0UL1r+qnF2SyO9A3qcI8MzKnsIFKHNVEkrDyNncQTKQQumsasmeq84eNMdBfsNQ== dependencies: acorn "^8.11.3" pathe "^1.1.2" - pkg-types "^1.0.3" - ufo "^1.3.2" + pkg-types "^1.1.0" + ufo "^1.5.3" module-details-from-path@^1.0.3: version "1.0.3" @@ -6626,9 +6625,9 @@ now-and-later@^3.0.0: once "^1.4.0" npm-run-path@^5.1.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-5.2.0.tgz#224cdd22c755560253dd71b83a1ef2f758b2e955" - integrity sha512-W4/tgAXFqFA0iL7fk0+uQ3g7wkL8xJmx3XdK0VGb4cHW//eZTtKGvFBBoRKVTpY7n6ze4NL9ly7rgXcHufqXKg== + version "5.3.0" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-5.3.0.tgz#e23353d0ebb9317f174e93417e4a4d82d0249e9f" + integrity sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ== dependencies: path-key "^4.0.0" @@ -6948,7 +6947,7 @@ path-type@^4.0.0: resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== -pathe@^1.1.0, pathe@^1.1.1, pathe@^1.1.2: +pathe@^1.1.1, pathe@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/pathe/-/pathe-1.1.2.tgz#6c4cb47a945692e48a1ddd6e4094d170516437ec" integrity sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ== @@ -6975,14 +6974,14 @@ pkg-dir@^7.0.0: dependencies: find-up "^6.3.0" -pkg-types@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/pkg-types/-/pkg-types-1.0.3.tgz#988b42ab19254c01614d13f4f65a2cfc7880f868" - integrity sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A== +pkg-types@^1.0.3, pkg-types@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/pkg-types/-/pkg-types-1.1.1.tgz#07b626880749beb607b0c817af63aac1845a73f2" + integrity sha512-ko14TjmDuQJ14zsotODv7dBlwxKhUKQEhuhmbqo1uCi9BB0Z2alo/wAXg6q1dTR5TyuqYyWhjtfe/Tsh+X28jQ== dependencies: - jsonc-parser "^3.2.0" - mlly "^1.2.0" - pathe "^1.1.0" + confbox "^0.1.7" + mlly "^1.7.0" + pathe "^1.1.2" pluralize@^8.0.0: version "8.0.0" @@ -7417,9 +7416,9 @@ react-is@^17.0.1: integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== react-is@^18.0.0: - version "18.2.0" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" - integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== + version "18.3.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e" + integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg== react-refresh@^0.14.0: version "0.14.0" @@ -8167,11 +8166,11 @@ strip-json-comments@^3.1.1: integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== strip-literal@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/strip-literal/-/strip-literal-2.0.0.tgz#5d063580933e4e03ebb669b12db64d2200687527" - integrity sha512-f9vHgsCWBq2ugHAkGMiiYY+AYG0D/cbloKKg0nhaaaSNsujdGIpVXCNsrJpCKr5M0f4aI31mr13UjY6GAuXCKA== + version "2.1.0" + resolved "https://registry.yarnpkg.com/strip-literal/-/strip-literal-2.1.0.tgz#6d82ade5e2e74f5c7e8739b6c84692bd65f0bd2a" + integrity sha512-Op+UycaUt/8FbN/Z2TWPBLge3jWrP3xj10f3fnYxf052bKuS3EKs1ZQcVGjnEMdsNVAM+plXRdmjrZ/KgG3Skw== dependencies: - js-tokens "^8.0.2" + js-tokens "^9.0.0" supports-color@^5.3.0: version "5.5.0" @@ -8296,14 +8295,14 @@ tiny-warning@^1.0.0: integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== tinybench@^2.5.1: - version "2.6.0" - resolved "https://registry.yarnpkg.com/tinybench/-/tinybench-2.6.0.tgz#1423284ee22de07c91b3752c048d2764714b341b" - integrity sha512-N8hW3PG/3aOoZAN5V/NSAEDz0ZixDSSt5b/a05iqtpgfLWMSVuCo7w0k2vVvEjdrIoeGqZzweX2WlyioNIHchA== + version "2.8.0" + resolved "https://registry.yarnpkg.com/tinybench/-/tinybench-2.8.0.tgz#30e19ae3a27508ee18273ffed9ac7018949acd7b" + integrity sha512-1/eK7zUnIklz4JUUlL+658n58XO2hHLQfSk1Zf2LKieUjxidN16eKFEoDEfjHc3ohofSSqK3X5yO6VGb6iW8Lw== -tinypool@^0.8.2: - version "0.8.2" - resolved "https://registry.yarnpkg.com/tinypool/-/tinypool-0.8.2.tgz#84013b03dc69dacb322563a475d4c0a9be00f82a" - integrity sha512-SUszKYe5wgsxnNOVlBYO6IC+8VGWdVGZWAqUxp3UErNBtptZvWbwyUOyzNL59zigz2rCA92QiL3wvG+JDSdJdQ== +tinypool@^0.8.3: + version "0.8.4" + resolved "https://registry.yarnpkg.com/tinypool/-/tinypool-0.8.4.tgz#e217fe1270d941b39e98c625dcecebb1408c9aa8" + integrity sha512-i11VH5gS6IFeLY3gMBQ00/MmLncVP7JLXOw1vlgkytLmJK7QnEr7NXf0LBdxfmNPAeyetukOk0bOYrJrFGjYJQ== tinyqueue@^2.0.3: version "2.0.3" @@ -8479,10 +8478,10 @@ typescript@^5.0.4, typescript@^5.1.6: resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.3.3.tgz#b3ce6ba258e72e6305ba66f5c9b452aaee3ffe37" integrity sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw== -ufo@^1.3.2: - version "1.4.0" - resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.4.0.tgz#39845b31be81b4f319ab1d99fd20c56cac528d32" - integrity sha512-Hhy+BhRBleFjpJ2vchUNN40qgkh0366FWJGqVLYBHev0vpHTrXSA0ryT+74UiW6KWsldNurQMKGqCm1M2zBciQ== +ufo@^1.5.3: + version "1.5.3" + resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.5.3.tgz#3325bd3c977b6c6cd3160bf4ff52989adc9d3344" + integrity sha512-Y7HYmWaFwPUmkoQCUIAYpKqkOf+SbVj/2fJJZ4RJMCfZp0rTGwRbzQD+HghfnhKOjL9E01okqz+ncJskGYfBNw== unbox-primitive@^1.0.2: version "1.0.2" @@ -8620,6 +8619,11 @@ util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== +uuid@10: + version "10.0.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-10.0.0.tgz#5a95aa454e6e002725c79055fd42aaba30ca6294" + integrity sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ== + uuid@9: version "9.0.1" resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" @@ -8713,10 +8717,10 @@ vinyl@^3.0.0, vinyl@~3.0.0: replace-ext "^2.0.0" teex "^1.0.1" -vite-node@1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/vite-node/-/vite-node-1.3.1.tgz#a93f7372212f5d5df38e945046b945ac3f4855d2" - integrity sha512-azbRrqRxlWTJEVbzInZCTchx0X69M/XPTCz4H+TLvlTcR/xH/3hkRqhOakT41fMJCMzXTu4UvegkZiEoJAWvng== +vite-node@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/vite-node/-/vite-node-1.6.0.tgz#2c7e61129bfecc759478fa592754fd9704aaba7f" + integrity sha512-de6HJgzC+TFzOu0NTC4RAIsyf/DY/ibWDYQUcuEA84EMHhcefTUGkjFHKKEJhQN4A+6I0u++kr3l36ZF2d7XRw== dependencies: cac "^6.7.14" debug "^4.3.4" @@ -8752,15 +8756,15 @@ vite@^5.0.0: fsevents "~2.3.3" vitest@^1.2.2: - version "1.3.1" - resolved "https://registry.yarnpkg.com/vitest/-/vitest-1.3.1.tgz#2d7e9861f030d88a4669392a4aecb40569d90937" - integrity sha512-/1QJqXs8YbCrfv/GPQ05wAZf2eakUPLPa18vkJAKE7RXOKfVHqMZZ1WlTjiwl6Gcn65M5vpNUB6EFLnEdRdEXQ== + version "1.6.0" + resolved "https://registry.yarnpkg.com/vitest/-/vitest-1.6.0.tgz#9d5ad4752a3c451be919e412c597126cffb9892f" + integrity sha512-H5r/dN06swuFnzNFhq/dnz37bPXnq8xB2xB5JOVk8K09rUtoeNN+LHWkoQ0A/i3hvbUKKcCei9KpbxqHMLhLLA== dependencies: - "@vitest/expect" "1.3.1" - "@vitest/runner" "1.3.1" - "@vitest/snapshot" "1.3.1" - "@vitest/spy" "1.3.1" - "@vitest/utils" "1.3.1" + "@vitest/expect" "1.6.0" + "@vitest/runner" "1.6.0" + "@vitest/snapshot" "1.6.0" + "@vitest/spy" "1.6.0" + "@vitest/utils" "1.6.0" acorn-walk "^8.3.2" chai "^4.3.10" debug "^4.3.4" @@ -8772,9 +8776,9 @@ vitest@^1.2.2: std-env "^3.5.0" strip-literal "^2.0.0" tinybench "^2.5.1" - tinypool "^0.8.2" + tinypool "^0.8.3" vite "^5.0.0" - vite-node "1.3.1" + vite-node "1.6.0" why-is-node-running "^2.2.2" void-elements@3.1.0: