delta-crdts
Delta state-based CRDTs in Javascript.
Install
$ npm install delta-crdts
Import
const CRDTs =
Instantiate a type
const type = 'rga' // or any of the other supported CRDT typesconst Type =
Create a replica
To create a replica you need pass in a unique node id.
const replica =
Mutate that replica
const deltas = deltasdeltas
Create a second replica
const replica2 =
Apply the deltas
deltas
Query the value
replica2value // ['some value', 'some other value']
Initialize a replica from the entire state
const replica3 = replica3
Conflict management
You can do concurrent edits on both replicas:
// create 2 replicasconst replicas = // create concurrent deltasconst deltas = deltas0deltas0 deltas1deltas1 deltas0deltas1 assert
Extend
You can extend the types, creating your own CRDT.
Example:
const Zero = 0 0 state mutators: // example mutator, returning a delta return 0 CRDT // now you can use it const replica = 'node id'
Support for incremental value computation
It's possible to allow types to have incremental value computation. If a type supports that, the value is incrementally computed on each delta that is applied.
To add support for incremental value computation to a CRDT, the type definition should support the following function:
Type { // ...}
As an example you can get inspiration from the RGA implementation.
Types
The following types are built-in:
(* means that the type is causal and can be embedded in an ORMap)
Counters
Name | Identifier | Mutators | Value Type |
---|---|---|---|
Increment-only Counter | gcounter |
.inc() |
int |
PN-Counter | pncounter |
.inc() ,.dec() |
int |
Lex-Counter | lexcounter |
.inc() ,.dec() |
int |
Causal Counter * | ccounter |
.inc() ,.dec() |
int |
Flags
Name | Identifier | Mutators | Value Type |
---|---|---|---|
Enable-Wins Flag * | ewflag |
.enable() , .disable() |
Boolean |
Disable-Wins Flag * | dwflag |
.enable() , .disable() |
Boolean |
Sets
Name | Identifier | Mutators | Value Type |
---|---|---|---|
Grow-Only Set | gset |
.add(element) |
Set |
Two-Phase Set | 2pset |
.add(element) , .remove(element) |
Set |
Add-Wins-Observed-Remove Set * | aworset |
.add(element) , .remove(element) |
Set |
Remove-Wins-Observed-Remove Set * | rworset |
.add(element) , .remove(element) |
Set |
Remove-Wins-Last-Write-Wins Set | rwlwwset |
.add(element) , .remove(element) |
Set |
Arrays
Name | Identifier | Mutators | Value Type |
---|---|---|---|
Replicable Growable Array | rga |
.push(element) , .insertAt(pos, element) , .removeAt(pos) , updateAt(pos, element) , insertAllAt(pos, elements) |
Array |
Registers
Name | Identifier | Mutators | Value Type |
---|---|---|---|
Last-Write-Wins Register | lwwreg |
.write(value) |
Value |
Multi-Value Register * | mvreg |
.write(value) |
Set of concurrent values |
Maps
Name | Identifier | Mutators | Value Type |
---|---|---|---|
Observed-Remove Map * | ormap |
.remove(key) , applySub(key, crdt_name, mutator_name, ...args) |
Object |
Embedding CRDTs in ORMaps
OR-Maps support embedding of other causal CRDTs. Example:
const ORMap = const m = const delta = mconsole // => {a: new Set(['A'])}
Of this collection, causal CRDTs are:
- AWORSet
- CCounter
- DWFlag
- EWFlag
- MVReg
- ORMap
- RWORSet
Sets, uniqueness and object id
For testing uniqueness in a way that is safe when replicas are distributed, for objects we calculate the hash using the hast-it
package.
If you want, you can override it by providing a hashCode
attribute in your object.
For all objects where typeof object !== 'object'
, we use the value itself as comparison.
Static methods
You may get the static definition of a type by doing
const type = CRDTtypetypeName
Each type has a series of static methods may need to use:
Type.initial()
Returns the initial state for the type. Example:
const GCounter = CRDTtype'gcounter'const initial = GCounter
Type.value(state)
Returns the view value of a given state.
Type.join(s1, s2)
Joins two states (or deltas) and returns the result.
const GCounter = CRDTtype'gcounter' const state = GCounter const value = GCountervaluestate
Example of using static methods:
const GCounter = deltas = deltasdeltasdeltas const bigDelta = deltas replica2
License
MIT