I am a little puzzled when dealing with collaborative table editing

When I edit a cell in a table, it appends a transaction. I have updated the code in ‘prosemirror-tables’ to prevent errors caused by multiple users editing the same table simultaneously. Here is the code snippet:

     appendTransaction(trs, oldState, state) {
            const preventSend = trs.some((t) => t.getMeta('isRemote') === true);
            const tr = normalizeSelection(state, fixTables(state, oldState), allowTableNodeSelection);
            if (preventSend) {
                return tr?.setMeta('sendToRemote', false);
            return tr;

The reason for this code update is that if ClientA makes a change to the table and sends it to ClientB, then ClientA and ClientB may both make subsequent changes to the table without properly coordinating with each other. This can result in errors.

However, I have encountered a new problem. If ClientA makes a non-table-related change and sends it to ClientB at the same time as ClientB makes a table-related change, my code does not properly handle the situation. ClientB’s subsequent changes may be incorrect.

Is there a way to group the transactions given to appendTransaction to avoid this issue?"

Since transactions added with appendTransaction will happen instantly, and the collab protocol defined in prosemirror-collab sends multiple transactions in one go, I’m not sure how you are ending up in a situation where the first transaction is sent to peers but the appended transaction isn’t immediately sent along in the same message.

I’m using a collaborative plugin that I wrote myself. Let me show you the code.

apply(tr, state: PluginState) {
                if (tr.getMeta('sendToRemote') === false) {
                    return state;
                const validSteps = tr.steps;
                const view = ctx.get(editorViewCtx);
                if (!view.editable) {
                    return state;
                const members = tr.getMeta(collabPluginKey);
                if (tr.getMeta(collabPluginKey)) {
                    state.onlineMembers = members;

                if (tr.docChanged) {
                    state.localSteps = (state.localSteps || []).concat(transformToRebaseable(validSteps, tr.docs));
                if (tr.selectionSet) {
                    const selectStep = new AddSelectStep(tr.selection.$from.pos, tr.selection.$to.pos);
                    state.localSteps = (state.localSteps || []).concat(transformToRebaseable([selectStep], [tr.doc]));
                state.localSteps = removeOldSelectStep(state.localSteps);
                state.lastDoc = tr.doc;
                if (state.localSteps.length) {
                    const now = Date.now();
                    state.timeVersion = now;
                    opts.network && opts.network.setPending(true, now);
                return state;

The step data is collected during apply, and appendTransaction generates a new transaction (tr), and send after view update ,so they may not be sent together.

This is the prosemirror version I am using

        "prosemirror-commands": "^1.3.1",
        "prosemirror-dropcursor": "^1.6.1",
        "prosemirror-gapcursor": "^1.3.1",
        "prosemirror-history": "^1.3.0",
        "prosemirror-inputrules": "^1.2.0",
        "prosemirror-keymap": "^1.2.0",
        "prosemirror-model": "^1.18.1",
        "prosemirror-schema-list": "^1.2.2",
        "prosemirror-state": "^1.4.2",
        "prosemirror-transform": "1.7.1",
        "prosemirror-view": "^1.29.0",

Thank you , you are right . I think the problem is not here