Sync protocol basic example

Hi, I am trying to work up a basic usage of the sync protocol based on y-protocol and y-websocket, but I am missing something as I can’t get 2 documents to sync and I am not sure.

Here are the basics of what I am trying to do:

  1. create a “Peer” class that handles initiating a peer, sharing updates, and receiving messages:
import * as syncProtocol from "y-protocols/sync";
import * as encoding from "lib0/encoding";
import * as decoding from "lib0/decoding";

export class Peer {
  constructor(sendMsg, peerId) {
    this._sendMsg = sendMsg;
    this.peerId = peerId;
  }

  // Call this in response to message
  applyMessage(msg, doc) {
    const decoder = decoding.createDecoder(new Uint8Array(msg));
    const encoder = encoding.createEncoder();

    const syncMessageType = syncProtocol.readSyncMessage(
      decoder,
      encoder,
      doc,
      this.peerId
    );

    // Send response if we have one
    if (encoding.length(encoder) > 0) {
      this._sendMsg(encoding.toUint8Array(encoder));
    }
  }

  // Call this on updates
  notify(update) {
    const encoder = encoding.createEncoder();
    syncProtocol.writeUpdate(encoder, update);
    const msg = encoding.toUint8Array(encoder);
    this._sendMsg(msg);
  }

  // Call this when peer connects first time
  init(doc) {
    const encoder = encoding.createEncoder();
    syncProtocol.writeSyncStep1(encoder, doc);
    const msg = encoding.toUint8Array(encoder);
    this._sendMsg(msg);
  }
}

  1. Do a simple test to see if I can sync 2 yjs docs this way:
import * as Y from "yjs";
import { Peer } from "./src/peer.js";

// Create 2 docs
const doc = new Y.Doc();
const doc2 = new Y.Doc();

// Create 2 peers
let peer;
let peer2;

peer = new Peer((msg) => {
  peer2.applyMessage(msg, doc2);
}, "A");

peer2 = new Peer((msg) => {
  peer.applyMessage(msg, doc);
}, "B");

// When the docs are updated, notify
doc.on("update", (update) => {
  peer.notify(update);
});

doc2.on("update", (update) => {
  peer2.notify(update);
});

// Initialize both peers
peer.init(doc);
peer2.init(doc2);

// Make a change to 1 doc
doc.getArray("foo").insert(0, ["Hello world"]);

// See if the docs are any different
console.log("DOC", doc.toJSON());
console.log("DOC2", doc2.toJSON());

However, when I run that test the docs seem to only partially sync. I get the following logged out:

DOC { foo: [ 'Hello world' ] }
DOC2 { foo: undefined }

What am I missing here? From poking around, it seems like I am not getting SyncStep2 messages generated even though I thought syncProtocol.readSyncMessage would create them in response to receiving a SyncStep1 message

EDIT: OK I realize now that the code above is working, just my test to compare the docs wasn’t. If I add doc2.getArray("foo").get(0), I can then see that doc2 does have the data expected.

That leaves me with a new question: How do you inspect an entire doc in JSON, or check equality between 2 docs? I’m interested in the latter for unit testing purposes

Hey @sperosck,

I’m also not happy about the toJSON method on ydoc, but we have to keep it around until the next major release.

Yjs only recognizes types that have been defined by doing ydoc.getArray('my type'). After defining all types, you can call the toJSON method. For future compatibility I recommend to compare by comparing each type individually compare(ydoc.getArray('my type').toJSON(), otherDoc.getArray('my type').toJSON()).