MatrixRTC and Yjs

Hey i have seen the work done by Yussef “Matrix-CRDT: Yjs provider that connects to Matrix”

I wanted to do the same thing but my project is closed source for now so i didn’t look at the code because of the license

insted Timo made a demo that is MIT licensed
toger5/matrixRTC-example

he talked about here too
" FOSDEM25 – MatrixRTC: Building Real-Time Applications on Matrix" at (14:19)

So i built this app using the MatrixRTC example
Matrix Notebook

i save the state of the doc as a state event in the matrix room every 5 mins and i use the device id so only one state in room per device exist and only the device will be able too override their own state

        const update = Y.encodeStateAsUpdate(ydoc);
        const updateString = btoa(String.fromCharCode(...update));

        await matrixClient.sendStateEvent(
          room_id,
          "yjs.doc." + matrixClient.getDeviceId()!,
          {
            type: "update",
            doc: updateString,
          },
          matrixClient.getUserId()!
        );



then at the start of the app i get the state events and apply them


        const stateEvents = await matrixClient.roomState(room_id);

        const yjsEvents = stateEvents.filter((event) =>
          event.type.startsWith("yjs.doc.")
        );

        yjsEvents.forEach((event) => {
          const binaryString = atob(event.content.doc);
          const update = new Uint8Array(binaryString.length);
          for (let i = 0; i < binaryString.length; i++) {
            update[i] = binaryString.charCodeAt(i);
          }

          Y.applyUpdate(ydoc, update, "remote");
        });

also MatrixRTC uses Livekit which is a scalable way to do webrtc …it will make a livekit room and then you can use it send doc updates and awareness updates between clients


    const livekitRoom = new Room({});

    livekitRoom.connect(sfuConfig.url, sfuConfig.jwt);

    livekitRoom.on("connected", () => {
        const update = Y.encodeStateAsUpdate(ydoc);
        const updateString = btoa(String.fromCharCode(...update));
        let update_json = JSON.stringify({
          type: "update",
          doc: updateString,
        });
        const update_encoder = new TextEncoder();
        const update_data = update_encoder.encode(update_json);

        livekitRoom.localParticipant.publishData(update_data, {
          reliable: false,
        });

        ydoc.on("update", async (u, origin) => {
          const update = Y.encodeStateAsUpdate(ydoc);
          const updateString = btoa(String.fromCharCode(...update));
          let json = JSON.stringify({
            type: "update",
            doc: updateString,
          });

          const encoder = new TextEncoder();
          const data = encoder.encode(json);

          livekitRoom.localParticipant.publishData(data, {
            reliable: false,
          });
        });

just wanted to showcase it here in case anyone was intrested in this

Hi @kemo-1 ,

Thanks for sharing! What lead you to start your own matrix provider? Or, which features were missing for you in matrix-crdt? Or did you implement this just because of general curiosity?

first because of the license ,i thought i can’t use it in closed source (but that when i make modifications only)

second from what i read from the readme it saying that the doc updates get sent as room events

i send them using MatrixRTC then save the doc in the room using state events (i am currently experimenting in matrix media repo)

Edit: Now i am using matrix media repo to save the yjs document

Yeah, the MPL license is also a puzzle for me. I think you should be able to use it in a closed-source project, as long as you keep it separate from the MPL-licensed code and distribute all modifications to the MPL-code under the original license.

(please don’t take this as advice. MPL has weird restrictions on how you have to distribute compiled software that I don’t understand)

Anyway, I do like the idea to use different storage mechanism in matrix. I think back then Matrix didn’t offer these APIs.