Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Activity
    Kevin Jahns
    @dmonad
    Exactly @alidlo - There are many connectors that allow you to sync document updates using different communication technologies (v12 of Yjs even supported XMPP, and IPFS to sync document updates). You can use them in conjunction, if you want to (e.g you could sync the webrtc network with the websocket network by using both connectors).
    Alid Lorenzo
    @alidlo
    @dmonad looking into comparisons between automerge n yjs, along with having immutability versus mutability, respectively, looks like automerge encapsulates a documents worth of data under a single struct rather than having individual crdts for each field/register.
    are there certain benefits to having individual crdts versus a single one to encapsulate all document changes?
    Alid Lorenzo
    @alidlo
    also looks like yjs does not have the same faciliaties for history tracking / time travel? have you looked into that at all?
    Kevin Jahns
    @dmonad

    @alidlo
    Immutability is a unique feature of Automerge. They create a view on the data and present it to the user. I specifically designed Yjs to be mutable, because manipulations on large lists (e.g. lists of text clusters) are more performant on a mutable data structure. These benchmarks certainly prove my point: https://github.com/dmonad/crdt-benchmarks

    Yjs just implements a single list CRDT. A Y.Map is just a mapping from key to a list, where the last item in the list denotes the current value (other values are automatically deleted). I'm pretty sure that Automerge uses two distinct CRDTs (one for list-like objects like Text and Array, and one for key-value stores).

    Yjs does history tracking very well (although Automerge's history tracking functionality is currently much easier to use). https://yjs.dev/ shows that you can make snapshots and see an old document state. You can even compute the differences between to states and highlight them by the user who created them. I don't think that you can do that in Automerge. Lots of thought has been put into history tracking (I mostly refer to it as snapshots). But the Yjs shared types don't expose convenient functionality to view past state.

    Kevin Jahns
    @dmonad
    Regarding using different CRDTs in a CRDT framework: In Yjs I like that I can re-use one CRDT implementation - this also means less, and better tested code. Using a specialized CRDT for Maps has the benefit that you can encode state updates on Maps more efficiently and that conflict resolution is potentially faster. But the performance benefit is very small and I prefer to reduce complexity and optimize what we already have.
    Callum Atwal
    @callum-atwal
    Hey @dmonad - How would one go about doing some kind of Voice/Video chat whilst having access to the provider (which all peers are within)?
    I tried looking at the simple-peer docs on this as they have a way of doing it with their API but i was unable to find the "Peer" object of type simple-peer within WebrtcProvider
    Callum Atwal
    @callum-atwal
    Essentially i just need a way i can share the MediaStream object - Y.Array/Map will not allow that type of object as content
    Callum Atwal
    @callum-atwal
    after many hours, figured it out. had to add the on('stream') event into y-webrtc.js and then call upon addStream for all peers in provider.room.webrtcConns
    Kevin Jahns
    @dmonad
    Hey @callum-atwal I gave some more hints on how you could do this in your PR yjs/y-webrtc#6
    Dias Sadykov
    @DiasSadykov
    Hi there! I am using Yjs with Monaco editor and I cannot see remote cursors, it seems for me that I am missing css styles for YRemoteSelection and YRemoteSelectionHead and I cannot resolve where to get them, can you help me? Many thanks in advance!
    Oh, It seems like I need to define them myself, as you did in demo example, the problem is solved!
    Jean Carlos
    @jean1187

    hey good afternoon,
    this code it is in utils.js to YJS-13

    if (typeof persistenceDir === 'string') {
    // @ts-ignore
    const LevelDbPersistence = require('y-leveldb').LevelDbPersistence
    persistence = new LevelDbPersistence(persistenceDir)
    }

    Is there a level-db for version 13?
    or any library to make persistent?

    Gerard de Brieder
    @smeevil
    Hi all, I've been messing around with yjs for a while now in my own editor and have everything working fine as long as it's a new document. I cannot seem to figure out how to populate a room with an existing document. The one thing I'd really would like to achieve with using y-websocket is : if I'm the only client connected to the room (provider.awareness.states.size === 1?) then reset the room and apply the document from this client (doc.getText('roomID').insert(0, content)?). What i cannot seem to figure out is how to clean out the server rooms document. Anyone might have a pointer for that ?
    Gerard de Brieder
    @smeevil
    Yes!! figured out it , or at least, it works for me:) I only had to change the y-websocket/utils.js to destroy the document if there where no connections anymore (which it originally only does when persisted)
    Dias Sadykov
    @DiasSadykov
    @smeevil what do you mean by "which it originally only does when persisted"? I am really curious now...
    Gerard de Brieder
    @smeevil
    @DiasSadykov the default utils.js from y-websocket only destroys documents when it is started with YPERSISTENCE env set, otherwise it just keeps them in memory
    BrianHung
    @BrianHung

    Has anyone used y-prosemirror with document layouts / schemas, for example enforcing a title node at the top by having content: "title block+"?

    I'm running into an issue with loading a prosemirror document that has been serialized as a state update. Specifically, with a RangeError: position xx out of range coming from the yjs prosemirror sync plugin. It occurs on line 310 trying to apply fragmentContent to the prosemirrorViewstate.

    BrianHung
    @BrianHung

    The issue occurs because, when initializing an editor with an enforced schema, the length of ydoc.getXmlFragment("prosemirror") goes from 0 to 2 for the title and paragraph node, and then 2 to 4 when Y.applyUpdate(ydoc, ystate) is called with ystate loaded from disk.

    So the flow is: new Y.Doc(), editor is initialized => the ydoc gets two nodes from that => applyupdate is applied and gives two more nodes from previous session. Ideally, yjs would recognize that these two nodes (title, paragraph) are identical; but im not sure why this doesn't occur. Maybe because its the editor thats creating them not a user?

    BrianHung
    @BrianHung

    I think I found the underlying problem; it's within the sync-plugin on line 145. (Link to Github here).

            update: () => {
              const pluginState = plugin.getState(view.state)
              if (pluginState.snapshot == null && pluginState.prevSnapshot == null) {
                if (changedInitialContent || view.state.doc.content.size > 2) {
                  changedInitialContent = true
                  binding._prosemirrorChanged(view.state.doc)
                }
              }
            },

    The issue is, when the default schema for an empty document results in a document with content size greater than 2, it will call binding._prosemirrorChanged(view.state.doc)even though changedInitialContent is false. I believe this is because the default prosemirror empty document is just a paragraph, which has size 2. However, a title + a paragraph has size 4.

    BrianHung
    @BrianHung
    I submitted a pull request at yjs/y-prosemirror#13 (realized I screwed up the link earlier).
    BrianHung
    @BrianHung

    Are new edits supposed to be appended to the end of the Uint8Array that comes from serializing the ydoc as an update, i.e. the first elements stay the same? Or is that not the case, that new edits can change the existing Uint8 Array anywhere?

    I'm printing the Uint8Array after each edit, and I'm noticing most of the elements in the front of the array stay the same. Mostly wondering if the git diff3 algorithm for merge can pick up on this, and auto merge different serialized Uint8Arrays.

    Kevin Jahns
    @dmonad
    If you are printing Y.encodeStateAsUpdate, yes an update can change other elements. Two document updates Insert(0, "a") • Insert(1, "b")are merged into a single document update Insert(0, "ab"). But what you are trying to do is not impossible. You can simply store all document updates in any order (preferably in the order that they are created). Just listen to the ydoc.on('update', incrementalUpdate => {}) event and get the incremental updates. In order to restore the document state you do Y.applyUpdate(ydoc, update) on all incremental updates. You'd loose a bit of the optimizations of update encoding (e.g. that updates are merged). But that should be fine. However, do not attempt to do diffs on the Uint8Array. That would destroy the integrity of the document update.
    markgarbers
    @markgarbers
    Apologies if this is a really silly question, but I can't seem to get the Yjs textarea example working in the browser. I'm failing at the first hurdle of using bower to install the components.
    I'm using this bower install --save yjs y-text y-memory y-webrtc y-websockets-client y-array to install but I'm getting this response and none of the options I've chosen have worked:
    Unable to find a suitable version for yjs, please choose one by typing one of the numbers below:
    1) yjs#^9.0.0 || ^10.0.0 || ^11.0.0 || ^12.0.0 which resolved to 12.3.3 and is required by y-memory#8.0.9
    2) yjs#>= 12.3.1 < 13.0.0 which resolved to 12.3.3 and is required by y-array#10.1.4
    3) yjs#^12.0.0 which resolved to 12.3.3 and is required by y-text#9.5.1
    4) yjs#^11.0.0 || ^12.0.0 which resolved to 12.3.3 and is required by y-websockets-client#8.0.16
    5) yjs#^13.0.4 which resolved to 13.0.4 and is required by includes
    6) yjs#^13.0.4 which resolved to 13.0.4
    Kevin Jahns
    @dmonad

    Hey @markgarbers! I guess that you read the tutorial on y-js.org ? The current documentation is here https://github.com/yjs/yjs and the current website is here https://yjs.dev . The old domain is not owned by me and it still links to the version 12 of Yjs. @istvank is working on linking the old domain to https://github.com/yjs/yjs so we don't have this issue anymore.

    You can install compatible versions like this bower install --save yjs@12 y-text y-memory y-webrtc@9 y-websockets-client y-array or use the current version. I propose that you use the current version and start with an example from here https://github.com/yjs/yjs-demos .

    markgarbers
    @markgarbers
    Ah, yes, that makes sense! I ended up doing exactly as you suggested and starting with the demos from the Git repo.
    All working now, thanks!
    Callum Atwal
    @callum-atwal
    @dmonad hey Kevin, would you happen to know of any literature which explains the strategy that WebRTC uses to handle packet delivery? Or rather, the lack of. Since WebRTC uses UDP as a transport protocol, is it not prone for packets not arriving? (which I guess for its intended use of voice/video chat is okay, but in a context of text synchronisation, could be critical)
    Hope everyone is well and safe, wherever in the world you are :D
    Or if you have factored this into yjs or if you know if simple-peer does this
    markgarbers
    @markgarbers
    Just checking whether there is an up to date abstract connector class and/or documentation on creating new connectors?
    Trying to write a connector to use PubNub and having a start would be great.
    Tried using the XMPP class as a starter, but can't get it working
    Kevin Jahns
    @dmonad
    @callum-atwal Good question! A lot of optimized protocols build on UDP, because it allows for configuration and customized error/correction/stream handling. HTTP/3, for example, now also builds on UDP. That doesn't mean that http/3 will be unreliable - it implements its own reliability features on-top of UDP. The same goes for WebRTC. The stream object (video/audio) of course uses UDP and is unreliable. But data channels use SCTP, which is also build on-top of UDP. The cool thing is that you can configure some of the reliability options. RTCDataChannel configuration I was actually thinking about configuring the order property, because y-protocols doesn't rely on the order of messages. But by default (yes you can configure it), it is as reliable as TCP.

    @markgarbers There is no abstract connector anymore. You can read up on the simplified update mechanism here https://github.com/yjs/yjs#Document-Updates.

    If you also want to implement the Awarenesss protocol, you should have a look at y-protocols, which provides convenient functions to design a communication protocol on your own. https://github.com/yjs/y-protocols

    Kevin Jahns
    @dmonad
    @markgarbers y-xmpp only works with v12. There is no y-xmpp for v13 yet (this is why you get error messages when installing y-xmpp alongside Yjs v13). If you want to use a project as a template maybe start with https://github.com/yjs/y-websocket
    markgarbers
    @markgarbers
    Ok, thanks, thought that may be the case.
    markgarbers
    @markgarbers

    Me again! Thanks for all your help on this... the more I use Yjs the more amazing I find it!

    This time my question is regarding the undoManager. I'm editing a doc from 2 browsers and merging updates as they come in... however, the undoManager only undoes the changes made by a particular user (i.e. it doesn't undo changes that came from the remote user). Any thoughts on how to effectively have a unified undo/redo stack?

    Duane Johnson
    @canadaduane
    @dmonad The link on this page ("our website") goes to a wiki page when I think it's supposed to take visitors to yjs.dev so I fixed it (https://github.com/yjs/yjs/wiki)
    (not sure why I'm allowed to, but hey! I'll take privileges where I can... :)
    Callum Atwal
    @callum-atwal
    @dmonad interesting! I'll read more into that. Thank you :)
    Jose Ortega
    @joorce
    Hi
    I'm trying to develop a simple collab app with prosemirror and found yjs-prosemirror to be very interesting
    for the other part of the app (a writing and reading platform) I'm using mongodb to store data
    about the books being writen, avaliable books, users, etc
    would it be possible to store the state of the yjs-prosemirror document in mongodb?
    LukenAgile42
    @LukenAgile42

    Hows it going,
    I'm wondering how I keep data separate? Currently when I have multiple WebsocketProvider instances in my app, they all receive the same data, even though they have different yDoc instances and shared data field names.

    I also specify different rooms, but this doesnt seem to have any effect either. When I look in the source code, roomname that is passed to the provider does not even seem to be used.

    Related issue that I raised: yjs/yjs#185
    Kevin Jahns
    @dmonad
    @markgarbers In most collaborative applications, you expect that every user has its own undo-stack that is not shared with other users. But you can configure what kind of changes the UndoManager stores with configurations. https://github.com/yjs/yjs#YUndoManager Every change has an origin (as explained in the docs). You could specifically add the origin of the connector to the UndoManager so that remote changes are also triggered.
    @canadaduane Similarly to Wikipedia, everybody can edit the Yjs Wiki! Feel free to add more useful information. And thanks for fixing the link :)
    Kevin Jahns
    @dmonad
    @joorce Sure! There are existing providers that manage storing data efficiently in a database. For example https://github.com/yjs/y-indexeddb and https://github.com/yjs/y-redis/. You can use either of them as a template, although they are a bit over-engineered. This doc explains how you can encode and decode the Yjs document to store it in Mongo: https://github.com/yjs/yjs#Document-Updates You could, for example, store the document after every change (maybe with a backoff mechanism).
    markgarbers
    @markgarbers
    @dmonad Thanks so much, will take a look at that. Thanks for your patience. I promise I have RTFM, but didn't twig that I'd be able to manually add to the Undo stack.
    Kevin Jahns
    @dmonad
    NP @markgarbers ;)