Iterate in pairing session
This commit is contained in:
@@ -108,7 +108,7 @@
|
|||||||
"livekit-client": "^2.13.0",
|
"livekit-client": "^2.13.0",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"loglevel": "^1.9.1",
|
"loglevel": "^1.9.1",
|
||||||
"matrix-js-sdk": "github:matrix-org/matrix-js-sdk#head=toger5/membership-manager-likely-disconnected",
|
"matrix-js-sdk": "github:matrix-org/matrix-js-sdk#head=develop",
|
||||||
"matrix-widget-api": "^1.13.0",
|
"matrix-widget-api": "^1.13.0",
|
||||||
"normalize.css": "^8.0.1",
|
"normalize.css": "^8.0.1",
|
||||||
"observable-hooks": "^4.2.3",
|
"observable-hooks": "^4.2.3",
|
||||||
|
|||||||
@@ -122,6 +122,8 @@ test("plays no sound when the participant list is more than the maximum size", (
|
|||||||
|
|
||||||
render(<CallEventAudioRenderer vm={vm} />);
|
render(<CallEventAudioRenderer vm={vm} />);
|
||||||
expect(playSound).not.toBeCalled();
|
expect(playSound).not.toBeCalled();
|
||||||
|
// Remove the last membership in the array to test the leaving sound
|
||||||
|
// (The array has length MAX_PARTICIPANT_COUNT_FOR_SOUND + 1)
|
||||||
act(() => {
|
act(() => {
|
||||||
rtcMemberships$.next(
|
rtcMemberships$.next(
|
||||||
mockRtcMemberships.slice(0, MAX_PARTICIPANT_COUNT_FOR_SOUND),
|
mockRtcMemberships.slice(0, MAX_PARTICIPANT_COUNT_FOR_SOUND),
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import {
|
|||||||
of,
|
of,
|
||||||
switchMap,
|
switchMap,
|
||||||
} from "rxjs";
|
} from "rxjs";
|
||||||
import { type MatrixClient } from "matrix-js-sdk";
|
import { SyncState, type MatrixClient } from "matrix-js-sdk";
|
||||||
import {
|
import {
|
||||||
ConnectionState,
|
ConnectionState,
|
||||||
type LocalParticipant,
|
type LocalParticipant,
|
||||||
@@ -48,6 +48,7 @@ import {
|
|||||||
mockRtcMembership,
|
mockRtcMembership,
|
||||||
MockRTCSession,
|
MockRTCSession,
|
||||||
mockMediaDevices,
|
mockMediaDevices,
|
||||||
|
mockEmitter,
|
||||||
} from "../utils/test";
|
} from "../utils/test";
|
||||||
import {
|
import {
|
||||||
ECAddonConnectionState,
|
ECAddonConnectionState,
|
||||||
@@ -240,6 +241,7 @@ function withCallViewModel(
|
|||||||
mediaDevices: MediaDevices,
|
mediaDevices: MediaDevices,
|
||||||
continuation: (
|
continuation: (
|
||||||
vm: CallViewModel,
|
vm: CallViewModel,
|
||||||
|
rtcSession: MockRTCSession,
|
||||||
subjects: { raisedHands$: BehaviorSubject<Record<string, RaisedHandInfo>> },
|
subjects: { raisedHands$: BehaviorSubject<Record<string, RaisedHandInfo>> },
|
||||||
) => void,
|
) => void,
|
||||||
options: CallViewModelOptions = {
|
options: CallViewModelOptions = {
|
||||||
@@ -249,8 +251,10 @@ function withCallViewModel(
|
|||||||
): void {
|
): void {
|
||||||
const room = mockMatrixRoom({
|
const room = mockMatrixRoom({
|
||||||
client: {
|
client: {
|
||||||
|
...mockEmitter(),
|
||||||
getUserId: () => localRtcMember.sender,
|
getUserId: () => localRtcMember.sender,
|
||||||
getDeviceId: () => localRtcMember.deviceId,
|
getDeviceId: () => localRtcMember.deviceId,
|
||||||
|
getSyncState: () => SyncState.Syncing,
|
||||||
} as Partial<MatrixClient> as MatrixClient,
|
} as Partial<MatrixClient> as MatrixClient,
|
||||||
getMember: (userId) => roomMembers.get(userId) ?? null,
|
getMember: (userId) => roomMembers.get(userId) ?? null,
|
||||||
});
|
});
|
||||||
@@ -307,7 +311,7 @@ function withCallViewModel(
|
|||||||
roomEventSelectorSpy!.mockRestore();
|
roomEventSelectorSpy!.mockRestore();
|
||||||
});
|
});
|
||||||
|
|
||||||
continuation(vm, { raisedHands$: raisedHands$ });
|
continuation(vm, rtcSession, { raisedHands$: raisedHands$ });
|
||||||
}
|
}
|
||||||
|
|
||||||
test("participants are retained during a focus switch", () => {
|
test("participants are retained during a focus switch", () => {
|
||||||
@@ -976,7 +980,7 @@ it("should rank raised hands above video feeds and below speakers and presenters
|
|||||||
of(ConnectionState.Connected),
|
of(ConnectionState.Connected),
|
||||||
new Map(),
|
new Map(),
|
||||||
mockMediaDevices({}),
|
mockMediaDevices({}),
|
||||||
(vm, { raisedHands$ }) => {
|
(vm, _rtcSession, { raisedHands$ }) => {
|
||||||
schedule("ab", {
|
schedule("ab", {
|
||||||
a: () => {
|
a: () => {
|
||||||
// We imagine that only two tiles (the first two) will be visible on screen at a time
|
// We imagine that only two tiles (the first two) will be visible on screen at a time
|
||||||
@@ -1240,7 +1244,7 @@ test("audio output changes when toggling earpiece mode", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test("media tracks are paused while reconnecting to MatrixRTC", () => {
|
test("media tracks are paused while reconnecting to MatrixRTC", () => {
|
||||||
withTestScheduler(({ behavior, schedule, expectObservable }) => {
|
withTestScheduler(({ schedule, expectObservable }) => {
|
||||||
const trackRunning$ = new BehaviorSubject(true);
|
const trackRunning$ = new BehaviorSubject(true);
|
||||||
const originalPublications = localParticipant.trackPublications;
|
const originalPublications = localParticipant.trackPublications;
|
||||||
localParticipant.trackPublications = new Map([
|
localParticipant.trackPublications = new Map([
|
||||||
@@ -1267,17 +1271,26 @@ test("media tracks are paused while reconnecting to MatrixRTC", () => {
|
|||||||
localParticipant.trackPublications = originalPublications;
|
localParticipant.trackPublications = originalPublications;
|
||||||
});
|
});
|
||||||
|
|
||||||
const rtcMemberMarbles = " aba";
|
// TODO: Add marbles for sync state and membership status as well
|
||||||
|
const connectedMarbles = " yny";
|
||||||
const expectedReconnectingMarbles = "nyn";
|
const expectedReconnectingMarbles = "nyn";
|
||||||
const expectedTrackRunningMarbles = "yny";
|
const expectedTrackRunningMarbles = "yny";
|
||||||
|
|
||||||
withCallViewModel(
|
withCallViewModel(
|
||||||
constant([]),
|
constant([]),
|
||||||
behavior(rtcMemberMarbles, { a: [localRtcMember], b: [] }),
|
constant([localRtcMember]),
|
||||||
of(ConnectionState.Connected),
|
of(ConnectionState.Connected),
|
||||||
new Map(),
|
new Map(),
|
||||||
mockMediaDevices({}),
|
mockMediaDevices({}),
|
||||||
(vm) => {
|
(vm, rtcSession) => {
|
||||||
|
schedule(connectedMarbles, {
|
||||||
|
y: () => {
|
||||||
|
rtcSession.probablyLeft = false;
|
||||||
|
},
|
||||||
|
n: () => {
|
||||||
|
rtcSession.probablyLeft = true;
|
||||||
|
},
|
||||||
|
});
|
||||||
expectObservable(vm.reconnecting$).toBe(
|
expectObservable(vm.reconnecting$).toBe(
|
||||||
expectedReconnectingMarbles,
|
expectedReconnectingMarbles,
|
||||||
yesNo,
|
yesNo,
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ import {
|
|||||||
type MatrixRTCSession,
|
type MatrixRTCSession,
|
||||||
MatrixRTCSessionEvent,
|
MatrixRTCSessionEvent,
|
||||||
MembershipManagerEvent,
|
MembershipManagerEvent,
|
||||||
|
Status,
|
||||||
} from "matrix-js-sdk/lib/matrixrtc";
|
} from "matrix-js-sdk/lib/matrixrtc";
|
||||||
|
|
||||||
import { ViewModel } from "./ViewModel";
|
import { ViewModel } from "./ViewModel";
|
||||||
@@ -407,17 +408,6 @@ function getRoomMemberFromRtcMember(
|
|||||||
// TODO: Move wayyyy more business logic from the call and lobby views into here
|
// TODO: Move wayyyy more business logic from the call and lobby views into here
|
||||||
export class CallViewModel extends ViewModel {
|
export class CallViewModel extends ViewModel {
|
||||||
private readonly userId = this.matrixRoom.client.getUserId();
|
private readonly userId = this.matrixRoom.client.getUserId();
|
||||||
private readonly deviceId = this.matrixRoom.client.getDeviceId();
|
|
||||||
|
|
||||||
private readonly memberships$: Observable<CallMembership[]> = merge(
|
|
||||||
// Handle call membership changes.
|
|
||||||
fromEvent(this.matrixRTCSession, MatrixRTCSessionEvent.MembershipsChanged),
|
|
||||||
// Handle room membership changes (and displayname updates)
|
|
||||||
fromEvent(this.matrixRoom, RoomStateEvent.Members),
|
|
||||||
).pipe(
|
|
||||||
startWith(null),
|
|
||||||
map(() => this.matrixRTCSession.memberships),
|
|
||||||
);
|
|
||||||
|
|
||||||
private readonly matrixConnected$ = this.scope.behavior(
|
private readonly matrixConnected$ = this.scope.behavior(
|
||||||
// To consider ourselves connected to MatrixRTC, we check the following:
|
// To consider ourselves connected to MatrixRTC, we check the following:
|
||||||
@@ -431,26 +421,24 @@ export class CallViewModel extends ViewModel {
|
|||||||
startWith([this.matrixRoom.client.getSyncState()]),
|
startWith([this.matrixRoom.client.getSyncState()]),
|
||||||
map(([state]) => state === SyncState.Syncing),
|
map(([state]) => state === SyncState.Syncing),
|
||||||
),
|
),
|
||||||
// We can see our own call membership
|
// Room state observed by session says we're connected
|
||||||
this.memberships$.pipe(
|
fromEvent(
|
||||||
map((ms) =>
|
this.matrixRTCSession,
|
||||||
ms.some(
|
MembershipManagerEvent.StatusChanged,
|
||||||
(m) => m.sender === this.userId && m.deviceId === this.deviceId,
|
).pipe(
|
||||||
),
|
startWith(null),
|
||||||
),
|
map(() => this.matrixRTCSession.membershipStatus === Status.Connected),
|
||||||
),
|
),
|
||||||
// Also watch out for warnings that we've likely hit a timeout and our
|
// Also watch out for warnings that we've likely hit a timeout and our
|
||||||
// delayed leave event is being sent (this condition is here because it
|
// delayed leave event is being sent (this condition is here because it
|
||||||
// provides an earlier warning than the sync loop timeout, and we wouldn't
|
// provides an earlier warning than the sync loop timeout, and we wouldn't
|
||||||
// see the actual leave event until we reconnect to the sync loop)
|
// see the actual leave event until we reconnect to the sync loop)
|
||||||
(
|
fromEvent(
|
||||||
fromEvent(
|
this.matrixRTCSession,
|
||||||
this.matrixRTCSession,
|
MembershipManagerEvent.ProbablyLeft,
|
||||||
MembershipManagerEvent.ProbablyLeft,
|
|
||||||
) as Observable<[SyncState]>
|
|
||||||
).pipe(
|
).pipe(
|
||||||
startWith([false]),
|
startWith(null),
|
||||||
map(([probablyLeft]) => !probablyLeft),
|
map(() => this.matrixRTCSession.probablyLeft !== true),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -576,8 +564,18 @@ export class CallViewModel extends ViewModel {
|
|||||||
// than on Chrome/Firefox). This means it is important that we multicast the result so that we
|
// than on Chrome/Firefox). This means it is important that we multicast the result so that we
|
||||||
// don't do this work more times than we need to. This is achieved by converting to a behavior:
|
// don't do this work more times than we need to. This is achieved by converting to a behavior:
|
||||||
public readonly memberDisplaynames$ = this.scope.behavior(
|
public readonly memberDisplaynames$ = this.scope.behavior(
|
||||||
this.memberships$.pipe(
|
merge(
|
||||||
map((memberships) => {
|
// Handle call membership changes.
|
||||||
|
fromEvent(
|
||||||
|
this.matrixRTCSession,
|
||||||
|
MatrixRTCSessionEvent.MembershipsChanged,
|
||||||
|
),
|
||||||
|
// Handle room membership changes (and displayname updates)
|
||||||
|
fromEvent(this.matrixRoom, RoomStateEvent.Members),
|
||||||
|
).pipe(
|
||||||
|
startWith(null),
|
||||||
|
map(() => {
|
||||||
|
const memberships = this.matrixRTCSession.memberships;
|
||||||
const displaynameMap = new Map<string, string>();
|
const displaynameMap = new Map<string, string>();
|
||||||
const room = this.matrixRoom;
|
const room = this.matrixRoom;
|
||||||
|
|
||||||
@@ -1592,9 +1590,12 @@ export class CallViewModel extends ViewModel {
|
|||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
// Pause all media tracks when we're disconnected from MatrixRTC, because it
|
// Pause upstream of all local media tracks when we're disconnected from
|
||||||
// can be an unpleasant surprise for the app to say 'reconnecting' and yet
|
// MatrixRTC, because it can be an unpleasant surprise for the app to say
|
||||||
// still be transmitting your media to others.
|
// 'reconnecting' and yet still be transmitting your media to others.
|
||||||
|
// We use matrixConnected$ rather than reconnecting$ because we want to
|
||||||
|
// pause tracks during the initial joining sequence too until we're sure
|
||||||
|
// that our own media is displayed on screen.
|
||||||
this.matrixConnected$.pipe(this.scope.bind()).subscribe((connected) => {
|
this.matrixConnected$.pipe(this.scope.bind()).subscribe((connected) => {
|
||||||
const publications =
|
const publications =
|
||||||
this.livekitRoom.localParticipant.trackPublications.values();
|
this.livekitRoom.localParticipant.trackPublications.values();
|
||||||
@@ -1602,7 +1603,9 @@ export class CallViewModel extends ViewModel {
|
|||||||
for (const p of publications) {
|
for (const p of publications) {
|
||||||
if (p.track?.isUpstreamPaused === true) {
|
if (p.track?.isUpstreamPaused === true) {
|
||||||
const kind = p.track.kind;
|
const kind = p.track.kind;
|
||||||
logger.log(`Reconnected to MatrixRTC; resuming ${kind} track`);
|
logger.log(
|
||||||
|
`Resumming ${kind} track (MatrixRTC connection present)`,
|
||||||
|
);
|
||||||
p.track
|
p.track
|
||||||
.resumeUpstream()
|
.resumeUpstream()
|
||||||
.catch((e) =>
|
.catch((e) =>
|
||||||
@@ -1617,7 +1620,7 @@ export class CallViewModel extends ViewModel {
|
|||||||
for (const p of publications) {
|
for (const p of publications) {
|
||||||
if (p.track?.isUpstreamPaused === false) {
|
if (p.track?.isUpstreamPaused === false) {
|
||||||
const kind = p.track.kind;
|
const kind = p.track.kind;
|
||||||
logger.log(`Lost connection to MatrixRTC; pausing ${kind} track`);
|
logger.log(`Pausing ${kind} track (no MatrixRTC connection)`);
|
||||||
p.track
|
p.track
|
||||||
.pauseUpstream()
|
.pauseUpstream()
|
||||||
.catch((e) =>
|
.catch((e) =>
|
||||||
|
|||||||
@@ -626,17 +626,6 @@ export class RemoteUserMediaViewModel extends BaseUserMediaViewModel {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
|
||||||
* The local volume, taking into account whether we're supposed to pretend
|
|
||||||
* that the audio stream is disconnected (since we don't necessarily want that
|
|
||||||
* to modify the UI state).
|
|
||||||
*/
|
|
||||||
private readonly actualLocalVolume$ = this.scope.behavior(
|
|
||||||
this.pretendToBeDisconnected$.pipe(
|
|
||||||
switchMap((disconnected) => (disconnected ? of(0) : this.localVolume$)),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
// This private field is used to override the value from the superclass
|
// This private field is used to override the value from the superclass
|
||||||
private __videoEnabled$: Behavior<boolean>;
|
private __videoEnabled$: Behavior<boolean>;
|
||||||
public get videoEnabled$(): Behavior<boolean> {
|
public get videoEnabled$(): Behavior<boolean> {
|
||||||
@@ -691,7 +680,13 @@ export class RemoteUserMediaViewModel extends BaseUserMediaViewModel {
|
|||||||
// Sync the local volume with LiveKit
|
// Sync the local volume with LiveKit
|
||||||
combineLatest([
|
combineLatest([
|
||||||
participant$,
|
participant$,
|
||||||
this.actualLocalVolume$.pipe(this.scope.bind()),
|
// The local volume, taking into account whether we're supposed to pretend
|
||||||
|
// that the audio stream is disconnected (since we don't necessarily want
|
||||||
|
// that to modify the UI state).
|
||||||
|
this.pretendToBeDisconnected$.pipe(
|
||||||
|
switchMap((disconnected) => (disconnected ? of(0) : this.localVolume$)),
|
||||||
|
this.scope.bind(),
|
||||||
|
),
|
||||||
]).subscribe(([p, volume]) => p?.setVolume(volume));
|
]).subscribe(([p, volume]) => p?.setVolume(volume));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,8 @@ import {
|
|||||||
tap,
|
tap,
|
||||||
withLatestFrom,
|
withLatestFrom,
|
||||||
} from "rxjs";
|
} from "rxjs";
|
||||||
import { Behavior } from "../state/Behavior";
|
|
||||||
|
import { type Behavior } from "../state/Behavior";
|
||||||
|
|
||||||
const nothing = Symbol("nothing");
|
const nothing = Symbol("nothing");
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,12 @@ import { vitest } from "vitest";
|
|||||||
import { type RelationsContainer } from "matrix-js-sdk/lib/models/relations-container";
|
import { type RelationsContainer } from "matrix-js-sdk/lib/models/relations-container";
|
||||||
import EventEmitter from "events";
|
import EventEmitter from "events";
|
||||||
|
|
||||||
import type { RoomMember, MatrixClient, Room } from "matrix-js-sdk";
|
import {
|
||||||
|
type RoomMember,
|
||||||
|
type MatrixClient,
|
||||||
|
type Room,
|
||||||
|
SyncState,
|
||||||
|
} from "matrix-js-sdk";
|
||||||
import { E2eeType } from "../e2ee/e2eeType";
|
import { E2eeType } from "../e2ee/e2eeType";
|
||||||
import { CallViewModel } from "../state/CallViewModel";
|
import { CallViewModel } from "../state/CallViewModel";
|
||||||
import {
|
import {
|
||||||
@@ -52,6 +57,7 @@ export function getBasicRTCSession(
|
|||||||
client: {
|
client: {
|
||||||
getUserId: () => localRtcMember.sender,
|
getUserId: () => localRtcMember.sender,
|
||||||
getDeviceId: () => localRtcMember.deviceId,
|
getDeviceId: () => localRtcMember.deviceId,
|
||||||
|
getSyncState: () => SyncState.Syncing,
|
||||||
sendEvent: vitest.fn().mockResolvedValue({ event_id: "$fake:event" }),
|
sendEvent: vitest.fn().mockResolvedValue({ event_id: "$fake:event" }),
|
||||||
redactEvent: vitest.fn().mockResolvedValue({ event_id: "$fake:event" }),
|
redactEvent: vitest.fn().mockResolvedValue({ event_id: "$fake:event" }),
|
||||||
decryptEventIfNeeded: vitest.fn().mockResolvedValue(undefined),
|
decryptEventIfNeeded: vitest.fn().mockResolvedValue(undefined),
|
||||||
|
|||||||
@@ -19,8 +19,11 @@ import {
|
|||||||
type Focus,
|
type Focus,
|
||||||
MatrixRTCSessionEvent,
|
MatrixRTCSessionEvent,
|
||||||
type MatrixRTCSessionEventHandlerMap,
|
type MatrixRTCSessionEventHandlerMap,
|
||||||
|
MembershipManagerEvent,
|
||||||
type SessionMembershipData,
|
type SessionMembershipData,
|
||||||
|
Status,
|
||||||
} from "matrix-js-sdk/lib/matrixrtc";
|
} from "matrix-js-sdk/lib/matrixrtc";
|
||||||
|
import { type MembershipManagerEventHandlerMap } from "matrix-js-sdk/lib/matrixrtc/IMembershipManager";
|
||||||
import {
|
import {
|
||||||
type LocalParticipant,
|
type LocalParticipant,
|
||||||
type LocalTrackPublication,
|
type LocalTrackPublication,
|
||||||
@@ -318,8 +321,10 @@ export function mockConfig(config: Partial<ResolvedConfigOptions> = {}): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class MockRTCSession extends TypedEventEmitter<
|
export class MockRTCSession extends TypedEventEmitter<
|
||||||
MatrixRTCSessionEvent | RoomAndToDeviceEvents,
|
MatrixRTCSessionEvent | RoomAndToDeviceEvents | MembershipManagerEvent,
|
||||||
MatrixRTCSessionEventHandlerMap & RoomAndToDeviceEventsHandlerMap
|
MatrixRTCSessionEventHandlerMap &
|
||||||
|
RoomAndToDeviceEventsHandlerMap &
|
||||||
|
MembershipManagerEventHandlerMap
|
||||||
> {
|
> {
|
||||||
public readonly statistics = {
|
public readonly statistics = {
|
||||||
counters: {},
|
counters: {},
|
||||||
@@ -354,6 +359,17 @@ export class MockRTCSession extends TypedEventEmitter<
|
|||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public readonly membershipStatus = Status.Connected;
|
||||||
|
|
||||||
|
private _probablyLeft = false;
|
||||||
|
public get probablyLeft(): boolean {
|
||||||
|
return this._probablyLeft;
|
||||||
|
}
|
||||||
|
public set probablyLeft(value: boolean) {
|
||||||
|
this._probablyLeft = value;
|
||||||
|
this.emit(MembershipManagerEvent.ProbablyLeft, value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const mockTrack = (identity: string): TrackReference =>
|
export const mockTrack = (identity: string): TrackReference =>
|
||||||
|
|||||||
@@ -7537,7 +7537,7 @@ __metadata:
|
|||||||
livekit-client: "npm:^2.13.0"
|
livekit-client: "npm:^2.13.0"
|
||||||
lodash-es: "npm:^4.17.21"
|
lodash-es: "npm:^4.17.21"
|
||||||
loglevel: "npm:^1.9.1"
|
loglevel: "npm:^1.9.1"
|
||||||
matrix-js-sdk: "github:matrix-org/matrix-js-sdk#head=toger5/membership-manager-likely-disconnected"
|
matrix-js-sdk: "github:matrix-org/matrix-js-sdk#head=develop"
|
||||||
matrix-widget-api: "npm:^1.13.0"
|
matrix-widget-api: "npm:^1.13.0"
|
||||||
normalize.css: "npm:^8.0.1"
|
normalize.css: "npm:^8.0.1"
|
||||||
observable-hooks: "npm:^4.2.3"
|
observable-hooks: "npm:^4.2.3"
|
||||||
@@ -10278,9 +10278,9 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"matrix-js-sdk@github:matrix-org/matrix-js-sdk#head=toger5/membership-manager-likely-disconnected":
|
"matrix-js-sdk@github:matrix-org/matrix-js-sdk#head=develop":
|
||||||
version: 37.13.0
|
version: 37.13.0
|
||||||
resolution: "matrix-js-sdk@https://github.com/matrix-org/matrix-js-sdk.git#commit=3f71ea8547c7765ea94710406f34834e7d6df82a"
|
resolution: "matrix-js-sdk@https://github.com/matrix-org/matrix-js-sdk.git#commit=3a33c658bbcb8ce8791ec066db899f2571f5c52f"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/runtime": "npm:^7.12.5"
|
"@babel/runtime": "npm:^7.12.5"
|
||||||
"@matrix-org/matrix-sdk-crypto-wasm": "npm:^15.1.0"
|
"@matrix-org/matrix-sdk-crypto-wasm": "npm:^15.1.0"
|
||||||
@@ -10296,7 +10296,7 @@ __metadata:
|
|||||||
sdp-transform: "npm:^2.14.1"
|
sdp-transform: "npm:^2.14.1"
|
||||||
unhomoglyph: "npm:^1.0.6"
|
unhomoglyph: "npm:^1.0.6"
|
||||||
uuid: "npm:11"
|
uuid: "npm:11"
|
||||||
checksum: 10c0/90238daaa5cad519b799a8ec53f768cbe295c6f5f4f7b82018dfee1f6311d6adbbc6fe71e86d4153fa3d2f711b67281f8202ad27dc0b1052c5a63621e96e05a2
|
checksum: 10c0/1db0d39cfbe4f1c69c8acda0ea7580a4819fc47a7d4bff057382e33e72d9a610f8c03043a6c00bc647dfdc2815aa643c69d25022fb759342a92b77e1841524f1
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user