mirror of
https://github.com/vector-im/element-call.git
synced 2026-01-30 03:15:55 +00:00
Use the New MatrixRTCSession MembershipManager (#3015)
* provide option to use the New MembershipManager * fix cryptoApi import change * add error screen * bump js-sdk * rename to `setUnrecoverableError` and remove onLeave call because that will be handled by an effect. * this was doing nothing (it is a fragment back when there was no deprecated `rtcSession.room`) * rename to error * Update src/utils/errors.ts Co-authored-by: Hugh Nimmo-Smith <hughns@users.noreply.github.com> * Update src/utils/errors.ts Co-authored-by: Hugh Nimmo-Smith <hughns@users.noreply.github.com> * review * bump js-sdk * expose lk log level changing in `window` * bump js-sdk - always log "Missing own membership: force re-join" - also check insertions queue * change lk log level to warn * Bump js-sdk * Bump js-sdk * . * Bump js-sdk * show user count based on meberships not users. Signed-off-by: Timo K <toger5@hotmail.de> * bump js-sdk * rename setting name * remove unused import * js sdk bump * remove `window.setLKLogLevel` * bump js sdk with reverted incompatible change * bump js-sdk with one less merge --------- Signed-off-by: Timo K <toger5@hotmail.de> Co-authored-by: Hugh Nimmo-Smith <hughns@users.noreply.github.com> Co-authored-by: Hugh Nimmo-Smith <hughns@element.io>
This commit is contained in:
@@ -70,7 +70,8 @@
|
||||
"livekit_sfu": "LiveKit SFU: {{url}}",
|
||||
"matrix_id": "Matrix ID: {{id}}",
|
||||
"show_connection_stats": "Show connection statistics",
|
||||
"show_non_member_tiles": "Show tiles for non-member media"
|
||||
"show_non_member_tiles": "Show tiles for non-member media",
|
||||
"use_new_membership_manager": "Use the new implementation of the call MembershipManager"
|
||||
},
|
||||
"disconnected_banner": "Connectivity to the server has been lost.",
|
||||
"error": {
|
||||
|
||||
@@ -91,7 +91,7 @@
|
||||
"livekit-client": "^2.5.7",
|
||||
"lodash-es": "^4.17.21",
|
||||
"loglevel": "^1.9.1",
|
||||
"matrix-js-sdk": "^36.1.0",
|
||||
"matrix-js-sdk": "github:matrix-org/matrix-js-sdk#0cdb07544d9926cf0855a76ca5cc7dab253bdb24",
|
||||
"matrix-widget-api": "1.11.0",
|
||||
"normalize.css": "^8.0.1",
|
||||
"observable-hooks": "^4.2.3",
|
||||
|
||||
@@ -16,12 +16,15 @@ import {
|
||||
} from "react";
|
||||
import { type MatrixClient } from "matrix-js-sdk/src/client";
|
||||
import {
|
||||
Room as LivekitRoom,
|
||||
isE2EESupported as isE2EESupportedBrowser,
|
||||
Room,
|
||||
} from "livekit-client";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
import { type MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession";
|
||||
import { JoinRule } from "matrix-js-sdk/src/matrix";
|
||||
import {
|
||||
MatrixRTCSessionEvent,
|
||||
type MatrixRTCSession,
|
||||
} from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession";
|
||||
import { JoinRule, type Room } from "matrix-js-sdk/src/matrix";
|
||||
import {
|
||||
OfflineIcon,
|
||||
WebBrowserIcon,
|
||||
@@ -66,8 +69,14 @@ import {
|
||||
ElementCallError,
|
||||
ErrorCategory,
|
||||
ErrorCode,
|
||||
RTCSessionError,
|
||||
} from "../utils/errors.ts";
|
||||
import { ElementCallRichError } from "../RichError.tsx";
|
||||
import {
|
||||
useNewMembershipManagerSetting as useNewMembershipManagerSetting,
|
||||
useSetting,
|
||||
} from "../settings/settings";
|
||||
import { useTypedEventEmitter } from "../useEvents";
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
@@ -126,6 +135,18 @@ export const GroupCallView: FC<Props> = ({
|
||||
};
|
||||
}, [rtcSession]);
|
||||
|
||||
useTypedEventEmitter(
|
||||
rtcSession,
|
||||
MatrixRTCSessionEvent.MembershipManagerError,
|
||||
(error) => {
|
||||
setError(
|
||||
new RTCSessionError(
|
||||
ErrorCode.MEMBERSHIP_MANAGER_UNRECOVERABLE,
|
||||
error.message ?? error,
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
useEffect(() => {
|
||||
// Sanity check the room object
|
||||
if (client.getRoom(rtcSession.room.roomId) !== rtcSession.room)
|
||||
@@ -134,11 +155,14 @@ export const GroupCallView: FC<Props> = ({
|
||||
);
|
||||
}, [client, rtcSession.room]);
|
||||
|
||||
const room = rtcSession.room as Room;
|
||||
const { displayName, avatarUrl } = useProfile(client);
|
||||
const roomName = useRoomName(rtcSession.room);
|
||||
const roomAvatar = useRoomAvatar(rtcSession.room);
|
||||
const roomName = useRoomName(room);
|
||||
const roomAvatar = useRoomAvatar(room);
|
||||
const { perParticipantE2EE, returnToLobby } = useUrlParams();
|
||||
const e2eeSystem = useRoomEncryptionSystem(rtcSession.room.roomId);
|
||||
const e2eeSystem = useRoomEncryptionSystem(room.roomId);
|
||||
const [useNewMembershipManager] = useSetting(useNewMembershipManagerSetting);
|
||||
|
||||
usePageTitle(roomName);
|
||||
|
||||
const matrixInfo = useMemo((): MatrixInfo => {
|
||||
@@ -146,21 +170,13 @@ export const GroupCallView: FC<Props> = ({
|
||||
userId: client.getUserId()!,
|
||||
displayName: displayName!,
|
||||
avatarUrl: avatarUrl!,
|
||||
roomId: rtcSession.room.roomId,
|
||||
roomId: room.roomId,
|
||||
roomName,
|
||||
roomAlias: rtcSession.room.getCanonicalAlias(),
|
||||
roomAlias: room.getCanonicalAlias(),
|
||||
roomAvatar,
|
||||
e2eeSystem,
|
||||
};
|
||||
}, [
|
||||
client,
|
||||
displayName,
|
||||
avatarUrl,
|
||||
rtcSession.room,
|
||||
roomName,
|
||||
roomAvatar,
|
||||
e2eeSystem,
|
||||
]);
|
||||
}, [client, displayName, avatarUrl, roomName, room, roomAvatar, e2eeSystem]);
|
||||
|
||||
// Count each member only once, regardless of how many devices they use
|
||||
const participantCount = useMemo(
|
||||
@@ -175,13 +191,18 @@ export const GroupCallView: FC<Props> = ({
|
||||
const enterRTCSessionOrError = async (
|
||||
rtcSession: MatrixRTCSession,
|
||||
perParticipantE2EE: boolean,
|
||||
newMembershipManager: boolean,
|
||||
): Promise<void> => {
|
||||
try {
|
||||
await enterRTCSession(rtcSession, perParticipantE2EE);
|
||||
await enterRTCSession(
|
||||
rtcSession,
|
||||
perParticipantE2EE,
|
||||
newMembershipManager,
|
||||
);
|
||||
} catch (e) {
|
||||
if (e instanceof ElementCallError) {
|
||||
// e.code === ErrorCode.MISSING_LIVE_KIT_SERVICE_URL)
|
||||
setEnterRTCError(e);
|
||||
setError(e);
|
||||
} else {
|
||||
logger.error(`Unknown Error while entering RTC session`, e);
|
||||
const error = new ElementCallError(
|
||||
@@ -189,7 +210,7 @@ export const GroupCallView: FC<Props> = ({
|
||||
ErrorCode.UNKNOWN_ERROR,
|
||||
ErrorCategory.UNKNOWN,
|
||||
);
|
||||
setEnterRTCError(error);
|
||||
setError(error);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -203,7 +224,7 @@ export const GroupCallView: FC<Props> = ({
|
||||
// permissions and give you device names unless you specify a kind, but
|
||||
// here we want all kinds of devices. This needs a fix in livekit-client
|
||||
// for the following name-matching logic to do anything useful.
|
||||
const devices = await Room.getLocalDevices(undefined, true);
|
||||
const devices = await LivekitRoom.getLocalDevices(undefined, true);
|
||||
|
||||
if (audioInput) {
|
||||
const deviceId = findDeviceByName(audioInput, "audioinput", devices);
|
||||
@@ -243,7 +264,11 @@ export const GroupCallView: FC<Props> = ({
|
||||
await defaultDeviceSetup(
|
||||
ev.detail.data as unknown as JoinCallData,
|
||||
);
|
||||
await enterRTCSessionOrError(rtcSession, perParticipantE2EE);
|
||||
await enterRTCSessionOrError(
|
||||
rtcSession,
|
||||
perParticipantE2EE,
|
||||
useNewMembershipManager,
|
||||
);
|
||||
widget.api.transport.reply(ev.detail, {});
|
||||
})().catch((e) => {
|
||||
logger.error("Error joining RTC session", e);
|
||||
@@ -256,13 +281,21 @@ export const GroupCallView: FC<Props> = ({
|
||||
} else {
|
||||
// No lobby and no preload: we enter the rtc session right away
|
||||
(async (): Promise<void> => {
|
||||
await enterRTCSessionOrError(rtcSession, perParticipantE2EE);
|
||||
await enterRTCSessionOrError(
|
||||
rtcSession,
|
||||
perParticipantE2EE,
|
||||
useNewMembershipManager,
|
||||
);
|
||||
})().catch((e) => {
|
||||
logger.error("Error joining RTC session", e);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
void enterRTCSessionOrError(rtcSession, perParticipantE2EE);
|
||||
void enterRTCSessionOrError(
|
||||
rtcSession,
|
||||
perParticipantE2EE,
|
||||
useNewMembershipManager,
|
||||
);
|
||||
}
|
||||
}
|
||||
}, [
|
||||
@@ -273,12 +306,11 @@ export const GroupCallView: FC<Props> = ({
|
||||
perParticipantE2EE,
|
||||
latestDevices,
|
||||
latestMuteStates,
|
||||
useNewMembershipManager,
|
||||
]);
|
||||
|
||||
const [left, setLeft] = useState(false);
|
||||
const [enterRTCError, setEnterRTCError] = useState<ElementCallError | null>(
|
||||
null,
|
||||
);
|
||||
const [error, setError] = useState<ElementCallError | null>(null);
|
||||
const navigate = useNavigate();
|
||||
|
||||
const onLeave = useCallback(
|
||||
@@ -292,7 +324,7 @@ export const GroupCallView: FC<Props> = ({
|
||||
// Otherwise the iFrame gets killed before the callEnded event got tracked.
|
||||
const posthogRequest = new Promise((resolve) => {
|
||||
PosthogAnalytics.instance.eventCallEnded.track(
|
||||
rtcSession.room.roomId,
|
||||
room.roomId,
|
||||
rtcSession.memberships.length,
|
||||
sendInstantly,
|
||||
rtcSession,
|
||||
@@ -321,11 +353,12 @@ export const GroupCallView: FC<Props> = ({
|
||||
});
|
||||
},
|
||||
[
|
||||
leaveSoundContext,
|
||||
widget,
|
||||
rtcSession,
|
||||
room.roomId,
|
||||
isPasswordlessUser,
|
||||
confineToRoom,
|
||||
leaveSoundContext,
|
||||
navigate,
|
||||
],
|
||||
);
|
||||
@@ -351,7 +384,7 @@ export const GroupCallView: FC<Props> = ({
|
||||
}
|
||||
}, [widget, isJoined, rtcSession]);
|
||||
|
||||
const joinRule = useJoinRule(rtcSession.room);
|
||||
const joinRule = useJoinRule(room);
|
||||
|
||||
const [shareModalOpen, setInviteModalOpen] = useState(false);
|
||||
const onDismissInviteModal = useCallback(
|
||||
@@ -379,8 +412,12 @@ export const GroupCallView: FC<Props> = ({
|
||||
const onReconnect = useCallback(() => {
|
||||
setLeft(false);
|
||||
resetError();
|
||||
enterRTCSessionOrError(rtcSession, perParticipantE2EE).catch((e) => {
|
||||
logger.error("Error re-entering RTC session", e);
|
||||
enterRTCSessionOrError(
|
||||
rtcSession,
|
||||
perParticipantE2EE,
|
||||
useNewMembershipManager,
|
||||
).catch((e) => {
|
||||
logger.error("Error re-entering RTC session on reconnect", e);
|
||||
});
|
||||
}, [resetError]);
|
||||
|
||||
@@ -402,7 +439,7 @@ export const GroupCallView: FC<Props> = ({
|
||||
);
|
||||
}
|
||||
return GroupCallErrorPage;
|
||||
}, [onLeave, rtcSession, perParticipantE2EE, t]);
|
||||
}, [t, rtcSession, onLeave, perParticipantE2EE, useNewMembershipManager]);
|
||||
|
||||
if (!isE2EESupportedBrowser() && e2eeSystem.kind !== E2eeType.NONE) {
|
||||
// If we have a encryption system but the browser does not support it.
|
||||
@@ -417,7 +454,7 @@ export const GroupCallView: FC<Props> = ({
|
||||
|
||||
const shareModal = (
|
||||
<InviteModal
|
||||
room={rtcSession.room}
|
||||
room={room}
|
||||
open={shareModalOpen}
|
||||
onDismiss={onDismissInviteModal}
|
||||
/>
|
||||
@@ -430,7 +467,11 @@ export const GroupCallView: FC<Props> = ({
|
||||
matrixInfo={matrixInfo}
|
||||
muteStates={muteStates}
|
||||
onEnter={() =>
|
||||
void enterRTCSessionOrError(rtcSession, perParticipantE2EE)
|
||||
void enterRTCSessionOrError(
|
||||
rtcSession,
|
||||
perParticipantE2EE,
|
||||
useNewMembershipManager,
|
||||
)
|
||||
}
|
||||
confineToRoom={confineToRoom}
|
||||
hideHeader={hideHeader}
|
||||
@@ -441,11 +482,11 @@ export const GroupCallView: FC<Props> = ({
|
||||
);
|
||||
|
||||
let body: ReactNode;
|
||||
if (enterRTCError) {
|
||||
if (error) {
|
||||
// If an ElementCallError was recorded, then create a component that will fail to render and throw
|
||||
// an ElementCallRichError error. This will then be handled by the ErrorBoundary component.
|
||||
const ErrorComponent = (): ReactNode => {
|
||||
throw new ElementCallRichError(enterRTCError);
|
||||
throw new ElementCallRichError(error);
|
||||
};
|
||||
body = <ErrorComponent />;
|
||||
} else if (isJoined) {
|
||||
|
||||
@@ -111,6 +111,7 @@ test("It joins the correct Session", async () => {
|
||||
{
|
||||
manageMediaKeys: false,
|
||||
useLegacyMemberEvents: false,
|
||||
useNewMembershipManager: true,
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -97,6 +97,7 @@ async function makePreferredLivekitFoci(
|
||||
export async function enterRTCSession(
|
||||
rtcSession: MatrixRTCSession,
|
||||
encryptMedia: boolean,
|
||||
useNewMembershipManager = true,
|
||||
): Promise<void> {
|
||||
PosthogAnalytics.instance.eventCallEnded.cacheStartCall(new Date());
|
||||
PosthogAnalytics.instance.eventCallStarted.track(rtcSession.room.roomId);
|
||||
@@ -114,6 +115,7 @@ export async function enterRTCSession(
|
||||
await makePreferredLivekitFoci(rtcSession, livekitAlias),
|
||||
makeActiveFocus(),
|
||||
{
|
||||
useNewMembershipManager,
|
||||
manageMediaKeys: encryptMedia,
|
||||
...(useDeviceSessionMemberEvents !== undefined && {
|
||||
useLegacyMemberEvents: !useDeviceSessionMemberEvents,
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
debugTileLayout as debugTileLayoutSetting,
|
||||
showNonMemberTiles as showNonMemberTilesSetting,
|
||||
showConnectionStats as showConnectionStatsSetting,
|
||||
useNewMembershipManagerSetting,
|
||||
} from "./settings";
|
||||
import type { MatrixClient } from "matrix-js-sdk/src/client";
|
||||
import type { Room as LivekitRoom } from "livekit-client";
|
||||
@@ -38,6 +39,10 @@ export const DeveloperSettingsTab: FC<Props> = ({ client, livekitRoom }) => {
|
||||
showConnectionStatsSetting,
|
||||
);
|
||||
|
||||
const [useNewMembershipManager, setNewMembershipManager] = useSetting(
|
||||
useNewMembershipManagerSetting,
|
||||
);
|
||||
|
||||
const sfuUrl = useMemo((): URL | null => {
|
||||
if (livekitRoom?.engine.client.ws?.url) {
|
||||
// strip the URL params
|
||||
@@ -134,6 +139,20 @@ export const DeveloperSettingsTab: FC<Props> = ({ client, livekitRoom }) => {
|
||||
)}
|
||||
/>
|
||||
</FieldRow>
|
||||
<FieldRow>
|
||||
<InputField
|
||||
id="useNewMembershipManager"
|
||||
type="checkbox"
|
||||
label={t("developer_mode.use_new_membership_manager")}
|
||||
checked={!!useNewMembershipManager}
|
||||
onChange={useCallback(
|
||||
(event: ChangeEvent<HTMLInputElement>): void => {
|
||||
setNewMembershipManager(event.target.checked);
|
||||
},
|
||||
[setNewMembershipManager],
|
||||
)}
|
||||
/>
|
||||
</FieldRow>
|
||||
{livekitRoom ? (
|
||||
<>
|
||||
<p>
|
||||
|
||||
@@ -113,4 +113,8 @@ export const soundEffectVolumeSetting = new Setting<number>(
|
||||
0.5,
|
||||
);
|
||||
|
||||
export const useNewMembershipManagerSetting = new Setting<boolean>(
|
||||
"new-membership-manager",
|
||||
true,
|
||||
);
|
||||
export const alwaysShowSelf = new Setting<boolean>("always-show-self", true);
|
||||
|
||||
@@ -9,10 +9,10 @@ import { type ComponentProps, useCallback, useEffect, useState } from "react";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
import {
|
||||
ClientEvent,
|
||||
type Crypto,
|
||||
type MatrixClient,
|
||||
type MatrixEvent,
|
||||
} from "matrix-js-sdk/src/matrix";
|
||||
import { type CryptoApi } from "matrix-js-sdk/src/crypto-api";
|
||||
|
||||
import { getLogsForReport } from "./rageshake";
|
||||
import { useClient } from "../ClientContext";
|
||||
@@ -34,7 +34,7 @@ const gzip = async (text: string): Promise<Blob> => {
|
||||
* Collects crypto related information.
|
||||
*/
|
||||
async function collectCryptoInfo(
|
||||
cryptoApi: Crypto.CryptoApi,
|
||||
cryptoApi: CryptoApi,
|
||||
body: FormData,
|
||||
): Promise<void> {
|
||||
body.append("crypto_version", cryptoApi.getVersion());
|
||||
@@ -82,7 +82,7 @@ async function collectCryptoInfo(
|
||||
*/
|
||||
async function collectRecoveryInfo(
|
||||
client: MatrixClient,
|
||||
cryptoApi: Crypto.CryptoApi,
|
||||
cryptoApi: CryptoApi,
|
||||
body: FormData,
|
||||
): Promise<void> {
|
||||
const secretStorage = client.secretStorage;
|
||||
|
||||
@@ -13,6 +13,7 @@ export enum ErrorCode {
|
||||
*/
|
||||
MISSING_MATRIX_RTC_FOCUS = "MISSING_MATRIX_RTC_FOCUS",
|
||||
CONNECTION_LOST_ERROR = "CONNECTION_LOST_ERROR",
|
||||
MEMBERSHIP_MANAGER_UNRECOVERABLE = "MEMBERSHIP_MANAGER_UNRECOVERABLE",
|
||||
UNKNOWN_ERROR = "UNKNOWN_ERROR",
|
||||
}
|
||||
|
||||
@@ -20,6 +21,7 @@ export enum ErrorCategory {
|
||||
/** Calling is not supported, server misconfigured (JWT service missing, no MSC support ...)*/
|
||||
CONFIGURATION_ISSUE = "CONFIGURATION_ISSUE",
|
||||
NETWORK_CONNECTIVITY = "NETWORK_CONNECTIVITY",
|
||||
RTC_SESSION_FAILURE = "RTC_SESSION_FAILURE",
|
||||
UNKNOWN = "UNKNOWN",
|
||||
// SYSTEM_FAILURE / FEDERATION_FAILURE ..
|
||||
}
|
||||
@@ -72,3 +74,9 @@ export class ConnectionLostError extends ElementCallError {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class RTCSessionError extends ElementCallError {
|
||||
public constructor(code: ErrorCode, message: string) {
|
||||
super("RTCSession Error", code, ErrorCategory.RTC_SESSION_FAILURE, message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ async function waitForSync(client: MatrixClient): Promise<void> {
|
||||
* otherwise rust crypto will throw since it is not ready to initialize a new session.
|
||||
* If another client is running make sure `.logout()` is called before executing this function.
|
||||
* @param clientOptions Object of options passed through to the client
|
||||
* @param restore If the rust crypto should be reset before the cient initialization or
|
||||
* @param restore If the rust crypto should be reset before the client initialization or
|
||||
* if the initialization should try to restore the crypto state from the indexDB.
|
||||
* @returns The MatrixClient instance
|
||||
*/
|
||||
@@ -160,7 +160,6 @@ export async function initClient(
|
||||
);
|
||||
}
|
||||
|
||||
client.setGlobalErrorOnUnknownDevices(false);
|
||||
// Once startClient is called, syncs are run asynchronously.
|
||||
// Also, sync completion is communicated only via events.
|
||||
// So, apply the event listener *before* starting the client.
|
||||
|
||||
17
yarn.lock
17
yarn.lock
@@ -1787,10 +1787,10 @@
|
||||
dependencies:
|
||||
"@bufbuild/protobuf" "^1.10.0"
|
||||
|
||||
"@matrix-org/matrix-sdk-crypto-wasm@^12.1.0":
|
||||
version "12.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@matrix-org/matrix-sdk-crypto-wasm/-/matrix-sdk-crypto-wasm-12.1.0.tgz#2aef64eab2d30c0a1ace9c0fe876f53aa2949f14"
|
||||
integrity sha512-NhJFu/8FOGjnW7mDssRUzaMSwXrYOcCqgAjZyAw9KQ9unNADKEi7KoIKe7GtrG2PWtm36y2bUf+hB8vhSY6Wdw==
|
||||
"@matrix-org/matrix-sdk-crypto-wasm@^14.0.1":
|
||||
version "14.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@matrix-org/matrix-sdk-crypto-wasm/-/matrix-sdk-crypto-wasm-14.0.1.tgz#e258ef84bcc7889f0e7eb3a7dbecf0830a6dd606"
|
||||
integrity sha512-CgLpHs6nTw5pjSsMBi9xbQnBXf2l8YhImQP9cv8nbGSCYdYjFI0FilMXffzjWV5HThpNHri/3pF20ahZtuS3VA==
|
||||
|
||||
"@matrix-org/olm@3.2.15":
|
||||
version "3.2.15"
|
||||
@@ -6334,13 +6334,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@^36.1.0:
|
||||
version "36.1.0"
|
||||
resolved "https://registry.yarnpkg.com/matrix-js-sdk/-/matrix-js-sdk-36.1.0.tgz#3685a85c0c1adf4e2c3622bce76c11430963f23d"
|
||||
integrity sha512-KNPswMSAGKDxBybJedxRpWadaRes9paxmjTCUsQT8t1Jg3ZENraAt6ynIaxh6PxazAH9D5ly6EYKHaLMLbZ1Dg==
|
||||
"matrix-js-sdk@github:matrix-org/matrix-js-sdk#0cdb07544d9926cf0855a76ca5cc7dab253bdb24":
|
||||
version "37.0.0"
|
||||
resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/0cdb07544d9926cf0855a76ca5cc7dab253bdb24"
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.12.5"
|
||||
"@matrix-org/matrix-sdk-crypto-wasm" "^12.1.0"
|
||||
"@matrix-org/matrix-sdk-crypto-wasm" "^14.0.1"
|
||||
"@matrix-org/olm" "3.2.15"
|
||||
another-json "^0.2.0"
|
||||
bs58 "^6.0.0"
|
||||
|
||||
Reference in New Issue
Block a user