@leosprograms/syn-store
Reactive store that holds the state for the syn
Holochain zome.
High-level design
These are the high level concepts that syn
implements:
- Each network that includes
syn
can manage multiple document
s.
- Each
document
is identified by its root commit hash.
- Each
document
has multiple workspaces
which can evolve independently of each other, and also fork and merge (eg. "main", "proposal").
- Each
workspace
has a latest "tip" commit, which represents the latest snapshot of the state of the document in that workspace.
- Finally, each
workspace
has a session
, which you can join to edit the state of the workspace collaboratively with other agents.
And at the level of code, these concepts translate to these classes:
SynStore
: to create and fetch the documents in this network.
DocumentStore
: to create and fetch the workspaces for the given document, and also its commits.
WorkspaceStore
: to fetch the latest snaphshot and also the previous commits for the given workspace.
SessionStore
: to edit the state of the given workspace in a real-time collaborative session.
Initialization
You can initialize a new document like this:
import { AppWebsocket, AppWebsocket } from '@holochain/client';
import { SynStore, DocumentStore, WorkspaceStore } from '@leosprograms/syn-store';
import { SynClient } from '@leosprograms/syn-client';
const appWs = await AppWebsocket.connect(url);
const client = await AppWebsocket.connect(appWs, 'YOUR_APP_ID')
const synStore = new SynStore(new SynClient(client, 'YOUR_ROLE_NAME', 'YOUR_ZOME_NAME'));
const documentStore = await synStore.createDocument(
{ applicationDefinedField: 'somevalue' },
{ meta: 'value'}
);
await synStore.client.tagDocument(documentHash, "active")
const workspaceStore = new documentStore.createWorkspace(
'main',
undefined
);
At this point, no synchronization is happening yet. This is because you haven't joined the session for the newly created workspace. Let's join the session:
const sessionStore: SessionStore = await sessionStore.joinSession();
If you want another peer to discover that document and join the same session, you can do this:
import { AnyDhtHash } from '@holochain/client'
import { Commit } from '@leosprograms/syn-client';
import { EntryRecord, EntryHashMap } from '@holochain-open-dev/utils';
import { DocumentStore, WorkspaceStore } from '@leosprograms/syn-store';
import { toPromise, joinAsyncMap, pipe } from '@holochain-open-dev/stores';
const documentsHashes: Array<AnyDhtHash> = await synStore.client.getDocumentsWithTag("active");
const documentStore = synStore.documents.get(documentsHashes[0]);
const workspaces: ReadonlyMap<EntryHash, WorkspaceStore> = await toPromise(documentStore.allWorkspaces);
const workspaceStore = Array.from(workspaces.entries())[0];
const sessionStore = await workspaceStore.joinSession();
State and state changes
Now you are connected to all the peers in that same workspace, and can subscribe to the current state for the workspace and also request changes to the state:
sessionStore.state.subscribe(state => console.log('New State!', state));
sessionStore.change(state => {
state.applicationDefinedField = 'Updated content!';
});
Alternatively, you can also get information about the current state of the workspace without joining the session:
workspaceStore.tip.subscribe(tip => {
if (tip.status === 'complete') {
console.log('current tip of the workspace: ', tip);
}
});
workspaceStore.latestSnapshot.subscribe(latestSnapshot => {
if (latestSnapshot.status === 'complete') {
console.log('current state of the workspace: ', latestSnapshot);
}
});
workspaceStore.sessionParticipants.subscribe(participants => {
if (participants.status === 'complete') {
console.log('current participants of the workspace session: ', participants);
}
});
This is useful to display information about the current state of the workspace without having to join the session.
Leaving the session
When you are done with those changes, you need to explicitly leave the session:
await sessionStore.leaveSession();
If you don't, all other participants in the session will try to keep synchronizing with you.
Committing
Changes are committed every 10 seconds by default, and also when the last participant for the workspaces leaves the workspace. You can also commit the changes manually:
await sessionStore.commitChanges(
{ applicationDefinedField: 'somevalue'}
);