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 🙏

© 2024 – Pkg Stats / Ryan Hefner

matrix-crdt

v0.2.1-alpha.1

Published

<a href="https://discord.gg/aDQxXezfNj"><img alt="Discord" src="https://img.shields.io/badge/Chat on discord%20-%237289DA.svg?&style=for-the-badge&logo=discord&logoColor=white"/></a> <a href="https://matrix.to/#/#matrixcrdt:matrix.org"><img alt="Matrix" s

Downloads

48

Readme

Matrix CRDT

npm version Coverage Status

Matrix-CRDT enables you to use Matrix as a backend for distributed, real-time collaborative web applications that sync automatically.

The MatrixProvider is a sync provider for Yjs, a proven, high performance CRDT implementation.

TL;DR

Create apps like this:

screencapture

And connect Matrix as transport + backend storage. Instead of chat messages (primary use-case of Matrix), we send an event stream of data model updates (for the rich-text demo, these are document edits) to Matrix.

Live demo

In the examples directory, you'll find some live examples:

Motivation

CRDTs (Conflict-free Replicated Data Types) make it easy to build decentralized, fast, collaborative local-first applications.

Read more about the benefits of Local-first software in this essay

When building local-first software on top of CRDTs, you probably still need a backend so users can access their data across devices and collaborate with each other.

While Matrix is primarily designed for messaging (chat), it's versatile enough to use as a backend for collaborative applications (see Architecture). The idea is that by building on top of Matrix, developers can focus on building clients and get the following benefits from the Matrix ecosystem out-of-the-box:

  • An open standard and active community
  • Multiple server implementations (including hosted servers)
  • Authentication (including support for SSO and 3rd party providers)
  • Access control via Rooms and Spaces
  • E2EE
  • A decentralized architecture with support for federation

Usage

Matrix-CRDT currently works with Yjs or SyncedStore.

Usage with Yjs

To setup Matrix-CRDT, 3 steps are needed:

  • Create a Yjs Y.Doc
  • Create and authenticate a client from matrix-js-sdk
  • Create and initialize your Matrix-CRDT MatrixProvider
import { MatrixProvider } from "matrix-crdt";
import * as Y from "yjs";
import sdk from "matrix-js-sdk";

// See https://matrix.org/docs/guides/usage-of-the-matrix-js-sdk
// for login methods
const matrixClient = sdk.createClient({
  baseUrl: "https://matrix.org",
  accessToken: "....MDAxM2lkZW50aWZpZXIga2V5CjAwMTBjaWQgZ2Vu....",
  userId: "@USERID:matrix.org",
});

// Extra configuration needed for certain matrix-js-sdk
// calls to work without calling sync start functions
matrixClient.canSupportVoip = false;
matrixClient.clientOpts = {
  lazyLoadMembers: true,
};

// Create a new Y.Doc and connect the MatrixProvider
const ydoc = new Y.Doc();
const provider = new MatrixProvider(ydoc, matrixClient, {
  type: "alias",
  alias: "matrix-room-alias",
});
provider.initialize();

// array of numbers which produce a sum
const yarray = ydoc.getArray("count");

// observe changes of the sum
yarray.observe((event) => {
  // print updates when the data changes
  console.log("new sum: " + yarray.toArray().reduce((a, b) => a + b));
});

// add 1 to the sum
yarray.push([1]); // => "new sum: 1"

Note for Vite / non-webpack If you're using Vite, or other non-webpack builds, note that matrix-js-sdk depends on certain polyfills available. See the Vite example and this issue on matrix-js-sdk.

SyncedStore

You can also use SyncedStore and use Matrix-CRDT as SyncProvider.

API

new MatrixProvider (doc, matrixClient, room, awareness?, opts?): MatrixProvider

The MatrixProvider syncs a Matrix room with a Yjs document.

Parameters

| Name | Type | Description | | :--------------------- | :------------------------------------------------------------------ | :---------------------------------------------------------------------------------------------------------------- | | doc | Y.Doc | The Y.Doc to sync over the Matrix room. | | matrixClient | MatrixClient | A matrix-js-sdk client with permissions to read (and/or write) from the room. | | room | { type: "id"; id: string; } or { type: "alias"; alias: string } | The room ID or Alias to sync with. | | awareness (optional) | awarenessProtocol.Awareness | A y-protocols Awareness instance that can be used to sync "awareness" data over the experimental webrtc bridge. | | opts (optional) | MatrixProviderOptions (see below) | Configure advanced properties, see below. |

MatrixProviderOptions

Additional configuration options that can be passed to the MatrixProvider constructor.

Defaults to:

{
  // Options for `ThrottledMatrixWriter`
  writer: {
    // throttle flushing write events to matrix by 500ms
    flushInterval: number = 500,
    // if writing to the room fails, wait 30 seconds before retrying
    retryIfForbiddenInterval: number = 30000
  },
  // Options for `MatrixCRDTEventTranslator`
  translator: {
    // set to true to send everything encapsulated in a m.room.message,
    // so you can view and debug messages easily in element or other matrix clients
    updatesAsRegularMessages: false,
    // The event type to use for updates
    updateEventType: "matrix-crdt.doc_update",
    // The event type to use for snapshots
    snapshotEventType: "matrix-crdt.doc_snapshot",
  }
  // Experimental; we can use WebRTC to sync updates instantly over WebRTC.
  // See SignedWebrtcProvider.ts for more details + motivation
  enableExperimentalWebrtcSync: boolean = false
  // Options for MatrixReader
  reader: {
    // How often to send a summary snapshot (defaults to once every 30 events)
    snapshotInterval: number = 30,
  },
}

Architecture

CRDT updates (in our case, Yjs document updates) are very similar to (chat) Messages, that Matrix has been optimized for.

Matrix-CRDT bridges Yjs documents to Matrix Rooms. and Yjs updates to Matrix events (regular chat messages are also a specific event type in Matrix). Yjs document updates are sent as base64-encoded events to the Matrix room.

When registering a MatrixProvider, we:

  • Listen to new matrix-crdt.doc_update events in the Matrix Room, and apply updates to the Yjs document.
  • Listen to Yjs document updates and send these to the Matrix room as matrix-crdt.doc_update events.

CRDTs are specifically designed to be eventually consistent. This means that the state of your data is eventually reconciled, regardless of the order of update events that reach each client or server (as long as you eventually get all updates).

This makes it possible to work offline, or for servers / clients to be out of sync for a while.

Snapshots

To reconstruct your application state (that is, the Yjs document), we eventually need to access all previous events. When there have been a lot of updates, it would be inefficient to read the entire document / room history from Matrix.

Matrix-CRDT sends periodic snapshots that contain a summary of all previous events. When retrieving a snapshot (stored as a Matrix event with type matrix-crdt.doc_snapshot), clients can reconstruct application state from that snapshot and don't need to fetch events occuring before that snapshots last_event_id (stored on the event).

WebRTC (experimental)

Matrix-CRDT by default throttles sent events every 500ms (for example, to prevent sending an event every keystroke when building a rich text editor). It also does not support Yjs Awareness updates (for presence information, etc) over Matrix.

You can use the (experimental) WebRTC provider to connect to peers over WebRTC and send updates (regular and Awareness updates) instantly.

Ideally, we'd replace this with Matrix Custom Ephemeral events when that Spec has landed.

Development

See CONTRIBUTING.md for instructions how to work with this repo (e.g.: installing and building using lerna).

Credits

Matrix-CRDT is built as part of TypeCell. TypeCell is proudly sponsored by the renowned NLNet foundation who are on a mission to support an open internet, and protect the privacy and security of internet users. Check them out!