{"id":13769806,"url":"https://github.com/yousefED/matrix-crdt","last_synced_at":"2025-05-11T02:33:38.557Z","repository":{"id":40322521,"uuid":"443814373","full_name":"YousefED/Matrix-CRDT","owner":"YousefED","description":"Use Matrix as a backend for local-first applications with the Matrix-CRDT Yjs provider.","archived":false,"fork":false,"pushed_at":"2024-03-27T13:23:53.000Z","size":5819,"stargazers_count":723,"open_issues_count":8,"forks_count":31,"subscribers_count":14,"default_branch":"main","last_synced_at":"2024-07-20T02:21:59.750Z","etag":null,"topics":["collaborative-editing","crdt","local-first","matrix","messaging","real-time","sync","yjs"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/YousefED.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-01-02T16:29:43.000Z","updated_at":"2024-07-07T14:05:01.000Z","dependencies_parsed_at":"2024-06-19T00:13:55.262Z","dependency_job_id":"f34b9c27-1ffe-4b06-807f-a8c99814cc6a","html_url":"https://github.com/YousefED/Matrix-CRDT","commit_stats":{"total_commits":44,"total_committers":1,"mean_commits":44.0,"dds":0.0,"last_synced_commit":"9ea070842ccd05880c09cbfa32480d3e78157f00"},"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/YousefED%2FMatrix-CRDT","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/YousefED%2FMatrix-CRDT/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/YousefED%2FMatrix-CRDT/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/YousefED%2FMatrix-CRDT/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/YousefED","download_url":"https://codeload.github.com/YousefED/Matrix-CRDT/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":213832277,"owners_count":15644974,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["collaborative-editing","crdt","local-first","matrix","messaging","real-time","sync","yjs"],"created_at":"2024-08-03T17:00:31.709Z","updated_at":"2024-08-03T17:02:34.609Z","avatar_url":"https://github.com/YousefED.png","language":"TypeScript","funding_links":[],"categories":["Collaborative Documents"],"sub_categories":["Single Purpose Bots"],"readme":"# Matrix CRDT\n\n\u003ca href=\"https://discord.gg/aDQxXezfNj\"\u003e\u003cimg alt=\"Discord\" src=\"https://img.shields.io/badge/Chat on discord%20-%237289DA.svg?\u0026style=for-the-badge\u0026logo=discord\u0026logoColor=white\"/\u003e\u003c/a\u003e \u003ca href=\"https://matrix.to/#/#matrixcrdt:matrix.org\"\u003e\u003cimg alt=\"Matrix\" src=\"https://img.shields.io/badge/Chat on matrix%20-%23000.svg?\u0026style=for-the-badge\u0026logo=matrix\u0026logoColor=white\"/\u003e\u003c/a\u003e\n\n[![npm version](https://badge.fury.io/js/matrix-crdt.svg)](https://badge.fury.io/js/matrix-crdt) [![Coverage Status](https://coveralls.io/repos/github/YousefED/Matrix-CRDT/badge.svg?branch=main)](https://coveralls.io/github/YousefED/Matrix-CRDT?branch=main)\n\nMatrix-CRDT enables you to use [Matrix](https://matrix.org/) as a backend for distributed, real-time collaborative web applications that sync automatically.\n\nThe MatrixProvider is a sync provider for [Yjs](https://github.com/yjs/yjs), a proven, high performance CRDT implementation.\n\n## TL;DR\n\nCreate apps like this:\n\n![screencapture](examples/rich-text-tiptap/richtext.gif)\n\nAnd connect [Matrix](https://matrix.org/) 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.\n\n## Live demo\n\nIn the [examples](examples) directory, you'll find some live examples:\n\n- [Collaborative Todo list](examples/todo-simple-react)\n- [Collaborative rich text editing](examples/rich-text-tiptap)\n\n## Motivation\n\n[CRDTs](https://crdt.tech/) (_Conflict-free Replicated Data Types_) make it easy to build **decentralized**, **fast**, **collaborative** **local-first** applications.\n\n\u003e Read more about [the benefits of Local-first software in this essay](https://www.inkandswitch.com/local-first.html)\n\nWhen 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.\n\nWhile [Matrix](https://www.matrix.org) is primarily designed for messaging (chat), it's versatile enough to use as a backend for collaborative applications (see [Architecture](#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:\n\n- An open standard and active community\n- Multiple server implementations (including hosted servers)\n- Authentication (including support for SSO and 3rd party providers)\n- Access control via Rooms and Spaces\n- E2EE\n- A decentralized architecture with support for federation\n\n# Usage\n\nMatrix-CRDT currently works with [Yjs](https://github.com/yjs/yjs) or [SyncedStore](https://www.syncedstore.org).\n\n## Usage with Yjs\n\nTo setup Matrix-CRDT, 3 steps are needed:\n\n- Create a [Yjs](https://github.com/yjs/yjs) `Y.Doc`\n- Create and authenticate a client from [matrix-js-sdk](https://matrix.org/docs/guides/usage-of-the-matrix-js-sdk)\n- Create and initialize your Matrix-CRDT `MatrixProvider`\n\n```typescript\nimport { MatrixProvider } from \"matrix-crdt\";\nimport * as Y from \"yjs\";\nimport sdk from \"matrix-js-sdk\";\n\n// See https://matrix.org/docs/guides/usage-of-the-matrix-js-sdk\n// for login methods\nconst matrixClient = sdk.createClient({\n  baseUrl: \"https://matrix.org\",\n  accessToken: \"....MDAxM2lkZW50aWZpZXIga2V5CjAwMTBjaWQgZ2Vu....\",\n  userId: \"@USERID:matrix.org\",\n});\n\n// Extra configuration needed for certain matrix-js-sdk\n// calls to work without calling sync start functions\nmatrixClient.canSupportVoip = false;\nmatrixClient.clientOpts = {\n  lazyLoadMembers: true,\n};\n\n// Create a new Y.Doc and connect the MatrixProvider\nconst ydoc = new Y.Doc();\nconst provider = new MatrixProvider(ydoc, matrixClient, {\n  type: \"alias\",\n  alias: \"#matrix-room-alias:matrix.org\",\n});\nprovider.initialize();\n\n// array of numbers which produce a sum\nconst yarray = ydoc.getArray(\"count\");\n\n// observe changes of the sum\nyarray.observe((event) =\u003e {\n  // print updates when the data changes\n  console.log(\"new sum: \" + yarray.toArray().reduce((a, b) =\u003e a + b));\n});\n\n// add 1 to the sum\nyarray.push([1]); // =\u003e \"new sum: 1\"\n```\n\n**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](examples/todo-simple-react-vite/) and [this issue on matrix-js-sdk](https://github.com/matrix-org/matrix-js-sdk/issues/2903).\n\n## SyncedStore\n\nYou can also use [SyncedStore](https://syncedstore.org/docs/) and use Matrix-CRDT as SyncProvider.\n\n## API\n\n**new MatrixProvider** (`doc`, `matrixClient`, `room`, `awareness?`, `opts?`): `MatrixProvider`\n\nThe `MatrixProvider` syncs a Matrix room with a Yjs document.\n\n#### Parameters\n\n| Name                   | Type                                                                | Description                                                                                                       |\n| :--------------------- | :------------------------------------------------------------------ | :---------------------------------------------------------------------------------------------------------------- |\n| `doc`                  | `Y.Doc`                                                             | The `Y.Doc` to sync over the Matrix room.                                                                         |\n| `matrixClient`         | `MatrixClient`                                                      | A `matrix-js-sdk` client with permissions to read (and/or write) from the room.                                   |\n| `room`                 | `{ type: \"id\"; id: string; }` or `{ type: \"alias\"; alias: string }` | The room ID or Alias to sync with.                                                                                |\n| `awareness` (optional) | `awarenessProtocol.Awareness`                                       | A `y-protocols` Awareness instance that can be used to sync \"awareness\" data over the experimental webrtc bridge. |\n| `opts` (optional)      | `MatrixProviderOptions` (see below)                                 | Configure advanced properties, see below.                                                                         |\n\n**MatrixProviderOptions**\n\nAdditional configuration options that can be passed to the `MatrixProvider` constructor.\n\nDefaults to:\n\n```typescript\n{\n  // Options for `ThrottledMatrixWriter`\n  writer: {\n    // throttle flushing write events to matrix by 500ms\n    flushInterval: number = 500,\n    // if writing to the room fails, wait 30 seconds before retrying\n    retryIfForbiddenInterval: number = 30000\n  },\n  // Options for `MatrixCRDTEventTranslator`\n  translator: {\n    // set to true to send everything encapsulated in a m.room.message,\n    // so you can view and debug messages easily in element or other matrix clients\n    updatesAsRegularMessages: false,\n    // The event type to use for updates\n    updateEventType: \"matrix-crdt.doc_update\",\n    // The event type to use for snapshots\n    snapshotEventType: \"matrix-crdt.doc_snapshot\",\n  }\n  // Experimental; we can use WebRTC to sync updates instantly over WebRTC.\n  // See SignedWebrtcProvider.ts for more details + motivation\n  enableExperimentalWebrtcSync: boolean = false\n  // Options for MatrixReader\n  reader: {\n    // How often to send a summary snapshot (defaults to once every 30 events)\n    snapshotInterval: number = 30,\n  },\n}\n```\n\n# Architecture\n\nCRDT updates (in our case, Yjs document updates) are very similar to (chat) Messages, that Matrix has been optimized for.\n\nMatrix-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.\n\nWhen registering a `MatrixProvider`, we:\n\n- Listen to new `matrix-crdt.doc_update` events in the Matrix Room, and apply updates to the Yjs document.\n- Listen to Yjs document updates and send these to the Matrix room as `matrix-crdt.doc_update` events.\n\nCRDTs 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).\n\nThis makes it possible to work offline, or for servers / clients to be out of sync for a while.\n\n## Snapshots\n\nTo 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.\n\nMatrix-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).\n\n## WebRTC (experimental)\n\nMatrix-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.\n\nYou can use the (experimental) `WebRTC` provider to connect to peers over WebRTC and send updates (regular and Awareness updates) instantly.\n\nIdeally, we'd replace this with Matrix Custom Ephemeral events when that [Spec](https://github.com/matrix-org/matrix-doc/pull/2477) has landed.\n\n# Development\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for instructions how to work with this repo (e.g.: installing and building using lerna).\n\n# Credits\n\nMatrix-CRDT is built as part of [TypeCell](https://www.typecell.org). TypeCell is proudly sponsored by the renowned [NLNet foundation](https://nlnet.nl/foundation/) who are on a mission to support an open internet, and protect the privacy and security of internet users. Check them out!\n\n\u003ca href=\"https://nlnet.nl\"\u003e\u003cimg src=\"https://nlnet.nl/image/logos/NGIAssure_tag.svg\" alt=\"NLNet\" width=\"100\"\u003e\u003c/a\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FyousefED%2Fmatrix-crdt","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FyousefED%2Fmatrix-crdt","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FyousefED%2Fmatrix-crdt/lists"}