streamich / json-joy

JSON CRDT, JSON CRDT Patch, JSON Patch+, JSON Predicate, JSON Pointer, JSON Expression, JSON Type
https://jsonjoy.com/libs/json-joy-js
Apache License 2.0
736 stars 14 forks source link

applying a patch doesn't result in a modified object #541

Closed almet closed 5 months ago

almet commented 5 months ago

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:

streamich commented 5 months ago

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.)