y-localforage v0.1.5
y-localforage
a simple Yjs storage provider using localForage for persistence
Yjs provides a complete ecosystem for (persisting and) sharing "Conflict-free replicated data types" (CRDT) among multiple clients using a variety of persistence and communication providers. LocalForage is a simple storage library for JavaScript which wraps IndexedDB, WebSQL and other storage technologies in a common, localStorage-like API.
This module implements a simple Yjs storage provider for browser-based applications which uses an arbitrary localForage store for persistance - this means: if there is a localForage "driver" for a storage of your choice, you can use this module to immediately instantiate a Yjs provider for it.
In addition to other database providers y-localforage
- contains an
isSyncedproperty which reflects the main document's own current synchronization status, - and an
isFullySyncedproperty which includes the synchronization state of any subdocs, - emits additional events (
sync-started,sync-continued,sync-finishedandsync-aborted) which inform about synchronization progress for the main document, - and
subdoc-syncedwhich informs about a given subdoc being successfully synchronized, - sends a
loadevent to the main doc and any subdoc as soon as thatY.Dochas been fully loaded from persistence, - automatically persists any subdocs as well, and
- includes rudimentary error handling which breaks down the provider upon failure (which means that you have to re-incarnate the provider after the cause for this failure has been removed).
y-localforage always tries to keep your data safe and not to overwrite or even delete previously written updates. Even a failure normally only means that the last update could not be written but all the previous ones are still safe.
Important: do not use the "copy" feature for
Y.Docs, i.e., do not create aY.Docinstance with the same GUID as another one -Y.Doccopies do not "synchronize" as described in the docs anyway.
NPM users: please consider the Github README for the latest description of this package (as updating the docs would otherwise always require a new NPM package version)
Just a small note: if you like this work and plan to use it, consider "starring" this repository (you will find the "Star" button on the top right of this page), so that I know which of my repositories to take most care of.
Installation
y-localforage may be used as an ECMAScript module (ESM), a CommonJS or AMD module or from a global variable.
You may either install the package into your build environment using NPM with the command
npm install y-localforage localforageor load the plain script files directly
<script src="https://unpkg.com/localforage"></script>
<script src="https://unpkg.com/y-localforage"></script>Access
How to access the package depends on the type of module you prefer
- ESM (or Svelte):
import { LocalForageProvider } from 'y-localforage' - CommonJS:
const LocalForageProvider = require('y-localforage') - AMD:
require(['y-localforage'], (LocalForageProvider) => {...})
Alternatively, you may access the global variable LocalForageProvider directly.
Note for ECMAScript module users: all module functions and values are exported individually, thus allowing your bundler to perform some "tree-shaking" in order to include actually used functions or values (together with their dependencies) only.
Usage within Svelte
For Svelte, it is recommended to import the package in a module context. From then on, its exports may be used as usual:
<script context="module">
import * as Y from 'yjs'
import { LocalForageProvider } from 'y-localforage'
</script>
<script>
localforage.config({
driver: [localforage.INDEXEDDB, localforage.WEBSQL]
})
localforage.ready(function () {
const DocStore = localforage.createInstance({
name:'Yjs-Persistence'
})
const sharedDoc = new Y.Doc()
const Persistence = new LocalForageProvider(DocStore, sharedDoc)
...
})
</script>Usage as ECMAscript, CommonJS or AMD Module (or as a global Variable)
Let's assume that you already "required" or "imported" (or simply loaded) the module according to your local environment. In that case, you may use it as follows:
...
localforage.config({
driver: [localforage.INDEXEDDB, localforage.WEBSQL]
})
localforage.ready(function () {
const DocStore = localforage.createInstance({
name:'Yjs-Persistence'
})
const sharedDoc = new Y.Doc()
const Persistence = new LocalForageProvider(DocStore, sharedDoc)
...
})API Reference
The following documentation shows method signatures as used by TypeScript - if you prefer plain JavaScript, just ignore the type annotations.
Constructor
LocalForageProvider (Store:any, sharedDoc:Y.Doc, UpdateLimit:number = 500)creates a new instance ofLocalForageProviderwhich synchronizes the givensharedDocon the given localForageStore.UpdateLimitindicates how many updates should be appended to theStorebefore they will be compacted into a single one
Properties
isSyncedreturnstruewhile the initially givenY.Docand this provider are in-sync - orfalseotherwise. Please note, thatisSynceddoes not inform about the synchronization status of any "subdocs"isFullySyncedreturnstruewhile the initially givenY.Docand all its "subdocs" are in-sync - orfalseotherwise
Methods
SubDocIsSynced (SubDoc:Y.Doc):booleanreturnstruewhile the givenSubDoc(of this provider's sharedY.Doc) and its provider are in-sync - orfalseotherwise.SubDocIsSyncedalso returnsfalseifSubDocis not a subdoc of this provider's sharedY.Docasync destroy ():Promise<void>stops any activities of this provider and deletes any persistence entries of this provider's sharedY.Docand its subdocs. Warning: this method completely destroys any written data and cannot be undone!
Events
on('sync-started', Handler:(Provider:LocalForageProvider, Progress:number) => void)thesync-startedevent is fired whenever a synchronization between this provider and its associatedY.Dochas begun.Providercontains a reference to this provider andProgressis always0.0on('sync-continued', Handler:(Provider:LocalForageProvider, Progress:number) => void)thesync-continuedevent may be fired several times while a synchronization between this provider and its associatedY.Docis in progress if this synchronization can not be completed instantaneously.Providercontains a reference to this provider andProgressis a number between0.0and1.0indicating how much has already been synchronized. Please note: depending on how many new updates are generated (in contrast to how many have been synchronized during that time) the reportedProgressmay not always increase but may even decrease sometimeson('sync-finished', Handler:(Provider:LocalForageProvider, Progress:number) => void)thesync-finishedevent is fired whenever a synchronization between this provider and its associatedY.Dochas finished.Providercontains a reference to this provider andProgressis always1.0on('sync-aborted', Handler:(Provider:LocalForageProvider, Progress:number) => void)thesync-abortedevent is fired when a synchronization between this provider and its associatedY.Dochas been aborted (e.g., because the space on localStorage was exhausted or the provider was destroyed).Providercontains a reference to this provider andProgressis always1.0. After such an event, theProviderremains unusable and has to be created againon('synced', Handler:(Provider:LocalForageProvider) => voidthesyncedevent works like in any other Yjs provider and is fired whenever (initially or after an update to the associatedY.Doc) this provider gets in-sync againon('subdoc-synced', Handler:(Provider:LocalForageProvider, SubDoc:Y.Doc) => voidthesubdoc-syncedevent is fired whenever any "subdoc" of this provider's mainY.Dochas been successfully synchronized.Providercontains a reference to this provider andSubDoca reference to the synchronized subdoc
Build Instructions
You may easily build this package yourself.
Just install NPM according to the instructions for your platform and follow these steps:
- either clone this repository using git or download a ZIP archive with its contents to your disk and unpack it there
- open a shell and navigate to the root directory of this repository
- run
npm installin order to install the complete build environment - execute
npm run buildto create a new build
You may also look into the author's build-configuration-study for a general description of his build environment.