Revert to prev state

Hi! On the backend I save backups of the document from time to time as encodeStateAsUdate(yDoc) to have some version history.

I want to be able to rollback to a previous state.

Given two documents I wrote the following code:

public getRevertedChanges({ currentVersion, oldVersion }: { currentVersion: Doc; oldVersion: Doc }): Uint8Array {
  const currentStateVector = encodeStateVector(currentVersion);
  const oldStateVector = encodeStateVector(oldVersion);
  
  const changes = encodeStateAsUpdate(currentVersion, oldStateVector);
  
  const um = new UndoManager([...oldVersion.share.values()]);
  
  applyUpdate(oldVersion, changes);
  
  um.undo();
  
  const revertedChanges = encodeStateAsUpdate(oldVersion, currentStateVector);
  
  um.destroy();
  
  return revertedChanges;
 }

Is oldVersionDoc required to initialize root share types, like oldVersionDoc.getMap(“map1”) etc., for UndoManager to work correctly or not? Are there any problems with this approach?

I think this should be fine.

encodeStateAsUpdate always includes the full delete set. Hence, I would use the update event to generate revertedChanges. Something like…

const updates = []
oldVersion.on('update', update => { updates.push })
um.undo()
const revertedChanges = Y.mergeUpdates(updates)

This gives you the minimal update to revert to the previous version. However, your approach is fine too.

thanks, this way the updates are really smaller

@dmonad I found a strange behavior, in some cases the initialization of root types affects the result of undo.

if I add initialization (getMap) at the beginning, console.log will output 1. And if I don’t, it outputs 2. If this looks like a bug in yjs, I can share the states of these documents so that you can reproduce the behavior. Or this is still a planned behavior and there is a required to initialize root types

  public getRevertedChanges({ currentVersion, oldVersion }: { currentVersion: Doc; oldVersion: Doc }): Uint8Array {
    // oldVersion.getMap("objects")

    const currentStateVector = encodeStateVector(currentVersion);
    const oldStateVector = encodeStateVector(oldVersion);

    const changes = encodeStateAsUpdate(currentVersion, oldStateVector);

    const um = new UndoManager([...oldVersion.share.values()]);

    applyUpdate(oldVersion, changes);

    um.undo();

    console.log("size after revert", oldVersion.getMap("objects").size);

    const revertedChanges = encodeStateAsUpdate(oldVersion, currentStateVector);

    um.destroy();

    return revertedChanges;
  }