All Projects → peer-base → Js Delta Crdts

peer-base / Js Delta Crdts

Delta State-based CRDTs in Javascript

Programming Languages

javascript
184084 projects - #8 most used programming language

Projects that are alternatives of or similar to Js Delta Crdts

SyncedStore
SyncedStore CRDT is an easy-to-use library for building live, collaborative applications that sync automatically.
Stars: ✭ 1,053 (+575%)
Mutual labels:  offline-first, crdt
Gun
An open source cybersecurity protocol for syncing decentralized graph data.
Stars: ✭ 15,172 (+9625.64%)
Mutual labels:  crdt, offline-first
Yjs
Shared data types for building collaborative software
Stars: ✭ 5,894 (+3678.21%)
Mutual labels:  crdt, offline-first
Redwood
A highly-configurable, distributed, realtime database that manages a state tree shared among many peers.
Stars: ✭ 218 (+39.74%)
Mutual labels:  crdt, offline-first
state
A Redux-based state container for local-first software, offering seamless synchronization using Automerge CRDTs. (Formerly known as 🐟 Cevitxe).
Stars: ✭ 126 (-19.23%)
Mutual labels:  offline-first, crdt
credt
CRDT-like data structures for building distributed, offline-first applications
Stars: ✭ 32 (-79.49%)
Mutual labels:  offline-first, crdt
Berty
Berty is a secure peer-to-peer messaging app that works with or without internet access, cellular data or trust in the network
Stars: ✭ 5,101 (+3169.87%)
Mutual labels:  crdt, offline-first
Notepad
📒 An offline capable Notepad PWA powered by ServiceWorker
Stars: ✭ 100 (-35.9%)
Mutual labels:  offline-first
Propertyfindar
🏘 🎃 Real Estate Sample App with RxJava3+Coroutines Flow, Dynamic Feature Modules, Dagger Hilt, Offline First, ConcatAdapter, Animations and tests for Room, Retrofit, useCase and ViewModels with TDD.
Stars: ✭ 133 (-14.74%)
Mutual labels:  offline-first
Wootjs
WOOT model for Scala and JavaScript via Scala.js
Stars: ✭ 99 (-36.54%)
Mutual labels:  crdt
Datakernel
Alternative Java platform, built from the ground up - with its own async I/O core and DI. Ultra high-performance, simple and minimalistic - redefines server-side programming, web-development and highload!
Stars: ✭ 87 (-44.23%)
Mutual labels:  crdt
Tetrys
𝌶 Tetris as Progressive Web Application
Stars: ✭ 100 (-35.9%)
Mutual labels:  offline-first
Monitaure
🔔 A server uptime monitoring progressive web application - NO LONGER MAINTAINED
Stars: ✭ 135 (-13.46%)
Mutual labels:  offline-first
Wq.app
💻📱 wq's app library: a JavaScript framework powering offline-first web & native apps for geospatial data collection, mobile surveys, and citizen science. Powered by Redux, React, Material UI and Mapbox GL.
Stars: ✭ 99 (-36.54%)
Mutual labels:  offline-first
Crdts
A library of Conflict-Free Replicated Data Types for JavaScript
Stars: ✭ 143 (-8.33%)
Mutual labels:  crdt
Cpg
CloudI Process Groups
Stars: ✭ 87 (-44.23%)
Mutual labels:  crdt
Justindb
⚛️ JustinDB is a highly available globally distributed key-value data store.
Stars: ✭ 147 (-5.77%)
Mutual labels:  crdt
Popularmovies
🎥 Movie discovery app showcasing Android best practices with Google's recommended architecture: MVVM + Repository + Offline support + Android Architecture Components + Paging library & Retrofit2.
Stars: ✭ 142 (-8.97%)
Mutual labels:  offline-first
Envoy
A CouchDB proxy to enable replication of database subsets
Stars: ✭ 123 (-21.15%)
Mutual labels:  offline-first
Ground Android
Ground mobile data collection app for Android
Stars: ✭ 120 (-23.08%)
Mutual labels:  offline-first

delta-crdts

Delta state-based CRDTs in Javascript.

Install

$ npm install delta-crdts

Import

const CRDTs = require('delta-crdts')

Instantiate a type

const type = 'rga' // or any of the other supported CRDT types
const Type = CRDT(type)

Create a replica

To create a replica you need pass in a unique node id.

const replica = Type('node id')

Mutate that replica

const deltas = []
deltas.push(replica.push('some value'))
deltas.push(replica.insertAt(0, 'some other value'))

Create a second replica

const replica2 = Type('node id 2')

Apply the deltas

deltas.forEach((delta) => replica2.apply(delta))

Query the value

replica2.value() // ['some value', 'some other value']

Initialize a replica from the entire state

const replica3 = Type('node id 3')
replica3.apply(replica2.state())

Conflict management

You can do concurrent edits on both replicas:

// create 2 replicas
const replicas = [Type('id1'), Type('id2')]

// create concurrent deltas
const deltas = [[], []]

deltas[0].push(replicas[0].push('a'))
deltas[0].push(replicas[0].push('b'))

deltas[1].push(replicas[1].push('c'))
deltas[1].push(replicas[1].push('d'))

deltas[0].forEach((delta) => replicas[1].apply(delta))
deltas[1].forEach((delta) => replicas[0].apply(delta))

assert.deepEqual(replicas[0].value(), replicas[1].value())

Extend

You can extend the types, creating your own CRDT.

Example:

const Zero = {
  initial: () => 0,
  join: (s1, s2) => 0,
  value: (state) => state,
  mutators: {
    doSomething (id, state, arg1) => {
      // example mutator, returning a delta
      return 0
    }
  }
}

CRDT.define('zero', Zero)

// now you can use it

const replica = CRDT('zero')('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.incrementalValue = function (beforeState, newState, delta, cache = { value: <some initial value>, ... }) {
  // ...
}

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 = CRDT('ormap')
const m = ORMap('id1')
const delta = m.applySub('a', 'mvreg', 'write', 'A')
console.log(m.value()) // => {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 = CRDT.type(typeName)

Each type has a series of static methods may need to use:

Type.initial()

Returns the initial state for the type. Example:

const GCounter = CRDT.type('gcounter')
const initial = GCounter.initial()

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 = CRDT.type('gcounter')

const state = GCounter.join(delta1, delta)

const value = GCounter.value(state)

Example of using static methods:

const GCounter = CRDT('gcounter')

deltas = []
deltas.push(replica1.inc())
deltas.push(replica1.inc())
deltas.push(replica1.inc())

const bigDelta = deltas.reduce(GCounter.join, GCounter.initial())

replica2.apply(bigDelta)

License

MIT

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].