streamich/json-joy

applying a patch doesn't result in a modified object

Closed this issue · 1 comments

Hi, and thanks for you work on this. I'm trying to see if json-joy is a good fit in order to add collaboration features.

Here's the code I have (roughly):

import { Model } from "json-joy/es6/json-crdt";
import { s } from "json-joy/es6/json-crdt-patch";
import { encode, decode } from "json-joy/es6/json-crdt-patch/codec/verbose";

// Instanciate the model
const model = Model.withLogicalClock();
model.api.root({
  markers: {},
});

// Generate a patch when needed (here that's when a new marker is created on the map)
model.api.obj("markers").set({ [uuid]: s.con(latlng) });
// send it to the websocket
ws.send("patch", encode(model.api.flush()));

// When receiving stuff from the websocket, apply the patch
let ws = new WebSocketTransport(({ kind, payload }) => {
  if (kind == "patch") {
    console.log("got a patch from another client");
    let patch = decode(payload);
    model.api.apply(patch);
    console.log(model.api.view());
  }
});

The websocket is mainly here to relay messages from one client to the other.


When the patches are applied (on the receiving end), it results in an empty view, and I'm not sure what I'm doing wrong.

Here are are a few questions:

  • I've seen in the exemples that it's initiating the same state by creating the model from the same binary (using Model.fromBinary). Is it possible to initiate from an empty state without doing that?
  • Why does the .view() return an empty object after applying the patch? (I see on the other client that the same .view() returns the markers I added.

Why does the .view() return an empty object after applying the patch?

My guess, that is because you have two different documents and each document has different objects (root object and object at /markers) inside of them. So, when you apply the operations on the second document, the operations cannot find the objects.

Try console-logging your models to see the IDs of the objects:

console.log(model + '');

Is it possible to initiate from an empty state without doing that?

Yes, you need to initiate a document with the default state on each side with the same session ID. And then fork it on each end. That way the common schema (the objects) will have the same IDs.

See example here: https://runkit.com/streamich/json-joy-issue-541

(Note on both ends documents are started with the same common session ID 11111111 and then forked. Once forked a new session ID is generated randomly. You can hard-code 11111111 into your application, it can be any big number.)