From c1b2346e22625ab91cf3d6c8eb830b42180f9d76 Mon Sep 17 00:00:00 2001 From: Timo K Date: Tue, 27 Jan 2026 16:49:25 +0100 Subject: [PATCH 1/4] Update tests based on new js-sdk changes (no more legacy notify event) --- .../CallNotificationLifecycle.test.ts | 22 ++++++++----------- .../CallNotificationLifecycle.ts | 4 ++-- src/state/CallViewModel/CallViewModel.test.ts | 7 ------ 3 files changed, 11 insertions(+), 22 deletions(-) diff --git a/src/state/CallViewModel/CallNotificationLifecycle.test.ts b/src/state/CallViewModel/CallNotificationLifecycle.test.ts index 236c126a..e5463e93 100644 --- a/src/state/CallViewModel/CallNotificationLifecycle.test.ts +++ b/src/state/CallViewModel/CallNotificationLifecycle.test.ts @@ -5,10 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial Please see LICENSE in the repository root for full details. */ -import { - type ICallNotifyContent, - type IRTCNotificationContent, -} from "matrix-js-sdk/lib/matrixrtc"; +import { type IRTCNotificationContent } from "matrix-js-sdk/lib/matrixrtc"; import { describe, it } from "vitest"; import { EventType, @@ -30,7 +27,6 @@ import { } from "./CallNotificationLifecycle"; import { trackEpoch } from "../ObservableScope"; -const mockLegacyRingEvent = {} as { event_id: string } & ICallNotifyContent; function mockRingEvent( eventId: string, lifetimeMs: number | undefined, @@ -54,7 +50,7 @@ describe("waitForCallPickup$", () => { behavior("a", { a: [] }).pipe(trackEpoch()), ), sentCallNotification$: hot("10ms a", { - a: [mockRingEvent("$notif1", 30), mockLegacyRingEvent], + a: [mockRingEvent("$notif1", 30)], }), receivedDecline$: hot(""), options: { @@ -86,7 +82,7 @@ describe("waitForCallPickup$", () => { }).pipe(trackEpoch()), ), sentCallNotification$: hot("5ms a", { - a: [mockRingEvent("$notif2", 100), mockLegacyRingEvent], + a: [mockRingEvent("$notif2", 100)], }), receivedDecline$: hot(""), options: { @@ -115,7 +111,7 @@ describe("waitForCallPickup$", () => { }).pipe(trackEpoch()), ), sentCallNotification$: hot("20ms a", { - a: [mockRingEvent("$notif2", 50), mockLegacyRingEvent], + a: [mockRingEvent("$notif2", 50)], }), receivedDecline$: hot(""), options: { @@ -142,7 +138,7 @@ describe("waitForCallPickup$", () => { }).pipe(trackEpoch()), ), sentCallNotification$: hot("10ms a", { - a: [mockRingEvent("$notif2", undefined), mockLegacyRingEvent], + a: [mockRingEvent("$notif2", undefined)], }), receivedDecline$: hot(""), options: { @@ -171,7 +167,7 @@ describe("waitForCallPickup$", () => { }).pipe(trackEpoch()), ), sentCallNotification$: hot("10ms a", { - a: [mockRingEvent("$notif5", 30), mockLegacyRingEvent], + a: [mockRingEvent("$notif5", 30)], }), receivedDecline$: hot(""), options: { @@ -210,7 +206,7 @@ describe("waitForCallPickup$", () => { }).pipe(trackEpoch()), ), sentCallNotification$: hot("10ms a", { - a: [mockRingEvent("$decl1", 50), mockLegacyRingEvent], + a: [mockRingEvent("$decl1", 50)], }), receivedDecline$: hot("40ms d", { d: [ @@ -254,7 +250,7 @@ describe("waitForCallPickup$", () => { }).pipe(trackEpoch()), ), sentCallNotification$: hot("10ms a", { - a: [mockRingEvent("$decl", 20), mockLegacyRingEvent], + a: [mockRingEvent("$decl", 20)], }), receivedDecline$: hot("40ms d", { d: [ @@ -305,7 +301,7 @@ describe("waitForCallPickup$", () => { }).pipe(trackEpoch()), ), sentCallNotification$: hot("10ms a", { - a: [mockRingEvent("$right", 50), mockLegacyRingEvent], + a: [mockRingEvent("$right", 50)], }), receivedDecline$: hot("20ms d", { d: [ diff --git a/src/state/CallViewModel/CallNotificationLifecycle.ts b/src/state/CallViewModel/CallNotificationLifecycle.ts index d90f35ba..b56e2f40 100644 --- a/src/state/CallViewModel/CallNotificationLifecycle.ts +++ b/src/state/CallViewModel/CallNotificationLifecycle.ts @@ -140,9 +140,9 @@ export function createCallNotificationLifecycle$({ scope.behavior( sentCallNotification$.pipe( filter( - (newAndLegacyEvents) => + (notificationEventArgs) => // only care about new events (legacy do not have decline pattern) - newAndLegacyEvents?.[0].notification_type === "ring", + notificationEventArgs?.[0].notification_type === "ring", ), map((e) => e as CallNotificationWrapper), switchMap(([notificationEvent]) => { diff --git a/src/state/CallViewModel/CallViewModel.test.ts b/src/state/CallViewModel/CallViewModel.test.ts index c355c627..5ee679b0 100644 --- a/src/state/CallViewModel/CallViewModel.test.ts +++ b/src/state/CallViewModel/CallViewModel.test.ts @@ -29,7 +29,6 @@ import { Status, type CallMembership, type IRTCNotificationContent, - type ICallNotifyContent, MatrixRTCSessionEvent, type LivekitTransport, } from "matrix-js-sdk/lib/matrixrtc"; @@ -232,10 +231,6 @@ function mockRingEvent( } as unknown as { event_id: string } & IRTCNotificationContent; } -// The app doesn't really care about the content of these legacy events, we just -// need a value to fill in for them when emitting notifications -const mockLegacyRingEvent = {} as { event_id: string } & ICallNotifyContent; - describe.each([ [MatrixRTCMode.Legacy], [MatrixRTCMode.Compatibility], @@ -1109,7 +1104,6 @@ describe.each([ rtcSession.emit( MatrixRTCSessionEvent.DidSendCallNotification, mockRingEvent("$notif1", 30), - mockLegacyRingEvent, ); }, }); @@ -1151,7 +1145,6 @@ describe.each([ rtcSession.emit( MatrixRTCSessionEvent.DidSendCallNotification, mockRingEvent("$notif2", 100), - mockLegacyRingEvent, ); }, d: () => { From bd8c4188d0c46c7c0de5c7f91379a0061681fdcd Mon Sep 17 00:00:00 2001 From: Timo K Date: Thu, 29 Jan 2026 17:24:21 +0100 Subject: [PATCH 2/4] bump js-sdk --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index fd7f2302..e486bf6b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11453,8 +11453,8 @@ __metadata: linkType: hard "matrix-js-sdk@matrix-org/matrix-js-sdk#develop": - version: 40.0.0 - resolution: "matrix-js-sdk@https://github.com/matrix-org/matrix-js-sdk.git#commit=dbb2ae5c0752c28639502e93f26cb3003d0d0595" + version: 40.1.0 + resolution: "matrix-js-sdk@https://github.com/matrix-org/matrix-js-sdk.git#commit=f2157f28bbadf2898fe21991f69ccb2af40df326" dependencies: "@babel/runtime": "npm:^7.12.5" "@matrix-org/matrix-sdk-crypto-wasm": "npm:^17.0.0" @@ -11470,7 +11470,7 @@ __metadata: sdp-transform: "npm:^3.0.0" unhomoglyph: "npm:^1.0.6" uuid: "npm:13" - checksum: 10c0/9f97cec346e0dcce8599bc3afa1608f5166408260937f8311fa9af95b8fd2ff6d86422124fcb721fc830a3ec269389067334c344b4f512b64299561484135326 + checksum: 10c0/d646b9214abbf0b9126760105edd9c57be7ffe8b53ae4acd5fefe841a51ad7d78fa57130922b3eac65ff2266b43f31ea60b4bdda9481e6bf8f1808d96726ed8a languageName: node linkType: hard From a0ad23895207fac6e295b4c95263b16349c5f98f Mon Sep 17 00:00:00 2001 From: Valere Date: Tue, 3 Feb 2026 15:29:19 +0100 Subject: [PATCH 3/4] fix: `DidSendCallNotification` is not emitting array anymore --- .../CallNotificationLifecycle.test.ts | 22 +++++++++---------- .../CallNotificationLifecycle.ts | 16 ++++++++------ 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/state/CallViewModel/CallNotificationLifecycle.test.ts b/src/state/CallViewModel/CallNotificationLifecycle.test.ts index e5463e93..c82253a1 100644 --- a/src/state/CallViewModel/CallNotificationLifecycle.test.ts +++ b/src/state/CallViewModel/CallNotificationLifecycle.test.ts @@ -5,7 +5,6 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial Please see LICENSE in the repository root for full details. */ -import { type IRTCNotificationContent } from "matrix-js-sdk/lib/matrixrtc"; import { describe, it } from "vitest"; import { EventType, @@ -22,6 +21,7 @@ import { localRtcMember, } from "../../utils/test-fixtures"; import { + type CallNotificationWrapper, createCallNotificationLifecycle$, type Props as CallNotificationLifecycleProps, } from "./CallNotificationLifecycle"; @@ -31,13 +31,13 @@ function mockRingEvent( eventId: string, lifetimeMs: number | undefined, sender = local.userId, -): { event_id: string } & IRTCNotificationContent { +): CallNotificationWrapper { return { event_id: eventId, ...(lifetimeMs === undefined ? {} : { lifetime: lifetimeMs }), notification_type: "ring", sender, - } as unknown as { event_id: string } & IRTCNotificationContent; + } as unknown as CallNotificationWrapper; } describe("waitForCallPickup$", () => { @@ -50,7 +50,7 @@ describe("waitForCallPickup$", () => { behavior("a", { a: [] }).pipe(trackEpoch()), ), sentCallNotification$: hot("10ms a", { - a: [mockRingEvent("$notif1", 30)], + a: mockRingEvent("$notif1", 30), }), receivedDecline$: hot(""), options: { @@ -82,7 +82,7 @@ describe("waitForCallPickup$", () => { }).pipe(trackEpoch()), ), sentCallNotification$: hot("5ms a", { - a: [mockRingEvent("$notif2", 100)], + a: mockRingEvent("$notif2", 100), }), receivedDecline$: hot(""), options: { @@ -111,7 +111,7 @@ describe("waitForCallPickup$", () => { }).pipe(trackEpoch()), ), sentCallNotification$: hot("20ms a", { - a: [mockRingEvent("$notif2", 50)], + a: mockRingEvent("$notif2", 50), }), receivedDecline$: hot(""), options: { @@ -138,7 +138,7 @@ describe("waitForCallPickup$", () => { }).pipe(trackEpoch()), ), sentCallNotification$: hot("10ms a", { - a: [mockRingEvent("$notif2", undefined)], + a: mockRingEvent("$notif2", undefined), }), receivedDecline$: hot(""), options: { @@ -167,7 +167,7 @@ describe("waitForCallPickup$", () => { }).pipe(trackEpoch()), ), sentCallNotification$: hot("10ms a", { - a: [mockRingEvent("$notif5", 30)], + a: mockRingEvent("$notif5", 30), }), receivedDecline$: hot(""), options: { @@ -206,7 +206,7 @@ describe("waitForCallPickup$", () => { }).pipe(trackEpoch()), ), sentCallNotification$: hot("10ms a", { - a: [mockRingEvent("$decl1", 50)], + a: mockRingEvent("$decl1", 50), }), receivedDecline$: hot("40ms d", { d: [ @@ -250,7 +250,7 @@ describe("waitForCallPickup$", () => { }).pipe(trackEpoch()), ), sentCallNotification$: hot("10ms a", { - a: [mockRingEvent("$decl", 20)], + a: mockRingEvent("$decl", 20), }), receivedDecline$: hot("40ms d", { d: [ @@ -301,7 +301,7 @@ describe("waitForCallPickup$", () => { }).pipe(trackEpoch()), ), sentCallNotification$: hot("10ms a", { - a: [mockRingEvent("$right", 50)], + a: mockRingEvent("$right", 50), }), receivedDecline$: hot("20ms d", { d: [ diff --git a/src/state/CallViewModel/CallNotificationLifecycle.ts b/src/state/CallViewModel/CallNotificationLifecycle.ts index b56e2f40..0b2bf27d 100644 --- a/src/state/CallViewModel/CallNotificationLifecycle.ts +++ b/src/state/CallViewModel/CallNotificationLifecycle.ts @@ -9,7 +9,6 @@ import { type CallMembership, type MatrixRTCSession, MatrixRTCSessionEvent, - type MatrixRTCSessionEventHandlerMap, } from "matrix-js-sdk/lib/matrixrtc"; import { combineLatest, @@ -34,6 +33,7 @@ import { EventType, type Room as MatrixRoom, RoomEvent, + type IRTCNotificationContent, } from "matrix-js-sdk"; import { type Behavior } from "../Behavior"; @@ -46,9 +46,11 @@ export type CallPickupState = | "decline" | "success" | null; -export type CallNotificationWrapper = Parameters< - MatrixRTCSessionEventHandlerMap[MatrixRTCSessionEvent.DidSendCallNotification] ->; + +export type CallNotificationWrapper = { + event_id: string; +} & IRTCNotificationContent; + export function createSentCallNotification$( scope: ObservableScope, matrixRTCSession: MatrixRTCSession, @@ -140,12 +142,12 @@ export function createCallNotificationLifecycle$({ scope.behavior( sentCallNotification$.pipe( filter( - (notificationEventArgs) => + (notificationEventArgs: CallNotificationWrapper | null) => // only care about new events (legacy do not have decline pattern) - notificationEventArgs?.[0].notification_type === "ring", + notificationEventArgs?.notification_type === "ring", ), map((e) => e as CallNotificationWrapper), - switchMap(([notificationEvent]) => { + switchMap((notificationEvent) => { const lifetimeMs = notificationEvent?.lifetime ?? 0; return concat( lifetimeMs === 0 From 9d8ebf8ef3211160f8ec25b88decdcd50d761b1b Mon Sep 17 00:00:00 2001 From: Valere Date: Tue, 3 Feb 2026 15:37:41 +0100 Subject: [PATCH 4/4] fix import --- src/state/CallViewModel/CallNotificationLifecycle.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/state/CallViewModel/CallNotificationLifecycle.ts b/src/state/CallViewModel/CallNotificationLifecycle.ts index 0b2bf27d..44ce2e43 100644 --- a/src/state/CallViewModel/CallNotificationLifecycle.ts +++ b/src/state/CallViewModel/CallNotificationLifecycle.ts @@ -7,6 +7,7 @@ Please see LICENSE in the repository root for full details. import { type CallMembership, + type IRTCNotificationContent, type MatrixRTCSession, MatrixRTCSessionEvent, } from "matrix-js-sdk/lib/matrixrtc"; @@ -33,11 +34,11 @@ import { EventType, type Room as MatrixRoom, RoomEvent, - type IRTCNotificationContent, } from "matrix-js-sdk"; import { type Behavior } from "../Behavior"; import { type Epoch, mapEpoch, type ObservableScope } from "../ObservableScope"; + export type AutoLeaveReason = "allOthersLeft" | "timeout" | "decline"; export type CallPickupState = | "unknown" @@ -82,6 +83,7 @@ export interface Props { options: { waitForCallPickup?: boolean; autoLeaveWhenOthersLeft?: boolean }; localUser: { deviceId: string; userId: string }; } + /** * @returns two observables: * `callPickupState$` The current call pickup state of the call.