Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Activity
    coffice1
    @coffice1
    each paragraph uses one Y.Text
    coffice1
    @coffice1
    i'm using yjs demo server. after restart server and reopen browser, the ydoc content is still there. where is it stored? how to clear it?
    16 replies
    kapil verma
    @kapv89

    i have built an application in which users can create diagrams for a specific domain, and work on them collaboratively. This application uses yjs + y-websocket for this. Awareness is used heavily for different features.

    I want to build a feature where a diagram can be made accessible publically, but everyone viewing the diagram loads a local copy of the diagram and can interact with it.

    I want to re-use the core engine which is used by the diagram editor, and load the yDoc in it. The problem is that awareness is used to keep track of collaborator cursor, object drags, object highlights and so on.

    I want an awareness implementation that operates locally. Is there some way to make this work?

    mustafaKamal-fe
    @mustafaKamal-fe
    Hello friends,
    I want to subscribe Yjs events to update my React state!!!
    So users will type down using a rich text editor. The output is xmlFragment. Now i would like to represent the output in HTML using React. However, I want to update only parts that have changed using to re-render only thoes parts. Is there any solution for this problem
    Joshua Fontany
    @joshuafontany
    @dmonad I got a friend to help webpack the QuillDelta library, but I thought I might ask again. Is there anything in the Yjs package that would allow me to generate a Delta of two Y.Texts, so that I can apply it to the document in my y-tiddlywiki Binding? My wiki software (Tiddlywiki) runs on immutable objects behind the scenes, and I get an object with a "title" and a set of named "fields" on each update from the user. I can easily get the "new strings", but then applying them to their bound Y.Maps is easy on straight up string replacement, but complicated if that field of the Y.Map holds a Y.Text.
    kapil verma
    @kapv89

    i have built an application in which users can create diagrams for a specific domain, and work on them collaboratively. This application uses yjs + y-websocket for this. Awareness is used heavily for different features.

    I want to build a feature where a diagram can be made accessible publically, but everyone viewing the diagram loads a local copy of the diagram and can interact with it.

    I want to re-use the core engine which is used by the diagram editor, and load the yDoc in it. The problem is that awareness is used to keep track of collaborator cursor, object drags, object highlights and so on.

    I want an awareness implementation that operates locally. Is there some way to make this work?

    by the way I managed to do this by building a local-awareness-provider :)

    Brian E. Granger
    @ellisonbg
    @dmonad congrts on the new move functionality in Yjs - that is pretty amazing!
    Kevin Jahns
    @dmonad
    Thanks @ellisonbg :)
    Nigel Gilbert
    @micrology
    I use awareness in a similar sort of visual editor for PRSM: the code is at https://github.com/micrology/prsm (look at the bottom of js/prsm.js)
    Braden Wiggins
    @FractalHQ
    @nodumo @whawker any chance either of you can provide some insight into how you solved the issue with a new connection causing the starting content to be duplicated / doc being replaced?
    Braden Wiggins
    @FractalHQ
    I've been trying to figure out how to avoid re-setting the default monaco editor state when new users join a room, but the initial state of all of the YJS objects are undefined when new users join even though the initial user has already set them.
    So I can't use them to populate local state
    Braden Wiggins
    @FractalHQ
    I can't seem to get any sort of on('connect' event to fire on provider or awareness which I imagine would help me wait for the data
    this is the webrtc provider btw, can't find much info on its events
    Braden Wiggins
    @FractalHQ
    provider.on('synced' also never fires
    Braden Wiggins
    @FractalHQ
    ok I'm making progress now with observeDeep
    Braden Wiggins
    @FractalHQ
    Got it working! 😅
    mustafaKamal-fe
    @mustafaKamal-fe

    Hello friends,
    I want to subscribe Yjs events to update my React state!!!
    So users will type down using a rich text editor. The output is xmlFragment. Now i would like to represent the output in HTML using React. However, I want to update only parts that have changed using to re-render only thoes parts. Is there any solution for this problem

    any Ideas ?

    FindAPattern
    @FindAPattern
    @mustafaKamal-fe You can use an approach like this: https://syncedstore.org.
    I personally don't like using proxies, because it's very slow, so I use a different approach of binding my yjs objects to their computed JSON in a state tree, and then using useSyncExternalStoreWithSelector to update the react tree efficiently.
    FindAPattern
    @FindAPattern

    @dmonad I'm running into an issue with using yjs for a collaborative text editing tool. When I inspect the IndexedDB database, it appears that the initial state update is getting stored twice. The documents can be quite large, so I don't want to waste all of this space.

    That said, I'm trying to understand encodeStateAsUpdate's second parameter, as it appears to exist to mitigate this issue, but it isn't operating the way I expect. My understanding is that if you supply the same state as the target object, you should get a very small or nonexistent update, but that's not happening.

    Example code for testing:

    const docA = new Y.Doc();
    const docB = new Y.Doc();
    
    docB.on('update', (update: Uint8Array) => {
      console.log('update', update);
    });
    
    docA.getMap().set('name', new Y.Text('El Pollo Diablo'));
    docB.getMap().set('name', new Y.Text('El Pollo Diablo'));
    
    const docBState = Y.encodeStateVector(docB);
    const update = Y.encodeStateAsUpdate(docA, docBState);
    
    console.log('before update');
    Y.applyUpdate(docB, update);
    console.log('after update');
    
    console.log(docA.getMap().toJSON());
    console.log(docB.getMap().toJSON());

    Output:

    update Uint8Array(42) [
        1,   2, 168, 154, 142, 211,   8,   0, 39,   1,
        0,   4, 110,  97, 109, 101,   2,   4,  0, 168,
      154, 142, 211,   8,   0,  15,  69, 108, 32,  80,
      111, 108, 108, 111,  32,  68, 105,  97, 98, 108,
      111,   0
    ]
    before update
    update Uint8Array(50) [
        1,   2, 152, 205, 189, 164,   9,   0,  39,   1,   0,
        4, 110,  97, 109, 101,   2,   4,   0, 152, 205, 189,
      164,   9,   0,  15,  69, 108,  32,  80, 111, 108, 108,
      111,  32,  68, 105,  97,  98, 108, 111,   1, 168, 154,
      142, 211,   8,   1,   0,  16
    ]
    after update
    { name: 'El Pollo Diablo' }
    { name: 'El Pollo Diablo' }
    So I guess my question is... what is the purpose of the second parameter in encodeStateAsUpdate?
    (Also, thank you for making this incredible library. I converted a considerably large React + Redux application to use it, and it just worked. No defects. No unexpected issues.)
    FindAPattern
    @FindAPattern
    My guess is that it's not doing an actual tree diff, which is somewhat problematic, as it makes restoring snapshots from JSON a bit difficult (since the local document size will increase very quickly).
    Kevin Jahns
    @dmonad

    Yjs never performs a diff between states (we don't even include any kind of diffing library in Yjs). It simply exchanges operations and transforms them so that everyone ends up with the same content.

    In your case, you simply perform the operation: set YText("El Pollo Diabolo") in a Y.Map with the key 'name'. One of the edits will win and overwrite the other state. Instead, you should perform operations on the Y.Text if you want more granular merges.

    The API is documented on the documentation website: https://docs.yjs.dev/api/document-updates
    FindAPattern
    @FindAPattern
    Thanks Kevin. The issue I'm dealing with is a bit higher level. All of the information in the application is syncing just fine. This was just a simple use case for me to figure out how to synchronize snapshots.
    I have a WebSocket w/ Redis provider setup, but I want to treat the Redis storage as entirely ephemeral, so I'm cleaning it up every time all clients disconnect.
    When all clients disconnect, I'm saving the entire document as JSON to a Postgres database. If a client connects again in the future, the server loads the JSON document and converts it to a YJS map, which it then syncs with the client's local IndexedDB document.
    Is there a better approach for doing this type of thing?
    I guess the ideal solution here would be to store the document state vector in Postgres as a binary column. Perhaps that would solve some of these issues.
    Kevin Jahns
    @dmonad
    I recommend to store the document in the Yjs update format in your postgres database (you can still store the json for indexing if needed). This allows you to avoid conflicts with history.
    kapil verma
    @kapv89
    @FindAPattern you can take a look at this repo https://github.com/kapv89/yjs-scalable-ws-backend for persistence to postgres
    Nigel Gilbert
    @micrology
    I'm using the default y-websocket with with default LevelDB persistence adapter. It seems that I could use a postgres database instead (or possibly some other database). Are there any advantages to switching to postgres?
    kapil verma
    @kapv89

    @FindAPattern you can take a look at this repo https://github.com/kapv89/yjs-scalable-ws-backend for persistence to postgres

    @micrology I use the code shared in this repo to set up authentication and persistence via an api endpoint that is protected by an api token

    MarshallChang
    @MarshallChang
    Hi, I'm using y-websocket with slate-yjs , can anyone help me to covert the Uint8Array to utf-8 ? so I can persist the updates into pg and view these operations by java
    FindAPattern
    @FindAPattern
    @MarshallChang Which Uint8Array?
    I'm currently persisting the document vector into PG using a binary column type.
    (I think we have exactly the same use case.)
    FindAPattern
    @FindAPattern
    @kapv89 Thank you so much! This is really well done. Can't believe I didn't see your message until now. I had already rewritten y-websocket for those use cases... this would have made it so much easier -.- .
    kapil verma
    @kapv89

    Hi, I'm using y-websocket with slate-yjs , can anyone help me to covert the Uint8Array to utf-8 ? so I can persist the updates into pg and view these operations by java

    there is a node package for this https://www.npmjs.com/package/js-base64

    MarshallChang
    @MarshallChang
    @FindAPattern I didn't know much about yjs before, I've been reading the docs and the examples for a few days. now I use y-websocket and y-redis for database provider and use CALL_BACK to persist the slate content into PG.I found I don't need to care about the opts, the yjs will do it well.
    @kapv89 thank you, I used it before but I found I can't decode this, it's binary. Now I don't care about it.
    MarshallChang
    @MarshallChang
    at now ,I only have one question leave, I can save snapshot into redis,but I don't know how to use it 😔, I'm trying to use the y-prosemirror in y-demos to intergrate into slate-yjs, Does anyone have any experience?
    Will Hawker
    @whawker
    Just curious, what browsers does YJS aim to support?
    apologies if I've missed something in the docs really obvious
    kapil verma
    @kapv89
    what is the difference between awareness change and update events?
    Kevin Jahns
    @dmonad
    @whawker Yjs works in all browsers that have been updated since 2015. If you want support for really old browsers you should use babel.
    Kevin Jahns
    @dmonad
    Yjs doesn't use generators or async functions. So there is fairly good support for old browsers. However, i dont have any tests. So if you are in doubt you should use babel, or bubel, or something similar.