npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@sableclient/matrixrtc

v0.1.0

Published

Engine-agnostic MatrixRTC call orchestration: MSC4143 session protocol, media key distribution and LiveKit key management, with no UI and no app state

Downloads

3,086

Readme

@sableclient/matrixrtc

Engine-agnostic MatrixRTC call logic: the MSC4143 session protocol, media-key distribution, LiveKit key-ring management and the notification/decline handling that sits around a call. No UI, no app state, no framework.

Extracted from Sable so the same call core can back a web client, a Tauri desktop build and a native mobile transport.

Install

pnpm add @sableclient/matrixrtc

Both SDKs are peer dependencies: the host owns their versions and their singletons:

pnpm add matrix-js-sdk livekit-client

The seam

CallTransport is the boundary between call logic and the media stack. On the web that is an in-page livekit-client Room; on mobile it is the native LiveKit SDK behind IPC. Everything above the seam is written once.

import type { CallTransport } from '@sableclient/matrixrtc';

Media keys

callKeyPipeline is the only subscriber to the session's EncryptionKeyChanged, so there is exactly one place a key can be lost. It feeds LivekitMatrixKeyProvider, which turns those keys into LiveKit key-ring entries.

import { createCallKeyPipeline, LivekitMatrixKeyProvider } from '@sableclient/matrixrtc';

const provider = new LivekitMatrixKeyProvider();
const pipeline = createCallKeyPipeline();
pipeline.setOnKey(provider.setKey);
pipeline.attach(session, { userId, deviceId });

Key indices are slots in a per-participant ring, not sequence numbers: they are reused modulo 256 and a peer that rejoins restarts at 0. Carry them through untouched, because filtering on them strands every frame encrypted with a dropped key.

Subpath imports are exported too, for contexts that must keep their import graph narrow (a service worker cannot pull in the runtime Matrix SDK):

import { normalizeCallIntent } from '@sableclient/matrixrtc/callIntent';

Host dependencies

Four things the host owns are injected rather than reached for, so nothing here depends on a singleton:

| dependency | where | | --- | --- | | request: typeof fetch | provisionLivekitToken, threaded through the join | | acquireOwner | createLivekitJsController, the one-call-at-a-time lease | | subscribeToCallRoom | the join, for eager roster hydration | | setLogSink | diagnostics |

createCallOwnership() ships a single-slot lease for hosts without a policy of their own.

Diagnostics

Nothing is logged until a host installs a sink, so the package never owns a transport, a buffer or a crash reporter:

import { setLogSink } from '@sableclient/matrixrtc';

setLogSink((namespace, level, category, message, data) => {
  myLogger[level](`${namespace}: ${message}`, data);
});

Consumers must bundle

matrix-js-sdk ships ESM directory imports that Node's own resolver rejects, so this package is consumed through a bundler (Vite, webpack, rollup) rather than loaded directly by Node. That is an upstream constraint, not a choice here: the same workaround appears in the SDK's own test setup and in Sable's Vitest config:

resolve: {
  alias: {
    'matrix-js-sdk/lib': path.resolve('node_modules/matrix-js-sdk/lib'),
    'matrix-js-sdk': path.resolve('node_modules/matrix-js-sdk/lib/matrix.js'),
  },
},
test: { server: { deps: { inline: [/matrix-js-sdk\/lib\//] } } },

What is deliberately not here

  • Anything that renders. Layout, controls and device pickers stay in the host.
  • App state. No jotai, no React, no store, and the lint config forbids them.
  • The Tauri/native transport and its controller, which speak to a platform plugin over IPC.

Scripts

pnpm typecheck    # tsc, no emit
pnpm test         # vitest
pnpm lint         # oxlint
pnpm fmt:check    # oxfmt
pnpm build        # tsc -> dist (ESM + declarations)

License

AGPL-3.0-only, matching Sable.