Discussions related to Shared Editing, Distributed Apps, and Yjs. Questions about Yjs should go to discuss.yjs.dev. Bug reports to the issue tracker.
Hi Everyone, I've been playing around with yjs and enjoying it so far :)
I've found that a nested text inside a map behaves differently to a top level text, which is surprising to me.
Here's the behaviour with two top level texts:
aText current state aaaaaa
bText current state bbbbbb
insert into aText 'AAA" at 2
insert into bText 'BBB' at 2
apply updates to both
adoc latest state bbBBBbbbbaaAAAaaaa
bdoc latest state bbBBBbbbbaaAAAaaaa
This makes sense to me - both texts end up with the combined inserts.
Whereas with a nested text inside a map:
aMap current state { 'my nested text': 'aaaaaa' }
bMap current state { 'my nested text': 'bbbbbb' }
insert into a nested text 'AAA" at 2
insert into b nested text 'BBB' at 2
apply updates to both
aMap latest state { 'my nested text': 'bbBBBbbbb' }
bMap latest state { 'my nested text': 'bbBBBbbbb' }
They randomly converge on either the text from A, or B, instead of including the changes from both.
This makes me feel like I've incorrectly set up my nested text inside my map. Happy to show my code, but I wanted to check as I couldn't find any conclusive statements in the docs beyond my intuition - the nested text state in my second example should end up looking just like the top level text in my first example, right? (otherwise there'd be little point nesting shared types)
I used the docs for Y.Text that has an example of a nested text for my inspiration, but the docs don't actually show it being updated and being propagated across multiple document instances
https://docs.yjs.dev/api/shared-types/y.text
Are there any other examples of nested text in the docs or demos?
Thanks :)
I've found that a nested text inside a map behaves differently to a top level text, which is surprising to me.
Here's the behaviour with two top level texts:
I solved my problem - it turns out that creating two Texts separately under the same key are treated as completely separate things - the key is not their identity, they are. The only safe way to collaboratively edit the same text is to create it on one document, and replicate it to the others by sending state as an update, then editing it afterwards!
Thanks, that makes a lot of sense and is something I'll bear in mind for the future!
Hello! I'm having a bit of trouble understanding the actual usage pattern of yjs from a macro standpoint. I'm not using nodejs for my server, but I could theoeretically call out to a managed nodejs process from my backend server, something I've set up for SSR already. I already have websocket connections set up from my clients to my server. Is there some way that I could use yjs on the clients, managed from a non-js server without having to involve nodejs server side?
@zachdaniel you can take a look at this repo https://github.com/kapv89/yjs-scalable-ws-backend and modify it to interact with an api instead of interacting directly with the db, and then have your actual api-backend in any language of your choice
That would be surprising to me too! The hard drive is an SSD. Does anyone else have any data on this?
Related to this, I am using both y-websocket and y-indexeddb. The README says
y-websocket
A module that contains a simple websocket backend and a websocket client that connects to that backend. The backend can be extended to persist updates in a leveldb database.
y-indexeddb
Efficiently persists document updates to the browsers indexeddb database. The document is immediately available and only diffs need to be synced through the network provider.from which I concluded that y-indexeddb (which uses the local client) should sync faster than y-websocket (the websocket server is in Ireland and I am in England). But I always find that the websocket provider syncs first, by a few milliseconds. Why?
The code looks like this (
exactTime()
yields the time now to the nearest millisecond):const doc = new Y.Doc(); const persistence = new IndexeddbPersistence(room, doc); persistence.once('synced', () => { console.log(exactTime() + ' local content loaded'); }); const wsProvider = new WebsocketProvider(websocket, 'prsm' + room, doc); wsProvider.on('sync', () => { console.log(exactTime() + ' remote content loaded'); }); yNodesMap = doc.getMap('nodes'); yEdgesMap = doc.getMap('edges');
Example output:
09:49:47:513 remote content loaded 09:49:47:516 local content loaded
I believe y-websocket implemented with a bug which did not wait both side exchange the initial vector, then sent out the initial empty data to client, then client thought it is "synced" but indeed the server side did not load the yjs doc from leveldb yet.
Hi, is there a way to delete a root type? Can't find a way to do it..
Essentially the same as:
const info = ydoc.getMap('info')
const value = new Y.Array()
value.insert(0, [1,2,3])
info.set('foo', value)
info.delete('foo')
But using a root type:
const foo = ydoc.getArray('info/foo')
foo.insert(0, [1,2,3])
// How to delete when I don't need this array anymore?
I am completely new to Yjs (and to npm etc.) I notice when I try to install y-array and y-text those have dependency issues. Could not resolve dependency: peer yjs@">= 12.3.1 < 13.0.0" from y-array@10.1.4
Is this a known issue?
Hello everyone :)
I've had some trouble getting the subdocs example code to work
https://docs.yjs.dev/api/subdocuments
and I suspect it's due to this line:
It is up to the providers to sync subdocuments.
as I'm trying to manually sync the two root docs usingY.applyUpdateV2(rootDoc2, Y.encodeStateAsUpdateV2(rootDoc1))
I'm assuming then that I need to use a fully fledged provider that can sync subdocuments properly.
Looking at the provider list, there doesn't seem to be anything useful for local testing - some kind of in-memory provider (beyond the manual application of updates as in my example above). Is this something that exists, and what have people used instead?
Would I have to implement it myself, similar to the code at the bottom of the subdocs docs page?
e.g. doc.on('subdocs', ...
Am I barking up the wrong tree here and overcomplicating it for myself?
Hi all, can someone point me to a current/good example of how to setup persistence on a server? I cant seem to find a recent oen
@yarnball you can check out this repo - https://github.com/kapv89/yjs-scalable-ws-backend
y-websocket
with subdocument support. I'll update the example server implementation to make use of the subdoc protocol I added later on but for now a working version is here: https://github.com/DAlperin/y-websocket/blob/master/src/y-websocket.js
i'm curious if the benefits of the current way of encoding/decoding data (lib0) are significant enough to warrant the added cost in complexity and resistance to adoption in other languages?
For example, readVarUint
:
numbers < 2^7 is stored in one bytlength
numbers < 2^14 is stored in two bylength
That pretty much eliminates using the standard buffer.readUInt8
, for example, right?
i'm trying to understand the reasoning and whether or not a port to go would be feasible.
uint8 would be a bad example.
There are few libraries that do variable-length encoding. buffer.readUint8 still uses 8 bytes for each integer. Furthermore, lib0/encoding also supports other types of efficient encoding and includes a library for RLE encoding. Node libraries are super bloated and have thousands of dependencies from questionable sources. And another thing: lib0 is much more performant than any other alternative. In some cases, lib0 is 1000x faster than alternatives.
If you are interested in writing a Go binding for Yjs, then I recommend to have a look at the yjs/y-crdt project that already includes some language bindings to other languages. I recommend to join the next Y Community meeting if you have any questions.