Thanks to visit codestin.com
Credit goes to Github.com

Skip to content

feat: beforeTransactionBuilt event#752

Open
Finesse wants to merge 1 commit intoyjs:mainfrom
Finesse:feat/before-transaction-built-event
Open

feat: beforeTransactionBuilt event#752
Finesse wants to merge 1 commit intoyjs:mainfrom
Finesse:feat/before-transaction-built-event

Conversation

@Finesse
Copy link

@Finesse Finesse commented Dec 10, 2025

This PR introduces a beforeTransactionBuilt event in Y.Doc. This event fires after the transaction is built (after the ydoc.transact() callback finishes) but before the transaction is committed.

The purpose of the beforeTransactionBuilt event is adding modifications to the document in response to other modifications somewhere else in the same transaction. Having the extra modifications in the same transaction ensures proper undo/redo and synchronization. My use-case is updating the document metadata when something changes deep inside the document:

ydoc.on("beforeTransactionBuilt", (transaction) => {
  // Watching only user-made changes
  if (transaction.origin === null) {
    ydoc.getMap("metadata").set("modifiedAt", new Date().toISOString());
  }
});
Alternative solutions and why they don't work

beforeObserverCalls

ydoc.on("beforeObserverCalls", (transaction) => {
  if (transaction.origin === null) {
    ydoc.getMap("metadata").set("modifiedAt", new Date().toISOString());
  }
});

Creates another transaction.

Wrapping all my document modifications

function myTransact(ydoc, f) {
  return ydoc.transact(() => {
    const result = f();

    ydoc.getMap("metadata").set("modifiedAt", new Date().toISOString());

    return result;
  });
}

myTransact(ydoc, () => {
  ydoc.getMap("foo").set("bar", "baz");
});

It doesn't work with third-party libraries, such as y-prosemirror.

Hijacking transact

const originalTransact = ydoc.transact.bind(ydoc);

ydoc.transact = (f, origin) => {
  return originalTransact((transaction, doc) => {
    const result = f(transaction, doc);

    if (transaction.origin === null) {
      ydoc.getMap("metadata").set("modifiedAt", new Date().toISOString());
    }

    return result;
  }, origin);
};

Works well for changes made inside ydoc.transact, but doesn't work for changes outside ydoc.transact.

I'm not 100% happy with the beforeTransactionBuilt event name, so I'm open for suggestions.

I'm not sure whether there should be a separate "all" event. According to the source code and my experiments, beforeTransaction and beforeAllTransactions events are always emitted together, so I don't understand how the "all" version should work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant