YousefED / SyncedStore

SyncedStore CRDT is an easy-to-use library for building live, collaborative applications that sync automatically.
https://syncedstore.org
MIT License
1.73k stars 52 forks source link

Ignore subdocuments? #98

Open joakim opened 1 year ago

joakim commented 1 year ago

First of all, I have to say that SyncedStore is really nice! Thanks for your work on this.

I wonder, would it be possible to include a subdocument in a SyncedMap, and have SyncedStore ignore it so that I can manage it from another provider?

I use SyncedStore to persist and sync items (a bit like files), which works great. The data model is a generic Item of many kinds (like filetypes), where content is managed by SyncedStore.

type Item = {
  id: number
  kind: string
  content: CRDT
}

type CRDT = {
  data: Record<string, unknown>
  meta: Record<string, unknown>
}

const shape: CRDT = {
  data: {},
  meta: {},
}

// ... when later creating/loading an item:

item.content = syncedStore(shape, doc)

This works great for JSON-like kinds of items. I'm now adding support for rich text using Lexical (via svelte-lexical) and have reached a conundrum. Lexical has great support for Yjs collaboration out of the box, with awareness and all, so I'd like to use that. But it requires a YDoc passed to it. I don't want to pass it item.content, as I still want SyncedStore to manage meta.

If only I could include a subdoc in my data model:

item.content.data.text = new Y.Doc({ autoLoad: true })

But SyncedStore sees it as any other object and throws an Error: invalid on the first value it sees that's a function.

Any ideas?

YousefED commented 1 year ago

Hi @joakim !

Glad you like SyncedStore. Indeed, unfortunately it doesn't support subdocs yet. However, you could probably workaround this by jumping into "raw yjs" functionality for subdocs.

e.g. (pseudocode:

ymap = getYjsValue(item.content.data)
ymap.set("text", new Y.Doc(...));

You could probably even use SyncedStore again for the new subdoc by passing the doc to the syncedStore method.

Let me know whether these suggestions work!

zzph commented 1 year ago

Hiya YousefED, awesome work on this!

Any progress on subdocs yet?

If not, mind showing how it might work with "raw yjs" functionality? I have tried and not succceeded on the below

My attempt:

// done by another client/server
const folder = rootDoc.getMap()

const subDoc = new Y.Doc()
subDoc.getArray().insert(0, ['a'])
folder.set('sub-doc-1', subDoc)

// store.js
const rootDoc = new Y.Doc
const subDoc = rootDoc.getMap().get('sub-doc-1')

export const store = syncedStore(subDoc);

// component
import { useSyncedStore } from "@syncedstore/react";

export default function App() {
  const subDoc = useSyncedStore(store);
  return subDoc.map(i=> <div> {i} </div>)
}
trenta3 commented 1 year ago

I'm interested as well in having a native subdocuments integration. @YousefED Do you have tips on how I could implement it? It is enough to copy the array implementation in the core package to mimick the methods that Y.Doc has? https://github.com/YousefED/SyncedStore/blob/main/packages/core/src/array.ts