Capturing who authored last change

Hi, we use Yjs with a collaborative text editor. We have a service that is responsible for persisting serialized Yjs doc state to a database while a document is being collaboratively edited. That service listens to updates from multiple clients making changes. When saving a serialized Yjs document, we want to capture which user made the latest change to the document.

Any recommendations on how to do this? Is there a way to take a Yjs document and inspect the history of transactions? Do those transactions keep metadata, such as origin?

Hi @sperosck,

Yjs does not associate users with the performed changes by default. However, this can be added using an experimental feature “PermanentUserData”. This is shown in the prosemirror versioning demo. Please note that this is stil in the experimental state and that there is little documentation about this rather complex feature.

Cheers -

2 Likes

Hi @sperosck

From my understanding of Yjs, this is something that would require significant engineering effort.

In my project I am persisting yjs updates in the db in the form of b64 encoded strings, and I merge the updates into one when fetching them for loading a document. This merging action would cause loss of information of which user sent which updates. And If you don’t merge them, then you’ll have millions of updates for a single yjs doc in your db very quickly.

The solution I have thought about for implementing an “audit-trail” of sort is to

  1. push the update along with the user-id of the user who sent that update into a job-queue
  2. maintain the state of the document in db in a separate table, which will only be used for calculating diffs caused by documents by updates sent within a certain interval
  3. calculate the document audit trail using background workers and store it in the db
1 Like

This feature is awesome. We have been looking at YJS at Aline for some time and are likely to implement collab in 2022, probably using YJS. Is the experimental feature “PermanentUserData” going to make it into the codebase as a stable feature in the future? We would be looking to utilize it to show diffs of document versions (legal contracts) to users within Aline’s editor (a fully paginated editor built on Slate). Great library! Thanks.

Thanks @BrentFarese You can already use PermanentUserData. But there is likely going to be v2, but with a compatible interface (I don’t plan a migration path from v1 to v2, but you could write it). The real issue is that Slate doesn’t support versioning yet. But I know that the author is currently working on a rewrite. If you pay him, he might be able to add versioning support. I recommend to talk to the author and find a way to fund him though slate-yjs - Open Collective

1 Like

Thank you! I’ll do that. Is it possible to show changes over time using YJS w/o user data? What I mean is something similar to Word’s compare feature where changes to the doc are shown, but not necessarily the user that made those changes. We will probably attach user data to changes but was curious as we might enable both.

@BrentFarese
Yeah, absolutely. In that case, you don’t need PermanentUserData and can use plain snapshots. This should make everything much simpler.

Hi @dmonad,

Can this versioning demo be implemented in Tiptap Editor?

Sure, that should be fairly straight-forward. You just need to figure out how to forward the y-prosemirror parameters to the TipTap plugin.

There’s one more thing I’m having a hard time figuring out, maybe you could help me with that. To give you a context of what I’m trying to create; I am creating a document reviewer, wherein some initial content will be rendered in the editor and users may make some changes to that document. These changes need to be tracked and saved in db. So far, by referring to the prosemirror-versions demo, I’m able to track these changes. But when the document is closed and re-opened again, I’m not able to figure out a way to reconstruct the current state of the document with the user meta data.

This is all already handled by the prosemirror-versions demo. I’m not sure why this doesn’t work for you.

@dmonad Can the PermanentUserData be used to track individual transactions? I want to use this information to keep cursors visible for actively typing users while timing out cursors for inactive but present users. I was trying to figure it out by playing around and reading the code but from what I can tell the user data is not forwarded with transactions. Do we need to create versions/snapshots to get the PermanentUserData to transmit?

I solved my problem another way. I ended up just using a throttled call to awareness.setLocalStateField('lastChanged', Date.now())