Keeping two docs in sync but only applying some transactions

Heyo,

I’m new to Yjs so I’d love some help understanding some behavior. My application needs two copies of a YDoc and I want to keep them in sync (one is in a WebView the other is within React Native). I was seeing some confusing behavior on subsequent transactions when I applied an ‘initial’ transaction to the YDocs (the initial transaction is to simulate what happens on a Quill instantiation). It looks like subsequent transactions don’t change the YText delta (although if I log the doc with Y.logUpdate(Y.encodeStateAsUpdate(doc)) I do see two transactions in each.

Here’s a minimal repro of the behavior:

describe("repro", () => {
	it("doesn't work", () => {
		const doc1 = new Y.Doc();
		const doc1Text = doc1.getText("quill");
		doc1Text.insert(0, "2");

		const doc2 = new Y.Doc();
		const doc2Text = doc2.getText("quill");
		doc2Text.insert(0, "2");

		let update: Uint8Array;
		doc1.on("updateV2", (u) => {
			assert(update === undefined);
			update = u;
		});
		doc1Text.insert(0, "1");

		const doc1Delta = doc1Text.toDelta();
		console.log("doc1", doc1Delta);
		// doc1 [ { insert: '12' } ]

		Y.applyUpdateV2(doc2, update!);

		const doc2Delta = doc2Text.toDelta();
		console.log("doc2", doc2Delta);
		// doc2 [ { insert: '2' } ]

		expect(doc1Delta).toEqual(doc2Delta);
		// fails, doc2 only has a delta of '2'
		// even though we applied the update from doc1 to doc2
	});

	it("works", () => {
		const doc1 = new Y.Doc();
		const doc1Text = doc1.getText("quill");

		let update: Uint8Array | undefined;
		doc1.on("updateV2", (u) => {
			assert(update === undefined);
			update = u;
		});

		doc1Text.insert(0, "2");

		const doc2 = new Y.Doc();
		Y.applyUpdateV2(doc2, update!);
		update = undefined;

		doc1Text.insert(0, "1");

		Y.applyUpdateV2(doc2, update!);

		const doc1Delta = doc1Text.toDelta();
		console.log("doc1", doc1Delta);
		// doc1 [ { insert: '12' } ]

		const doc2Delta = doc2.getText("quill").toDelta();
		console.log("doc2", doc2Delta);
		// doc2 [ { insert: '12' } ]

		expect(doc1Delta).toEqual(doc2Delta);
	});
});

Could someone help me understand what I’m missing, I’d expect both of these tests to produce the same quill deltas.

You need to apply all updates to ensure that all documents sync.

In the first test case, you only applied the second update of doc1. The correct merge should be 122 or 221 (since you applied three operations). The second update depends on the first one, hence nothing happens.

Think of Yjs documents as a git history. You start with a empty folder and then apply changesets. If you merge two different repositories with the exact same content, you still get a merge conflict because the histories are different.

Only ever initialize once. You can’t initialize twice (like you attempt to do in the first example). The result will be duplication or loss of data.

Thank you, that’s super helpful!

Another question for you - we’re debugging issues where updates appear to be lost. Is there a way to tell when this ‘merge conflict’ is happening/has happened? Y.logUpdate is somewhat hard to read.