yousefed / syncedstore Goto Github PK
View Code? Open in Web Editor NEWSyncedStore CRDT is an easy-to-use library for building live, collaborative applications that sync automatically.
Home Page: https://syncedstore.org
License: MIT License
SyncedStore CRDT is an easy-to-use library for building live, collaborative applications that sync automatically.
Home Page: https://syncedstore.org
License: MIT License
Thanks for sharing SyncedStore! I'm digging in and starting by playing with the examples.
It looks like the package.json for the todo-react example works with npm 6.14.13 but not npm 8.1.4 (latest stable). Not sure exactly what version started the issue but the message is:
npm ERR! code EWORKSPACESCONFIG
npm ERR! workspaces config expects an Array
Gist of a shell session trying it out:
https://gist.github.com/jasonm/33e2d7a7501d3c4f6a8f7df150ed34ec
This seems to fix it:
diff --git a/examples/todo-react/package.json b/examples/todo-react/package.json
index 3ac21ec..4d3cece 100644
--- a/examples/todo-react/package.json
+++ b/examples/todo-react/package.json
@@ -44,10 +44,5 @@
"last 1 firefox version",
"last 1 safari version"
]
- },
- "workspaces": {
- "nohoist": [
- "**"
- ]
}
}
The vue todo example included in this repo has this problem when testing the "Clear Completed" functionality. It filters the todo's array by completed todo objects and then tries to set the todos array to the filtered array leading to this error TypeError: Cannot read property 'forEach' of null
simplified code to reproduce:
import { crdt, Y } from "./packages/reactive-crdt/dist/reactive-crdt.js";
const doc1 = new Y.Doc();
let store1 = crdt(doc1);
store1.arr = [];
store1.arr.push({ title: "Todo 1", completed: true });
store1.arr.push({ title: "Todo 2", completed: false });
let filtered_array = store1.arr.filter(x => !x.completed);
store1.testit = filtered_array[0]; // this will throw error
stack trace
;/** @type {Map<string, any>} */ (this._prelimContent).forEach((value, key) => {
^
TypeError: Cannot read property 'forEach' of null
at YMap._integrate (C:\reactive-crdt\node_modules\yjs\dist\yjs.cjs:5438:60)
at ContentType.integrate (C:\reactive-crdt\node_modules\yjs\dist\yjs.cjs:8714:15)
at Item.integrate (C:\reactive-crdt\node_modules\yjs\dist\yjs.cjs:9263:20)
at C:\reactive-crdt\node_modules\yjs\dist\yjs.cjs:4904:20
at Array.forEach (<anonymous>)
at typeListInsertGenericsAfter (C:\reactive-crdt\node_modules\yjs\dist\yjs.cjs:4880:11)
at typeListInsertGenerics (C:\reactive-crdt\node_modules\yjs\dist\yjs.cjs:4933:12)
at C:\reactive-crdt\node_modules\yjs\dist\yjs.cjs:5258:9
at transact (C:\reactive-crdt\node_modules\yjs\dist\yjs.cjs:3201:5)
at YArray.insert (C:\reactive-crdt\node_modules\yjs\dist\yjs.cjs:5257:7)
at YArray._integrate (C:\reactive-crdt\node_modules\yjs\dist\yjs.cjs:5205:10)
at ContentType.integrate (C:\reactive-crdt\node_modules\yjs\dist\yjs.cjs:8714:15)
at Item.integrate (C:\reactive-crdt\node_modules\yjs\dist\yjs.cjs:9263:20)
at typeMapSet (C:\reactive-crdt\node_modules\yjs\dist\yjs.cjs:5067:130)
at C:\reactive-crdt\node_modules\yjs\dist\yjs.cjs:5573:9
at transact (C:\reactive-crdt\node_modules\yjs\dist\yjs.cjs:3201:5)
at YMap.set (C:\reactive-crdt\node_modules\yjs\dist\yjs.cjs:5572:7)
at Object.set (C:\reactive-crdt\packages\reactive-crdt\dist\reactive-crdt.js:91:13)
at file:///C:/reactive-crdt/test.mjs:22:12
tried to debug and found that the object proxied by reactive-crdt is not "unwrapped" before passing it to yjs but not sure why not or if that's really the problem
Do you know of a usage example of using SyncedStore with hocuspocus.dev as the server?
This looks fantastic, but I'm interested in creating my own provider, EG hasura or supabase.
Is there any guide to implementing your own provider? If so I would love to contribute by creating some open source ones.
An error occurs in the following reproduction sandbox (adapted from the one in the documentation for syncedstore and vue). There are two input fields, the first one uses the reactive object contained within the store for getting the model property. The second one uses the full reference path to the store. The first input field errors when it's touched by the user (the value changed) since the object becomes empty because SyncedStore modifies it in a weird way.
https://codesandbox.io/s/sandpack-project-forked-p3fkw6?file=/src/App.vue
<template>
<main id="app">
baz.title.foo.content
<input
autocomplete="off"
v-model="baz.title.foo.content"
/>
store.documents.baz.title.foo.content
<input
autocomplete="off"
v-model="store.documents.baz.title.foo.content"
/>
</main>
</template>
<script>
import { store } from "./store";
import { ref } from "vue";
import * as Vue from "vue";
import { enableVueBindings } from "@syncedstore/core";
// make SyncedStore use Vuejs internally
enableVueBindings(Vue);
export default {
name: "App",
setup() {
store.documents.baz = {
completed: false,
title: {
foo: {
content: "foo",
user: null
}
}
};
const baz = store.documents.baz;
return {
store, // Put the store on the data() of the component
baz
};
}
};
</script>
...
import { syncedStore, getYjsValue } from "@syncedstore/core";
import { WebrtcProvider } from "y-webrtc";
type Todo = {
completed: boolean
title: {
foo: {
content: string,
user: null
}
}
}
export const store = syncedStore({
documents: {} as Record<string, Todo>
})
...
Hello! if I have the sample todo list, and I do a "todo.completed = false;" always false
if the value is already false, it triggers a change in the store.. and the page refreshes. is it possible to trigger a change only if the set value is different from the current one? of course, I can check if completed is false, but would like a way to do this automatically if possible. Thanks!
Hi, you have a very impressive library. Are you planning to add Angular support?
Hi,thanks for this useful project. I found that there is only old option api usage in Vue example. Because Vue 3 has the powerful composition api just look like react hook, maybe it's a good idea to add composition features for Vue's users. If you agree with this proposal, I'd be glad to open a pr for it;)
I create a sandbox:
https://codesandbox.io/s/sandpack-project-forked-4p6tep?file=/src/App.vue
On the screen, click on "Insert" button, an error will raise that says "this.store.myText.text.insert is not a function". I have no idea what I did wrong.
Hi,
is there a way in SyncedStore to do doc transact as in Yjs, to reduce the number of update calls?
Hi, trying to install the library, I get a dependency failure due to an apparent incompatibility with yjs
npm ERR! code ELIFECYCLE
npm ERR! errno 2
npm ERR! [email protected] dist: `rm -rf dist && rollup -c && tsc`
npm ERR! Exit status 2
npm ERR!
npm ERR! Failed at the [email protected] dist script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
It seems like array assignment by index is not supported currently. For example, if I have a store
export const store = syncedStore({
todos: [] as Todo[],
myText: {} as { text?: any },
arr: [],
fragment: "xml"
});
Then I type:
store.arr.push(1);
store.arr[0] = 1;
It gives me an error says array assignment is not supported. Is there any other way I can do to accomplish equivalent operation?
Hi, nice work!
I'm the author of valtio, and thinking to develop a library valtio-yjs
(no repo yet), which binds those two worlds.
My plan is to use both public APIs, and create two-way bindings. After I spent a couple of hours, I noticed it's not that trivial. (And then got busy with other stuff.)
There might be something I can learn from your work and here's the start of discussion.
I'd be more than happy if we could collaborate on it, but as I see reactive and valtio are different API-wise and maybe for some base concepts. So, not sure what is feasible.
Is it possible to use SyncedStore
without one of the Y.js providers ?
I wonder if SyncedStore
could be used like any other state library (redux, mobx...) and only upgrade/configure it once you really need collaboration?
Thanks to SyncedStore for the results.
Are there any plans to bundle SyncStore with rxjs?
We need clearer examples / introduction of the relation between reactive-crdt, yjs-reactive-bindings and reactive work. And / or maybe rename this package
While looking at the source code and trying out building the doc site, I came to the custom sandbox preview (with the double renders to mimic collaborators) which depends on @theme-init/CodeBlock
.
Is that package available somewhere?
Is it allowed to pass mobx store instance into syncedStore
fn? My store has a bunch of methods and I am worried this will not work. In this case, how should I integrate with mobx? Separate actions/getters somehow?
Example store:
class TodoStore {
todos = [];
get completedTodosCount() {
return this.todos.filter(
todo => todo.completed === true
).length;
}
addTodo(task) {
this.todos.push({
task: task,
completed: false,
assignee: null
});
}
}
const todoStore = new TodoStore();
Thanks!
Maybe I'm missing something, but I tried to follow the examples and it's just not working. I tried a brand new Svelte kit app, installed dependencies, and set up a bare bones store
npm create svelte@latest ss-svelte && cd ss-svelte
npm i --save @syncedstore/core yjs @syncedstore/svelte
npm run dev
Then just src/routes/+page.svelte
and src/lib/stores.js
as follows:
<script>
import {store} from '$lib/stores.js'
function setVal(val) {
return () => {
$store.data.val = val
}
}
</script>
<p>Current value of $store.data.val is {$store.data.val}</p>
<p>$store.todos.length is {$store.todos.length}</p>
<h1 on:click="{setVal(1)}">1</h1>
<h1 on:click="{setVal(2)}">2</h1>
<h1 on:click="{setVal(3)}">3</h1>
import { syncedStore } from "@syncedstore/core";
import { svelteSyncedStore } from "@syncedstore/svelte";
// Create your SyncedStore store
const sStore = syncedStore({ data: {}, todos: [] });
// Create Svelte Store for use in your components.
// You can treat this like any other store, including `bind`.
export const store = svelteSyncedStore(sStore);
hi! if I have "const params = useSyncedStore(store.data.params)" and I have a store that has { data: { params: {} } as ISomeInterface }
imagine I want to set params to a new object, I can't do params = newParams;. I need to do useSyncedStore(store.data) and then do data.params = newParams
the problem is that because I'm observing store.data, it will refresh on any update. if I observe store.data.params, how do I set params to newParams?
TIA
Hi there,
Firstly, this library is great.
Apologies if this is an obvious question- I’d like to filter the data before it’s sent to the store
For example, if I only wanted “completed” todos.
FWIW: I tired using “y-socket” to decode and then return filter but had no success. My thinking was to decode the entire store, then only send back specific data (or even indexes if a different data structure where data is in different “rooms” ie ws://…/key)
How I can filter the data before it arrives to the client? Can you offer any suggestions?
thanks
It seems like it's possible to use SyncedStore in multiple tabs in a browser, just locally. Just BroadcastChannel and y-indexeddb
, no signaling servers, and I don't think it would need any WebRTC activity.
I can share some code I've tried but first I just wanted to ask the question... Is there an official way to use it purely locally?
Hi Yousef,
Good day,
Is it possible for you to give me some pointers around document updates in SyncedStore for persistence?
Currently, I am thinking of computing the the diff of YDoc by getting the previous state before editing and current state after editing. The diff will then be persisted to database for future retrieval.
const doc = getYjsValue(store);
const prevState = Y.encodeStateAsUpdate(doc);
// editing happens here
const newState = Y.encodeStateAsUpdate(doc);
const diff = Y.diffUpdate(prevState, newState);
// the diff will then be persisted to database
However, the diff have to happen in every functions that are going to be used for editing.
The second option is to listen for the update
event on YDoc:
doc.on("update", (update, origin) => {
console.log("update from doc: ", update, origin);
// however, origin is null thus couldnt differentiate whether the updates happens locally or from remote peers
});
FYI, the connection provider is WebRTCProvider.
Thus, if I am able to determine origin, I could persist the updates to database if the updates happens locally.
Is there a way to get to know the origin to differentiate oneself from other peers?
The document updates would then be retrieved from database and merged locally in each of the clients if needed.
Can I know whether my understanding and ideas is correct?
Thanks,
Vincent
First off, this is an amazing project and I'm incredibly impressed with how wide a range of reactive bindings and library integrations you were able to provide. Thank you for your work on this!
If it is important to the solution, I am using the Vue3 bindings.
The problem I'm running into is being able to initialize a document using a value stored in the server. When i try to provide a document with initial values to syncedStore
like so:
const doc = syncedStore({
items: ['a', 'b', 'c'],
})
I get the error: Root Array initializer must always be empty array
.
I can technically initialize everything to an empty state and then add the data, but if there is a race condition or users have slow connections/offline mode this will cause duplication of data when they re-sync. Furthermore I want the flow of my document to be as such:
New document creation:
/list/:listID
In your opinion what is the best way to allow for a document to be persisted and picked up again allowing for initialization of a template document or an existing databased stored document?
Any help greatly appreciated!!!
Hello! I am using SyncedStore in a React application and have come across an issue that I cannot figure out.
It appears that if I have an array of objects in a store, and I change a property of one object, then a component whose render depends on that object does not get updated.
The state data looks like this:
const sections = [
{
id: 1,
todos: [
{ completed: true, title: "Write some code" },
{ completed: false, title: "Write a test" }
]
},
{
id: 2,
todos: [
{ completed: false, title: "Read a paper" }
]
},
];
I have made a minimal repro as a fork of the documentation’s CSB react app and a brief video describing the behavior that I see:
Modifying the data structure to use an object instead of an array seems to work like I’d expect:
sandpack-project-forked-zixtx
I have tried to write a good failing test in this PR YousefED/reactive#4 but I have not read that code carefully enough to know if this is a good repro case.
If it is more helpful to try to write a test against this repo, I'm happy to try that.
Thanks!
First let me say – thanks for an amazing library! It's been really useful for our project 🙌
I've tracked down an issue related to array usage within SyncedStore objects, which eventually results in stack overflow. Here's the shortest example I could create that demonstrates the issue:
import { syncedStore } from "@syncedstore/core";
type StoreRoot = {
foo: Foo;
};
type Foo = {
bar?: number[];
};
const store = syncedStore<StoreRoot>({ foo: {} });
const count = 100000;
for (let i = 0; i < count; ++i) {
if (i % 1000 === 0) {
console.log(`${i} of ${count}`);
}
// Results in patchGetter('length') being called on the array, even though it's already been patched
store.foo.bar = [42];
// Once the loop has executed enough times, reading the length will result in stack overflow
store.foo.bar.length;
}
Output:
0 of 100000
1000 of 100000
2000 of 100000
3000 of 100000
4000 of 100000
5000 of 100000
6000 of 100000
@reactivedata/reactive:372
get: function get(target, key, receiver) {
^
RangeError: Maximum call stack size exceeded
at Object.get (@reactivedata/reactive:372:20)
at observable (@reactivedata/reactive:287:13)
at Atom.reportObserved (@reactivedata/reactive:561:12)
at reportSelfAtom (@syncedstore/yjs-reactive-bindings:111:14)
at YArray.descriptor.get (@syncedstore/yjs-reactive-bindings:185:9)
at YArray.descriptor.get (@syncedstore/yjs-reactive-bindings:188:25)
at YArray.descriptor.get (@syncedstore/yjs-reactive-bindings:188:25)
at YArray.descriptor.get (@syncedstore/yjs-reactive-bindings:188:25)
at YArray.descriptor.get (@syncedstore/yjs-reactive-bindings:188:25)
at YArray.descriptor.get (@syncedstore/yjs-reactive-bindings:188:25)
In our application we run into this quite regularly during any periods of extended usage. Please let me know if I can be of any further help!
Array.unshift
and YArray.unshift
receive different parameter types
YArray.unshift
recive an array parameter
https://codesandbox.io/s/happy-curie-678u8p?file=/src/index.ts
I’ve been trying to move my test code to a CodeSandbox. The code works fine with Vite on my local machine, but somehow I see an error when I tried to replicate it on CodeSandbox. No idea what’s wrong and wether it is related to this repo…
https://codesandbox.io/s/mystifying-wood-5zf8z?file=/src/App.vue
I tried installing the Vue example with npm and it failed - I try not to use npm. Then did yarn install
and all went well. However when I go yarn run serve
I get:
yarn run v1.22.10
$ vue-cli-service serve
INFO Starting development server...
98% after emitting CopyPlugin
ERROR Failed to compile with 4 errors 6:49:29 pm
This dependency was not found:
* yjs in ./node_modules/@reactivedata/reactive-crdt/dist/reactive-crdt.module.js, ./node_modules/@reactivedata/yjs-reactive-bindings/dist/yjs-reactive-bindings.module.js and 2 others
To install it, you can run: npm install --save yjs
Issues checking in progress...
Error from chokidar (C:\): Error: EBUSY: resource busy or locked, lstat 'C:\DumpStack.log.tmp'
No issues found.
I just wanted to have a quick play, so don't go to any trouble. I'm new to yjs and saw your post: https://discuss.yjs.dev/t/reactive-crdt-easy-to-use-api-to-use-yjs-and-build-collaborative-apps/507/7
I understand you are using a fork of yjs.
FYI For managing state I was using NX Observe, then moved to onChange and more recently the reactive code in Acebase which is the best fit so far.
I am now looking seriously at yjs which is how I discovered your lib. The ability to use plain JS objects and arrays is very appealing. I don't use Vue or React 😀
PS. I'm using Node v16.1.0 on Windows 10
This looks like a great project - I'm looking at using it for a collaborative app I'm working on.
My model has deeply nested structures, but in the client side store and in the database these are flattened out using unique IDs. If an object contains nested objects, I store IDs instead. In the store everything becomes top level.
It seems like this approach would work well with SyncedStore, but I'm wondering how allocating new IDs would be handled, to ensure they are unique across devices.
One solution would be to use UUIDs, but I find it a pain to work with these huge long IDs.
My current solution is to generate client-specific temp-IDs, and when objects are persisted to the server, the server allocates a proper unique ID and sends a mapping (temp-ID -> perm-ID) back to the client, so the client-side store can be updated accordingly. It's working but I don't love this approach. It's easy to make mistakes and introduce bugs.
It seems this must be a common issue with the kinds of apps SyncedStore is intended for. Is there a built-in solution?
Thanks very much.
I have been using yjs for some time now. And I usually store binary data in my yjs documents using Uint8Array objects. I wonder if you could add the option to store Uint8Array objects without using the boxed function.
The warning doc.ts:46 property not found on root doc __v_isRef
and similar warnings about other internal Vue properties are spammed on the console. In certain situations, it also prints properties that I'm working with myself as a warning. It would be good if this library could filter out these warnings for internal Vue properties as there doesn't seem to be a way around it. The Vue3 examples in the documentation also have this issue with the warnings.
When I look at the Svelte demo in the docs https://syncedstore.org/docs/svelte/
The two boxes go red when I mouse over them and I see the error "too much recursion" in both boxes.
title ^^ TIA
Is there a way to do undo/redo using Synced Store?
After running npm build
, it seems like some instances and functions are duplicated.
For example, there are two INTERNAL_SYMBOL in packages\core\dist\syncedstore.js
var INTERNAL_SYMBOL$1 = Symbol("INTERNAL_SYMBOL");
var INTERNAL_SYMBOL = Symbol("INTERNAL_SYMBOL");
thanks for this library, been playing with it but stumbled upon an issue when trying to nest an array inside a top level map, when I set the array it appears to be not-boxed (e.g. I can get crdt.myarray.length) but as soon as it gets synced back again from yjs it returns as boxed (crdt.myarray.length doesnt work anymore and instead need to use crdt.myarray.value.length)
is this expected?
I'm investigating SyncedStore.
My use case is allowing users to select multiple documents (projects, i.e., JSON) they can edit. I want to each document synced separately using y-indexeddb (for now) and y-webrtc (goal).
My current approach is to create the store:
import { syncedStore } from '@syncedstore/core'
import { svelteSyncedStore } from '@syncedstore/svelte'
const projects = syncedStore({projects: []})
const store = svelteSyncedStore(projects)
export default store
And then, when the user inputs the id of the document in a form, attempting the following:
const createProject = () => {
const doc = getYjsValue(store)
new IndexeddbPersistence(projectId, doc);
const project = {name, id: projectId, ...description && {description}}
$store.projects.push(project)
clear()
}
Doing that creates a IndexedDB database named as the projectId, but causes the following console errors:
Uncaught TypeError: Cannot read properties of undefined (reading 'on')
at new IndexeddbPersistence (y-indexeddb.js:113:9)
at HTMLButtonElement.createProject (CreateProjectModal.svelte:27:41)
encoding.js:506 Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'store')
at writeStateAsUpdate (encoding.js:506:36)
at encodeStateAsUpdateV2 (encoding.js:525:3)
at encodeStateAsUpdate (encoding.js:556:71)
at y-indexeddb.js:77:27
Can I do what I'm wanting to do with SyncedStore?
Hello!
I'm running into an error with null or undefined values inside a SyncedStore using @syncedstore/[email protected]
:
TypeError: Cannot read properties of undefined (reading 'Symbol(INTERNAL_SYMBOL)')
at getYjsValue (/...myapp.../node_modules/@syncedstore/core/src/index.ts:65:21)
at crdtValue (/...myapp.../node_modules/@syncedstore/core/src/internal.ts:48:12)
at Object.set (/...myapp.../node_modules/@syncedstore/core/src/object.ts:31:23)
at crdtObject (/...myapp.../node_modules/@syncedstore/core/src/object.ts:99:5)
at crdtValue (/...myapp.../node_modules/@syncedstore/core/src/internal.ts:70:14)
at Object.set (/...myapp.../node_modules/@syncedstore/core/src/object.ts:31:23)
at crdtObject (/...myapp.../node_modules/@syncedstore/core/src/object.ts:99:5)
at crdtValue (/...myapp.../node_modules/@syncedstore/core/src/internal.ts:70:14)
at Object.set (/...myapp.../node_modules/@syncedstore/core/src/object.ts:31:23)
at crdtObject (/...myapp.../node_modules/@syncedstore/core/src/object.ts:99:5)
My particular use-case is inserting a modest JSON document from an API response into a boxed value, and that response happens to have some undefined
values in it. Something like this:
const store = syncedStore<StoreShape>({/* ... */});
const apiResp = fetchThing(/*...*/).json();
store.key1.key2 = boxed(apiResp);
I don't see boxing directly related in the traceback, but I'm mentioning it in case it's helpful to understand the use case here.
Here's a small repro case based off the React sandbox from the docs. It adds field to the Todo
type called description
which may be undefined
, and will set the description
to undefined
if you add a new todo named "bad".
WDYT about storing null/undefined in SyncedStore stores?
Hello! I was investigating using yjs in a react project, and started designing my own abstraction when I came across this project. It looks really cool although I haven't been able to get state to sync across two browser windows. Oddly enough, the state syncs when I have my app open in two tabs in the same browser window. I haven't pushed my code anywhere as I'm still playing around with different approaches before incorporating a solution into my main project, but I was able to repro the issue in the react example app: https://3xemy.csb.app/, if you open that link in a chrome window, and then open it again in a second incognito window, the state doesn't get synced across the two windows. In my local playground app, I use y-webrtc
as my provider and determined that the two windows are indeed connecting to each other, but haven't investigated much beyond that.
Hi,
How can we instantiate multiple SyncedStore for multiple To Do list instead of creating one Global store?
Thanks,
Vincent
Has anyone looked at Svelte integration? It seems like a natural fit. I wrote https://svelt-yjs.dev/ which is also an attempt at making yjs easier to use for Svelte, but I like this approach better.
(Please let me know if there's a better place for discussions like this. Do you prefer e.g. https://discuss.yjs.dev?)
I'm curious how you think about exposing awareness through SyncedStore.
A caveat — as I'm fairly new to Yjs, the answer here may very well be "don't use awareness like that." 😄
In this discuss.yjs.dev
thread about Yjs Redux bindings I shared a bit code I've written that I use to provide some facilities reminiscent of redux and react-redux on top of SyncedStore: making the state available throughout the component tree with React context and hooks, and a way of organizing accessors and mutations with names drawn from redux, "selectors" and "actions". I shared a hasty gist here: https://gist.github.com/jasonm/8d81f233a6a4f853ddbd981a8784bc41
There's another piece that I added about awareness, to provide access to the awareness throughout the React component tree. I couldn't quite figure out how to wrap the awareness crdt in reactive/syncedstate (though I admit I haven't yet tried very hard 🙈 ) and ended up subscribing to awareness changes in a useEffect
hook and mirroring them into React state that is provided by my context provider. This all happens in this part of this gist: https://gist.github.com/jasonm/8d81f233a6a4f853ddbd981a8784bc41#file-synccontext-tsx-L51-L74
However (back to my original caveat) this seems to rely on the provider being connected, which isn't great for an offline-friendly/offline-first approach. Perhaps I should not rely on storing the user identity state (currentUserId / JWT claims / etc) into the awareness crdt, and instead store it elsewhere (plain react state?) and then push the interesting parts into provider.awareness
purely for, well, awareness (cursors, etc.)
@YousefED I wonder if you've thought about this?
The minimal example from the documentation:
import { syncedStore, getYjsValue } from "@syncedstore/core";
import { WebrtcProvider } from "y-webrtc";
// (optional, define types for TypeScript)
type Vehicle = { color: string; brand: string };
// Create your SyncedStore store
export const store = syncedStore({ vehicles: [] as Vehicle[] });
// Get the Yjs document and sync automatically using y-webrtc
const doc = getYjsValue(store);
const webrtcProvider = new WebrtcProvider("my-document-id", doc);
Doesn't typecheck on line 12, because Argument of type 'Doc | AbstractType<any> | undefined' is not assignable to parameter of type 'Doc'. Type 'undefined' is not assignable to type 'Doc'.
Will consider to implement SyncedStore to other platforms like IOS and Android?
Hi, I stumbled on this problem that seems very simple, but I can't find info about the solution in the docs of either Yjs or SyncedStore.
"observe" doesn't work immediately after filling SyncedMap:
const store = new syncedStore({ obj: {} })
store.obj.array = []
getYjsValue(store.obj.array).observe(event => {
console.log(event)
})
// Inserting into store.obj.array doesn't trigger console.log
"observe" works after sufficient delay:
const store = new syncedStore({ obj: {} })
store.obj.array = []
setTimeout(() => {
getYjsValue(store.obj.array).observe(event => {
console.log(event)
})
}, 2000)
// Inserting into store.obj.array triggers console.log
There seems to be a delay after which I'm able to use observe.
So I'm wondering: is there a hook in which I can initialize my observes?
Thanks
Btw, I'm using SyncedStore with Vue
This project looks awesome. I was reading about y.js and tried it with Vue which worked, but you seem to have taken it a lot further and almost make the whole magic "invisible".
I’ve tried the example for Vue, but can’t seem to get it to work. How do I need to set up the data without TypeScript?
sharedData: crdt<{
vehicles: Vehicle[];
}>(doc),
I’ve tried:
sharedData: crdt(doc)
But changing arbitrary keys on sharedData (like sharedData.vehicles) wasn’t noticed.
SyncedText
does throw an exception as show in the example below:
I would except that SyncedText is a valid synced object.
import { SyncedText, syncedStore, observeDeep } from "@syncedstore/core";
export const store = syncedStore({ myObject: {} });
store.myObject.myText = new SyncedText("hello");
observeDeep(store.myObject.myText, () => { // Does throw an exception
store.myObject.myText.toString();
});
store.myObject.myText.insert(0, "My name is Bob, ");
I did create a codesandbox example, so it can be reproduced easily:
https://codesandbox.io/s/syncedstore-syncedtext-issue-kpomzt?file=/src/index.js:0-386
This part has been taken from the docs:
https://syncedstore.org/docs/advanced/text#syncedtext-objects
Hi, apologies if this question is answered elsewhere, I looked through all the docs and other issues and couldn't see anything though.
I have a simple chat app, and I would like to use this library to get instant updates. However, I also want each message to be persisted in my database, and when data is fetched from that db I want to replace the syncedstore with that new data.
So really I just want to do this:
// when adding a comment
const handleAddComment = () => {
// update store to trigger real time updates for others
state.comments.push({
comment,
})
// persist to db, might take a second or so and won't trigger any updates
addCommentHook.mutate({
comment
})
}
// data is from the server, I don't know exactly when it will change,
// but if it does I want to fully replace the contents of my store with it
useEffect(() => {
state.comments = data.comments
}, [data])
However, this doesn't work because state.comments is read only. Is there a way to do this? Or am I going down the wrong path entirely?
I have an array in synced store and I wanted to sort
I'm using
const [removed] = store.nodes.splice(srcIndex, 1);
store.nodes.splice(destIndex, 0, removed)
I keep getting an error Not supported: reassigning object that already occurs in the tree.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.