Applying Steps and collaborative editing

Hi! In continuation of my previous topic [Solved] Steps and collaborative editing.
I’m implementing collaborative editing, and now I have the following problem: when I edit a document in the first window, it’s updated in the second, but when after that I try to make changes in the second, an error occurs in the first.

Here’s how I send and receive changes:

// Send
this.view = new EditorView(target, {
  state,

  dispatchTransaction(transaction) {
    const newState = this.state.apply(transaction);

    this.updateState(newState);

    const sendable = collab.sendableSteps(newState);

    if (sendable) {
      socket.emit('update', 
        sendable.version, 
        sendable.steps, 
        sendable.clientID,
      );
    }
  },
});
// Receive
socket.on('updated', ([version, stepsJSON, clientID])=> {
  if (clientID == userId) return false;

  const steps = stepsJSON
    .slice(collab.getVersion(this.view.state))
    .map((json) => Step.fromJSON(this.view.state.schema, json));

  const transaction: Transaction = collab.receiveTransaction(
    this.view.state,
    steps,
    clientID,
    { mapSelectionBackward: true },
  );

  this.view.dispatch(transaction);
})

Initially, I have an empty document opened in two windows. My actions:

  1. I enter “1” in the first window. In the second I get:
    And my code works! The editor accepts the update!
  2. I enter “2” in the second window. In the first I get: image image

Which is strange, if I do the same thing, but with a longer text, I get a different error already: “RangeError: Position X out of range”.

What am I missing? :melting_face:

I understood that when I start typing, the cyclic dependence starts to occur, events begin to follow each other endlessly. I think that I’m missing something conceptual, but can’t understand what. I have read documentation and the source files of the example, but cannot see where my problem might be. In fact, I believe that it’s related to versions of documents that I should be controlling… Or maybe not…

My code hasn’t changed, now it looks like this:

const view = new EditorView(target, {
  state,

  dispatchTransaction(transaction) {
    const newState = this.state.apply(transaction);

    view.updateState(newState);

    const sendable = sendableSteps(newState);

    if (sendable) {
      socket.emit('update', sendable);
    }
  }
});

socket.on('updated', ({ version, steps, clientId }) => {
  if (clientId == userId) return false;

  const transaction = receiveTransaction(
    view.state,
    steps
      .slice(getVersion(view.state))
      .map((json) => Step.fromJSON(view.state.schema, json)),
      clientId ?? 0,
    );

  view.dispatch(transaction);
});

This is all! When I make changes to the document, my socket-events start causing each other endlessly. What logic should I add to avoid this?

@marijn sorry to bother you, perhaps your eyes will immediately see the cause of my problem

I changed the way I applied the changes from another window:

socket.on('updated', ({ version, steps, clientID }) => {
  if (clientID == userId) return false;

  const transaction = receiveTransaction(
    view.state,
    steps
      .slice(getVersion(view.state))
      .map(json => Step.fromJSON(view.state.schema, json)),
    clientID,
);

  view.updateState(view.state.apply(transaction));
});

But I can still edit the document only from one window, the second one gets the changes, but when it initiates the changes itself, I get the error again: Uncaught (in promise) RangeError: Position X out of range

ezgif.com-video-to-gif

Can anyone see what I’m doing wrong?

Closed. I’ve made some nonsense here.