Hey Sam,
Sure you can do that. Maybe I misunderstood, but it might make sense to change the perspective a bit and work purely with document updates.
Yjs documents can be transformed to document updates (representing some state of the document). E.g. using update = Y.encodeStateAsUpdate(ydoc)
. Document updates are commutative (which allows, for example, p2p network protocols) and idempotent. Idempotency is a neat property because it allows you to create a powerful templating engine. Basically, it says that updates can be merged even if they contain duplicate information (the duplicate information is then stripped away in the output).
Here is a templating engine for text documents:
import * as Y from 'yjs'
// basic template that should be inherited by all
const basicTemplate = new Y.Doc()
basicTemplate.getText().insert(0, '# Headline\n')
console.log('Basic template: \n' + basicTemplate.getText(''))
// meeting notes template change the headline and add a bullet list
const meetingNotes = new Y.Doc()
// inherit changes from basicTemplate
Y.applyUpdate(meetingNotes, Y.encodeStateAsUpdate(basicTemplate))
meetingNotes.getText().applyDelta([
{ retain: 2 }, // skip "# "
{ delete: 8 }, // delete headline
{ insert: "Meeting Notes" }, // add new headline
{ retain: 1 }, // skip newline
{ insert: "• \n• \n" } // add two bullet items
])
console.log('Meeting notes template: \n' + meetingNotes.getText())
// Now we create a document based on the meetingNotes template
const ydoc = new Y.Doc()
Y.applyUpdate(ydoc, Y.encodeStateAsUpdate(meetingNotes))
console.log('Document state:\n' + ydoc.getText())
// A client can perform some operations on any template. E.g. add a citation to the basic template
basicTemplate.getText().insert(10, "\n> citation")
// We need to apply the changes on all documents that use basicTemplate
Y.applyUpdate(ydoc, Y.encodeStateAsUpdate(basicTemplate))
// the new paragraph is added in the final document
console.log('New state:\n' + ydoc.getText())
Maybe you can adapt this for your own scenario. The above example works on text because it is the most complex scenario. But I think you will see that working with updates makes sense in this scenario. Let me know what you think.