Take the word call out of the member API

membership$ is typed as RTCMembership, the subset of the js-sdk CallMembership that hosts read. UnknownCallError is UnknownRTCError throughout, not only in the export. applicationData reaches the membership whole, since the js-sdk takes it next to the intent. The plan records the three slices as implemented.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Timo K.
2026-10-08 13:53:57 +02:00
co-authored by Claude Fable 5.1
parent b9f79be106
commit 6bd6e3f953
7 changed files with 65 additions and 29 deletions
+23 -4
View File
@@ -48,9 +48,10 @@ export interface MatrixRTCClientOptions {
/** The application's slot in the room. Default `ROOM`. */
slot?: string;
/**
* Whatever the application wants to say about itself in the membership.
* Opaque to the SDK. Today the js-sdk carries one key, `m.call.intent`
* (`"audio"` or `"video"`); anything else is dropped until it can.
* Whatever the application wants to say about itself in the membership,
* under namespaced keys. Opaque to the SDK, apart from `m.call.intent`
* (`"audio"` or `"video"`), which the membership format carries as a
* field of its own.
*/
applicationData?: Record<string, unknown>;
/** Session timings the host has configured; the defaults otherwise. */
@@ -211,13 +212,31 @@ export type ResolvedTransport =
// ---------------------------------------------------------------------------
// Members
/**
* What a membership says, as hosts read it. The js-sdk `CallMembership` is
* behind it; anything beyond this is the js-sdk's API, not the SDK's.
*/
export type RTCMembership = Pick<
CallMembership,
| "userId"
| "deviceId"
| "memberId"
| "rtcBackendIdentity"
| "application"
| "applicationData"
| "getTransport"
| "transports"
| "createdTs"
| "getAbsoluteExpiry"
>;
export interface RTCMember {
local: boolean;
/** The identity the media backend knows this member by. */
id: string;
userId: string;
deviceId: string;
membership$: Behavior<CallMembership>;
membership$: Behavior<RTCMembership>;
displayName$: Behavior<string>;
avatarUrl$: Behavior<string | undefined>;
/** Which transport this member is on; undefined when the membership has none. */
+1 -1
View File
@@ -80,7 +80,7 @@ export class MembershipManagerError extends MatrixRTCError {
}
}
export class UnknownCallError extends MatrixRTCError {
export class UnknownRTCError extends MatrixRTCError {
public constructor(cause: Error) {
super(
cause.message || "Unknown error",
+3 -3
View File
@@ -40,7 +40,7 @@ import {
LivekitConnectionError,
PeerConnectionTimeoutError,
SFURoomCreationRestrictedError,
UnknownCallError,
UnknownRTCError,
} from "../errors";
export interface ConnectionOpts {
@@ -381,8 +381,8 @@ export class Connection {
error instanceof MatrixRTCError
? error
: error instanceof Error
? new UnknownCallError(error)
: new UnknownCallError(new Error(`${error}`)),
? new UnknownRTCError(error)
: new UnknownRTCError(new Error(`${error}`)),
);
// Its okay to ignore the throw. The error is part of the state.
throw error;
+3 -2
View File
@@ -47,8 +47,8 @@ export function joinJsSdkSession(
delayedLeave,
}: Options,
): void {
// The one piece of application data the js-sdk can put in a membership
const intent = applicationData?.["m.call.intent"];
// The membership format carries the intent as a field of its own
const { "m.call.intent": intent, ...rest } = applicationData ?? {};
const callIntent =
typeof intent === "string" ? (intent as RTCCallIntent) : undefined;
// Give up on the network as soon as either the sync has been down for the
@@ -61,6 +61,7 @@ export function joinJsSdkSession(
session.joinRTCSession(ownMembershipIdentity, [transport], {
notificationType: sendNotificationType,
callIntent,
applicationData: rest,
manageMediaKeys: encryptMedia,
delayedLeaveEventRestartMs: delayedLeave.restart_ms,
delayedLeaveEventDelayMs: delayedLeave.delay_ms,