Skip to content
12 changes: 12 additions & 0 deletions apps/web/src/stores/widgets/ElementWidgetDriver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
type IWidgetApiErrorResponseDataDetails,
type ISearchUserDirectoryResult,
type IGetMediaConfigResult,
type IRtcTransportsResult,
} from "matrix-widget-api";
import {
ClientEvent,
Expand Down Expand Up @@ -123,6 +124,7 @@ export class ElementWidgetDriver extends WidgetDriver {
// This is a trusted Element Call widget that we control
this.allowedCapabilities.add(MatrixCapabilities.AlwaysOnScreen);
this.allowedCapabilities.add(MatrixCapabilities.MSC3846TurnServers);
this.allowedCapabilities.add(MatrixCapabilities.MSC4515RtcTransports);
this.allowedCapabilities.add(`org.matrix.msc2762.timeline:${inRoomId}`);
this.allowedCapabilities.add(MatrixCapabilities.MSC4157SendDelayedEvent);
this.allowedCapabilities.add(MatrixCapabilities.MSC4157UpdateDelayedEvent);
Expand Down Expand Up @@ -765,6 +767,16 @@ export class ElementWidgetDriver extends WidgetDriver {
}
}

public async getRtcTransports(): Promise<IRtcTransportsResult> {
const client = MatrixClientPeg.safeGet();
// Delegate to the authenticated CS endpoint (MSC4143). Any error (e.g. the
// homeserver not supporting it) propagates and is turned into a widget error
// response by ClientWidgetApi. The js-sdk Transport and widget-api IRtcTransport
// types are structurally identical.
const transports = await client._unstable_getRTCTransports();
return { rtc_transports: transports };
}

public async readEventRelations(
eventId: string,
roomId?: string,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
type ITurnServer as IClientTurnServer,
Direction,
EventType,
MatrixError,
MatrixEvent,
MsgType,
RelationType,
Expand Down Expand Up @@ -89,6 +90,7 @@
const requestedCapabilities = new Set([
"m.always_on_screen",
"town.robin.msc3846.turn_servers",
"org.matrix.msc4515.rtc_transports",
"org.matrix.msc2762.timeline:!1:example.org",
"org.matrix.msc2762.send.event:org.matrix.msc4075.call.notify",
"org.matrix.msc2762.send.event:org.matrix.msc4075.rtc.notification",
Expand Down Expand Up @@ -148,7 +150,7 @@
]);

const approvedCapabilities = await driver.validateCapabilities(requestedCapabilities);
expect(approvedCapabilities).toEqual(requestedCapabilities);

Check failure on line 153 in apps/web/test/unit-tests/stores/widgets/ElementWidgetDriver-test.ts

View workflow job for this annotation

GitHub Actions / Jest (Element Web) (2)

ElementWidgetDriver › auto-approves capabilities of virtual Element Call widgets

expect(received).toEqual(expected) // deep equality - Expected - 1 + Received + 0 @@ -52,8 +52,7 @@ "org.matrix.msc4039.download_file", "org.matrix.msc4157.send.delayed_event", "org.matrix.msc4157.update_delayed_event", "org.matrix.msc4407.receive.sticky_event", "org.matrix.msc4407.send.sticky_event", - "org.matrix.msc4515.rtc_transports", "town.robin.msc3846.turn_servers", } at Object.toEqual (test/unit-tests/stores/widgets/ElementWidgetDriver-test.ts:153:38)
});

it("approves capabilities via module api", async () => {
Expand Down Expand Up @@ -420,6 +422,34 @@
});
});

describe("getRtcTransports", () => {
let driver: WidgetDriver;

beforeEach(() => {
driver = mkDefaultDriver();
});

it("gets the RTC transports from the homeserver", async () => {
const transports = [{ type: "livekit", livekit_service_url: "https://livekit-jwt.example.com" }];
client._unstable_getRTCTransports.mockResolvedValue(transports);

await expect(driver.getRtcTransports()).resolves.toEqual({ rtc_transports: transports });

expect(client._unstable_getRTCTransports).toHaveBeenCalledWith();
});

it("propagates errors from the homeserver", async () => {
const error = new MatrixError(
{ errcode: "M_NOT_FOUND", error: "Not found" },
404,
);

client._unstable_getRTCTransports.mockRejectedValue(error);

await expect(driver.getRtcTransports()).rejects.toBe(error);
});
});

describe("readEventRelations", () => {
let driver: WidgetDriver;

Expand Down
Loading