"read-only" or one-way only sync

Is there a way to signal to a Y.Doc that it should not accept any incoming state sync directives? I’m particularly interested in this over y-websocket. For certain relms (like the Welcome relm) we want it to be a non-collaborative space until people earn the privilege of modifying the world (i.e. they must gain trust first).

Ideally on the server side we would be able to tell certain Y.Docs to just not accept incoming state sync updates.

1 Like

Hi @canadaduane,

unfortunately we don’t have that feature yet. This also needs to be enforced by the server. Although, I agree, it would be nice to have that information directly in Y.Doc too - as a common API.

Hi @dmonad, is ignoring messages of the format [YjsSyncStep1][YjsUpdate][data] in a client-server setup, like y-websocket, enough to achieve a “read-only” state, or are there other considerations that need to be made?

Sorry for the grave-dig, but it looked like a relevant enough topic :sweat_smile:

That’s fine. Happy you looked for a solution first :slight_smile:

If you want to achieve read-only abilities in y-websockets, you only need to ignore “SyncStep2” and “update” messages. These messages are part of the sync protocol, so you want to disable messages that start with either [0, 1, ..] or [0, 2, ..] (this would be a blacklist approach).

You explicitly want to allow “SyncStep1” because it is a request to the server that asks if there is any new content. So [0, 0] should be allowed.

The first 0 identifies the message as a message from the “sync” protocol. See https://github.com/yjs/y-websocket/blob/master/src/y-websocket.js#L24

The second number is used to identify what kind of sync-message it is. See https://github.com/yjs/y-protocols/blob/master/sync.js#L38

  • [0, 0] is a SyncStep1. It is request to receive the missing state (it contains a state-vector that the server uses to compute the missing updates)
  • [0, 1] is SyncStep2, which is the reply to a SyncStep1. It contains the missing updates. You want to ignore this message as it contains document updates.
  • [0, 2] is a regular document update message.
  • [1, x] Awareness message. This information is only used to represent shared cursors and the name of each user. However, with enough malice intention you could assign other users temporarily false identities.

I think the best approach would be a whitelist approach (safe for future upgrades to the sync-protocol). Something like this

if (!readonly || message[0] !== 0 || message[1] === 0) {
  /* apply message */
} else {  /* filter message */ }
2 Likes

Oh, I’ve actually implemented this if anyone is interested:

Basically did exactly what dmonad was suggesting. I modified it to ignore sync step 2 and update messages.

6 Likes

I’d like to have this feature on my server as well. Will likely implement it myself.

  • [0, 0] is a SyncStep1. It is request to receive the missing state (it contains a state-vector that the server uses to compute the missing updates)
  • [0, 1] is SyncStep2,

This info and pointers about the protocol is very useful, thanks!

Also looking for “permissions” feature - perhaps will do it with some sort of end-to-end encryption (to support p2p) and key sharing through central server.

I’ll likely “hack” the y-websocket protocol by adding my own custom e.g. “messageXX = 3/etc” values to set/get readonly info and exchange crypto keys.

This sounds like very interesting work! There are some similar needs we have at Relm. It would be valuable to see how you implement some of these pieces.

This was really useful, thanks!

unfortunately this fails with

const readItemContent = (decoder, info) => contentRefs[info & binary.BITS5](decoder);
                                                                           ^

TypeError: contentRefs[(info & binary.BITS5)] is not a function
    at readItemContent (file:///Users/adelnizamutdinov/Projects/diagrams/node_modules/yjs/dist/yjs.mjs:9426:76)
    at readClientsStructRefs (file:///Users/adelnizamutdinov/Projects/diagrams/node_modules/yjs/dist/yjs.mjs:1308:13)
    at file:///Users/adelnizamutdinov/Projects/diagrams/node_modules/yjs/dist/yjs.mjs:1535:16
    at transact (file:///Users/adelnizamutdinov/Projects/diagrams/node_modules/yjs/dist/yjs.mjs:3198:5)
    at readUpdateV2 (file:///Users/adelnizamutdinov/Projects/diagrams/node_modules/yjs/dist/yjs.mjs:1528:3)
    at readUpdate (file:///Users/adelnizamutdinov/Projects/diagrams/node_modules/yjs/dist/yjs.mjs:1607:58)
    at readSyncMessage (file:///Users/adelnizamutdinov/Projects/diagrams/back/dist/src/sync.js:82:17)

with yjs 13.5.11 when trying to actually write something

I’m still trying to wrap my head around how to implement authentication / read-only “guests” - The above conversation is helpful, but I’m still confused.

Wondering if anyone might know of some demos or open source code out there that implements something similar? :slight_smile:

2 Likes

@dmonad @braden What is the best approach for ensuring client data from the server during initial sync?

I’m utilizing y-indexeddb to enable offline editing capabilities. However, a challenge arises when users retain outdated data and remain away from the application for an extended period. Upon reopening the application, this older data interferes with the current data.

I’d appreciate your insights and suggestions on how to address this issue.

@toantd90 So you are saying that you don’t want data that is created while offline interferes with the “current” data that the server has?

Maybe you don’t want offline editing?

You can also just discard the data, if it’s older than ‘x’ days. y-indexeddb supports storing custom data (see yIndexeddbProvider.set(key, value)) that you could use to store the time the user was last offline…

I achieve this ,but I find the problem which the client change will still broadcast to other client, though the ydoc don’t change on the server
my topic