mirror of
https://github.com/vector-im/element-call.git
synced 2026-10-16 23:45:50 +00:00
Put the media behind a backend seam and move LiveKit into it
The session speaks MatrixRTC and sees media through MediaBackend in sdk/src/backend/api.ts. Everything LiveKit lives in sdk/src/backend/livekit/, the only place in the SDK that imports livekit-client; the import boundary rule now enforces that outside sdk/src/backend/ the LiveKit packages appear in type imports only. The seam sits above the connection manager: one connection per transport url is the LiveKit multi-SFU strategy, not a MatrixRTC concept, so a cascading SFU or full mesh replaces the folder, not the session. A backend prepares the local transport the session discovered (the token exchange and the delegation probe, reported as canDelegateDelayedLeave), hands the delayed leave over per delay id, gives the local member one publish switch plus publish/unpublish, builds a remote member's media from its membership and registers that membership's transport for as long as the member lives, and reports its connections for the transport registry, which keys on the raw transport serialised with sorted keys. The backend's context carries no Matrix client (a backend picks what it calls in its own options), no membership list, and no js-sdk session: media keys arrive as a stream replayed on subscribe, and MatrixKeyProvider subscribes to it. The MatrixRTC mode no longer reaches LiveKit; it becomes a tokenEndpoint choice made where the default backend is built. Two behaviour changes ride along. Publishing is one boolean, joined and homeserver reachable, where before a sync hiccup after leave() resumed the upstream of tracks that were meant to stay silent. And ResolvedConnection keeps one ResolvedTransport object per fetch, so a state change no longer reads as a change of what was fetched. MatrixRTCClientOptions gains backend?: MediaBackendFactory, defaulting to createLivekitBackend built from the client options. authenticateWithTransport takes tokenEndpoint instead of matrixRTCMode.
This commit is contained in:
@@ -20,11 +20,21 @@ const BANNED_PACKAGES = [
|
||||
"@vector-im/",
|
||||
];
|
||||
|
||||
/**
|
||||
* Packages only a media backend may import. The session speaks MatrixRTC and
|
||||
* sees media through `sdk/src/backend/api.ts`; a backend under
|
||||
* `sdk/src/backend/<name>/` is the one place its protocol's library appears.
|
||||
*/
|
||||
const BACKEND_PACKAGES = ["livekit-client", "@livekit/"];
|
||||
|
||||
/**
|
||||
* Keeps the SDK free of Element Call: nothing under `sdk/` may import a file
|
||||
* outside `sdk/` by relative path (that is `src/`, `component/`,
|
||||
* `playwright/`) or one of the packages above. The development harness under
|
||||
* `sdk/dev/` is a host, not part of the library, and is exempt.
|
||||
* `sdk/dev/` is a host, not part of the library, and is exempt. Keeps the
|
||||
* session free of any one media backend, too: outside `sdk/src/backend/`,
|
||||
* a backend's packages may only be imported for their types, and only in
|
||||
* the public API, the errors and the test helpers that have to name them.
|
||||
*/
|
||||
const rule = ESLintUtils.RuleCreator(
|
||||
() => "https://github.com/element-hq/element-call",
|
||||
@@ -41,6 +51,8 @@ const rule = ESLintUtils.RuleCreator(
|
||||
"The SDK must not import '{{specifier}}': it resolves outside sdk/. Copy or move what it needs into sdk/src.",
|
||||
bannedPackage:
|
||||
"The SDK must not import '{{specifier}}': a host supplies that, the SDK has no UI.",
|
||||
backendPackage:
|
||||
"Only a media backend under sdk/src/backend/ may import '{{specifier}}'; the session sees media through backend/api.ts.",
|
||||
},
|
||||
schema: [],
|
||||
},
|
||||
@@ -50,9 +62,28 @@ const rule = ESLintUtils.RuleCreator(
|
||||
const sdkRoot = resolve(context.cwd, "sdk") + sep;
|
||||
if (!filename.startsWith(sdkRoot)) return {};
|
||||
if (filename.startsWith(resolve(sdkRoot, "dev") + sep)) return {};
|
||||
const inBackend = filename.startsWith(
|
||||
resolve(sdkRoot, "src", "backend") + sep,
|
||||
);
|
||||
|
||||
const check = (node, specifier) => {
|
||||
const matchesPackage = (specifier, pkg) =>
|
||||
specifier === pkg ||
|
||||
specifier.startsWith(pkg.endsWith("/") ? pkg : `${pkg}/`);
|
||||
|
||||
const check = (node, specifier, typeOnly = false) => {
|
||||
if (typeof specifier !== "string") return;
|
||||
if (
|
||||
!inBackend &&
|
||||
!typeOnly &&
|
||||
BACKEND_PACKAGES.some((pkg) => matchesPackage(specifier, pkg))
|
||||
) {
|
||||
context.report({
|
||||
node,
|
||||
messageId: "backendPackage",
|
||||
data: { specifier },
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (specifier.startsWith(".")) {
|
||||
const target = resolve(dirname(filename), specifier);
|
||||
if (!target.startsWith(sdkRoot))
|
||||
@@ -62,11 +93,7 @@ const rule = ESLintUtils.RuleCreator(
|
||||
data: { specifier },
|
||||
});
|
||||
} else if (
|
||||
BANNED_PACKAGES.some(
|
||||
(pkg) =>
|
||||
specifier === pkg ||
|
||||
specifier.startsWith(pkg.endsWith("/") ? pkg : `${pkg}/`),
|
||||
)
|
||||
BANNED_PACKAGES.some((pkg) => matchesPackage(specifier, pkg))
|
||||
) {
|
||||
context.report({
|
||||
node,
|
||||
@@ -78,7 +105,12 @@ const rule = ESLintUtils.RuleCreator(
|
||||
|
||||
return {
|
||||
ImportDeclaration(node) {
|
||||
check(node, node.source.value);
|
||||
check(
|
||||
node,
|
||||
node.source.value,
|
||||
node.importKind === "type" ||
|
||||
node.specifiers.every((s) => s.importKind === "type"),
|
||||
);
|
||||
},
|
||||
ExportNamedDeclaration(node) {
|
||||
if (node.source) check(node, node.source.value);
|
||||
|
||||
Reference in New Issue
Block a user